drakongen 1.0.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/.vscode/launch.json +18 -0
- package/LICENSE +24 -0
- package/README.md +80 -0
- package/browser/drakongen.js +1303 -0
- package/browsertest.html +84 -0
- package/buildbrowser +4 -0
- package/buildexamples.js +61 -0
- package/examples/00.Empty.drakon +1 -0
- package/examples/00.Empty.txt +5 -0
- package/examples/01. /320/221/320/265/320/273/321/213/320/270/314/206.drakon" +13 -0
- package/examples/01. /320/221/320/265/320/273/321/213/320/271.json" +16 -0
- package/examples/01. /320/221/320/265/320/273/321/213/320/271.txt" +4 -0
- package/examples/02. /320/247/320/265/314/210/321/200/320/275/321/213/320/270/314/206.drakon" +28 -0
- package/examples/02. /320/247/321/221/321/200/320/275/321/213/320/271.json" +31 -0
- package/examples/02. /320/247/321/221/321/200/320/275/321/213/320/271.txt" +10 -0
- package/examples/03. /320/241/320/265/321/200/321/213/320/270/314/206.drakon" +20 -0
- package/examples/03. /320/241/320/265/321/200/321/213/320/271.json" +23 -0
- package/examples/03. /320/241/320/265/321/200/321/213/320/271.txt" +6 -0
- package/examples/04. /320/221/321/203/321/200/321/213/320/270/314/206.drakon" +25 -0
- package/examples/04. /320/221/321/203/321/200/321/213/320/271.json" +29 -0
- package/examples/04. /320/221/321/203/321/200/321/213/320/271.txt" +7 -0
- package/examples/05. /320/226/320/265/314/210/320/273/321/202/321/213/320/270/314/206.drakon" +25 -0
- package/examples/05. /320/226/321/221/320/273/321/202/321/213/320/271.json" +29 -0
- package/examples/05. /320/226/321/221/320/273/321/202/321/213/320/271.txt" +7 -0
- package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/270/314/206.drakon" +30 -0
- package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.json" +35 -0
- package/examples/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.txt" +10 -0
- package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +42 -0
- package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.json" +49 -0
- package/examples/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.txt" +14 -0
- package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/270/314/206.drakon" +27 -0
- package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.json" +27 -0
- package/examples/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.txt" +6 -0
- package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/270/314/206.drakon" +37 -0
- package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.json" +39 -0
- package/examples/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.txt" +10 -0
- package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/270/314/206.drakon" +42 -0
- package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.json" +54 -0
- package/examples/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.txt" +16 -0
- package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/270/314/206.drakon" +37 -0
- package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.json" +39 -0
- package/examples/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.txt" +10 -0
- package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/270/314/206.drakon" +44 -0
- package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.json" +43 -0
- package/examples/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.txt" +10 -0
- package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +54 -0
- package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.json" +63 -0
- package/examples/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +18 -0
- package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/270/314/206.drakon" +64 -0
- package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.json" +73 -0
- package/examples/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.txt" +22 -0
- package/examples/15. /320/241/320/270/320/275/320/270/320/270/314/206.drakon" +54 -0
- package/examples/15. /320/241/320/270/320/275/320/270/320/271.json" +87 -0
- package/examples/15. /320/241/320/270/320/275/320/270/320/271.txt" +26 -0
- package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/270/314/206.drakon" +37 -0
- package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.json" +48 -0
- package/examples/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.txt" +13 -0
- package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/270/314/206.drakon" +39 -0
- package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.json" +41 -0
- package/examples/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +10 -0
- package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/270/314/206.drakon" +49 -0
- package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.json" +67 -0
- package/examples/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.txt" +19 -0
- package/examples/19. Lilla.drakon +39 -0
- package/examples/19. Lilla.json +45 -0
- package/examples/19. Lilla.txt +11 -0
- package/examples/Adaptive design.drakon +116 -0
- package/examples/Adaptive design.json +153 -0
- package/examples/Adaptive design.txt +47 -0
- package/examples/And test.drakon +46 -0
- package/examples/And test.json +46 -0
- package/examples/And test.txt +10 -0
- package/examples/Arrow - double exit.drakon +41 -0
- package/examples/Arrow - double exit.json +62 -0
- package/examples/Arrow - double exit.txt +14 -0
- package/examples/Complex arrow.drakon +93 -0
- package/examples/Complex arrow.json +162 -0
- package/examples/Complex arrow.txt +43 -0
- package/examples/DoubleArrow.drakon +53 -0
- package/examples/DoubleArrow.json +86 -0
- package/examples/DoubleArrow.txt +18 -0
- package/examples/Find pointing nodes.drakon +104 -0
- package/examples/Find pointing nodes.json +137 -0
- package/examples/Find pointing nodes.txt +29 -0
- package/examples/How to tune PID on a quadcopter.drakon +488 -0
- package/examples/How to tune PID on a quadcopter.json +734 -0
- package/examples/How to tune PID on a quadcopter.txt +169 -0
- package/examples/Or test.drakon +47 -0
- package/examples/Or test.json +46 -0
- package/examples/Or test.txt +10 -0
- package/examples/Silhouette test 1.drakon +47 -0
- package/examples/Silhouette test 1.json +82 -0
- package/examples/Silhouette test 1.txt +24 -0
- package/examples/Work out action-check.drakon +30 -0
- package/examples/Work out action-check.json +45 -0
- package/examples/Work out action-check.txt +9 -0
- package/examples/Workout foreach.drakon +63 -0
- package/examples/Workout foreach.json +62 -0
- package/examples/Workout foreach.txt +14 -0
- package/examples/ar01.drakon +25 -0
- package/examples/ar01.json +40 -0
- package/examples/ar01.txt +7 -0
- package/examples/ar02.drakon +30 -0
- package/examples/ar02.json +45 -0
- package/examples/ar02.txt +10 -0
- package/examples/ar03.drakon +32 -0
- package/examples/ar03.json +44 -0
- package/examples/ar03.txt +7 -0
- package/examples/ar04.drakon +37 -0
- package/examples/ar04.json +49 -0
- package/examples/ar04.txt +10 -0
- package/examples/ar05.drakon +37 -0
- package/examples/ar05.json +59 -0
- package/examples/ar05.txt +11 -0
- package/examples/ar06.drakon +40 -0
- package/examples/ar06.json +70 -0
- package/examples/ar06.txt +13 -0
- package/examples/ar07.drakon +40 -0
- package/examples/ar07.json +70 -0
- package/examples/ar07.txt +13 -0
- package/examples/ar08.drakon +47 -0
- package/examples/ar08.json +81 -0
- package/examples/ar08.txt +16 -0
- package/examples/ar09.drakon +52 -0
- package/examples/ar09.json +87 -0
- package/examples/ar09.txt +17 -0
- package/examples/ar10.drakon +52 -0
- package/examples/ar10.json +88 -0
- package/examples/ar10.txt +18 -0
- package/examples/ar11.drakon +47 -0
- package/examples/ar11.json +82 -0
- package/examples/ar11.txt +17 -0
- package/examples/ar12.drakon +37 -0
- package/examples/ar12.json +49 -0
- package/examples/ar12.txt +10 -0
- package/examples/getToken.drakon +76 -0
- package/examples/getToken.json +88 -0
- package/examples/getToken.txt +41 -0
- package/examples/tmp.drakon +49 -0
- package/examples/tmp.json +82 -0
- package/examples/tmp.txt +37 -0
- package/package.json +21 -0
- package/prompts/drakonToPrompt.txt +139 -0
- package/prompts/index.txt +17 -0
- package/prompts/printPseudo.txt +116 -0
- package/src/browserTools.js +39 -0
- package/src/drakonToPromptStruct.js +44 -0
- package/src/drakonToStruct.js +416 -0
- package/src/drakongen.js +16 -0
- package/src/index.js +17 -0
- package/src/main.js +157 -0
- package/src/nodeTools.js +38 -0
- package/src/printPseudo.js +167 -0
- package/src/structFlow.js +382 -0
- package/src/technicalTree.js +84 -0
- package/src/tools.js +36 -0
- package/src/translate.js +108 -0
|
@@ -0,0 +1,1303 @@
|
|
|
1
|
+
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
|
2
|
+
|
|
3
|
+
function htmlToString(html) {
|
|
4
|
+
if (!html) return '';
|
|
5
|
+
if (!html.startsWith('<') || !html.endsWith('>')) {
|
|
6
|
+
return html.split("\n").map(line => {return line.trim()})
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const parser = new DOMParser();
|
|
10
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
11
|
+
|
|
12
|
+
const root = doc.body
|
|
13
|
+
const output = [];
|
|
14
|
+
|
|
15
|
+
root.childNodes.forEach((node) => {
|
|
16
|
+
if (node.tagName === 'P') {
|
|
17
|
+
output.push(node.textContent.trim());
|
|
18
|
+
} else if (node.tagName === 'UL') {
|
|
19
|
+
output.push('');
|
|
20
|
+
node.childNodes.forEach((item) => {
|
|
21
|
+
if (item.tagName === 'LI') {
|
|
22
|
+
output.push(`- ${item.textContent.trim()}`);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
output.push('');
|
|
26
|
+
} else if (node.tagName === 'OL') {
|
|
27
|
+
output.push('');
|
|
28
|
+
node.childNodes.forEach((item, index) => {
|
|
29
|
+
if (item.tagName === 'LI') {
|
|
30
|
+
output.push(`${index + 1}. ${item.textContent.trim()}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
output.push('');
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return output;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {htmlToString}
|
|
41
|
+
},{}],2:[function(require,module,exports){
|
|
42
|
+
const {drakonToStruct} = require("./drakonToStruct");
|
|
43
|
+
const {printPseudo} = require('./printPseudo');
|
|
44
|
+
const {addRange} = require("./tools")
|
|
45
|
+
|
|
46
|
+
function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate) {
|
|
47
|
+
var diagram = drakonToStruct(drakonJson, name, filename, translate)
|
|
48
|
+
var lines = []
|
|
49
|
+
if (diagram.params) {
|
|
50
|
+
addRange(lines, htmlToString(diagram.params))
|
|
51
|
+
lines.push("")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
lines.push(translate("Procedure") + " \"" + diagram.name + "\"")
|
|
55
|
+
lines.push("")
|
|
56
|
+
lines.push(translate("Algorithm") + ":")
|
|
57
|
+
|
|
58
|
+
if (diagram.branches.length === 0) {
|
|
59
|
+
lines.push(translate("Empty"))
|
|
60
|
+
} else if (diagram.branches.length === 1) {
|
|
61
|
+
var first = diagram.branches[0]
|
|
62
|
+
printPseudo(first, translate, lines, htmlToString)
|
|
63
|
+
} else {
|
|
64
|
+
var first = diagram.branches[0]
|
|
65
|
+
lines.push(translate("Call subroutine") + ": \"" + htmlToString(first.name) + "\"")
|
|
66
|
+
diagram.branches.forEach(branch => {
|
|
67
|
+
lines.push("")
|
|
68
|
+
lines.push(translate("Subroutine") + ": \"" + htmlToString(branch.name) + "\"")
|
|
69
|
+
printPseudo(branch, translate, lines, htmlToString)
|
|
70
|
+
lines.push(translate("End of subroutine"))
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
lines.push(translate("End of procedure"))
|
|
74
|
+
if (diagram.description) {
|
|
75
|
+
lines.push("")
|
|
76
|
+
addRange(lines, htmlToString(diagram.description))
|
|
77
|
+
lines.push("")
|
|
78
|
+
}
|
|
79
|
+
var text = lines.join("\n")
|
|
80
|
+
|
|
81
|
+
var str = JSON.stringify(diagram, null, 4)
|
|
82
|
+
return {text:text,json:str}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { drakonToPseudocode };
|
|
86
|
+
},{"./drakonToStruct":3,"./printPseudo":5,"./tools":8}],3:[function(require,module,exports){
|
|
87
|
+
const { structFlow, redirectNode } = require("./structFlow");
|
|
88
|
+
const { createError } = require("./tools");
|
|
89
|
+
|
|
90
|
+
var translate
|
|
91
|
+
|
|
92
|
+
function drakonToStruct(drakonJson, name, filename, translateFunction) {
|
|
93
|
+
translate = translateFunction
|
|
94
|
+
let drakonGraph;
|
|
95
|
+
try {
|
|
96
|
+
drakonJson = drakonJson || ""
|
|
97
|
+
drakonJson = drakonJson.trim()
|
|
98
|
+
drakonJson = drakonJson || "{}"
|
|
99
|
+
drakonGraph = JSON.parse(drakonJson);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
var message = translate("Error parsing JSON") + ": " + error.message
|
|
102
|
+
throw createError(message, filename)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const nodes = drakonGraph.items || {};
|
|
106
|
+
|
|
107
|
+
var branches = []
|
|
108
|
+
var firstNodeId = findStartNode(nodes, filename, branches)
|
|
109
|
+
|
|
110
|
+
if (!firstNodeId) {
|
|
111
|
+
return {
|
|
112
|
+
name: name,
|
|
113
|
+
params: drakonGraph.params || "",
|
|
114
|
+
description: drakonGraph.description || "",
|
|
115
|
+
branches: []
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
buildTwoWayConnections(nodes, firstNodeId)
|
|
120
|
+
|
|
121
|
+
rewireSelectsMarkLoops(nodes, filename)
|
|
122
|
+
branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
|
|
123
|
+
rewireShortcircuit(nodes, filename)
|
|
124
|
+
branches.forEach(branch => cutOffBranch(nodes, branch))
|
|
125
|
+
|
|
126
|
+
var branchTrees = structFlow(nodes, branches, filename, translate)
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
name: name,
|
|
130
|
+
params: drakonGraph.params || "",
|
|
131
|
+
description: drakonGraph.description || "",
|
|
132
|
+
branches: branchTrees
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function drakonToGraph(drakonJson, name, filename, translateFunction) {
|
|
137
|
+
translate = translateFunction
|
|
138
|
+
let drakonGraph;
|
|
139
|
+
try {
|
|
140
|
+
drakonGraph = JSON.parse(drakonJson);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
var message = translate("Error parsing JSON") + ": " + error.message
|
|
143
|
+
throw createError(message, filename)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const nodes = drakonGraph.items || {};
|
|
147
|
+
|
|
148
|
+
var branches = []
|
|
149
|
+
var firstNodeId = findStartNode(nodes, filename, branches)
|
|
150
|
+
|
|
151
|
+
if (!firstNodeId) {
|
|
152
|
+
return undefined
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
buildTwoWayConnections(nodes, firstNodeId)
|
|
156
|
+
|
|
157
|
+
rewireSelectsMarkLoops(nodes, filename)
|
|
158
|
+
rewireShortcircuit(nodes, filename)
|
|
159
|
+
branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
|
|
160
|
+
branches.forEach(branch => cutOffBranch(nodes, branch))
|
|
161
|
+
|
|
162
|
+
var branchTrees = structFlow(nodes, branches, filename, translate)
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
name: name,
|
|
166
|
+
params: drakonGraph.params || "",
|
|
167
|
+
description: drakonGraph.description || "",
|
|
168
|
+
branches: branchTrees
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
function checkBranchIsReferenced(branch, firstNodeId, filename) {
|
|
174
|
+
if (branch.id === firstNodeId) {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
if (branch.prev.length === 0) {
|
|
178
|
+
throw createError(translate("A silhouette branch is not referenced"), filename, branch.id)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function cutOffBranch(nodes, branch) {
|
|
183
|
+
var end = {
|
|
184
|
+
type: "end",
|
|
185
|
+
id: branch.id + "-end",
|
|
186
|
+
prev: []
|
|
187
|
+
}
|
|
188
|
+
nodes[end.id] = end
|
|
189
|
+
branch.next = branch.one
|
|
190
|
+
var addresses = []
|
|
191
|
+
traverseToHitBranch(nodes, branch.id, {}, (prev, node) => addFakeEnd(nodes, prev, node, end, addresses))
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function traverseToHitBranch(nodes, nodeId, visited, action) {
|
|
195
|
+
if (!nodeId) {return}
|
|
196
|
+
if (nodeId in visited) {return}
|
|
197
|
+
visited[nodeId] = true
|
|
198
|
+
var node = nodes[nodeId]
|
|
199
|
+
if (!node) {return}
|
|
200
|
+
if (node.one) {
|
|
201
|
+
var one = nodes[node.one]
|
|
202
|
+
if (one.type === "branch") {
|
|
203
|
+
action(node, one)
|
|
204
|
+
} else {
|
|
205
|
+
traverseToHitBranch(nodes, node.one, visited, action)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (node.two) {
|
|
209
|
+
var two = nodes[node.two]
|
|
210
|
+
if (two.type === "branch") {
|
|
211
|
+
action(node, two)
|
|
212
|
+
} else {
|
|
213
|
+
traverseToHitBranch(nodes, node.two, visited, action)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
var idCounter = 1000
|
|
219
|
+
function addFakeEnd(nodes, prev, node, end, addresses) {
|
|
220
|
+
var lastAddress = undefined
|
|
221
|
+
if (addresses.length > 0) {
|
|
222
|
+
lastAddress = addresses[addresses.length - 1]
|
|
223
|
+
}
|
|
224
|
+
var address
|
|
225
|
+
if (lastAddress && lastAddress.branch === node.id) {
|
|
226
|
+
address = lastAddress
|
|
227
|
+
} else {
|
|
228
|
+
address = {
|
|
229
|
+
type: "address",
|
|
230
|
+
content: node.content,
|
|
231
|
+
id: "ad-" + idCounter,
|
|
232
|
+
branch: node.id,
|
|
233
|
+
one: end.id,
|
|
234
|
+
prev: []
|
|
235
|
+
}
|
|
236
|
+
idCounter++
|
|
237
|
+
nodes[address.id] = address
|
|
238
|
+
end.prev.push(address.id)
|
|
239
|
+
addresses.push(address)
|
|
240
|
+
}
|
|
241
|
+
redirectNode(nodes, prev, node.id, address.id)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function buildTwoWayConnections(nodes, firstNodeId) {
|
|
245
|
+
for (var id in nodes) {
|
|
246
|
+
var node = nodes[id]
|
|
247
|
+
node.id = id
|
|
248
|
+
node.prev = []
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
traverse(nodes, firstNodeId, {}, connectBack)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function findStartNode(nodes, filename, branches) {
|
|
255
|
+
var firstNodeId = undefined
|
|
256
|
+
var minBranchId = 10000
|
|
257
|
+
for (var id in nodes) {
|
|
258
|
+
var node = nodes[id]
|
|
259
|
+
if (node.type === "branch") {
|
|
260
|
+
if (node.branchId < minBranchId) {
|
|
261
|
+
firstNodeId = id
|
|
262
|
+
minBranchId = node.branchId
|
|
263
|
+
}
|
|
264
|
+
branches.push(node)
|
|
265
|
+
} else if (node.type === "select") {
|
|
266
|
+
if (!node.content) {
|
|
267
|
+
throw createError(translate("A Select icon must have content"), filename, id)
|
|
268
|
+
}
|
|
269
|
+
node.cases = [];
|
|
270
|
+
} else if (node.type === "loopbegin") {
|
|
271
|
+
if (!node.content) {
|
|
272
|
+
throw createError(translate("A Loop begin icon must have content"), filename, id)
|
|
273
|
+
}
|
|
274
|
+
} else if (node.type === "question") {
|
|
275
|
+
if (!node.content) {
|
|
276
|
+
throw createError(translate("A Question icon must have content"), filename, id)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return firstNodeId
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function rewireSelectsMarkLoops(nodes, filename) {
|
|
285
|
+
for (var id of Object.keys(nodes)) {
|
|
286
|
+
var node = nodes[id]
|
|
287
|
+
if (!node) { continue }
|
|
288
|
+
if (node.type === "select") {
|
|
289
|
+
rewireSelect(nodes, node, filename)
|
|
290
|
+
} else if (node.type === "loopbegin") {
|
|
291
|
+
markLoopBody(nodes, node, filename)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function rewireSelect(nodes, selectNode, filename) {
|
|
297
|
+
var caseNodeId = selectNode.one
|
|
298
|
+
while (caseNodeId) {
|
|
299
|
+
var caseNode = nodes[caseNodeId]
|
|
300
|
+
caseNodeId = caseNode.two
|
|
301
|
+
if (caseNode.content) {
|
|
302
|
+
caseNode.type = "question"
|
|
303
|
+
caseNode.flag1 = 1
|
|
304
|
+
caseNode.content = {operator: "equal", left:selectNode.content, right:caseNode.content}
|
|
305
|
+
if (!caseNode.two) {
|
|
306
|
+
var errorId = caseNode.id + "-unexpected"
|
|
307
|
+
var errorAction = insertIcon(nodes, "error", errorId, selectNode.content)
|
|
308
|
+
errorAction.message = "Unexpected case value"
|
|
309
|
+
|
|
310
|
+
caseNode.two = errorId
|
|
311
|
+
errorAction.prev.push(caseNode.id)
|
|
312
|
+
errorAction.one = caseNode.one
|
|
313
|
+
|
|
314
|
+
var next = nodes[caseNode.one]
|
|
315
|
+
next.prev.push(errorId)
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
if (caseNode.two) {
|
|
319
|
+
throw createError(translate("Only the rightmost Case icon can be empty"), filename, caseNode.id)
|
|
320
|
+
}
|
|
321
|
+
removeNodeOne(nodes, caseNode.id)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
removeNodeOne(nodes, selectNode.id)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function insertIcon(nodes, type, id, content) {
|
|
328
|
+
var node = {
|
|
329
|
+
type: type,
|
|
330
|
+
id: id,
|
|
331
|
+
content: content,
|
|
332
|
+
prev: []
|
|
333
|
+
}
|
|
334
|
+
nodes[id] = node
|
|
335
|
+
return node
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function removeNodeOne(nodes, nodeId) {
|
|
339
|
+
var node = nodes[nodeId]
|
|
340
|
+
redirectPrev(nodes, node, node.one)
|
|
341
|
+
redirectNext(nodes, node, node.one)
|
|
342
|
+
delete nodes[nodeId]
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function removeFromNext(node, next) {
|
|
346
|
+
next.prev = next.prev.filter(prevId => prevId !== node.id)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function redirectPrev(nodes, node, newTarget) {
|
|
350
|
+
for (var prevId of node.prev) {
|
|
351
|
+
var prev = nodes[prevId]
|
|
352
|
+
if (prev.one === node.id) {
|
|
353
|
+
prev.one = newTarget
|
|
354
|
+
}
|
|
355
|
+
if (prev.two === node.id) {
|
|
356
|
+
prev.two = newTarget
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function redirectNext(nodes, node, newTarget) {
|
|
362
|
+
var target = nodes[newTarget]
|
|
363
|
+
removeFromNext(node, target)
|
|
364
|
+
for (var prevId of node.prev) {
|
|
365
|
+
target.prev.push(prevId)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function rewireShortcircuit(nodes) {
|
|
370
|
+
while (findShortcusts(nodes)) {
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function findShortcusts(nodes) {
|
|
376
|
+
for (var id in nodes) {
|
|
377
|
+
var node = nodes[id]
|
|
378
|
+
if (node.type === "question") {
|
|
379
|
+
var andOperand = findAndOperand(nodes, node)
|
|
380
|
+
if (andOperand) {
|
|
381
|
+
writeAndShortcut(nodes, node, andOperand)
|
|
382
|
+
return true
|
|
383
|
+
}
|
|
384
|
+
var orOperand = findOrOperand(nodes, node)
|
|
385
|
+
if (orOperand) {
|
|
386
|
+
writeOrShortcut(nodes, node, orOperand)
|
|
387
|
+
return true
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return false
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function findAndOperand(nodes, node) {
|
|
395
|
+
var below = nodes[node.one]
|
|
396
|
+
if (below.type === "question") {
|
|
397
|
+
if (below.prev.length === 1 && below.two === node.two) {
|
|
398
|
+
return below
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return undefined
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function findOrOperand(nodes, node) {
|
|
405
|
+
var right = nodes[node.two]
|
|
406
|
+
if (right.type === "question") {
|
|
407
|
+
if (right.prev.length === 1 && right.one === node.one) {
|
|
408
|
+
return right
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return undefined
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function writeAndShortcut(nodes, node, andOperand) {
|
|
415
|
+
var right = nodes[node.two]
|
|
416
|
+
var down = nodes[andOperand.one]
|
|
417
|
+
removeFromNext(andOperand, right)
|
|
418
|
+
removeFromNext(andOperand, down)
|
|
419
|
+
node.content = {
|
|
420
|
+
operator: "and",
|
|
421
|
+
left: normalizeContent(node),
|
|
422
|
+
right: normalizeContent(andOperand)
|
|
423
|
+
}
|
|
424
|
+
node.one = down.id
|
|
425
|
+
node.flag1 = 1
|
|
426
|
+
down.prev.push(node.id)
|
|
427
|
+
delete nodes[andOperand.id]
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function writeOrShortcut(nodes, node, orOperand) {
|
|
431
|
+
var right = nodes[orOperand.two]
|
|
432
|
+
var down = nodes[orOperand.one]
|
|
433
|
+
removeFromNext(orOperand, right)
|
|
434
|
+
removeFromNext(orOperand, down)
|
|
435
|
+
node.content = {
|
|
436
|
+
operator: "or",
|
|
437
|
+
left: normalizeContent(node),
|
|
438
|
+
right: normalizeContent(orOperand)
|
|
439
|
+
}
|
|
440
|
+
node.two = right.id
|
|
441
|
+
node.flag1 = 1
|
|
442
|
+
right.prev.push(node.id)
|
|
443
|
+
delete nodes[orOperand.id]
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function normalizeContent(question) {
|
|
447
|
+
if (question.flag1 === 1) {
|
|
448
|
+
return question.content
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
operator: "not",
|
|
453
|
+
operand: question.content
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
function traverse(nodes, nodeId, visited, action) {
|
|
459
|
+
if (!nodeId) {
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (nodeId in visited) {
|
|
464
|
+
return
|
|
465
|
+
}
|
|
466
|
+
visited[nodeId] = true
|
|
467
|
+
var node = nodes[nodeId]
|
|
468
|
+
action(nodes, node)
|
|
469
|
+
traverse(nodes, node.one, visited, action)
|
|
470
|
+
traverse(nodes, node.two, visited, action)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function connectBack(nodes, node) {
|
|
474
|
+
if (node.one) {
|
|
475
|
+
var one = nodes[node.one]
|
|
476
|
+
one.prev.push(node.id)
|
|
477
|
+
}
|
|
478
|
+
if (node.two) {
|
|
479
|
+
var two = nodes[node.two]
|
|
480
|
+
two.prev.push(node.id)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function markLoopBody(nodes, start, filename) {
|
|
485
|
+
var nextNodeId = start.one
|
|
486
|
+
while (nextNodeId) {
|
|
487
|
+
var current = nodes[nextNodeId]
|
|
488
|
+
nextNodeId = current.one
|
|
489
|
+
current.parentLoopId = start.id
|
|
490
|
+
if (current.type === "loopbegin") {
|
|
491
|
+
nextNodeId = markLoopBody(nodes, current, filename)
|
|
492
|
+
} else if (current.type === "loopend") {
|
|
493
|
+
start.end = current.id
|
|
494
|
+
start.next = current.one
|
|
495
|
+
current.start = start.id
|
|
496
|
+
return nextNodeId
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
throw createError(translate("Loop end expected here"), filename, start.one)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
module.exports = { drakonToStruct, drakonToGraph };
|
|
503
|
+
},{"./structFlow":6,"./tools":8}],4:[function(require,module,exports){
|
|
504
|
+
const { drakonToPseudocode } = require('./drakonToPromptStruct');
|
|
505
|
+
const {htmlToString} = require("./browserTools")
|
|
506
|
+
const { setUpLanguage, translate } = require("./translate")
|
|
507
|
+
const {drakonToStruct} = require("./drakonToStruct");
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
window.toPseudocode = function(drakonJson, name, filename, language) {
|
|
511
|
+
setUpLanguage(language)
|
|
512
|
+
return drakonToPseudocode(drakonJson, name, filename, htmlToString, translate).text
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
window.toTree = function(drakonJson, name, filename, language) {
|
|
516
|
+
setUpLanguage(language)
|
|
517
|
+
var result = drakonToStruct(drakonJson, name, filename, translate)
|
|
518
|
+
return JSON.stringify(result, null, 4)
|
|
519
|
+
}
|
|
520
|
+
},{"./browserTools":1,"./drakonToPromptStruct":2,"./drakonToStruct":3,"./translate":9}],5:[function(require,module,exports){
|
|
521
|
+
var {addRange} = require("./tools")
|
|
522
|
+
|
|
523
|
+
function printPseudo(algorithm, translate, output, htmlToString) {
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
function printStructuredContent(content, indent, output) {
|
|
528
|
+
var lines = printStructuredContentNoIdent(content)
|
|
529
|
+
printWithIndent(lines, indent, output)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function printWithIndent(lines, indent, output) {
|
|
533
|
+
lines.forEach(line => output.push(indent + line))
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function printStructuredContentNoIdent(content) {
|
|
537
|
+
var lines = []
|
|
538
|
+
|
|
539
|
+
if (typeof content === "string") {
|
|
540
|
+
return htmlToString(content);
|
|
541
|
+
} else if (content.operator === "not") {
|
|
542
|
+
lines = printStructuredContentNoIdent(content.operand)
|
|
543
|
+
if (lines.length > 0) {
|
|
544
|
+
lines[0] = translate("not") + " (" + lines[0] + ")"
|
|
545
|
+
}
|
|
546
|
+
} else if (content.operator === "and" || content.operator === "or") {
|
|
547
|
+
var operator = translate(content.operator)
|
|
548
|
+
printBinary(content, operator, lines)
|
|
549
|
+
} else if (content.operator === "equal") {
|
|
550
|
+
var operator = "=="
|
|
551
|
+
printBinary(content, operator, lines)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return lines;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function printBinary(content, operator, lines) {
|
|
558
|
+
const leftLines = printOperand(content.left);
|
|
559
|
+
const rightLines = printOperand(content.right);
|
|
560
|
+
if (leftLines.length === 1 && rightLines.length === 1) {
|
|
561
|
+
lines.push(leftLines[0] + " " + operator + " " + rightLines[0])
|
|
562
|
+
} else {
|
|
563
|
+
addRange(lines, leftLines)
|
|
564
|
+
lines.push(operator);
|
|
565
|
+
addRange(lines, rightLines)
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function printOperand(content) {
|
|
570
|
+
var lines = printStructuredContentNoIdent(content)
|
|
571
|
+
if (typeof content === "string" || content.operator === "not") {
|
|
572
|
+
return lines
|
|
573
|
+
}
|
|
574
|
+
if (lines.length > 0) {
|
|
575
|
+
lines[0] = "(" + lines[0]
|
|
576
|
+
last = lines.length - 1
|
|
577
|
+
lines[last] = lines[last] + ")"
|
|
578
|
+
}
|
|
579
|
+
return lines
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function makeIndent(depth) {
|
|
583
|
+
return " ".repeat(depth * 4);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function printSteps(steps, depth, output) {
|
|
587
|
+
const indent = makeIndent(depth)
|
|
588
|
+
for (var step of steps) {
|
|
589
|
+
if (step.type === "end" || step.type === "branch" || step.type === "comment") { continue }
|
|
590
|
+
if (step.type === "question") {
|
|
591
|
+
printQuestion(step, depth, output)
|
|
592
|
+
} else if (step.type === "loop") {
|
|
593
|
+
printLoop(step, depth, output)
|
|
594
|
+
} else if (step.type === "address") {
|
|
595
|
+
printAddress(step, indent, output)
|
|
596
|
+
} else if (step.type === "error") {
|
|
597
|
+
printError(step, indent, output)
|
|
598
|
+
} else if (step.type === "break") {
|
|
599
|
+
output.push(indent + translate("break"))
|
|
600
|
+
} else {
|
|
601
|
+
printOther(step, indent, output)
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function printOther(step, indent, output) {
|
|
607
|
+
if (!step.content && !step.secondary) {return}
|
|
608
|
+
if (step.secondary) {
|
|
609
|
+
printStructuredContent(step.secondary, indent, output)
|
|
610
|
+
}
|
|
611
|
+
if (step.content) {
|
|
612
|
+
printStructuredContent(step.content, indent, output)
|
|
613
|
+
}
|
|
614
|
+
output.push("")
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function printAddress(step, indent, output) {
|
|
618
|
+
var label
|
|
619
|
+
if (step.content) {
|
|
620
|
+
label = htmlToString(step.content);
|
|
621
|
+
} else {
|
|
622
|
+
label = translate("Subroutine") + " " + step.branch
|
|
623
|
+
}
|
|
624
|
+
output.push(indent + translate("Call subroutine") + " \"" + label + "\"")
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function printError(step, indent, output) {
|
|
628
|
+
output.push(indent + translate("error") + ":")
|
|
629
|
+
output.push(indent + step.message)
|
|
630
|
+
if (step.content) {
|
|
631
|
+
printStructuredContent(step.content, indent, output)
|
|
632
|
+
}
|
|
633
|
+
output.push("")
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function empty(array) {
|
|
637
|
+
return array.length === 0
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function printQuestion(step, depth, output) {
|
|
641
|
+
const indent = makeIndent(depth)
|
|
642
|
+
const indent2 = makeIndent(depth + 1)
|
|
643
|
+
var yesBody = []
|
|
644
|
+
printSteps(step.yes, depth + 1, yesBody)
|
|
645
|
+
var noBody = []
|
|
646
|
+
printSteps(step.no, depth + 1, noBody)
|
|
647
|
+
if (empty(yesBody) && empty(noBody)) {
|
|
648
|
+
yesBody.push(indent2 + translate("pass"))
|
|
649
|
+
}
|
|
650
|
+
var content = step.content
|
|
651
|
+
if (empty(yesBody)) {
|
|
652
|
+
content = {operator:"not",operand:step.content}
|
|
653
|
+
}
|
|
654
|
+
var lines = printStructuredContentNoIdent(content)
|
|
655
|
+
lines[0] = translate("if") + " " + lines[0]
|
|
656
|
+
printWithIndent(lines, indent, output)
|
|
657
|
+
if (empty(yesBody)) {
|
|
658
|
+
addRange(output, noBody)
|
|
659
|
+
} else {
|
|
660
|
+
addRange(output, yesBody)
|
|
661
|
+
if (!empty(noBody)) {
|
|
662
|
+
output.push(indent + translate("else"))
|
|
663
|
+
addRange(output, noBody)
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function printLoop(step, depth, output) {
|
|
669
|
+
const indent2 = makeIndent(depth + 1)
|
|
670
|
+
const indent = makeIndent(depth)
|
|
671
|
+
var body = []
|
|
672
|
+
printSteps(step.body, depth + 1, body)
|
|
673
|
+
if (empty(body)) {
|
|
674
|
+
body.push(indent2 + translate("pass"))
|
|
675
|
+
}
|
|
676
|
+
var content = step.content
|
|
677
|
+
if (!content) {
|
|
678
|
+
content = translate("loop forever")
|
|
679
|
+
}
|
|
680
|
+
printStructuredContent(content, indent, output)
|
|
681
|
+
addRange(output, body)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
printSteps(algorithm.body, 0, output)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
module.exports = {printPseudo}
|
|
688
|
+
},{"./tools":8}],6:[function(require,module,exports){
|
|
689
|
+
var {buildTree} = require("./technicalTree")
|
|
690
|
+
const { createError, sortByProperty } = require("./tools");
|
|
691
|
+
|
|
692
|
+
function redirectNode(nodes, node, from, to) {
|
|
693
|
+
if (node.one === from) {
|
|
694
|
+
node.one = to;
|
|
695
|
+
}
|
|
696
|
+
if (node.two === from) {
|
|
697
|
+
node.two = to;
|
|
698
|
+
}
|
|
699
|
+
if (node.next === from) {
|
|
700
|
+
node.next = to
|
|
701
|
+
}
|
|
702
|
+
if (node.start && node.type === "loopend") {
|
|
703
|
+
start = nodes[node.start]
|
|
704
|
+
if (start.next === from) {
|
|
705
|
+
start.next = to
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function structFlow(nodes, branches, filename, translate) {
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
function flowGraph(nodes, nodeId, branchingStack) {
|
|
715
|
+
if (!nodeId) {return;}
|
|
716
|
+
|
|
717
|
+
const node = nodes[nodeId];
|
|
718
|
+
|
|
719
|
+
if (!node.stack) {
|
|
720
|
+
node.stack = [];
|
|
721
|
+
node.remaining = node.prev.length;
|
|
722
|
+
}
|
|
723
|
+
node.remaining--;
|
|
724
|
+
|
|
725
|
+
mergeBranchingStack(nodes, node, branchingStack);
|
|
726
|
+
if (node.remaining > 0) {return;}
|
|
727
|
+
|
|
728
|
+
if (node.type === "question") {
|
|
729
|
+
for (let i = 0; i < node.stack.length; i++) {
|
|
730
|
+
const questionId = node.stack[i];
|
|
731
|
+
const question = nodes[questionId];
|
|
732
|
+
question.branching++;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const stackOne = node.stack.slice();
|
|
736
|
+
const stackTwo = node.stack.slice();
|
|
737
|
+
stackOne.push(nodeId);
|
|
738
|
+
stackTwo.push(nodeId);
|
|
739
|
+
|
|
740
|
+
flowGraph(nodes, node.two, stackTwo);
|
|
741
|
+
flowGraph(nodes, node.one, stackOne);
|
|
742
|
+
} else if (node.type === "arrow-loop") {
|
|
743
|
+
const stackOne = node.stack.slice();
|
|
744
|
+
stackOne.push(nodeId);
|
|
745
|
+
flowGraph(nodes, node.one, stackOne);
|
|
746
|
+
} else if (node.type === "arrow-stub") {
|
|
747
|
+
decrementBranchingForArrow(nodes, node)
|
|
748
|
+
} else {
|
|
749
|
+
flowGraph(nodes, node.one, node.stack);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function decrementBranchingForArrow(nodes, node) {
|
|
754
|
+
var algonode = nodes[node.arrow]
|
|
755
|
+
algonode.branching--
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function decrementQuestions(nodes, algonode, dictionary) {
|
|
759
|
+
var stub = nodes[algonode.stub]
|
|
760
|
+
for (var id of stub.stack) {
|
|
761
|
+
var snode = nodes[id]
|
|
762
|
+
if (id != algonode) {
|
|
763
|
+
if (id in dictionary) {
|
|
764
|
+
snode.branching--
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return stub
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
function mergeBranchingStack(nodes, node, branchingStack) {
|
|
774
|
+
// Append all elements of the branching stack to node.stack
|
|
775
|
+
addRange(node.stack, branchingStack)
|
|
776
|
+
|
|
777
|
+
// Build a dictionary of occurrences
|
|
778
|
+
const dictionary = buildDictionaryOfOccurences(node);
|
|
779
|
+
|
|
780
|
+
// Merge all nodes
|
|
781
|
+
mergeAll(nodes, node, dictionary);
|
|
782
|
+
|
|
783
|
+
// Rebuild the stack
|
|
784
|
+
node.stack = buildStackFromDictionary(dictionary);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function addRange(dst, src) {
|
|
788
|
+
for (let i = 0; i < src.length; i++) {
|
|
789
|
+
dst.push(src[i]);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
function buildStackFromDictionary(dictionary) {
|
|
794
|
+
const rebuiltStack = [];
|
|
795
|
+
for (const id in dictionary) {
|
|
796
|
+
if (dictionary[id] > 0) {
|
|
797
|
+
rebuiltStack.push(id);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return rebuiltStack;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function buildDictionaryOfOccurences(node) {
|
|
804
|
+
const dictionary = {};
|
|
805
|
+
for (let i = 0; i < node.stack.length; i++) {
|
|
806
|
+
const id = node.stack[i];
|
|
807
|
+
dictionary[id] = (dictionary[id] || 0) + 1;
|
|
808
|
+
}
|
|
809
|
+
return dictionary;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function mergeAll(nodes, node, dictionary) {
|
|
813
|
+
for (const id in dictionary) {
|
|
814
|
+
const occurrences = dictionary[id];
|
|
815
|
+
const algonode = nodes[id];
|
|
816
|
+
if (occurrences > 1) {
|
|
817
|
+
algonode.branching--;
|
|
818
|
+
dictionary[id] = occurrences - 1;
|
|
819
|
+
}
|
|
820
|
+
if (algonode.branching === 1) {
|
|
821
|
+
if (algonode.type === "arrow-loop" && !algonode.next) {
|
|
822
|
+
if (!isInMap(node.astack, id)) {
|
|
823
|
+
algonode.next = node.id
|
|
824
|
+
dictionary[algonode.id] = 0;
|
|
825
|
+
var stub = decrementQuestions(nodes, algonode, dictionary)
|
|
826
|
+
stub.one = node.id
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
for (const id in dictionary) {
|
|
833
|
+
const algonode = nodes[id];
|
|
834
|
+
if (algonode.branching === 1) {
|
|
835
|
+
if (algonode.type === "question") {
|
|
836
|
+
algonode.next = node.id;
|
|
837
|
+
dictionary[algonode.id] = 0;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function isInMap(map, key) {
|
|
843
|
+
if (!map) { return false }
|
|
844
|
+
return key in map
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
function prepareQuestions(nodes) {
|
|
848
|
+
for (const nodeId in nodes) {
|
|
849
|
+
const node = nodes[nodeId];
|
|
850
|
+
if (node.type === "question") {
|
|
851
|
+
node.branching = 2;
|
|
852
|
+
} else if (node.type === "arrow-loop") {
|
|
853
|
+
node.branching = 1;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function rewireArrows(nodes, branches) {
|
|
859
|
+
branches.forEach(branch => rewireArrowsInBranch(nodes, branch.id, branch.next, []))
|
|
860
|
+
for (var id in nodes) {
|
|
861
|
+
var node = nodes[id]
|
|
862
|
+
if (node.type === "arrow-loop") {
|
|
863
|
+
var stub = insertArrowStub(nodes, node)
|
|
864
|
+
fillAStack(nodes, stub, stub.arrow)
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function fillAStack(nodes, node, arrowId) {
|
|
870
|
+
if (!node.astack) {
|
|
871
|
+
node.astack = {}
|
|
872
|
+
}
|
|
873
|
+
node.astack[arrowId] = true
|
|
874
|
+
if (node.id === arrowId) {
|
|
875
|
+
return
|
|
876
|
+
}
|
|
877
|
+
for (var prevId of node.prev) {
|
|
878
|
+
var prev = nodes[prevId]
|
|
879
|
+
fillAStack(nodes, prev, arrowId)
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
function rewireArrowsInBranch(nodes, prevNodeId, nodeId, arrowStack) {
|
|
884
|
+
if (!nodeId) {return}
|
|
885
|
+
var node = nodes[nodeId]
|
|
886
|
+
if (node.type === "branch") {
|
|
887
|
+
return
|
|
888
|
+
}
|
|
889
|
+
if (node.type === "arrow-loop") {
|
|
890
|
+
if (!node.noloop) {
|
|
891
|
+
node.noloop = {}
|
|
892
|
+
}
|
|
893
|
+
if (arrowStack.includes(nodeId)) {
|
|
894
|
+
return
|
|
895
|
+
}
|
|
896
|
+
node.noloop[prevNodeId] = true
|
|
897
|
+
arrowStack = arrowStack.slice()
|
|
898
|
+
arrowStack.push(nodeId)
|
|
899
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
|
|
900
|
+
} else if (node.type === "question") {
|
|
901
|
+
var left = arrowStack.slice()
|
|
902
|
+
var right = arrowStack.slice()
|
|
903
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, left)
|
|
904
|
+
rewireArrowsInBranch(nodes, nodeId, node.two, right)
|
|
905
|
+
} else {
|
|
906
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack)
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function insertArrowStub(nodes, node) {
|
|
911
|
+
var stub = {
|
|
912
|
+
type: "arrow-stub",
|
|
913
|
+
id: "arrow-stub-" + node.id,
|
|
914
|
+
arrow: node.id,
|
|
915
|
+
prev: []
|
|
916
|
+
}
|
|
917
|
+
nodes[stub.id] = stub
|
|
918
|
+
node.stub = stub.id
|
|
919
|
+
var prev2 = []
|
|
920
|
+
for (var prevId of node.prev) {
|
|
921
|
+
if (prevId in node.noloop) {
|
|
922
|
+
prev2.push(prevId)
|
|
923
|
+
} else {
|
|
924
|
+
stub.prev.push(prevId)
|
|
925
|
+
var prev = nodes[prevId]
|
|
926
|
+
redirectNode(nodes, prev, node.id, stub.id)
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
node.prev = prev2
|
|
930
|
+
return stub
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function rewriteTree(body, index, endId, output) {
|
|
934
|
+
while (index < body.length) {
|
|
935
|
+
var node = body[index]
|
|
936
|
+
index++
|
|
937
|
+
if (endId && node.id === endId) {
|
|
938
|
+
return index
|
|
939
|
+
}
|
|
940
|
+
if (node.type === "question") {
|
|
941
|
+
var transformed = rewriteQuestionTree(node, output)
|
|
942
|
+
if (endId) {
|
|
943
|
+
var breakYes = findLoopEnd(transformed.yes, endId)
|
|
944
|
+
var breakNo = findLoopEnd(transformed.no, endId)
|
|
945
|
+
if (breakYes || breakNo) {
|
|
946
|
+
var toBreak = []
|
|
947
|
+
findPlacesToBreak(transformed.yes, endId, toBreak)
|
|
948
|
+
findPlacesToBreak(transformed.no, endId, toBreak)
|
|
949
|
+
addBreaks(toBreak)
|
|
950
|
+
return index
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
} else if (node.type === "loopbegin") {
|
|
954
|
+
var body2 = []
|
|
955
|
+
index = rewriteTree(body, index, node.end, body2)
|
|
956
|
+
output.push({
|
|
957
|
+
id: node.id,
|
|
958
|
+
type: "loop",
|
|
959
|
+
content: node.content,
|
|
960
|
+
body: body2
|
|
961
|
+
})
|
|
962
|
+
} else {
|
|
963
|
+
output.push(node)
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function findPlacesToBreak(body, endId, output) {
|
|
969
|
+
if (body.length === 0) {
|
|
970
|
+
output.push(body)
|
|
971
|
+
return
|
|
972
|
+
}
|
|
973
|
+
var last = body[body.length - 1]
|
|
974
|
+
if (last.id === endId) {
|
|
975
|
+
return
|
|
976
|
+
}
|
|
977
|
+
if (last.type === "question") {
|
|
978
|
+
var qends = []
|
|
979
|
+
findPlacesToBreak(last.yes, endId, qends)
|
|
980
|
+
findPlacesToBreak(last.no, endId, qends)
|
|
981
|
+
if (qends.length === 2
|
|
982
|
+
&& qends[0] === last.yes
|
|
983
|
+
&& qends[1] === last.no) {
|
|
984
|
+
output.push(body)
|
|
985
|
+
} else {
|
|
986
|
+
addRange(output, qends)
|
|
987
|
+
}
|
|
988
|
+
} else {
|
|
989
|
+
output.push(body)
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
function findLoopEnd(body, endId) {
|
|
994
|
+
for (var i = 0; i < body.length; i++) {
|
|
995
|
+
var node = body[i]
|
|
996
|
+
if (node.id === endId) {
|
|
997
|
+
if (i === body.length - 1) {
|
|
998
|
+
return true
|
|
999
|
+
} else {
|
|
1000
|
+
throw createError(
|
|
1001
|
+
translate("An exit from the loop must lead to the point right after the loop end"),
|
|
1002
|
+
filename,
|
|
1003
|
+
node.id
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (node.type === "question") {
|
|
1008
|
+
if (findLoopEnd(node.yes, endId)) {
|
|
1009
|
+
return true
|
|
1010
|
+
}
|
|
1011
|
+
if (findLoopEnd(node.no, endId)) {
|
|
1012
|
+
return true
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return false
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function addBreaks(toBreak) {
|
|
1020
|
+
for (var body of toBreak) {
|
|
1021
|
+
body.push({
|
|
1022
|
+
type: "break"
|
|
1023
|
+
})
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
function rewriteQuestionTree(question, output) {
|
|
1028
|
+
var yes = []
|
|
1029
|
+
var no = []
|
|
1030
|
+
rewriteTree(question.yes, 0, undefined, yes)
|
|
1031
|
+
rewriteTree(question.no, 0, undefined, no)
|
|
1032
|
+
var transformed = {
|
|
1033
|
+
type: "question",
|
|
1034
|
+
id: question.id,
|
|
1035
|
+
content: question.content,
|
|
1036
|
+
yes: yes,
|
|
1037
|
+
no: no
|
|
1038
|
+
}
|
|
1039
|
+
output.push(transformed)
|
|
1040
|
+
return transformed
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
function structMain() {
|
|
1045
|
+
rewireArrows(nodes, branches)
|
|
1046
|
+
prepareQuestions(nodes)
|
|
1047
|
+
var result = []
|
|
1048
|
+
for (var branch of branches) {
|
|
1049
|
+
flowGraph(nodes, branch.next, [])
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
for (var branch of branches) {
|
|
1053
|
+
var body = []
|
|
1054
|
+
buildTree(nodes, branch.next, body, "<dummy id>")
|
|
1055
|
+
var body2 = []
|
|
1056
|
+
rewriteTree(body, 0, undefined, body2)
|
|
1057
|
+
result.push({
|
|
1058
|
+
name: branch.content,
|
|
1059
|
+
branchId: branch.branchId,
|
|
1060
|
+
start: branch.next,
|
|
1061
|
+
body: body2
|
|
1062
|
+
})
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
return sortByProperty(result, "branchId")
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
return structMain()
|
|
1069
|
+
}
|
|
1070
|
+
module.exports = { structFlow, redirectNode };
|
|
1071
|
+
},{"./technicalTree":7,"./tools":8}],7:[function(require,module,exports){
|
|
1072
|
+
function buildTree(nodes, nodeId, body, stopId) {
|
|
1073
|
+
while (nodeId) {
|
|
1074
|
+
if (nodeId === stopId) {return;}
|
|
1075
|
+
const node = nodes[nodeId];
|
|
1076
|
+
let transformed;
|
|
1077
|
+
let next;
|
|
1078
|
+
|
|
1079
|
+
if (node.type === "question") {
|
|
1080
|
+
next = reserveNext(nodes, node)
|
|
1081
|
+
|
|
1082
|
+
transformed = {
|
|
1083
|
+
id: node.id,
|
|
1084
|
+
type: "question",
|
|
1085
|
+
content: node.content || "",
|
|
1086
|
+
yes: [],
|
|
1087
|
+
no: []
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
const yesNodeId = node.flag1 === 1 ? node.one : node.two;
|
|
1091
|
+
const noNodeId = node.flag1 === 1 ? node.two : node.one;
|
|
1092
|
+
|
|
1093
|
+
buildTree(nodes, yesNodeId, transformed.yes, node.next);
|
|
1094
|
+
buildTree(nodes, noNodeId, transformed.no, node.next);
|
|
1095
|
+
} else if (node.type === "arrow-loop") {
|
|
1096
|
+
transformed = {
|
|
1097
|
+
id: node.id,
|
|
1098
|
+
type: "loopbegin",
|
|
1099
|
+
content: "",
|
|
1100
|
+
end: node.stub
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
next = node.one;
|
|
1104
|
+
} else if (node.type === "arrow-stub") {
|
|
1105
|
+
transformed = {
|
|
1106
|
+
id: node.id,
|
|
1107
|
+
type: "loopend",
|
|
1108
|
+
start: node.arrow
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
next = node.one;
|
|
1112
|
+
} else {
|
|
1113
|
+
transformed = {
|
|
1114
|
+
id: node.id,
|
|
1115
|
+
type: node.type,
|
|
1116
|
+
}
|
|
1117
|
+
copyFields(
|
|
1118
|
+
transformed,
|
|
1119
|
+
node,
|
|
1120
|
+
[
|
|
1121
|
+
"content",
|
|
1122
|
+
"secondary",
|
|
1123
|
+
"start",
|
|
1124
|
+
"message",
|
|
1125
|
+
"end"
|
|
1126
|
+
]
|
|
1127
|
+
)
|
|
1128
|
+
next = node.one;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
body.push(transformed);
|
|
1132
|
+
nodeId = next;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function copyFields(dst, src, fields) {
|
|
1137
|
+
for (var field of fields) {
|
|
1138
|
+
var value = src[field]
|
|
1139
|
+
if (value !== "" && value !== undefined && value !== null) {
|
|
1140
|
+
dst[field] = value
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
function reserveNext(nodes, node) {
|
|
1146
|
+
const target = nodes[node.next];
|
|
1147
|
+
if (target.targetTaken) {
|
|
1148
|
+
return undefined;
|
|
1149
|
+
} else {
|
|
1150
|
+
target.targetTaken = true;
|
|
1151
|
+
return node.next;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
module.exports = {buildTree}
|
|
1156
|
+
|
|
1157
|
+
},{}],8:[function(require,module,exports){
|
|
1158
|
+
|
|
1159
|
+
function createError(message, filename, nodeId) {
|
|
1160
|
+
var error = new Error(message)
|
|
1161
|
+
error.nodeId = nodeId
|
|
1162
|
+
error.filename = filename
|
|
1163
|
+
return error
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
function sortByProperty(array, property, order = "asc") {
|
|
1167
|
+
if (!Array.isArray(array)) {
|
|
1168
|
+
throw new Error("First argument must be an array");
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
return array.slice().sort((a, b) => {
|
|
1172
|
+
const valA = a[property];
|
|
1173
|
+
const valB = b[property];
|
|
1174
|
+
|
|
1175
|
+
if (valA === null || valB === null || valA === undefined || valB === undefined) {
|
|
1176
|
+
return 0; // Handle null or undefined values
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (valA < valB) {
|
|
1180
|
+
return order === "asc" ? -1 : 1;
|
|
1181
|
+
}
|
|
1182
|
+
if (valA > valB) {
|
|
1183
|
+
return order === "asc" ? 1 : -1;
|
|
1184
|
+
}
|
|
1185
|
+
return 0; // Values are equal
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
function addRange(to, from) {
|
|
1189
|
+
for (var item of from) {
|
|
1190
|
+
to.push(item)
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
module.exports = { createError, sortByProperty, addRange }
|
|
1194
|
+
},{}],9:[function(require,module,exports){
|
|
1195
|
+
var translationsRu = {
|
|
1196
|
+
"error": "ОШИБКА",
|
|
1197
|
+
"not": "не",
|
|
1198
|
+
break: 'выход из цикла',
|
|
1199
|
+
"and": "и",
|
|
1200
|
+
"or": "или",
|
|
1201
|
+
"if": "Если",
|
|
1202
|
+
"else": "Иначе",
|
|
1203
|
+
"empty": "ПУСТОЙ",
|
|
1204
|
+
"loop forever": "Бесконечный цикл",
|
|
1205
|
+
"pass": "Пропустить",
|
|
1206
|
+
"Only the rightmost Case icon can be empty": "Только самая правая икона Вариант может быть пустой",
|
|
1207
|
+
"Error parsing JSON": "Ошибка парсинга JSON",
|
|
1208
|
+
"A Loop begin icon must have content": "Икона начала цикла ДЛЯ должна содержать данные",
|
|
1209
|
+
"A Question icon must have content": "Икона Вопрос должна содержать данные",
|
|
1210
|
+
"A Select icon must have content": "Икона Выбор должна содержать данные",
|
|
1211
|
+
"Loop end expected here": "Здесь ожидается конец цикла",
|
|
1212
|
+
"An exit from the loop must lead to the point right after the loop end": "Выход из цикла должен вести в точку сразу за его концом",
|
|
1213
|
+
"A silhouette branch is not referenced": "Нет ссылок на ветку силуэта",
|
|
1214
|
+
"Call subroutine": "Вызвать подпрограмму",
|
|
1215
|
+
"Procedure": "Процедура",
|
|
1216
|
+
"End of procedure": "Конец процедуры",
|
|
1217
|
+
"Subroutine": "Подпрограмма",
|
|
1218
|
+
"End of subroutine": "Конец подпрограммы",
|
|
1219
|
+
"Description": "Описание",
|
|
1220
|
+
"Algorithm": "Алгоритм",
|
|
1221
|
+
Remarks: "Замечания"
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
var translationsEn = {
|
|
1225
|
+
error: 'Error',
|
|
1226
|
+
not: 'not',
|
|
1227
|
+
break: 'break',
|
|
1228
|
+
and: 'and',
|
|
1229
|
+
or: 'or',
|
|
1230
|
+
if: 'If',
|
|
1231
|
+
else: 'Else',
|
|
1232
|
+
empty: 'Empty',
|
|
1233
|
+
'loop forever': 'Loop forever',
|
|
1234
|
+
pass: 'Pass',
|
|
1235
|
+
'Only the rightmost Case icon can be empty': 'Only the rightmost Case icon can be empty',
|
|
1236
|
+
'Error parsing JSON': 'Error parsing JSON',
|
|
1237
|
+
'A Loop begin icon must have content': 'A Loop begin icon must have content',
|
|
1238
|
+
'A Question icon must have content': 'A Question icon must have content',
|
|
1239
|
+
'A Select icon must have content': 'A Select icon must have content',
|
|
1240
|
+
'Loop end expected here': 'Loop end expected here',
|
|
1241
|
+
'An exit from the loop must lead to the point right after the loop end': 'An exit from the loop must lead to the point right after the loop end',
|
|
1242
|
+
'A silhouette branch is not referenced': 'A silhouette branch is not referenced',
|
|
1243
|
+
'Call subroutine': 'Call subroutine',
|
|
1244
|
+
Procedure: 'Procedure',
|
|
1245
|
+
'End of procedure': 'End of procedure',
|
|
1246
|
+
Subroutine: 'Subroutine',
|
|
1247
|
+
'End of subroutine': 'End of subroutine',
|
|
1248
|
+
Description: 'Description',
|
|
1249
|
+
Algorithm: 'Algorithm',
|
|
1250
|
+
Remarks: "Remarks"
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
var translationsNo = {
|
|
1254
|
+
error: 'Feil',
|
|
1255
|
+
not: 'ikke',
|
|
1256
|
+
break: 'avslutt løkken',
|
|
1257
|
+
and: 'og',
|
|
1258
|
+
or: 'eller',
|
|
1259
|
+
if: 'Hvis',
|
|
1260
|
+
else: 'Ellers',
|
|
1261
|
+
empty: 'Tom',
|
|
1262
|
+
'loop forever': 'Gjør evig',
|
|
1263
|
+
pass: 'Hopp over',
|
|
1264
|
+
'Only the rightmost Case icon can be empty': 'Bare den ytterste høyre Case-ikonet kan være tomt',
|
|
1265
|
+
'Error parsing JSON': 'Feil ved parsing av JSON',
|
|
1266
|
+
'A Loop begin icon must have content': 'Et Loop-startikon må ha innhold',
|
|
1267
|
+
'A Question icon must have content': 'Et Spørsmål-ikon må ha innhold',
|
|
1268
|
+
'A Select icon must have content': 'Et Velg-ikon må ha innhold',
|
|
1269
|
+
'Loop end expected here': 'Slutt på løkke forventet her',
|
|
1270
|
+
'An exit from the loop must lead to the point right after the loop end': 'En utgang fra løkken må føre til punktet rett etter løkkens slutt',
|
|
1271
|
+
'A silhouette branch is not referenced': 'En silhuettgren er ikke referert',
|
|
1272
|
+
'Call subroutine': 'Kall delprosedyre',
|
|
1273
|
+
Procedure: 'Prosedyre',
|
|
1274
|
+
'End of procedure': 'Slutt på prosedyre',
|
|
1275
|
+
Subroutine: 'Delprosedyre',
|
|
1276
|
+
'End of subroutine': 'Slutt på delprosedyre',
|
|
1277
|
+
Description: 'Beskrivelse',
|
|
1278
|
+
Algorithm: 'Algoritme',
|
|
1279
|
+
Remarks: "Bemerkninger"
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
var translations = translationsEn
|
|
1284
|
+
|
|
1285
|
+
function translate(text) {
|
|
1286
|
+
return translations[text] || text;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
function setUpLanguage(language) {
|
|
1290
|
+
if (language === "ru") {
|
|
1291
|
+
translations = translationsRu
|
|
1292
|
+
} else if (language === "no") {
|
|
1293
|
+
translations = translationsNo
|
|
1294
|
+
} else if (language === "en") {
|
|
1295
|
+
translations = translationsEn
|
|
1296
|
+
} else {
|
|
1297
|
+
translations = {}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
module.exports = { setUpLanguage, translate };
|
|
1303
|
+
},{}]},{},[4]);
|