Пример #1
0
def make_function_at(static, addr):
    if static[addr]["function"] != None:
        # already function
        return
    rc = static.r2core
    rc.cmd("af @ %d" % (addr,))
    this_function = Function(addr)
    static["functions"].add(this_function)

    info = rc.cmd_json("afj %d" % (addr,))[0]
    callrefs = info["callrefs"]
    for ref in callrefs:
        if ref["type"] == "J":
            static[ref["addr"]]["crefs"].add(addr)
        if ref["type"] == "C":
            static[ref["addr"]]["xrefs"].add(addr)

    function_details = rc.cmd_json("pdfj @ %d" % addr)
    if function_details["addr"] == addr:
        for opcode in function_details["ops"]:
            static[opcode["offset"]]["function"] = this_function
            i = static[opcode["offset"]]["instruction"]

    addr_re = re.compile(r"\| (0x[a-f0-9]+) ")
    blocks = rc.cmd_json("agj %d" % addr)[0]["blocks"]
    for block in blocks:
        this_block = Block(block["offset"])
        this_function.add_block(this_block)
        for op in block["ops"]:
            address = op["offset"]
            this_block.add(address)
            static[address]["block"] = this_block
        static["blocks"].add(this_block)
Пример #2
0
    def test_simple_csp_to_logic_conversion(self):

        domain = []
        for x in range(3):
            for y in range(3):
                for rotation in range(0, 360, 90):
                    domain.append(Block.Value(x, y, rotation))

        original_problem = BlockCSPProblem([
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 1, domain),
            Block(Polygon([(0, 0), (3, 0), (3, 3), (1, 3), (1, 2),
                           (0, 2)]), 2, domain),
        ], Polygon([(0, 0), (3, 0), (3, 3), (0, 3)]))

        logic_problem = original_problem.get_propositional_logic_cnf()

        solved_problem = dfs_with_ac3(original_problem)

        self.assertIsNotNone(solved_problem)

        self.assertTrue(
            TestBlockLogicProblem.does_solution_satisfy_logic_problem(
                solved_problem, logic_problem))

        self.assertFalse(
            TestBlockLogicProblem.does_solution_satisfy_logic_problem(
                original_problem, logic_problem))
Пример #3
0
    def test_create_problem_from_structured_data(self):
        BlockCSPProblem(
            [
                Block(
                    Polygon(
                        [
                            (0, 0),
                            (1, 0),
                            (1, 1),
                            (0, 1),
                        ]
                    ),
                    1,
                    self.domain,
                ),
                Block(
                    Polygon(
                        [
                            (0, 0),
                            (1, 0),
                            (1, 1),
                            (0, 1),
                        ]
                    ),
                    1,
                    self.domain,
                ),

            ]
        )
Пример #4
0
def make_function_at(static, addr):
  if static[addr]['function'] != None:
    # already function
    return
  rc = static.r2core
  rc.cmd("af @ %d" % (addr,))
  this_function = Function(addr)
  static['functions'].add(this_function)
      
  info = rc.cmd_json("afj %d" % (addr,))[0]
  callrefs = info['callrefs'] 
  for ref in callrefs:
    if ref["type"] == "J":
      static[ref['addr']]['crefs'].add(addr)
    if ref["type"] == "C":
      static[ref['addr']]['xrefs'].add(addr)

  function_details = rc.cmd_json("pdfj @ %d" % addr)
  if function_details['addr'] == addr:
    for opcode in function_details['ops']:
      static[opcode['offset']]['function'] = this_function 
      i = static[opcode['offset']]['instruction']

  addr_re = re.compile(r'\| (0x[a-f0-9]+) ')
  blocks = rc.cmd_json("agj %d" % addr)[0]['blocks']
  for block in blocks:
    this_block = Block(block['offset'])
    this_function.add_block(this_block)
    addresses = addr_re.findall(block['code']) 
    for address in addresses:
      address = int(address[2:],16)
      this_block.add(address)
      static[address]['block'] = this_block
    static['blocks'].add(this_block)
