<commit_before># -*- coding: utf-8 -*-

from __future__ import unicode_literals

from mock import patch, Mock

from django.utils.six.moves.urllib_parse import urlsplit, urljoin
from django.conf import settings

from nose.plugins.attrib import attr
from django_webtest import WebTest

from candidates.tests.factories import (
    AreaTypeFactory, ElectionFactory, PostExtraFactory,
    ParliamentaryChamberFactory, ParliamentaryChamberExtraFactory,
    PartySetFactory, AreaExtraFactory
)
from elections.models import Election
from .mapit_postcode_results import se240ag_result, sw1a1aa_result

def fake_requests_for_mapit(url, *args, **kwargs):
    """Return reduced MapIt output for some known URLs"""
    if url == urljoin(settings.MAPIT_BASE_URL, '/postcode/sw1a1aa'):
        status_code = 200
        json_result = sw1a1aa_result
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/se240ag'):
        status_code = 200
        json_result = se240ag_result
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/cb28rq'):
        status_code = 404
        json_result = {
            "code": 404,
            "error": "No Postcode matches the given query."
        }
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/foobar'):
        status_code = 400
        json_result = {
            "code": 400,
            "error": "Postcode 'FOOBAR' is not valid."
        }
    else:
        raise Exception("URL that hasn't been mocked yet: " + url)
    return Mock(**{
        'json.return_value': json_result,
        'status_code': status_code
    })

