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 +4 -1
- package/browser-user-data-manager.js +4 -1
- package/gologin.js +46 -45
- package/package.json +1 -1
- package/profile_export_example.csv +2 -0
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">
|
|
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
|
-
|
|
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
|
-
|
|
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, ${
|
|
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, ${
|
|
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
|
@@ -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
|