How to use lookupCmap method in wpt

Best JavaScript code snippet using wpt

font_renderer.js

Source:font_renderer.js Github

copy

Full Screen

...108 startOffset = endOffset;109 }110 return glyphs;111 }112 function lookupCmap(ranges, unicode) {113 var code = unicode.charCodeAt(0);114 var l = 0, r = ranges.length - 1;115 while (l < r) {116 var c = (l + r + 1) >> 1;117 if (code < ranges[c].start) {118 r = c - 1;119 } else {120 l = c;121 }122 }123 if (ranges[l].start <= code && code <= ranges[l].end) {124 return (ranges[l].idDelta + (ranges[l].ids ?125 ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;126 }127 return 0;128 }129 function compileGlyf(code, js, font) {130 function moveTo(x, y) {131 js.push('c.moveTo(' + x + ',' + y + ');');132 }133 function lineTo(x, y) {134 js.push('c.lineTo(' + x + ',' + y + ');');135 }136 function quadraticCurveTo(xa, ya, x, y) {137 js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +138 x + ',' + y + ');');139 }140 var i = 0;141 var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;142 var flags;143 var x = 0, y = 0;144 i += 10;145 if (numberOfContours < 0) {146 // composite glyph147 do {148 flags = (code[i] << 8) | code[i + 1];149 var glyphIndex = (code[i + 2] << 8) | code[i + 3];150 i += 4;151 var arg1, arg2;152 if ((flags & 0x01)) {153 arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;154 arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;155 i += 4;156 } else {157 arg1 = code[i++]; arg2 = code[i++];158 }159 if ((flags & 0x02)) {160 x = arg1;161 y = arg2;162 } else {163 x = 0; y = 0; // TODO "they are points" ?164 }165 var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;166 if ((flags & 0x08)) {167 scaleX =168 scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;169 i += 2;170 } else if ((flags & 0x40)) {171 scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;172 scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;173 i += 4;174 } else if ((flags & 0x80)) {175 scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;176 scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;177 scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;178 scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;179 i += 8;180 }181 var subglyph = font.glyphs[glyphIndex];182 if (subglyph) {183 js.push('c.save();');184 js.push('c.transform(' + scaleX + ',' + scale01 + ',' +185 scale10 + ',' + scaleY + ',' + x + ',' + y + ');');186 compileGlyf(subglyph, js, font);187 js.push('c.restore();');188 }189 } while ((flags & 0x20));190 } else {191 // simple glyph192 var endPtsOfContours = [];193 var j, jj;194 for (j = 0; j < numberOfContours; j++) {195 endPtsOfContours.push((code[i] << 8) | code[i + 1]);196 i += 2;197 }198 var instructionLength = (code[i] << 8) | code[i + 1];199 i += 2 + instructionLength; // skipping the instructions200 var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;201 var points = [];202 while (points.length < numberOfPoints) {203 flags = code[i++];204 var repeat = 1;205 if ((flags & 0x08)) {206 repeat += code[i++];207 }208 while (repeat-- > 0) {209 points.push({flags: flags});210 }211 }212 for (j = 0; j < numberOfPoints; j++) {213 switch (points[j].flags & 0x12) {214 case 0x00:215 x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;216 i += 2;217 break;218 case 0x02:219 x -= code[i++];220 break;221 case 0x12:222 x += code[i++];223 break;224 }225 points[j].x = x;226 }227 for (j = 0; j < numberOfPoints; j++) {228 switch (points[j].flags & 0x24) {229 case 0x00:230 y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;231 i += 2;232 break;233 case 0x04:234 y -= code[i++];235 break;236 case 0x24:237 y += code[i++];238 break;239 }240 points[j].y = y;241 }242 var startPoint = 0;243 for (i = 0; i < numberOfContours; i++) {244 var endPoint = endPtsOfContours[i];245 // contours might have implicit points, which is located in the middle246 // between two neighboring off-curve points247 var contour = points.slice(startPoint, endPoint + 1);248 if ((contour[0].flags & 1)) {249 contour.push(contour[0]); // using start point at the contour end250 } else if ((contour[contour.length - 1].flags & 1)) {251 // first is off-curve point, trying to use one from the end252 contour.unshift(contour[contour.length - 1]);253 } else {254 // start and end are off-curve points, creating implicit one255 var p = {256 flags: 1,257 x: (contour[0].x + contour[contour.length - 1].x) / 2,258 y: (contour[0].y + contour[contour.length - 1].y) / 2259 };260 contour.unshift(p);261 contour.push(p);262 }263 moveTo(contour[0].x, contour[0].y);264 for (j = 1, jj = contour.length; j < jj; j++) {265 if ((contour[j].flags & 1)) {266 lineTo(contour[j].x, contour[j].y);267 } else if ((contour[j + 1].flags & 1)){268 quadraticCurveTo(contour[j].x, contour[j].y,269 contour[j + 1].x, contour[j + 1].y);270 j++;271 } else {272 quadraticCurveTo(contour[j].x, contour[j].y,273 (contour[j].x + contour[j + 1].x) / 2,274 (contour[j].y + contour[j + 1].y) / 2);275 }276 }277 startPoint = endPoint + 1;278 }279 }280 }281 function compileCharString(code, js, font) {282 var stack = [];283 var x = 0, y = 0;284 var stems = 0;285 function moveTo(x, y) {286 js.push('c.moveTo(' + x + ',' + y + ');');287 }288 function lineTo(x, y) {289 js.push('c.lineTo(' + x + ',' + y + ');');290 }291 function bezierCurveTo(x1, y1, x2, y2, x, y) {292 js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +293 x + ',' + y + ');');294 }295 function parse(code) {296 var i = 0;297 while (i < code.length) {298 var stackClean = false;299 var v = code[i++];300 var xa, xb, ya, yb, y1, y2, y3, n, subrCode;301 switch (v) {302 case 1: // hstem303 stems += stack.length >> 1;304 stackClean = true;305 break;306 case 3: // vstem307 stems += stack.length >> 1;308 stackClean = true;309 break;310 case 4: // vmoveto311 y += stack.pop();312 moveTo(x, y);313 stackClean = true;314 break;315 case 5: // rlineto316 while (stack.length > 0) {317 x += stack.shift();318 y += stack.shift();319 lineTo(x, y);320 }321 break;322 case 6: // hlineto323 while (stack.length > 0) {324 x += stack.shift();325 lineTo(x, y);326 if (stack.length === 0) {327 break;328 }329 y += stack.shift();330 lineTo(x, y);331 }332 break;333 case 7: // vlineto334 while (stack.length > 0) {335 y += stack.shift();336 lineTo(x, y);337 if (stack.length === 0) {338 break;339 }340 x += stack.shift();341 lineTo(x, y);342 }343 break;344 case 8: // rrcurveto345 while (stack.length > 0) {346 xa = x + stack.shift(); ya = y + stack.shift();347 xb = xa + stack.shift(); yb = ya + stack.shift();348 x = xb + stack.shift(); y = yb + stack.shift();349 bezierCurveTo(xa, ya, xb, yb, x, y);350 }351 break;352 case 10: // callsubr353 n = stack.pop() + font.subrsBias;354 subrCode = font.subrs[n];355 if (subrCode) {356 parse(subrCode);357 }358 break;359 case 11: // return360 return;361 case 12:362 v = code[i++];363 switch (v) {364 case 34: // flex365 xa = x + stack.shift();366 xb = xa + stack.shift(); y1 = y + stack.shift();367 x = xb + stack.shift();368 bezierCurveTo(xa, y, xb, y1, x, y1);369 xa = x + stack.shift();370 xb = xa + stack.shift();371 x = xb + stack.shift();372 bezierCurveTo(xa, y1, xb, y, x, y);373 break;374 case 35: // flex375 xa = x + stack.shift(); ya = y + stack.shift();376 xb = xa + stack.shift(); yb = ya + stack.shift();377 x = xb + stack.shift(); y = yb + stack.shift();378 bezierCurveTo(xa, ya, xb, yb, x, y);379 xa = x + stack.shift(); ya = y + stack.shift();380 xb = xa + stack.shift(); yb = ya + stack.shift();381 x = xb + stack.shift(); y = yb + stack.shift();382 bezierCurveTo(xa, ya, xb, yb, x, y);383 stack.pop(); // fd384 break;385 case 36: // hflex1386 xa = x + stack.shift(); y1 = y + stack.shift();387 xb = xa + stack.shift(); y2 = y1 + stack.shift();388 x = xb + stack.shift();389 bezierCurveTo(xa, y1, xb, y2, x, y2);390 xa = x + stack.shift();391 xb = xa + stack.shift(); y3 = y2 + stack.shift();392 x = xb + stack.shift();393 bezierCurveTo(xa, y2, xb, y3, x, y);394 break;395 case 37: // flex1396 var x0 = x, y0 = y;397 xa = x + stack.shift(); ya = y + stack.shift();398 xb = xa + stack.shift(); yb = ya + stack.shift();399 x = xb + stack.shift(); y = yb + stack.shift();400 bezierCurveTo(xa, ya, xb, yb, x, y);401 xa = x + stack.shift(); ya = y + stack.shift();402 xb = xa + stack.shift(); yb = ya + stack.shift();403 x = xb; y = yb;404 if (Math.abs(x - x0) > Math.abs(y - y0)) {405 x += stack.shift();406 } else {407 y += stack.shift();408 }409 bezierCurveTo(xa, ya, xb, yb, x, y);410 break;411 default:412 error('unknown operator: 12 ' + v);413 }414 break;415 case 14: // endchar416 if (stack.length >= 4) {417 var achar = stack.pop();418 var bchar = stack.pop();419 y = stack.pop();420 x = stack.pop();421 js.push('c.save();');422 js.push('c.translate('+ x + ',' + y + ');');423 var gid = lookupCmap(font.cmap, String.fromCharCode(424 font.glyphNameMap[Encodings.StandardEncoding[achar]]));425 compileCharString(font.glyphs[gid], js, font);426 js.push('c.restore();');427 gid = lookupCmap(font.cmap, String.fromCharCode(428 font.glyphNameMap[Encodings.StandardEncoding[bchar]]));429 compileCharString(font.glyphs[gid], js, font);430 }431 return;432 case 18: // hstemhm433 stems += stack.length >> 1;434 stackClean = true;435 break;436 case 19: // hintmask437 stems += stack.length >> 1;438 i += (stems + 7) >> 3;439 stackClean = true;440 break;441 case 20: // cntrmask442 stems += stack.length >> 1;443 i += (stems + 7) >> 3;444 stackClean = true;445 break;446 case 21: // rmoveto447 y += stack.pop();448 x += stack.pop();449 moveTo(x, y);450 stackClean = true;451 break;452 case 22: // hmoveto453 x += stack.pop();454 moveTo(x, y);455 stackClean = true;456 break;457 case 23: // vstemhm458 stems += stack.length >> 1;459 stackClean = true;460 break;461 case 24: // rcurveline462 while (stack.length > 2) {463 xa = x + stack.shift(); ya = y + stack.shift();464 xb = xa + stack.shift(); yb = ya + stack.shift();465 x = xb + stack.shift(); y = yb + stack.shift();466 bezierCurveTo(xa, ya, xb, yb, x, y);467 }468 x += stack.shift();469 y += stack.shift();470 lineTo(x, y);471 break;472 case 25: // rlinecurve473 while (stack.length > 6) {474 x += stack.shift();475 y += stack.shift();476 lineTo(x, y);477 }478 xa = x + stack.shift(); ya = y + stack.shift();479 xb = xa + stack.shift(); yb = ya + stack.shift();480 x = xb + stack.shift(); y = yb + stack.shift();481 bezierCurveTo(xa, ya, xb, yb, x, y);482 break;483 case 26: // vvcurveto484 if (stack.length % 2) {485 x += stack.shift();486 }487 while (stack.length > 0) {488 xa = x; ya = y + stack.shift();489 xb = xa + stack.shift(); yb = ya + stack.shift();490 x = xb; y = yb + stack.shift();491 bezierCurveTo(xa, ya, xb, yb, x, y);492 }493 break;494 case 27: // hhcurveto495 if (stack.length % 2) {496 y += stack.shift();497 }498 while (stack.length > 0) {499 xa = x + stack.shift(); ya = y;500 xb = xa + stack.shift(); yb = ya + stack.shift();501 x = xb + stack.shift(); y = yb;502 bezierCurveTo(xa, ya, xb, yb, x, y);503 }504 break;505 case 28:506 stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);507 i += 2;508 break;509 case 29: // callgsubr510 n = stack.pop() + font.gsubrsBias;511 subrCode = font.gsubrs[n];512 if (subrCode) {513 parse(subrCode);514 }515 break;516 case 30: // vhcurveto517 while (stack.length > 0) {518 xa = x; ya = y + stack.shift();519 xb = xa + stack.shift(); yb = ya + stack.shift();520 x = xb + stack.shift();521 y = yb + (stack.length === 1 ? stack.shift() : 0);522 bezierCurveTo(xa, ya, xb, yb, x, y);523 if (stack.length === 0) {524 break;525 }526 xa = x + stack.shift(); ya = y;527 xb = xa + stack.shift(); yb = ya + stack.shift();528 y = yb + stack.shift();529 x = xb + (stack.length === 1 ? stack.shift() : 0);530 bezierCurveTo(xa, ya, xb, yb, x, y);531 }532 break;533 case 31: // hvcurveto534 while (stack.length > 0) {535 xa = x + stack.shift(); ya = y;536 xb = xa + stack.shift(); yb = ya + stack.shift();537 y = yb + stack.shift();538 x = xb + (stack.length === 1 ? stack.shift() : 0);539 bezierCurveTo(xa, ya, xb, yb, x, y);540 if (stack.length === 0) {541 break;542 }543 xa = x; ya = y + stack.shift();544 xb = xa + stack.shift(); yb = ya + stack.shift();545 x = xb + stack.shift();546 y = yb + (stack.length === 1 ? stack.shift() : 0);547 bezierCurveTo(xa, ya, xb, yb, x, y);548 }549 break;550 default:551 if (v < 32) {552 error('unknown operator: ' + v);553 }554 if (v < 247) {555 stack.push(v - 139);556 } else if (v < 251) {557 stack.push((v - 247) * 256 + code[i++] + 108);558 } else if (v < 255) {559 stack.push(-(v - 251) * 256 - code[i++] - 108);560 } else {561 stack.push(((code[i] << 24) | (code[i + 1] << 16) |562 (code[i + 2] << 8) | code[i + 3]) / 65536);563 i += 4;564 }565 break;566 }567 if (stackClean) {568 stack.length = 0;569 }570 }571 }572 parse(code);573 }574 var noop = '';575 function CompiledFont(fontMatrix) {576 this.compiledGlyphs = {};577 this.fontMatrix = fontMatrix;578 }579 CompiledFont.prototype = {580 getPathJs: function (unicode) {581 var gid = lookupCmap(this.cmap, unicode);582 var fn = this.compiledGlyphs[gid];583 if (!fn) {584 this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);585 }586 return fn;587 },588 compileGlyph: function (code) {589 if (!code || code.length === 0 || code[0] === 14) {590 return noop;591 }592 var js = [];593 js.push('c.save();');594 js.push('c.transform(' + this.fontMatrix.join(',') + ');');595 js.push('c.scale(size, -size);');596 this.compileGlyphImpl(code, js);597 js.push('c.restore();');598 return js.join('\n');599 },600 compileGlyphImpl: function () {601 error('Children classes should implement this.');602 },603 hasBuiltPath: function (unicode) {604 var gid = lookupCmap(this.cmap, unicode);605 return gid in this.compiledGlyphs;606 }607 };608 function TrueTypeCompiled(glyphs, cmap, fontMatrix) {609 fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];610 CompiledFont.call(this, fontMatrix);611 this.glyphs = glyphs;612 this.cmap = cmap;613 this.compiledGlyphs = [];614 }615 Util.inherit(TrueTypeCompiled, CompiledFont, {616 compileGlyphImpl: function (code, js) {617 compileGlyf(code, js, this);618 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var options = {3};4wptools.page('Barack_Obama', options).then(function(page) {5 return page.lookupCmap();6}).then(function(cmap) {7 console.log(cmap);8});9{ 'Barack Obama': 'Q76' }

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var wiki = wptools.page('Barack Obama');3wiki.lookupCmap(function(err, data) {4 console.log(data);5});6var wptools = require('wptools');7var wiki = wptools.page('Barack Obama');8wiki.lookupCmap(function(err, data) {9 console.log(data);10});11var wptools = require('wptools');12var wiki = wptools.page('Barack Obama');13wiki.lookupCmap(function(err, data) {14 console.log(data);15});16var wptools = require('wptools');17var wiki = wptools.page('Barack Obama');18wiki.lookupCmap(function(err, data) {19 console.log(data);20});21var wptools = require('wptools');22var wiki = wptools.page('Barack Obama');23wiki.lookupCmap(function(err, data) {24 console.log(data);25});26var wptools = require('wptools');27var wiki = wptools.page('Barack Obama');28wiki.lookupCmap(function(err, data) {29 console.log(data);30});31var wptools = require('wptools');32var wiki = wptools.page('Barack Obama');33wiki.lookupCmap(function(err, data) {34 console.log(data);35});36var wptools = require('wptools');37var wiki = wptools.page('Barack Obama');38wiki.lookupCmap(function(err, data) {39 console.log(data);40});41var wptools = require('wptools');42var wiki = wptools.page('Barack Obama');43wiki.lookupCmap(function(err, data) {44 console.log(data);45});46var wptools = require('wptools');47var wiki = wptools.page('Barack Obama');48wiki.lookupCmap(function(err

Full Screen

Using AI Code Generation

copy

Full Screen

1const wptools = require('wptools');2const lookupCmap = wptools.lookupCmap;3lookupCmap('en', 'India', function (err, res) {4 if (err) {5 console.log(err);6 } else {7 console.log(res);8 }9});10const wptools = require('wptools');11const lookupCmap = wptools.lookupCmap;12lookupCmap('en', 'India', function (err, res) {13 if (err) {14 console.log(err);15 } else {16 console.log(res);17 }18});19const wptools = require('wptools');20const lookupCmap = wptools.lookupCmap;21lookupCmap('en', 'India', function (err, res) {22 if (err) {23 console.log(err);24 } else {25 console.log(res);26 }27});28const wptools = require('wptools');29const lookupCmap = wptools.lookupCmap;30lookupCmap('en', 'India', function (err, res) {31 if (err) {32 console.log(err);33 } else {34 console.log(res);35 }36});37const wptools = require('wptools');38const lookupCmap = wptools.lookupCmap;39lookupCmap('en', 'India', function (err, res) {40 if (err) {41 console.log(err);42 } else {43 console.log(res);44 }45});46const wptools = require('wptools');47const lookupCmap = wptools.lookupCmap;48lookupCmap('en', 'India', function (err, res) {49 if (err) {50 console.log(err);51 } else {52 console.log(res);53 }54});

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wikimedia-page-library').wptools;2wptools.lookupCmap('en.wikipedia.org', 'Paris', 'fr.wikipedia.org').then(function(cmap) {3 console.log(cmap);4});5var wptools = require('wikimedia-page-library').wptools;6wptools.lookupCmap('en.wikipedia.org', 'Paris', 'fr.wikipedia.org').then(function(cmap) {7 console.log(cmap);8});

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var wiki = new wptools('Wikipedia:WikiProject Military history/Color key');3wiki.lookupCmap(function(err, data) {4 console.log(data);5});6{ 'Wikipedia:WikiProject Military history/Color key': { color: '#ff0000',7 type: 'cmap' },8 'Wikipedia:WikiProject Military history/Color key/1': { color: '#ff0000',9 type: 'cmap' } }

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var wp = new wptools();3wp.lookupCmap('en', 'Cmap', 'test', function(err, data){4 if (err) {5 console.log(err);6 } else {7 console.log(data);8 }9});10var wptools = require('wptools');11var wp = new wptools();12wp.lookupCmap('en', 'Cmap', 'test', function(err, data){13 if (err) {14 console.log(err);15 } else {16 console.log(data);17 }18});19var wptools = require('wptools');20var wp = new wptools();21wp.lookupCmap('en', 'Cmap', 'test', function(err, data){22 if (err) {23 console.log(err);24 } else {25 console.log(data);26 }27});28var wptools = require('wptools');29var wp = new wptools();30wp.lookupCmap('en', 'Cmap', 'test', function(err, data){31 if (err) {32 console.log(err);33 } else {34 console.log(data);35 }36});37var wptools = require('wptools');38var wp = new wptools();39wp.lookupCmap('en', 'Cmap', 'test', function(err, data){40 if (err) {41 console.log(err);42 } else {43 console.log(data);44 }45});46var wptools = require('wptools');47var wp = new wptools();48wp.lookupCmap('en', 'Cmap', 'test', function(err, data){49 if (err) {50 console.log(err);51 } else {52 console.log(data);53 }54});55var wptools = require('wptools');

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