Пример #1
0
def list(config, app_id, id, type):
    """List available application policies.

    Examples:

    List all group policies that belong to application 50:

        $ jaguar policy list 50 --type group

    List instance policy 101 that belongs to application 50:

        $ jaguar policy list 50 --type instance --id 101
    """
    try:
        url = config.server_url + '/v1/applications/' \
              + str(app_id) + '/policies/'
        if type:
            url += type + '/'
            if id > 0:
                url += str(id)

        rest = Rest(url, {'username': config.user})
        display(rest.get())

    except RestError as error:
        quit(error.message)
Пример #2
0
def list(config, app_id, id, type):
    """List available application policies.

    Examples:

    List all group policies that belong to application 50:

        $ jaguar policy list 50 --type group

    List instance policy 101 that belongs to application 50:

        $ jaguar policy list 50 --type instance --id 101
    """
    try:
        url = config.server['url'] + '/v1/applications/' \
              + str(app_id) + '/policies/'
        if type:
            url += type + '/'
            if id > 0:
                url += str(id)

        rest = Rest(url, {'username':config.user})
        display(rest.get())

    except RestError as error:
        quit(error.message)
Пример #3
0
def add():
    usertable = {}
    usertable["username"] = request.form['username']
    usertable["mac"] = request.form['mac']
    usertable["port"] = request.form['port']
    print json.dumps(usertable)
    Rest.add_user(json.dumps(usertable))
    return redirect(url_for('main'))
Пример #4
0
def unregister(config, id):
    """Unregister an application."""
    try:
        url = config.server_url + '/v1/applications/' + str(id)
        headers = {'username': config.user}
        rest = Rest(url, headers)
        display(rest.delete())
    except RestError as error:
        quit(error.message)
Пример #5
0
    def extract_job(self, job):
        engine = Rest.get_engine(job['engine_id'])
        target = Rest.get_target(job['target_id'])
        options = {}
        for opt in engine['options']:
            for opt_val in job['options']:
                if opt['id'] == opt_val['option_id']:
                    options[opt['name']] = opt_val['value']

        return engine, target, options
Пример #6
0
    def get_platform_id(self):
        plat_name = platform.system() + ' ' + platform.release()

        plats = Rest.list_platform()
        if plats is not None and len(plats) > 0:
            for p in plats:
                if p['name'] == plat_name:
                    return p['id']

        new_platform = Rest.create_platform(plat_name)
        return new_platform['id']
Пример #7
0
def delete(config, app_id, type, id):
    """Delete an application policy.
    """
    try:
        url = config.server['url'] + '/v1/applications/' + str(app_id) \
              + '/policies/' + type + '/' + str(id)
        headers = {'username':config.user, 'Content-Type':'application/json'}
        rest = Rest(url, headers)
        display(rest.delete())
    except RestError as error:
        quit(error.message)
Пример #8
0
    def get_arch_id(self):
        arch_name = platform.machine()

        arches = Rest.list_arch()
        if arches is not None and len(arches) > 0:
            for a in arches:
                if a['name'] == arch_name:
                    return a['id']

        new_arch = Rest.create_arch(arch_name)
        return new_arch['id']
Пример #9
0
def delete(config, app_id, type, id):
    """Delete an application policy.
    """
    try:
        url = config.server_url + '/v1/applications/' + str(app_id) \
              + '/policies/' + type + '/' + str(id)
        headers = {'username': config.user, 'Content-Type': 'application/json'}
        rest = Rest(url, headers)
        display(rest.delete())
    except RestError as error:
        quit(error.message)
Пример #10
0
def dpid_policy(dpid):
    sw_dpid_list = Rest.get_switch_list()

    if sw_dpid_list is False or int(dpid) not in sw_dpid_list:
        abort(404)

    flow_table = None
    flow_table = Rest.get_flow_table(dpid)
    global global_flow_table
    global_flow_table = flow_table
    port = Rest.get_switch_port(dpid)

    return render_template("policy.html", sw_dpid_list=sw_dpid_list, dpid=dpid, port=port, flow_table=flow_table)
Пример #11
0
def register(config, name, provider, enable):
    """Register an application for monitor and evaluation."""
    try:
        url = config.server_url + '/v1/applications'
        headers = {'username': config.user, 'Content-Type': 'application/json'}
        data = json.dumps({
            'name': name,
            'provider': provider,
            'enabled': enable
        })
        rest = Rest(url, headers, data)
        display(rest.post())
    except RestError as error:
        quit(error.message)