@attr(country='uk')
@patch('elections.uk.mapit.requests')
class TestConstituencyPostcodeFinderView(WebTest):
    def setUp(self):
        wmc_area_type = AreaTypeFactory.create()
        gb_parties = PartySetFactory.create(slug='gb', name='Great Britain')
        commons = ParliamentaryChamberFactory.create()
        election = ElectionFactory.create(
            slug='2015',
            name='2015 General Election',
            area_types=(wmc_area_type,),
            organization=commons,
        )
        area_extra = AreaExtraFactory.create(
            base__name="Dulwich and West Norwood",
            base__identifier='gss:E14000673',
            type=wmc_area_type,
        )
        self.area = area_extra.base
        PostExtraFactory.create(
            elections=(election,),
            base__organization=commons,
            slug='65808',
            base__label='Member of Parliament for Dulwich and West Norwood',
            party_set=gb_parties,
            base__area=area_extra.base,
        )

    def test_front_page(self, mock_requests):
        response = self.app.get('/')
        # Check that there is a form on that page
        response.forms['form-postcode']

    def test_valid_postcode_redirects_to_constituency(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['postcode'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/WMC-gss:E14000673',
        )

    def test_valid_postcode_redirects_to_multiple_areas(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        # Create some extra posts and areas:
        london_assembly = ParliamentaryChamberExtraFactory.create(
            slug='london-assembly', base__name='London Assembly'
        )
        lac_area_type = AreaTypeFactory.create(name='LAC')
        gla_area_type = AreaTypeFactory.create(name='GLA')
        area_extra_lac = AreaExtraFactory.create(
            base__identifier='gss:E32000010',
            base__name="Dulwich and West Norwood",
            type=lac_area_type,
        )
        area_extra_gla = AreaExtraFactory.create(
            base__identifier='unit_id:41441',
            base__name='Greater London Authority',
            type=gla_area_type,
        )
        election_lac = ElectionFactory.create(
            slug='gb-gla-2016-05-05-c',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Constituencies)',
            area_types=(lac_area_type,),
        )
        election_gla = ElectionFactory.create(
            slug='gb-gla-2016-05-05-a',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Additional)',
            area_types=(gla_area_type,),
        )
        PostExtraFactory.create(
            elections=(election_lac,),
            base__area=area_extra_lac.base,
            base__organization=london_assembly.base,
            slug='11822',
            base__label='Assembly Member for Lambeth and Southwark',
        )
        PostExtraFactory.create(
            elections=(election_gla,),
            base__area=area_extra_gla.base,
            base__organization=london_assembly.base,
            slug='2247',
            base__label='2016 London Assembly Election (Additional)',
        )
        # ----------------------------
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['postcode'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/GLA-unit_id:41441,LAC-gss:E32000010,WMC-gss:E14000673',
        )

    def test_valid_postcode_redirects_to_only_real_areas(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        # Create some extra posts and areas:
        london_assembly = ParliamentaryChamberExtraFactory.create(
            slug='london-assembly', base__name='London Assembly'
        )
        lac_area_type = AreaTypeFactory.create(name='LAC')
        gla_area_type = AreaTypeFactory.create(name='GLA')
        area_extra_gla = AreaExtraFactory.create(
            base__identifier='unit_id:41441',
            base__name='Greater London Authority',
            type=gla_area_type,
        )
        ElectionFactory.create(
            slug='gb-gla-2016-05-05-c',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Constituencies)',
            area_types=(lac_area_type,),
        )
        election_gla = ElectionFactory.create(
            slug='gb-gla-2016-05-05-a',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Additional)',
            area_types=(gla_area_type,),
        )
        PostExtraFactory.create(
            elections=(election_gla,),
            base__area=area_extra_gla.base,
            base__organization=london_assembly.base,
            slug='2247',
            base__label='2016 London Assembly Election (Additional)',
        )
        # ----------------------------
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['postcode'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/GLA-unit_id:41441,WMC-gss:E14000673',
        )

    def test_unknown_postcode_returns_to_finder_with_error(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # This looks like a postcode to the usual postcode-checking
        # regular expressions, but doesn't actually exist
        form['postcode'] = 'CB2 8RQ'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn('The postcode “CB2 8RQ” couldn’t be found', response)

    def test_nonsense_postcode_returns_to_finder_with_error(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # This looks like a postcode to the usual postcode-checking
        # regular expressions, but doesn't actually exist
        form['postcode'] = 'foo bar'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn('Postcode 'FOOBAR' is not valid.', response)

    def test_nonascii_postcode(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # Postcodes with non-ASCII characters should be rejected
        form['postcode'] = 'SW1A 1ӔA'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn(
            'There were disallowed characters in "SW1A 1ӔA"',
            response
        )
<commit_msg>Update the name of the field in the postcode search form<commit_after># -*- coding: utf-8 -*-

from __future__ import unicode_literals

from mock import patch, Mock

from django.utils.six.moves.urllib_parse import urlsplit, urljoin
from django.conf import settings

from nose.plugins.attrib import attr
from django_webtest import WebTest

from candidates.tests.factories import (
    AreaTypeFactory, ElectionFactory, PostExtraFactory,
    ParliamentaryChamberFactory, ParliamentaryChamberExtraFactory,
    PartySetFactory, AreaExtraFactory
)
from elections.models import Election
from .mapit_postcode_results import se240ag_result, sw1a1aa_result

def fake_requests_for_mapit(url, *args, **kwargs):
    """Return reduced MapIt output for some known URLs"""
    if url == urljoin(settings.MAPIT_BASE_URL, '/postcode/sw1a1aa'):
        status_code = 200
        json_result = sw1a1aa_result
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/se240ag'):
        status_code = 200
        json_result = se240ag_result
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/cb28rq'):
        status_code = 404
        json_result = {
            "code": 404,
            "error": "No Postcode matches the given query."
        }
    elif url == urljoin(settings.MAPIT_BASE_URL, '/postcode/foobar'):
        status_code = 400
        json_result = {
            "code": 400,
            "error": "Postcode 'FOOBAR' is not valid."
        }
    else:
        raise Exception("URL that hasn't been mocked yet: " + url)
    return Mock(**{
        'json.return_value': json_result,
        'status_code': status_code
    })

@attr(country='uk')
@patch('elections.uk.mapit.requests')
class TestConstituencyPostcodeFinderView(WebTest):
    def setUp(self):
        wmc_area_type = AreaTypeFactory.create()
        gb_parties = PartySetFactory.create(slug='gb', name='Great Britain')
        commons = ParliamentaryChamberFactory.create()
        election = ElectionFactory.create(
            slug='2015',
            name='2015 General Election',
            area_types=(wmc_area_type,),
            organization=commons,
        )
        area_extra = AreaExtraFactory.create(
            base__name="Dulwich and West Norwood",
            base__identifier='gss:E14000673',
            type=wmc_area_type,
        )
        self.area = area_extra.base
        PostExtraFactory.create(
            elections=(election,),
            base__organization=commons,
            slug='65808',
            base__label='Member of Parliament for Dulwich and West Norwood',
            party_set=gb_parties,
            base__area=area_extra.base,
        )

    def test_front_page(self, mock_requests):
        response = self.app.get('/')
        # Check that there is a form on that page
        response.forms['form-postcode']

    def test_valid_postcode_redirects_to_constituency(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['q'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/WMC-gss:E14000673',
        )

    def test_valid_postcode_redirects_to_multiple_areas(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        # Create some extra posts and areas:
        london_assembly = ParliamentaryChamberExtraFactory.create(
            slug='london-assembly', base__name='London Assembly'
        )
        lac_area_type = AreaTypeFactory.create(name='LAC')
        gla_area_type = AreaTypeFactory.create(name='GLA')
        area_extra_lac = AreaExtraFactory.create(
            base__identifier='gss:E32000010',
            base__name="Dulwich and West Norwood",
            type=lac_area_type,
        )
        area_extra_gla = AreaExtraFactory.create(
            base__identifier='unit_id:41441',
            base__name='Greater London Authority',
            type=gla_area_type,
        )
        election_lac = ElectionFactory.create(
            slug='gb-gla-2016-05-05-c',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Constituencies)',
            area_types=(lac_area_type,),
        )
        election_gla = ElectionFactory.create(
            slug='gb-gla-2016-05-05-a',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Additional)',
            area_types=(gla_area_type,),
        )
        PostExtraFactory.create(
            elections=(election_lac,),
            base__area=area_extra_lac.base,
            base__organization=london_assembly.base,
            slug='11822',
            base__label='Assembly Member for Lambeth and Southwark',
        )
        PostExtraFactory.create(
            elections=(election_gla,),
            base__area=area_extra_gla.base,
            base__organization=london_assembly.base,
            slug='2247',
            base__label='2016 London Assembly Election (Additional)',
        )
        # ----------------------------
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['q'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/GLA-unit_id:41441,LAC-gss:E32000010,WMC-gss:E14000673',
        )

    def test_valid_postcode_redirects_to_only_real_areas(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        # Create some extra posts and areas:
        london_assembly = ParliamentaryChamberExtraFactory.create(
            slug='london-assembly', base__name='London Assembly'
        )
        lac_area_type = AreaTypeFactory.create(name='LAC')
        gla_area_type = AreaTypeFactory.create(name='GLA')
        area_extra_gla = AreaExtraFactory.create(
            base__identifier='unit_id:41441',
            base__name='Greater London Authority',
            type=gla_area_type,
        )
        ElectionFactory.create(
            slug='gb-gla-2016-05-05-c',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Constituencies)',
            area_types=(lac_area_type,),
        )
        election_gla = ElectionFactory.create(
            slug='gb-gla-2016-05-05-a',
            organization=london_assembly.base,
            name='2016 London Assembly Election (Additional)',
            area_types=(gla_area_type,),
        )
        PostExtraFactory.create(
            elections=(election_gla,),
            base__area=area_extra_gla.base,
            base__organization=london_assembly.base,
            slug='2247',
            base__label='2016 London Assembly Election (Additional)',
        )
        # ----------------------------
        response = self.app.get('/')
        form = response.forms['form-postcode']
        form['q'] = 'SE24 0AG'
        response = form.submit()
        self.assertEqual(response.status_code, 302)
        split_location = urlsplit(response.location)
        self.assertEqual(
            split_location.path,
            '/areas/GLA-unit_id:41441,WMC-gss:E14000673',
        )

    def test_unknown_postcode_returns_to_finder_with_error(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # This looks like a postcode to the usual postcode-checking
        # regular expressions, but doesn't actually exist
        form['q'] = 'CB2 8RQ'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn('The postcode “CB2 8RQ” couldn’t be found', response)

    def test_nonsense_postcode_returns_to_finder_with_error(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # This looks like a postcode to the usual postcode-checking
        # regular expressions, but doesn't actually exist
        form['q'] = 'foo bar'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn('Postcode 'FOOBAR' is not valid.', response)

    def test_nonascii_postcode(self, mock_requests):
        mock_requests.get.side_effect = fake_requests_for_mapit
        response = self.app.get('/')
        form = response.forms['form-postcode']
        # Postcodes with non-ASCII characters should be rejected
        form['q'] = 'SW1A 1ӔA'
        response = form.submit()
        self.assertEqual(response.status_code, 200)
        self.assertIn(
            'There were disallowed characters in "SW1A 1ӔA"',
            response
        )
<|endoftext|>


<commit_before>from typing import TYPE_CHECKING

import PyQt5.QtGui as QtGui
import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore

from electrum.i18n import _
from electrum.util import bh2u, format_time
from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction
from electrum.lnchan import htlcsum
from electrum.lnaddr import LnAddr, lndecode
from electrum.bitcoin import COIN

if TYPE_CHECKING:
    from .main_window import ElectrumWindow

class HTLCItem(QtGui.QStandardItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setEditable(False)

class SelectableLabel(QtWidgets.QLabel):
    def __init__(self, text=''):
        super().__init__(text)
        self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)

class LinkedLabel(QtWidgets.QLabel):
    def __init__(self, text, on_clicked):
        super().__init__(text)
        self.linkActivated.connect(on_clicked)

class ChannelDetailsDialog(QtWidgets.QDialog):
    def make_htlc_item(self, i: UpdateAddHtlc, direction: Direction) -> HTLCItem:
        it = HTLCItem(_('Sent HTLC with ID {}' if Direction.SENT == direction else 'Received HTLC with ID {}').format(i.htlc_id))
        it.appendRow([HTLCItem(_('Amount')),HTLCItem(self.format(i.amount_msat))])
        it.appendRow([HTLCItem(_('CLTV expiry')),HTLCItem(str(i.cltv_expiry))])
        it.appendRow([HTLCItem(_('Payment hash')),HTLCItem(bh2u(i.payment_hash))])
        return it

    def append_lnaddr(self, it: HTLCItem, lnaddr: LnAddr):
        invoice = HTLCItem(_('Invoice'))
        invoice.appendRow([HTLCItem(_('Remote node public key')), HTLCItem(bh2u(lnaddr.pubkey.serialize()))])
        invoice.appendRow([HTLCItem(_('Amount in sat')), HTLCItem(str(lnaddr.amount * COIN))]) # might have a comma because mSAT!
        invoice.appendRow([HTLCItem(_('Description')), HTLCItem(dict(lnaddr.tags).get('d', _('N/A')))])
        invoice.appendRow([HTLCItem(_('Date')), HTLCItem(format_time(lnaddr.date))])
        it.appendRow([invoice])

    def make_inflight(self, lnaddr, i: UpdateAddHtlc, direction: Direction) -> HTLCItem:
        it = self.make_htlc_item(i, direction)
        self.append_lnaddr(it, lnaddr)
        return it

    def make_model(self, htlcs) -> QtGui.QStandardItemModel:
        model = QtGui.QStandardItemModel(0, 2)
        model.setHorizontalHeaderLabels(['HTLC', 'Property value'])
        parentItem = model.invisibleRootItem()
        folder_types = {'settled': _('Fulfilled HTLCs'), 'inflight': _('HTLCs in current commitment transaction')}
        self.folders = {}
        self.keyname_rows = {}

        for keyname, i in folder_types.items():
            myFont=QtGui.QFont()
            myFont.setBold(True)
            folder = HTLCItem(i)
            folder.setFont(myFont)
            parentItem.appendRow(folder)
            self.folders[keyname] = folder
            mapping = {}
            num = 0

        invoices = dict(self.window.wallet.lnworker.invoices)
        for pay_hash, item in htlcs.items():
            chan_id, i, direction, status = item
            if pay_hash in invoices:
                invoice = invoices[pay_hash][1]
                lnaddr = lndecode(invoice)
            if status == 'inflight':
                it = self.make_inflight(lnaddr, i, direction)
            elif status == 'settled':
                it = self.make_htlc_item(i, direction)
                # if we made the invoice and still have it, we can show more info
                if pay_hash in invoices:
                    self.append_lnaddr(it, lndecode(invoice))
            self.folders[status].appendRow(it)
            mapping[i.payment_hash] = num
            num += 1
            self.keyname_rows[keyname] = mapping
        return model

    def move(self, fro: str, to: str, payment_hash: bytes):
        assert fro != to
        row_idx = self.keyname_rows[fro].pop(payment_hash)
        row = self.folders[fro].takeRow(row_idx)
        self.folders[to].appendRow(row)
        dest_mapping = self.keyname_rows[to]
        dest_mapping[payment_hash] = len(dest_mapping)

    ln_payment_completed = QtCore.pyqtSignal(str, float, Direction, UpdateAddHtlc, bytes, bytes)
    htlc_added = QtCore.pyqtSignal(str, UpdateAddHtlc, LnAddr, Direction)

    @QtCore.pyqtSlot(str, UpdateAddHtlc, LnAddr, Direction)
    def do_htlc_added(self, evtname, htlc, lnaddr, direction):
        mapping = self.keyname_rows['inflight']
        mapping[htlc.payment_hash] = len(mapping)
        self.folders['inflight'].appendRow(self.make_inflight(lnaddr, htlc, direction))

    @QtCore.pyqtSlot(str, float, Direction, UpdateAddHtlc, bytes, bytes)
    def do_ln_payment_completed(self, evtname, date, direction, htlc, preimage, chan_id):
        self.move('inflight', 'settled', htlc.payment_hash)
        self.update_sent_received()

    def update_sent_received(self):
        self.sent_label.setText(str(htlcsum(self.chan.hm.settled_htlcs_by(LOCAL))))
        self.received_label.setText(str(htlcsum(self.chan.hm.settled_htlcs_by(REMOTE))))

    @QtCore.pyqtSlot(str)
    def show_tx(self, link_text: str):
        funding_tx = self.window.wallet.transactions[self.chan.funding_outpoint.txid]
        self.window.show_transaction(funding_tx, tx_desc=_('Funding Transaction'))

    def __init__(self, window: 'ElectrumWindow', chan_id: bytes):
        super().__init__(window)

        # initialize instance fields
        self.window = window
        chan = self.chan = window.wallet.lnworker.channels[chan_id]
        self.format = lambda msat: window.format_amount_and_units(msat / 1000)

        # connect signals with slots
        self.ln_payment_completed.connect(self.do_ln_payment_completed)
        self.htlc_added.connect(self.do_htlc_added)

        # register callbacks for updating
        window.network.register_callback(self.ln_payment_completed.emit, ['ln_payment_completed'])
        window.network.register_callback(self.htlc_added.emit, ['htlc_added'])

        # set attributes of QDialog
        self.setWindowTitle(_('Channel Details'))
        self.setMinimumSize(800, 400)

        # add layouts
        vbox = QtWidgets.QVBoxLayout(self)
        form_layout = QtWidgets.QFormLayout(None)
        vbox.addLayout(form_layout)

        # add form content
        form_layout.addRow(_('Node ID:'), SelectableLabel(bh2u(chan.node_id)))
        form_layout.addRow(_('Channel ID:'), SelectableLabel(bh2u(chan.channel_id)))
        funding_label_text = f'{chan.funding_outpoint.txid}:{chan.funding_outpoint.output_index}'
        form_layout.addRow(_('Funding Outpoint:'), LinkedLabel(funding_label_text, self.show_tx))
        form_layout.addRow(_('Short Channel ID:'), SelectableLabel(format_short_channel_id(chan.short_channel_id)))
        self.received_label = SelectableLabel()
        form_layout.addRow(_('Received (mSAT):'), self.received_label)
        self.sent_label = SelectableLabel()
        form_layout.addRow(_('Sent (mSAT):'), self.sent_label)
        self.htlc_minimum_msat = SelectableLabel(str(chan.config[REMOTE].htlc_minimum_msat))
        form_layout.addRow(_('Minimum HTLC value accepted by peer (mSAT):'), self.htlc_minimum_msat)
        self.max_htlcs = SelectableLabel(str(chan.config[REMOTE].max_accepted_htlcs))
        form_layout.addRow(_('Maximum number of concurrent HTLCs accepted by peer:'), self.max_htlcs)
        self.max_htlc_value = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].max_htlc_value_in_flight_msat / 1000))
        form_layout.addRow(_('Maximum value of in-flight HTLCs accepted by peer:'), self.max_htlc_value)
        self.dust_limit = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].dust_limit_sat))
        form_layout.addRow(_('Remote dust limit:'), self.dust_limit)
        self.reserve = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].reserve_sat))
        form_layout.addRow(_('Remote channel reserve:'), self.reserve)

        # add htlc tree view to vbox (wouldn't scale correctly in QFormLayout)
        form_layout.addRow(_('Payments (HTLCs):'), None)
        w = QtWidgets.QTreeView(self)
        htlc_dict = chan.get_payments()
        w.setModel(self.make_model(htlc_dict))
        w.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        vbox.addWidget(w)

        # initialize sent/received fields
        self.update_sent_received()
