#!/usr/bin/env python2
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *

# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):

    def setup_chain(self):
        print("Initializing test directory "+self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, 4)

    def setup_network(self, split=False):
        self.nodes = start_nodes(4, self.options.tmpdir)

        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)
        connect_nodes_bi(self.nodes,0,3)

        self.is_network_split=False
        self.sync_all()

    def run_test(self):
        print "Mining blocks..."

        min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
        # This test is not meant to test fee estimation and we'd like
        # to be sure all txs are sent at a consistent desired feerate
        for node in self.nodes:
            node.settxfee(min_relay_tx_fee)

        # if the fee's positive delta is higher than this value tests will fail,
        # neg. delta always fail the tests.
        # The size of the signature of every input may be at most 2 bytes larger
        # than a minimum sized signature.

        #            = 2 bytes * minRelayTxFeePerByte
        feeTolerance = 2 * min_relay_tx_fee/1000

        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(121)
        self.sync_all()

        watchonly_address = self.nodes[0].getnewaddress()
        watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"]
        watchonly_amount = Decimal(2000)
        self.nodes[3].importpubkey(watchonly_pubkey, "", True)
        watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount)
        self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10)

        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 15)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 50)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        ###############
        # simple test #
        ###############
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 10 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert(len(dec_tx['vin']) > 0) #test if we have enought inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 22 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert(len(dec_tx['vin']) > 0) #test if we have enough inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 26 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert(len(dec_tx['vin']) > 0)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        ################################
        # simple test with two outputs #
        ################################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 26, self.nodes[1].getnewaddress() : 25 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert(len(dec_tx['vin']) > 0)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        #########################################################################
        # test a fundrawtransaction with a VIN greater than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 50:
                utx = aUtx
                break

        assert(utx!=False)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : 10 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee

        #####################################################################
        # test a fundrawtransaction with which will not get a change output #
        #####################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 50:
                utx = aUtx
                break

        assert(utx!=False)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : Decimal(50) - fee - feeTolerance }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(rawtxfund['changepos'], -1)
        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee

        #########################################################################
        # test a fundrawtransaction with a VIN smaller than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 10:
                utx = aUtx
                break

        assert(utx!=False)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : 10 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)

        # 4-byte version + 1-byte vin count + 36-byte prevout then script_len
        rawtx = rawtx[:82] + "0100" + rawtx[84:]

        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for i, out in enumerate(dec_tx['vout']):
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts+=1
            else:
                assert_equal(i, rawtxfund['changepos'])

        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        ###########################################
        # test a fundrawtransaction with two VINs #
        ###########################################
        utx  = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 10:
                utx = aUtx
            if aUtx['amount'] == 50:
                utx2 = aUtx

        assert(utx!=False)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
        outputs = { self.nodes[0].getnewaddress() : 60 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts+=1

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        matchingIns = 0
        for vinOut in dec_tx['vin']:
            for vinIn in inputs:
                if vinIn['txid'] == vinOut['txid']:
                    matchingIns+=1

        assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params

        #########################################################
        # test a fundrawtransaction with two VINs and two vOUTs #
        #########################################################
        utx  = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 10:
                utx = aUtx
            if aUtx['amount'] == 50:
                utx2 = aUtx

        assert(utx!=False)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
        outputs = { self.nodes[0].getnewaddress() : 60, self.nodes[0].getnewaddress() : 10 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts+=1

        assert_equal(matchingOuts, 2)
        assert_equal(len(dec_tx['vout']), 3)

        ##############################################
        # test a fundrawtransaction with invalid vin #
        ##############################################
        listunspent = self.nodes[2].listunspent()
        inputs  = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin!
        outputs = { self.nodes[0].getnewaddress() : 10}
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        try:
            rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
            raise AssertionError("Spent more than available")
        except JSONRPCException as e:
            assert("Insufficient" in e.error['message'])

        ############################################################
        #compare fee of a standard pubkeyhash transaction
        inputs = []
        outputs = {self.nodes[1].getnewaddress():11}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 11)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction with multiple outputs
        inputs = []
        outputs = {self.nodes[1].getnewaddress():11,self.nodes[1].getnewaddress():12,self.nodes[1].getnewaddress():1,self.nodes[1].getnewaddress():13,self.nodes[1].getnewaddress():2,self.nodes[1].getnewaddress():3}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)
        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendmany("", outputs)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a 2of2 multisig p2sh transaction

        # create 2of2 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)

        mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])

        inputs = []
        outputs = {mSigObj:11}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 11)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction

        # create 4of5 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()
        addr3 = self.nodes[1].getnewaddress()
        addr4 = self.nodes[1].getnewaddress()
        addr5 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)
        addr3Obj = self.nodes[1].validateaddress(addr3)
        addr4Obj = self.nodes[1].validateaddress(addr4)
        addr5Obj = self.nodes[1].validateaddress(addr5)

        mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']])

        inputs = []
        outputs = {mSigObj:11}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 11)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        # spend a 2of2 multisig transaction over fundraw

        # create 2of2 addr
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])

        # send 12 ESMA to msig addr
        txId = self.nodes[0].sendtoaddress(mSigObj, 12)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        oldBalance = self.nodes[1].getbalance()
        inputs = []
        outputs = {self.nodes[1].getnewaddress():11}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[2].fundrawtransaction(rawTx)

        signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance+Decimal('11.0000000'), self.nodes[1].getbalance())

        ############################################################
        # locked wallet test
        self.nodes[1].encryptwallet("test")
        self.nodes.pop(1)
        stop_nodes(self.nodes)
        wait_bitcoinds()

        self.nodes = start_nodes(4, self.options.tmpdir)
        # This test is not meant to test fee estimation and we'd like
        # to be sure all txs are sent at a consistent desired feerate
        for node in self.nodes:
            node.settxfee(min_relay_tx_fee)

        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)
        connect_nodes_bi(self.nodes,0,3)
        self.is_network_split=False
        self.sync_all()

        try:
            self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 12)
            raise AssertionError("Wallet unlocked without passphrase")
        except JSONRPCException as e:
            assert('walletpassphrase' in e.error['message'])

        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress():11}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #now we need to unlock
        self.nodes[1].walletpassphrase("test", 100)
        signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance+Decimal('511.0000000'), self.nodes[0].getbalance())

        ###############################################
        # multiple (~19) inputs tx test | Compare fee #
        ###############################################

        #empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0,20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        inputs = []
        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[1].sendmany("", outputs)
        signedFee = self.nodes[1].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs

        #############################################
        # multiple (~19) inputs tx test | sign/send #
        #############################################

        #again, empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0,20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)
        fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(oldBalance+Decimal('500.19000000'), self.nodes[0].getbalance()) #0.19+block reward

        #####################################################
        # test fundrawtransaction with OP_RETURN and no vin #
        #####################################################

        rawtx   = "0100000000010000000000000000066a047465737400000000"
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        assert_equal(len(dec_tx['vin']), 0)
        assert_equal(len(dec_tx['vout']), 1)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])

        assert_greater_than(len(dec_tx['vin']), 0) # at least one vin
        assert_equal(len(dec_tx['vout']), 2) # one change output added

        ##################################################
        # test a fundrawtransaction using only watchonly #
        ##################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        result = self.nodes[3].fundrawtransaction(rawtx, True)
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 1)
        assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)

        assert("fee" in result.keys())
        assert_greater_than(result["changepos"], -1)

        ###############################################################
        # test fundrawtransaction using the entirety of watched funds #
        ###############################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress() : watchonly_amount}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        result = self.nodes[3].fundrawtransaction(rawtx, True)
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 2)
        assert(res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid)

        assert_greater_than(result["fee"], 0)
        assert_greater_than(result["changepos"], -1)
        assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10)

        signedtx = self.nodes[3].signrawtransaction(result["hex"])
        assert(not signedtx["complete"])
        signedtx = self.nodes[0].signrawtransaction(signedtx["hex"])
        assert(signedtx["complete"])
        self.nodes[0].sendrawtransaction(signedtx["hex"])

if __name__ == '__main__':
    RawTransactionsTest().main()

!/usr/bin/env python2 Copyright (c) 2014-2015 The Bitcoin Core developers Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. Create one-input, one-output, no-fee transaction: This test is not meant to test fee estimation and we'd like to be sure all txs are sent at a consistent desired feerate if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests. The size of the signature of every input may be at most 2 bytes larger than a minimum sized signature.            = 2 bytes * minRelayTxFeePerByte simple test test if we have enought inputs simple test with two coins test if we have enough inputs simple test with two coins  simple test with two outputs  test a fundrawtransaction with a VIN greater than the required amount compare vin total and totalout+fee test a fundrawtransaction with which will not get a change output compare vin total and totalout+fee test a fundrawtransaction with a VIN smaller than the required amount  4-byte version + 1-byte vin count + 36-byte prevout then script_len test a fundrawtransaction with two VINs we now must see two vins identical to vins given as params test a fundrawtransaction with two VINs and two vOUTs  test a fundrawtransaction with invalid vin invalid vin!compare fee of a standard pubkeyhash transactioncreate same transaction over sendtoaddresscompare feecompare fee of a standard pubkeyhash transaction with multiple outputscreate same transaction over sendtoaddresscompare feecompare fee of a 2of2 multisig p2sh transaction create 2of2 addrcreate same transaction over sendtoaddresscompare feecompare fee of a standard pubkeyhash transaction create 4of5 addrcreate same transaction over sendtoaddresscompare fee spend a 2of2 multisig transaction over fundraw create 2of2 addr send 12 ESMA to msig addr make sure funds are received at node1 locked wallet test This test is not meant to test fee estimation and we'd like to be sure all txs are sent at a consistent desired feeratenow we need to unlock make sure funds are received at node1 multiple (~19) inputs tx test | Compare fee empty node1, send some small coins from node0 to node1fund a tx with ~20 small inputscreate same transaction over sendtoaddresscompare fee~19 inputs multiple (~19) inputs tx test | sign/send again, empty node1, send some small coins from node0 to node1fund a tx with ~20 small inputs0.19+block reward test fundrawtransaction with OP_RETURN and no vin  at least one vin one change output added test a fundrawtransaction using only watchonly  test fundrawtransaction using the entirety of watched funds