Пример #12
0
def del_flow():
    index = request.form["index"]

    flow_cmd = {}
    match_dict = {}

    for key, list in global_flow_table.iteritems():
        flow_cmd["dpid"] = key
        match_dict = list[int(index)]["match"]

    flow_cmd["match"] = match_dict
    #print json.dumps(flow_cmd)

    Rest.del_flow(json.dumps(flow_cmd))
    return "foo"
Пример #13
0
def del_flow():
    index = request.form["index"]

    flow_cmd = {}
    match_dict = {}

    for key, list in global_flow_table.iteritems():
        flow_cmd["dpid"] = key
        match_dict = list[int(index)]["match"]

    flow_cmd["match"] = match_dict
    # print json.dumps(flow_cmd)

    Rest.del_flow(json.dumps(flow_cmd))
    return "foo"
Пример #14
0
    def report_crash_sample(self, job, target, sample):
        if platform.system() == 'Linux':
            tmp = tempfile.NamedTemporaryFile()
            dump_file_name = tmp.name

            dbg_cmd = [
                'gdb',
                '-batch',
                '-ex', 'run',
                '-ex', 'set disassembly-flavor intel',
                '-ex', 'info registers',
                '-ex', 'bt full',
                '-ex', 'disass',
                '-ex', 'generate-core-file %s' % dump_file_name,
                '--args',
                target['path'],
                sample
            ]

            print dbg_cmd

            dbg_file = dump_file = None
            proc = subprocess.Popen(dbg_cmd, stdout=subprocess.PIPE)
            if proc.wait() == 0:
                try:
                    dbg_file = Rest.upload_file(proc.stdout)
                    dump_file = Rest.upload_file(open(dump_file_name, 'rb'))
                except:
                    None



            crash_payload = {}
            crash_payload['job_id'] = job['id']

            repro_file = Rest.upload_file(open(sample, 'rb'))
            if repro_file is not None:
                crash_payload['repro_file'] = repro_file['upload_path']
            if dump_file is not None:
                crash_payload['dump_file'] = dump_file['upload_path']
            if dbg_file is not None:
                crash_payload['dbg_file'] = dbg_file['upload_path']

            print Rest.create_crash(crash_payload)


        else:
            print "No Implemented!!!"
Пример #15
0
    def fill_holes(self):
        ''' Fills empty beats with rests.'''

        for measure in range(self.length):
            shortest = 1
            for note in self.notes:  # e.g. if shortest note is 1/8, measure contains 8 columns
                if measure == note.measure:  #
                    if note.duration < shortest:  #
                        shortest = note.duration  #
            for rest in self.rests:
                if measure == rest.measure:  #
                    if rest.duration < shortest:  #
                        shortest = rest.duration  #

            for i in range(1, int(1 / shortest) + 1):
                a = 0
                for note in self.notes:
                    if measure == note.measure:
                        if note.start == i * shortest:
                            a += 1
                        elif note.start < (i * shortest) and (
                                note.start + note.duration) > (i * shortest):
                            a += 1
                for rest in self.rests:
                    if measure == rest.measure:
                        if rest.start == i * shortest:
                            a += 1
                        elif rest.start < (i * shortest) and (
                                rest.start + rest.duration) > (i * shortest):
                            a += 1
                if a == 0:
                    rest = Rest(
                        measure, i * shortest, shortest
                    )  # (item_type, pitch, measure, start, duration)
                    self.add_rest(rest)
Пример #16
0
def query_flow(dpid):
    #dpid = request.args.get("dpid")
    flow_table = Rest.get_flow_table(dpid)

    #print flow_table

    return render_template("policy.html", flow_table=flow_table)
Пример #17
0
def policy():
    sw_dpid_list = Rest.get_switch_list()

    if sw_dpid_list is False:
        abort(404)

    return render_template("policy.html", sw_dpid_list=sw_dpid_list)
