From 4c79dae878576b37511c2fc75a72a8abffee7b77 Mon Sep 17 00:00:00 2001 From: George Gevoian Date: Mon, 11 Sep 2023 21:49:10 -0400 Subject: [PATCH] Copy changes from Phabricator --- .dockerignore | 1 + .github/workflows/docker_latest.yml | 2 +- .github/workflows/main.yml | 10 +- .gitignore | 1 + .nvmrc | 2 +- Dockerfile | 4 +- app/server/lib/FlexServer.ts | 3 +- app/server/lib/NSandbox.ts | 4 + app/server/lib/SamlConfig.ts | 3 +- app/server/lib/SandboxControl.ts | 8 +- app/server/lib/expressWrap.ts | 6 +- mocha-webdriver-0.3.2.tgz | Bin 0 -> 44135 bytes package.json | 16 +- static/test.html | 4 +- test/declarations.d.ts | 28 - test/gen-server/seed.ts | 4 +- test/mocha.opts | 5 - test/nbrowser/ChartView1.ts | 804 +++++++++++++++ test/nbrowser/ChoiceList.ts | 35 +- test/nbrowser/CustomWidgetsConfig.ts | 16 +- test/nbrowser/DetailView.ntest.js | 13 +- test/nbrowser/DocTutorial.ts | 57 +- test/nbrowser/FillLinkedRecords.ntest.js | 11 +- test/nbrowser/Pages.ts | 1 - test/nbrowser/RawData.ts | 5 +- test/nbrowser/RightPanel.ts | 2 +- test/nbrowser/SavePosition.ntest.js | 11 +- test/nbrowser/SelectByRefList.ts | 2 +- test/nbrowser/WebhookPage.ts | 12 +- test/nbrowser/chartViewTestUtils.ts | 99 ++ test/nbrowser/gristUtil-nbrowser.js | 15 +- test/nbrowser/gristUtils.ts | 161 ++- test/server/Comm.ts | 66 +- test/server/customUtil.ts | 2 +- test/server/lib/DocApi.ts | 4 +- test/server/lib/ManyFetches.ts | 2 +- test/server/lib/Telemetry.ts | 12 + test/server/lib/Webhooks-Proxy.ts | 4 +- test/server/lib/helpers/TestProxyServer.ts | 7 +- test/split-tests.js | 2 +- yarn.lock | 1043 +++++++------------- 41 files changed, 1613 insertions(+), 874 deletions(-) create mode 100644 mocha-webdriver-0.3.2.tgz delete mode 100644 test/mocha.opts create mode 100644 test/nbrowser/ChartView1.ts create mode 100644 test/nbrowser/chartViewTestUtils.ts diff --git a/.dockerignore b/.dockerignore index f2e04e8d31f..9d0449ec292 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,3 +14,4 @@ !test !ext **/_build +!mocha-webdriver-0.3.2.tgz \ No newline at end of file diff --git a/.github/workflows/docker_latest.yml b/.github/workflows/docker_latest.yml index 6140fc76205..5b79ef03a11 100644 --- a/.github/workflows/docker_latest.yml +++ b/.github/workflows/docker_latest.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: python-version: [3.9] - node-version: [14.x] + node-version: [18.x] steps: - name: Check out the repo uses: actions/checkout@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 98db1d33cbd..28a244fbfef 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: python-version: [3.9] - node-version: [14.x] + node-version: [18.x] tests: - ':lint:python:client:common:smoke:' - ':server-1-of-2:' @@ -30,10 +30,10 @@ jobs: - ':nbrowser-^[^A-S]:' include: - tests: ':lint:python:client:common:smoke:' - node-version: 14.x + node-version: 18.x python-version: '3.10' - tests: ':lint:python:client:common:smoke:' - node-version: 14.x + node-version: 18.x python-version: '3.11' steps: - uses: actions/checkout@v3 @@ -72,6 +72,10 @@ jobs: - name: Build Node.js code run: yarn run build:prod + - name: Install chromedriver + if: contains(matrix.tests, ':nbrowser-') || contains(matrix.tests, ':smoke:') + run: ./node_modules/selenium-webdriver/bin/linux/selenium-manager --driver chromedriver + - name: Run smoke test if: contains(matrix.tests, ':smoke:') run: VERBOSE=1 DEBUG=1 MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:smoke diff --git a/.gitignore b/.gitignore index cc60d2ebfd1..53b934812c9 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,4 @@ timings.txt xunit.xml **/_build +!mocha-webdriver-0.3.2.tgz diff --git a/.nvmrc b/.nvmrc index 28515227601..4a1f488b6c3 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14.20.1 +18.17.1 diff --git a/Dockerfile b/Dockerfile index 17415c0f39c..1b4002e2364 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ FROM scratch as ext ## Javascript build stage ################################################################################ -FROM node:14-buster as builder +FROM node:18-buster as builder # Install all node dependencies. WORKDIR /grist @@ -67,7 +67,7 @@ FROM gristlabs/gvisor-unprivileged:buster as sandbox ################################################################################ # Now, start preparing final image. -FROM node:14-buster-slim +FROM node:18-buster-slim # Install libexpat1, libsqlite3-0 for python3 library binary dependencies. # Install pgrep for managing gvisor processes. diff --git a/app/server/lib/FlexServer.ts b/app/server/lib/FlexServer.ts index 6fa2307912c..d442603f07d 100644 --- a/app/server/lib/FlexServer.ts +++ b/app/server/lib/FlexServer.ts @@ -67,7 +67,6 @@ import {addUploadRoute} from 'app/server/lib/uploads'; import {buildWidgetRepository, IWidgetRepository} from 'app/server/lib/WidgetRepository'; import {setupLocale} from 'app/server/localization'; import axios from 'axios'; -import * as bodyParser from 'body-parser'; import * as cookie from 'cookie'; import express from 'express'; import * as fse from 'fs-extra'; @@ -752,7 +751,7 @@ export class FlexServer implements GristServer { public addJsonSupport() { if (this._check('json')) { return; } - this.app.use(bodyParser.json({limit: '1mb'})); // Increase from the default 100kb + this.app.use(express.json({limit: '1mb'})); // Increase from the default 100kb } public addSessions() { diff --git a/app/server/lib/NSandbox.ts b/app/server/lib/NSandbox.ts index 05ec7c8bc31..ac61a033493 100644 --- a/app/server/lib/NSandbox.ts +++ b/app/server/lib/NSandbox.ts @@ -737,6 +737,10 @@ function gvisor(options: ISandboxOptions): SandboxProcess { wrapperArgs.push(process.env.GRIST_CHECKPOINT!); } const child = spawn(command, [...wrapperArgs.get(), `python${pythonVersion}`, '--', ...pythonArgs]); + if (!child.pid) { + throw new Error(`failed to spawn python${pythonVersion}`); + } + // For gvisor under ptrace, main work is done by a traced process identifiable as // being labeled "exe" and having a parent also labeled "exe". const recognizeTracedProcess = (p: ProcessInfo) => { diff --git a/app/server/lib/SamlConfig.ts b/app/server/lib/SamlConfig.ts index 5cdac99a039..bc51669c8f4 100644 --- a/app/server/lib/SamlConfig.ts +++ b/app/server/lib/SamlConfig.ts @@ -52,7 +52,6 @@ * */ -import * as bodyParser from 'body-parser'; import * as express from 'express'; import * as fse from 'fs-extra'; import * as saml2 from 'saml2-js'; @@ -161,7 +160,7 @@ export class SamlConfig { })); // Assert endpoint for when the login completes as POST. - app.post("/saml/assert", bodyParser.urlencoded({extended: true}), expressWrap(async (req, res, next) => { + app.post("/saml/assert", express.urlencoded({extended: true}), expressWrap(async (req, res, next) => { const relayState: string = req.body.RelayState; if (!relayState) { throw new Error('Login or logout failed to complete'); } const permitStore = this._gristServer.getExternalPermitStore(); diff --git a/app/server/lib/SandboxControl.ts b/app/server/lib/SandboxControl.ts index d2626d1bf47..64341ecd9e2 100644 --- a/app/server/lib/SandboxControl.ts +++ b/app/server/lib/SandboxControl.ts @@ -30,12 +30,16 @@ export interface ISandboxControl { * Control a single process directly. A thin wrapper around the Throttle class. */ export class DirectProcessControl implements ISandboxControl { + private _pid: number; private _throttle?: Throttle; constructor(private _process: childProcess.ChildProcess, logMeta?: log.ILogMeta) { + if (!_process.pid) { throw new Error(`process identifier (PID) is undefined`); } + + this._pid = _process.pid; if (process.env.GRIST_THROTTLE_CPU) { this._throttle = new Throttle({ - pid: _process.pid, + pid: this._pid, logMeta: {...logMeta, pid: _process.pid}, }); } @@ -55,7 +59,7 @@ export class DirectProcessControl implements ISandboxControl { } public async getUsage() { - const memory = (await pidusage(this._process.pid)).memory; + const memory = (await pidusage(this._pid)).memory; return { memory }; } } diff --git a/app/server/lib/expressWrap.ts b/app/server/lib/expressWrap.ts index 6e69bdf2fb6..a2f707798a0 100644 --- a/app/server/lib/expressWrap.ts +++ b/app/server/lib/expressWrap.ts @@ -2,10 +2,14 @@ import {RequestWithLogin} from 'app/server/lib/Authorizer'; import log from 'app/server/lib/log'; import * as express from 'express'; +export interface AsyncRequestHandler { + (req: express.Request, res: express.Response, next: express.NextFunction): any | Promise; +} + /** * Wrapper for async express endpoints to catch errors and forward them to the error handler. */ -export function expressWrap(callback: express.RequestHandler): express.RequestHandler { +export function expressWrap(callback: AsyncRequestHandler): express.RequestHandler { return async (req, res, next) => { try { await callback(req, res, next); diff --git a/mocha-webdriver-0.3.2.tgz b/mocha-webdriver-0.3.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2d464bb857d146743c44b7d8285bd830317e3d6b GIT binary patch literal 44135 zcmV(yKq9 zJQ7HPA}kW10Z@lM`tPr(BVJzP|q8-aW7C_x1J72OD?qd;fL!{)6?6jRz0bq22n%`sPFY_rLyvKZ`66QUK)( zOcMTh`rrSMKi*A$+VfyI3B700FpRTs<(ig%3)3u0VsF!5Z+gE3@ghhsz0LLYdrM!M zMs$!IaepPSMZwjD)To<@TO{_X{tH^L#qkvF*X z4#FXKvH|_4$>L<<{pclQ_!2?8WVo1xabAQgNlSnYllf&DolJ5sIgi8C1CZdwD8KZA zMLtQ==p&6M{Zze?PlDWoK~K^EUW`wuk>J4sAUp}CUXQvi0kMd2f&_i&1w-mZK>=uh zw$e=k4Ftd_%y?)(Xr3n1rWd54`Z6V;n>ZW%brFx?wP7-wC9(7*4ZZUypKw1spzrM@ zDZw#cr1JzQ#$Z)1xLTu{^ird#WL`aL@TA;gCuh-UfqkW(O&`)hcmdEx83F=u&!Q|Nf+srTO+d?1BDDh;Z3tTs zw%4pkY4bE3hiMA0)6+3w{1k_nC8G$Y7SOIz3mnD6>4H!Jo6w7s+?z(T2uFu?%#v|_ zj^vfmfUqbdz`ojh)RA<<4Vr5IkE4@CO3z_grlG|?_6F~P6w06n@g@HT%dwc!{urmp z3?2?AK@3o<4FXgVXV@}O1Vz70r zM!-nUf@m5HrfUCNe5r}t6bWz`2q^`cFDUK?Xn@9=y)mYsaYSeh@*HIgVMswMUDRO$ z;YBc;!^rR=uy!DGei2)?=kpLozJSd%P0kwz3*9h{&H#&Np@#^`YDEgbF{*JOvzMM2 z2MX{(km2IRv=v7<22wvz5A!M0D~n{+7$3wbP~ldN_ox8{8;g+v9tY~UJ-qQJ)~w? zJL+DfMjFn7Nbk>Z9;8Gmh!>j1EKI}cCG3Ovln^%nYC$@QgIU;6iyi?ZO2@&FghbPl zks7Hbpb$G@GB&H;K~^p@zH-Hjdq8hlYdnoW*>FmhYB;bnXHAHPN1}#g z0pGMXMUGrQfuX00ZD)%C@D5=fO79@*BFG6m*$Ole@$r&cp;np1-L=xfR#cEH)9^^| zgAkB822?CpUT!Dty_%j=P5NSauh}xZ6i#6SrU@|PCa%IDm=YbGr}$n>%EuxW?0dKi zY@~+Cvdb(FXPM2yLFO(( z6d^;Bk0e}h(iSywh?cj;|>=YNqHJ^M*LFL$k)X2jA#lk6cXII zDtd&eWbz!c}Os(wMQfna!0$kdmH-AP-pxz)V^k=>?!1!Yo0< zn}<1IMv)(|zUk;ZLR}+H;ufuZ1~bO5Ezo+>6EvKX%V3&cw#I1)-y%@#&XOTA@{%+c z`ws_H))u@0du)z$T;g#}Se-h&7S40rU|@3ON<{(yGd74C-kj%ZtsbcB(Agw73rWjU z0FfP?jK`?wfe;9%z<&8};3!F&^TKF8Ad0eRg~Vpm%n${PU27`BCtQu zNVHZ@uN7ZV6JiTjq%DBYN}dax3~`Q2p=6!!^~bpW+7`-yQz1?3MaiQR1|c{J@G&tt zG2H7$U}@btO|q;-2*YU%lLhKe{2f+4@TS3ewuo|^>NGrIApjUtz#E;Qz!k4!a3m8L z@Jvi?)6dW>&ZU}`T8|lNs?ZIqVlE{rl}Q<+vQw0yVfL7aJf&5!bigf&tEXrs$dtl1 zf*%#}Y3xF8XeW-C72NZ^{m}Ld`84z_xHO!t$c2CpMoPDF_|Y|59xVx~jWE~(m>kg& zYBca~q9w9xHnRv{!pWM(6e5He(wc=KuktvVf=$HoUGc816>V2Fc%}=Wv=f9E!DD*^ zmNkMYBGa-}Uu_-YpVCAFk`F~o;t`2aHRiw?lN~okl}0-X?RR$Sq)0+wK14Cn30seu zH9WF7P14vWn(ilrjF9_rM;=-ur(q5otf};7%Y-NE03a$(&Kg(`Xb7T-JIqMOrciei z+2SZfy{Ty_6GWo9*={m7c0p9YQ)H>G=EmGp^+CXm5>jYE%HT8+oxJ1H+z2kE!51g$ zB5l+_rlr?k3_o1z+V0+AztgM1=DWxV-?;5$3{<(TaqQh?v4D!5Qo<~)m(`UrJp)+7 zU_>^iA-b>ddL5Aj(?WLDj%x(q6 z2nO9!Ua~f{KL-XgDi&b?M(E*$tuW+YWi(ssP09nC(%Q)f zHiR)=QA2UTk-bG6>(cSfYq1fGM))~Jd&j0os}}{jVCXhGp~=|KU?J=|kv)a(jnOEK zM~j(KTOEo~jD_t#wVXwsMhI3;3_wHWW+HDD*i5Vkq>Cc`F=CdTTU4URSQVtUlCz!_ zfP&-8S_* z9}aDK^9%r`(<(;_Ypol7$)rjn9XW0pZK)J20cSz(ld&Tw0c@)pEim)FS20M@j211t zfPsb)n!nVebwHy18<#~b(sE{5ZmgxQE2HV-h($*Zt9k?5`}{eknW$L=rbRH^1*@(j zb^6Hf?qq_KX;2{o7*h{@uN!4#I^m)1*n187 zC*b8$ZvqYK;F1kkvb@p6GHifWk&GAP1#6lGlf9oAQ0oXQIt_{@s@)phm(Jog(60q7 zzt%qR`Uf>{yM53d<@L-rsNU9`<_&-rl}_EWfwowRhimzxH>#pzcI` z0(^nq(ag*wBEB-R+@xj)k)JeBeCiU6TtXEYL}{7D0x}Q#htGOV!1`{hzq_;F-+j`1 z-rGHFde3|Nou>e0d%ORvfB1$-Xs3U;+dJU!fwuJVqP-6b_Uc)C-+S?D|Ha-xkEJc2 z7EbYG0pOp*pb?!q(8&y2g)X_k%B9IXjZi(O36FugunEzh;kcH+l)a5v209T=SF!6T zBhH>B!$_OS%+%$amAtX`L2KEVW!n3}hwlod_|mf|7(`P#Jny6A^+5fJbAp5WfS;!1 z>;xFW(zaYJ>Ld#YD7Re(adHeojix^BZaS`9?fJQp-s`L=pih4q4M?FQ;7-sV zq0cSUkU2&mWOO=Sy+4?HI^qMJGHS`D5e+OJ0b1H%7M!>~e0*Dl1eoA}Y#!p-x^?;t z8wwO#K1x6ZhJCttASazF4vjuHfE(S_DW9366xXsEPmPO)E@5+_dCY=;iDFqyi?7-q zgZi~+;tDF9_B3IFJxP+$c{H_sho>NvlleSAFCpp#3j}-|MAJpe(kPgY7qL-pNC;L$ zg5W6t60eO99yrW^aF7mBK`%Puqz~;(4@PGZ9g>bEd;@lXAVCE;NcX%0e)PTe5M=^l zL2+IjxorfswJBatP<3~=Yw@t~+T%8*g$^f4!d_7FbUKIal2Q^;f{MHU%|PZ({c zXw3W>H$3lm!p&IYW)zOWT;VrBGagmA&VzJDoJc9x8jEH-FVfVUmWk&WcrsY!Xsogm zwORHX4=zR7FcZ2&3>chhW&YfvMoVqfurLAlcDpE7tHR*udHcl+Xwv`t7A_%q3xK0u zO89~ux`)pQlyiNSgyD6!e4!~}6s|WxsnrSWniS0NTzNH`#*!aL;dGRFARu6~Gt(d7 zDP;(hS$q4gW{ec{Oo+6*RK!GFRjfYClJ>oNH;GquynwYwRp;L{JhIlwOwB;O07?KA zU&A5RfhD%Bvsv6L*(LDv3w;nuMm+-nd;(saW_Uowt;J8OxHz?Cx&bOfjg`$VQZwgD z7^|bzL1;o&=!8^3lHrRr0FE5j$b)MrE8LS$34TE^f$$=I9xs?v=dRj4W1Jj8I-KB% zH4}q5OniF@f8Kd-32uP1aLW3QnhTMPESt$CpQarU>eaD{67-l+9(_>PVg|#f1mwT@&D`h?mpZo#{X~L-`w~b|NmF~sUhP<-ZRW= zk5>2y(C6Uw7a$iw-MOp-4*`7?l)u{1QJ6hXMvG}!YkHr&vtYUiw>)&!dRM^HrJ)~^ ztEG$7)CuM}S_+T7vm_dM>yK8}zW;v3``+6Tqk)d(f(V795T9sO0jp=8isn`St5k_6F;dc}>{1kP>i=z#@fxkvSnl{*Du?hZ$Ed*w; z8Q38{1|z5k(xcu04Kq1a4npIwP1|P}h=!-}3wk<+;sAF!^Q)<{h-Rdcy58M~K-owp_4TG~b{~N15#~qF_<7c- zH;TQG-F_ZKnvM8OMgAC(N>i5JE$q81z@M(n4rcC_mK_kVle&@+mDk57sS0m$&=9*00} zoy-JSHXX#zo6qHRVCz{t0^dc((b`2;QFD4X6TlWY2?T}Af}e@a`xqvVBh>YiCO-g6 z&;1?Na?7jXmIPi{b64m0kq`j_>8B91Ss``@Vl-@CiMakr@dZ#;PTRsa7N=>MQddPherleZ&2n|{oi4N3(P zCxzz?@1Otl>S8$X6X4TzCDZCj(*y0|6#l=dSQT>K(@pO&$Q*PUP@-(Z!(Y5pW)TPn zI?Lb}=^1$6-g&G{lCC(?Ky|{-g|T42-_UCaQVm|Isl#0W>6@8v%oh*~__L4R8d50X z4f;Xn{0&HYd@@-G2+SwoH;Y+FPucFl^tyaYi*S_S7y`IRV{i8M^xY%x%DZCdn59)) zSP7!1NuwakL#g!#F_^qP-FydM2?*%1p%$09=>ZUZ#mbt8w5%G08Ah)W7gi9Eu)-ea zh~im;#VP3#H2^4BOab|*NXUdi(&h=;7XBp2td;apS2Pyp9B^JBF!K<@QV~60%uWqP zqr+rBoKI1Z$ZxQm&(V%}3U)_k{Z7gkJ$bFn2-K+TCTuHQ--f5wrDxX9unP~u)cp-C zxjpg~<5Z&YC0fkx<5D-H;twK&Z3uwh4NqUE!5miMc?g!ksPbuHv})n2a6{)JmW|KK z2jC&H?P>gO>}~wk&R$>`F1nEm?OH+Bn#(iu4&l~rN+zFqp7L7i$N1em%|cLCqs8n< z8-lLAub#K`a~oO!CcM7&8aFa8jiKQ~hKgqjIvdPX0^Biufv#` z>K>*T0a|*;Ji_+Y6Afu=K3#BUus}$%b$1Poqh$M1OzvY&>F_==iCl5K;Hv487I3vm zX92?ilcm5y1XHL;15NBU^iO;`DL7_*lsomKY(GSP5RU57ym8DHJ~Alm$(^jC!<)DW zcTXJT2Db0ne4huDO+f;{Af^X%zT^O}2#*z7Jes8WdS&X6(5iFHW>PpBC4>ob(0HDU zVGttpUef~>)SFV^m%=*X+H}48h;U?c{ra_g!3Y7=vAul-y+H%VdZMMjm@jjbkvq(` z4YA~bF=sP>g{8l!>qR=%4{o!9Wv=zvt7!pJ!35RvBFOgU+Prpi-2}G7gg+Z%2M(8^ zD{yZOfRPbj3JlYujXPp_o7F7uCSa9}`)mk#P%R@1TlE$48MV213oK(_J_dBE`UClD z<^@wsA;1Ky2_9X_p>}wYrvaGcGi937`k@>tN@tn zker{RP@FUvqD93Fh8RdYA?=0Atg!14xTQL34KKjf^De`jULn8p1j9uKDMmzMs`!j~ z67$fKZh>yg7YIiE(^XT{K|pf-h(eI(MYrfTN8)t7!3Vku3`-Om43@|!R)91rkFvW_ zpwUs|YNeA?)>H<2i;%oiiZ`z66y_@r^%C!M%mJr!3A^nCF+~Dr;dn9Sb5Y<*bp9!! z`#!&l!)4a1@D{dGaSR0)v)0z?FypR+5EjkJbfnce4JST6vJv049>|RKi?*-CRu1)N zJ@3OrB^hYy^OCtl_>l9K>;l0))42L7oZRQY9&9{-o$X=N7zNgSuP6>CEnSn&t6~tS zh=eLnLfJE+w&l)Ztge7wq@+1=XCvSjMdWX##CA=3>k9eV;6-;)<5XnCXvdb(0De-n1&LS(UzD z^)r)mRoC%iIwk4+JeX$`MXeb~CdX7!>eYxn)jUy`d{GaNxP2y@9J;8x{E#CwQc8BW z4!P=)4@(fm8Kq39Xlf*t;S>|`s0s)ASvYkN69Qv_&6gxF9D%}J1Y{UzA<;rJETe-J zTI6Jh;uLhNG{km=-KNc{IyZDrb8bAz`9>iEjaAh}k$>qnut3tLsU}5pCF8nL$*fp? z)jgc(9;CH8DS&l6!01Z~Bj%VE>N*^?K*3V0HNoVhnDWwx(=dn^ux!3XShjJgKNFF3 zlGzNlR%;qzx-thQad86A)ZzWGbh9ke;0RDs8Y{YqjE}g-vSY zyQprp+Ul(ulJ2m(D$qJJGbqZpEFmV7h~dw3_d==exsNZb1)NQhQZ?S z3RW+XQbQm#Nfl_PC)t+wb`@rswgQZ2ehl(C8wT@m_1%?sPN#oan5+GP?L2BnOHIs- z3BN$lwv(Z*pnU9ox>7WZbQKcv&B|H{D%uQ1eyF%XmGz9e6ZzC_#woP>$B#1<0Jy`R z;qj(Aq-b6b47K(9yE}Ug+x2D}^2qdMUV=yAv30ZaU?k{`qY!q)lGmg_S_uWGg_u8= zB^0(hl?*eKO+-r_>Kue;&Yju#wIrN?BEM9?!oNti)0{)PD58!BpyE-XBx9SZdRT8K znbG+wb887nt9gSU#+o{+`!+M?JmP>q9m58+gc1;~@+26^i9DO>9HtH$XOIF=!)Y`; zRWM+b7+LIcFr477mrXJWr*l-SfC0Q;kN}a{L|oPn?SFseHs^D@dqV5>&8fTK2$Ffm-6}-C6hlW*o z9$+ETjUO8zh0<`#?gRs03FTWf;=P9tE1!A_v0DnTLNj3y{P_O8AF3Z0y1Bpkz-ni| z@`}7?Vv}&`CXngpQ9Me{;R7(lebDGAtOC=XkuOL+3FZr=N-@@&Dw@{H62^!SfvAqF zp}=ZLy)d!?;B~6hMIu|lTMRUKdmfGQ$w3an6Ew?{Ne&<1Swi|6a`Q6~r+K}0VG}d= zN}XaaL7Ig-z21cLJ-{^bCG$ErzjXp}Mrql^oX! z#%-7j*f-_(9^DM(HSgVy@wE4!xZICc6jZkC1`@&-{XC6kxEY9y)_%+GtW_^}5$53b z(+jF*RI!-UqA%5v#4LCZEL4~8 z1S3gn1homhYaFOZ))wZLa~UKIH3O!= zZhg&S1O^%1=o8aff(to44=zDQa^x5nvDAQKufY&2RZXc#(i~**06kwlm8gqnn?|~d zRUjqwP_H=$T8~lHW;L2r@4C{#-6kDH(4?js@~&znGp;)bbsO&JJwg3hTf}Nd z2(eV+{#f~!$PCpcWs|j3a!8?#5J2Qmg1ur#v)r*@;k2f8-~KeonGt~(*?LNe7dmg6uSadx_} zb|B+FeYvJUS);0w+1mXF8ymM`=+E1KKkBrfJ*(jAR6|UO>3*EwuAip2vEFdQ7Qd-; zS3h~{jT-}N`|(*YjYb>-Kx}U5P^jUfW?vmd%ah=$35ny4B|}zzuUqe`w!V~Fz<7)G zX8G*a*S~b|heo~lVv}*_2n%ukS}tMZ?*k8%(bD%sgR1H~sfGIj1eM72L79VG1 z+DAZJDhq*{3jT(rfe&@d;n0_qW>Tf(e1uYZ*(gYkOEQCLIKjX5S@uH<-f8csOmb2d``U}=ji3m>Z6Azj~m zK8-&h5?_X5Zd$}K${H?TpcDCl&_`2_N!Lj8su{nH1fz{p2-acgar?CLdcy)YBlNK!+2q8wE7@_W5x|QzsNO9HA0Uv(Q46upl{7pk=mOn}bQc zoHl>DCSY#aBjQfoMDkkla5m4mL@e)4KGeoUDCTd+%9$jiQ>uP6#!dpSNOqhW<<+s^ zTQJqt9nVAY<%+wWX#IUMpwkOoGMf)F8osxka1JsS$O_OZ!xA1LuNj+0>a+jwWU*s#uhZ-fe(k?F>OAYUcVE4*cO}t8eHmqF!XtkDB+Mn*i*W^L zLX>1wC$fwj*m%fJu+Cq8Ii-C^>NZ=3pa)SezPBr-elK}FmoAZyulHk@H#P-BYcz#6 zXi5TG8l9lhAzo0*W0CYNP^Gq3$UmsGaf11MMmg!<>U^3OCU~`|yA@(aK`vG8g?ed! ztFr8wIxrN0rmQ4mGep!42YrL>ttuQ}QqW0CU7`>`$;+F5aGPI8b&ofQsi5}&S%4(8g$e@fMghTDYkb7a zJ`!C4P^Ui;f2YG1(VZAGmagQ46l;Mm8i_CFr}QDMi?K+ATWoJBioXE8q7`TnSM5-GxiilklS_W2_b4V|@e8HBttB`yP%7U z#2Nkpbv0dKZZJ)Tr>epb_hUP8lq3W=-@bcvohhMO`twCLQ4MIYdZXy2!y|cuTphrt z;R)8)NmZbi2|o}!!0p}leM=7OD1g)O5~u@KR>drUQlsMu5`)8r@k+c#0Zm10EIi6Z zK)AVV2Zu!I`WSDo;E|p*2-pSLuvhwsT%~f_@g51YGr)pyGECtH<0;_8KRGa?$jKI+ z?F;C{2<+Ga9O0ZwE=4MM6bIl#AL>iuimV%gq;3oKORr#9>`5rKjf^Tjo(4K3$U1!A zk`N)$HZv>caCMxu$d64CX5Xv44+>?ejgzF-#844bHRY-2=?nsBfB}eOK&jHz;1?ei z=^dCKu6d(I>?uypCBSTC&qcbtDux-E5fC3uc4Rc2QZkRdTAbLw)D&g2P+cDAa*Y~a z)R-}@t;5Smg<d-lJ>N{OqI*{aK<_C|)cR9SB1(BEIB=$xrAG zvFTe00RlAzK-h@_Hkk6Tz`cy#%*wLiUbOK7Z@_0`Q>~9stsW}XhK`dEeNZ}%jwqHI zaN$MVgm~uQIw93Qt%IhTCDXG|_&|Or7N7jw^zN@)oB$^o#fwmDEg+E45~11&9Q?yk zI4Z7urP886I|4D3$mIy~8AB`TbhCR7rp6cixZ?ZfF7HXSJ{g^P{v`&XHw>~%v z*`C8*2?9 zOsPfbZqcoUMZFTL>Jdd;VJS9U8%e2AsL09Dyh`;&G_Cr>EIZ2RwxJ|lZPcoI-?5_c zA6cCDWSR_uX|`4QlBZXY3gzioUXDHd3{b4Np|=q)={vp_5l!|GORZs$QPFdt06F%U zEb8BVipY{#2L)(#6*Qmds=De62BkNl!jjzQ9@5IM%8$y3qXCmY@&*-;Dy9goyRqLK##jN;p5ERoU_*de#!ACZmGtM!I!=!_$dH*{vX)J;=9SDN))@UDR`HTN;&8$ z<129_^ht`rGubtKDtbw&su5OM#lUjRc%eIJ$f(BkT?K{tESOeeT4*$rzCteWos zs%kH4G`oXkg@~x)xi|vUzUMbe-THW$4lx$kPb?O)P;hGtXw~92J-DDQe{mS(!wGS% zBrUxNKiOwBhSsi%a%Ks@iCKLL=K>W%IsCBva#bLWA*=G)oUmi)#y6QSrDGKwiM>8i zM*k8ROMA1uHQ4hknAfYPbL|n1+IoZc7K@hTH$P{5>x*ip5h!fclV6S0R!*1{z1bX^Q+bQ3e2k(J4ot+T z;dVg{Ntd9cld(`j!H6tZY+9yQV>iyZNkvs8Rq^L*MWnCwpK{8${_^FYZm9oyfBnIF zss7Xb%?DrWKmEtne^tfd+_E}_WUo@$njOX2s_WOdwPnVcQ;bDkGni$YwY? zLj9{)VnRJ^;lr9WFAJKtHDTa@h}v+9_gUg6DU|`AOHIzA}+ zj^ivyK9hgsJY1zStPz&NmxLr`Y>(xxb##~d6~>VF_PDpdzqjx0^bR{u`@2uPXM0Z$ z&`%ZmGUcn|cU2}6N1}#C{w^o>!Y}Hq<1CbXX_yJ)68*ibHetxt0?^VLr$Blms+ki~ zBv9&@J!S#uvvq>;LR~*A9qBtS(H8_fapoMP;*STpiZ$;79=Stbw{G}((m&WcAY04| zoPMqdi*!kqO@*4|F9&Kp3m7;vVutgz%xAzZ?-BqU=#>- zl+7{Z(w>AY7*&l#*yXz~_CBYOoHV^vZ?z%GC5{1$^(`3>S4aTV2OWSC(c*8KB*eUZ zfw9i&!UiDYmb#s7R8?2`@Xd?fK~pXnGvy`Fc|dnJ3HR~6E(fqu@C6Wr!;6Fiy>sIa z3cR=OTEDOeim%;N5|vv}DS#sHH@W2bjnU`Ff^VRV z{0cTNg`yvq!pohAZi1o^a8Z_==c^J>+}+QqB_EMhmBI=A*RN#l3}Xj z7W4`U#ov`*(b?Q^d#wTm)2~BvOv?~WBVOMpQCzS6hDZE&Jp32+Fbs9r@>YXYCvMeL zIl?~5g2>X+)W;>YbHy(BY9#(IxBnc)_sbcA*V})0Hy=JI+JATNu0Q;0|NY0>e`T)s zIrbas^dOo)?Ov&q7;@)>e3>TaO$h=;ZFmq~CZH?rKHdO~gAOQ>FQg=MsdLi!F>@O; z;y_6rEKcb72z1bMj*y`01C$C2GaiqlVMJGdCDR38Gscmt9^Dc?4NoFa04b)GXgB91;RByXz8vD#EtMn{XP4oSZnfZ)FLW~X@U)I!J_DqIP3(RPmx_kQi|0(Nj( zS&@~ARiGz0?)=6T^e6=`sU+9aG#6AClP zFY+1-brpusHM~?F3|}sy-q@h_P4#tCzJfjD17`9FjISIA7}G@^DoBuTy=R*Zi_uY8 zI^QX*MmD^-SkW%H)YnCj{vns_a)=+7k>Eya`V2u~$9CVy5 zhC^6mDmwAKPLWDdiaU)2-t3zCJ2w5-)ljbDtyY>=%L<@Zt&OrtEgOXj9es|9(P$)) znld~cZW>!cPtdQ>IOs~ey7`WEp6Z6IR?k-(WyL~0cMgqFr^awNJf7Tm^vH|v+^NX% z0oy@e?jSQ&Mi@=B>4_Z~+vB=^3tcHA^lBG1(t*7C-cj%Goo7^U3`0VDy}$Pl4ml1F zG0S^L6=&oHWKRs82WK9p=@myX*ADXys6on^8EQ{w`o1FCXk#j(oU72^TOwPb1d)B= zVB5mDYE+q@Djt>c8KE2<`a?X}A9i z7r{}nRd)K>^`VKY+JVdZ(zn0#5WtkdRQ`CJ z$J~w~Rh`89%%_(W#2d;D>s;W7%Yh^4wN4VpA+cZVo}$5Ol6d8N^*>PWs9{SBG90zY z$jIKw^QqKjrn!^ggMGe8#kql5+E@i`7F@jG8vRt?$D=#Jzo&S9L@(uSbGEgFkwqX3 zy}mA)DrJW$VlKW^xuh*-T~u;_ipa1;`ce@bPDvt5ceBc$+b!y<8e(Cx)`9cOMY!Ow zwyB~P$?!c3l@CaYTlcU(+-g&rsh9$d3 zQVR_8(F3l!Ar1o(e0)hd<@Kq2I$g;Iv;R`8xINM#%HpEp0?;kI4@<2GxScGLn0s*bxC==vspNb$bZ@75_z;J^#*H7Qu#kr zSg`JTWr(nqJ<5Qp^oc*ErEq7e%9~n@W~h?vrI$HWnANFzMfh{s^;3$N6`WI4Ix0R* zuUzV}?6@drIau@Ci{)|%?pvM83+_-86C|rjFYKti5MmrzH0ppYB-KI}S=rrEiLAo) zm~N(q_B+~3>Yih(F@JizY>VEU1)vHKUgY~ipiGC^BpN%4B@U>YmHHP*?v!S)U#VYz zL|)uT?j;HZ#^wI7OhqdxKL1y|ORoNBN|pU({-2GFjrCIe=iT+qul}F^;P}tVB6q+0 z4#I-ps2_8V0%n)Z2}ZkW9~YLTAV3htTw0cjZ(*J0NWHr5zCr>1d}{^WFoQXS>gu0N z3NMjxT9b?CsCrk9MW14+Xs?_LbpUT1V8*im>2Lb$reH}HhBL_&qq6sS6e*>oK#Q0r z>XJTzOe8R9ptFEr%X0B)Nc~XqutYiE7qy6^oYF2CZmv_6MfoD&BF##r)filFa(zD~ zK+d`TPpnQ%SkXO~@^uU>-@SKCbsSYTR+AM7aR`QV{vePuAOKmVRxYd=Uo?iqbYCCJ?=5g1{N}nvd$}sg@z(|q$y}5QYVa3oP{sMKd{_KR;Hho-AY9g%rh(Ub!L@q zaPQd0gXXN1q-Yfvghy{@@1)G8%#Y5LznKB#qwF={sJ?o%+K}JacGtfa?E=*uQzw7( zF>96x@}K{d2G^SgG{p*{cJz#@yC_%0tjDt)Sjnl8I94FF+BZ%NhZ04Pms}{Oa{py> z@J$ku8)vJ$Zof;hwF6bd-t|LpF;6Pztb%ZWg0O;HG~zs=a>geKV1%JCIh#RfaIS1~3}voFFC)n|p!; z;|1l1*pA>@?ir)<8-brey zBrg=U$vZ?Y%kxllOSO|?%Yh@m)t95u?HCgSkerq_z@CubsLIw&nl)FW$Tywp0kXdg zD|oDhnkCNWTzr=Av>RXoErz`C3J|shNBmP$Uqxw^nI&9A?CX*nC`O*v?%k4x7055u z6L?0l;jufi%4zsbUt=ouOjU7ERZ1tZuX$$~e8}MgDaPp1Z1`54Moq*l?WTB;dX3hu zwpDY|e~33cHf!^C;~mhc{ne*7^|jyX^|$}ndiQ-}>$lOJwW{kkGyspK-=Fzk>~qV) zbg`-oqtgPy&!%`g#zupt%0)@BxHzDfQ{Fh(a!oP-%84zM=8fFp8~kJ<29N7p+=?qJ z9XDuzJ-!|yrb-$>AE^ofb08DHoRo&SyeFFT~3+Y;LZEWcaBZ5-^78J4| z9cAQ~SHG-n-2dU>kFEE?S-`czT9f3wl_xE}F*XldK@0j`OoOxq1EhT8T?-9Gc*12F zbi7M@e|O94M%dAe0&taI`&i(&y#o8;Ne>|Y8Qq^?3*q07j=l3BqmV7WWC)|IND0@o zW-Z-v$Iqu;9g(2#VmPKVtDo#5!h-1fsy|MW)uy+$-QHho&|uo~vQUkysv?1o3}eib746?x)e9FL^bR+w4v4dmJA*ZKtzHa%Qr-sS8(5x0`&r+vzeC3+qs3SEq?Vkun#(=* z-U3Z6#w|c)2LPR`LS+d+c+v&ff8m zLordWZ@iFT&~mx_F&?(8xTU$5=}bjGPE!?YM7k|fgPj_S$|g3FIad#`eTgOTO+R`C z_(lk(&QiSe44vH-=^u!dLisKWg6y+EunT+9a3Ia?ilj6axdsIqbdl1J&J=KbyeY$i zUMh`0KM04qs>w10o~u_&U{hAPFJ$u!V@kr&Eho4Hgc96JwYWyf{XE56oqX_lSy{X0 z-}xSkszH~6SirD;<7Q-Q?#>ng`Le4Gm*cV7ro2m0g}GK|R#oOJ72;b?wvr+=yti4( zSpsTa7c{*3U;#F7Oc9}#H)Z2f|5Uvh?2{5L<1{M3cs2hE zfJmWZtbw&0jOWQ&xP4j2%#9geeDk{pn?YCg;!Q5-o{!?K>M8EgL;uBIfA_GrkJ5(W zXcQm?DjEHX*GPcUg4ap>ZV*cyx#QUH4+rJVA>F9EROPFaMK{pnmWWnU1{Z^@7v|_> zk8QcGt;)nR+54(e;FkEyiZunBD_2}c#S)Jy7_B596?^(!0Frtq;lL7f#k8_72255Qm(?P`^%GuKO$n8RD#^!-uOi$)lccEYuU z$bE@jztdvR7E*5uHGCM9{zy;G1uPn^S`Q9+kR@$tWN5AcT|lD0M|fAR1Tf-?!qEtC zX!{l;J0iTHc6GJnf5OfvmP$_uU-9u3{fqJBdE~Y8R~v=StTMg~`_*@!2nhIBhPZnB z-6zK6)w|=06~NP;Wpw1864os(15iUhEz`!A>EcqLK`EaOC;daJIXR}wy7!mb81ox; z1LJZMWIM@lk=3iU?z6CJ-Wg1MI5|wnQ`8dg2<75FMT7uU3dZS<(wv{S)jr8 z#+=5C@A+774zMDI7ASPnQHo`Ds8b7YX2Vq*jr71UyU`rG?Npk0Vf1v#ga~FeBDE{Q zSn@1iDTB2l`9e#!1PG}HR|9PKj@n@k zUlw7xHG^Q3S2)N?q~BSjQ~BjiMZuku6uO@VgKVupX#R-}(`k5lo}?oSESDlZnU_7~ z2urESy31V{8unn3Pm&bjdV&CW&j13Z8H~J-Gnzzuj#tCAHvM&e1PHWfN#^xAbCOa* zW?GYE1{8J@er`wKVm=D&PuX^u;RRbI3N7%UeT3cq_TH=6rOb}=kfnh z9Nn5T9ZlKR!^&B$7aJziB$YrWo{4|I)X2fWL%=|>frAJOLGlFy?W8v{~ zg!mf|^g2}mdRJ3-)-r>v`#%~Gn2FJY`_P>MoyI11D5L#guxOsO_z0FPlB+lD|H0xA*uHHNgju-cVog4BcK+fVpY2C!$_ zdeEG~=8>trg1z0mq-o;2J#K%p4Fd_3L;Q<+1e_f3Co>)a8nip_3EUk-)l>6?ANSk6 zr`F2~dxPc=@coAle*V!$3C+PE^>w@bhC6ym3s=B7&5Hga?3)MX6M?G`alg}y0D;jC zetEycMu4gSgug3%>ontCzdo3}w^U+sA-wW^eW%^%Frq_q#}YJIhHA{(GiA z{kYw2o^;zkY_-1r8$@BTq8 zpdk9Y?e+|%eJAcV?`&IofYWRfnr-&*%iUfx>57KXnRlBRe97ob-X+~Z_qKp15q$x+ zb_bq(pf72+c@Mf?$F6%D+ZNL|9Nh3{;ZePh+oXm(vDBA)*h721-TYw(r=?hQ8=H@u z)*o<^)J@!JZbIwL9h%Bc^Aa^5e9}JaH19mYept6rJ#_%W2hb?O$+tfO?9?b|w*%D# z*z)O9{BZ_v&a5{(gwRXs{$jg%LT?iDR$$Vs5Yk@>(pUIYX7U74P|$>WC_6~h^a=L{ zVd^nUSX2lOm&y76sZ_Go;qUd1t7JXwVnt!zjT{FY`6OaOIInl z&mCw$7`GEq20*?h)a_ZX3Bt7G$?^Uk8ennQViq;BHHyP9=!fzo*zi z=NgI>Iji8Cm)srKyi{;46sW;`Qj?hWmQTLG$zGB`UpnP7--|mI@g%BVF zw&L9#x5FQ$L)2}5AU^iv4r!1lPe|i>;(n2>+o!EdC?pMaDGEPyNV{-}vRCBOq=p;h z8Z6iwaG56v;lJA}YH*h5BK)8)Z@X%v;S<1|VZ3_7;uBCvYzApmG49WPMuM}3;4e1iT-D1({Yzk&G_NAyJVt)^hpEx0eIgJv?YGLW>27ezBJ_X zu~TGX1^K-Eb!+XcO;FIwOuw!r0eYWeUx^@3fO0(GC;nE9r^;Xp}NWpco+QFxPeJd&6EbSsVZb zzXAZHxAiWzD?OYpxcJv|n&AnN40L<~RB}R8GTC7S0G#NS6o z{`j{p65T7A@B^641EnxiSBAwsQ6BwN_OQ{u9JPDCT~zK&o4%gsbK6jJM5QZt@s$IM zR;e!<`Fd~mQYY~({}RQJmZ)l?ZDKJ>f!C@L8WKH=R9KZ0L#xW(E|bW|?Hion3cPr` zQj5M0(RmfU7K|73$!zT^HbRV-X6k4V_e(03W1+s%yLS)&GrI_5ON55 z+Nq>`(=o4rCbfq)ZpCPF%`WyhRUkqHZJPw`Iy_mYCmTI=wALn_HbWbdp5#3_W~7~8 zz@&pb=N-`v+N2w>69&}{vcR`dOX}D&qxS$FduT|ltZ9z<vRbNEvtVZSiMyB|3ks*BuJrWr z`=clAgC(B6zSaPK)w<}AR0r09MbK$1A<_JD8^NGlf1oi}HFR;04L4l1yU^6pwDZo5 zhmtSIkEaOrj&jp?);g|lXnos7pE@uXP@do!hU+@bZMt_@dnhvW4z#~RJZ-I4DJ2Wq zs39XG@v5FW6m-#5=P2yU7xBXcQt6(e;}o}(wXS9C&F}zuTd&?O9XjKB?<(aRtQkXa zRU5}_7l&ZLGIB(vYxW>HMae|Vj;&bKSx+5l!}<%MbjEs;JC*3z?BR)&yR|-6 zH$Cl;bJabv=vFqJL9eqyukUv(Uuwl^i-kIaQ+NHv=TkMJ*<2Nhgf&vt0|{BE=A$62 zES;i=5@>!}nCGM#dmmusKkO8A(1yn8ojv?25CVwWx(44;Ve&RzA>v!3SD!kQeAk`!S5qyVLvu z9{r%yFY{KFuyYTQ+{X4eg?37P=~Qs*NzXEo?!ct(kj}Mcb6CeCXAt+sY_D$7=eKMl z5PKHpxOek$1S?@x){3*rrSPQkisqf-&aNJ>r;KCcd}A}e0_BCx7n_sY9i?NwBptIX zfJ&rMrO_<&i(Bh!8W)-rsIls4#W_wvIe&uo+5t{tzc_R1(D>!heY4H#jUlH~bV!iW zGku~I(Kacf&Y>QWr;X%5`7t)SmBXsJ4U1Znbrfbe6k$=0e2fiB2EB56tqC5?{;Y5W zU~fUC?~0j#^L?k#A=wwUH$q&$ZF2n<{5bIH8&X|Lr-l`TON?W?_(Yw3kjqxM-k#Po zU+S6QC&E~-c#f-H*()+n)#PO*_TSJklzZfjVR-H80ScH5q>E{Zf4UojBIMHTq93$s z6Ga5D|z~@qBuKCR6+rL<}WH_}wSzIF9twoTN zw-L|yUKtyG+wvV0tRClV@*%rJD%GR{ld0^xs$tb9dlC*my4$tPoaZbg@01pTV#ExlcqNLO7YtEKk@MMjl360j>(6H!R5r z*(x{UQYQA2LR5*{RfU}u>}}JbVfS83gJd~L_oIq)4ivhD9(JOFqt;@|O<7v$WpDvA(PlMK%zl`&LhK3Cb$1*df> zObwl2PN3Fxqg*dq3wCY+UPZ!Gfx4F} zLbCD&^cMcAiW8geT-Tq%!`U@~1r^q#gh+grHCfo21p+uQ%Y3^IhxUJZT=H++K-YP73Yw$)y>j>6N7`dMmaolN8g1>zY_|s#=^Ln{c;4)7+U#Z%o^{Jw zpPU$+ZfmnDv?zUPh>t|(VN6P|Xj1`pURV(X1t(acH)G5>M5cn3s{(hc`ZCc&Zj4@O zqniw<(~g>U@pW>jmH;Ryy1ivbP=&Jz=a9%IS~dLw$a$}z_EV^v>%sUNdGuc`SCt+8 zFJ8krny>VN+-{jW#|w^9V%mp)4)?140raJ4pt zt3^Qa5y`RlPu$#~s)%eSIfu_F_evU{5 zE*;#8``fR4W(|mH$3V|^4D{l15Q@#*btpa_P?)W5h4tTBOZ~XBTuU|a;{{iM8=-Dj zO!&7^Y|F6Uq}YDEMzJkqfK+*3SQZolp@Ab#w~Ky&q}zV|)tUS6!2iQE3Z~J=u!ZGE zznBcTf&V|aTgv~xcW?7+{{O#_|Ci|Cb~2#w+O=|krGQb_Q7-gVV4;fD+9d7tjgEL( zaAev}MV6*g;Xk+`p_ppFB;VzU<4~2niA@|;<*xFnzV>VxM*dndGpnLHmWD@E1w~vN z=856q)1Hbt;KUXVA|vlwDeniG4+^fIqCeCrbaa=^8>%p~V;yo<$(e#TqTtgG$p3`m z_JDfZS7FTfj`QrT@Eso&bv#b6}>*ob=xJ?1BYPt;`18 zE6nJ*L`T}YA*W+=n}ms*4CRD|@IJlYEpF|Kv^KqKpHdpb6Dvwyl~7T@nlybnJK3ww z(Yh6|#?_^O{n1v?wP-SlW!sg96XvU3L!cb@vet2BW$ApXpX(Uu3{MJg$HB_)v(Wpw6Z*y0kL3 ztFq1Q=LMVD0K4=6)d_~2KB)}FG*n$E#ZwiLOx|-lTvJG{O(drkC=Kr`jjy3yvZtcz z5w6Gco1>l|7BaV-@+VH(QUc8qYBt|#o&Xpp#NQ^RB+rWUvs+}S6+t!0{MW64s?KBZ zT@?_%G+UyA!-*nTKxu#G>uCr`yX4x^N1k-PUF*g~og!W{QcOcia8Xwiz7#|4+JW<@)-M z>znt={-3*eCh%4N{}<{1B|5m32~c?JdMkhqfH%AC4wWErETsM4BmgmA5EvC!WI;YR1yc)lLOC9CkT>$drP2+ulyw1|1Fo5?E{s*E%~(}P%w5x7mD7;}$L-(>?4|Rz@s*vg!pcjRGM$}`E2B1WPhFLRed#G=K|6h3p(*M*YTe3sS3|U=DAt>84XH|4Ra)$MMb=AIVq?WF zSZZ9@F@MYId|DcMA$N9ZQgT&EkG`&Dx_s~UmQBL^X58roBd1qNKDyicOva?*P<1R< zUKO`p;7nzbJKc6^?tY2pmaUGI=vi86tlauXJCm%iyUGPRrk&*r;HI{3{{fcCRWysK zk-B3Cm6u@1QNB+ZhIdI?+*Pl_Ho^H!Za{0xABsGE0i|vZ|?uuGm;=(Y8E~U8r z-rqIT?o4PMGde=cOY!K1U=O$c;H`k+!ls4AFQigbl@_?RB=J&iL87^9&0T?{kgQ8S z&Wy-n)UWlHD=`)YnOYjRL4i|XvRAG}fTb-AuxhPcU|HvQNv?haA#V7nRD#oH8s((= z<@$$Rz{9{JZj9c*A(sOYhUjHih(uqn!enok~Pfl_efR@WN6?UXF3 zT(z)f?CTb3-YuTL@*){diRTv9NrR{sOSiHj{gYDBma0V7C05Fr@qik=<0h!?{z0e; z`92i{WJ6^U^Z{M~V2XzddyJH7yb~Gg@d3f zqo{A>e~|_BRFUV8*OW^s9OjwA&y~ebUSjNTAz`{)3jFT21(1pFJME}!w7I=;&@ULG zad&syO+b9=R=cc{j&};~KqVcmLUl7sI;LNxLOh~V=9!t<1(SAMO~pvOjX6LR1_VQ%Mc1WV3oVY zbXZk!rVz+_ZJ|SQM)Znl`X&~jkh)(;0qdLd*~028J7nK_*_hM?g{rE~0@vIzJ4H=& zRx~lzy2S!&O9et%tKa)f(?cB>RofdJzxr0T3B4gFh}2SiW9X=g zHz>Aqv0d~N0!tWJ>6cDy-!(N!L>F56+%C{fx1;uo1rI2U{7pp}k^?M5qKp0(5u!N! z;SIWzavmRWdAdFppnGHD#;PihTz}7OP*Iz8usVM|L^zO-RC`jHu@9BxHkUh-p1W~rTG8# z`}e-a|NJF?zV&9wa1yk1@XpH0+i%`(FQVzlJII54k-e)=@_e3ct*r&~$j{T@EXrEL z$WPLfwUac;@@X*0)(XA&+1bg@gEWYTlgG0l%fqx``nhEv4TL0~&pe4xG93(p(Mjl! z7wM%RC2Q|1M{nG|d1GbeC+~F{<)QZ+pLkh*ISsu$%<{}zWKn$LW#Kf8qs7d;)b!4y zeB#Z5_|h9D@fkc0W6XY7Svj19-f>}!V^4OPmqoMrG#W=?<_*&@$g%rDnw)20DnmxG z_sfBoq~77>JUket(L84`R?1+&aNmCG^<$vo=@dFk;+2)-bT zTchx-wBXR3I(d}=cq=Q22!ttcpxUBta{wqKfL7Mlym68o!XrP=R$xv^ntPvu3|`2a z9(R4^jnic2trkXHeWcod?*$nk2JpxY@gqE48PO<%u)Zo|tTw&zA|B%W>J9JHisuc& zagv7hAiIo*#b=(EPom7vqgj|N^7^z+ei~-U z^en6&9gU(CgV!2YYXZXyK#xDkXVYWq>k9scf1XdK0(`l>&{URE0j;9+=?*Bec5)#~}1RSg0DM+>;Wh+|x~d=gp< zMsz^vrytj>C0qH{J50P$I9T9XkArARufx;o7rfR0s3=Za;YF15nDzdcsmY5nZ<=7% z=cS^!aMbkDMeH5>YjH9Pk7mheF%7dde-OpI0gsWykH4!UnZl0^`LzKg{U%w!&bp*+ zH_T~HnivxgId<+HAM~E}cKffMA8qgNy*}veKORnih{Au4qZDZ4;@Au0vnWmCSs3Tu zS&&A-0Csgf3q$X%+DI#-WN2|X_4DL|e*(LEF+hf)eq6)0$OPBk2WJ6qgEgMkT6tsg zz1Tv_s80n|60;KCDFsoF6xYZg(8BU;e zGG7240bM;F1nF_3y8qYx-Gl!B^h%Hu&ou*{1Co<-V5uL&rh*~!j$ik?hfgn__WDnr z9v&+Qeq3L_c(A^{Y{cj7zaMql&z|A5rqL{7s^g+YUNVNMrbyLOEebqJa^~p*`E$#r z$AjHJ_KApxK@6-rul}* zgN=;_EaHkL;}&2k9tG1RuI}vY%#g9w7TC%#U;$U_Byk)PoAQ7MhI!2k(=ijj z+1`_Ge;;rKv;^Ysy|6f5ptoU+OWj4@(h27IA_cI%aURk&t^usqVdbrSl zn_1AxLR?(fNU-qmDl9ew@fJq+NaX!F974*co&f$epFoi>OagGgCjSITzVa1qD^nG$bl8) z-VSq9lx2vSUlwubZLV+p=r7qv2Z!y>uZR2X4k5S~Pe2C@JxUMta>@^78WGW$VtjbB zngOj416s0*{U^J7`@N&i)BU~Yy(9SLpue{ZBX*h1cq|M=;Q&=@5+VSTAP0%9SSRx? zEwGfLiSuMM_}*@k&WOz1mUi!69X3FoCiGyyEmcpjJB}}dH1>D2!XafDxLrI=f>E|6FSS@i!Y2?QuP49&S%*X^f#Mh78Aao9n4%B? z?Jt}rb9j>ohc=2OWMCZ#LCCa_FNE}JGz0s9wjseFg}0~pJnrK7y(WJgjp1mF`(B(h$B^6qB1m;SZj(R zcOHSUfQ*&)BMgd!LO{@$TdoF1DN5EEXp9gz0R04E2}dn>Wu9aiQwOMXrxB%q zSRF#|X~-hTOpiE3gu7=HokgPs%?XA?Vu7dgGyyh}AxUlnm%22Nn z=GZcY{W1m(6Es(a3pH_IN}#4Fgd8IRn$CipC-G`d)3XK8N)&^_Ms-g{23zoXF@IEq z4RQK5O@OUVlH}A9D+I&)jQ04qqY%shfUFg?ux$(5VonVRiiW6H%o;P%c>uM?U@DOD z`V>1x-Y+&?I9^P>S(s0f5$OCCW@(xLilM6vmNF%+lUO!soubR><|v}WbPQa43%mbT z)@v{AP3Z-;UzjB&XjdOhfXz;b*(4r51Ppm0HzpzufR&=J0Z7<>0y7$BnWuVEYL!2n zg2vfGyNoAT4MBT4t(#ZhV&YMlzN-cYR!2q!T^RYYB1J~64TbNuQSS!P9!*Kc!2Sxn z*Wo~oO=Ojm^-n_{qei?SOh&R+O%y*7@<3%3deC$lF?}F3`2Ls_Ldjc|kwb8f^ zr?0_EwU8>d_49*ph!}?b1)Q#gVlr(}KQU`tg=Ez&z5?3|c{>hUh3*vx-OGRlWj2S; z7Q93LWj{RWUCaT@oybD)O$$$KAQrsy0!1lmil7UfPm&BZ0}vl*s&iLiwqkk$@d%p+ zR-`=~hI1Hg01^~BJ6TMF)C0v2MHv!;G{kK&p9T?%a_G>!em(Kgf)~9smRmvLqy|f# zCvmOmtua7r%7uX1AZq})WI(@TRDMu>OT!>b;*5wli9ybNScEBhuxv{&!Iq?}he3)s z5Z~D^S{DXZsaoH>cm;xU7VwYIA9fTFe`SFQ3QlqPTuS&t>$h?v^FV|kl#GQb&{dY( z%#>&r;TrNY57#EceWP~2njU-YX@Xn zYPVVpz(lSCP@M_PlqN(jikNv3H5)ozXR2fTAs-68BH>kdz@m7*$o<)6i$1J23Mk-$^I5&#a??h7Q>5RHitDimfimCAdhjD zBtPF~pxU+;i)i$&24j-~9HAdJ%~9D8QW#;uibKTgZol{9S<_RXfnE(}#JLSMn(#E| zXcpnF5XAwcSO~r0elp(QjFgpqdgGW4O(oG_nSqZs1K5zDkTtzY$UmM(qkM98Omb5gwDbUq5`ucHxB%~t1UdsEp03E? zqY8T>M(-ZJx~p(m6P=6wn>CuF(qtoWChfjmTD=!7c~-SfPF1B-f+C zKJ3y_4ZT9PXA^|ipW&eP0r&w^O>I;P3O_8xqh&+@`5#r z%&Y0wYA7sg(zHe-q@0Kb1>8dujXn6+f7aVMB)Ha{ zeTVC+i6zO%BkvBBS#t6e{zc{oKY93B+fC%2F1#0<;hCN|GwU$uiy)r>pra^7Bpn8) z=;XH?p3KJZy$tm)^yEE%eRR;-@AY;Mp6(qUb^H5P{pHrD-79|{pBy7$ps84Hz2s;l zLLC9|iS7ykjCU$4O0Z)cXHu3cF9Z4l&?sv9{B6-)iJzwibfK=ora)9 z4MQe|+6L&Wwapr-4wfysV)Q8--}maTC+L@`90I1d7$|ph6lQGQTjQ=^W72OGSBjLn z&+{W0iJniG1ax#ec!yN~8viFNp~DaeSG0$FaSJ zoZ0UX)-+NB?FcoaZW$P?|NX0{s@_YtS{GvM&F;X-i9zaq?{D4fDdw^VY^Zu3_i2S- zUMLyd8#r(N39PrVcVwyPl+E)F%p5J^U`YduDF#X`>7cjB!LW9PXQtgN8W+@>DW7io z<6xDyYA!{man6RS1GXU;76wAk`>TAy8o1={9lSmewmTwaeoXp8J~=u{FWA*D9GPUn zGssJjz1YJ6qkhS$nn%Ho@52};Wr54IQ1#74L{`+{xA&J<;w{(@|Dt{akv@W_6H)_C z(|@5eQYoH^+#=xxhzNjZ5gHSlz)IFAvCPs{$R~XmJH16yuL63?sqEEFD0n5jzZ9lo4ehcMO87Mjf=}*2w9Q_Jaf0 zGW%uLAoP1ZfW|anf#mhig_onx$?=jV~}m60;^@sB#!WKFDJP5V*T8n$guJzHOH2)cyzV~8rNQ@U>)qo6BC=#u z=Az5ouulZFA1s-Xlw{c$u{py^D%P=34Q?;Obd3$8sQ`xk~Yp7 zh)|PgwOB1`X@`4X8m4uXm!6B(PA}!nm14DsnAomDX^AOJopi$?RW}yebw>w|zkbeg zQXXwE*P09B3IY=0nP|~MZQsZbR@|(SzvM63MZ*Tp3)(~ZbHz=V6D#L`E2mPvrWO!! z*yYc#PeO$P)(nGRF8?9lOXmS%64e&&4~m!kj0O^uT=`xWvxke%`*b!T#ka4Xd_LY` zzqsfHrCFM7qi^i4ZOE?Cr?gH&72!#Pcq$|VBA7fI$;)iT6A~3{n~NUSN9=X%;~nFgUU_r6 zq8B?x3Y*f1{8qR82eEs2fP2zT2LsriL!F!YC+OH~dl6BPBI{?vDF-;3Pfut#)7~9v z@j%8qbq9pIvnw=8&a0;-H2fXx;hB|onFEL%276(n!5(K&LkPR@-Qp=WdyD#D1iM2B zSYx))4JKl2ApQLJBsp{LS#{P%2udDv3+3aPa-+d z9_TR;%rt6XzzpO-A~nM!lD`uY`oK^`e^AdE@fd{0=oyV6sXhQDZI=pNg z=pr1n>+}LyB{w|cz-ax~f=;t_K-6) zq-QLmwwjS|klcXf1@^nrr+4*J_yViFH1kn>#^1M>^kSZKPB^uZDEl!%KIJeli8#de zI<_Dye;!NN3*As+4B6zENacwA;Jj#siI}JR(bzQsn&MkP$XVaG7a~cB6Cwqs3Xr;&sqBZES3^KYE2-6)Pa`qUOx!^-~D7Uy2 zbjz#8QtX-tz2IDi#*b(30gbjnDx?Nk>z=pW& z;9gr)(;|4ouH}ebcCV7-xPSRB$Gc+GoL+6wEb!X03?x-{1dpl1#X~QSbX7dTyx@=!G+Ct>|yZ z*~R6}Ps1hf(Fh*=@SwNxQ1nVjN4=mmd!1UH22{M$tVoy;@HM0-Tco>H!ne}G#W&C$ z^cff%`;=r4p*>_i0U-VK_!vdJS^nD~zy*e;I<8zv)6dN%Gxccb-=wgtEIVS-2} z6I?HGSH?DA2~orm`t$^C3(-_)GqBna9UHZZ2Bg6N3Kk16($9KF6o)(|0Y~_2zdsqX zZp3;cC@@&dlR^o;Byq6xOT!+6ECeCq*+dtKIgZN;e2@p)G!JoQ5FusVLnaf!t6MD0 za@gLe=auTV^=Yt}0Ebz|nlLD6GVmosZ))?-eyX^1%K=xzOlYBga2~(AuwTX@n63D&)T=&HiB=1CmI)K!@|P0 zjSKSwXFa3U;uLMR$%rWi?P~-SX%q-K9Vh(i;MxIXN|7{d>|2C@&5Hm-k3W%O@VXp7 zhS;%dy*V30Mz5m<_EaeH2jZV3Bri70qnVMQp7a^#{P9PeQp)-auWzarBfP{D1*L=L zf-Xo+7_i;SSqzDyWBQzsjJS5Ot~)53h~8T>uDn6gA7Zhs&9}~W*yE_Dty?_&`Q{j&SD&fZz9afJcpQ`G3gbEd11XTY}WRA{S|9!hz(z^V91^r}Y%r8kz_dkZ|6Q#{wxaL^eNXyXJshIEu##zaXZUhUYI8kQi|@rR96U z0SLTl>_{^Wa%i{j??RNM52qt*sb-)k8GVfEPoP^-oP|&v^+UPKI1IBFJZ!snDzSVH z@kU$F#SA!HIj}*?@VwhO&N&LSG{~?C;5hcLd96#*4?g1$H9Six2||s&*>Wcgkw?T$ z=ooyny$za|=gFWI{PnNFH~igMGQu9ZdD3727+^Ge&Oq?p@^VkgL@5uN-gU;ixZ~Z| z;suv>-H7oWMvd+nu;VdP<;WyFg!Y?`e34uf<7pL$`)o}a3UKrT79juEtyuDnJZN#Y!5!Cysy zJC85jzy}!*kLAN4sK;gPc(@bu08g0Anc*s*#QqS}hH(&=^Tg3+eQy@SQ(D$lvunci&HFTzNM`hO@>2j zXsomhmA2-k?I5JB%6leT!cNIV9Yp$$$XMPo_RJsd376ejA_guksjcyGRpWr>Y`Odx z>jEpK$yk3Mi_QM}S-`Z}yqdt|%!o^~nm5x6-U<`>5#xTerEg?s*LqDx|;Iv^jPyKDpS;o*by0`5_A&@<>oX(O&NOF#0KjG}K6rR<1bVYpBXKXx-4Czt1Xs-2o{W!a^Y>ab=y8`Q#HiRNc9Zwxv!t~@4bBDiJSoho z;kkgHV_0ChrVE!t3=T@JBCF@~zqgYEnFmO@}^-AT7S2`7w-IlW*WCJFnu3 zaGsnrIbFhc%lR|rLTDZh6U>ee3udp(691m>{}J{7hL!)N^bFmFrDFr{IbS`lytBZfz~4g+(68~UXKzr}&sv?hp)9Sh(_a59wuoBK zmHsxPmU`Lsf*%Z;>-o3r=Upx};J;xMWmyr`mFKC-3+yBfY+ytrDJ*Yq+qu>LY&Mi~ z?|M-Gmzz+47x2yu*3o=njBwR3RCcXrll_;zhkzKo=f@yD+$`Lzd1kS7X1Q@@nQdmq zG&9$Cduy609r8IQ8BNFMaN+Q3$}&9oK7>R7UcB!x&ZY16{N}wnRp+`mTdsK|M&zvO zh(*LAo3qy2vOY`?Y#`M3bu8^Y3}9a|1?Yt#&HVk$L_T>k>Q^^2{Sot$8?XQ_@&07P zf!!CKBPMQEgg5J%{a6>wz63S;)=+h0hN>GdQ1RAgHI^v%_Lc{fvD9!i-)7ZWXs`0E zRYQl-_RFF)D+Y+$k+*S6o%K86M~OeZII46D{Iv1k#j?VHE;O%M7C_kgY(BkhiHo-Y5T-{_sdlu;_c{*!}-WN>0b z57(m|eEKx!saE%S%R9RN*NnC0!&+;q?RkBBMq0pBUDexZed0Uu4~0NeS=oy80|q`+ zDxp?@$d?BMrt;eHK&EBfq*t(FnwTGJYl!&c=;iAdZycJJLXcUOt^+Ic_0Zg@T_Nv2 znxflymaI`Xi$kw88fY1LJCyEg1nAEE^Cw#xdheceyVH zKbNQiW60T=pl|~xhYc?=q-Bw7Gxf&WGakq&xnK&gL)#=c>7rV9OUVDLl>5ixBuS>D@pbWCKbkN0Z6 z_rUCy^{xdw{V+=}wpf9)I5PM&@XK>5mYEjkjLgeU#dk%Ha1NnT)3){@aWD~#*@(}G zom>VKXY7GA*74p2Adogapp!Vt`9c_m=b&c77y-L+&NT5C+BTFrY!l-d!+#(R(2rb< z9`|(b;lr74Y#x2j490sz>4AK8|K9hrUsYbefA@htV;=ogq)dgpk4JQoh#?EyJpGcJ z@)|@4M=0t=*GRzi6a=4TAXypOfD6DO(1o+1$vTP>gLg*eS-QUIzWT@3GqjM<~jPFBW0*!kkQLksCw{$i#m^G@}SjAEoD{yYho}2DnJhGqDn%<(8Z>V9TmMJeI2Bb*OzO%J>Xmj70u0SV% z_1!KZU~9C;%xKjSo7ucdItFz)X{y-E?Yft7{cay;o0T7j)k03V3g>-PrbtC9P!U9gB z|L??$2Z~2OQ}q+oM>2unN2UVZXjg)fX@ibH`!=k6cnWA0#V`yd`=IUDJJsscoUsnp zZEJ%@fyiSpGfYMvk5f6l$dsl3o}N`px0>RcQtbp~B$I+|fGd@RjViL6s=rH4Ty0aq zV?F|&*r$!D?o6k%%4v;O&dAYSo&0AVavFj^eYIl zBDJzm8ye}>ef`uNPZkW_VXZ!4>;k1_au2<*C!5>x4!Sm+Pj6XxluR*s7gp?LgrLK2@yYofy1<$(^XfHjI0EnQg|pySoUXE3?$MBW zM7ff;(?JymmR4O42S+$3(()4>7K5hU=i3hPe3V2+ z8&c$h>lXrFf#%xM=4Ha$&n6?wC|{0>)!OI;8wPNj%@(0F^C(z{hBcc&^>Xwv9;O3{ zQ($^Dw`qvP5QT~Hs|7==w<#2kZ&AldFc3Kg|2U~a=4=OL*J@aOq9co7xtH4LJ-fZw zIChMkpcdqC6pOvwv$1lPA3en!??&O4;f84w*AWF{36&$%ZeWTfFN zgq({dW?GIxDz*QeCU;5R**5ad#QWO{9tRu5Y1X&Y(x(gHzx)V;lZE=viBiqV>E==e zS^q+>kj!mmuF+j(dHT7h$7`Y!u17aZFMrW!!addq{=1qXT8ve~-z zT-kgm5d=7na=*ADs$n5gmq!NXpAI&`BHvH!jQFjFroMUicSsn|c(<%yu}qtVo`^6& zckf5BtUWT6Zlz;V$w~Cj23Aq9gh*iVa{XvcHIdS(@F^!%rz16AV4knKUb+F83sJyXENES&sJAZ%q_WjdW&!4>h^=;da zy$$D4t+wwl`&&|In!79!tqxWKZ~=MEnsg91o16nOv$z!0DwZ}2gLBWVM8WF>1Lg|! z3wI{M>n}%TI@QsoSu-)jW^4lWsfc|{4NOok2`s$^8>DK>)7yw#SDij@Ftq?MKHa6< z99oOnZ&=BhIUvMkjDFxm=9HTOspGJkk(oBf=Zv{Y5M;1vnS;8SK%EBZ$8>;7K9H?R zVU(62wE>IZWKwVeEIKvxPB9q~kr`eZ^yAi8!i|lnl)x^}aP-uO5#>zPO)jA}2ADtJ zW}3_;HH~qda-ruSWP>Jc%hQ)_jwwScFjC`oFFJ7B8%#@}0psRtTEB&cMl)s*rhouD zFImU8l?NS892b&+on8eUS(#|Ye_4q+=VPzJ!c{ebeD3|~h!Pk@;i~tG!$3rSyDG6oK_XN!SD2bMiu&$Qeup6uzMEGNaE%|C}gZEmQWx zVMYS4m}aycXK^r`sTVLa`f#8JFq2^SfKx#+Nb<4#ht+v|^>DXjlh6bgr{1~wr6?mbLCXKdn%S< zi{2c5h)g}3Z9R7y*`WcjwjhuBfaceef1*RwQ-YPZBh0wnF*=Pc%u=eVBK1u;2u}+i zwxXJ%&MhN!2)GtVk5&m3oyon?3;1+!acP?igx#u#U@_04N=s7*OJAG=@x=0W@1S>N zG8}Be(F-ZN194F#a?8>S0U*kSTUWQv)VwMer}E2mK=M;3ak*4gKhNJAWb;+}v4b`VzM2bIz z13gFKovW1foOP0uS}hWgQUuhzOSssUk^Jvmp~>liRa+~wnXPGsJ#P0j>OuuW1DXrN z=S5-JQM-15^4T-<7}1yT@Gm*LrK79Ib`aI~qDRlf=4_jyvn})m>|ZIiawOQl9O}cD zSNF(1-U(XjNSfIiQ}9{Qv03z~(&l-4bVn*o_vn{;Mq~HHQW~Wx%J8nkz1%AtWx z4w6R!@$mF`MD+MqBOB9M98Z#|mds?6D&H$@&r;c+RYmd`m!9-F!i(0OqqlVhPyyYwzE9zB0RV5)I!e;pu6&C?kEbyb)EItlYv1gQd+e@xQR_w!LHkR-m`# zitnW?*Q+9__bKYf{gY&miGedw$|7kfEPfBK4ry%urt>2()UhBZb~<;gGScJUipuo{ z0gdML^yA6#N%5RxJ7_+yxaI>1*;YTxM%;QazO2OTXk}cG@u!+iKuewu((Kd%)zv&8 zfZLI0Sn~u1QF%fqAB;K6i+57yht&>ABH@qdUm|<*jC=@^C3QaA#*jz5&t7I3y_*&- zLTOQa3(X6!d`U-YFtP@RFj3GhI0|h;VQW%d##YrEv@ic zGofH;PKM|5SbB&`3v5EjVVIGEvEEjM$;a0vjUoB?WPI$|sjb{E4~m_-ZsC2yzn6hj z8cNhx?Gk^YFK*K0NpaV5di;!>@?n{3HlD0AHn&Bh^2c~syUcnjO}(x}9i56M%2Q5{ zh}(PVg8o9+5OlMede_xw3Vv2AH32DRnU&P2YpN>%@KpqiOAh45bnYtVeDcUbpC z<6N{mG-BU(uM%~pYpD%59njlR-P19fG)x!x+mwFXvY2?rFko)De6L?dsFuNmgRYKH z{yfo@^x3X?V*Y#OK~x{_qlPF`plm$zIDKRy>&@|*wL8rjSLU|V5JURwk@alR_tvgQ zjumS@d$^7riH77IwOMGpbU*zM}+UWDJzVSCzMOn+O!$V9ITIt zzSmTu+SKd;F73!ti@fnM%{exS4IUojud4&=RH& z7{>d?;Xjwx|Jazp|6okeTl|l&hW}BA@9ALK>k!)bjl*^Bfm zYVV=Q5wSS_TdaP~t$HXzgBD=P8Qdf$Q~E@5=KVxf6cwKw4%0qr`&m_&guWTtwxm3U zJpaNzE)gjn@Cau9*bd9%=teb>uZ{n7lpBB~>xkT1QqaR963xOi z&9Ckuv6`>hjFzxf%RM{NPrJ}G6&Z(!A5&f%q9h?t4u+|O$WX(WJ{h+3$uOl)C6@GQ zh9S*mL~z>Mb~~2ebu7EFvT&OkT^L!SdH zZ4%m0hKOYI!U5^4)@a^kl`}jQTi=L!*v(!MAEHlG;bd(*2ov8goJ1pQANqCl`zSjf zY3{kyXe`xLFiBThSlAXN#_-r2eV(*9vS5&M8C{9BQ|l(I!{Cryh}im*c?Nq2&)>a! z^DcPteD~?kFJJ#Hc=hIQJ8%Oekxp)Uu(*{#?TU6hjGbrS0#ocLH^C7meDd&_-D6`Xe2e6XTeLCrdy{NIgc$_?HB>S zS2DmaYR2y^S8W1Jb1z21RmB zbox7eeHQWy^c&Z>@f&NGl8BK-7jwF?pIzchEajK0y#eJQ;m5S4j$?fvvUC(Se?uVD zcLDzG1XqX^>jka2H7)Z?eftYq+)DPJlJIqNhM>jr|N6rRGx)D0{@>!ie$D!S7Q2Q? zP22}n&~WHN4|zv@kNCKG^?KT*FMm%Ah8(=&$vEwkpmlVVUPL8?8uZXSNruCWV?m0G zqA3)}zT8QBl$i;Tk< zm5>5in^8kMeLI{SbHoHG3+EE&$A~VBU_gQZ5t2T%YkFWf!HG8s8$kj)^)NY3NnGbt4#`F$ zweA!_2$NCz&xt1Gb|f>2ak*@gglUk4-$Rm^FN4$Had)~HS=$8mA~X5*``tHxfBu?8 z0Zgj~?dz6e{%I*@ErQuK>7}PMnS;Q4Y4gcU6HaO1=h_|=(n|^bw9Csw?dW(o(8pm<*@qOGC<&SuO-_FZ!Z+`q|JT!3jLe7>iRaJ%>*da_1fFB{! zX4ycoj&TfB9w3q2wM}Cjqy`li*dk*|K{VGnx3!A-iUH%Thzm)7Sz$5Fvo@-+2d=C!FHs*c4{WKDDRWBWDEQGQDI6H1q46#lM(su8v9COSIcIxG{`X+S zZ_*9C#Q(dwKI8x0+`NBV|NGD5|8>}`#vILTPQq{8p%F4BnGBM7GN(NCY-~6#j^a|* zzf%jBr#aJx<#dhq&nX4WWR5ONe1E{`;bL%ip=`corM~xQwt1!YK4b3)&V*PgnF2L8 zz=rP%^ToGdxs2p*E&LdQHV@m$DkG=oINd-JSk#fwf`tij=9B>T3?83#xE|y zRLxJ+BTDd@E@Z=jZrpKv%d~EpRz1_I^_f>#mO=~FaV@BTv!|i?#ho9VUiU06;F3GI@UfK=!{1BEAXo(?ZLH4fdvCMn37Qf~-$+~(74G)kCqqj^r(XeyRL6oj7v zrP=oR4V$Jc)5+N`Qxrq3lfiRm)=5-%GFI~`@Q;9ydm3N7l|o?*JBh4Zw2RbOEH5J> z367B_c%;NmgO?V|UQ0u8O3UcdAh&dd=rM*DV<8GpD@A21S22Z%6x*2dj{pxri|*$j zEr>ZT;b#8G?a@XhFc^D%JPKtby+CTjRVMD$%8}wprZC*}R&V<=>VFmTe^WZ(V*0Wc8{*NEfP)qv4MScDgts9IrL5JWBTftY85xllQ;L`nh()tL9@PPu40|GD> zG*b0dshWgUW&|Y#FY@spEC$*b^|1yvGhAJyQo^a5j@*9LtoJ~GjnziV3Dwoz^OZpH zm2EEoSKtNUH4&&c^RWl)N*efi!l%vT&@#;0>1i@Z*`MAKw0+(;T2WTawGL%sR%Yx# z@?=nW%Jgu^Q2*-M>zcK6)#9XZgX==arg|N}B^lhJtB0k`a^K}x$!*q^W*7jhs9j9! z&8q@O=z!mhwDzd9VB&LiA)t`!iWzuYae`my@f+APse{t!hb}y=_S5o=bv%AvdBZ;< zr7dt_s;22j+tu4Qi;-Z;3tSZM^xVk7$WPKEYbrpa_7QGFd-#ss#P+LDbM~iR$aM7> z!vtdrW!_3x|J(F`SH<}&`hV};osIvx`{368|25@5a4^BYx3EcU6^4j#m@uxb2koDu zd>awarEvbn&<)T#MH}S!hLM=6wy6*-8*3z1TQ-+SWV`v1Jo;+B1d0_rVLAi`|!{qUS&ES`mmjaVL29C_EbVJo##u8PmIV&1cqcE{jW} z)@tMig-e7#t-TzY(#h@4ifdozcc@u@uEZ?37mOP0376Ki9T8J2GJ`WQf46eO9`iZ7 zB(-5x#Hwr*?+BW&Y}6m$BUg$3$K6Nadq!H>rLEZATK;aOsD!EJ`){rPd*uJC`F}Uo zH#hFi_c>IbBW4KvPn^9d-cEkqAbV;);xD5cWEPs};ef??+oOI$Eapp09HV4fC}SW4g- zqk&z)^-h_Qo(p#U$V5F_qRJ4+GS~xNf&;GTV;Evb2&hs|Ed;FfnQe_7Ng?gqO5?1J zIZlfG;qcgz<)5w?wi}|rE1jzrD_e6=;)G%QfW5WSjz0oJ<%LlSUomcG&SgzUM;UXK zojGOOJf5|^A?=+Tj_IP(prt!(EW?IOL^#?v`e_birx>Rp)q*7gN|ke+5-#SAR82ct z?u^TK$YUrj9ib!_8pW=!=@)?hZb;JKrZhw=CjaRDQ?Pw{o=^6GZwtaeE%z_IFn$h&mxPm0rFDd^(L^G>_f@qbqv!E8`P z+xGLDq@kDb6RY60foRoP_hbL&9=@A zuJDT;Ggju%SH3+E+}gx66b1#-Kj@Hfov5v42ZkMJfZ)URaM@SXNTo zPMSDM#~!$)9Ip@_f%sBG5~Y29;r)BtyeZezj6USe;A2j|6!Z&A0r2LuBU>-X9$R5N z!z}wUDP8QS=ZOD-A^gscp89exp%Z~GT9?+K>X+xX#bZ{uNG zdk12Tlxhtu0JoWfO_vi!e~wz9&9KS4*z7eud=$Rt+ipYlHumX=`hQ0JOt|)281DUd zZ~xnN@3+BsYp!Ook9RJ3Jlg7G`4=try!G8GodQ`zZvas~MA6}mc2M(!c}qDg)S9Gq z7N8$VcU)6Mg)#yNBb0(Be1qRyPToN%wGsrj|DfGA1WU^Dju^q2&dAv0a5^6_lTQzm z#CE|wSZJC5{w@EOHh!%WwC?=X6GK`Cq=bPV>`7-zoVbf%S+-p!%c9+N{*DMVH4uE~ z7PC^imJ`Q>8W=El1?G<@MMgW6_SyHvAi9P@}5Q(8aXPg5e0d^bDmYQ zc&&#GezE_~t+(k0{67^MbW<*%#r~g%ckj;Re{4Q{c$@$KReo&#-;=&3)-E(7*yKPP zFl5h+m#1Oj<($<4s6(v^imMmYFNl7JTD;Vcxd#vP$~%@|^gZ2<3kV&7H@|#AkH55k zs^)-x@$+r4b3)Iba7|iGZAjFnL?h_Ke5ip+>ddD;@DG>!F<*J<;xkLMwXnl;TP|;8 z`;{W9XNY9NqN{0i$yiY0Yi2whQOP1_o!bCgZo8OS4%2hG4+am$NW8$x7%QqU9* zCq)vrPDo@h?7cE&*b`=VM+VZP7JDV2e=j_1_mQ_ayLD^w!aK9M6!`QfFIPt7A$*&T zMkt(lQMlD|HluNJoLtQA8Q1z5)t#@teDm%(YEd0Ozc>p%-RNCVmCID zbLTVX&di_FXWgf%4b4`|aC4SuHfQP6bCn!D+qYmH+NHycz9kXN*uYEEb%fBpZ!DU% zq!B--*(6V%W#^-i4t9}^9(!?or69Ad@+-fdUGs%svX9A6mmy+EPxHq;ZwUCgu+40h zKEJH_d^*1;Is=2hqncL~aaAv`K;qnYu*Av&!~P-N(73O~8TC`a6{MHuw_!I?HgcCs zo-fHY{Kxy9r|+IWf4%ebo89+I(hObGGp{YlG_-H}joe7)VRazU{2p#N`Oxp?%O)Y( zp4QwED<=ysPG?`1!anExFo-W)oC#OEbJ&m}2?#Jk#9X|LRBxzsZE>zzx@bf&DM#%v z`m?d$hXE69GZh3XEkiaHQccC+l2+hoWfFP)%FGlJSpt{uLLleRKr4(crh;;}`X|IZ z_>>H?)kvgqC@!Uu%trtllNZ;J1G#Ew_H>w{M%t36c09TzZY7UyEq-%yc#87SONYVr zl@~t6#h1c5+&J5gEkCs2Arh3{p?I73Oqtf7rvu=I){*;@Bt1SU>c6{~!y#%Igg2UT zWhhS>wHpJhV^BB6o))a~Nu0mP`jgxr)M1vvzUqxA&EJYdv*a;&bp1zUF#gnHCMApH z@N%=$%0+n^pT&piFfCBZ?8@KepMMDg#u8K=i7aQc89=v8>=*qdE%GkR*^ z+7`s4)Y_4(A*oW$pkqXd8M{*Xg))?bd)PxVX;rH+d^KZ~iaFOcM6v904I|Xto<7F{ zWe0Kd)~CfQv$E;Qj_`VBr_b+wxy|W@El&PSZ_?W2FU6NJHQAA0!_4&Q#?JbUS(vKR zSk=1p=|*fzD;t+kK_VX#N$L&K9I8>zlBX_I>C)=`G2;`j#I+4iC|CfIn-r6C3yLdC zeyB`{Z-#KB=+*NVyNzoatIGXM&aT_bD)uec2NFuTBf1Li_{8+ts3=)YIG}MdX7j{Z zmZuUYWjx-Aua`znD-jLtQ(8KnqB5O74``tQ%w{HX=bZK~JC{DL zV_Gu}{%lLaCKpM60(f5q852GO`-VNU2ER!k!K8<#^Utx-RV@r(#5niI40Co&U(z7= z6^wCT#}KDBoX<1Bee%t3Gyat?YInO4o11ZMT-(+*olEU+%*-~+3|2C+am{rHHQpCX zTY&N95U)%Wm=#%(>7aHEd1J;4d3}prV>NT#A2ZdhV5VDaqO%klo70~Zid5iCX3D7YT5l9edinGfZKJ;iV;uSI`_}Fw1zee4>&OWv_ zzLyT_%!eh5VW(mx>^RF{$5{iXwX=2BKQj?KBAsO`cUd*e71Dp%$j=3q#JUaAVt`CF zC8Wx5@Dn30D4#t|2ZLcUv)~|*7Z}AF-GWQg1=f-Y4wKDG&7L~S5twg7BHe8IP;18( zIbkI!VZk{xD{8R#OZPL?Td86W=Kj%?n3r)Zwt=qNiAv-q72?^OUyPb%B`j2cYph^T zt)oNhT>uXb#Kt;9gh;ky(oK{nJ!H_5#MuKDT4q<8o=@I{yI2BetrnbPb)1m?f`SSs zIA*5plgqP=UgeNKtoBplT&T?`i5$iz+>FM_pxH+BxclfR%c8@0+>>oO!=T3#tXU|qr5tL_`8S{_bOZkgb!!J#Fw_IBhF{0D6`khF zm6J&G2z^BSh{WpS4e4R=EAotcr^wD0zi{cEJG@I(5M zKj}^*SoU)*gVyZY`bB5J3oNRxH|&>3hL;UW!|iz1IoqihaZb&dxN=v;k`4XQYZ6fV zCprc#Z23B?SU!V0SEhq0%SLyuY&X+`b~PNG-d(c()rs8D7A)F@RrWy6H?5SMZ&Eb} zYD<*V)#K#iEFkGICap^zF@SS)#ECP1-Bs=dG zSy%XXk#yrOwLBTd<1RIiWOiDtF624-Mh0sj$DX`<-3y+jXy=r*YLoYRpp*0ylQgXD zF>)e<9{+#qAUKb6#?)i=lVR{UEkGwMSp#0O?%6O1F@Mu8Q7R<7Ke837J&SG&5=5&L zto`)l-CCQw((D^4t=tCO9TKo|97}GS^QIw6!5V1$P+3kVz--sn3^o%*hI_2Tp7UZV zbXQ)vD71Iv0!oG*(Wu{(gr7Twjf2x8e8_QBo#OG^Bxwfx>-Up0SjH#mkVR0*OeFgB zjEge;`tB72keM8!vLUt$WGyc2+&hgg_?Irx$73Y7YAGe;9@6K(_w4B!pdK+Y7o*ec zU+HidN7?vzEg5xx-B}xC{d|p%@Y;XS3ESZlw)QSz^GiQjd&B9D**ITwC*v>f*Y|Wp z-=9u~MM|@NuM72_%^2^G#>hl{pN-#(F)(ji`eZLZN=8XWq1hKsO_fvI3Lf*71+kGW z3H2$LK(p8VZSA+;{`=0i-#w1P_NTqy_OGV@oE}&;N6JF^VQ6ttTRN5vDa~yE9tc7y>5oVJ^Nqq2h;g%SS&QxVZ)tZCC}cYIsT71 zN2G?|E;%T|BNm+&|FHP`YQ2X3BOCjr{nFFYuUN3=ZOUiycxz^x&+O;(c3NSzBzmqN zxH$~{3|_i4$l)Y+>R!~)ymun&>G7y8d91?|;Uha!k6{&~p00y0e4{aaDE#R%>gP_Q zHAfz_MbE19uJQ#z^7`4>$*W8H zvFR)VNG3PQiH-6#$gK3^R>FGxm+ru4I5lfF3bPD3>Lk*0`3hFKWH39?QpdK#c6km) zI$2>F*Kt6XM_!-rEouI$_N`B?rm5pJ$Gd_=;)Ho-?`XimW^4 zo?o-xr>P%CtP-e8+8zz(tN!`}8q*TTbiC__q|WG>VTs*&zS)@ud^Nq%ah}55eU)(_ zTTcVpqPK5ezTSQQjwN&%($t%Qb#>1Sf2r^LvxZuAvHK*zZ)Ij!*K>)N?yGUgZ_8k< z^Ib)jL(^>e_SjP?E{@O}XxTm6t1YpFMYbMH^N5S}Yd~bI$QI9CyjoefFtliybTN}| zUMF5Gk}|)Zd|^iM?m{J(p#VrEq!rY0Bo7$oy4WFV{ zeEdmYLQ3@dTWaCS8(vV!?CPx)X7U-s%Pa9LO9m=&EMIuZa*dW*I24JO`Qn?$K{;~= z(lF6BHRGs+$JB@mwIMuJF~LUMtlWhVqCF6pmxE4_4gkq^EcNZ#j*d?EEwA@k_MWXp zFT;B|uuD-MY&vLpU+hZrbDrfs>2Yp*zg#|Yuv5SkmJUdEX#EBFM)YehXtheVP&B|8 zVs`j=Ji_Dl6K75i*mNAV+FnDt><4$QbSb8HuDEmhSDT;i-MNxAo9-V}cY&jS7VLl* z4YcUEacGk#V%cb?8vUt;7_6#3EoMtu2s%fQs(CsiyUZ^33Mw;!Ms_CNn0RN^TR H0LB6U!co@V literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 3a6c451dd56..921c02a602c 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/diff-match-patch": "1.0.32", "@types/dompurify": "2.4.0", "@types/double-ended-queue": "2.1.0", - "@types/express": "4.16.0", + "@types/express": "4.17.17", "@types/form-data": "2.2.1", "@types/fs-extra": "5.0.4", "@types/http-proxy": "1.17.9", @@ -64,16 +64,17 @@ "@types/marked": "4.0.8", "@types/mime-types": "2.1.0", "@types/minio": "7.0.15", - "@types/mocha": "5.2.5", + "@types/mocha": "10.0.1", "@types/moment-timezone": "0.5.9", - "@types/node": "^14", + "@types/node": "18.11.9", "@types/node-fetch": "2.6.2", "@types/pidusage": "2.0.1", "@types/plotly.js": "2.12.1", + "@types/proper-lockfile": "4.1.2", "@types/qrcode": "1.4.2", "@types/redlock": "3.0.2", "@types/saml2-js": "2.0.1", - "@types/selenium-webdriver": "4.0.0", + "@types/selenium-webdriver": "4.1.16", "@types/sinon": "5.0.5", "@types/sqlite3": "3.1.6", "@types/tmp": "0.0.33", @@ -93,10 +94,10 @@ "i18next-scanner": "4.1.0", "jsdom": "16.5.0", "mocha": "10.2.0", - "mocha-webdriver": "0.2.13", "moment-locales-webpack-plugin": "^1.2.0", "nodemon": "^2.0.4", "otplib": "12.0.1", + "proper-lockfile": "4.1.2", "sinon": "7.1.1", "source-map-loader": "^0.2.4", "tmp-promise": "1.0.5", @@ -136,7 +137,7 @@ "dompurify": "3.0.0", "double-ended-queue": "2.1.0-0", "exceljs": "4.2.1", - "express": "4.16.4", + "express": "4.18.2", "file-type": "16.5.4", "fs-extra": "7.0.0", "grain-rpc": "0.1.7", @@ -147,7 +148,7 @@ "https-proxy-agent": "5.0.1", "i18n-iso-countries": "6.1.0", "i18next": "21.9.1", - "i18next-http-middleware": "3.2.1", + "i18next-http-middleware": "3.3.2", "image-size": "0.6.3", "jquery": "3.5.0", "js-yaml": "3.14.1", @@ -158,6 +159,7 @@ "lodash": "4.17.21", "marked": "4.2.12", "minio": "7.0.32", + "mocha-webdriver": "./mocha-webdriver-0.3.2.tgz", "moment": "2.29.4", "moment-timezone": "0.5.35", "morgan": "1.9.1", diff --git a/static/test.html b/static/test.html index c2bf553b81f..06aaf3f5139 100644 --- a/static/test.html +++ b/static/test.html @@ -24,8 +24,8 @@ } mocha.checkLeaks(); - // fxdriver_id is set by selenium, execWebdriverJQuery by webdriverjq.js. - mocha.globals(['cmd', 'fxdriver_id', 'execWebdriverJQuery']); + // fxdriver_id and ret_nodes are set by selenium, execWebdriverJQuery by webdriverjq.js. + mocha.globals(['cmd', 'fxdriver_id', 'execWebdriverJQuery', 'ret_nodes']); var runner = mocha.run(); mocha.failedTests = []; runner.on('fail', function(test, err) { diff --git a/test/declarations.d.ts b/test/declarations.d.ts index 63c06435d8f..46b736b9418 100644 --- a/test/declarations.d.ts +++ b/test/declarations.d.ts @@ -15,31 +15,3 @@ declare namespace Chai { notIncludeMembers(superset: T[], subset: T[], message?: string): void; } } - -declare module "selenium-webdriver" { - interface WebDriver { - withActions(cb: (actions: WebActions) => void): Promise; - } - - // This is not a complete definition of available methods, but only those that we use for now. - // TODO: find documentation for this interface or update selenium-webdriver. - interface WebActions { - contextClick(el?: WebElement): WebActions; - click(el?: WebElement): WebActions; - press(): WebActions; - move(params: {origin?: WebElement|string, x?: number, y?: number}): WebActions; - keyDown(key: string): WebActions; - keyUp(key: string): WebActions; - dragAndDrop(element: WebElement, target: WebElement): WebActions; - release(): WebActions; - doubleClick(element: WebElement): WebActions; - pause(ms: number): WebActions; - } -} - -import "mocha-webdriver"; -declare module "mocha-webdriver" { - // It looks like this hack makes tsc see our definition as primary, adding - // the typed version override (of the withActions method) as the default one. - export declare let driver: import("selenium-webdriver").WebDriver; -} diff --git a/test/gen-server/seed.ts b/test/gen-server/seed.ts index 5ac9dc02f9f..7ef2d06bd42 100644 --- a/test/gen-server/seed.ts +++ b/test/gen-server/seed.ts @@ -23,7 +23,7 @@ */ import {addPath} from 'app-module-path'; -import {IHookCallbackContext} from 'mocha'; +import {Context} from 'mocha'; import * as path from 'path'; import {Connection, getConnectionManager, Repository} from 'typeorm'; @@ -643,7 +643,7 @@ function _generateData(numOrgs: number, numWorkspaces: number, numDocs: number) * To set up TYPEORM_* environment variables for testing, call this in a before() call of a test * suite, using setUpDB(this); */ -export function setUpDB(context?: IHookCallbackContext) { +export function setUpDB(context?: Context) { if (!process.env.TYPEORM_DATABASE) { process.env.TYPEORM_DATABASE = ":memory:"; } else { diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index cef2aeb32d2..00000000000 --- a/test/mocha.opts +++ /dev/null @@ -1,5 +0,0 @@ ---require source-map-support/register -test/report-why-tests-hang -test/init-mocha-webdriver -test/split-tests -test/chai-as-promised diff --git a/test/nbrowser/ChartView1.ts b/test/nbrowser/ChartView1.ts new file mode 100644 index 00000000000..337431e11a0 --- /dev/null +++ b/test/nbrowser/ChartView1.ts @@ -0,0 +1,804 @@ +import {UserAPI} from 'app/common/UserAPI'; +import {assert, driver, Key} from 'mocha-webdriver'; +import {addYAxis, checkAxisConfig, checkAxisRange, findYAxis, getAxisTitle, getChartData, + removeYAxis, selectChartType, selectXAxis, + setSplitSeries} from 'test/nbrowser/chartViewTestUtils'; +import * as gu from 'test/nbrowser/gristUtils'; +import {setupTestSuite} from 'test/nbrowser/testUtils'; + +describe('ChartView1', function() { + this.timeout(20000); + const cleanup = setupTestSuite(); + let api: UserAPI; + let doc: any; + + before(async function() { + const session = await gu.session().teamSite.login(); + doc = await session.tempDoc(cleanup, 'ChartData.grist'); + api = session.createHomeApi(); + }); + + gu.bigScreen(); + afterEach(() => gu.checkForErrors()); + + it('should allow adding and removing chart viewsections', async function() { + // Starting out with one section + assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 1); + + // Add a new chart section + await gu.addNewSection(/Chart/, /ChartData/); + + // Check that there are now two sections + assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 2); + + // Delete the newly added one + await gu.openSectionMenu('viewLayout', 'CHARTDATA Chart'); + await driver.find('.test-section-delete').click(); + await gu.waitForServer(); + + // Check that there is now only one section + assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 1); + }); + + it('should display a bar chart by default', async function() { + // Add a new chart section, and make sure it has focus + await gu.addNewSection(/Chart/, /ChartData/); + const section = await gu.getSection('CHARTDATA Chart'); + assert.equal(await section.matches('.active_section'), true); + + const chartDom = await section.find('.test-chart-container'); + assert.equal(await chartDom.isDisplayed(), true); + + const data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 6, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 1, 2, 3, 4, 5, 6 ]); + }); + + it('should allow viewing raw data underlying chart', async function() { + // No raw data overlay at first + assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent()); + + // Show raw data overlay + await gu.openSectionMenu('viewLayout'); + await driver.find('.test-show-raw-data').click(); + + // Test that overlay is showed. + assert.isTrue(await driver.findWait('.test-raw-data-overlay', 100).isDisplayed()); + + // Test that the widget menu doesn't have the raw data option any more + await gu.openSectionMenu('viewLayout'); + assert.isTrue(await driver.findContentWait('.grist-floating-menu li', 'Print widget', 100).isDisplayed()); + assert.isFalse(await driver.findContent('.grist-floating-menu li', 'Show raw data').isPresent()); + + // Go back and confirm that the overlay is gone again + await driver.find('.test-raw-data-close-button').click(); + assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent()); + + // Open once again and close by escaping. + await gu.openSectionMenu('viewLayout'); + await driver.find('.test-show-raw-data').click(); + assert.isTrue(await driver.findWait('.test-raw-data-overlay', 100).isDisplayed()); + await gu.sendKeys(Key.ESCAPE); + assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent()); + }); + + it('should update as the underlying data changes', async function() { + await gu.getCell({section: 'ChartData', col: 0, rowNum: 1}).click(); + await driver.sendKeys(Key.ENTER, '1', Key.ENTER); // Change from 6 to 61 + await gu.waitForServer(); + + const chartDom = await driver.find('.test-chart-container'); + let data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 1, 2, 3, 4, 5, 6 ]); + + await gu.getCell({section: 'ChartData', col: 1, rowNum: 1}).click(); + await driver.sendKeys(Key.ENTER, '6', Key.ENTER); // Change from 1 to 16 + await gu.waitForServer(); + + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]); + }); + + it('should skip empty points', async function() { + const chartDom = await driver.find('.test-chart-container'); + let data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]); + + // Enter some blank values and a zero. The zero should be included in the plot, but blanks + // should not. + await gu.getCell({col: 1, rowNum: 1}).click(); + await driver.sendKeys(Key.DELETE); + await gu.getCell({col: 1, rowNum: 4}).click(); + await driver.sendKeys(Key.DELETE); + await gu.getCell({col: 1, rowNum: 6}).click(); + await driver.sendKeys('0', Key.ENTER); + await gu.waitForServer(); + + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].x, [ 5, 4, 2, 1 ]); + assert.deepEqual(data[0].y, [ 2, 3, 5, 0 ]); + + // Undo and verify that the range is restored. + await gu.undo(3); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]); + }); + + it('should update chart when new columns are included', async function() { + const chartDom = await driver.find('.test-chart-container'); + // Check to make sure intial values are correct. + let data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]); + + // Check that the intial scales are correct for the dataset. + checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 16.5); + + // Open the view config pane for the Chart section. + await gu.getSection('ChartData chart').find('.viewsection_title').click(); + await gu.toggleSidePanel('right', 'open'); + await driver.find('.test-right-tab-pagewidget').click(); + await driver.find('.test-config-widget').click(); + + // Check intial visible fields. + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['value'] + }); + + // Adds 'largeValue' + await driver.find('.test-chart-add-y-axis').click(); + await driver.findContent('.grist-floating-menu li', 'largeValue').click(); + await gu.waitForServer(); + + // Check axis are correct + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['value', 'largeValue'] + }); + + // Move 'largeValue' above 'value'. Scroll it into view first, since dragging is a bit messed + // up when it causes the pane to scroll. + await gu.scrollIntoView(findYAxis('largeValue')); + await driver.withActions((actions) => actions.dragAndDrop(findYAxis('largeValue'), findYAxis('value'))); + await gu.waitForServer(); + + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['largeValue', 'value'] + }); + + // Make sure only y axis updates to the new column of data + await driver.sleep(50); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[0].y, [ 22, 33, 11, 44, 22, 55 ]); + assert.deepEqual(data[1].type, 'bar'); + assert.deepEqual(data[1].x, [ 61, 5, 4, 3, 2, 1 ]); + assert.deepEqual(data[1].y, [ 16, 2, 3, 4, 5, 6 ]); + + // Check that the scales are correct for the new y values. + checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 57); + + // select 'largeValue' as x axis + await selectXAxis('largeValue'); + + // check x-axis is correct + await checkAxisConfig({ + xaxis: 'largeValue', + yaxis: ['value'] // note: 'largeValue' was correctly removed from y-axis + }); + + // adds 'label' as y axis + await addYAxis('label'); + + // check axis are correct + await checkAxisConfig({ + xaxis: 'largeValue', + yaxis: ['value', 'label'] + }); + + // Reverse the order of the columns and make sure the data updates to reflect that. + await driver.sleep(50); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].x, [ 22, 33, 11, 44, 55 ]); + assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 6 ]); + assert.deepEqual(data[1].type, 'bar'); + assert.deepEqual(data[1].x, [ 22, 33, 11, 44, 55 ]); + assert.deepEqual(data[1].y, [ 61, 5, 4, 3, 1 ]); + + // Check that the scales are correct for the new values. + checkAxisRange(await getChartData(chartDom), 5.5, 60.5, 0, 61); + + // select 'label' as x axis + await selectXAxis('label'); + + // adds 'largeValue' as y axis + await addYAxis('largeValue'); + + // moves 'largeValue' above 'value' + await driver.withActions((actions) => actions.dragAndDrop(findYAxis('largeValue'), findYAxis('value'))); + await gu.waitForServer(); + + // check axis correctness + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['largeValue', 'value'] + }); + }); + + it('should be able to render different types of charts', async function() { + const chartDom = await driver.find('.test-chart-container'); + + await selectChartType('Pie Chart'); + let data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'pie'); + assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL'); + await selectChartType('Line Chart'); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'scatter'); + // Make sure we are not grouping (which would produce names like "1 · value") + assert.equal(data[0].name, 'largeValue'); + assert.equal(data[1].name, 'value'); + assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'X-AXIS'); + + await selectChartType('Area Chart'); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data[0].line!.shape, 'spline'); + assert.deepEqual(data[0].fill, 'tozeroy'); + assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart'); + + // Make sure first field of scatter plot is marked label, not x-axis. + await selectChartType('Scatter Plot'); + assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL'); + + // Make sure first field of Kaplan-Meier plot is marked label, not x-axis. + await selectChartType('Kaplan-Meier Plot'); + assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL'); + + // Return to Area Chart. + await selectChartType('Area Chart'); + }); + + it('should render pie charts with a single series, or counts', async function() { + await selectChartType('Pie Chart'); + + // select 'person' for x axis + await selectXAxis('person'); + + // adds 'label' and move to be first y axis + await addYAxis('label'); + await driver.withActions((actions) => actions.dragAndDrop(findYAxis('label'), findYAxis('largeValue'))); + await gu.waitForServer(); + + // check axis + await checkAxisConfig({ + xaxis: 'person', + yaxis: ['label', 'largeValue', 'value'] + }); + + const chartDom = await driver.find('.test-chart-container'); + let data = (await getChartData(chartDom)).data; + // Only the first series of values is included. + assert.deepEqual(data[0].values, [ 61, 4, 2, 5, 3, 1 ]); + assert.lengthOf(data, 1); + + // When no series is included, just counts are used. + await removeYAxis('largeValue'); + await removeYAxis('label'); + await removeYAxis('value'); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].values, [1, 1, 1, 1, 1, 1]); + assert.lengthOf(data, 1); + + await gu.undo(7); + + // check axis + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['largeValue', 'value'] + }); + + // check chart type + assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart'); + }); + + it('should support Y-axis options', async function() { + const chartDom = await driver.find('.test-chart-container'); + await selectChartType('Bar Chart'); + checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 57); + + await driver.findContent('label', /Invert Y-axis/).find('input').click(); + await gu.waitForServer(); + checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 57, 0); + + await driver.findContent('label', /Invert Y-axis/).find('input').click(); + await driver.findContent('label', /Log scale Y-axis/).find('input').click(); + await gu.waitForServer(); + checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0.22, 1.82); + + await gu.undo(4); + // check axis + await checkAxisConfig({ + xaxis: 'label', + yaxis: ['largeValue', 'value'] + }); + // check chart type + assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart'); + }); + + it('should be able to render multiseries line charts', async function() { + const chartDom = await driver.find('.test-chart-container'); + + // switch type to line chart + await selectChartType('Line Chart'); + + // pick 'largeValue' as the x axis + await selectXAxis('largeValue'); + + // set 'label' as the groupby column + await setSplitSeries('label'); + + let {data, layout} = await getChartData(chartDom); + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data.map(d => d.name), ['1', '2', '3', '4', '5', '61']); + assert.equal(getAxisTitle(layout.xaxis), 'largeValue'); + assert.equal(getAxisTitle(layout.yaxis), 'value'); + + // Select person for grouping by column + await setSplitSeries('person'); + + await checkAxisConfig({ + groupingByColumn: 'person', + xaxis: 'largeValue', + yaxis: ['value'], + }); + + ({data, layout} = await getChartData(chartDom)); + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data.map(d => d.name), ['Alice', 'Bob']); + assert.equal(getAxisTitle(layout.xaxis), 'largeValue'); + assert.equal(getAxisTitle(layout.yaxis), 'value'); + + // Add a second series. If we have more than one, its name should be included into the series + // names rather than in the yaxis.title. + await addYAxis('label'); + + await checkAxisConfig({ + groupingByColumn: 'person', + xaxis: 'largeValue', + yaxis: ['value', 'label'], + }); + + ({data, layout} = await getChartData(chartDom)); + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data.map(d => d.name), ['Alice • value', 'Alice • label', 'Bob • value', 'Bob • label']); + assert.equal(getAxisTitle(layout.xaxis), 'largeValue'); + assert.equal(getAxisTitle(layout.yaxis), undefined); + + await gu.undo(5); + await checkAxisConfig({ + groupingByColumn: false, + xaxis: 'label', + yaxis: ['largeValue', 'value'], + }); + // check chart type + assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart'); + }); + + it('should get options for SPLIT SERIES and X AXIS in sync when table changes', async function() { + + // click change widget + await driver.findContent('button', 'Change Widget').click(); + + // click sum symbol + await driver.findContent('.test-wselect-table', 'People').click(); + + // click save + await driver.find('.test-wselect-addBtn').click(); + await gu.waitForServer(); + + // click Split series + await driver.findContent('label', 'Split series').click(); + + // open split series options + await driver.find('.test-chart-group-by-column').click(); + + // check group-data options + assert.deepEqual( + await driver.findAll('.test-select-menu li', e => e.getText()), + ['Pick a column', 'Name', 'B'] + ); + + // send ESCAPE to close menu + await driver.sendKeys(Key.ESCAPE); + + // open x axis options + await driver.find('.test-chart-x-axis').click(); + + // check x axis options + assert.deepEqual( + await driver.findAll('.test-select-menu li', e => e.getText()), + ['Name', 'B'] + ); + + // send ESCAPE to close menu + await driver.sendKeys(Key.ESCAPE); + + // undo + await gu.undo(1); + }); + + it('should get series name right when grouped column has \'\' values', async function() { + // remove series 'value' + await removeYAxis('value'); + + // add a row with person left as blank + const {retValues} = await api.applyUserActions(doc.id, [ + ['AddRecord', 'ChartData', 7, {largeValue: 44}] + ]); + await setSplitSeries('person'); + + // check that series name is correct + const data = (await getChartData()).data; + assert.deepEqual(data.map(d => d.name), ['[Blank]', 'Alice', 'Bob']); + + // remove row + await api.applyUserActions(doc.id, [ + ['RemoveRecord', 'ChartData', retValues[0]] + ]); + + // undo + await gu.undo(2); + }); + + it('should disabled split series option for pie charts', async function() { + + // start with line chart type + await selectChartType('Line Chart'); + + // check the split series option is present + assert.equal(await driver.findContent('label', /Split series/).isPresent(), true); + assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), true); + + // select 'person' as the split series column + await setSplitSeries('person'); + + // check split series option + assert.equal(await driver.findContent('label', /Split series/).isPresent(), true); + assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), true); + + // check axis + await checkAxisConfig({ + groupingByColumn: 'person', + xaxis: 'label', + yaxis: ['largeValue', 'value'], + }); + + // select pie chart type + await selectChartType('Pie Chart'); + + // check that the split series option is not present + assert.equal(await driver.findContent('label', /Split series/).isPresent(), false); + assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), false); + + // check axis + await checkAxisConfig({ + groupingByColumn: false, + xaxis: 'label', + yaxis: ['largeValue', 'value'], + }); + assert.equal(await driver.find('.test-chart-type').getText(), 'Pie Chart'); + + // undo + await gu.undo(2); + await checkAxisConfig({ + groupingByColumn: false, + xaxis: 'label', + yaxis: ['largeValue', 'value'], + }); + assert.equal(await driver.find('.test-chart-type').getText(), 'Line Chart'); + }); + + it('should render dates properly on X-axis', async function() { + await gu.getSection('ChartData').find('.viewsection_title').click(); + + // Add a new first column. + await gu.getCell({col: 0, rowNum: 1}).click(); + // driver.sendKeys() doesn't support key combinations, but elem.sendKeys() does. + await driver.find('body').sendKeys(Key.chord(Key.ALT, Key.SHIFT, '=')); + await gu.waitForServer(); + await driver.find('.test-column-title-label').sendKeys('MyDate', Key.ENTER); + await gu.waitForServer(); + + // Convert it to Date + await gu.toggleSidePanel('right', 'open'); + await driver.find('.test-right-tab-field').click(); + await gu.setType(/Date/); + await gu.waitForServer(); + + // Enter some values. + await gu.enterGridRows({col: 0, rowNum: 1}, [ + ["2018-01-15"], ["2018-01-31"], ["2018-02-14"], ["2018-03-04"], ["2018-03-14"], ["2018-03-26"] + ]); + + // Open the view config pane for the Chart section. + await gu.getSection('ChartData chart').find('.viewsection_title').click(); + await driver.find('.test-right-tab-pagewidget').click(); + + // select MyDate for x axis + await selectXAxis('MyDate'); + + const chartDom = await driver.find('.test-chart-container'); + const {data, layout} = await getChartData(chartDom); + // This check helps understand Plotly's actual interpretation of the dates. E.g. if the range + // endpoints are like '2018-03-25 20:00', plotly is misinterpreting the timezone. + assert.deepEqual(layout.xaxis.range, ['2018-01-15', '2018-03-26']); + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data[0].name, 'largeValue'); + assert.deepEqual(data[0].x, [ + "2018-01-15T00:00:00.000Z", "2018-01-31T00:00:00.000Z", "2018-02-14T00:00:00.000Z", + "2018-03-04T00:00:00.000Z", "2018-03-14T00:00:00.000Z", "2018-03-26T00:00:00.000Z" + ]); + assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]); + assert.deepEqual(data[1].type, 'scatter'); + assert.deepEqual(data[1].name, 'value'); + assert.deepEqual(data[0].x, [ + "2018-01-15T00:00:00.000Z", "2018-01-31T00:00:00.000Z", "2018-02-14T00:00:00.000Z", + "2018-03-04T00:00:00.000Z", "2018-03-14T00:00:00.000Z", "2018-03-26T00:00:00.000Z" + ]); + assert.deepEqual(data[1].y, [16, 2, 3, 4, 5, 6]); + }); + + it('should support error bars', async function() { + // We start with a line chart with MyDate on X-axis, and two series: largeValue and value. + await selectChartType('Line Chart'); + await checkAxisConfig({xaxis: 'MyDate', yaxis: ['largeValue', 'value']}); + + // Symmetric error bars should leave only the largeValue series, with 'value' for error bars. + await driver.find('.test-chart-error-bars .test-select-open').click(); + await driver.findContent('.test-select-menu li', /Symmetric/).click(); + await gu.waitForServer(); + + const chartDom = await driver.find('.test-chart-container'); + let data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'scatter'); + assert.deepEqual(data[0].name, 'largeValue'); + assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]); + assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]); + assert.deepEqual(data[0].error_y!.symmetric, true); + assert.lengthOf(data, 1); + + // Using separate error bars for above+below will leave just the "above" error bars. + await driver.find('.test-chart-error-bars .test-select-open').click(); + await driver.findContent('.test-select-menu li', /Above.*Below/).click(); + await gu.waitForServer(); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]); + assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]); + assert.deepEqual((data[0].error_y as any).arrayminus, null); + assert.deepEqual(data[0].error_y!.symmetric, false); + assert.lengthOf(data, 1); + + // If we add another line, it'll be used for "below" error bars. + await addYAxis('label'); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]); + assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]); + assert.deepEqual((data[0].error_y as any).arrayminus, [61, 5, 4, 3, 2, 1]); + assert.deepEqual(data[0].error_y!.symmetric, false); + assert.lengthOf(data, 1); + + // Should work also for bar charts + await selectChartType('Bar Chart'); + data = (await getChartData(chartDom)).data; + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]); + assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]); + assert.deepEqual((data[0].error_y as any).arrayminus, [61, 5, 4, 3, 2, 1]); + assert.deepEqual(data[0].error_y!.symmetric, false); + assert.lengthOf(data, 1); + await gu.undo(1); + + + await gu.undo(3); + }); + + it('should fetch data for tables not yet loaded', async function() { + // Create a Page that only has a Chart, no other sections. + await gu.addNewPage(/Chart/, /ChartData/); + + let chartDom = await driver.findWait('.test-chart-container', 1000); + assert.equal(await chartDom.isDisplayed(), true); + let data = (await getChartData(chartDom)).data; + assert.lengthOf(data, 1); + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].y, [ 61, 5, 4, 3, 2, 1 ]); + + // Reload the page and test that the chart loaded. + await driver.navigate().refresh(); + await gu.waitForDocToLoad(); + + await driver.sleep(1000); + chartDom = await driver.findWait('.test-chart-container', 1000); + assert.equal(await chartDom.isDisplayed(), true); + data = (await getChartData(chartDom)).data; + assert.lengthOf(data, 1); + assert.deepEqual(data[0].type, 'bar'); + assert.deepEqual(data[0].y, [ 61, 5, 4, 3, 2, 1 ]); + }); + + it('should resize chart when side panels open or close', async function() { + // Open a document with some chart data. + const session = await gu.session().teamSite.login(); + doc = await session.tempDoc(cleanup, 'ChartData.grist'); + await gu.toggleSidePanel('right', 'close'); + + // Add a chart section. + await gu.addNewSection(/Chart/, /ChartData/); + const chart = await driver.findWait('.viewsection_content .svg-container', 1000); + const initialRect = await chart.getRect(); + // We expect the left panel open initially. + assert.equal(await gu.isSidePanelOpen('left'), true); + + // Open the RightPanel, check that chart's width was reduced. + await gu.toggleSidePanel('right', 'open'); + await driver.wait(async () => (await chart.getRect()).width < initialRect.width, 1000); + + // Close the panel and check the chart went back to initial size. + await gu.toggleSidePanel('right', 'close'); + await driver.wait(async () => (await chart.getRect()).width === initialRect.width, 1000); + assert.deepEqual(await chart.getRect(), initialRect); + + // Close the left panel, and check that chart width was increased. + await gu.toggleSidePanel('left', 'close'); + await driver.wait(async () => (await chart.getRect()).width > initialRect.width, 1000); + + // Reopen the left panel and check the chart went back to initial size. + await gu.toggleSidePanel('left', 'open'); + await driver.wait(async () => (await chart.getRect()).width === initialRect.width, 1000); + assert.deepEqual(await chart.getRect(), initialRect); + }); + + // Tests a bug where js errors would be thrown when fewer than 2 series were visible + // and any chart settings were changed. + it('should not throw errors when no y-axis are set', async function() { + // Open the RightPanel and hide both series. + await gu.toggleSidePanel('right', 'open'); + await removeYAxis('value'); + + // Invert the y-axis. (This is meant to trigger js errors if the bug is present) + await driver.findContent('label', /Invert Y-axis/).find('input').click(); + await gu.waitForServer(); + + // Group by the first column. (This is meant to trigger js errors if the bug is present) + await setSplitSeries('value'); + + // Disable groupby column + await setSplitSeries(false); + + // Revert changes. + await gu.undo(3); + }); + + // Tests a bug where hitting enter would try to edit a non-existent cell for summary charts. + it('should not throw errors when pressing enter on summary charts', async function() { + // Click the section and press 'Enter'. + await gu.getSection('ChartData chart').click(); + await driver.sendKeys(Key.ENTER); + await gu.checkForErrors(); + }); + + it('should not throw errors when switching to a chart page', async function() { + await gu.getPageItem('People').click(); + await gu.waitForServer(); + await gu.getPageItem('ChartData').click(); + await gu.waitForServer(); + const chartDom = await gu.getSection('ChartData chart').find('.test-chart-container'); + assert.equal(await chartDom.isDisplayed(), true); + await gu.checkForErrors(); + }); + + it('should not throw errors when summarizing or un-summarizing underlying table', async function() { + // activate the chart widget + await gu.getSection('ChartData chart').click(); + + // open widget option + await gu.openSectionMenu('viewLayout'); + await driver.findContent('.grist-floating-menu li', 'Widget options').click(); + + // open the page widget picker + await driver.findContent('.test-right-panel button', 'Change Widget').click(); + + // click the summarize button + await driver.findContent('.test-wselect-table', 'ChartData').find('.test-wselect-pivot').click(); + + // click save + await driver.find('.test-wselect-addBtn').click(); + + // wait for server + await gu.waitForServer(); + + // wait for chart to be changed + await gu.waitToPass(async () => { + assert.equal( + await gu.getActiveSectionTitle(), + 'CHARTDATA [Totals] Chart' + ); + }); + + // check for error + await gu.checkForErrors(); + + // undo 1 + await gu.undo(1); + }); + + it('should sort x-axis values', async function() { + // Import a small table of numbers to test this. + await gu.importFileDialog('uploads/ChartData-Sort_Test.csv'); + + await driver.find('.test-modal-confirm').click(); + await gu.waitForServer(); + + // Add a chart of this data, and configure it first to just show X and Y1, Y2 series. + await gu.addNewSection(/Chart/, /ChartData-Sort_Test/); + await gu.toggleSidePanel('right', 'open'); + await selectChartType('Line Chart'); + + // Show series X, Y1, Y2, grouped by Group. + await selectXAxis('X'); + await setSplitSeries('Group'); + await addYAxis('Y1'); + await addYAxis('Y2'); + + const chartDom = await driver.findWait('.test-chart-container', 1000); + let {data} = await getChartData(chartDom); + assert.lengthOf(data, 4); + assert.deepInclude(data[0], {type: 'scatter', name: 'Bar • Y1'}); + assert.deepInclude(data[1], {type: 'scatter', name: 'Bar • Y2'}); + assert.deepInclude(data[2], {type: 'scatter', name: 'Foo • Y1'}); + assert.deepInclude(data[3], {type: 'scatter', name: 'Foo • Y2'}); + assert.deepEqual(data[0].x, [ 1.5, 2.5, 3.5, 4.5, 5.5 ]); + assert.deepEqual(data[0].y, [ 1.5, 1, 3.5, 2.5, 4 ]); + assert.deepEqual(data[1].x, [ 1.5, 2.5, 3.5, 4.5, 5.5 ]); + assert.deepEqual(data[1].y, [ 6.9, 6, 4.9, 5, 7 ]); + assert.deepEqual(data[2].x, [ 1, 2, 3, 4, 5 ]); + assert.deepEqual(data[2].y, [ 1.5, 1, 3.5, 2.5, 4 ]); + assert.deepEqual(data[3].x, [ 1, 2, 3, 4, 5 ]); + assert.deepEqual(data[3].y, [ 6.9, 6, 4.9, 5, 7 ]); + + // Now show series ungrouped. + await setSplitSeries(false); + + ({data} = await getChartData(chartDom)); + assert.lengthOf(data, 2); + assert.deepInclude(data[0], {type: 'scatter', name: 'Y1'}); + assert.deepInclude(data[1], {type: 'scatter', name: 'Y2'}); + assert.deepEqual(data[0].x, [ 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5 ]); + assert.deepEqual(data[0].y, [ 1.5, 1.5, 1, 1, 3.5, 3.5, 2.5, 2.5, 4, 4 ]); + assert.deepEqual(data[1].x, [ 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5 ]); + assert.deepEqual(data[1].y, [ 6.9, 6.9, 6, 6, 4.9, 4.9, 5, 5, 7, 7 ]); + }); + + it('should not throw when picking the grouping by column for the x-axis', async function() { + await checkAxisConfig({xaxis: 'X', yaxis: ['Y1', 'Y2']}); + await setSplitSeries('Group'); + await checkAxisConfig({xaxis: 'X', yaxis: ['Y1', 'Y2'], groupingByColumn: 'Group'}); + await selectXAxis('Group'); + await checkAxisConfig({xaxis: 'Group', yaxis: ['Y1', 'Y2']}); + await gu.checkForErrors(); + await gu.undo(2); + }); +}); diff --git a/test/nbrowser/ChoiceList.ts b/test/nbrowser/ChoiceList.ts index 6108e2e2f73..27d9c12c1b4 100644 --- a/test/nbrowser/ChoiceList.ts +++ b/test/nbrowser/ChoiceList.ts @@ -135,7 +135,7 @@ async function saveChoiceEntries() { } describe('ChoiceList', function() { - this.timeout(20000); + this.timeout(30000); const cleanup = setupTestSuite(); const WHITE_FILL = 'rgba(255, 255, 255, 1)'; @@ -748,12 +748,17 @@ describe('ChoiceList', function() { await gu.sendKeys('Choice 1', Key.ENTER, 'Choice 2', Key.ENTER, 'Choice 3', Key.ENTER); // Copy all the choices - await gu.sendKeys(Key.chord(modKey, 'a'), await gu.copyKey()); + await gu.sendKeys(await gu.selectAllKey()); + await gu.withSafeClipboard(async (cb) => { + await cb.copy(); - // Delete all the choices, then paste them back and verify no data was lost. - await driver.sendKeys(Key.BACK_SPACE); - assert.deepEqual(await getEditModeChoiceLabels(), []); - await gu.sendKeys(await gu.pasteKey()); + // Delete all the choices, then paste them back + await driver.sendKeys(Key.BACK_SPACE); + assert.deepEqual(await getEditModeChoiceLabels(), []); + await cb.paste(); + }); + + // Verify no data was lost assert.deepEqual(await getEditModeChoiceLabels(), ['Choice 1', 'Choice 2', 'Choice 3']); // In Jenkins, clipboard contents are pasted from the system clipboard, which only copies @@ -846,14 +851,16 @@ describe('ChoiceList', function() { // Make sure we can copy and paste without adding new item await clickEntry('foo'); - await gu.sendKeys(await gu.cutKey()); - await gu.sendKeys(await gu.pasteKey()); - await gu.sendKeys(await gu.pasteKey()); - await gu.sendKeys(Key.ENTER); - await clickEntry('two'); - await gu.sendKeys(await gu.copyKey()); - await gu.sendKeys(Key.ARROW_RIGHT); - await gu.sendKeys(await gu.pasteKey()); + await gu.withSafeClipboard(async (cb) => { + await cb.cut(); + await cb.paste(); + await cb.paste(); + await gu.sendKeys(Key.ENTER); + await clickEntry('two'); + await cb.copy(); + await gu.sendKeys(Key.ARROW_RIGHT); + await cb.paste(); + }); await gu.sendKeys(Key.ENTER); assert.deepEqual(await getEditModeChoiceLabels(), ["foofoo", "three", "twotwo"]); await saveChoiceEntries(); diff --git a/test/nbrowser/CustomWidgetsConfig.ts b/test/nbrowser/CustomWidgetsConfig.ts index e480b24393f..a4b6ff443d7 100644 --- a/test/nbrowser/CustomWidgetsConfig.ts +++ b/test/nbrowser/CustomWidgetsConfig.ts @@ -73,11 +73,13 @@ async function givenAccess(level?: AccessLevel) { await gu.waitForServer(); } } - // Checks if access prompt is visible. const hasPrompt = () => driver.find('.test-config-widget-access-accept').isPresent(); +// Waits for access prompt to be visible. +const waitForPrompt = async () => await gu.waitToPass(async () => + assert.isTrue(await hasPrompt()), 1000); // Accepts new access level. -const accept = () => driver.find('.test-config-widget-access-accept').click(); +const accept = () => driver.findWait('.test-config-widget-access-accept', 1000).click(); // When refreshing, we need to make sure widget repository is enabled once again. async function refresh() { await driver.navigate().refresh(); @@ -489,6 +491,7 @@ describe('CustomWidgetsConfig', function () { await toggleWidgetMenu(); await clickOption(COLUMN_WIDGET); await accept(); + await widget.waitForFrame(); assert.equal(await driver.find(pickerDrop('Column')).getText(), 'Pick a column'); assert.isFalse(await driver.find('.test-vfc-visible-fields-select-all').isPresent()); assert.isTrue(await driver.find('.test-config-widget-label-for-Column').isPresent()); @@ -690,6 +693,7 @@ describe('CustomWidgetsConfig', function () { await gu.setType(/Numeric/); await gu.selectSectionByTitle('Widget'); await driver.find(".test-right-tab-pagewidget").click(); + await gu.waitForServer(); // Drop should be empty, assert.equal(await driver.find(pickerDrop("M1")).getText(), "Pick a text column"); assert.isEmpty(await getListItems("M2")); @@ -906,25 +910,31 @@ describe('CustomWidgetsConfig', function () { // Select widget without request await toggleWidgetMenu(); await clickOption(NORMAL_WIDGET); + await widget.waitForFrame(); assert.isFalse(await hasPrompt()); assert.equal(await givenAccess(), AccessLevel.none); assert.equal(await widget.access(), AccessLevel.none); // Select widget that requests read access. await toggleWidgetMenu(); await clickOption(READ_WIDGET); - assert.isTrue(await hasPrompt()); + await widget.waitForFrame(); + await waitForPrompt(); assert.equal(await givenAccess(), AccessLevel.none); assert.equal(await widget.access(), AccessLevel.none); await accept(); + await widget.waitForFrame(); assert.equal(await givenAccess(), AccessLevel.read_table); assert.equal(await widget.access(), AccessLevel.read_table); // Select widget that requests full access. await toggleWidgetMenu(); await clickOption(FULL_WIDGET); + await widget.waitForFrame(); + await waitForPrompt(); assert.isTrue(await hasPrompt()); assert.equal(await givenAccess(), AccessLevel.none); assert.equal(await widget.access(), AccessLevel.none); await accept(); + await widget.waitForFrame(); assert.equal(await givenAccess(), AccessLevel.full); assert.equal(await widget.access(), AccessLevel.full); await gu.undo(5); diff --git a/test/nbrowser/DetailView.ntest.js b/test/nbrowser/DetailView.ntest.js index 904b0fdddbe..e23e58ba044 100644 --- a/test/nbrowser/DetailView.ntest.js +++ b/test/nbrowser/DetailView.ntest.js @@ -2,6 +2,7 @@ import { By, assert, driver } from 'mocha-webdriver'; import { $, gu, test } from 'test/nbrowser/gristUtil-nbrowser'; describe("DetailView.ntest", function () { + this.timeout(30000); const cleanup = test.setupTestSuite(this); gu.bigScreen(); @@ -130,11 +131,13 @@ describe("DetailView.ntest", function () { // Should allow pasting into the add record row. await gu.getDetailCell('Actor', 1).click(); - await gu.sendKeys($.COPY); - await $('.detail-add-btn').click(); - // Paste '100' into the last field of the row and check that it is added as its own row. - await gu.getDetailCell('Character', 1).click(); - await gu.sendKeys($.PASTE); + await gu.withSafeClipboard(async (cb) => { + await cb.copy(); + await $('.detail-add-btn').click(); + // Paste '100' into the last field of the row and check that it is added as its own row. + await gu.getDetailCell('Character', 1).click(); + await cb.paste(); + }); await gu.waitForServer(); assert.deepEqual(await gu.getDetailCell('Character', 1).text(), '100'); diff --git a/test/nbrowser/DocTutorial.ts b/test/nbrowser/DocTutorial.ts index f52e34babc6..8a80fe8e506 100644 --- a/test/nbrowser/DocTutorial.ts +++ b/test/nbrowser/DocTutorial.ts @@ -7,7 +7,6 @@ import {EnvironmentSnapshot} from 'test/server/testUtils'; describe('DocTutorial', function () { this.timeout(60000); - setupTestSuite(); gu.bigScreen(); @@ -196,8 +195,10 @@ describe('DocTutorial', function () { const windowWidth: any = await driver.executeScript('return window.innerWidth'); assert.equal(dims.y + dims.height, windowHeight - 16); - // Now move it offscreen as low as possible. - await move({y: windowHeight - dims.y - 10}); + // Now we'll test moving the window outside the viewport. Selenium throws when + // the mouse exceeds the bounds of the viewport, so we can't test every scenario. + // Start by moving the window as low as possible. + await move({y: windowHeight - dims.y - 32}); // Make sure it is still visible. dims = await driver.find('.test-floating-popup-window').getRect(); @@ -213,72 +214,34 @@ describe('DocTutorial', function () { assert.equal(dims.x, windowWidth - 32 * 4); // Now move it to the left as far as possible. - await move({x: -3000}); + await move({x: -windowWidth + 128}); // Make sure it is still visible. dims = await driver.find('.test-floating-popup-window').getRect(); - assert.isBelow(dims.x, 0); + assert.equal(dims.x, 0); assert.isAbove(dims.x + dims.width, 30); - const miniButton = driver.find(".test-floating-popup-minimize-maximize"); - // Now move it back, but this time manually as the move handle is off screen. - await driver.withActions((a) => a - .move({origin: miniButton }) - .press() - .move({origin: miniButton, x: Math.abs(dims.x) + 20}) - .release() - ); - - // Maximize it (it was minimized as we used the button to move it). - await driver.find(".test-floating-popup-minimize-maximize").click(); - // Now move it to the top as far as possible. // Move it a little right, so that we don't end up on the logo. Driver is clicking logo sometimes. - await move({y: -windowHeight, x: 100}); + await move({y: -windowHeight + 16, x: 100}); // Make sure it is still visible. dims = await driver.find('.test-floating-popup-window').getRect(); assert.equal(dims.y, 16); - assert.isAbove(dims.x, 100); - assert.isBelow(dims.x, windowWidth); + assert.equal(dims.x, 100); // Move back where it was. - let moverNow = await driver.find('.test-floating-popup-move-handle').getRect(); + const moverNow = await driver.find('.test-floating-popup-move-handle').getRect(); await move({x: moverInitial.x - moverNow.x}); // And restore the size by double clicking the resizer. await driver.withActions((a) => a.doubleClick(driver.find('.test-floating-popup-resize-handle'))); - - // Now test if we can't resize it offscreen. - await move({y: 10000}); - await move({y: -100}); - // Header is about 100px above the viewport. - dims = await driver.find('.test-floating-popup-window').getRect(); - assert.isBelow(dims.y, windowHeight); - assert.isAbove(dims.x, windowHeight - 140); - - // Now resize as far as possible. - await resize({y: 10}); - await resize({y: 300}); - - // Make sure it is still visible. - dims = await driver.find('.test-floating-popup-window').getRect(); - assert.isBelow(dims.y, windowHeight - 16); - - // Now move back and resize. - moverNow = await driver.find('.test-floating-popup-move-handle').getRect(); - await move({x: moverInitial.x - moverNow.x, y: moverInitial.y - moverNow.y}); - await driver.withActions((a) => a.doubleClick(driver.find('.test-floating-popup-resize-handle'))); - - dims = await driver.find('.test-floating-popup-window').getRect(); - assert.equal(dims.height, initialDims.height); - assert.equal(dims.y, initialDims.y); - assert.equal(dims.x, initialDims.x); }); it('is visible on all pages', async function() { for (const page of ['access-rules', 'raw', 'code', 'settings']) { await driver.find(`.test-tools-${page}`).click(); assert.isTrue(await driver.find('.test-doc-tutorial-popup').isDisplayed()); + await gu.waitForServer(); } }); diff --git a/test/nbrowser/FillLinkedRecords.ntest.js b/test/nbrowser/FillLinkedRecords.ntest.js index bb12499454b..462bd51e538 100644 --- a/test/nbrowser/FillLinkedRecords.ntest.js +++ b/test/nbrowser/FillLinkedRecords.ntest.js @@ -6,6 +6,8 @@ import { $, gu, test } from 'test/nbrowser/gristUtil-nbrowser'; * records automatically get assigned the filter value. */ describe('FillLinkedRecords.ntest', function() { + this.timeout(30000); + const cleanup = test.setupTestSuite(this); gu.bigScreen(); @@ -130,9 +132,12 @@ describe('FillLinkedRecords.ntest', function() { // Copy a range of three values, and paste them into the Add-New row. await gu.clickCell({col: 2, rowNum: 1}); - await gu.sendKeys([$.SHIFT, $.DOWN, $.DOWN], $.COPY); - await gu.clickCell({col: 2, rowNum: 5}); - await gu.sendKeys($.PASTE); + await gu.sendKeys([$.SHIFT, $.DOWN, $.DOWN]); + await gu.withSafeClipboard(async (cb) => { + await cb.copy(); + await gu.clickCell({col: 2, rowNum: 5}); + await cb.paste(); + }); await gu.waitForServer(); // Verify that three new rows now show up, with Film auto-filled. diff --git a/test/nbrowser/Pages.ts b/test/nbrowser/Pages.ts index ba1947f892e..1e4069046ba 100644 --- a/test/nbrowser/Pages.ts +++ b/test/nbrowser/Pages.ts @@ -8,7 +8,6 @@ import values = require('lodash/values'); describe('Pages', function() { this.timeout(60000); - setupTestSuite(); let doc: DocCreationInfo; let api: UserAPI; let session: Session; diff --git a/test/nbrowser/RawData.ts b/test/nbrowser/RawData.ts index 091c90f208b..05cfa2fd903 100644 --- a/test/nbrowser/RawData.ts +++ b/test/nbrowser/RawData.ts @@ -1,7 +1,7 @@ import {UserAPI} from 'app/common/UserAPI'; import {assert, driver, Key} from 'mocha-webdriver'; import * as gu from 'test/nbrowser/gristUtils'; -import {server, setupTestSuite} from 'test/nbrowser/testUtils'; +import {cleanupExtraWindows, server, setupTestSuite} from 'test/nbrowser/testUtils'; describe('RawData', function () { this.timeout(30000); @@ -11,6 +11,7 @@ describe('RawData', function () { // At the time of writing this test, undo was basically not possible and was throwing all sort // of exceptions (related to summary tables). let revertAll: () => Promise; + cleanupExtraWindows(); setupTestSuite(); gu.bigScreen(); afterEach(() => gu.checkForErrors()); @@ -675,7 +676,7 @@ async function openMenu(tableId: string) { } async function waitForRawData() { - await driver.findWait('.test-raw-data-list', 2000); + await driver.findWait('.test-raw-data-list', 4000); await gu.waitForServer(); } diff --git a/test/nbrowser/RightPanel.ts b/test/nbrowser/RightPanel.ts index a2f4af4bc4f..e10c544ce55 100644 --- a/test/nbrowser/RightPanel.ts +++ b/test/nbrowser/RightPanel.ts @@ -3,7 +3,7 @@ import * as gu from 'test/nbrowser/gristUtils'; import {server, setupTestSuite} from 'test/nbrowser/testUtils'; describe('RightPanel', function() { - this.timeout(20000); + this.timeout(30000); const cleanup = setupTestSuite(); afterEach(() => gu.checkForErrors()); diff --git a/test/nbrowser/SavePosition.ntest.js b/test/nbrowser/SavePosition.ntest.js index bce9d9bb02a..09fd13135ca 100644 --- a/test/nbrowser/SavePosition.ntest.js +++ b/test/nbrowser/SavePosition.ntest.js @@ -2,10 +2,11 @@ import { assert } from 'mocha-webdriver'; import { $, gu, test } from 'test/nbrowser/gristUtil-nbrowser'; describe('SavePosition.ntest', function() { + this.timeout(30000); // Long-running test, unfortunately + const cleanup = test.setupTestSuite(this); before(async function() { - this.timeout(Math.max(this.timeout(), 20000)); // Long-running test, unfortunately await gu.supportOldTimeyTestCode(); await gu.useFixtureDoc(cleanup, "World.grist", true); }); @@ -96,9 +97,11 @@ describe('SavePosition.ntest', function() { it('should paste into saved position', async function() { await gu.getCell({col: 1, rowNum: 9, section: 'Country'}).click(); await gu.actions.selectTabView('City'); - await gu.sendKeys($.COPY); - await gu.actions.selectTabView('Country'); - await gu.sendKeys($.PASTE); + await gu.withSafeClipboard(async (cb) => { + await cb.copy(); + await gu.actions.selectTabView('Country'); + await cb.paste(); + }); await gu.waitForServer(); assert.deepEqual(await gu.getVisibleGridCells(1, [8, 9, 10]), ['United Arab Emirates', 'Pará', 'Armenia']); diff --git a/test/nbrowser/SelectByRefList.ts b/test/nbrowser/SelectByRefList.ts index 6d3d3b562c9..7684f009d0a 100644 --- a/test/nbrowser/SelectByRefList.ts +++ b/test/nbrowser/SelectByRefList.ts @@ -4,7 +4,7 @@ import * as gu from 'test/nbrowser/gristUtils'; import {server, setupTestSuite} from 'test/nbrowser/testUtils'; describe('SelectByRefList', function() { - this.timeout(80000); + this.timeout(100000); setupTestSuite(); addToRepl('gu2', gu); gu.bigScreen(); diff --git a/test/nbrowser/WebhookPage.ts b/test/nbrowser/WebhookPage.ts index 639e63fdc4b..073994d85e1 100644 --- a/test/nbrowser/WebhookPage.ts +++ b/test/nbrowser/WebhookPage.ts @@ -6,7 +6,7 @@ import {server, setupTestSuite} from 'test/nbrowser/testUtils'; import {EnvironmentSnapshot} from 'test/server/testUtils'; describe('WebhookPage', function () { - this.timeout(60000); + this.timeout(90000); const cleanup = setupTestSuite(); let session: gu.Session; @@ -192,7 +192,7 @@ describe('WebhookPage', function () { await openWebhookPage(); // Open another tab. - await driver.executeScript("return window.open('about:blank', '_blank')"); + await driver.executeScript("window.open('about:blank', '_blank')"); const [ownerTab, owner2Tab] = await driver.getAllWindowHandles(); await driver.switchTo().window(owner2Tab); @@ -256,9 +256,11 @@ describe('WebhookPage', function () { await openWebhookPage(); await setField(1, 'Name', '1234'); await gu.waitForServer(); - await gu.sendKeys(await gu.copyKey()); - await gu.getDetailCell({col: 'Memo', rowNum: 1}).click(); - await gu.sendKeys(await gu.pasteKey()); + await gu.withSafeClipboard(async (cb) => { + await cb.copy(); + await gu.getDetailCell({col: 'Memo', rowNum: 1}).click(); + await cb.paste(); + }); await gu.waitForServer(); assert.equal(await getField(1, 'Memo'), '1234'); }); diff --git a/test/nbrowser/chartViewTestUtils.ts b/test/nbrowser/chartViewTestUtils.ts new file mode 100644 index 00000000000..135a312b3a1 --- /dev/null +++ b/test/nbrowser/chartViewTestUtils.ts @@ -0,0 +1,99 @@ +import {assert, driver, WebElement} from 'mocha-webdriver'; +import {Layout, LayoutAxis, PlotData} from 'plotly.js'; +import * as gu from 'test/nbrowser/gristUtils'; +import isString = require('lodash/isString'); +import isUndefined = require('lodash/isUndefined'); + +export interface ChartData { + data: Partial[]; + layout: Layout; +} + +export async function selectChartType(chartType: string) { + await driver.find('.test-chart-type').click(); + await driver.findContent('.test-select-row', chartType).click(); + return gu.waitForServer(); +} + +export async function getChartData(chartElem?: WebElement|string): Promise { + if (isString(chartElem) || isUndefined(chartElem)) { + const section = isString(chartElem) ? + await gu.getSection(chartElem) : + await driver.findWait('.active_section', 4000); + chartElem = await section.find('.test-chart-container'); + } + return driver.executeScript((el: any) => ({data: el.data, layout: el.layout}), chartElem); +} + +export function checkAxisRange({layout}: ChartData, xMin: number, xMax: number, yMin: number, yMax: number) { + assert.closeTo(layout.xaxis.range![0], xMin, xMin * 0.1); + assert.closeTo(layout.xaxis.range![1], xMax, xMax * 0.1); + assert.closeTo(layout.yaxis.range![0], yMin, yMin * 0.1); + assert.closeTo(layout.yaxis.range![1], yMax, yMax * 0.1); +} + +export function getAxisTitle(axis: Partial): string|undefined { + return axis.title && (axis.title as any).text; +} + +export function findYAxis(name: string) { + return driver.findContent('.test-chart-y-axis', name); +} + +export async function removeYAxis(name: string) { + await findYAxis(name).mouseMove().find('.test-chart-ref-select-remove').click(); + await gu.waitForServer(); +} + +export async function checkAxisConfig(expected: {groupingByColumn?: string|false, + xaxis: string|undefined, yaxis: string[]}) { + const isGroupByPresent = await driver.find('.test-chart-group-by-column').isPresent(); + let groupingByColumn = isGroupByPresent ? await driver.find('.test-chart-group-by-column').getText() : false; + if (groupingByColumn === 'Pick a column') { + groupingByColumn = false; + } + const xaxis = await driver.find('.test-chart-x-axis').getText(); + assert.deepEqual({ + groupingByColumn, + xaxis: xaxis === 'Pick a column' ? undefined : xaxis, + yaxis: await driver.findAll('.test-chart-y-axis', (e) => e.getText()), + }, {...expected, groupingByColumn: expected.groupingByColumn || false}); +} + +export async function setSplitSeries(name: string|false, section?: string) { + await gu.openSectionMenu('viewLayout', section); + await driver.findContent('.grist-floating-menu li', 'Widget options').click(); + + const isChecked = await driver.findContent('label', /Split series/).find('input').matches(':checked'); + if (name === false && isChecked === true || + name && isChecked === false) { + await driver.findContent('label', /Split series/).click(); + } + if (name) { + await driver.find('.test-chart-group-by-column').click(); + await driver.findContent('.test-select-menu li', name || 'Pick a column').click(); + } + await gu.waitForServer(); +} + +export async function selectXAxis(name: string, opt: {noWait?: boolean} = {}) { + await driver.find('.test-chart-x-axis').click(); + await driver.findContent('.test-select-menu li', name).click(); + if (!opt.noWait) { + await gu.waitForServer(); + } +} + + +export async function setYAxis(names: string[]) { + // let's first remove all yaxis and then add new ones + const toRemove = await driver.findAll('.test-chart-y-axis', (e) => e.getText()); + for (const n of toRemove) { await removeYAxis(n); } + for (const n of names) { await addYAxis(n); } +} + +export async function addYAxis(name: string) { + await driver.find('.test-chart-add-y-axis').click(); + await driver.findContent('.grist-floating-menu li', name).click(); + await gu.waitForServer(); +} diff --git a/test/nbrowser/gristUtil-nbrowser.js b/test/nbrowser/gristUtil-nbrowser.js index 72526111bdd..c65a4957edb 100644 --- a/test/nbrowser/gristUtil-nbrowser.js +++ b/test/nbrowser/gristUtil-nbrowser.js @@ -25,9 +25,6 @@ function rep(n, value) { // We do that later, during test initialization. async function applyPatchesToJquerylikeObject($) { $.MOD = await guBase.modKey(); - $.COPY = await guBase.copyKey(); - $.CUT = await guBase.cutKey(); - $.PASTE = await guBase.pasteKey(); $.SELECT_ALL = await guBase.selectAllKey(); const capabilities = await driver.getCapabilities(); if (capabilities.getBrowserName() === 'chrome' && await guBase.isMac()) { @@ -302,9 +299,15 @@ const gu = { * endCell[1]: 0-based column index. **/ async selectGridArea(startCell, endCell) { - let start = await gu.getCell({rowNum: startCell[0], col: startCell[1]}); - let end = await gu.getCell({rowNum: endCell[0], col: endCell[1]}); - await driver.withActions(a => a.click(start).keyDown($.SHIFT).click(end).keyUp($.SHIFT)); + const [startRowNum, startCol] = startCell; + const [endRowNum, endCol] = endCell; + if (startRowNum === endRowNum && startCol === endCol) { + await gu.getCell({rowNum: endRowNum, col: endCol}).click(); + } else { + const start = await gu.getCell({rowNum: startRowNum, col: startCol}); + const end = await gu.getCell({rowNum: endRowNum, col: endCol}); + await driver.withActions(a => a.click(start).keyDown($.SHIFT).click(end).keyUp($.SHIFT)); + } }, /** diff --git a/test/nbrowser/gristUtils.ts b/test/nbrowser/gristUtils.ts index ae1552e1169..492df206c3d 100644 --- a/test/nbrowser/gristUtils.ts +++ b/test/nbrowser/gristUtils.ts @@ -10,8 +10,9 @@ import startCase = require('lodash/startCase'); import { assert, driver as driverOrig, error, Key, WebElement, WebElementPromise } from 'mocha-webdriver'; import { stackWrapFunc, stackWrapOwnMethods, WebDriver } from 'mocha-webdriver'; import * as path from 'path'; +import { lock } from 'proper-lockfile'; -import {csvDecodeRow} from 'app/common/csvFormat'; +import { csvDecodeRow } from 'app/common/csvFormat'; import { decodeUrl } from 'app/common/gristUrls'; import { FullUser, UserProfile } from 'app/common/LoginSessionAPI'; import { resetOrg } from 'app/common/resetOrg'; @@ -893,6 +894,10 @@ export async function userActionsVerify(expectedUserActions: unknown[]): Promise if (!Array.isArray(assertError.actual)) { throw new Error('userActionsVerify: no user actions, run userActionsCollect() first'); } + if (!Array.isArray(assertError.expected)) { + throw new Error('userActionsVerify: no expected user actions'); + } + assertError.actual = assertError.actual.map((a: any) => JSON.stringify(a) + ",").join("\n"); assertError.expected = assertError.expected.map((a: any) => JSON.stringify(a) + ",").join("\n"); assert.deepEqual(assertError.actual, assertError.expected); @@ -948,6 +953,9 @@ export async function waitForLabelInput(): Promise { * Sends UserActions using client api from the browser. */ export async function sendActions(actions: UserAction[]) { + await driver.manage().setTimeouts({ + script: 1000 * 2, /* 2 seconds, default is 0.5s */ + }); const result = await driver.executeAsyncScript(` const done = arguments[arguments.length - 1]; const prom = gristDocPageModel.gristDoc.get().docModel.docData.sendActions(${JSON.stringify(actions)}); @@ -1361,6 +1369,9 @@ export async function closeSearch() { } export async function closeTooltip() { + if (!await driver.find('.test-tooltip').isPresent()) { return; } + + await driver.find('.test-tooltip').mouseMove(); await driver.mouseMoveBy({x : 100, y: 100}); await waitToPass(async () => { assert.equal(await driver.find('.test-tooltip').isPresent(), false); @@ -1539,29 +1550,16 @@ export async function applyTypeTransform() { } export async function isMac(): Promise { - return /Darwin|Mac|iPod|iPhone|iPad/i.test((await driver.getCapabilities()).get('platform')); + const platform = (await driver.getCapabilities()).getPlatform() ?? ''; + return /Darwin|Mac|mac os x|iPod|iPhone|iPad/i.test(platform); } export async function modKey() { return await isMac() ? Key.COMMAND : Key.CONTROL; } -// For copy-pasting, use different key combinations for Chrome on Mac. -// See http://stackoverflow.com/a/41046276/328565 -export async function copyKey() { - return await isMac() ? Key.chord(Key.CONTROL, Key.INSERT) : Key.chord(Key.CONTROL, 'c'); -} - -export async function cutKey() { - return await isMac() ? Key.chord(Key.CONTROL, Key.DELETE) : Key.chord(Key.CONTROL, 'x'); -} - -export async function pasteKey() { - return await isMac() ? Key.chord(Key.SHIFT, Key.INSERT) : Key.chord(Key.CONTROL, 'v'); -} - export async function selectAllKey() { - return await isMac() ? Key.chord(Key.HOME, Key.SHIFT, Key.END) : Key.chord(Key.CONTROL, 'a'); + return await isMac() ? Key.chord(Key.COMMAND, 'a') : Key.chord(Key.CONTROL, 'a'); } /** @@ -1575,14 +1573,13 @@ export async function sendKeys(...keys: string[]) { const toRelease: string[] = []; for (const part of keys) { for (const key of part) { - if ([Key.SHIFT, Key.CONTROL, Key.ALT, Key.META].includes(key)) { + if ([Key.ALT, Key.CONTROL, Key.SHIFT, Key.COMMAND, Key.META].includes(key)) { a.keyDown(key); toRelease.push(key); } else if (key === Key.NULL) { toRelease.splice(0).reverse().forEach(k => a.keyUp(k)); } else { - a.keyDown(key); - a.keyUp(key); + a.sendKeys(key); } } } @@ -1590,11 +1587,10 @@ export async function sendKeys(...keys: string[]) { } /** - * Clears active input/textarea by sending CTRL HOME + CTRL + SHIFT END + DELETE. + * Clears active input/textarea. */ export async function clearInput() { - const ctrl = await modKey(); - return sendKeys(Key.chord(ctrl, Key.HOME), Key.chord(ctrl, Key.SHIFT, Key.END), Key.DELETE); + return sendKeys(await selectAllKey(), Key.DELETE); } /** @@ -2676,18 +2672,39 @@ export async function getEnabledOptions(): Promise { return options; } +/** + * Switches to the window with the specified `windowHandle`. + */ +export async function switchToWindow(windowHandle: string) { + // Try switching up to 10 times. Typically, retries aren't needed, but in + // chromedriver 116, switching fails every now and then when done + // immediately after a new window/tab is opened. + // + // TODO: investigate further. + for (let i = 1; i <= 10; i++) { + try { + await driver.switchTo().window(windowHandle); + return; + } catch (e) { + if (i === 3) { throw e; } + + await driver.sleep(100); + } + } +} + /** * Runs action in a separate tab, closing the tab after. * In case of an error tab is not closed, consider using cleanupExtraWindows - * on whole test suit if needed. + * on whole test suite if needed. */ export async function onNewTab(action: () => Promise) { - await driver.executeScript("return window.open('about:blank', '_blank')"); + await driver.executeScript("window.open('about:blank', '_blank')"); const tabs = await driver.getAllWindowHandles(); - await driver.switchTo().window(tabs[tabs.length - 1]); + await switchToWindow(tabs[tabs.length - 1]); await action(); await driver.close(); - await driver.switchTo().window(tabs[tabs.length - 2]); + await switchToWindow(tabs[tabs.length - 2]); } /** @@ -3166,6 +3183,96 @@ export async function downloadSectionCsvGridCells( return ([] as string[]).concat(...csvRows); } +export type ClipboardAction = 'copy' | 'cut' | 'paste'; + +export interface ClipboardActionOptions { + method?: 'keyboard' | 'menu'; +} + +export interface IClipboard { + copy(options?: ClipboardActionOptions): Promise; + cut(options?: ClipboardActionOptions): Promise; + paste(options?: ClipboardActionOptions): Promise; +} + +class Clipboard implements IClipboard { + constructor() { + + } + + public async copy(options: ClipboardActionOptions = {}) { + await this._performAction('copy', options); + } + + public async cut(options: ClipboardActionOptions = {}) { + await this._performAction('cut', options); + } + + public async paste(options: ClipboardActionOptions = {}) { + await this._performAction('paste', options); + } + + private async _performAction(action: ClipboardAction, options: ClipboardActionOptions) { + const {method = 'keyboard'} = options; + switch (method) { + case 'keyboard': { + await this._performActionWithKeyboard(action); + break; + } + case 'menu': { + await this._performActionWithMenu(action); + break; + } + } + } + + private async _performActionWithKeyboard(action: ClipboardAction) { + switch (action) { + case 'copy': { + await sendKeys(Key.chord(await isMac() ? Key.COMMAND : Key.CONTROL, 'c')); + break; + } + case 'cut': { + await sendKeys(Key.chord(await isMac() ? Key.COMMAND : Key.CONTROL, 'x')); + break; + } + case 'paste': { + await sendKeys(Key.chord(await isMac() ? Key.COMMAND : Key.CONTROL, 'v')); + break; + } + } + } + + private async _performActionWithMenu(action: ClipboardAction) { + const field = await driver.find('.active_section .field_clip.has_cursor'); + await driver.withActions(actions => { actions.contextClick(field); }); + await driver.findWait('.grist-floating-menu', 1000); + const menuItemName = action.charAt(0).toUpperCase() + action.slice(1); + await driver.findContent('.grist-floating-menu li', menuItemName).click(); + } +} + +/** + * Requests exclusive access to the system clipboard, locking it for the duration of `cb`. + * + * Recommended for use in contexts where the system clipboard may be accessed by multiple + * parallel processes, such as Mocha tests. + */ +export async function withSafeClipboard(cb: (clipboard: IClipboard) => Promise) { + const release = await lock('test', { + lockfilePath: 'test/.clipboard.lock', + retries: { + /* The clipboard generally isn't locked for long, so retry frequently. */ + maxTimeout: 2000, + }, + }); + try { + await cb(new Clipboard()); + } finally { + await release(); + } +} + } // end of namespace gristUtils stackWrapOwnMethods(gristUtils); diff --git a/test/server/Comm.ts b/test/server/Comm.ts index 8beac886fe5..5b6b7edf91e 100644 --- a/test/server/Comm.ts +++ b/test/server/Comm.ts @@ -277,37 +277,49 @@ describe('Comm', function() { }); async function testMissedResponses(sendShouldFail: boolean) { - const logMessages = await testUtils.captureLog('debug', async () => { - const {cliComm, forwarder} = await startManagedConnection({...assortedMethods, - // An extra method that simulates a lost connection on server side prior to response. - testDisconnect: async function(client, x, y) { - await delay(0); // disconnect on the same tick. - await forwarder.disconnectServerSide(); - if (!sendShouldFail) { - // Add a delay to let the 'close' event get noticed first. - await delay(20); - } - return {x: x, y: y, name: "testDisconnect"}; - }, - }); + let failedSendCount = 0; + + const {cliComm, forwarder} = await startManagedConnection({...assortedMethods, + // An extra method that simulates a lost connection on server side prior to response. + testDisconnect: async function(client, x, y) { + setTimeout(() => forwarder.disconnectServerSide(), 0); + if (!sendShouldFail) { + // Add a delay to let the 'close' event get noticed first. + await delay(20); + } + return {x: x, y: y, name: "testDisconnect"}; + }, + }); + + const resp1 = await cliComm._makeRequest(null, null, "methodSync", "foo", 1); + assert.deepEqual(resp1, {name: 'methodSync', x: "foo", y: 1}); - const resp1 = await cliComm._makeRequest(null, null, "methodSync", "foo", 1); - assert.deepEqual(resp1, {name: 'methodSync', x: "foo", y: 1}); + if (sendShouldFail) { + // In Node 18, the socket is closed during the call to 'testDisconnect'. + // In prior versions of Node, the socket was still disconnecting. + // This test is sensitive to timing and only passes in the latter, unless we + // stub the method below to produce similar behavior in the former. + sandbox.stub(Client.prototype as any, '_sendToWebsocket') + .onFirstCall() + .callsFake(() => { + failedSendCount += 1; + throw new Error('WebSocket is not open'); + }) + .callThrough(); + } - // Make more calls, with a disconnect before they return. The server should queue up responses. - const resp2Promise = cliComm._makeRequest(null, null, "testDisconnect", "foo", 2); - const resp3Promise = cliComm._makeRequest(null, null, "methodAsync", "foo", 3); - assert.equal(await isLongerThan(resp2Promise, 250), true); + // Make more calls, with a disconnect before they return. The server should queue up responses. + const resp2Promise = cliComm._makeRequest(null, null, "testDisconnect", "foo", 2); + const resp3Promise = cliComm._makeRequest(null, null, "methodAsync", "foo", 3); + assert.equal(await isLongerThan(resp2Promise, 250), true); - // Once we reconnect, the response should arrive. - await forwarder.connect(); - assert.deepEqual(await resp2Promise, {name: 'testDisconnect', x: "foo", y: 2}); - assert.deepEqual(await resp3Promise, {name: 'methodAsync', x: "foo", y: 3}); - }); + // Once we reconnect, the response should arrive. + await forwarder.connect(); + assert.deepEqual(await resp2Promise, {name: 'testDisconnect', x: "foo", y: 2}); + assert.deepEqual(await resp3Promise, {name: 'methodAsync', x: "foo", y: 3}); - // Check that we saw the situations we were hoping to test. - assert.equal(logMessages.some(m => /^warn: .*send error.*WebSocket is not open/.test(m)), sendShouldFail, - `Expected to see a failed send:\n${logMessages.join('\n')}`); + // Check that we saw the situation we were hoping to test. + assert.equal(failedSendCount, sendShouldFail ? 1 : 0, 'Expected to see a failed send'); } it("should receive all server messages (small) in order when send doesn't fail", async function() { diff --git a/test/server/customUtil.ts b/test/server/customUtil.ts index 789d7422745..c2646573df4 100644 --- a/test/server/customUtil.ts +++ b/test/server/customUtil.ts @@ -20,7 +20,7 @@ export function addStatic(app: express.Express, rootDir?: string) { res.sendFile(req.params[0], {root: path.resolve(getAppRoot(), "static")})); app.use(express.static(rootDir || path.resolve(fixturesRoot, "sites"), { - setHeaders: (res) => { + setHeaders: (res: express.Response) => { res.set("Access-Control-Allow-Origin", "*"); } })); diff --git a/test/server/lib/DocApi.ts b/test/server/lib/DocApi.ts index 8c7750d2866..2a8f2c92658 100644 --- a/test/server/lib/DocApi.ts +++ b/test/server/lib/DocApi.ts @@ -17,8 +17,8 @@ import { import {delayAbort} from 'app/server/lib/serverUtils'; import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'; import {delay} from 'bluebird'; -import * as bodyParser from 'body-parser'; import {assert} from 'chai'; +import * as express from 'express'; import FormData from 'form-data'; import * as fse from 'fs-extra'; import * as _ from 'lodash'; @@ -3786,7 +3786,7 @@ function testDocApi() { // TODO test retries on failure and slowness in a new test serving = await serveSomething(app => { - app.use(bodyParser.json()); + app.use(express.json()); app.post('/200', ({body}, res) => { successCalled.emit(body[0].A); res.sendStatus(200); diff --git a/test/server/lib/ManyFetches.ts b/test/server/lib/ManyFetches.ts index 11a6f7c5c5e..aa6bb69680c 100644 --- a/test/server/lib/ManyFetches.ts +++ b/test/server/lib/ManyFetches.ts @@ -14,7 +14,7 @@ import fetch from 'node-fetch'; import WebSocket from 'ws'; describe('ManyFetches', function() { - this.timeout(30000); + this.timeout(40000); setTmpLogLevel('warn'); // Set to 'info' to see what heap size actually is. let oldEnv: EnvironmentSnapshot; diff --git a/test/server/lib/Telemetry.ts b/test/server/lib/Telemetry.ts index b9644697d47..08991e3446c 100644 --- a/test/server/lib/Telemetry.ts +++ b/test/server/lib/Telemetry.ts @@ -8,12 +8,24 @@ import {assert} from 'chai'; import * as sinon from 'sinon'; import {TestServer} from 'test/gen-server/apiUtils'; import {configForUser} from 'test/gen-server/testUtils'; +import * as testUtils from 'test/server/testUtils'; const chimpy = configForUser('Chimpy'); const kiwi = configForUser('Kiwi'); const anon = configForUser('Anonymous'); describe('Telemetry', function() { + let oldEnv: testUtils.EnvironmentSnapshot; + + before(async function() { + oldEnv = new testUtils.EnvironmentSnapshot(); + process.env.TYPEORM_DATABASE = ':memory:'; + }); + + after(function() { + oldEnv.restore(); + }); + const variants: [GristDeploymentType, TelemetryLevel, PrefSource][] = [ ['saas', 'off', 'environment-variable'], ['saas', 'limited', 'environment-variable'], diff --git a/test/server/lib/Webhooks-Proxy.ts b/test/server/lib/Webhooks-Proxy.ts index 7ad895b1eee..d8c45cc8866 100644 --- a/test/server/lib/Webhooks-Proxy.ts +++ b/test/server/lib/Webhooks-Proxy.ts @@ -1,8 +1,8 @@ import {UserAPIImpl} from 'app/common/UserAPI'; import {WebhookSubscription} from 'app/server/lib/DocApi'; import axios from 'axios'; -import * as bodyParser from 'body-parser'; import {assert} from 'chai'; +import * as express from 'express'; import {tmpdir} from 'os'; import * as path from 'path'; import {createClient} from 'redis'; @@ -218,7 +218,7 @@ describe('Webhooks-Proxy', function () { this.timeout(30000); serving = await serveSomething(app => { - app.use(bodyParser.json()); + app.use(express.json()); app.post('/200', ({body}, res) => { successCalled.emit(body[0].A); res.sendStatus(200); diff --git a/test/server/lib/helpers/TestProxyServer.ts b/test/server/lib/helpers/TestProxyServer.ts index c5cd472a753..d5d171dc629 100644 --- a/test/server/lib/helpers/TestProxyServer.ts +++ b/test/server/lib/helpers/TestProxyServer.ts @@ -1,6 +1,5 @@ import {serveSomething, Serving} from "test/server/customUtil"; -import * as bodyParser from "body-parser"; -import {Request, Response} from "express-serve-static-core"; +import * as express from "express"; import axios from "axios"; export class TestProxyServer { @@ -27,8 +26,8 @@ export class TestProxyServer { private async _prepare(portNumber: number) { this._proxyServing = await serveSomething(app => { - app.use(bodyParser.json()); - app.all('*', async (req: Request, res: Response) => { + app.use(express.json()); + app.all('*', async (req: express.Request, res: express.Response) => { this._proxyCallsCounter += 1; let responseCode; try { diff --git a/test/split-tests.js b/test/split-tests.js index 144aa263bb5..2d355eb2931 100644 --- a/test/split-tests.js +++ b/test/split-tests.js @@ -1,6 +1,6 @@ /** * This module handles splitting tests for parallelizing them. This module is imported by any run - * of mocha, due by being listed in test/mocha.opts. + * of mocha, due by being listed in package.json. * * It only does anything if TEST_SPLITS is set, which must have the form "3-of-8". * diff --git a/yarn.lock b/yarn.lock index 158b1b93a08..ddde09e2e55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -505,11 +505,6 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^4.0.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - "@sinonjs/commons@^1", "@sinonjs/commons@^1.2.0", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.7.0": version "1.8.3" resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz" @@ -556,13 +551,6 @@ dependencies: defer-to-connect "^1.0.1" -"@szmarczak/http-timer@^4.0.5": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== - dependencies: - defer-to-connect "^2.0.0" - "@tokenizer/token@^0.3.0": version "0.3.0" resolved "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz" @@ -604,16 +592,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" - integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "^3.1.4" - "@types/node" "*" - "@types/responselike" "^1.0.0" - "@types/chai-as-promised@7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.0.tgz" @@ -631,11 +609,6 @@ resolved "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz" integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - "@types/connect@*": version "3.4.33" resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz" @@ -696,22 +669,24 @@ resolved "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== -"@types/express-serve-static-core@*": - version "4.17.7" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz" - integrity sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw== +"@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" + "@types/send" "*" -"@types/express@4.16.0": - version "4.16.0" - resolved "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz" - integrity sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w== +"@types/express@4.17.17": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== dependencies: "@types/body-parser" "*" - "@types/express-serve-static-core" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" "@types/serve-static" "*" "@types/form-data@2.2.1": @@ -728,10 +703,10 @@ dependencies: "@types/node" "*" -"@types/http-cache-semantics@*": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" - integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== "@types/http-proxy@1.17.9": version "1.17.9" @@ -792,13 +767,6 @@ dependencies: "@types/node" "*" -"@types/keyv@^3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" - integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== - dependencies: - "@types/node" "*" - "@types/lodash@4.14.117": version "4.14.117" resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.117.tgz" @@ -824,6 +792,11 @@ resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz" integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q== +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/minio@7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/minio/-/minio-7.0.15.tgz#6fbf2e17aeae172cbf181ea52b1faa05a601ce42" @@ -831,10 +804,10 @@ dependencies: "@types/node" "*" -"@types/mocha@5.2.5": - version "5.2.5" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz" - integrity sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww== +"@types/mocha@10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" + integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/moment-timezone@0.5.9": version "0.5.9" @@ -856,10 +829,10 @@ resolved "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz" integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA== -"@types/node@^14": - version "14.18.21" - resolved "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz" - integrity sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q== +"@types/node@18.11.9": + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== "@types/node@^14.0.1": version "14.17.6" @@ -885,6 +858,13 @@ dependencies: "@types/d3" "^3" +"@types/proper-lockfile@4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@types/proper-lockfile/-/proper-lockfile-4.1.2.tgz#49537cee7134055ee13a1833b76a1c298f39bb26" + integrity sha512-kd4LMvcnpYkspDcp7rmXKedn8iJSCoa331zRRamUp5oanKt/CefbEGPQP7G89enz7sKD4bvsr8mHSsC8j5WOvA== + dependencies: + "@types/retry" "*" + "@types/qrcode@1.4.2": version "1.4.2" resolved "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.4.2.tgz" @@ -910,30 +890,39 @@ "@types/bluebird" "*" "@types/events" "*" -"@types/responselike@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" - integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== - dependencies: - "@types/node" "*" +"@types/retry@*": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" + integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== "@types/saml2-js@2.0.1": version "2.0.1" resolved "https://registry.npmjs.org/@types/saml2-js/-/saml2-js-2.0.1.tgz" integrity sha512-Gr7528CgFBXqAoMlxdGjj8s8ihgAIXXvVjoUthjZGHJBz2TDyXMObmDALWnFeudcGilxqha/WpFdWJ+FI6RlWA== -"@types/selenium-webdriver@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.0.0.tgz" - integrity sha512-x/OwFhZaZBkucIl/SuooCmkdu1V6LBfHcBeBV5rj05Co8EenuL1KJiIRUU/Da2hscoqbXyF3QuWDOZZ4sLVA5Q== +"@types/selenium-webdriver@4.1.16": + version "4.1.16" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.1.16.tgz#8438a3027c7905f516f7b2fbf85e7ded3763bc53" + integrity sha512-ETje9rr7nTrD0r/mNnIuCAF7fAZ2xKE/1WyxXZZH9N9Cy2NKJTrpEd7SCdzuIlm/1iu1gjHCVbaDwT+MuDrVZg== + dependencies: + "@types/ws" "*" + +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" "@types/serve-static@*": - version "1.13.3" - resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz" - integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== dependencies: - "@types/express-serve-static-core" "*" + "@types/http-errors" "*" "@types/mime" "*" + "@types/node" "*" "@types/sinon@5.0.5": version "5.0.5" @@ -984,6 +973,13 @@ resolved "https://registry.npmjs.org/@types/which/-/which-2.0.1.tgz" integrity sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ== +"@types/ws@*": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + "@types/ws@^6": version "6.0.4" resolved "https://registry.npmjs.org/@types/ws/-/ws-6.0.4.tgz" @@ -1254,13 +1250,13 @@ accept-language-parser@1.5.0: resolved "https://registry.npmjs.org/accept-language-parser/-/accept-language-parser-1.5.0.tgz" integrity sha1-iHfFQECo3LWeCgfZwf3kIpgzR5E= -accepts@~1.3.5: - version "1.3.7" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" + mime-types "~2.1.34" + negotiator "0.6.3" ace-builds@1.23.3: version "1.23.3" @@ -1369,11 +1365,6 @@ acorn@^8.4.1, acorn@^8.5.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== -adm-zip@0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.9.tgz#b33691028333821c0cf95c31374c5462f2905a83" - integrity sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg== - agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -1430,11 +1421,6 @@ ansi-regex@^4.1.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -1447,21 +1433,13 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - any-base@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz" @@ -1569,7 +1547,7 @@ argparse@^1.0.7: argparse@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-filter@~0.0.0: @@ -1597,23 +1575,11 @@ array-reduce@~0.0.0: resolved "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz" integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - 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.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - arrify@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz" @@ -1650,7 +1616,7 @@ assert@^1.4.0: assertion-error@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== async-mutex@0.2.4: @@ -1717,9 +1683,9 @@ backbone@1.3.3: underscore ">=1.8.3" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.2.0, base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" @@ -1756,9 +1722,9 @@ bignumber.js@^9.0.0: integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz" - integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== binary@~0.3.0: version "0.3.0" @@ -1784,7 +1750,7 @@ block-stream2@^2.0.0: dependencies: readable-stream "^3.4.0" -bluebird@3.7.2, bluebird@^3.3.3, bluebird@^3.5.0: +bluebird@^3.3.3, bluebird@^3.5.0: version "3.7.2" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -1809,21 +1775,23 @@ bn.js@^5.1.1: resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.1.1.tgz" integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA== -body-parser@1.18.3: - version "1.18.3" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz" - integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== dependencies: - bytes "3.0.0" + bytes "3.1.2" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.2" - http-errors "~1.6.3" - iconv-lite "0.4.23" - on-finished "~2.3.0" - qs "6.5.2" - raw-body "2.3.3" - type-is "~1.6.16" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" bootstrap-datepicker@1.9.0: version "1.9.0" @@ -1858,7 +1826,7 @@ boxen@^4.2.0: brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1914,7 +1882,7 @@ browser-resolve@^1.11.0, browser-resolve@^1.7.0: browser-stdout@1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== browserify-aes@^1.0.0, browserify-aes@^1.0.4: @@ -2050,7 +2018,7 @@ browserslist@^4.21.3: node-releases "^2.0.6" update-browserslist-db "^1.0.9" -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= @@ -2111,10 +2079,10 @@ builtin-status-codes@^3.0.0: resolved "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacache@^15.2.0: version "15.3.0" @@ -2140,11 +2108,6 @@ cacache@^15.2.0: tar "^6.0.2" unique-filename "^1.1.1" -cacheable-lookup@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" - integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz" @@ -2158,19 +2121,6 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" - integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" - cached-path-relative@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz" @@ -2249,14 +2199,15 @@ chai@4.2.0: type-detect "^4.0.5" chai@^4.1.2: - version "4.3.4" - resolved "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz" - integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== + version "4.3.8" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.8.tgz#40c59718ad6928da6629c70496fe990b2bb5b17c" + integrity sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ== dependencies: assertion-error "^1.1.0" check-error "^1.0.2" - deep-eql "^3.0.1" + deep-eql "^4.1.2" get-func-name "^2.0.0" + loupe "^2.3.1" pathval "^1.1.1" type-detect "^4.0.5" @@ -2294,7 +2245,7 @@ chalk@^4.0.0: chalk@^4.1.0: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -2307,8 +2258,8 @@ chance@1.0.16: check-error@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== chokidar@3.5.3: version "3.5.3" @@ -2352,17 +2303,6 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^74.0.0: - version "74.0.0" - resolved "https://registry.npmjs.org/chromedriver/-/chromedriver-74.0.0.tgz" - integrity sha512-xXgsq0l4gVTY9X5vuccOSVj/iEBm3Bf5MIwzSAASIRJagt4BlWw77SxQq1f4JAJ35/9Ys4NLMA/kWFbd7A/gfQ== - dependencies: - del "^3.0.0" - extract-zip "^1.6.7" - mkdirp "^0.5.1" - request "^2.88.0" - tcp-port-used "^1.0.1" - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" @@ -2409,7 +2349,7 @@ cliui@^6.0.0: cliui@^7.0.2: version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" @@ -2472,7 +2412,7 @@ collect-js-deps@^0.1.1: color-convert@2.0.1, color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" @@ -2491,7 +2431,7 @@ color-name@1.1.3: color-name@~1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== color-support@^1.1.2, color-support@^1.1.3: @@ -2563,10 +2503,10 @@ compress-commons@^4.1.0: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.6.1, concat-stream@^1.6.2: +concat-stream@^1.6.1: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -2620,10 +2560,12 @@ constants-browserify@~1.0.0: resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" content-type@~1.0.4: version "1.0.4" @@ -2668,11 +2610,16 @@ cookie@0.5.0: resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + crc-32@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz" @@ -2836,14 +2783,14 @@ dayjs@^1.8.34: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz" integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw== -debug@2.6.9, debug@^2.2.0, debug@^2.6.0, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0, debug@^2.6.0: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@4.3.1: +debug@4: version "4.3.1" resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -2891,13 +2838,6 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz" @@ -2905,6 +2845,13 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" @@ -2930,11 +2877,6 @@ defer-to-connect@^1.0.1: resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -defer-to-connect@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - define-properties@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" @@ -2953,18 +2895,6 @@ defined@~0.0.0: resolved "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz" integrity sha1-817qfXBekzuvE7LwOz+D2SFAOz4= -del@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/del/-/del-3.0.0.tgz" - integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= - dependencies: - globby "^6.1.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - p-map "^1.1.1" - pify "^3.0.0" - rimraf "^2.2.8" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" @@ -2980,16 +2910,16 @@ denque@^1.5.0: resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== +depd@2.0.0, depd@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -depd@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - deps-sort@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz" @@ -3008,10 +2938,10 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detect-libc@^2.0.0: version "2.0.1" @@ -3190,7 +3120,7 @@ emoji-regex@^7.0.1: emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emojis-list@^3.0.0: @@ -3410,7 +3340,7 @@ esbuild@^0.14.39: escalade@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-goat@^2.0.0: @@ -3625,39 +3555,40 @@ exit-on-epipe@~1.0.1: resolved "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz" integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== -express@4.16.4: - version "4.16.4" - resolved "https://registry.npmjs.org/express/-/express-4.16.4.tgz" - integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== +express@4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== dependencies: - accepts "~1.3.5" + accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.18.3" - content-disposition "0.5.2" + body-parser "1.20.1" + content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.3.1" + cookie "0.5.0" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.2" + depd "2.0.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.1" + finalhandler "1.2.0" fresh "0.5.2" + http-errors "2.0.0" merge-descriptors "1.0.1" methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.2" + on-finished "2.4.1" + parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.4" - qs "6.5.2" - range-parser "~1.2.0" - safe-buffer "5.1.2" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" utils-merge "1.0.1" vary "~1.1.2" @@ -3666,16 +3597,6 @@ extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -extract-zip@^1.6.7: - version "1.7.0" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz" - integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== - dependencies: - concat-stream "^1.6.2" - debug "^2.6.9" - mkdirp "^0.5.4" - yauzl "^2.10.0" - extsprintf@1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" @@ -3759,13 +3680,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3784,7 +3698,7 @@ file-type@16.5.4: fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" @@ -3794,17 +3708,17 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== -finalhandler@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz" - integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.4.0" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" unpipe "~1.0.0" find-up@5.0.0: @@ -3889,10 +3803,10 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fresh@0.5.2: version "0.5.2" @@ -3924,7 +3838,7 @@ fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^8.0.1: version "8.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: graceful-fs "^4.2.0" @@ -3948,8 +3862,8 @@ fs-mkdirp-stream@^1.0.0: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.1.2: version "2.1.3" @@ -3957,9 +3871,9 @@ fsevents@~2.1.2: integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== fstream@^1.0.12: version "1.0.12" @@ -4029,17 +3943,6 @@ gcp-metadata@^4.2.0: gaxios "^4.0.0" json-bigint "^1.0.0" -geckodriver@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-3.2.0.tgz#6b0a85e2aafbce209bca30e2d53af857707b1034" - integrity sha512-p+qR2RKlI/TQoCEYrSuTaYCLqsJNni96WmEukTyXmOmLn+3FLdgPAEwMZ0sG2Cwi9hozUzGAWyT6zLuhF6cpiQ== - dependencies: - adm-zip "0.5.9" - bluebird "3.7.2" - got "11.8.5" - https-proxy-agent "5.0.1" - tar "6.1.11" - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4057,8 +3960,8 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: get-func-name@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: version "1.1.1" @@ -4142,7 +4045,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@*, glob@^7.0.3, glob@^7.1.0, glob@^7.1.3, glob@^7.1.4: +glob@*, glob@^7.1.0, glob@^7.1.4: version "7.1.6" resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -4166,9 +4069,9 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.6, glob@^7.2.0: +glob@^7.1.1, glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -4217,17 +4120,6 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - globwatcher@~1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/globwatcher/-/globwatcher-1.2.3.tgz" @@ -4279,23 +4171,6 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@11.8.5: - version "11.8.5" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" - integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz" @@ -4323,7 +4198,12 @@ graceful-fs@^4.1.2: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graceful-fs@^4.2.2: version "4.2.6" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -4389,7 +4269,7 @@ has-flag@^3.0.0: has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: @@ -4466,7 +4346,7 @@ hdr-histogram-percentiles-obj@^3.0.0: he@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== highlight.js@10.7.3, highlight.js@^10.7.1: @@ -4505,15 +4385,16 @@ http-cache-semantics@^4.1.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: - version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" http-errors@~1.8.0: version "1.8.0" @@ -4562,14 +4443,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" - integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz" @@ -4605,10 +4478,10 @@ i18n-iso-countries@6.1.0: dependencies: diacritics "1.3.0" -i18next-http-middleware@3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/i18next-http-middleware/-/i18next-http-middleware-3.2.1.tgz" - integrity sha512-zBwXxDChT0YLoTXIR6jRuqnUUhXW0Iw7egoTnNXyaDRtTbfWNXwU0a53ThyuRPQ+k+tXu3ZMNKRzfLuononaRw== +i18next-http-middleware@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/i18next-http-middleware/-/i18next-http-middleware-3.3.2.tgz#6a24fee6bde44952a5af24364d43fa32f6c1b9b6" + integrity sha512-PSeLXQXr9Qiv9Q3GCWCoIJenKVbxCcVsXb7VMp/mOprV4gu+AMJT7VHw4+QEf6oYW6GU31QSLnfDpLNoSMtx3g== i18next-scanner@4.1.0: version "4.1.0" @@ -4650,13 +4523,6 @@ i18next@21.9.1, i18next@^21.0.1: dependencies: "@babel/runtime" "^7.17.2" -iconv-lite@0.4.23: - version "0.4.23" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -4693,8 +4559,8 @@ image-size@0.6.3: immediate@~3.0.5: version "3.0.6" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -4739,8 +4605,8 @@ infer-owner@^1.0.4: inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -4793,11 +4659,6 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -ip-regex@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== - ip@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" @@ -4831,7 +4692,7 @@ is-arguments@^1.0.4: is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" @@ -4869,8 +4730,8 @@ is-core-module@^2.9.0: is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^2.0.0: version "2.0.0" @@ -4879,7 +4740,7 @@ is-fullwidth-code-point@^2.0.0: is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-function@^1.0.7: @@ -4896,20 +4757,13 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - is-installed-globally@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz" @@ -4935,7 +4789,7 @@ is-npm@^4.0.0: is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-obj@^2.0.0: @@ -4943,25 +4797,6 @@ is-obj@^2.0.0: resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" - integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= - -is-path-in-cwd@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz" - integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - is-path-inside@^3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz" @@ -5024,11 +4859,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-url@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz" - integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== - is-utf8@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -5049,15 +4879,6 @@ is-yarn-global@^0.3.0: resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== -is2@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/is2/-/is2-2.0.6.tgz" - integrity sha512-+Z62OHOjA6k2sUDOKXoZI3EXv7Fb1K52jpTBLbkfx62bcUeSsrTBLhEquCRDKTx0XE5XbHcG/S2vrtE3lnEDsQ== - dependencies: - deep-is "^0.1.3" - ip-regex "^4.1.0" - is-url "^1.2.4" - isarray@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" @@ -5065,8 +4886,8 @@ isarray@0.0.1: isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" @@ -5181,11 +5002,6 @@ json-buffer@3.0.0: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - json-parse-even-better-errors@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" @@ -5242,8 +5058,8 @@ json5@^2.2.1: jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== optionalDependencies: graceful-fs "^4.1.6" @@ -5282,7 +5098,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jszip@^3.5.0: +jszip@^3.10.1, jszip@^3.5.0: version "3.10.1" resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== @@ -5338,13 +5154,6 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -keyv@^4.0.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" - integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== - dependencies: - json-buffer "3.0.1" - kind-of@^6.0.2: version "6.0.3" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" @@ -5402,7 +5211,7 @@ levn@~0.3.0: lie@~3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== dependencies: immediate "~3.0.5" @@ -5589,6 +5398,13 @@ lolex@^5.0.1: dependencies: "@sinonjs/commons" "^1.7.0" +loupe@^2.3.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== + dependencies: + get-func-name "^2.0.0" + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" @@ -5724,7 +5540,7 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.46.0" -mime-types@^2.1.14, mime-types@^2.1.27: +mime-types@^2.1.14, mime-types@^2.1.27, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -5738,21 +5554,16 @@ mime-types@~2.1.24: dependencies: mime-db "1.44.0" -mime@1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz" - integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" @@ -5763,7 +5574,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@*, minimatch@^3.0.4: +minimatch@*: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -5785,7 +5596,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -5891,7 +5702,7 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.4: +"mkdirp@>=0.5 0", mkdirp@^0.5.1: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -5903,21 +5714,18 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mocha-webdriver@0.2.13: - version "0.2.13" - resolved "https://registry.yarnpkg.com/mocha-webdriver/-/mocha-webdriver-0.2.13.tgz#6e39360e08dc32e2de7375c6eaee83bd6aa98cc6" - integrity sha512-xSQ9fTViIucIZs+loRzKhOkUtztMheHYRg2+CrgqBPg9/MYjOWbcUk+uye5r117BN/r57KRuZxvsZRH0Jm0gCg== +mocha-webdriver@./mocha-webdriver-0.3.2.tgz: + version "0.3.2" + resolved "./mocha-webdriver-0.3.2.tgz#ee2561f9f8c17a00c140164bef6fe0714ee36260" dependencies: chai "^4.1.2" chai-as-promised "^7.1.1" - chromedriver "^74.0.0" fs-extra "^8.0.1" - geckodriver "^3.2.0" - mocha "^10.1.0" + mocha "^10.2.0" npm-run-path "^3.1.0" - selenium-webdriver "^4.0.0-alpha.1" + selenium-webdriver "^4.12.0" -mocha@10.2.0, mocha@^10.1.0: +mocha@10.2.0, mocha@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== @@ -6012,7 +5820,7 @@ ms@2.0.0: ms@2.1.2, ms@^2.1.1: version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== ms@2.1.3, ms@^2.0.0: @@ -6048,12 +5856,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -negotiator@^0.6.2: +negotiator@0.6.3, negotiator@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -6196,7 +5999,7 @@ normalize-path@^2.1.1: normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^4.1.0: @@ -6204,11 +6007,6 @@ normalize-url@^4.1.0: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - now-and-later@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c" @@ -6218,7 +6016,7 @@ now-and-later@^2.0.0: npm-run-path@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== dependencies: path-key "^3.0.0" @@ -6278,6 +6076,13 @@ object.assign@^4.0.4: has-symbols "^1.0.3" object-keys "^1.1.1" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" @@ -6292,8 +6097,8 @@ on-headers@~1.0.1, on-headers@~1.0.2: once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -6352,11 +6157,6 @@ p-cancelable@^1.0.0: resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" @@ -6385,11 +6185,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz" - integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== - p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -6472,7 +6267,7 @@ parse5@^5.1.1: resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== -parseurl@~1.3.2, parseurl@~1.3.3: +parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -6489,18 +6284,13 @@ path-dirname@^1.0.0: path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" @@ -6555,11 +6345,6 @@ peek-readable@^4.1.0: resolved "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz" integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" @@ -6621,38 +6406,11 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - piscina@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/piscina/-/piscina-3.2.0.tgz#f5a1dde0c05567775690cccefe59d9223924d154" @@ -6744,7 +6502,7 @@ printj@~1.1.0: process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process-nextick-args@~1.0.6: @@ -6770,12 +6528,21 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -proxy-addr@~2.0.4: - version "2.0.6" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== +proper-lockfile@4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" psl@^1.1.28: @@ -6867,10 +6634,12 @@ qrcode@1.5.0: pngjs "^5.0.0" yargs "^15.3.1" -qs@6.5.2, qs@~6.5.2: - version "6.5.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" qs@^6.7.0: version "6.10.1" @@ -6879,6 +6648,11 @@ qs@^6.7.0: dependencies: side-channel "^1.0.4" +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + query-string@^7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" @@ -6909,11 +6683,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz" @@ -6939,19 +6708,19 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@~1.2.0: +range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz" - integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: - bytes "3.0.0" - http-errors "1.6.3" - iconv-lite "0.4.23" + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" unpipe "1.0.0" rc@^1.2.8: @@ -6980,7 +6749,7 @@ read-only-stream@^2.0.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -7005,6 +6774,19 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readable-web-to-node-stream@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz" @@ -7165,7 +6947,7 @@ request-promise-native@^1.0.9: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.0, request@^2.88.2: +request@^2.88.2: version "2.88.2" resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7193,8 +6975,8 @@ request@^2.88.0, request@^2.88.2: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-main-filename@^2.0.0: version "2.0.0" @@ -7206,11 +6988,6 @@ requires-port@^1.0.0: resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -resolve-alpn@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" - integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" @@ -7269,13 +7046,6 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -responselike@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" - integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== - dependencies: - lowercase-keys "^2.0.0" - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -7286,7 +7056,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2, rimraf@^2.2.8, rimraf@^2.7.1: +rimraf@2: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -7317,7 +7087,7 @@ run-parallel@^1.1.9: safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-buffer@5.2.0: @@ -7370,15 +7140,14 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -selenium-webdriver@^4.0.0-alpha.1: - version "4.0.0-beta.2" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-beta.2.tgz" - integrity sha512-uuNl3T1JjhrXCO4UAAy+iIIgZ/PqgYNiYvy+yfWCY+x2vHH9y7tIdD9a/q1rwbf/5jD/ENwYlVuNj46uIngknA== +selenium-webdriver@^4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.12.0.tgz#a8dc8ecf129a2414c2ace6e429aba84722a950a5" + integrity sha512-zvPzmTsky6WfO6+BGMj2mCJsw7qKnfQONur2b+pGn8jeTiC+WAUOthZOnaK+HkX5wiU6L4uoMF+JIcOVstp25A== dependencies: - jszip "^3.5.0" - rimraf "^2.7.1" + jszip "^3.10.1" tmp "^0.2.1" - ws "^7.3.1" + ws ">=8.13.0" semver-diff@^3.1.1: version "3.1.1" @@ -7404,24 +7173,24 @@ semver@^7.3.5, semver@^7.3.7: dependencies: lru-cache "^6.0.0" -send@0.16.2: - version "0.16.2" - resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz" - integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== dependencies: debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" + depd "2.0.0" + destroy "1.2.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" serialize-javascript@6.0.0, serialize-javascript@^6.0.0: version "6.0.0" @@ -7430,15 +7199,15 @@ serialize-javascript@6.0.0, serialize-javascript@^6.0.0: dependencies: randombytes "^2.1.0" -serve-static@1.13.2: - version "1.13.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz" - integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.2" + parseurl "~1.3.3" + send "0.18.0" set-blocking@^2.0.0: version "2.0.0" @@ -7450,11 +7219,6 @@ setimmediate@^1.0.5, setimmediate@~1.0.4: resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" @@ -7684,16 +7448,16 @@ stackback@0.0.2: resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz" integrity sha1-Gsig2Ug4SNFpXkGLbQMaPDzmjjs= -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.5.0 < 2": version "1.5.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== - stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz" @@ -7756,7 +7520,7 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7774,7 +7538,7 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.0.0, string-width@^4.1.0: +string-width@^4.0.0: version "4.2.0" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -7783,15 +7547,6 @@ string-width@^4.0.0, string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -7813,7 +7568,7 @@ string_decoder@~1.0.0: string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" @@ -7825,14 +7580,7 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-ansi@^6.0.1: +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7884,9 +7632,9 @@ supports-color@^5.3.0, supports-color@^5.5.0: has-flag "^3.0.0" supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" @@ -7923,18 +7671,6 @@ tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@6.1.11: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: version "6.1.13" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" @@ -7947,14 +7683,6 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -tcp-port-used@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz" - integrity sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA== - dependencies: - debug "4.3.1" - is2 "^2.0.6" - term-size@^2.1.0: version "2.2.0" resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz" @@ -8095,7 +7823,7 @@ to-readable-stream@^1.0.0: to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" @@ -8112,6 +7840,11 @@ toidentifier@1.0.0: resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + token-types@^4.1.1: version "4.2.1" resolved "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz" @@ -8237,7 +7970,7 @@ type-check@~0.3.2: type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.20.2: @@ -8250,9 +7983,9 @@ type-fest@^0.8.1: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.16: +type-is@~1.6.18: version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -8379,7 +8112,7 @@ unique-string@^2.0.0: universalify@^0.1.0: version "0.1.2" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^0.2.0: @@ -8839,7 +8572,7 @@ wrap-ansi@^6.2.0: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -8848,8 +8581,8 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^3.0.0: version "3.0.3" @@ -8866,10 +8599,10 @@ ws@8.13.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== -ws@^7.3.1: - version "7.4.4" - resolved "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz" - integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw== +ws@>=8.13.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.1.tgz#4b9586b4f70f9e6534c7bb1d3dc0baa8b8cf01e0" + integrity sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A== ws@^7.4.4: version "7.5.9" @@ -8966,9 +8699,9 @@ y18n@^4.0.0: integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: - version "5.0.5" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz" - integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" @@ -8994,9 +8727,9 @@ yargs-parser@^18.1.2: decamelize "^1.2.0" yargs-parser@^20.2.2: - version "20.2.7" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs-parser@^21.0.0: version "21.1.1" @@ -9056,14 +8789,6 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.0.0" -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"