refactor block generator and use some new field

This commit is contained in:
yyc12345 2020-04-11 22:51:03 +08:00
parent 4ecad56d3b
commit b24a341da6
7 changed files with 226 additions and 80 deletions

View File

@ -1,24 +1,24 @@
FONT_SIZE = 12 FONT_SIZE = 12
GRAPH_POFFSET = 40 GRAPH_POFFSET = 40 # 主体bb的p距离左边框距离
GRAPH_BOFFSET = 40 GRAPH_BOFFSET = 40 # 主体bb的b距离上边框距离
GRAPH_PSPAN = 20 GRAPH_PSPAN = 20 # 主体bb的每个p之间的水平间距
GRAPH_BSPAN = 20 GRAPH_BSPAN = 20 # 主体bb的每个b之间的垂直间距
GRAPH_LAYER_SPAN = 50 GRAPH_LAYER_SPAN = 50 # 绘图中各个bb层之间的间距
GRAPH_BB_SPAN = 25 GRAPH_BB_SPAN = 25 # 绘图中每个bb之间的距离
GRAPH_SPAN_BB_POPER = 60 # 每个bb上面挂载的oper和被挂载bb之间的垂直距离 和 每个bb上面挂载的oper的各层之间的垂直距离
GRAPH_CONTENTOFFSET_X = 40 # 绘图内容原点到左边框的距离
GRAPH_CONTENTOFFSET_Y = 40 # 绘图内容原点到顶边框的距离
BB_POFFSET = 20 BB_POFFSET = 20 # bb框中的p距离左边框距离
BB_BOFFSET = 10 BB_BOFFSET = 10 # bb框中的b距离上边框距离
BB_PSPAN = 20 BB_PSPAN = 20 # bb框每个p之间的水平间距
BB_BSPAN = 20 BB_BSPAN = 20 # bb框每个b之间的垂直间距
BB_PBSIZE = 6 BB_PBSIZE = 6 # bb框中o和b的正方形符号的边长
CELL_WIDTH = 15 CELL_WIDTH = 15
CELL_HEIGHT = 5 CELL_HEIGHT = 5
GRAPH_CONTENTOFFSET_X = 40
GRAPH_CONTENTOFFSET_Y = 40
class dbPLinkInputOutputType(object): class dbPLinkInputOutputType(object):
PIN = 0 PIN = 0
POUT = 1 POUT = 1
@ -60,31 +60,28 @@ class BBResult(object):
self.expandable = expandable self.expandable = expandable
def computSize(self): def computSize(self):
wText = max(len(self.name), len(self.assistName)) * FONT_SIZE wText = max(len(self.name), len(self.assistName)) * FONT_SIZE / 2
hText = FONT_SIZE * 4 hText = FONT_SIZE * 3
wp = 2 * BB_POFFSET + max(self.pin, self.pout) * (BB_PBSIZE + BB_PSPAN) wp = max(self.pin, self.pout) * (BB_PBSIZE + BB_PSPAN)
hb = 2 * BB_BOFFSET + max(self.bin, self.bout) * (BB_PBSIZE + BB_BSPAN) hb = max(self.bin, self.bout) * (BB_PBSIZE + BB_BSPAN)
self.width = max(wp, wText) self.width = 2 * BB_POFFSET + max(wp, wText)
self.height = max(hb, hText) self.height = 2 * BB_BOFFSET + max(hb, hText)
class pOperArrangement(object):
def __init__(self, attachedBB, sublayer):
self.attachedBB = attachedBB
self.sublayer = sublayer
class OperResult(object): class OperResult(object):
def __init__(self, name, x): def __init__(self, name):
self.name = name self.name = name
self.x = x self.x = 0.0
self.y = 0.0 self.y = 0.0
self.pinData = []
self.poutData = []
self.height = 0.0 self.height = 0.0
self.width = 0.0 self.width = 0.0
def computSize(self): def computSize(self):
wText = len(self.name) * FONT_SIZE wText = len(self.name) * FONT_SIZE / 2
hText = FONT_SIZE * 4 hText = FONT_SIZE * 3
wp = 2 * BB_POFFSET + 2 * (BB_PBSIZE + BB_PSPAN) wp = 2 * BB_POFFSET + 2 * (BB_PBSIZE + BB_PSPAN)
hb = 2 * BB_BOFFSET + 0 * (BB_PBSIZE + BB_BSPAN) hb = 2 * BB_BOFFSET + 0 * (BB_PBSIZE + BB_BSPAN)

View File

@ -5,28 +5,27 @@ import queue
def run(): def run():
exportDb = sqlite3.connect('export.db') exportDb = sqlite3.connect('export.db')
decorateDb = sqlite3.connect('decorate.db') decorateDb = sqlite3.connect('decorate.db')
exportCur = exportDb.cursor()
decorateCur = decorateDb.cursor()
# init table # init table
print('Init decorate.dll') print('Init decorate.dll')
initDecorateDb(decorateCur) initDecorateDb(decorateDb)
decorateDb.commit() decorateDb.commit()
# decorate graph # decorate graph
graphList = [] graphList = []
decorateGraph(exportCur, decorateCur, graphList) decorateGraph(exportDb, decorateDb, graphList)
# decorate each graph # decorate each graph
for i in graphList: for i in graphList:
(plocal_layer, bbMap, operMap) = buildBlock(exportCur, decorateCur, i) (plocal_layer, bbMap, operMap) = buildBlock(exportDb, decorateDb, i)
# give up all change of eexport.db (because no change) # give up all change of eexport.db (because no change)
exportDb.close() exportDb.close()
decorateDb.commit() decorateDb.commit()
decorateDb.close() decorateDb.close()
def initDecorateDb(cur): def initDecorateDb(db):
cur = db.cursor()
cur.execute("CREATE TABLE graph([graph] INTEGER, [graph_name] TEXT, [width] INTEGER, [height] INTEGER, [index] INTEGER, [belong_to] TEXT);") cur.execute("CREATE TABLE graph([graph] INTEGER, [graph_name] TEXT, [width] INTEGER, [height] INTEGER, [index] INTEGER, [belong_to] TEXT);")
cur.execute("CREATE TABLE info([target] INTEGER, [field] TEXT, [data] TEXT);") cur.execute("CREATE TABLE info([target] INTEGER, [field] TEXT, [data] TEXT);")
@ -34,7 +33,9 @@ def initDecorateDb(cur):
cur.execute("CREATE TABLE cell([belong_to_graph] INETGER, [thisobj] INTEGER, [name] TEXT, [assist_text] TEXT, [x] REAL, [y] REAL, [type] INTEGER);") cur.execute("CREATE TABLE cell([belong_to_graph] INETGER, [thisobj] INTEGER, [name] TEXT, [assist_text] TEXT, [x] REAL, [y] REAL, [type] INTEGER);")
cur.execute("CREATE TABLE link([belong_to_graph] INETGER, [thisobj] INTEGER, [delay] INTEGER, [startobj] INTEGER, [endobj] INTEGER, [start_index] INTEGER, [end_index] INTEGER, [x1] REAL, [y1] REAL, [x2] REAL, [y2] REAL);") cur.execute("CREATE TABLE link([belong_to_graph] INETGER, [thisobj] INTEGER, [delay] INTEGER, [startobj] INTEGER, [endobj] INTEGER, [start_index] INTEGER, [end_index] INTEGER, [x1] REAL, [y1] REAL, [x2] REAL, [y2] REAL);")
def decorateGraph(exCur, deCur, graph): def decorateGraph(exDb, deDb, graph):
exCur = exDb.cursor()
deCur = deDb.cursor()
scriptMap = {} scriptMap = {}
exCur.execute("SELECT [behavior], [index], [name] FROM script;") exCur.execute("SELECT [behavior], [index], [name] FROM script;")
@ -62,7 +63,10 @@ def decorateGraph(exCur, deCur, graph):
# sub bb # sub bb
deCur.execute("INSERT INTO graph VALUES(?, ?, 0, 0, -1, '')", (lines[0], lines[2])) deCur.execute("INSERT INTO graph VALUES(?, ?, 0, 0, -1, '')", (lines[0], lines[2]))
def buildBlock(exCur, deCur, target): def buildBlock(exDb, deDb, target):
exCur = exDb.cursor()
deCur = deDb.cursor()
# sort inner bb # sort inner bb
# use current graph input as the start point # use current graph input as the start point
treeRoot = dcv.BBTreeNode(target, -1) treeRoot = dcv.BBTreeNode(target, -1)
@ -72,6 +76,7 @@ def buildBlock(exCur, deCur, target):
# get no linked bb and place them. linked bb position will be computed following # get no linked bb and place them. linked bb position will be computed following
# calc each bb's x postion, as for y, calc later # calc each bb's x postion, as for y, calc later
# flat bb tree
arrangedLayer+=1 arrangedLayer+=1
singleBB = set() singleBB = set()
bbResult = {} bbResult = {}
@ -93,7 +98,32 @@ def buildBlock(exCur, deCur, target):
recursiveCalcBBX(treeRoot, dcv.GRAPH_CONTENTOFFSET_X, bbResult, bb_layer_map) recursiveCalcBBX(treeRoot, dcv.GRAPH_CONTENTOFFSET_X, bbResult, bb_layer_map)
# calc bb y # calc poper
allBB = processedBB | singleBB
processedOper = set()
pluggedOper = {}
occupiedLayerCountForSpecificBB = {}
exCur.execute('SELECT [thisobj] FROM pOper WHERE [belong_to] == ?', (target, ))
newCur = exDb.cursor()
newCur2 = exDb.cursor()
for i in exCur.fetchall():
if i[0] in processedOper:
continue
# check current bout, plugin into the first bb
newCur.execute("SELECT [output_obj] FROM pLink WHERE ([input_obj] == ? AND [output_type] == ? AND [output_is_bb] == 1)", (i[0], dcv.dbPLinkInputOutputType.PIN))
for j in newCur.fetchall():
if j[0] in allBB:
# can be plugin
# try get tree
if j[0] not in pluggedOper.keys():
pluggedOper[j[0]] = {}
recursiveBuildOperTree(i[0], bb_layer_map, processedOper, occupiedLayerCountForSpecificBB, newCur2, 1, j[0], target, pluggedOper[j[0]])
# exit for due to have found a proper host bb
break
# calc layer position
layer_height = {} layer_height = {}
layer_y = {} layer_y = {}
layer_height[0] = 25 layer_height[0] = 25
@ -105,6 +135,10 @@ def buildBlock(exCur, deCur, target):
else: else:
layer_height[curLayer] = max(layer_height.get(curLayer, 0), bbResult[i].height) layer_height[curLayer] = max(layer_height.get(curLayer, 0), bbResult[i].height)
layer_height[arrangedLayer] = layer_height.get(arrangedLayer, 0) # make sure misc bb height exist layer_height[arrangedLayer] = layer_height.get(arrangedLayer, 0) # make sure misc bb height exist
for i in occupiedLayerCountForSpecificBB.keys(): # add oper occipation
layer_height[i] += occupiedLayerCountForSpecificBB[i] * dcv.GRAPH_SPAN_BB_POPER
# calc bb Y
baseY = dcv.GRAPH_CONTENTOFFSET_Y baseY = dcv.GRAPH_CONTENTOFFSET_Y
for i in range(arrangedLayer + 1): for i in range(arrangedLayer + 1):
baseY += layer_height[i] + dcv.GRAPH_LAYER_SPAN baseY += layer_height[i] + dcv.GRAPH_LAYER_SPAN
@ -112,28 +146,72 @@ def buildBlock(exCur, deCur, target):
for i in bbResult.keys(): for i in bbResult.keys():
cache = bbResult[i] cache = bbResult[i]
layer = bb_layer_map[i] layer = bb_layer_map[i]
cache.y = layer_y[layer] - layer_height[layer] + cache.height cache.y = layer_y[layer] - layer_height[layer]
# calc poper # calc oper position
# flat oper tree
operResult = {} operResult = {}
baseX = dcv.GRAPH_CONTENTOFFSET_X
exCur.execute('SELECT [thisobj], [op] FROM pOper WHERE [belong_to] == ?', (target, )) exCur.execute('SELECT [thisobj], [op] FROM pOper WHERE [belong_to] == ?', (target, ))
homelessOperCurrentX = dcv.GRAPH_CONTENTOFFSET_X
for i in exCur.fetchall(): for i in exCur.fetchall():
cache = dcv.OperResult(i[1], baseX) if i[0] not in processedOper:
cache.computSize() # homeless oper
baseX += cache.width + dcv.GRAPH_BB_SPAN cache2 = dcv.OperResult(i[1])
cache.y = layer_y[1] - cache.height cache2.computSize()
operResult[i[0]] = cache cache2.x = homelessOperCurrentX
cache2.y = layer_y[1] - cache2.height
homelessOperCurrentX += cache2.width + dcv.GRAPH_BB_SPAN
operResult[i[0]] = cache2
for i in pluggedOper.keys(): # plugged oper
cache = bbResult[i]
for j in pluggedOper[i]:
jCache = pluggedOper[i][j]
baseX = cache.x
for q in jCache:
exCur.execute("SELECT [op] FROM pOper WHERE [thisobj] == ?", (q, ))
cache2 = dcv.OperResult(exCur.fetchone()[0])
cache2.computSize()
cache2.x = baseX
baseX += cache2.width + dcv.GRAPH_BB_SPAN
cache2.y = cache.y - j * dcv.GRAPH_SPAN_BB_POPER
operResult[q] = cache2
# query bb pin's data
for i in allBB:
cache = bbResult[i]
exCur.execute("SELECT [thisobj] FROM bIn WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.binData.append(str(j[0]))
exCur.execute("SELECT [thisobj] FROM bOut WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.boutData.append(str(j[0]))
exCur.execute("SELECT [thisobj] FROM pIn WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.pinData.append(str(j[0]))
exCur.execute("SELECT [thisobj] FROM pOut WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.poutData.append(str(j[0]))
# query oper pin's data
for i in operResult.keys():
cache = operResult[i]
exCur.execute("SELECT [thisobj] FROM pIn WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.pinData.append(str(j[0]))
exCur.execute("SELECT [thisobj] FROM pOut WHERE [belong_to] == ? ORDER BY [index];", (i, ))
for j in exCur.fetchall():
cache.poutData.append(str(j[0]))
# write to database and return # write to database and return
for i in bbResult.keys(): for i in bbResult.keys():
cache = bbResult[i] cache = bbResult[i]
deCur.execute('INSERT INTO block VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', deCur.execute('INSERT INTO block VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
(target, i, cache.name, cache.assistName, cache.pin, cache.pout, cache.bin, cache.bout, cache.x, cache.y, cache.width, cache.height, cache.expandable)) (target, i, cache.name, cache.assistName, ','.join(cache.pinData), ','.join(cache.poutData), ','.join(cache.binData), ','.join(cache.boutData), cache.x, cache.y, cache.width, cache.height, cache.expandable))
for i in operResult.keys(): for i in operResult.keys():
cache = operResult[i] cache = operResult[i]
deCur.execute("INSERT INTO block VALUES (?, ?, ?, '', 2, 1, 0, 0, ?, ?, ?, ?, -1)", deCur.execute("INSERT INTO block VALUES (?, ?, ?, '', ?, ?, '', '', ?, ?, ?, ?, -1)",
(target, i, cache.name, cache.x, cache.y, cache.width, cache.height)) (target, i, cache.name, ','.join(cache.pinData), ','.join(cache.poutData), cache.x, cache.y, cache.width, cache.height))
return (layer_y[0] - dcv.CELL_HEIGHT, bbResult, operResult) return (layer_y[0] - dcv.CELL_HEIGHT, bbResult, operResult)
@ -143,9 +221,10 @@ def recursiveBuildBBTree(node, exCur, processedBB, layer, depth, graphId):
exCur.execute("SELECT [output_obj] FROM bLink WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", exCur.execute("SELECT [output_obj] FROM bLink WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;",
(node.bb, (dcv.dbBLinkInputOutputType.INPUT if depth == 0 else dcv.dbBLinkInputOutputType.OUTPUT), graphId)) (node.bb, (dcv.dbBLinkInputOutputType.INPUT if depth == 0 else dcv.dbBLinkInputOutputType.OUTPUT), graphId))
for i in exCur.fetchall(): for i in exCur.fetchall():
if i[0] != graphId: # omit self
realLinkedBB.add(i[0]) realLinkedBB.add(i[0])
if (len(cache) == 0): if (len(realLinkedBB) == 0):
return layer return layer
# ignore duplicated bb # ignore duplicated bb
@ -158,7 +237,7 @@ def recursiveBuildBBTree(node, exCur, processedBB, layer, depth, graphId):
for i in realLinkedBB: for i in realLinkedBB:
# recursive execute this method # recursive execute this method
newNode = dcv.BBTreeNode(i, layer) newNode = dcv.BBTreeNode(i, layer)
layer = recursiveBuildBBTree(newNode, exCur, deCur, processedBB, layer, depth + 1, graphId) layer = recursiveBuildBBTree(newNode, exCur, processedBB, layer, depth + 1, graphId)
# add new node into list and ++layer # add new node into list and ++layer
layer+=1 layer+=1
node.nodes.append(newNode) node.nodes.append(newNode)
@ -178,3 +257,35 @@ def recursiveCalcBBX(node, baseX, resultList, layerMap):
for i in node.nodes: for i in node.nodes:
recursiveCalcBBX(i, baseX + maxExpand + dcv.GRAPH_BB_SPAN, resultList, layerMap) recursiveCalcBBX(i, baseX + maxExpand + dcv.GRAPH_BB_SPAN, resultList, layerMap)
def recursiveBuildOperTree(oper, bb_layer_map, processedOper, occupiedLayerMap, exCur, sublayer, bb, graphId, subLayerColumnMap):
if oper in processedOper:
return
# for avoid fucking export parameter feature. check whether self is current graph's memeber
exCur.execute("SELECT [belong_to] FROM pOper WHERE [thisobj] == ?;", (oper, ))
if (exCur.fetchone()[0] != graphId):
# fuck export param, exit
return
# make sure sub layer column map is ok
if sublayer not in subLayerColumnMap.keys():
subLayerColumnMap[sublayer] = []
# register self
# mark processed
processedOper.add(oper)
subLayerColumnMap[sublayer].append(oper)
# record layer occupation
layer = bb_layer_map[bb]
occupiedLayerMap[layer] = max(occupiedLayerMap.get(layer, -1), sublayer)
# iterate sub item
exCur.execute("SELECT [input_obj] FROM pLink WHERE ([output_obj] == ? AND [input_type] == ? AND [input_is_bb] == 0) ORDER BY [output_index];", (oper, dcv.dbPLinkInputOutputType.POUT))
res = []
for i in exCur.fetchall():
res.append(i[0])
for i in res:
recursiveBuildOperTree(i, bb_layer_map, processedOper, occupiedLayerMap, exCur, sublayer + 1, bb, graphId, subLayerColumnMap)

View File

@ -4,7 +4,9 @@ from flask import render_template
from flask import url_for from flask import url_for
from flask import request from flask import request
from functools import reduce
import sqlite3 import sqlite3
import json
import ServerStruct as ss import ServerStruct as ss
app = Flask(__name__) app = Flask(__name__)
@ -21,6 +23,13 @@ def close_connection(exception):
if db is not None: if db is not None:
db.close() db.close()
@app.template_global(name = 'pinDecoder')
def block_pin_filter(target):
if target == '':
return []
# return json.loads(target)
return target.split(',')
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
def indexHandle(): def indexHandle():
cur = get_db().cursor() cur = get_db().cursor()
@ -43,19 +52,21 @@ def scriptHandle(scriptPath):
hamburgerMap = {} hamburgerMap = {}
hamburger = [] hamburger = []
for i in cur.fetchall(): for i in cur.fetchall():
hamburgerMap[i[0]] = i[1] hamburgerMap[str(i[0])] = i[1]
for i in pathSlice: currentHamburger = hamburgerMap[pathSlice[-1]]
hamburger.append(hamburgerMap[int(i)])
currentHamburger = hamburger.pop() for i in range(len(pathSlice) - 1):
hamburger.append(ss.HamburgerItem(hamburgerMap[pathSlice[i]], reduce(lambda x,y: x + '/' + y, pathSlice[0:i + 1], '')))
# get blocks # get blocks
cur.execute('SELECT * FROM block WHERE [belong_to_graph] = ?', (pathSlice[-1],)) cur.execute('SELECT * FROM block WHERE [belong_to_graph] = ?', (pathSlice[-1], ))
dbBlocks = cur.fetchall() dbBlocks = cur.fetchall()
# todo:xxxxx # todo:xxxxx
# render # render
return render_template('viewer.html', return render_template('viewer.html',
currentPath = scriptPath,
hamburgerHistory = hamburger, hamburgerHistory = hamburger,
static_css = url_for('static', filename='site.css'), static_css = url_for('static', filename='site.css'),
static_js = url_for('static', filename='site.js'), static_js = url_for('static', filename='site.js'),

View File

@ -2,3 +2,8 @@ class ScriptItem(object):
def __init__(self, name, id): def __init__(self, name, id):
self.name = name self.name = name
self.id = id self.id = id
class HamburgerItem(object):
def __init__(self, name, path):
self.name = name
self.path = path

View File

@ -4,7 +4,7 @@ import os
import sys import sys
# debug use # debug use
os.remove('decorate.db') # os.remove('decorate.db')
print('Super Script View') print('Super Script View')
if not os.path.isfile("decorate.db"): if not os.path.isfile("decorate.db"):
@ -18,4 +18,4 @@ if not os.path.isfile("decorate.db"):
print('Decorated database generating done.') print('Decorated database generating done.')
# todo: start flask # todo: start flask
# ServerCore.run() ServerCore.run()

View File

@ -17,6 +17,24 @@ p.block-text {
position: absolute; position: absolute;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 12px;
color: black;
}
p.block-expandable-text {
position: absolute;
margin: 0;
padding: 0;
font-size: 12px;
color: #5f5f5f;
}
p.block-asstext {
position: absolute;
margin: 0;
padding: 0;
font-size: 9px;
color: white
} }
div.block-body { div.block-body {

View File

@ -16,7 +16,7 @@
{% for i in hamburgerHistory %} {% for i in hamburgerHistory %}
<p class="hamburger">&gt;&gt;</p> <p class="hamburger">&gt;&gt;</p>
<p class="hamburger"><a href="{{ "../" * loop.revindex }}">{{ i|e }}</a></p> <p class="hamburger"><a href="{{ i.path }}">{{ i.name|e }}</a></p>
{% endfor %} {% endfor %}
<p class="hamburger">&gt;&gt;</p> <p class="hamburger">&gt;&gt;</p>
@ -24,36 +24,40 @@
</div> </div>
<div style="width: 100px;"> <div style="width: 100px;">
<button style="width: 100px; height: 50px;">SAVE !!</button> <button style="width: 100px; height: 50px;">LEGEND</button>
</div> </div>
</div> </div>
<div style="background: #7f7f7f; width: 100%; height: 100%; overflow: scroll; position: relative;"> <div style="background: #7f7f7f; width: 100%; height: 100%; overflow: scroll; position: relative;">
<div> <div>
{% for i in blocks %}
<div class="block-body" style="height: {{ i[11] }}px; width: {{ i[10] }}px; top: {{ i[9] }}px; left: {{ i[8] }}px;">
{% for pin in range(i[4]) %}
<div class="block-p" style="height: 6px; width: 6px; top: 0; left: {{ 20 + pin * ( 6 + 20) }}px;"></div>
{% endfor %}
{% for pout in range(i[5]) %}
<div class="block-p" style="height: 6px; width: 6px; bottom: 0; left: {{ 20 + pout * ( 6 + 20) }}px;"></div>
{% endfor %}
{% for bin in range(i[6]) %}
<div class="block-b" style="height: 6px; width: 6px; top: {{ 10 + bin * ( 6 + 20) }}px; left: 0;"></div>
{% endfor %}
{% for bout in range(i[6]) %}
<div class="block-b" style="height: 6px; width: 6px; top: {{ 10 + bout * ( 6 + 20) }}px; right: 0;"></div>
{% endfor %}
<p class="block-text" style="top: 10px; left: 20px;">{{ i[2]|e }}</p>
<p class="block-text" style="top: 24px; left: 20px;"><i>{{ i[3]|e }}</i></p>
</div>
{% endfor %}
<svg version="1.1" width="5000px" height="5000px" style="position: absolute; top: 0; left: 0;"> <svg version="1.1" width="5000px" height="5000px" style="position: absolute; top: 0; left: 0;">
<line x1="502" y1="210" x2="100" y2="100" stroke="black" stroke-width="1px"></line> <line x1="502" y1="210" x2="100" y2="100" stroke="black" stroke-width="1px"></line>
<line x1="320" y1="200" x2="100" y2="100" stroke="blue" stroke-width="1px" stroke-dasharray="10, 5"> <line x1="320" y1="200" x2="100" y2="100" stroke="blue" stroke-width="1px" stroke-dasharray="10, 5">
</line> </line>
<text x="200" y="155" fill="black">0</text> <text x="200" y="155" fill="black">0</text>
</svg> </svg>
{% for i in blocks %}
<div class="block-body" style="height: {{ i[11] }}px; width: {{ i[10] }}px; top: {{ i[9] }}px; left: {{ i[8] }}px;">
{% for pin in pinDecoder(i[4]) %}
<div class="block-p" title="{{ pin|e }}" style="height: 6px; width: 6px; top: 0; left: {{ 20 + loop.index0 * ( 6 + 20) }}px;"></div>
{% endfor %}
{% for pout in pinDecoder(i[5]) %}
<div class="block-p" title="{{ pout|e }}" style="height: 6px; width: 6px; bottom: 0; left: {{ 20 + loop.index0 * ( 6 + 20) }}px;"></div>
{% endfor %}
{% for bin in pinDecoder(i[6]) %}
<div class="block-b" title="{{ bin|e }}" style="height: 6px; width: 6px; top: {{ 10 + loop.index0 * ( 6 + 20) }}px; left: 0;"></div>
{% endfor %}
{% for bout in pinDecoder(i[6]) %}
<div class="block-b" title="{{ bout|e }}" style="height: 6px; width: 6px; top: {{ 10 + loop.index0 * ( 6 + 20) }}px; right: 0;"></div>
{% endfor %}
{% if i[12] != -1 %}
<p class="block-expandable-text" style="top: 10px; left: 20px;"><a href="{{ "/%s/%s"|format(currentPath, i[12]) }}">{{ i[2]|e }}</a></p>
{% else %}
<p class="block-text" style="top: 10px; left: 20px;">{{ i[2]|e }}</p>
{% endif %}
<p class="block-asstext" style="top: 24px; left: 20px;">{{ i[3]|e }}</p>
</div>
{% endfor %}
</div> </div>
</div> </div>