Best JavaScript code snippet using mocha
monitoring2.js
Source:monitoring2.js
1/* 2 * To change this license header, choose License Headers in Project Properties.3 * To change this template file, choose Tools | Templates4 * and open the template in the editor.5 */6/* global moment, cp, headerName, token, uuid, sotoken, filterOldJson ,*/7var socket;8var stompClient;9var timeformat = "DD/MM HH:mm:ss";10var timeformatsmall = "HH:mm:ss";11var errorlistJson = {};12var array_regular = [];13var array_spec = [];14//var strop = "<option value='~'>contains</option><option value='!~'>doesn't contain</option><option value='=='>equal</option><option value='!='>not equal</option><option value='!*'>none</option><option value='*'>any</option> <option value='regexp'>RegExp true</option><option value='regexp'>RegExp false</option>";15var strop = "<option value='~'>" + locale['contains'] + "</option><option value='!~'>" + locale['doesntContain'] + "</option><option value='=='>" + locale['equal'] + "</option><option value='!='>" + locale['notEqual'] + "</option>";16var eniumop = "<option value='='>" + locale['is'] + "</option><option value='!'>" + locale['isNot'] + "</option>";17function redrawBoard() {18 $(".monitorlist ul").html("");19 if (Object.keys(errorlistJson).length > 0)20 {21 DrawErrorList(errorlistJson, $(".metrictable"));22 }23}24function connectstompClient()25{26 var headers = {};27 headers[headerName] = token;28 headers["sotoken"] = sotoken;29 headers["options"] = JSON.stringify(optionsJson);30 realtimeconnect(headers);31}32function realtimeconnect(head)33{34 console.log("connect START");35 socket = new SockJS(cp + '/subscribe');36 stompClient = Stomp.over(socket);37 stompClient.debug = null;38 stompClient.connect(head,39 function (frame) {40 console.log("Monitor connected");41 stompClient.subscribe('/user/' + uuid + '/' + sotoken + '/errors', aftersubscribe);42// console.log(frame);43 },44 function (message) {45 console.log("Monitor:" + message);46 setTimeout(function () {47 realtimeconnect(head);48 }, 6000);49 });50}51function aftersubscribe(error) {52 $(".metrictable").find("tr.wait").remove();53 var errorjson = JSON.parse(error.body);54 if (errorlistJson[errorjson.hash])55 {56 errorjson.index = errorlistJson[errorjson.hash].index;57 }58 if (typeof (errorjson.index) !== "undefined")59 {60 errorjson.index = errorjson.index + 1;61 } else62 {63 errorjson.index = 0;64 }65 if (errorlistJson[errorjson.hash])66 {67 if (errorjson.time >= errorlistJson[errorjson.hash].time)68 {69 if (errorjson.level === -1)70 {71 delete errorlistJson[errorjson.hash];72 } else73 {74 errorlistJson[errorjson.hash] = errorjson;75 }76 reDrawErrorList(errorlistJson, "monitorlist", errorjson);77 }78 } else79 {80 if (errorjson.level === -1)81 {82 delete errorlistJson[errorjson.hash];83 } else84 {85 errorlistJson[errorjson.hash] = errorjson;86 }87 reDrawErrorList(errorlistJson, "monitorlist", errorjson);88 }89 if (Object.keys(errorlistJson).length > 200)90 {91// stompClient.disconnect();92 $('#manyalert').fadeIn();93 } else94 {95 $('#manyalert').fadeOut();96 }97// console.log(errorlistJson[errorjson.hash]);98}99function findeByhash(element, array) {100 for (var i = 0; i < array.length; i++) {101 if (array[i].hash === element.hash) {102 return i;103 }104 }105 return -1;106}107function findeBy_ihash(hash, array) {108 for (var i = 0; i < array.length; i++) {109 if (array[i].hash === hash) {110 return i;111 }112 }113 return -1;114}115function drawUL(errorjson, table, hashindex, update) { 116 if (typeof (hashindex) === "undefined")117 {118 hashindex = null;119 }120 if (typeof (update) === update)121 {122 type = false;123 }124 var message = "";125 if (errorjson.isspec === 1)126 {127 message = errorjson.message;128 } else129 {130 var val = 0;131 var count = 0;132 for (var key in errorjson.values)133 {134 val = val + errorjson.values[key].value;135 count++;136// val = errorjson.values[key].value;137 }138 val = val / count;139 if (val > 1000)140 {141 val = format_metric(errorjson.values[key].value);142 } else143 {144 if (!Number.isInteger(val))145 {146 val = val.toFixed(2);147 }148 }149 message = message + val;150 }151 var starttime = "";152 if (typeof (errorjson.time) !== "undefined")153 {154 starttime = moment(errorjson.time * 1).format(timeformatsmall);155 }156 var arrowclass = "";157 var color = "red";158 if (errorjson.action === 2)159 {160 arrowclass = "fas fa-long-arrow-alt-down";161 color = "green";162 }163 if (errorjson.action === 3)164 {165 arrowclass = "fas fa-long-arrow-alt-up";166 color = "red";167 }168 var eRclass = "level_" + errorjson.level;169 var UlID = "regularlist";170 if (errorjson.isspec !== 0)171 {172 eRclass = eRclass + " spec";173 UlID = "speciallist";174 }175 if (errorjson.flap > 5)176 {177 console.log(errorjson.info.name + " " + errorjson.flap);178 eRclass = eRclass + " flapdetect";179 }180 181 if (!update)182 {183 var html = '<li style="display:none" id="' + errorjson.hash + '" class="' + eRclass + '" time="' + moment().format("x") + '">';184 var re = /_/gi;185 optionsJson.f_col.forEach(186 function (entry) {187 var obj = $('.f_col option[value=' + entry + ']');188// if (obj.length === 0)189// {190// console.log(entry);191// }192 switch (obj.attr("key")) {193 case "actions":194 {195 if (errorjson.isspec === 0)196 {197// html = html + '<div class="inline icons"><input type="checkbox" class="rawflat" name="table_records"><div class="fa-div"> <a href="' + cp + '/chart/' + errorjson.hash + '" target="_blank"><i class="fa fas fa-chart-area"></i></a><a href="' + cp + '/history/' + errorjson.hash + '" target="_blank"><i class="fa fa-history"></i></a> <i class="action fa ' + arrowclass + '" style="color:' + color + ';"></i></div></div>';198 html = html + '<div class="icons"><i class="pull-left action fa ' + arrowclass + '" style="color:' + color + ';"></i> <a href="' + cp + '/chart/' + errorjson.hash + '" target="_blank"><i class="fa fas fa-chart-area"></i></a><a href="' + cp + '/history/' + errorjson.hash + '" target="_blank"><i class="fa fa-history"></i></a>' +199 '<a href="#"><i class="fa far fa-bell-slash resetregretion"></i></a>' +200 '<a href="#"><i class="fa far fa-trash-alt deletemetric"></i></a>' +201// '<a href="#"><span class="glyphicon glyphicon-trash resetrules" aria-hidden="true"></span></a>' +202 '</div>';203 } else204 {205 html = html + '<div class="icons"><i class="fa fa-bell pull-left"></i> <a href="' + cp + '/history/' + errorjson.hash + '" target="_blank"><i class="fa fa-history"></i></a><a href="#"><i class="fa far fa-trash-alt deletemetric"></i></a></div>';206 }207 break;208 }209 case "message":210 {211 if (errorjson.isspec !== 0)212 {213 html = html + '<div class="message"><i class="fa fa-comment-o"></i> ' + message + '</div>';214 }215 break;216 }217 case "info":218 {219 if (errorjson.isspec === 0)220 {221 var valuearrowclass = "fas fa-long-arrow-alt-down";222 if (errorjson.upstate)223 {224 valuearrowclass = "fas fa-long-arrow-alt-up";225 }226 html = html + '<div class="valueinfo"><i class="action fa ' + valuearrowclass + '"></i> ' + message + '</div>';227 }228 break;229 }230 case "StartTime":231 {232 var st = errorjson.starttimes[errorjson.level] ? errorjson.starttimes[errorjson.level] : errorjson.time;233 html = html + '<div class="inline starttime">' + moment(st * 1).format(timeformat) + '</div>';234 break;235 }236 case "LastTime":237 {238 var st = errorjson.time;239 html = html + '<div class="inline timelocal">' + moment(st * 1).format(timeformatsmall) + '</div>';240 break;241 }242 case "updateinterval":243 {244 var st = errorjson.starttimes[errorjson.level] ? errorjson.starttimes[errorjson.level] : errorjson.time;245 html = html + '<div class="inline timeinterval badge bg-white">0</div>';246 break;247 }248 case "updatecounter":249 {250 html = html + '<div class="inline updatecounter badge">0</div>';251 break;252 }253 case "duration":254 {255 var st = errorjson.starttimes[errorjson.level] ? errorjson.starttimes[errorjson.level] : errorjson.time;256 var lt = errorjson.time;257 html = html + '<div class="inline duration badge">' + moment.duration(lt - st).humanize() + '</div>';258 break;259 }260 case "levelname":261 {262 html = html + '<div class="label label-info level inline">' + locale['level_'+errorjson.level] + '</div>';263 break;264 }265 //html = html + "<div><span class='timeinterval'>0</span> <span class='refreshes'>1</span></div>";266 case "info.name":267 {268 var value = errorjson.info.name;269 if (errorjson.isspec === 0)270 {271 if (value)272 {273 html = html + '<div class="metricname ' + entry.replace(re, " ") + '"><div> <i class="samegroup fas fa-object-group" data-key="_name" data-value="' + value + '" data-toggle="tooltip" data-placement="top" title="'+ locale['title.selectIdentic'] +'"></i> <a href="' + cp + '/metriq/' + errorjson.hash + '" target="_blank">' + value + '</a></div></div>';274 }275 } else276 {277 html = html + '<div class="metricname ' + entry.replace(re, " ") + '"><div> <i class="samegroup fas fa-object-group" data-key="_name" data-value="' + value + '" data-toggle="tooltip" data-placement="top" title="'+ locale["title.selectIdentic"] +'"></i> ' + value + '</div></div>';278 }279 break;280 }281 default:282 {283// console.log(entry);284// console.log(obj);285// console.log(obj.attr("key"));286 if (obj.attr("key"))287 {288 var path = obj.attr("key").split(".");289 } else290 {291 var path = entry.split("_");292 }293 var value = errorjson;294 $.each(path, function (i, item) {295 if (value)296 {297 value = value[item];298 }299 });300 if (value)301 {302 html = html + '<div class="' + entry.replace(re, " ") + '"><div><i class="samegroup fas fa-object-group" data-key="' + path.join("_") + '" data-value="' + value + '" data-toggle="tooltip" data-placement="top" title ="'+ locale["title.selectIdentic"]+'"></i> ' + value + '</div></div>';303 }304 break;305 }306 }307 }308 );309 html = html + "</li>";310 $("." + table).find("ul#" + UlID).prepend(html);311 312 $("." + table).find("li#" + errorjson.hash).find('[data-toggle="tooltip"]').tooltip();313 $("." + table).find("li#" + errorjson.hash).show("slide", {direction: "left"}, 1000);314 } else315 {316 $("." + table).find("li#" + hashindex + " .info.metricname").effect("shake", {direction: "down", distance: 2}, "slow");317 /*318 var index = $("." + table).find("li#" + hashindex).index() % 10+1; 319 var audio = new Audio(cp+"/assets/Sounds/"+index+".mp3");320 audio.play();321 */322 $("." + table).find("li#" + hashindex).removeClass(function (index, className) {323 return (className.match(/(^|\s)level_\S+/g) || []).join(' ');324 });325 $("." + table).find("li#" + hashindex).addClass("level_" + errorjson.level);326 //var eRclass = "level_" + errorjson.level;327// .attr("class", eRclass);328 $("." + table).find("li#" + hashindex + " .level").html(locale['level_'+errorjson.level]);329 var st = errorjson.starttimes[errorjson.level] ? errorjson.starttimes[errorjson.level] : errorjson.time;330 var lt = errorjson.time;331 $("." + table).find("li#" + hashindex + " .duration").html(moment.duration(lt - st).humanize());332 if (errorjson.starttimes[errorjson.level])333 {334 $("." + table).find("li#" + hashindex + " .starttime").html(moment(st * 1).format(timeformat));335 }336// var rectime=moment();337 var rectime = moment(lt);338 $("." + table).find("li#" + hashindex + " .timelocal").html(rectime.format(timeformatsmall));339 $("." + table).find("li#" + hashindex).attr('time', moment().format("x"));340 var refreshes = $("." + table).find("li#" + hashindex + " .updatecounter");341 var val = refreshes.text() * 1 + 1;342 refreshes.text(val);343//errorjson.flap344 if (errorjson.isspec === 0)345 {346 var valuearrowclass = "fas fa-long-arrow-alt-down";347 if (errorjson.upstate)348 {349 valuearrowclass = "fas fa-long-arrow-alt-up";350 }351 $("." + table).find("li#" + hashindex + " .valueinfo").html('<i class="action fa ' + valuearrowclass + '"></i> ' + message);352 } else353 {354 $("." + table).find("li#" + hashindex + " .message").html('<i class="action fa fa-comment-o"></i> ' + message);355 }356 if (arrowclass !== "")357 {358 $("." + table).find("li#" + hashindex + " .icons i.action").attr("class", "action pull-left fa " + arrowclass);359 $("." + table).find("li#" + hashindex + " .icons i.action").css("color", color);360 }361 }362 $('.summary .Tablecount').html(array_regular.length + array_spec.length);363 $('.summary .regcount').html(array_regular.length);364 $('.summary .Speccount').html(array_spec.length);365}366function reDrawErrorList(listJson, listclass, errorjson)367{368 var filtred = checkfilter(errorjson);369 if (!filtred)370 {371 delete listJson[errorjson.hash];372 }373 if (errorjson.isspec === 0)374 {375 var indexregular = findeByhash(errorjson, array_regular);376 if (filtred)377 {378 if (indexregular === -1)379 {380 array_regular.push(errorjson);381 var index2 = findeByhash(errorjson, array_regular);382 if (index2 < array_regular.length - 1)383 {384 drawUL(array_regular[index2], listclass, array_regular[index2 + 1].hash);385 } else386 {387 drawUL(array_regular[index2], listclass);388 }389 } else390 {391 array_regular[indexregular] = errorjson;392 drawUL(array_regular[indexregular], listclass, array_regular[indexregular].hash, true);393 } 394 } else395 {396 if (indexregular !== -1)397 {398 array_regular.splice(indexregular, 1);399 }400 errorjson.index = 0;401 var hash_r = errorjson.hash;402 $("." + listclass).find("li#" + hash_r).hide("slide", {direction: "left"}, 1000, function () {403 $("." + listclass).find("li#" + hash_r).remove();404 $("." + listclass).find(".ui-effects-placeholder").remove(); 405 });406// console.log($("." + listclass).find(".ui-effects-placeholder").length);407 }408 } else409 {410// console.log($("." + listclass).remove(".ui-effects-placeholder").length);411 var indexspec = findeByhash(errorjson, array_spec);412 if (filtred)413 {414 if (indexspec === -1)415 {416 array_spec.push(errorjson);417 var index2 = findeByhash(errorjson, array_spec);418 if (index2 < array_spec.length - 1)419 {420 drawUL(array_spec[index2], listclass, array_spec[index2 + 1].hash);421 } else422 {423 drawUL(array_spec[index2], listclass, 0);424 }425 } else426 {427 array_spec[indexspec] = errorjson;428 drawUL(array_spec[indexspec], listclass, array_spec[indexspec].hash, true);429 }430 } else431 {432 if (indexspec !== -1)433 {434 array_spec.splice(indexspec, 1);435 }436 errorjson.index = 0;437 var hash_s = errorjson.hash;438 $("." + listclass).find("li#" + hash_s).fadeOut(400, function () {439 $("." + listclass).find("li#" + hash_s).remove(); 440 $("." + listclass).find(".ui-effects-placeholder").remove();441 }); 442 }443 }444}445function DrawErrorList(listJson, table)446{447 array_regular = [];448 array_spec = [];449 for (var key in listJson) {450 var errorjson = listJson[key];451 var filtred = checkfilter(errorjson);452 if (filtred)453 {454 if (errorjson.isspec === 0)455 {456 array_regular.push(errorjson);457 } else458 {459 array_spec.push(errorjson);460 }461 } else462 {463 delete listJson[key];464 }465 }466 for (key in array_spec)467 {468 drawUL(array_spec[key], "monitorlist");469 }470 for (key in array_regular)471 {472 drawUL(array_regular[key], "monitorlist");473 }474 table.find('tbody input.rawflat').iCheck({475 checkboxClass: 'icheckbox_flat-green',476 radioClass: 'iradio_flat-green'477 });478}479function checkfilter(message)480{481 var filtred = true;482 for (var filterindex in optionsJson.v)483 {484 if ((filterindex === "allfilter") ||485 ((filterindex === "mlfilter") && (message.isspec === 0)) ||486 ((filterindex === "manualfilter") && (message.isspec !== 0))487 )488 {489 for (var fvalue in optionsJson.v[filterindex])490 {491 var filtervalue = optionsJson.v[filterindex][fvalue];492 var filterop = optionsJson.op[filterindex][fvalue];493 var path = fvalue.split(".");494 var value = message;495 $.each(path, function (i, item) {496 value = value[item];497 });498 if (filterop === "=")499 {500 filtred = filtervalue.indexOf("" + value) !== -1;501 } else if (filterop === "!")502 {503 filtred = filtervalue.indexOf("" + value) === -1;504 } else if (filterop === "~")505 {506 filtred = value.indexOf("" + filtervalue) !== -1;507 } else if (filterop === "!~")508 {509 filtred = value.indexOf("" + filtervalue) === -1;510 } else if (filterop === "==")511 {512 filtred = value === filtervalue;513 } else if (filterop === "!=")514 {515 filtred = value !== filtervalue;516 } else517 {518// console.log(value);519// console.log(filterop);520 }521 if (!filtred)522 {523 break;524 }525 }526 }527 if (!filtred)528 {529 break;530 }531 }532 return filtred;533}534$(document).ready(function () {535 $("body").on("click", "#apply_filter", function () {536 updateFilter();537 stompClient.send("/input/chagefilter/", {}, JSON.stringify(optionsJson));538 redrawBoard();539 });540 $('body').on("click", "#Show_chart", function () {541 hashes = "";542 if ($("#regularlist li.selected").length === 1)543 {544 hashes = "/" + $("#regularlist li.selected").first().attr("id");545 } else546 {547 hashes = "?hashes=";548 $("#regularlist li.selected").each(function () {549 hashes = hashes + $(this).attr("id") + ";";550 });551 }552 var win = window.open(cp + "/chart" + hashes, '_blank');553 win.focus();554 });555 function cleareregresion() {556 var sendData = {};557 sendData.hash = $(this).attr("id");558 var header = $("meta[name='_csrf_header']").attr("content");559 var token = $("meta[name='_csrf']").attr("content");560 url = cp + "/resetregression";561 $.ajax({562 dataType: 'json',563 type: 'POST',564 url: url,565 data: sendData,566 beforeSend: function (xhr) {567 xhr.setRequestHeader(header, token);568 }569 }).done(function (msg) {570 if (msg.sucsses)571 {572 console.log("Message Sended " + sendData.hash);573 } else574 {575 console.log("Request failed " + sendData.hash);576 }577 }).fail(function (jqXHR, textStatus) {578 console.log("Request failed");579 });580 }581 $('body').on("click", ".monitorlist li ul li a", function (e) {582 e.stopPropagation();583 });584 $('body').on("click", ".deletemetric", function (e) {585 e.stopPropagation();586 $(this).closest("li").each(function () {587 $.getJSON(cp + "/deletemetrics?hash=" + $(this).attr("id"), function (data) {});588 var index = findeBy_ihash($(this).attr("id"), array_regular);589 if (index !== -1)590 {591 array_regular.splice(index, 1);592 }593 index = findeBy_ihash($(this).attr("id") * 1, array_spec);594 if (index !== -1)595 {596 array_spec.splice(index, 1);597 }598 $(this).hide("slide", {direction: "left"}, 1000, function () {599 $(this).remove();600 $(this).parent().remove(".ui-effects-placeholder");601 });602 });603 });604 $('body').on("click", ".resetregretion", function (e) {605 e.stopPropagation();606 $(this).closest("li").each(cleareregresion);607 });608 $('body').on("click", "#Clear_reg", function (e) {609 $("#regularlist li.selected").each(cleareregresion);610 });611 $('body').on("click", "#Move_down", function (e) {612 $("li.selected").each(function () {613 $(this).hide("slide", {direction: "left"}, 1000, function () {614 $(this).parent().append(this);615 $(this).show("slide", {direction: "left"}, 1000);616 });617 });618 });619 $('body').on("click", "#Move_top", function (e) {620 $("li.selected").each(function () {621 $(this).hide("slide", {direction: "left"}, 1000, function () {622 $(this).parent().prepend(this);623 $(this).show("slide", {direction: "left"}, 1000);624 });625 });626 });627 $("body").on("click", "#add_filter", function () {628 updateFilter();629 var sendData = {};630 url = cp + "/addmonitoringpage/";631 sendData.optionsjson = JSON.stringify(optionsJson);632 sendData.optionsname = $("#saveas_name").val();633 var header = $("meta[name='_csrf_header']").attr("content");634 var token = $("meta[name='_csrf']").attr("content");635 $.ajax({636 dataType: 'json',637 type: 'POST',638 url: url,639 data: sendData,640 beforeSend: function (xhr) {641 xhr.setRequestHeader(header, token);642 }643 }).done(function (msg) {644 if (msg.sucsses)645 {646 $('#saveModal .modal-title').text(locale["dashboard.Modal.successfullySaved"]);647 $('#saveModal').modal('show');648 setTimeout(function () {649 $('#saveModal').modal('hide');650 }, 2000);651 } else652 {653 $('#saveModal .modal-title').text(locale["dash.errorSavingData"]);654 $('#saveModal').modal('show');655 setTimeout(function () {656 $('#saveModal').modal('hide');657 }, 2000);658 }659 }).fail(function (jqXHR, textStatus) {660 alert(locale["requestFailed"]);661 });662 });663 $("body").on("click", "#save_filter", function () {664 updateFilter();665 var sendData = {};666 url = cp + "/addmonitoringpage/";667 sendData.optionsjson = JSON.stringify(optionsJson);668 sendData.optionsname = nameoptions;669// console.log(sendData.optionsname);670 var header = $("meta[name='_csrf_header']").attr("content");671 var token = $("meta[name='_csrf']").attr("content");672 $.ajax({673 dataType: 'json',674 type: 'POST',675 url: url,676 data: sendData,677 beforeSend: function (xhr) {678 xhr.setRequestHeader(header, token);679 }680 }).done(function (msg) {681 if (msg.sucsses)682 {683 $('#saveModal .modal-title').text(locale["dashboard.Modal.successfullySaved"]);684 $('#saveModal').modal('show');685 setTimeout(function () {686 $('#saveModal').modal('hide');687 }, 2000);688 } else689 {690 $('#saveModal .modal-title').text(locale["dash.errorSavingData"]);691 $('#saveModal').modal('show');692 setTimeout(function () {693 $('#saveModal').modal('hide');694 }, 2000);695 }696 }).fail(function (jqXHR, textStatus) {697 alert(locale["requestFailed"]);698 });699 });700 $("body").on("click", "#deleteviewconfirm", function () {701 url = cp + "/deletemonitoringpage/";702 sendData = {optionsname: nameoptions};703 var header = $("meta[name='_csrf_header']").attr("content");704 var token = $("meta[name='_csrf']").attr("content");705 $.ajax({706 dataType: 'json',707 type: 'POST',708 url: url,709 data: sendData,710 beforeSend: function (xhr) {711 xhr.setRequestHeader(header, token);712 }713 }).done(function (msg) {714 if (msg.sucsses)715 {716 window.location = cp + "/monitoring/";717 } else718 {719 alert(locale["requestFailed"]);720 }721 }).fail(function (jqXHR, textStatus) {722 alert(locale["requestFailed"]);723 });724 });725 $('body').on("click", "#rem_filter", function () {726 $("#deleteConfirm").find('.btn-ok').attr('id', "deleteviewconfirm");727 $("#deleteConfirm").find('.btn-ok').attr('class', "btn btn-ok btn-danger");728 $("#deleteConfirm").find('.modal-body p').html(locale["monitorings2.modal.confirmDelView"]);729 $("#deleteConfirm").find('.modal-body .text-warning').html(nameoptions);730 $("#deleteConfirm").modal('show');731 });732 setInterval(function () {733 $(".monitorlist li ul li").each(function () {734 var interval = moment($(this).attr("time") * 1).diff(moment()) / -1000;735 $(this).find(".timeinterval").text(interval.toFixed(0) + "sec.");736 });737 }, 1000);738 $("body").on("change", ".add_filter_select", function () {739 $(this).find(':selected').attr("disabled", "disabled");740 var row = $("<tr>");741 row.append("<td class='filter_label'>" + $(this).find(':selected').attr("fname") + "</td>");742 if ($(this).find(':selected').attr("value") === 'level')743 {744 row.append('<td class="action"><select class="operators_' + $(this).find(':selected').attr("value") + '" name="op[' + $(this).attr("id") + "_" + $(this).find(':selected').attr("value") + ']">' + eniumop + '</select> </td>');745 row.append('<td class="value"><select class="value" id="values_' + $(this).find(':selected').attr("value") + '_1" name="v[' + $(this).attr("id") + "_" + $(this).find(':selected').attr("value") + '][]" multiple="multiple" size="4"><option value="0">' + locale["level_0"] + '</option><option value="1">' + locale["level_1"] + '</option><option value="2">' + locale["level_2"] + '</option><option value="3">' + locale["level_3"] + '</option><option value="4">' + locale["level_4"] + '</option><option value="5">' + locale["level_5"] + '</option></select></td>');746 } else747 {748 row.append("<td class='action'> <select class='operators_subject' name='op[" + $(this).attr("id") + "_" + $(this).find(':selected').attr("value") + "]' tagkey='" + $(this).find(':selected').attr("value") + "'>" + strop + " </select> </td>");749 row.append("<td class='value'><input class='filter-value' type='text' name='v[" + $(this).attr("id") + "_" + $(this).find(':selected').attr("value") + "]' tagkey='" + $(this).find(':selected').attr("value") + "' autocomplete='off'></td>");750 }751 $(this).parents(".filter").find(".filters-table").append(row);752 //filters-table753 $(this).find('option').prop('selected', function () {754 return this.defaultSelected;755 });756 $("select").select2({minimumResultsForSearch: 15});757 });758 $("body").on("change", ".add_notifier_select", function () {759// $(this).find(':selected').attr("disabled", "disabled");760 var row = $("<div class='col-lg-4 col-md-6'>");761 row.append("<div class='item notifier_label'>" + $(this).find(':selected').attr("fname") + "</div>");762 row.append("<div class='item value'><input class='notifier-value' type='text' name='notifier-v[" + $(this).find(':selected').attr("value") + "][]' autocomplete='off'></div>");763 $(this).parents(".filter-body").find(".notifiers-table").append(row);764 //filters-table765 $(this).find('option').prop('selected', function () {766 return this.defaultSelected;767 });768 $("select").select2({minimumResultsForSearch: 15});769 });770 if (optionsJson === null)771 {772 var levels = [];773 for (var Oldindex in filterOldJson)774 {775 var filteritem = filterOldJson[Oldindex];776 if (Oldindex.indexOf("check_") !== -1)777 {778 if (Oldindex.indexOf("check_level_") !== -1)779 {780 levels.push(Oldindex.replace("check_level_", ""));781 } else782 {783 var row = $("<tr>");784 var name = Oldindex.replace("check_", "");785 var opt = $(".all_filter .add_filter_select option[alias=" + name + "]:first");786 opt.attr("disabled", "disabled");787 row.append("<td class='filter_label'>" + opt.attr("fname") + "</td>");788 row.append("<td class='action'> <select class='operators_subject' name='op[" + $(".all_filter .add_filter_select").attr("id") + "_" + opt.attr("value") + "]' tagkey='" + opt.attr("value") + "'>" + strop + " </select> </td>");789 row.append("<td class='value'><input class='filter-value' type='text' name='v[" + $(".all_filter .add_filter_select").attr("id") + "_" + opt.attr("value") + "]' tagkey='" + opt.attr("value") + "' autocomplete='off' value=" + filterOldJson[name + "_input"] + "></td>");790 $(".all_filter").find(".filters-table").append(row);791 }792 }793 }794 if (levels.length > 0)795 {796 var row = $("<tr>");797 var name = "level";798 var opt = $(".all_filter .add_filter_select option[value=" + name + "]:first");799 opt.attr("disabled", "disabled");800 row.append("<td class='filter_label'>" + opt.attr("fname") + "</td>");801 $(".all_filter").find(".filters-table").append(row);802 row.append('<td class="action"><select tagkey="' + opt.attr("value") + '" class="operators_' + opt.attr("value") + '" name="op[' + $(".all_filter .add_filter_select").attr("id") + "_" + opt.attr("value") + ']">' + eniumop + '</select> </td>');803 row.append('<td class="value"><select tagkey="' + opt.attr("value") + '"class="value" id="values_' + opt.attr("value") + '_1" name="v[' + $(".all_filter .add_filter_select").attr("id") + "_" + opt.attr("value") + '][]" multiple="multiple" size="4">' +804 '<option value="0" ' + (levels.indexOf("0") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_0"] + '</option>' +805 '<option value="1" ' + (levels.indexOf("1") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_1"] + '</option>' +806 '<option value="2" ' + (levels.indexOf("2") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_2"] + '</option>' +807 '<option value="3" ' + (levels.indexOf("3") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_3"] + '</option>' +808 '<option value="4" ' + (levels.indexOf("4") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_4"] + '</option>' +809 '<option value="5" ' + (levels.indexOf("5") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_5"] + '</option>' +810 '</select></td>');811 }812 $(".card-fields.value .f_col option").prop('selected', 'selected');813 updateFilter();814 } else815 {816 optionsJson.f_col.forEach(function (entry) {817 $(".card-fields.value .f_col option[value=" + entry + "]").prop('selected', 'selected');818 }819 );820 for (var section in optionsJson.v)821 {822 var Domsection = $(".add_filter_select#" + section).parents(".filter");823 for (var filter in optionsJson.v[section])824 {825 if (filter === "level")826 {827 levels = optionsJson.v[section][filter];828 var row = $("<tr>");829 var name = "level";830 var opt = Domsection.find(".add_filter_select option[value=" + name + "]:first");831 opt.attr("disabled", "disabled");832 row.append("<td class='filter_label'>" + opt.attr("fname") + "</td>");833 Domsection.find(".filters-table").append(row);834 row.append('<td class="action"><select tagkey="' + opt.attr("value") + '" class="operators_' + opt.attr("value") + '" name="op[' + Domsection.find(".add_filter_select").attr("id") + "_" + opt.attr("value") + ']">' + eniumop + '</select> </td>');835 row.find(".action option[value='" + optionsJson.op[section][filter] + "']").prop('selected', 'selected');836 row.append('<td class="value"><select tagkey="' + opt.attr("value") + '"class="value" id="values_' + opt.attr("value") + '_1" name="v[' + Domsection.find(".add_filter_select").attr("id") + "_" + opt.attr("value") + '][]" multiple="multiple" size="4">' +837 '<option value="0" ' + (levels.indexOf("0") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_0"] + '</option>' +838 '<option value="1" ' + (levels.indexOf("1") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_1"] + '</option>' +839 '<option value="2" ' + (levels.indexOf("2") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_2"] + '</option>' +840 '<option value="3" ' + (levels.indexOf("3") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_3"] + '</option>' +841 '<option value="4" ' + (levels.indexOf("4") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_4"] + '</option>' +842 '<option value="5" ' + (levels.indexOf("5") !== -1 ? ' selected="selected" ' : "") + '>' + locale["level_5"] + '</option>' +843 '</select></td>');844 } else845 {846 if (optionsJson.op[section])847 {848 var row = $("<tr>");849 var name = filter;850 var opt = Domsection.find(".add_filter_select option[value='" + name + "']:first");851 opt.attr("disabled", "disabled");852 row.append("<td class='filter_label'>" + opt.attr("fname") + "</td>");853 row.append("<td class='action'> <select class='operators_subject' name='op[" + Domsection.find(".add_filter_select").attr("id") + "_" + opt.attr("value") + "]' tagkey='" + opt.attr("value") + "'>" + strop + " </select> </td>");854 row.append("<td class='value'><input class='filter-value' type='text' name='v[" + Domsection.find(".add_filter_select").attr("id") + "_" + opt.attr("value") + "]' tagkey='" + opt.attr("value") + "' autocomplete='off' value=" + optionsJson.v[section][filter] + "></td>");855 row.find(".action option[value='" + optionsJson.op[section][filter] + "']").prop('selected', 'selected');856 Domsection.find(".filters-table").append(row);857 }858 }859 }860 }861 var Domsection = $(".add_notifier_select").parents(".filter-body");862 for (var notifier in optionsJson["notifier-v"])863 {864 name = notifier;865 var opt = Domsection.find(".add_notifier_select option[value='" + name + "']:first");866 for (var nvalue in optionsJson["notifier-v"][notifier])867 {868// console.log(notifier + "=" + optionsJson["notifier-v"][notifier][nvalue]);869 var row = $("<div class='col-lg-4 col-md-6'>");870 row.append("<div class='item notifier_label'>" + opt.attr("fname") + "</div>");871 row.append("<div class='item value'><input class='notifier-value' type='text' name='notifier-v[" + opt.attr("value") + "][]' value='" + optionsJson["notifier-v"][notifier][nvalue] + "' autocomplete='off'></div>");872 Domsection.find(".notifiers-table").append(row);873 }874 }875 }876 $('body').on("click", '.monitorlist li ul li .samegroup', function (e) {877 e.stopPropagation();878 var ctrl = e.ctrlKey;879 880 var key = $(this).attr("data-key");881 var value = $(this).attr("data-value");882 if (!ctrl)883 {884 $(".selected").toggleClass("selected");885 }886 $("[data-key='" + key + "'][data-value='" + value + "']").each(function () {887 $(this).parents("li:first").addClass("selected");888 });889 if ($("#regularlist .selected").length > 0)890 {891 $(".selected-actions").show("slide", {direction: "right"}, 1000);892 } else893 {894 $(".selected-actions").hide("slide", {direction: "right"}, 1000);895 }896 $(".selected-actions .badge").text($("#regularlist .selected").length);897 });898 $('body').on("click", '.monitorlist li ul li', function (e) {899 $(this).toggleClass("selected");900 if ($("#regularlist .selected").length > 0)901 {902 $(".selected-actions").show("slide", {direction: "right"}, 1000);903 } else904 {905 $(".selected-actions").hide("slide", {direction: "right"}, 1000);906 }907 $(".selected-actions .badge").text($("#regularlist .selected").length);908 });909// redrawBoard();910 $('body').on("click", 'fieldset.collapsible legend', function () {911 if ($(this).parent().hasClass("collapsed"))912 {913 $(this).parent().removeClass("collapsed");914 $(this).find(".fa-chevron-down").addClass("fa-chevron-up");915 $(this).parent().find(".fa-chevron-down").removeClass("fa-chevron-down");916 $(this).parent().find("select").select2({minimumResultsForSearch: 15});917 } else918 {919 $(this).parent().addClass("collapsed");920 $(this).find(".fa-chevron-up").addClass("fa-chevron-down");921 $(this).find(".fa-chevron-up").removeClass("fa-chevron-up");922 }923 });924 $("select").select2({minimumResultsForSearch: 15});925 connectstompClient();926});927function updateFilter() {928 var formData = $("form.form-options").serializeArray();929 optionsJson = {};930 const regex = /[a-zA-Z-.]+/g;931 jQuery.each(formData, function (i, field) {932 if (field.value !== "")933 {934 var name = field.name;935 if (field.name.indexOf("op[") !== -1)936 {937 name = "op";938 if (!optionsJson[name])939 {940 optionsJson[name] = {};941 }942 var m = field.name.match(regex);943 var fgroup = m[1];944 var fname = m[2];945 if (!optionsJson[name][fgroup])946 {947 optionsJson[name][fgroup] = {};948 }949 optionsJson[name][fgroup][fname] = field.value;950 } else if (field.name.indexOf("v[") !== -1)951 {952 name = field.name.substring(0, field.name.indexOf("v[") + 1);953 if (!optionsJson[name])954 {955 optionsJson[name] = {};956 }957 if (field.name.indexOf("[]") !== -1)958 {959 var lname = field.name.replace("[]", "");960 var m = lname.match(regex);961 var fgroup = m[1];962 var fname = m[2];963 if (fname)964 {965 if (!optionsJson[name][fgroup])966 {967 optionsJson[name][fgroup] = {};968 }969 if (!optionsJson[name][fgroup][fname])970 {971 optionsJson[name][fgroup][fname] = [];972 }973 optionsJson[name][fgroup][fname].push(field.value);974 } else975 {976 if (!optionsJson[name][fgroup])977 {978 optionsJson[name][fgroup] = [];979 }980 optionsJson[name][fgroup].push(field.value);981 }982 } else983 {984 var m = field.name.match(regex);985 var fgroup = m[1];986 var fname = m[2];987 if (!optionsJson[name][fgroup])988 {989 optionsJson[name][fgroup] = {};990 }991 optionsJson[name][fgroup][fname] = field.value;992 }993 } else994 {995 if (field.name.indexOf("[]") !== -1)996 {997 lname = field.name.replace("[]", "");998 if (!optionsJson[lname])999 {1000 optionsJson[lname] = [];1001 }1002 optionsJson[lname].push(field.value);1003 } else1004 {1005 optionsJson[field.name] = field.value;1006 }1007 }1008 }1009 });...
validateRequestParams.js
Source:validateRequestParams.js
1/*2 * Copyright 2019 Google LLC3 *4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 *8 * https://www.apache.org/licenses/LICENSE-2.09 *10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15*/16/**17 * @file18 * validateRequestParams.js19 * Generic Script is for validation of request based on config provided20 */21// Maximum allowed page size value, according to CDS standards22const MAX_PAGE_SIZE = 1000;23// Extract validation configuration24RequestConfig = JSON.parse(context.getVariable("validateParamConfig"));25var error = validateRequest(RequestConfig);26if (error.isError) {27 context.setVariable("isError", error.isError);28 context.setVariable("errorResponseCode", error.errorCode);29 context.setVariable("errorTitle", error.errorTitle);30 context.setVariable("errorDescription", error.errorDescription);31}32else {33 context.setVariable("isError", false);34}35function validateRequest(RequestConfig) {36 var key, i, j, ispresent;37 var errorJson = {};38 errorJson.isError = true;39 errorJson.errorResponseCode = 400;40 41 validPayload = {};42 // validate Headers43 if (RequestConfig.Headers) {44 for (i = 0; i < RequestConfig.Headers.length; i++) {45 for (key in RequestConfig.Headers[i]) {46 ispresent = false;47 var headerVal = context.getVariable("request.header." + key);48 var headerValidation = RequestConfig.Headers[i][key];49 if (headerVal) {50 ispresent = true;51 }52 errorJson.errorDescription = key;53 // check if header is mandatory54 if (headerValidation.Mandatory) {55 if (!ispresent) {56 errorJson.errorCode = "urn:au-cds:error:cds-all:Header/Missing";57 errorJson.errorTitle = "Missing Header";58 return errorJson;59 }60 }61 errorJson.errorCode = "urn:au-cds:error:cds-all:Header/Invalid";62 errorJson.errorTitle = "Invalid Header";63 //validate type of header value64 if (isValidParamType(headerVal, headerValidation, ispresent) === false) {65 if (headerValidation.ValueType == "Date") {66 errorJson.errorCode = " urn:au-cds:error:cds-all:Field/InvalidDateTime";67 errorJson.errorTitle = "Invalid Date";68 }69 return errorJson;70 }71 // validate max length of header value72 if (isInvalidMaxLength(headerVal, headerValidation, ispresent)) {73 errorJson.errorDescription = "" + key + " header value length exceeds the maximum length limit";74 return errorJson;75 }76 // validate min length of header value77 if (isInvalidMinLength(headerVal, headerValidation, ispresent)) {78 errorJson.errorDescription = "" + key + " header value length less than minimum length limit";79 return errorJson;80 }81 // validate against list of allowed values for the header82 if (isInvalidParamValue(headerVal, headerValidation, ispresent)) {83 return errorJson;84 }85 }86 }87 }88 // query parameters validation89 if (RequestConfig.QueryParams) {90 for (i = 0; i < RequestConfig.QueryParams.length; i++) {91 for (key in RequestConfig.QueryParams[i]) {92 ispresent = false;93 var queryParamVal = context.getVariable("request.queryparam." + key);94 var queryParamValidation = RequestConfig.QueryParams[i][key];95 if (queryParamVal) {96 ispresent = true;97 }98 errorJson.errorDescription = key;99 // check if query param is mandatory100 if (queryParamValidation.Mandatory) {101 if (!ispresent) {102 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/Missing";103 errorJson.errorTitle = "Missing Field";104 return errorJson;105 }106 }107 108 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/Invalid";109 errorJson.errorTitle = "Invalid Field";110 111 //validate the type of query parameter112 if (isValidParamType(queryParamVal, queryParamValidation, ispresent) === false) {113 if (queryParamValidation.ValueType == "Date") {114 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/InvalidDateTime";115 errorJson.errorTitle = "Invalid Date";116 }117 return errorJson;118 }119 // validate max length allowed for the query parameter120 if (isInvalidMaxLength(queryParamVal, queryParamValidation, ispresent)) {121 errorJson.errorDescription = "" + key + " query parameter value length exceeds the maximum length limit";122 return errorJson;123 }124 // validae min length allowed for the query parameter125 if (isInvalidMinLength(queryParamVal, queryParamValidation, ispresent)) {126 errorJson.errorDescription = "" + key + " query parameter value length less than minimum length limit";127 return errorJson;128 }129 // validate against the list of possible values allowed for the query parameter130 if (isInvalidParamValue(queryParamVal, queryParamValidation, ispresent)) {131 return errorJson;132 }133 134 135 // Valideate page-size param if present136 if ((key == "page-size") && (isInvalidPageSize(queryParamVal, ispresent))) {137 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/InvalidPageSize";138 errorJson.errorTitle = "Invalid Page Size";139 errorJson.errorDescription = "page-size provided (" + queryParamVal + ") needs to be an integer between 1 and " + MAX_PAGE_SIZE;140 return errorJson;141 }142 }143 }144 }145 // request payload validation146 var reqVerb = context.getVariable("request.verb");147 if (reqVerb == "POST") {148 if (RequestConfig.Body) {149 for (i = 0; i < RequestConfig.Body.length; i++) {150 for (key in RequestConfig.Body[i]) {151 ispresent = false;152 var bodyParam = getBodyParameterVal(key);153 //context.setVariable("bodyparam", bodyParam);154 var bodyValidation = RequestConfig.Body[i][key];155 if (bodyParam != "invalid") {156 ispresent = true;157 }158 159 errorJson.errorDescription = key;160 // check if the body parameter is mandatory and if not present in the request, return error161 if (bodyValidation.Mandatory) {162 if (bodyParam == "invalid") {163 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/Missing";164 errorJson.errorTitle = "Missing Field";165 return errorJson;166 }167 }168 169 errorJson.errorCode = "urn:au-cds:error:cds-all:Field/Invalid";170 errorJson.errorTitle = "Invalid Field";171 172 var typeCastedBodyParam = null;173 //validate the type of the body parameter value174 var isBodyParamValid = isValidParamType(bodyParam, bodyValidation, ispresent);175 if (bodyValidation.ValueType == "Date") {176 errorJson.errorCode = " urn:au-cds:error:cds-all:Field/InvalidDateTime";177 errorJson.errorTitle = "Invalid Date";178 }179 if (isBodyParamValid === false) {180 return errorJson;181 }182 else {183 if (isBodyParamValid.length == 1) {184 typeCastedBodyParam = isBodyParamValid[0];185 }186 }187 // validate maximum length of the body parameter188 if (isInvalidMaxLength(bodyParam, bodyValidation, ispresent)) {189 errorJson.errorDescription = "" + key + " length exceeds the maximum limit";190 return errorJson;191 }192 //validate minimum length of the body parameter193 if (isInvalidMinLength(bodyParam, bodyValidation, ispresent)) {194 errorJson.errorDescription = "" + key + " value length less than minimum length limit";195 return errorJson;196 }197 // validate if the body parameter value is one in the list of allowed values for it198 if (isInvalidParamValue(bodyParam, bodyValidation, ispresent)) {199 return errorJson;200 }201 if (ispresent) {202 setKeyVal(key, typeCastedBodyParam);203 }204 }205 }206 }207 }208 context.setVariable("validPayload", JSON.stringify(validPayload));209 errorJson.isError = false;210 errorJson.errorResponseCode = 200;211 return errorJson;212}213function getBodyParameterVal(param) {214 // check for empty payload215 if (context.getVariable("request.content")) {216 var content = JSON.parse(context.getVariable("request.content"));217 var contextBodyParam = "";218 try {219 var keys = param.split('.');220 var value = content[keys[0]];221 for (var i = 1; i < keys.length; i++) {222 value = value[keys[i]];223 }224 if (value) {225 return value;226 }227 else {228 return "invalid";229 }230 }231 catch (err) {232 return "invalid";233 }234 }235 else return "invalid";236}237function isInvalidMaxLength(param, configparam, ispresent) {238 if (configparam.MaxText && ispresent) {239 if (param.length > configparam.MaxText)240 return true;241 else return false;242 }243 return false;244}245function isInvalidMinLength(param, configparam, ispresent) {246 if (configparam.MinText && ispresent) {247 if (param.length < configparam.MinText)248 return true;249 else return false;250 }251 return false;252}253// Checks that, if present, page-size is non empty and less than the maximum value allowed254function isInvalidPageSize(paramvalue, ispresent) {255 if (ispresent) {256 if ( (paramvalue > MAX_PAGE_SIZE) )257 return true;258 else return false;259 }260 if ( paramvalue === "" )261 return true;262 else263 return false;264}265function isValidParamType(param, configparam, ispresent) {266 var paramtype = Object.prototype.toString.call(param).split(" ")[1].slice(0, -1);267 var valueArr = [];268 if (configparam.ValueType && ispresent) {269 if (paramtype == "String") {270 if (configparam.ValueType == "String") {271 return valueObj;272 }273 else if ( (configparam.ValueType == "Integer") || (configparam.ValueType == "PositiveInteger") ) {274 if (isNaN(param) || isNaN(parseInt(param))) {275 return false;276 }277 else if ( (configparam.ValueType == "PositiveInteger") && (parseInt(param) < 1) ) {278 return false;279 }280 else 281 {282 valueArr.push(parseInt(param));283 return valueArr;284 }285 }286 else if (configparam.ValueType == "Number") {287 if (isNaN(param) || isNaN(parseFloat(param))) {288 return false;289 }290 else {291 valueArr.push(parseFloat(param));292 return valueArr;293 }294 }295 else if (configparam.ValueType == "Boolean") {296 if (param.toString().toLowerCase() != "false" && param.toString().toLowerCase() != "true") {297 return false;298 }299 else {300 valueArr.push(param);301 return valueArr;302 }303 }304 // To Do - Handle DateString, TimeString, DateTimeString305 else if (configparam.ValueType == "Date") {306 if (isNaN(Date.parse(param))) {307 return false;308 }309 else {310 valueArr.push(Date.parse(param));311 return valueArr;312 }313 }314 else return false;315 }316 else if (paramtype != configparam.ValueType) {317 return false;318 }319 valueArr.push(param);320 return valueArr;321 }322 valueArr.push(param);323 return valueArr;324}325function isInvalidParamValue(param, configparam, ispresent) {326 if (configparam.ValueList && ispresent) {327 if (configparam.ValueList.indexOf(param) <= -1)328 return true;329 else return false;330 }331 return false;332}333function setKeyVal(keyPath, param) {334 var temp = validPayload; // a moving reference to internal objects within obj335 var keyList = keyPath.split('.');336 var len = keyList.length;337 for (var i = 0; i < len - 1; i++) {338 var elem = keyList[i];339 if (!temp[elem]) temp[elem] = {}340 temp = temp[elem];341 }342 temp[keyList[len - 1]] = param;...
custom skill.js
Source:custom skill.js
1let https = require('https');2exports.handler = (event, context) => {3 console.log(JSON.stringify(event));4 let request = event.request;5 if((request.type === 'IntentRequest')&&(request.intent.name === "GetAmdocsVideo")){6 console.log(`INTENT REQUEST`);7 let videoName = 'rec_cam_';8 let date = request.intent.slots.date.value;9 let cameraNumber = request.intent.slots.cameraNumber.value;10 date.replace('9','8');11 videoName += cameraNumber + '_' + date;12 //let endpoint = 'https://std.ch.amdocs.com/alexa-rest-service/rest/playSavedVideo?name='+videoName+'&access_token=' + event.session.user.accessToken;13 let body;14 let returnJson = {15 "version": "1.0",16 "sessionAttributes": null,17 "response": {18 "outputSpeech": null,19 "card": null,20 "directives": [21 {22 "type": "VideoApp.Launch",23 "videoItem":24 {25 "source": "https://www.example.com/video/sample-video-1.mp4",26 "metadata": {27 "title": "Title for Sample Video",28 "subtitle": "Secondary Title for Sample Video"29 }30 }31 }32 ],33 "reprompt": null34 }35 };36 let errorJson = {37 "version": "1.0",38 "sessionAttributes": null,39 "response": {40 "outputSpeech": {41 "type": "PlainText",42 "text": null43 },44 "card":{45 "type": "Standard",46 "title" : "Something Went Wrong",47 "text" : null,48 "image" : {49 "largeImageUrl": "https://s3.amazonaws.com/alexamta/9436653177_fd00cc9d2c_b.jpg"50 }51 },52 "shouldEndSession": true53 }54 };55 // http request not implemeted56 //console.log('The access url: ' + endpoint);57 //https.get(endpoint, (response) => {58 // response.on('data', (chunk) => { body += chunk });59 // response.on('end', () => {60 // console.log(body);61 // let data = JSON.parse(body.replace('undefined',''));62 // console.log(JSON.stringify(body));63 console.log(errorJson);64 console.log(videoName);65 if(cameraNumber !== '5'){66 console.log('wrong camera nubmer ' + cameraNumber);67 errorJson.response.outputSpeech.text = 'Can you please repeat the camera number, I didnt get it right';68 errorJson.response.card.text = 'Can you please repeat the camera number, I didnt get it righ';69 console.log(JSON.stringify(errorJson));70 context.succeed(errorJson);71 }72 else{73 console.log('good camera nubmer ' + cameraNumber)74 let url;75 let urls = ["https://s3.amazonaws.com/alexamta/rec_cam_5_2018-01-05-09-49-17.mp4",76 "https://s3.amazonaws.com/alexamta/rec_cam_5_2018-01-25-10-08-32.mp4"];77 for (let m_url in urls) {78 console.log(urls[m_url], m_url);79 if (urls[m_url].includes(videoName))80 url = urls[m_url];81 }82 console.log("the url: " + url);83 if(url){84 console.log('good url ' + url)85 returnJson.response.directives[0].videoItem.source = url;86 returnJson.response.directives[0].videoItem.metadata.title = 'Amdocs camera video';87 returnJson.response.directives[0].videoItem.metadata.subtitle = 'Amdocs video: '+videoName;88 console.log(JSON.stringify(returnJson));89 context.succeed(returnJson);90 }91 else{92 console.log('wrong url ' + url)93 errorJson.response.outputSpeech.text = 'Can you please repeat the date, I didnt get it right';94 errorJson.response.card.text = 'Can you please repeat the date, I didnt get it right';95 console.log(JSON.stringify(errorJson));96 context.succeed(errorJson);97 }98 }99 }...
user.js
Source:user.js
1const validator = require('validator');2const mongoose = require('mongoose');3function validateFetchUserSession(data) {4 const errorJSON = {5 status: false,6 message: [],7 };8 if(!data.email) errorJSON.message.push('Email is required.');9 if(!data.password) errorJSON.message.push('Password is required.');10 if(!(11 (typeof data.email === 'string') &&12 validator.isEmail(data.email)13 )) errorJSON.message.push('Email is invalid.');14 if(!(15 (typeof data.password === 'string') &&16 (data.password.length >= 8) &&17 data.password.match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/)18 )) errorJSON.message.push('Password is invalid.');19 20 if(errorJSON.message.length) {21 errorJSON.status = true;22 errorJSON.message = errorJSON.message.join('\n');23 }24 return errorJSON;25}26function validateUpdateUserProfile(data) {27 const errorJSON = {28 status: false,29 message: [],30 };31 if(!data._id) errorJSON.message.push('User Id is required.');32 if(!mongoose.Types.ObjectId.isValid(data._id)) errorJSON.message.push('User Id is invalid.');33 if(data.email &&34 !(35 (typeof data.email === 'string') &&36 validator.isEmail(data.email)37 )) errorJSON.message.push('Email is invalid.');38 if(data.name &&39 !(40 (typeof data.name === 'string') &&41 (data.name.length !== 0)42 )) errorJSON.message.push('Name is invalid.');43 if (data.password &&44 !(45 (typeof data.password === 'string') &&46 (data.password.length >= 8) &&47 data.password.match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/)48 )) errorJSON.message.push('Password is invalid.');49 if (data.expectedPerDayIntakeCalorie &&50 !(51 (typeof data.expectedPerDayIntakeCalorie === 'number')52 )) errorJSON.message.push('expectedPerDayIntakeCalorie is invalid.');53 54 55 if(errorJSON.message.length) {56 errorJSON.status = true;57 errorJSON.message = errorJSON.message.join('\n');58 }59 return errorJSON;60}61function validateSaveUserProfile(data) {62 const errorJSON = {63 status: false,64 message: [],65 };66 if(!data) errorJSON.message.push('User Data is required.');67 if(typeof data !== 'object') errorJSON.message.push('User Data is invalid.');68 if(!data.userEmail) errorJSON.message.push('Email is required.');69 if(!(70 (typeof data.userEmail === 'string') &&71 validator.isEmail(data.userEmail)72 )) errorJSON.message.push('Email is invalid.');73 if(!data.userName) errorJSON.message.push('Name is required.');74 if(!(75 (typeof data.userName === 'string') &&76 (data.userName.length !== 0)77 )) errorJSON.message.push('Name is invalid.');78 if(!data.userPassword) errorJSON.message.push('Password is required.');79 if(!(80 (typeof data.userPassword === 'string') &&81 (data.userPassword.length >= 8) &&82 data.userPassword.match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/)83 )) errorJSON.message.push('Password is invalid.');84 // if(!data.expectedPerDayIntakeCalorie) errorJSON.message.push('Min Intake Calorie is required.');85 // if(typeof data.expectedPerDayIntakeCalorie !== 'number') errorJSON.message.push('Min Intake Calorie is invalid.');86 87 88 if(errorJSON.message.length) {89 errorJSON.status = true;90 errorJSON.message = errorJSON.message.join('\n');91 }92 return errorJSON;93}94module.exports = {95 validateFetchUserSession,96 validateUpdateUserProfile,97 validateSaveUserProfile...
meal.js
Source:meal.js
1const moment = require('moment');2const mongoose = require('mongoose');3function validateAddMeal(data) {4 const errorJSON = {5 status: false,6 message: [],7 };8 if(!data.mealName) errorJSON.message.push('Meal Name is required.');9 if(typeof data.mealName !== 'string') errorJSON.message.push('Meal Name is invalid.');10 if(!data.mealCalories) errorJSON.message.push('Meal Calories is required.');11 if(typeof data.mealCalories !== 'number') errorJSON.message.push('Meal Calories is invalid.');12 if(!data.mealDate) errorJSON.message.push('Meal Date is required.');13 if(typeof data.mealDate !== 'string') errorJSON.message.push('Meal Date is invalid.');14 if(!moment(data.mealDate, 'YYYY/MM/DD', true).isValid()) errorJSON.message.push('Meal Date is invalid.');15 16 if(errorJSON.message.length) {17 errorJSON.status = true;18 errorJSON.message = errorJSON.message.join('\n');19 } else 20 errorJSON.message = errorJSON.message.join('\n');21 return errorJSON;22}23function validateUpdateMeal(data) {24 const errorJSON = validateAddMeal(data);25 errorJSON.message = [errorJSON.message];26 if(!data._id) errorJSON.message.push('Meal Id is required.');27 if(!mongoose.Types.ObjectId.isValid(data._id)) errorJSON.message.push('Meal Id is invalid.');28 29 errorJSON.message = errorJSON.message.filter(e => e || undefined);30 if(errorJSON.message.length) {31 errorJSON.status = true;32 errorJSON.message = errorJSON.message.join('\n');33 }34 return errorJSON;35}36function validateDeleteMeal(data) {37 const errorJSON = {38 status: false,39 message: [],40 };41 if(!data) errorJSON.message.push('Meal Id is required.');42 if(!mongoose.Types.ObjectId.isValid(data)) errorJSON.message.push('Meal Id is invalid.');43 44 if(errorJSON.message.length) {45 errorJSON.status = true;46 errorJSON.message = errorJSON.message.join('\n');47 }48 return errorJSON;49}50function validateFetchMeal(data) {51 const errorJSON = {52 status: false,53 message: [],54 };55 if(!data) errorJSON.message.push('Meal Date Range is required.');56 if(typeof data !== 'object') errorJSON.message.push('Meal Date Range is invalid.');57 else {58 if(!data.min) errorJSON.message.push('Meal Date Min Range is required.');59 if(typeof data.min !== 'string') errorJSON.message.push('Meal Date Min Range is invalid.');60 if(!moment(data.min, 'YYYY/MM/DD', true).isValid()) errorJSON.message.push('Meal Date Min Range is invalid.');61 if(!data.max) errorJSON.message.push('Meal Date Max Range is required.');62 if(typeof data.max !== 'string') errorJSON.message.push('Meal Date Max Range is invalid.');63 if(!moment(data.max, 'YYYY/MM/DD', true).isValid()) errorJSON.message.push('Meal Date Max Range is invalid.');64 }65 66 if(errorJSON.message.length) {67 errorJSON.status = true;68 errorJSON.message = errorJSON.message.join('\n');69 }70 return errorJSON;71}72module.exports = {73 validateAddMeal,74 validateUpdateMeal,75 validateDeleteMeal,76 validateFetchMeal,...
MbError.js
Source:MbError.js
1const { errorCodes, errorTypes } = require("./errorCodes");2class MbError extends Error {3 constructor(4 message,5 errorObject = {},6 errorCode = "MB000",7 errorType = "T001",8 statusCode = 4009 ) {10 super();11 this.statusCode = statusCode;12 this.message = message;13 this.errorObject = errorObject;14 this.errorCode = errorCode;15 (this.errorCodeDefinition = errorCodes[errorCode]16 ? errorCodes[errorCode]17 : "ERROR_CODE_NOT_DEFINED"),18 (this.errorType = errorType),19 (this.errorTypeDefinition = errorTypes[errorType]20 ? errorTypes[errorType]21 : "ERROR_TYPE_NOT_DEFINED");22 }23}24class MbJoiValidationError extends Error {25 constructor(message, joiObject = {}, statusCode = 422) {26 super();27 this.type = "JOI_VALIDATION_ERROR";28 this.statusCode = statusCode;29 this.message = message;30 this.joiObject = joiObject;31 }32 handleError(res) {33 const errorJson = {34 type: this.type,35 statusCode: this.statusCode,36 message: this.message,37 joiObject: this.joiObject38 };39 res.status(this.statusCode).json(errorJson);40 }41}42class CustomValidationError extends Error {43 constructor(message, errorObject = {}, statusCode = 422) {44 super();45 this.type = "CUSTOM_VALIDATION_ERROR";46 this.statusCode = statusCode;47 this.message = message;48 this.errorObject = errorObject;49 }50 handleError(res) {51 const errorJson = {52 type: this.type,53 statusCode: this.statusCode,54 message: this.message,55 errorObject: this.errorObject56 };57 res.status(this.statusCode).json(errorJson);58 }59}60class GeneralError extends Error {61 constructor(message, errorObject = {}, statusCode = 422) {62 super();63 this.type = "GENERAL_ERROR";64 this.statusCode = statusCode;65 this.message = message;66 this.errorObject = errorObject;67 }68 handleError(res) {69 const errorJson = {70 type: this.type,71 statusCode: this.statusCode,72 message: this.message,73 errorObject: this.errorObject74 };75 res.status(this.statusCode).json(errorJson);76 }77}78const MbErrorHandler = async (err, res) => {79 const {80 statusCode,81 message,82 errorObject,83 errorCode,84 errorCodeDefinition,85 errorType,86 errorTypeDefinition87 } = err;88 const errorJson = {89 status: "error",90 message,91 errorObject,92 errorCode,93 errorCodeDefinition,94 errorType,95 errorTypeDefinition96 };97 console.error(errorJson);98 res.status(400).json(errorJson);99};100// const MbErrorHandler = async (err, res) => {101// const errorJson = {102// status: "error",103// message,104// errorObject,105// errorCode,106// errorCodeDefinition,107// errorType,108// errorTypeDefinition109// }110// console.error(errorJson);111// res.status(400).json(errorJson)112// }113module.exports = {114 MbError,115 MbErrorHandler,116 MbJoiValidationError,117 CustomValidationError,118 GeneralError...
admin.js
Source:admin.js
1const validator = require('validator');2const mongoose = require('mongoose');3function validateFetchAdminSession(data) {4 const errorJSON = {5 status: false,6 message: [],7 };8 if(!data.email) errorJSON.message.push('Email is required.');9 if(!data.password) errorJSON.message.push('Password is required.');10 if(!(11 (typeof data.email === 'string') &&12 validator.isEmail(data.email)13 )) errorJSON.message.push('Email is invalid.');14 if(!(15 (typeof data.password === 'string') &&16 (data.password.length >= 8) &&17 data.password.match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/)18 )) errorJSON.message.push('Password is invalid.');19 20 if(errorJSON.message.length) {21 errorJSON.status = true;22 errorJSON.message = errorJSON.message.join('\n');23 }24 return errorJSON;25}26function validateToggleUserActive(data) {27 const errorJSON = {28 status: false,29 message: [],30 };31 if (!data._id) errorJSON.message.push('User Id is required.');32 if (!mongoose.Types.ObjectId.isValid(data._id)) errorJSON.message.push('User Id is invalid.');33 if (data.isActive === undefined) errorJSON.message.push('isActive is required.');34 if (typeof data.isActive !== 'boolean') errorJSON.message.push('isActive is invalid.');35 36 if(errorJSON.message.length) {37 errorJSON.status = true;38 errorJSON.message = errorJSON.message.join('\n');39 }40 return errorJSON;41}42function validateCreateUserSession(data) {43 const errorJSON = {44 status: false,45 message: [],46 };47 if (!data) errorJSON.message.push('User Id is required.');48 if (!mongoose.Types.ObjectId.isValid(data)) errorJSON.message.push('User Id is invalid.');49 50 if(errorJSON.message.length) {51 errorJSON.status = true;52 errorJSON.message = errorJSON.message.join('\n');53 }54 return errorJSON;55}56module.exports = {57 validateFetchAdminSession,58 validateToggleUserActive,59 validateCreateUserSession...
handleErrors.js
Source:handleErrors.js
1const logger = require('../utils/logger');2const handleErrors = (err, req, res, next) => {3 const errorJSON = {4 status: 'error',5 message: 'internal server error',6 };7 const errCode = err.code;8 if (errCode === 11000) {9 errorJSON.message = 'resource already exists';10 return res.status(409).json(errorJSON);11 }12 if (errCode !== 500 && errCode !== undefined) {13 errorJSON.message = err.message;14 return res.status(errCode).json(errorJSON);15 }16 logger.error(err);17 return res.status(500).json(errorJSON);18};...
Using AI Code Generation
1var assert = require('assert');2describe('Array', function() {3 describe('#indexOf()', function() {4 it('should return -1 when the value is not present', function() {5 assert.equal(-1, [1,2,3].indexOf(5));6 assert.equal(-1, [1,2,3].indexOf(0));7 });8 });9});10 #indexOf()11 0 passing (9ms)12 1) Array #indexOf() should return -1 when the value is not present:13 at Context.<anonymous> (test.js:8:16)14var assert = require('assert');15describe('Array', function() {16 describe('#indexOf()', function() {17 it('should return -1 when the value is not present', function() {18 assert.equal(-1, [1,2,3].indexOf(5));19 assert.equal(-1, [1,2,3].indexOf(0));20 });21 });22});23{24 "stats": {25 },26 {27 "fullTitle": "Array #indexOf() should return -1 when the value is not present",
Using AI Code Generation
1const chai = require('chai');2const chaiHttp = require('chai-http');3const expect = chai.expect;4const app = require('../app');5chai.use(chaiHttp);6describe('GET /', function() {7 it('should return the homepage', function() {8 .request(app)9 .get('/')10 .then(function(res) {11 expect(res).to.have.status(200);12 expect(res).to.be.html;13 });14 });15});16const express = require('express');17const morgan = require('morgan');18const app = express();19app.use(morgan('common'));20app.get('/', (req, res) => {21 res.send('Hello Express!');22});23module.exports = app;24const chai = require('chai');25const chaiHttp = require('chai-http');26const expect = chai.expect;27const app = require('../app');28chai.use(chaiHttp);29describe('POST /blog-posts', function() {30 it('should add a blog post on POST', function() {31 const newPost = {
Using AI Code Generation
1var assert = require('chai').assert;2var errorJSON = require('chai').errorJSON;3var should = require('chai').should();4var expect = require('chai').expect;5describe('test', function () {6 it('should return the error message', function () {7 var err = new Error('this is an error');8 err.should.have.property('message', 'this is an error');9 expect(err).to.have.property('message', 'this is an error');10 assert.equal(err.message, 'this is an error');11 });12});13 0 passing (9ms)14 AssertionError: expected { Object (message, stack) } to have property 'message' of 'this is an error', but got 'this is an error'15 at Context.it (test.js:12:29)16 AssertionError: expected { Object (message, stack) } to have property 'message' of 'this is an error', but got 'this is an error'17 at Context.it (test.js:13:29)18 AssertionError: expected { Object (message, stack) } to have property 'message' of 'this is an error', but got 'this is an error'19 at Context.it (test.js:14:29)20 at Context.it (test.js:12:29)21 at Context.it (test.js:13:29)22 at Context.it (test.js:14:29)
Using AI Code Generation
1var assert = require('assert');2var errorJSON = require('assert').errorJSON;3assert.equal(1, 2, 'one is not equal to two');4assert.equal(1, 2, 'one is not equal to two');5assert.equal(1, 2, 'one is not equal to two');6assert.equal(1, 2, 'one is not equal to two');7assert.equal(1, 2, 'one is not equal to two');8assert.equal(1, 2, 'one is not equal to two');9assert.equal(1, 2, 'one is not equal to two');10assert.equal(1, 2, 'one is not equal to two');11assert.equal(1, 2, 'one is not equal to two');12assert.equal(1, 2, 'one is not equal to two');13assert.equal(1, 2, 'one is not equal to two');14assert.equal(1, 2, 'one is not equal to two');
Using AI Code Generation
1var assert = require('assert');2var app = require('../app.js');3var request = require('supertest');4var should = require('should');5describe('GET /', function(){6 it('respond with hello world', function(done){7 request(app)8 .get('/')9 .expect(200)10 .expect('Hello World', done);11 });12});13describe('GET /users', function(){14 it('respond with json', function(done){15 request(app)16 .get('/users')17 .set('Accept', 'application/json')18 .expect('Content-Type', /json/)19 .expect(200)20 .end(function(err, res){21 if (err) return done(err);22 res.body.should.be.instanceof(Array);23 res.body.should.have.lengthOf(3);24 done();25 });26 });27});28describe('GET /users/:id', function(){29 it('respond with json', function(done){30 request(app)31 .get('/users/1')32 .set('Accept', 'application/json')33 .expect('Content-Type', /json/)34 .expect(200)35 .end(function(err, res){36 if (err) return done(err);37 res.body.should.have.property('id', 1);38 done();39 });40 });41});42describe('POST /users', function(){43 it('respond with 201 created', function(done){44 request(app)45 .post('/users')46 .send({ name: 'john', email: '
Using AI Code Generation
1var errorJSON = require('mocha/lib/utils').errorJSON;2var filterStack = require('mocha/lib/utils').filterStack;3var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;4var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;5var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;6var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;7var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;8var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;9var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;10var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;11var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;12var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;13var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;14var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;15var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;16var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;17var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;18var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;19var stackTraceFilter = require('mocha/lib/utils').stackTraceFilter;
Using AI Code Generation
1var assert = require('assert');2var errorJSON = require('chai').util.errorJSON;3var object = { name: 'Mocha' };4assert.equal(object, object);5assert.equal(object, { name: 'Mocha' });6assert.equal(object, { name: 'mocha' });7assert.equal(object, { name: 'Mocha' });8assert.equal(object, { name: 'mocha' });9assert.equal(object, { name: 'mocha' });10assert.equal(object, { name: 'mocha' });11assert.equal(object, { name: 'mocha' });12assert.equal(object, { name: 'mocha' });13assert.equal(object, { name: 'mocha' });14assert.equal(object, { name: 'mocha' });15assert.equal(object, { name: 'mocha' });16assert.equal(object, { name: 'mocha' });17assert.equal(object, { name: 'mocha' });18assert.equal(object, { name: 'mocha' });19assert.equal(object, { name: '
Using AI Code Generation
1var assert = require('assert');2var errorJSON = require('./errorJSON.js');3describe('errorJSON', function() {4 it('should return a JSON object with the error message', function() {5 assert.equal(errorJSON('test error message'), '{"error":"test error message"}');6 });7});8module.exports = function errorJSON(err) {9 return JSON.stringify({error: err});10};11 1 passing (9ms)12You can run multiple test cases by adding additional it() blocks to the test suite. For example, the following test suite runs two test cases:13describe('errorJSON', function() {14 it('should return a JSON object with the error message', function() {15 assert.equal(errorJSON('test error message'), '{"error":"test error message"}');16 });17 it('should return a JSON object with the error message', function() {18 assert.equal(errorJSON('another test error message'), '{"error":"another test error message"}');19 });20});21If you want to run multiple test suites, you can add additional describe() blocks to the test file. For example, the following test file runs two test suites:
Using AI Code Generation
1var errorJSON = require('mocha/lib/utils').errorJSON;2var add = require('../app.js').add;3describe("Addition Tests", function(){4 it("should return 5", function(){5 if(add(2,3) !== 5){6 throw new Error("2+3 should equal 5");7 }8 });9 it("should throw an error if args not numbers", function(){10 try{11 add(2, "3");12 } catch(e){13 if(!e instanceof TypeError){14 throw e;15 }16 return;17 }18 throw new Error("add did not throw an error!");19 });20});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!