Пример #5
0
    def test_arc_consistency_checking_algorithm(self):

        domain = []
        for x in range(3):
            for y in range(3):
                for rotation in range(0, 360, 90):
                    domain.append(
                        Block.Value(x, y, rotation)
                    )

        original_problem = BlockCSPProblem([
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 1, domain),
            Block(Polygon([(0, 0), (3, 0), (3, 3), (1, 3), (1, 2), (0, 2)]), 2, domain),
        ], Polygon([(0, 0), (3, 0), (3, 3), (0, 3)])
        )

        still_consistent = True
        for source_variable in original_problem.variables:
            for destination_variable in original_problem.variables:
                if source_variable is destination_variable:
                    continue
                if not source_variable.is_arc_consistent_with(destination_variable):
                    still_consistent = False

        self.assertFalse(still_consistent)

        consistent_problem = arc_consistency_checking_algorithm(original_problem)

        for source_variable in consistent_problem.variables:
            for destination_variable in consistent_problem.variables:
                if source_variable is destination_variable:
                    continue
                self.assertTrue(source_variable.is_arc_consistent_with(destination_variable))
Пример #6
0
def make_function_at(static, addr):
    if static[addr]['function'] != None:
        # already function
        return
    rc = static.r2core
    rc.cmd("af @ %d" % (addr, ))
    this_function = Function(addr)
    static['functions'].add(this_function)

    info = rc.cmd_json("afj %d" % (addr, ))[0]
    callrefs = info['callrefs']
    for ref in callrefs:
        if ref["type"] == "J":
            static[ref['addr']]['crefs'].add(addr)
        if ref["type"] == "C":
            static[ref['addr']]['xrefs'].add(addr)

    function_details = rc.cmd_json("pdfj @ %d" % addr)
    if function_details['addr'] == addr:
        for opcode in function_details['ops']:
            static[opcode['offset']]['function'] = this_function
            i = static[opcode['offset']]['instruction']

    addr_re = re.compile(r'\| (0x[a-f0-9]+) ')
    blocks = rc.cmd_json("agj %d" % addr)[0]['blocks']
    for block in blocks:
        this_block = Block(block['offset'])
        this_function.add_block(this_block)
        for op in block['ops']:
            address = op['offset']
            this_block.add(address)
            static[address]['block'] = this_block
        static['blocks'].add(this_block)
Пример #7
0
 def regesiter2server(self):
     global regist_status
     if (self.isOpen == False):
         return -1
     Block.blocks_clean()  # 清空数据库
     dataFormat = DataFormat("REGIST", "OK")
     json_str = json.dumps(dataFormat, default=DataFormat.DataFormat2dict)
     client.sendall(bytes(json_str, encoding="utf-8"))
     time.sleep(DEF_DELAY)
     return regist_status
Пример #8
0
 def save_block(self, drip_campaign_id, start_time, nodes_id):
     """
     save basic block info
     """
     new_block = Block(
         drip_campaign_id=drip_campaign_id,
         start_time=start_time,
         nodes_id=nodes_id
     )
     new_block.save()
Пример #9
0
 def setUp(self):
     super().setUp()
     self.reference_polygon = Polygon([
         (0, 0),
         (1, 0),
         (1, 1),
         (0, 1),
     ])
     self.side_tangent_polygon = Polygon([
         (1, 0),
         (2, 0),
         (2, 1),
         (1, 1),
     ])
     self.point_tangent_polygon = Polygon([
         (1, 1),
         (2, 1),
         (2, 2),
         (1, 2),
     ])
     self.crossing_polygon = Polygon([
         (0, 0.5),
         (1, 0.5),
         (1, 1.5),
         (0, 1.5),
     ])
     domain = []
     for x in range(3):
         for y in range(3):
             for rotation in range(0, 360, 90):
                 domain.append(
                     Block.Value(x, y, rotation)
                 )
     self.domain = domain