<commit_msg>qt: channel_details: prevent crash on stuck SENT htlc<commit_after>from typing import TYPE_CHECKING

import PyQt5.QtGui as QtGui
import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore

from electrum.i18n import _
from electrum.util import bh2u, format_time
from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction
from electrum.lnchan import htlcsum
from electrum.lnaddr import LnAddr, lndecode
from electrum.bitcoin import COIN

if TYPE_CHECKING:
    from .main_window import ElectrumWindow

class HTLCItem(QtGui.QStandardItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setEditable(False)

class SelectableLabel(QtWidgets.QLabel):
    def __init__(self, text=''):
        super().__init__(text)
        self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)

class LinkedLabel(QtWidgets.QLabel):
    def __init__(self, text, on_clicked):
        super().__init__(text)
        self.linkActivated.connect(on_clicked)

class ChannelDetailsDialog(QtWidgets.QDialog):
    def make_htlc_item(self, i: UpdateAddHtlc, direction: Direction) -> HTLCItem:
        it = HTLCItem(_('Sent HTLC with ID {}' if Direction.SENT == direction else 'Received HTLC with ID {}').format(i.htlc_id))
        it.appendRow([HTLCItem(_('Amount')),HTLCItem(self.format(i.amount_msat))])
        it.appendRow([HTLCItem(_('CLTV expiry')),HTLCItem(str(i.cltv_expiry))])
        it.appendRow([HTLCItem(_('Payment hash')),HTLCItem(bh2u(i.payment_hash))])
        return it

    def append_lnaddr(self, it: HTLCItem, lnaddr: LnAddr):
        invoice = HTLCItem(_('Invoice'))
        invoice.appendRow([HTLCItem(_('Remote node public key')), HTLCItem(bh2u(lnaddr.pubkey.serialize()))])
        invoice.appendRow([HTLCItem(_('Amount in sat')), HTLCItem(str(lnaddr.amount * COIN))]) # might have a comma because mSAT!
        invoice.appendRow([HTLCItem(_('Description')), HTLCItem(dict(lnaddr.tags).get('d', _('N/A')))])
        invoice.appendRow([HTLCItem(_('Date')), HTLCItem(format_time(lnaddr.date))])
        it.appendRow([invoice])

    def make_inflight(self, lnaddr, i: UpdateAddHtlc, direction: Direction) -> HTLCItem:
        it = self.make_htlc_item(i, direction)
        self.append_lnaddr(it, lnaddr)
        return it

    def make_model(self, htlcs) -> QtGui.QStandardItemModel:
        model = QtGui.QStandardItemModel(0, 2)
        model.setHorizontalHeaderLabels(['HTLC', 'Property value'])
        parentItem = model.invisibleRootItem()
        folder_types = {'settled': _('Fulfilled HTLCs'), 'inflight': _('HTLCs in current commitment transaction')}
        self.folders = {}
        self.keyname_rows = {}

        for keyname, i in folder_types.items():
            myFont=QtGui.QFont()
            myFont.setBold(True)
            folder = HTLCItem(i)
            folder.setFont(myFont)
            parentItem.appendRow(folder)
            self.folders[keyname] = folder
            mapping = {}
            num = 0

        invoices = dict(self.window.wallet.lnworker.invoices)
        for pay_hash, item in htlcs.items():
            chan_id, i, direction, status = item
            lnaddr = None
            if pay_hash in invoices:
                invoice = invoices[pay_hash][1]
                lnaddr = lndecode(invoice)
            if status == 'inflight':
                if lnaddr is not None:
                    it = self.make_inflight(lnaddr, i, direction)
                else:
                    it = self.make_htlc_item(i, direction)
            elif status == 'settled':
                it = self.make_htlc_item(i, direction)
                # if we made the invoice and still have it, we can show more info
                if lnaddr is not None:
                    self.append_lnaddr(it, lnaddr)
            self.folders[status].appendRow(it)
            mapping[i.payment_hash] = num
            num += 1
            self.keyname_rows[keyname] = mapping
        return model

    def move(self, fro: str, to: str, payment_hash: bytes):
        assert fro != to
        row_idx = self.keyname_rows[fro].pop(payment_hash)
        row = self.folders[fro].takeRow(row_idx)
        self.folders[to].appendRow(row)
        dest_mapping = self.keyname_rows[to]
        dest_mapping[payment_hash] = len(dest_mapping)

    ln_payment_completed = QtCore.pyqtSignal(str, float, Direction, UpdateAddHtlc, bytes, bytes)
    htlc_added = QtCore.pyqtSignal(str, UpdateAddHtlc, LnAddr, Direction)

    @QtCore.pyqtSlot(str, UpdateAddHtlc, LnAddr, Direction)
    def do_htlc_added(self, evtname, htlc, lnaddr, direction):
        mapping = self.keyname_rows['inflight']
        mapping[htlc.payment_hash] = len(mapping)
        self.folders['inflight'].appendRow(self.make_inflight(lnaddr, htlc, direction))

    @QtCore.pyqtSlot(str, float, Direction, UpdateAddHtlc, bytes, bytes)
    def do_ln_payment_completed(self, evtname, date, direction, htlc, preimage, chan_id):
        self.move('inflight', 'settled', htlc.payment_hash)
        self.update_sent_received()

    def update_sent_received(self):
        self.sent_label.setText(str(htlcsum(self.chan.hm.settled_htlcs_by(LOCAL))))
        self.received_label.setText(str(htlcsum(self.chan.hm.settled_htlcs_by(REMOTE))))

    @QtCore.pyqtSlot(str)
    def show_tx(self, link_text: str):
        funding_tx = self.window.wallet.transactions[self.chan.funding_outpoint.txid]
        self.window.show_transaction(funding_tx, tx_desc=_('Funding Transaction'))

    def __init__(self, window: 'ElectrumWindow', chan_id: bytes):
        super().__init__(window)

        # initialize instance fields
        self.window = window
        chan = self.chan = window.wallet.lnworker.channels[chan_id]
        self.format = lambda msat: window.format_amount_and_units(msat / 1000)

        # connect signals with slots
        self.ln_payment_completed.connect(self.do_ln_payment_completed)
        self.htlc_added.connect(self.do_htlc_added)

        # register callbacks for updating
        window.network.register_callback(self.ln_payment_completed.emit, ['ln_payment_completed'])
        window.network.register_callback(self.htlc_added.emit, ['htlc_added'])

        # set attributes of QDialog
        self.setWindowTitle(_('Channel Details'))
        self.setMinimumSize(800, 400)

        # add layouts
        vbox = QtWidgets.QVBoxLayout(self)
        form_layout = QtWidgets.QFormLayout(None)
        vbox.addLayout(form_layout)

        # add form content
        form_layout.addRow(_('Node ID:'), SelectableLabel(bh2u(chan.node_id)))
        form_layout.addRow(_('Channel ID:'), SelectableLabel(bh2u(chan.channel_id)))
        funding_label_text = f'{chan.funding_outpoint.txid}:{chan.funding_outpoint.output_index}'
        form_layout.addRow(_('Funding Outpoint:'), LinkedLabel(funding_label_text, self.show_tx))
        form_layout.addRow(_('Short Channel ID:'), SelectableLabel(format_short_channel_id(chan.short_channel_id)))
        self.received_label = SelectableLabel()
        form_layout.addRow(_('Received (mSAT):'), self.received_label)
        self.sent_label = SelectableLabel()
        form_layout.addRow(_('Sent (mSAT):'), self.sent_label)
        self.htlc_minimum_msat = SelectableLabel(str(chan.config[REMOTE].htlc_minimum_msat))
        form_layout.addRow(_('Minimum HTLC value accepted by peer (mSAT):'), self.htlc_minimum_msat)
        self.max_htlcs = SelectableLabel(str(chan.config[REMOTE].max_accepted_htlcs))
        form_layout.addRow(_('Maximum number of concurrent HTLCs accepted by peer:'), self.max_htlcs)
        self.max_htlc_value = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].max_htlc_value_in_flight_msat / 1000))
        form_layout.addRow(_('Maximum value of in-flight HTLCs accepted by peer:'), self.max_htlc_value)
        self.dust_limit = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].dust_limit_sat))
        form_layout.addRow(_('Remote dust limit:'), self.dust_limit)
        self.reserve = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].reserve_sat))
        form_layout.addRow(_('Remote channel reserve:'), self.reserve)

        # add htlc tree view to vbox (wouldn't scale correctly in QFormLayout)
        form_layout.addRow(_('Payments (HTLCs):'), None)
        w = QtWidgets.QTreeView(self)
        htlc_dict = chan.get_payments()
        w.setModel(self.make_model(htlc_dict))
        w.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        vbox.addWidget(w)

        # initialize sent/received fields
        self.update_sent_received()
