Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Jake Read
ucbus-stepper
Commits
a0d55428
Commit
a0d55428
authored
Feb 14, 2021
by
Jake Read
Browse files
start submodule-based js oversight
parent
efc05ff5
Changes
34
Expand all
Hide whitespace changes
Inline
Side-by-side
.gitmodules
View file @
a0d55428
[submodule "firmware/osape-smoothieroll-drop-stepper/src/osape"]
path = firmware/osape-smoothieroll-drop-stepper/src/osape
url = ssh://git@gitlab.cba.mit.edu:846/jakeread/osape.git
[submodule "controller/osapjs"]
path = controller/osapjs
url = ssh://git@gitlab.cba.mit.edu:846/jakeread/osapjs.git
controller/.gitignore
0 → 100644
View file @
a0d55428
/node_modules
\ No newline at end of file
controller/cl-tuner.js
0 → 100644
View file @
a0d55428
/*
clank controller init
serves client modules, bootstraps local scripts from client ui.
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the open systems assembly protocol (OSAP) project.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
// new year new bootstrap
const
express
=
require
(
'
express
'
)
const
app
=
express
()
// this include lets us read data out of put requests,
const
bodyparser
=
require
(
'
body-parser
'
)
// our fs tools,
const
fs
=
require
(
'
fs
'
)
//const filesys = require('./filesys.js')
// and we occasionally spawn local pipes (workers)
const
child_process
=
require
(
'
child_process
'
)
// will use these to figure where tf we are
let
ownIp
=
''
const
os
=
require
(
'
os
'
)
// serve everything: https://expressjs.com/en/resources/middleware/serve-static.html
app
.
use
(
express
.
static
(
__dirname
))
// accept post bodies as json,
app
.
use
(
bodyparser
.
json
())
app
.
use
(
bodyparser
.
urlencoded
({
extended
:
true
}))
// redirect traffic to /client,
app
.
get
(
'
/
'
,
(
req
,
res
)
=>
{
res
.
redirect
(
'
/client
'
)
})
// we also want to institute some pipes: this is a holdover for a better system
// more akin to nautilus, where server-side graphs are manipulated
// for now, we just want to dive down to a usb port, probably, so this shallow link is OK
let
processes
=
[]
app
.
get
(
'
/startLocal/:file
'
,
(
req
,
res
)
=>
{
// launches another node instance at this file w/ these args,
let
args
=
''
if
(
req
.
query
.
args
){
args
=
req
.
query
.
args
.
split
(
'
,
'
)
}
console
.
log
(
`attempt to start
${
req
.
params
.
file
}
with args
${
args
}
`
)
// startup, let's spawn,
const
process
=
child_process
.
spawn
(
'
node
'
,
[
'
-r
'
,
'
esm
'
,
`local/
${
req
.
params
.
file
}
`
])
// add our own tag,
process
.
fileName
=
req
.
params
.
file
let
replied
=
false
let
pack
=
''
process
.
stdout
.
on
(
'
data
'
,
(
buf
)
=>
{
// these emerge as buffers,
let
msg
=
buf
.
toString
()
// can only reply once to xhr req
if
(
msg
.
includes
(
'
OSAP-wss-addr:
'
)
&&
!
replied
){
res
.
send
(
msg
)
replied
=
true
}
// ok, dealing w/ newlines
pack
=
pack
.
concat
(
msg
)
let
index
=
pack
.
indexOf
(
'
\n
'
)
while
(
index
>=
0
){
console
.
log
(
`
${
process
.
fileName
}
${
process
.
pid
}
:
${
pack
.
substring
(
0
,
index
)}
`
)
pack
=
pack
.
slice
(
index
+
1
)
index
=
pack
.
indexOf
(
'
\n
'
)
}
})
process
.
stderr
.
on
(
'
data
'
,
(
err
)
=>
{
if
(
!
replied
){
res
.
send
(
'
err in local script
'
)
replied
=
true
}
console
.
log
(
`
${
process
.
fileName
}
${
process
.
pid
}
err:`
,
err
.
toString
())
})
process
.
on
(
'
close
'
,
(
code
)
=>
{
console
.
log
(
`
${
process
.
fileName
}
${
process
.
pid
}
closes:`
,
code
)
if
(
!
replied
){
res
.
send
(
'
local process closed
'
)
replied
=
true
}
})
console
.
log
(
`started
${
process
.
fileName
}
w/ pid
${
process
.
pid
}
`
)
})
// finally, we tell the express server to listen here:
let
port
=
8080
app
.
listen
(
port
)
// once we're listening, report our IP:
let
ifaces
=
os
.
networkInterfaces
()
// this just logs the processes IP's to the termina
Object
.
keys
(
ifaces
).
forEach
(
function
(
ifname
)
{
var
alias
=
0
;
ifaces
[
ifname
].
forEach
(
function
(
iface
)
{
if
(
'
IPv4
'
!==
iface
.
family
){
//} || iface.internal !== false) {
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
return
;
}
ownIp
=
iface
.
address
if
(
alias
>=
1
)
{
console
.
log
(
'
clank-tool available on:
\t
'
/*ifname + ':' + alias,*/
+
iface
.
address
+
`:
${
port
}
`
);
// this single interface has multiple ipv4 addresses
// console.log('serving at: ' ifname + ':' + alias + iface.address + `:${port}`);
}
else
{
console
.
log
(
'
clank-tool available on:
\t
'
/*ifname + ':' + alias,*/
+
iface
.
address
+
`:
${
port
}
`
);
// this interface has only one ipv4 adress
//console.log(ifname, iface.address);
}
++
alias
;
});
});
controller/client/clankClient.js
0 → 100644
View file @
a0d55428
This diff is collapsed.
Click to expand it.
controller/client/clankVirtualMachine.js
0 → 100644
View file @
a0d55428
/*
clankVirtualMachine.js
vm for Clank-CZ
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2021
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the open systems assembly protocol (OSAP) project.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
import
{
TS
,
PK
,
DK
,
AK
,
EP
}
from
'
../osapjs/core/ts.js
'
import
TempVM
from
'
./tempVirtualMachine.js
'
import
MotorVM
from
'
./motorVirtualMachine.js
'
/* bus ID (osap maps +1)
X: 0
YL: 1
YR: 2, term
Z: 3
TCS: 4
E: 5
HE: 6
LC: 7
BED: 8
*/
export
default
function
ClankVM
(
osap
,
route
)
{
// ------------------------------------------------------ MOTION
// ok: we make an 'endpoint' that will transmit moves,
let
moveEP
=
osap
.
endpoint
()
// add the machine head's route to it,
moveEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
1
),
512
)
// and set a long timeout,
moveEP
.
setTimeoutLength
(
60000
)
// move like: { position: {X: num, Y: num, Z: num}, rate: num }
this
.
addMoveToQueue
=
(
move
)
=>
{
// write the gram,
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
20
)
// write rate
wptr
+=
TS
.
write
(
'
float32
'
,
move
.
rate
,
datagram
,
wptr
,
true
)
// write posns
wptr
+=
TS
.
write
(
'
float32
'
,
move
.
position
.
X
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
move
.
position
.
Y
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
move
.
position
.
Z
,
datagram
,
wptr
,
true
)
if
(
move
.
position
.
E
)
{
//console.log(move.position.E)
wptr
+=
TS
.
write
(
'
float32
'
,
move
.
position
.
E
,
datagram
,
wptr
,
true
)
}
else
{
wptr
+=
TS
.
write
(
'
float32
'
,
0
,
datagram
,
wptr
,
true
)
}
// do the networking,
return
new
Promise
((
resolve
,
reject
)
=>
{
moveEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// to set the current position,
let
setPosEP
=
osap
.
endpoint
()
setPosEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
2
),
512
)
setPosEP
.
setTimeoutLength
(
10000
)
this
.
setPos
=
(
pos
)
=>
{
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
16
)
wptr
+=
TS
.
write
(
'
float32
'
,
pos
.
X
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
pos
.
Y
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
pos
.
Z
,
datagram
,
wptr
,
true
)
if
(
pos
.
E
)
{
wptr
+=
TS
.
write
(
'
float32
'
,
pos
.
E
,
datagram
,
wptr
,
true
)
}
else
{
wptr
+=
TS
.
write
(
'
float32
'
,
0
,
datagram
,
wptr
,
true
)
}
// ship it
return
new
Promise
((
resolve
,
reject
)
=>
{
setPosEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// an a 'query' to check current position
let
posQuery
=
osap
.
query
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
2
),
512
)
this
.
getPos
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
posQuery
.
pull
().
then
((
data
)
=>
{
let
pos
=
{
X
:
TS
.
read
(
'
float32
'
,
data
,
0
,
true
),
Y
:
TS
.
read
(
'
float32
'
,
data
,
4
,
true
),
Z
:
TS
.
read
(
'
float32
'
,
data
,
8
,
true
),
E
:
TS
.
read
(
'
float32
'
,
data
,
12
,
true
)
}
resolve
(
pos
)
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// another query to see if it's currently moving,
// update that endpoint so we can 'write halt' / 'write go' with a set
let
motionQuery
=
osap
.
query
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
3
),
512
)
this
.
awaitMotionEnd
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
let
check
=
()
=>
{
motionQuery
.
pull
().
then
((
data
)
=>
{
if
(
data
[
0
]
>
0
)
{
setTimeout
(
check
,
50
)
}
else
{
resolve
()
}
}).
catch
((
err
)
=>
{
reject
(
err
)
})
}
setTimeout
(
check
,
50
)
})
}
// an endpoint to write 'wait time' on the remote,
let
waitTimeEP
=
osap
.
endpoint
()
waitTimeEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
4
),
512
)
this
.
setWaitTime
=
(
ms
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
let
datagram
=
new
Uint8Array
(
4
)
TS
.
write
(
'
uint32
'
,
ms
,
datagram
,
0
,
true
)
waitTimeEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// endpoint to set per-axis accelerations,
let
accelEP
=
osap
.
endpoint
()
accelEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
5
),
512
)
this
.
setAccels
=
(
accels
)
=>
{
// float array, len 4 XYZE
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
16
)
wptr
+=
TS
.
write
(
'
float32
'
,
accels
.
X
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
accels
.
Y
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
accels
.
Z
,
datagram
,
wptr
,
true
)
if
(
accels
.
E
)
{
wptr
+=
TS
.
write
(
'
float32
'
,
accels
.
E
,
datagram
,
wptr
,
true
)
}
else
{
wptr
+=
TS
.
write
(
'
float32
'
,
0
,
datagram
,
wptr
,
true
)
}
return
new
Promise
((
resolve
,
reject
)
=>
{
accelEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
let
rateEP
=
osap
.
endpoint
()
rateEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
6
),
512
)
this
.
setRates
=
(
rates
)
=>
{
// in firmware we think of mm/sec,
// in gcode and up here we think in mm/minute
// so conversion happens here
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
16
)
wptr
+=
TS
.
write
(
'
float32
'
,
rates
.
X
/
60
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
rates
.
Y
/
60
,
datagram
,
wptr
,
true
)
wptr
+=
TS
.
write
(
'
float32
'
,
rates
.
Z
/
60
,
datagram
,
wptr
,
true
)
if
(
rates
.
E
)
{
wptr
+=
TS
.
write
(
'
float32
'
,
rates
.
E
/
60
,
datagram
,
wptr
,
true
)
}
else
{
wptr
+=
TS
.
write
(
'
float32
'
,
100
,
datagram
,
wptr
,
true
)
}
return
new
Promise
((
resolve
,
reject
)
=>
{
rateEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// ------------------------------------------------------ MOTORS
// clank cz:
// AXIS SPU INVERT
// X: 320 false
// YL: 320 true
// YR: 320 false
// Z: 924.4r false
// E: 550 true
// per bondtech, for BMG on 16 microsteps, do 415: we are 32 microsteps
// https://www.bondtech.se/en/customer-service/faq/
// however, this is measured & calibrated: 830 was extruding 75mm for a 50mm request
/* bus ID (osap maps +1)
X: 0
YL: 1
YR: 2, term
Z: 3
TCS: 4
E: 5
HE: 6
LC: 7
BED: 8
*/
this
.
motors
=
{
X
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
1
).
end
()),
YL
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
2
).
end
()),
YR
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
3
).
end
()),
Z
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
4
).
end
()),
E
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
6
).
end
()),
}
let
motorCurrents
=
[
0.5
,
0.5
,
0.5
,
0.5
,
0.5
]
this
.
setMotorCurrents
=
async
()
=>
{
try
{
await
this
.
motors
.
X
.
setCScale
(
motorCurrents
[
0
])
await
this
.
motors
.
YL
.
setCScale
(
motorCurrents
[
1
])
await
this
.
motors
.
YR
.
setCScale
(
motorCurrents
[
2
])
await
this
.
motors
.
Z
.
setCScale
(
motorCurrents
[
3
])
//await this.motors.E.setCScale(motorCurrents[4])
}
catch
(
err
)
{
console
.
error
(
'
bad motor current set
'
)
throw
err
}
}
// alias...
this
.
enableMotors
=
this
.
setMotorCurrents
this
.
disableMotors
=
async
()
=>
{
try
{
await
this
.
motors
.
X
.
setCScale
(
0
)
await
this
.
motors
.
YL
.
setCScale
(
0
)
await
this
.
motors
.
YR
.
setCScale
(
0
)
await
this
.
motors
.
Z
.
setCScale
(
0
)
await
this
.
motors
.
E
.
setCScale
(
0
)
}
catch
(
err
)
{
console
.
error
(
'
bad motor disable set
'
)
throw
err
}
}
this
.
initMotors
=
async
()
=>
{
// so, really, for these & the disable / enable / set current
// could do them all parallel: like this halts if i.e. YL fails,
// where it might just be that motor with an error... that'd be catching / continuing, accumulating
// errors, and reporting them in a group
try
{
await
this
.
motors
.
X
.
setAxisPick
(
0
)
await
this
.
motors
.
X
.
setAxisInversion
(
false
)
await
this
.
motors
.
X
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad x motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
YL
.
setAxisPick
(
1
)
await
this
.
motors
.
YL
.
setAxisInversion
(
true
)
await
this
.
motors
.
YL
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad yl motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
YR
.
setAxisPick
(
1
)
await
this
.
motors
.
YR
.
setAxisInversion
(
false
)
await
this
.
motors
.
YR
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad yr motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
Z
.
setAxisPick
(
2
)
await
this
.
motors
.
Z
.
setAxisInversion
(
false
)
await
this
.
motors
.
Z
.
setSPU
(
924.444444
)
}
catch
(
err
)
{
console
.
error
(
'
bad z motor init
'
)
throw
err
}
/*
try {
await this.motors.E.setAxisPick(3)
await this.motors.E.setAxisInversion(true)
await this.motors.E.setSPU(550)
} catch (err) {
console.error('bad e motor init')
throw err
}
*/
await
this
.
setMotorCurrents
()
}
// ------------------------------------------------------ TOOLCHANGER
let
tcServoEP
=
osap
.
endpoint
()
tcServoEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
5
).
end
(),
TS
.
endpoint
(
0
,
0
),
512
)
this
.
setTCServo
=
(
micros
)
=>
{
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
4
)
// write micros
wptr
+=
TS
.
write
(
'
uint32
'
,
micros
,
datagram
,
wptr
,
true
)
// do the shipment
return
new
Promise
((
resolve
,
reject
)
=>
{
tcServoEP
.
write
(
datagram
).
then
(()
=>
{
console
.
warn
(
'
tc set
'
,
micros
)
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
this
.
openTC
=
()
=>
{
return
this
.
setTCServo
(
2000
)
}
this
.
closeTC
=
()
=>
{
return
this
.
setTCServo
(
875
)
}
// ------------------------------------------------------ TOOL CHANGING
// tool localization for put-down & pickup, tool statefulness,
// from back left 0,0
// put-down HE at (23.8, -177) -> (23.8, -222.6) -> release -> (-17.8, -208.6) clear -> (-17.8, -183)
// { position: {X: num, Y: num, Z: num}, rate: num }
let
delay
=
(
ms
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
setTimeout
(()
=>
{
resolve
()
},
ms
)
})
}
this
.
delta
=
async
(
move
,
rate
)
=>
{
try
{
if
(
!
rate
)
rate
=
6000
await
this
.
setWaitTime
(
1
)
await
delay
(
5
)
await
this
.
awaitMotionEnd
()
let
cp
=
await
this
.
getPos
()
console
.
log
(
'
current
'
,
cp
)
await
this
.
addMoveToQueue
({
position
:
{
X
:
cp
.
X
+
move
[
0
],
Y
:
cp
.
Y
+
move
[
1
],
Z
:
cp
.
Z
+
move
[
2
]
},
rate
:
rate
})
await
delay
(
5
)
await
this
.
awaitMotionEnd
()
await
this
.
setWaitTime
(
100
)
}
catch
(
err
)
{
console
.
error
(
'
arising during delta
'
)
throw
err
}
}
this
.
goto
=
async
(
pos
,
rate
)
=>
{
try
{
if
(
!
rate
)
rate
=
6000
// set remote queue-wait-time
await
this
.
setWaitTime
(
1
)
await
delay
(
5
)
// wait for the stop
await
this
.
awaitMotionEnd
()
await
this
.
addMoveToQueue
({
position
:
{
X
:
pos
[
0
],
Y
:
pos
[
1
],
Z
:
pos
[
2
],
E
:
0
},
rate
:
rate
})
await
delay
(
5
)
await
this
.
awaitMotionEnd
()
await
this
.
setWaitTime
(
100
)
}
catch
(
err
)
{
console
.
error
(
'
during goto
'
)
throw
err
}
}
let
tools
=
[{
pickX
:
16.8
,
pickY
:
-
177
,
plunge
:
-
45.6
}]
this
.
dropTool
=
async
(
num
)
=>
{
try
{
await
this
.
awaitMotionEnd
()
await
this
.
closeTC
()
let
cp
=
await
this
.
getPos
()
await
this
.
goto
([
tools
[
num
].
pickX
,
tools
[
num
].
pickY
,
cp
.
Z
])
console
.
warn
(
'
done setup
'
)
await
this
.
delta
([
0
,
tools
[
num
].
plunge
,
0
])
await
this
.
openTC
()
await
delay
(
250
)
console
.
warn
(
'
tc open
'
)
await
this
.
delta
([
-
6
,
10
,
0
])
await
this
.
delta
([
0
,
50
,
0
])
await
this
.
goto
([
tools
[
num
].
pickX
,
tools
[
num
].
pickY
,
cp
.
Z
])
}
catch
(
err
)
{
console
.
error
(
`at T
${
num
}
drop`
)
throw
err
}
}
this
.
pickTool
=
async
(
num
)
=>
{
try
{
await
this
.
awaitMotionEnd
()
await
this
.
openTC
()
let
cp
=
await
this
.
getPos
()
await
this
.
goto
([
tools
[
num
].
pickX
,
tools
[
num
].
pickY
,
cp
.
Z
])
await
this
.
delta
([
-
6
,
0
,
0
])
await
this
.
delta
([
0
,
tools
[
num
].
plunge
+
10
,
0
])
await
this
.
delta
([
6
,
-
10
,
0
])
await
this
.
closeTC
()
await
delay
(
250
)
await
this
.
delta
([
0
,
-
tools
[
num
].
plunge
,
0
])
await
delay
(
250
)
}
catch
(
err
)
{
console
.
error
(
`at T
${
num
}
pick`
)
throw
err
}
}
// ------------------------------------------------------ HEATER JUNK
this
.
tvm
=
[]
this
.
tvm
[
0
]
=
new
TempVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
7
).
end
())
this
.
tvm
[
1
]
=
new
TempVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
9
).
end
())
}
\ No newline at end of file
controller/client/index.html
0 → 100644
View file @
a0d55428
<!DOCTYPE html>
<html>
<head>
<title>
clank-tool
</title>
<!-- these three disable caching -->
<meta
http-equiv=
"Cache-Control"
content=
"no-cache, no-store, must-revalidate"
/>
<meta
http-equiv=
"Pragma"
content=
"no-cache"
/>
<meta
http-equiv=
"Expires"
content=
"-1"
/>
</head>
<body>
<link
href=
"style.css"
rel=
"stylesheet"
>
<script
src=
"../osapjs/client/libs/jquery.min.js"
></script>
<script
src=
"../osapjs/client/libs/math.js"
type=
"text/javascript"
></script>
<script
src=
"../osapjs/client/libs/d3.js"
></script>
<script
type=
"module"
src=
"clankClient.js"
></script>
<div
id=
"wrapper"
>
<!-- bootloop puts first view inside of this div -->
</div>
</body>
</html>