Пример #10
0
    def test_dfs_with_ac3_simple(self):

        domain = []
        for x in range(3):
            for y in range(3):
                for rotation in range(0, 360, 90):
                    domain.append(
                        Block.Value(x, y, rotation)
                    )

        original_problem = BlockCSPProblem([
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 1, domain),
            Block(Polygon([(0, 0), (3, 0), (3, 3), (1, 3), (1, 2), (0, 2)]), 2, domain),
        ], Polygon([(0, 0), (3, 0), (3, 3), (0, 3)]))

        self.help_test_dfs_with_ac3_with_problem(original_problem)
Пример #11
0
def rcvMsg(sock):
    save = []
    index = 0
    global username

    while True:
        try:
            data = sock.recv(1024)
            if not data:
                break
            print(data.decode())
            decode_data = data.decode('utf-8')
            if not 'role:' in decode_data and not 'is join' in decode_data and not 'is quit' in decode_data:
                save.append(decode_data)

            if username == "miner1" and len(save) == 10:
                f = open('chat.txt', 'a+t')
                f.writelines(str(save))
                f.write('\n')
                f.close()
                pow = ProofOfWork.pow()
                index = Block.brick(pow, index)
                index = index + 1
                for i in range(10):
                    save.pop()

        except:
            pass
Пример #12
0
def add_Block(patient, describe):
    global user
    global current_block
    timestamp = time.time()

    block = Block(timestamp=timestamp,
                  doctor=user.name,
                  patient=patient,
                  describe=describe)
    if current_block == "":
        blocks = get_all_blocks()
        current_block = copy.deepcopy(blocks[0])
    block.index = int(current_block.index) + 1
    block.encryption = str(hash(current_block))  # 同态加密
    db.session.add(block)
    db.session.commit()
    ClientNode.send_ADDBLOCK_message(block)
    current_block = copy.deepcopy(block)  # 更新当前block数据
Пример #13
0
def client_handl_rev(data):
    global current_block
    print("客户端收到数据:" + data)
    global regist_status
    d_format = json.loads(data, object_hook=DataFormat.dict2DataFormat)
    if d_format.dataType == DEF_REGIST:  # 节点注册成功,则开启服务
        if d_format.param == "OK":
            regist_status = 0
        else:
            regist_status = -1
    elif d_format.dataType == DEF_ADDBLOCK:  # 增加节点
        print("not support the format type:" + d_format.dataType)
        print(d_format.param)
        block = json.loads(d_format.param, object_hook=Block.dict2Block)
        if current_block == "":  # 第一个block由中央服务器产生
            current_block = copy.deepcopy(block)
            print("复制区块成功"+ str(sys._getframe().f_lineno) )
            print(current_block.index)
        Block.server_add_block(block, current_block)
        print("添加区块成功")
    else:
        print("not support the format type:" + d_format.dataType)
Пример #14
0
    def rcvMsg(self, sock):
        save = []
        index = 0

        while True:
            try:
                data = sock.recv(1024)
                if not data:
                    break
                print(data.decode())
                decode_data = data.decode('utf-8')
                if not 'role:' in decode_data and not 'is join' in decode_data and not 'is quit' in decode_data:
                    save.append(decode_data)

                self.interface.send_log(decode_data + "\n")

                if 'is join' in decode_data:
                    splited_data: str = decode_data.split()
                    received_user = splited_data[0][1:-1]
                    if received_user != self.username:
                        self.interface.receive_other_user(received_user)

                elif 'has joined' in decode_data:
                    splited_data: str = decode_data.split()
                    received_user = splited_data[0][1:-1]
                    if received_user != self.username:
                        self.interface.receive_other_user(received_user)

                elif 'is quit' in decode_data:
                    splited_data: str = decode_data.split()
                    received_user = splited_data[0][1:-1]
                    if received_user != self.username:
                        self.interface.remove_other_user(received_user)

                if len(save) == 10:
                    f = open('chat.txt', 'a+t')
                    f.writelines(str(save))
                    f.write('\n')
                    f.close()
                    pow = ProofOfWork.pow()
                    index = Block.brick(pow, index)
                    index = index + 1
                    for i in range(10):
                        save.pop()

                else:
                    pass

            except:
                pass
Пример #15
0
 def is_solution_sound(solved_problem):
     for source_variable in solved_problem.variables:
         for destination_variable in solved_problem.variables:
             if source_variable is destination_variable:
                 continue
             if source_variable.domain.__len__() !=  1:
                 return False
             if destination_variable.domain.__len__() != 1:
                 return False
             constraint_is_complied = Block.check_constraint(
                 source_variable, source_variable.domain[0],
                 destination_variable, destination_variable.domain[0]
             )
             if not constraint_is_complied:
                 return False
     return True
Пример #16
0
    def get_propositional_logic_cnf(self):

        logic_variables = []
        clauses = []
        clauses_to_ensure_at_least_one_assignment = []
        for variable in self.variables:
            clause_to_ensure_at_least_one_assignment = []
            for value in variable.domain:
                logic_variable = (variable, value)
                logic_variables.append(
                    logic_variable
                )
                clause_to_ensure_at_least_one_assignment.append((logic_variable, True))
                for other_value in variable.domain:
                    other_logic_variable = (variable, other_value)
                    if value is other_value:
                        continue
                    clause_to_ensure_at_most_one_assignment = [
                        (logic_variable, False), (other_logic_variable, False)
                    ]
                    clauses.append(clause_to_ensure_at_most_one_assignment)
            clauses_to_ensure_at_least_one_assignment.append(clause_to_ensure_at_least_one_assignment)

        for first_logic_variable in logic_variables:
            for second_logic_variable in logic_variables:
                if first_logic_variable is second_logic_variable:
                    continue
                there_is_conflict = not Block.check_constraint(
                    first_logic_variable[0], first_logic_variable[1],
                    second_logic_variable[0], second_logic_variable[1]
                )
                if there_is_conflict:
                    clause_to_ensure_constraint = [
                        (first_logic_variable, False), (second_logic_variable, False)
                    ]

                    clauses.append(clause_to_ensure_constraint)

        clauses.extend(clauses_to_ensure_at_least_one_assignment)

        return clauses
Пример #17
0
    def test_simple_block_logic_problem(self):
        domain = []
        for x in range(2):
            for y in range(1):
                for rotation in range(0, 360, 90):
                    domain.append(Block.Value(x, y, rotation))

        original_problem = BlockCSPProblem([
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 1, domain),
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 0, domain),
        ], Polygon([(0, 0), (3, 0), (3, 3), (0, 3)]))

        logic_problem = original_problem.get_propositional_logic_cnf()

        solved_problem = dpll(logic_problem)

        self.assertIsNotNone(solved_problem)

        self.assertTrue(
            evaluate_clauses_with_model(logic_problem, solved_problem))

        original_problem.import_cnf_model(solved_problem)
        self.assertTrue(BlockCSPProblem.is_solution_sound(original_problem))

        domain = []
        for x in range(3):
            for y in range(3):
                for rotation in range(0, 360, 90):
                    domain.append(Block.Value(x, y, rotation))

        original_problem = BlockCSPProblem([
            Block(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), 1, domain),
            Block(Polygon([(0, 0), (3, 0), (3, 3), (1, 3), (1, 2),
                           (0, 2)]), 2, domain),
        ], Polygon([(0, 0), (3, 0), (3, 3), (0, 3)]))

        logic_problem = original_problem.get_propositional_logic_cnf()

        solved_problem = dpll(logic_problem)

        self.assertIsNotNone(solved_problem)

        self.assertTrue(
            evaluate_clauses_with_model(logic_problem, solved_problem))

        original_problem.import_cnf_model(solved_problem)
        self.assertTrue(BlockCSPProblem.is_solution_sound(original_problem))