Пример #18
0
    def __init__(self, key=None, url=None):
        self.testnet_base_url = "https://live.coinpit.me/api/v1"
        self.livenet_base_url = "https://live.coinpit.io/api/v1"
        self.base_url_map = {0: self.livenet_base_url, 111: self.testnet_base_url}
        self.private_key = key
        self.account = None
        self.rest = None

        self.all = None
        self.contract = None

        if self.private_key is None:
            return
        self.network_code = crypto.get_network_code(self.private_key)
        self.base_url = url if url is not None else self.base_url_map[self.network_code]
        self.rest = Rest(self.base_url)
Пример #19
0
def policy():
    sw_dpid_list = Rest.get_switch_list()

    if sw_dpid_list is False:
        abort(404)

    return render_template("policy.html", sw_dpid_list=sw_dpid_list)
Пример #20
0
def query_flow(dpid):
    # dpid = request.args.get("dpid")
    flow_table = Rest.get_flow_table(dpid)

    # print flow_table

    return render_template("policy.html", flow_table=flow_table)
Пример #21
0
def dpid_policy(dpid):
    sw_dpid_list = Rest.get_switch_list()

    if sw_dpid_list is False or int(dpid) not in sw_dpid_list:
        abort(404)

    flow_table = None
    flow_table = Rest.get_flow_table(dpid)
    global global_flow_table
    global_flow_table = flow_table
    port = Rest.get_switch_port(dpid)

    return render_template("policy.html",
                           sw_dpid_list=sw_dpid_list,
                           dpid=dpid,
                           port=port,
                           flow_table=flow_table)
Пример #22
0
def main():
    print "test"
    sw_desc = Rest.get_switch_desc()
    print sw_desc
    sw_dpid_list = Rest.get_switch_list()
    print sw_dpid_list
    
    #if sw_desc is False  or int(dpid) not in sw_dpid_list:     
     #   sw_desc = "not connected"
    for dpid in sw_dpid_list:
        print dpid
        dpid_t = dpid
        flow_table = None
        flow_table = Rest.get_flow_table(dpid)
        global global_flow_table
        global_flow_table = flow_table
        port = Rest.get_switch_port(dpid)
        print "test"
    return render_template("index.html",sw_desc=sw_desc,dpid=dpid_t, port=port, flow_table=flow_table)
Пример #23
0
def update(config, app_id, type, id, file):
    """Update an application policy.
    """
    try:
        data = ''
        while True:
            chunk = file.read(1024)
            if not chunk:
                break
            data += chunk
        if not is_json(data):
            raise click.BadParameter('The policy file ' + file.name \
                                     + ' is not a valid json file.')
        url = config.server['url'] + '/v1/applications/' + str(app_id) \
              + '/policies/' + type + '/' + str(id)
        headers = {'username':config.user, 'Content-Type':'application/json'}
        rest = Rest(url, headers, data)
        display(rest.put())
    except RestError as error:
        quit(error.message)
Пример #24
0
def list(config, id):
    """List registered applications.

    Examples:

    $ jaguar application list

    $ jaguar application list --id 50
    """
    try:
        if id > 0:
            url = config.server_url + '/v1/applications/' + str(id)
        else:
            url = config.server_url + '/v1/applications'
        headers = {'username': config.user}
        rest = Rest(url, headers)
        display(rest.get())

    except RestError as error:
        quit(error.message)
Пример #25
0
def update(config, app_id, type, id, file):
    """Update an application policy.
    """
    try:
        data = ''
        while True:
            chunk = file.read(1024)
            if not chunk:
                break
            data += chunk
        if not is_json(data):
            raise click.BadParameter('The policy file ' + file.name \
                                     + ' is not a valid json file.')
        url = config.server_url + '/v1/applications/' + str(app_id) \
              + '/policies/' + type + '/' + str(id)
        headers = {'username': config.user, 'Content-Type': 'application/json'}
        rest = Rest(url, headers, data)
        display(rest.put())
    except RestError as error:
        quit(error.message)
Пример #26
0
    def get_platform_id(self):
        plat_name = platform.system() + ' ' + platform.release()
        plat_name = platform.system()
        plats = Rest.list_platform()
        if plats is not None and len(plats) > 0:
            for p in plats:
                if p['name'] == plat_name:
                    return p['id']
        
        new_platform = Rest.create_platform(plat_name)

        """
        plat_shortname = platform.system()
        if plats is not None and len(plats) > 0:
            found = False
            for p in plats:
                if p['name'] == plat_shortname:
                    found = True
                    break
            if found == False:
                Rest.create_platform(plat_shortname)
        """

        return new_platform['id']