# Copyright (c) 2017, John Skinner
import unittest
import numpy as np
import arvet.database.tests.database_connection as dbconn
from arvet.config.path_manager import PathManager
import arvet.batch_analysis.task as task

class MockTask(task.Task):
    def run_task(self, path_manager: PathManager):
        pass

    def get_unique_name(self) -> str:
        return "mock_task_{0}".format(self.pk)

class TestTaskDatabase(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        dbconn.connect_to_test_db()

    def setUp(self):
        # Remove the collection as the start of the test, so that we're sure it's empty
        task.Task._mongometa.collection.drop()

    @classmethod
    def tearDownClass(cls):
        # Clean up after ourselves by dropping the collection for this model
        task.Task._mongometa.collection.drop()

    def test_stores_and_loads_simple(self):
        obj = MockTask(state=task.JobState.UNSTARTED)
        obj.save()

        # Load all the entities
        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)
        all_entities[0].delete()

    def test_stores_and_loads_all_params(self):
        obj = MockTask(
            state=task.JobState.RUNNING,
            node_id='test-hpc',
            job_id=15,
            num_cpus=3,
            num_gpus=150,
            memory_requirements='4KB',
            expected_duration='100:00:00'
        )
        obj.save()

        # Load all the entities
        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)
        all_entities[0].delete()

    def test_stores_and_loads_after_change_state(self):
        obj = MockTask(
            state=task.JobState.RUNNING,
            node_id='test-hpc',
            job_id=15,
            num_cpus=3,
            num_gpus=150,
            memory_requirements='4KB',
            expected_duration='100:00:00'
        )
        obj.save()

        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)

        obj.mark_job_failed()
        obj.save()

        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)

        obj.mark_job_started('test_node', 143)
        obj.save()

        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)

        obj.mark_job_complete()
        obj.save()

        all_entities = list(task.Task.objects.all())
        self.assertGreaterEqual(len(all_entities), 1)
        self.assertEqual(all_entities[0], obj)

