iobroker.javascript 10.2.4 → 10.3.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.
- package/README.md +10 -21
- package/admin/assets/AiChatPanel-CpY4Bun-.js +27 -0
- package/admin/assets/{AiChatService-Bsp_rhVx.js → AiChatService-QKcpW4jQ.js} +1 -1
- package/admin/assets/AiDiffView-DscPfZ38.js +1 -0
- package/admin/assets/{AiInlineProvider-BxOW88xU.js → AiInlineProvider-DTSPKoXG.js} +1 -1
- package/admin/assets/BlocklyEditor-BZyoN1JE.js +301 -0
- package/admin/assets/Compile-B0uHjrBE.css +1 -0
- package/admin/assets/Compile-Oss28m_f.js +165 -0
- package/admin/assets/Debugger-teJTIU-2.js +15 -0
- package/admin/assets/Documentation-uz4Ut9pT.js +4339 -0
- package/admin/assets/ExpandMore-V5Ix1QB1.js +1 -0
- package/admin/assets/FbEditor-B8S-mCvc.css +1 -0
- package/admin/assets/FbEditor-aOZ-RpPV.js +15 -0
- package/admin/assets/Import-BIC5Ee9z.js +1 -0
- package/admin/assets/NotificationsActive-BdzH44gp.js +1 -0
- package/admin/assets/RulesEditor-CcDVthPa.js +1 -0
- package/admin/assets/{ScriptEditor-BCGahS47.js → ScriptEditor-CviB6Hif.js} +2 -2
- package/admin/assets/ScriptEditorVanillaMonaco-ByuXwybM.js +3 -0
- package/admin/assets/Send-Mdo32jMb.js +1 -0
- package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BnL93BgK.js +1 -0
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-NI-3Uv4e.js +1217 -0
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DVaMIZyC.js +9 -0
- package/admin/assets/aiPromptBuilder-yTB6N2VT.js +1 -0
- package/admin/assets/blocklyTheme-CGhU3cEO.js +1 -0
- package/admin/assets/blocks_action-BQ4O7NRE.js +1 -0
- package/admin/assets/{blocks_convert-CLb0DLyc.js → blocks_convert-0VBjfhqQ.js} +1 -1
- package/admin/assets/blocks_logic-DAo99xDr.js +1 -0
- package/admin/assets/blocks_number-C--e19NU.js +1 -0
- package/admin/assets/blocks_object-D0TPhdzg.js +1 -0
- package/admin/assets/blocks_procedures-DgTxgXdB.js +3 -0
- package/admin/assets/{blocks_sendto-BxCMg9X4.js → blocks_sendto-CRIrtOUc.js} +1 -1
- package/admin/assets/blocks_switch-b_GYfF0n.js +2 -0
- package/admin/assets/blocks_system-BdkUdSsc.js +1 -0
- package/admin/assets/blocks_text-DSFhEVOf.js +1 -0
- package/admin/assets/blocks_time-CqALAiJp.js +1 -0
- package/admin/assets/blocks_timeout-yrOD2pZp.js +1 -0
- package/admin/assets/{blocks_trigger-XivsIDE5.js → blocks_trigger-DeAYXpSS.js} +1 -1
- package/admin/assets/{cronHoverProvider-BZMOFHO_.js → cronHoverProvider-DoO2_tpG.js} +1 -1
- package/admin/assets/{field_cron-CxKi__cX.js → field_cron-D3Ts_s9M.js} +1 -1
- package/admin/assets/{field_oid-CJIYiGxY.js → field_oid-BRNXredg.js} +1 -1
- package/admin/assets/{field_script-CehplM7L.js → field_script-3X6ousg7.js} +1 -1
- package/admin/assets/helpers-BTGaTdnT.js +1 -0
- package/admin/assets/{hostInit-Bs-bStPF.js → hostInit-2h2Cbsaw.js} +1 -1
- package/admin/assets/iconLibraryData-B5fiyl1C.js +1 -0
- package/admin/assets/index-BHhhebRG.css +1 -0
- package/admin/assets/index-CbQlIKB_.js +156 -0
- package/admin/assets/{inlineChatWidget-NIvdRGmU.js → inlineChatWidget-BwQVCPkx.js} +1 -1
- package/admin/assets/{inlineDiffController-Qh402KhK.js → inlineDiffController-BsDDsDHn.js} +1 -1
- package/admin/assets/loadBlocks-RpqM7PwO.js +117 -0
- package/admin/assets/loadMonaco-BVOEahNw.js +1 -0
- package/admin/assets/{mf-entry-bootstrap-0-019228a5.js → mf-entry-bootstrap-0-0deef484.js} +3 -3
- package/admin/assets/{pendingShares-B3t6ewri.js → pendingShares-BaAadIDv.js} +1 -1
- package/admin/assets/reactour.esm-DX9ZgYlx.js +137 -0
- package/admin/assets/stateHoverProvider-BEadnSXp.js +11 -0
- package/admin/assets/tileFbd-CWAy7R7m.svg +85 -0
- package/admin/custom/assets/Components-FkGDIlId.js +1 -0
- package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Cs88NUCd.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-P-8ffWXw.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-ZVuRAEo5.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DVb0ZZ1Q.js +1217 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-Dna3WF04.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-DcjdCGAx.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__date_mf_2_fns__loadShare__.js-CnhNjamd.js +1 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__leaflet__loadShare__.js-im3edKNs.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__leaflet__loadShare__.js-Dz7BFJqH.js} +1 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-B0olko2J.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-CzN4reh_.js +122 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__leaflet__prebuild__-xPcBaiTQ.js +1 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-Byvr2uOb.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js} +1 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_2_dom_mf_1_client__prebuild__-DuFBE5fh.js +9 -0
- package/admin/custom/assets/{hostInit-IJMNq3h7.js → hostInit-6oh4UY2k.js} +1 -1
- package/admin/custom/assets/iconLibraryData-B5fiyl1C.js +1 -0
- package/admin/custom/assets/index-BrlyEy6J.js +1 -0
- package/admin/custom/assets/lib-BmDlTzq2.js +3 -0
- package/admin/custom/assets/{mf-entry-bootstrap-0-f149bc46.js → mf-entry-bootstrap-0-ad1cd7d0.js} +3 -3
- package/admin/custom/assets/pendingShares-kV2kwejX.js +1 -0
- package/admin/custom/assets/rolldown-runtime-Dqfqb5bO.js +1 -0
- package/admin/custom/customComponents.js +3 -2
- package/admin/custom/i18n/en.json +39 -39
- package/admin/custom/i18n/es.json +1 -1
- package/admin/custom/i18n/fr.json +2 -2
- package/admin/custom/i18n/it.json +1 -1
- package/admin/custom/i18n/nl.json +2 -2
- package/admin/custom/i18n/pt.json +2 -2
- package/admin/custom/i18n/ru.json +2 -2
- package/admin/custom/i18n/uk.json +1 -1
- package/admin/custom/i18n/zh-cn.json +1 -1
- package/admin/i18n/de.json +1 -1
- package/admin/i18n/en.json +115 -115
- package/admin/i18n/fr.json +115 -115
- package/admin/i18n/it.json +115 -115
- package/admin/i18n/nl.json +115 -115
- package/admin/i18n/pl.json +1 -1
- package/admin/i18n/pt.json +115 -115
- package/admin/i18n/ru.json +115 -115
- package/admin/i18n/uk.json +115 -115
- package/admin/i18n/zh-cn.json +115 -115
- package/admin/mf-manifest.json +1 -1
- package/admin/mf-stats.json +1 -1
- package/admin/remoteEntry.js +2 -2
- package/admin/tab.html +3 -7
- package/build/lib/fb/analyze.js +288 -0
- package/build/lib/fb/analyze.js.map +1 -0
- package/build/lib/fb/blocks.js +605 -0
- package/build/lib/fb/blocks.js.map +1 -0
- package/build/lib/fb/generate.js +326 -0
- package/build/lib/fb/generate.js.map +1 -0
- package/build/lib/fb/graph.js +240 -0
- package/build/lib/fb/graph.js.map +1 -0
- package/build/lib/fb/index.js +57 -0
- package/build/lib/fb/index.js.map +1 -0
- package/build/lib/fb/js.js +33 -0
- package/build/lib/fb/js.js.map +1 -0
- package/build/lib/fb/layout.js +205 -0
- package/build/lib/fb/layout.js.map +1 -0
- package/build/lib/fb/library.js +657 -0
- package/build/lib/fb/library.js.map +1 -0
- package/build/lib/fb/runtime.js +793 -0
- package/build/lib/fb/runtime.js.map +1 -0
- package/build/lib/fb/time.js +76 -0
- package/build/lib/fb/time.js.map +1 -0
- package/build/lib/fb/types.js +19 -0
- package/build/lib/fb/types.js.map +1 -0
- package/build/lib/fb/user.js +78 -0
- package/build/lib/fb/user.js.map +1 -0
- package/build/lib/javascript.d.ts +17 -17
- package/build/lib/mirror.js +4 -0
- package/build/lib/mirror.js.map +1 -1
- package/build/lib/sandbox.js +44 -0
- package/build/lib/sandbox.js.map +1 -1
- package/build/main.js +66 -1
- package/build/main.js.map +1 -1
- package/build/types.d.ts +9 -1
- package/docs/de/README.md +1 -1
- package/docs/de/fbd.md +274 -0
- package/docs/de/javascript.md +2167 -0
- package/docs/en/fbd.md +260 -0
- package/docs/en/javascript.md +28 -30
- package/io-package.json +52 -28
- package/package.json +8 -8
- package/admin/assets/AiChatPanel-AZko1BsN.js +0 -27
- package/admin/assets/AiDiffView-Cri2QFh1.js +0 -1
- package/admin/assets/Debugger-CVDh3kgz.js +0 -15
- package/admin/assets/Error-Ch2nx5uC.js +0 -1
- package/admin/assets/Import-XKVP-nRT.js +0 -1
- package/admin/assets/RulesEditor-DsO4cKIk.js +0 -1
- package/admin/assets/ScriptEditorVanillaMonaco-BDAw2Bw6.js +0 -3
- package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BMAFQFoH.js +0 -1
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-D-gi6Mty.js +0 -1217
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CDctpiPx.js +0 -9
- package/admin/assets/aiPromptBuilder-aJfHa-eU.js +0 -1
- package/admin/assets/blocks_action-DS28sNfo.js +0 -1
- package/admin/assets/blocks_logic-Dpp2fwlu.js +0 -1
- package/admin/assets/blocks_number-N4IfHvYD.js +0 -1
- package/admin/assets/blocks_object-uK7FHVhS.js +0 -1
- package/admin/assets/blocks_procedures-C_KD0Bm6.js +0 -3
- package/admin/assets/blocks_switch-C8Rls5pK.js +0 -2
- package/admin/assets/blocks_system-CEQnj5fY.js +0 -1
- package/admin/assets/blocks_text-BDEWxu0P.js +0 -1
- package/admin/assets/blocks_time-aHQQK1Uz.js +0 -1
- package/admin/assets/blocks_timeout-C2L93TLJ.js +0 -1
- package/admin/assets/helpers-DiwtLpXM.js +0 -1
- package/admin/assets/index-B0FfAYMN.js +0 -871
- package/admin/assets/index-CXaeqPRy.css +0 -1
- package/admin/assets/stateHoverProvider-BkW15VMN.js +0 -9
- package/admin/assets/virtualExposes-DgGB-18P.js +0 -1
- package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-CiidVc0O.js +0 -1
- package/admin/assets/virtual_mf-exposes___mfe_internal__iobroker_javascript__remoteEntry_js-ChiJXsfH.js +0 -1
- package/admin/custom/assets/Components-SGnA-3W_.js +0 -1
- package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Bx3X6TLB.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-Cc7MmJgr.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CdvEvX5z.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-D5NaoeJi.js +0 -1217
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-Cbgw_a3f.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-CMr75K5w.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__date_mf_2_fns__loadShare__.js-DKIvPDPX.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-D50aYKgD.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-CEzQFX7o.js +0 -122
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__leaflet__prebuild__-BUDmnAcx.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__136440932828998__prebuild__react_mf_2_dom_mf_1_client__prebuild__-D_1oh1WH.js +0 -9
- package/admin/custom/assets/index-7r4VklMp.js +0 -1
- package/admin/custom/assets/lib-DDU2Oe48.js +0 -3
- package/admin/custom/assets/pendingShares-DarGQhyO.js +0 -1
- package/admin/custom/assets/rolldown-runtime-BcKkbAw3.js +0 -1
- package/admin/custom/assets/virtualExposes-C0IqMANQ.js +0 -1
- package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-CqKvh5Xu.js +0 -1
- package/admin/custom/assets/virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-DrBN_S5o.js +0 -2
package/docs/en/fbd.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Function block diagrams (FBD)
|
|
2
|
+
|
|
3
|
+
A function block diagram is logic drawn from blocks, the way a PLC is programmed in CFC: timers, flip-flops,
|
|
4
|
+
comparisons and arithmetic, wired to ioBroker states. It is meant for logic that runs all the time - delays,
|
|
5
|
+
latches, thresholds - and for users who know this style from a PLC. To react to a single event, Blockly or Rules
|
|
6
|
+
are usually the simpler choice.
|
|
7
|
+
|
|
8
|
+
The diagram is turned into JavaScript when it is saved and runs like every other script of this adapter.
|
|
9
|
+
|
|
10
|
+
## Creating a diagram
|
|
11
|
+
|
|
12
|
+
Add a new script and choose **Function block diagram**. The editor has three parts:
|
|
13
|
+
|
|
14
|
+
- **Palette** (left), with a search and three tabs:
|
|
15
|
+
- **Blocks**: the blocks by category - drag one onto the canvas, or click it to add it. A category opens and
|
|
16
|
+
closes with a click on its name.
|
|
17
|
+
- **Variables**: the states the diagram reads and writes; a click shows the block.
|
|
18
|
+
- **Favorites**: the blocks marked with the star that shows when the mouse is over a block.
|
|
19
|
+
- **Canvas**: connect an output (right side of a block) with an input (left side). Only fitting types can be
|
|
20
|
+
connected - the color of a pin shows its type; a link let go on a pin that does not take it says why. An input
|
|
21
|
+
takes one link. `Delete` removes what is selected.
|
|
22
|
+
- **Properties** (right): **Properties** shows the settings of the selected block in parts that open and close -
|
|
23
|
+
general (instance name, type, a comment), parameters, inputs and, for timers, flip-flops, edges and control blocks,
|
|
24
|
+
a **preview**: a timing diagram of the block with its values. **Documentation** describes the block and its pins.
|
|
25
|
+
With nothing selected: the settings of the diagram, and the keys.
|
|
26
|
+
|
|
27
|
+
A block shows what matters right in it: the state it reads or writes, the value of a `CONST`, and the values of the
|
|
28
|
+
inputs that are not connected - these can be changed right there: a click switches a BOOL, anything else is typed in
|
|
29
|
+
and taken with `Enter`. In the head of a block, the gear shows its properties, the menu `⋮` duplicates or deletes it
|
|
30
|
+
(online also: breakpoint; for an own block: inside view).
|
|
31
|
+
|
|
32
|
+
Problems are listed at the bottom of the canvas; a click selects the block. A diagram with errors can be saved, but
|
|
33
|
+
its script does not run - it logs the errors instead.
|
|
34
|
+
|
|
35
|
+
The button **FBD → JS** shows the generated code.
|
|
36
|
+
|
|
37
|
+
Editing works as usual: `Ctrl+Z` / `Ctrl+Y` (or the buttons of the toolbar) undo and redo, `Ctrl+C`, `Ctrl+X`
|
|
38
|
+
and `Ctrl+V` copy, cut and paste the selected blocks with the links between them - also into another diagram. Pasted
|
|
39
|
+
blocks get new IDs, and new names where the old ones are taken.
|
|
40
|
+
|
|
41
|
+
The bar above the canvas shows the diagram (and the path into an instance) and has the tools:
|
|
42
|
+
|
|
43
|
+
- the zoom: smaller, the zoom (a click: 100 %), larger
|
|
44
|
+
- **Arrange automatically** puts the blocks in columns along the data flow: inputs on the left, outputs on the
|
|
45
|
+
right, each block level with the blocks it is linked to. Comments stay where they are. `Ctrl+Z` takes it back.
|
|
46
|
+
- **Find in the diagram** (`Ctrl+F`) finds blocks by instance name, type, state ID or other parameter, comments by
|
|
47
|
+
their text. `Enter` goes to the next match, `Shift+Enter` to the one before, `Esc` closes the search.
|
|
48
|
+
- **Grid** on or off (with it, blocks snap to it), and links as curves or at right angles as in CFC - both are kept
|
|
49
|
+
by the browser, not in the diagram
|
|
50
|
+
- on the right the online view, see below
|
|
51
|
+
|
|
52
|
+
**Connection marks**: a link across the whole diagram can be shown as a mark at both ends instead of a line - select
|
|
53
|
+
the link and switch on **Show as a connection mark** in its properties. Both marks show the name of the block the
|
|
54
|
+
link comes from, or a name of their own. A double click on a mark jumps to the other end. Only the drawing changes,
|
|
55
|
+
the link works the same.
|
|
56
|
+
|
|
57
|
+
## Online view
|
|
58
|
+
|
|
59
|
+
**Online** (on the right of the bar above the canvas) shows the values of the running diagram: at every output, BOOL
|
|
60
|
+
links in green (`TRUE`) or grey (`FALSE`), other links with their value in the middle. Next to the button, or under
|
|
61
|
+
it:
|
|
62
|
+
|
|
63
|
+
- the cycle count - it stands still when the diagram stopped running
|
|
64
|
+
- a warning when no data comes (the script does not run, or its instance is stopped)
|
|
65
|
+
- a hint when the diagram was changed after saving: the values belong to the saved version
|
|
66
|
+
|
|
67
|
+
When a cycle fails, the block whose code failed is framed in red and the error is listed at the bottom left; the
|
|
68
|
+
log names the block too (`Error in the function block diagram in block b7: ...`).
|
|
69
|
+
|
|
70
|
+
The values only flow while an editor shows the diagram online: the editor asks the adapter every 10 s, and after 30 s
|
|
71
|
+
without a request the diagram stops sending. At most four updates a second are sent, each with the values that
|
|
72
|
+
changed only. A diagram saved before this version shows the cycle count, but no values - save it once.
|
|
73
|
+
|
|
74
|
+
### Inside an instance
|
|
75
|
+
|
|
76
|
+
A double click on an instance of an own block (or **Inside view** in its properties) shows the diagram of the
|
|
77
|
+
block - as this diagram carries it, read only - and online with the values of just this instance. An instance inside
|
|
78
|
+
it opens the same way; the path at the top left leads back, and so does `Esc`. Values inside can be forced;
|
|
79
|
+
breakpoints are set in the diagram itself. The values inside need a diagram saved with this version.
|
|
80
|
+
|
|
81
|
+
### Forcing values, breakpoints, single steps
|
|
82
|
+
|
|
83
|
+
While the diagram is shown online, it can be steered:
|
|
84
|
+
|
|
85
|
+
- **Forcing**: select a block (or a link) - its properties show the outputs with their values. **TRUE** / **FALSE**,
|
|
86
|
+
or a value and **Force**, hold the output at that value, whatever the block computes; the blocks behind it and the
|
|
87
|
+
states the diagram writes get the forced value. A forced value is framed in orange; **Release** lets it go.
|
|
88
|
+
- **Breakpoints**: the dot at the top left of a block, `F9` or **Breakpoint** in its properties. The diagram stops in
|
|
89
|
+
front of that block; the block that runs next is framed in yellow, and the values show how far the cycle got.
|
|
90
|
+
- The buttons left of **Online**: **Pause** / **Run on** (`F8`), **One cycle**, and **One block** (`F10`). While the
|
|
91
|
+
diagram waits, the changes of its inputs wait too. A cycle started by hand counts one cycle time as time passed,
|
|
92
|
+
so timers behave as they would, however long the diagram waited.
|
|
93
|
+
|
|
94
|
+
All of that ends with the online view: when the editor switches it off, is closed or goes away (30 s without a
|
|
95
|
+
request), the runtime releases the forced values, removes the breakpoints and runs on - it logs that. Saving the
|
|
96
|
+
diagram keeps forced values and breakpoints while the online view stays open. Breakpoints and single steps need a
|
|
97
|
+
diagram saved with this version; a diagram saved before can already be forced and paused.
|
|
98
|
+
|
|
99
|
+
**Careful:** a forced value acts on real devices - the diagram writes its states with it.
|
|
100
|
+
|
|
101
|
+
## Blocks
|
|
102
|
+
|
|
103
|
+
| Category | Blocks |
|
|
104
|
+
|------------|------------------------------------------------------------------|
|
|
105
|
+
| ioBroker | `STATE_IN`, `STATE_OUT`, `CONST` |
|
|
106
|
+
| Logic | `AND`, `OR`, `XOR`, `NOT` |
|
|
107
|
+
| Memory | `RS`, `SR`, `R_TRIG`, `F_TRIG` |
|
|
108
|
+
| Timers | `TON`, `TOF`, `TP`, `BLINK` |
|
|
109
|
+
| Counters | `CTU`, `CTD`, `CTUD` |
|
|
110
|
+
| Comparison | `GT`, `GE`, `LT`, `LE`, `EQ`, `NE` |
|
|
111
|
+
| Arithmetic | `ADD`, `SUB`, `MUL`, `DIV`, `MIN`, `MAX`, `ROUND` |
|
|
112
|
+
| Conversion | `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME`, `TO_STRING`, `CONCAT` |
|
|
113
|
+
| Control | `HYST`, `RAMP`, `PT1`, `PID` |
|
|
114
|
+
| Calendar | `CLOCK`, `TIMEWINDOW`, `SCHEDULE`, `ASTRO` |
|
|
115
|
+
| Messages | `LOG`, `NOTIFY`, `SENDTO` |
|
|
116
|
+
| Expert | `JS` |
|
|
117
|
+
|
|
118
|
+
The names and the behavior follow IEC 61131-3. `AND`, `OR`, `XOR`, `ADD`, `MUL`, `MIN`, `MAX` and `CONCAT` can
|
|
119
|
+
have 2 to 16 inputs. Times are entered like `500ms`, `2s`, `1m30s` or `T#2s`, times of day like `08:30`.
|
|
120
|
+
|
|
121
|
+
The control blocks:
|
|
122
|
+
|
|
123
|
+
- `HYST` - two-point switch: `Q` goes on when `IN` rises above `HIGH` and off when it falls below `LOW`; in between
|
|
124
|
+
it stays as it is. A heating that switches on below `LOW` takes `Q` inverted (`NOT`, or an inverted input).
|
|
125
|
+
- `RAMP` - `OUT` follows `IN`, but changes by at most `UP` per second upwards and `DOWN` per second downwards; `0`
|
|
126
|
+
does not limit. It starts at `IN`.
|
|
127
|
+
- `PT1` - low pass of the first order: `OUT` follows `IN` with the time constant `T` (after `T`, 63 % of a step are
|
|
128
|
+
reached). Smooths a noisy value; it starts at `IN`.
|
|
129
|
+
- `PID` - PID controller: set point `SP`, process value `PV`, output `Y` between `YMIN` and `YMAX`. `KP` is the gain,
|
|
130
|
+
`TN` the reset time of the integral part, `TV` the derivative time; `TN` or `TV` of `0` leaves that part out.
|
|
131
|
+
While `Y` is at a limit, the integral part does not grow further (anti-windup); the derivative is taken from `PV`,
|
|
132
|
+
so a new set point gives no kick. `RST` clears the integral part.
|
|
133
|
+
|
|
134
|
+
`RAMP`, `PT1` and `PID` depend on time: a diagram with them runs cyclically.
|
|
135
|
+
|
|
136
|
+
Timers and counters:
|
|
137
|
+
|
|
138
|
+
- `BLINK` - while `EN` is true, `Q` is true for `TH` and false for `TL`, beginning with true.
|
|
139
|
+
- `CTU` counts the rising edges of `CU`; `R` sets `CV` back to 0, `Q` is true once `CV` reached `PV`. `CTD`
|
|
140
|
+
counts down on `CD`, `LD` loads `PV`, `Q` is true at 0 and below. `CTUD` does both; `R` goes before `LD`, and
|
|
141
|
+
edges of `CU` and `CD` in the same cycle cancel out. An input that is already true when the script starts is no
|
|
142
|
+
edge. The count is not kept over a restart of the script.
|
|
143
|
+
|
|
144
|
+
Conversion: `TO_BOOL`, `TO_INT`, `TO_REAL`, `TO_TIME` and `TO_STRING` take any type. `TO_INT` rounds, a decimal
|
|
145
|
+
comma counts as a point, and what is no number gives 0; `TO_TIME` reads a number as ms and a text like `2s` or
|
|
146
|
+
`08:30`. `CONCAT` joins its inputs into one text - numbers as they are, so round them with `ROUND` first (`DIGITS`
|
|
147
|
+
decimals, 0 to 10).
|
|
148
|
+
|
|
149
|
+
The calendar:
|
|
150
|
+
|
|
151
|
+
- `CLOCK` - the local time: `TOD` (time of day), `HOUR`, `MIN`, `WDAY` (1 Monday ... 7 Sunday), `DAY`, `MONTH`,
|
|
152
|
+
`YEAR`.
|
|
153
|
+
- `TIMEWINDOW` - `Q` is true from `START` to `END` on the chosen days (every day, Monday to Friday, Saturday and
|
|
154
|
+
Sunday). A window over midnight, like `22:00` to `06:00`, belongs to the day it starts on: on Monday to Friday it
|
|
155
|
+
lasts from Friday night into Saturday morning, but not from Sunday night into Monday.
|
|
156
|
+
- `SCHEDULE` - `Q` is true for one cycle when the time of the cron pattern comes, like `0 8 * * 1-5` for 8:00 on
|
|
157
|
+
Monday to Friday, or with seconds in front `*/5 * * * * *` for every 5 seconds. The button next to the field opens the dialog for the pattern.
|
|
158
|
+
- `ASTRO` - `Q` is true from one event of the sun to another, like from `sunset` to `sunrise`, each with an offset
|
|
159
|
+
in minutes. `START` and `END` are the times of the two events today. The position is the one in the settings of
|
|
160
|
+
the adapter; without it there are no times, and `Q` stays false.
|
|
161
|
+
|
|
162
|
+
`CLOCK`, `TIMEWINDOW` and `ASTRO` make a diagram run cyclically. `SCHEDULE` does not: when its time comes, the
|
|
163
|
+
diagram runs at once, and once more right after it to end the pulse.
|
|
164
|
+
|
|
165
|
+
- `STATE_IN` reads a state and converts it to the chosen type (`BOOL`, `INT`, `REAL`, `STRING`). A value that
|
|
166
|
+
cannot be converted is reported once in the log and read as 0. When the state ID changes - picked in the dialog
|
|
167
|
+
or typed - the type is taken from the object of the state, and a block that still has its first name is named
|
|
168
|
+
after the state. The type can be set differently afterwards; it is taken again only with the next ID.
|
|
169
|
+
- `STATE_OUT` writes a state only when the value changes. `Minimum time between writes` limits how often it
|
|
170
|
+
writes; the last value is written when the time is over.
|
|
171
|
+
- `CONST` is a value of the chosen type. Linked to an input of another type, it takes the type of the input and
|
|
172
|
+
keeps its value as far as it goes (`"0"` becomes 0 ms for a `TIME`) - unless it feeds other inputs already that
|
|
173
|
+
the new type would not fit.
|
|
174
|
+
|
|
175
|
+
The messages:
|
|
176
|
+
|
|
177
|
+
- `LOG` writes a line into the log of ioBroker, with the chosen level (`info`, `warn`, `error`, `debug`): on a
|
|
178
|
+
rising edge of `TRIG`, or whenever `IN` changes. `%s` in the text is the value of `IN`. At most 20 lines a minute -
|
|
179
|
+
a diagram that runs every 200 ms would flood the log otherwise; the 20th line says so.
|
|
180
|
+
- `NOTIFY` sends the text as a notification of ioBroker - a message or an alert - and `SENDTO` to an adapter like
|
|
181
|
+
`telegram.0`, `pushover.0` or `email.0`, as `{ text, message, title, subject }` with the chosen command (`send`).
|
|
182
|
+
Both send when `LOG` would write, at most 5 times a minute; the log says when more were left out.
|
|
183
|
+
|
|
184
|
+
The expert block `JS` runs code of its own. The code is the body of a function that gets the inputs `IN1` ...
|
|
185
|
+
`INn` (0 to 8, of any type), `dt` (ms since the last cycle), `firstScan` and `state` - an object that is kept from
|
|
186
|
+
one cycle to the next. It returns the value of `OUT1`, or an array `[OUT1, OUT2, ...]` for more outputs (1 to 8);
|
|
187
|
+
where it gives `undefined`, an output keeps its value. The outputs may be connected to inputs of any type, so the
|
|
188
|
+
code has to put out what they expect.
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
// counts how often IN1 went above IN2
|
|
192
|
+
if (IN1 > IN2 && !state.above) {
|
|
193
|
+
state.count = (state.count || 0) + 1;
|
|
194
|
+
}
|
|
195
|
+
state.above = IN1 > IN2;
|
|
196
|
+
return state.count || 0;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The code runs in the script of the diagram, so it can call the functions of scripts like `log()` - but it should
|
|
200
|
+
not wait for anything: the next block needs its outputs at once. A syntax error is shown before the diagram is
|
|
201
|
+
saved, an error when it runs at the block.
|
|
202
|
+
|
|
203
|
+
Signal types: `BOOL`, `INT`, `REAL`, `TIME`, `STRING`. An `INT` may be connected to a `REAL` input; other
|
|
204
|
+
conversions are not done by themselves.
|
|
205
|
+
|
|
206
|
+
## Own blocks
|
|
207
|
+
|
|
208
|
+
A diagram can be a block itself, which other diagrams use as often as they like - like a function block in a PLC.
|
|
209
|
+
Switch on **This diagram is a block** in the settings of the diagram and give the block a name and a description.
|
|
210
|
+
|
|
211
|
+
- The inputs of the block are `FB_IN` blocks, its outputs `FB_OUT` blocks (category **Interface**, only offered in
|
|
212
|
+
the diagram of a block). The pin name is what the input or output is called on the block; `FB_IN` also has a type
|
|
213
|
+
and the value the input has when it is not connected.
|
|
214
|
+
- A block has no access to states: `STATE_IN` and `STATE_OUT` are not allowed in it, `CONST` is. It may use other
|
|
215
|
+
own blocks, but not itself.
|
|
216
|
+
- Every instance has its own state - two instances of a block with a timer time independently.
|
|
217
|
+
- The script of a block does nothing when it runs; the block only works in the diagrams that use it.
|
|
218
|
+
|
|
219
|
+
The blocks of all diagrams are offered in the palette under **Own blocks**. The diagram that uses a block stores a
|
|
220
|
+
copy of it, and with it the version: every saved change of a block is a new version. The diagrams that use an older
|
|
221
|
+
one keep working with it and show a notice - **Update** in the properties of an instance takes the new version into
|
|
222
|
+
the diagram, **Open block** opens the diagram of the block. Links to inputs or outputs that no longer exist are
|
|
223
|
+
removed by the update.
|
|
224
|
+
|
|
225
|
+
Because the copy is stored with the diagram, a diagram keeps working when the block is deleted, and it can be
|
|
226
|
+
exported and imported alone. Copying instances into another diagram takes the block along.
|
|
227
|
+
|
|
228
|
+
An error in a block is reported at the instance that ran it, in the editor and in the log.
|
|
229
|
+
|
|
230
|
+
## Execution
|
|
231
|
+
|
|
232
|
+
The blocks run in the order of the data flow; the number in the corner of each block is its position. Blocks that
|
|
233
|
+
could run at the same time run from left to right, then from top to bottom.
|
|
234
|
+
|
|
235
|
+
- **Event driven**: when no block depends on time, the diagram runs whenever an input changes. Changes within
|
|
236
|
+
20 ms run together in one cycle.
|
|
237
|
+
- **Cyclic**: as soon as the diagram contains a timer, it runs every 200 ms (50 ms to 10 s, see the settings of
|
|
238
|
+
the diagram), and additionally right after an input changed.
|
|
239
|
+
|
|
240
|
+
The execution mode is chosen automatically, or can be set in the settings of the diagram.
|
|
241
|
+
|
|
242
|
+
A loop is only allowed through a block that stores a value (timer, counter, flip-flop, edge, control block,
|
|
243
|
+
`JS`, own block): the link that leads back
|
|
244
|
+
reads what that block put out in the previous cycle and is drawn as a double line. A loop without such a block
|
|
245
|
+
is an error.
|
|
246
|
+
|
|
247
|
+
A timer counts from the cycle in which it sees its input change, so it never expires before its time - at most
|
|
248
|
+
one cycle later.
|
|
249
|
+
|
|
250
|
+
## Limits
|
|
251
|
+
|
|
252
|
+
- Not for safety related functions. A diagram runs in a script of ioBroker, without real time guarantees.
|
|
253
|
+
- The state of the blocks is not kept over a restart of the script.
|
|
254
|
+
- Not yet available: breakpoints inside an own block, a manual execution order, links routed around blocks.
|
|
255
|
+
|
|
256
|
+
## Storage
|
|
257
|
+
|
|
258
|
+
The diagram is stored in the script itself, as the last line of `common.source` (`//#fbd:{...}`); the lines above
|
|
259
|
+
are the generated code. The diagram includes the copies of the own blocks it uses. The blocks of the library are implemented in the module `@iobroker/fb-runtime`, which comes with the
|
|
260
|
+
adapter, and not copied into every script.
|
package/docs/en/javascript.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
## Content
|
|
2
|
-
- [Note](#note)
|
|
3
2
|
- [Global functions](#global-functions)
|
|
4
3
|
- [Best practice](#best-practice)
|
|
5
4
|
|
|
6
|
-
- [Functions](#following-functions-can-be-used-in-scripts)
|
|
5
|
+
- [Functions](#the-following-functions-can-be-used-in-scripts)
|
|
7
6
|
- [require - load some module](#require---load-some-module)
|
|
8
7
|
- [console - Gives out the message into log](#console---gives-out-the-message-into-log)
|
|
9
8
|
- [exec - execute some OS command, like "cp file1 file2"](#exec---execute-some-os-command-like-cp-file1-file2)
|
|
@@ -90,7 +89,6 @@
|
|
|
90
89
|
- [registerNotification](#registerNotification)
|
|
91
90
|
|
|
92
91
|
- [Scripts activity](#scripts-activity)
|
|
93
|
-
- [Changelog](#changelog)
|
|
94
92
|
|
|
95
93
|
## Global functions
|
|
96
94
|
You can define the global scripts in the `global` folder.
|
|
@@ -146,7 +144,7 @@ exec('ls /var/log', (error, stdout, stderr) => {
|
|
|
146
144
|
Node.js uses /bin/sh to execute commands. If you want to use another shell, you can use the option object as described in the [Node.js documentation](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback) for child_process.exec.
|
|
147
145
|
It is the best practice to always use fill path names to commands to make sure the right command is executed.
|
|
148
146
|
|
|
149
|
-
**Notice:** you must enable *Enable command "
|
|
147
|
+
**Notice:** you must enable *Enable command "exec"* option to call it.
|
|
150
148
|
|
|
151
149
|
### on - Subscribe on changes or updates of some state
|
|
152
150
|
```js
|
|
@@ -243,29 +241,29 @@ You can use the following parameters to specify the trigger:
|
|
|
243
241
|
| oldAck | bool | Acknowledged state of previous value is equal to given one |
|
|
244
242
|
| oldQ | number | Quality code state of previous value is equal to given one. You can use '*' for matching to any code |
|
|
245
243
|
| | | |
|
|
246
|
-
| ts |
|
|
247
|
-
| tsGt |
|
|
248
|
-
| tsGe |
|
|
249
|
-
| tsLt |
|
|
250
|
-
| tsLe |
|
|
244
|
+
| ts | number | New value time stamp must be equal to given one (state.ts == ts) |
|
|
245
|
+
| tsGt | number | New value time stamp must be greater than given one (state.ts > ts) |
|
|
246
|
+
| tsGe | number | New value time stamp must be greater or equal to given one (state.ts >= ts) |
|
|
247
|
+
| tsLt | number | New value time stamp must be smaller than given one (state.ts < ts) |
|
|
248
|
+
| tsLe | number | New value time stamp must be smaller or equal to given one (state.ts <= ts) |
|
|
251
249
|
| | | |
|
|
252
|
-
| oldTs |
|
|
253
|
-
| oldTsGt |
|
|
254
|
-
| oldTsGe |
|
|
255
|
-
| oldTsLt |
|
|
256
|
-
| oldTsLe |
|
|
250
|
+
| oldTs | number | Previous time stamp must be equal to given one (oldState.ts == ts) |
|
|
251
|
+
| oldTsGt | number | Previous time stamp must be greater than given one (oldState.ts > ts) |
|
|
252
|
+
| oldTsGe | number | Previous time stamp must be greater or equal to given one (oldState.ts >= ts) |
|
|
253
|
+
| oldTsLt | number | Previous time stamp must be smaller than given one (oldState.ts < ts) |
|
|
254
|
+
| oldTsLe | number | Previous time stamp must be smaller or equal to given one (oldState.ts <= ts) |
|
|
257
255
|
| | | |
|
|
258
|
-
| lc |
|
|
259
|
-
| lcGt |
|
|
260
|
-
| lcGe |
|
|
261
|
-
| lcLt |
|
|
262
|
-
| lcLe |
|
|
256
|
+
| lc | number | Last change time stamp must be equal to given one (state.lc == lc) |
|
|
257
|
+
| lcGt | number | Last change time stamp must be greater than given one (state.lc > lc) |
|
|
258
|
+
| lcGe | number | Last change time stamp must be greater or equal to given one (state.lc >= lc) |
|
|
259
|
+
| lcLt | number | Last change time stamp must be smaller than given one (state.lc < lc) |
|
|
260
|
+
| lcLe | number | Last change time stamp must be smaller or equal to given one (state.lc <= lc) |
|
|
263
261
|
| | | |
|
|
264
|
-
| oldLc |
|
|
265
|
-
| oldLcGt |
|
|
266
|
-
| oldLcGe |
|
|
267
|
-
| oldLcLt |
|
|
268
|
-
| oldLcLe |
|
|
262
|
+
| oldLc | number | Previous last change time stamp must be equal to given one (oldState.lc == lc) |
|
|
263
|
+
| oldLcGt | number | Previous last change time stamp must be greater than given one (oldState.lc > lc) |
|
|
264
|
+
| oldLcGe | number | Previous last change time stamp must be greater or equal to given one (oldState.lc >= lc) |
|
|
265
|
+
| oldLcLt | number | Previous last change time stamp must be smaller than given one (oldState.lc < lc) |
|
|
266
|
+
| oldLcLe | number | Previous last change time stamp must be smaller or equal to given one (oldState.lc <= lc) |
|
|
269
267
|
| | | |
|
|
270
268
|
| channelId | string | Channel ID must be equal to given one |
|
|
271
269
|
| | RegExp | Channel ID matched to regular expression |
|
|
@@ -563,7 +561,7 @@ on({ astro: 'sunset', shift: 10 }, () => {
|
|
|
563
561
|
});
|
|
564
562
|
```
|
|
565
563
|
|
|
566
|
-
|
|
564
|
+
### scheduleById
|
|
567
565
|
```js
|
|
568
566
|
scheduleById(id, callback);
|
|
569
567
|
scheduleById(id, ack, callback);
|
|
@@ -655,7 +653,7 @@ If the first attribute is string, the function will try to parse the string as J
|
|
|
655
653
|
```js
|
|
656
654
|
getAstroDate(pattern, date, offsetMinutes);
|
|
657
655
|
```
|
|
658
|
-
Returns a javascript Date object for the specified astro-name (e.g. `"sunrise"` or `"sunriseEnd"`). For valid values, see the list of allowed values in the [Astro](#astro
|
|
656
|
+
Returns a javascript Date object for the specified astro-name (e.g. `"sunrise"` or `"sunriseEnd"`). For valid values, see the list of allowed values in the [Astro](#astro-function) section in the *schedule* function.
|
|
659
657
|
|
|
660
658
|
The returned Date object is calculated for the passed *date*. If no date is provided, the current day is used.
|
|
661
659
|
|
|
@@ -701,7 +699,7 @@ Time can be Date object or Date with time or just time.
|
|
|
701
699
|
|
|
702
700
|
You can use astro-names for the time definition. All 3 parameters can be set as astro time.
|
|
703
701
|
Following values are possible: `sunrise`, `sunset`, `sunriseEnd`, `sunsetStart`, `dawn`, `dusk`, `nauticalDawn`, `nauticalDusk`, `nightEnd`, `night`, `goldenHourEnd`, `goldenHour`.
|
|
704
|
-
See [Astro](#astro
|
|
702
|
+
See [Astro](#astro-function) for detail.
|
|
705
703
|
|
|
706
704
|
```js
|
|
707
705
|
log(compareTime('sunsetStart', 'sunsetEnd', 'between') ? 'Now is sunrise' : 'Now is no sunrise');
|
|
@@ -1205,7 +1203,7 @@ The following commands are supported:
|
|
|
1205
1203
|
- `'updateMultihost'`
|
|
1206
1204
|
- `'upgradeController'` - Upgrade js-controller to newest version
|
|
1207
1205
|
- `'getInterfaces'` - Returns all available network interfaces of the system
|
|
1208
|
-
- `'
|
|
1206
|
+
- `'upload'` - Starts an adapter upload
|
|
1209
1207
|
- `'rebuildAdapter'`
|
|
1210
1208
|
- `'readBaseSettings'`
|
|
1211
1209
|
- `'writeBaseSettings'`
|
|
@@ -1226,7 +1224,7 @@ sendToHost('myComputer', 'cmdExec', { data: 'ls /' }, (res) => {
|
|
|
1226
1224
|
});
|
|
1227
1225
|
```
|
|
1228
1226
|
|
|
1229
|
-
**Notice:** you must enable *Enable command "
|
|
1227
|
+
**Notice:** you must enable *Enable command "sendToHost"* option to call it.
|
|
1230
1228
|
|
|
1231
1229
|
### sendToHostAsync
|
|
1232
1230
|
```js
|
|
@@ -2049,7 +2047,7 @@ readFile('0_userdata.0', 'test.jpg', (err, data, mimeType) => {
|
|
|
2049
2047
|
});
|
|
2050
2048
|
```
|
|
2051
2049
|
|
|
2052
|
-
|
|
2050
|
+
### registerNotification
|
|
2053
2051
|
|
|
2054
2052
|
*Requires version >= 8.8.0*
|
|
2055
2053
|
|