├── README.md
└── PX-baiduyunpan.user.js
/README.md:
--------------------------------------------------------------------------------
1 | # PX-百度云盘
2 | 无责任的兴趣之作, 基于"EX-百度云盘"项目, 实现了配合Proxyee-down下载的功能。:star2:
3 | ## 功能
4 | - 添加了推送任务至Proxyee-down下载器的功能(通过POST实现, 需要授予跨域权限)
5 | - 其余功能请查看[原项目地址](https://github.com/gxvv/ex-baiduyunpan/)
6 |
--------------------------------------------------------------------------------
/PX-baiduyunpan.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name PX-百度云盘
3 | // @namespace https://github.com/lihaoyun6/px-baiduyunpan
4 | // @version 0.10.7
5 | // @description 百度网盘文件直链提取, 支持一键发送至proxyee-down进行下载
6 | // @author lihaoyun6
7 | // @license MIT
8 | // @supportURL https://github.com/lihaoyun6/px-baiduyunpan/issues
9 | // @date 01/01/2018
10 | // @modified 05/06/2018
11 | // @match *://pan.baidu.com/disk/home*
12 | // @match *://yun.baidu.com/disk/home*
13 | // @match *://pan.baidu.com/s/*
14 | // @match *://yun.baidu.com/s/*
15 | // @match *://pan.baidu.com/share/link?*
16 | // @match *://yun.baidu.com/share/link?*
17 | // @match *://eyun.baidu.com/s/*
18 | // @match *://eyun.baidu.com/enterprise/*
19 | // @run-at document-end
20 | // @grant unsafeWindow
21 | // @grant GM_addStyle
22 | // @grant GM_info
23 | // @grant GM_xmlhttpRequest
24 | // @require https://cdn.bootcss.com/jquery/1.7.1/jquery.min.js
25 | // @require https://cdn.bootcss.com/clipboard.js/1.5.16/clipboard.min.js
26 | // @icon https://www.baidu.com/favicon.ico
27 | // ==/UserScript==
28 |
29 | (function(require, define, Promise) {
30 | 'use strict';
31 | unsafeWindow.api = function(data, callback) {
32 | if (data === undefined) data = new Object;
33 | var proxyeeaddr = window.localStorage ? localStorage.getItem("proxyeeaddr") : Cookie.read("proxyeeaddr");
34 | if (!proxyeeaddr) {
35 | var proxyeeaddr = "127.0.0.1";
36 | if (window.localStorage) {
37 | localStorage.setItem("proxyeeaddr", proxyeeaddr);
38 | } else {
39 | Cookie.write("proxyeeaddr", proxyeeaddr);
40 | }
41 | }
42 | var proxyeeport = window.localStorage ? localStorage.getItem("proxyeeport") : Cookie.read("proxyeeport");
43 | if (!proxyeeport) {
44 | var proxyeeport = "26339";
45 | if (window.localStorage) {
46 | localStorage.setItem("proxyeeport", proxyeeport);
47 | } else {
48 | Cookie.write("proxyeeport", proxyeeport);
49 | }
50 | }
51 | GM_xmlhttpRequest({
52 | url: 'http://' + proxyeeaddr + ':' + proxyeeport + '/open/createTask',
53 | headers: {'Content-type': 'application/json;charset=UTF-8'},
54 | method: 'POST',
55 | data: JSON.stringify(data),
56 | dataType: 'json',
57 | //onload: function(response) {
58 | //console.log(response);
59 | //},
60 | success: function(ret) {
61 | callback(ret);
62 | },
63 | error: function(ret) {
64 | console.error(ret);
65 | alert("内部错误");
66 | },
67 | timeout: function(ret) {
68 | console.error("request timeout");
69 | alert("请求超时");
70 | }
71 | });
72 | };
73 | unsafeWindow.proxyeedown = function(urls, filename, path, thsize) {
74 | //alert(urls);
75 | urls = urls.split('|');
76 | filename = filename.split('|');
77 | //var thsize = thread;
78 | for (var i in urls) {
79 | var url = urls[i];
80 | var output = filename[i];
81 | var parts = url.split('\t');
82 | console.log(parts);
83 | if (parts.length > 1) {
84 | url = parts[0];
85 | output = parts[1];
86 | }
87 | var options = {
88 | request: {
89 | url: url
90 | },
91 | filePath: path,
92 | fileName: output,
93 | connections: thsize
94 | };
95 | //console.log(options);
96 | api(options,
97 | function() {
98 | setTimeout(refresh, 1000);
99 | });
100 | }
101 | };
102 | function showError(msg) {
103 | GM_addStyle('#errorDialog{position: fixed;top: 76.5px; bottom: auto; left: 423px; right: auto;background: #fff;border: 1px solid #ced1d9;border-radius: 4px;box-shadow: 0 0 3px #ced1d9;color: black;word-break: break-all;display: block;width: 520px;padding: 10px 20px;z-index: 9999;}#errorDialog h3{border-bottom: 1px solid #ced1d9;font-size: 1.5em;font-weight: bold;}');
104 | var $;
105 | try {
106 | $ = require('base:widget/libs/jquerypacket.js');
107 | } catch (e) {
108 | var div = document.createElement('div');
109 | $ = function(str) {
110 | div.innerHTML = str;
111 | div.onclick = function() { this.remove(); };
112 | return $;
113 | };
114 | $.on = function() {
115 | return { appendTo: function() { document.body.appendChild(div); } };
116 | };
117 | }
118 | var $dialog = $('
' +
119 | '
PX-baiduyunpan:程序异常
' +
120 | '
请尝试更新脚本或复制以下信息提交issue
' +
121 | '
Exception: ' + msg + '
' +
122 | '
Script Ver: ' + GM_info.script.version + '
' +
123 | '
TemperMonkey Ver: ' + GM_info.version + '
' +
124 | '
UA: ' + navigator.userAgent + '
' +
125 | '
关闭 ');
126 | $dialog.on('click', '.close', function(event) {
127 | $dialog.remove();
128 | }).appendTo(document.body);
129 | }
130 | define('px-yunpan:pageInfo', function(require) {
131 | var url = location.href;
132 | var currentPage = 'pan';
133 | var matchs = {
134 | '.*://pan.baidu.com/disk/home.*': 'pan',
135 | '.*://yun.baidu.com/disk/home.*': 'pan',
136 | '.*://pan.baidu.com/s/.*': 'share',
137 | '.*://yun.baidu.com/s/.*': 'share',
138 | '.*://pan.baidu.com/share/link?.*': 'share',
139 | '.*://yun.baidu.com/share/link?.*': 'share',
140 | '.*://eyun.baidu.com/s/.*': 'enterprise',
141 | '.*://eyun.baidu.com/enterprise/.*': 'enterprise'
142 | };
143 | var PAGE_CONFIG = {
144 | pan: {
145 | prefix: 'function-widget-1:',
146 | containers: ['.g-button:has(.icon-download):visible'],
147 | style: function() {
148 | }
149 | },
150 | share: {
151 | prefix: 'function-widget-1:',
152 | containers: [
153 | '.KKtwaH .x-button-box>.g-button:has(.icon-download)',
154 | '.module-share-top-bar .x-button-box>.g-button:has(.icon-download)'
155 | ],
156 | style: function() {
157 | var styleList = [
158 | '.KPDwCE .QxJxtg{z-index: 2;}',
159 | '.module-share-header .slide-show-right{width: auto;}',
160 | '.px-yunpan-dropdown-button.g-dropdown-button.button-open .menu{z-index:41;}',
161 | '.module-share-header .slide-show-header h2{width:230px;}',
162 | '.KPDwCE .xGLMIab .g-dropdown-button.px-yunpan-dropdown-button{margin: 0 5px;}'
163 | ];
164 | GM_addStyle(styleList.join(''));
165 | }
166 | },
167 | enterprise: {
168 | prefix: 'business-function:',
169 | containers: ['.button-box-container>.g-button:has(:contains("下载"))'],
170 | style: function() {
171 | var styleList = [
172 | '.px-yunpan-dropdown-button .icon-download{background-image: url(/box-static/business-function/infos/icons_z.png?t=1476004014313);}',
173 | '.px-yunpan-dropdown-button .g-button:hover .icon-download{background-position: 0px -34px;}'
174 | ];
175 | GM_addStyle(styleList.join(''));
176 | }
177 | }
178 | };
179 | for (var match in matchs) {
180 | if (new RegExp(match).test(url) === true) {
181 | currentPage = matchs[match];
182 | }
183 | }
184 | return PAGE_CONFIG[currentPage];
185 | });
186 |
187 | define('px-yunpan:downloadBtnInit', function(require) {
188 | var ctx = require('system-core:context/context.js').instanceForSystem;
189 | var $ = require('base:widget/libs/jquerypacket.js');
190 | var pageInfo = require('px-yunpan:pageInfo');
191 | var prefix = pageInfo.prefix;
192 | var dServ = null;
193 | require.async(prefix + 'download/service/dlinkService.js', function(dlinkService) {
194 | dServ = dlinkService;
195 | });
196 |
197 | var menu = [{
198 | title: '下载设置',
199 | 'click': function() {
200 | var clipboard = new Clipboard('.btn');
201 | clipboard.on('success',
202 | function(e) {
203 | dialog.hide();
204 | });
205 | clipboard.on('error',
206 | function(e) {
207 | dialog.hide();
208 | });
209 | var proxyeeaddr = window.localStorage ? localStorage.getItem("proxyeeaddr") : Cookie.read("proxyeeaddr");
210 | //alert(proxyeeaddr);
211 | if (!proxyeeaddr) {
212 | proxyeeaddr = "127.0.0.1";
213 | }
214 | //alert(proxyeeaddr);
215 | var proxyeeport = window.localStorage ? localStorage.getItem("proxyeeport") : Cookie.read("proxyeeport");
216 | if (!proxyeeport) {
217 | proxyeeport = "26339";
218 | }
219 | var proxyeethread = window.localStorage ? localStorage.getItem("proxyeethread") : Cookie.read("proxyeethread");
220 | if (!proxyeethread) {
221 | proxyeethread = "32";
222 | }
223 | var proxyeepath = window.localStorage ? localStorage.getItem("proxyeepath") : Cookie.read("proxyeepath");
224 | if (!proxyeepath) {
225 | proxyeepath = "请输入下载路径";
226 | }
227 | var text = '
';
228 | var dialog = ctx.ui.confirm({
229 | title: '下载设置',
230 | body: text,
231 | sureText: '保存设置',
232 | onClose: function() {
233 | //clipboard && clipboard.destory && clipboard.destroy();
234 | }
235 | });
236 | //alert(urls);
237 | dialog.buttonIns[0].dom.attr({
238 | 'href': 'javascript:var proxyeeaddr = document.getElementById("proxyeeaddr").value;var proxyeeport = document.getElementById("proxyeeport").value;var proxyeethread = document.getElementById("proxyeethread").value;var proxyeepath = document.getElementById("proxyeepath").value;if (window.localStorage) {localStorage.setItem("proxyeeaddr", proxyeeaddr);localStorage.setItem("proxyeeport", proxyeeport);localStorage.setItem("proxyeethread", proxyeethread);localStorage.setItem("proxyeepath", proxyeepath);} else {Cookie.write("proxyeeaddr", proxyeeaddr);Cookie.write("proxyeeport", proxyeeport);Cookie.write("proxyeethread", proxyeethread);Cookie.write("proxyeepath", proxyeepath);};',
239 | 'data-clipboard-action': 'copy',
240 | 'data-clipboard-target': '#proxyeeaddr'
241 | }).addClass('btn').off();
242 | },
243 | availableProduct: ['pan', 'share', 'enterprise']
244 | }, {
245 | title: 'PX-下载',
246 | 'click': function() {
247 | var fetchDownLinks = require('px-yunpan:fetchDownLinks.js');
248 | fetchDownLinks.start(ctx, dServ);
249 | },
250 | availableProduct: ['pan', 'share', 'enterprise']
251 | }, {
252 | title: 'PX-压缩下载',
253 | 'click': function() {
254 | var fetchDownLinks = require('px-yunpan:fetchDownLinks.js');
255 | fetchDownLinks.start(ctx, dServ, true);
256 | },
257 | availableProduct: ['pan', 'share', 'enterprise']
258 | }
259 | //, {
260 | // title: '',
261 | // availableProduct: ['pan', 'share', 'enterprise']
262 | //}
263 | ];
264 |
265 | var exDlBtnConfig = {
266 | type: 'dropdown',
267 | title: 'PX-下载',
268 | resize: true,
269 | menu: menu.filter(function (btn) {
270 | var currentProduct = ctx.pageInfo.currentProduct;
271 | return ~btn.availableProduct.indexOf(currentProduct);
272 | }),
273 | icon: 'icon-download'
274 | };
275 | var selector = pageInfo.containers.join();
276 | $(selector).each(function(i, e) {
277 | var exDlBtn = ctx.ui.button(exDlBtnConfig);
278 | $(e).after(exDlBtn.dom.addClass('px-yunpan-dropdown-button'));
279 | exDlBtn.resizeButtonWidth();
280 | });
281 | pageInfo.style();
282 | });
283 |
284 | define('px-yunpan:fetchDownLinks.js', function (require, exports, module) {
285 | var $ = require('base:widget/libs/jquerypacket.js');
286 |
287 | function start(ctx, dServ, allZip) {
288 | var selectedList = ctx.list.getSelected();
289 | if (selectedList.length === 0) return ctx.ui.tip({ mode: 'caution', msg: '您还没有选择下载的文件' });
290 | ctx.ui.tip({ mode: 'loading', msg: '开始请求链接...' });
291 |
292 | var foldersList = selectedList.filter(function(e) {
293 | return e.isdir === 1;
294 | });
295 | var filesList = selectedList.filter(function(e) {
296 | return e.isdir === 0;
297 | });
298 |
299 | var currentProduct = ctx.pageInfo.currentProduct;
300 |
301 | if (!~['pan', 'share', 'enterprise'].indexOf(currentProduct)) {
302 | return ctx.ui.tip({ mode: 'caution', msg: '提取链接在当前页面不可用', hasClose: true, autoClose: false });
303 | }
304 |
305 | if (filesList.length > 0 && currentProduct !== 'enterprise' && !allZip) {
306 | foldersList.unshift(filesList);
307 | } else {
308 | [].push.apply(foldersList, filesList);
309 | }
310 |
311 | var requestMethod;
312 | if (currentProduct === 'pan') {
313 | requestMethod = function(e, cb) {
314 | dServ.getDlinkPan(dServ.getFsidListData(e), allZip ? 'batch' : e.isdir === 1 ? 'batch' : 'nolimit', cb, undefined, undefined, 'POST');
315 | };
316 | } else if (currentProduct === 'share') {
317 | var yunData = require('disk-share:widget/data/yunData.js').get();
318 | requestMethod = function(e, cb) {
319 | dServ.getDlinkShare({
320 | share_id: yunData.shareid,
321 | share_uk: yunData.uk,
322 | sign: yunData.sign,
323 | timestamp: yunData.timestamp,
324 | list: e,
325 | type: allZip ? 'batch' : e.isdir === 1 ? 'batch' : 'nolimit'
326 | }, cb);
327 | };
328 | } else {
329 | var yunData = require('page-common:widget/data/yunData.js').get();
330 | requestMethod = function(e, cb) {
331 | dServ.getDlinkShare({
332 | share_id: yunData.shareid,
333 | share_uk: yunData.uk,
334 | sign: yunData.sign,
335 | timestamp: yunData.timestamp,
336 | list: [e],
337 | isForBatch: allZip
338 | }, cb);
339 | };
340 | }
341 | var timeout = foldersList.length === 1 ? 3e4 : 3e3;
342 | var promises = foldersList.map(function(e) {
343 | return new Promise(function(resolve, reject) {
344 | var timer = setTimeout(function() {
345 | resolve($.extend({}, e));
346 | }, timeout);
347 | requestMethod(e, function(result) {
348 | resolve($.extend({}, e, result));
349 | });
350 | });
351 | });
352 | Promise.all(promises).then(function(result) {
353 | ctx.ui.hideTip();
354 | var dlinks = [];
355 | var needToRetry = result.filter(function(e) {
356 | return e.errno !== 0;
357 | });
358 | if (needToRetry.length > 0) {
359 | try {
360 | dServ.dialog.hide();
361 | } catch (ex) {}
362 | ctx.ui.tip({
363 | mode: 'caution',
364 | msg: needToRetry.length + '个文件请求链接失败'
365 | });
366 | }
367 | result.filter(function(e) {
368 | return e.errno === 0;
369 | }).forEach(function(e) {
370 | if (typeof e.dlink === 'string') {
371 | var dlink = e.dlink + "&zipname=" + encodeURIComponent((e.isdir ? '【文件夹】' : '【文件】') + e.server_filename + '.zip');
372 | dlinks.push(e.dlink && dlink);
373 | } else {
374 | [].push.apply(dlinks, (e.dlink || e.list || []).map(function(e) {
375 | return e.dlink;
376 | }));
377 | }
378 | });
379 | if (dlinks.length === 0) return ctx.ui.tip({ mode: 'caution', msg: '失败:未获取到链接' });
380 | var clipboard = new Clipboard('.btn');
381 | clipboard.on('success', function(e) {
382 | ctx.ui.tip({ mode: 'success', msg: '成功' + dlinks.length + '个文件' });
383 | e.clearSelection();
384 | dialog.hide();
385 | clipboard.destroy();
386 | });
387 | clipboard.on('error', function(e) {
388 | ctx.ui.tip({ mode: 'caution', msg: '失败' });
389 | });
390 | var urlnow = location.href;
391 | if(urlnow.indexOf('pan.baidu.com/disk/home') > 0 ){
392 | alert('由于百度云文件解析策略调整\n请使用"分享"功能将需要下载的文件进行分享\n再前往分享链接界面导出下载');
393 | return false;
394 | } else if(urlnow.indexOf('yun.baidu.com/disk/home') > 0 ) {
395 | alert('由于百度云文件解析策略调整\n请使用"分享"功能将需要下载的文件进行分享\n再前往分享链接界面导出下载');
396 | return false;
397 | } else if(urlnow.indexOf('eyun.baidu.com/enterprise') > 0 ) {
398 | alert('由于百度云文件解析策略调整\n请使用"分享"功能将需要下载的文件进行分享\n再前往分享链接界面导出下载');
399 | return false;
400 | }
401 | var proxyeethread = window.localStorage ? localStorage.getItem("proxyeethread") : Cookie.read("proxyeethread");
402 | if (!proxyeethread) {
403 | var proxyeethread = "32";
404 | if (window.localStorage) {
405 | localStorage.setItem("proxyeethread", proxyeethread);
406 | } else {
407 | Cookie.write("proxyeethread", proxyeethread);
408 | }
409 | }
410 | var proxyeepath = window.localStorage ? localStorage.getItem("proxyeepath") : Cookie.read("proxyeepath");
411 | if (!proxyeepath) {
412 | var proxyeepath = "请输入下载路径";
413 | if (window.localStorage) {
414 | localStorage.setItem("proxyeepath", proxyeepath);
415 | } else {
416 | Cookie.write("proxyeepath", proxyeepath);
417 | }
418 | }
419 | var showurls = dlinks.join('\n');
420 | //var showurls = showurlss.replace(/d.pcs.baidu.com/g, 'pcs.baidu.com');
421 | var text = '
';
422 | var filenames;
423 | var foldersList = selectedList.filter(function(e) {
424 | return e.isdir === 1;
425 | });
426 | var filesList = selectedList.filter(function(e) {
427 | return e.isdir === 0;
428 | });
429 | result.filter(function(e) {
430 | return e.errno === 0;
431 | }).forEach(function(e) {
432 | if (e.isdir === 1) {
433 | //alert('isdir');
434 | var filenamearr = [];
435 | //alert('nodir');
436 | for (var i = 0; i < foldersList.length; i++) {
437 | var fname = foldersList[i]['server_filename'];
438 | var ffname = fname.replace(/|/g, '');
439 | var fffname = ('【文件夹】' + ffname + '.zip');
440 | filenamearr.push(fffname);
441 | }
442 | filenames = filenamearr.join('|');
443 | } else {
444 | var filenamearr = [];
445 | //alert('nodir');
446 | for (var i = 0; i < filesList.length; i++) {
447 | var fname = filesList[i]['server_filename'];
448 | var ffname = fname.replace(/|/g, '');
449 | filenamearr.push(ffname);
450 | }
451 | filenames = filenamearr.join('|');
452 | }
453 | });
454 | //alert(filenames);
455 | var urls = dlinks.join('|');
456 | //var urls = urlss.replace(/d.pcs.baidu.com/g, 'pcs.baidu.com');
457 | //alert(urls);
458 | var dialog = ctx.ui.confirm({
459 | title: 'proxyee-down下载',
460 | body: text,
461 | sureText: 'proxyee-down下载',
462 | onClose: function() {
463 | //clipboard && clipboard.destory && clipboard.destroy();
464 | }
465 | });
466 | //alert(urls);
467 | dialog.buttonIns[0].dom.attr({
468 | 'href': "javascript:var path = document.getElementById('proxyeepath').value;if(path=='请输入下载路径') {alert('未设置默认下载路径, 请在此填写或前往下载设置界面进行设置!');} else {var proxyeethread = document.getElementById('proxyeethread').value;window.proxyeedown('" + urls + "', '" + filenames + "', path, proxyeethread);}",
469 | 'data-clipboard-action': 'copy',
470 | 'data-clipboard-target': '#bar'
471 | }).addClass('btn').off();
472 | //dialog.hide();
473 | }).catch(function(e) {
474 | showError(e);
475 | });
476 | };
477 | module.exports = {
478 | start: start
479 | };
480 | });
481 |
482 | define('px-yunpan:pluginInit.js', function(require) {
483 | var ctx = require('system-core:context/context.js').instanceForSystem;
484 | var $ = require('base:widget/libs/jquerypacket.js');
485 | var pageInfo = require('px-yunpan:pageInfo');
486 | var prefix = pageInfo.prefix;
487 | require.async(prefix + 'download/util/context.js', function(e) {
488 | e.getContext = function() {
489 | return ctx;
490 | };
491 | });
492 | var dmPromise = new Promise(function(resolve, reject) {
493 | $(unsafeWindow).on('load', function() {
494 | reject('downloadManager.js');
495 | });
496 | resolve();
497 | /*require.async(prefix + 'download/service/downloadManager.js', function(dm) {
498 | dm.MODE_PRE_INSTALL = dm.MODE_PRE_DOWNLOAD;
499 | resolve();
500 | });*/
501 | });
502 | var gjcPromise = new Promise(function(resolve, reject) {
503 | $(unsafeWindow).on('load', function() {
504 | reject('guanjiaConnector.js');
505 | });
506 | require.async(prefix + 'download/service/guanjiaConnector.js', function(gjC) {
507 | gjC.init = function() {
508 | setTimeout(function() {
509 | ctx.ui.tip({ mode: 'caution', msg: '检测到正在调用云管家,若脚本失效,请检查更新或提交issue', hasClose: true, autoClose: false });
510 | }, 5e3);
511 | };
512 | resolve();
513 | });
514 | });
515 | var ddsPromise = new Promise(function(resolve, reject) {
516 | $(unsafeWindow).on('load', function() {
517 | reject('downloadDirectService.js');
518 | });
519 | resolve();
520 | /*require.async(prefix + 'download/service/downloadDirectService.js', function(dDS) {
521 | var $preDlFrame = null;
522 | var _ = dDS.straightforwardDownload;
523 | if (typeof _ !== 'function') return;
524 | dDS.straightforwardDownload = function() {
525 | ctx.ui.tip({ mode: 'loading', msg: '正在开始下载...' });
526 | if ($preDlFrame === null) {
527 | setTimeout(function() {
528 | var $frame = $('#pcsdownloadiframe');
529 | if ($frame.length === 0) return;
530 | $frame.ready(function(event) { ctx.ui.hideTip(); });
531 | $preDlFrame = $frame;
532 | }, 1e3);
533 | }
534 | _.apply(dDS, arguments);
535 | };
536 | resolve();
537 | });*/
538 | });
539 | Promise.all([dmPromise, gjcPromise, ddsPromise]).then(function() {
540 | try {
541 | require('px-yunpan:downloadBtnInit');
542 | ctx.ui.tip({ mode: 'success', msg: 'px-baiduyunpan: 插件加载成功' });
543 | } catch (e) {
544 | ctx.ui.tip({ mode: 'caution', msg: 'px-baiduyunpan: 插件加载成功,按钮初始化失败', autoClose: false, hasClose: true });
545 | }
546 | }).catch(function(msg) {
547 | if(document.querySelector('#share_nofound_des') !== null) return;
548 | showError(msg + '加载失败');
549 | });
550 | });
551 | try {
552 | require('px-yunpan:pluginInit.js');
553 | } catch (ex) { showError(ex); }
554 | })(unsafeWindow.require, unsafeWindow.define, unsafeWindow.Promise);
555 |
--------------------------------------------------------------------------------