Пример #18
0
from algorithm.logic import dpll
from model import Block, BlockCSPProblem
from algorithm.csp import dfs_with_ac3
from shapely.geometry import Polygon, Point
import timeit

m, n, p = map(int, input().split())

space = Polygon([(0, 0), (n, 0), (n, m), (0, m)])

domain = []
for i in range(n):
    for j in range(m):
        for rotation in range(0, 360, 90):
            domain.append(Block.Value(i, j, rotation))

blocks = []
for i in range(p):
    k, c = map(int, input().split())
    pieces = []
    for j in range(k):
        line = input()
        for x in range(len(line)):
            if line[x] == '*':
                pieces.append(
                    Polygon([(x, j), (x + 1, j), (x + 1, j + 1), (x, j + 1)]))

    block_polygon = pieces[0]
    for piece in pieces:
        block_polygon = block_polygon.union(piece).simplify(0)
Пример #19
0
def make_function_at(static, address, recurse = True):
  if static['arch'] != "i386" and static['arch'] != "x86-64":
    print "*** static only works with x86(_64), someone should fix it"
    return
  if static[address]['function'] != None:
    # already function
    return
  block_starts = set([address])
  function_starts = set()
  this_function = Function(address)
  static['functions'].add(this_function)

  def disassemble(address):
    raw = static.memory(address, 0x10)
    d = static[address]['instruction']
    static[address]['function'] = this_function
    for (c,flag) in d.dests():
      if flag == DESTTYPE.call:
        static._auto_update_name(c,"sub_%x"%(c))
        function_starts.add(c)
        #print "%s %x is in %x xrefs" % (d,address, c)
        static[c]['xrefs'].add(address)
        # add this to the potential function boundary starts
        continue
      if c != address + d.size():
        #print "%s %x is in %x crefs" % (d,address, c)
        static[c]['crefs'].add(address)
        static._auto_update_name(c,"loc_%x"%(c))
        block_starts.add(c)

      #if we come after a jump and are an implicit xref, we are the start
      #of a new block
      elif d.is_jump():
        static._auto_update_name(c,"loc_%x"%(c))
        block_starts.add(c)
    return d.dests()

  # recursive descent pass
  pending = Queue.Queue()
  done = set()
  pending.put(address)
  while not pending.empty():
    dests = disassemble(pending.get())
    for (d,flag) in dests:
      if flag == DESTTYPE.call:
        #this will get handled in the function pass
        continue
      if d not in done:
        pending.put(d)
        done.add(d)

  #print map(hex, done)

  # block finding pass
  for b in block_starts:
    this_block = Block(b)
    this_function.add_block(this_block)
    address = b
    i = static[address]['instruction']
    while not i.is_ending() and i.size() != 0:
      if address + i.size() in block_starts:
        break
      address += i.size()
      i = static[address]['instruction']
      this_block.add(address)
      static[address]['block'] = this_block
    static['blocks'].add(this_block)

   # find more functions
  for f in function_starts:
    if static[f]['function'] == None:
      make_function_at(static, f)
Пример #20
0
    def test_constraint(self):
        reference_block = Block(self.reference_polygon, 1, self.domain)
        reference_value = Block.Value(0, 0, 0)
        block_with_same_color = Block(self.reference_polygon, 1, self.domain)
        block_with_different_color = Block(self.reference_polygon, 2, self.domain)

        self.assertTrue(Block.check_constraint(
            reference_block, reference_value,
            block_with_different_color, Block.Value(1, 0, 0)
        ))

        self.assertFalse(Block.check_constraint(
            reference_block, reference_value,
            block_with_same_color, Block.Value(1, 0, 0)
        ))

        self.assertFalse(Block.check_constraint(
            reference_block, reference_value,
            block_with_different_color, Block.Value(0, 0, 0)
        ))

        self.assertFalse(Block.check_constraint(
            reference_block, reference_value,
            block_with_same_color, Block.Value(0, 0, 0)
        ))

        self.assertTrue(Block.check_constraint(
            reference_block, reference_value,
            block_with_different_color, Block.Value(1, 1, 0)
        ))

        self.assertTrue(Block.check_constraint(
            reference_block, reference_value,
            block_with_same_color, Block.Value(1, 1, 0)
        ))