class TestTask(unittest.TestCase):

    def test_mark_job_started_changes_unstarted_to_running(self):
        subject = MockTask(state=task.JobState.UNSTARTED)
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        subject.mark_job_started('test', 12)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)

    def test_mark_job_started_doesnt_affect_already_running_jobs(self):
        subject = MockTask(state=task.JobState.RUNNING, node_id='external', job_id=3)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        self.assertFalse(subject.is_finished)
        subject.mark_job_started('test', 12)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        self.assertFalse(subject.is_finished)
        self.assertEqual('external', subject.node_id)
        self.assertEqual(3, subject.job_id)

    def test_mark_job_started_doesnt_affect_finished_jobs(self):
        subject = MockTask(state=task.JobState.DONE)
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        subject.mark_job_started('test', 12)
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_mark_job_failed_changes_running_to_unstarted(self):
        subject = MockTask(state=task.JobState.RUNNING, node_id='test', job_id=5)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        subject.mark_job_failed()
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_mark_job_failed_increases_failed_count(self):
        subject = MockTask(state=task.JobState.RUNNING, node_id='test', job_id=5, failure_count=4)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        subject.mark_job_failed()
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertEqual(5, subject.failure_count)

    def test_mark_job_failed_doesnt_affect_unstarted_jobs(self):
        subject = MockTask(state=task.JobState.UNSTARTED)
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_finished)
        subject.mark_job_failed()
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_finished)
        self.assertEqual(0, subject.failure_count)

    def test_mark_job_failed_doesnt_affect_finished_jobs(self):
        subject = MockTask(state=task.JobState.DONE)
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        subject.mark_job_failed()
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_mark_job_complete_changes_running_to_finished(self):
        subject = MockTask(state=task.JobState.RUNNING, node_id='test', job_id=5)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        subject.mark_job_complete()
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_mark_job_complete_doesnt_affect_unstarted_jobs(self):
        subject = MockTask(state=task.JobState.UNSTARTED)
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertFalse(subject.is_finished)
        subject.mark_job_complete()
        self.assertTrue(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertFalse(subject.is_finished)

    def test_mark_job_complete_doesnt_affect_finished_jobs(self):
        subject = MockTask(state=task.JobState.DONE)
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        subject.mark_job_complete()
        self.assertFalse(subject.is_unstarted)
        self.assertFalse(subject.is_running)
        self.assertTrue(subject.is_finished)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_change_job_id_doesnt_affect_state(self):
        subject = MockTask(state=task.JobState.RUNNING)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        self.assertFalse(subject.is_finished)
        subject.change_job_id('test', 12)
        self.assertFalse(subject.is_unstarted)
        self.assertTrue(subject.is_running)
        self.assertFalse(subject.is_finished)

    def test_change_job_id_changes_job_info(self):
        subject = MockTask(state=task.JobState.RUNNING, node_id='external', job_id=3)
        self.assertEqual('external', subject.node_id)
        self.assertEqual(3, subject.job_id)
        subject.change_job_id('test', 12)
        self.assertEqual('test', subject.node_id)
        self.assertEqual(12, subject.job_id)

    def test_change_job_id_doesnt_affect_unstarted_jobs(self):
        subject = MockTask(state=task.JobState.UNSTARTED)
        self.assertTrue(subject.is_unstarted)
        subject.change_job_id('test', 12)
        self.assertTrue(subject.is_unstarted)
        self.assertIsNone(subject.node_id)
        self.assertIsNone(subject.job_id)

    def test_change_job_id_doesnt_affect_finished_jobs(self):
        subject = MockTask(state=task.JobState.DONE, node_id='external', job_id=3)
        self.assertTrue(subject.is_finished)
        self.assertEqual('external', subject.node_id)
        self.assertEqual(3, subject.job_id)
        subject.change_job_id('test', 12)
        self.assertTrue(subject.is_finished)
        self.assertEqual('external', subject.node_id)
        self.assertEqual(3, subject.job_id)

    def test_state_remains_consistent(self):
        random = np.random.RandomState(144135)
        subject = MockTask(state=task.JobState.UNSTARTED)
        for idx in range(50):
            change = random.randint(0, 4 if idx > 30 else 3)
            if idx > 30 and change == 3:
                subject.mark_job_complete()
            elif change == 2:
                subject.change_job_id('external', random.randint(0, 1000))
            elif change == 1:
                subject.mark_job_started('test', random.randint(0, 1000))
            else:
                subject.mark_job_failed()
            # Make sure that the node id and job id match the state
            if subject.is_unstarted or subject.is_finished:
                self.assertIsNone(subject.node_id)
                self.assertIsNone(subject.job_id)
            else:
                self.assertIsNotNone(subject.node_id)
                self.assertIsNotNone(subject.job_id)

Copyright (c) 2017, John Skinner Remove the collection as the start of the test, so that we're sure it's empty Clean up after ourselves by dropping the collection for this model Load all the entities Load all the entities Make sure that the node id and job id match the state


# coding: utf-8

"""
    vautoscaling

    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

import pprint
import re  # noqa: F401

import six

from ncloud_vautoscaling.model.process import Process  # noqa: F401,E501

class ResumeProcessesResponse(object):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'request_id': 'str',
        'return_code': 'str',
        'return_message': 'str',
        'total_rows': 'int',
        'process_list': 'list[Process]'
    }

    attribute_map = {
        'request_id': 'requestId',
        'return_code': 'returnCode',
        'return_message': 'returnMessage',
        'total_rows': 'totalRows',
        'process_list': 'processList'
    }

    def __init__(self, request_id=None, return_code=None, return_message=None, total_rows=None, process_list=None):  # noqa: E501
        """ResumeProcessesResponse - a model defined in Swagger"""  # noqa: E501

        self._request_id = None
        self._return_code = None
        self._return_message = None
        self._total_rows = None
        self._process_list = None
        self.discriminator = None

        if request_id is not None:
            self.request_id = request_id
        if return_code is not None:
            self.return_code = return_code
        if return_message is not None:
            self.return_message = return_message
        if total_rows is not None:
            self.total_rows = total_rows
        if process_list is not None:
            self.process_list = process_list

    @property
    def request_id(self):
        """Gets the request_id of this ResumeProcessesResponse.  # noqa: E501

        :return: The request_id of this ResumeProcessesResponse.  # noqa: E501
        :rtype: str
        """
        return self._request_id

    @request_id.setter
    def request_id(self, request_id):
        """Sets the request_id of this ResumeProcessesResponse.

        :param request_id: The request_id of this ResumeProcessesResponse.  # noqa: E501
        :type: str
        """

        self._request_id = request_id

    @property
    def return_code(self):
        """Gets the return_code of this ResumeProcessesResponse.  # noqa: E501

        :return: The return_code of this ResumeProcessesResponse.  # noqa: E501
        :rtype: str
        """
        return self._return_code

    @return_code.setter
    def return_code(self, return_code):
        """Sets the return_code of this ResumeProcessesResponse.

        :param return_code: The return_code of this ResumeProcessesResponse.  # noqa: E501
        :type: str
        """

        self._return_code = return_code

    @property
    def return_message(self):
        """Gets the return_message of this ResumeProcessesResponse.  # noqa: E501

        :return: The return_message of this ResumeProcessesResponse.  # noqa: E501
        :rtype: str
        """
        return self._return_message

    @return_message.setter
    def return_message(self, return_message):
        """Sets the return_message of this ResumeProcessesResponse.

        :param return_message: The return_message of this ResumeProcessesResponse.  # noqa: E501
        :type: str
        """

        self._return_message = return_message

    @property
    def total_rows(self):
        """Gets the total_rows of this ResumeProcessesResponse.  # noqa: E501

        :return: The total_rows of this ResumeProcessesResponse.  # noqa: E501
        :rtype: int
        """
        return self._total_rows

    @total_rows.setter
    def total_rows(self, total_rows):
        """Sets the total_rows of this ResumeProcessesResponse.

        :param total_rows: The total_rows of this ResumeProcessesResponse.  # noqa: E501
        :type: int
        """

        self._total_rows = total_rows

    @property
    def process_list(self):
        """Gets the process_list of this ResumeProcessesResponse.  # noqa: E501

        :return: The process_list of this ResumeProcessesResponse.  # noqa: E501
        :rtype: list[Process]
        """
        return self._process_list

    @process_list.setter
    def process_list(self, process_list):
        """Sets the process_list of this ResumeProcessesResponse.

        :param process_list: The process_list of this ResumeProcessesResponse.  # noqa: E501
        :type: list[Process]
        """

        self._process_list = process_list

    def to_dict(self):
        """Returns the model properties as a dict"""
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value

        return result

    def to_str(self):
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self):
        """For `print` and `pprint`"""
        return self.to_str()

    def __eq__(self, other):
        """Returns true if both objects are equal"""
        if not isinstance(other, ResumeProcessesResponse):
            return False

        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """Returns true if both objects are not equal"""
        return not self == other

NOTE: This class is auto generated by the swagger code generator program.

Do not edit the class manually.
Returns true if both objects are equal
ResumeProcessesResponse - a model defined in Swagger
Returns true if both objects are not equal
For `print` and `pprint`
Gets the process_list of this ResumeProcessesResponse.  # noqa: E501

:return: The process_list of this ResumeProcessesResponse.  # noqa: E501
:rtype: list[Process]
Sets the process_list of this ResumeProcessesResponse.

:param process_list: The process_list of this ResumeProcessesResponse.  # noqa: E501
:type: list[Process]
Gets the request_id of this ResumeProcessesResponse.  # noqa: E501

:return: The request_id of this ResumeProcessesResponse.  # noqa: E501
:rtype: str
Sets the request_id of this ResumeProcessesResponse.

:param request_id: The request_id of this ResumeProcessesResponse.  # noqa: E501
:type: str
Gets the return_code of this ResumeProcessesResponse.  # noqa: E501

:return: The return_code of this ResumeProcessesResponse.  # noqa: E501
:rtype: str
Sets the return_code of this ResumeProcessesResponse.

:param return_code: The return_code of this ResumeProcessesResponse.  # noqa: E501
:type: str
Gets the return_message of this ResumeProcessesResponse.  # noqa: E501

:return: The return_message of this ResumeProcessesResponse.  # noqa: E501
:rtype: str
Sets the return_message of this ResumeProcessesResponse.

:param return_message: The return_message of this ResumeProcessesResponse.  # noqa: E501
:type: str
Returns the model properties as a dict
Returns the string representation of the model
Gets the total_rows of this ResumeProcessesResponse.  # noqa: E501

:return: The total_rows of this ResumeProcessesResponse.  # noqa: E501
:rtype: int
Sets the total_rows of this ResumeProcessesResponse.

:param total_rows: The total_rows of this ResumeProcessesResponse.  # noqa: E501
:type: int
vautoscaling

Generated by: https://github.com/swagger-api/swagger-codegen.git

 coding: utf-8 noqa: F401 noqa: F401,E501 noqa: E501 noqa: E501


#!/usr/bin/env python3
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from . import css_checker
from os import path as os_path
import re
from sys import path as sys_path
import unittest

_HERE = os_path.dirname(os_path.abspath(__file__))
sys_path.append(os_path.join(_HERE, '..', '..'))

from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi, MockFile

class CssCheckerTest(unittest.TestCase):
  def setUp(self):
    super(CssCheckerTest, self).setUp()

    self.input_api = MockInputApi()
    self.checker = css_checker.CSSChecker(self.input_api, MockOutputApi())

  def _create_file(self, contents, filename):
    self.input_api.files.append(MockFile(filename, contents.splitlines()))

  def VerifyContentIsValid(self, contents, filename='fake.css'):
    self._create_file(contents, filename)
    results = self.checker.RunChecks()
    self.assertEqual(len(results), 0)

  def VerifyContentsProducesOutput(self, contents, output, filename='fake.css'):
    self._create_file(contents, filename)
    results = self.checker.RunChecks()
    self.assertEqual(len(results), 1)
    self.assertEqual(results[0].message, filename + ':\n' + output.strip())

  def testCssAlphaWithAtBlock(self):
    self.VerifyContentsProducesOutput("""
<include src="../shared/css/cr/ui/overlay.css">
<include src="chrome://resources/totally-cool.css" />

/* A hopefully safely ignored comment and @media statement. /**/
@media print {
  div {
    display: block;
    color: red;
  }
}

.rule {
  z-index: 5;
<if expr="not is macosx">
  background-image: url(chrome://resources/BLAH); /* TODO(dbeam): Fix this. */
  background-color: rgb(235, 239, 249);
</if>
<if expr="is_macosx">
  background-color: white;
  background-image: url(chrome://resources/BLAH2);
</if>
  color: black;
}

<if expr="is_macosx">
.language-options-right {
  visibility: hidden;
  opacity: 1; /* TODO(dbeam): Fix this. */
}
</if>

@media (prefers-color-scheme: dark) {
  a[href] {
    z-index: 3;
    color: blue;
  }
}""", """
- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
    display: block;
    color: red;

    z-index: 5;
    color: black;

    z-index: 3;
    color: blue;""")

  def testCssStringWithAt(self):
    self.VerifyContentIsValid("""
#logo {
  background-image: url(images/google_logo.png@2x);
}

body.alternate-logo #logo {
  -webkit-mask-image: url(images/google_logo.png@2x);
  background: none;
}

div {
  margin-inline-start: 5px;
}

.stuff1 {
}

.stuff2 {
}
      """)

  def testCssAlphaWithNonStandard(self):
    self.VerifyContentsProducesOutput("""
div {
  /* A hopefully safely ignored comment and @media statement. /**/
  color: red;
  -webkit-margin-before-collapse: discard;
}""", """
- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
    color: red;
    -webkit-margin-before-collapse: discard;""")

  def testCssAlphaWithLongerDashedProps(self):
    self.VerifyContentsProducesOutput("""
div {
  border-inline-start: 5px;  /* A hopefully removed comment. */
  border: 5px solid red;
}""", """
- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
    border-inline-start: 5px;
    border: 5px solid red;""")

  def testCssAlphaWithVariables(self):
    self.VerifyContentIsValid("""
#id {
  --zzyxx-xylophone: 3px;
  --aardvark-animal: var(--zzyxz-xylophone);
}
""")

  def testCssBracesHaveSpaceBeforeAndNothingAfter(self):
    self.VerifyContentsProducesOutput("""
/* Hello! */div/* Comment here*/{
  display: block;
}

blah /* hey! */
{
  rule: value;
}

.mixed-in {
  display: none;
}

.this.is { /* allowed */
  rule: value;
}""", """
- Start braces ({) end a selector, have a space before them and no rules after.
    div{
    {""")

  def testMixins(self):
    self.VerifyContentsProducesOutput(
        """
.mixed-in {
  --css-mixin: {
    color: red;
  }
}""", """
- Avoid using CSS mixins. Use CSS shadow parts, CSS variables, or common CSS \
classes instead.
    --css-mixin: {""")

  def testCssClassesUseDashes(self):
    self.VerifyContentsProducesOutput("""
.className,
.ClassName,
.class-name /* We should not catch this. */,
.class_name,
[i18n-values*='.innerHTML:'] {
  display: block;
}""", """
 - Classes use .dash-form.
    .className,
    .ClassName,
    .class_name,""")

  def testCssCloseBraceOnNewLine(self):
    self.VerifyContentsProducesOutput("""
@-webkit-keyframe blah {
  from { height: rotate(-10turn); }
  100% { height: 500px; }
}

#id { /* $i18n{*} and $i18nRaw{*} should be ignored. */
  rule: $i18n{someValue};
  rule2: $i18nRaw{someValue};
}

#rule {
  rule: value; }""", """
- Always put a rule closing brace (}) on a new line.
    rule: value; }""")

  def testCssColonsHaveSpaceAfter(self):
    self.VerifyContentsProducesOutput("""
div:not(.class):not([attr=5]), /* We should not catch this. */
div:not(.class):not([attr]) /* Nor this. */ {
  background: url(data:image/jpeg,asdfasdfsadf); /* Ignore this. */
  background: -webkit-linear-gradient(left, red,
                                      80% blah blee blar);
  color: red;
  display:block;
}""", """
- Colons (:) should have a space after them.
    display:block;

- Don't use data URIs in source files. Use grit instead.
    background: url(data:image/jpeg,asdfasdfsadf);""")

  def testCssFavorSingleQuotes(self):
    self.VerifyContentsProducesOutput("""
