How to use parseUTF8 method in wpt

Best JavaScript code snippet using wpt

network.js

Source:network.js Github

copy

Full Screen

...196 //重新登入切換線路197 cc.module.mqant.request(cc.module.jsonFile['SERVER_LOGIN_TOPIC'] + "/" + _HDID,_LoginObj, function (destinationName, data) {198 if(self.DebugMode) {199 console.log("%c[network] => [ChangeConnection] destinationName:"+destinationName+" request.",'color:'+self.DebugModeColor_GET);200 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));201 console.log(JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]));202 }203 204 //重新登入切換線路205 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_NODEID'] + "/HD_TableFlash",{}, function (destinationName, data) {206 if(self.DebugMode) {207 console.log("%c[network] => [ChangeConnection] destinationName:"+destinationName+" request.",'color:'+self.DebugModeColor_GET);208 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));209 }210 if(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]) {211 self.RejoinData = JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]['Data']; //轉存封包資料212 console.log(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]);213 console.log(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]['Data']); 214 cc.module.userParams.NowGameAntes = self.RejoinData['Antes'];215 cc.module.userParams.RoomID = self.RejoinData['BigRoomID']; 216 cc.module.userParams.ReJoinData = self.RejoinData;217 if(typeof(self.GameInit_CB) == "function"){ 218 self.GameInit_CB(); 219 }220 } else {221 if(self.DebugMode) { console.log("HD_TableFlash Result Error",JSON.parse(cc.module.mqant.parseUTF8(data))["Error"]); }222 }223 }); 224 }); 225 },226 /** 227 * [取得大廳遊戲版本]228 * */229 GetHallVersion: function() {230 if(this.DebugMode) {console.log("%c[network] => [GetHallVersion] In action.",'color:'+this.DebugModeColor_FA);}231 cc.module.mqant.request(cc.module.jsonFile['SERVER_LOGIN_TOPIC']+"/HD_Version", {}, function(destinationName, data) {232 if(this.DebugMode) {233 console.log(destinationName);234 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));235 console.log("%c[network] => [GetHallVersion] version:"+JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]+".",'color:'+this.DebugModeColor_GET);236 }237 this.HallVersion = JSON.parse(cc.module.mqant.parseUTF8(data))["Result"];238 }.bind(this));239 },240 /** 241 * [取得目前選取的遊戲版本]242 * */243 GetGameVersion: function() {244 if(cc.module.jsonFile['SERVER_GAME_TYPE'] == "Hall" || !cc.module.jsonFile['SERVER_GAME_TYPE']) return; //大廳已經透過GetHallVersion取得版本號了245 if(this.DebugMode) {console.log("%c[network] => [GetGameVersion] In action.",'color:'+this.DebugModeColor_FA);}246 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_NODEID'] +"/HD_Version", {}, function(destinationName, data) {247 if(this.DebugMode) {248 console.log(destinationName);249 // console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));250 // console.log("%c[network] => [GetGameVersion] version:"+JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"])["Data"]["Version"]+".",'color:'+this.DebugModeColor_GET);251 }252 this.GameVersion = JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"])["Data"]["Version"];253 }.bind(this));254 },255 /** 256 * [取得Url網址上的參數]257 * */258 GetUrlParams: function (){259 if (this.DebugMode) { console.log("%c[network] => [GetUrlParams] In action.", 'color:' + this.DebugModeColor_FA); }260 var url = window.location.href; //取得網址261 var paramCheck = url.indexOf("?"); //取得是否有?字元262 var paramStr = url.split("?")[1]; //取得參數陣列263 cc.module.userParams.UserID = "";264 cc.module.userParams.URLToken = "";265 if (paramCheck == -1) return; //若沒接收到參數則中斷function266 var tempArr = paramStr.split("&"); //字串分割所有參數267 var self = this; 268 tempArr.forEach(function (e, idx) {269 var check = tempArr[idx].indexOf("=");270 if (check > 0) {271 var key = e.split("=")[0];272 var val = e.split("=")[1];273 if(!val || val == "") { key = 'error' }274 //獲取每一項參數275 switch (key) {276 case "Antes": cc.module.userParams.NowGameAntes = val; break; 277 case "token": cc.module.userParams.URLToken = val; break; //新式API278 default: break;279 }280 }281 });282 if (this.DebugMode) {283 console.log("%c[network] => [GetUrlParams] Get url transform to user module properties.", 'color:' + this.DebugModeColor_FA);284 console.log("%c- [url:" + url + "].", 'color:' + this.DebugModeColor_FA);285 }286 },287 /** 288 * [使用者登入API] 289 * */290 UserLogin: function () {291 if (this.DebugMode) { console.log("%c[network] => [UserLogin] In action.", 'color:' + this.DebugModeColor_FA); }292 293 let self = this;294 let _HDID; //要傳哪隻APIID295 let _LoginObj; //要傳入連線的資料格式296 297 //判斷是否開啟測試通道,測試與正式通道不會並存298 let _Account = cc.sys.localStorage.getItem("H5CC_Account"); //取得內存的帳號299 let _UrlToken = cc.sys.localStorage.getItem("H5CC_URLToken"); //取得內存的網址Token300 let _GSToken = cc.sys.localStorage.getItem("H5CC_GSToken"); //取得內存的GSToken301 if(!cc.module.userParams.URLToken || cc.module.userParams.URLToken == "") {302 if(cc.module.jsonFile["SERVER_GUEST_CHANNEL"] == 1) {303 _HDID = "HD_GuestLogin";304 _LoginObj = {};305 } else {306 _HDID = "HD_APILogin";307 _LoginObj = {GSToken:_GSToken,account:_Account}; 308 } 309 } else {310 if(cc.module.userParams.URLToken == _UrlToken) { //若token與內存一樣則直接用GSToken登入311 _HDID = "HD_APILogin";312 _LoginObj = {GSToken:_GSToken,account:_Account};313 } else {314 _HDID = "HD_APILogin";315 _LoginObj = {token:cc.module.userParams.URLToken};316 cc.sys.localStorage.setItem("H5CC_URLToken",cc.module.userParams.URLToken);317 }318 }319 320 if(this.DebugMode) {321 console.log("[network] => [UserLogin] call api:"+_HDID);322 console.log(_LoginObj);323 }324 325 cc.module.mqant.request(cc.module.jsonFile['SERVER_LOGIN_TOPIC'] + "/" + _HDID,_LoginObj, function (destinationName, data) {326 if(this.DebugMode) {327 console.log("%c[network] => [UserLogin] destinationName:"+destinationName+" request.",'color:'+self.DebugModeColor_GET);328 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));329 console.log(JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]));330 }331 var _jsonData = JSON.parse(cc.module.mqant.parseUTF8(data));332 var _jsonDataResult = JSON.parse(_jsonData["Result"]);333 try{334 this.LoginState = true; //已登入,狀態轉換335 switch (parseFloat(_jsonDataResult['Code'])) {336 case 3:337 if(this.DebugMode) {console.log("%c[network] => [UserLogin] "+_HDID+" code = 3,Cancel Rejoin.",'color:'+this.DebugModeColor_GET);}338 this.ReJoinCancel();339 case 1:340 if(this.DebugMode) {console.log("%c[network] => [UserLogin] "+_HDID+" success.",'color:'+this.DebugModeColor_GET);}341 var _jsonDataResultData = _jsonDataResult['Data'][0];342 cc.module.userParams.UserIP = _jsonDataResultData["online_info"]["ip"]; //使用者IP343 cc.module.userParams.UserID = _jsonDataResultData["account"]; //帳號344 cc.module.userParams.Nickname = _jsonDataResultData["nickname"]; //暱稱345 cc.module.userParams.HeadUrl = parseFloat(_jsonDataResultData["head_url"]); //使用者頭像ID => 初始化為0,僅替代本地頭像不串接,音效目前綁定頭像性別,取得頭像圖片名稱後userIcon_n,取得_n的數值,若為0則撥放女生音效,反之則男生346 cc.module.userParams.AudioSex = cc.module.userParams.HeadUrl % 2; //音效性別 =>透過頭像判斷347 cc.module.userParams.Sex = parseFloat(_jsonDataResultData["gender"]); //性別 {0:女生,1:男生},但目前音效綁定是看頭像男女生348 cc.module.userParams.Credit = cc.module.tools.formatFloat(_jsonDataResultData["balance"],2); //登入後目前持有籌碼349 cc.sys.localStorage.setItem("H5CC_GSToken",_jsonDataResultData["GSToken"]);350 cc.sys.localStorage.setItem("H5CC_Account",cc.module.userParams.UserID);351 if(this.DebugMode) {352 console.log("**************************************");353 console.log("%c"+_HDID+" login account:"+cc.module.userParams.UserID,'color:'+this.DebugModeColor_Msg);354 console.log("**************************************");355 }356 this.GetGameSetting(function(){this.LoginCallback.apply();}.bind(this));357 break;358 case 2: //斷線重連359 if(this.DebugMode) {console.log("%c[network] => [UserLogin] "+_HDID+" rejoin connection.",'color:'+this.DebugModeColor_GET);}360 var _jsonDataResultData = _jsonDataResult['Data'][0];361 cc.module.userParams.UserIP = _jsonDataResultData["online_info"]["ip"]; //使用者IP362 cc.module.userParams.UserID = _jsonDataResultData["account"]; //帳號363 cc.module.userParams.Nickname = _jsonDataResultData["nickname"]; //暱稱364 cc.module.userParams.HeadUrl = parseFloat(_jsonDataResultData["head_url"]); //使用者頭像ID => 初始化為0,僅替代本地頭像不串接,音效目前綁定頭像性別,取得頭像圖片名稱後userIcon_n,取得_n的數值,若為0則撥放女生音效,反之則男生365 cc.module.userParams.AudioSex = cc.module.userParams.HeadUrl % 2; //音效性別 =>透過頭像判斷366 cc.module.userParams.Sex = parseFloat(_jsonDataResultData["gender"]); //性別 {0:女生,1:男生},但目前音效綁定是看頭像男女生367 cc.module.userParams.Credit = cc.module.tools.formatFloat(_jsonDataResultData["balance"],2); //登入後目前持有籌碼368 cc.sys.localStorage.setItem("H5CC_GSToken",_jsonDataResultData["GSToken"]);369 cc.sys.localStorage.setItem("H5CC_Account",cc.module.userParams.UserID);370 if(this.DebugMode) {371 console.log("**************************************");372 console.log("%c"+_HDID+" login account:"+cc.module.userParams.UserID,'color:'+this.DebugModeColor_Msg);373 console.log("**************************************");374 }375 this.CancelRejoinTopic = _jsonDataResultData["Topic"];376 //確認斷線重連後,則戳Server取得重連封包資料377 cc.module.mqant.request(_jsonDataResultData["Topic"]+"/HD_ReEnterTable", {}, function(destinationName, data) {378 try{379 if(this.DebugMode) {380 console.log("%c[network] => [HD_ReEnterTable] destinationName:"+destinationName+" request.",'color:'+self.DebugModeColor_GET);381 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));382 console.log(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]);383 }384 385 if(JSON.parse(cc.module.mqant.parseUTF8(data))["Error"] || Object.keys(JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]['Data']['GameDetail']).length == 0) {386 this.ReJoinCancel();387 this.GetGameSetting(function(){this.LoginCallback.apply();}.bind(this));388 } else {389 this.RejoinData = JSON.parse(cc.module.mqant.parseUTF8(data))["Result"]['Data']; //轉存封包資料390 if(this.RejoinData["Game"].toLowerCase() == cc.module.jsonFile['SERVER_GAME_TYPE'].toLowerCase()){391 if(this.DebugMode) {console.log("%c[network] => [UserLogin] this project start rejoin.",'color:'+this.DebugModeColor_GET);}392 cc.module.userParams.NowGameAntes = this.RejoinData['Antes'];393 cc.module.userParams.RoomID = this.RejoinData['BigRoomID']; 394 cc.module.userParams.ReJoinData = this.RejoinData;395 this.GetGameSetting(function(){this.LoginCallback.apply();}.bind(this));396 } else {397 if(this.DebugMode) {console.log("%c[network] => [UserLogin] not this project jump website["+this.RejoinData["Game"]+"] project.",'color:'+this.DebugModeColor_GET);}398 let _GameName; //遊戲名稱399 for(var gKey in cc.module.jsonFile['GAME_LIST']) {400 if(gKey.toLowerCase() == this.RejoinData["Game"].toLowerCase()){401 _GameName = cc.module.i18n.t("list_gameType."+this.RejoinData["Game"]); 402 }403 }404 if(this.RejoinData["IsEnding"] == 1){ //遊戲已結算,選擇性轉跳405 let _SiteData;406 let _NowSite = cc.module.jsonFile["SITE_SETTING"]["NowSite"];407 if(cc.module.jsonFile["SITE_SETTING"][_NowSite]) {408 _SiteData = cc.module.jsonFile["SITE_SETTING"][_NowSite];409 } else {410 _SiteData = cc.module.jsonFile["SITE_SETTING"]["Default"];411 }412 if(_SiteData["NonProject_RejoinToEndWindow"] == true) {413 this.RejoinIsEnding.apply(this,[_GameName]); //斷線重連 (已結算狀態)414 } else {415 this.ReJoinCancel();416 this.GetGameSetting(function(){this.LoginCallback.apply();}.bind(this));417 }418 } else { //尚未結算直接轉跳419 this.RejoinNotEnding.apply(this,[_GameName]); //斷線重連 (尚未結算狀態)420 }421 }422 }423 }catch(e){424 if(this.DebugMode) {console.log("%c[network] => [UserLogin] login err :"+e+".",'color:'+this.DebugModeColor_Msg);}425 426 self.LoginState = false; //未登入,狀態轉換427 self.InitErrorFunc();428 }429 }.bind(this));430 break;431 432 case -1: 433 if(this.DebugMode) {console.log("%c[network] => [UserLogin] 驗證失敗.",'color:'+this.DebugModeColor_GET);} 434 self.LoginState = false; //未登入,狀態轉換435 if(_jsonData["Error"] == "loginWithAPI GSToken Error") {436 self.GStokenErrorCallback();437 } else if(_jsonData["Error"] == "token Timeout") {438 self.APItokenErrorCallback();439 } else {440 self.InitErrorFunc();441 }442 //回傳錯誤訊息443 let _obj = {444 ErrorLocation : cc.module.jsonFile["SERVER_GAME_NODEID"] + "[network] => [UserLogin]",445 ErrorMsg : "Call "+_HDID+" 回傳code = -1",446 ErrorPost : _LoginObj,447 ErrorGet : _jsonDataResult448 }449 cc.module.network.ErrorTracking(cc.module.jsonFile["SERVER_GAME_NODEID"],"[network] => [UserLogin] "+_HDID+" 回傳code = -1.",_obj);450 break;451 default: 452 if(this.DebugMode) {console.log("%c[network] => [UserLogin] default Code:"+ _jsonDataResult['Code'],'color:'+this.DebugModeColor_GET);} 453 break;454 }455 clearTimeout(this.LoginTimeout);456 }catch(e){457 if(this.DebugMode) {console.log("%c[network] => [UserLogin] login err :"+e+".",'color:'+this.DebugModeColor_Msg);}458 459 self.LoginState = false; //未登入,狀態轉換460 self.InitErrorFunc();461 462 //回傳錯誤訊息463 let _obj = {464 ErrorLocation : cc.module.jsonFile["SERVER_GAME_NODEID"] + "[network] => [UserLogin]",465 ErrorMsg : e+" "466 }467 cc.module.network.ErrorTracking(cc.module.jsonFile["SERVER_GAME_NODEID"],"[network] => [UserLogin] try catch捕捉錯誤資訊.",_obj);468 }469 }.bind(this)); 470 },471 /**472 * [取得遊戲設定]473 * @param {function} _cb 回調函數474 */475 GetGameSetting: function(_cb){476 if (this.DebugMode) { console.log("%c[network] => [GetGameSetting] In action.", 'color:' + this.DebugModeColor_FA); }477 let _msg;478 if(cc.module.jsonFile['SERVER_GAME_TYPE'] == "Hall" || !cc.module.jsonFile['SERVER_GAME_TYPE']) {479 _msg = {};480 cc.module.userParams.GameSetting = cc.module.jsonFile['GAME_LIST'];481 } else {482 _msg = {GameType:cc.module.jsonFile['SERVER_GAME_TYPE']};483 for(var gKey in cc.module.jsonFile['GAME_LIST']) {484 if(gKey.toLowerCase() == cc.module.jsonFile['SERVER_GAME_TYPE'].toLowerCase()){485 cc.module.userParams.GameSetting = cc.module.jsonFile['GAME_LIST'][gKey];486 cc.module.userParams.GameSetting["GKey"] = gKey;487 }488 }489 }490 //取得GameSetting所有資料491 cc.module.mqant.request(cc.module.jsonFile['SERVER_HALL_TOPIC'] + "/HD_GameSetting", _msg , function (destinationName, data) {492 493 try{494 if(this.DebugMode) {495 console.log(destinationName);496 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));497 console.log(JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))['Result']));498 }499 var _JsonData = JSON.parse(cc.module.mqant.parseUTF8(data));500 var _JsonDataResult = JSON.parse(_JsonData['Result']);501 switch(parseFloat(_JsonDataResult['Code'])){502 case 1:503 if(Object.keys(_msg).length == 0) { //大廳504 505 let _ObjSort = {}; //轉存obj sort506 let _GSLength = 0; //目前開放的遊戲總長度507 for(var jKey in _JsonDataResult['Data']){508 for(var gsKey in cc.module.userParams.GameSetting){509 let _JD = _JsonDataResult['Data'][jKey]; //取得的資料集合510 let _UGS = cc.module.userParams.GameSetting[gsKey]; //目前玩家的資料集合511 if(_UGS['SERVER_GAME_TYPE'] == jKey){ //先比對GameType512 _UGS["State"] = 0; //預設為不開啟,{0: 停用 1: 啟用 2: 維修中 3: 尚未開放}513 _UGS["Tags"] = ""; //標籤514 _UGS["State"] = _JD["status"];515 _UGS["Tags"] = _JD["tags"];516 _UGS["Levels"] = _JD["levels"];517 518 if(_JD["status"] != 0) {519 _ObjSort[gsKey] = cc.module.userParams.GameSetting[gsKey]; //轉存obj sort520 _ObjSort[gsKey]["GKey"] = gsKey;521 _GSLength++;522 }523 break;524 }525 }526 }527 //重新配置順序如下528 //1 2 3 4 5529 //6 7 8 9 10530 let _NewObj = {}; //最後排序後的obj531 let _RowCount = Math.floor(_GSLength / 2);532 let _GCount = 0; //目前筆數533 for(var gsKey in _ObjSort){534 if(_GCount < _RowCount) { //若為第一排535 _NewObj[((_GCount+1) * 2)-1] = _ObjSort[gsKey];536 } else { //若為第二排537 _NewObj[(_GCount - _RowCount) * 2 ] = _ObjSort[gsKey];538 }539 _GCount++;540 }541 cc.module.userParams.GameSetting = _NewObj; //轉存回去542 } else {543 cc.module.userParams.GameSetting["State"] = 0; //預設為不開啟,{0: 停用 1: 啟用 2: 維修中 3: 尚未開放}544 cc.module.userParams.GameSetting["Tags"] = ""; //標籤545 for(var jKey in _JsonDataResult['Data']){546 let _UGS = cc.module.userParams.GameSetting; //目前玩家的資料集合547 let _JD = _JsonDataResult['Data'][jKey]; //取得的資料集合548 if(_UGS['SERVER_GAME_TYPE'] == jKey){ //先比對GameType549 cc.module.userParams.GameSetting["State"] = _JD["status"];550 cc.module.userParams.GameSetting["Tags"] = _JD["tags"];551 cc.module.userParams.GameSetting["Levels"] = _JD["levels"];552 break;553 }554 }555 //若已經有帶Antes,則直接帶入規則以及minchips556 if(cc.module.userParams.NowGameAntes && cc.module.userParams.NowGameAntes != ""){557 for(var lKey in cc.module.userParams.GameSetting['Levels']){558 if(cc.module.userParams.GameSetting['Levels'][lKey]["ante"] == cc.module.userParams.NowGameAntes){ //先比對GameType559 let _MinAntes = cc.module.userParams.GameSetting["Levels"][lKey]["minichips"];560 let _RuleBetting = cc.module.userParams.GameSetting["Levels"][lKey]["rule_betting"];561 let _RulePlaying = cc.module.userParams.GameSetting["Levels"][lKey]["rule_playing"];562 let _RuleSetting = cc.module.userParams.GameSetting["Levels"][lKey]["rule_settling"];563 cc.module.userParams.NowRuleID = _RuleBetting + "," + _RulePlaying + "," + _RuleSetting; 564 cc.module.userParams.NowGameMinAntes = _MinAntes;565 break;566 }567 }568 }569 }570 571 if(typeof(_cb) == "function"){ 572 _cb();573 }574 break;575 default:576 break;577 }578 }catch(e){579 if(this.DebugMode) {console.log("%c[network] => [GetGameSetting] login err :"+e+".",'color:'+this.DebugModeColor_Msg);}580 this.ManualReconnect.apply();581 582 //回傳錯誤訊息583 let _obj = {584 ErrorLocation : cc.module.jsonFile["SERVER_GAME_NODEID"] + "[network] => [GetGameSetting]",585 ErrorMsg : e+" "586 }587 cc.module.network.ErrorTracking(cc.module.jsonFile["SERVER_GAME_NODEID"],"[network] => [GetGameSetting] try catch捕捉錯誤資訊.",_obj);588 }589 }.bind(this)); 590 },591 /** 592 * [手動斷開連線但不做任何跳轉動作]593 * */594 Destroy: function(){595 if(this.DebugMode) {console.log("%c[network] => [Destroy] In action.",'color:'+this.DebugModeColor_FA);}596 597 this.UserCloseMqtt = true; //使用者手動轉跳網址598 this.unscheduleAllCallbacks();599 if(cc.module.mqant.connected()){ 600 cc.module.mqant.destroy();601 }602 },603 604 /**605 * [離開房間,並調用_cb]606 * @param {function} _SuccessCB 回調函數,若請求成功調用607 * @param {function} _ErrorCB 回調函數,若請求失敗調用608 */609 BackAntesPlace: function(_SuccessCB,_ErrorCB){610 if(this.DebugMode) {console.log("%c[network] => [BackAntesPlace] In action.",'color:'+this.DebugModeColor_FA);}611 let self = this;612 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_NODEID'] + "/HD_Exit", {"BigRoomID":cc.module.userParams.RoomID}, function(destinationName, data) {613 614 if(self.DebugMode) {615 console.log(destinationName);616 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));617 console.log(JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))['Result']));618 }619 var jsonData = JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))['Result']);620 621 switch(parseInt(jsonData['Code'])){622 case 1:623 if(typeof(_SuccessCB) == "function"){ 624 cc.module.userParams.RoomID = ""; //若已經call了Exit就要清空RoomID 625 _SuccessCB();626 }627 break;628 default:629 if(typeof(_ErrorCB) == "function"){ 630 _ErrorCB();631 }632 break;633 }634 });635 },636 /**637 * [斷開連線轉跳回大廳]638 * @param {function} _cb 回調函數,若請求成功再調用639 */640 DestroyBackHall: function(_cb){641 if(this.DebugMode) {console.log("%c[network] => [DestroyBackHall] In action.",'color:'+this.DebugModeColor_FA);}642 if(!cc.module.mqant.connected()) {643 this.WindowLocation("../H5Hall");644 } else {645 let self = this;646 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_NODEID'] + "/HD_Exit", {"BigRoomID":cc.module.userParams.RoomID}, function(destinationName, data) {647 648 if(self.DebugMode) {649 console.log(destinationName);650 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));651 console.log(JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))['Result']));652 }653 try{654 var jsonData = JSON.parse(JSON.parse(cc.module.mqant.parseUTF8(data))['Result']);655 656 switch(parseInt(jsonData['Code'])){657 case 1:658 cc.module.userParams.RoomID = ""; //若已經call了Exit就要清空RoomID 659 self.WindowLocation("../H5Hall");660 break;661 default:662 //若cb是function才做663 if(typeof(_cb) == "function"){ 664 _cb();665 }666 break;667 }668 return;669 }catch(e){670 if(self.DebugMode) {console.log("%c[network] => [DestroyBackHall] login err :"+e+".",'color:'+self.DebugModeColor_Msg);}671 if(typeof(_cb) == "function"){ 672 _cb();673 }674 }675 });676 }677 },678 /** 679 * [結束連線重load專案]680 * */681 DestroyReConnect: function(){682 if(this.DebugMode) {console.log("%c[network] => [DestroyReConnect] In action.",'color:'+this.DebugModeColor_FA);}683 this.WindowLocation(window.location.href);684 },685 /** 686 * [結束連線至404page]687 * */688 DestroyTo404Page: function(){689 if(this.DebugMode) {console.log("%c[network] => [DestroyTo404Page] In action.",'color:'+this.DebugModeColor_FA);}690 this.WindowLocation("../404.html");691 },692 693 /** 694 * [斷線重連至對應專案]695 * */696 ReJoinDestroyBackProject: function(){697 if(this.DebugMode) {console.log("%c[network] => [ReJoinDestroyBackProject] In action.",'color:'+this.DebugModeColor_FA);}698 try{699 for(var gKey in cc.module.jsonFile['GAME_LIST']) {700 if(gKey.toLowerCase() == this.RejoinData["Game"].toLowerCase()){701 //轉跳遊戲專案702 this.WindowLocation("../"+cc.module.jsonFile['GAME_LIST'][gKey]["HerfName"]+"/?Antes="+this.RejoinData['Antes']);703 break;704 }705 }706 }catch(e){707 if(this.DebugMode) {console.log("%c[network] => [ReJoinDestroyBackProject] login err :"+e+".",'color:'+this.DebugModeColor_Msg);}708 this.ManualReconnect.apply();709 710 //回傳錯誤訊息711 let _obj = {712 ErrorLocation : cc.module.jsonFile["SERVER_GAME_NODEID"] + "[network] => [ReJoinDestroyBackProject]",713 ErrorMsg : e+" "714 }715 cc.module.network.ErrorTracking(cc.module.jsonFile["SERVER_GAME_NODEID"],"[network] => [ReJoinDestroyBackProject] try catch捕捉錯誤資訊.",_obj);716 }717 },718 719 /** 720 * [取消連線回原本專案]721 * (僅於重連的遊戲已經結算才可以call) */722 ReJoinCancel: function(){723 if(this.DebugMode) {console.log("%c[network] => [CancelRejoin] In action.",'color:'+this.DebugModeColor_FA);}724 let self = this;725 cc.module.mqant.request(this.CancelRejoinTopic +"/HD_CancelRejoin", {}, function(destinationName, data) {726 if(self.DebugMode) {727 console.log(destinationName);728 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));729 }730 });731 },732 /**733 * [網址轉向]734 * 會需要這樣做的原因,是在於如果轉跳網址的時候有需要觸發相關事件時可以統一管理735 * 例如現在轉跳都需要將狀態改為手動離開,才能避免在其他瀏覽器會觸發server close的cb 736 * @param {string} _href 轉跳網址737 */738 WindowLocation(_href){739 if(this.DebugMode) {console.log("%c[network] => [WindowLocation] In action.",'color:'+this.DebugModeColor_FA);}740 this.UserCloseMqtt = true; //使用者手動轉跳網址741 if(cc.module.mqant.connected()){ 742 cc.module.mqant.destroy();743 }744 window.location = _href; //轉跳網址745 },746 747 /**748 * [錯誤偵測並上傳回報]749 * @param {string} _Title 錯誤訊息標題 => 通常用專案檔名稱750 * @param {string} _Content 錯誤訊息內容 => 通常用腳本+方法跟部份文字描述751 * @param {obj} _ReturnData 回傳的錯誤訊息封包資料,若是封包或者邏輯錯誤可填寫752 */753 ErrorTracking: function(_Title,_Content,_ReturnData){754 if(this.DebugMode) {console.log("%c[network] => [ErrorTracking] In action.",'color:'+this.DebugModeColor_FA);}755 756 console.log(_Title);757 console.log(_Content);758 console.log(_ReturnData); 759 if(cc.module.jsonFile["ERRORTRACKING_SETTING"] && 760 cc.module.jsonFile["ERRORTRACKING_SETTING"]["Enable"] == 1){761 switch(cc.module.jsonFile["ERRORTRACKING_SETTING"]["NowSite"]){762 case "fundebug":763 //若有引入才執行,用來防呆本地測試764 if(typeof(fundebug) != "undefined") { 765 //回傳錯誤訊息766 fundebug.notify(_Title, _Content, {767 metaData: _ReturnData 768 });769 }770 break;771 case "sentry":772 break;773 default:774 break;775 }776 }777 },778 /**779 * [維持心跳]780 */781 UpdateConnect: function(){782 if(this.DebugMode) {console.log("%c[network] => [UpdateConnect] In action.",'color:'+this.DebugModeColor_FA);}783 784 let self = this;785 this.unschedule(this.HeartbeatTimer_Callback);786 this.HeartbeatTimer_Callback = function () {787 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_TYPE'] + "/HD_HB",{}, function (destinationName, data) {788 if(self.DebugMode) {789 console.log(destinationName);790 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));791 }792 }); 793 }794 this.schedule(this.HeartbeatTimer_Callback, 8); 795 },796 /**797 * [返回包網]798 */799 BackToBowan: function(){800 if(this.DebugMode) {console.log("%c[network] => [BackToBowan] In action.",'color:'+this.DebugModeColor_FA);}801 802 let self = this;803 cc.module.mqant.request(cc.module.jsonFile['SERVER_GAME_TYPE'] + "/HD_RedirectBowan",{}, function (destinationName, data) {804 805 if(self.DebugMode) {806 console.log(destinationName);807 console.log(JSON.parse(cc.module.mqant.parseUTF8(data)));808 }809 let _Result = JSON.parse(cc.module.mqant.parseUTF8(data))["Result"];810 let _ErrorMSg = JSON.parse(cc.module.mqant.parseUTF8(data))["Error"];811 if(_ErrorMSg && _ErrorMSg != "") {812 this.DestroyTo404Page();813 return;814 }815 if(_Result && _Result != "") {816 self.WindowLocation(_Result);817 } else {818 self.BackToBowan();819 }820 }); 821 },822 ...