Пример #21
0
    def handle(self):
        server_interface.send_log('[%s] is connected\n' %
                                  self.client_address[0])
        global save
        save = []
        try:
            username = self.registerUsername()

            for user in self.userman.users:
                if user is not username:
                    self.request.send(("[%s] has joined." % user).encode())

            msg = self.request.recv(1024)

            while msg:
                data = msg.decode('utf-8')
                print(data)

                data_list = data.split(" ")

                if data_list[0] == username and data_list[
                        1] in self.userman.users:
                    conn, addr = self.userman.users[data_list[1]]
                    #conn.send(data.encode())
                    save.append(data)
                    if len(save) % 10 == 0:
                        for name in self.minerman.users:
                            conn, addr = self.minerman.users[name]
                            for i in range(0, 10):
                                tx = save[i]
                                print(tx)
                                conn.send(tx.encode())
                                time.sleep(0.01)
                            for i in range(10):
                                save.pop(0)
                            time.sleep(3)
                            server_interface.send_log('Block Received\n')
                            fr = open('block.txt', 'r')
                            server_interface.send_log(
                                'Successfully Opened Block\n')
                            last_dict = fr.readlines()[-1].rstrip()
                            hash, signature, public_key = Block.brick_hash(
                                last_dict)
                            server_interface.send_log('Validation Process: ')
                            server_interface.send_log(
                                str(
                                    KeyGenerator.validation(
                                        last_dict.encode('utf-8'), signature,
                                        KeyGenerator.readKey())) + " ")
                            server_interface.send_log(
                                'Send Block to Participants\n')
                            self.userman.sendMessageToAll(
                                'Validated Block Sent\n')
                            break
                    else:
                        conn.send(data.encode())
                else:
                    conn, addr = self.userman.users[username]
                    conn.send("Invalid transaction".encode())
                msg = self.request.recv(1024)

        except Exception as e:
            server_interface.send_log('in error\n')
            server_interface.send_log(str(e) + "\n")

        server_interface.send_log('[%s] Termination\n' %
                                  self.client_address[0])
        self.userman.removeUser(username)
Пример #22
0
def make_function_at(static, address, recurse=True):
    if static[address]['function'] != None:
        # already function
        return
    start = time.time()
    block_starts = set([address])
    function_starts = set()
    this_function = Function(address)
    static['functions'].add(this_function)

    def disassemble(address):
        raw = static.memory(address, 0x10)
        d = static[address]['instruction']
        static[address]['function'] = this_function
        for (c, flag) in d.dests():
            if flag == DESTTYPE.call:
                static._auto_update_name(c, "sub_%x" % (c))
                function_starts.add(c)
                #print "%s %x is in %x xrefs" % (d,address, c)
                static[c]['xrefs'].add(address)
                # add this to the potential function boundary starts
                continue
            if c != address + d.size():
                #print "%s %x is in %x crefs" % (d,address, c)
                static[c]['crefs'].add(address)
                static._auto_update_name(c, "loc_%x" % (c))
                block_starts.add(c)

            #if we come after a jump and are an implicit xref, we are the start
            #of a new block
            elif d.is_jump() and not d.is_call():
                static._auto_update_name(c, "loc_%x" % (c))
                block_starts.add(c)
        return d.dests()

    # recursive descent pass
    pending = Queue.Queue()
    done = set()
    pending.put(address)
    while not pending.empty():
        dests = disassemble(pending.get())
        for (d, flag) in dests:
            if flag == DESTTYPE.call:
                #this will get handled in the function pass
                continue
            if d not in done:
                pending.put(d)
                done.add(d)
        if (time.time() - start) > 0.01:
            time.sleep(0.01)
            start = time.time()

    #print map(hex, done)

    # block finding pass
    for b in block_starts:
        this_block = Block(b)
        this_function.add_block(this_block)
        address = b
        i = static[address]['instruction']
        while not i.is_ending() and i.size() != 0:
            if address + i.size() in block_starts:
                break
            address += i.size()
            i = static[address]['instruction']
            this_block.add(address)
            static[address]['block'] = this_block
            if (time.time() - start) > 0.01:
                time.sleep(0.01)
                start = time.time()
        static['blocks'].add(this_block)

    # find more functions
    if recurse:
        for f in function_starts:
            if static[f]['function'] == None:
                make_function_at(static, f)