html[dir="rtl"] body,
html[dir=ltr] body /* TODO(dbeam): Require '' around rtl in future? */ {
  font-family: "Open Sans";
<if expr="is_macosx">
  blah: blee;
</if>
}""", """
- Use single quotes (') instead of double quotes (") in strings.
    html[dir="rtl"] body,
    font-family: "Open Sans";""")

  def testCssHexCouldBeShorter(self):
    self.VerifyContentsProducesOutput("""
#abc,
#abc-,
#abc-ghij,
#abcdef-,
#abcdef-ghij,
#aaaaaa,
#bbaacc {
  background-color: #336699; /* Ignore short hex rule if not gray. */
  color: #999999;
  color: #666;
}""", """
- Use abbreviated hex (#rgb) when in form #rrggbb.
    color: #999999; (replace with #999)

- Use rgb() over #hex when not a shade of gray (like #333).
    background-color: #336699; (replace with rgb(51, 102, 153))""")

  def testCssUseMillisecondsForSmallTimes(self):
    self.VerifyContentsProducesOutput("""
.transition-0s /* This is gross but may happen. */ {
  transform: one 0.2s;
  transform: two .1s;
  transform: tree 1s;
  transform: four 300ms;
}""", """
- Use milliseconds for time measurements under 1 second.
    transform: one 0.2s; (replace with 200ms)
    transform: two .1s; (replace with 100ms)""")

  def testCssNoDataUrisInSourceFiles(self):
    self.VerifyContentsProducesOutput("""
img {
  background: url( data:image/jpeg,4\/\/350|\/|3|2 );
}""", """
- Don't use data URIs in source files. Use grit instead.
    background: url( data:image/jpeg,4\/\/350|\/|3|2 );""")

  def testCssNoMixinShims(self):
    self.VerifyContentsProducesOutput("""
:host {
  --good-property: red;
  --not-okay-mixin_-_not-okay-property: green;
}""", """
- Don't override custom properties created by Polymer's mixin shim. Set \
mixins or documented custom properties directly.
    --not-okay-mixin_-_not-okay-property: green;""")

  def testCssNoQuotesInUrl(self):
    self.VerifyContentsProducesOutput("""
img {
  background: url('chrome://resources/images/blah.jpg');
  background: url("../../folder/hello.png");
}""", """
- Use single quotes (') instead of double quotes (") in strings.
    background: url("../../folder/hello.png");

- Don't use quotes in url().
    background: url('chrome://resources/images/blah.jpg');
    background: url("../../folder/hello.png");""")

  def testCssOneRulePerLine(self):
    self.VerifyContentsProducesOutput("""
a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type,
a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type ~
    input[type='checkbox']:not([hidden]),
div {
  background: url(chrome://resources/BLAH);
  rule: value; /* rule: value; */
  rule: value; rule: value;
}
""", """
- One rule per line (what not to do: color: red; margin: 0;).
    rule: value; rule: value;""")

  def testCssOneSelectorPerLine(self):
    self.VerifyContentsProducesOutput(
        """
a,
div,a,
div,/* Hello! */ span,
#id.class([dir=rtl]):not(.class):any(a, b, d),
div :is(:not(a), #b, .c) {
  rule: value;
}

a,
div,a {
  some-other: rule here;
}""", """
- One selector per line (what not to do: a, b {}).
    div,a,
    div, span,
    div,a {""")

  def testCssPseudoElementDoubleColon(self):
    self.VerifyContentsProducesOutput("""
a:href,
br::after,
::-webkit-scrollbar-thumb,
a:not([empty]):hover:focus:active, /* shouldn't catch here and above */
abbr:after,
.tree-label:empty:after,
b:before,
:-WebKit-ScrollBar {
  rule: value;
}""", """
- Pseudo-elements should use double colon (i.e. ::after).
    :after (should be ::after)
    :after (should be ::after)
    :before (should be ::before)
    :-WebKit-ScrollBar (should be ::-WebKit-ScrollBar)
    """)

  def testCssRgbIfNotGray(self):
    self.VerifyContentsProducesOutput(
        """
#abc,
#aaa,
#aabbcc {
  background: -webkit-linear-gradient(left, from(#abc), to(#def));
  color: #bad;
  color: #bada55;
}""", """
- Use rgb() over #hex when not a shade of gray (like #333).
    background: -webkit-linear-gradient(left, from(#abc), to(#def)); """
        """(replace with rgb(170, 187, 204), rgb(221, 238, 255))
    color: #bad; (replace with rgb(187, 170, 221))
    color: #bada55; (replace with rgb(186, 218, 85))""")

  def testPrefixedLogicalAxis(self):
    self.VerifyContentsProducesOutput("""
.test {
  -webkit-logical-height: 50%;
  -webkit-logical-width: 50%;
  -webkit-max-logical-height: 200px;
  -webkit-max-logical-width: 200px;
  -webkit-min-logical-height: 100px;
  -webkit-min-logical-width: 100px;
}
""", """
- Unprefix logical axis property.
    -webkit-logical-height: 50%; (replace with block-size)
    -webkit-logical-width: 50%; (replace with inline-size)
    -webkit-max-logical-height: 200px; (replace with max-block-size)
    -webkit-max-logical-width: 200px; (replace with max-inline-size)
    -webkit-min-logical-height: 100px; (replace with min-block-size)
    -webkit-min-logical-width: 100px; (replace with min-inline-size)""")

  def testPrefixedLogicalSide(self):
    self.VerifyContentsProducesOutput("""
.test {
  -webkit-border-after: 1px solid blue;
  -webkit-border-after-color: green;
  -webkit-border-after-style: dotted;
  -webkit-border-after-width: 10px;
  -webkit-border-before: 2px solid blue;
  -webkit-border-before-color: green;
  -webkit-border-before-style: dotted;
  -webkit-border-before-width: 20px;
  -webkit-border-end: 3px solid blue;
  -webkit-border-end-color: green;
  -webkit-border-end-style: dotted;
  -webkit-border-end-width: 30px;
  -webkit-border-start: 4px solid blue;
  -webkit-border-start-color: green;
  -webkit-border-start-style: dotted;
  -webkit-border-start-width: 40px;
  -webkit-margin-after: 1px;
  -webkit-margin-after-collapse: discard;
  -webkit-margin-before: 2px;
  -webkit-margin-before-collapse: discard;
  -webkit-margin-end: 3px;
  -webkit-margin-end-collapse: discard;
  -webkit-margin-start: 4px;
  -webkit-margin-start-collapse: discard;
  -webkit-padding-after: 1px;
  -webkit-padding-before: 2px;
  -webkit-padding-end: 3px;
  -webkit-padding-start: 4px;
}
""", """
- Unprefix logical side property.
    -webkit-border-after: 1px solid blue; (replace with border-block-end)
    -webkit-border-after-color: green; (replace with border-block-end-color)
    -webkit-border-after-style: dotted; (replace with border-block-end-style)
    -webkit-border-after-width: 10px; (replace with border-block-end-width)
    -webkit-border-before: 2px solid blue; (replace with border-block-start)
    -webkit-border-before-color: green; (replace with border-block-start-color)
    -webkit-border-before-style: dotted; (replace with border-block-start-style)
    -webkit-border-before-width: 20px; (replace with border-block-start-width)
    -webkit-border-end: 3px solid blue; (replace with border-inline-end)
    -webkit-border-end-color: green; (replace with border-inline-end-color)
    -webkit-border-end-style: dotted; (replace with border-inline-end-style)
    -webkit-border-end-width: 30px; (replace with border-inline-end-width)
    -webkit-border-start: 4px solid blue; (replace with border-inline-start)
    -webkit-border-start-color: green; (replace with border-inline-start-color)
    -webkit-border-start-style: dotted; (replace with border-inline-start-style)
    -webkit-border-start-width: 40px; (replace with border-inline-start-width)
    -webkit-margin-after: 1px; (replace with margin-block-end)
    -webkit-margin-before: 2px; (replace with margin-block-start)
    -webkit-margin-end: 3px; (replace with margin-inline-end)
    -webkit-margin-start: 4px; (replace with margin-inline-start)
    -webkit-padding-after: 1px; (replace with padding-block-end)
    -webkit-padding-before: 2px; (replace with padding-block-start)
    -webkit-padding-end: 3px; (replace with padding-inline-end)
    -webkit-padding-start: 4px; (replace with padding-inline-start)""")

  def testStartEndInsteadOfLeftRight(self):
    self.VerifyContentsProducesOutput("""
.inline-node {
  --var-is-ignored-left: 10px;
  --var-is-ignored-right: 10px;
  border-left-color: black;
  border-right: 1px solid blue;  /* csschecker-disable-line left-right */
  margin-right: 5px;
  padding-left: 10px;    /* csschecker-disable-line some-other-thing */
  text-align: right;
}""", """
- Use -start/end instead of -left/right (https://goo.gl/gQYY7z, add /* csschecker-disable-line left-right */ to suppress)
    border-left-color: black; (replace with border-inline-start-color)
    margin-right: 5px; (replace with margin-inline-end)
    padding-left: 10px; (replace with padding-inline-start)
    text-align: right; (replace with text-align: end)
""")

  def testCssZeroWidthLengths(self):
    self.VerifyContentsProducesOutput("""
@-webkit-keyframe anim {
  0% { /* Ignore key frames */
    width: 0px;
  }
  10% {
    width: 10px;
  }
  50% { background-image: url(blah.svg); }
  100% {
    width: 100px;
  }
}

#logo {
  background-image: url(images/google_logo.png@2x);
}

body.alternate-logo #logo {
  -webkit-mask-image: url(images/google_logo.png@2x);
}

/* http://crbug.com/359682 */
#spinner-container #spinner {
  -webkit-animation-duration: 1.0s;
  background-image: url(images/google_logo0.svg);
}

.media-button.play > .state0.active,
.media-button[state='0'] > .state0.normal /* blah */, /* blee */
.media-button[state='0']:not(.disabled):hover > .state0.hover {
  -webkit-animation: anim 0s;
  -webkit-animation-duration: anim 0ms;
  -webkit-transform: scale(0%);
  background-position-x: 0em;
  background-position-y: 0ex;
  border-width: 0em;
  color: hsl(0, 0%, 85%); /* Shouldn't trigger error. */
  opacity: .0;
  opacity: 0.0;
  opacity: 0.;
}

@page {
  border-width: 0mm;
  height: 0cm;
  width: 0in;
}""", """
- Use "0" for zero-width lengths (i.e. 0px -> 0)
    width: 0px;
    -webkit-transform: scale(0%);
    background-position-x: 0em;
    background-position-y: 0ex;
    border-width: 0em;
    opacity: .0;
    opacity: 0.0;
    opacity: 0.;
    border-width: 0mm;
    height: 0cm;
    width: 0in;
""")

  def testInlineStyleInHtml(self):
    self.VerifyContentsProducesOutput("""<!doctype html>
<html>
<head>
  <!-- Don't warn about problems outside of style tags
    html,
    body {
      margin: 0;
      height: 100%;
    }
  -->
  <style>
    body {
      flex-direction:column;
    }
  </style>
</head>
</html>""", """
- Colons (:) should have a space after them.
    flex-direction:column;
""", filename='test.html')

  def testInlineStyleInHtmlWithIncludes(self):
    self.VerifyContentsProducesOutput("""<!doctype html>
<html>
  <style include="fake-shared-css other-shared-css">
    body {
      flex-direction:column;
    }
  </style>
</head>
</html>""", """
- Colons (:) should have a space after them.
    flex-direction:column;
""", filename='test.html')

  def testInlineStyleInHtmlWithTagsInComments(self):
    self.VerifyContentsProducesOutput("""<!doctype html>
<html>
  <style>
    body {
      /* You better ignore the <tag> in this comment! */
      flex-direction:column;
    }
  </style>
</head>
</html>""", """
- Colons (:) should have a space after them.
    flex-direction:column;
""", filename='test.html')

  def testRemoveAtBlocks(self):
    self.assertEqual(self.checker.RemoveAtBlocks("""
@media (prefers-color-scheme: dark) {
  .magic {
    color: #000;
  }
}"""), """
  .magic {
    color: #000;
  }""")

    self.assertEqual(self.checker.RemoveAtBlocks("""
@media (prefers-color-scheme: dark) {
  .magic {
    --mixin-definition: {
      color: red;
    };
  }
}"""), """
  .magic {
    --mixin-definition: {
      color: red;
    };
  }""")

    self.assertEqual(self.checker.RemoveAtBlocks("""
@keyframes jiggle {
  from { left: 0; }
  50% { left: 100%; }
  to { left: 10%; }
}"""), """
  from { left: 0; }
  50% { left: 100%; }
  to { left: 10%; }""")

    self.assertEqual(self.checker.RemoveAtBlocks("""
@media print {
  .rule1 {
    color: black;
  }
  .rule2 {
    margin: 1in;
  }
}"""), """
  .rule1 {
    color: black;
  }
  .rule2 {
    margin: 1in;
  }""")

    self.assertEqual(self.checker.RemoveAtBlocks("""
@media (prefers-color-scheme: dark) {
  .rule1 {
    color: gray;
  }
  .rule2 {
    margin: .5in;
  }
  @keyframe dark-fade {
    0% { background: black; }
    100% { background: darkgray; }
  }
}"""), """
  .rule1 {
    color: gray;
  }
  .rule2 {
    margin: .5in;
  }
    0% { background: black; }
    100% { background: darkgray; }""")

    self.assertEqual(self.checker.RemoveAtBlocks("""
@-webkit-keyframe anim {
  0% { /* Ignore key frames */
    width: 0px;
  }
  10% {
    width: 10px;
  }
  50% { background-image: url(blah.svg); }
  100% {
    width: 100px;
  }
}"""), """
  0% { /* Ignore key frames */
    width: 0px;
  }
  10% {
    width: 10px;
  }
  50% { background-image: url(blah.svg); }
  100% {
    width: 100px;
  }""")

if __name__ == '__main__':
  unittest.main()

!/usr/bin/env python3 Copyright 2015 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.


from typing import Dict, List, Optional
from db.sql.dal.general import sanitize
from db.sql.utils import query_to_dicts

class Region:
    admin: str
    admin_id: str
    region_type: str
    country: str
    country_id: str
    admin1: Optional[str]
    admin1_id: Optional[str]
    admin2: Optional[str]
    admin2_id: Optional[str]
    admin3: Optional[str]
    admin3_id: Optional[str]
    region_coordinate: Optional[str]
    alias: Optional[str]

    COUNTRY = 'Q6256'
    ADMIN1 = 'Q10864048'
    ADMIN2 = 'Q13220204'
    ADMIN3 = 'Q13221722'

    def __init__(self, **kwargs):
        self.admin = kwargs['admin']
        self.admin_id = kwargs['admin_id']
        self.region_type = kwargs['region_type']
        self.country = kwargs['country']
        self.country_id = kwargs['country_id']
        self.admin1 = kwargs.get('admin1')
        self.admin1_id = kwargs.get('admin1_id')
        self.admin2 = kwargs.get('admin2')
        self.admin2_id = kwargs.get('admin2_id')
        self.admin3 = kwargs.get('admin3')
        self.admin3_id = kwargs.get('admin3_id')
        self.region_coordinate = kwargs.get('region_coordinate')
        self.alias = kwargs.get('alias')

        # country, admin1 and admin2 queries return both admin and country,admin1,admin2 fields.
        # admin3 queries do not, so we need to feel these fields ourselves
        if self.region_type == Region.ADMIN3:
            self.admin3_id, self.admin_3 = self.admin_id, self.admin

    def __getitem__(self, key: str) -> str:
        return getattr(self, key)

def query_country_qnodes(countries: List[str]) -> Dict[str, Optional[str]]:
    # Translates countries to Q-nodes. Returns a dictionary of each input country and its QNode (None if not found)
    # We look for countries in a case-insensitive fashion.
    if not countries:
        return {}

    regions = query_countries(countries)
    result_dict: Dict[str, Optional[str]] = {region.country: region.country_id for region in regions}

    # The result dictionary contains all the countries we have found, we need to add those we did not find
    found_countries = set([country.lower() for country in result_dict.keys()])
    for country in countries:
        if country.lower() not in found_countries:
            result_dict[country] = None

    return result_dict

def list_to_where(field: str, elements: List[str], lower=False) -> Optional[str]:
    if not elements:
        return None

    if lower:
        elements = [element.lower() for element in elements]
        field = f"LOWER({field})"
    santized = [sanitize(element) for element in elements]
    quoted = [f"'{element}'" for element in santized]
    joined = ', '.join(quoted)

    return f"{field} IN ({joined})"

def region_where_clause(region_field: str, region_list: List[str], region_id_field: str,
                        region_id_list: List[str], alias_field: Optional[str] = None) -> str:
    if not region_list and not region_id_list:
        return "1=1"

    region_where = list_to_where(region_field, region_list, lower=True) or "0=1"
    if alias_field:
        alias_where = list_to_where(alias_field, region_list, lower=True) or "0=1"
    else:
        alias_where = "0=1"

    region_id_where = list_to_where(region_id_field, region_id_list) or "0=1"

    return f'({region_where} OR {region_id_where} OR {alias_where})'

def _query_regions(query: str) -> List[Region]:
    dicts = query_to_dicts(query)
    return [Region(**d) for d in dicts]

def query_countries(countries: List[str] = [], country_ids: List[str] = []) -> List[Region]:
    """ Returns a list of countries:
    If countries or country_ids are not empty, only those countries are returned (all of those in both lists)
    Otherwise, all countries are returned
    """
    where = region_where_clause('s_country_label.text', countries, 'e_country.node1', country_ids)
    query = f'''
    SELECT  e_country.node1 AS admin_id,
            s_country_label.text AS admin,
            'Q6256' AS region_type,
            e_country.node1 AS country_id,
            s_country_label.text AS country,
            NULL as admin1_id,
            NULL as admin1,
            NULL as admin2_id,
            NULL as admin2,
            NULL as admin3_id,
            NULL as admin3
    FROM edges e_country
        JOIN edges e_country_label JOIN strings s_country_label ON (e_country_label.id=s_country_label.edge_id)
            ON (e_country.node1=e_country_label.node1 AND e_country_label.label='label')
    WHERE e_country.label='P31' AND e_country.node2='Q6256' AND {where}
    ORDER BY country
    '''

    return _query_regions(query)

def query_admin1s(country: Optional[str] = None, country_id: Optional[str] = None, admin1s: List[str] = [],
                  admin1_ids: List[str] = []) -> List[Region]:
    """
    Returns a list of admin1s. If country or country_id is specified, return the admin1s only of that country.
    If admin1s or admin1_ids are provided, only those admins are returned.
    If all arguments are empty, all admin1s in the system are returned.
    """
    if country and country_id:
        raise ValueError('Only one of country, country_id may be specified')

    if country_id:
        country_where = f"e_country.node2='{country_id}'"
    elif country:  # We are certain country is not None here, but need an `elif` because mypy isn't certain
        country_where = f"LOWER(s_country_label.text)='{country.lower()}'"
    else:
        country_where = "1=1"
    admin1_where = region_where_clause('s_admin1_label.text', admin1s, 'e_admin1.node1', admin1_ids)

    query = f'''
    SELECT  e_admin1.node1 AS admin_id,
            s_admin1_label.text AS admin,
            'Q10864048' AS region_type,
            e_country.node2 AS country_id,
            s_country_label.text AS country,
            e_admin1.node1 as admin1_id,
            s_admin1_label.text as admin1,
            NULL as admin2_id,
            NULL as admin2,
            NULL as admin3_id,
            NULL as admin3
    FROM edges e_admin1
        JOIN edges e_admin1_label JOIN strings s_admin1_label ON (e_admin1_label.id=s_admin1_label.edge_id)
            ON (e_admin1.node1=e_admin1_label.node1 AND e_admin1_label.label='label')
        JOIN edges e_country ON (e_country.node1=e_admin1.node1 AND e_country.label='P17')
        JOIN edges e_country_label JOIN strings s_country_label ON (e_country_label.id=s_country_label.edge_id)
            ON (e_country.node2=e_country_label.node1 AND e_country_label.label='label')
    WHERE e_admin1.label='P31' AND e_admin1.node2='Q10864048' AND {country_where} AND {admin1_where}
    ORDER BY admin1
    '''

    return _query_regions(query)

def query_admin2s(admin1: Optional[str] = None, admin1_id: Optional[str] = None, admin2s: List[str] = [],
                  admin2_ids: List[str] = []) -> List[Region]:
    """
    Returns a list of admin2s. If admin1 or admin1_id is specified, return the admin2s only of that admin1.
    If admin2s or admin2_ids are provided, only those admins are returned.
    If all arguments are empty, all admin2s in the system are returned.
    """
    if admin1 and admin1_id:
        raise ValueError('Only one of admin1, admin1_id may be specified')

    if admin1_id:
        admin1_where = f"e_admin1.node2='{admin1_id}'"
    elif admin1:
        admin1_where = f"LOWER(s_admin1_label.text)=LOWER('{admin1}')"
    else:
        admin1_where = "1=1"

    admin2_where = region_where_clause('s_admin2_label.text', admin2s, 'e_admin2.node1', admin2_ids)

    query = f'''
    SELECT  e_admin2.node1 AS admin_id,
            s_admin2_label.text AS admin,
            'Q13220204' AS region_type,
            e_country.node2 AS country_id,
            s_country_label.text AS country,
            e_admin1.node2 AS admin1_id,
            s_admin1_label.text AS admin1,
            e_admin2.node1 AS admin2_id,
            s_admin2_label.text AS admin2,
            NULL as admin3_id,
            NULL as admin3
    FROM edges e_admin2
        JOIN edges e_admin2_label JOIN strings s_admin2_label ON (e_admin2_label.id=s_admin2_label.edge_id)
            ON (e_admin2.node1=e_admin2_label.node1 AND e_admin2_label.label='label')
        JOIN edges e_admin1 ON (e_admin1.node1=e_admin2.node1 AND e_admin1.label='P2006190001')
        JOIN edges e_admin1_label JOIN strings s_admin1_label ON (e_admin1_label.id=s_admin1_label.edge_id)
            ON (e_admin1.node2=e_admin1_label.node1 AND e_admin1_label.label='label')
        JOIN edges e_country ON (e_country.node1=e_admin1.node2 AND e_country.label='P17')
        JOIN edges e_country_label JOIN strings s_country_label ON (e_country_label.id=s_country_label.edge_id)
            ON (e_country.node2=e_country_label.node1 AND e_country_label.label='label')
    WHERE e_admin2.label='P31' AND e_admin2.node2='Q13220204' AND {admin1_where} AND {admin2_where}
    ORDER BY admin2
    '''

    return _query_regions(query)

def query_admin3s(admin2: Optional[str] = None, admin2_id: Optional[str] = None, admin3s: List[str] = [],
                  admin3_ids: List[str] = [], debug=False) -> List[Region]:
    """
    Returns a list of admin3s. If admin2 or admin2_id is specified, return the admin3s only of that admin2.
    If admin3s or admin3_ids are provided, only those admins are returned.
    If all arguments are empty, all admin3s in the system are returned.
    """
    if admin2 and admin2_id:
        raise ValueError('Only one of admin2, admin2_id may be specified')

    if admin2_id:
        admin2_where = f"e_admin2.node2='{admin2_id}'"
    elif admin2:
        admin2_where = f"LOWER(s_admin2_label.text)=LOWER('{admin2}')"
    else:
        admin2_where = "1=1"

    admin3_where = region_where_clause('s_admin3_label.text', admin3s, 'e_admin3.node1', admin3_ids)

    query = f'''
    SELECT  e_admin3.node1 AS admin_id,
            s_admin3_label.text AS admin,
            'Q13221722' AS region_type,
            e_country.node2 AS country_id,
            s_country_label.text AS country,
            e_admin1.node2 AS admin1_id,
            s_admin1_label.text AS admin1,
            e_admin2.node2 AS admin2_id,
            s_admin2_label.text AS admin2,
            e_admin2.node1 AS admin3_id,
            s_admin3_label.text AS admin3
    FROM
        edges e_admin3
        JOIN edges e_admin3_label JOIN strings s_admin3_label ON (e_admin3_label.id=s_admin3_label.edge_id)
            ON (e_admin3.node1=e_admin3_label.node1 AND e_admin3_label.label='label')
        JOIN edges e_admin2 ON (e_admin2.node1=e_admin3.node1 AND e_admin2.label='P2006190002')
        JOIN edges e_admin2_label JOIN strings s_admin2_label ON (e_admin2_label.id=s_admin2_label.edge_id)
            ON (e_admin2.node2=e_admin2_label.node1 AND e_admin2_label.label='label')
        JOIN edges e_admin1 ON (e_admin1.node1=e_admin2.node1 AND e_admin1.label='P2006190001')
        JOIN edges e_admin1_label JOIN strings s_admin1_label ON (e_admin1_label.id=s_admin1_label.edge_id)
            ON (e_admin1.node2=e_admin1_label.node1 AND e_admin1_label.label='label')
        JOIN edges e_country ON (e_country.node1=e_admin1.node2 AND e_country.label='P17')
        JOIN edges e_country_label JOIN strings s_country_label ON (e_country_label.id=s_country_label.edge_id)
            ON (e_country.node2=e_country_label.node1 AND e_country_label.label='label')
    WHERE e_admin3.label='P31' AND e_admin3.node2='Q13221722' AND {admin2_where} AND {admin3_where}
    ORDER BY admin3
    '''
    if debug:
        print(query)

    return _query_regions(query)

def query_admins(admins: List[str] = [], admin_ids: List[str] = [], debug=False) -> List[Region]:
    where = region_where_clause('s_region_label.text', admins, 'e_region.node1', admin_ids, 's_region_alias.text')

    query = f'''
    SELECT e_region.node1 AS admin_id, s_region_label.text AS admin, e_region.node2 AS region_type,
        e_country.node2 AS country_id, s_country_label.text AS country,
        e_admin1.node2 AS admin1_id, s_admin1_label.text AS admin1,
        e_admin2.node2 AS admin2_id, s_admin2_label.text AS admin2,
        'POINT(' || c_coordinate.longitude || ' ' || c_coordinate.latitude || ')' as region_coordinate,
        s_region_alias.text AS alias
        FROM edges e_region
        JOIN edges e_region_label ON (e_region_label.node1=e_region.node1 AND e_region_label.label='label')
        JOIN strings s_region_label ON (e_region_label.id=s_region_label.edge_id)
        JOIN edges e_country
            JOIN edges e_country_label
                JOIN strings s_country_label
                ON (s_country_label.edge_id=e_country_label.id)
            ON (e_country.node2=e_country_label.node1 AND e_country_label.label='label')
        ON (e_region.node1=e_country.node1 AND e_country.label='P17')
        LEFT JOIN edges e_admin1
            JOIN edges e_admin1_label
                JOIN strings s_admin1_label
                ON (s_admin1_label.edge_id=e_admin1_label.id)
            ON (e_admin1.node2=e_admin1_label.node1 AND e_admin1_label.label='label')
        ON (e_region.node1=e_admin1.node1 AND e_admin1.label='P2006190001')
        LEFT JOIN edges e_admin2
            JOIN edges e_admin2_label
                JOIN strings s_admin2_label
                ON (s_admin2_label.edge_id=e_admin2_label.id)
            ON (e_admin2.node2=e_admin2_label.node1 AND e_admin2_label.label='label')
        ON (e_region.node1=e_admin2.node1 AND e_admin2.label='P2006190002')
        LEFT JOIN edges e_coordinate
            JOIN coordinates c_coordinate
            ON (c_coordinate.edge_id=e_coordinate.id)
        ON (e_region.node1=e_coordinate.node1 AND e_coordinate.label='P625')
        LEFT JOIN edges e_region_alias
            JOIN strings s_region_alias
            ON (s_region_alias.edge_id=e_region_alias.id)
          ON (e_region.node1=e_region_alias.node1 AND e_region_alias.label='alias')
    WHERE e_region.label='P31' AND e_region.node2 IN ('Q6256', 'Q10864048', 'Q13220204', 'Q13221722') AND {where}
    '''
    if debug:
        print(query)
    return _query_regions(query)

Returns a list of admin1s. If country or country_id is specified, return the admin1s only of that country.
If admin1s or admin1_ids are provided, only those admins are returned.
If all arguments are empty, all admin1s in the system are returned.
Returns a list of admin2s. If admin1 or admin1_id is specified, return the admin2s only of that admin1.
If admin2s or admin2_ids are provided, only those admins are returned.
If all arguments are empty, all admin2s in the system are returned.
Returns a list of admin3s. If admin2 or admin2_id is specified, return the admin3s only of that admin2.
If admin3s or admin3_ids are provided, only those admins are returned.
If all arguments are empty, all admin3s in the system are returned.
Returns a list of countries:
If countries or country_ids are not empty, only those countries are returned (all of those in both lists)
Otherwise, all countries are returned

 country, admin1 and admin2 queries return both admin and country,admin1,admin2 fields. admin3 queries do not, so we need to feel these fields ourselves Translates countries to Q-nodes. Returns a dictionary of each input country and its QNode (None if not found) We look for countries in a case-insensitive fashion. The result dictionary contains all the countries we have found, we need to add those we did not find We are certain country is not None here, but need an `elif` because mypy isn't certain


# -*- coding: utf-8 -*-
import json
import csv
import scrapy
import re

from locations.items import GeojsonPointItem

COOKIES = {
    "bm_sz": "04B124C1C96D68082A9F61BAAAF0B6D5~YAAQdjsvF22E8Xl6AQAACr1VfAxPEt+enarZyrOZrBaNvyuX71lK5QPuDR/FgDEWBZVMRhjiIf000W7Z1PiAjxobrz2Y5LcYMH3CvUNvpdS3MjVLUMGwMEBCf9L5nD5Gs9ho2YL8T7Tz7lYvpolvaOlJnKrHyhCFxxk/uyBZ2G/0QrGKLwSaCQShDsz7ink=",
    "_abck": "440E40C406E69413DCCC08ABAA3E9022~-1~YAAQdjsvF26E8Xl6AQAACr1VfAYznoJdJhX7TNIZW1Rfh6qRhzquXg+L1TWoaL7nZUjXlNls2iPIKFQrCdrWqY/CNXW+mHyXibInMflIXJi5VVB/Swq53kABYJDuXYSlCunYvJAzMSr1q12NOYswz134Y8HRNzVWhkb2jMS5whmHxS/v0vniIvS1TQtKjEQlMGzQYmN41CmLX0JobipQhDtUB4VyNwztb2DCAZiqDX8BLwWg7h/DtPd4158qU69hNhayFTgWmD76/MiR8/T536tMmcoRyWLl4fEtP/XUmKOcksuZO7dbfNxXBffTxIXPYwf1eO77LNuZTCQq5kfsGZLJX8ODju2KSjnIF1vdnyHAe98FDIm+hw==~-1~-1~-1"
}

HEADERS = {
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'accept-encoding': 'gzip, deflate, br',
    'cache-control': 'max-age=0',
    'referer': 'https://www.aldi.co.uk/store-finder',
    'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
    'sec-ch-ua-mobile': '?0',
    'sec-fetch-dest': 'document',
    'sec-fetch-mode': 'navigate',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-user': '?1',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',
}

class AldiUKSpider(scrapy.Spider):
    name = "aldi_uk"
    item_attributes = {'brand': "Aldi"}
    allowed_domains = ['aldi.co.uk']
    download_delay = 0.5
    custom_settings = {
        'USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
    }

    def start_requests(self):
        url = 'https://www.aldi.co.uk/sitemap/store-en_gb-gbp'

        yield scrapy.http.FormRequest(
            url=url,
            method='GET',
            dont_filter=True,
            cookies=COOKIES,
            headers=HEADERS,
            callback=self.parse
        )

    def parse(self, response):
        response.selector.remove_namespaces()
        store_urls = response.xpath('//url/loc/text()').extract()

        for store_url in store_urls:

            yield scrapy.http.FormRequest(
                url=store_url,
                method='GET',
                dont_filter=True,
                cookies=COOKIES,
                headers=HEADERS,
                callback=self.parse_store
            )

    def parse_store(self, response):

        store_js = response.xpath('//script[@type="text/javascript"]/text()').extract_first()
        json_data = re.search('gtmData =(.+?);', store_js).group(1)
        data = json.loads(json_data)

        geojson_data = response.xpath('//script[@class="js-store-finder-initial-state"][@type="application/json"]/text()').extract_first()
        geodata = json.loads(geojson_data)

        properties = {
            'name': data['seoData']['name'],
            'ref': data['seoData']['name'],
            'addr_full': data['seoData']['address']['streetAddress'],
            'city': data['seoData']['address']['addressLocality'],
            'postcode': data['seoData']['address']['postalCode'],
            'country': data['seoData']['address']['addressCountry'],
            'website': response.request.url,
            'opening_hours': str(data['seoData']['openingHours']).replace('[','').replace(']','').replace("'",''),
            'lat': geodata['store']['latlng']['lat'],
            'lon': geodata['store']['latlng']['lng'],
        }

        yield GeojsonPointItem(**properties)


#!/usr/bin/env python
# vim: set sts=4 sw=4 et:

import time
import xmlrpc.client
from . import players
from . import rpc
from .common import GameState, CardSet, GameError, RuleError, ProtocolError, simple_decorator
from .events import EventList, CardPlayedEvent, MessageEvent, TrickPlayedEvent, TurnEvent, StateChangedEvent

@simple_decorator
def error2fault(func):
    """
    Catch known exceptions and translate them to
    XML-RPC faults.
    """
    def catcher(*args):
        try:
            return func(*args)
        except GameError as error:
            raise xmlrpc.client.Fault(GameError.rpc_code, str(error))
        except RuleError as error:
            raise xmlrpc.client.Fault(RuleError.rpc_code, str(error))
        except ProtocolError as error:
            raise xmlrpc.client.Fault(ProtocolError.rpc_code, str(error))
    return catcher

@simple_decorator
def fault2error(func):
    """
    Catch known XML-RPC faults and translate them to
    custom exceptions.
    """
    def catcher(*args):
        try:
            return func(*args)
        except xmlrpc.client.Fault as error:
            error_classes = (GameError, RuleError, ProtocolError)
            for klass in error_classes:
                if error.faultCode == klass.rpc_code:
                    raise klass(error.faultString)

            raise error

    return catcher

class XMLRPCCliPlayer(players.CliPlayer):
    """
    XML-RPC command line interface human player.
    """
    def __init__(self, player_name):
        players.CliPlayer.__init__(self, player_name)
        self.game_state = GameState()
        self.hand = None

    def handle_event(self, event):
        if isinstance(event, CardPlayedEvent):
            self.card_played(event.player, event.card, event.game_state)
        elif isinstance(event, MessageEvent):
            self.send_message(event.sender, event.message)
        elif isinstance(event, TrickPlayedEvent):
            self.trick_played(event.player, event.game_state)
        elif isinstance(event, TurnEvent):
            self.game_state.update(event.game_state)
            state = self.controller.get_state(self.id)
            self.hand = state['hand']
            self.game_state.update(state['game_state'])
        elif isinstance(event, StateChangedEvent):
            self.game_state.update(event.game_state)
        else:
            print("unknown event: %s" % event)

    def wait_for_turn(self):
        """
        Wait for this player's turn.
        """
        while True:

            time.sleep(0.5)

            if self.controller is not None:
                events = self.controller.get_events(self.id)
                for event in events:
                    self.handle_event(event)

            if self.game_state.turn_id == self.id:
                break

class XMLRPCProxyController():
    """
    Client-side proxy object for the server/GameController.
    """
    def __init__(self, server_uri):
        super(XMLRPCProxyController, self).__init__()
        if not server_uri.startswith('http://') and \
            not server_uri.startswith('https://'):
            server_uri = 'http://' + server_uri

        self.server = xmlrpc.client.ServerProxy(server_uri)
        self.game_id = None
        self.akey = None

    @fault2error
    def play_card(self, _player, card):
        self.server.game.play_card(self.akey, self.game_id, rpc.rpc_encode(card))

    @fault2error
    def get_events(self, _player_id):
        return rpc.rpc_decode(EventList, self.server.get_events(self.akey))

    @fault2error
    def get_state(self, _player_id):
        state = self.server.game.get_state(self.akey, self.game_id)
        state['game_state'] = rpc.rpc_decode(GameState, state['game_state'])
        state['hand'] = rpc.rpc_decode(CardSet, state['hand'])
        return state

    @fault2error
    def player_quit(self, _player_id):
        self.server.player.quit(self.akey)

    @fault2error
    def register_player(self, player):
        player.controller = self
        plr_data = self.server.player.register(rpc.rpc_encode(player))
        player.id = plr_data['id']
        self.akey = plr_data['akey']

    @fault2error
    def start_game_with_bots(self):
        return self.server.game.start_with_bots(self.akey, self.game_id)

    @fault2error
    def create_game(self):
        self.game_id = self.server.game.create(self.akey)
        return self.game_id

XML-RPC command line interface human player.
Client-side proxy object for the server/GameController.
Catch known exceptions and translate them to
XML-RPC faults.
Catch known XML-RPC faults and translate them to
custom exceptions.
Wait for this player's turn.

!/usr/bin/env python vim: set sts=4 sw=4 et:


Okay.  /

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


{D So, }

(SBARQ (INTJ (UH So)) (, ,) (WHNP-1 (WHNP (WP What) (NN kind)) (PP (IN of) (NP (NP (NN experience)) (PP (-NONE- *ICH*-2))))) (SQ (EDITED (RM (-DFL- \[)) (SQ-UNF (VBP do) (NP-SBJ (PRP you))) (, ,) (IP (-DFL- \+))) (VBP do) (NP-SBJ (PRP you)) (RS (-DFL- \])) (VP (VB have) (NP (-NONE- *T*-1)) (, ,) (ADVP (RB then)) (PP-2 (IN with) (NP (NN child) (NN care))))) (. ?) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


[ [ I guess, +

(S (EDITED (RM (-DFL- \[)) (EDITED (RM (-DFL- \[)) (S (NP-SBJ (PRP I)) (VP-UNF (VBP guess))) (, ,) (IP (-DFL- \+))) (S (NP-SBJ (PRP I)) (VP-UNF (VBP think))) (, ,) (RS (-DFL- \])) (IP (-DFL- \+))) (INTJ (UH uh)) (, ,) (NP-SBJ (PRP I)) (VP (VBP wonder) (RS (-DFL- \])) (SBAR (IN if) (S (NP-SBJ (DT that)) (VP (VBD worked))))) (. .) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


What kind of experience [ do you, + do you ] have, then with child care? /

[ What/WP kind/NN ] of/IN  [ experience/NN ] do/VBP  [ you/PRP ] ,/, do/VBP  [ you/PRP ] have/VB ,/, then/RB with/IN  [ child/NN care/NN ] ?/.

(SBARQ (INTJ (UH So)) (, ,) (WHNP-1 (WHNP (WP What) (NN kind)) (PP (IN of) (NP (NP (NN experience)) (PP (-NONE- *ICH*-2))))) (SQ (EDITED (RM (-DFL- \[)) (SQ-UNF (VBP do) (NP-SBJ (PRP you))) (, ,) (IP (-DFL- \+))) (VBP do) (NP-SBJ (PRP you)) (RS (-DFL- \])) (VP (VB have) (NP (-NONE- *T*-1)) (, ,) (ADVP (RB then)) (PP-2 (IN with) (NP (NN child) (NN care))))) (. ?) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


I think, ] + {F uh, } I wonder ] if that worked. /

[ I/PRP ] think/VBP ,/, uh/UH ,/,  [ I/PRP ] wonder/VBP if/IN that/DT worked/VBD ./.

(S (EDITED (RM (-DFL- \[)) (EDITED (RM (-DFL- \[)) (S (NP-SBJ (PRP I)) (VP-UNF (VBP guess))) (, ,) (IP (-DFL- \+))) (S (NP-SBJ (PRP I)) (VP-UNF (VBP think))) (, ,) (RS (-DFL- \])) (IP (-DFL- \+))) (INTJ (UH uh)) (, ,) (NP-SBJ (PRP I)) (VP (VBP wonder) (RS (-DFL- \])) (SBAR (IN if) (S (NP-SBJ (DT that)) (VP (VBD worked))))) (. .) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


Does it say something? /

Does/VBZ  [ it/PRP ] say/VB  [ something/NN ] ?/.

(SQ (VBZ Does) (NP-SBJ (PRP it)) (VP (VB say) (NP (NN something))) (. ?) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


I think it usually does.  /

[ I/PRP ] think/VBP  [ it/PRP ] usually/RB does/VBZ ./.

(S (NP-SBJ (PRP I)) (VP (VBP think) (SBAR (-NONE- 0) (S (NP-SBJ (PRP it)) (ADVP-TMP (RB usually)) (VP (VBZ does))))) (. .) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


You might try, {F uh, }  /

[ You/PRP ] might/MD try/VB ,/, uh/UH ,/,

(S (NP-SBJ (PRP You)) (VP (MD might) (VP-UNF (VB try) (, ,) (INTJ (UH uh)))) (, ,) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


I don't know,  /

(S (NP-SBJ (PRP I)) (VP (VBP do) (RB n't) (VP (VB know))) (, ,) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


hold it down a little longer,  /

hold/VB  [ it/PRP ] down/RB  [ a/DT little/RB longer/JJR ] ,/,

(S-IMP (NP-SBJ (-NONE- *)) (VP (VB hold) (NP (PRP it)) (PRT (RB down)) (ADVP-TMP (NP (DT a) (RB little)) (JJR longer))) (, ,) (-DFL- E_S))

Prompt: FIND OUT WHAT CRITERIA THE OTHER CALLER WOULD USE IN SELECTING CHILD CARE SERVICES FOR A PRESCHOOLER.  IS IT EASY OR DIFFICULT TO FIND SUCH CARE?


PIECE_START STYLE=JSFAKES GENRE=JSFAKES TRACK_START INST=0 BAR_START NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=77 TIME_DELTA=4 NOTE_OFF=77 NOTE_ON=74 TIME_DELTA=4 NOTE_OFF=74 NOTE_ON=72 TIME_DELTA=2 NOTE_OFF=72 NOTE_ON=74 TIME_DELTA=2 NOTE_OFF=74 BAR_END BAR_START NOTE_ON=75 TIME_DELTA=4 NOTE_OFF=75 NOTE_ON=72 TIME_DELTA=8 NOTE_OFF=72 NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 BAR_END BAR_START NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 NOTE_ON=69 TIME_DELTA=4 NOTE_OFF=69 BAR_END BAR_START NOTE_ON=70 TIME_DELTA=2 NOTE_OFF=70 NOTE_ON=69 TIME_DELTA=2 NOTE_OFF=69 NOTE_ON=67 TIME_DELTA=8 NOTE_OFF=67 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END TRACK_END TRACK_START INST=32 BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=53 TIME_DELTA=4 NOTE_OFF=53 BAR_END BAR_START NOTE_ON=51 TIME_DELTA=4 NOTE_OFF=51 NOTE_ON=53 TIME_DELTA=8 NOTE_OFF=53 NOTE_ON=46 TIME_DELTA=4 NOTE_OFF=46 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 NOTE_ON=55 TIME_DELTA=4 NOTE_OFF=55 NOTE_ON=53 TIME_DELTA=2 NOTE_OFF=53 NOTE_ON=51 TIME_DELTA=2 NOTE_OFF=51 BAR_END BAR_START NOTE_ON=50 TIME_DELTA=2 NOTE_OFF=50 NOTE_ON=48 TIME_DELTA=2 NOTE_OFF=48 NOTE_ON=46 TIME_DELTA=4 NOTE_OFF=46 NOTE_ON=48 TIME_DELTA=4 NOTE_OFF=48 NOTE_ON=41 TIME_DELTA=4 NOTE_OFF=41 BAR_END TRACK_END TRACK_START INST=48 BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 NOTE_ON=65 TIME_DELTA=8 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=62 TIME_DELTA=2 NOTE_OFF=62 NOTE_ON=64 TIME_DELTA=2 NOTE_OFF=64 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=64 TIME_DELTA=4 NOTE_OFF=64 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 BAR_END TRACK_END TRACK_START INST=24 BAR_START NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 BAR_END BAR_START NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=2 NOTE_OFF=58 NOTE_ON=60 TIME_DELTA=2 NOTE_OFF=60 NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=60 TIME_DELTA=2 NOTE_OFF=60 NOTE_ON=58 TIME_DELTA=2 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 BAR_END TRACK_END PIECE_END


PIECE_START STYLE=JSFAKES GENRE=JSFAKES TRACK_START INST=32 BAR_START NOTE_ON=51 TIME_DELTA=4 NOTE_OFF=51 NOTE_ON=53 TIME_DELTA=8 NOTE_OFF=53 NOTE_ON=46 TIME_DELTA=4 NOTE_OFF=46 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 NOTE_ON=55 TIME_DELTA=4 NOTE_OFF=55 NOTE_ON=53 TIME_DELTA=2 NOTE_OFF=53 NOTE_ON=51 TIME_DELTA=2 NOTE_OFF=51 BAR_END BAR_START NOTE_ON=50 TIME_DELTA=2 NOTE_OFF=50 NOTE_ON=48 TIME_DELTA=2 NOTE_OFF=48 NOTE_ON=46 TIME_DELTA=4 NOTE_OFF=46 NOTE_ON=48 TIME_DELTA=4 NOTE_OFF=48 NOTE_ON=41 TIME_DELTA=4 NOTE_OFF=41 BAR_END BAR_START NOTE_ON=50 TIME_DELTA=4 NOTE_OFF=50 NOTE_ON=51 TIME_DELTA=4 NOTE_OFF=51 NOTE_ON=46 TIME_DELTA=4 NOTE_OFF=46 NOTE_ON=51 TIME_DELTA=4 NOTE_OFF=51 BAR_END TRACK_END TRACK_START INST=0 BAR_START NOTE_ON=75 TIME_DELTA=4 NOTE_OFF=75 NOTE_ON=72 TIME_DELTA=8 NOTE_OFF=72 NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 BAR_END BAR_START NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 NOTE_ON=69 TIME_DELTA=4 NOTE_OFF=69 BAR_END BAR_START NOTE_ON=70 TIME_DELTA=2 NOTE_OFF=70 NOTE_ON=69 TIME_DELTA=2 NOTE_OFF=69 NOTE_ON=67 TIME_DELTA=8 NOTE_OFF=67 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 NOTE_ON=70 TIME_DELTA=4 NOTE_OFF=70 BAR_END TRACK_END TRACK_START INST=24 BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 BAR_END BAR_START NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=2 NOTE_OFF=58 NOTE_ON=60 TIME_DELTA=2 NOTE_OFF=60 NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=60 TIME_DELTA=2 NOTE_OFF=60 NOTE_ON=58 TIME_DELTA=2 NOTE_OFF=58 NOTE_ON=57 TIME_DELTA=4 NOTE_OFF=57 BAR_END BAR_START NOTE_ON=58 TIME_DELTA=4 NOTE_OFF=58 NOTE_ON=58 TIME_DELTA=2 NOTE_OFF=58 NOTE_ON=60 TIME_DELTA=2 NOTE_OFF=60 NOTE_ON=62 TIME_DELTA=4 NOTE_OFF=62 NOTE_ON=63 TIME_DELTA=2 NOTE_OFF=63 NOTE_ON=62 TIME_DELTA=2 NOTE_OFF=62 BAR_END TRACK_END TRACK_START INST=48 BAR_START NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 NOTE_ON=65 TIME_DELTA=8 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=62 TIME_DELTA=2 NOTE_OFF=62 NOTE_ON=64 TIME_DELTA=2 NOTE_OFF=64 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 BAR_END BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=64 TIME_DELTA=4 NOTE_OFF=64 NOTE_ON=60 TIME_DELTA=4 NOTE_OFF=60 BAR_END BAR_START NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 NOTE_ON=65 TIME_DELTA=4 NOTE_OFF=65 NOTE_ON=67 TIME_DELTA=4 NOTE_OFF=67 BAR_END TRACK_END PIECE_END