cubing 0.57.4 → 0.58.0

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.
@@ -268,6 +268,12 @@ async function unsafeEncryptBlockWithIV(key, plaintextBlock, iv) {
268
268
  );
269
269
  return cryptoResult.slice(0, blockSize);
270
270
  }
271
+ async function unsafeEncryptBlock(key, plaintextBlock) {
272
+ return (await unsafeEncryptBlockWithIV(key, plaintextBlock, zeros)).slice(
273
+ 0,
274
+ blockSize
275
+ );
276
+ }
271
277
  async function unsafeDecryptBlock(key, ciphertextBlock) {
272
278
  const paddingBlock = await unsafeEncryptBlockWithIV(
273
279
  key,
@@ -288,6 +294,52 @@ async function unsafeDecryptBlock(key, ciphertextBlock) {
288
294
  return cryptoResult.slice(0, blockSize);
289
295
  }
290
296
 
297
+ // src/cubing/bluetooth/smart-puzzle/common.ts
298
+ var reidEdgeOrder = "UF UR UB UL DF DR DB DL FR FL BR BL".split(" ");
299
+ var reidCornerOrder = "UFR URB UBL ULF DRF DFL DLB DBR".split(" ");
300
+ function rotateLeft(s, i) {
301
+ return s.slice(i) + s.slice(0, i);
302
+ }
303
+ var pieceMap = {};
304
+ reidEdgeOrder.forEach((edge, idx) => {
305
+ for (let i = 0; i < 2; i++) {
306
+ pieceMap[rotateLeft(edge, i)] = { piece: idx, orientation: i };
307
+ }
308
+ });
309
+ reidCornerOrder.forEach((corner, idx) => {
310
+ for (let i = 0; i < 3; i++) {
311
+ pieceMap[rotateLeft(corner, i)] = { piece: idx, orientation: i };
312
+ }
313
+ });
314
+ function getPatternData(stickers, faceOrder3, edgeMappings, cornerMappings) {
315
+ const patternData = {
316
+ CORNERS: {
317
+ pieces: [],
318
+ orientation: []
319
+ },
320
+ EDGES: {
321
+ pieces: [],
322
+ orientation: []
323
+ },
324
+ CENTERS: {
325
+ pieces: [0, 1, 2, 3, 4, 5],
326
+ orientation: [0, 0, 0, 0, 0, 0],
327
+ orientationMod: [1, 1, 1, 1, 1, 1]
328
+ }
329
+ };
330
+ for (const cornerMapping of cornerMappings) {
331
+ const pieceInfo = pieceMap[cornerMapping.map((i) => faceOrder3[stickers[i]]).join("")];
332
+ patternData["CORNERS"].pieces.push(pieceInfo.piece);
333
+ patternData["CORNERS"].orientation.push(pieceInfo.orientation);
334
+ }
335
+ for (const edgeMapping of edgeMappings) {
336
+ const pieceInfo = pieceMap[edgeMapping.map((i) => faceOrder3[stickers[i]]).join("")];
337
+ patternData["EDGES"].pieces.push(pieceInfo.piece);
338
+ patternData["EDGES"].orientation.push(pieceInfo.orientation);
339
+ }
340
+ return patternData;
341
+ }
342
+
291
343
  // src/cubing/bluetooth/smart-puzzle/gan.ts
292
344
  var DEFAULT_INTERVAL_MS = 150;
293
345
  var MAX_LATEST_MOVES = 6;
@@ -454,22 +506,6 @@ function buf2hex(buffer) {
454
506
  (x) => `00${x.toString(16)}`.slice(-2)
455
507
  ).join(" ");
456
508
  }
457
- var reidEdgeOrder = "UF UR UB UL DF DR DB DL FR FL BR BL".split(" ");
458
- var reidCornerOrder = "UFR URB UBL ULF DRF DFL DLB DBR".split(" ");
459
- function rotateLeft(s, i) {
460
- return s.slice(i) + s.slice(0, i);
461
- }
462
- var pieceMap = {};
463
- reidEdgeOrder.forEach((edge, idx) => {
464
- for (let i = 0; i < 2; i++) {
465
- pieceMap[rotateLeft(edge, i)] = { piece: idx, orientation: i };
466
- }
467
- });
468
- reidCornerOrder.forEach((corner, idx) => {
469
- for (let i = 0; i < 3; i++) {
470
- pieceMap[rotateLeft(corner, i)] = { piece: idx, orientation: i };
471
- }
472
- });
473
509
  var gan356iCornerMappings = [
474
510
  [0, 21, 15],
475
511
  [5, 13, 47],
@@ -625,33 +661,15 @@ var GanCube = class _GanCube extends BluetoothPuzzle {
625
661
  v >>= 3;
626
662
  }
627
663
  }
628
- const patternData = {
629
- CORNERS: {
630
- pieces: [],
631
- orientation: []
632
- },
633
- EDGES: {
634
- pieces: [],
635
- orientation: []
636
- },
637
- CENTERS: {
638
- pieces: [0, 1, 2, 3, 4, 5],
639
- orientation: [0, 0, 0, 0, 0, 0],
640
- orientationMod: [1, 1, 1, 1, 1, 1]
641
- // TODO
642
- }
643
- };
644
- for (const cornerMapping of gan356iCornerMappings) {
645
- const pieceInfo = pieceMap[cornerMapping.map((i) => faceOrder[stickers[i]]).join("")];
646
- patternData["CORNERS"].pieces.push(pieceInfo.piece);
647
- patternData["CORNERS"].orientation.push(pieceInfo.orientation);
648
- }
649
- for (const edgeMapping of gan356iEdgeMappings) {
650
- const pieceInfo = pieceMap[edgeMapping.map((i) => faceOrder[stickers[i]]).join("")];
651
- patternData["EDGES"].pieces.push(pieceInfo.piece);
652
- patternData["EDGES"].orientation.push(pieceInfo.orientation);
653
- }
654
- return new KPattern(this.kpuzzle, patternData);
664
+ return new KPattern(
665
+ this.kpuzzle,
666
+ getPatternData(
667
+ stickers,
668
+ faceOrder,
669
+ gan356iEdgeMappings,
670
+ gan356iCornerMappings
671
+ )
672
+ );
655
673
  }
656
674
  async faceletStatus1Characteristic() {
657
675
  this.cachedFaceletStatus1Characteristic = this.cachedFaceletStatus1Characteristic || this.service.getCharacteristic(UUIDs.faceletStatus1Characteristic);
@@ -1198,11 +1216,637 @@ var heykubeConfig = {
1198
1216
  optionalServices: [UUIDs4.heykubeService]
1199
1217
  };
1200
1218
 
1219
+ // src/cubing/bluetooth/smart-puzzle/qiyi.ts
1220
+ var UUIDs5 = {
1221
+ qiyiMainService: 65520,
1222
+ qiyiMainCharacteristic: 65526
1223
+ };
1224
+ var qiyiMoveToBlockMove = {
1225
+ 1: new Move("L", -1),
1226
+ 2: new Move("L"),
1227
+ 3: new Move("R", -1),
1228
+ 4: new Move("R"),
1229
+ 5: new Move("D", -1),
1230
+ 6: new Move("D"),
1231
+ 7: new Move("U", -1),
1232
+ 8: new Move("U"),
1233
+ 9: new Move("F", -1),
1234
+ 10: new Move("F"),
1235
+ 11: new Move("B", -1),
1236
+ 12: new Move("B")
1237
+ };
1238
+ var faceOrder2 = "LRDUFB";
1239
+ var qiyiCornerMappings = [
1240
+ [8, 20, 9],
1241
+ // UFR,
1242
+ [2, 11, 45],
1243
+ // URB,
1244
+ [0, 47, 36],
1245
+ // UBL,
1246
+ [6, 38, 18],
1247
+ // ULF,
1248
+ [29, 15, 26],
1249
+ // DRF,
1250
+ [27, 24, 44],
1251
+ // DFL,
1252
+ [33, 42, 53],
1253
+ // DLB,
1254
+ [35, 51, 17]
1255
+ // DBR,
1256
+ ];
1257
+ var qiyiEdgeMappings = [
1258
+ [7, 19],
1259
+ // UF,
1260
+ [5, 10],
1261
+ // UR,
1262
+ [1, 46],
1263
+ // UB,
1264
+ [3, 37],
1265
+ // UL,
1266
+ [28, 25],
1267
+ // DF,
1268
+ [32, 16],
1269
+ // DR,
1270
+ [34, 52],
1271
+ // DB,
1272
+ [30, 43],
1273
+ // DL,
1274
+ [23, 12],
1275
+ // FR,
1276
+ [21, 41],
1277
+ // FL,
1278
+ [48, 14],
1279
+ // BR,
1280
+ [50, 39]
1281
+ // BL,
1282
+ ];
1283
+ function generateChecksum(data) {
1284
+ const TABLE = new Uint16Array([
1285
+ 0,
1286
+ 49345,
1287
+ 49537,
1288
+ 320,
1289
+ 49921,
1290
+ 960,
1291
+ 640,
1292
+ 49729,
1293
+ 50689,
1294
+ 1728,
1295
+ 1920,
1296
+ 51009,
1297
+ 1280,
1298
+ 50625,
1299
+ 50305,
1300
+ 1088,
1301
+ 52225,
1302
+ 3264,
1303
+ 3456,
1304
+ 52545,
1305
+ 3840,
1306
+ 53185,
1307
+ 52865,
1308
+ 3648,
1309
+ 2560,
1310
+ 51905,
1311
+ 52097,
1312
+ 2880,
1313
+ 51457,
1314
+ 2496,
1315
+ 2176,
1316
+ 51265,
1317
+ 55297,
1318
+ 6336,
1319
+ 6528,
1320
+ 55617,
1321
+ 6912,
1322
+ 56257,
1323
+ 55937,
1324
+ 6720,
1325
+ 7680,
1326
+ 57025,
1327
+ 57217,
1328
+ 8e3,
1329
+ 56577,
1330
+ 7616,
1331
+ 7296,
1332
+ 56385,
1333
+ 5120,
1334
+ 54465,
1335
+ 54657,
1336
+ 5440,
1337
+ 55041,
1338
+ 6080,
1339
+ 5760,
1340
+ 54849,
1341
+ 53761,
1342
+ 4800,
1343
+ 4992,
1344
+ 54081,
1345
+ 4352,
1346
+ 53697,
1347
+ 53377,
1348
+ 4160,
1349
+ 61441,
1350
+ 12480,
1351
+ 12672,
1352
+ 61761,
1353
+ 13056,
1354
+ 62401,
1355
+ 62081,
1356
+ 12864,
1357
+ 13824,
1358
+ 63169,
1359
+ 63361,
1360
+ 14144,
1361
+ 62721,
1362
+ 13760,
1363
+ 13440,
1364
+ 62529,
1365
+ 15360,
1366
+ 64705,
1367
+ 64897,
1368
+ 15680,
1369
+ 65281,
1370
+ 16320,
1371
+ 16e3,
1372
+ 65089,
1373
+ 64001,
1374
+ 15040,
1375
+ 15232,
1376
+ 64321,
1377
+ 14592,
1378
+ 63937,
1379
+ 63617,
1380
+ 14400,
1381
+ 10240,
1382
+ 59585,
1383
+ 59777,
1384
+ 10560,
1385
+ 60161,
1386
+ 11200,
1387
+ 10880,
1388
+ 59969,
1389
+ 60929,
1390
+ 11968,
1391
+ 12160,
1392
+ 61249,
1393
+ 11520,
1394
+ 60865,
1395
+ 60545,
1396
+ 11328,
1397
+ 58369,
1398
+ 9408,
1399
+ 9600,
1400
+ 58689,
1401
+ 9984,
1402
+ 59329,
1403
+ 59009,
1404
+ 9792,
1405
+ 8704,
1406
+ 58049,
1407
+ 58241,
1408
+ 9024,
1409
+ 57601,
1410
+ 8640,
1411
+ 8320,
1412
+ 57409,
1413
+ 40961,
1414
+ 24768,
1415
+ 24960,
1416
+ 41281,
1417
+ 25344,
1418
+ 41921,
1419
+ 41601,
1420
+ 25152,
1421
+ 26112,
1422
+ 42689,
1423
+ 42881,
1424
+ 26432,
1425
+ 42241,
1426
+ 26048,
1427
+ 25728,
1428
+ 42049,
1429
+ 27648,
1430
+ 44225,
1431
+ 44417,
1432
+ 27968,
1433
+ 44801,
1434
+ 28608,
1435
+ 28288,
1436
+ 44609,
1437
+ 43521,
1438
+ 27328,
1439
+ 27520,
1440
+ 43841,
1441
+ 26880,
1442
+ 43457,
1443
+ 43137,
1444
+ 26688,
1445
+ 30720,
1446
+ 47297,
1447
+ 47489,
1448
+ 31040,
1449
+ 47873,
1450
+ 31680,
1451
+ 31360,
1452
+ 47681,
1453
+ 48641,
1454
+ 32448,
1455
+ 32640,
1456
+ 48961,
1457
+ 32e3,
1458
+ 48577,
1459
+ 48257,
1460
+ 31808,
1461
+ 46081,
1462
+ 29888,
1463
+ 30080,
1464
+ 46401,
1465
+ 30464,
1466
+ 47041,
1467
+ 46721,
1468
+ 30272,
1469
+ 29184,
1470
+ 45761,
1471
+ 45953,
1472
+ 29504,
1473
+ 45313,
1474
+ 29120,
1475
+ 28800,
1476
+ 45121,
1477
+ 20480,
1478
+ 37057,
1479
+ 37249,
1480
+ 20800,
1481
+ 37633,
1482
+ 21440,
1483
+ 21120,
1484
+ 37441,
1485
+ 38401,
1486
+ 22208,
1487
+ 22400,
1488
+ 38721,
1489
+ 21760,
1490
+ 38337,
1491
+ 38017,
1492
+ 21568,
1493
+ 39937,
1494
+ 23744,
1495
+ 23936,
1496
+ 40257,
1497
+ 24320,
1498
+ 40897,
1499
+ 40577,
1500
+ 24128,
1501
+ 23040,
1502
+ 39617,
1503
+ 39809,
1504
+ 23360,
1505
+ 39169,
1506
+ 22976,
1507
+ 22656,
1508
+ 38977,
1509
+ 34817,
1510
+ 18624,
1511
+ 18816,
1512
+ 35137,
1513
+ 19200,
1514
+ 35777,
1515
+ 35457,
1516
+ 19008,
1517
+ 19968,
1518
+ 36545,
1519
+ 36737,
1520
+ 20288,
1521
+ 36097,
1522
+ 19904,
1523
+ 19584,
1524
+ 35905,
1525
+ 17408,
1526
+ 33985,
1527
+ 34177,
1528
+ 17728,
1529
+ 34561,
1530
+ 18368,
1531
+ 18048,
1532
+ 34369,
1533
+ 33281,
1534
+ 17088,
1535
+ 17280,
1536
+ 33601,
1537
+ 16640,
1538
+ 33217,
1539
+ 32897,
1540
+ 16448
1541
+ ]);
1542
+ let crc = 65535;
1543
+ for (const dataPoint of data) {
1544
+ const xor = (dataPoint ^ crc) & 255;
1545
+ crc >>= 8;
1546
+ crc ^= TABLE[xor];
1547
+ }
1548
+ return crc;
1549
+ }
1550
+ async function prepareMessage(message, aesKey) {
1551
+ const messageCopyForChecksum = structuredClone(message);
1552
+ const checksum = generateChecksum(messageCopyForChecksum);
1553
+ messageCopyForChecksum.push(checksum & 255);
1554
+ messageCopyForChecksum.push(checksum >> 8);
1555
+ const paddedLength = Math.ceil(messageCopyForChecksum.length / 16) * 16;
1556
+ const paddedArray = new Uint8Array([
1557
+ ...messageCopyForChecksum,
1558
+ ...Array(paddedLength - messageCopyForChecksum.length).fill(0)
1559
+ ]);
1560
+ const encryptedMessage = new Uint8Array(paddedLength);
1561
+ for (let i = 0; i < paddedArray.length / 16; i++) {
1562
+ const encryptedBlock = new Uint8Array(
1563
+ await unsafeEncryptBlock(aesKey, paddedArray.slice(i * 16, (i + 1) * 16))
1564
+ );
1565
+ encryptedMessage.set(encryptedBlock, i * 16);
1566
+ }
1567
+ return encryptedMessage;
1568
+ }
1569
+ async function decryptMessage(encryptedMessage, aesKey) {
1570
+ const decryptedMessage = new Uint8Array(encryptedMessage.length);
1571
+ for (let i = 0; i < encryptedMessage.length / 16; i++) {
1572
+ const decryptedBlock = new Uint8Array(
1573
+ await unsafeDecryptBlock(
1574
+ aesKey,
1575
+ encryptedMessage.slice(i * 16, (i + 1) * 16)
1576
+ )
1577
+ );
1578
+ decryptedMessage.set(decryptedBlock, i * 16);
1579
+ }
1580
+ return decryptedMessage;
1581
+ }
1582
+ function getMacAddress(device) {
1583
+ if (device.name === void 0) {
1584
+ return;
1585
+ }
1586
+ return [
1587
+ 204,
1588
+ 163,
1589
+ 0,
1590
+ 0,
1591
+ parseInt(device.name.slice(10, 12), 16),
1592
+ parseInt(device.name.slice(12, 14), 16)
1593
+ ];
1594
+ }
1595
+ var MAX_TIMESTAMP_COUNT = 12;
1596
+ var TIMESTAMP_SCALE = 1.6;
1597
+ var CUBE_HELLO = 2;
1598
+ var STATE_CHANGE = 3;
1599
+ var QiyiCube = class _QiyiCube extends BluetoothPuzzle {
1600
+ constructor(kpuzzle, aesKey, server) {
1601
+ super();
1602
+ this.kpuzzle = kpuzzle;
1603
+ this.aesKey = aesKey;
1604
+ this.server = server;
1605
+ this.sendAppHello();
1606
+ this.startNotifications();
1607
+ this.allTimeStamps = /* @__PURE__ */ new Set();
1608
+ this.allTimeStampsQueue = [];
1609
+ }
1610
+ latestTimestamp;
1611
+ allTimeStamps;
1612
+ // Without this set, moves are constantly duplicated
1613
+ allTimeStampsQueue;
1614
+ stickers = [
1615
+ 3,
1616
+ 3,
1617
+ 3,
1618
+ 3,
1619
+ 3,
1620
+ 3,
1621
+ 3,
1622
+ 3,
1623
+ 3,
1624
+ 1,
1625
+ 1,
1626
+ 1,
1627
+ 1,
1628
+ 1,
1629
+ 1,
1630
+ 1,
1631
+ 1,
1632
+ 1,
1633
+ 4,
1634
+ 4,
1635
+ 4,
1636
+ 4,
1637
+ 4,
1638
+ 4,
1639
+ 4,
1640
+ 4,
1641
+ 4,
1642
+ 2,
1643
+ 2,
1644
+ 2,
1645
+ 2,
1646
+ 2,
1647
+ 2,
1648
+ 2,
1649
+ 2,
1650
+ 2,
1651
+ 0,
1652
+ 0,
1653
+ 0,
1654
+ 0,
1655
+ 0,
1656
+ 0,
1657
+ 0,
1658
+ 0,
1659
+ 0,
1660
+ 5,
1661
+ 5,
1662
+ 5,
1663
+ 5,
1664
+ 5,
1665
+ 5,
1666
+ 5,
1667
+ 5,
1668
+ 5
1669
+ ];
1670
+ batteryLevel = 100;
1671
+ static async connect(server) {
1672
+ const aesKey = await importKey(
1673
+ new Uint8Array([
1674
+ 87,
1675
+ 177,
1676
+ 249,
1677
+ 171,
1678
+ 205,
1679
+ 90,
1680
+ 232,
1681
+ 167,
1682
+ 156,
1683
+ 185,
1684
+ 140,
1685
+ 231,
1686
+ 87,
1687
+ 140,
1688
+ 81,
1689
+ 8
1690
+ ])
1691
+ );
1692
+ return new _QiyiCube(await puzzles["3x3x3"].kpuzzle(), aesKey, server);
1693
+ }
1694
+ async sendAppHello() {
1695
+ const mainService = await this.server.getPrimaryService(
1696
+ UUIDs5.qiyiMainService
1697
+ );
1698
+ const mainCharacteristic = await mainService.getCharacteristic(
1699
+ UUIDs5.qiyiMainCharacteristic
1700
+ );
1701
+ for (let macGuessCounter = 0; macGuessCounter < 8; macGuessCounter++) {
1702
+ const mac = getMacAddress(this.server.device);
1703
+ mac[3] = macGuessCounter;
1704
+ const reversedMac = mac.reverse();
1705
+ const appHello = [
1706
+ 254,
1707
+ 21,
1708
+ 0,
1709
+ 0,
1710
+ 0,
1711
+ 0,
1712
+ 0,
1713
+ 0,
1714
+ 0,
1715
+ 0,
1716
+ 0,
1717
+ 0,
1718
+ 0,
1719
+ ...reversedMac
1720
+ ];
1721
+ const appHelloMessage = await prepareMessage(appHello, this.aesKey);
1722
+ await mainCharacteristic.writeValue(appHelloMessage);
1723
+ }
1724
+ }
1725
+ async startNotifications() {
1726
+ const mainService = await this.server.getPrimaryService(
1727
+ UUIDs5.qiyiMainService
1728
+ );
1729
+ const mainCharacteristic = await mainService.getCharacteristic(
1730
+ UUIDs5.qiyiMainCharacteristic
1731
+ );
1732
+ mainCharacteristic.addEventListener(
1733
+ "characteristicvaluechanged",
1734
+ this.cubeMessageHandler.bind(this)
1735
+ );
1736
+ await mainCharacteristic.startNotifications();
1737
+ }
1738
+ async cubeMessageHandler(event) {
1739
+ const characteristic = event.target;
1740
+ const decryptedMessage = await decryptMessage(
1741
+ new Uint8Array(characteristic.value.buffer),
1742
+ this.aesKey
1743
+ );
1744
+ const opCode = decryptedMessage[2];
1745
+ let needsAck = false;
1746
+ switch (opCode) {
1747
+ case CUBE_HELLO: {
1748
+ const initialState = decryptedMessage.slice(7, 34);
1749
+ this.updateState(initialState);
1750
+ this.batteryLevel = decryptedMessage[35];
1751
+ needsAck = true;
1752
+ break;
1753
+ }
1754
+ case STATE_CHANGE: {
1755
+ const state = decryptedMessage.slice(7, 34);
1756
+ this.updateState(state);
1757
+ const latestMove = qiyiMoveToBlockMove[decryptedMessage[34]];
1758
+ const latestTimestamp = new DataView(
1759
+ decryptedMessage.slice(3, 7).buffer
1760
+ ).getInt32(0);
1761
+ const moves = [[latestMove, latestTimestamp]];
1762
+ const previousMoves = new DataView(
1763
+ decryptedMessage.slice(36, 91).buffer
1764
+ );
1765
+ for (let i = previousMoves.byteLength - 1; i > 0 && previousMoves.getUint8(i) !== 255; i -= 5) {
1766
+ const move = qiyiMoveToBlockMove[previousMoves.getUint8(i)];
1767
+ const timestamp = previousMoves.getUint32(i - 4);
1768
+ if (this.latestTimestamp === void 0 || timestamp <= this.latestTimestamp) {
1769
+ continue;
1770
+ }
1771
+ moves.push([move, timestamp]);
1772
+ }
1773
+ moves.sort((a, b) => a[1] - b[1]);
1774
+ for (const move of moves) {
1775
+ const latestAlgLeaf = move[0];
1776
+ const timeStamp = Math.round(move[1] / TIMESTAMP_SCALE);
1777
+ if (!this.allTimeStamps.has(timeStamp)) {
1778
+ this.dispatchAlgLeaf({
1779
+ latestAlgLeaf,
1780
+ timeStamp
1781
+ });
1782
+ this.allTimeStamps.add(timeStamp);
1783
+ this.allTimeStampsQueue.push(timeStamp);
1784
+ if (this.allTimeStampsQueue.length > MAX_TIMESTAMP_COUNT) {
1785
+ this.allTimeStamps.delete(this.allTimeStampsQueue.shift());
1786
+ }
1787
+ }
1788
+ }
1789
+ this.latestTimestamp = latestTimestamp;
1790
+ needsAck = decryptedMessage[91] === 1;
1791
+ break;
1792
+ }
1793
+ default:
1794
+ console.error(`Opcode not implemented: ${opCode}`);
1795
+ break;
1796
+ }
1797
+ if (needsAck) {
1798
+ await characteristic.writeValue(
1799
+ await prepareMessage(
1800
+ [254, 9, ...decryptedMessage.slice(2, 7)],
1801
+ this.aesKey
1802
+ )
1803
+ );
1804
+ }
1805
+ }
1806
+ updateState(state) {
1807
+ this.stickers = Array.from(state).flatMap((twoPieces) => [
1808
+ twoPieces & 15,
1809
+ twoPieces >> 4
1810
+ ]);
1811
+ }
1812
+ name() {
1813
+ return this.server.device.name;
1814
+ }
1815
+ disconnect() {
1816
+ this.server.disconnect();
1817
+ }
1818
+ async getPattern() {
1819
+ return new KPattern(
1820
+ this.kpuzzle,
1821
+ getPatternData(
1822
+ this.stickers,
1823
+ faceOrder2,
1824
+ qiyiEdgeMappings,
1825
+ qiyiCornerMappings
1826
+ )
1827
+ );
1828
+ }
1829
+ getBattery() {
1830
+ return this.batteryLevel;
1831
+ }
1832
+ };
1833
+ var qiyiConfig = {
1834
+ connect: QiyiCube.connect.bind(QiyiCube),
1835
+ prefixes: ["QY-QYSC"],
1836
+ filters: [
1837
+ {
1838
+ namePrefix: "QY-QYSC"
1839
+ }
1840
+ ],
1841
+ optionalServices: [UUIDs5.qiyiMainService]
1842
+ };
1843
+
1201
1844
  // src/cubing/bluetooth/smart-puzzle/connect.ts
1202
1845
  var smartPuzzleConfigs = [
1203
1846
  ganConfig,
1204
1847
  goCubeConfig,
1205
1848
  heykubeConfig,
1849
+ qiyiConfig,
1206
1850
  giiKERConfig
1207
1851
  // GiiKER must be last, due to Xiaomi naming. TODO: enforce this using tests.
1208
1852
  ];
@@ -1224,7 +1868,7 @@ var U_D_SWAP = new Alg("F B R2 L2 B' F'");
1224
1868
  var U_D_UNSWAP = U_D_SWAP.invert();
1225
1869
  var F_B_SWAP = new Alg("U D R2 L2 D' U'");
1226
1870
  var F_B_UNSWAP = F_B_SWAP.invert();
1227
- var UUIDs5 = {
1871
+ var UUIDs6 = {
1228
1872
  ganRobotService: "0000fff0-0000-1000-8000-00805f9b34fb",
1229
1873
  statusCharacteristic: "0000fff2-0000-1000-8000-00805f9b34fb",
1230
1874
  moveCharacteristic: "0000fff3-0000-1000-8000-00805f9b34fb"
@@ -1310,13 +1954,13 @@ var GanRobot = class _GanRobot extends EventTarget {
1310
1954
  // We have to perform async operations before we call the constructor.
1311
1955
  static async connect(server, device) {
1312
1956
  const ganTimerService = await server.getPrimaryService(
1313
- UUIDs5.ganRobotService
1957
+ UUIDs6.ganRobotService
1314
1958
  );
1315
1959
  const statusCharacteristic = await ganTimerService.getCharacteristic(
1316
- UUIDs5.statusCharacteristic
1960
+ UUIDs6.statusCharacteristic
1317
1961
  );
1318
1962
  const moveCharacteristic = await ganTimerService.getCharacteristic(
1319
- UUIDs5.moveCharacteristic
1963
+ UUIDs6.moveCharacteristic
1320
1964
  );
1321
1965
  const timer = new _GanRobot(
1322
1966
  ganTimerService,
@@ -1470,7 +2114,7 @@ var ganTimerConfig = {
1470
2114
  connect: GanRobot.connect.bind(GanRobot),
1471
2115
  prefixes: ["GAN"],
1472
2116
  filters: [{ namePrefix: "GAN" }],
1473
- optionalServices: [UUIDs5.ganRobotService]
2117
+ optionalServices: [UUIDs6.ganRobotService]
1474
2118
  };
1475
2119
 
1476
2120
  // src/cubing/bluetooth/smart-robot/index.ts
@@ -1480,7 +2124,7 @@ async function connectSmartRobot(options) {
1480
2124
  }
1481
2125
 
1482
2126
  // src/cubing/bluetooth/smart-timer/GanTimer.ts
1483
- var UUIDs6 = {
2127
+ var UUIDs7 = {
1484
2128
  ganTimerService: "0000fff0-0000-1000-8000-00805f9b34fb",
1485
2129
  timeCharacteristic: "0000fff2-0000-1000-8000-00805f9b34fb"
1486
2130
  };
@@ -1501,11 +2145,11 @@ var GanTimer = class _GanTimer extends EventTarget {
1501
2145
  // We have to perform async operations before we call the constructor.
1502
2146
  static async connect(server, device) {
1503
2147
  const ganTimerService = await server.getPrimaryService(
1504
- UUIDs6.ganTimerService
2148
+ UUIDs7.ganTimerService
1505
2149
  );
1506
2150
  console.log("Service:", ganTimerService);
1507
2151
  const timeCharacteristic = await ganTimerService.getCharacteristic(
1508
- UUIDs6.timeCharacteristic
2152
+ UUIDs7.timeCharacteristic
1509
2153
  );
1510
2154
  console.log("Characteristic:", timeCharacteristic);
1511
2155
  const timer = new _GanTimer(
@@ -1576,7 +2220,7 @@ var ganTimerConfig2 = {
1576
2220
  connect: GanTimer.connect.bind(GanTimer),
1577
2221
  prefixes: ["GAN"],
1578
2222
  filters: [{ namePrefix: "GAN" }],
1579
- optionalServices: [UUIDs6.ganTimerService]
2223
+ optionalServices: [UUIDs7.ganTimerService]
1580
2224
  };
1581
2225
 
1582
2226
  // src/cubing/bluetooth/smart-timer/index.ts