<|endoftext|>


<commit_before>from array import array
from typing import Collection, Optional, List

__all__ = ["suggestion_list"]

def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
    """Get list with suggestions for a given input.

    Given an invalid input string and list of valid options, returns a filtered list
    of valid options sorted based on their similarity with the input.
    """
    options_by_distance = {}
    lexical_distance = LexicalDistance(input_)

    threshold = int(len(input_) * 0.4) + 1
    for option in options:
        distance = lexical_distance.measure(option, threshold)
        if distance is not None:
            options_by_distance[option] = distance

    # noinspection PyShadowingNames
    return sorted(
        options_by_distance,
        key=lambda option: (options_by_distance.get(option, 0), option),
    )

class LexicalDistance:
    """Computes the lexical distance between strings A and B.

    The "distance" between two strings is given by counting the minimum number of edits
    needed to transform string A into string B. An edit can be an insertion, deletion,
    or substitution of a single character, or a swap of two adjacent characters.

    This distance can be useful for detecting typos in input or sorting.
    """

    _input: str
    _input_lower_case: str
    _input_list = List[int]
    _rows: List[List[int]]

    def __init__(self, input_: str):
        self._input = input_
        self._input_lower_case = input_.lower()
        row_size = len(input_) + 1
        self._input_list = list(map(ord, self._input_lower_case))

        self._rows = [[0] * row_size, [0] * row_size, [0] * row_size]

    def measure(self, option: str, threshold: int) -> Optional[int]:
        if self._input == option:
            return 0

        option_lower_case = option.lower()

        # Any case change counts as a single edit
        if self._input_lower_case == option_lower_case:
            return 1

        a, b = list(map(ord, option_lower_case)), self._input_list
        a_len, b_len = len(a), len(b)
        if a_len < b_len:
            a, b = b, a
            a_len, b_len = b_len, a_len

        if a_len - b_len > threshold:
            return None

        rows = self._rows
        for j in range(0, b_len + 1):
            rows[0][j] = j

        for i in range(1, a_len + 1):
            up_row = rows[(i - 1) % 3]
            current_row = rows[i % 3]

            smallest_cell = current_row[0] = i
            for j in range(1, b_len + 1):
                cost = 0 if a[i - 1] == b[j - 1] else 1

                current_cell = min(
                    up_row[j] + 1,  # delete
                    current_row[j - 1] + 1,  # insert
                    up_row[j - 1] + cost,  # substitute
                )

                if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]:
                    # transposition
                    double_diagonal_cell = rows[(i - 2) % 3][j - 2]
                    current_cell = min(current_cell, double_diagonal_cell + 1)

                if current_cell < smallest_cell:
                    smallest_cell = current_cell

                current_row[j] = current_cell

            # Early exit, since distance can't go smaller than smallest element
            # of the previous row.
            if smallest_cell > threshold:
                return None

        distance = rows[a_len % 3][b_len]
        return distance if distance <= threshold else None
<commit_msg>Fix typing issue in suggestion_list<commit_after>from typing import Collection, Optional, List

__all__ = ["suggestion_list"]

def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
    """Get list with suggestions for a given input.

    Given an invalid input string and list of valid options, returns a filtered list
    of valid options sorted based on their similarity with the input.
    """
    options_by_distance = {}
    lexical_distance = LexicalDistance(input_)

    threshold = int(len(input_) * 0.4) + 1
    for option in options:
        distance = lexical_distance.measure(option, threshold)
        if distance is not None:
            options_by_distance[option] = distance

    # noinspection PyShadowingNames
    return sorted(
        options_by_distance,
        key=lambda option: (options_by_distance.get(option, 0), option),
    )

class LexicalDistance:
    """Computes the lexical distance between strings A and B.

    The "distance" between two strings is given by counting the minimum number of edits
    needed to transform string A into string B. An edit can be an insertion, deletion,
    or substitution of a single character, or a swap of two adjacent characters.

    This distance can be useful for detecting typos in input or sorting.
    """

    _input: str
    _input_lower_case: str
    _input_list: List[int]
    _rows: List[List[int]]

    def __init__(self, input_: str):
        self._input = input_
        self._input_lower_case = input_.lower()
        row_size = len(input_) + 1
        self._input_list = list(map(ord, self._input_lower_case))

        self._rows = [[0] * row_size, [0] * row_size, [0] * row_size]

    def measure(self, option: str, threshold: int) -> Optional[int]:
        if self._input == option:
            return 0

        option_lower_case = option.lower()

        # Any case change counts as a single edit
        if self._input_lower_case == option_lower_case:
            return 1

        a, b = list(map(ord, option_lower_case)), self._input_list
        a_len, b_len = len(a), len(b)
        if a_len < b_len:
            a, b = b, a
            a_len, b_len = b_len, a_len

        if a_len - b_len > threshold:
            return None

        rows = self._rows
        for j in range(0, b_len + 1):
            rows[0][j] = j

        for i in range(1, a_len + 1):
            up_row = rows[(i - 1) % 3]
            current_row = rows[i % 3]

            smallest_cell = current_row[0] = i
            for j in range(1, b_len + 1):
                cost = 0 if a[i - 1] == b[j - 1] else 1

                current_cell = min(
                    up_row[j] + 1,  # delete
                    current_row[j - 1] + 1,  # insert
                    up_row[j - 1] + cost,  # substitute
                )

                if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]:
                    # transposition
                    double_diagonal_cell = rows[(i - 2) % 3][j - 2]
                    current_cell = min(current_cell, double_diagonal_cell + 1)

                if current_cell < smallest_cell:
                    smallest_cell = current_cell

                current_row[j] = current_cell

            # Early exit, since distance can't go smaller than smallest element
            # of the previous row.
            if smallest_cell > threshold:
                return None

        distance = rows[a_len % 3][b_len]
        return distance if distance <= threshold else None
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from io import BytesIO as StringIO
from string import Template
import base64

__version__ = "0.2"
renderers = []

try:
    import cv2
    import numpy

    def render_opencv(img, fmt="png"):
        if not isinstance(img, numpy.ndarray):
            return None

        retval, buf = cv2.imencode(".%s" % fmt, img)
        if not retval:
            return None

        return buf, "image/%s" % fmt

    renderers.append(render_opencv)
except ImportError:
    pass

try:
    from PIL import Image

    def render_pil(img, fmt="png"):
        if not callable(getattr(img, "save", None)):
            return None

        output = StringIO()
        img.save(output, format=fmt)
        contents = output.getvalue()
        output.close()

        return contents, "image/%s" % fmt

    renderers.append(render_pil)
except ImportError:
    pass

try:
    import pylab

    def render_pylab(img, fmt="png"):
        if not callable(getattr(img, "savefig", None)):
            return None

        output = StringIO()
        img.savefig(output, format=fmt)
        contents = output.getvalue()
        output.close()

        return contents, "image/%s" % fmt

    renderers.append(render_pylab)
except ImportError:
    pass

class VisualRecord(object):
    def __init__(self, title="", imgs=None, footnotes="", fmt="png"):
        self.title = title
        self.fmt = fmt

        if imgs is None:
            imgs = []

        self.imgs = imgs

        if not isinstance(imgs, (list, tuple, set, frozenset)):
            self.imgs = [self.imgs]

        self.footnotes = footnotes

    def render_images(self):
        rendered = []

        for img in self.imgs:
            for renderer in renderers:
                # Trying renderers we have one by one
                res = renderer(img, self.fmt)

                if res is None:
                    continue
                else:
                    rendered.append(res)
                    break

        return "".join(
            Template('').substitute({
                "data": base64.b64encode(data),
                "mime": mime
            }) for data, mime in rendered)

    def render_footnotes(self):
        if not self.footnotes:
            return ""

        return Template("
$footnotes
").substitute({
            "footnotes": self.footnotes
        })

    def __str__(self):
        t = Template(
            """

$title

            $imgs
            $footnotes

""")

        return t.substitute({
            "title": self.title,
            "imgs": self.render_images(),
            "footnotes": self.render_footnotes()
        })
<commit_msg>added .decode() to base64 encoding for it work with Python 3.5.2<commit_after># -*- coding: utf-8 -*-

from io import BytesIO as StringIO
from string import Template
import base64

__version__ = "0.2"
renderers = []

try:
    import cv2
    import numpy

    def render_opencv(img, fmt="png"):
        if not isinstance(img, numpy.ndarray):
            return None

        retval, buf = cv2.imencode(".%s" % fmt, img)
        if not retval:
            return None

        return buf, "image/%s" % fmt

    renderers.append(render_opencv)
except ImportError:
    pass

try:
    from PIL import Image

    def render_pil(img, fmt="png"):
        if not callable(getattr(img, "save", None)):
            return None

        output = StringIO()
        img.save(output, format=fmt)
        contents = output.getvalue()
        output.close()

        return contents, "image/%s" % fmt

    renderers.append(render_pil)
except ImportError:
    pass

try:
    import pylab

    def render_pylab(img, fmt="png"):
        if not callable(getattr(img, "savefig", None)):
            return None

        output = StringIO()
        img.savefig(output, format=fmt)
        contents = output.getvalue()
        output.close()

        return contents, "image/%s" % fmt

    renderers.append(render_pylab)
except ImportError:
    pass

