>>1,Un=[["ary",dn],["bind",sn],["bindKey",hn],["curry",_n],["curryRight",vn],["flip",wn],["partial",gn],["partialRight",yn],["rearg",bn]],Bn="[object Arguments]",Tn="[object Array]",$n="[object AsyncFunction]",Dn="[object Boolean]",Mn="[object Date]",Fn="[object DOMException]",Nn="[object Error]",Pn="[object Function]",qn="[object GeneratorFunction]",Zn="[object Map]",Kn="[object Number]",Vn="[object Null]",Gn="[object Object]",Hn="[object Promise]",Jn="[object Proxy]",Yn="[object RegExp]",Qn="[object Set]",Xn="[object String]",nt="[object Symbol]",tt="[object Undefined]",rt="[object WeakMap]",et="[object WeakSet]",ut="[object ArrayBuffer]",it="[object DataView]",ot="[object Float32Array]",ft="[object Float64Array]",ct="[object Int8Array]",at="[object Int16Array]",lt="[object Int32Array]",st="[object Uint8Array]",ht="[object Uint8ClampedArray]",pt="[object Uint16Array]",_t="[object Uint32Array]",vt=/\b__p \+= '';/g,gt=/\b(__p \+=) '' \+/g,yt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,dt=/&(?:amp|lt|gt|quot|#39);/g,bt=/[&<>"']/g,wt=RegExp(dt.source),mt=RegExp(bt.source),xt=/<%-([\s\S]+?)%>/g,jt=/<%([\s\S]+?)%>/g,At=/<%=([\s\S]+?)%>/g,kt=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Ot=/^\w*$/,It=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Rt=/[\\^$.*+?()[\]{}|]/g,zt=RegExp(Rt.source),Et=/^\s+|\s+$/g,St=/^\s+/,Wt=/\s+$/,Lt=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Ct=/\{\n\/\* \[wrapped with (.+)\] \*/,Ut=/,? & /,Bt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Tt=/\\(\\)?/g,$t=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Dt=/\w*$/,Mt=/^[-+]0x[0-9a-f]+$/i,Ft=/^0b[01]+$/i,Nt=/^\[object .+?Constructor\]$/,Pt=/^0o[0-7]+$/i,qt=/^(?:0|[1-9]\d*)$/,Zt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Kt=/($^)/,Vt=/['\n\r\u2028\u2029\\]/g,Gt="\\ud800-\\udfff",Ht="\\u0300-\\u036f",Jt="\\ufe20-\\ufe2f",Yt="\\u20d0-\\u20ff",Qt=Ht+Jt+Yt,Xt="\\u2700-\\u27bf",nr="a-z\\xdf-\\xf6\\xf8-\\xff",tr="\\xac\\xb1\\xd7\\xf7",rr="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",er="\\u2000-\\u206f",ur=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",ir="A-Z\\xc0-\\xd6\\xd8-\\xde",or="\\ufe0e\\ufe0f",fr=tr+rr+er+ur,cr="['\u2019]",ar="["+Gt+"]",lr="["+fr+"]",sr="["+Qt+"]",hr="\\d+",pr="["+Xt+"]",_r="["+nr+"]",vr="[^"+Gt+fr+hr+Xt+nr+ir+"]",gr="\\ud83c[\\udffb-\\udfff]",yr="(?:"+sr+"|"+gr+")",dr="[^"+Gt+"]",br="(?:\\ud83c[\\udde6-\\uddff]){2}",wr="[\\ud800-\\udbff][\\udc00-\\udfff]",mr="["+ir+"]",xr="\\u200d",jr="(?:"+_r+"|"+vr+")",Ar="(?:"+mr+"|"+vr+")",kr="(?:"+cr+"(?:d|ll|m|re|s|t|ve))?",Or="(?:"+cr+"(?:D|LL|M|RE|S|T|VE))?",Ir=yr+"?",Rr="["+or+"]?",zr="(?:"+xr+"(?:"+[dr,br,wr].join("|")+")"+Rr+Ir+")*",Er="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Sr="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",Wr=Rr+Ir+zr,Lr="(?:"+[pr,br,wr].join("|")+")"+Wr,Cr="(?:"+[dr+sr+"?",sr,br,wr,ar].join("|")+")",Ur=RegExp(cr,"g"),Br=RegExp(sr,"g"),Tr=RegExp(gr+"(?="+gr+")|"+Cr+Wr,"g"),$r=RegExp([mr+"?"+_r+"+"+kr+"(?="+[lr,mr,"$"].join("|")+")",Ar+"+"+Or+"(?="+[lr,mr+jr,"$"].join("|")+")",mr+"?"+jr+"+"+kr,mr+"+"+Or,Sr,Er,hr,Lr].join("|"),"g"),Dr=RegExp("["+xr+Gt+Qt+or+"]"),Mr=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Fr=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Nr=-1,Pr={};
+Pr[ot]=Pr[ft]=Pr[ct]=Pr[at]=Pr[lt]=Pr[st]=Pr[ht]=Pr[pt]=Pr[_t]=!0,Pr[Bn]=Pr[Tn]=Pr[ut]=Pr[Dn]=Pr[it]=Pr[Mn]=Pr[Nn]=Pr[Pn]=Pr[Zn]=Pr[Kn]=Pr[Gn]=Pr[Yn]=Pr[Qn]=Pr[Xn]=Pr[rt]=!1;var qr={};qr[Bn]=qr[Tn]=qr[ut]=qr[it]=qr[Dn]=qr[Mn]=qr[ot]=qr[ft]=qr[ct]=qr[at]=qr[lt]=qr[Zn]=qr[Kn]=qr[Gn]=qr[Yn]=qr[Qn]=qr[Xn]=qr[nt]=qr[st]=qr[ht]=qr[pt]=qr[_t]=!0,qr[Nn]=qr[Pn]=qr[rt]=!1;var Zr={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a",
+"\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae",
+"\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g",
+"\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O",
+"\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w",
+"\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"},Kr={"&":"&","<":"<",">":">",'"':""","'":"'"},Vr={"&":"&","<":"<",">":">",""":'"',"'":"'"},Gr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Hr=parseFloat,Jr=parseInt,Yr="object"==typeof global&&global&&global.Object===Object&&global,Qr="object"==typeof self&&self&&self.Object===Object&&self,Xr=Yr||Qr||Function("return this")(),ne="object"==typeof exports&&exports&&!exports.nodeType&&exports,te=ne&&"object"==typeof module&&module&&!module.nodeType&&module,re=te&&te.exports===ne,ee=re&&Yr.process,ue=function(){
+try{var n=te&&te.require&&te.require("util").types;return n?n:ee&&ee.binding&&ee.binding("util")}catch(n){}}(),ie=ue&&ue.isArrayBuffer,oe=ue&&ue.isDate,fe=ue&&ue.isMap,ce=ue&&ue.isRegExp,ae=ue&&ue.isSet,le=ue&&ue.isTypedArray,se=m("length"),he=x(Zr),pe=x(Kr),_e=x(Vr),ve=function p(x){function q(n){if(oc(n)&&!yh(n)&&!(n instanceof Bt)){if(n instanceof H)return n;if(yl.call(n,"__wrapped__"))return to(n)}return new H(n)}function G(){}function H(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,
+this.__index__=0,this.__values__=Y}function Bt(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=Wn,this.__views__=[]}function Gt(){var n=new Bt(this.__wrapped__);return n.__actions__=Uu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Uu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Uu(this.__views__),n}function Ht(){if(this.__filtered__){var n=new Bt(this);n.__dir__=-1,
+n.__filtered__=!0}else n=this.clone(),n.__dir__*=-1;return n}function Jt(){var n=this.__wrapped__.value(),t=this.__dir__,r=yh(n),e=t<0,u=r?n.length:0,i=Ai(0,u,this.__views__),o=i.start,f=i.end,c=f-o,a=e?f:o-1,l=this.__iteratees__,s=l.length,h=0,p=Vl(c,this.__takeCount__);if(!r||!e&&u==c&&p==c)return du(n,this.__actions__);var _=[];n:for(;c--&&h-1}function cr(n,t){var r=this.__data__,e=Er(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this}function ar(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Dr(n,t,e,u,i,o){var f,c=t&on,a=t&fn,l=t&cn;if(e&&(f=i?e(n,u,i,o):e(n)),f!==Y)return f;if(!ic(n))return n;var s=yh(n);if(s){if(f=Ii(n),!c)return Uu(n,f)}else{var h=Is(n),p=h==Pn||h==qn;if(bh(n))return ku(n,c);if(h==Gn||h==Bn||p&&!i){if(f=a||p?{}:Ri(n),!c)return a?$u(n,Lr(f,n)):Tu(n,Wr(f,n))}else{if(!qr[h])return i?n:{};f=zi(n,h,c)}}o||(o=new dr);var _=o.get(n);if(_)return _;o.set(n,f),jh(n)?n.forEach(function(r){f.add(Dr(r,t,e,r,n,o))}):mh(n)&&n.forEach(function(r,u){
+f.set(u,Dr(r,t,e,u,n,o))});var v=l?a?gi:vi:a?Nc:Fc,g=s?Y:v(n);return r(g||n,function(r,u){g&&(u=r,r=n[u]),zr(f,u,Dr(r,t,e,u,n,o))}),f}function Mr(n){var t=Fc(n);return function(r){return Zr(r,n,t)}}function Zr(n,t,r){var e=r.length;if(null==n)return!e;for(n=cl(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===Y&&!(u in n)||!i(o))return!1}return!0}function Kr(n,t,r){if("function"!=typeof n)throw new sl(tn);return Es(function(){n.apply(Y,r)},t)}function Vr(n,t,r,e){var u=-1,i=o,a=!0,l=n.length,s=[],h=t.length;
+if(!l)return s;r&&(t=c(t,R(r))),e?(i=f,a=!1):t.length>=X&&(i=E,a=!1,t=new vr(t));n:for(;++uu?0:u+r),
+e=e===Y||e>u?u:jc(e),e<0&&(e+=u),e=r>e?0:Ac(e);r0&&r(f)?t>1?te(f,t-1,r,e,u):a(u,f):e||(u[u.length]=f)}return u}function ee(n,t){return n&&ys(n,t,Fc)}function ue(n,t){return n&&ds(n,t,Fc)}function se(n,t){return i(t,function(t){return rc(n[t])})}function ve(n,t){t=ju(t,n);for(var r=0,e=t.length;null!=n&&rt}function we(n,t){return null!=n&&yl.call(n,t)}function me(n,t){return null!=n&&t in cl(n)}function xe(n,t,r){return n>=Vl(t,r)&&n=120&&p.length>=120)?new vr(a&&p):Y}p=n[0];
+var _=-1,v=l[0];n:for(;++_-1;)f!==n&&Sl.call(f,a,1),Sl.call(n,a,1);return n}function Qe(n,t){for(var r=n?t.length:0,e=r-1;r--;){
+var u=t[r];if(r==e||u!==i){var i=u;Wi(u)?Sl.call(n,u,1):vu(n,u)}}return n}function Xe(n,t){return n+Ml(Jl()*(t-n+1))}function nu(n,t,r,e){for(var u=-1,i=Kl(Dl((t-n)/(r||1)),0),o=el(i);i--;)o[e?i:++u]=n,n+=r;return o}function tu(n,t){var r="";if(!n||t<1||t>zn)return r;do t%2&&(r+=n),t=Ml(t/2),t&&(n+=n);while(t);return r}function ru(n,t){return Ss(Zi(n,t,Sa),n+"")}function eu(n){return kr(na(n))}function uu(n,t){var r=na(n);return Yi(r,$r(t,0,r.length))}function iu(n,t,r,e){if(!ic(n))return n;t=ju(t,n);
+for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++uu?0:u+t),r=r>u?u:r,r<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var i=el(u);++e>>1,o=n[i];null!==o&&!yc(o)&&(r?o<=t:o=X){var s=t?null:js(n);if(s)return N(s);c=!1,u=E,l=new vr}else l=t?[]:a;n:for(;++e=e?n:fu(n,t,r)}function ku(n,t){if(t)return n.slice();var r=n.length,e=Il?Il(r):new n.constructor(r);
+return n.copy(e),e}function Ou(n){var t=new n.constructor(n.byteLength);return new Ol(t).set(new Ol(n)),t}function Iu(n,t){return new n.constructor(t?Ou(n.buffer):n.buffer,n.byteOffset,n.byteLength)}function Ru(n){var t=new n.constructor(n.source,Dt.exec(n));return t.lastIndex=n.lastIndex,t}function zu(n){return hs?cl(hs.call(n)):{}}function Eu(n,t){return new n.constructor(t?Ou(n.buffer):n.buffer,n.byteOffset,n.length)}function Su(n,t){if(n!==t){var r=n!==Y,e=null===n,u=n===n,i=yc(n),o=t!==Y,f=null===t,c=t===t,a=yc(t);
+if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n=f)return c;return c*("desc"==r[e]?-1:1)}}return n.index-t.index}function Lu(n,t,r,e){for(var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Kl(i-o,0),l=el(c+a),s=!e;++f1?r[u-1]:Y,o=u>2?r[2]:Y;for(i=n.length>3&&"function"==typeof i?(u--,i):Y,o&&Li(r[0],r[1],o)&&(i=u<3?Y:i,u=1),t=cl(t);++e-1?u[i?t[o]:o]:Y}}function Hu(n){return _i(function(t){var r=t.length,e=r,u=H.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if("function"!=typeof i)throw new sl(tn);if(u&&!o&&"wrapper"==yi(i))var o=new H([],!0)}for(e=o?e:r;++e1&&d.reverse(),s&&cf))return!1;var a=i.get(n),l=i.get(t);if(a&&l)return a==t&&l==n;var s=-1,p=!0,_=r&ln?new vr:Y;for(i.set(n,t),i.set(t,n);++s1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(Lt,"{\n/* [wrapped with "+t+"] */\n")}function Si(n){return yh(n)||gh(n)||!!(Wl&&n&&n[Wl])}function Wi(n,t){var r=typeof n;
+return t=null==t?zn:t,!!t&&("number"==r||"symbol"!=r&&qt.test(n))&&n>-1&&n%1==0&&n0){if(++t>=jn)return arguments[0]}else t=0;
+return n.apply(Y,arguments)}}function Yi(n,t){var r=-1,e=n.length,u=e-1;for(t=t===Y?e:t;++r=this.__values__.length;return{done:n,value:n?Y:this.__values__[this.__index__++]}}function rf(){return this}function ef(n){for(var t,r=this;r instanceof G;){var e=to(r);e.__index__=0,e.__values__=Y,t?u.__wrapped__=e:t=e;var u=e;r=r.__wrapped__}return u.__wrapped__=n,t}function uf(){var n=this.__wrapped__;if(n instanceof Bt){var t=n;return this.__actions__.length&&(t=new Bt(this)),t=t.reverse(),t.__actions__.push({func:Qo,args:[Ro],thisArg:Y}),new H(t,this.__chain__)}return this.thru(Ro);
+}function of(){return du(this.__wrapped__,this.__actions__)}function ff(n,t,r){var e=yh(n)?u:Gr;return r&&Li(n,t,r)&&(t=Y),e(n,bi(t,3))}function cf(n,t){return(yh(n)?i:ne)(n,bi(t,3))}function af(n,t){return te(vf(n,t),1)}function lf(n,t){return te(vf(n,t),Rn)}function sf(n,t,r){return r=r===Y?1:jc(r),te(vf(n,t),r)}function hf(n,t){return(yh(n)?r:vs)(n,bi(t,3))}function pf(n,t){return(yh(n)?e:gs)(n,bi(t,3))}function _f(n,t,r,e){n=Vf(n)?n:na(n),r=r&&!e?jc(r):0;var u=n.length;return r<0&&(r=Kl(u+r,0)),
+gc(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&y(n,t,r)>-1}function vf(n,t){return(yh(n)?c:Fe)(n,bi(t,3))}function gf(n,t,r,e){return null==n?[]:(yh(t)||(t=null==t?[]:[t]),r=e?Y:r,yh(r)||(r=null==r?[]:[r]),Ve(n,t,r))}function yf(n,t,r){var e=yh(n)?l:j,u=arguments.length<3;return e(n,bi(t,4),r,u,vs)}function df(n,t,r){var e=yh(n)?s:j,u=arguments.length<3;return e(n,bi(t,4),r,u,gs)}function bf(n,t){return(yh(n)?i:ne)(n,Lf(bi(t,3)))}function wf(n){return(yh(n)?kr:eu)(n)}function mf(n,t,r){return t=(r?Li(n,t,r):t===Y)?1:jc(t),
+(yh(n)?Or:uu)(n,t)}function xf(n){return(yh(n)?Ir:ou)(n)}function jf(n){if(null==n)return 0;if(Vf(n))return gc(n)?K(n):n.length;var t=Is(n);return t==Zn||t==Qn?n.size:$e(n).length}function Af(n,t,r){var e=yh(n)?h:cu;return r&&Li(n,t,r)&&(t=Y),e(n,bi(t,3))}function kf(n,t){if("function"!=typeof t)throw new sl(tn);return n=jc(n),function(){if(--n<1)return t.apply(this,arguments)}}function Of(n,t,r){return t=r?Y:t,t=n&&null==t?n.length:t,fi(n,dn,Y,Y,Y,Y,t)}function If(n,t){var r;if("function"!=typeof t)throw new sl(tn);
+return n=jc(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=Y),r}}function Rf(n,t,r){t=r?Y:t;var e=fi(n,_n,Y,Y,Y,Y,Y,t);return e.placeholder=Rf.placeholder,e}function zf(n,t,r){t=r?Y:t;var e=fi(n,vn,Y,Y,Y,Y,Y,t);return e.placeholder=zf.placeholder,e}function Ef(n,t,r){function e(t){var r=h,e=p;return h=p=Y,d=t,v=n.apply(e,r)}function u(n){return d=n,g=Es(f,t),b?e(n):v}function i(n){var r=n-y,e=n-d,u=t-r;return w?Vl(u,_-e):u}function o(n){var r=n-y,e=n-d;return y===Y||r>=t||r<0||w&&e>=_;
+}function f(){var n=ih();return o(n)?c(n):(g=Es(f,i(n)),Y)}function c(n){return g=Y,m&&h?e(n):(h=p=Y,v)}function a(){g!==Y&&xs(g),d=0,h=y=p=g=Y}function l(){return g===Y?v:c(ih())}function s(){var n=ih(),r=o(n);if(h=arguments,p=this,y=n,r){if(g===Y)return u(y);if(w)return xs(g),g=Es(f,t),e(y)}return g===Y&&(g=Es(f,t)),v}var h,p,_,v,g,y,d=0,b=!1,w=!1,m=!0;if("function"!=typeof n)throw new sl(tn);return t=kc(t)||0,ic(r)&&(b=!!r.leading,w="maxWait"in r,_=w?Kl(kc(r.maxWait)||0,t):_,m="trailing"in r?!!r.trailing:m),
+s.cancel=a,s.flush=l,s}function Sf(n){return fi(n,wn)}function Wf(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new sl(tn);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Wf.Cache||ar),r}function Lf(n){if("function"!=typeof n)throw new sl(tn);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:
+return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function Cf(n){return If(2,n)}function Uf(n,t){if("function"!=typeof n)throw new sl(tn);return t=t===Y?t:jc(t),ru(n,t)}function Bf(t,r){if("function"!=typeof t)throw new sl(tn);return r=null==r?0:Kl(jc(r),0),ru(function(e){var u=e[r],i=Au(e,0,r);return u&&a(i,u),n(t,this,i)})}function Tf(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new sl(tn);return ic(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),
+Ef(n,t,{leading:e,maxWait:t,trailing:u})}function $f(n){return Of(n,1)}function Df(n,t){return sh(xu(t),n)}function Mf(){if(!arguments.length)return[];var n=arguments[0];return yh(n)?n:[n]}function Ff(n){return Dr(n,cn)}function Nf(n,t){return t="function"==typeof t?t:Y,Dr(n,cn,t)}function Pf(n){return Dr(n,on|cn)}function qf(n,t){return t="function"==typeof t?t:Y,Dr(n,on|cn,t)}function Zf(n,t){return null==t||Zr(n,t,Fc(t))}function Kf(n,t){return n===t||n!==n&&t!==t}function Vf(n){return null!=n&&uc(n.length)&&!rc(n);
+}function Gf(n){return oc(n)&&Vf(n)}function Hf(n){return n===!0||n===!1||oc(n)&&de(n)==Dn}function Jf(n){return oc(n)&&1===n.nodeType&&!_c(n)}function Yf(n){if(null==n)return!0;if(Vf(n)&&(yh(n)||"string"==typeof n||"function"==typeof n.splice||bh(n)||Ah(n)||gh(n)))return!n.length;var t=Is(n);if(t==Zn||t==Qn)return!n.size;if($i(n))return!$e(n).length;for(var r in n)if(yl.call(n,r))return!1;return!0}function Qf(n,t){return ze(n,t)}function Xf(n,t,r){r="function"==typeof r?r:Y;var e=r?r(n,t):Y;return e===Y?ze(n,t,Y,r):!!e;
+}function nc(n){if(!oc(n))return!1;var t=de(n);return t==Nn||t==Fn||"string"==typeof n.message&&"string"==typeof n.name&&!_c(n)}function tc(n){return"number"==typeof n&&Pl(n)}function rc(n){if(!ic(n))return!1;var t=de(n);return t==Pn||t==qn||t==$n||t==Jn}function ec(n){return"number"==typeof n&&n==jc(n)}function uc(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=zn}function ic(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function oc(n){return null!=n&&"object"==typeof n}function fc(n,t){
+return n===t||We(n,t,mi(t))}function cc(n,t,r){return r="function"==typeof r?r:Y,We(n,t,mi(t),r)}function ac(n){return pc(n)&&n!=+n}function lc(n){if(Rs(n))throw new il(nn);return Le(n)}function sc(n){return null===n}function hc(n){return null==n}function pc(n){return"number"==typeof n||oc(n)&&de(n)==Kn}function _c(n){if(!oc(n)||de(n)!=Gn)return!1;var t=Rl(n);if(null===t)return!0;var r=yl.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&gl.call(r)==ml}function vc(n){
+return ec(n)&&n>=-zn&&n<=zn}function gc(n){return"string"==typeof n||!yh(n)&&oc(n)&&de(n)==Xn}function yc(n){return"symbol"==typeof n||oc(n)&&de(n)==nt}function dc(n){return n===Y}function bc(n){return oc(n)&&Is(n)==rt}function wc(n){return oc(n)&&de(n)==et}function mc(n){if(!n)return[];if(Vf(n))return gc(n)?V(n):Uu(n);if(Ll&&n[Ll])return $(n[Ll]());var t=Is(n);return(t==Zn?D:t==Qn?N:na)(n)}function xc(n){if(!n)return 0===n?n:0;if(n=kc(n),n===Rn||n===-Rn){return(n<0?-1:1)*En}return n===n?n:0}function jc(n){
+var t=xc(n),r=t%1;return t===t?r?t-r:t:0}function Ac(n){return n?$r(jc(n),0,Wn):0}function kc(n){if("number"==typeof n)return n;if(yc(n))return Sn;if(ic(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=ic(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(Et,"");var r=Ft.test(n);return r||Pt.test(n)?Jr(n.slice(2),r?2:8):Mt.test(n)?Sn:+n}function Oc(n){return Bu(n,Nc(n))}function Ic(n){return n?$r(jc(n),-zn,zn):0===n?n:0}function Rc(n){return null==n?"":pu(n)}function zc(n,t){var r=_s(n);
+return null==t?r:Wr(r,t)}function Ec(n,t){return v(n,bi(t,3),ee)}function Sc(n,t){return v(n,bi(t,3),ue)}function Wc(n,t){return null==n?n:ys(n,bi(t,3),Nc)}function Lc(n,t){return null==n?n:ds(n,bi(t,3),Nc)}function Cc(n,t){return n&&ee(n,bi(t,3))}function Uc(n,t){return n&&ue(n,bi(t,3))}function Bc(n){return null==n?[]:se(n,Fc(n))}function Tc(n){return null==n?[]:se(n,Nc(n))}function $c(n,t,r){var e=null==n?Y:ve(n,t);return e===Y?r:e}function Dc(n,t){return null!=n&&Oi(n,t,we)}function Mc(n,t){return null!=n&&Oi(n,t,me);
+}function Fc(n){return Vf(n)?Ar(n):$e(n)}function Nc(n){return Vf(n)?Ar(n,!0):De(n)}function Pc(n,t){var r={};return t=bi(t,3),ee(n,function(n,e,u){Cr(r,t(n,e,u),n)}),r}function qc(n,t){var r={};return t=bi(t,3),ee(n,function(n,e,u){Cr(r,e,t(n,e,u))}),r}function Zc(n,t){return Kc(n,Lf(bi(t)))}function Kc(n,t){if(null==n)return{};var r=c(gi(n),function(n){return[n]});return t=bi(t),He(n,r,function(n,r){return t(n,r[0])})}function Vc(n,t,r){t=ju(t,n);var e=-1,u=t.length;for(u||(u=1,n=Y);++et){
+var e=n;n=t,t=e}if(r||n%1||t%1){var u=Jl();return Vl(n+u*(t-n+Hr("1e-"+((u+"").length-1))),t)}return Xe(n,t)}function ia(n){return Jh(Rc(n).toLowerCase())}function oa(n){return n=Rc(n),n&&n.replace(Zt,he).replace(Br,"")}function fa(n,t,r){n=Rc(n),t=pu(t);var e=n.length;r=r===Y?e:$r(jc(r),0,e);var u=r;return r-=t.length,r>=0&&n.slice(r,u)==t}function ca(n){return n=Rc(n),n&&mt.test(n)?n.replace(bt,pe):n}function aa(n){return n=Rc(n),n&&zt.test(n)?n.replace(Rt,"\\$&"):n}function la(n,t,r){n=Rc(n),t=jc(t);
+var e=t?K(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return ni(Ml(u),r)+n+ni(Dl(u),r)}function sa(n,t,r){n=Rc(n),t=jc(t);var e=t?K(n):0;return t&&e>>0)?(n=Rc(n),n&&("string"==typeof t||null!=t&&!xh(t))&&(t=pu(t),!t&&B(n))?Au(V(n),0,r):n.split(t,r)):[]}function ya(n,t,r){return n=Rc(n),r=null==r?0:$r(jc(r),0,n.length),t=pu(t),n.slice(r,r+t.length)==t}function da(n,t,r){var e=q.templateSettings;r&&Li(n,t,r)&&(t=Y),n=Rc(n),t=zh({},t,e,ci);var u,i,o=zh({},t.imports,e.imports,ci),f=Fc(o),c=z(o,f),a=0,l=t.interpolate||Kt,s="__p += '",h=al((t.escape||Kt).source+"|"+l.source+"|"+(l===At?$t:Kt).source+"|"+(t.evaluate||Kt).source+"|$","g"),p="//# sourceURL="+(yl.call(t,"sourceURL")?(t.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++Nr+"]")+"\n";
+n.replace(h,function(t,r,e,o,f,c){return e||(e=o),s+=n.slice(a,c).replace(Vt,C),r&&(u=!0,s+="' +\n__e("+r+") +\n'"),f&&(i=!0,s+="';\n"+f+";\n__p += '"),e&&(s+="' +\n((__t = ("+e+")) == null ? '' : __t) +\n'"),a=c+t.length,t}),s+="';\n";var _=yl.call(t,"variable")&&t.variable;_||(s="with (obj) {\n"+s+"\n}\n"),s=(i?s.replace(vt,""):s).replace(gt,"$1").replace(yt,"$1;"),s="function("+(_||"obj")+") {\n"+(_?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(u?", __e = _.escape":"")+(i?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+s+"return __p\n}";
+var v=Yh(function(){return ol(f,p+"return "+s).apply(Y,c)});if(v.source=s,nc(v))throw v;return v}function ba(n){return Rc(n).toLowerCase()}function wa(n){return Rc(n).toUpperCase()}function ma(n,t,r){if(n=Rc(n),n&&(r||t===Y))return n.replace(Et,"");if(!n||!(t=pu(t)))return n;var e=V(n),u=V(t);return Au(e,S(e,u),W(e,u)+1).join("")}function xa(n,t,r){if(n=Rc(n),n&&(r||t===Y))return n.replace(Wt,"");if(!n||!(t=pu(t)))return n;var e=V(n);return Au(e,0,W(e,V(t))+1).join("")}function ja(n,t,r){if(n=Rc(n),
+n&&(r||t===Y))return n.replace(St,"");if(!n||!(t=pu(t)))return n;var e=V(n);return Au(e,S(e,V(t))).join("")}function Aa(n,t){var r=mn,e=xn;if(ic(t)){var u="separator"in t?t.separator:u;r="length"in t?jc(t.length):r,e="omission"in t?pu(t.omission):e}n=Rc(n);var i=n.length;if(B(n)){var o=V(n);i=o.length}if(r>=i)return n;var f=r-K(e);if(f<1)return e;var c=o?Au(o,0,f).join(""):n.slice(0,f);if(u===Y)return c+e;if(o&&(f+=c.length-f),xh(u)){if(n.slice(f).search(u)){var a,l=c;for(u.global||(u=al(u.source,Rc(Dt.exec(u))+"g")),
+u.lastIndex=0;a=u.exec(l);)var s=a.index;c=c.slice(0,s===Y?f:s)}}else if(n.indexOf(pu(u),f)!=f){var h=c.lastIndexOf(u);h>-1&&(c=c.slice(0,h))}return c+e}function ka(n){return n=Rc(n),n&&wt.test(n)?n.replace(dt,_e):n}function Oa(n,t,r){return n=Rc(n),t=r?Y:t,t===Y?T(n)?J(n):_(n):n.match(t)||[]}function Ia(t){var r=null==t?0:t.length,e=bi();return t=r?c(t,function(n){if("function"!=typeof n[1])throw new sl(tn);return[e(n[0]),n[1]]}):[],ru(function(e){for(var u=-1;++uzn)return[];var r=Wn,e=Vl(n,Wn);t=bi(t),n-=Wn;for(var u=O(e,t);++r1?n[t-1]:Y;return r="function"==typeof r?(n.pop(),
+r):Y,Vo(n,r)}),Js=_i(function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,u=function(t){return Tr(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Bt&&Wi(r)?(e=e.slice(r,+r+(t?1:0)),e.__actions__.push({func:Qo,args:[u],thisArg:Y}),new H(e,this.__chain__).thru(function(n){return t&&!n.length&&n.push(Y),n})):this.thru(u)}),Ys=Du(function(n,t,r){yl.call(n,r)?++n[r]:Cr(n,r,1)}),Qs=Gu(lo),Xs=Gu(so),nh=Du(function(n,t,r){yl.call(n,r)?n[r].push(t):Cr(n,r,[t])}),th=ru(function(t,r,e){var u=-1,i="function"==typeof r,o=Vf(t)?el(t.length):[];
+return vs(t,function(t){o[++u]=i?n(r,t,e):ke(t,r,e)}),o}),rh=Du(function(n,t,r){Cr(n,r,t)}),eh=Du(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),uh=ru(function(n,t){if(null==n)return[];var r=t.length;return r>1&&Li(n,t[0],t[1])?t=[]:r>2&&Li(t[0],t[1],t[2])&&(t=[t[0]]),Ve(n,te(t,1),[])}),ih=Tl||function(){return Xr.Date.now()},oh=ru(function(n,t,r){var e=sn;if(r.length){var u=F(r,di(oh));e|=gn}return fi(n,e,t,r,u)}),fh=ru(function(n,t,r){var e=sn|hn;if(r.length){var u=F(r,di(fh));e|=gn;
+}return fi(t,e,n,r,u)}),ch=ru(function(n,t){return Kr(n,1,t)}),ah=ru(function(n,t,r){return Kr(n,kc(t)||0,r)});Wf.Cache=ar;var lh=ms(function(t,r){r=1==r.length&&yh(r[0])?c(r[0],R(bi())):c(te(r,1),R(bi()));var e=r.length;return ru(function(u){for(var i=-1,o=Vl(u.length,e);++i=t}),gh=Oe(function(){return arguments}())?Oe:function(n){return oc(n)&&yl.call(n,"callee")&&!El.call(n,"callee")},yh=el.isArray,dh=ie?R(ie):Ie,bh=Nl||Na,wh=oe?R(oe):Re,mh=fe?R(fe):Se,xh=ce?R(ce):Ce,jh=ae?R(ae):Ue,Ah=le?R(le):Be,kh=ei(Me),Oh=ei(function(n,t){return n<=t}),Ih=Mu(function(n,t){if($i(t)||Vf(t))return Bu(t,Fc(t),n),Y;for(var r in t)yl.call(t,r)&&zr(n,r,t[r])}),Rh=Mu(function(n,t){Bu(t,Nc(t),n)}),zh=Mu(function(n,t,r,e){Bu(t,Nc(t),n,e)}),Eh=Mu(function(n,t,r,e){Bu(t,Fc(t),n,e);
+}),Sh=_i(Tr),Wh=ru(function(n,t){n=cl(n);var r=-1,e=t.length,u=e>2?t[2]:Y;for(u&&Li(t[0],t[1],u)&&(e=1);++r1),t}),Bu(n,gi(n),r),e&&(r=Dr(r,on|fn|cn,li));for(var u=t.length;u--;)vu(r,t[u]);return r}),Mh=_i(function(n,t){return null==n?{}:Ge(n,t)}),Fh=oi(Fc),Nh=oi(Nc),Ph=Zu(function(n,t,r){return t=t.toLowerCase(),n+(r?ia(t):t)}),qh=Zu(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Zh=Zu(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Kh=qu("toLowerCase"),Vh=Zu(function(n,t,r){
+return n+(r?"_":"")+t.toLowerCase()}),Gh=Zu(function(n,t,r){return n+(r?" ":"")+Jh(t)}),Hh=Zu(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),Jh=qu("toUpperCase"),Yh=ru(function(t,r){try{return n(t,Y,r)}catch(n){return nc(n)?n:new il(n)}}),Qh=_i(function(n,t){return r(t,function(t){t=Qi(t),Cr(n,t,oh(n[t],n))}),n}),Xh=Hu(),np=Hu(!0),tp=ru(function(n,t){return function(r){return ke(r,n,t)}}),rp=ru(function(n,t){return function(r){return ke(n,r,t)}}),ep=Xu(c),up=Xu(u),ip=Xu(h),op=ri(),fp=ri(!0),cp=Qu(function(n,t){
+return n+t},0),ap=ii("ceil"),lp=Qu(function(n,t){return n/t},1),sp=ii("floor"),hp=Qu(function(n,t){return n*t},1),pp=ii("round"),_p=Qu(function(n,t){return n-t},0);return q.after=kf,q.ary=Of,q.assign=Ih,q.assignIn=Rh,q.assignInWith=zh,q.assignWith=Eh,q.at=Sh,q.before=If,q.bind=oh,q.bindAll=Qh,q.bindKey=fh,q.castArray=Mf,q.chain=Jo,q.chunk=ro,q.compact=eo,q.concat=uo,q.cond=Ia,q.conforms=Ra,q.constant=za,q.countBy=Ys,q.create=zc,q.curry=Rf,q.curryRight=zf,q.debounce=Ef,q.defaults=Wh,q.defaultsDeep=Lh,
+q.defer=ch,q.delay=ah,q.difference=Ls,q.differenceBy=Cs,q.differenceWith=Us,q.drop=io,q.dropRight=oo,q.dropRightWhile=fo,q.dropWhile=co,q.fill=ao,q.filter=cf,q.flatMap=af,q.flatMapDeep=lf,q.flatMapDepth=sf,q.flatten=ho,q.flattenDeep=po,q.flattenDepth=_o,q.flip=Sf,q.flow=Xh,q.flowRight=np,q.fromPairs=vo,q.functions=Bc,q.functionsIn=Tc,q.groupBy=nh,q.initial=bo,q.intersection=Bs,q.intersectionBy=Ts,q.intersectionWith=$s,q.invert=Ch,q.invertBy=Uh,q.invokeMap=th,q.iteratee=Wa,q.keyBy=rh,q.keys=Fc,q.keysIn=Nc,
+q.map=vf,q.mapKeys=Pc,q.mapValues=qc,q.matches=La,q.matchesProperty=Ca,q.memoize=Wf,q.merge=Th,q.mergeWith=$h,q.method=tp,q.methodOf=rp,q.mixin=Ua,q.negate=Lf,q.nthArg=$a,q.omit=Dh,q.omitBy=Zc,q.once=Cf,q.orderBy=gf,q.over=ep,q.overArgs=lh,q.overEvery=up,q.overSome=ip,q.partial=sh,q.partialRight=hh,q.partition=eh,q.pick=Mh,q.pickBy=Kc,q.property=Da,q.propertyOf=Ma,q.pull=Ds,q.pullAll=Ao,q.pullAllBy=ko,q.pullAllWith=Oo,q.pullAt=Ms,q.range=op,q.rangeRight=fp,q.rearg=ph,q.reject=bf,q.remove=Io,q.rest=Uf,
+q.reverse=Ro,q.sampleSize=mf,q.set=Gc,q.setWith=Hc,q.shuffle=xf,q.slice=zo,q.sortBy=uh,q.sortedUniq=Bo,q.sortedUniqBy=To,q.split=ga,q.spread=Bf,q.tail=$o,q.take=Do,q.takeRight=Mo,q.takeRightWhile=Fo,q.takeWhile=No,q.tap=Yo,q.throttle=Tf,q.thru=Qo,q.toArray=mc,q.toPairs=Fh,q.toPairsIn=Nh,q.toPath=Va,q.toPlainObject=Oc,q.transform=Jc,q.unary=$f,q.union=Fs,q.unionBy=Ns,q.unionWith=Ps,q.uniq=Po,q.uniqBy=qo,q.uniqWith=Zo,q.unset=Yc,q.unzip=Ko,q.unzipWith=Vo,q.update=Qc,q.updateWith=Xc,q.values=na,q.valuesIn=ta,
+q.without=qs,q.words=Oa,q.wrap=Df,q.xor=Zs,q.xorBy=Ks,q.xorWith=Vs,q.zip=Gs,q.zipObject=Go,q.zipObjectDeep=Ho,q.zipWith=Hs,q.entries=Fh,q.entriesIn=Nh,q.extend=Rh,q.extendWith=zh,Ua(q,q),q.add=cp,q.attempt=Yh,q.camelCase=Ph,q.capitalize=ia,q.ceil=ap,q.clamp=ra,q.clone=Ff,q.cloneDeep=Pf,q.cloneDeepWith=qf,q.cloneWith=Nf,q.conformsTo=Zf,q.deburr=oa,q.defaultTo=Ea,q.divide=lp,q.endsWith=fa,q.eq=Kf,q.escape=ca,q.escapeRegExp=aa,q.every=ff,q.find=Qs,q.findIndex=lo,q.findKey=Ec,q.findLast=Xs,q.findLastIndex=so,
+q.findLastKey=Sc,q.floor=sp,q.forEach=hf,q.forEachRight=pf,q.forIn=Wc,q.forInRight=Lc,q.forOwn=Cc,q.forOwnRight=Uc,q.get=$c,q.gt=_h,q.gte=vh,q.has=Dc,q.hasIn=Mc,q.head=go,q.identity=Sa,q.includes=_f,q.indexOf=yo,q.inRange=ea,q.invoke=Bh,q.isArguments=gh,q.isArray=yh,q.isArrayBuffer=dh,q.isArrayLike=Vf,q.isArrayLikeObject=Gf,q.isBoolean=Hf,q.isBuffer=bh,q.isDate=wh,q.isElement=Jf,q.isEmpty=Yf,q.isEqual=Qf,q.isEqualWith=Xf,q.isError=nc,q.isFinite=tc,q.isFunction=rc,q.isInteger=ec,q.isLength=uc,q.isMap=mh,
+q.isMatch=fc,q.isMatchWith=cc,q.isNaN=ac,q.isNative=lc,q.isNil=hc,q.isNull=sc,q.isNumber=pc,q.isObject=ic,q.isObjectLike=oc,q.isPlainObject=_c,q.isRegExp=xh,q.isSafeInteger=vc,q.isSet=jh,q.isString=gc,q.isSymbol=yc,q.isTypedArray=Ah,q.isUndefined=dc,q.isWeakMap=bc,q.isWeakSet=wc,q.join=wo,q.kebabCase=qh,q.last=mo,q.lastIndexOf=xo,q.lowerCase=Zh,q.lowerFirst=Kh,q.lt=kh,q.lte=Oh,q.max=Ha,q.maxBy=Ja,q.mean=Ya,q.meanBy=Qa,q.min=Xa,q.minBy=nl,q.stubArray=Fa,q.stubFalse=Na,q.stubObject=Pa,q.stubString=qa,
+q.stubTrue=Za,q.multiply=hp,q.nth=jo,q.noConflict=Ba,q.noop=Ta,q.now=ih,q.pad=la,q.padEnd=sa,q.padStart=ha,q.parseInt=pa,q.random=ua,q.reduce=yf,q.reduceRight=df,q.repeat=_a,q.replace=va,q.result=Vc,q.round=pp,q.runInContext=p,q.sample=wf,q.size=jf,q.snakeCase=Vh,q.some=Af,q.sortedIndex=Eo,q.sortedIndexBy=So,q.sortedIndexOf=Wo,q.sortedLastIndex=Lo,q.sortedLastIndexBy=Co,q.sortedLastIndexOf=Uo,q.startCase=Gh,q.startsWith=ya,q.subtract=_p,q.sum=tl,q.sumBy=rl,q.template=da,q.times=Ka,q.toFinite=xc,q.toInteger=jc,
+q.toLength=Ac,q.toLower=ba,q.toNumber=kc,q.toSafeInteger=Ic,q.toString=Rc,q.toUpper=wa,q.trim=ma,q.trimEnd=xa,q.trimStart=ja,q.truncate=Aa,q.unescape=ka,q.uniqueId=Ga,q.upperCase=Hh,q.upperFirst=Jh,q.each=hf,q.eachRight=pf,q.first=go,Ua(q,function(){var n={};return ee(q,function(t,r){yl.call(q.prototype,r)||(n[r]=t)}),n}(),{chain:!1}),q.VERSION=Q,r(["bind","bindKey","curry","curryRight","partial","partialRight"],function(n){q[n].placeholder=q}),r(["drop","take"],function(n,t){Bt.prototype[n]=function(r){
+r=r===Y?1:Kl(jc(r),0);var e=this.__filtered__&&!t?new Bt(this):this.clone();return e.__filtered__?e.__takeCount__=Vl(r,e.__takeCount__):e.__views__.push({size:Vl(r,Wn),type:n+(e.__dir__<0?"Right":"")}),e},Bt.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){var r=t+1,e=r==kn||r==In;Bt.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:bi(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){
+var r="take"+(t?"Right":"");Bt.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Bt.prototype[n]=function(){return this.__filtered__?new Bt(this):this[r](1)}}),Bt.prototype.compact=function(){return this.filter(Sa)},Bt.prototype.find=function(n){return this.filter(n).head()},Bt.prototype.findLast=function(n){return this.reverse().find(n)},Bt.prototype.invokeMap=ru(function(n,t){return"function"==typeof n?new Bt(this):this.map(function(r){
+return ke(r,n,t)})}),Bt.prototype.reject=function(n){return this.filter(Lf(bi(n)))},Bt.prototype.slice=function(n,t){n=jc(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Bt(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==Y&&(t=jc(t),r=t<0?r.dropRight(-t):r.take(t-n)),r)},Bt.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Bt.prototype.toArray=function(){return this.take(Wn)},ee(Bt.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=q[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);
+u&&(q.prototype[t]=function(){var t=this.__wrapped__,o=e?[1]:arguments,f=t instanceof Bt,c=o[0],l=f||yh(t),s=function(n){var t=u.apply(q,a([n],o));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(f=l=!1);var h=this.__chain__,p=!!this.__actions__.length,_=i&&!h,v=f&&!p;if(!i&&l){t=v?t:new Bt(this);var g=n.apply(t,o);return g.__actions__.push({func:Qo,args:[s],thisArg:Y}),new H(g,h)}return _&&v?n.apply(this,o):(g=this.thru(s),_?e?g.value()[0]:g.value():g)})}),r(["pop","push","shift","sort","splice","unshift"],function(n){
+var t=hl[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);q.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(yh(u)?u:[],n)}return this[r](function(r){return t.apply(yh(r)?r:[],n)})}}),ee(Bt.prototype,function(n,t){var r=q[t];if(r){var e=r.name+"";yl.call(is,e)||(is[e]=[]),is[e].push({name:t,func:r})}}),is[Ju(Y,hn).name]=[{name:"wrapper",func:Y}],Bt.prototype.clone=Gt,Bt.prototype.reverse=Ht,Bt.prototype.value=Jt,q.prototype.at=Js,
+q.prototype.chain=Xo,q.prototype.commit=nf,q.prototype.next=tf,q.prototype.plant=ef,q.prototype.reverse=uf,q.prototype.toJSON=q.prototype.valueOf=q.prototype.value=of,q.prototype.first=q.prototype.head,Ll&&(q.prototype[Ll]=rf),q},ge=ve();"function"==typeof define&&"object"==typeof define.amd&&define.amd?(Xr._=ge,define(function(){return ge})):te?((te.exports=ge)._=ge,ne._=ge):Xr._=ge}).call(this);
\ No newline at end of file
diff --git a/node_modules/lodash/package.json b/node_modules/lodash/package.json
index d0967f7a9..ef6c08de2 100644
--- a/node_modules/lodash/package.json
+++ b/node_modules/lodash/package.json
@@ -1,6 +1,6 @@
{
"name": "lodash",
- "version": "4.17.15",
+ "version": "4.17.19",
"description": "Lodash modular utilities.",
"keywords": "modules, stdlib, util",
"homepage": "https://lodash.com/",
diff --git a/package-lock.json b/package-lock.json
index 8ef3b0742..1874c365c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1876,10 +1876,9 @@
}
},
"lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
- "dev": true
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash.clonedeep": {
"version": "4.5.0",
diff --git a/src/analysis-paths.test.ts b/src/analysis-paths.test.ts
index 5a6d555b2..7579fd782 100644
--- a/src/analysis-paths.test.ts
+++ b/src/analysis-paths.test.ts
@@ -11,6 +11,7 @@ test("emptyPaths", async t => {
queries: {},
pathsIgnore: [],
paths: [],
+ originalUserInput: {},
};
analysisPaths.includeAndExcludeAnalysisPaths(config);
t.is(process.env['LGTM_INDEX_INCLUDE'], undefined);
@@ -24,6 +25,7 @@ test("nonEmptyPaths", async t => {
queries: {},
paths: ['path1', 'path2', '**/path3'],
pathsIgnore: ['path4', 'path5', 'path6/**'],
+ originalUserInput: {},
};
analysisPaths.includeAndExcludeAnalysisPaths(config);
t.is(process.env['LGTM_INDEX_INCLUDE'], 'path1\npath2');
diff --git a/src/autobuild.ts b/src/autobuild.ts
index ee2c753ce..6b70119d8 100644
--- a/src/autobuild.ts
+++ b/src/autobuild.ts
@@ -4,9 +4,40 @@ import { getCodeQL } from './codeql';
import * as sharedEnv from './shared-environment';
import * as util from './util';
+interface AutobuildStatusReport extends util.StatusReportBase {
+ // Comma-separated set of languages being autobuilt
+ autobuild_languages: string;
+ // Language that failed autobuilding (or undefined if all languages succeeded).
+ autobuild_failure?: string;
+}
+
+async function sendCompletedStatusReport(
+ startedAt: Date,
+ allLanguages: string[],
+ failingLanguage?: string,
+ cause?: Error) {
+
+ const status = failingLanguage !== undefined || cause !== undefined ? 'failure' : 'success';
+ const statusReportBase = await util.createStatusReportBase(
+ 'autobuild',
+ status,
+ startedAt,
+ cause?.message,
+ cause?.stack);
+ const statusReport: AutobuildStatusReport = {
+ ...statusReportBase,
+ autobuild_languages: allLanguages.join(','),
+ autobuild_failure: failingLanguage,
+ };
+ await util.sendStatusReport(statusReport);
+}
+
async function run() {
+ const startedAt = new Date();
+ let language;
try {
- if (util.should_abort('autobuild', true) || !await util.reportActionStarting('autobuild')) {
+ if (util.should_abort('autobuild', true) ||
+ !await util.sendStatusReport(await util.createStatusReportBase('autobuild', 'starting', startedAt), true)) {
return;
}
@@ -15,7 +46,7 @@ async function run() {
// The languages are sorted in order specified by user or by lines of code if we got
// them from the GitHub API, so try to build the first language on the list.
const autobuildLanguages = process.env[sharedEnv.CODEQL_ACTION_TRACED_LANGUAGES]?.split(',') || [];
- const language = autobuildLanguages[0];
+ language = autobuildLanguages[0];
if (!language) {
core.info("None of the languages in this project require extra build steps");
@@ -36,11 +67,11 @@ async function run() {
} catch (error) {
core.setFailed("We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. " + error.message);
- await util.reportActionFailed('autobuild', error.message, error.stack);
+ await sendCompletedStatusReport(startedAt, [language], language, error);
return;
}
- await util.reportActionSucceeded('autobuild');
+ await sendCompletedStatusReport(startedAt, [language]);
}
run().catch(e => {
diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts
index b4ca3873f..d1534b4ab 100644
--- a/src/config-utils.test.ts
+++ b/src/config-utils.test.ts
@@ -187,6 +187,13 @@ test("load non-empty input", async t => {
queries: {'javascript': ['/foo/a.ql', '/bar/b.ql']},
pathsIgnore: ['a', 'b'],
paths: ['c/d'],
+ originalUserInput: {
+ name: 'my config',
+ 'disable-default-queries': true,
+ queries: [{ uses: './foo' }],
+ 'paths-ignore': ['a', 'b'],
+ paths: ['c/d'],
+ },
};
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
diff --git a/src/config-utils.ts b/src/config-utils.ts
index 55cb8078d..87f97b0c0 100644
--- a/src/config-utils.ts
+++ b/src/config-utils.ts
@@ -17,6 +17,20 @@ const QUERIES_USES_PROPERTY = 'uses';
const PATHS_IGNORE_PROPERTY = 'paths-ignore';
const PATHS_PROPERTY = 'paths';
+/**
+ * Format of the config file supplied by the user.
+ */
+export interface UserConfig {
+ name?: string;
+ 'disable-default-queries'?: boolean;
+ queries?: {
+ name?: string;
+ uses: string;
+ }[];
+ 'paths-ignore'?: string[];
+ paths?: string[];
+}
+
/**
* Format of the parsed config file.
*/
@@ -39,6 +53,14 @@ export interface Config {
* List of paths to include in analysis.
*/
paths: string[];
+ /**
+ * A unaltered copy of the original user input.
+ * Mainly intended to be used for status reporting.
+ * If any field is useful for the actual processing
+ * of the action then consider pulling it out to a
+ * top-level field above.
+ */
+ originalUserInput: UserConfig;
}
/**
@@ -460,7 +482,8 @@ export async function getDefaultConfig(): Promise {
languages: languages,
queries: queries,
pathsIgnore: [],
- paths: []
+ paths: [],
+ originalUserInput: {},
};
}
@@ -468,7 +491,7 @@ export async function getDefaultConfig(): Promise {
* Load the config from the given file.
*/
async function loadConfig(configFile: string): Promise {
- let parsedYAML;
+ let parsedYAML: UserConfig;
if (isLocal(configFile)) {
// Treat the config file as relative to the workspace
@@ -486,7 +509,7 @@ async function loadConfig(configFile: string): Promise {
if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
throw new Error(getNameInvalid(configFile));
}
- if (parsedYAML[NAME_PROPERTY].length === 0) {
+ if (parsedYAML[NAME_PROPERTY]!.length === 0) {
throw new Error(getNameInvalid(configFile));
}
}
@@ -507,7 +530,7 @@ async function loadConfig(configFile: string): Promise {
if (typeof parsedYAML[DISABLE_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
throw new Error(getDisableDefaultQueriesInvalid(configFile));
}
- disableDefaultQueries = parsedYAML[DISABLE_DEFAULT_QUERIES_PROPERTY];
+ disableDefaultQueries = parsedYAML[DISABLE_DEFAULT_QUERIES_PROPERTY]!;
}
if (!disableDefaultQueries) {
await addDefaultQueries(languages, queries);
@@ -517,7 +540,7 @@ async function loadConfig(configFile: string): Promise {
if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
throw new Error(getQueriesInvalid(configFile));
}
- for (const query of parsedYAML[QUERIES_PROPERTY]) {
+ for (const query of parsedYAML[QUERIES_PROPERTY]!) {
if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
throw new Error(getQueryUsesInvalid(configFile));
}
@@ -529,7 +552,7 @@ async function loadConfig(configFile: string): Promise {
if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
throw new Error(getPathsIgnoreInvalid(configFile));
}
- parsedYAML[PATHS_IGNORE_PROPERTY].forEach(path => {
+ parsedYAML[PATHS_IGNORE_PROPERTY]!.forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsIgnoreInvalid(configFile));
}
@@ -541,7 +564,7 @@ async function loadConfig(configFile: string): Promise {
if (!(parsedYAML[PATHS_PROPERTY] instanceof Array)) {
throw new Error(getPathsInvalid(configFile));
}
- parsedYAML[PATHS_PROPERTY].forEach(path => {
+ parsedYAML[PATHS_PROPERTY]!.forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsInvalid(configFile));
}
@@ -549,7 +572,13 @@ async function loadConfig(configFile: string): Promise {
});
}
- return {languages, queries, pathsIgnore, paths};
+ return {
+ languages,
+ queries,
+ pathsIgnore,
+ paths,
+ originalUserInput: parsedYAML
+ };
}
/**
@@ -584,7 +613,7 @@ function isLocal(configPath: string): boolean {
return (configPath.indexOf("@") === -1);
}
-function getLocalConfig(configFile: string, workspacePath: string): any {
+function getLocalConfig(configFile: string, workspacePath: string): UserConfig {
// Error if the config file is now outside of the workspace
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
throw new Error(getConfigFileOutsideWorkspaceErrorMessage(configFile));
@@ -598,7 +627,7 @@ function getLocalConfig(configFile: string, workspacePath: string): any {
return yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
}
-async function getRemoteConfig(configFile: string): Promise {
+async function getRemoteConfig(configFile: string): Promise {
// retrieve the various parts of the config location, and ensure they're present
const format = new RegExp('(?[^/]+)/(?[^/]+)/(?[^@]+)@(?[.*)');
const pieces = format.exec(configFile);
diff --git a/src/finalize-db.ts b/src/finalize-db.ts
index ecc95b445..4c48d1d98 100644
--- a/src/finalize-db.ts
+++ b/src/finalize-db.ts
@@ -9,6 +9,53 @@ import * as sharedEnv from './shared-environment';
import * as upload_lib from './upload-lib';
import * as util from './util';
+interface QueriesStatusReport {
+ // Time taken in ms to analyze builtin queries for cpp (or undefined if this language was not analyzed)
+ analyze_builtin_queries_cpp_duration_ms?: number;
+ // Time taken in ms to analyze builtin queries for csharp (or undefined if this language was not analyzed)
+ analyze_builtin_queries_csharp_duration_ms?: number;
+ // Time taken in ms to analyze builtin queries for go (or undefined if this language was not analyzed)
+ analyze_builtin_queries_go_duration_ms?: number;
+ // Time taken in ms to analyze builtin queries for java (or undefined if this language was not analyzed)
+ analyze_builtin_queries_java_duration_ms?: number;
+ // Time taken in ms to analyze builtin queries for javascript (or undefined if this language was not analyzed)
+ analyze_builtin_queries_javascript_duration_ms?: number;
+ // Time taken in ms to analyze builtin queries for python (or undefined if this language was not analyzed)
+ analyze_builtin_queries_python_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for cpp (or undefined if this language was not analyzed)
+ analyze_custom_queries_cpp_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for csharp (or undefined if this language was not analyzed)
+ analyze_custom_queries_csharp_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for go (or undefined if this language was not analyzed)
+ analyze_custom_queries_go_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for java (or undefined if this language was not analyzed)
+ analyze_custom_queries_java_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for javascript (or undefined if this language was not analyzed)
+ analyze_custom_queries_javascript_duration_ms?: number;
+ // Time taken in ms to analyze custom queries for python (or undefined if this language was not analyzed)
+ analyze_custom_queries_python_duration_ms?: number;
+ // Name of language that errored during analysis (or undefined if no langauge failed)
+ analyze_failure_language?: string;
+}
+
+interface FinishStatusReport extends util.StatusReportBase, upload_lib.UploadStatusReport, QueriesStatusReport {}
+
+async function sendStatusReport(
+ startedAt: Date,
+ queriesStats: QueriesStatusReport | undefined,
+ uploadStats: upload_lib.UploadStatusReport | undefined,
+ error?: Error) {
+
+ const status = queriesStats?.analyze_failure_language !== undefined || error !== undefined ? 'failure' : 'success';
+ const statusReportBase = await util.createStatusReportBase('finish', status, startedAt, error?.message, error?.stack);
+ const statusReport: FinishStatusReport = {
+ ...statusReportBase,
+ ...(queriesStats || {}),
+ ...(uploadStats || {}),
+ };
+ await util.sendStatusReport(statusReport);
+}
+
async function createdDBForScannedLanguages(databaseFolder: string) {
const scannedLanguages = process.env[sharedEnv.CODEQL_ACTION_SCANNED_LANGUAGES];
if (scannedLanguages) {
@@ -33,35 +80,53 @@ async function finalizeDatabaseCreation(databaseFolder: string, config: configUt
}
// Runs queries and creates sarif files in the given folder
-async function runQueries(databaseFolder: string, sarifFolder: string, config: configUtils.Config) {
+async function runQueries(
+ databaseFolder: string,
+ sarifFolder: string,
+ config: configUtils.Config): Promise {
+
const codeql = getCodeQL();
- for (let database of fs.readdirSync(databaseFolder)) {
- core.startGroup('Analyzing ' + database);
+ for (let language of fs.readdirSync(databaseFolder)) {
+ core.startGroup('Analyzing ' + language);
- const queries = config.queries[database] || [];
+ const queries = config.queries[language] || [];
if (queries.length === 0) {
- throw new Error('Unable to analyse ' + database + ' as no queries were selected for this language');
+ throw new Error('Unable to analyse ' + language + ' as no queries were selected for this language');
}
- // Pass the queries to codeql using a file instead of using the command
- // line to avoid command line length restrictions, particularly on windows.
- const querySuite = path.join(databaseFolder, database + '-queries.qls');
- const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
- fs.writeFileSync(querySuite, querySuiteContents);
- core.debug('Query suite file for ' + database + '...\n' + querySuiteContents);
+ try {
+ // Pass the queries to codeql using a file instead of using the command
+ // line to avoid command line length restrictions, particularly on windows.
+ const querySuite = path.join(databaseFolder, language + '-queries.qls');
+ const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
+ fs.writeFileSync(querySuite, querySuiteContents);
+ core.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
- const sarifFile = path.join(sarifFolder, database + '.sarif');
+ const sarifFile = path.join(sarifFolder, language + '.sarif');
- await codeql.databaseAnalyze(path.join(databaseFolder, database), sarifFile, querySuite);
+ await codeql.databaseAnalyze(path.join(databaseFolder, language), sarifFile, querySuite);
- core.debug('SARIF results for database ' + database + ' created at "' + sarifFile + '"');
- core.endGroup();
+ core.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
+ core.endGroup();
+
+ } catch (e) {
+ // For now the fields about query performance are not populated
+ return {
+ analyze_failure_language: language,
+ };
+ }
}
+
+ return {};
}
async function run() {
+ const startedAt = new Date();
+ let queriesStats: QueriesStatusReport | undefined = undefined;
+ let uploadStats: upload_lib.UploadStatusReport | undefined = undefined;
try {
- if (util.should_abort('finish', true) || !await util.reportActionStarting('finish')) {
+ if (util.should_abort('finish', true) ||
+ !await util.sendStatusReport(await util.createStatusReportBase('finish', 'starting', startedAt), true)) {
return;
}
const config = await configUtils.getConfig();
@@ -78,22 +143,19 @@ async function run() {
await finalizeDatabaseCreation(databaseFolder, config);
core.info('Analyzing database');
- await runQueries(databaseFolder, sarifFolder, config);
+ queriesStats = await runQueries(databaseFolder, sarifFolder, config);
if ('true' === core.getInput('upload')) {
- if (!await upload_lib.upload(sarifFolder)) {
- await util.reportActionFailed('finish', 'upload');
- return;
- }
+ uploadStats = await upload_lib.upload(sarifFolder);
}
} catch (error) {
core.setFailed(error.message);
- await util.reportActionFailed('finish', error.message, error.stack);
+ await sendStatusReport(startedAt, queriesStats, uploadStats, error);
return;
}
- await util.reportActionSucceeded('finish');
+ await sendStatusReport(startedAt, queriesStats, uploadStats);
}
run().catch(e => {
diff --git a/src/fingerprints.ts b/src/fingerprints.ts
index b75f11e93..83ab602e1 100644
--- a/src/fingerprints.ts
+++ b/src/fingerprints.ts
@@ -148,10 +148,10 @@ function locationUpdateCallback(result: any, location: any): hashCallback {
if (!existingFingerprint) {
result.partialFingerprints.primaryLocationLineHash = hash;
} else if (existingFingerprint !== hash) {
- core.warning("Calculated fingerprint of " + hash +
- " for file " + location.physicalLocation.artifactLocation.uri +
- " line " + lineNumber +
- ", but found existing inconsistent fingerprint value " + existingFingerprint);
+ core.warning('Calculated fingerprint of ' + hash +
+ ' for file ' + location.physicalLocation.artifactLocation.uri +
+ ' line ' + lineNumber +
+ ', but found existing inconsistent fingerprint value ' + existingFingerprint);
}
};
}
@@ -167,7 +167,7 @@ export function resolveUriToFile(location: any, artifacts: any[]): string | unde
location.index < 0 ||
location.index >= artifacts.length ||
typeof artifacts[location.index].location !== 'object') {
- core.debug('Ignoring location as index "' + location.index + '" is invalid');
+ core.debug(`Ignoring location as URI "${location.index}" is invalid`);
return undefined;
}
location = artifacts[location.index].location;
@@ -175,7 +175,7 @@ export function resolveUriToFile(location: any, artifacts: any[]): string | unde
// Get the URI and decode
if (typeof location.uri !== 'string') {
- core.debug('Ignoring location as uri "' + location.uri + '" is invalid');
+ core.debug(`Ignoring location as index "${location.uri}" is invalid`);
return undefined;
}
let uri = decodeURIComponent(location.uri);
@@ -186,14 +186,14 @@ export function resolveUriToFile(location: any, artifacts: any[]): string | unde
uri = uri.substring(fileUriPrefix.length);
}
if (uri.indexOf('://') !== -1) {
- core.debug('Ignoring location URI "' + uri + "' as the scheme is not recognised");
+ core.debug(`Ignoring location URI "${uri}" as the scheme is not recognised`);
return undefined;
}
// Discard any absolute paths that aren't in the src root
const srcRootPrefix = process.env['GITHUB_WORKSPACE'] + '/';
if (uri.startsWith('/') && !uri.startsWith(srcRootPrefix)) {
- core.debug('Ignoring location URI "' + uri + "' as it is outside of the src root");
+ core.debug(`Ignoring location URI "${uri}" as it is outside of the src root`);
return undefined;
}
@@ -206,7 +206,7 @@ export function resolveUriToFile(location: any, artifacts: any[]): string | unde
// Check the file exists
if (!fs.existsSync(uri)) {
- core.debug("Unable to compute fingerprint for non-existent file: " + uri);
+ core.debug(`Unable to compute fingerprint for non-existent file: ${uri}`);
return undefined;
}
@@ -228,10 +228,8 @@ export function addFingerprints(sarifContents: string): string {
for (const result of run.results || []) {
// Check the primary location is defined correctly and is in the src root
const primaryLocation = (result.locations || [])[0];
- if (!primaryLocation ||
- !primaryLocation.physicalLocation ||
- !primaryLocation.physicalLocation.artifactLocation) {
- core.debug("Unable to compute fingerprint for invalid location: " + JSON.stringify(primaryLocation));
+ if (!primaryLocation?.physicalLocation?.artifactLocation) {
+ core.debug(`Unable to compute fingerprint for invalid location: ${JSON.stringify(primaryLocation)}`);
continue;
}
diff --git a/src/setup-tracer.ts b/src/setup-tracer.ts
index a217b7b5a..5e0a60664 100644
--- a/src/setup-tracer.ts
+++ b/src/setup-tracer.ts
@@ -131,13 +131,54 @@ function concatTracerConfigs(configs: { [lang: string]: TracerConfig }): TracerC
return { env, spec };
}
+interface InitSuccessStatusReport extends util.StatusReportBase {
+ // Comma-separated list of languages that analysis was run for
+ // This may be from the workflow file or may be calculated from repository contents
+ languages: string;
+ // Comma-separated list of languages specified explicitly in the workflow file
+ workflow_languages: string;
+ // Comma-separated list of paths, from the 'paths' config field
+ paths: string;
+ // Comma-separated list of paths, from the 'paths-ignore' config field
+ paths_ignore: string;
+ // Commas-separated list of languages where the default queries are disabled
+ disable_default_queries: string;
+ // Comma-separated list of queries sources, from the 'queries' config field
+ queries: string;
+}
+
+async function sendSuccessStatusReport(startedAt: Date, config: configUtils.Config) {
+ const statusReportBase = await util.createStatusReportBase('init', 'success', startedAt);
+
+ const languages = config.languages.join(',');
+ const workflowLanguages = core.getInput('languages', { required: false });
+ const paths = (config.originalUserInput.paths || []).join(',');
+ const pathsIgnore = (config.originalUserInput['paths-ignore'] || []).join(',');
+ const disableDefaultQueries = config.originalUserInput['disable-default-queries'] ? languages : '';
+ const queries = (config.originalUserInput.queries || []).map(q => q.uses).join(',');
+
+ const statusReport: InitSuccessStatusReport = {
+ ...statusReportBase,
+ languages: languages,
+ workflow_languages: workflowLanguages,
+ paths: paths,
+ paths_ignore: pathsIgnore,
+ disable_default_queries: disableDefaultQueries,
+ queries: queries,
+ };
+
+ await util.sendStatusReport(statusReport);
+}
+
async function run() {
+ const startedAt = new Date();
let config: configUtils.Config;
let codeql: CodeQL;
try {
- if (util.should_abort('init', false) || !await util.reportActionStarting('init')) {
+ if (util.should_abort('init', false) ||
+ !await util.sendStatusReport(await util.createStatusReportBase('init', 'starting', startedAt), true)) {
return;
}
@@ -153,7 +194,7 @@ async function run() {
} catch (e) {
core.setFailed(e.message);
- await util.reportActionAborted('init', e.message);
+ await util.sendStatusReport(await util.createStatusReportBase('init', 'aborted', startedAt, e.message));
return;
}
@@ -226,10 +267,15 @@ async function run() {
} catch (error) {
core.setFailed(error.message);
- await util.reportActionFailed('init', error.message, error.stack);
+ await util.sendStatusReport(await util.createStatusReportBase(
+ 'init',
+ 'failure',
+ startedAt,
+ error.message,
+ error.stack));
return;
}
- await util.reportActionSucceeded('init');
+ await sendSuccessStatusReport(startedAt, config);
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
}
diff --git a/src/shared-environment.ts b/src/shared-environment.ts
index 58d687d15..471d16eaf 100644
--- a/src/shared-environment.ts
+++ b/src/shared-environment.ts
@@ -8,6 +8,6 @@ export const CODEQL_ACTION_TRACED_LANGUAGES = 'CODEQL_ACTION_TRACED_LANGUAGES';
// action (i.e. the upload action is being used by a third-party integrator)
// then this variable will be assigned the start time of the action invoked
// rather that the init action.
-export const CODEQL_ACTION_STARTED_AT = 'CODEQL_ACTION_STARTED_AT';
+export const CODEQL_WORKFLOW_STARTED_AT = 'CODEQL_WORKFLOW_STARTED_AT';
// Populated when the init action completes successfully
export const CODEQL_ACTION_INIT_COMPLETED = 'CODEQL_ACTION_INIT_COMPLETED';
diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts
index e6f6d6144..50fb0c812 100644
--- a/src/upload-lib.test.ts
+++ b/src/upload-lib.test.ts
@@ -7,12 +7,10 @@ setupTests(test);
test('validateSarifFileSchema - valid', t => {
const inputFile = __dirname + '/../src/testdata/valid-sarif.sarif';
- t.true(uploadLib.validateSarifFileSchema(inputFile));
+ t.notThrows(() => uploadLib.validateSarifFileSchema(inputFile));
});
test('validateSarifFileSchema - invalid', t => {
const inputFile = __dirname + '/../src/testdata/invalid-sarif.sarif';
- t.false(uploadLib.validateSarifFileSchema(inputFile));
- // validateSarifFileSchema calls core.setFailed which sets the exit code on error
- process.exitCode = 0;
+ t.throws(() => uploadLib.validateSarifFileSchema(inputFile));
});
diff --git a/src/upload-lib.ts b/src/upload-lib.ts
index a8f04093d..7cb438334 100644
--- a/src/upload-lib.ts
+++ b/src/upload-lib.ts
@@ -35,13 +35,13 @@ export function combineSarifFiles(sarifFiles: string[]): string {
// Upload the given payload.
// If the request fails then this will retry a small number of times.
-async function uploadPayload(payload): Promise {
+async function uploadPayload(payload) {
core.info('Uploading results');
// If in test mode we don't want to upload the results
const testMode = process.env['TEST_MODE'] === 'true' || false;
if (testMode) {
- return true;
+ return;
}
const [owner, repo] = util.getRequiredEnvParam("GITHUB_REPOSITORY").split("/");
@@ -64,15 +64,14 @@ async function uploadPayload(payload): Promise {
const statusCode = response.status;
if (statusCode === 202) {
core.info("Successfully uploaded results");
- return true;
+ return;
}
const requestID = response.headers["x-github-request-id"];
// On any other status code that's not 5xx mark the upload as failed
if (!statusCode || statusCode < 500 || statusCode >= 600) {
- core.setFailed('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
- return false;
+ throw new Error('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
}
// On a 5xx status code we may retry the request
@@ -89,25 +88,34 @@ async function uploadPayload(payload): Promise {
// If the upload fails with 5xx then we assume it is a temporary problem
// and not an error that the user has caused or can fix.
// We avoid marking the job as failed to avoid breaking CI workflows.
- core.error('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
- return false;
+ throw new Error('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
}
}
- return false;
+ // This case shouldn't ever happen as the final iteration of the loop
+ // will always throw an error instead of exiting to here.
+ throw new Error('Upload failed');
+}
+
+export interface UploadStatusReport {
+ // Size in bytes of unzipped SARIF upload
+ raw_upload_size_bytes?: number;
+ // Size in bytes of actual SARIF upload
+ zipped_upload_size_bytes?: number;
+ // Number of results in the SARIF upload
+ num_results_in_sarif?: number;
}
// Uploads a single sarif file or a directory of sarif files
// depending on what the path happens to refer to.
// Returns true iff the upload occurred and succeeded
-export async function upload(input: string): Promise {
+export async function upload(input: string): Promise {
if (fs.lstatSync(input).isDirectory()) {
const sarifFiles = fs.readdirSync(input)
.filter(f => f.endsWith(".sarif"))
.map(f => path.resolve(input, f));
if (sarifFiles.length === 0) {
- core.setFailed("No SARIF files found to upload in \"" + input + "\".");
- return false;
+ throw new Error("No SARIF files found to upload in \"" + input + "\".");
}
return await uploadFiles(sarifFiles);
} else {
@@ -125,50 +133,42 @@ export function countResultsInSarif(sarif: string): number {
}
// Validates that the given file path refers to a valid SARIF file.
-// Returns a non-empty list of error message if the file is invalid,
-// otherwise returns the empty list if the file is valid.
-export function validateSarifFileSchema(sarifFilePath: string): boolean {
+// Throws an error if the file is invalid.
+export function validateSarifFileSchema(sarifFilePath: string) {
const sarif = JSON.parse(fs.readFileSync(sarifFilePath, 'utf8'));
const schema = JSON.parse(fs.readFileSync(__dirname + '/../src/sarif_v2.1.0_schema.json', 'utf8'));
const result = new jsonschema.Validator().validate(sarif, schema);
- if (result.valid) {
- return true;
- } else {
- // Set the failure message to the stacks of all the errors.
- // This should be of a manageable size and may even give enough to fix the error.
- const errorMessages = result.errors.map(e => "- " + e.stack);
- core.setFailed("Unable to upload \"" + sarifFilePath + "\" as it is not valid SARIF:\n" + errorMessages.join("\n"));
-
- // Also output the more verbose error messages in groups as these may be very large.
+ if (!result.valid) {
+ // Output the more verbose error messages in groups as these may be very large.
for (const error of result.errors) {
core.startGroup("Error details: " + error.stack);
core.info(JSON.stringify(error, null, 2));
core.endGroup();
}
- return false;
+ // Set the main error message to the stacks of all the errors.
+ // This should be of a manageable size and may even give enough to fix the error.
+ const sarifErrors = result.errors.map(e => "- " + e.stack);
+ throw new Error("Unable to upload \"" + sarifFilePath + "\" as it is not valid SARIF:\n" + sarifErrors.join("\n"));
}
}
// Uploads the given set of sarif files.
// Returns true iff the upload occurred and succeeded
-async function uploadFiles(sarifFiles: string[]): Promise {
+async function uploadFiles(sarifFiles: string[]): Promise {
core.startGroup("Uploading results");
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
if (process.env[sentinelEnvVar]) {
- core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
- return false;
+ throw new Error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
// Validate that the files we were asked to upload are all valid SARIF files
for (const file of sarifFiles) {
- if (!validateSarifFileSchema(file)) {
- return false;
- }
+ validateSarifFileSchema(file);
}
const commitOid = await util.getCommitOid();
@@ -176,7 +176,7 @@ async function uploadFiles(sarifFiles: string[]): Promise {
const ref = util.getRef();
const analysisKey = await util.getAnalysisKey();
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
- const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
+ const startedAt = process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT];
let sarifPayload = combineSarifFiles(sarifFiles);
sarifPayload = fingerprints.addFingerprints(sarifPayload);
@@ -187,8 +187,7 @@ async function uploadFiles(sarifFiles: string[]): Promise {
const workflowRunID = parseInt(workflowRunIDStr, 10);
if (Number.isNaN(workflowRunID)) {
- core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
- return false;
+ throw new Error('GITHUB_RUN_ID must define a non NaN workflow run ID');
}
let matrix: string | undefined = core.getInput('matrix');
@@ -212,14 +211,21 @@ async function uploadFiles(sarifFiles: string[]): Promise {
});
// Log some useful debug info about the info
- core.debug("Raw upload size: " + sarifPayload.length + " bytes");
- core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
- core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
+ const rawUploadSizeBytes = sarifPayload.length;
+ core.debug("Raw upload size: " + rawUploadSizeBytes + " bytes");
+ const zippedUploadSizeBytes = zipped_sarif.length;
+ core.debug("Base64 zipped upload size: " + zippedUploadSizeBytes + " bytes");
+ const numResultInSarif = countResultsInSarif(sarifPayload);
+ core.debug("Number of results in upload: " + numResultInSarif);
// Make the upload
- const succeeded = await uploadPayload(payload);
+ await uploadPayload(payload);
core.endGroup();
- return succeeded;
+ return {
+ raw_upload_size_bytes: rawUploadSizeBytes,
+ zipped_upload_size_bytes: zippedUploadSizeBytes,
+ num_results_in_sarif: numResultInSarif,
+ };
}
diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts
index 8d3aada6d..10f38435a 100644
--- a/src/upload-sarif.ts
+++ b/src/upload-sarif.ts
@@ -3,20 +3,36 @@ import * as core from '@actions/core';
import * as upload_lib from './upload-lib';
import * as util from './util';
+interface UploadSarifStatusReport extends util.StatusReportBase, upload_lib.UploadStatusReport {}
+
+async function sendSuccessStatusReport(startedAt: Date, uploadStats: upload_lib.UploadStatusReport) {
+ const statusReportBase = await util.createStatusReportBase('upload-sarif', 'success', startedAt);
+ const statusReport: UploadSarifStatusReport = {
+ ...statusReportBase,
+ ... uploadStats,
+ };
+ await util.sendStatusReport(statusReport);
+}
+
async function run() {
- if (util.should_abort('upload-sarif', false) || !await util.reportActionStarting('upload-sarif')) {
+ const startedAt = new Date();
+ if (util.should_abort('upload-sarif', false) ||
+ !await util.sendStatusReport(await util.createStatusReportBase('upload-sarif', 'starting', startedAt), true)) {
return;
}
try {
- if (await upload_lib.upload(core.getInput('sarif_file'))) {
- await util.reportActionSucceeded('upload-sarif');
- } else {
- await util.reportActionFailed('upload-sarif', 'upload');
- }
+ const uploadStats = await upload_lib.upload(core.getInput('sarif_file'));
+ await sendSuccessStatusReport(startedAt, uploadStats);
+
} catch (error) {
core.setFailed(error.message);
- await util.reportActionFailed('upload-sarif', error.message, error.stack);
+ await util.sendStatusReport(await util.createStatusReportBase(
+ 'upload-sarif',
+ 'failure',
+ startedAt,
+ error.message,
+ error.stack));
return;
}
}
diff --git a/src/util.ts b/src/util.ts
index 1b4f9c715..c35148f11 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -5,7 +5,6 @@ import * as os from 'os';
import * as path from 'path';
import * as api from './api-client';
-import * as configUtils from './config-utils';
import * as sharedEnv from './shared-environment';
/**
@@ -138,21 +137,36 @@ export function getRef(): string {
type ActionName = 'init' | 'autobuild' | 'finish' | 'upload-sarif';
type ActionStatus = 'starting' | 'aborted' | 'success' | 'failure';
-interface StatusReport {
+export interface StatusReportBase {
+ // ID of the workflow run containing the action run
"workflow_run_id": number;
+ // Workflow name. Converted to analysis_name further down the pipeline.
"workflow_name": string;
+ // Job name from the workflow
"job_name": string;
+ // Analysis key, normally composed from the workflow path and job name
"analysis_key": string;
+ // Value of the matrix for this instantiation of the job
"matrix_vars"?: string;
- "languages": string;
+ // Commit oid that the workflow was triggered on
"commit_oid": string;
+ // Ref that the workflow was triggered on
"ref": string;
+ // Name of the action being executed
"action_name": ActionName;
+ // Version if the action being executed, as a commit oid
"action_oid": string;
+ // Time the first action started. Normally the init action
"started_at": string;
+ // Time this action started
+ "action_started_at": string;
+ // Time this action completed, or undefined if not yet completed
"completed_at"?: string;
+ // State this action is currently in
"status": ActionStatus;
+ // Cause of the failure (or undefined if status is not failure)
"cause"?: string;
+ // Stack trace of the failure (or undefined if status is not failure)
"exception"?: string;
}
@@ -161,26 +175,17 @@ interface StatusReport {
*
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
* @param status The status. Must be 'success', 'failure', or 'starting'
+ * @param startedAt The time this action started executing.
* @param cause Cause of failure (only supply if status is 'failure')
* @param exception Exception (only supply if status is 'failure')
*/
-async function createStatusReport(
+export async function createStatusReportBase(
actionName: ActionName,
status: ActionStatus,
+ actionStartedAt: Date,
cause?: string,
exception?: string):
- Promise {
-
- // If this is not the init action starting up or aborting then try to load the config.
- // If it fails then carry because it's important to still send the status report.
- let config: configUtils.Config | undefined = undefined;
- if (actionName !== 'init' || (status !== 'starting' && status !== 'aborted')) {
- try {
- config = await configUtils.getConfig();
- } catch (e) {
- core.error('Unable to load config: ' + e);
- }
- }
+ Promise {
const commitOid = process.env['GITHUB_SHA'] || '';
const ref = getRef();
@@ -192,21 +197,23 @@ async function createStatusReport(
const workflowName = process.env['GITHUB_WORKFLOW'] || '';
const jobName = process.env['GITHUB_JOB'] || '';
const analysis_key = await getAnalysisKey();
- const languages = config?.languages?.join(',') || "";
- const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT] || new Date().toISOString();
- core.exportVariable(sharedEnv.CODEQL_ACTION_STARTED_AT, startedAt);
+ let workflowStartedAt = process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT];
+ if (workflowStartedAt === undefined) {
+ workflowStartedAt = actionStartedAt.toISOString();
+ core.exportVariable(sharedEnv.CODEQL_WORKFLOW_STARTED_AT, workflowStartedAt);
+ }
- let statusReport: StatusReport = {
+ let statusReport: StatusReportBase = {
workflow_run_id: workflowRunID,
workflow_name: workflowName,
job_name: jobName,
analysis_key: analysis_key,
- languages: languages,
commit_oid: commitOid,
ref: ref,
action_name: actionName,
action_oid: "unknown", // TODO decide if it's possible to fill this in
- started_at: startedAt,
+ started_at: workflowStartedAt,
+ action_started_at: actionStartedAt.toISOString(),
status: status
};
@@ -231,9 +238,16 @@ async function createStatusReport(
/**
* Send a status report to the code_scanning/analysis/status endpoint.
*
- * Returns the status code of the response to the status request.
+ * Optionally checks the response from the API endpoint and sets the action
+ * as failed if the status report failed. This is only expected to be used
+ * when sending a 'starting' report.
+ *
+ * Returns whether sending the status report was successful of not.
*/
-async function sendStatusReport(statusReport: StatusReport): Promise {
+export async function sendStatusReport](
+ statusReport: S,
+ ignoreFailures?: boolean): Promise {
+
const statusReportJSON = JSON.stringify(statusReport);
core.debug('Sending status report: ' + statusReportJSON);
@@ -245,68 +259,27 @@ async function sendStatusReport(statusReport: StatusReport): Promise {
repo: repo,
data: statusReportJSON,
});
- return statusResponse.status;
-}
-/**
- * Send a status report that an action is starting.
- *
- * If the action is `init` then this also records the start time in the environment,
- * and ensures that the analysed languages are also recorded in the envirenment.
- *
- * Returns true unless a problem occurred and the action should abort.
- */
-export async function reportActionStarting(action: ActionName): Promise {
- const statusCode = await sendStatusReport(await createStatusReport(action, 'starting'));
-
- // If the status report request fails with a 403 or a 404, then this is a deliberate
- // message from the endpoint that the SARIF upload can be expected to fail too,
- // so the action should fail to avoid wasting actions minutes.
- //
- // Other failure responses (or lack thereof) could be transitory and should not
- // cause the action to fail.
- if (statusCode === 403) {
- core.setFailed('The repo on which this action is running is not opted-in to CodeQL code scanning.');
- return false;
- }
- if (statusCode === 404) {
- core.setFailed('Not authorized to used the CodeQL code scanning feature on this repo.');
- return false;
+ if (!ignoreFailures) {
+ // If the status report request fails with a 403 or a 404, then this is a deliberate
+ // message from the endpoint that the SARIF upload can be expected to fail too,
+ // so the action should fail to avoid wasting actions minutes.
+ //
+ // Other failure responses (or lack thereof) could be transitory and should not
+ // cause the action to fail.
+ if (statusResponse.status === 403) {
+ core.setFailed('The repo on which this action is running is not opted-in to CodeQL code scanning.');
+ return false;
+ }
+ if (statusResponse.status === 404) {
+ core.setFailed('Not authorized to used the CodeQL code scanning feature on this repo.');
+ return false;
+ }
}
return true;
}
-/**
- * Report that an action has failed.
- *
- * Note that the started_at date is always that of the `init` action, since
- * this is likely to give a more useful duration when inspecting events.
- */
-export async function reportActionFailed(action: ActionName, cause?: string, exception?: string) {
- await sendStatusReport(await createStatusReport(action, 'failure', cause, exception));
-}
-
-/**
- * Report that an action has succeeded.
- *
- * Note that the started_at date is always that of the `init` action, since
- * this is likely to give a more useful duration when inspecting events.
- */
-export async function reportActionSucceeded(action: ActionName) {
- await sendStatusReport(await createStatusReport(action, 'success'));
-}
-
-/**
- * Report that an action has been aborted.
- *
- * Note that the started_at date is always that of the `init` action, since
- * this is likely to give a more useful duration when inspecting events.
- */
-export async function reportActionAborted(action: ActionName, cause?: string) {
- await sendStatusReport(await createStatusReport(action, 'aborted', cause));
-}
-
/**
* Get the array of all the tool names contained in the given sarif contents.
*