Пример #27
0
    def register_host(self):
        print "[*] Trying to register the host..."
        platform_id = self.get_platform_id()
        arch_id = self.get_arch_id()
        mac = self.get_mac()
        #hostname, alias_list, addr_list = socket.gethostbyaddr(self.get_default_ip())
        #ip = addr_list[0]
        ip = self.get_default_ip()
        host_payload = {
            'name' : self.get_default_ip(),
            'mac' : mac,
            'ip' : ip,
            'platform_id': platform_id,
            'arch_id': arch_id
        }

        self.host = Rest.get_host_by_mac(mac)
        if self.host is not None:
            print "[!] Host with mac address %s has already been registered." % mac
            Rest.update_host(self.host['id'], host_payload)
        else:
            self.host = Rest.create_host(host_payload)

        return self.host
Пример #28
0
    def update(self):
        print "[*] Trying to update the client..."

        print "Skipping..."
        return
        try:
            with open("client.zip", "rb") as f:
                cli = f.read()
                hsh = hashlib.md5(cli).hexdigest()
        except IOError:
            hsh = "INVALID"

        path = Rest.get_update(hsh)
        if path is not None:
            shutil.rmtree('engine')
            shutil.rmtree('client')
            os.remove('client.py')
            os.remove('requirements.txt')

            f = zipfile.ZipFile(path, "r")
            f.extractall('tmp')
            f.close()

            root = 'tmp' + os.sep + 'client' + os.sep
            shutil.move(root + 'client', '.')
            shutil.move(root + 'engine', '.')
            shutil.move(root + 'client.py', '.')
            shutil.move(root + 'requirements.txt', '.')
            shutil.rmtree('tmp')

            args = sys.argv[:]
            print "[*] Update installed successfully, restarting...\n"

            args.insert(0, sys.executable)
            if sys.platform == 'win32':
                args = ['"%s"' % arg for arg in args]

            os.execv(sys.executable, args)
            sys.exit(1)

        else:
            print "[!] Client is already the latest version."
Пример #29
0
    def parse_tauot(self, line):
        try:
            if line.strip() != "":
                parts = line.split(",")
                measure = int(parts[0].strip())  # measure
                start = parts[1].split("/")
                start = float(int(start[0].strip()) /
                              int(start[1].strip()))  # start
                duration = parts[2].split("/")
                if len(duration) == 1:
                    duration = float(duration[0].strip())
                elif len(duration) == 2:
                    duration = float(
                        int(duration[0].strip()) / int(duration[1].strip()))
                else:
                    raise CorruptedCompositionFileError("Huono kesto")

                rest = Rest(measure, start, duration)
                Composition.add_rest(self.comp, rest)
                return True
        except:
            print("Huono tauko.")
Пример #30
0
def update(config, id, enable):
    """Update an application"""
    try:
        url = config.server_url + '/v1/applications/' + str(id)
        headers = {'username': config.user, 'Content-Type': 'application/json'}
        rest = Rest(url, headers)
        # check if the application exists
        response = rest.get()
        if response.status_code != requests.codes.ok:
            quit('Error: Application ' + str(id) + ' does not exist.')
        result = response.json()
        # update the field
        result['enabled'] = enable
        # post the data back
        data = json.dumps(result)
        rest = Rest(url, headers, data)
        display(rest.put())
    except RestError as error:
        quit(error.message)
Пример #31
0
def user_login(username, password, rest_url=common_data.stg_url):
    load = {"username": username, "password": password}
    response = Rest(rest_url).send(restful_uri_data.user_login, data=load)
    print(response)
Пример #32
0
def summary():
    sw_desc = Rest.get_switch_desc()
    if sw_desc is False:
        abort(404)
    return render_template("summary.html", sw_desc=sw_desc)
Пример #33
0
def topology():
    topo = Rest.get_topology()
    return render_template("topology.html", topo=topo)
Пример #34
0
def query_port():
    dpid = request.args.get("dpid")
    port = Rest.get_switch_port(dpid)

    return jsonify(port)