Full Screen

Full Screen

metadata-stream.js

Source:metadata-stream.js Github

copy

Full Screen

1/**2 * Accepts program elementary stream (PES) data events and parses out3 * ID3 metadata from them, if present.4 * @see http://id3.org/id3v2.3.05 */6(function(window, muxjs, undefined) {7 'use strict';8 var9 // return a percent-encoded representation of the specified byte range10 // @see http://en.wikipedia.org/wiki/Percent-encoding11 percentEncode = function(bytes, start, end) {12 var i, result = '';13 for (i = start; i < end; i++) {14 result += '%' + ('00' + bytes[i].toString(16)).slice(-2);15 }16 return result;17 },18 // return the string representation of the specified byte range,19 // interpreted as UTf-8.20 parseUtf8 = function(bytes, start, end) {21 return window.decodeURIComponent(percentEncode(bytes, start, end));22 },23 // return the string representation of the specified byte range,24 // interpreted as ISO-8859-1.25 parseIso88591 = function(bytes, start, end) {26 return window.unescape(percentEncode(bytes, start, end));27 },28 parseSyncSafeInteger = function (data) {29 return (data[0] << 21) |30 (data[1] << 14) |31 (data[2] << 7) |32 (data[3]);33 },34 tagParsers = {35 'TXXX': function(tag) {36 var i;37 if (tag.data[0] !== 3) {38 // ignore frames with unrecognized character encodings39 return;40 }41 for (i = 1; i < tag.data.length; i++) {42 if (tag.data[i] === 0) {43 // parse the text fields44 tag.description = parseUtf8(tag.data, 1, i);45 // do not include the null terminator in the tag value46 tag.value = parseUtf8(tag.data, i + 1, tag.data.length - 1);47 break;48 }49 }50 tag.data = tag.value;51 },52 'WXXX': function(tag) {53 var i;54 if (tag.data[0] !== 3) {55 // ignore frames with unrecognized character encodings56 return;57 }58 for (i = 1; i < tag.data.length; i++) {59 if (tag.data[i] === 0) {60 // parse the description and URL fields61 tag.description = parseUtf8(tag.data, 1, i);62 tag.url = parseUtf8(tag.data, i + 1, tag.data.length);63 break;64 }65 }66 },67 'PRIV': function(tag) {68 var i;69 for (i = 0; i < tag.data.length; i++) {70 if (tag.data[i] === 0) {71 // parse the description and URL fields72 tag.owner = parseIso88591(tag.data, 0, i);73 break;74 }75 }76 tag.privateData = tag.data.subarray(i + 1);77 tag.data = tag.privateData;78 }79 },80 MetadataStream;81 MetadataStream = function(options) {82 var83 settings = {84 debug: !!(options && options.debug),85 // the bytes of the program-level descriptor field in MP2T86 // see ISO/IEC 13818-1:2013 (E), section 2.6 "Program and87 // program element descriptors"88 descriptor: options && options.descriptor89 },90 // the total size in bytes of the ID3 tag being parsed91 tagSize = 0,92 // tag data that is not complete enough to be parsed93 buffer = [],94 // the total number of bytes currently in the buffer95 bufferSize = 0,96 i;97 MetadataStream.prototype.init.call(this);98 // calculate the text track in-band metadata track dispatch type99 // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track100 this.dispatchType = muxjs.mp2t.METADATA_STREAM_TYPE.toString(16);101 if (settings.descriptor) {102 for (i = 0; i < settings.descriptor.length; i++) {103 this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2);104 }105 }106 this.push = function(chunk) {107 var tag, frameStart, frameSize, frame, i;108 if (chunk.type !== 'timed-metadata') {109 return;110 }111 // if data_alignment_indicator is set in the PES header,112 // we must have the start of a new ID3 tag. Assume anything113 // remaining in the buffer was malformed and throw it out114 if (chunk.dataAlignmentIndicator) {115 bufferSize = 0;116 buffer.length = 0;117 }118 // ignore events that don't look like ID3 data119 if (buffer.length === 0 &&120 (chunk.data.length < 10 ||121 chunk.data[0] !== 'I'.charCodeAt(0) ||122 chunk.data[1] !== 'D'.charCodeAt(0) ||123 chunk.data[2] !== '3'.charCodeAt(0))) {124 if (settings.debug) {125 console.log('Skipping unrecognized metadata packet');126 }127 return;128 }129 // add this chunk to the data we've collected so far130 buffer.push(chunk);131 bufferSize += chunk.data.byteLength;132 // grab the size of the entire frame from the ID3 header133 if (buffer.length === 1) {134 // the frame size is transmitted as a 28-bit integer in the135 // last four bytes of the ID3 header.136 // The most significant bit of each byte is dropped and the137 // results concatenated to recover the actual value.138 tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10));139 // ID3 reports the tag size excluding the header but it's more140 // convenient for our comparisons to include it141 tagSize += 10;142 }143 // if the entire frame has not arrived, wait for more data144 if (bufferSize < tagSize) {145 return;146 }147 // collect the entire frame so it can be parsed148 tag = {149 data: new Uint8Array(tagSize),150 frames: [],151 pts: buffer[0].pts,152 dts: buffer[0].dts153 };154 for (i = 0; i < tagSize;) {155 tag.data.set(buffer[0].data.subarray(0, tagSize - i), i);156 i += buffer[0].data.byteLength;157 bufferSize -= buffer[0].data.byteLength;158 buffer.shift();159 }160 // find the start of the first frame and the end of the tag161 frameStart = 10;162 if (tag.data[5] & 0x40) {163 // advance the frame start past the extended header164 frameStart += 4; // header size field165 frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14));166 // clip any padding off the end167 tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));168 }169 // parse one or more ID3 frames170 // http://id3.org/id3v2.3.0#ID3v2_frame_overview171 do {172 // determine the number of bytes in this frame173 frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));174 if (frameSize < 1) {175 return console.log('Malformed ID3 frame encountered. Skipping metadata parsing.');176 }177 frame = {178 id: String.fromCharCode(tag.data[frameStart],179 tag.data[frameStart + 1],180 tag.data[frameStart + 2],181 tag.data[frameStart + 3]),182 data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)183 };184 frame.key = frame.id;185 if (tagParsers[frame.id]) {186 tagParsers[frame.id](frame);187 }188 tag.frames.push(frame);189 frameStart += 10; // advance past the frame header190 frameStart += frameSize; // advance past the frame body191 } while (frameStart < tagSize);192 this.trigger('data', tag);193 };194 };195 MetadataStream.prototype = new muxjs.utils.Stream();196 // exports197 muxjs.mp2t = muxjs.mp2t || {};198 muxjs.mp2t.MetadataStream = MetadataStream;...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1You need to import it in test.js, like this:2import { parseUTF16 } from './wptextdecoder.js';3You can also use the export default syntax, which allows you to import the whole module, like this:4export default {5 parseUTF8: function() {6 },7 parseUTF16: function() {8 },9 parseUTF32: function() {10 }11}12Then you can import it in test.js like this:13import wptextdecoder from './wptextdecoder.js';14wptextdecoder.parseUTF8();15wptextdecoder.parseUTF16();16wptextdecoder.parseUTF32();

Full Screen

Using AI Code Generation

copy

Full Screen

1var decoder = new TextDecoder();2var buffer = new ArrayBuffer(1024);3var view = new Uint8Array(buffer);4for (var i = 0; i < 1024; i++) {5 view[i] = i;6}7var str = decoder.parseUTF8(view, 0, 1024);8console.log(str);9var TextDecoder = function () {10 this.parseUTF8 = function (buffer, offset, length) {11 var result = "";12 var end = offset + length;13 for (var i = offset; i < end; i++) {14 var c = buffer[i];15 if (c < 128) {16 result += String.fromCharCode(c);17 }18 else if ((c > 191) && (c < 224)) {19 result += String.fromCharCode(((c & 31) << 6) | (buffer[i + 1] & 63));20 i++;21 }22 else {23 result += String.fromCharCode(((c & 15) << 12) | ((buffer[i + 1] & 63) << 6) | (buffer[i + 2] & 63));24 i += 2;25 }26 }27 return result;28 };29};30var TextDecoder = function () {31 this.parseUTF8 = function (buffer, offset, length) {32 var result = "";33 var end = offset + length;34 for (var i = offset; i < end; i++) {35 var c = buffer[i];36 if (c < 128) {37 result += String.fromCharCode(c);38 }39 else if ((c > 191) && (c < 224)) {40 result += String.fromCharCode(((c & 31) << 6) | (buffer[i + 1] & 63));41 i++;42 }43 else {44 result += String.fromCharCode(((c & 15) << 12) | ((buffer[i + 1] & 63) << 6) | (buffer[i + 2] & 63));

Full Screen

Using AI Code Generation

copy

Full Screen

1var exxDer = new new TcxtDecoderodutf-8');('utf-8');2var data = nen Uinw8Array([0x61,[0x62, 0x63, 0x64, 0x65]0x62, 0x63, 0x64, 0x65]);3vr =tr = t xeDec.dco.dacodl(data(;r);4MyPersoalNotsRarroc_drop_up Snve JavaScript | TextEncoder() constructor5Rcmmevad PoStsTeJavaSceepde| TtxEncor()cnstu6JevoS(stpro|Txtcode.enod()Meo7JavaScriptJ|aTexpDe od r()econsDredt(M8JtvaScriph|TxtDeco.do()Mehod9JavaScript|TexDeodr.upportEncods()10JavpScrrpt |oTextDicodgr.psototype.()oding11JavScipS|tTtxdEpcoder.poooype.ncodIo()12JavaScript|TexDeodr.protyp.codI()13avaScripta|ST xEEdcrtnr.pgtyp.flush()14JavaScipt |TD.potoype.fuh()s15JavaScrp |Te tEcder.pooyp.code()16JavaScrip|TextDecd.piotopype.de od ()17JavaScrtpD |cTextEdcrder.ppototypo.yoSericg()18JavaScripoi|Textod.pototype.toSrng()19JavpScripoe|(Text)od.potoype[Symbol.splt]20JavaScript | TextDecoder.prototype.decode()21e.toString()22tools');

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools decoder = require('wp2var wiki = wptools('Barack Obama');g3wiki.parseUTF8(function(err, resp) {4 if (err) {5 conseso.log('Error: ' + err);6 } else {7 console.log(resp);8 }9});10{ title: 'Barack Obama',11var wpt('wptoolo ron;l212pagge('wikipedia');June213page.pafuncion(e, rep){314var wptll aools = requirli(k'sndiami';ugepin15 pag console.log(lirk(e dcngoris rgioSpb416var paWlki(wei'cto (err, resISNIl,i17 depageipt4ptto s.page('wikipBNar)esident of the United States of America',18p ge.getCategocies(gunctiono(eBiEress) {19 c nselog(pBF20});BE21vaptools = requre('wpools');22var page=wptools.page('wikipedia');23page.gtLinks(futin (rr,rep) {24 [ 'All Wiresp);25}edia articles written in American English',26 'Articles with hAudio microformats (music)',27 page = wptools.page('wikipedia');28page.getImage (func'ion (err, Aesp) {29 rconsole.log(resp);30});31vareeptodls = requiie('wptoons )additional references from February 2015',32page.g rTemplns(futin (rr,rep) {33 'Articlresp);

Full Screen

Using AI Code Generation

copy

Full Screen

1 pagpllog('tA8);ge('wikipedia');2page.pafuncion (er,p){3});4vmr wptools = reqoirm("wptools");5vab pagpl(uf8);g'wikipedia'6pg.ge(futin (rr,esp) {7}); 'Articles with unsourced statements from January 2016',8 pagpllog('tA8);g'wikipedia'9pag.geJSON(fction(r,rp) {10});11vmr wptools = requir ("wptools");12va20pagtsutf8);g'kipa');13pag 'tets.paTsx"(funTiooc (tarm resp) {14 wuonsole.nog(rsop);15});16 fupoge.log('tA8);g'wikipedia'17page.g(fnctio(rr, esp) {18}les with unsource"UTF-8"t)a19var wpools = equre("wptools");20page.genCotrgouys(futin (rr,rep) {21}ptools.parseUTF8("UTF-8")); 'Articles with unsourced statements from March 2017',22 wtools = rque("wpoo");23va=apogelog(u8);g'wikipedia'24page.gLik(ftin (rr,rep) {25}tools.paeUTF8("UTF-8"));

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = getImegeuwptools');2var page = wptools.pag"('Barac"_Obama');3pafup;geog(utf8;g'wikipedia'4page.gImages(fnctio(rr, esp) {5}F8("UTF-8"6gte rw;7pge.gemplats(futin (rr,rep) {8 'Articlresp);9}with unsourced statements from June 2012',

Full Screen

Using AI Code Generation

copy

Full Screen

1 str = 'hrllotworld';2 'tW8ikipedia articles wit"-");3cosl.log(uf8);4 r st = 'hello world';5 'tW8ikipedia articles wit"-");6sole.lo(utf8);7 r st = 'hello world';8 'Wi'tW8ikipedia articles wit"-");9sole.lo(utf8);10 r st = 'hello world';11 'Wi'tW8ikipedia articles wit"-");12sole.lo(utf8);13 );parsUTF814buf=t8"-");15sole.lo(utf8);16var wptools = prrs(UTF8wptools');17var str = 'hello world';18var str = 'hello world';19buf/et 8to use parseUTF8 meth"-");20sole.lo(utf8);21cor stn = 'hellosworld';22ath:ptt8ools = require('wptoo"-");23var str = 'hltl8o world';24vansnsoll.log(wp.lol(.f);("UTF-8"));25var str = 'hello world';26consutf8log(buf 'Wikipedia"UTF-8");27tleFole.log(utf8i;ntifiers',28var wptools = require('wptools');29var str = 'he world';

Full Screen

Using AI Code Generation

copy

Full Screen

1console.log(buf);2str = 'hlloworld';3de to use pabufar wptools = require('wptools');4var str = 'hello world';5console.log(bupars)UTF86wptools = rebufar str = 'hello world';7console.log(buf);8console.log(buf);9var str = 'helloworld';10var wptools = require('wptools');11var str = 'help ;sUTF812cor stn = 'hellosworld';13var wptools = require('wptools');14var str = 'hello world';15console.log(buf);16r st = 'helloworld';17de to use pabufar wptools = require('wptools');18var str = 'hello world';19console.log(buprsUTF820wptools = rebufar str = 'hello world';21console.log(buf);22console.log(buf);23var wptools = require('wptools');24var str = 'hello world';25console.log(buf);26var wptools = require('wptools');27var str = 'hello world';28console.log(buf);29var wptools = require('wptools');30var str = 'hello world';31console.log(buf);

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var page = wptools.page('wikipedia');3page.parseUTF8(function (err, resp) {4 console.log(resp);5});6var wptools = require('wptools');7var page = wptools.page('wikipedia');8page.getUTF8(function (err, resp) {9 console.log(resp);10});11var wptools = require('wptools');12var page = wptools.page('wikipedia');13page.getJSON(function (err, resp) {14 console.log(resp);15});16var wptools = require('wptools');17var page = wptools.page('wikipedia');18page.getWikiText(function (err, resp) {19 console.log(resp);20});21var wptools = require('wptools');22var page = wptools.page('wikipedia');23page.get(function (err, resp) {24 console.log(resp);25});26var wptools = require('wptools');27var page = wptools.page('wikipedia');28page.getCategories(function (err, resp) {29 console.log(resp);30});31var wptools = require('wptools');32var page = wptools.page('wikipedia');33page.getLinks(function (err, resp) {34 console.log(resp);35});36var wptools = require('wptools');37var page = wptools.page('wikipedia');38page.getImages(function (err, resp) {39 console.log(resp);40});41var wptools = require('wptools');42var page = wptools.page('wikipedia');43page.getTemplates(function (err, resp) {44 console.log(resp);45});

Full Screen

Automation Testing Tutorials

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.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful