[update] Blockly v11 の FieldColour に対応。指紋センサで読み込んだ指紋のビットマップ画像をキャンバスに表示するブロックを追加

This commit is contained in:
ocogeclub 2024-05-27 23:00:31 +09:00
parent 66233aece1
commit 1f1b9f67d6
10 changed files with 610 additions and 317 deletions

View File

@ -1,17 +1,113 @@
// Custom Color Picker // Color Picker : ビルトインのブロックがウチの環境でどうもうまく働かないので自作
Blockly.FieldColour.COLOURS = [ registerFieldColour();
'#ffffff', '#808000', '#ffff00', '#ff00ff', '#ff4500', Blockly.defineBlocksWithJsonArray([
'#c0c0c0', '#00ffff', '#00ff00', '#ff0000', '#ff1493', {
'#808080', '#0000ff', '#008000', '#800080', '#8a2be2', type: 'colour_picker',
'#000000', '#000080', '#008080', '#800000', '#2e8b57' message0: '%1',
]; "output": "Colour",
Blockly.FieldColour.TITLES = [ "tooltip": "パレットから色を選んでください",
'white', 'olive', 'yellow', 'magenta', 'orangered', "helpUrl": "",
'silver', 'aqua', 'lime', 'red', 'deeppink', "style": "colour_blocks",
'gray', 'blue', 'green', 'purple', 'blueviolet', args0: [
'black', 'navy', 'teal', 'maroon', 'seagreen' {
]; type: 'field_colour',
Blockly.FieldColour.COLUMNS = 5; name: 'COLOUR',
colour: '#ff0000',
},
],
},
]);
javascript.javascriptGenerator.forBlock['colour_picker'] = function (block, generator) {
const code = generator.quote_(block.getFieldValue('COLOUR'));
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.defineBlocksWithJsonArray([
{
type: 'coupycolor_picker',
message0: 'クーピー30色: %1',
"output": "Colour",
"tooltip": "サクラクーピーペンシル30色のカラーチャートによる",
"helpUrl": "https://www.craypas.co.jp/products/painting-school/013/0031/182945.html#color-chart",
"style": "colour_blocks",
args0: [
{
type: 'field_colour',
name: 'COLOUR',
colour: '#E281A0',
colourOptions: [
'#F5ED68',
'#F6E92B',
'#EEB818',
'#EA9D13',
'#F2C198',
'#FBF5C5',
'#7E422A',
'#B8591F',
'#CD9711',
'#4F371D',
'#D83A2F',
'#D61242',
'#E281A0',
'#A41759',
'#E0BED6',
'#1D2973',
'#1794CE',
'#0FA275',
'#8ABC29',
'#0C834D',
'#0C834D',
'#0A68AE',
'#096CB0',
'#0F3460',
'#9CA5A4',
'#277565',
'#3F3939',
'#FFFFFF',
'#AE901E',
'#A5AEB3',
],
colourTitles: [
'レモンいろ',
'きいろ',
'やまぶきいろ',
'だいだいいろ',
'うすだいだい',
'たまごいろ',
'ちゃいろ',
'あかちゃいろ',
'おうどいろ',
'こげちゃいろ',
'しゅいろ',
'あか',
'ももいろ',
'あかむらさき',
'うすむらさき',
'むらさき',
'みずいろ',
'エメラルドいろ',
'きみどり',
'みどり',
'ふかみどり',
'あお',
'ぐんじょういろ',
'あいいろ',
'ねずみいろ',
'はいみどり',
'くろ',
'しろ',
'きんいろ',
'ぎんいろ',
],
columns: 5,
},
],
},
]);
javascript.javascriptGenerator.forBlock['coupycolor_picker'] = function (block, generator) {
const code = generator.quote_(block.getFieldValue('COLOUR'));
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
/** Additional Basic Blocks********************************************************************************* */ /** Additional Basic Blocks********************************************************************************* */
Blockly.defineBlocksWithJsonArray([{ Blockly.defineBlocksWithJsonArray([{

View File

@ -188,22 +188,53 @@ javascript.javascriptGenerator.forBlock['oc_sfmv17_registration'] = function (bl
return [code, Blockly.JavaScript.ORDER_ATOMIC]; return [code, Blockly.JavaScript.ORDER_ATOMIC];
}; };
// 全ユーザ一括削除 // ユーザ削除 / ID 0 で全削除
Blockly.defineBlocksWithJsonArray([{ Blockly.defineBlocksWithJsonArray([{
"type": "oc_sfmv17_deletealluser", "type": "oc_sfmv17_deleteuser",
"message0": "指紋一括削除", "message0": "ID %1 の指紋を削除",
"args0": [
{
"type": "input_value",
"name": "uid"
}
],
"inputsInline": true,
"previousStatement": null, "previousStatement": null,
"nextStatement": null, "nextStatement": null,
"tooltip": "指紋センサに登録されている指紋を全て削除します。", "tooltip": "登録済みの指紋から ID で指定したものを削除します。ID 0 を指定すると全部の指紋を削除します。",
"helpUrl": "", "helpUrl": "",
"style": "sensor_blocks" "style": "sensor_blocks"
}]); }]);
javascript.javascriptGenerator.forBlock['oc_sfmv17_deletealluser'] = function (block, generator) { javascript.javascriptGenerator.forBlock['oc_sfmv17_deleteuser'] = function (block, generator) {
var code = `await _sfm.deleteAllUser();\n`; var value_uid = generator.valueToCode(block, 'uid', javascript.Order.ATOMIC);
var code = `await _sfm.deleteUser(${value_uid});\n`;
return code; return code;
}; };
// 指紋画像を取得
Blockly.defineBlocksWithJsonArray([{
"type": "oc_sfmv17_getimage",
"message0": "指紋画像をキャンバスに表示",
"previousStatement": null,
"nextStatement": null,
"tooltip": "指紋センサで読み取った指紋をキャンバスに表示します。",
"helpUrl": "",
"style": "sensor_blocks"
}]);
javascript.javascriptGenerator.forBlock['oc_sfmv17_getimage'] = function (block, generator) {
var code = ` let r = await _sfm.getImage();
console.log(r);
console.log(r.length)
let imgdata = _ctx.createImageData(160, 160);
for (let pixel=0; pixel<r.length; pixel++){
for (let rgb=0; rgb<3; rgb++)
imgdata.data[pixel*4+rgb] = r[pixel];
imgdata.data[pixel*4+3] = 0xff;
}
_ctx.putImageData(imgdata,0,0);
`;
return code;
};
// 切断 // 切断
Blockly.defineBlocksWithJsonArray([{ Blockly.defineBlocksWithJsonArray([{
"type": "oc_sfmv17_stop", "type": "oc_sfmv17_stop",
@ -277,7 +308,21 @@ flyout_contents = flyout_contents.concat([
}, },
{ {
"kind": "block", "kind": "block",
"type": "oc_sfmv17_deletealluser" "type": "oc_sfmv17_deleteuser",
"inputs": {
"uid": {
"shadow": {
"type": "math_number",
"fields": {
"NUM": "0"
}
}
}
}
},
{
"kind": "block",
"type": "oc_sfmv17_getimage"
}, },
{ {
"kind": "block", "kind": "block",

28
finger_test.js Normal file
View File

@ -0,0 +1,28 @@
const main = async () => {
const _rg = require('@ocoge/rgpio');
const _sfm = require('@ocoge/sfmv17');
const fs = require('node:fs')
const _sleep = sec =>
new Promise(r => setTimeout(r, sec * 1000));
await _rg.rgpio_sbc('192.168.0.202');
await _sfm.init(_rg, '/dev/ttyS0', 115200);
await _sleep(0.1);
let r = await _sfm.getImage();
console.log(r);
console.log(r.length)
fs.writeFile("fptest.bmp", r, (err) => {
if (err) throw err;
console.log('正常に書き込みが完了しました');
});
await _sleep(0.1);
await _sfm.stop();
await _rg.sbc_stop();
}
main();

View File

@ -24,17 +24,9 @@
<!-- コードダイアログ --> <!-- コードダイアログ -->
<dialog id="codeDlg"> <dialog id="codeDlg">
<div id="dlgTitle">Source Code:</div> <div id="dlgTitle">Source Code:</div>
<!-- <pre id="dlgContent" class="prettyprint lang-js linenums"></pre> -->
<pre id="dlgContent" class="line-numbers"><code id="code"></code></pre> <pre id="dlgContent" class="line-numbers"><code id="code"></code></pre>
<button id="dlgClose" title="このダイアログを閉じます。">閉じる</button> <button id="dlgClose" title="このダイアログを閉じます。">閉じる</button>
<button id="dlgExport" title="ソースコードを保存します。">保存</button> <button id="dlgExport" title="ソースコードを保存します。">保存</button>
<!-- <span id="cli" class="dlgCli" title="ソースコードの window.alert() などを console.log() に置換します。コンソールで動作させるときにちょっと便利です。"><input
type="checkbox" id="dlgCli">CLI</span> -->
<!-- <div id="conmenu">
<ul>
<li><a href="#" onclick="document.execCommand('copy');" class="conCopy">コピー</a></li>
</ul>
</div> -->
</dialog> </dialog>
@ -340,13 +332,6 @@
<category name="GPIO" css-icon="customIcon fab fa-raspberry-pi" categorystyle="gpio_category"> <category name="GPIO" css-icon="customIcon fab fa-raspberry-pi" categorystyle="gpio_category">
<label text="基本"></label> <label text="基本"></label>
<block type="ugj_gpio_open"></block> <block type="ugj_gpio_open"></block>
<!-- <block type="oc_gpio_open_remote">
<value name="host">
<shadow type="text">
<field name="TEXT">192.168.0.120</field>
</shadow>
</value>
</block> -->
<block type="ugj_gpio_close"></block> <block type="ugj_gpio_close"></block>
<block type="oc_gpio_set_output"> <block type="oc_gpio_set_output">
<value name="ugpio"> <value name="ugpio">
@ -393,7 +378,6 @@
<block type="oc_i2c_close"> <block type="oc_i2c_close">
<field name="i2c_hand">I2Cデバイス</field> <field name="i2c_hand">I2Cデバイス</field>
</block> </block>
<!-- <block type="ugj_i2c_close"></block> -->
<block type="oc_i2c_write_byte"> <block type="oc_i2c_write_byte">
<field name="i2c_hand">I2Cデバイス</field> <field name="i2c_hand">I2Cデバイス</field>
<value name="byte_val"> <value name="byte_val">
@ -496,32 +480,6 @@
</shadow> </shadow>
</value> </value>
</block> </block>
<!-- <block type="ugj_serial_open">
<field name="baud">9600</field>
</block>
<block type="ugj_serial_close"></block>
<block type="ugj_serial_read">
<value name="count">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
<block type="ugj_serial_write">
<value name="data">
<shadow type="text_join">
<mutation items="2"></mutation>
<value name="ADD0">
<shadow type="text">
<field name="TEXT">ohayo-.</field>
</shadow>
</value>
<value name="ADD1">
<shadow type="ugj_text_cr"></shadow>
</value>
</shadow>
</value>
</block> -->
<label text="Extra" web-line="4.0" web-line-width="200"></label> <label text="Extra" web-line="4.0" web-line-width="200"></label>
<label text="_" web-line="4.0" web-line-width="200"></label> <label text="_" web-line="4.0" web-line-width="200"></label>
</category> </category>
@ -614,25 +572,8 @@
<block type="ugj_canvas_finalize"></block> <block type="ugj_canvas_finalize"></block>
<label text="色" web-line="4.0" web-line-width="200"></label> <label text="色" web-line="4.0" web-line-width="200"></label>
<block type="colour_picker"> <block type="colour_picker">
<field name="COLOUR">#ff0000</field>
</block> </block>
<block type="colour_random"></block> <block type="coupycolor_picker">
<block type="colour_rgb">
<value name="RED">
<shadow type="math_number">
<field name="NUM">100</field>
</shadow>
</value>
<value name="GREEN">
<shadow type="math_number">
<field name="NUM">50</field>
</shadow>
</value>
<value name="BLUE">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
</block> </block>
<label text="サウンド" web-line="4.0" web-line-width="200"></label> <label text="サウンド" web-line="4.0" web-line-width="200"></label>
<block type="ugj_sound_play"> <block type="ugj_sound_play">
@ -698,27 +639,16 @@
</value> </value>
</block> </block>
<label text="音声コマンド認識" web-line="4.0" web-line-width="200"></label> <label text="音声コマンド認識" web-line="4.0" web-line-width="200"></label>
<!-- <block type="oc_speechcommands_init">
<value name="custom_model">
<shadow type="text">
<field name="TEXT"></field>
</shadow>
</value>
</block> -->
<block type="oc_speechcommands_init"> <block type="oc_speechcommands_init">
<field name="classlabels" iid="aV;:;wdjQ;:3+(Bx8Z!$">ラベル</field> <field name="classlabels">ラベル</field>
<value name="custom_model"> <value name="custom_model">
<shadow type="text"> <shadow type="text">
<field name="TEXT"></field> <field name="TEXT"></field>
</shadow> </shadow>
</value> </value>
</block> </block>
<!-- <block type="oc_speechcommand_listen">
<field name="classlabels" iid="-aysulrCq~BT0?GQL|V:">ラベル</field>
<field name="scores" iid="#?-HvxDFqQ#vb+swl_k:">スコア</field>
</block> -->
<block type="oc_speechcommand_listen"> <block type="oc_speechcommand_listen">
<field name="scores" iid="|!AWY]V:il;fu;lRwDC*">スコア</field> <field name="scores">スコア</field>
</block> </block>
<label text="_" web-line="4.0" web-line-width="200"></label> <label text="_" web-line="4.0" web-line-width="200"></label>
</category> </category>
@ -973,7 +903,6 @@
</shadow> </shadow>
</value> </value>
</block> </block>
<!-- <block type="ugj_dev_run_js"></block> -->
<label text="_" web-line="4.0" web-line-width="200"></label> <label text="_" web-line="4.0" web-line-width="200"></label>
</category> </category>
<category name="RP2 専用" css-icon="customIcon fab fa-python" categorystyle="rp2_category"> <category name="RP2 専用" css-icon="customIcon fab fa-python" categorystyle="rp2_category">
@ -1038,12 +967,12 @@
<block type="oc_rp2_ir_transmit"></block> <block type="oc_rp2_ir_transmit"></block>
</category> </category>
</xml> </xml>
<script src="./node_modules/blockly/blockly_compressed.js"></script> <script src="./node_modules/blockly/blockly_compressed.js"></script>
<script src="./node_modules/blockly/javascript_compressed.js"></script> <script src="./node_modules/blockly/javascript_compressed.js"></script>
<script src="./node_modules/blockly/python_compressed.js"></script> <script src="./node_modules/blockly/python_compressed.js"></script>
<script src="./node_modules/blockly/blocks_compressed.js"></script> <script src="./node_modules/blockly/blocks_compressed.js"></script>
<script src="./node_modules/blockly/msg/ja.js"></script> <script src="./node_modules/blockly/msg/ja.js"></script>
<script src="./node_modules/@blockly/field-colour/dist/index.js"></script>
<script src="./node_modules/@blockly/field-slider/dist/index.js"></script> <script src="./node_modules/@blockly/field-slider/dist/index.js"></script>
<script src="./lib/custom-dialog.js"></script> <script src="./lib/custom-dialog.js"></script>
<script src="./apptool.js"></script> <script src="./apptool.js"></script>

View File

@ -1,7 +0,0 @@
const foo = [["CE1", "35"], ["CE0", "52"], ["SCLK", "50"], ["MISO", "48"], ["MOSI", "49"], ["RXD", "132"], ["TXD", "131"], ["SCL", "46"], ["SDA", "47"], ["P0", "138"], ["P1", "29"], ["P2", "139"], ["P3", "28"], ["P4", "59"], ["P5", "58"], ["P6", "92"], ["P7", "54"]];
// console.log(foo["CE0"]);
let bar = JSON.stringify(foo);
console.log(bar);

View File

@ -0,0 +1,153 @@
module.exports = require('bindings')('rgpio');
module.exports.SET_ACTIVE_LOW = 4;
module.exports.SET_OPEN_DRAIN = 8;
module.exports.SET_OPEN_SOURCE = 16;
module.exports.SET_PULL_UP = 32;
module.exports.SET_PULL_DOWN = 64;
module.exports.SET_PULL_NONE = 128;
// Properties
let sbc = -1;
let chip_hand = [];
module.exports.rgpio_sbc = async (host = 'localhost', port = 8889, show_errors = true) => {
if (sbc < 0) {
sbc = await module.exports._rgpiod_start(host, port.toString());
if (sbc < 0) {
if (show_errors) console.log(sbc);
}
}
return sbc;
}
module.exports.sbc_stop = async () => {
await module.exports._rgpiod_stop(sbc);
chip_hand = [];
sbc = -1;
}
module.exports.gpiochip_open = async gpiochip => {
if (!chip_hand[gpiochip] || chip_hand[gpiochip] < 0) {
chip_hand[gpiochip] = await module.exports._gpiochip_open(sbc, gpiochip);
}
return chip_hand[gpiochip];
// return await module.exports._gpiochip_open(sbc, gpiochip);
}
module.exports.gpio_set_input = async (ugpio, lFlags = 0) => {
let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip);
return await module.exports._gpio_claim_input(sbc, handle, lFlags, gpio);
}
module.exports.gpio_set_output = async (ugpio, level = 0, lFlags = 0) => {
let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip);
return await module.exports._gpio_claim_output(sbc, handle, lFlags, gpio, level);
}
module.exports.gpio_read = async (ugpio) => {
let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip);
return await module.exports._gpio_read(sbc, handle, gpio);
}
module.exports.gpio_write = async (ugpio, level) => {
let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip);
return await module.exports._gpio_write(sbc, handle, gpio, level);
}
module.exports.serial_open = async (tty, baud, ser_flags = 0) => {
return await module.exports._serial_open(sbc, tty, baud, ser_flags);
}
module.exports.serial_close = async handle => {
await module.exports._serial_close(sbc, handle);
}
module.exports.serial_read = async (handle, count = 0, raw = false) => {
if (count === 0) {
count = await module.exports._serial_data_available(sbc, handle);
if (count === 0) return '';
}
if (raw)
return await module.exports._serial_read(sbc, handle, count);
else
return new TextDecoder().decode(await module.exports._serial_read(sbc, handle, count));
}
module.exports.serial_write = async (handle, data) => {
return await module.exports._serial_write(sbc, handle, Buffer.from(data), -1);
}
module.exports.serial_data_available = async handle => {
return await module.exports._serial_data_available(sbc, handle);
}
module.exports.i2c_open = async (i2c_bus, i2c_address, i2c_flags = 0) => {
return await module.exports._i2c_open(sbc, i2c_bus, i2c_address, i2c_flags);
}
module.exports.i2c_close = async handle => {
await module.exports._i2c_close(sbc, handle);
}
module.exports.i2c_write_byte = async (handle, byte_val) => {
return await module.exports._i2c_write_byte(sbc, handle, byte_val);
}
module.exports.i2c_read_byte = async handle => {
return await module.exports._i2c_read_byte(sbc, handle);
}
module.exports.i2c_write_byte_data = async (handle, reg, byte_val) => {
return await module.exports._i2c_write_byte_data(sbc, handle, reg, byte_val);
}
module.exports.i2c_read_byte_data = async (handle, reg) => {
return await module.exports._i2c_read_byte_data(sbc, handle, reg);
}
module.exports.i2c_read_i2c_block_data = async (handle, reg, count = -1) => {
return await module.exports._i2c_read_i2c_block_data(sbc, handle, reg, count);
}
module.exports.i2c_write_i2c_block_data = async (handle, reg, data) => {
return await module.exports._i2c_write_i2c_block_data(sbc, handle, reg, Buffer.from(data), -1);
}
module.exports.i2c_read_word_data = async (handle, reg) => {
return await module.exports._i2c_read_word_data(sbc, handle, reg);
}
module.exports.i2c_write_word_data = async (handle, reg, word_val) => {
return await module.exports._i2c_write_word_data(sbc, handle, reg, word_val);
}
module.exports.i2c_read_device = async (handle, count) => {
return new TextDecoder().decode(await module.exports._i2c_read_device(sbc, handle, count));
}
module.exports.i2c_write_device = async (handle, data) => {
return await module.exports._i2c_write_device(sbc, handle, Buffer.from(data), -1);
}
/***** 同期関数 *****/
module.exports.rgpio_sbc_sync = (host = 'localhost', port = 8889, show_errors = true) => {
if (sbc < 0) {
sbc = module.exports._rgpiod_start_sync(host, port.toString());
if (sbc < 0) {
if (show_errors) console.log(sbc);
}
}
return sbc;
}
module.exports.sbc_stop_sync = () => {
module.exports._rgpiod_stop_sync(sbc);
chip_hand = [];
sbc = -1;
}
module.exports.i2c_open_sync = (i2c_bus, i2c_address, i2c_flags = 0) => {
return module.exports._i2c_open_sync(sbc, i2c_bus, i2c_address, i2c_flags);
}
module.exports.i2c_close_sync = handle => {
module.exports._i2c_close_sync(sbc, handle);
}
module.exports.i2c_read_byte_sync = handle => {
return module.exports._i2c_read_byte_sync(sbc, handle);
}
module.exports.i2c_write_device_sync = (handle, data, count = -1) => {
let buffer = Buffer.from(data);
if (count < 0) count = buffer.length;
return module.exports._i2c_write_device_sync(sbc, handle, buffer, count);
}
// 終了処理
module.exports.close_all_handle = async () => {
await module.exports.sbc_stop();
}

View File

@ -1,153 +1,155 @@
module.exports = require('bindings')('rgpio'); 'use strict';
module.exports.SET_ACTIVE_LOW = 4; let rg = require('bindings')('rgpio');
module.exports.SET_OPEN_DRAIN = 8;
module.exports.SET_OPEN_SOURCE = 16; exports.SET_ACTIVE_LOW = 4;
module.exports.SET_PULL_UP = 32; exports.SET_OPEN_DRAIN = 8;
module.exports.SET_PULL_DOWN = 64; exports.SET_OPEN_SOURCE = 16;
module.exports.SET_PULL_NONE = 128; exports.SET_PULL_UP = 32;
exports.SET_PULL_DOWN = 64;
exports.SET_PULL_NONE = 128;
// Properties // Properties
let sbc = -1; let sbc = -1;
let chip_hand = []; let chip_hand = [];
module.exports.rgpio_sbc = async (host = 'localhost', port = 8889, show_errors = true) => { exports.rgpio_sbc = async (host = 'localhost', port = 8889, show_errors = true) => {
if (sbc < 0) { if (sbc < 0) {
sbc = await module.exports._rgpiod_start(host, port.toString()); sbc = await rg._rgpiod_start(host, port.toString());
if (sbc < 0) { if (sbc < 0) {
if (show_errors) console.log(sbc); if (show_errors) console.log(sbc);
} }
} }
return sbc; return sbc;
} }
module.exports.sbc_stop = async () => { exports.sbc_stop = async () => {
await module.exports._rgpiod_stop(sbc); await rg._rgpiod_stop(sbc);
chip_hand = []; chip_hand = [];
sbc = -1; sbc = -1;
} }
module.exports.gpiochip_open = async gpiochip => { exports.gpiochip_open = async gpiochip => {
if (!chip_hand[gpiochip] || chip_hand[gpiochip] < 0) { if (!chip_hand[gpiochip] || chip_hand[gpiochip] < 0) {
chip_hand[gpiochip] = await module.exports._gpiochip_open(sbc, gpiochip); chip_hand[gpiochip] = await rg._gpiochip_open(sbc, gpiochip);
} }
return chip_hand[gpiochip]; return chip_hand[gpiochip];
// return await module.exports._gpiochip_open(sbc, gpiochip); // return await rg._gpiochip_open(sbc, gpiochip);
} }
module.exports.gpio_set_input = async (ugpio, lFlags = 0) => { exports.gpio_set_input = async (ugpio, lFlags = 0) => {
let chip = Math.trunc(ugpio / 32); let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32; let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip); let handle = await this.gpiochip_open(chip);
return await module.exports._gpio_claim_input(sbc, handle, lFlags, gpio); return await rg._gpio_claim_input(sbc, handle, lFlags, gpio);
} }
module.exports.gpio_set_output = async (ugpio, level = 0, lFlags = 0) => { exports.gpio_set_output = async (ugpio, level = 0, lFlags = 0) => {
let chip = Math.trunc(ugpio / 32); let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32; let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip); let handle = await this.gpiochip_open(chip);
return await module.exports._gpio_claim_output(sbc, handle, lFlags, gpio, level); return await rg._gpio_claim_output(sbc, handle, lFlags, gpio, level);
} }
module.exports.gpio_read = async (ugpio) => { exports.gpio_read = async (ugpio) => {
let chip = Math.trunc(ugpio / 32); let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32; let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip); let handle = await this.gpiochip_open(chip);
return await module.exports._gpio_read(sbc, handle, gpio); return await rg._gpio_read(sbc, handle, gpio);
} }
module.exports.gpio_write = async (ugpio, level) => { exports.gpio_write = async (ugpio, level) => {
let chip = Math.trunc(ugpio / 32); let chip = Math.trunc(ugpio / 32);
let gpio = ugpio % 32; let gpio = ugpio % 32;
let handle = await module.exports.gpiochip_open(chip); let handle = await this.gpiochip_open(chip);
return await module.exports._gpio_write(sbc, handle, gpio, level); return await rg._gpio_write(sbc, handle, gpio, level);
} }
module.exports.serial_open = async (tty, baud, ser_flags = 0) => { exports.serial_open = async (tty, baud, ser_flags = 0) => {
return await module.exports._serial_open(sbc, tty, baud, ser_flags); return await rg._serial_open(sbc, tty, baud, ser_flags);
} }
module.exports.serial_close = async handle => { exports.serial_close = async handle => {
await module.exports._serial_close(sbc, handle); await rg._serial_close(sbc, handle);
} }
module.exports.serial_read = async (handle, count = 0, raw = false) => { exports.serial_read = async (handle, count = 0, raw = false) => {
if (count === 0) { if (count === 0) {
count = await module.exports._serial_data_available(sbc, handle); count = await rg._serial_data_available(sbc, handle);
if (count === 0) return ''; if (count === 0) return '';
} }
if (raw) if (raw)
return await module.exports._serial_read(sbc, handle, count); return await rg._serial_read(sbc, handle, count);
else else
return new TextDecoder().decode(await module.exports._serial_read(sbc, handle, count)); return new TextDecoder().decode(await rg._serial_read(sbc, handle, count));
} }
module.exports.serial_write = async (handle, data) => { exports.serial_write = async (handle, data) => {
return await module.exports._serial_write(sbc, handle, Buffer.from(data), -1); return await rg._serial_write(sbc, handle, Buffer.from(data), -1);
} }
module.exports.serial_data_available = async handle => { exports.serial_data_available = async handle => {
return await module.exports._serial_data_available(sbc, handle); return await rg._serial_data_available(sbc, handle);
} }
module.exports.i2c_open = async (i2c_bus, i2c_address, i2c_flags = 0) => { exports.i2c_open = async (i2c_bus, i2c_address, i2c_flags = 0) => {
return await module.exports._i2c_open(sbc, i2c_bus, i2c_address, i2c_flags); return await rg._i2c_open(sbc, i2c_bus, i2c_address, i2c_flags);
} }
module.exports.i2c_close = async handle => { exports.i2c_close = async handle => {
await module.exports._i2c_close(sbc, handle); await rg._i2c_close(sbc, handle);
} }
module.exports.i2c_write_byte = async (handle, byte_val) => { exports.i2c_write_byte = async (handle, byte_val) => {
return await module.exports._i2c_write_byte(sbc, handle, byte_val); return await rg._i2c_write_byte(sbc, handle, byte_val);
} }
module.exports.i2c_read_byte = async handle => { exports.i2c_read_byte = async handle => {
return await module.exports._i2c_read_byte(sbc, handle); return await rg._i2c_read_byte(sbc, handle);
} }
module.exports.i2c_write_byte_data = async (handle, reg, byte_val) => { exports.i2c_write_byte_data = async (handle, reg, byte_val) => {
return await module.exports._i2c_write_byte_data(sbc, handle, reg, byte_val); return await rg._i2c_write_byte_data(sbc, handle, reg, byte_val);
} }
module.exports.i2c_read_byte_data = async (handle, reg) => { exports.i2c_read_byte_data = async (handle, reg) => {
return await module.exports._i2c_read_byte_data(sbc, handle, reg); return await rg._i2c_read_byte_data(sbc, handle, reg);
} }
module.exports.i2c_read_i2c_block_data = async (handle, reg, count = -1) => { exports.i2c_read_i2c_block_data = async (handle, reg, count = -1) => {
return await module.exports._i2c_read_i2c_block_data(sbc, handle, reg, count); return await rg._i2c_read_i2c_block_data(sbc, handle, reg, count);
} }
module.exports.i2c_write_i2c_block_data = async (handle, reg, data) => { exports.i2c_write_i2c_block_data = async (handle, reg, data) => {
return await module.exports._i2c_write_i2c_block_data(sbc, handle, reg, Buffer.from(data), -1); return await rg._i2c_write_i2c_block_data(sbc, handle, reg, Buffer.from(data), -1);
} }
module.exports.i2c_read_word_data = async (handle, reg) => { exports.i2c_read_word_data = async (handle, reg) => {
return await module.exports._i2c_read_word_data(sbc, handle, reg); return await rg._i2c_read_word_data(sbc, handle, reg);
} }
module.exports.i2c_write_word_data = async (handle, reg, word_val) => { exports.i2c_write_word_data = async (handle, reg, word_val) => {
return await module.exports._i2c_write_word_data(sbc, handle, reg, word_val); return await rg._i2c_write_word_data(sbc, handle, reg, word_val);
} }
module.exports.i2c_read_device = async (handle, count) => { exports.i2c_read_device = async (handle, count) => {
return new TextDecoder().decode(await module.exports._i2c_read_device(sbc, handle, count)); return new TextDecoder().decode(await rg._i2c_read_device(sbc, handle, count));
} }
module.exports.i2c_write_device = async (handle, data) => { exports.i2c_write_device = async (handle, data) => {
return await module.exports._i2c_write_device(sbc, handle, Buffer.from(data), -1); return await rg._i2c_write_device(sbc, handle, Buffer.from(data), -1);
} }
/***** 同期関数 *****/ /***** 同期関数 *****/
module.exports.rgpio_sbc_sync = (host = 'localhost', port = 8889, show_errors = true) => { exports.rgpio_sbc_sync = (host = 'localhost', port = 8889, show_errors = true) => {
if (sbc < 0) { if (sbc < 0) {
sbc = module.exports._rgpiod_start_sync(host, port.toString()); sbc = rg._rgpiod_start_sync(host, port.toString());
if (sbc < 0) { if (sbc < 0) {
if (show_errors) console.log(sbc); if (show_errors) console.log(sbc);
} }
} }
return sbc; return sbc;
} }
module.exports.sbc_stop_sync = () => { exports.sbc_stop_sync = () => {
module.exports._rgpiod_stop_sync(sbc); rg._rgpiod_stop_sync(sbc);
chip_hand = []; chip_hand = [];
sbc = -1; sbc = -1;
} }
module.exports.i2c_open_sync = (i2c_bus, i2c_address, i2c_flags = 0) => { exports.i2c_open_sync = (i2c_bus, i2c_address, i2c_flags = 0) => {
return module.exports._i2c_open_sync(sbc, i2c_bus, i2c_address, i2c_flags); return rg._i2c_open_sync(sbc, i2c_bus, i2c_address, i2c_flags);
} }
module.exports.i2c_close_sync = handle => { exports.i2c_close_sync = handle => {
module.exports._i2c_close_sync(sbc, handle); rg._i2c_close_sync(sbc, handle);
} }
module.exports.i2c_read_byte_sync = handle => { exports.i2c_read_byte_sync = handle => {
return module.exports._i2c_read_byte_sync(sbc, handle); return rg._i2c_read_byte_sync(sbc, handle);
} }
module.exports.i2c_write_device_sync = (handle, data, count = -1) => { exports.i2c_write_device_sync = (handle, data, count = -1) => {
let buffer = Buffer.from(data); let buffer = Buffer.from(data);
if (count < 0) count = buffer.length; if (count < 0) count = buffer.length;
return module.exports._i2c_write_device_sync(sbc, handle, buffer, count); return rg._i2c_write_device_sync(sbc, handle, buffer, count);
} }
// 終了処理 // 終了処理
module.exports.close_all_handle = async () => { exports.close_all_handle = async () => {
await module.exports.sbc_stop(); await this.sbc_stop();
} }

View File

@ -46,7 +46,7 @@ let ser_hand = -1;
const delay = microsec => const delay = microsec =>
new Promise(r => setTimeout(r, microsec)); new Promise(r => setTimeout(r, microsec));
// Calculate checksum // Calculate XOR checksum
const getCheckSum = buffer => { const getCheckSum = buffer => {
let result = 0; let result = 0;
for (let i = 1; i <= 5; i++) { for (let i = 1; i <= 5; i++) {
@ -61,30 +61,43 @@ const sendCmd = async (cmdType, p1, p2, p3) => {
let cmdBuffer = [0xF5, cmdType, p1, p2, p3, 0, 0, 0xF5]; let cmdBuffer = [0xF5, cmdType, p1, p2, p3, 0, 0, 0xF5];
cmdBuffer[6] = getCheckSum(cmdBuffer); cmdBuffer[6] = getCheckSum(cmdBuffer);
await rg.serial_write(ser_hand, cmdBuffer); await rg.serial_write(ser_hand, cmdBuffer);
}
const getAck = async () => {
let ackBuffer = Buffer.from([]); let ackBuffer = Buffer.from([]);
let timer = SFM_SERIAL_TIMEOUT; let timer = SFM_SERIAL_TIMEOUT;
while (timer--) { while (timer--) {
if (await rg.serial_data_available(ser_hand)) { if (await rg.serial_data_available(ser_hand) > 0) {
ackBuffer = Buffer.concat([ackBuffer, await rg.serial_read(ser_hand, 0, true)]); ackBuffer = Buffer.concat([ackBuffer, await rg.serial_read(ser_hand, 0, true)]);
} }
else if (ackBuffer.length >= 8) { else if (ackBuffer.length >= 8) {
// console.log(ackBuffer); // 1/100秒待ってデバイス側にデータが残っていないか再チェック
await delay(10);
timer -= 10;
if (await rg.serial_data_available(ser_hand) > 0) continue;
// もうデータは残っていないらしい
if (ackBuffer[6] == getCheckSum(ackBuffer)) if (ackBuffer[6] == getCheckSum(ackBuffer))
return [ackBuffer[4], ackBuffer[1], ackBuffer[2], ackBuffer[3]]; if (ackBuffer.length > 8) { // Has data field
if (ackBuffer[ackBuffer.length - 1] == 0xF5) {
let dataBuffer = Buffer.alloc(ackBuffer.length - 8);
ackBuffer.copy(dataBuffer, 0, 8);
return [ackBuffer[1], ackBuffer[2], ackBuffer[3], ackBuffer[4], dataBuffer];
}
} else
return [ackBuffer[1], ackBuffer[2], ackBuffer[3], ackBuffer[4]];
else else
return [SFM_ACK_FAIL]; return [null, null, null, SFM_ACK_FAIL];
} }
await delay(1); await delay(1);
} }
return [SFM_ACK_SERIALTIMEOUT]; return [null, null, null, SFM_ACK_SERIALTIMEOUT];
} }
// Rapping sendCmd... Returns tuple // Rapping sendCmd... Returns tuple
const getCmdReturn = async (cmdType, p1 = 0, p2 = 0, p3 = 0) => { const sendAndGet = async (cmdType, p1 = 0, p2 = 0, p3 = 0) => {
let [q3, ackType, q1, q2] = await sendCmd(cmdType, p1, p2, p3); await sendCmd(cmdType, p1, p2, p3);
let [ackType, q1, q2, q3, dataBuffer] = await getAck();
this.last_status = q3; // コマンド実行結果ステータスを保存 this.last_status = q3; // コマンド実行結果ステータスを保存
if (ackType == cmdType) return [q3, ackType, q1, q2]; if (ackType == cmdType) return [ackType, q1, q2, q3, dataBuffer];
else return [SFM_ACK_FAIL, 0, 0, 0]; else return [SFM_ACK_FAIL, 0, 0, 0];
} }
@ -102,13 +115,13 @@ exports.setRingColor = async (start_color, end_color = -1, period = 500) => {
if (period < 30) period = 30; if (period < 30) period = 30;
else if (period > 200) period = 200; else if (period > 200) period = 200;
if (end_color == -1) end_color = start_color; if (end_color == -1) end_color = start_color;
let [q3, ackType, q1, q2] = await getCmdReturn(0xC3, start_color, end_color, period); let [ackType, q1, q2, q3] = await sendAndGet(0xC3, start_color, end_color, period);
return q3; return q3;
} }
// Count users // Count users
exports.getUserCount = async () => { exports.getUserCount = async () => {
let [q3, ackType, q1, q2] = await getCmdReturn(0x09, 0x00, 0x00, 0x00); let [ackType, q1, q2, q3] = await sendAndGet(0x09, 0x00, 0x00, 0x00);
let userCount = -1; let userCount = -1;
if (q3 != SFM_ACK_FAIL) userCount = (q1 << 8) | q2; if (q3 != SFM_ACK_FAIL) userCount = (q1 << 8) | q2;
// else userCount = -1; // else userCount = -1;
@ -117,7 +130,7 @@ exports.getUserCount = async () => {
// Recognize fingerprint... returns userID / 0: not found / -1: error // Recognize fingerprint... returns userID / 0: not found / -1: error
exports.recognition_1vN = async () => { exports.recognition_1vN = async () => {
let [q3, ackType, q1, q2] = await getCmdReturn(0x0C, 0x00, 0x00, 0x00); let [ackType, q1, q2, q3] = await sendAndGet(0x0C, 0x00, 0x00, 0x00);
let uid = (q1 << 8) | q2; let uid = (q1 << 8) | q2;
if (uid == 0 && q3 != SFM_ACK_SUCCESS) return -1; if (uid == 0 && q3 != SFM_ACK_SUCCESS) return -1;
else return uid; else return uid;
@ -130,24 +143,45 @@ exports.recognition_1vN = async () => {
exports.register_3c3r = async (step, uid = 0) => { exports.register_3c3r = async (step, uid = 0) => {
let q3, ackType, q1, q2; let q3, ackType, q1, q2;
if (step == 1) { if (step == 1) {
[q3, ackType, q1, q2] = await getCmdReturn(0x01, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE); [ackType, q1, q2, q3] = await sendAndGet(0x01, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE);
if (q3 == SFM_ACK_SUCCESS) return 0; if (q3 == SFM_ACK_SUCCESS) return 0;
else return -1; else return -1;
} else if (step == 2) { } else if (step == 2) {
[q3, ackType, q1, q2] = await getCmdReturn(0x02); [ackType, q1, q2, q3] = await sendAndGet(0x02);
if (q3 == SFM_ACK_SUCCESS) return 0; if (q3 == SFM_ACK_SUCCESS) return 0;
else return -1; else return -1;
} else if (step == 3) { } else if (step == 3) {
[q3, ackType, q1, q2] = await getCmdReturn(0x03, 0x00, 0x00, 0x00); [ackType, q1, q2, q3] = await sendAndGet(0x03, 0x00, 0x00, 0x00);
let uid = -1; let uid = -1;
if (q3 == SFM_ACK_SUCCESS) uid = (q1 << 8) | q2; if (q3 == SFM_ACK_SUCCESS) uid = (q1 << 8) | q2;
return uid; return uid;
} }
} }
// Delete all users // Get fingerprint image
exports.deleteAllUser = async () => { exports.getImage = async () => {
let [q3, ackType, q1, q2] = await getCmdReturn(0x05); let [ackType, q1, q2, q3, dataBuffer] = await sendAndGet(0x24);
if (q3 == SFM_ACK_SUCCESS) {
// console.log(dataBuffer)
let width = q1 << 2;
let height = q2 << 2;
let len = width * height;
let imgBuffer = Buffer.alloc(len);//dataBuffer.slice(1, 1 + len);
dataBuffer.copy(imgBuffer, 0, 1, 1 + len);
// const imgblob = new Blob([imgBuffer], { type: "image/bmp" });
return imgBuffer;
}
// return [, ];
else return -1;
}
// Delete user(s)
exports.deleteUser = async (uid) => {
let ackType, q1, q2, q3;
if (uid == 0) // Delete All users
[ackType, q1, q2, q3] = await sendAndGet(0x05);
else // Delete specific user
[ackType, q1, q2, q3] = await sendAndGet(0x04, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE);
if (q3 == SFM_ACK_SUCCESS) return 0; if (q3 == SFM_ACK_SUCCESS) return 0;
else return -1; else return -1;
} }

240
package-lock.json generated
View File

@ -9,7 +9,8 @@
"version": "0.1.12", "version": "0.1.12",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@blockly/field-slider": "^6.1.10", "@blockly/field-colour": "^5.0.0",
"@blockly/field-slider": "^7.0.0",
"@ocoge/amg8833": "file:local_modules/amg8833", "@ocoge/amg8833": "file:local_modules/amg8833",
"@ocoge/bme280": "file:local_modules/bme280", "@ocoge/bme280": "file:local_modules/bme280",
"@ocoge/paj7620": "file:local_modules/paj7620", "@ocoge/paj7620": "file:local_modules/paj7620",
@ -20,8 +21,8 @@
"@tensorflow-models/mobilenet": "^2.1.1", "@tensorflow-models/mobilenet": "^2.1.1",
"@tensorflow-models/speech-commands": "^0.5.4", "@tensorflow-models/speech-commands": "^0.5.4",
"@tensorflow/tfjs-node": "^4.19.0", "@tensorflow/tfjs-node": "^4.19.0",
"axios": "^1.7.0", "axios": "^1.7.2",
"blockly": "^10.4.3", "blockly": "^11.0.0",
"canvas": "github:Automattic/node-canvas", "canvas": "github:Automattic/node-canvas",
"dracula-prism": "^2.1.16", "dracula-prism": "^2.1.16",
"js-beautify": "^1.15.1", "js-beautify": "^1.15.1",
@ -34,7 +35,7 @@
"@electron-forge/cli": "^7.4.0", "@electron-forge/cli": "^7.4.0",
"@electron-forge/maker-deb": "^7.4.0", "@electron-forge/maker-deb": "^7.4.0",
"@electron/rebuild": "^3.6.0", "@electron/rebuild": "^3.6.0",
"electron": "^30.0.6" "electron": "^30.0.8"
}, },
"optionalDependencies": { "optionalDependencies": {
"@ocoge/rgpio": "file:local_modules/rgpio" "@ocoge/rgpio": "file:local_modules/rgpio"
@ -81,15 +82,26 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@blockly/field-slider": { "node_modules/@blockly/field-colour": {
"version": "6.1.10", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/@blockly/field-slider/-/field-slider-6.1.10.tgz", "resolved": "https://registry.npmjs.org/@blockly/field-colour/-/field-colour-5.0.0.tgz",
"integrity": "sha512-l0Vzm2CTynjyfs4ATiFdb1zqS7V4T5oJB0lUeEIjlIZl08jMkyZR3AkUg4P+C4e/kI5tTHKAqhlnldv+ij4fyA==", "integrity": "sha512-UyelwXh9xjaodIM1OxA4pjsA0vlk+wVvNEGgGIUdWOrBGeZsRYDprB/IjK7Pzr9iC7Y54bzj8c09ysC2dsX3bQ==",
"engines": { "engines": {
"node": ">=8.0.0" "node": ">=8.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"blockly": "^10.0.0" "blockly": "^11.0.0"
}
},
"node_modules/@blockly/field-slider": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@blockly/field-slider/-/field-slider-7.0.0.tgz",
"integrity": "sha512-3PJXPi70LRlFYD/O/cfmF6etgizNGnatBm4hU2tguKqLeich/u1QgWF2Lm4cyA1NxSqomV14sw7jJ4Ou1rFhkQ==",
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"blockly": "^11.0.0"
} }
}, },
"node_modules/@electron-forge/cli": { "node_modules/@electron-forge/cli": {
@ -1301,6 +1313,7 @@
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
"dev": true,
"engines": { "engines": {
"node": ">= 10" "node": ">= 10"
} }
@ -1425,12 +1438,6 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/abab": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
"deprecated": "Use your platform's native atob() and btoa() methods instead"
},
"node_modules/abbrev": { "node_modules/abbrev": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -1529,6 +1536,7 @@
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"deprecated": "This package is no longer supported.",
"dependencies": { "dependencies": {
"delegates": "^1.0.0", "delegates": "^1.0.0",
"readable-stream": "^3.6.0" "readable-stream": "^3.6.0"
@ -1602,9 +1610,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.7.0", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
"integrity": "sha512-IiB0wQeKyPRdsFVhBgIo31FbzOyf2M6wYl7/NVutFwFBRMiAbjNiydJIHKeLmPugF4kJLfA1uWZ82Is2QzqqFA==", "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.6",
"form-data": "^4.0.0", "form-data": "^4.0.0",
@ -1655,11 +1663,14 @@
} }
}, },
"node_modules/blockly": { "node_modules/blockly": {
"version": "10.4.3", "version": "11.0.0",
"resolved": "https://registry.npmjs.org/blockly/-/blockly-10.4.3.tgz", "resolved": "https://registry.npmjs.org/blockly/-/blockly-11.0.0.tgz",
"integrity": "sha512-+opfBmQnSiv7vTiY/TkDEBOslxUyfj8luS3S+qs1NnQKjInC+Waf2l9cNsMh9J8BMkmiCIT+Ed/3mmjIaL9wug==", "integrity": "sha512-6Ie7HuZWZLaETIVKFEP4FPDz267Pubn6+weQNZvXzqnkOYp9sKPSsPue8QIMCV9Qb5F4wYhqivgiDcZJcE1UlQ==",
"dependencies": { "dependencies": {
"jsdom": "22.1.0" "jsdom": "23.0.0"
},
"engines": {
"node": ">=18"
} }
}, },
"node_modules/bluebird": { "node_modules/bluebird": {
@ -2213,16 +2224,15 @@
} }
}, },
"node_modules/data-urls": { "node_modules/data-urls": {
"version": "4.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
"integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
"dependencies": { "dependencies": {
"abab": "^2.0.6", "whatwg-mimetype": "^4.0.0",
"whatwg-mimetype": "^3.0.0", "whatwg-url": "^14.0.0"
"whatwg-url": "^12.0.0"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=18"
} }
}, },
"node_modules/debug": { "node_modules/debug": {
@ -2374,18 +2384,6 @@
"p-limit": "^3.1.0 " "p-limit": "^3.1.0 "
} }
}, },
"node_modules/domexception": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
"integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
"deprecated": "Use your platform's native DOMException instead",
"dependencies": {
"webidl-conversions": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/dracula-prism": { "node_modules/dracula-prism": {
"version": "2.1.16", "version": "2.1.16",
"resolved": "https://registry.npmjs.org/dracula-prism/-/dracula-prism-2.1.16.tgz", "resolved": "https://registry.npmjs.org/dracula-prism/-/dracula-prism-2.1.16.tgz",
@ -2444,9 +2442,9 @@
} }
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "30.0.6", "version": "30.0.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-30.0.6.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-30.0.8.tgz",
"integrity": "sha512-PkhEPFdpYcTzjAO3gMHZ+map7g2+xCrMDedo/L1i0ir2BRXvAB93IkTJX497U6Srb/09r2cFt+k20VPNVCdw3Q==", "integrity": "sha512-ivzXJJ/9gdb4oOw+5SDuaZpSInz8C+Z021dKZfFLMltKbDa4sSqt5cRBiUg7J36Z2kdus+Jai0bdHWutYE9wAA==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
@ -3275,6 +3273,7 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"deprecated": "This package is no longer supported.",
"dependencies": { "dependencies": {
"aproba": "^1.0.3 || ^2.0.0", "aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2", "color-support": "^1.1.2",
@ -3675,14 +3674,14 @@
"dev": true "dev": true
}, },
"node_modules/html-encoding-sniffer": { "node_modules/html-encoding-sniffer": {
"version": "3.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
"dependencies": { "dependencies": {
"whatwg-encoding": "^2.0.0" "whatwg-encoding": "^3.1.1"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
} }
}, },
"node_modules/http-cache-semantics": { "node_modules/http-cache-semantics": {
@ -3695,6 +3694,7 @@
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
"dev": true,
"dependencies": { "dependencies": {
"@tootallnate/once": "2", "@tootallnate/once": "2",
"agent-base": "6", "agent-base": "6",
@ -3708,6 +3708,7 @@
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"dev": true,
"dependencies": { "dependencies": {
"debug": "4" "debug": "4"
}, },
@ -4110,39 +4111,37 @@
"dev": true "dev": true
}, },
"node_modules/jsdom": { "node_modules/jsdom": {
"version": "22.1.0", "version": "23.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz",
"integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==",
"dependencies": { "dependencies": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0", "cssstyle": "^3.0.0",
"data-urls": "^4.0.0", "data-urls": "^5.0.0",
"decimal.js": "^10.4.3", "decimal.js": "^10.4.3",
"domexception": "^4.0.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"html-encoding-sniffer": "^3.0.0", "html-encoding-sniffer": "^4.0.0",
"http-proxy-agent": "^5.0.0", "http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^5.0.1", "https-proxy-agent": "^7.0.2",
"is-potential-custom-element-name": "^1.0.1", "is-potential-custom-element-name": "^1.0.1",
"nwsapi": "^2.2.4", "nwsapi": "^2.2.7",
"parse5": "^7.1.2", "parse5": "^7.1.2",
"rrweb-cssom": "^0.6.0", "rrweb-cssom": "^0.6.0",
"saxes": "^6.0.0", "saxes": "^6.0.0",
"symbol-tree": "^3.2.4", "symbol-tree": "^3.2.4",
"tough-cookie": "^4.1.2", "tough-cookie": "^4.1.3",
"w3c-xmlserializer": "^4.0.0", "w3c-xmlserializer": "^5.0.0",
"webidl-conversions": "^7.0.0", "webidl-conversions": "^7.0.0",
"whatwg-encoding": "^2.0.0", "whatwg-encoding": "^3.1.1",
"whatwg-mimetype": "^3.0.0", "whatwg-mimetype": "^4.0.0",
"whatwg-url": "^12.0.1", "whatwg-url": "^14.0.0",
"ws": "^8.13.0", "ws": "^8.14.2",
"xml-name-validator": "^4.0.0" "xml-name-validator": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=18"
}, },
"peerDependencies": { "peerDependencies": {
"canvas": "^2.5.0" "canvas": "^3.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"canvas": { "canvas": {
@ -4151,26 +4150,38 @@
} }
}, },
"node_modules/jsdom/node_modules/agent-base": { "node_modules/jsdom/node_modules/agent-base": {
"version": "6.0.2", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
"dependencies": { "dependencies": {
"debug": "4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
"node": ">= 6.0.0" "node": ">= 14"
}
},
"node_modules/jsdom/node_modules/http-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dependencies": {
"agent-base": "^7.1.0",
"debug": "^4.3.4"
},
"engines": {
"node": ">= 14"
} }
}, },
"node_modules/jsdom/node_modules/https-proxy-agent": { "node_modules/jsdom/node_modules/https-proxy-agent": {
"version": "5.0.1", "version": "7.0.4",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
"dependencies": { "dependencies": {
"agent-base": "6", "agent-base": "^7.0.2",
"debug": "4" "debug": "4"
}, },
"engines": { "engines": {
"node": ">= 6" "node": ">= 14"
} }
}, },
"node_modules/json-buffer": { "node_modules/json-buffer": {
@ -4951,6 +4962,7 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"deprecated": "This package is no longer supported.",
"dependencies": { "dependencies": {
"are-we-there-yet": "^2.0.0", "are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0", "console-control-strings": "^1.1.0",
@ -4959,9 +4971,9 @@
} }
}, },
"node_modules/nwsapi": { "node_modules/nwsapi": {
"version": "2.2.9", "version": "2.2.10",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz",
"integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ=="
}, },
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -6555,9 +6567,9 @@
} }
}, },
"node_modules/tough-cookie": { "node_modules/tough-cookie": {
"version": "4.1.3", "version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"dependencies": { "dependencies": {
"psl": "^1.1.33", "psl": "^1.1.33",
"punycode": "^2.1.1", "punycode": "^2.1.1",
@ -6577,14 +6589,14 @@
} }
}, },
"node_modules/tr46": { "node_modules/tr46": {
"version": "4.1.1", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
"dependencies": { "dependencies": {
"punycode": "^2.3.0" "punycode": "^2.3.1"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=18"
} }
}, },
"node_modules/trim-repeated": { "node_modules/trim-repeated": {
@ -6707,14 +6719,14 @@
} }
}, },
"node_modules/w3c-xmlserializer": { "node_modules/w3c-xmlserializer": {
"version": "4.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
"integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
"dependencies": { "dependencies": {
"xml-name-validator": "^4.0.0" "xml-name-validator": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=18"
} }
}, },
"node_modules/wcwidth": { "node_modules/wcwidth": {
@ -6735,34 +6747,34 @@
} }
}, },
"node_modules/whatwg-encoding": { "node_modules/whatwg-encoding": {
"version": "2.0.0", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
"dependencies": { "dependencies": {
"iconv-lite": "0.6.3" "iconv-lite": "0.6.3"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
} }
}, },
"node_modules/whatwg-mimetype": { "node_modules/whatwg-mimetype": {
"version": "3.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
"engines": { "engines": {
"node": ">=12" "node": ">=18"
} }
}, },
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "12.0.1", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
"integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dependencies": { "dependencies": {
"tr46": "^4.1.1", "tr46": "^5.0.0",
"webidl-conversions": "^7.0.0" "webidl-conversions": "^7.0.0"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=18"
} }
}, },
"node_modules/which": { "node_modules/which": {
@ -6937,9 +6949,9 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.16.0", "version": "8.17.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },
@ -6957,11 +6969,11 @@
} }
}, },
"node_modules/xml-name-validator": { "node_modules/xml-name-validator": {
"version": "4.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
"engines": { "engines": {
"node": ">=12" "node": ">=18"
} }
}, },
"node_modules/xmlbuilder": { "node_modules/xmlbuilder": {

View File

@ -25,10 +25,11 @@
"@electron-forge/cli": "^7.4.0", "@electron-forge/cli": "^7.4.0",
"@electron-forge/maker-deb": "^7.4.0", "@electron-forge/maker-deb": "^7.4.0",
"@electron/rebuild": "^3.6.0", "@electron/rebuild": "^3.6.0",
"electron": "^30.0.6" "electron": "^30.0.8"
}, },
"dependencies": { "dependencies": {
"@blockly/field-slider": "^6.1.10", "@blockly/field-colour": "^5.0.0",
"@blockly/field-slider": "^7.0.0",
"@ocoge/amg8833": "file:local_modules/amg8833", "@ocoge/amg8833": "file:local_modules/amg8833",
"@ocoge/bme280": "file:local_modules/bme280", "@ocoge/bme280": "file:local_modules/bme280",
"@ocoge/paj7620": "file:local_modules/paj7620", "@ocoge/paj7620": "file:local_modules/paj7620",
@ -39,8 +40,8 @@
"@tensorflow-models/mobilenet": "^2.1.1", "@tensorflow-models/mobilenet": "^2.1.1",
"@tensorflow-models/speech-commands": "^0.5.4", "@tensorflow-models/speech-commands": "^0.5.4",
"@tensorflow/tfjs-node": "^4.19.0", "@tensorflow/tfjs-node": "^4.19.0",
"axios": "^1.7.0", "axios": "^1.7.2",
"blockly": "^10.4.3", "blockly": "^11.0.0",
"canvas": "github:Automattic/node-canvas", "canvas": "github:Automattic/node-canvas",
"dracula-prism": "^2.1.16", "dracula-prism": "^2.1.16",
"js-beautify": "^1.15.1", "js-beautify": "^1.15.1",