gologin 1.0.48 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,7 +103,10 @@ For debugging use `DEBUG=* node example.js` command
103
103
  To use GoLogin with Selenium see `selenium/example.js`
104
104
 
105
105
  ## Full GoLogin API
106
- <a href="https://api.gologin.com/docs" target="_blank">API link here</a>
106
+ **Swagger:** <a href="https://api.gologin.com/docs" target="_blank">link here</a>
107
+
108
+ **Postman:** <a href="https://documenter.getpostman.com/view/21126834/Uz5GnvaL" target="_blank">link here</a>
109
+
107
110
 
108
111
  ## For local profiles
109
112
 
@@ -113,7 +113,10 @@ class BrowserUserDataManager {
113
113
 
114
114
  const fileContent = await readFile(path.resolve(__dirname, 'fonts_config'), 'utf-8');
115
115
  const result = fileContent.replace(/\$\$GOLOGIN_FONTS\$\$/g, path.join(profilePath, FONTS_DIR_NAME));
116
- await writeFile(path.join(profilePath, 'Default', 'fonts_config'), result);
116
+
117
+ const defaultFolderPath = path.join(profilePath, 'Default');
118
+ await mkdir(defaultFolderPath, { recursive: true });
119
+ await writeFile(path.join(defaultFolderPath, 'fonts_config'), result);
117
120
  }
118
121
 
119
122
  static setExtPathsAndRemoveDeleted(settings = {}, profileExtensionsCheckRes = []) {
package/gologin.js CHANGED
@@ -60,16 +60,16 @@ class GoLogin {
60
60
  }
61
61
  }
62
62
 
63
- this.cookiesFilePath = path.join(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Cookies');
63
+ this.cookiesFilePath = path.join(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Network', 'Cookies');
64
64
  this.profile_zip_path = path.join(this.tmpdir, `gologin_${this.profile_id}.zip`);
65
65
  debug('INIT GOLOGIN', this.profile_id);
66
66
  }
67
-
67
+
68
68
  async checkBrowser() { return this.browserChecker.checkBrowser(this.autoUpdateBrowser) }
69
69
 
70
70
  async setProfileId(profile_id) {
71
71
  this.profile_id = profile_id;
72
- this.cookiesFilePath = path.join(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Cookies');
72
+ this.cookiesFilePath = path.join(this.tmpdir, `gologin_profile_${this.profile_id}`, 'Default', 'Network', 'Cookies');
73
73
  this.profile_zip_path = path.join(this.tmpdir, `gologin_${this.profile_id}.zip`);
74
74
  }
75
75
 
@@ -125,15 +125,15 @@ class GoLogin {
125
125
  }
126
126
  })
127
127
  debug("profileResponse", profileResponse.statusCode, profileResponse.body);
128
-
129
-
128
+
129
+
130
130
  if (profileResponse.statusCode === 404) {
131
131
  throw new Error(JSON.parse(profileResponse.body).message);
132
- }
132
+ }
133
133
 
134
134
  if (profileResponse.statusCode === 403) {
135
135
  throw new Error(JSON.parse(profileResponse.body).message);
136
- }
136
+ }
137
137
 
138
138
  if (profileResponse.statusCode !== 200) {
139
139
  throw new Error(`Gologin /browser/${id} response error ${profileResponse.statusCode} INVALID TOKEN OR PROFILE NOT FOUND`);
@@ -141,7 +141,7 @@ class GoLogin {
141
141
 
142
142
  if (profileResponse.statusCode === 401) {
143
143
  throw new Error("invalid token");
144
- }
144
+ }
145
145
 
146
146
 
147
147
  return JSON.parse(profileResponse.body);
@@ -268,7 +268,7 @@ class GoLogin {
268
268
  enable: true,
269
269
  width: parseInt(this.resolution.width, 10),
270
270
  height: parseInt(this.resolution.height, 10),
271
- device_scale_factor: deviceScaleFactor,
271
+ device_scale_factor: deviceScaleFactor,
272
272
  }
273
273
  }
274
274
 
@@ -278,7 +278,7 @@ class GoLogin {
278
278
  audioInputs: preferences.mediaDevices.audioInputs,
279
279
  audioOutputs: preferences.mediaDevices.audioOutputs,
280
280
  }
281
-
281
+
282
282
  return preferences;
283
283
  }
284
284
 
@@ -306,7 +306,7 @@ class GoLogin {
306
306
  });
307
307
 
308
308
  debug('createBrowserExtension done');
309
- }
309
+ }
310
310
 
311
311
  extractProfile(path, zipfile) {
312
312
  debug(`extactProfile ${zipfile}, ${path}`);
@@ -375,7 +375,7 @@ class GoLogin {
375
375
  } catch(e) {
376
376
  console.trace(e);
377
377
  profile_folder = await this.emptyProfileFolder();
378
- await writeFile(this.profile_zip_path, profile_folder);
378
+ await writeFile(this.profile_zip_path, profile_folder);
379
379
  await this.extractProfile(profilePath, this.profile_zip_path);
380
380
  }
381
381
 
@@ -394,12 +394,12 @@ class GoLogin {
394
394
  if (!prefFileExists) {
395
395
  debug('Preferences file not exists waiting', pref_file_name, '. Using empty profile');
396
396
  profile_folder = await this.emptyProfileFolder();
397
- await writeFile(this.profile_zip_path, profile_folder);
397
+ await writeFile(this.profile_zip_path, profile_folder);
398
398
  await this.extractProfile(profilePath, this.profile_zip_path);
399
399
  }
400
400
 
401
401
  const preferences_raw = await readFile(pref_file_name);
402
- let preferences = JSON.parse(preferences_raw.toString());
402
+ let preferences = JSON.parse(preferences_raw.toString());
403
403
  let proxy = _.get(profile, 'proxy');
404
404
  let name = _.get(profile, 'name');
405
405
  const chromeExtensions = _.get(profile, 'chromeExtensions');
@@ -453,7 +453,7 @@ class GoLogin {
453
453
  'username': _.get(profile, 'autoProxyUsername'),
454
454
  'password': _.get(profile, 'autoProxyPassword'),
455
455
  }
456
-
456
+
457
457
  profile.proxy.username = _.get(profile, 'autoProxyUsername');
458
458
  profile.proxy.password = _.get(profile, 'autoProxyPassword');
459
459
  }
@@ -484,13 +484,14 @@ class GoLogin {
484
484
  };
485
485
  profile.geoLocation = this.getGeolocationParams(profileGeolocation, tzGeoLocation);
486
486
  profile.name = name;
487
+ profile.profile_id = this.profile_id;
487
488
 
488
489
  profile.webRtc = {
489
490
  mode: _.get(profile, 'webRTC.mode') === 'alerted' ? 'public' : _.get(profile, 'webRTC.mode'),
490
491
  publicIP: _.get(profile, 'webRTC.fillBasedOnIp') ? this._tz.ip : _.get(profile, 'webRTC.publicIp'),
491
492
  localIps: _.get(profile, 'webRTC.localIps', []),
492
493
  };
493
-
494
+
494
495
  debug('profile.webRtc=', profile.webRtc);
495
496
  debug('profile.timezone=', profile.timezone);
496
497
  debug('profile.mediaDevices=', profile.mediaDevices);
@@ -546,11 +547,11 @@ class GoLogin {
546
547
  }
547
548
 
548
549
  const [languages] = this.language.split(';');
549
-
550
+
550
551
  if(preferences.gologin==null){
551
552
  preferences.gologin = {};
552
553
  }
553
-
554
+
554
555
  preferences.gologin.langHeader = gologin.language;
555
556
  preferences.gologin.languages = languages;
556
557
  // debug("convertedPreferences=", preferences.gologin)
@@ -705,7 +706,7 @@ class GoLogin {
705
706
 
706
707
  async spawnArguments() {
707
708
  const profile_path = this.profilePath();
708
-
709
+
709
710
  let proxy = this.proxy;
710
711
  proxy = `${proxy.mode}://${proxy.host}:${proxy.port}`;
711
712
 
@@ -735,10 +736,10 @@ class GoLogin {
735
736
  let remote_debugging_port = this.remote_debugging_port;
736
737
  if (!remote_debugging_port) {
737
738
  remote_debugging_port = await this.getRandomPort();
738
- }
739
-
739
+ }
740
+
740
741
  const profile_path = this.profilePath();
741
-
742
+
742
743
  let proxy = this.proxy;
743
744
  let proxy_host = '';
744
745
  if (proxy) {
@@ -747,9 +748,9 @@ class GoLogin {
747
748
  }
748
749
 
749
750
  this.port = remote_debugging_port;
750
-
751
+
751
752
  const ORBITA_BROWSER = this.executablePath || this.browserChecker.getOrbitaPath;
752
- console.log("ORBITA_BROWSER=", ORBITA_BROWSER)
753
+ debug(`ORBITA_BROWSER=${ORBITA_BROWSER}`)
753
754
  const env = {};
754
755
  Object.keys(process.env).forEach((key) => {
755
756
  env[key] = process.env[key];
@@ -777,8 +778,8 @@ class GoLogin {
777
778
 
778
779
  let params = [
779
780
  `--remote-debugging-port=${remote_debugging_port}`,
780
- `--user-data-dir=${profile_path}`,
781
- `--password-store=basic`,
781
+ `--user-data-dir=${profile_path}`,
782
+ `--password-store=basic`,
782
783
  `--tz=${tz}`,
783
784
  `--lang=${browserLang}`,
784
785
  ];
@@ -824,13 +825,13 @@ class GoLogin {
824
825
  const child = execFile(ORBITA_BROWSER, params, {env});
825
826
  // const child = spawn(ORBITA_BROWSER, params, { env, shell: true });
826
827
  child.stdout.on('data', (data) => debug(data.toString()));
827
- debug('SPAWN CMD', ORBITA_BROWSER, params.join(" "));
828
+ debug('SPAWN CMD', ORBITA_BROWSER, params.join(" "));
828
829
  }
829
830
 
830
831
  debug('GETTING WS URL FROM BROWSER');
831
832
 
832
833
  let data = await requests.get(`http://127.0.0.1:${remote_debugging_port}/json/version`, {json: true});
833
-
834
+
834
835
  debug('WS IS', _.get(data, 'body.webSocketDebuggerUrl', ''))
835
836
  this.is_active = true;
836
837
 
@@ -873,7 +874,7 @@ class GoLogin {
873
874
 
874
875
  if (!local) {
875
876
  await rimraf(path.join(this.tmpdir, `gologin_${this.profile_id}.zip`));
876
- }
877
+ }
877
878
  debug(`PROFILE ${this.profile_id} STOPPED AND CLEAR`);
878
879
  return false;
879
880
  }
@@ -883,7 +884,7 @@ class GoLogin {
883
884
  if (!this.port) {
884
885
  throw new Error('Empty GoLogin port');
885
886
  }
886
- const ls = await spawn('fuser',
887
+ const ls = await spawn('fuser',
887
888
  [
888
889
  '-k TERM',
889
890
  `-n tcp ${this.port}`
@@ -918,7 +919,7 @@ class GoLogin {
918
919
  await Promise.all(remove_dirs.map(d => {
919
920
  const path_to_remove = `${that.profilePath()}${d}`
920
921
  return new Promise(resolve => {
921
- debug('DROPPING', path_to_remove);
922
+ debug('DROPPING', path_to_remove);
922
923
  rimraf(path_to_remove, { maxBusyTries: 100 }, (e) => {
923
924
  // debug('DROPPING RESULT', e);
924
925
  resolve();
@@ -970,7 +971,7 @@ class GoLogin {
970
971
  return false;
971
972
  }
972
973
  debug('profile is', profileResponse.body);
973
- return true;
974
+ return true;
974
975
  }
975
976
 
976
977
 
@@ -979,16 +980,16 @@ class GoLogin {
979
980
 
980
981
  if (options.os) {
981
982
  os = options.os;
982
- }
983
+ }
983
984
 
984
985
  let fingerprint = await requests.get(`${API_URL}/browser/fingerprint?os=${os}`,{
985
986
  headers: {
986
987
  'Authorization': `Bearer ${this.access_token}`,
987
988
  'User-Agent': 'gologin-api',
988
989
  }
989
- });
990
+ });
990
991
 
991
- return JSON.parse(fingerprint.body);
992
+ return JSON.parse(fingerprint.body);
992
993
  }
993
994
 
994
995
  async create(options) {
@@ -996,7 +997,7 @@ class GoLogin {
996
997
 
997
998
  const fingerprint = await this.getRandomFingerprint(options);
998
999
  debug("fingerprint=", fingerprint)
999
-
1000
+
1000
1001
  if (fingerprint.statusCode === 500) {
1001
1002
  throw new Error("no valid random fingerprint check os param");
1002
1003
  }
@@ -1045,11 +1046,11 @@ class GoLogin {
1045
1046
  });
1046
1047
 
1047
1048
  if (response.body.statusCode === 400) {
1048
- throw new Error(`gologin failed account creation with status code, ${data.statusCode} DATA ${JSON.stringify(response.body.message)}`);
1049
+ throw new Error(`gologin failed account creation with status code, ${response.statusCode} DATA ${JSON.stringify(response.body.message)}`);
1049
1050
  }
1050
1051
 
1051
1052
  if (response.body.statusCode === 500) {
1052
- throw new Error(`gologin failed account creation with status code, ${data.statusCode}`);
1053
+ throw new Error(`gologin failed account creation with status code, ${response.statusCode}`);
1053
1054
  }
1054
1055
  debug(JSON.stringify(response.body));
1055
1056
  return response.body.id;
@@ -1068,7 +1069,7 @@ class GoLogin {
1068
1069
  async update(options) {
1069
1070
  this.profile_id = options.id;
1070
1071
  const profile = await this.getProfile();
1071
-
1072
+
1072
1073
  if (options.navigator) {
1073
1074
  Object.keys(options.navigator).map((e)=>{profile.navigator[e]=options.navigator[e]});
1074
1075
  }
@@ -1081,7 +1082,7 @@ class GoLogin {
1081
1082
  headers: {
1082
1083
  'Authorization': `Bearer ${this.access_token}`
1083
1084
  }
1084
- });
1085
+ });
1085
1086
  debug('response', JSON.stringify(response.body));
1086
1087
  return response.body
1087
1088
  }
@@ -1106,7 +1107,7 @@ class GoLogin {
1106
1107
  accuracy: profileGeolocationParams.accuracy,
1107
1108
  }
1108
1109
  };
1109
-
1110
+
1110
1111
  getViewPort() {
1111
1112
  return { ...this.resolution };
1112
1113
  };
@@ -1186,7 +1187,7 @@ class GoLogin {
1186
1187
  if (!this.executablePath) {
1187
1188
  await this.checkBrowser();
1188
1189
  }
1189
-
1190
+
1190
1191
  const ORBITA_BROWSER = this.executablePath || this.browserChecker.getOrbitaPath;
1191
1192
 
1192
1193
  const orbitaBrowserExists = await access(ORBITA_BROWSER).then(() => true).catch(() => false);
@@ -1258,7 +1259,7 @@ class GoLogin {
1258
1259
  return {'status': 'failure', 'code': profileResponse.statusCode};
1259
1260
  }
1260
1261
  */
1261
-
1262
+
1262
1263
  // if (profileResponse.body === 'ok') {
1263
1264
  const profile = await this.getProfile();
1264
1265
 
@@ -1267,7 +1268,7 @@ class GoLogin {
1267
1268
  'Authorization': `Bearer ${this.access_token}`
1268
1269
  }
1269
1270
  });
1270
-
1271
+
1271
1272
  debug('profileResponse', profileResponse.statusCode, profileResponse.body);
1272
1273
 
1273
1274
  if (profileResponse.statusCode === 401){
@@ -1298,7 +1299,7 @@ class GoLogin {
1298
1299
  let wsUrl = await this.waitDebuggingUrl(delay_ms);
1299
1300
  if(wsUrl!=''){
1300
1301
  return { 'status': 'success', wsUrl }
1301
- }
1302
+ }
1302
1303
 
1303
1304
  return { 'status': 'failure', 'message': profileResponse.body };
1304
1305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gologin",
3
- "version": "1.0.48",
3
+ "version": "1.0.51",
4
4
  "description": "A high-level API to control Orbita browser over GoLogin API",
5
5
  "main": "./gologin.js",
6
6
  "repository": {
@@ -0,0 +1,2 @@
1
+ _id,name,notes,proxy,os,isM1,timezone.enabled,timezone.fillBasedOnIp,timezone.timezone,geolocation.accuracy,geolocation.customize,geolocation.enabled,geolocation.fillBasedOnIp,geolocation.latitude,geolocation.longitude,geolocation.mode,cookies,webGLMetadata.renderer,webGLMetadata.vendor,proxy.autoProxyRegion,proxy.torProxyRegion,audioContext.mode,audioContext.noise,browserType,canvas.mode,canvas.noise,chromeExtensions,clientRects.mode,clientRects.noise,devicePixelRatio,dns,extensions.enabled,extensions.preloadCustom,fonts.enableDomRect,fonts.enableMasking,fonts.families,googleServicesEnabled,lockEnabled,mediaDevices.audioInputs,mediaDevices.audioOutputs,mediaDevices.enableMasking,mediaDevices.uid,mediaDevices.videoInputs,navigator.deviceMemory,navigator.hardwareConcurrency,navigator.language,navigator.maxTouchPoints,navigator.platform,navigator.resolution,navigator.userAgent,plugins.enableFlash,plugins.enableVulnerable,proxyEnabled,startUrl,storage.bookmarks,storage.extensions,storage.history,storage.local,storage.passwords,storage.session,updateUALastChosenBrowserV,userChromeExtensions,webGL.getClientRectsNoise,webGL.mode,webGL.noise,webGLMetadata.mode,webRTC.customize,webRTC.enabled,webRTC.fillBasedOnIp,webRTC.localIpMasking,webRTC.localIps,webRTC.mode,webRTC.publicIp,webglParams.antialiasing,webglParams.extensions,webglParams.glCanvas,webglParams.glParamValues,webglParams.shaiderPrecisionFormat,webglParams.supportedFunctions,webglParams.textureMaxAnisotropyExt
2
+ "62ceac1ebf5c65e7b9737e90",divine-moon,,gologin://us,lin,,true,true,,10,true,true,true,0,0,prompt,"[{""sameSite"":""unspecified"",""url"":""http://accounts.youtube.com/accounts"",""domain"":""accounts.youtube.com"",""name"":""CheckConnectionTempCookie418"",""value"":""583900"",""path"":""/accounts"",""secure"":false,""httpOnly"":false,""hostOnly"":true,""session"":false,""expirationDate"":1657711797},{""sameSite"":""no_restriction"",""url"":""https://google.com/"",""domain"":"".google.com"",""name"":""NID"",""value"":""511=pmrVWL6S6C04qFVhNbPwFk7VuJS3Q4GIbuYcwLeIBx8qxFPkraAGDr89L_9v1OxfCdvukGBBXLZzQ-Zx17qqxmKesRDAwk91GzT2uXWM6n_62DBXD0K5Dt2vBPtnVV15UA-AkE1ujldxEDI5FJjzN6RJ_VLYK3YaJax_Drdhp_I"",""path"":""/"",""secure"":true,""httpOnly"":true,""hostOnly"":false,""session"":false,""expirationDate"":1673522989.3169844},{""sameSite"":""unspecified"",""url"":""https://accounts.google.com/"",""domain"":""accounts.google.com"",""name"":""__Host-GAPS"",""value"":""1:XwbHhqGMbhJNRMbV1-WjwIE3WM3iqA:SGVT-tDrpcVPTnu3"",""path"":""/"",""secure"":true,""httpOnly"":true,""hostOnly"":true,""session"":false,""expirationDate"":1720783788.086744}]",,Google Inc.,us,us,noise,2.992842533846e-8,chrome,off,0.3554128,[],noise,5.40273,1.34375,,true,true,true,true,"[""AIGDT"",""AMGDT"",""Alef"",""Ani"",""AnjaliOldLipi"",""Caladea"",""Chilanka"",""David Libre"",""DejaVu Sans"",""DejaVu Sans Condensed"",""DejaVu Sans Light"",""DejaVu Serif"",""Droid Sans"",""Frank Ruehl"",""Frank Ruehl Libre"",""Frank Ruehl Libre Black"",""Frank Ruehl Libre Light"",""FreeMono"",""FreeSans"",""FreeSerif"",""Gargi"",""Gubbi"",""Jamrul"",""KacstBook"",""KacstLetter"",""KacstNaskh"",""Kalapi"",""Kalimati"",""Karumbi"",""Khmer OS"",""Khmer UI"",""Kinnari"",""Liberation Mono"",""Liberation Sans"",""Liberation Sans Narrow"",""Liberation Serif"",""Lohit Devanagari"",""Loma"",""Meera"",""Meera Inimai"",""Miriam"",""Miriam Fixed"",""Miriam Libre"",""Mitra Mono"",""Mukti Narrow"",""Nakula"",""Navuli"",""Nimbus Roman"",""Nimbus Sans"",""Nimbus Sans Narrow"",""Norasi"",""Noto Sans"",""Noto Sans Arabic UI"",""Noto Sans CJK JP"",""Noto Sans CJK KR"",""Noto Sans CJK SC"",""Noto Sans CJK TC"",""Noto Sans Mono CJK HK"",""Noto Sans Mono CJK KR"",""Noto Sans Mono CJK SC"",""Noto Sans Mono CJK TC"",""Noto Serif"",""Noto Serif CJK JP"",""Noto Serif CJK KR"",""Noto Serif CJK SC"",""Noto Serif Georgian"",""Oswald"",""Padauk"",""Pagul"",""Phetsarath OT"",""Pothana2000"",""Purisa"",""Roboto Light"",""Roboto Medium"",""Roboto Thin"",""Rubik"",""Sahadeva"",""Samyak Devanagari"",""Samyak Gujarati"",""Source Code Pro"",""Source Code Pro Black"",""Source Code Pro Extra Light"",""Source Code Pro Light"",""Source Code Pro Medium"",""Source Code Pro Semibold"",""Source Sans Pro"",""Source Sans Pro Black"",""Source Sans Pro Extra Light"",""Source Sans Pro Semibold"",""Source Serif Pro"",""Source Serif Pro Light"",""Source Serif Pro Semibold"",""Suruma"",""Tibetan Machine Uni"",""Tlwg Mono"",""Tlwg Typist"",""URW Gothic L"",""Uroob"",""Vemana2000""]",false,false,1,1,true,b04187cb002a40aeb4382c7c2d9cc3ccb395aee9613241af81df212fd0,0,8,8,"en-US,en;q=0.9",0,Linux x86_64,1600x900,"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36",true,true,true,https://iphey.com,true,true,true,true,true,true,,[],5.40273,noise,35.999,mask,true,true,true,true,[],alerted,,false,"[""ANGLE_instanced_arrays"",""EXT_blend_minmax"",""EXT_color_buffer_half_float"",""EXT_float_blend"",""EXT_frag_depth"",""EXT_sRGB"",""EXT_shader_texture_lod"",""EXT_texture_compression_rgtc"",""EXT_texture_filter_anisotropic"",""KHR_parallel_shader_compile"",""OES_element_index_uint"",""OES_fbo_render_mipmap"",""OES_standard_derivatives"",""OES_texture_float"",""OES_texture_float_linear"",""OES_texture_half_float"",""OES_texture_half_float_linear"",""OES_vertex_array_object"",""WEBGL_color_buffer_float"",""WEBGL_compressed_texture_astc"",""WEBGL_compressed_texture_s3tc"",""WEBGL_compressed_texture_s3tc_srgb"",""WEBGL_debug_renderer_info"",""WEBGL_debug_shaders"",""WEBGL_depth_texture"",""WEBGL_draw_buffers"",""WEBGL_lose_context"",""WEBGL_multi_draw"",""WEBKIT_EXT_texture_filter_anisotropic"",""WEBKIT_WEBGL_compressed_texture_s3tc"",""WEBKIT_WEBGL_depth_texture"",""WEBKIT_WEBGL_lose_context""]",webgl,"[{""name"":""ALIASED_LINE_WIDTH_RANGE"",""value"":{""0"":1,""1"":7}},{""name"":""ALIASED_POINT_SIZE_RANGE"",""value"":{""0"":1,""1"":255}},{""name"":[""DEPTH_BITS"",""STENCIL_BITS""],""value"":""n/a""},{""name"":""MAX_3D_TEXTURE_SIZE"",""value"":""n/a""},{""name"":""MAX_ARRAY_TEXTURE_LAYERS"",""value"":""n/a""},{""name"":""MAX_COLOR_ATTACHMENTS"",""value"":""n/a""},{""name"":""MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_COMBINED_TEXTURE_IMAGE_UNITS"",""value"":32},{""name"":""MAX_COMBINED_UNIFORM_BLOCKS"",""value"":""n/a""},{""name"":""MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_CUBE_MAP_TEXTURE_SIZE"",""value"":8192},{""name"":""MAX_DRAW_BUFFERS"",""value"":""n/a""},{""name"":""MAX_FRAGMENT_INPUT_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_FRAGMENT_UNIFORM_BLOCKS"",""value"":""n/a""},{""name"":""MAX_FRAGMENT_UNIFORM_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_FRAGMENT_UNIFORM_VECTORS"",""value"":1024},{""name"":""MAX_PROGRAM_TEXEL_OFFSET"",""value"":""n/a""},{""name"":""MAX_RENDERBUFFER_SIZE"",""value"":8192},{""name"":""MAX_SAMPLES"",""value"":""n/a""},{""name"":""MAX_TEXTURE_IMAGE_UNITS"",""value"":16},{""name"":""MAX_TEXTURE_LOD_BIAS"",""value"":""n/a""},{""name"":""MAX_TEXTURE_SIZE"",""value"":8192},{""name"":""MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"",""value"":""n/a""},{""name"":""MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_UNIFORM_BLOCK_SIZE"",""value"":""n/a""},{""name"":""MAX_UNIFORM_BUFFER_BINDINGS"",""value"":""n/a""},{""name"":""MAX_VARYING_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_VARYING_VECTORS"",""value"":16},{""name"":""MAX_VERTEX_ATTRIBS"",""value"":16},{""name"":""MAX_VERTEX_OUTPUT_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_VERTEX_TEXTURE_IMAGE_UNITS"",""value"":16},{""name"":""MAX_VERTEX_UNIFORM_BLOCKS"",""value"":""n/a""},{""name"":""MAX_VERTEX_UNIFORM_COMPONENTS"",""value"":""n/a""},{""name"":""MAX_VERTEX_UNIFORM_VECTORS"",""value"":1024},{""name"":""MAX_VIEWPORT_DIMS"",""value"":{""0"":8192,""1"":8192}},{""name"":""MIN_PROGRAM_TEXEL_OFFSET"",""value"":""n/a""},{""name"":[""RED_BITS"",""GREEN_BITS"",""BLUE_BITS"",""ALPHA_BITS""],""value"":""n/a""},{""name"":""RENDERER"",""value"":""WebKit WebGL""},{""name"":""SHADING_LANGUAGE_VERSION"",""value"":""WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)""},{""name"":""UNIFORM_BUFFER_OFFSET_ALIGNMENT"",""value"":""n/a""},{""name"":""VENDOR"",""value"":""WebKit""},{""name"":""VERSION"",""value"":""WebGL 1.0 (OpenGL ES 2.0 Chromium)""}]",highp/highp,"[{""name"":""beginQuery"",""supported"":false},{""name"":""beginTransformFeedback"",""supported"":false},{""name"":""bindBufferBase"",""supported"":false},{""name"":""bindBufferRange"",""supported"":false},{""name"":""bindSampler"",""supported"":false},{""name"":""bindTransformFeedback"",""supported"":false},{""name"":""bindVertexArray"",""supported"":false},{""name"":""blitFramebuffer"",""supported"":false},{""name"":""clearBufferfi"",""supported"":false},{""name"":""clearBufferfv"",""supported"":false},{""name"":""clearBufferiv"",""supported"":false},{""name"":""clearBufferuiv"",""supported"":false},{""name"":""clientWaitSync"",""supported"":false},{""name"":""compressedTexImage3D"",""supported"":false},{""name"":""compressedTexSubImage3D"",""supported"":false},{""name"":""copyBufferSubData"",""supported"":false},{""name"":""copyTexSubImage3D"",""supported"":false},{""name"":""createQuery"",""supported"":false},{""name"":""createSampler"",""supported"":false},{""name"":""createTransformFeedback"",""supported"":false},{""name"":""createVertexArray"",""supported"":false},{""name"":""deleteQuery"",""supported"":false},{""name"":""deleteSampler"",""supported"":false},{""name"":""deleteSync"",""supported"":false},{""name"":""deleteTransformFeedback"",""supported"":false},{""name"":""deleteVertexArray"",""supported"":false},{""name"":""drawArraysInstanced"",""supported"":false},{""name"":""drawBuffers"",""supported"":false},{""name"":""drawElementsInstanced"",""supported"":false},{""name"":""drawRangeElements"",""supported"":false},{""name"":""endQuery"",""supported"":false},{""name"":""endTransformFeedback"",""supported"":false},{""name"":""fenceSync"",""supported"":false},{""name"":""framebufferTextureLayer"",""supported"":false},{""name"":""getActiveUniformBlockName"",""supported"":false},{""name"":""getActiveUniformBlockParameter"",""supported"":false},{""name"":""getActiveUniforms"",""supported"":false},{""name"":""getBufferSubData"",""supported"":false},{""name"":""getFragDataLocation"",""supported"":false},{""name"":""getIndexedParameter"",""supported"":false},{""name"":""getInternalformatParameter"",""supported"":false},{""name"":""getQuery"",""supported"":false},{""name"":""getQueryParameter"",""supported"":false},{""name"":""getSamplerParameter"",""supported"":false},{""name"":""getSyncParameter"",""supported"":false},{""name"":""getTransformFeedbackVarying"",""supported"":false},{""name"":""getUniformBlockIndex"",""supported"":false},{""name"":""getUniformIndices"",""supported"":false},{""name"":""invalidateFramebuffer"",""supported"":false},{""name"":""invalidateSubFramebuffer"",""supported"":false},{""name"":""isQuery"",""supported"":false},{""name"":""isSampler"",""supported"":false},{""name"":""isSync"",""supported"":false},{""name"":""isTransformFeedback"",""supported"":false},{""name"":""isVertexArray"",""supported"":false},{""name"":""pauseTransformFeedback"",""supported"":false},{""name"":""readBuffer"",""supported"":false},{""name"":""renderbufferStorageMultisample"",""supported"":false},{""name"":""resumeTransformFeedback"",""supported"":false},{""name"":""samplerParameterf"",""supported"":false},{""name"":""samplerParameteri"",""supported"":false},{""name"":""texImage3D"",""supported"":false},{""name"":""texStorage2D"",""supported"":false},{""name"":""texStorage3D"",""supported"":false},{""name"":""texSubImage3D"",""supported"":false},{""name"":""transformFeedbackVaryings"",""supported"":false},{""name"":""uniform1ui"",""supported"":false},{""name"":""uniform1uiv"",""supported"":false},{""name"":""uniform2ui"",""supported"":false},{""name"":""uniform2uiv"",""supported"":false},{""name"":""uniform3ui"",""supported"":false},{""name"":""uniform3uiv"",""supported"":false},{""name"":""uniform4ui"",""supported"":false},{""name"":""uniform4uiv"",""supported"":false},{""name"":""uniformBlockBinding"",""supported"":false},{""name"":""uniformMatrix2x3fv"",""supported"":false},{""name"":""uniformMatrix2x4fv"",""supported"":false},{""name"":""uniformMatrix3x2fv"",""supported"":false},{""name"":""uniformMatrix3x4fv"",""supported"":false},{""name"":""uniformMatrix4x2fv"",""supported"":false},{""name"":""uniformMatrix4x3fv"",""supported"":false},{""name"":""vertexAttribDivisor"",""supported"":false},{""name"":""vertexAttribI4i"",""supported"":false},{""name"":""vertexAttribI4iv"",""supported"":false},{""name"":""vertexAttribI4ui"",""supported"":false},{""name"":""vertexAttribI4uiv"",""supported"":false},{""name"":""vertexAttribIPointer"",""supported"":false},{""name"":""waitSync"",""supported"":false}]",16