class VisualRecord(object):
    def __init__(self, title="", imgs=None, footnotes="", fmt="png"):
        self.title = title
        self.fmt = fmt

        if imgs is None:
            imgs = []

        self.imgs = imgs

        if not isinstance(imgs, (list, tuple, set, frozenset)):
            self.imgs = [self.imgs]

        self.footnotes = footnotes

    def render_images(self):
        rendered = []

        for img in self.imgs:
            for renderer in renderers:
                # Trying renderers we have one by one
                res = renderer(img, self.fmt)

                if res is None:
                    continue
                else:
                    rendered.append(res)
                    break

        return "".join(
            Template('').substitute({
                "data": base64.b64encode(data).decode(),
                "mime": mime
            }) for data, mime in rendered)

    def render_footnotes(self):
        if not self.footnotes:
            return ""

        return Template("
$footnotes
").substitute({
            "footnotes": self.footnotes
        })

    def __str__(self):
        t = Template(
            """

$title

            $imgs
            $footnotes

""")

        return t.substitute({
            "title": self.title,
            "imgs": self.render_images(),
            "footnotes": self.render_footnotes()
        })
<|endoftext|>


<commit_before>"""
Distributed Cloud Emulator (dcemulator)
(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
"""

import logging
import threading
import zerorpc
import site
from subprocess import Popen

logging.basicConfig(level=logging.INFO)

class ZeroRpcApiEndpointDCNetwork(object):
    """
    Simple API endpoint that offers a zerorpc-based
    interface. This interface will be used by the
    default command line client.
    It can be used as a reference to implement
    REST interfaces providing the same semantics,
    like e.g. OpenStack compute API.
    """

    def __init__(self, listenip, port, DCNetwork=None):
        if DCNetwork :
            self.connectDCNetwork(DCNetwork)
        self.ip = listenip
        self.port = port
        logging.debug("Created monitoring API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

        # start Ryu controller with rest-API
        python_install_path = site.getsitepackages()[0]
        ryu_path = python_install_path + '/ryu/app/ofctl_rest.py'
        ryu_cmd =  'ryu-manager'
        self.ryu_process = Popen([ryu_cmd,ryu_path])

    def connectDCNetwork(self, net):
        self.net = net
        logging.info("Connected DCNetwork to API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

    def start(self):
        thread = threading.Thread(target=self._api_server_thread, args=())
        thread.daemon = True
        thread.start()
        logging.debug("Started API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

    def _api_server_thread(self):
        s = zerorpc.Server(DCNetworkApi(self.net))
        s.bind("tcp://%s:%d" % (self.ip, self.port))
        s.run()

    def stop(self):
        # stop ryu controller
        logging.info("Stop the monitoring API endpoint")
        self.ryu_process.terminate()
        #self.ryu_process.kill()
        return

class DCNetworkApi(object):
    """
        Just pass through the corresponding request to the
        selected data center. Do not implement provisioning
        logic here because will will have multiple API
        endpoint implementations at the end.
    """

    def __init__(self, net):
        self.net = net

    def network_action_start(self, vnf_src_name, vnf_dst_name):
        # call DCNetwork method, not really datacenter specific API for now...
        # provided dc name needs to be part of API endpoint
        # no check if vnfs are really connected to this datacenter...
        logging.debug("RPC CALL: network chain start")
        try:
            c = self.net.setChain(
                vnf_src_name, vnf_dst_name)
            return str(c)
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

    def network_action_stop(self, vnf_src_name, vnf_dst_name):
        # call DCNetwork method, not really datacenter specific API for now...
        # provided dc name needs to be part of API endpoint
        # no check if vnfs are really connected to this datacenter...
        logging.debug("RPC CALL: network chain stop")
        try:
            c = self.net.setChain(
                vnf_src_name, vnf_dst_name, cmd='del-flows')
            return c
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

    # get egress(default) or ingress rate of a vnf
    def monitor_get_rate(self, vnf_name, direction):
        logging.debug("RPC CALL: get rate")
        try:
            c = self.net.monitor_agent.get_rate(vnf_name, direction)
            return c
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

<commit_msg>update RemoteController in Dockernet<commit_after>"""
Distributed Cloud Emulator (dcemulator)
(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
"""

import logging
import threading
import zerorpc
import site
from subprocess import Popen

logging.basicConfig(level=logging.INFO)

class ZeroRpcApiEndpointDCNetwork(object):
    """
    Simple API endpoint that offers a zerorpc-based
    interface. This interface will be used by the
    default command line client.
    It can be used as a reference to implement
    REST interfaces providing the same semantics,
    like e.g. OpenStack compute API.
    """

    def __init__(self, listenip, port, DCNetwork=None):
        if DCNetwork :
            self.connectDCNetwork(DCNetwork)
        self.ip = listenip
        self.port = port
        logging.debug("Created monitoring API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

        # start Ryu controller with rest-API
        python_install_path = site.getsitepackages()[0]
        ryu_path = python_install_path + '/ryu/app/simple_switch_13.py'
        ryu_path2 =  python_install_path + '/ryu/app/ofctl_rest.py'
        ryu_cmd =  'ryu-manager'
        self.ryu_process = Popen([ryu_cmd, ryu_path, ryu_path2])

    def connectDCNetwork(self, net):
        self.net = net
        logging.info("Connected DCNetwork to API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

    def start(self):
        thread = threading.Thread(target=self._api_server_thread, args=())
        thread.daemon = True
        thread.start()
        logging.debug("Started API endpoint %s(%s:%d)" % (
            self.__class__.__name__, self.ip, self.port))

    def _api_server_thread(self):
        s = zerorpc.Server(DCNetworkApi(self.net))
        s.bind("tcp://%s:%d" % (self.ip, self.port))
        s.run()

    def stop(self):
        # stop ryu controller
        logging.info("Stop the monitoring API endpoint")
        self.ryu_process.terminate()
        #self.ryu_process.kill()
        return

class DCNetworkApi(object):
    """
        Just pass through the corresponding request to the
        selected data center. Do not implement provisioning
        logic here because will will have multiple API
        endpoint implementations at the end.
    """

    def __init__(self, net):
        self.net = net

    def network_action_start(self, vnf_src_name, vnf_dst_name):
        # call DCNetwork method, not really datacenter specific API for now...
        # provided dc name needs to be part of API endpoint
        # no check if vnfs are really connected to this datacenter...
        logging.debug("RPC CALL: network chain start")
        try:
            c = self.net.setChain(
                vnf_src_name, vnf_dst_name)
            return str(c)
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

    def network_action_stop(self, vnf_src_name, vnf_dst_name):
        # call DCNetwork method, not really datacenter specific API for now...
        # provided dc name needs to be part of API endpoint
        # no check if vnfs are really connected to this datacenter...
        logging.debug("RPC CALL: network chain stop")
        try:
            c = self.net.setChain(
                vnf_src_name, vnf_dst_name, cmd='del-flows')
            return c
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

    # get egress(default) or ingress rate of a vnf
    def monitor_get_rate(self, vnf_name, direction):
        logging.debug("RPC CALL: get rate")
        try:
            c = self.net.monitor_agent.get_rate(vnf_name, direction)
            return c
        except Exception as ex:
            logging.exception("RPC error.")
            return ex.message

<|endoftext|>


<commit_before>import numpy as np

from mayavi.core.ui.api import MlabSceneModel
from mayavi.sources.vtk_data_source import VTKDataSource
from mayavi.tools.tools import add_dataset
from traits.api import CInt, HasTraits, Instance, List, on_trait_change
from tvtk.api import tvtk

from ensemble.ctf.editor import CtfEditor
from ensemble.ctf.gui_utils import get_color, get_filename
from ensemble.volren.volume_3d import Volume3D, volume3d
from ensemble.volren.volume_data import VolumeData

CLIP_MAX = 512

class VolumeRenderer(HasTraits):
    # The view displayed
    model = Instance(MlabSceneModel, ())

    # The data to plot
    volume_data = Instance(VolumeData)

    # The mayavi data source for the volume data
    volume_data_source = Instance(VTKDataSource)

    # The mayavi volume renderer object
    volume = Instance(Volume3D)

    # The minimum and maximum displayed intensity values.
    vmin = CInt(0)
    vmax = CInt(255)

    # Clip plane positions
    clip_bounds = List(CInt)

    # The transfer function editor
    ctf_editor = Instance(CtfEditor)

    # Whether to show the histogram on the CTF editor.
    histogram_bins = CInt(0)

    #--------------------------------------------------------------------------
    # Default values
    #--------------------------------------------------------------------------

    def _clip_bounds_default(self):
        return [0, CLIP_MAX, 0, CLIP_MAX, 0, CLIP_MAX]

    def _ctf_editor_default(self):
        return CtfEditor(prompt_color_selection=get_color,
                         prompt_file_selection=get_filename)

    #--------------------------------------------------------------------------
    # Traits notifications
    #--------------------------------------------------------------------------

    def _volume_data_changed(self):
        self.vmin = self.volume_data.data.min()
        self.vmax = self.volume_data.data.max()

        if self.volume_data_source is not None:
            image_data = self.volume_data.resampled_image_data
            self.volume_data_source.data = image_data
            self.volume_data_source.update()
            self._setup_volume()

    def _clip_bounds_items_changed(self):
        self._set_volume_clip_planes()

    @on_trait_change('ctf_editor.function_updated')
    def ctf_updated(self):
        ctf = tvtk.ColorTransferFunction()
        otf = tvtk.PiecewiseFunction()
        lerp = lambda x: self.vmin + x * (self.vmax - self.vmin)

        for color in self.ctf_editor.colors.items():
            ctf.add_rgb_point(lerp(color[0]), *(color[1:]))
        alphas = self.ctf_editor.opacities.items()
        for i, alpha in enumerate(alphas):
            x = alpha[0]
            if i > 0:
                # Look back one item. VTK doesn't like exact vertical jumps, so
                # we need to jog a value that is exactly equal by a little bit.
                if alphas[i-1][0] == alpha[0]:
                    x += 1e-8
            otf.add_point(lerp(x), alpha[1])

        self._set_volume_ctf(ctf, otf)

    #--------------------------------------------------------------------------
    # Scene activation callbacks
    #--------------------------------------------------------------------------

    @on_trait_change('model.activated')
    def display_model(self):
        sf = add_dataset(self.volume_data.resampled_image_data,
                         figure=self.model.mayavi_scene)
        self.volume_data_source = sf
        self.volume = volume3d(sf, figure=self.model.mayavi_scene)
        self._setup_volume()

        self.model.mlab.view(40, 50)
        self.model.scene.background = (0, 0, 0)

        # Keep the view always pointing up
        interactor = self.model.scene.interactor
        interactor.interactor_style = tvtk.InteractorStyleTerrain()

        # Add some axes
        bounds = self.volume.actors[0].bounds
        cube_axes = tvtk.CubeAxesActor(
            bounds=bounds,
            camera=self.model.camera,
            tick_location='outside',
            x_title='', y_title='', z_title='',
            x_units='', y_units='', z_units='',
        )
        self.model.renderer.add_actor(cube_axes)

    #--------------------------------------------------------------------------
    # Private methods
    #--------------------------------------------------------------------------

    def _setup_volume(self):
        self.volume.volume_mapper.trait_set(sample_distance=0.2)
        self.volume.volume_property.trait_set(shade=False)
        self._set_volume_clip_planes()
        self.ctf_updated()

    def _set_volume_clip_planes(self):
        bounds = [b/CLIP_MAX for b in self.volume_data.bounds]
        mn = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[::2])]
        mx = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[1::2])]
        planes = tvtk.Planes()
        # The planes need to be inside out to serve as clipping planes
        planes.set_bounds(mx[0], mn[0],
                          mx[1], mn[1],
                          mx[2], mn[2])
        # Set them as the clipping planes for the volume mapper
        self.volume.volume.mapper.clipping_planes = planes

    def _set_volume_ctf(self, ctf, otf):
        if self.volume is not None:
            vp = self.volume.volume_property
            vp.set_scalar_opacity(otf)
            vp.set_color(ctf)
            self.volume._update_ctf_fired()

    @on_trait_change('histogram_bins,volume_data')
    def _new_histogram(self):
        if (self.histogram_bins > 0 and
                self.volume_data is not None and
                self.volume_data.data is not None):
            self.ctf_editor.histogram = np.histogram(self.volume_data.data,
                                                     bins=self.histogram_bins,
                                                     density=False)
        else:
            self.ctf_editor.histogram = None
<commit_msg>Allow axes and their ranges to be controlled by traits<commit_after>import numpy as np

from mayavi.core.ui.api import MlabSceneModel
from mayavi.sources.vtk_data_source import VTKDataSource
from mayavi.tools.tools import add_dataset
from traits.api import (Bool, CInt, Float, HasTraits, Instance, List, Tuple,
                        on_trait_change)
from tvtk.api import tvtk

from ensemble.ctf.editor import CtfEditor
from ensemble.ctf.gui_utils import get_color, get_filename
from ensemble.volren.volume_3d import Volume3D, volume3d
from ensemble.volren.volume_data import VolumeData

CLIP_MAX = 512

FloatPair = Tuple(Float, Float)

class VolumeRenderer(HasTraits):
    # The view displayed
    model = Instance(MlabSceneModel, ())

    # The data to plot
    volume_data = Instance(VolumeData)

    # The mayavi data source for the volume data
    volume_data_source = Instance(VTKDataSource)

    # The mayavi volume renderer object
    volume = Instance(Volume3D)

    # The minimum and maximum displayed intensity values.
    vmin = CInt(0)
    vmax = CInt(255)

    # Clip plane positions
    clip_bounds = List(CInt)

    # The transfer function editor
    ctf_editor = Instance(CtfEditor)

    # Whether to show the histogram on the CTF editor.
    histogram_bins = CInt(0)

    # What are the physical value ranges for each axis?
    visible_axis_ranges = Tuple(FloatPair, FloatPair, FloatPair)

    # Which axes should have a scale shown?
    visible_axis_scales = Tuple(Bool, Bool, Bool)

    #--------------------------------------------------------------------------
    # Default values
    #--------------------------------------------------------------------------

    def _clip_bounds_default(self):
        return [0, CLIP_MAX, 0, CLIP_MAX, 0, CLIP_MAX]

    def _ctf_editor_default(self):
        return CtfEditor(prompt_color_selection=get_color,
                         prompt_file_selection=get_filename)

    def _visible_axis_ranges_default(self):
        return ((0.0, 1.0), (0.0, 1.0), (0.0, 1.0))

    def _visible_axis_scales_default(self):
        return (False, False, False)

    #--------------------------------------------------------------------------
    # Traits notifications
    #--------------------------------------------------------------------------

    def _volume_data_changed(self):
        self.vmin = self.volume_data.data.min()
        self.vmax = self.volume_data.data.max()

        if self.volume_data_source is not None:
            image_data = self.volume_data.resampled_image_data
            self.volume_data_source.data = image_data
            self.volume_data_source.update()
            self._setup_volume()

    def _clip_bounds_items_changed(self):
        self._set_volume_clip_planes()

    @on_trait_change('ctf_editor.function_updated')
    def ctf_updated(self):
        ctf = tvtk.ColorTransferFunction()
        otf = tvtk.PiecewiseFunction()
        lerp = lambda x: self.vmin + x * (self.vmax - self.vmin)

        for color in self.ctf_editor.colors.items():
            ctf.add_rgb_point(lerp(color[0]), *(color[1:]))
        alphas = self.ctf_editor.opacities.items()
        for i, alpha in enumerate(alphas):
            x = alpha[0]
            if i > 0:
                # Look back one item. VTK doesn't like exact vertical jumps, so
                # we need to jog a value that is exactly equal by a little bit.
                if alphas[i-1][0] == alpha[0]:
                    x += 1e-8
            otf.add_point(lerp(x), alpha[1])

        self._set_volume_ctf(ctf, otf)

    #--------------------------------------------------------------------------
    # Scene activation callbacks
    #--------------------------------------------------------------------------

    @on_trait_change('model.activated')
    def display_model(self):
        sf = add_dataset(self.volume_data.resampled_image_data,
                         figure=self.model.mayavi_scene)
        self.volume_data_source = sf
        self.volume = volume3d(sf, figure=self.model.mayavi_scene)
        self._setup_volume()

        self.model.mlab.view(40, 50)
        self.model.scene.background = (0, 0, 0)

        # Keep the view always pointing up
        interactor = self.model.scene.interactor
        interactor.interactor_style = tvtk.InteractorStyleTerrain()

        # Add some axes
        bounds = self.volume.actors[0].bounds
        x_vis, y_vis, z_vis = self.visible_axis_scales
        x_range, y_range, z_range = self.visible_axis_ranges
        cube_axes = tvtk.CubeAxesActor(
            bounds=bounds,
            camera=self.model.camera,
            tick_location='outside',
            x_title='', x_units='',
            y_title='', y_units='',
            z_title='', z_units='',
            x_axis_visibility=x_vis,
            y_axis_visibility=y_vis,
            z_axis_visibility=z_vis,
            x_axis_range=x_range,
            y_axis_range=y_range,
            z_axis_range=z_range,
        )
        self.model.renderer.add_actor(cube_axes)

    #--------------------------------------------------------------------------
    # Private methods
    #--------------------------------------------------------------------------

    def _setup_volume(self):
        self.volume.volume_mapper.trait_set(sample_distance=0.2)
        self.volume.volume_property.trait_set(shade=False)
        self._set_volume_clip_planes()
        self.ctf_updated()

    def _set_volume_clip_planes(self):
        bounds = [b/CLIP_MAX for b in self.volume_data.bounds]
        mn = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[::2])]
        mx = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[1::2])]
        planes = tvtk.Planes()
        # The planes need to be inside out to serve as clipping planes
        planes.set_bounds(mx[0], mn[0],
                          mx[1], mn[1],
                          mx[2], mn[2])
        # Set them as the clipping planes for the volume mapper
        self.volume.volume.mapper.clipping_planes = planes

    def _set_volume_ctf(self, ctf, otf):
        if self.volume is not None:
            vp = self.volume.volume_property
            vp.set_scalar_opacity(otf)
            vp.set_color(ctf)
            self.volume._update_ctf_fired()

    @on_trait_change('histogram_bins,volume_data')
    def _new_histogram(self):
        if (self.histogram_bins > 0 and
                self.volume_data is not None and
                self.volume_data.data is not None):
            self.ctf_editor.histogram = np.histogram(self.volume_data.data,
                                                     bins=self.histogram_bins,
                                                     density=False)
        else:
            self.ctf_editor.histogram = None