Пример #23
0
    def load_entire_campaign(self, drip_campaign_id):
        """
        helps frontend with loading entire campaigns
        takes drip campaign id and loads all of its components
        in a drip superstructure as frontend wants
        """
        # load campaign
        drip_campaign = DripCampaign.objects(id=drip_campaign_id)[0]
        drip_campaign_frontend = {
            "id": drip_campaign["id"],
            "name": drip_campaign["name"],
            "userListId": drip_campaign["list_id"],
        }
        # load blocks
        blocks = Block.objects(drip_campaign_id=drip_campaign_id)
        blocks_frontend = [
            {
                "id": block["id"],
                "datetime": block["start_time"],
                "nodeIds": block["nodes_id"],
            }
            for block in blocks
        ]
        # load nodes
        nodes_frontend = []
        for node in Node.objects(drip_campaign_id=drip_campaign_id):
            def get_trigger_action_id(trigger):
                if trigger.opened:
                    return self.get_frontend_action_id("open")
                if trigger.any_click:
                    return self.get_frontend_action_id("any click")
                if trigger.default:
                    return self.get_frontend_action_id("default")
                return self.get_frontend_action_id(trigger.clicked)
            triggers = [
                {
                    "id": trigger["id"],
                    "actionId":  get_trigger_action_id(trigger),
                    "nodeId": trigger["node_to"],
                }
                for trigger in Trigger.objects(node_from=node["id"])
            ]
            nodes_frontend.append({
                "id": node["id"],
                "name": node["title"],
                "description": node["description"],
                "templateId": node["content"]["template_id"],
                "triggers": triggers,
            })
        # update and load lists and templates
        lists = self.update_lists()
        lists_frontend = [
            {
                "id": lst["id"],
                "name": lst["name"],
            }
            for lst in lists
        ]
        templates = self.update_templates()
        templates_frontend = [
            {
                "id": tmplt["id"],
                "name": tmplt["name"],
            }
            for tmplt in templates
        ]

        # create actions for frontend
        # set default actions that apply to all templates
        actions = {
            self.get_frontend_action_id(action_type): {
                "id": self.get_frontend_action_id(action_type),
                "name": self.get_frontend_action_name(action_type),
                "templates": [],
            }
            for action_type in self.DEFAULT_ACTIONS
        }
        # iterate over all tempaltes and update actions
        for tmplt in templates:
            # first, add the template to all default actions
            for action_type in self.DEFAULT_ACTIONS:
                action_frontend_id = self.get_frontend_action_id(action_type)
                actions[action_frontend_id]["templates"].append(tmplt["id"])
            # second, add template to all its link click actions
            for link in self.get_links(tmplt["template_id"]):
                action_frontend_id = self.get_frontend_action_id(link)
                # if this link is new, add a new action
                if action_frontend_id not in actions:
                    actions[action_frontend_id] = {
                        "id": action_frontend_id,
                        "name": self.get_frontend_action_name(link),
                        "templates": [],
                    }
                # add the template to this link's click action
                actions[action_frontend_id]["templates"].append(tmplt["id"])
        # ditch the mapping
        actions_frontend = actions.values()

        # form the resulting frontend superstructure
        return {
            "campaign": drip_campaign_frontend,
            "userLists": lists_frontend,
            "templates": templates_frontend,
            "actions": actions_frontend,
            "blocks": blocks_frontend,
            "nodes": nodes_frontend,
        }