Skip to content

Commit

Permalink
chore: update for pyteal 0.21.0 and py-sdk 2.0.0 (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
barnjamin authored Jan 20, 2023
1 parent 7ee6589 commit ee0cef3
Show file tree
Hide file tree
Showing 60 changed files with 1,654 additions and 1,645 deletions.
11 changes: 9 additions & 2 deletions beaker/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,16 @@ class Application:
address: Final[Expr] = Global.current_application_address()
id: Final[Expr] = Global.current_application_id()

def __init__(self, version: int = MAX_TEAL_VERSION):
def __init__(
self,
version: int = MAX_TEAL_VERSION,
optimize_options: OptimizeOptions = OptimizeOptions(
scratch_slots=True, frame_pointers=True
),
):
"""Initialize the Application, finding all the custom attributes and initializing the Router"""
self.teal_version = version
self.optimize_options = optimize_options

# Get initial list of all attrs declared
initial_attrs = {
Expand Down Expand Up @@ -280,7 +287,7 @@ def compile(self, client: Optional[AlgodClient] = None) -> tuple[str, str]:
) = self.router.compile_program(
version=self.teal_version,
assemble_constants=True,
optimize=OptimizeOptions(scratch_slots=True),
optimize=self.optimize_options,
)

return self.approval_program, self.clear_program
Expand Down
4 changes: 3 additions & 1 deletion beaker/client/api_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ class PureStake(APIProvider):
def algod(self, token: str = "") -> AlgodClient:
algod_client = super().algod()
algod_client.headers = {self.token_header: token}
return algod_client

def indexer(self, token: str = "") -> IndexerClient:
indexer_client = super().algod()
indexer_client = super().indexer()
indexer_client.headers = {self.token_header: token}
return indexer_client


class Sandbox(APIProvider):
Expand Down
22 changes: 16 additions & 6 deletions beaker/client/application_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from base64 import b64decode
import copy
from typing import Any, cast
from typing import Any, cast, Optional

from algosdk.account import address_from_private_key
from algosdk.atomic_transaction_composer import (
Expand All @@ -15,7 +15,7 @@
abi,
AtomicTransactionResponse,
)
from algosdk.future import transaction
from algosdk import transaction
from algosdk.logic import get_application_address
from algosdk.source_map import SourceMap
from algosdk.v2client.algod import AlgodClient
Expand Down Expand Up @@ -67,7 +67,7 @@ def __init__(

def compile(
self, teal: str, source_map: bool = False
) -> tuple[bytes, str, SourceMap]:
) -> tuple[bytes, str, Optional[SourceMap]]:
result = self.client.compile(teal, source_map=source_map)
src_map = None
if source_map:
Expand Down Expand Up @@ -418,7 +418,7 @@ def call(
self,
method: abi.Method | HandlerFunc,
sender: str | None = None,
signer: TransactionSigner = None,
signer: TransactionSigner | None = None,
suggested_params: transaction.SuggestedParams | None = None,
on_complete: transaction.OnComplete = transaction.OnComplete.NoOpOC,
local_schema: transaction.StateSchema | None = None,
Expand Down Expand Up @@ -468,6 +468,8 @@ def call(
boxes=boxes,
**kwargs,
)
if atc is None:
raise Exception("ATC none?")

# If its a read-only method, use dryrun (TODO: swap with simulate later?)
if hints.read_only:
Expand All @@ -492,7 +494,7 @@ def _parse_result(
method_results = []
for i, tx_info in enumerate(txns):

raw_value = None
raw_value = b""
return_value = None
decode_error = None

Expand Down Expand Up @@ -527,7 +529,12 @@ def _parse_result(
raise Exception("no logs")

raw_value = result_bytes[4:]
return_value = methods[i].returns.type.decode(raw_value)
abi_return_type = methods[i].returns.type
if isinstance(abi_return_type, abi.ABIType):
return_value = abi_return_type.decode(raw_value)
else:
return_value = raw_value

except Exception as e:
decode_error = e

Expand Down Expand Up @@ -633,6 +640,9 @@ def add_method_call(
def add_transaction(
self, atc: AtomicTransactionComposer, txn: transaction.Transaction
) -> AtomicTransactionComposer:
if self.signer is None:
raise Exception("No signer available")

atc.add_transaction(TransactionWithSigner(txn=txn, signer=self.signer))
return atc

Expand Down
3 changes: 2 additions & 1 deletion beaker/client/logic_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def __init__(
self.lines = program.split("\n")

self.txid, self.msg, self.pc = txid, msg, pc
self.line_no = self.map.get_line_for_pc(self.pc)
line = self.map.get_line_for_pc(self.pc)
self.line_no = line if line is not None else 0

def __str__(self) -> str:
return f"Txn {self.txid} had error '{self.msg}' at PC {self.pc} and Source Line {self.line_no}: \n\n\t{self.trace()}"
Expand Down
47 changes: 18 additions & 29 deletions beaker/lib/math/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
BytesMinus,
BytesMul,
Btoi,
Concat,
Exp,
Expr,
ExtractUint64,
Expand All @@ -17,8 +16,6 @@
Len,
Not,
Return,
ScratchSlot,
Seq,
Subroutine,
TealType,
)
Expand Down Expand Up @@ -163,7 +160,21 @@ def wide_power(x, n):
bytes representing the high and low bytes of a wide power evaluation
"""
return Seq(InlineAssembly("expw", x, n), stack_to_wide())
return InlineAssembly(
"expw; itob; swap; itob; swap; concat", x, n, type=TealType.bytes
)


@Subroutine(TealType.bytes)
def exponential_impl(x, f, n, _scale):
return If(
n == Int(1),
BytesAdd(_scale, BytesMul(x, _scale)),
BytesAdd(
exponential_impl(x, BytesDiv(f, Itob(n)), n - Int(1), _scale),
BytesDiv(BytesMul(_scale, wide_power(bytes_to_int(x), n)), f),
),
)


def exponential(x, n):
Expand All @@ -180,19 +191,9 @@ def exponential(x, n):
"""
_scale = Itob(Int(1000))

@Subroutine(TealType.bytes)
def _impl(x, f, n):
return If(
n == Int(1),
BytesAdd(_scale, BytesMul(x, _scale)),
BytesAdd(
_impl(x, BytesDiv(f, Itob(n)), n - Int(1)),
BytesDiv(BytesMul(_scale, wide_power(bytes_to_int(x), n)), f),
),
)

return bytes_to_int(BytesDiv(_impl(Itob(x), wide_factorial(Itob(n)), n), _scale))
return bytes_to_int(
BytesDiv(exponential_impl(Itob(x), wide_factorial(Itob(n)), n, _scale), _scale)
)


# @Subroutine(TealType.uint64)
Expand Down Expand Up @@ -243,15 +244,3 @@ def _impl(x, f, n):
@Subroutine(TealType.uint64)
def bytes_to_int(x):
return If(Len(x) < Int(8), Btoi(x), ExtractUint64(x, Len(x) - Int(8)))


@Subroutine(TealType.bytes)
def stack_to_wide():
"""stack_to_wide returns the combination of the high and low integers returned from a wide math operation as bytes"""
h = ScratchSlot()
l = ScratchSlot()
return Seq(
l.store(),
h.store(), # Take the low and high ints off the stack and combine them
Concat(Itob(h.load()), Itob(l.load())),
)
23 changes: 14 additions & 9 deletions beaker/precompile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
Len,
Substring,
Suffix,
Subroutine,
Sha512_256,
TxnField,
TxnType,
)
from algosdk.v2client.algod import AlgodClient
from algosdk.source_map import SourceMap
from algosdk.future.transaction import LogicSigAccount
from algosdk.transaction import LogicSigAccount
from algosdk.constants import APP_PAGE_MAX_SIZE
from algosdk.atomic_transaction_composer import LogicSigTransactionSigner
from beaker.consts import PROGRAM_DOMAIN_SEPARATOR, num_extra_program_pages
Expand Down Expand Up @@ -127,7 +126,11 @@ def assemble(self, client: AlgodClient) -> None:
self.binary = Bytes(self._binary)
for tv in self._template_values:
# +1 to acount for the pushbytes/pushint op
tv.pc = self._map.get_pcs_for_line(tv.line)[0] + 1
pcs = self._map.get_pcs_for_line(tv.line)
if pcs is None:
tv.pc = 0
else:
tv.pc = pcs[0] + 1

def _hash_program(data: bytes) -> bytes:
"""compute the hash"""
Expand Down Expand Up @@ -261,11 +264,7 @@ def populate_template_expr(self, *args: Expr) -> Expr:
buff.load(),
]

@Subroutine(TealType.bytes)
def populate_template_program() -> Expr:
return Seq(*populate_program)

return populate_template_program()
return Seq(*populate_program)

def template_hash(self, *args) -> Expr: # type: ignore
"""
Expand Down Expand Up @@ -380,6 +379,8 @@ def signer(self) -> LogicSigTransactionSigner:
It should only be used for non templated Precompiles.
"""
if self.logic._binary is None:
raise Exception("Cannot get signer until the program is compiled")
return LogicSigTransactionSigner(LogicSigAccount(self.logic._binary))


Expand All @@ -399,7 +400,11 @@ def _gather_asserts(program: str, src_map: SourceMap) -> dict[int, ProgramAssert
if line != "assert":
continue

pc = src_map.get_pcs_for_line(idx)[0]
pcs = src_map.get_pcs_for_line(idx)
if pcs is None:
pc = 0
else:
pc = pcs[0]

# TODO: this will be wrong for multiline comments
line_before = program_lines[idx - 1]
Expand Down
2 changes: 1 addition & 1 deletion beaker/state.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import abstractmethod, ABC
from copy import copy
from typing import Callable, Mapping, cast, Any, Optional
from algosdk.future.transaction import StateSchema
from algosdk.transaction import StateSchema
from pyteal import (
abi,
SubroutineFnWrapper,
Expand Down
2 changes: 1 addition & 1 deletion beaker/testing/unit_testing_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from beaker import client, sandbox
from beaker import Application, external, delete, update, opt_in, close_out

algod_client: AlgodClient = None
algod_client: AlgodClient | None = None
sandbox_accounts: list[sandbox.SandboxAccount] | None = None


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"hints": {},
"source": {
"approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDEyNyAwIDEgOCAxMjggMjU1CmJ5dGVjYmxvY2sgMHggMHgwNjgwMDAzNTAwODEwMTQzIDB4MDAwMTAyMDMwNDA1MDYwNzA4MDkwYTBiMGMwZDBlMGYKdHhuIE51bUFwcEFyZ3MKaW50Y18xIC8vIDAKPT0KYm56IG1haW5fbDYKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHg3NmUzYzZkYyAvLyAiYWRkX2FjY291bnQoYnl0ZVtdKXZvaWQiCj09CmJueiBtYWluX2w1CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4MTliMTRmZGEgLy8gImZsaXBfYml0KGFjY291bnQsdWludDMyKXZvaWQiCj09CmJueiBtYWluX2w0CmVycgptYWluX2w0Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMSAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMSAvLyAwCiE9CiYmCmFzc2VydAp0eG5hIEFwcGxpY2F0aW9uQXJncyAxCmludGNfMSAvLyAwCmdldGJ5dGUKc3RvcmUgMAp0eG5hIEFwcGxpY2F0aW9uQXJncyAyCmludGNfMSAvLyAwCmV4dHJhY3RfdWludDMyCnN0b3JlIDEKbG9hZCAwCmxvYWQgMQpjYWxsc3ViIGZsaXBiaXRfMgppbnRjXzIgLy8gMQpyZXR1cm4KbWFpbl9sNToKdHhuIE9uQ29tcGxldGlvbgppbnRjXzIgLy8gT3B0SW4KPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18xIC8vIDAKIT0KJiYKYXNzZXJ0CnR4bmEgQXBwbGljYXRpb25BcmdzIDEKY2FsbHN1YiBhZGRhY2NvdW50XzEKaW50Y18yIC8vIDEKcmV0dXJuCm1haW5fbDY6CnR4biBPbkNvbXBsZXRpb24KaW50Y18xIC8vIE5vT3AKPT0KYm56IG1haW5fbDgKZXJyCm1haW5fbDg6CnR4biBBcHBsaWNhdGlvbklECmludGNfMSAvLyAwCj09CmFzc2VydApjYWxsc3ViIGNyZWF0ZV8wCmludGNfMiAvLyAxCnJldHVybgoKLy8gY3JlYXRlCmNyZWF0ZV8wOgppbnRjXzIgLy8gMQpyZXR1cm4KCi8vIGFkZF9hY2NvdW50CmFkZGFjY291bnRfMToKc3RvcmUgMgp0eG4gU2VuZGVyCnB1c2hieXRlcyAweDUwNzI2ZjY3NzI2MTZkIC8vICJQcm9ncmFtIgpjYWxsc3ViIHBvcHVsYXRldGVtcGxhdGVwcm9ncmFtXzQKY29uY2F0CnNoYTUxMl8yNTYKPT0KYXNzZXJ0CnR4biBSZWtleVRvCmdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCj09CmFzc2VydAp0eG4gU2VuZGVyCmNhbGxzdWIgaW1wbF81CnJldHN1YgoKLy8gZmxpcF9iaXQKZmxpcGJpdF8yOgpzdG9yZSAxMQpzdG9yZSAxMApsb2FkIDEwCnR4bmFzIEFjY291bnRzCmxvYWQgMTEKaW50Y18zIC8vIDgKLwpjYWxsc3ViIGltcGxfNgpzdG9yZSAxMgpsb2FkIDEyCmxvYWQgMTEKaW50Y18zIC8vIDgKJQpsb2FkIDEyCmxvYWQgMTEKaW50Y18zIC8vIDgKJQpnZXRiaXQKIQpzZXRiaXQKc3RvcmUgMTIKbG9hZCAxMAp0eG5hcyBBY2NvdW50cwpsb2FkIDExCmludGNfMyAvLyA4Ci8KbG9hZCAxMgpjYWxsc3ViIGltcGxfNwpyZXRzdWIKCi8vIGVuY29kZV91dmFyaW50X2ltcGwKZW5jb2RldXZhcmludGltcGxfMzoKc3RvcmUgOApzdG9yZSA3CmxvYWQgOApsb2FkIDcKaW50YyA0IC8vIDEyOAo+PQpibnogZW5jb2RldXZhcmludGltcGxfM19sMgpsb2FkIDcKaW50YyA1IC8vIDI1NQomCml0b2IKZXh0cmFjdCA3IDEKYiBlbmNvZGV1dmFyaW50aW1wbF8zX2wzCmVuY29kZXV2YXJpbnRpbXBsXzNfbDI6CmxvYWQgNwpwdXNoaW50IDcgLy8gNwpzaHIKbG9hZCA3CmludGMgNSAvLyAyNTUKJgppbnRjIDQgLy8gMTI4CnwKaXRvYgpleHRyYWN0IDcgMQpsb2FkIDcKbG9hZCA4CnVuY292ZXIgMwp1bmNvdmVyIDMKY2FsbHN1YiBlbmNvZGV1dmFyaW50aW1wbF8zCmNvdmVyIDIKc3RvcmUgOApzdG9yZSA3CmVuY29kZXV2YXJpbnRpbXBsXzNfbDM6CmNvbmNhdApyZXRzdWIKCi8vIHBvcHVsYXRlX3RlbXBsYXRlX3Byb2dyYW0KcG9wdWxhdGV0ZW1wbGF0ZXByb2dyYW1fNDoKaW50Y18xIC8vIDAKc3RvcmUgMwppbnRjXzEgLy8gMApzdG9yZSA0CmJ5dGVjXzAgLy8gIiIKc3RvcmUgNQpieXRlY18wIC8vICIiCnN0b3JlIDYKbG9hZCAyCmV4dHJhY3QgMiAwCmxlbgpieXRlY18wIC8vICIiCmNhbGxzdWIgZW5jb2RldXZhcmludGltcGxfMwpsb2FkIDIKZXh0cmFjdCAyIDAKY29uY2F0CnN0b3JlIDUKbG9hZCA2CmJ5dGVjXzEgLy8gMHgwNjgwMDAzNTAwODEwMTQzCmxvYWQgMwpwdXNoaW50IDIgLy8gMgpzdWJzdHJpbmczCmNvbmNhdApsb2FkIDUKY29uY2F0CnN0b3JlIDYKbG9hZCA0CmxvYWQgNQpsZW4KKwppbnRjXzIgLy8gMQotCnN0b3JlIDQKcHVzaGludCAyIC8vIDIKaW50Y18yIC8vIDEKKwpzdG9yZSAzCmxvYWQgNgpieXRlY18xIC8vIDB4MDY4MDAwMzUwMDgxMDE0Mwpsb2FkIDMKZGlnIDEKbGVuCnN1YnN0cmluZzMKY29uY2F0CnN0b3JlIDYKbG9hZCA2CnJldHN1YgoKLy8gX2ltcGwKaW1wbF81OgpzdG9yZSA5CmxvYWQgOQpwdXNoYnl0ZXMgMHgwMCAvLyAweDAwCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApsb2FkIDkKcHVzaGJ5dGVzIDB4MDEgLy8gMHgwMQppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKbG9hZCA5CnB1c2hieXRlcyAweDAyIC8vIDB4MDIKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmxvYWQgOQpwdXNoYnl0ZXMgMHgwMyAvLyAweDAzCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApsb2FkIDkKcHVzaGJ5dGVzIDB4MDQgLy8gMHgwNAppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKbG9hZCA5CnB1c2hieXRlcyAweDA1IC8vIDB4MDUKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmxvYWQgOQpwdXNoYnl0ZXMgMHgwNiAvLyAweDA2CmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApsb2FkIDkKcHVzaGJ5dGVzIDB4MDcgLy8gMHgwNwppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKbG9hZCA5CnB1c2hieXRlcyAweDA4IC8vIDB4MDgKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmxvYWQgOQpwdXNoYnl0ZXMgMHgwOSAvLyAweDA5CmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApsb2FkIDkKcHVzaGJ5dGVzIDB4MGEgLy8gMHgwYQppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKbG9hZCA5CnB1c2hieXRlcyAweDBiIC8vIDB4MGIKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmxvYWQgOQpwdXNoYnl0ZXMgMHgwYyAvLyAweDBjCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApsb2FkIDkKcHVzaGJ5dGVzIDB4MGQgLy8gMHgwZAppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKbG9hZCA5CnB1c2hieXRlcyAweDBlIC8vIDB4MGUKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmxvYWQgOQpwdXNoYnl0ZXMgMHgwZiAvLyAweDBmCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApyZXRzdWIKCi8vIF9pbXBsCmltcGxfNjoKc3RvcmUgMTMKYnl0ZWNfMiAvLyAweDAwMDEwMjAzMDQwNTA2MDcwODA5MGEwYjBjMGQwZTBmCmxvYWQgMTMKaW50Y18wIC8vIDEyNwovCmludGNfMiAvLyAxCmV4dHJhY3QzCmFwcF9sb2NhbF9nZXQKbG9hZCAxMwppbnRjXzAgLy8gMTI3CiUKZ2V0Ynl0ZQpyZXRzdWIKCi8vIF9pbXBsCmltcGxfNzoKc3RvcmUgMTYKc3RvcmUgMTUKc3RvcmUgMTQKYnl0ZWNfMiAvLyAweDAwMDEwMjAzMDQwNTA2MDcwODA5MGEwYjBjMGQwZTBmCmxvYWQgMTUKaW50Y18wIC8vIDEyNwovCmludGNfMiAvLyAxCmV4dHJhY3QzCnN0b3JlIDE3CmxvYWQgMTQKbG9hZCAxNwpsb2FkIDE0CmxvYWQgMTcKYXBwX2xvY2FsX2dldApsb2FkIDE1CmludGNfMCAvLyAxMjcKJQpsb2FkIDE2CnNldGJ5dGUKYXBwX2xvY2FsX3B1dApyZXRzdWI=",
"approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDEyNyAwIDEgOCAxMjggMjU1CmJ5dGVjYmxvY2sgMHggMHgwODgwMDAzNTAwODEwMTQzIDB4MDAwMTAyMDMwNDA1MDYwNzA4MDkwYTBiMGMwZDBlMGYKdHhuIE51bUFwcEFyZ3MKaW50Y18xIC8vIDAKPT0KYm56IG1haW5fbDYKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHg3NmUzYzZkYyAvLyAiYWRkX2FjY291bnQoYnl0ZVtdKXZvaWQiCj09CmJueiBtYWluX2w1CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4MTliMTRmZGEgLy8gImZsaXBfYml0KGFjY291bnQsdWludDMyKXZvaWQiCj09CmJueiBtYWluX2w0CmVycgptYWluX2w0Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMSAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMSAvLyAwCiE9CiYmCmFzc2VydAp0eG5hIEFwcGxpY2F0aW9uQXJncyAxCmludGNfMSAvLyAwCmdldGJ5dGUKc3RvcmUgMAp0eG5hIEFwcGxpY2F0aW9uQXJncyAyCmludGNfMSAvLyAwCmV4dHJhY3RfdWludDMyCnN0b3JlIDEKbG9hZCAwCmxvYWQgMQpjYWxsc3ViIGZsaXBiaXRfMgppbnRjXzIgLy8gMQpyZXR1cm4KbWFpbl9sNToKdHhuIE9uQ29tcGxldGlvbgppbnRjXzIgLy8gT3B0SW4KPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18xIC8vIDAKIT0KJiYKYXNzZXJ0CnR4bmEgQXBwbGljYXRpb25BcmdzIDEKY2FsbHN1YiBhZGRhY2NvdW50XzEKaW50Y18yIC8vIDEKcmV0dXJuCm1haW5fbDY6CnR4biBPbkNvbXBsZXRpb24KaW50Y18xIC8vIE5vT3AKPT0KYm56IG1haW5fbDgKZXJyCm1haW5fbDg6CnR4biBBcHBsaWNhdGlvbklECmludGNfMSAvLyAwCj09CmFzc2VydApjYWxsc3ViIGNyZWF0ZV8wCmludGNfMiAvLyAxCnJldHVybgoKLy8gY3JlYXRlCmNyZWF0ZV8wOgpwcm90byAwIDAKaW50Y18yIC8vIDEKcmV0dXJuCgovLyBhZGRfYWNjb3VudAphZGRhY2NvdW50XzE6CnByb3RvIDEgMAp0eG4gU2VuZGVyCnB1c2hieXRlcyAweDUwNzI2ZjY3NzI2MTZkIC8vICJQcm9ncmFtIgppbnRjXzEgLy8gMApzdG9yZSAyCmludGNfMSAvLyAwCnN0b3JlIDMKYnl0ZWNfMCAvLyAiIgpzdG9yZSA0CmJ5dGVjXzAgLy8gIiIKc3RvcmUgNQpmcmFtZV9kaWcgLTEKZXh0cmFjdCAyIDAKbGVuCmJ5dGVjXzAgLy8gIiIKY2FsbHN1YiBlbmNvZGV1dmFyaW50aW1wbF8zCmZyYW1lX2RpZyAtMQpleHRyYWN0IDIgMApjb25jYXQKc3RvcmUgNApsb2FkIDUKYnl0ZWNfMSAvLyAweDA4ODAwMDM1MDA4MTAxNDMKbG9hZCAyCnB1c2hpbnQgMiAvLyAyCnN1YnN0cmluZzMKY29uY2F0CmxvYWQgNApjb25jYXQKc3RvcmUgNQpsb2FkIDMKbG9hZCA0CmxlbgorCmludGNfMiAvLyAxCi0Kc3RvcmUgMwpwdXNoaW50IDIgLy8gMgppbnRjXzIgLy8gMQorCnN0b3JlIDIKbG9hZCA1CmJ5dGVjXzEgLy8gMHgwODgwMDAzNTAwODEwMTQzCmxvYWQgMgpkaWcgMQpsZW4Kc3Vic3RyaW5nMwpjb25jYXQKc3RvcmUgNQpsb2FkIDUKY29uY2F0CnNoYTUxMl8yNTYKPT0KYXNzZXJ0CnR4biBSZWtleVRvCmdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCj09CmFzc2VydAp0eG4gU2VuZGVyCmNhbGxzdWIgaW1wbF80CnJldHN1YgoKLy8gZmxpcF9iaXQKZmxpcGJpdF8yOgpwcm90byAyIDAKZnJhbWVfZGlnIC0yCnR4bmFzIEFjY291bnRzCmZyYW1lX2RpZyAtMQppbnRjXzMgLy8gOAovCmNhbGxzdWIgaW1wbF81CnN0b3JlIDYKbG9hZCA2CmZyYW1lX2RpZyAtMQppbnRjXzMgLy8gOAolCmxvYWQgNgpmcmFtZV9kaWcgLTEKaW50Y18zIC8vIDgKJQpnZXRiaXQKIQpzZXRiaXQKc3RvcmUgNgpmcmFtZV9kaWcgLTIKdHhuYXMgQWNjb3VudHMKZnJhbWVfZGlnIC0xCmludGNfMyAvLyA4Ci8KbG9hZCA2CmNhbGxzdWIgaW1wbF82CnJldHN1YgoKLy8gZW5jb2RlX3V2YXJpbnRfaW1wbAplbmNvZGV1dmFyaW50aW1wbF8zOgpwcm90byAyIDEKZnJhbWVfZGlnIC0xCmZyYW1lX2RpZyAtMgppbnRjIDQgLy8gMTI4Cj49CmJueiBlbmNvZGV1dmFyaW50aW1wbF8zX2wyCmZyYW1lX2RpZyAtMgppbnRjIDUgLy8gMjU1CiYKaXRvYgpleHRyYWN0IDcgMQpiIGVuY29kZXV2YXJpbnRpbXBsXzNfbDMKZW5jb2RldXZhcmludGltcGxfM19sMjoKZnJhbWVfZGlnIC0yCnB1c2hpbnQgNyAvLyA3CnNocgpmcmFtZV9kaWcgLTIKaW50YyA1IC8vIDI1NQomCmludGMgNCAvLyAxMjgKfAppdG9iCmV4dHJhY3QgNyAxCmNhbGxzdWIgZW5jb2RldXZhcmludGltcGxfMwplbmNvZGV1dmFyaW50aW1wbF8zX2wzOgpjb25jYXQKcmV0c3ViCgovLyBfaW1wbAppbXBsXzQ6CnByb3RvIDEgMApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MDAgLy8gMHgwMAppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKZnJhbWVfZGlnIC0xCnB1c2hieXRlcyAweDAxIC8vIDB4MDEKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmZyYW1lX2RpZyAtMQpwdXNoYnl0ZXMgMHgwMiAvLyAweDAyCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MDMgLy8gMHgwMwppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKZnJhbWVfZGlnIC0xCnB1c2hieXRlcyAweDA0IC8vIDB4MDQKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmZyYW1lX2RpZyAtMQpwdXNoYnl0ZXMgMHgwNSAvLyAweDA1CmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MDYgLy8gMHgwNgppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKZnJhbWVfZGlnIC0xCnB1c2hieXRlcyAweDA3IC8vIDB4MDcKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmZyYW1lX2RpZyAtMQpwdXNoYnl0ZXMgMHgwOCAvLyAweDA4CmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MDkgLy8gMHgwOQppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKZnJhbWVfZGlnIC0xCnB1c2hieXRlcyAweDBhIC8vIDB4MGEKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmZyYW1lX2RpZyAtMQpwdXNoYnl0ZXMgMHgwYiAvLyAweDBiCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MGMgLy8gMHgwYwppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKZnJhbWVfZGlnIC0xCnB1c2hieXRlcyAweDBkIC8vIDB4MGQKaW50Y18wIC8vIDEyNwpiemVybwphcHBfbG9jYWxfcHV0CmZyYW1lX2RpZyAtMQpwdXNoYnl0ZXMgMHgwZSAvLyAweDBlCmludGNfMCAvLyAxMjcKYnplcm8KYXBwX2xvY2FsX3B1dApmcmFtZV9kaWcgLTEKcHVzaGJ5dGVzIDB4MGYgLy8gMHgwZgppbnRjXzAgLy8gMTI3CmJ6ZXJvCmFwcF9sb2NhbF9wdXQKcmV0c3ViCgovLyBfaW1wbAppbXBsXzU6CnByb3RvIDIgMQpmcmFtZV9kaWcgLTIKYnl0ZWNfMiAvLyAweDAwMDEwMjAzMDQwNTA2MDcwODA5MGEwYjBjMGQwZTBmCmZyYW1lX2RpZyAtMQppbnRjXzAgLy8gMTI3Ci8KaW50Y18yIC8vIDEKZXh0cmFjdDMKYXBwX2xvY2FsX2dldApmcmFtZV9kaWcgLTEKaW50Y18wIC8vIDEyNwolCmdldGJ5dGUKcmV0c3ViCgovLyBfaW1wbAppbXBsXzY6CnByb3RvIDMgMApieXRlY18yIC8vIDB4MDAwMTAyMDMwNDA1MDYwNzA4MDkwYTBiMGMwZDBlMGYKZnJhbWVfZGlnIC0yCmludGNfMCAvLyAxMjcKLwppbnRjXzIgLy8gMQpleHRyYWN0MwpzdG9yZSA3CmZyYW1lX2RpZyAtMwpsb2FkIDcKZnJhbWVfZGlnIC0zCmxvYWQgNwphcHBfbG9jYWxfZ2V0CmZyYW1lX2RpZyAtMgppbnRjXzAgLy8gMTI3CiUKZnJhbWVfZGlnIC0xCnNldGJ5dGUKYXBwX2xvY2FsX3B1dApyZXRzdWI=",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDgKcHVzaGludCAwIC8vIDAKcmV0dXJu"
},
"schema": {
Expand Down
Loading

0 comments on commit ee0cef3

Please sign in to comment.