<|endoftext|>


<commit_before>from __future__ import print_function
from capstone import *
from keystone import *
import pefile
import random
import sys
from capstone import x86_const

class Pymetamorph(object):
    def __init__(self, file, debug=False, load_file=True):
        self.load_file = load_file
        self.file = file
        self.debug = debug
        self.instructions = []
        self.cs = Cs(CS_ARCH_X86, CS_MODE_32)
        self.cs.detail = True
        self.ks = Ks(KS_ARCH_X86, KS_MODE_32)
        if load_file:
            self.pe = pefile.PE(self.file)
            if self.debug:
                print('loading file')
            self.base_of_code = self.pe.OPTIONAL_HEADER.BaseOfCode
            code_section = self.find_section(self.base_of_code)
            if code_section is None:
                raise Exception('unable to find .text section')
            raw_code = code_section.get_data(self.base_of_code, code_section.SizeOfRawData)
            for i in self.cs.disasm(raw_code,
                                    self.base_of_code):
                self.instructions += [MetaIns(i)]
        else:
            self.instructions = []

    def find_section(self, address):
        for section in self.pe.sections:
            if section.contains_rva(address):
                return section
        return None

    def insert_nop(self):
        if self.load_file:
            address = self.instructions[0].new_addr
        else:
            address = 0
        nop = None
        for nop in self.cs.disasm(str(bytearray([0x90])), 0x1000):
            break
        new_inst = []
        for i in self.instructions:
            if random.random() < 0.2:
                for j in range(random.randint(0, 10)):
                    address = self.append_instruction(new_inst, nop, address, True)
        if random.random() < 1:
            for j in range(random.randint(0, 10)):
                address = self.append_instruction(new_inst, nop, address, True)
        self.instructions = new_inst

    @staticmethod
    def append_instruction(instruction_list, instruction, address, overwrite_original_address=False):
        ins = MetaIns(instruction)
        if overwrite_original_address:
            ins.original_addr = address
        ins.new_addr = address
        instruction_list.append(ins)
        return address + instruction.size

    def shuffle_blocks(self, initial_address=None):
        """
        divides the code in blocks and shuffles them to morph the code of the program.
        It also insert a jump instruction to the next block at the end of each code block
        """
        size_of_blocks = random.randint(len(self.instructions) / 10, len(self.instructions) / 3)
        offset = 0
        blocks = []
        initial_block_inst = dict()
        i = 0
        if initial_address is None:
            initial_address = self.base_of_code
        while offset <= len(self.instructions):
            blocks.append((i, self.instructions[offset:min(offset + size_of_blocks, len(self.instructions))]))
            initial_block_inst[i] = blocks[i][1][0]
            i += 1
            offset += size_of_blocks
        random.shuffle(blocks)
        instructions = []
        for block_number, block in blocks:
            jump_inst = None
            if block_number + 1 in initial_block_inst:
                asm, _ = self.ks.asm('jmp 0x%x' % initial_block_inst[block_number + 1].original_addr)
                for jump_inst in self.cs.disasm(str(bytearray(asm)), 0):
                    break
            if jump_inst is not None:
                self.append_instruction(block, jump_inst, 0)
            instructions += block
        self.update_addresses(instructions, initial_address)

    def sort_instructions(self):
        sorted(self.instructions, key=lambda instruction: instruction.new_addr)

    def generate_label_tables(self):
        jmp_table = []
        for inst in self.instructions:
            print(
                "0x%x:\t%s\t%s" % (inst.original_inst.address, inst.original_inst.mnemonic, inst.original_inst.op_str))
            print('{},{},{},{}'.format(inst.original_inst.id, inst.original_inst.groups,
                                       inst.original_inst.regs_read, inst.original_inst.regs_write))
            if (x86_const.X86_INS_JAE <= inst.original_inst.id <= x86_const.X86_INS_JS) \
                    or x86_const.X86_INS_CALL == inst.original_inst.id:
                jmp_table.append(int(inst.original_inst.op_str, 16))
        return jmp_table

    @staticmethod
    def update_addresses(instructions, initial_address):
        address = initial_address
        for instruction in instructions:
            instruction.new_addr = address
            address += instruction.size