Пример #35
0
def add_flow():
    req = json.loads(request.form["flow_cmd"])

    flow_cmd = {}
    match_dict = {}
    action_list = []

    flow_cmd["dpid"] = req["common"]["dpid"]
    flow_cmd["priority"] = req["common"]["priority"]
    flow_cmd["idle_timeout"] = req["common"]["idle"]
    flow_cmd["hard_timeout"] = req["common"]["hard"]

    if req["match"]["input"] != "Any":
        match_dict["in_port"] = int(req["match"]["input"])

    if req["match"]["dl_saddr"] != "None":
        match_dict["dl_src"] = req["match"]["dl_saddr"]

    if req["match"]["dl_daddr"] != "None":
        match_dict["dl_dst"] = req["match"]["dl_daddr"]

    if req["match"]["nw_saddr"] != "None":
        match_dict["nw_src"] = req["match"]["nw_saddr"]

    if req["match"]["nw_daddr"] != "None":
        match_dict["nw_dst"] = req["match"]["nw_daddr"]

    if req["match"]["nw_saddr"] != "None" or req["match"]["nw_daddr"] != "None" or req["match"]["l4_proto"]:
        match_dict["dl_type"] = 2048

    if req["match"]["l4_proto"] != "None":
        if req["match"]["l4_proto"] == "TCP":
            match_dict["nw_proto"] = 6
        elif req["match"]["l4_proto"] == "UDP":
            match_dict["nw_proto"] = 17

    if req["match"]["sport"] != "None":
        match_dict["tp_src"] = int(req["match"]["sport"])

    if req["match"]["dport"] != "None":
        match_dict["tp_dst"] = int(req["match"]["dport"])

    if req["match"]["vlan_id"] != "None":
        match_dict["dl_vlan"] = int(req["match"]["vlan_id"])

    if req["action"]["output"] != "Drop":
        for value in req["action"]["output"].split(" "):
            action_dict = {}
            action_dict["port"] = int(value)
            action_dict["type"] = "OUTPUT"
            action_list.append(action_dict)

    if req["action"]["vlan_action"] != "None":
        if "Strip" in req["action"]["vlan_action"]:
            action_dict = {}
            action_dict["type"] = "POP_VLAN"
            action_list.append(action_dict)
        elif "Swap" in req["action"]["vlan_action"]:
            action_dict = {}
            action_dict["field"] = "vlan_vid"
            action_dict["value"] = req["action"]["vlan_action"].split(" ")[-1]
            action_dict["type"] = "SET_FIELD"
            action_list.append(action_dict)
        elif "New" in req["action"]["vlan_action"]:
            push_vlan_dict = {}
            push_vlan_dict["ethertype"] = 33024
            push_vlan_dict["type"] = "PUSH_VLAN"
            action_list.append(push_vlan_dict)

            action_dict = {}
            action_dict["field"] = "vlan_vid"
            action_dict["value"] = req["action"]["vlan_action"].split(" ")[-1]
            action_dict["type"] = "SET_FIELD"
            action_list.append(action_dict)

    flow_cmd["match"] = match_dict
    flow_cmd["actions"] = action_list

    # print json.dumps(flow_cmd)
    Rest.add_flow(json.dumps(flow_cmd))

    return "foo"
Пример #36
0
 def update_job_output(self, job_id, content):
     output = base64.encodestring(content)
     return Rest.update_job(job_id, {
         'output': output
     })
Пример #37
0
#!/usr/bin/env python3
import os
from pathlib import Path
from typing import Dict, Any, List

import bcrypt  # type: ignore
import jwt

from rest import Rest, Method  # type: ignore
from models import Session, User  # type: ignore
from response import response, Status  # type: ignore
from util import create_jwt, send_verification_email  # type: ignore

CONFIG_PATH = f"{Path(__file__).parent.absolute()}{os.sep}config.json"

rest: Rest = Rest(CONFIG_PATH)

secret = rest.get_secret()


