diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js
index 30d7af55aa627bd0af2d0f11e24e86ddb1f0c24f..b4dc762c8e3ca6aa8a089aab624481775fdb88ea 100644
--- a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js
+++ b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js
@@ -1,2 +1 @@
-(function(){var e,t,n,o,r,i,s;o=25,s={_whatToTrace:[function(e,t){return"groupBy=substr("+e+",1)"},function(e,t){return e+"="+t+"*&groupBy="+e},function(e,t){return e+"="+t}],ipAddr:[function(e,t){return"groupBy=net("+e+",16,1)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",32,2)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",48,3)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",128,4)"},function(e,t){return e+"="+t+"&groupBy=_whatToTrace"},function(e,t,n){return n.replace(/\&groupBy.*$/,"")+"&_whatToTrace="+t}],_startTime:[function(e,t){return"groupBy=substr("+e+",8)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",10)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",11)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",12)"},function(e,t){return e+"="+t+"*&groupBy=_whatToTrace"},function(e,t,n){return console.log(e),console.log(t),console.log(n),n.replace(/\&groupBy.*$/,"")+"&_whatToTrace="+t}],doubleIp:[function(e,t){return e},function(e,t){return"_whatToTrace="+t+"&groupBy=ipAddr"},function(e,t,n){return n.replace(/\&groupBy.*$/,"")+"&ipAddr="+t}],_session_uid:[function(e,t){return"groupBy=substr("+e+",1)"},function(e,t){return e+"="+t+"*&groupBy="+e},function(e,t){return e+"="+t}]},i={_whatToTrace:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null},ipAddr:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),n>0&&n<4&&!t.match(/^\d+\.\d/)&&o<2?e+"="+t+"*&groupBy=net("+e+","+(16*n+4*(o+1))+","+(1+n+o)+")":null},_startTime:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),n>3?e+"="+t+"*&groupBy=substr("+e+","+(10+n+o)+")":null},_session_uid:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null}},t="_password",e={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]},r={session:[{title:"deleteSession",icon:"trash"}],home:[]},n=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]),n.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(n,u,l,a,c){var p,d,g,f;return n.links=links,n.menulinks=menulinks,n.staticPrefix=staticPrefix,n.scriptname=scriptname,n.formPrefix=formPrefix,n.impPrefix=impPrefix,n.sessionTTL=sessionTTL,n.availableLanguages=availableLanguages,n.waiting=!0,n.showM=!1,n.showT=!0,n.data=[],n.currentScope=null,n.currentSession=null,n.menu=r,n.translateP=u.translateP,n.translate=u.translate,n.translateTitle=function(e){return u.translateField(e,"title")},f="global",n.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(n.currentNode,n);break;case"string":n[e.action]();break;default:console.log(typeof e.action)}return n.showM=!1},n.deleteOIDCConsent=function(e,t){var o;return o=angular.element(".data-"+t),o.remove(),n.waiting=!0,c.delete(scriptname+"sessions/OIDCConsent/"+f+"/"+n.currentSession.id+"?rp="+e+"&epoch="+t).then(function(e){return n.waiting=!1},function(e){return n.waiting=!1}),n.showT=!1},n.deleteSession=function(){return n.waiting=!0,c.delete(scriptname+"sessions/"+f+"/"+n.currentSession.id).then(function(e){return n.currentSession=null,n.currentScope.remove(),n.waiting=!1},function(e){return n.currentSession=null,n.currentScope.remove(),n.waiting=!1})},n.stoggle=function(e){var t;return t=e.$modelValue,0===t.nodes.length&&n.updateTree(t.value,t.nodes,t.level,t.over,t.query,t.count),e.toggle()},n.displaySession=function(o){var r,i;return i=function(o){var r,i,s,u,l,a,c,p,d,g,f,h,_,m,T,y,w,v,S,$,B,b,D,L,A,P,x,C,I,k,O,R,E,H,M,U;r=function(e,t){var n,r,i,s;i=[],r=new RegExp(e);for(n in o)s=o[n],n.match(r)&&s&&(i.push({title:n,value:s}),delete o[n]);if(i.length>0)return I.push({title:t,nodes:i})},E=o._utime,g=o._session_id;for(_ in o)U=o[_],U?("string"==typeof o&&U.match(/; /)&&(o[_]=U.split("; ")),"object"!=typeof o[_]&&(t.match(new RegExp("\b"+_+"\b"))?o[_]="********":_.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)?o[_]=n.localeDate(U):_.match(/^(_startTime|_updateTime)$/)&&(o[_]=n.strToLocaleDate(U)))):delete o[_];I=[];for(l in e){for(u=e[l],R=[],d=0,T=u.length;d0&&I.push({title:"__"+l+"__",nodes:R})}if(r("^openid","OpenID"),r("^notification_(.+)","__notificationsDone__"),o._loginHistory){if(M=[],o._loginHistory.successLogin)for(x=o._loginHistory.successLogin,B=0,v=x.length;Bt.title?1:e.title real attribute"),P.push(c)):O.push(c);return M=O.concat(P),I.push({title:"__attributesAndMacros__",nodes:M}),{_utime:E,id:g,nodes:I}},n.currentScope=o,r=o.$modelValue.session,c.get(scriptname+"sessions/"+f+"/"+r).then(function(e){return n.currentSession=i(e.data)}),n.showT=!1},n.localeDate=function(e){var t;return t=new Date(1e3*e),t.toLocaleString()},n.isValid=function(e,t){var n,o,r;return r=l.path(),o=Date.now()/1e3,console.log("Path",r),console.log("Session epoch",e),console.log("Current date",o),console.log("Session TTL",sessionTTL),n=o-eo&&i[n.type]&&(h=i[n.type](n.type,e,r,u,l))?(u++,d=h,r-=1):u=0,c.get(scriptname+"sessions/"+f+"?"+d).then(function(o){var i,s,l,a,c;if(i=o.data,i.result){for(c=i.values,s=0,l=c.length;s level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null},ipAddr:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),0 level",n,"over",o),3 level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null}},M={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]},s={session:[{title:"deleteSession",icon:"trash"}],home:[]},angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]).controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(H,t,i,e,o){var d,n,r,g;return H.links=links,H.menulinks=menulinks,H.staticPrefix=staticPrefix,H.scriptname=scriptname,H.formPrefix=formPrefix,H.impPrefix=impPrefix,H.sessionTTL=sessionTTL,H.availableLanguages=availableLanguages,H.waiting=!0,H.showM=!1,H.showT=!0,H.data=[],H.currentScope=null,H.currentSession=null,H.menu=s,H.translateP=t.translateP,H.translate=t.translate,H.translateTitle=function(e){return t.translateField(e,"title")},g="global",H.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(H.currentNode,H);break;case"string":H[e.action]();break;default:console.log(typeof e.action)}return H.showM=!1},H.deleteOIDCConsent=function(e,t){return angular.element(".data-"+t).remove(),H.waiting=!0,o.delete(scriptname+"sessions/OIDCConsent/"+g+"/"+H.currentSession.id+"?rp="+e+"&epoch="+t).then(function(e){return H.waiting=!1},function(e){return H.waiting=!1}),H.showT=!1},H.deleteSession=function(){return H.waiting=!0,o.delete(scriptname+"sessions/"+g+"/"+H.currentSession.id).then(function(e){return H.currentSession=null,H.currentScope.remove(),H.waiting=!1},function(e){return H.currentSession=null,H.currentScope.remove(),H.waiting=!1})},H.stoggle=function(e){var t;return 0===(t=e.$modelValue).nodes.length&&H.updateTree(t.value,t.nodes,t.level,t.over,t.query,t.count),e.toggle()},H.displaySession=function(e){var t,n;return n=function(s){var e,t,n,o,r,i,u,l,a,c,p,d,g,f,h,_,m,T,y,w,v,S,$,B,b,D,L,A,P,x,C,I,k,O,R,E;for(g in e=function(e,t){var n,o,r,i;for(n in r=[],o=new RegExp(e),s)i=s[n],n.match(o)&&i&&(r.push({title:n,value:i}),delete s[n]);if(0t.title?1:e.title real attribute"),D.push(u)):C.push(u);return R=C.concat(D),P.push({title:"__attributesAndMacros__",nodes:R}),{_utime:k,id:c,nodes:P}},t=(H.currentScope=e).$modelValue.session,o.get(scriptname+"sessions/"+g+"/"+t).then(function(e){return H.currentSession=n(e.data)}),H.showT=!1},H.localeDate=function(e){return new Date(1e3*e).toLocaleString()},H.isValid=function(e,t){var n,o,r;return r=i.path(),o=Date.now()/1e3,console.log("Path",r),console.log("Session epoch",e),console.log("Current date",o),console.log("Session TTL",sessionTTL),n=o-econf->{certificateResetByMailCeaAttribute}
|| "description";
my $certificateAttribute =
@@ -29,8 +23,6 @@ sub modifCertificate {
|| "userCertificate;binary";
# Set the dn unless done before
- #
- #
my $dn;
if ( $req->userData->{_dn} ) {
$dn = $req->userData->{_dn};
@@ -41,7 +33,7 @@ sub modifCertificate {
$self->logger->debug("Get DN from session data: $dn");
}
unless ($dn) {
- $self->logger->error('"dn" is not set, aborting password modification');
+ $self->logger->error('"dn" is not set, aborting certificate reset');
return PE_ERROR;
}
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CertificateResetByMail.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CertificateResetByMail.pm
index b8ef82be2d2a554579642a96ed31fea48df6cf68..dca48f7a924041670cb71c24ec6eabfde79bc666 100644
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CertificateResetByMail.pm
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CertificateResetByMail.pm
@@ -261,8 +261,7 @@ sub _certificateReset {
my $mailSession = $self->getCertificateSession( $req->{user} );
unless ( $mailSession or $mailToken ) {
- # Create a new session
-
+ ## Create a new session
my $infos = {};
# Set _utime for session autoremove
@@ -423,7 +422,7 @@ sub modifyCertificate {
my $x509;
my $notAfter;
- $self->logger->debug('Change your Certificate form response');
+ $self->logger->debug('Change your certificate form response');
if ( my $token = $req->param('token') ) {
$req->sessionInfo( $self->ott->getToken($token) );
@@ -451,10 +450,9 @@ sub modifyCertificate {
#Updload certificate
my $upload = $req->uploads->{certif};
- unless ( $upload->size > 0 ) { return PE_RESETCERTIFICATE_FORMEMPTY; }
-
- # Get Certificate
+ return PE_RESETCERTIFICATE_FORMEMPTY unless ( $upload->size > 0 );
+ # Get certificate
my $file = $upload->path;
$self->userLogger->debug( "Temporaly file " . $file );
@@ -472,11 +470,9 @@ sub modifyCertificate {
unless ($x509) {
$self->userLogger->debug( "Unable to decode certificate for user "
. Net::SSLeay::ERR_error_string( Net::SSLeay::ERR_get_error() ) );
-
- #return PE_CERTIFICATE_INVALID;
return PE_RESETCERTIFICATE_INVALID;
}
- $self->userLogger->debug("Certificate decoded successfully");
+ $self->userLogger->debug("Certificate successfully decoded");
$notAfter = Net::SSLeay::P_ASN1_TIME_get_isotime(
Net::SSLeay::X509_get_notAfter($x509) );
@@ -487,25 +483,22 @@ sub modifyCertificate {
Net::SSLeay::X509_get_serialNumber($x509) );
$self->userLogger->debug(
-"Certificate will expire after $notAfter, Issuer $x509issuer and serialNumber $x509serial"
+"Certificate will expire after $notAfter, Issuer $x509issuer and serialNumber $x509serial"
);
- # Check Certificate Validity before store
+ # Check certificate validity before store
if (
$self->checkCertificateValidity( $notAfter,
$self->conf->{certificateResetByMailValidityDelay} ) == 0
)
{
$self->userLogger->debug(
-"Your cettificate is no longer valid in $self->conf->{certificateValidityDelay}"
+"Your certificate is no longer valid in $self->conf->{certificateValidityDelay}"
);
return PE_RESETCERTIFICATE_INVALID;
-
- #return PE_PASSWORD_MISMATCH;
}
# Build serial number hex: example f3:08:52:63:28:29:fa:e2
-
my @numberstring = split //, lc($x509serial);
my $serial = "";
for ( my $i = 0 ; $i <= $#numberstring ; $i += 2 ) {
@@ -514,7 +507,6 @@ sub modifyCertificate {
}
# format issuer in the good format example "CN=CA,OU=CISIRH,O=MINEFI,L=Paris,ST=France,C=FR"
-
my @issuertab = split /\//, $x509issuer;
shift(@issuertab);
my $issuer = join( ",", reverse(@issuertab) );
@@ -528,7 +520,7 @@ sub modifyCertificate {
# Get attribut userCertificate;binary value
my $cert = $self->certificateHash($file);
- # modif the ldap certificate attribute
+ # Modify ldap certificate attribute
$req->user( $req->{sessionInfo}->{_user} );
my $result =
$self->registerModule->modifCertificate( $certificatExactAssertion,
@@ -539,7 +531,7 @@ sub modifyCertificate {
#
return $result unless ( $result == PE_OK );
- # Send mail to notify the certificate reset sucessfully
+ # Send mail to notify the certificate has been successfully reset
$req->data->{mailAddress} ||=
$self->p->getFirstValue(
$req->{sessionInfo}->{ $self->conf->{mailSessionKey} } );
@@ -562,8 +554,9 @@ sub modifyCertificate {
else {
# Use HTML template
- $body = $self->loadTemplate(
- 'mail_certificatReset',
+ $body = $self->loadMailTemplate(
+ $req,
+ 'mail_certificateReset',
filter => $tr,
params => \%tplPrms
);
@@ -627,7 +620,7 @@ sub display {
$tplPrm{MAIL_TOKEN} = $req->data->{mailToken};
}
- # Display captcha if it's enabled
+ # Display captcha if enabled
if ( $req->captcha ) {
$tplPrm{CAPTCHA_SRC} = $req->captcha;
$tplPrm{CAPTCHA_SIZE} = $self->conf->{captcha_size};
@@ -669,7 +662,7 @@ sub display {
$tplPrm{DISPLAY_MAILSENT} = 1;
}
- # Display Certificate Reset form
+ # Display certificate reset form
elsif ( $req->data->{mailToken}
and $req->error != PE_MAILERROR
and $req->error != PE_BADMAILTOKEN
@@ -679,7 +672,7 @@ sub display {
$tplPrm{DISPLAY_CERTIF_FORM} = 1;
}
- # Display Certificate Reset form again if certificate invalid
+ # Display certificate reset form again if certificate invalid
elsif ($req->error == PE_RESETCERTIFICATE_FORMEMPTY
|| $req->error == PE_RESETCERTIFICATE_INVALID )
{
@@ -719,7 +712,6 @@ sub getCertificateSession {
}
# Use Certificate Update parameter to send mail
-
sub sendmail {
my ( $self, $mail, $subject, $body, $html ) = @_;
diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js
index 150913fdacb6c60cf214478b6b23fb52a37b0a07..f5b43a2e0a1210683acb890d637571219413cbda 100644
--- a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js
+++ b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js
@@ -1,2 +1 @@
-(function(){var t,e,n,a,r,i,o,s,l,u,c,g,p,h,f=[].indexOf||function(t){for(var e=0,n=this.length;e div.category",update:function(){return u()}}),o(),$("div.message").fadeIn("slow"),$("input[name=timezone]").val(-(new Date).getTimezoneOffset()/60),E=$("#menu").tabs({active:0}),L=$('#menu a[href="#'+t.displaytab+'"]').parent().index(),L<0&&(L=0),E.tabs("option","active",L),c=$("#authMenu").tabs({active:0}),t.choicetab&&c.tabs("option","active",$('#authMenu a[href="#'+t.choicetab+'"]').parent().index()),t.login?$("input[type=password]:first").focus():0===$("input[autofocus]").length&&$("input[type!=hidden]:first").focus(),t.newwindow&&$("#appslist a").attr("target","_blank"),$("p.removeOther").length&&(e=$("form.login").attr("action"),P=$("form.login").attr("method"),g="",-1!==e.indexOf("?")?e.substring(0,e.indexOf("?")):g=e+"?",$("form.login input[type=hidden]").each(function(t){return g+="&"+$(this).attr("name")+"="+$(this).val()}),j=$("p.removeOther a").attr("href")+"&method="+P+"&url="+btoa(g),$("p.removeOther a").attr("href",j)),m=n("llnglanguage"))f.call(window.availableLanguages,m)<0&&(m=window.availableLanguages[0]);else if(navigator){for(w=[],b=[],I=[navigator.language],navigator.languages&&(I=navigator.languages),C=window.availableLanguages,h=0,y=C.length;h ';for(d=0,x=I.length;d",m),s("llnglanguage",m),p(m),v="",A=window.availableLanguages,S=0,O=A.length;S ';return $("#languages").html(v),$(".langicon").on("click",function(){return m=$(this).attr("title"),s("llnglanguage",m),p(m)}),t.pingInterval&&t.pingInterval>0&&window.setTimeout(r,t.pingInterval),$(".localeDate").each(function(){var t;return t=new Date(1e3*$(this).attr("val")),$(this).text(t.toLocaleString())}),$(".oidcConsent").on("click",function(){return i($(this).attr("partner"))})})}).call(this);
-//# sourceMappingURL=lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js.map
\ No newline at end of file
+(function(){var L,e,E,P,S,D,I,_,t,C,h,o,N,s,A=[].indexOf||function(t){for(var e=0,n=this.length;e div.category",update:function(){return C()}}),I(),$("div.message").fadeIn("slow"),$("input[name=timezone]").val(-(new Date).getTimezoneOffset()/60),v=$("#menu").tabs({active:0}),(m=$('#menu a[href="#'+L.displaytab+'"]').parent().index())<0&&(m=0),v.tabs("option","active",m),n=$("#authMenu").tabs({active:0}),L.choicetab&&n.tabs("option","active",$('#authMenu a[href="#'+L.choicetab+'"]').parent().index()),L.login?$("input[type=password]:first").focus():0===$("input[autofocus]").length&&$("input[type!=hidden]:first").focus(),L.newwindow&&$("#appslist a").attr("target","_blank"),$("p.removeOther").length&&(t=$("form.login").attr("action"),w=$("form.login").attr("method"),a="",-1!==t.indexOf("?")?t.substring(0,t.indexOf("?")):a=t+"?",$("form.login input[type=hidden]").each(function(t){return a+="&"+$(this).attr("name")+"="+$(this).val()}),f=$("p.removeOther a").attr("href")+"&method="+w+"&url="+btoa(a),$("p.removeOther a").attr("href",f)),o=E("llnglanguage"))A.call(window.availableLanguages,o)<0&&(o=window.availableLanguages[0]);else if(navigator){for(l=[],u=[],x=[navigator.language],navigator.languages&&(x=navigator.languages),r=0,c=(O=window.availableLanguages).length;r ';for(i=0,g=x.length;i",o),_("llnglanguage",o),N(o),s="",b=0,h=(k=window.availableLanguages).length;b ';return $("#languages").html(s),$(".langicon").on("click",function(){return o=$(this).attr("title"),_("llnglanguage",o),N(o)}),L.pingInterval&&0
Hello $cn,
-Your certificate was reset sucessfully.
+Your certificate has been successfully reset!
diff --git a/lemonldap-ng-portal/t/44-CertificateResetByMail-LDAP.t b/lemonldap-ng-portal/t/44-CertificateResetByMail-LDAP.t
index 2acc0a89a4ece09e36076d42f1277e712ade8c96..580a95b48c1814d38c6c1cd3d5d1f46f5ab95750 100644
--- a/lemonldap-ng-portal/t/44-CertificateResetByMail-LDAP.t
+++ b/lemonldap-ng-portal/t/44-CertificateResetByMail-LDAP.t
@@ -47,7 +47,7 @@ SKIP: {
certificateResetByMailStep1Body =>
'Click here to confirm your mail. It will expire $expMailDate',
certificateResetByMailStep2Body =>
- 'Certificate Reset sucessfully!',
+ 'Certificate successfully reset!',
certificateValidityDelay => 30
}
@@ -210,7 +210,7 @@ lkRrWfQftwmLyNIu3HfSgXlgAZS30ymfbzBU
}
);
- ok( mail() =~ /Certificate Reset sucessfully/, 'Certificate was changed' );
+ ok( mail() =~ /Certificate successfully reset/, 'Certificate has been reset' );
}
count($maintests);