class MetaIns(object):
    def __init__(self, original_inst):
        self.original_inst = original_inst
        self.original_addr = original_inst.address
        self.new_addr = original_inst.address
        self.original_bytes = original_inst.bytes
        self.new_bytes = original_inst.bytes
        self.size = original_inst.size

def main(file_path):
    meta = Pymetamorph(file_path, load_file=True)
    meta.shuffle_blocks()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        main(sys.argv[1])
<commit_msg>Added label table to class fields generate label table function modified to only store jumps to final instructions print_disass funciton added<commit_after>from __future__ import print_function

import random
import sys

import pefile
from capstone import *
from capstone import x86_const
from keystone import *

class Pymetamorph(object):
    def __init__(self, file, debug=False, load_file=True):
        self.load_file = load_file
        self.file = file
        self.debug = debug
        self.instructions = []
        self.cs = Cs(CS_ARCH_X86, CS_MODE_32)
        self.cs.detail = True
        self.ks = Ks(KS_ARCH_X86, KS_MODE_32)
        self.label_table = None
        if load_file:
            self.pe = pefile.PE(self.file)
            if self.debug:
                print(self.pe.dump_info())
                print('loading file')
            self.base_of_code = self.pe.OPTIONAL_HEADER.BaseOfCode
            code_section = self.find_section(self.base_of_code)
            if code_section is None:
                raise Exception('unable to find .text section')
            raw_code = code_section.get_data(self.base_of_code, code_section.SizeOfRawData)
            for i in self.cs.disasm(raw_code,
                                    self.base_of_code):
                self.instructions += [MetaIns(i)]
        else:
            self.instructions = []

    def find_section(self, address):
        for section in self.pe.sections:
            if section.contains_rva(address):
                return section
        return None

    def insert_nop(self):
        if self.load_file:
            address = self.instructions[0].new_addr
        else:
            address = 0
        nop = None
        for nop in self.cs.disasm(str(bytearray([0x90])), 0x1000):
            break
        new_inst = []
        for i in self.instructions:
            if random.random() < 0.2:
                for j in range(random.randint(0, 10)):
                    address = self.append_instruction(new_inst, nop, address, True)
        if random.random() < 1:
            for j in range(random.randint(0, 10)):
                address = self.append_instruction(new_inst, nop, address, True)
        self.instructions = new_inst

    @staticmethod
    def append_instruction(instruction_list, instruction, address, overwrite_original_address=False):
        ins = MetaIns(instruction)
        if overwrite_original_address:
            ins.original_addr = address
        ins.new_addr = address
        instruction_list.append(ins)
        return address + instruction.size

    def shuffle_blocks(self, initial_address=None):
        """
        divides the code in blocks and shuffles them to morph the code of the program.
        It also insert a jump instruction to the next block at the end of each code block
        """
        size_of_blocks = random.randint(len(self.instructions) / 10, len(self.instructions) / 3)
        offset = 0
        blocks = []
        initial_block_inst = dict()
        i = 0
        if initial_address is None:
            initial_address = self.base_of_code
        while offset <= len(self.instructions):
            blocks.append((i, self.instructions[offset:min(offset + size_of_blocks, len(self.instructions))]))
            initial_block_inst[i] = blocks[i][1][0]
            i += 1
            offset += size_of_blocks
        if self.debug:
            print('number of blocks: %d' % (len(blocks)))
        random.shuffle(blocks)
        instructions = []
        for block_number, block in blocks:
            jump_inst = None
            if block_number + 1 in initial_block_inst:
                asm, _ = self.ks.asm('jmp 0x%x' % initial_block_inst[block_number + 1].original_addr)
                for jump_inst in self.cs.disasm(str(bytearray(asm)), 0):
                    break
            if jump_inst is not None:
                self.append_instruction(block, jump_inst, 0)
            instructions += block
        self.update_addresses(instructions, initial_address)
        self.instructions = instructions

    def sort_instructions(self):
        sorted(self.instructions, key=lambda instruction: instruction.new_addr)

    def generate_label_table(self):
        jmp_table = dict()
        for inst in self.instructions:
            try:
                if (x86_const.X86_INS_JAE <= inst.original_inst.id <= x86_const.X86_INS_JS) \
                        or x86_const.X86_INS_CALL == inst.original_inst.id:
                    addr = int(inst.original_inst.op_str, 16)
                    jmp_table[addr] = addr
                    # jmp_table['0x%x' % addr] = addr
            except:
                pass
        # if self.debug:
        print(sorted(jmp_table))
        return jmp_table

    @staticmethod
    def update_addresses(instructions, initial_address):
        address = initial_address
        for instruction in instructions:
            instruction.new_addr = address
            address += instruction.size

    def print_disass(self):
        out = open("code.asm", 'w')
        for inst in self.instructions:
            out.write("0x%x:\t%s\t%s\n" % (
                inst.original_inst.address, inst.original_inst.mnemonic, inst.original_inst.op_str))
            print(
                "0x%x:\t%s\t%s" % (inst.original_inst.address, inst.original_inst.mnemonic, inst.original_inst.op_str))
        out.close()

    def write_file(self, path):
        new_entry_point = self.locate_by_original_address(
            self.pe.NT_HEADERS.OPTIONAL_HEADER.AddressOfEntryPoint).new_addr
        self.pe.NT_HEADERS.OPTIONAL_HEADER.AddressOfEntryPoint = new_entry_point
        if self.debug:
            print(self.pe.dump_info())

    def locate_by_original_address(self, Address):
        for intstruction in self.instructions:
            if intstruction.original_addr == Address:
                return intstruction
        return None

    def update_label_table(self):
        self.label_table = self.generate_label_table()
        self.get_new_addresses_of_labels()

    def get_new_addresses_of_labels(self):
        for instruction in self.instructions:
            if instruction.original_addr in self.label_table:
                self.label_table[instruction.original_addr] = instruction.new_addr

    def aply_label_table(self):
        new_instructions = []
        for instruction in self.instructions:
            if (x86_const.X86_INS_JAE <= instruction.original_inst.id <= x86_const.X86_INS_JS) \
                    or x86_const.X86_INS_CALL == instruction.original_inst.id:
                new_jump = None
                asm = None
                for asm in self.ks.asm('%s 0x%x' % (
                        instruction.original_inst.mnemonic,
                        self.label_table[int(instruction.original_inst.op_str), 16])):
                    break
                for ins in self.cs.disasm(asm, 0):
                    new_jump = MetaIns(ins)
                    new_jump.original_addr = instruction.original_addr
                    new_jump.new_addr = instruction.new_addr
                    break
                new_instructions.append(new_jump)
            else:
                new_instructions.append(instruction)
        self.instructions = new_instructions

class MetaIns(object):
    def __init__(self, original_inst):
        self.original_inst = original_inst
        self.original_addr = original_inst.address
        self.new_addr = original_inst.address
        self.original_bytes = original_inst.bytes
        self.new_bytes = original_inst.bytes
        self.size = original_inst.size

def main(file_path):
    meta = Pymetamorph(file_path, load_file=True)
    meta.shuffle_blocks()
    meta.update_label_table()
    meta.debug = True
    meta.aply_label_table()
    meta.write_file('meta.exe')
    # meta.print_disass()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        main(sys.argv[1])

