@aiyiran/myclaw 1.1.65 → 1.1.66

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.
@@ -213,7 +213,7 @@
213
213
  leftGroup.appendChild(titleSpan);
214
214
 
215
215
  var eyeBtn = document.createElement('span');
216
- var updateEyeUI = function() {
216
+ var updateEyeUI = function () {
217
217
  if (showHiddenArtifacts) {
218
218
  eyeBtn.textContent = '👁';
219
219
  eyeBtn.style.opacity = '1';
@@ -228,9 +228,9 @@
228
228
  };
229
229
  eyeBtn.style.cssText = 'cursor:pointer;border-radius:3px;padding:2px 4px;transition:all 0.15s;font-size:13px;';
230
230
  updateEyeUI();
231
- eyeBtn.onmouseenter = function() { eyeBtn.style.background = 'rgba(255,255,255,0.1)'; };
232
- eyeBtn.onmouseleave = function() { eyeBtn.style.background = 'none'; };
233
- eyeBtn.onclick = function() {
231
+ eyeBtn.onmouseenter = function () { eyeBtn.style.background = 'rgba(255,255,255,0.1)'; };
232
+ eyeBtn.onmouseleave = function () { eyeBtn.style.background = 'none'; };
233
+ eyeBtn.onclick = function () {
234
234
  showHiddenArtifacts = !showHiddenArtifacts;
235
235
  updateEyeUI();
236
236
  var contentEl = document.querySelector('#myclaw-artifacts-content');
@@ -249,19 +249,19 @@
249
249
  searchBoxHeader.id = 'myclaw-search-box';
250
250
  searchBoxHeader.placeholder = '搜索...';
251
251
  searchBoxHeader.style.cssText = 'max-width:120px;height:22px;padding:2px 8px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:4px;color:#cdd6f4;font-size:11px;font-family:monospace;box-sizing:border-box;';
252
- searchBoxHeader.onkeyup = function() {
252
+ searchBoxHeader.onkeyup = function () {
253
253
  applySearch();
254
254
  };
255
255
  header.appendChild(searchBoxHeader);
256
256
  }
257
257
 
258
258
  // 搜索过滤函数
259
- window.applySearch = function() {
259
+ window.applySearch = function () {
260
260
  var searchBox = document.querySelector('#myclaw-search-box');
261
261
  if (!searchBox || !searchBox.value) return;
262
262
  var keyword = searchBox.value.toLowerCase();
263
263
  var items = document.querySelectorAll('[data-artifact-item]');
264
- items.forEach(function(item) {
264
+ items.forEach(function (item) {
265
265
  var fileName = item.getAttribute('data-artifact-name') || '';
266
266
  item.style.display = (keyword === '' || fileName.toLowerCase().indexOf(keyword) !== -1) ? 'flex' : 'none';
267
267
  });
@@ -483,7 +483,7 @@
483
483
  'BOOTSTRAP.md',
484
484
  'AGENTS.md'
485
485
  ];
486
-
486
+
487
487
  // 黑名单目录:隐藏特定的系统目录
488
488
  var DIR_BLACKLIST = [
489
489
  'memory/',
@@ -494,17 +494,17 @@
494
494
  sorted = sorted.filter(function (asset) {
495
495
  var path = asset.path || asset.name || '';
496
496
  var basename = path.split('/').pop();
497
-
497
+
498
498
  // 1. 检查文件名是否包含在黑名单中
499
499
  if (ARTIFACT_BLACKLIST.indexOf(basename) !== -1) return false;
500
-
500
+
501
501
  // 2. 检查路径是否以黑名单目录开头
502
502
  for (var i = 0; i < DIR_BLACKLIST.length; i++) {
503
503
  if (path.indexOf(DIR_BLACKLIST[i]) === 0) {
504
504
  return false;
505
505
  }
506
506
  }
507
-
507
+
508
508
  return true;
509
509
  });
510
510
  }
@@ -641,7 +641,7 @@
641
641
  fname.style.cssText = 'flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:2px;';
642
642
 
643
643
  var fullPath = asset.path || asset.name || '未命名';
644
- var parts = fullPath.split('/').filter(function(p) { return p !== ''; });
644
+ var parts = fullPath.split('/').filter(function (p) { return p !== ''; });
645
645
  // 上行:倒数第二层以上的路径(若只有一层目录则无上行)
646
646
  // 下行:直接父文件夹/文件名
647
647
  var topPart = '';
@@ -674,6 +674,22 @@
674
674
 
675
675
  row.appendChild(leftCol);
676
676
  row.appendChild(fname);
677
+
678
+ // HTML 文件:右侧显示源码查看图标
679
+ var assetExtForSrc = (asset.path || '').split('.').pop().toLowerCase();
680
+ if (assetExtForSrc === 'html' || assetExtForSrc === 'htm') {
681
+ var srcIcon = document.createElement('span');
682
+ srcIcon.textContent = '</>';
683
+ srcIcon.title = '查看源代码';
684
+ srcIcon.style.cssText = 'flex-shrink:0;align-self:center;color:#555;font-size:11px;font-family:monospace;cursor:pointer;padding:2px 5px;border-radius:3px;border:1px solid transparent;transition:color 0.15s,border-color 0.15s,background 0.15s;margin-left:4px;white-space:nowrap;';
685
+ srcIcon.onmouseenter = function () { srcIcon.style.color = '#a78bfa'; srcIcon.style.borderColor = 'rgba(167,139,250,0.4)'; srcIcon.style.background = 'rgba(167,139,250,0.08)'; };
686
+ srcIcon.onmouseleave = function () { srcIcon.style.color = '#555'; srcIcon.style.borderColor = 'transparent'; srcIcon.style.background = ''; };
687
+ srcIcon.onclick = (function (a) {
688
+ return function (e) { e.stopPropagation(); openSourceModal(a); };
689
+ }(asset));
690
+ row.appendChild(srcIcon);
691
+ }
692
+
677
693
  listContent.appendChild(row);
678
694
  });
679
695
 
@@ -878,6 +894,71 @@
878
894
  if (modal) modal.remove();
879
895
  }
880
896
 
897
+ // ═══ 源代码查看弹框 ═══
898
+ function openSourceModal(asset) {
899
+ if (document.querySelector('#myclaw-source-modal')) return;
900
+
901
+ var overlay = document.createElement('div');
902
+ overlay.id = 'myclaw-source-modal';
903
+ overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:99999;display:flex;align-items:center;justify-content:center;font-family:monospace;';
904
+ overlay.onclick = function (e) { if (e.target === overlay) overlay.remove(); };
905
+
906
+ var box = document.createElement('div');
907
+ box.style.cssText = 'background:#1e1e2e;border:1px solid rgba(255,255,255,0.1);border-radius:8px;width:calc(100vw - 40px);height:calc(100vh - 40px);display:flex;flex-direction:column;color:#cdd6f4;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,0.6);';
908
+
909
+ var head = document.createElement('div');
910
+ head.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid rgba(255,255,255,0.1);flex-shrink:0;';
911
+
912
+ var headTitle = document.createElement('span');
913
+ headTitle.textContent = '</> ' + (asset.path || '');
914
+ headTitle.style.cssText = 'font-size:13px;color:#cdd6f4;';
915
+
916
+ var headRight = document.createElement('span');
917
+ headRight.style.cssText = 'display:flex;align-items:center;gap:10px;';
918
+
919
+ var copyBtn = document.createElement('span');
920
+ copyBtn.textContent = '复制';
921
+ copyBtn.style.cssText = 'cursor:pointer;padding:4px 10px;border-radius:4px;font-size:12px;background:rgba(255,255,255,0.08);transition:background 0.15s;';
922
+ copyBtn.onmouseenter = function () { copyBtn.style.background = 'rgba(255,255,255,0.18)'; };
923
+ copyBtn.onmouseleave = function () { copyBtn.style.background = 'rgba(255,255,255,0.08)'; };
924
+
925
+ var closeBtn = document.createElement('span');
926
+ closeBtn.textContent = '✕';
927
+ closeBtn.style.cssText = 'cursor:pointer;padding:4px 10px;border-radius:4px;font-size:18px;font-weight:bold;transition:background 0.15s;';
928
+ closeBtn.onmouseenter = function () { closeBtn.style.background = 'rgba(255,255,255,0.15)'; };
929
+ closeBtn.onmouseleave = function () { closeBtn.style.background = 'none'; };
930
+ closeBtn.onclick = function () { overlay.remove(); };
931
+
932
+ headRight.appendChild(copyBtn);
933
+ headRight.appendChild(closeBtn);
934
+ head.appendChild(headTitle);
935
+ head.appendChild(headRight);
936
+ box.appendChild(head);
937
+
938
+ var pre = document.createElement('pre');
939
+ pre.style.cssText = 'flex:1;margin:0;padding:16px;overflow:auto;font-size:12px;line-height:1.6;color:#cdd6f4;background:#1a1a2e;white-space:pre;';
940
+ pre.textContent = '加载中…';
941
+
942
+ var apiUrl = MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
943
+ fetch(apiUrl)
944
+ .then(function (r) { return r.ok ? r.arrayBuffer() : Promise.reject('HTTP ' + r.status); })
945
+ .then(function (buf) {
946
+ var text = new TextDecoder('utf-8').decode(buf);
947
+ pre.textContent = text;
948
+ copyBtn.onclick = function () {
949
+ navigator.clipboard.writeText(text).then(function () {
950
+ copyBtn.textContent = '✓ 已复制';
951
+ setTimeout(function () { copyBtn.textContent = '复制'; }, 1500);
952
+ });
953
+ };
954
+ })
955
+ .catch(function (e) { pre.textContent = '加载失败: ' + e; });
956
+
957
+ box.appendChild(pre);
958
+ overlay.appendChild(box);
959
+ document.body.appendChild(overlay);
960
+ }
961
+
881
962
  // ═══ 历史记录弹框 ═══
882
963
  function openHistoryModal(defaultPath) {
883
964
  if (document.querySelector('#myclaw-history-modal')) return;
@@ -1199,21 +1280,21 @@
1199
1280
  mTitleTime.style.cssText = 'font-size:11px;color:#888;font-weight:normal;';
1200
1281
  function updateStatsTime() {
1201
1282
  var now = new Date();
1202
- var pad = function(n){return n<10?'0'+n:n;};
1203
- mTitleTime.textContent = now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+pad(now.getHours())+':'+pad(now.getMinutes())+':'+pad(now.getSeconds());
1283
+ var pad = function (n) { return n < 10 ? '0' + n : n; };
1284
+ mTitleTime.textContent = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate()) + ' ' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
1204
1285
  }
1205
1286
  updateStatsTime();
1206
1287
  var statsTimerInterval = setInterval(updateStatsTime, 1000);
1207
- overlay.addEventListener('remove', function(){ clearInterval(statsTimerInterval); }, {once:true});
1288
+ overlay.addEventListener('remove', function () { clearInterval(statsTimerInterval); }, { once: true });
1208
1289
  // 监听 overlay 被移除时清除 timer
1209
- var statsTimerObserver = new MutationObserver(function(mutations){
1210
- mutations.forEach(function(m){
1211
- m.removedNodes.forEach(function(n){
1212
- if(n === overlay){ clearInterval(statsTimerInterval); statsTimerObserver.disconnect(); }
1290
+ var statsTimerObserver = new MutationObserver(function (mutations) {
1291
+ mutations.forEach(function (m) {
1292
+ m.removedNodes.forEach(function (n) {
1293
+ if (n === overlay) { clearInterval(statsTimerInterval); statsTimerObserver.disconnect(); }
1213
1294
  });
1214
1295
  });
1215
1296
  });
1216
- statsTimerObserver.observe(document.body, {childList:true});
1297
+ statsTimerObserver.observe(document.body, { childList: true });
1217
1298
  mTitle.appendChild(mTitleText);
1218
1299
  mTitle.appendChild(mTitleTime);
1219
1300
  var mClose = document.createElement('span');
@@ -1259,7 +1340,7 @@
1259
1340
  function openJsonPreviewModal(title, jsonUrl, sortKey) {
1260
1341
  var jOverlay = document.createElement('div');
1261
1342
  jOverlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:100000;display:flex;align-items:center;justify-content:center;';
1262
- jOverlay.onclick = function(e){ if(e.target===jOverlay) jOverlay.remove(); };
1343
+ jOverlay.onclick = function (e) { if (e.target === jOverlay) jOverlay.remove(); };
1263
1344
 
1264
1345
  var jBox = document.createElement('div');
1265
1346
  jBox.style.cssText = 'background:#1e1e2e;border-radius:10px;width:min(94vw,700px);height:min(80vh,600px);overflow:hidden;box-shadow:0 16px 48px rgba(0,0,0,0.8);font-family:monospace;color:#cdd6f4;display:flex;flex-direction:column;';
@@ -1271,9 +1352,9 @@
1271
1352
  var jClose = document.createElement('span');
1272
1353
  jClose.textContent = '✕';
1273
1354
  jClose.style.cssText = 'cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;';
1274
- jClose.onmouseenter = function(){ jClose.style.background='rgba(255,255,255,0.1)'; };
1275
- jClose.onmouseleave = function(){ jClose.style.background='none'; };
1276
- jClose.onclick = function(){ jOverlay.remove(); };
1355
+ jClose.onmouseenter = function () { jClose.style.background = 'rgba(255,255,255,0.1)'; };
1356
+ jClose.onmouseleave = function () { jClose.style.background = 'none'; };
1357
+ jClose.onclick = function () { jOverlay.remove(); };
1277
1358
  jHead.appendChild(jTitle);
1278
1359
  jHead.appendChild(jClose);
1279
1360
 
@@ -1287,15 +1368,15 @@
1287
1368
  document.body.appendChild(jOverlay);
1288
1369
 
1289
1370
  fetch(jsonUrl)
1290
- .then(function(r){ return r.ok ? r.json() : Promise.reject('HTTP ' + r.status); })
1291
- .then(function(data){
1371
+ .then(function (r) { return r.ok ? r.json() : Promise.reject('HTTP ' + r.status); })
1372
+ .then(function (data) {
1292
1373
  if (sortKey) {
1293
1374
  // 支持顶层数组 或 对象内某个数组字段(如 { assets: [...] })
1294
1375
  var arr = Array.isArray(data) ? data : (data && typeof data === 'object' ? (
1295
- Object.values(data).find(function(v){ return Array.isArray(v); })
1376
+ Object.values(data).find(function (v) { return Array.isArray(v); })
1296
1377
  ) : null);
1297
1378
  if (arr) {
1298
- arr.sort(function(a, b){
1379
+ arr.sort(function (a, b) {
1299
1380
  var ta = a[sortKey] ? new Date(a[sortKey]).getTime() : 0;
1300
1381
  var tb = b[sortKey] ? new Date(b[sortKey]).getTime() : 0;
1301
1382
  return tb - ta;
@@ -1305,7 +1386,7 @@
1305
1386
  jBody.style.color = '#a6e3a1';
1306
1387
  jBody.textContent = JSON.stringify(data, null, 2);
1307
1388
  })
1308
- .catch(function(err){
1389
+ .catch(function (err) {
1309
1390
  jBody.style.color = '#f87171';
1310
1391
  jBody.textContent = '加载失败: ' + err;
1311
1392
  });
@@ -1315,9 +1396,9 @@
1315
1396
  var sec1 = makeSection('📁', '文件资产');
1316
1397
  sec1.style.cursor = 'pointer';
1317
1398
  sec1.title = '点击查看 JSON';
1318
- sec1.onmouseenter = function(){ sec1.style.background='rgba(255,255,255,0.04)'; };
1319
- sec1.onmouseleave = function(){ sec1.style.background=''; };
1320
- sec1.onclick = function(){
1399
+ sec1.onmouseenter = function () { sec1.style.background = 'rgba(255,255,255,0.04)'; };
1400
+ sec1.onmouseleave = function () { sec1.style.background = ''; };
1401
+ sec1.onclick = function () {
1321
1402
  var wsPrefix = getWorkspaceId();
1322
1403
  openJsonPreviewModal('📁 文件资产 — __MY_ARTIFACTS__.json', MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(wsPrefix + '/.myclaw/__MY_ARTIFACTS__.json'), 'updated_at');
1323
1404
  };
@@ -1355,9 +1436,9 @@
1355
1436
  var sec2 = makeSection('🎨', '美术资源');
1356
1437
  sec2.style.cursor = 'pointer';
1357
1438
  sec2.title = '点击查看 JSON';
1358
- sec2.onmouseenter = function(){ sec2.style.background='rgba(255,255,255,0.04)'; };
1359
- sec2.onmouseleave = function(){ sec2.style.background=''; };
1360
- sec2.onclick = function(){
1439
+ sec2.onmouseenter = function () { sec2.style.background = 'rgba(255,255,255,0.04)'; };
1440
+ sec2.onmouseleave = function () { sec2.style.background = ''; };
1441
+ sec2.onclick = function () {
1361
1442
  openJsonPreviewModal('🎨 美术资源 — media-generation-log.json', MYCLAW_API_BASE + '/api/file?path=myclaw/log/media-generation-log.json', 'started_at');
1362
1443
  };
1363
1444
  var mediaPlaceholder = document.createElement('div');
@@ -1401,8 +1482,8 @@
1401
1482
  var syncBtn = document.createElement('button');
1402
1483
  syncBtn.textContent = '全量同步';
1403
1484
  syncBtn.style.cssText = 'padding:2px 10px;background:none;color:#555;border:1px solid rgba(255,255,255,0.1);border-radius:4px;font-size:11px;font-family:monospace;cursor:pointer;transition:color 0.15s,border-color 0.15s;';
1404
- syncBtn.onmouseenter = function () { syncBtn.style.color='#aaa'; syncBtn.style.borderColor='rgba(255,255,255,0.25)'; };
1405
- syncBtn.onmouseleave = function () { syncBtn.style.color='#555'; syncBtn.style.borderColor='rgba(255,255,255,0.1)'; };
1485
+ syncBtn.onmouseenter = function () { syncBtn.style.color = '#aaa'; syncBtn.style.borderColor = 'rgba(255,255,255,0.25)'; };
1486
+ syncBtn.onmouseleave = function () { syncBtn.style.color = '#555'; syncBtn.style.borderColor = 'rgba(255,255,255,0.1)'; };
1406
1487
  syncBtn.onclick = function () {
1407
1488
  var confirm = document.createElement('div');
1408
1489
  confirm.style.cssText = 'margin-top:10px;padding:10px;background:rgba(250,204,21,0.08);border:1px solid rgba(250,204,21,0.2);border-radius:6px;font-size:11px;color:#facc15;line-height:1.7;';
@@ -1456,7 +1537,7 @@
1456
1537
 
1457
1538
  // 读取上次发布缓存
1458
1539
  var savedForm = {};
1459
- try { savedForm = JSON.parse(localStorage.getItem('myclaw-publish-cache')) || {}; } catch (e) {}
1540
+ try { savedForm = JSON.parse(localStorage.getItem('myclaw-publish-cache')) || {}; } catch (e) { }
1460
1541
 
1461
1542
  var overlay = document.createElement('div');
1462
1543
  overlay.id = 'myclaw-artifacts-publish-modal';
@@ -1936,7 +2017,7 @@
1936
2017
  }
1937
2018
 
1938
2019
  // ═══ QR 码生成(qrcodejs 内联,无外部依赖,无 CSP 问题) ═══
1939
- var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c<a.length&&0==a[c];)c++;this.num=new Array(a.length-c+b);for(var d=0;d<a.length-c;d++)this.num[d]=a[d+c]}function j(a,b){this.totalCount=a,this.dataCount=b}function k(){this.buffer=[],this.length=0}function m(){return"undefined"!=typeof CanvasRenderingContext2D}function n(){var a=!1,b=navigator.userAgent;return/android/i.test(b)&&(a=!0,aMat=b.toString().match(/android ([0-9]\.[0-9])/i),aMat&&aMat[1]&&(a=parseFloat(aMat[1]))),a}function r(a,b){for(var c=1,e=s(a),f=0,g=l.length;g>=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=new Array(this.moduleCount);for(var e=0;e<this.moduleCount;e++)this.modules[d][e]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(a,c),this.typeNumber>=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f<this.modules.length;f++)for(var g=f*e,h=0;h<this.modules[f].length;h++){var i=h*e,j=this.modules[f][h];j&&(d.beginFill(0,100),d.moveTo(i,g),d.lineTo(i+e,g),d.lineTo(i+e,g+e),d.lineTo(i,g+e),d.endFill())}return d},setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(var b=8;b<this.moduleCount-8;b++)null==this.modules[6][b]&&(this.modules[6][b]=0==b%2)},setupPositionAdjustPattern:function(){for(var a=f.getPatternPosition(this.typeNumber),b=0;b<a.length;b++)for(var c=0;c<a.length;c++){var d=a[b],e=a[c];if(null==this.modules[d][e])for(var g=-2;2>=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g<a.length&&(j=1==(1&a[g]>>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h<d.length;h++){var i=d[h];g.put(i.mode,4),g.put(i.getLength(),f.getLengthInBits(i.mode,a)),i.write(g)}for(var l=0,h=0;h<e.length;h++)l+=e[h].dataCount;if(g.getLengthInBits()>8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j<b.length;j++){var k=b[j].dataCount,l=b[j].totalCount-k;d=Math.max(d,k),e=Math.max(e,l),g[j]=new Array(k);for(var m=0;m<g[j].length;m++)g[j][m]=255&a.buffer[m+c];c+=k;var n=f.getErrorCorrectPolynomial(l),o=new i(g[j],n.getLength()-1),p=o.mod(n);h[j]=new Array(n.getLength()-1);for(var m=0;m<h[j].length;m++){var q=m+p.getLength()-h[j].length;h[j][m]=q>=0?p.get(q):0}}for(var r=0,m=0;m<b.length;m++)r+=b[m].totalCount;for(var s=new Array(r),t=0,m=0;d>m;m++)for(var j=0;j<b.length;j++)m<g[j].length&&(s[t++]=g[j][m]);for(var m=0;e>m;m++)for(var j=0;j<b.length;j++)m<h[j].length&&(s[t++]=h[j][m]);return s};for(var c={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},d={L:1,M:0,Q:3,H:2},e={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},f={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var b=a<<10;f.getBCHDigit(b)-f.getBCHDigit(f.G15)>=0;)b^=f.G15<<f.getBCHDigit(b)-f.getBCHDigit(f.G15);return(a<<10|b)^f.G15_MASK},getBCHTypeNumber:function(a){for(var b=a<<12;f.getBCHDigit(b)-f.getBCHDigit(f.G18)>=0;)b^=f.G18<<f.getBCHDigit(b)-f.getBCHDigit(f.G18);return a<<12|b},getBCHDigit:function(a){for(var b=0;0!=a;)b++,a>>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<<h;for(var h=8;256>h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;c<this.getLength();c++)for(var d=0;d<a.getLength();d++)b[c+d]^=g.gexp(g.glog(this.get(c))+g.glog(a.get(d)));return new i(b,0)},mod:function(a){if(this.getLength()-a.getLength()<0)return this;for(var b=g.glog(this.get(0))-g.glog(a.get(0)),c=new Array(this.getLength()),d=0;d<this.getLength();d++)c[d]=this.get(d);for(var d=0;d<a.getLength();d++)c[d]^=g.gexp(g.glog(a.get(d))+b);return new i(c,0).mod(a)}},j.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],j.getRSBlocks=function(a,b){var c=j.getRsBlockTable(a,b);if(void 0==c)throw new Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+b);for(var d=c.length/3,e=[],f=0;d>f;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(false/*android2.1 fix disabled*/){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=['<table style="border:0;border-collapse:collapse;">'],h=0;d>h;h++){g.push("<tr>");for(var i=0;d>i;i++)g.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:'+e+"px;height:"+f+"px;background-color:"+(a.isDark(h,i)?b.colorDark:b.colorLight)+';"></td>');g.push("</tr>")}g.push("</table>"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();
2020
+ var QRCode; !function () { function a(a) { this.mode = c.MODE_8BIT_BYTE, this.data = a, this.parsedData = []; for (var b = [], d = 0, e = this.data.length; e > d; d++) { var f = this.data.charCodeAt(d); f > 65536 ? (b[0] = 240 | (1835008 & f) >>> 18, b[1] = 128 | (258048 & f) >>> 12, b[2] = 128 | (4032 & f) >>> 6, b[3] = 128 | 63 & f) : f > 2048 ? (b[0] = 224 | (61440 & f) >>> 12, b[1] = 128 | (4032 & f) >>> 6, b[2] = 128 | 63 & f) : f > 128 ? (b[0] = 192 | (1984 & f) >>> 6, b[1] = 128 | 63 & f) : b[0] = f, this.parsedData = this.parsedData.concat(b) } this.parsedData.length != this.data.length && (this.parsedData.unshift(191), this.parsedData.unshift(187), this.parsedData.unshift(239)) } function b(a, b) { this.typeNumber = a, this.errorCorrectLevel = b, this.modules = null, this.moduleCount = 0, this.dataCache = null, this.dataList = [] } function i(a, b) { if (void 0 == a.length) throw new Error(a.length + "/" + b); for (var c = 0; c < a.length && 0 == a[c];)c++; this.num = new Array(a.length - c + b); for (var d = 0; d < a.length - c; d++)this.num[d] = a[d + c] } function j(a, b) { this.totalCount = a, this.dataCount = b } function k() { this.buffer = [], this.length = 0 } function m() { return "undefined" != typeof CanvasRenderingContext2D } function n() { var a = !1, b = navigator.userAgent; return /android/i.test(b) && (a = !0, aMat = b.toString().match(/android ([0-9]\.[0-9])/i), aMat && aMat[1] && (a = parseFloat(aMat[1]))), a } function r(a, b) { for (var c = 1, e = s(a), f = 0, g = l.length; g >= f; f++) { var h = 0; switch (b) { case d.L: h = l[f][0]; break; case d.M: h = l[f][1]; break; case d.Q: h = l[f][2]; break; case d.H: h = l[f][3] }if (h >= e) break; c++ } if (c > l.length) throw new Error("Too long data"); return c } function s(a) { var b = encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g, "a"); return b.length + (b.length != a ? 3 : 0) } a.prototype = { getLength: function () { return this.parsedData.length }, write: function (a) { for (var b = 0, c = this.parsedData.length; c > b; b++)a.put(this.parsedData[b], 8) } }, b.prototype = { addData: function (b) { var c = new a(b); this.dataList.push(c), this.dataCache = null }, isDark: function (a, b) { if (0 > a || this.moduleCount <= a || 0 > b || this.moduleCount <= b) throw new Error(a + "," + b); return this.modules[a][b] }, getModuleCount: function () { return this.moduleCount }, make: function () { this.makeImpl(!1, this.getBestMaskPattern()) }, makeImpl: function (a, c) { this.moduleCount = 4 * this.typeNumber + 17, this.modules = new Array(this.moduleCount); for (var d = 0; d < this.moduleCount; d++) { this.modules[d] = new Array(this.moduleCount); for (var e = 0; e < this.moduleCount; e++)this.modules[d][e] = null } this.setupPositionProbePattern(0, 0), this.setupPositionProbePattern(this.moduleCount - 7, 0), this.setupPositionProbePattern(0, this.moduleCount - 7), this.setupPositionAdjustPattern(), this.setupTimingPattern(), this.setupTypeInfo(a, c), this.typeNumber >= 7 && this.setupTypeNumber(a), null == this.dataCache && (this.dataCache = b.createData(this.typeNumber, this.errorCorrectLevel, this.dataList)), this.mapData(this.dataCache, c) }, setupPositionProbePattern: function (a, b) { for (var c = -1; 7 >= c; c++)if (!(-1 >= a + c || this.moduleCount <= a + c)) for (var d = -1; 7 >= d; d++)-1 >= b + d || this.moduleCount <= b + d || (this.modules[a + c][b + d] = c >= 0 && 6 >= c && (0 == d || 6 == d) || d >= 0 && 6 >= d && (0 == c || 6 == c) || c >= 2 && 4 >= c && d >= 2 && 4 >= d ? !0 : !1) }, getBestMaskPattern: function () { for (var a = 0, b = 0, c = 0; 8 > c; c++) { this.makeImpl(!0, c); var d = f.getLostPoint(this); (0 == c || a > d) && (a = d, b = c) } return b }, createMovieClip: function (a, b, c) { var d = a.createEmptyMovieClip(b, c), e = 1; this.make(); for (var f = 0; f < this.modules.length; f++)for (var g = f * e, h = 0; h < this.modules[f].length; h++) { var i = h * e, j = this.modules[f][h]; j && (d.beginFill(0, 100), d.moveTo(i, g), d.lineTo(i + e, g), d.lineTo(i + e, g + e), d.lineTo(i, g + e), d.endFill()) } return d }, setupTimingPattern: function () { for (var a = 8; a < this.moduleCount - 8; a++)null == this.modules[a][6] && (this.modules[a][6] = 0 == a % 2); for (var b = 8; b < this.moduleCount - 8; b++)null == this.modules[6][b] && (this.modules[6][b] = 0 == b % 2) }, setupPositionAdjustPattern: function () { for (var a = f.getPatternPosition(this.typeNumber), b = 0; b < a.length; b++)for (var c = 0; c < a.length; c++) { var d = a[b], e = a[c]; if (null == this.modules[d][e]) for (var g = -2; 2 >= g; g++)for (var h = -2; 2 >= h; h++)this.modules[d + g][e + h] = -2 == g || 2 == g || -2 == h || 2 == h || 0 == g && 0 == h ? !0 : !1 } }, setupTypeNumber: function (a) { for (var b = f.getBCHTypeNumber(this.typeNumber), c = 0; 18 > c; c++) { var d = !a && 1 == (1 & b >> c); this.modules[Math.floor(c / 3)][c % 3 + this.moduleCount - 8 - 3] = d } for (var c = 0; 18 > c; c++) { var d = !a && 1 == (1 & b >> c); this.modules[c % 3 + this.moduleCount - 8 - 3][Math.floor(c / 3)] = d } }, setupTypeInfo: function (a, b) { for (var c = this.errorCorrectLevel << 3 | b, d = f.getBCHTypeInfo(c), e = 0; 15 > e; e++) { var g = !a && 1 == (1 & d >> e); 6 > e ? this.modules[e][8] = g : 8 > e ? this.modules[e + 1][8] = g : this.modules[this.moduleCount - 15 + e][8] = g } for (var e = 0; 15 > e; e++) { var g = !a && 1 == (1 & d >> e); 8 > e ? this.modules[8][this.moduleCount - e - 1] = g : 9 > e ? this.modules[8][15 - e - 1 + 1] = g : this.modules[8][15 - e - 1] = g } this.modules[this.moduleCount - 8][8] = !a }, mapData: function (a, b) { for (var c = -1, d = this.moduleCount - 1, e = 7, g = 0, h = this.moduleCount - 1; h > 0; h -= 2)for (6 == h && h--; ;) { for (var i = 0; 2 > i; i++)if (null == this.modules[d][h - i]) { var j = !1; g < a.length && (j = 1 == (1 & a[g] >>> e)); var k = f.getMask(b, d, h - i); k && (j = !j), this.modules[d][h - i] = j, e--, -1 == e && (g++, e = 7) } if (d += c, 0 > d || this.moduleCount <= d) { d -= c, c = -c; break } } } }, b.PAD0 = 236, b.PAD1 = 17, b.createData = function (a, c, d) { for (var e = j.getRSBlocks(a, c), g = new k, h = 0; h < d.length; h++) { var i = d[h]; g.put(i.mode, 4), g.put(i.getLength(), f.getLengthInBits(i.mode, a)), i.write(g) } for (var l = 0, h = 0; h < e.length; h++)l += e[h].dataCount; if (g.getLengthInBits() > 8 * l) throw new Error("code length overflow. (" + g.getLengthInBits() + ">" + 8 * l + ")"); for (g.getLengthInBits() + 4 <= 8 * l && g.put(0, 4); 0 != g.getLengthInBits() % 8;)g.putBit(!1); for (; ;) { if (g.getLengthInBits() >= 8 * l) break; if (g.put(b.PAD0, 8), g.getLengthInBits() >= 8 * l) break; g.put(b.PAD1, 8) } return b.createBytes(g, e) }, b.createBytes = function (a, b) { for (var c = 0, d = 0, e = 0, g = new Array(b.length), h = new Array(b.length), j = 0; j < b.length; j++) { var k = b[j].dataCount, l = b[j].totalCount - k; d = Math.max(d, k), e = Math.max(e, l), g[j] = new Array(k); for (var m = 0; m < g[j].length; m++)g[j][m] = 255 & a.buffer[m + c]; c += k; var n = f.getErrorCorrectPolynomial(l), o = new i(g[j], n.getLength() - 1), p = o.mod(n); h[j] = new Array(n.getLength() - 1); for (var m = 0; m < h[j].length; m++) { var q = m + p.getLength() - h[j].length; h[j][m] = q >= 0 ? p.get(q) : 0 } } for (var r = 0, m = 0; m < b.length; m++)r += b[m].totalCount; for (var s = new Array(r), t = 0, m = 0; d > m; m++)for (var j = 0; j < b.length; j++)m < g[j].length && (s[t++] = g[j][m]); for (var m = 0; e > m; m++)for (var j = 0; j < b.length; j++)m < h[j].length && (s[t++] = h[j][m]); return s }; for (var c = { MODE_NUMBER: 1, MODE_ALPHA_NUM: 2, MODE_8BIT_BYTE: 4, MODE_KANJI: 8 }, d = { L: 1, M: 0, Q: 3, H: 2 }, e = { PATTERN000: 0, PATTERN001: 1, PATTERN010: 2, PATTERN011: 3, PATTERN100: 4, PATTERN101: 5, PATTERN110: 6, PATTERN111: 7 }, f = { PATTERN_POSITION_TABLE: [[], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]], G15: 1335, G18: 7973, G15_MASK: 21522, getBCHTypeInfo: function (a) { for (var b = a << 10; f.getBCHDigit(b) - f.getBCHDigit(f.G15) >= 0;)b ^= f.G15 << f.getBCHDigit(b) - f.getBCHDigit(f.G15); return (a << 10 | b) ^ f.G15_MASK }, getBCHTypeNumber: function (a) { for (var b = a << 12; f.getBCHDigit(b) - f.getBCHDigit(f.G18) >= 0;)b ^= f.G18 << f.getBCHDigit(b) - f.getBCHDigit(f.G18); return a << 12 | b }, getBCHDigit: function (a) { for (var b = 0; 0 != a;)b++, a >>>= 1; return b }, getPatternPosition: function (a) { return f.PATTERN_POSITION_TABLE[a - 1] }, getMask: function (a, b, c) { switch (a) { case e.PATTERN000: return 0 == (b + c) % 2; case e.PATTERN001: return 0 == b % 2; case e.PATTERN010: return 0 == c % 3; case e.PATTERN011: return 0 == (b + c) % 3; case e.PATTERN100: return 0 == (Math.floor(b / 2) + Math.floor(c / 3)) % 2; case e.PATTERN101: return 0 == b * c % 2 + b * c % 3; case e.PATTERN110: return 0 == (b * c % 2 + b * c % 3) % 2; case e.PATTERN111: return 0 == (b * c % 3 + (b + c) % 2) % 2; default: throw new Error("bad maskPattern:" + a) } }, getErrorCorrectPolynomial: function (a) { for (var b = new i([1], 0), c = 0; a > c; c++)b = b.multiply(new i([1, g.gexp(c)], 0)); return b }, getLengthInBits: function (a, b) { if (b >= 1 && 10 > b) switch (a) { case c.MODE_NUMBER: return 10; case c.MODE_ALPHA_NUM: return 9; case c.MODE_8BIT_BYTE: return 8; case c.MODE_KANJI: return 8; default: throw new Error("mode:" + a) } else if (27 > b) switch (a) { case c.MODE_NUMBER: return 12; case c.MODE_ALPHA_NUM: return 11; case c.MODE_8BIT_BYTE: return 16; case c.MODE_KANJI: return 10; default: throw new Error("mode:" + a) } else { if (!(41 > b)) throw new Error("type:" + b); switch (a) { case c.MODE_NUMBER: return 14; case c.MODE_ALPHA_NUM: return 13; case c.MODE_8BIT_BYTE: return 16; case c.MODE_KANJI: return 12; default: throw new Error("mode:" + a) } } }, getLostPoint: function (a) { for (var b = a.getModuleCount(), c = 0, d = 0; b > d; d++)for (var e = 0; b > e; e++) { for (var f = 0, g = a.isDark(d, e), h = -1; 1 >= h; h++)if (!(0 > d + h || d + h >= b)) for (var i = -1; 1 >= i; i++)0 > e + i || e + i >= b || (0 != h || 0 != i) && g == a.isDark(d + h, e + i) && f++; f > 5 && (c += 3 + f - 5) } for (var d = 0; b - 1 > d; d++)for (var e = 0; b - 1 > e; e++) { var j = 0; a.isDark(d, e) && j++, a.isDark(d + 1, e) && j++, a.isDark(d, e + 1) && j++, a.isDark(d + 1, e + 1) && j++, (0 == j || 4 == j) && (c += 3) } for (var d = 0; b > d; d++)for (var e = 0; b - 6 > e; e++)a.isDark(d, e) && !a.isDark(d, e + 1) && a.isDark(d, e + 2) && a.isDark(d, e + 3) && a.isDark(d, e + 4) && !a.isDark(d, e + 5) && a.isDark(d, e + 6) && (c += 40); for (var e = 0; b > e; e++)for (var d = 0; b - 6 > d; d++)a.isDark(d, e) && !a.isDark(d + 1, e) && a.isDark(d + 2, e) && a.isDark(d + 3, e) && a.isDark(d + 4, e) && !a.isDark(d + 5, e) && a.isDark(d + 6, e) && (c += 40); for (var k = 0, e = 0; b > e; e++)for (var d = 0; b > d; d++)a.isDark(d, e) && k++; var l = Math.abs(100 * k / b / b - 50) / 5; return c += 10 * l } }, g = { glog: function (a) { if (1 > a) throw new Error("glog(" + a + ")"); return g.LOG_TABLE[a] }, gexp: function (a) { for (; 0 > a;)a += 255; for (; a >= 256;)a -= 255; return g.EXP_TABLE[a] }, EXP_TABLE: new Array(256), LOG_TABLE: new Array(256) }, h = 0; 8 > h; h++)g.EXP_TABLE[h] = 1 << h; for (var h = 8; 256 > h; h++)g.EXP_TABLE[h] = g.EXP_TABLE[h - 4] ^ g.EXP_TABLE[h - 5] ^ g.EXP_TABLE[h - 6] ^ g.EXP_TABLE[h - 8]; for (var h = 0; 255 > h; h++)g.LOG_TABLE[g.EXP_TABLE[h]] = h; i.prototype = { get: function (a) { return this.num[a] }, getLength: function () { return this.num.length }, multiply: function (a) { for (var b = new Array(this.getLength() + a.getLength() - 1), c = 0; c < this.getLength(); c++)for (var d = 0; d < a.getLength(); d++)b[c + d] ^= g.gexp(g.glog(this.get(c)) + g.glog(a.get(d))); return new i(b, 0) }, mod: function (a) { if (this.getLength() - a.getLength() < 0) return this; for (var b = g.glog(this.get(0)) - g.glog(a.get(0)), c = new Array(this.getLength()), d = 0; d < this.getLength(); d++)c[d] = this.get(d); for (var d = 0; d < a.getLength(); d++)c[d] ^= g.gexp(g.glog(a.get(d)) + b); return new i(c, 0).mod(a) } }, j.RS_BLOCK_TABLE = [[1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9], [1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16], [1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13], [1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9], [1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12], [2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15], [2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14], [2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15], [2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13], [2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16], [4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13], [2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15], [4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12], [3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13], [5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12], [5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16], [1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15], [5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15], [3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14], [3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16], [4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17], [2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13], [4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16], [6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17], [8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16], [10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17], [8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16], [3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16], [7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16], [5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16], [13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16], [17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16], [17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16], [13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17], [12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16], [6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16], [17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16], [4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16], [20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16], [19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]], j.getRSBlocks = function (a, b) { var c = j.getRsBlockTable(a, b); if (void 0 == c) throw new Error("bad rs block @ typeNumber:" + a + "/errorCorrectLevel:" + b); for (var d = c.length / 3, e = [], f = 0; d > f; f++)for (var g = c[3 * f + 0], h = c[3 * f + 1], i = c[3 * f + 2], k = 0; g > k; k++)e.push(new j(h, i)); return e }, j.getRsBlockTable = function (a, b) { switch (b) { case d.L: return j.RS_BLOCK_TABLE[4 * (a - 1) + 0]; case d.M: return j.RS_BLOCK_TABLE[4 * (a - 1) + 1]; case d.Q: return j.RS_BLOCK_TABLE[4 * (a - 1) + 2]; case d.H: return j.RS_BLOCK_TABLE[4 * (a - 1) + 3]; default: return void 0 } }, k.prototype = { get: function (a) { var b = Math.floor(a / 8); return 1 == (1 & this.buffer[b] >>> 7 - a % 8) }, put: function (a, b) { for (var c = 0; b > c; c++)this.putBit(1 == (1 & a >>> b - c - 1)) }, getLengthInBits: function () { return this.length }, putBit: function (a) { var b = Math.floor(this.length / 8); this.buffer.length <= b && this.buffer.push(0), a && (this.buffer[b] |= 128 >>> this.length % 8), this.length++ } }; var l = [[17, 14, 11, 7], [32, 26, 20, 14], [53, 42, 32, 24], [78, 62, 46, 34], [106, 84, 60, 44], [134, 106, 74, 58], [154, 122, 86, 64], [192, 152, 108, 84], [230, 180, 130, 98], [271, 213, 151, 119], [321, 251, 177, 137], [367, 287, 203, 155], [425, 331, 241, 177], [458, 362, 258, 194], [520, 412, 292, 220], [586, 450, 322, 250], [644, 504, 364, 280], [718, 560, 394, 310], [792, 624, 442, 338], [858, 666, 482, 382], [929, 711, 509, 403], [1003, 779, 565, 439], [1091, 857, 611, 461], [1171, 911, 661, 511], [1273, 997, 715, 535], [1367, 1059, 751, 593], [1465, 1125, 805, 625], [1528, 1190, 868, 658], [1628, 1264, 908, 698], [1732, 1370, 982, 742], [1840, 1452, 1030, 790], [1952, 1538, 1112, 842], [2068, 1628, 1168, 898], [2188, 1722, 1228, 958], [2303, 1809, 1283, 983], [2431, 1911, 1351, 1051], [2563, 1989, 1423, 1093], [2699, 2099, 1499, 1139], [2809, 2213, 1579, 1219], [2953, 2331, 1663, 1273]], o = function () { var a = function (a, b) { this._el = a, this._htOption = b }; return a.prototype.draw = function (a) { function g(a, b) { var c = document.createElementNS("http://www.w3.org/2000/svg", a); for (var d in b) b.hasOwnProperty(d) && c.setAttribute(d, b[d]); return c } var b = this._htOption, c = this._el, d = a.getModuleCount(); Math.floor(b.width / d), Math.floor(b.height / d), this.clear(); var h = g("svg", { viewBox: "0 0 " + String(d) + " " + String(d), width: "100%", height: "100%", fill: b.colorLight }); h.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"), c.appendChild(h), h.appendChild(g("rect", { fill: b.colorDark, width: "1", height: "1", id: "template" })); for (var i = 0; d > i; i++)for (var j = 0; d > j; j++)if (a.isDark(i, j)) { var k = g("use", { x: String(i), y: String(j) }); k.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template"), h.appendChild(k) } }, a.prototype.clear = function () { for (; this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild) }, a }(), p = "svg" === document.documentElement.tagName.toLowerCase(), q = p ? o : m() ? function () { function a() { this._elImage.src = this._elCanvas.toDataURL("image/png"), this._elImage.style.display = "block", this._elCanvas.style.display = "none" } function d(a, b) { var c = this; if (c._fFail = b, c._fSuccess = a, null === c._bSupportDataURI) { var d = document.createElement("img"), e = function () { c._bSupportDataURI = !1, c._fFail && _fFail.call(c) }, f = function () { c._bSupportDataURI = !0, c._fSuccess && c._fSuccess.call(c) }; return d.onabort = e, d.onerror = e, d.onload = f, d.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==", void 0 } c._bSupportDataURI === !0 && c._fSuccess ? c._fSuccess.call(c) : c._bSupportDataURI === !1 && c._fFail && c._fFail.call(c) } if (false/*android2.1 fix disabled*/) { var b = 1 / window.devicePixelRatio, c = CanvasRenderingContext2D.prototype.drawImage; CanvasRenderingContext2D.prototype.drawImage = function (a, d, e, f, g, h, i, j) { if ("nodeName" in a && /img/i.test(a.nodeName)) for (var l = arguments.length - 1; l >= 1; l--)arguments[l] = arguments[l] * b; else "undefined" == typeof j && (arguments[1] *= b, arguments[2] *= b, arguments[3] *= b, arguments[4] *= b); c.apply(this, arguments) } } var e = function (a, b) { this._bIsPainted = !1, this._android = n(), this._htOption = b, this._elCanvas = document.createElement("canvas"), this._elCanvas.width = b.width, this._elCanvas.height = b.height, a.appendChild(this._elCanvas), this._el = a, this._oContext = this._elCanvas.getContext("2d"), this._bIsPainted = !1, this._elImage = document.createElement("img"), this._elImage.style.display = "none", this._el.appendChild(this._elImage), this._bSupportDataURI = null }; return e.prototype.draw = function (a) { var b = this._elImage, c = this._oContext, d = this._htOption, e = a.getModuleCount(), f = d.width / e, g = d.height / e, h = Math.round(f), i = Math.round(g); b.style.display = "none", this.clear(); for (var j = 0; e > j; j++)for (var k = 0; e > k; k++) { var l = a.isDark(j, k), m = k * f, n = j * g; c.strokeStyle = l ? d.colorDark : d.colorLight, c.lineWidth = 1, c.fillStyle = l ? d.colorDark : d.colorLight, c.fillRect(m, n, f, g), c.strokeRect(Math.floor(m) + .5, Math.floor(n) + .5, h, i), c.strokeRect(Math.ceil(m) - .5, Math.ceil(n) - .5, h, i) } this._bIsPainted = !0 }, e.prototype.makeImage = function () { this._bIsPainted && d.call(this, a) }, e.prototype.isPainted = function () { return this._bIsPainted }, e.prototype.clear = function () { this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height), this._bIsPainted = !1 }, e.prototype.round = function (a) { return a ? Math.floor(1e3 * a) / 1e3 : a }, e }() : function () { var a = function (a, b) { this._el = a, this._htOption = b }; return a.prototype.draw = function (a) { for (var b = this._htOption, c = this._el, d = a.getModuleCount(), e = Math.floor(b.width / d), f = Math.floor(b.height / d), g = ['<table style="border:0;border-collapse:collapse;">'], h = 0; d > h; h++) { g.push("<tr>"); for (var i = 0; d > i; i++)g.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + e + "px;height:" + f + "px;background-color:" + (a.isDark(h, i) ? b.colorDark : b.colorLight) + ';"></td>'); g.push("</tr>") } g.push("</table>"), c.innerHTML = g.join(""); var j = c.childNodes[0], k = (b.width - j.offsetWidth) / 2, l = (b.height - j.offsetHeight) / 2; k > 0 && l > 0 && (j.style.margin = l + "px " + k + "px") }, a.prototype.clear = function () { this._el.innerHTML = "" }, a }(); QRCode = function (a, b) { if (this._htOption = { width: 256, height: 256, typeNumber: 4, colorDark: "#000000", colorLight: "#ffffff", correctLevel: d.H }, "string" == typeof b && (b = { text: b }), b) for (var c in b) this._htOption[c] = b[c]; "string" == typeof a && (a = document.getElementById(a)), this._android = n(), this._el = a, this._oQRCode = null, this._oDrawing = new q(this._el, this._htOption), this._htOption.text && this.makeCode(this._htOption.text) }, QRCode.prototype.makeCode = function (a) { this._oQRCode = new b(r(a, this._htOption.correctLevel), this._htOption.correctLevel), this._oQRCode.addData(a), this._oQRCode.make(), this._el.title = a, this._oDrawing.draw(this._oQRCode), this.makeImage() }, QRCode.prototype.makeImage = function () { "function" == typeof this._oDrawing.makeImage && (!this._android || this._android >= 3) && this._oDrawing.makeImage() }, QRCode.prototype.clear = function () { this._oDrawing.clear() }, QRCode.CorrectLevel = d }();
1940
2021
 
1941
2022
  function loadAndGenerateQR(container, text, size) {
1942
2023
  try {
@@ -2256,13 +2337,13 @@
2256
2337
  var _btnMutedLeave = 'background:rgba(167,139,250,0.12);';
2257
2338
 
2258
2339
  var deployBtn = document.createElement('button');
2259
- deployBtn.textContent = 'workspace-playgrounds ';
2340
+ deployBtn.textContent = '⬇创建 -> 训练场';
2260
2341
  deployBtn.style.cssText = _btnMuted;
2261
2342
  deployBtn.onmouseenter = function () { deployBtn.style.background = 'rgba(167,139,250,0.22)'; };
2262
2343
  deployBtn.onmouseleave = function () { deployBtn.style.background = 'rgba(167,139,250,0.12)'; };
2263
2344
 
2264
2345
  var copyLocalBtn = document.createElement('button');
2265
- copyLocalBtn.textContent = '新建工作区 ';
2346
+ copyLocalBtn.textContent = '⬇创建 -> 新伙伴';
2266
2347
  copyLocalBtn.style.cssText = _btnMuted;
2267
2348
  copyLocalBtn.onmouseenter = function () { copyLocalBtn.style.background = 'rgba(167,139,250,0.22)'; };
2268
2349
  copyLocalBtn.onmouseleave = function () { copyLocalBtn.style.background = 'rgba(167,139,250,0.12)'; };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.1.65",
3
+ "version": "1.1.66",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -55,6 +55,12 @@ description: 面向中文课堂的小专题课程模板流水线。适用于把
55
55
  - move 负责把任务文件夹移动到 `yiran-playground-template-use` skill 的 `templates/`,并自动触发索引重建
56
56
  - publish 负责把模板文件夹内所有资源上传到七牛 CDN,并重写 HTML 中的资源引用为 CDN 绝对地址(见 `cdn-convention.md`)
57
57
 
58
+ **推荐发布入口(内容确认后):**
59
+ ```bash
60
+ python3 scripts/release_template.py <模板目录>
61
+ ```
62
+ `release_template.py` 自动依次执行 build → move → publish,对新目录和已入库的 vN/ 目录均适用。
63
+
58
64
  ## 原则
59
65
 
60
66
  - 先做 demo
@@ -130,7 +130,7 @@
130
130
  控制 iframe 加载哪个页面文件。
131
131
  默认可写:
132
132
  ```json
133
- "示例页面文件": "example.html"
133
+ "示例页面文件": "__demo__.html"
134
134
  ```
135
135
 
136
136
  ---
@@ -102,6 +102,24 @@ python3 scripts/publish_template.py --all
102
102
 
103
103
  ---
104
104
 
105
+ ## 一键发布:release_template.py(推荐)
106
+
107
+ 如果已确认内容没问题,可跳过手动执行脚本2 + 脚本3,直接用一键发布脚本:
108
+
109
+ ```bash
110
+ python3 scripts/release_template.py 任务文件夹
111
+ ```
112
+
113
+ 该脚本自动依次执行:
114
+ 1. `build_template_views.py` — 生成 HTML 视图(Step 1)
115
+ 2. `move_template_task.py` — 创建新版本目录 vN+1/(Step 2)
116
+ 3. `publish_template.py` — 上传 CDN + 上传索引(Step 3)
117
+
118
+ > **注意:** build 阶段仍可单独运行(用于调试预览),脚本1无需通过 release 脚本触发。
119
+ > release_template.py 对已入库的 vN/ 目录同样适用,会自动产出 vN+1/。
120
+
121
+ ---
122
+
105
123
  ## 原则
106
124
 
107
125
  1. 先在当前工作目录完成中间产物
@@ -34,5 +34,5 @@
34
34
  }
35
35
  ],
36
36
  "示例区标题": "示范样例",
37
- "示例页面文件": "example.html"
38
- }
37
+ "示例页面文件": "__demo__.html"
38
+ }
@@ -175,7 +175,7 @@
175
175
 
176
176
  例如:
177
177
  ```json
178
- "示例页面文件": "example.html"
178
+ "示例页面文件": "__demo__.html"
179
179
  ```
180
180
 
181
181
  ---
@@ -7,7 +7,6 @@ identify_template.py
7
7
 
8
8
  写入字段:
9
9
  _id : 8位十六进制,首次颁发,后续不变
10
- _version : 首次=1,更新=已有版本+1
11
10
  任务类别 : 校准后的系列(A/B/C)
12
11
  任务编号 : 校准后的3位编号(100起)
13
12
 
@@ -163,7 +162,6 @@ def main():
163
162
 
164
163
  # ── 3. 写回 __teacher__.json ───────────────────────────────────────────
165
164
  teacher['_id'] = tid
166
- teacher['_version'] = new_version
167
165
  teacher['任务类别'] = category
168
166
  teacher['任务编号'] = f'{calibrated:03d}'
169
167
  save_json(teacher_path, teacher)
@@ -42,6 +42,19 @@ def sanitize_name(name: str) -> str:
42
42
  return re.sub(r'[/\\ ]', '_', str(name).strip())
43
43
 
44
44
 
45
+ def get_latest_version_num(folder: Path) -> int:
46
+ """返回 folder 下最大的版本号,没有则返回 0"""
47
+ if not folder.exists():
48
+ return 0
49
+ max_v = 0
50
+ for d in folder.iterdir():
51
+ if d.is_dir():
52
+ m = re.match(r'^v(\d+)$', d.name)
53
+ if m:
54
+ max_v = max(max_v, int(m.group(1)))
55
+ return max_v
56
+
57
+
45
58
  def main():
46
59
  if len(sys.argv) < 2:
47
60
  print('用法: python3 move_template_task.py <模板目录> [目标根目录]')
@@ -69,10 +82,10 @@ def main():
69
82
  category = teacher.get('任务类别', '').upper()
70
83
  number = teacher.get('任务编号', '100')
71
84
  name = sanitize_name(teacher.get('任务名称', 'untitled'))
72
- version = teacher.get('_version', 1)
73
85
 
74
86
  folder_name = f'{category.lower()}{number}_{name}'
75
- version_str = f'v{version}'
87
+ next_version = get_latest_version_num(target_root / folder_name) + 1
88
+ version_str = f'v{next_version}'
76
89
  target_dir = target_root / folder_name / version_str
77
90
 
78
91
  if target_dir.exists():
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ release_template.py
4
+
5
+ 一键发布脚本:合并 build → move → publish 三个步骤。
6
+
7
+ 传入原始模板目录(或已有 vN/ 目录),自动执行:
8
+ Step 1: build_template_views.py <source_dir> → 生成/更新 HTML 视图
9
+ Step 2: move_template_task.py <source_dir> → 创建新版本目录 vN+1/
10
+ Step 3: publish_template.py <templates/xxx/> → 上传 CDN + 上传 index
11
+
12
+ 用法:
13
+ python3 scripts/release_template.py <模板目录>
14
+ """
15
+ import json
16
+ import re
17
+ import subprocess
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ ROOT = Path(__file__).resolve().parent.parent
22
+ BUILD_SCRIPT = ROOT / 'scripts' / 'build_template_views.py'
23
+ MOVE_SCRIPT = ROOT / 'scripts' / 'move_template_task.py'
24
+ PUBLISH_SCRIPT = ROOT / 'scripts' / 'publish_template.py'
25
+ TEMPLATES_DIR = ROOT / 'templates'
26
+
27
+
28
+ def load_json(path: Path) -> dict:
29
+ try:
30
+ return json.loads(path.read_text(encoding='utf-8'))
31
+ except Exception:
32
+ return {}
33
+
34
+
35
+ def sanitize_name(name: str) -> str:
36
+ return re.sub(r'[/\\ ]', '_', str(name).strip())
37
+
38
+
39
+ def main():
40
+ if len(sys.argv) < 2:
41
+ print('用法: python3 scripts/release_template.py <模板目录>')
42
+ sys.exit(1)
43
+
44
+ source_dir = Path(sys.argv[1]).expanduser().resolve()
45
+
46
+ if not source_dir.is_dir():
47
+ print(f'❌ 目录不存在: {source_dir}')
48
+ sys.exit(1)
49
+
50
+ teacher_path = source_dir / '__teacher__.json'
51
+ if not teacher_path.exists():
52
+ print(f'❌ 找不到 __teacher__.json: {teacher_path}')
53
+ sys.exit(1)
54
+
55
+ # ── Step 1: Build HTML views ──────────────────────────────────────────
56
+ print('\n══ Step 1: 生成 HTML 视图 ══════════════════════════════')
57
+ subprocess.run([sys.executable, str(BUILD_SCRIPT), str(source_dir)], check=True)
58
+
59
+ # ── Step 2: Move to templates/ ────────────────────────────────────────
60
+ print('\n══ Step 2: 移入 templates/ ═════════════════════════════')
61
+ subprocess.run([sys.executable, str(MOVE_SCRIPT), str(source_dir)], check=True)
62
+
63
+ # ── Determine publish target from updated teacher.json ────────────────
64
+ teacher = load_json(teacher_path)
65
+ category = teacher.get('任务类别', '').upper()
66
+ number = teacher.get('任务编号', '100')
67
+ name = sanitize_name(teacher.get('任务名称', 'untitled'))
68
+ folder_name = f'{category.lower()}{number}_{name}'
69
+ publish_target = TEMPLATES_DIR / folder_name
70
+
71
+ if not publish_target.is_dir():
72
+ print(f'❌ 发布目标目录不存在: {publish_target}')
73
+ sys.exit(1)
74
+
75
+ # ── Step 3: Publish to CDN ────────────────────────────────────────────
76
+ print('\n══ Step 3: 上传 CDN ════════════════════════════════════')
77
+ subprocess.run([sys.executable, str(PUBLISH_SCRIPT), str(publish_target)], check=True)
78
+
79
+ print('\n✅ 发布完成!')
80
+ print(f' 模板目录: {publish_target}')
81
+
82
+
83
+ if __name__ == '__main__':
84
+ main()
@@ -1,5 +1,5 @@
1
1
  {
2
- "index_updated_at": "2026-04-22T16:42:59Z",
2
+ "index_updated_at": "2026-04-22T17:22:47Z",
3
3
  "templates": {
4
4
  "696de592": {
5
5
  "id": "696de592",
@@ -7,9 +7,9 @@
7
7
  "编号": "100",
8
8
  "名称": "给依然老师设计一个AI画像",
9
9
  "文件夹名": "a100_给依然老师设计一个AI画像",
10
- "version": "v1",
11
- "路径": "templates/a100_给依然老师设计一个AI画像/v1",
12
- "入口文件": "templates/a100_给依然老师设计一个AI画像/v1/index.html",
10
+ "version": "v5",
11
+ "路径": "templates/a100_给依然老师设计一个AI画像/v5",
12
+ "入口文件": "templates/a100_给依然老师设计一个AI画像/v5/index.html",
13
13
  "一句话说明": "先让 AI 生成一个老师形象,再用网页把它展示出来,重点练习描述和小修改。",
14
14
  "主能力标签": "表达构建",
15
15
  "任务类型标签": "视听表达",
@@ -26,7 +26,7 @@
26
26
  "表达构建",
27
27
  "视听表达"
28
28
  ],
29
- "updated_at": "2026-04-22T15:55:39Z"
29
+ "updated_at": "2026-04-22T17:22:41Z"
30
30
  },
31
31
  "d0ff11ee": {
32
32
  "id": "d0ff11ee",
@@ -34,9 +34,9 @@
34
34
  "编号": "101",
35
35
  "名称": "做3张同主题图片",
36
36
  "文件夹名": "a101_做3张同主题图片",
37
- "version": "v1",
38
- "路径": "templates/a101_做3张同主题图片/v1",
39
- "入口文件": "templates/a101_做3张同主题图片/v1/index.html",
37
+ "version": "v2",
38
+ "路径": "templates/a101_做3张同主题图片/v2",
39
+ "入口文件": "templates/a101_做3张同主题图片/v2/index.html",
40
40
  "一句话说明": "先确定一个有趣的主题,再用 AI 生成 3 张风格统一、但情节不同的系列图片。",
41
41
  "主能力标签": "表达构建",
42
42
  "任务类型标签": "视听表达",
@@ -52,7 +52,7 @@
52
52
  "表达构建",
53
53
  "视听表达"
54
54
  ],
55
- "updated_at": "2026-04-22T15:55:40Z"
55
+ "updated_at": "2026-04-22T17:15:44Z"
56
56
  },
57
57
  "d48d94b6": {
58
58
  "id": "d48d94b6",
@@ -60,9 +60,9 @@
60
60
  "编号": "102",
61
61
  "名称": "图片资源展示",
62
62
  "文件夹名": "a102_图片资源展示",
63
- "version": "v1",
64
- "路径": "templates/a102_图片资源展示/v1",
65
- "入口文件": "templates/a102_图片资源展示/v1/index.html",
63
+ "version": "v2",
64
+ "路径": "templates/a102_图片资源展示/v2",
65
+ "入口文件": "templates/a102_图片资源展示/v2/index.html",
66
66
  "一句话说明": "把图片放到网页上,做成一个方便点击查看的小展示页。",
67
67
  "主能力标签": "第二能力:表达构建",
68
68
  "任务类型标签": "视听表达",
@@ -78,7 +78,7 @@
78
78
  "第二能力:表达构建",
79
79
  "视听表达"
80
80
  ],
81
- "updated_at": "2026-04-22T15:55:40Z"
81
+ "updated_at": "2026-04-22T17:15:47Z"
82
82
  },
83
83
  "e1aab9bf": {
84
84
  "id": "e1aab9bf",
@@ -86,9 +86,9 @@
86
86
  "编号": "103",
87
87
  "名称": "做一个介绍页面",
88
88
  "文件夹名": "a103_做一个介绍页面",
89
- "version": "v1",
90
- "路径": "templates/a103_做一个介绍页面/v1",
91
- "入口文件": "templates/a103_做一个介绍页面/v1/index.html",
89
+ "version": "v2",
90
+ "路径": "templates/a103_做一个介绍页面/v2",
91
+ "入口文件": "templates/a103_做一个介绍页面/v2/index.html",
92
92
  "一句话说明": "用一张图片加一段文字,做一个属于自己的介绍页面,练一练图文组合的技巧。",
93
93
  "主能力标签": "表达构建",
94
94
  "任务类型标签": "视听表达",
@@ -104,7 +104,7 @@
104
104
  "表达构建",
105
105
  "视听表达"
106
106
  ],
107
- "updated_at": "2026-04-22T15:55:40Z"
107
+ "updated_at": "2026-04-22T17:15:55Z"
108
108
  },
109
109
  "3c61e07d": {
110
110
  "id": "3c61e07d",
@@ -112,9 +112,9 @@
112
112
  "编号": "104",
113
113
  "名称": "做一个会出招的神奇按钮",
114
114
  "文件夹名": "a104_做一个会出招的神奇按钮",
115
- "version": "v1",
116
- "路径": "templates/a104_做一个会出招的神奇按钮/v1",
117
- "入口文件": "templates/a104_做一个会出招的神奇按钮/v1/index.html",
115
+ "version": "v3",
116
+ "路径": "templates/a104_做一个会出招的神奇按钮/v3",
117
+ "入口文件": "templates/a104_做一个会出招的神奇按钮/v3/index.html",
118
118
  "一句话说明": "先试试按钮效果,再改一点,最后加一个你自己的新按钮。",
119
119
  "主能力标签": "迭代推进",
120
120
  "任务类型标签": "游戏机制",
@@ -132,7 +132,7 @@
132
132
  "迭代推进",
133
133
  "游戏机制"
134
134
  ],
135
- "updated_at": "2026-04-22T15:55:40Z"
135
+ "updated_at": "2026-04-22T17:22:44Z"
136
136
  },
137
137
  "c360e192": {
138
138
  "id": "c360e192",
@@ -140,9 +140,9 @@
140
140
  "编号": "100",
141
141
  "名称": "做一个按钮页面",
142
142
  "文件夹名": "b100_做一个按钮页面",
143
- "version": "v1",
144
- "路径": "templates/b100_做一个按钮页面/v1",
145
- "入口文件": "templates/b100_做一个按钮页面/v1/index.html",
143
+ "version": "v2",
144
+ "路径": "templates/b100_做一个按钮页面/v2",
145
+ "入口文件": "templates/b100_做一个按钮页面/v2/index.html",
146
146
  "一句话说明": "亲手做一个会“变魔术”的按钮,学习网页是如何接收指令并产生变化的。",
147
147
  "主能力标签": "表达构建",
148
148
  "任务类型标签": "游戏机制",
@@ -158,22 +158,22 @@
158
158
  "表达构建",
159
159
  "游戏机制"
160
160
  ],
161
- "updated_at": "2026-04-22T15:55:41Z"
161
+ "updated_at": "2026-04-22T17:16:00Z"
162
162
  },
163
163
  "8a7e39dd": {
164
164
  "id": "8a7e39dd",
165
165
  "系列": "B",
166
- "编号": "701",
166
+ "编号": "101",
167
167
  "名称": "会跳舞的机器人",
168
- "文件夹名": "b701_会跳舞的机器人",
169
- "version": "v1",
170
- "路径": "templates/b701_会跳舞的机器人/v1",
171
- "入口文件": "templates/b701_会跳舞的机器人/v1/index.html",
168
+ "文件夹名": "b101_会跳舞的机器人",
169
+ "version": "v2",
170
+ "路径": "templates/b101_会跳舞的机器人/v2",
171
+ "入口文件": "templates/b101_会跳舞的机器人/v2/index.html",
172
172
  "一句话说明": "先把机器人视频放到网页上,再配上音乐,最后调一调播放效果,让机器人更像在跳舞。",
173
173
  "主能力标签": "表达构建",
174
174
  "任务类型标签": "视听表达",
175
175
  "关键词": [
176
- "b701_会跳舞的机器人",
176
+ "b101_会跳舞的机器人",
177
177
  "先把机器人视频放到网页上,再配上音乐,最后调一调播放效果,让机器人更像在跳舞。",
178
178
  "已经能开始动手,但还不太会把多种素材组织到一起的学生",
179
179
  "会做简单网页,但还不太会处理视频、音乐和动画配合的学生",
@@ -186,7 +186,7 @@
186
186
  "表达构建",
187
187
  "视听表达"
188
188
  ],
189
- "updated_at": "2026-04-22T16:42:48Z"
189
+ "updated_at": "2026-04-22T16:52:16Z"
190
190
  },
191
191
  "6490af0a": {
192
192
  "id": "6490af0a",
@@ -194,9 +194,9 @@
194
194
  "编号": "100",
195
195
  "名称": "给小组作品做一次小修改",
196
196
  "文件夹名": "c100_给小组作品做一次小修改",
197
- "version": "v1",
198
- "路径": "templates/c100_给小组作品做一次小修改/v1",
199
- "入口文件": "templates/c100_给小组作品做一次小修改/v1/index.html",
197
+ "version": "v2",
198
+ "路径": "templates/c100_给小组作品做一次小修改/v2",
199
+ "入口文件": "templates/c100_给小组作品做一次小修改/v2/index.html",
200
200
  "一句话说明": "先看这 3 个小组作品,找出一个你最想改的小地方,再把这个修改要求说给 AI。",
201
201
  "主能力标签": "问题判断",
202
202
  "任务类型标签": "改编优化",
@@ -214,7 +214,7 @@
214
214
  "问题判断",
215
215
  "改编优化"
216
216
  ],
217
- "updated_at": "2026-04-22T15:55:41Z"
217
+ "updated_at": "2026-04-22T17:16:03Z"
218
218
  }
219
219
  }
220
220
  }
@@ -4,72 +4,72 @@
4
4
 
5
5
  ## A100 给依然老师设计一个AI画像
6
6
  - ID:696de592
7
- - 版本:v1
8
- - 路径:templates/a100_给依然老师设计一个AI画像/v1
9
- - 入口文件:templates/a100_给依然老师设计一个AI画像/v1/index.html
7
+ - 版本:v5
8
+ - 路径:templates/a100_给依然老师设计一个AI画像/v5
9
+ - 入口文件:templates/a100_给依然老师设计一个AI画像/v5/index.html
10
10
  - 主能力标签:表达构建
11
11
  - 任务类型标签:视听表达
12
12
  - 关键词:a100_给依然老师设计一个AI画像, 先让 AI 生成一个老师形象,再用网页把它展示出来,重点练习描述和小修改。, 初次接触, 需要明确目标, 持续迭代, 围绕明确对象生成形象, 把人物图片放进网页中完成展示, 通过小幅修改让作品逐步变好, 给依然老师设计一个AI画像, 表达构建, 视听表达
13
13
 
14
14
  ## A101 做3张同主题图片
15
15
  - ID:d0ff11ee
16
- - 版本:v1
17
- - 路径:templates/a101_做3张同主题图片/v1
18
- - 入口文件:templates/a101_做3张同主题图片/v1/index.html
16
+ - 版本:v2
17
+ - 路径:templates/a101_做3张同主题图片/v2
18
+ - 入口文件:templates/a101_做3张同主题图片/v2/index.html
19
19
  - 主能力标签:表达构建
20
20
  - 任务类型标签:视听表达
21
21
  - 关键词:a101_做3张同主题图片, 先确定一个有趣的主题,再用 AI 生成 3 张风格统一、但情节不同的系列图片。, 初次接触, 需要明确目标, 练习通过提示词锁定画面风格, 理解作品一致性的价值, 初步接触提示词的模块化修改, 做3张同主题图片, 表达构建, 视听表达
22
22
 
23
23
  ## A102 图片资源展示
24
24
  - ID:d48d94b6
25
- - 版本:v1
26
- - 路径:templates/a102_图片资源展示/v1
27
- - 入口文件:templates/a102_图片资源展示/v1/index.html
25
+ - 版本:v2
26
+ - 路径:templates/a102_图片资源展示/v2
27
+ - 入口文件:templates/a102_图片资源展示/v2/index.html
28
28
  - 主能力标签:第二能力:表达构建
29
29
  - 任务类型标签:视听表达
30
30
  - 关键词:a102_图片资源展示, 把图片放到网页上,做成一个方便点击查看的小展示页。, 刚开始接触网页展示的学生, 需要先从添加素材开始动手的学生, 把本地图片放进网页里, 理解图片展示卡片的基本结构, 为后续继续扩充图片资源做准备, 图片资源展示, 第二能力:表达构建, 视听表达
31
31
 
32
32
  ## A103 做一个介绍页面
33
33
  - ID:e1aab9bf
34
- - 版本:v1
35
- - 路径:templates/a103_做一个介绍页面/v1
36
- - 入口文件:templates/a103_做一个介绍页面/v1/index.html
34
+ - 版本:v2
35
+ - 路径:templates/a103_做一个介绍页面/v2
36
+ - 入口文件:templates/a103_做一个介绍页面/v2/index.html
37
37
  - 主能力标签:表达构建
38
38
  - 任务类型标签:视听表达
39
39
  - 关键词:a103_做一个介绍页面, 用一张图片加一段文字,做一个属于自己的介绍页面,练一练图文组合的技巧。, 初次接触网页制作, 有一点基础想练排版, 图片与文字的组合方式, 网页结构的基本层次感, 排版的视觉优先级, 做一个介绍页面, 表达构建, 视听表达
40
40
 
41
41
  ## A104 做一个会出招的神奇按钮
42
42
  - ID:3c61e07d
43
- - 版本:v1
44
- - 路径:templates/a104_做一个会出招的神奇按钮/v1
45
- - 入口文件:templates/a104_做一个会出招的神奇按钮/v1/index.html
43
+ - 版本:v3
44
+ - 路径:templates/a104_做一个会出招的神奇按钮/v3
45
+ - 入口文件:templates/a104_做一个会出招的神奇按钮/v3/index.html
46
46
  - 主能力标签:迭代推进
47
47
  - 任务类型标签:游戏机制
48
48
  - 关键词:a104_做一个会出招的神奇按钮, 先试试按钮效果,再改一点,最后加一个你自己的新按钮。, 想先动手再思考的学生, 刚开始学网页互动的学生, 容易卡在空白页不知从哪开始的学生, 先运行现成示例,快速进入任务, 从已有功能里挑一个做小改动, 理解一个按钮对应一个功能, 把新增功能接入现有页面结构, 做一个会出招的神奇按钮, 迭代推进, 游戏机制
49
49
 
50
50
  ## B100 做一个按钮页面
51
51
  - ID:c360e192
52
- - 版本:v1
53
- - 路径:templates/b100_做一个按钮页面/v1
54
- - 入口文件:templates/b100_做一个按钮页面/v1/index.html
52
+ - 版本:v2
53
+ - 路径:templates/b100_做一个按钮页面/v2
54
+ - 入口文件:templates/b100_做一个按钮页面/v2/index.html
55
55
  - 主能力标签:表达构建
56
56
  - 任务类型标签:游戏机制
57
57
  - 关键词:b100_做一个按钮页面, 亲手做一个会“变魔术”的按钮,学习网页是如何接收指令并产生变化的。, 喜欢做项目, 需要明确目标, 掌握基础的 JavaScript 点击事件绑定, 理解 HTML/CSS/JS 三者如何协作完成交互, 学习利用 CSS Class 切换来实现视觉变化, 做一个按钮页面, 表达构建, 游戏机制
58
58
 
59
- ## B701 会跳舞的机器人
59
+ ## B101 会跳舞的机器人
60
60
  - ID:8a7e39dd
61
- - 版本:v1
62
- - 路径:templates/b701_会跳舞的机器人/v1
63
- - 入口文件:templates/b701_会跳舞的机器人/v1/index.html
61
+ - 版本:v2
62
+ - 路径:templates/b101_会跳舞的机器人/v2
63
+ - 入口文件:templates/b101_会跳舞的机器人/v2/index.html
64
64
  - 主能力标签:表达构建
65
65
  - 任务类型标签:视听表达
66
- - 关键词:b701_会跳舞的机器人, 先把机器人视频放到网页上,再配上音乐,最后调一调播放效果,让机器人更像在跳舞。, 已经能开始动手,但还不太会把多种素材组织到一起的学生, 会做简单网页,但还不太会处理视频、音乐和动画配合的学生, 想从静态页面进入多媒体网页表达的学生, 把机器人视频放进网页中, 让视频和音乐形成基本配合, 尝试处理循环播放和播放节奏, 让网页从静态展示变成更有动态感的作品, 会跳舞的机器人, 表达构建, 视听表达
66
+ - 关键词:b101_会跳舞的机器人, 先把机器人视频放到网页上,再配上音乐,最后调一调播放效果,让机器人更像在跳舞。, 已经能开始动手,但还不太会把多种素材组织到一起的学生, 会做简单网页,但还不太会处理视频、音乐和动画配合的学生, 想从静态页面进入多媒体网页表达的学生, 把机器人视频放进网页中, 让视频和音乐形成基本配合, 尝试处理循环播放和播放节奏, 让网页从静态展示变成更有动态感的作品, 会跳舞的机器人, 表达构建, 视听表达
67
67
 
68
68
  ## C100 给小组作品做一次小修改
69
69
  - ID:6490af0a
70
- - 版本:v1
71
- - 路径:templates/c100_给小组作品做一次小修改/v1
72
- - 入口文件:templates/c100_给小组作品做一次小修改/v1/index.html
70
+ - 版本:v2
71
+ - 路径:templates/c100_给小组作品做一次小修改/v2
72
+ - 入口文件:templates/c100_给小组作品做一次小修改/v2/index.html
73
73
  - 主能力标签:问题判断
74
74
  - 任务类型标签:改编优化
75
75
  - 关键词:c100_给小组作品做一次小修改, 先看这 3 个小组作品,找出一个你最想改的小地方,再把这个修改要求说给 AI。, 已经能看懂图片内容,但不太会说哪里有问题的学生, 会说喜欢或不喜欢,但不太会提出具体修改点的学生, 已经能做第一版作品,想练习小步修改的学生, 先发现一个具体问题, 把大问题收成一个最小修改点, 用简单的话把修改要求说清楚, 比较修改前后有没有更接近自己的想法, 给小组作品做一次小修改, 问题判断, 改编优化
@@ -0,0 +1,196 @@
1
+ # 模板系统设计经验总结
2
+
3
+ ## 一、版本化目录结构
4
+
5
+ ### 问题
6
+ CDN 有缓存,更新模板后旧内容仍被访问。
7
+
8
+ ### 方案
9
+ ```
10
+ templates/
11
+ a104_做一个会出招的神奇按钮/
12
+ v1/ ← 每次更新递增版本号,CDN 路径变了,缓存自然失效
13
+ v2/
14
+ ```
15
+
16
+ ### 经验
17
+ - **本地只保留一个版本**:下载新版前先删旧版目录,避免就绪状态歧义
18
+ - **目录存在即就绪**:不需要额外标记文件(`.sync-done`),目录本身就是状态
19
+ - **原子性替换**:下载到 `.tmp/`,完成后 `rename .tmp/ → v1/`,不会出现"半完成"状态
20
+
21
+ ---
22
+
23
+ ## 二、稳定 ID 设计
24
+
25
+ ### 问题
26
+ 模板可能改编号(A100 → A105)、改名,如果用路径/编号做唯一标识会丢失对应关系。
27
+
28
+ ### 方案
29
+ ```json
30
+ // __teacher__.json
31
+ {
32
+ "_id": "696de592", // 8位hex,颁发一次永不变
33
+ "_version": 1 // 每次更新递增
34
+ }
35
+ ```
36
+
37
+ ### 经验
38
+ - ID 在 `move` 阶段颁发,之后不再改变
39
+ - CDN index 以 `_id` 为 key(平铺字典),而不是 `{系列: {编号: record}}` 嵌套结构
40
+ - 本地/CDN 比对:用 `_id` 找记录,再比较 `version` 字段判断是否需要更新
41
+
42
+ ---
43
+
44
+ ## 三、非阻塞同步 + 轮询进度
45
+
46
+ ### 问题
47
+ 下载几十个文件要几分钟,HTTP handler 不能阻塞。
48
+
49
+ ### 方案
50
+ ```python
51
+ # 立刻写 index(前端列表立刻出现),然后后台下载
52
+ with open(TEMPLATE_LOCAL_INDEX, 'w') as f:
53
+ json.dump(cdn_index, f)
54
+
55
+ t = threading.Thread(target=_do_sync_templates, args=(...), daemon=True)
56
+ t.start()
57
+ self._send_json({'syncing': True, 'total': len(pending)})
58
+ ```
59
+ 前端每 3 秒轮询 `/api/sync-status`。
60
+
61
+ ### 经验
62
+ - **先写 index 再下载**:用户立刻看到列表,下载在后台进行
63
+ - **守卫变量防重复轮询**:`if (_pollTimer) return`
64
+ - **轮询 vs WebSocket**:简单场景轮询够用,不要过度设计
65
+
66
+ ---
67
+
68
+ ## 四、前端就绪状态简化
69
+
70
+ ### 反面教材(复杂版)
71
+ 维护 `_readyFolders` Set + `_rowMap` + `updateActionBtns()` + 开屏预取状态,
72
+ 按钮 disabled/opacity 联动,约 40 行状态管理代码。
73
+
74
+ ### 正确做法(简单版)
75
+ - 按钮永远可点
76
+ - 点击后服务端检查就绪状态,未就绪返回 `{code: 'not_ready'}`
77
+ - 前端只需在 `.then()` 里判断 `res.code === 'not_ready'` 显示提示
78
+
79
+ ```js
80
+ if (res.code === 'not_ready') {
81
+ setFooterStatus('⟳ 模板文件下载中,完成后即可使用', '#f59e0b');
82
+ }
83
+ ```
84
+
85
+ ### 经验
86
+ **让服务端做校验,前端做展示**,不要在前端维护服务端状态的镜像。
87
+
88
+ ---
89
+
90
+ ## 五、同一文件存在两个副本
91
+
92
+ ### 问题
93
+ `deploy_to_workspace.py` 存在于两个路径:
94
+ - `.openclaw/skills/.../deploy_to_workspace.py` ← 服务端实际运行
95
+ - `.openclaw/workspace-yiranclaw/myclaw/skills/.../deploy_to_workspace.py` ← 源文件
96
+
97
+ `mc patch` 会用源文件覆盖服务端文件,导致修改被还原。
98
+
99
+ ### 经验
100
+ - **改脚本必须改两处**,或者建立符号链接
101
+ - 发现改动被还原时,先查是哪个路径在被覆盖,再两处同步修改
102
+
103
+ ---
104
+
105
+ ## 六、Pipeline 职责拆分
106
+
107
+ ### 原则:每个脚本只做一件事
108
+
109
+ | 脚本 | 职责 |
110
+ |------|------|
111
+ | `identify_template.py` | 颁发 `_id`、校准编号、设置 `_version` |
112
+ | `move_template_task.py` | 调用 identify、创建 `v{N}/` 子目录、复制文件 |
113
+ | `build_template_index.py` | 扫描本地目录、生成 JSON index |
114
+ | `publish_template.py` | 上传到 CDN(带版本路径)、上传 index |
115
+ | `migrate_templates.py` | 一次性迁移旧结构到新结构 |
116
+
117
+ ### 经验
118
+ - `move` 不再删除原文件夹(改为复制),避免误操作丢失源文件
119
+ - 版本号在 `move` 阶段确定,`publish` 不决定版本号
120
+ - 迁移脚本加 `--dry-run` 参数,先验证再执行
121
+
122
+ ---
123
+
124
+ ## 七、API 设计:参数复用代替接口重复
125
+
126
+ ### 问题
127
+ "复制到 playgrounds" 和 "创建新 workspace" 流程完全相同,只是目标 workspace 名不同。
128
+
129
+ ### 反面做法
130
+ 新增 `/api/template/new-workspace` 接口,重复了 90% 的代码。
131
+
132
+ ### 正确做法
133
+ ```python
134
+ # POST /api/template/deploy
135
+ # body: {"folder": "...", "agent": "playgrounds"} ← 已有 workspace
136
+ # body: {"folder": "..."} ← 不传则自动生成唯一名
137
+ agent_name = body.get('agent') or '{}-{}-{}'.format(series, version, hhmm)
138
+ ```
139
+
140
+ ### 经验
141
+ **加参数,不加接口**。两个行为只有一个变量不同时,用参数区分而不是新建接口。
142
+
143
+ ---
144
+
145
+ ## 八、mc 命令扩展
146
+
147
+ ### 方法
148
+ 在 `index.js` 里添加两处:
149
+
150
+ ```js
151
+ // 1. 路由
152
+ } else if (command === 'sync-templates') {
153
+ runSyncTemplates();
154
+
155
+ // 2. 函数(调本地 API,轮询进度)
156
+ function runSyncTemplates() {
157
+ const http = require('http');
158
+ const apiPort = process.platform === 'linux' ? '8080' : '18800';
159
+ // apiGet → /api/sync-templates → 轮询 /api/sync-status
160
+ }
161
+ ```
162
+
163
+ ### 经验
164
+ - `mc` 命令本质是 Node.js 脚本,扩展成本极低
165
+ - 本地 API 端口:Mac=18800,Linux=8080
166
+ - 轮询用 `setTimeout` 递归,而不是 `setInterval`(更容易控制退出)
167
+
168
+ ---
169
+
170
+ ## 九、命名规范
171
+
172
+ ### 实例目录命名
173
+ ```
174
+ {业务名}_{HH:MM}
175
+ 做一个会出招的神奇按钮_1911
176
+ ```
177
+
178
+ ### 新建 workspace 命名
179
+ ```
180
+ {作品编号}-{版本号}-{小时分钟}
181
+ a104-v1-1911
182
+ → workspace-a104-v1-1911
183
+ ```
184
+
185
+ ### 原则
186
+ - 去掉冗余信息(日期、系列前缀 `a104` 在实例名里不需要)
187
+ - 保留区分信息(时间保证唯一,版本号便于追溯)
188
+ - 用 `-` 分隔 workspace 名的各段,用 `_` 分隔实例名各段
189
+
190
+ ---
191
+
192
+ ## 十、window.open vs window.location.href
193
+
194
+ - `window.open('url', '_blank')` 会被浏览器弹窗拦截器阻止(非用户直接触发的点击)
195
+ - setTimeout 内的跳转用 `window.location.href` 更可靠
196
+ - 如果必须新标签,需要在用户点击的同步代码里调用 `window.open`