@rest.route("/create/user", Method.POST)
def create_user(payload: Dict[Any, Any]) -> Dict[Any, Any]:
    """
    Creates a User from POST payload

    Parameters
    ----------

    payload: Dict[Any, Any]
         Payload of the form
         {
Пример #38
0
from constants import HEADERS
from constants import URL

from rest import Rest

api = Rest(URL, HEADERS)


def list_zones():
    resp = api.get('/zones')
    return {
        x['name']: {
            'status': x['status'],
            'id': x['id']
        }
        for x in resp['result']
    }


def list_records(zone_id, typ=None, name=None):
    params = {}
    if typ is not None:
        params['type'] = typ
    if name is not None:
        params['name'] = name
    resp = api.get(
        '/zones/{0}/dns_records'.format(zone_id),
        params if params else None,
    )
    return sorted([{
        'id': x['id'],
Пример #39
0
def do_config_call(ip, admin_port, mcd_port):
    rest = Rest(ip, admin_port, mcd_port)
    dcp_client = rest.vbDCPClient(0)
    for i in xrange(0, CALL_COUNT_PER_CHILD):
        dcp_client.get_cluster_config(0)
Пример #40
0
def query_port():
    dpid = request.args.get("dpid")
    port = Rest.get_switch_port(dpid)

    return jsonify(port)
Пример #41
0
def add_flow():
    req = json.loads(request.form["flow_cmd"])

    flow_cmd = {}
    match_dict = {}
    action_list = []

    flow_cmd["dpid"] = req["common"]["dpid"]
    flow_cmd["priority"] = req["common"]["priority"]
    flow_cmd["idle_timeout"] = req["common"]["idle"]
    flow_cmd["hard_timeout"] = req["common"]["hard"]

    if req["match"]["input"] != "Any":
        match_dict["in_port"] = int(req["match"]["input"])

    if req["match"]["dl_saddr"] != "None":
        match_dict["dl_src"] = req["match"]["dl_saddr"]

    if req["match"]["dl_daddr"] != "None":
        match_dict["dl_dst"] = req["match"]["dl_daddr"]

    if req["match"]["nw_saddr"] != "None":
        match_dict["nw_src"] = req["match"]["nw_saddr"]

    if req["match"]["nw_daddr"] != "None":
        match_dict["nw_dst"] = req["match"]["nw_daddr"]

    if req["match"]["nw_saddr"] != "None" or req["match"][
            "nw_daddr"] != "None" or req["match"]["l4_proto"]:
        match_dict["dl_type"] = 2048

    if req["match"]["l4_proto"] != "None":
        if req["match"]["l4_proto"] == "TCP":
            match_dict["nw_proto"] = 6
        elif req["match"]["l4_proto"] == "UDP":
            match_dict["nw_proto"] = 17

    if req["match"]["sport"] != "None":
        match_dict["tp_src"] = int(req["match"]["sport"])

    if req["match"]["dport"] != "None":
        match_dict["tp_dst"] = int(req["match"]["dport"])

    if req["match"]["vlan_id"] != "None":
        match_dict["dl_vlan"] = int(req["match"]["vlan_id"])

    if req["action"]["output"] != "Drop":
        for value in req["action"]["output"].split(" "):
            action_dict = {}
            action_dict["port"] = int(value)
            action_dict["type"] = "OUTPUT"
            action_list.append(action_dict)

    if req["action"]["vlan_action"] != "None":
        if "Strip" in req["action"]["vlan_action"]:
            action_dict = {}
            action_dict["type"] = "POP_VLAN"
            action_list.append(action_dict)
        elif "Swap" in req["action"]["vlan_action"]:
            action_dict = {}
            action_dict["field"] = "vlan_vid"
            action_dict["value"] = req["action"]["vlan_action"].split(" ")[-1]
            action_dict["type"] = "SET_FIELD"
            action_list.append(action_dict)
        elif "New" in req["action"]["vlan_action"]:
            push_vlan_dict = {}
            push_vlan_dict["ethertype"] = 33024
            push_vlan_dict["type"] = "PUSH_VLAN"
            action_list.append(push_vlan_dict)

            action_dict = {}
            action_dict["field"] = "vlan_vid"
            action_dict["value"] = req["action"]["vlan_action"].split(" ")[-1]
            action_dict["type"] = "SET_FIELD"
            action_list.append(action_dict)

    flow_cmd["match"] = match_dict
    flow_cmd["actions"] = action_list

    #print json.dumps(flow_cmd)
    Rest.add_flow(json.dumps(flow_cmd))

    return "foo"
Пример #42
0
def topology():
    topo = Rest.get_topology()
    return render_template("topology.html", topo=topo)
Пример #43
0
def summary():
    sw_desc = Rest.get_switch_desc()
    if sw_desc is False:
        abort(404)
    return render_template("summary.html", sw_desc=sw_desc)