'''print(
                "0x%x:\t%s\t%s" % (inst.original_inst.address, inst.original_inst.mnemonic, inst.original_inst.op_str))
            print('{},{},{},{}'.format(inst.original_inst.id, inst.original_inst.groups,
                                       inst.original_inst.regs_read, inst.original_inst.regs_write))'''
<|endoftext|>


<commit_before>#!/usr/bin/env python
# encoding: utf-8

#MODIFIED#

# First Start the server: $> bin/start.py
import random, threading, argparse
import itertools
try:
  from hfo import *
except:
  print('Failed to import hfo. To install hfo, in the HFO directory'\
    ' run: \"pip install .\"')
  exit()
params = {'SHT_DST':0.136664020547, 'SHT_ANG':-0.747394386098,
          'PASS_ANG':0.464086704478, 'DRIB_DST':-0.999052871962}

def can_shoot(goal_dist, goal_angle):
  """Returns True if if player can have a good shot at goal"""
  if goal_dist < params['SHT_DST'] and goal_angle > params['SHT_ANG']:
    return True
  else:
    return False

def has_better_pos(dist_to_op, goal_angle, pass_angle, curr_goal_angle):
  """Returns True if teammate is in a better attacking position"""
  if curr_goal_angle > goal_angle or dist_to_op<params['DRIB_DST']:
    return False
  if pass_angle < params['PASS_ANG']:
    return False
  return True

def can_dribble(dist_to_op):
  if dist_to_op > params['DRIB_DST']:
    return True
  else:
    return False

def get_action(state,hfo_env,num_teammates):
  """Returns the action to be taken by the agent"""

  goal_dist = float(state[6])
  goal_op_angle = float(state[8])
  if can_shoot(goal_dist, goal_op_angle):
    hfo_env.act(SHOOT)
    return
  for i in range(num_teammates):
    teammate_uniform_number=state[10 + 3*num_teammates + 3*i +2]
    if has_better_pos(dist_to_op = float(state[10 + num_teammates + i]),
                      goal_angle = float(state[10 + i]),
                      pass_angle = float(state[10 + 2*num_teammates + i]),
                      curr_goal_angle = goal_op_angle):
      hfo_env.act(PASS, teammate_uniform_number)
      return
  if can_dribble(dist_to_op = state[9]):
    hfo_env.act(DRIBBLE)
    return
  # If nothing can be done pass
  hfo_env.act(PASS)

def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('--port', type=int, default=6000)
  parser.add_argument('--numTeammates', type=int, default=0)
  parser.add_argument('--numOpponents', type=int, default=1)
  args=parser.parse_args()
  hfo_env = HFOEnvironment()
  hfo_env.connectToServer(HIGH_LEVEL_FEATURE_SET,
                      'bin/teams/base/config/formations-dt', args.port,
                      'localhost', 'base_left', False)
  #itertools.count() counts forever
  for episode in itertools.count():
    status=IN_GAME
    count=0
    while status==IN_GAME:
      state = hfo_env.getState()
      #print(state)
      if int(state[5]) == 1: # state[5] is 1 when player has the ball
        tmp = get_action(state,hfo_env,args.numTeammates)
        #print(tmp)
        #hfo_env.act(tmp)
      else:
        hfo_env.act(MOVE)
      status=hfo_env.step()
      #print(status)
      if status == SERVER_DOWN:
        hfo_env.act(QUIT)
        break

if __name__ == '__main__':
  main()
<commit_msg>Prevent endless loop after server exit for high_level_custom_agent.py<commit_after>#!/usr/bin/env python
# encoding: utf-8

#MODIFIED#

# First Start the server: $> bin/start.py
import random, threading, argparse
import itertools
try:
  from hfo import *
except:
  print('Failed to import hfo. To install hfo, in the HFO directory'\
    ' run: \"pip install .\"')
  exit()
params = {'SHT_DST':0.136664020547, 'SHT_ANG':-0.747394386098,
          'PASS_ANG':0.464086704478, 'DRIB_DST':-0.999052871962}

def can_shoot(goal_dist, goal_angle):
  """Returns True if if player can have a good shot at goal"""
  if goal_dist < params['SHT_DST'] and goal_angle > params['SHT_ANG']:
    return True
  else:
    return False

def has_better_pos(dist_to_op, goal_angle, pass_angle, curr_goal_angle):
  """Returns True if teammate is in a better attacking position"""
  if curr_goal_angle > goal_angle or dist_to_op<params['DRIB_DST']:
    return False
  if pass_angle < params['PASS_ANG']:
    return False
  return True

def can_dribble(dist_to_op):
  if dist_to_op > params['DRIB_DST']:
    return True
  else:
    return False

def get_action(state,hfo_env,num_teammates):
  """Returns the action to be taken by the agent"""

  goal_dist = float(state[6])
  goal_op_angle = float(state[8])
  if can_shoot(goal_dist, goal_op_angle):
    hfo_env.act(SHOOT)
    return
  for i in range(num_teammates):
    teammate_uniform_number=state[10 + 3*num_teammates + 3*i +2]
    if has_better_pos(dist_to_op = float(state[10 + num_teammates + i]),
                      goal_angle = float(state[10 + i]),
                      pass_angle = float(state[10 + 2*num_teammates + i]),
                      curr_goal_angle = goal_op_angle):
      hfo_env.act(PASS, teammate_uniform_number)
      return
  if can_dribble(dist_to_op = state[9]):
    hfo_env.act(DRIBBLE)
    return
  # If nothing can be done pass
  hfo_env.act(PASS)

def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('--port', type=int, default=6000)
  parser.add_argument('--numTeammates', type=int, default=0)
  parser.add_argument('--numOpponents', type=int, default=1)
  args=parser.parse_args()
  hfo_env = HFOEnvironment()
  hfo_env.connectToServer(HIGH_LEVEL_FEATURE_SET,
                      'bin/teams/base/config/formations-dt', args.port,
                      'localhost', 'base_left', False)
  #itertools.count() counts forever
  for episode in itertools.count():
    status=IN_GAME
    count=0
    while status==IN_GAME:
      state = hfo_env.getState()
      #print(state)
      if int(state[5]) == 1: # state[5] is 1 when player has the ball
        tmp = get_action(state,hfo_env,args.numTeammates)
        #print(tmp)
        #hfo_env.act(tmp)
      else:
        hfo_env.act(MOVE)
      status=hfo_env.step()
      #print(status)
      if status == SERVER_DOWN:
        hfo_env.act(QUIT)
        exit()

if __name__ == '__main__':
  main()
<|endoftext|>


<commit_before>##############################################################################
#
#    Copyright (C) 2020 Compassion CH (http://www.compassion.ch)
#    @author: William Martin <wmartin@compassion.ch>
#
#    The licence is in the file __manifest__.py
#
##############################################################################

from odoo import api, models
import re

class AccountMoveLine(models.Model):
    _inherit = "account.move.line"

    @api.multi
    def _check_analytic_distribution_required_msg(self):
        message = super(AccountMoveLine, self).\
            _check_analytic_distribution_required_msg()
        pattern = r'.*mutually exclusive.*'
        if message and not re.match(pattern, message, re.IGNORECASE):
            return message
<commit_msg>CO-3248 copy analytic tags at asset creation in vendor bills (#114)<commit_after>##############################################################################
#
#    Copyright (C) 2020 Compassion CH (http://www.compassion.ch)
#    @author: William Martin <wmartin@compassion.ch>
#
#    The licence is in the file __manifest__.py
#
##############################################################################

from odoo import api, models
import re

class AccountMoveLine(models.Model):
    _inherit = "account.move.line"

    @api.multi
    def _check_analytic_distribution_required_msg(self):
        message = super(AccountMoveLine, self).\
            _check_analytic_distribution_required_msg()
        pattern = r'.*mutually exclusive.*'
        if message and not re.match(pattern, message, re.IGNORECASE):
            return message

    @api.model
    def _get_asset_analytic_values(self, vals, asset_vals):
        super()._get_asset_analytic_values(vals, asset_vals)
        asset_vals['analytic_tag_ids'] = vals.get(
            'analytic_tag_ids', False)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Yannick Vaucher
#    Copyright 2013 Camptocamp SA
#    Copyright 2015 Akretion (www.akretion.com)
#    @author Alexis de Lattre <alexis.delattre@akretion.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

{
    'name': 'Payment Term Extension',
    'version': '9.0.1.0.0',
    'category': 'Accounting & Finance',
    'summary': 'Adds rounding, months, weeks and multiple payment days '
               'properties on payment term lines',
    'description': "",
    'author': 'Camptocamp,'
              'Serv. Tecnol. Avanzados - Pedro M. Baeza,'
              'Odoo Community Association (OCA)',
    'maintainer': 'OCA',
    'website': 'http://www.camptocamp.com/',
    'license': 'AGPL-3',
    'depends': ['account'],
    'data': ['account_view.xml'],
    'demo': ['account_demo.xml'],
    'test': [],
    'installable': True,
}
<commit_msg>[IMP] account_payment_term_extension: Switch company<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Yannick Vaucher
#    Copyright 2013 Camptocamp SA
#    Copyright 2015 Akretion (www.akretion.com)
#    @author Alexis de Lattre <alexis.delattre@akretion.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

{
    'name': 'Payment Term Extension',
    'version': '9.0.1.0.0',
    'category': 'Accounting & Finance',
    'summary': 'Adds rounding, months, weeks and multiple payment days '
               'properties on payment term lines',
    'description': "",
    'author': 'Camptocamp,'
              'Tecnativa,'
              'Odoo Community Association (OCA)',
    'maintainer': 'OCA',
    'website': 'http://www.camptocamp.com/',
    'license': 'AGPL-3',
    'depends': ['account'],
    'data': ['account_view.xml'],
    'demo': ['account_demo.xml'],
    'test': [],
    'installable': True,
}
<|endoftext|>