[
  {
    "path": ".gitignore",
    "content": "pset0?/pset0?\n"
  },
  {
    "path": "README.md",
    "content": "# MAS.S62 Spring 2018\n# Cryptocurrency Engineering and Design\n\n### NOTE:  This document is a draft and is subject to change.\n\n## Information\n\nInstructors:  Tadge Dryja ([tdryja@media.mit.edu](tdryja@media.mit.edu)) and Neha Narula ([narula@media.mit.edu](narula@media.mit.edu))\n\nTime:  MW 10-11:30 AM \n\nPlace:  E14-341\n\nContact: [cryptocurrency-sp18-staff@mit.edu](cryptocurrency-sp18-staff@mit.edu)\n\nYou are welcome to contact us via email.  However, if you think your\nquestion would be useful for others to see, please file it as [an issue](https://github.com/mit-dci/mas.s62/issues)\nin this repository!\n\nDescription:\n\nBitcoin and other cryptographic currencies have gained attention over\nthe years as the systems continue to evolve.  This course looks at the\ndesign of Bitcoin and other cryptocurrencies and how they function in\npractice, focusing on cryptography, game theory, and network\narchitecture.  Future developments in smart contracts and privacy will\nbe covered as well.  Programming assignments in the course will give\npractical experience interacting with these currencies, so some\nprogramming experience is required.\n\nOffice hours: 4-6 PM Tuesdays\n\nOffice hours location:  The big table outside E15-357\n\n### Office hours 2018-05-08 are in Koch Cafe -- all spaces in the Media Lab building are taken by the event this day.\n\nTA: James Lovejoy [jlovejoy@mit.edu](jlovejoy@mit.edu)\n\n## Schedule\n\nNOTE:  The schedule is in flux and subject to change.\n\n\n| # | Date | Lecturer | Topic | Readings | Lecture Notes | Labs |\n|---|------|----------|-------|----------|---------------|-|\n| 1 | 2018-02-07 | Neha and Tadge | Introduction. Signatures, hashing, hash chains, e-cash, and motivation | [Untraceable Electronic Cash](http://www.wisdom.weizmann.ac.il/~/naor/PAPERS/untrace.pdf) | [tadge's slides](https://github.com/mit-dci/mas.s62/tree/master/slides/lec01-tadge.pdf), [neha's slides](https://github.com/mit-dci/mas.s62/tree/master/slides/lec01-neha.ppt) |  |\n| 2 | 2018-02-12 | Neha and Tadge | Proof of Work and Mining | [Bitcoin](http://www.bitcoin.org/bitcoin.pdf) | [tadge's slides](https://github.com/mit-dci/mas.s62/tree/master/slides/lec02-tadge.pdf) | |\n| 3 | 2018-02-14 | Tadge | Signatures | [Simple Schnorr Multi-Signatures with Applications to Bitcoin](https://eprint.iacr.org/2018/068.pdf) | [tadge's slides](https://github.com/mit-dci/mas.s62/tree/master/slides/lec03-tadge.pdf) | LAB 1 DUE |\n| 4 | 2018-02-20 | Neha | Transactions and the UTXO model | [Bitcoin Transactions](https://en.bitcoin.it/wiki/Transaction) | [neha's slides](https://github.com/mit-dci/mas.s62/tree/master/slides/lec04-neha.pptx) | |\n| 5 | 2018-02-21 | Tadge | Synchronization process, pruning | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec05-tadge.pdf) |\n| 6 | 2018-02-26 | Tadge | SPV and wallet types | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec06-tadge.pdf) | NOTE: No office hours 2018-02-27 ! |\n| 7 | 2018-02-28 | Alin Tomescu | OP_RETURN and Catena | | [alin's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec07-alin.pdf), [Catena paper](https://people.csail.mit.edu/alinush/papers/catena-sp2017.pdf), [Catena code](https://www.github.com/alinush/catena-java) | LAB 2 DUE |\n| 8 | 2018-03-05 | Neha | Forks | [neha's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec08.pptx) | | |\n| 9 | 2018-03-07 | Sharon Goldberg | Peer-to-peer networks |  | | |\n| 10 | 2018-03-12 | Tadge | PoW recap, other fork types | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec10-tadge.pdf) | |\n| 11 | 2018-03-14 | Tadge | Fees | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec11-tadge.pdf) | Note: Office hours on Thursday the 15th, 4-6 usual place |\n| 12 | 2018-03-19 | Tadge | Transaction malleability and segregated witness | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec12-tadge.pdf) | |\n| 13 | 2018-03-21 | Tadge | Payment channels and Lightning Network | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec13-tadge.pdf) | |\n| 14 | 2018-04-02 | Tadge | Lightning Network and Cross-chain Swaps | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec14-tadge.pdf) | |\n| 15 | 2018-04-04 | Tadge | Discreet Log Contracts | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec15-tadge.pdf) | |\n| 16 | 2018-04-09 | Tadge | MAST, Taproot, Graftroot | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec16-tadge.pdf) | |\n| 17 | 2018-04-11 | Tadge | Anonimity, Coinjoin and Signature Aggregation | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec17-tadge.pdf) | |\n| 18 | 2018-04-18 | Tadge | Confidential Transactions | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec18-tadge.pdf) | |\n| 19 | 2018-04-23 | Joseph Bonneau | Ethereum and smart contracts | | | |\n| 20 | 2018-04-25 | Tadge | More about Ethereum NOTE: Class is in E15-359 | | | |\n| 21 | 2018-04-30 | David Vorick | Proof of Work at Industrial Scales (note: no video will be taken) | | | |\n| 22 | 2018-05-02 | Tadge | Alternative consensus mechanisms | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec22-tadge.pdf)  | |\n| 23 | 2018-05-07 | Tadge | New Directions in Crypto* | | [tadge's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec23-tadge.pdf) | |\n| 24 | 2018-05-09 | Neha | zkLedger NOTE: Class is in E15-359 | | [neha's slides](https://github.com/mit-dci/mas.s62/blob/master/slides/lec24-neha.pptx) | |\n| 25 | 2018-05-14 | | Final Presentations Day 1 | | | |\n| 26 | 2018-05-16 | | NOTE: Class is in E15-359 Final Presentations Day 2 | | | |\n\n## Labs and Problem Sets\n\n| # | Due Date | Assignment | \n|---|------|------------|\n| 1 | 2018-02-14 | Hash-based signature schemes.  Code your own signatures and sign with them! In the [pset01](https://github.com/mit-dci/mas.s62/tree/master/pset01) |\n| 2 | 2018-02-28 | Mine your name |\n| 3 | 2018-03-21 | UTXOhunt |\n\nAll labs are due by 11:59 PM on the day specified.\n\n## Final Projects\n\nYou may form groups of 1-4 students and prepare a\npresentation and a ~4 page paper on one of the following:\n\nProject proposals are due 2018-04-18 29:59 EDT - submit them via github repo.  (e-mail is also OK if you can get git to work)\n\n1.  Design and implement an application or system\n2.  Add a new feature to an existing system like Bitcoin, Ethereum, or another cryptocurrency or shared ledger implementation\n3.  Propose a formalization in this space for a topic that has not been formalized yet  \n4.  Pose and solve an interesting problem\n\n## Final Project Submission\n\nFork this repo on github and add your materials to the projects folder.  Make a subfolder with the name of your project so that it's organized.  Also, please include a LISCENSE file describing the license for the source code of the project material, as people out there on the internet may be insterested in using this code and / or collaborating.\nPlease submit PRs but Wednesday night, and I'll merge them.\n"
  },
  {
    "path": "projects/README.md",
    "content": "## class final projects go here (in subfolders)\n"
  },
  {
    "path": "projects.md",
    "content": "# MAS.S62 Spring 2018\n\n# Half-baked Project Ideas\n\n* [zkLedger](https://eprint.iacr.org/2018/241.pdf)\n  * Add an actual blockchain to zkLedger (or, use Raft if you're taking 6.824)\n  * Help implement an OTC market on top of zkLedger. If interested, talk to [Sophie](sophie.meralli@sloan.mit.edu).\n  * Find the fastest golang elliptic curve implmentation for zkLedger\n\n* Blockchain analysis\n  * How much would features like cut-through save on blockchain space?\n  * Make a nice block explorer\n\n* lit"
  },
  {
    "path": "pset01/README.md",
    "content": "# Problem Set 1\n\nIn the first part of this problem set, you'll implement Lamport signatures.  In the second part, you'll take advantage of incorrect usage to forge signatures.\n\n## Getting started\n\nYou'll implement all labs in Go. The [Go website](https://golang.org/) contains a lot of useful information including a tutorial for learning Go if you're not already familiar with it.\n\nYou will probably find it most convenient to install Go 1.9 on your own computer, but you can also use it on Athena.\n\nYou can use a regular editor like vim / emacs / notepad.exe.  There is also a go-specific open source IDE that Tadge recommends & uses, [LiteIDE](https://github.com/visualfc/liteide) which may make things easier.\n\nIn order to submit your lab, you'll need to use git.  You can read about [git here](https://www.kernel.org/pub/software/scm/git/docs/user-manual.html).\n\n## Collaboration Policy\n\nYou must write all of the code you hand in, except for what we give you with the assignment.  You may discuss the assignments with other students, but you should not look at or copy each other's code.\n\n## Part 1\n\nIn this problem set, you will build a hash-based signature system.  It will be helpful to read about [Lamport signatures](https://en.wikipedia.org/wiki/Lamport_signature).\n\nImplement the `GenerateKey()`, `Sign()` and `Verify()` functions in `main.go`.  When you have done so correctly, the program should print `Verify worked? true`.  You can test this by doing the following:\n\n```\ngo build\n./pset01\n```\n\nHint: You will need to look at the bits in each byte in a hash.  You can use [bit operators](https://medium.com/learning-the-go-programming-language/bit-hacking-with-go-e0acee258827) in order to do so.\n\nMake sure your code passes the tests by running:\n\n```\ngo test\n```\n\n## Part 2\n\nThere is a public key and 4 signatures provided in the signatures.go file.  Given this data, you should be able to forge another signature of your choosing.  Make the message which you sign have the word \"forge\" in it, and also your name or email address.  There is a forge_test.go file which will check for the term 'forge' in the signed message.\n\nNote that this may take a decent amount of CPU time even on a good computer.  We're not talking days or anything though; 4 signatures is enough to make it so that an efficient implementation is relatively quick.\n\nTo make sure you're in the right ballpark: On an AMD Ryzen 7 1700 CPU, using 8 cores, my (adiabat / Tadge) implementation could create a forgery in about 3 minutes of real time.  An equally efficient signle core implementation would take about 25 minutes.  On slower CPUs or with less efficient code it may take longer.\n\nIf you use CUDA or AVX-512 or AES-NI or something crazy like that and get it to run in 5 seconds, cool!  It should still run in go and pass the tests here, but note that you can do all the \"work\" in a different program and import the solution to this code if you want.\n\nThat's certainly not necessary though as it shouldn't take that long on most computers.  A raspberry pi might be too slow though.  If you get the forge_test.go test to pass, you're probably all set!  just run\n\n```\ngo test\n```\nand see what fun errors you get! :)\n\n## Testing and Timeouts\n\nTo run tests,\n```\n$ go test\n```\nwill work, but by default it will give up after 10 minutes.  If your functions need more time to complete, you can change the timeout by typing\n```\n$ go test -timeout 30m\n```\nto timeout after 30 minutes instead of 10.\n\n## Submission\n"
  },
  {
    "path": "pset01/forge.go",
    "content": "package main\n\nimport \"fmt\"\n\n/*\nA note about the provided keys and signatures:\nthe provided pubkey and signature, as well as \"HexTo___\" functions may not work\nwith all the different implementations people could built.  Specifically, they\nare tied to an endian-ness.  If, for example, you decided to encode your public\nkeys as (according to the diagram in the slides) up to down, then left to right:\n<bit 0, row 0> <bit 0, row 1> <bit 1, row 0> <bit 1, row 1> ...\n\nthen it won't work with the public key provided here, because it was encoded as\n<bit 0, row 0> <bit 1, row 0> <bit 2, row 0> ... <bit 255, row 0> <bit 0, row 1> ...\n(left to right, then up to down)\n\nso while in class I said that any decisions like this would work as long as they\nwere consistent... that's not actually the case!  Because your functions will\nneed to use the same ordering as the ones I wrote in order to create the signatures\nhere.  I used what I thought was the most straightforward / simplest encoding, but\nendian-ness is something of a tabs-vs-spaces thing that people like to argue\nabout :).\n\nSo for clarity, and since it's not that obvious from the HexTo___ decoding\nfunctions, here's the order used:\n\nsecret keys and public keys:\nall 256 elements of row 0, most significant bit to least significant bit\n(big endian) followed by all 256 elements of row 1.  Total of 512 blocks\nof 32 bytes each, for 16384 bytes.\nFor an efficient check of a bit within a [32]byte array using this ordering,\nyou can use:\n    arr[i/8]>>(7-(i%8)))&0x01\nwhere arr[] is the byte array, and i is the bit number; i=0 is left-most, and\ni=255 is right-most.  The above statement will return a 1 or a 0 depending on\nwhat's at that bit location.\n\nMessages: messages are encoded the same way the sha256 function outputs, so\nnothing to choose there.\n\nSignatures: Signatures are also read left to right, MSB to LSB, with 256 blocks\nof 32 bytes each, for a total of 8192 bytes.  There is no indication of whether\nthe provided preimage is from the 0-row or the 1-row; the accompanying message\nhash can be used instead, or both can be tried.  This again interprets the message\nhash in big-endian format, where\n    message[i/8]>>(7-(i%8)))&0x01\ncan be used to determine which preimage block to reveal, where message[] is the\nmessage to be signed, and i is the sequence of bits in the message, and blocks\nin the signature.\n\nHopefully people don't have trouble with different encoding schemes.  If you\nreally want to use your own method which you find easier to work with or more\nintuitive, that's OK!  You will need to re-encode the key and signatures provided\nin signatures.go to match your ordering so that they are valid signatures with\nyour system.  This is probably more work though and I recommend using the big\nendian encoding described here.\n\n*/\n\n// Forge is the forgery function, to be filled in and completed.  This is a trickier\n// part of the assignment which will require the computer to do a bit of work.\n// It's possible for a single core or single thread to complete this in a reasonable\n// amount of time, but may be worthwhile to write multithreaded code to take\n// advantage of multi-core CPUs.  For programmers familiar with multithreaded code\n// in golang, the time spent on parallelizing this code will be more than offset by\n// the CPU time speedup.  For programmers with access to 2-core or below CPUs, or\n// who are less familiar with multithreaded code, the time taken in programming may\n// exceed the CPU time saved.  Still, it's all about learning.\n// The Forge() function doesn't take any inputs; the inputs are all hard-coded into\n// the function which is a little ugly but works OK in this assigment.\n// The input public key and signatures are provided in the \"signatures.go\" file and\n// the code to convert those into the appropriate data structures is filled in\n// already.\n// Your job is to have this function return two things: A string containing the\n// substring \"forge\" as well as your name or email-address, and a valid signature\n// on the hash of that ascii string message, from the pubkey provided in the\n// signatures.go file.\n// The Forge function is tested by TestForgery() in forge_test.go, so if you\n// run \"go test\" and everything passes, you should be all set.\nfunc Forge() (string, Signature, error) {\n\t// decode pubkey, all 4 signatures into usable structures from hex strings\n\tpub, err := HexToPubkey(hexPubkey1)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tsig1, err := HexToSignature(hexSignature1)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tsig2, err := HexToSignature(hexSignature2)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tsig3, err := HexToSignature(hexSignature3)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tsig4, err := HexToSignature(hexSignature4)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tvar sigslice []Signature\n\tsigslice = append(sigslice, sig1)\n\tsigslice = append(sigslice, sig2)\n\tsigslice = append(sigslice, sig3)\n\tsigslice = append(sigslice, sig4)\n\n\tvar msgslice []Message\n\n\tmsgslice = append(msgslice, GetMessageFromString(\"1\"))\n\tmsgslice = append(msgslice, GetMessageFromString(\"2\"))\n\tmsgslice = append(msgslice, GetMessageFromString(\"3\"))\n\tmsgslice = append(msgslice, GetMessageFromString(\"4\"))\n\n\tfmt.Printf(\"ok 1: %v\\n\", Verify(msgslice[0], pub, sig1))\n\tfmt.Printf(\"ok 2: %v\\n\", Verify(msgslice[1], pub, sig2))\n\tfmt.Printf(\"ok 3: %v\\n\", Verify(msgslice[2], pub, sig3))\n\tfmt.Printf(\"ok 4: %v\\n\", Verify(msgslice[3], pub, sig4))\n\n\tmsgString := \"my forged message\"\n\tvar sig Signature\n\n\t// your code here!\n\t// ==\n\t// Geordi La\n\t// ==\n\n\treturn msgString, sig, nil\n\n}\n\n// hint:\n// arr[i/8]>>(7-(i%8)))&0x01\n"
  },
  {
    "path": "pset01/forge_test.go",
    "content": "package main\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\n// TestForgery tests the Forge() function to see that it produces a valid\n// signature from the hardcoded public key.\n// If this test passes along with the other tests, the forgery has worked.\nfunc TestForgery(t *testing.T) {\n\n\t// get pubkey from global variable\n\tpub, err := HexToPubkey(hexPubkey1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Note that this tests calls forge which can take quite a while.\n\t// One way to make this a lot faster is that once you find a forged signature,\n\t// you can change the code in Forge() to start right before it hits the\n\t// forgery, so that runtime of Forge() is very quick.\n\t// The fact that you know to stat at iteration 2 billion or so is good\n\t// evidence that you've already done the CPU work before.\n\tforgedString, forgedSig, err := Forge()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// make sure that the message for the forged signature contains the string\n\t// \"forge\" in it.  This ensures that it's different from the 4 signed\n\t// messages provided.  It should also have the forger's name in it, but\n\t// we don't check that here.\n\n\tif !strings.Contains(forgedString, \"forge\") {\n\t\tt.Fatalf(\"Error: Forged message:\\n%s\\n does not contain substring 'forge'\",\n\t\t\tforgedString)\n\t}\n\n\t// report the correct string here\n\tt.Logf(\"Forged message string:\\n%s\\n cointains substring 'forge'; OK\",\n\t\tforgedString)\n\n\tforgedMsg := GetMessageFromString(forgedString)\n\n\t// verify signature\n\tworked := Verify(forgedMsg, pub, forgedSig)\n\n\tif !worked {\n\t\tt.Fatalf(\"Verify returned false, expected true\")\n\t}\n\n}\n"
  },
  {
    "path": "pset01/main.go",
    "content": "// Problem set 01: Hash based signatures.\n\n// A lot of this lab is set up and templated for you to get used to\n// what may be an unfamiliar language (Go).  Go is syntactically\n// similar to C / C++ in many ways, including comments.\n\n// In this pset, you need to build a hash based signature system.  We'll use sha256\n// as our hash function, and Lamport's simple signature design.\n\n// Currently this compiles but doesn't do much.  You need to implement parts which\n// say \"your code here\".  It also could be useful to make your own functions or\n// methods on existing structs, espectially in the forge.go file.\n\n// If you run `go test` and everything passes, you're all set.\n\n// There's probably some way to get it to pass the tests without making an actual\n// functioning signature scheme, but I think that would be harder than just doing\n// it the right way :)\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\t// Define your message\n\ttextString := \"1\"\n\tfmt.Printf(\"%s\\n\", textString)\n\n\t// convert message into a block\n\tm := GetMessageFromString(textString)\n\tfmt.Printf(\"%x\\n\", m[:])\n\n\t// generate keys\n\tsec, pub, err := GenerateKey()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// print pubkey.\n\tfmt.Printf(\"pub:\\n%s\\n\", pub.ToHex())\n\n\t// sign message\n\tsig1 := Sign(m, sec)\n\tfmt.Printf(\"sig1:\\n%s\\n\", sig1.ToHex())\n\n\t// verify signature\n\tworked := Verify(m, pub, sig1)\n\n\t// done\n\tfmt.Printf(\"Verify worked? %v\\n\", worked)\n\n\t// Forge signature\n\tmsgString, sig, err := Forge()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"forged msg: %s sig: %s\\n\", msgString, sig.ToHex())\n\n\treturn\n}\n\n// Signature systems have 3 functions: GenerateKey(), Sign(), and Verify().\n// We'll also define the data types: SecretKey, PublicKey, Message, Signature.\n\n// --- Types\n\n// A block of data is always 32 bytes long; we're using sha256 and this\n// is the size of both the output (defined by the hash function) and our inputs\ntype Block [32]byte\n\ntype SecretKey struct {\n\tZeroPre [256]Block\n\tOnePre  [256]Block\n}\n\ntype PublicKey struct {\n\tZeroHash [256]Block\n\tOneHash  [256]Block\n}\n\n// --- Methods on PublicKey type\n\n// ToHex gives a hex string for a PublicKey. no newline at the end\nfunc (self PublicKey) ToHex() string {\n\t// format is zerohash 0...255, onehash 0...255\n\tvar s string\n\tfor _, zero := range self.ZeroHash {\n\t\ts += zero.ToHex()\n\t}\n\tfor _, one := range self.OneHash {\n\t\ts += one.ToHex()\n\t}\n\treturn s\n}\n\n// HexToPubkey takes a string from PublicKey.ToHex() and turns it into a pubkey\n// will return an error if there are non hex characters or if the lenght is wrong.\nfunc HexToPubkey(s string) (PublicKey, error) {\n\tvar p PublicKey\n\n\texpectedLength := 256 * 2 * 64 // 256 blocks long, 2 rows, 64 hex char per block\n\n\t// first, make sure hex string is of correct length\n\tif len(s) != expectedLength {\n\t\treturn p, fmt.Errorf(\n\t\t\t\"Pubkey string %d characters, expect %d\", expectedLength)\n\t}\n\n\t// decode from hex to a byte slice\n\tbts, err := hex.DecodeString(s)\n\tif err != nil {\n\t\treturn p, err\n\t}\n\t// we already checked the length of the hex string so don't need to re-check\n\tbuf := bytes.NewBuffer(bts)\n\n\tfor i, _ := range p.ZeroHash {\n\t\tp.ZeroHash[i] = BlockFromByteSlice(buf.Next(32))\n\t}\n\tfor i, _ := range p.OneHash {\n\t\tp.OneHash[i] = BlockFromByteSlice(buf.Next(32))\n\t}\n\n\treturn p, nil\n}\n\n// A message to be signed is just a block.\ntype Message Block\n\n// --- Methods on the Block type\n\n// ToHex returns a hex encoded string of the block data, with no newlines.\nfunc (self Block) ToHex() string {\n\treturn fmt.Sprintf(\"%064x\", self[:])\n}\n\n// Hash returns the sha256 hash of the block.\nfunc (self Block) Hash() Block {\n\treturn sha256.Sum256(self[:])\n}\n\n// IsPreimage returns true if the block is a preimage of the argument.\n// For example, if Y = hash(X), then X.IsPreimage(Y) will return true,\n// and Y.IsPreimage(X) will return false.\nfunc (self Block) IsPreimage(arg Block) bool {\n\treturn self.Hash() == arg\n}\n\n// BlockFromByteSlice returns a block from a variable length byte slice.\n// Watch out!  Silently ignores potential errors like the slice being too\n// long or too short!\nfunc BlockFromByteSlice(by []byte) Block {\n\tvar bl Block\n\tcopy(bl[:], by)\n\treturn bl\n}\n\n// A signature consists of 32 blocks.  It's a selective reveal of the private\n// key, according to the bits of the message.\ntype Signature struct {\n\tPreimage [256]Block\n}\n\n// ToHex returns a hex string of a signature\nfunc (self Signature) ToHex() string {\n\tvar s string\n\tfor _, b := range self.Preimage {\n\t\ts += b.ToHex()\n\t}\n\n\treturn s\n}\n\n// HexToSignature is the same idea as HexToPubkey, but half as big.  Format is just\n// every block of the signature in sequence.\nfunc HexToSignature(s string) (Signature, error) {\n\tvar sig Signature\n\n\texpectedLength := 256 * 64 // 256 blocks long, 1 row, 64 hex char per block\n\n\t// first, make sure hex string is of correct length\n\tif len(s) != expectedLength {\n\t\treturn sig, fmt.Errorf(\n\t\t\t\"Pubkey string %d characters, expect %d\", expectedLength)\n\t}\n\n\t// decode from hex to a byte slice\n\tbts, err := hex.DecodeString(s)\n\tif err != nil {\n\t\treturn sig, err\n\t}\n\t// we already checked the length of the hex string so don't need to re-check\n\tbuf := bytes.NewBuffer(bts)\n\n\tfor i, _ := range sig.Preimage {\n\t\tsig.Preimage[i] = BlockFromByteSlice(buf.Next(32))\n\t}\n\treturn sig, nil\n}\n\n// GetMessageFromString returns a Message which is the hash of the given string.\nfunc GetMessageFromString(s string) Message {\n\treturn sha256.Sum256([]byte(s))\n}\n\n// --- Functions\n\n// GenerateKey takes no arguments, and returns a keypair and potentially an\n// error.  It gets randomness from the OS via crypto/rand\n// This can return an error if there is a problem with reading random bytes\nfunc GenerateKey() (SecretKey, PublicKey, error) {\n\t// initialize SecretKey variable 'sec'.  Starts with all 00 bytes.\n\tvar sec SecretKey\n\tvar pub PublicKey\n\n\t// Your code here\n\t// ===\n\n\t// ===\n\treturn sec, pub, nil\n}\n\n// Sign takes a message and secret key, and returns a signature.\nfunc Sign(msg Message, sec SecretKey) Signature {\n\tvar sig Signature\n\n\t// Your code here\n\t// ===\n\n\t// ===\n\treturn sig\n}\n\n// Verify takes a message, public key and signature, and returns a boolean\n// describing the validity of the signature.\nfunc Verify(msg Message, pub PublicKey, sig Signature) bool {\n\n\t// Your code here\n\t// ===\n\n\t// ===\n\n\treturn true\n}\n"
  },
  {
    "path": "pset01/main_test.go",
    "content": "// You should not need to modify this file.  We will replace\n// main_test.go after submission, so all changes will be lost.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\n// TestSig generates, signs, and verifies to make sure that flow works\nfunc TestGoodSig(t *testing.T) {\n\n\t// generate message (hash of good)\n\tmsg := GetMessageFromString(\"good\")\n\n\t// generate keys\n\tsec, pub, err := GenerateKey()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// sign message\n\tsig := Sign(msg, sec)\n\n\t// verify signature\n\tworked := Verify(msg, pub, sig)\n\n\tif !worked {\n\t\tt.Fatalf(\"Verify returned false, expected true\")\n\t}\n}\n\n// TestBadSig signs, but then modifies the signature by hashing one of the\n// blocks in it.  This should break the signature with overwhelming probability.\n// Also tries to apply the signature to a completely different message\nfunc TestBadSig(t *testing.T) {\n\t// generate message (hash of 1)\n\n\tmsg := GetMessageFromString(\"bad\")\n\n\t// generate keys\n\tsec, pub, err := GenerateKey()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// sign message\n\tsig := Sign(msg, sec)\n\n\t// alter signature.  Hashing a part should break it except with 2^-256 chance\n\tsig.Preimage[16] = sig.Preimage[26].Hash()\n\n\t// verify signature\n\tworked := Verify(msg, pub, sig)\n\n\tif worked {\n\t\tt.Fatalf(\"Verify returned true, expected false\")\n\t}\n\n\t// try with completely different message\n\tmsg = GetMessageFromString(\"worse\")\n\tworked = Verify(msg, pub, sig)\n\n\tif worked {\n\t\tt.Fatalf(\"Verify returned true, expected false\")\n\t}\n}\n\n// TestGoodMany tests 1000 signatures that all should work.\nfunc TestGoodMany(t *testing.T) {\n\tfor i := 0; i < 1000; i++ {\n\t\ts := fmt.Sprintf(\"good %d\", i)\n\t\tmsg := GetMessageFromString(s)\n\t\t// generate keys\n\t\tsec, pub, err := GenerateKey()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\t// sign message\n\t\tsig := Sign(msg, sec)\n\t\t// verify signature\n\t\tworked := Verify(msg, pub, sig)\n\t\tif !worked {\n\t\t\tt.Fatalf(\"Verify returned false, expected true\")\n\t\t}\n\t}\n}\n\n// TestBadMany tests 1000 signatures, modifying all of them so that they should\n// fail.\nfunc TestBadMany(t *testing.T) {\n\tfor i := 0; i < 1000; i++ {\n\t\ts := fmt.Sprintf(\"bad %d\", i)\n\t\tmsg := GetMessageFromString(s)\n\t\t// generate keys\n\t\tsec, pub, err := GenerateKey()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\t// sign message\n\t\tsig := Sign(msg, sec)\n\t\tsig.Preimage[i%10] = sig.Preimage[i%11].Hash()\n\t\t// verify signature\n\t\tworked := Verify(msg, pub, sig)\n\t\tif worked {\n\t\t\tt.Fatalf(\"Verify returned true, expected false\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pset01/signatures.go",
    "content": "package main\n\n// Here is a single public key, and 4 signatures on different messages from this\n// public key.  With these 4 signatures, you should be able to forge a signature\n// for a message of your choosing, due to the fact that many of the private key\n// blocks have been revealed.  You will not be able to sign any message, only\n// some small subset of messages.  It's up to you to search for a message that\n// can be signed, and produce a forged signature.  The message must include your\n// name or e-mail address, and the word \"forgery\".\n// If you would like to verify these messages, the messages signed were\n// \"1\", \"2\", \"3\", and \"4\" respectively.\n\nvar (\n\thexPubkey1 = \"b6f016f0b9839485ef0f73f894072246c171e99d45f1c83302346d96e2eeb6e04bd8fc3726a5d466fd9805e427bca7093129fa8fb486a4afe8856e4c8045a467628c376d18d101737dd1f3f2b9b01a15972eee26cd1b810db7cb94007db6fdc5cfcd45bb2c0692e9b1fc7b84453440f637430109c57b4075d2c7701601c6141890a13841c729660d8da005d7b31b81e05d7c3146d5b1069089a8bac2e40507bb959e77a4ebe64cde80168104451f45d41d87fa80033d771777799fb2ac3081cf0d6131143f9f1a92d5e551af68df61900f6eb7a4bcc6e2193e75b399d9a26d082a938429f9ba9232272c50fabb8f3a497995818043a11189517319a6371f13fb0989adbabade295732c03444836c97d1379dea18837fb0560cf84808457447599b251e892ac2ecc65e825f55e49922c179abe4f07c094449c4b1018c2f3f8c6cc599ea88b999bad603be8e6bffb990b92492e3df165ca9b2cacf86f481a738179154610797b6f550762ac7b80d77625a0a82c32acc04f2bf4d66aaf9075d66d2752c653a141d9be51b6348847083b1f271a8033279704d34e142096ed62f16d5f0fd43a7e4c030e08c8d351c8b500a9c54562b1add1548d72fc9d8c67db5ecf7b0657c4a9a66451d9a7e304f502c9d0ef99d22d7269b8813f0297da19aa53097a6840db41c619f9bf5506b681076969ce65d8469410303a252d3590ad3683e1bc60c636ce9eaee4652fa1fcb12e5b73a0a905717689ccb44292cbcb7c611d299c946311ec33077f0273d45c8cfce0163f7989ce76b833ad3ac1e36c877ea4c3136484cba975c7469439834c03aae5020a54229bf52e7a6e2c8e0d37c9197e73c1aef3f18343a7658a4e560b12b23d597eee586f88ffce15e83a3ad5f664a84a24e40b0f3d9f8db30f3dc271da5a0ea33dafec406c5903d569f4b565bc66f4645be2d7f690af664e857c6a6636f779cc83334dcf5a925beb733b4cc6389cc7878030ba9d3ab2b04640d7da45f11ace0b3a6cd1844857ff959950f1ae67f9270afb26cad1f7aa4d2b41c7369aea6ef32ff2fc2d7eba599a65c491d34843fdb1fdb787b0c0e502427a542e87cb8f3947132f1a88196aa910e0893512b47bcfa4a85a9c640b8093369837692fb95e5d86d227d812f5532a006e9ac3c53e7a4fbe172fd8d3d9ea325c9e06d23e1439f4ffdafcdf04f653a541f8a427525531a03c37de1ccb9adfa7fcda22f20e9a1d8434c1fe58e5e8cb72845d3b26c4493c77c2746017b5f37ea8ad19ed0bb11b64f311c571904a03f9c0f713442149f6a8050c154d516c1dfab985fb9083ec10551e1f2ca5da3803f3f604413a969547718b764eb255e0cd2e05869a1bbf7167922a4977be914fef4d76892136169b50d8d414e01243f1c6f43381bce0c9146aa836f9e60b226905e66798a06978921d123fbd765fe41a22aa2eb0dbf9c9e29f86548002b1a1afdf478eb1b871397223336077e5004e1593a091f26de123c2df5cf105fec5b343e66d405d3e4a5b3d45f92c3081d3b6556afc052327baa1e5c6cd9646730cdd75878cf5914e845ba1a1f2b53706a400eab03d75aa5bbf3ceae9311b45f20faa5d0e10a1612bc6f8a35a43d430285ba7380538f112dbe306e024b5c3e96bfa63b19c0b523bda1b11684635311bde23afe18e8ec1e60210add3629d5765d7b7d7cf9f746ab330fe119f5c6ca5a1254ab3477b410078cb6d54fe654a2134ab3bea4729df46685cc9fcdb77537ebbbc25a8cc79002dfc763295ce6261104180bc8819f345f67a70873b4c0ad2b5ec5f412ceede59e3f55bc012a82285af4c496c6c0e444fdab5b3ebb9e09062ffcd4d13aebf9d7b6b94445347a7ef24c442e2b7c880cba94f3d2aab3a25ad084e8a8613e4884697ad8a8bc3fec3c96fccc4f92eedcedcccbc61a43d33c867cba6abdc13b83c6ac4713563d778350e08adfe1ec3e77dfb1aff35744d84e3b0046d4f94df29813914f60bb8001c1a08d918ad87b4a56273dfa92a5c2111891541b1b797c051308de00782034b387d34d767618cdf04b366e3bb29c2c1fa83fab63e1d18aa54a72a68a968427af63ec402f1d726e4287c061d5781d335642c0f611accdd28b288ba474c011fafbc8309d6435c267f9b67115eef26311c056102a92d159dac8d9857a271e1e7901600446e65601cbd3de4721c04d5a5c10b402ac50cbdd3edeaee99a08655365e66cac25a598629a2b9dacfba57d35e70ad79abcf04404c8b61d8ae05c304c1d880b1ef7511110029bfd73ab9c6ba9dc7c6b9622e291c81797ad5bf109972ca88332bcd4b8df9f8ba7a3965e8429c0cb29c1a17ab97e2efb8906a94f5076fa041c5c69ee18f14cf36932fa62b76a5ec28c7b4d80ba93fd4ec1e34697bef59519dab4b1ca32d28420eeba01514aef61a76efc4033ef810de2750795f12968de6af646e9be4275d63c40eaacdff21aaa4423a43a1cc6a57af6f77e0ba62f773a50343b3725400678c802c39eb677f5137ba73e87a9c17ececdfca4aa559beb2be2d4dc83a3df02d87123186af3bf943ee132d8f46a8824585cb9fb7c36d0dd1369d227da30de92347f4fb989538e81e26adc319d0be17668ff971cbf95a84b206d4d6f6d337be53b2510a40ac132814d84a516545ce51508949528fa8c23e08cb8072508521517333cef74ce3e7c768c048f0862a7a30bbb4a9ba49378705bd0602ba232068b67d8c11b12985ed89226544b5eea5416ad3c3cee95e7eb3bb075fa8128ae9959719f52e5e1849ef307fbeef44648c14e194b6f94ae9ad3c10660e349fd9b00df4e383517ab537bddd58e77883a45724f58b2050a7b0f723e5ce5ea6984285fc52ee2c2e8dafa5c07a340c22acdde11a1297c924d764e4af3f0ec8c07ad5bec6441fdd70037f7fee705faa0fbcdef8bbc24ddd79a4cc9de5b53279bc90d87b59fbea65442ba0b177f30b7fe204d624acc8c42380825932eb1600df5338f319f991443f36582b64933f2ad952c862939601fe690269779e611a738c3389a0cd84d7719a38d9349ba672002e1717ce6dd47664cc8802e40eafa00d7ea2f598b80caa155bd11847a274d22940c5aee6038011b1d2a942872be0c5e03802e13f49c19d4b3f750c15a38bc6453568aeaf41ca19808e32525c540fabfdb2153fa8ccbba0c830ada26ad511495de2c919bfcfd69f3a420fed0e3db901f812f33a24140ffd966612340019f2e1ea39c4a12cf9ebcc8ce513cadec0e2a8b10980c2fa06fefa1aa750d0d1746635ebaae8c3bfa9ae8c8880a3b5e532a9b7cbab8e843abc3a2164a4c7716099192921903d78cd2af4b92740fad3841179ef510b84e5ca6083cf8f3eaf7dc3f90ece27ec02ed7d8be9c93cd25ecac5be1f4fc3bc554156efc864a9ef829070995770489f951c9387f31e16e478a88f498ac21e331d476111d475e90c9f5d800b5918c98b69e7b01582a367b19a575ad5ad391c056f2053ecf62eae6041f684695f751f0b4aeb58928526b5750707d7c0d399c49bb46e1a909ee5c97a41a68691cd263d74902a1dcb6c5876498e97e14ea9949d826a66ea1e54c6c8c76fa339226b147a9e06d162fa2d966536906308c77a9938de1af3cc85ff8bd4477a6af85f5cdee121c931ec6571ebc5c44b1734d76af70cb26a1b68ba3c0dbd09d058b8776f2208561f86a8f3f637b74000c68eb68678aca82bee671dbaf2d0eb4ac818eafb5d8257e5077b840d750ffd02d13055b9c40c54715691d3c55cee990bb0c80d75f6de9bdc5d43678976b002adc871c5b54d6993ec82959b84e9ca7c4cec300dee22b6766b0d67d33465f10540f813b8b772746d18c3712320865ea1db8ebd58be5f3d554a0cc2825816b381d4bc65034dae57a02bd532f6898e03cb575e06e8d79828cbd0235274662719f7475130efab0bdd7a4f7c777c9f2f1f48114058f475f07ce4a533c61ba968cad0c6cc5fad9c12ef0350f2932fe23e7f6d3d33ce89e759d288b25240707b9f31132833b2b933124a78d5b6c63af99e1bfd0ab159747382ded84dc747e105298feeac3448606067fc015dd3a2993d8268ccfa2d19bbd69028df5035cbfe11ed57ebe106063fde4508539f57cfa389cf774fa12f94334086bcd4c50aee488edefc460605d24b2cacf33377c5cd60768744b45e6a285500bbc9f45ea5bdafb3ed48c4626b7c133a6a8412fba22801923a3ca1c25fc97039e9fe730f626f655407a102e46f739b8bda61fde872161eb83142f2bb6a0b466e7acdc3000ba602bcf9fd910bc8ae09bee67abe919eddc04d6958cf463b7d903c03a9b43f2069c94dc56ef4c3c3575c658d427dbb1077a2d066742bd498a07607ae0b264f6b9d0b709b6e50ab41c8e8b8e39217e039b4bceebca1e756df1ea2bf9c9551aea6c2fc15d98d20a7f60ed580697948a23f7c5b65688c1ffeecf9931bd2610a240c5f900f5e12a2c87152cc46ed7792b3f6bfc94cf9bad80887d702449969735fd33fd144cd5a53c86d84298a936ce770409197604cac920b7b1bb2c9630f4ff182844f0074207c863ab8217ca93c1d1a09f5b582f7c63ebfff81096983d70be249b950aabf046db474d99bec76e3cf68e444a32fdc9a8b1f2da70cb68cb6eba06bf0ca53ba1055cee2775a2239a0c834f1cc41644ae3c67bb28243056be658e001bc22a6a88f08349ea023e4b14194871afac0aecbf8b4952bb6a713b9fe34caf78c97b351e808667904818de46b999090ad785248462fea4c28982351b36b053b4c272f51850f8153d0822df083c05f227a41f5b863114b12aa7aae1f0516cd4ab09e9a2d846c0cf2408e17df9b0b64784ca1cc855276b8b0c2308d99a3844b6c929e0ef0d16f17be2dfb4a5320749f37a00a16259c756dbbe5db86acaf678b0e99484fbe01fa05c076e90a45faaecaf84b40fb7b11322eaf2d4bbde32a9ac59d219ea181f30c553438d1d0418bab10c8da1406d71ab492007b92ef88c97cead52727306e770eda50bdad4c8020c71d4fe2c08445ab307e0d29f2abbd43fefcd4a7898869a8ee0fe5492a49881bea5ed7754396ecf4e5919404d34862b606bfbc65a3734d9ecc9a61061fe3b4ca67c2dc4f843dc03a59e110a5effa80bcaadba7a8b45e9cc418bc0c52b7df3885d3098d7618fa6a4737cf276d85b22ab704532de492cdd04ca90d98c198aa3e402c41e7558cf42c858e6840ba821be18b2ef6d4b240de795e2dbdf926e223da668d04a528cc6dccd3aa72dee6441fc3b39a9700eb0f7e29f202573a234e9a4a73e1892b8b4aa250f54b8149e1959cdc5fbba3472823cb1cf4fd50f4cd86b0bc1cabb3844edbe8f1d1388f1e2ffd10738c1c91600a6104b169ecb1f0f118f32753596c80cac6754854ee4e3612f74bbf3b4ca2024d63429825bc8d0bc6554539d1db7baf4361d1785b75b85cbca3d9a1933feb7257ba0d0a74c26d328f5110c3c60a7c93074f3f0cc51c665f9e7c05a78293c76e7a282890ae34ecd20901f089bf6969ec6d32d130db1b7a4a85230f45fcb4c618d8e31048311191dbc889bf689f0e4f43f226909af8a2c3a5633d0880c051d46cb7fa43b650b2fe4426cb034e075d7f3ad27609ceecffe6a341b15d639a8dd15ddd2c06e33a6e0b5f693e3ec2118560336bf2c936eeac6aefca0a4c18fa6bc6fc6d594c7615b84a070ec4e4daeac6ff74537c65d0320e7f78eefc449ce53408bfe7f0f7a930dc8b5e70cb7abdbd7fd2222aec2e802b902091c58fd62002d1550a105f3ff4f357b9540491ff83e9682fa04557510066f1767972abd36b02dc7e56a4be3c7cf876649a1eee96cc5d4b10344f5374c33668587aab622cfebb1962407010386ac557126689b884d17bb536694122dddb344f04565e82c58e47de0d38e1356529040ad0e5780219ce15ead5bcfadb143787cf5f712f58e13ca06b4a0de4d65b1b666163770c283c5fadd237d306694d25d923a0528820550181ffc7a4609e5fcd4e20657ae16572e09e31f93bc5e670e585abb0d49852f0d71a016b3c6446224f3307c79fcd8d9ebacbd7bb5840df33cab998d11798c6f04702c9901ceb80d7a106280927c96a52b818c158f78594b7d965312c05b40e97e48d119a6fac5d886b37ecc65f05b74df3a5a9556901ec718a3281d74e4228d463a690ea01d4af1b0a1e1cb5d2278ea4658b8d710e652c8b000a1ad4bb490dc7e126a389a459bca29370b7acfc5df1f8d3d90f2da72217036d07e8d458d646c465aba83d8d8247a52b97346922327a71ec08ef061abd9813970d137b81a9eaef7923d7a23a9bfcfeb4d655c3c684386f0ef914c8b9d791ad4a66bace189418d36374980dac1a205189fe60b2dd7e98dcd61a478b60cc2d4d42c37f24da59c7488101dc5850239f91d27f313de8f4f38fc21355e0ac02ee9dfcc3a91b6a3fb773cb04a9fc0761a7a7624eec08cdea32cfaace2aa5491715930dec94bdb2279051c9e98d8cb049ff01a7a118abbfcc98587ed3b315fc40148f15977de5dd8b17aaad7eb2416693c6c9fe2ebaa337b3df2b7bf8af92dfb78268aac7fd41525bcdc4e983419fc22e16dc093ca8f2b378f6ab5540de3e4d92a8e0d4e68472939e4372d8dc5a790eb0de965217b28064bca71f29770a7a9f93e76d1843571177aa66e2a526f99c826fc6f02e31ac2ed536732d165f7448d9af749ffb6d45121102a561304ab0b8630afd730ec10e0920717db3f39732fd40f12ad1926362bb6df0032dfa031d9947ca83965398c6c123f54306eef6648616be7cad6f56e6401ba2cac3c4b2b7387bbd227d29d4acd4f03361e5040b970ce41bc62be6d69d985b9420ef94bb2059b94f7bc4530467f47345239e40e071977c519b9ca34498ef70793106e44444f7071de772949d80968d923ffad7017bbb038a9b330941509a20240abab02c9635a862ed2a85f4297311242ccf247f3edbab2821817ffe10e53247d8c760adff363695631069466114a1a325d55cb5ce058035878118596e7adba6ba16776eb035a79c8d1d47648016887d9b705fea7eb7067ae1786f9e521067a89043543456e141d06c9a97e00ed3f9aa8d32b0de071a7535213c8aaf3388fcb3ef06ee183b284581e0b7e7b9f2e30b53bcc098902a8254aeede8de1ec57748f56f3ae0ccdb38a440c4a89279e01b38a6d125343e3e0641461acdfd21f4911547e2a7d505e1c3a382d683883d544335f7c782581819351791f95d47fef49586adcfb3dede4b1362becd96f54435d424084f181d219493b29386ca7b02f2cb8f686edd572597db46ce43c3f8ffaac67096b79b8fc6411a61bee33b256cba76b6227aeeea95a7b69b5111c391e295b327d2f5435d09799bb66c1ed876706f85638bdd8eca7874c9612631f550b5497f09505c257009e04558615e300250a04171044cfb5b9c5144c274cbf2329ed0f2941a69c34ab02567dfa41c9c7a264e3797e73032f7424dc9eb87560013c315d9bf735ae96fc3699adb9e2c91d5eca71b479f03f3d9dd7dcd72771c0daa45d8982eddaa023f7d6c92391300287f02433917af4cba3b738b43612fdd8880774d4848327612bb2bde989f1529db026b7846265ad298cc8bf1bf4fda52add2f2660fcbfac6b047cfd74d069e4000698bf51e1024cf5c27951230296b4d2b7df0674224ec8e9bf73629ceaddfbc545b5c37de811c2e34467e7e0921044fc0a61fd5b66f6c50c274a9727806fc8a49362626a8a4bb2171169623ff566fa9aff8b41b069ad5f40056aee52146f95ab6561a16e8f57e089a79a45a12942db117d43a53ffa87ce09a604244078cd49ea9348a930ae398972d7b6b87f0851cc3b373201030a70a9347d762e6d571b1cd470180796b2f727ca8a5762abca270330ed4d0ed9e21117c0f2d2eb2438074ecb90fcfd2621d80e1cd3f70e578a032dc945336d784e61493fd95ad23314e301f2f541929bc76ae7e93b302c4a18788d2c4f3405b8df322166333e88759042477b6068d417a843ff28e796aceb1e7e847e463babe25ee54e7693af7137155ef11bf39082e3c3007ab59993b5c51844bb2b759e88259d7050eb64cfafa26689c8f167839d1ab4fdf8b2e7bde292f67e0fd7908694762fde429d364211240d1c42286b98bcfdd3de98c8b93d70a3124aacf69771c8725fafce657cee16a135b64fde87d2d2db41d91b50426e0fc7b817a5a70e728e88a8ef59415084404ce0af04fa163815d224f33acd37dee7542f84a018100fd56aae03bcbbbbfca64472c65234a1e04ccad8a77a54965d5dfe3d9dc134a543484c857f6d5dbfca2871a5d3a8581ed7657e28ca1c00de9908446e0d5f5e9b8594ba49ab52a0a4462ab4e835c4c2da21b7a149c2389ecb33b8c4994831c229aa09f459a8ae302033215acfe69e12a54a91b0db6b227787489e3d96c908fd1c23be4548b7a8a3c3f3d54ed06cec581bea3dc239588435bcdf0af718e518d1e5801114ee9176018fb7d8a6b4af9a9a2142a6fca5eb57d93f0cfa2ef0107636c67ed5c47172b7139711f208683349ed350429afb15bb6a5b357e9509ebb8dffb776a8fcb998de40ce293fdab36c69b71531ad699ae02f1beeb489969243fcf8cd841ed1e2c48d7e73f3d432abdc7425a6c52d20da22caa56221490f9bd60a8c63032b34ef6b22822448f9b7b322240d960cc7f3203f6e5c5365ee580e3d473c52a1c20e3159eee3a02690e926885ae788b0590ba034f4a6bcff473926ba2c4181bb66a4d6e5971b1fe33635ad34e96b2bee235c1e79d7e19facaedb32921f6d1de7d70c0d7507514053d89d80df1a6143be5f96158f68dbc2ab738f7d2dd0523c44f97e1fcdac38caad88958e38d5e16b5681816684303291a7bd85113731c26a039e96621e4d788bd684298a526678a41cc2d568596e2fa91490ef86f7d7a603909b41f034997808c2b3686a3c9100edb10b5a0e718ae620683c86dc947df3f7ae78961c17771182d9493a655977ca1d2ee84fd0806a45cfafab5c4ab67acc440447a962f606c372daf3a149596e161fc31c10a4fe57c51c9225cdf55d7309b53784611511b239094fe8732f70f988bfe908859adbaf46e7a096003c4a61f01e17a5d8bc76d7742662019cd98d82f9b4db8b09b8f287b5a9c270af7ebb09e9e02604e12606d9d92296f7cdf2de28255ad9c1558bc03be47bf6b9dc33449392722d1e7b08178469ecc6635809b4653d8a0a79fe316bb10dd0310769852de5e76b7470345ff445155898189de37d168cf73877fefed3e7d83e5402267179df6ce57edf26e08e55b5f5f7637057f615840ac6864a99b3c87705e5158fc42a0a33f8d25ac899d88a8608ba3e4bff051f4ce17c5a6231bd738fa44b099c2457acc0ffe02492a81232d83bab62bc64c1d5b1b2c98223e823cffbf6af9bcb9adfb0dfb0c3dbce0989b5b44f93622371af967690c4fd6d479f3ccc11ab18c1b46fe15227319658cada471ba8c8256c03d590041949766652248c706b414c7badc42ea278857936b6411cb84ffb43013dc9fac5197950d5fd29316613214ee00e8a4943353b18ba23409886a367ce2963e8bceacb145499a5297e1e0a3b77cfeeb3733037b6a7c4f9160819b6e1b07d1b0883533cdee80b94930b71856902b1e7a9327d1628baf70c8d961e095f1ac1bc891374d0e928728008e88a900308052262c739e4a656f4c7789c74500e7053dd75dad045aa744f0582d9abf0495f17903b627361ce9146e1add2ad6cf60471dd26e5b5b5a95c9f18f73b5a7650e9eb8ba8c5b8b5376011c1870c6ab9ff913e21bd92848c4157a72d383db7b1372b4c7ac4fc88ccbf53894b71fd285d328c34fb72df305ca3e35cee6d9c4f23383b4dfb8b47c87d729442b8ce11dde793eee5ee65c5734454cfb8d9e4ced705a66abd556f81af3401b17ee1be62bb824b95fc63536581f3bc25f86df488217bf21d0efab6c0a80252062aae8d542f8a4a1844f1a45760a11eaa3947cbe0f810b508355545b695d44ccfd1fc5895c0fd40d4bf9fb830a18c6b1c658e8fc683da89d1ed3b6c48fffade5dcd0bc9cd97243127565d83776bc951b340bb5dc7dabac19ddc27dc6dcc7382c2c9387ff14b3f6a33d78d04c40920d82af2436e4051fc23777a8fc2031b217d373659b6bc004e5f4f1cbd3c33e3fc6d7126aec42ee127889884ede45f6538d4c51b08ac965c75f23d9d0377cfaecab5d1c897c7bd50f0f31901e5260cb1eadb5abf5f3c89098c4cebed0bf424a0ba344eea67d6978b1bea4183213e561e696fe4b10e7543cdaad70ea1cd054040aeb04620cb4e7879bec94d9fb3a9ee7a16e370c34946022fd06f391d66d0f13512306d73a8e56ca4bc7b4701d665f914eeff8048fadbeafe46b1124acde372808cb2278c8061555e540b4d6c1cc3476c8e410d4ca3762c5e858c682b63166fa74796c4546afd881ab453e9d5868fc8877f97f0aa2edf0e6d959657d1785926bca12153df613255206e89e53796b1e53d4cf860d3bed977fcbc3dabafa3b9ce1ebca0ea28ed55ff48d74b01ea75d22149123f9380579b2b19992a86a32a5c1d679b753ccc08d0a5b949d2ce436d65f35a031d817129ec8bce203b38173c81185516ea824c0c2ee08ca7ed850bef73afca49a08d4d82d55ccfeec20eb674e17e563ac70ebc740794742f100adcc7000108efba6ac05f976fa1dea12efc65126dae58d629155b3d90afb29e7117d0e30d4e5c772b070228c7c1d2b8eae20c14081f40d63755931559427ceaf560004f74ac7dc38f36e1d7e87a60c657e1d12b24284e4bf107d709836bcb83a6257894985218d6bf50a6a49c0c00205d25ab855a27d4fc38182e6864284b215dc44ba0c27b7e71ddc78ecc17d1e31d7c3b75647b37b4c0f26547c741fb98b0e96f7db9f53766497ad80d4fec726737c779cf0797fcccee7f7386933198c649962707e438fd7249d74a0b9724793c3bcc74ef21d72171673810bf826b03c988d615b4f372aefe2e23848431a9afc4758713ad5405929aeaaf8662f28d0f3841251da1cca213f4491b41d097fb71a9dbcccce8e800924b7d22e7c02ef2ea9da7246eb5144bb9cc5316b8f26310bff4eb230a44e4b302fb7f9dfa69e805afb25367b77b8a9ea0463fe83b165be7c1756430d32cd8071289b88f90c3fbee880c2fb3d5d2cc7411b0a6adea4a69df56360bba821422af09365321356d1e6b4cc1d34452cd13811c763754dc88e80870a50eb52db1809d2986b21ce6bdd54de3c607dc04873354f66d212cc51e09b831a529252f60d1f6081f041e46bae2f4342c812d05f7bd67e4097e2527e5060e62d8ab34873f1c65966152c5e39054b2111087cdbc207c88ef5edb1bfc4ce8a0c95ecc903f0b34007d7931f6a9283d579020f52e1fba549410477090d6da74f78ddebadbf72e6038551aac63450c963fcd8a621384ffe70a11a862f0e3c11132ca6f1633329e18f02fb3f70259286b8655cc8d98aafb6d261aab62ccb31e3898b2ff26e4f4ab2b84d0bd71e6ad320c55a7c5e7dc71ccd82aa2a8091b6f29c5db555690144b993f3cd31beda060ca1de763bfcb3758aab80ca743fe0af386254aca729d37b5ddc8ce068535b68ff25745169078295398a9aae22979afc8f5fac36ad0e30e3da01909a9f4c6b21661e536632ac37253e2eebfdcab15c37e77b714df568eccd804a75b75d407b8228d98092a5f626ef6d8f21c8ee3aa31c55bca7d55a4be9f35faf7f2be0de6185c5a524d0172a9a13c16dddb438a52e5d351ec597661b45cf3c2717108008892365b08427cabf571123117c8d7c923dabfab370c6398381e615eb9fa536c96fd96a4940fbaf5b692e11e6eec9a90e057bef39719094fe5f59d75fa5496a247a09b0069ce054048dbd223ba5b872561663fb563b71cc9a6688f050d2706a94d7e9adf758404a5c6b39ec4b954e9886bef28b83a75319fadb2a1121161c2900ea128c2e3ce3a562fa149c699891c953a8de69e34ca48fc477528995d9faae31d3352a0309001eb2b9f8528bc3efdbc80c278b763cd831341a343650dd38cc519557a32f0c6f43108b0c6947f50edd3b2ea9631fb9c2ed578c303b00b6975acdc3d83a0760eb4f7015e8f8c126f85dbb36d2f23caddb4d4fb05a6d487262f19edae90951bf548fc76758c154bc49d549dd7a0a75b548f7cd8e70d1695943805477b1152b33cc6b7391d608b2aafc5e1c427a7c41d2cb9b81ce60125f0b250af468b80aba7cfeebc875785f63903a6dba351238b910a76bd7ad6b054a2f67d4174437d9707c91cc7b7d770ad0825c9340cd5cc920e6469e4e2cf52fdd074bc2dc797f8d2f0e7fcb34ad946425794a1612910eab086576db8a2fd5f8732025030ae7521670a82ed93909d10af9f6c546f75c995238184a245d6bcddcc949335bd169fb57e79a7a2a9b40f4a873a15e4639c2fed6414dd0696e18c8a718f6609325535f495cf98185b682914e2dfee505451432c318f8f267a65fa4a9d983e822b125105ab7b46052d3099cc58b0e73002a6c3c0d438735d3781e6ec5823ba5584995f16b47483fadeb36401f701091e227d1c9865b0afabf2ddc0d8c30f5e3ff9d0c2db05d7001a6044388ec238564521b4e3d836c4090f5e4eb9854dd43ecb100f0945ca1d43693ed57d731834ea089251c748d2f40a1911f590b569e9c324290b88e1013db9649e18391daeb19b1d949dedf75508a32f92b8fe54f26fca5b97e77303ae8dc529c98345c5bae54fdd437255bad801c11391f01f3fdd56752c8c0e12a2235795e7ec32f24d95c5f4bbe57f1a12884b6d7d6ee5b0650cfb020ceb98acc71ad6906dd22bc9a94b10777e8a348cee774fc5826117af39273c7d6bbc804dfb310f8fcabdf49cbf2030e133bbe6c6bf52b7ec31f3a8d71b51a330d4dfcd1cbf0257b5d528f024aadefdd9fc00b58c9f54fe661cc05469957b9b6674094e81b0c2fb0dbca264d77bc25ffca32d144466f9df7b694d9336e33783b4215dca6b0e3e0780fe4d7fb8819ea993a196f76989be8d3450d9835575c1b235710e91cfd20aecf2cc892d58395ac92a89f71846e2e35243db767a7cdb58f36562a6f6242da9c9f9e8b597bdbfa3a2828b270300629bb14410e982c444abf3aba71e1bff4bf985d1d89377c8bdca42f79130d27e7eeca98f6e0c2d31710c2b6c83203df6d804d69102bacda35e71165825807487be6f69f1778af252b5baf69e0460e0ba2cd7c515f44949f4e61ea65417e15b19b520e9149dabbfc47b75ae5b252066e1655ed3fba15c360385f5de249b70fd6a5115f5f324f7f5eeb99cecd49216d634c3f14ad2a93c925856ad41ad7a4fc4e4dba74156ff66077956bb37233a1b89212d6f0552ced14936f8b7ad19e3ee83a124bd40d7ab3babbfbcc12c85225735b141e8d59195c15676b117d93bbe0fa7933b655e1593e05f788ab4719157026a0b3eca2d42d093e35bf00eb40b6d37605d5a15ef13214398a35a9f0632df490b90febaf4466965382dfb0248fb314b04480bb97ebce2d0982e6613dab0934fc1168f8ccf2f6e9afa8b60a3aa5152847020ef6565b61fc0d881eaace4aa5862bdc21598231d79ea6925e66efed029b5ff65e16b65397f58735ed0d60739e6f07a030fccaf8e355be7ed7458fec0d8f3c7e6842fe2761796df3fc898f916a04c83c53099fc7ecd44600d62f896f7ae8bba96bba96522b40f065a6b4f45fe860b1110547f242ee7d340acb90411155eb5bc094443f54f0025a3b1d61b8733f8bfbc932d6d0171da4600dfa932bf3133c2b9e5c7bb4b165d29eb959f266dc55a2e25d3c13ea67b12d436c240c95a9fdeee6be8ec6272787a35a71ec070c2361cd79460b5156fac4f8112322b7e936658fb1a4ba633010bb88e2b7afb9bdab9a3d93b757a8831fbe7367f0058b3e69566c8bb1243b49e0f849068d35d12f422ed87ef599e2c51a9100626e14606a4b8a14c8558297ff8a9c4564e3189885ee6a28212ab824a04b3ac3aa314da565c1329c27cf81dd3f93cdca2b3b37823552204c542fc80a0fc3e7519e2daef8eb0006fd9f9a0d8fe886d58873d2e67b8af7585802424a7c58f6cbda186808e003d720e6405ef82095c82eed087f128704624d06f2bea72f61fa2c47743a7acb63ae0344bd9c51fdcc68ef6f8ca3b8437cc1e83b12c202bf3648caf752a3249de9f194729bcc89093d95c5f074982fd1e720ead9401cb6e2e53eaa3e522ab37e336daacbd64ca4bf6a5000376925196e0be477f5202b86b246c34fef52506e76792a98592527e47f32b26454eac9a529f28177052220d33eff5fde9a35dc40a521997e19da4eee1a616ff969a5e16a0d8a0ab173acba33a606702c581c42109227a8f87df07156b8de776893ddc7e595415458b1f39c69e74f686f756658569ee7e6b443128b8b8a55a99e150e7a879723764ce2ee07c70641f76097040fff8a4a01469ebd6801353f04579ea0d85acc6731d2b6a4933498de0d6ca7248fa4ebca326568836da4415b50efc07389f474250741ff6843db1cf3f1178534fcee1ec11cc5744fcab7f9e3ffec1e22904f4bd4d0a50a388037d9a43914848dc1d05e6b306dcd3cfd8fe16c0528efd36c24edcb2d6c2b1f6be5d761754cb09319163e0c7b2af97850879131103cd351caba6b0efddecffa07ebf0ece5c8cd3af76d75cc84d7157e53b222cbbb38c3b012d41ec426f4ab46c5ca6cd50f63fb069b80924612ada32b2d03451c5548679912243ca8aa981884c842df6c979eb2f1a4a05c75fbe5b34d7c1facc4aa25186b64f5df99f5ee6024354a5b380f9254dc04a5eecda6bf24d2f9273288cefb9ad935042a7a520d4287aa2b08ab4259963cd6bd6ba796d1241d171b319f6df4e7053a043262c7c1487fa67ef2df54caaef8f797fad6463d511e1124d77f361cd948081c4dee630f8176b5a66bc5cbda8c73765f473e53255631fb670d2cc1fd4fb3cfd9e43459dd041f38e57b2747a1bd63fa804b8f0228f696443343ea2ff2ae7044a08ff902c60cf9912dee8536ccbe5c9ed704021496ccc599f8dd937e27fd8117722e96f748313d8645072570ee8190af7609d6138b89889efa4ce9ac473eaf399b1586b8708b9745586d8af6198f5eb802d260291656bde1b9f45d04e5862b068604bca889684cd5be62471c720f71c2ae429c21f0b9fac631f0d13fc4f994c7b3945e4ef27329b43d560d6e267efa370d16aaa25c434da3519ead94f6a34a074857e04853db4e293f67f43a987c22754cda275afe7c24bf7eb2d915fbff09aafdb0467c2c1caad2265a95bbbd59501a34f5f3208aa50736b92833cbafb334a5993a6f6b48145a5803e61405d7129d34cb3d75a560172210a9f4c757d94e3cad3a5dc35c12f26c6cb52ee1ee176f002f82ade16450084c4a925d32c5ac7783253653d9b09013ad9a2820a8e10c576b8c6716c626788b750567e39452d09107a5033393173154168b0a840a4715d6ef42baad5687455680b26972a5d7cc071c5be634a8492ae2aa56fd03f6c594e660020507b92f8155cec3bacbeff2e995b14db7808a123d7b42c6ef6752af3a5992f972beb2e255138a42a1976c8f0b100bfaaf9e56b701f912a4c36e6173cffc73b60575d008cffa0e6188d18cf2df2e5a995b1049272e8495b8ff0921d441b80d345b7dad292278321ecc34a2666932cd4c573db3df7b164215641ab119925dc106e76a875f08c855c4d068efcc1e8d273275840c184d11ccbf97af5aeae0d5f54380f3b2bdd9e10d659db41f75125e31474ec4a3974a6884a06194a59869c6bd596375d8ca5bf1471fa2b0e1e85333b8be56762d50db73c9829f1a74cc94a818eee32f5c2b82bf4b7c5a4f540f7448f30e873e615d2f945f0581c64376a7366e816e7c729130b0ae7c3191a22ea66da9b996892f2a5d5767c1fc1c04a6a35ff49a0118bb63d9a58b5daa2f7ff93f7759dc2d6ebf07d8fdbf482358c9a22924c30699ead34fabbd2cf10bc86d56414063e5e0139c10dbea00c2a7a70f5acebf8e6887ab9458262c40b33ce0df0f0625c546e9fb717b115521e7b95e03b34d0d9ad612f3dee54469225573089bff802b4d2b91242f3f4475daf44c26ac639b7c5b9cb4e6f28fe852578d99659b4591d101cbd77f1126b0328d9117c122c8eaba5fe18e9af45226120126c22d12a317b108c1438df61efaa1ee75c0f5d30902df4580a56731812d577706d806bf51ab098994485600835b85de4d255ee9d3b741500393a9b803e8cfda5be51fc673023522dbea258a3bd03d8e1d3b9c03ea4621deb203b53b64e358332cafc06de882dee49304e1fb5dd14a51eec0591a8104943a717fe8680054ef38eda5befaaee3d90e9a6f66c5a0b785cd119af7c90b1477bd11c9245e95688b8702d0a3617938a9f6f8e1028edbb193cbe6680b870e0f78e9f606582559bdd74bf6ed68ed39c3205937710f3a5d710022813e1d1ebbeeb8a86b05c067c7d92bad82d5175847c15732ce281aadbda87639df5c5c9af7aa358c8701be66a32b268276f35861551cc1ca518f5effb1faa754eca9ff2b9a8cf0d9c359af9a2ecceafb107f099e8c34ebfdd96af4ff72d53c60befcb8348d2f4345639e781e13ab6906a47df66090af9f48dd625cc90603c3f88d092eadaf1932728cc426b8138ba7a22d0269b92adf3f601de5ad2775f2d31ce48b0272661111efd3dbcb90720077407ed523519045af214f765ba23cf2de6f789aa3df2193579da75f84e533143ba40a94acbad978ab6389a33cabef8b328a173283f6b55d8d3dadd05087a7286a84a748fb259a21b63836097bafc2204a3179d851f7a8d2d9db7e6fddf0ee809550d881d8c3dcd25a4351d2faa58fd5a361b927fed995d8316fd44d876b9828d74b1d763ed5b4db1f077cde1b4b9b1274b517a81659da21ab200acbd849b20a2251b10a11b63bb012fd0c495ed243cb875ae7f5f320183120fc502f7961fe0d8eb13fa335a23707774173723e9a8f42acdaf6056116bdb59db0c92b24a1d2689df15cd231cd01cb99e7f2766c9981b598908f010bff0857fcde68a9302ccc50914e3d0951cf81d01d12ba3b5695635c2e8bba7971d472374bc04ab3c3f9bc143e99639b4047729716ab3a584ceab3d3a44a201b1d75cb5854400824950da8fb9e8ad21b68272fcb5b48b843802a802256cbbd3e5d1907229fee28ed6332b0a20485c7bcb40cfd5c64a25792b55b77df62e0fb843db747b6a7e1fd89c751b7b03accdcb0a226db0d7c0f34c2c1eea2ca6f4fe1ef9abe6c5a82ea970222719979b06f4eb2a1c94fbf8c1290fec0bb7af0484f9e01715bc47fd019c8842a435b0b34337773ebfb0d283cf16c801a210274c694b2ceba3ed51a787850b1fa8116e39281df84644793a9b7333c9419bf3ca063c144f72c4d465dff5355f6e50c610b5c3e0e0fdbfe55dca2f42bec858917b18500b432695789c212405a4e8e0b40b42d45fd6e7babd218b6cba15cc8aedaa1531b59ae0987817de091aa9c5b34130ef60ffd940cff3b5cfd9ba51b4608af93d0aa44ea903354f2f28fe3dc233201255f6bfec854eba07488df5a36c05afee92f90d838fc4f86bff81b7e970859df9e728111b98a07d8ffb190935969e3a5da14ae5cb7a0c08a9e1e92c5ed0b643f77d1e9639321a3822a285af5a512e6efeae763af9829dd32b8ae89a124eeb32dcdefa14637894635321a6f9b4ae80aefb143af639f390b64c745103db05ad4d081235e84faba2d223fd275fb5f6308473ee168bdd368a9a9b2f559e0c1f1142f284b57c1824ec8713b342c35acff283bef84fff191f2deeb9626bf79a3b1b9e542047c527ff76f4a9b699b4d4ef5333049c803604b711625a57fb770993c0222bf1de0887d67a55c6db5dd9bd00cd3e5013f11667e215b221c909f863c6f61e1b0e457d3293ac98af912f0a71b88df2288481d4e420a48a44bc3094be67fd7e16312dfb71cef395588ffddba7c64ee110aae425864f45605ba443a69d89b9773f61549f195b720913f44aece8aacaa0bb0e65f7cc2487102604fe1901f9ba67e87a5165c134f5f7e1447198519eae8edf0d5799d33dbd58fd66a1fb3d533c908ea32f319f77eb95fe09fbe96895be8f877472bf6dc305eaf1532853ff2ef46e30b72c71a465f3c4745f275a984886cab0bf64e87ed55a581224de597fcf4b02396570d3478373d77d499e7972f7b0d6cef35ffd3b3f6c8dd3e32bbc22979610a1981d3576084a52632a3df66fde61a71bca36f948d90b14c2222a876d30154e918647dfbb2d0dfd3c1b8fdec8a2f2fff36484f461436c918e9f7279711dd5f28dd30e2577c0b111f3f3b18181c4a1a29f3b2c27dea1acd19114e4345172547b37a8df37932a6ff085d81721d2365eca72ea4b4f12253ebecb09d8879851786fd160348116a6fd23167813e6e63b8e2e08016531697627a882b44f9314adf200d6d0047eb5d225f1855d723f29f427622295cf78d2c5e12234cf94f4e0540e32ec3641da4d1e2025a3cf9a187885707aef248e65682525ea8963a61441d158345105b6df7c0587819f215afb122318114617a3f253e634b8b082c0bd82b080c74e755d3cbe9b7a51571aa5d6d2c509718896fc1d42e6df6e6676b7cf745d6c91a380f360b0756ec9ed3c52450642d9e8e2104ed6d6af13245756418854aedc51ca6e2e26576db72b7ef7db598fb72b86f3a52c85e0b33b910b2bfe041528e98c91df0441358fa28b1de7cdfcbfe5edbc757db57ed97b170a8e0c6686a6b17f09865e8ea3099fba61f8ad2a7e03b9651103d8ce22fa258515ec66599a1f25a85cd23e826a6c6de64f6857a93160254dfa2c004dee60b7442ebce2567d76058ed2b1dd3b1e96a156bf52c8392aa68284b38a895734f487ca58856ef5bf1e07208abe0fdb33e0764c86f22d675a0cf8034825b010395c91449fe29d080df432143aa1394223b18da6c3dfb54bc0b9a24e45246c2608f8583224c857bbfc5c1d796d7d70531d2d61027fdb17a476290a2195478bfe001e2192392ddc6a444e58379cf2508cd6d4510d90aabb5d7e09e3b4215ff5a707a20c571d61c06cca40e9fc8334dc357781350c37b79410e3598452bbc74f54e54920cdb1bd012ccd27ae4b79797a8989cd74cee9732367ffdbeb613228213530bf74ecdad8514a7b90328e4f90ad40989baaade78e041971baab8f932ead6c0e8cb15cf0f6002fd66c931ba45f393f82c83db1f08e8b9b53ef12cb3d86fe1ecd282d9678af674b4bf1a2f2d483ee117366d241d622e03476bbbe00515c91c0b51d7c87f433f8a839de49ccfd7d1b893cf059c7374eb9a2f9009ded57a0f2ca0a881a5f715dfc01833cd5fd3521709a2b8fc177deee595b3ccc5dbcb0cda87dac92721765734d515a88a100ee689438cf958767fb0deb5009b6bf181262498c4ff0275d715d21a18f88396661d5f65e0465185b1c257c033baf558605249894060e121af50f089b703e5cb04625667d74d9990de7f048e336de01f143fd7770bb6bcb4d64440beafdb052cf158d8dbfd9b2f559b65cb411ca27521b1ebc5321f48c8644111d9f8b0a8d1ee69296d8eef8e56d6ad74369382bf445ccf8e8f636d9b5c84b3a960b6a2d605319dcf5fb88cc6ff18936d64821aed75cdeb30305c9551b5d8aab487bd949dbadd5b49ee2790a8c0d2ba41b64aadaeed6af484c15db3981006994a0f7a35e4f130ab5a6a47d31c302c1bb6c9ffe32f84405d2c1196df855d54fbc65ed3b3f556faf2649b5f87491d5570df073de32887544332b80052e2bc332cb88c251f8c2d858757175302c76a1a4c9a204e74fb20a058cb874b0cc688e52d35176b55a1eb3b8de03865c512757fb04a3d940077f2d820ee9e93e84c4651d23537bd3617561931765dbef6100890522d267edc0b5668a0291edf11279920dea52bf3b12ae4f4c63c0ca214c7c513ec4578978856dfb42d5b06bb41de8cc2f8a3a12a2976aadbfeb915bd81806894b7433b9df1874efcc0782bf2ab9dd1740ee618b709a8992755ca70b5a01820c9255a94adf56758147e7a47115ded989ce4094551ba24f6bbaa43e675c4b4a3eec58a74fcb82cee7eb391db0163c5df78665bcdd7e3c6ab440719811ec2d392714c26f688330632f57c2869277427643361e7037eab7268115cb30cdc47c4d6828317eab207b5ab6507549336e8385c565a7e5ef49ea17607489d94c16ac3b4e2ad7e2c05e847b64d4d0057682c82d87f6bff68215f80add18a7d375f92655ff36850163a7d0f11c132c39e968be422d112507298ad17577a123902f02b3e1d3f07d7c2120257e895e92f92c56a0b48858b33ad47d074ecb07e4a9d1c96d88eff41765f9fe517fc5871d6ede065b2aae2e1ee0f3ff799430758cf52afec259b877eaca373477dd65ba948f26b888089fff8fb5237da1a6232b54e65990d16d72752a0d3db900f2b6ae935981ce60a37fe784c25071ef6b6e1cb70f868aef1b5db93ba4d3da7627a7d598e6c0382136008bd2b281bcaeee2f1ca3e862dafc70412c84abac805a22c536d1696940e6e461048f1cec0e7520aacdf295a3314dad7c01ff7f984a63b3dbaff67d2708aec10701476d38fcd0643ad82b43e7fecf30e16a1df8457724894cb1facf54fa61cb7508bb47e8829d9b48e33e502a4d77846630dc16bb41d075cb9f88493be4fcf4685b922735790e73d44276a568ef134996da2c33db8455451d75144c9b62e4940184fd9774c331bd1117ed0a24e479fb23cd0ac28e6b8c1f3d71157d3eeb100c4ef6f24b6c4608b25b8f6bfdc3f23a6f7ff06e846ae7946fea4759962038f327d5dab09174399e0b6b10d24527298064d24f1792442f8b2f1616522bea058dba08e39f5fca419e63ed975d6bdd3163fa38f0b873dd0177704921481afccdfddfed52e20209bb947a7c5b5eb1ed2efdb8ff5f9d97969c67f18f88ba1985cde4d7f27156d5e1a8a1180a95912d4fd3db96efcc9b26a5a4ab4a70290b2f76ec030cd4db9ff93a2a4aad7dd9061e03241346020e52dfafcc72483ada76cd8ead985dea3aa7db21a5a30ade6bda02c255a037bbbfd8fd0713bf6874262035d1eb6dca4419750e214e848f02965ce745d893734faa3bdd2640f8e1603d946beb2ea9a0368bc5c296707fbe4fb482843b1392c1293317db7cb90209b8fa7096274a8ba00437b5230248e9c90ae3d7a1ece46069e923b151e7477a99c8e6443335a7d9f8df108974df68767d4c427e0a7c158ede2986824e69207d46b1bfbad152b5c8d47958712c302bbe8680980c72cb7d16ce6e5d750338da061d1ddf93ff752537e2a4d915ba683c3acf5555a1748f41dc03835de52cf3f19af54cf14165fc77db3fe9e60f17e72a71bd86a5840a8e64d6ca47158095795442a8df291e71b0de84a4385409a61a6e67d98f1e1083ca34f4a0023006970c0cdf133df147b20d526e85d5754c54c2f46e0d539cb40c7cfd4389a923fbe3d09c693008f2ce226b1f71460245ca9c7d00e494d5b2eadfd0b99a5f55b25b59d79482005c0749f61df353cc1eee96f77cbccaa8fb786841cfe78b15b958cb7602b005b955daee806bef2c919881bd57107dc727b1db98e94213bb31925fb59b9c414a450b309a09d2d515b0a54dda5c964d5aa02728f774bfb6580b42835d16204a46ba6fdbaf0151bfe4427a9e1d33b9ec5a3c675649836392fd69028d2dfdafe920043c809e36e7b79cec0d193cf27b3e45e31a79c03ea0caacdfa3e4e13b77b45c4483db878282463eb4530d842a2c46cf86489c1345fd85ee4fc196b96e4a38dead0009e0e99e57947dccdd0202a73fc741f59278582d78fcfa5d4abaf4bb3f8a3b7d62303759c0a2edab50a2871a808fdaa0c7e3371fc3b7ba8db87e9f4cce8869e5064a8f0aa9bf66e4da4e8874cef5ee1603dca6f24d5a5a5c1d8877e76e9e26539e2aa6b7631f256cc3677e4283d9fdee7154093a62dbb953b5d751cb7e4836348b2589d09a23d6a487a1d7679a722922577fde5c0342c6105ec4f579cf5ff17340e84a506fc6343506ae6d618b6eac04e9527b1a0b2ccdaea04ae4e6a392022010be60ef6d29eb4506a7b46f13dd6debcb69d95542e0d4eed9f084512d413149d2e3163104a57a6516e306faff7c76ad5fd67f7999f7ec22d1ee0ef06c3d159b675be9fc6feede9a14ec9f745bdd887cfe9923452277c1f0238f7a99fa61715e1dab8a3f39a4cb65a75afad65018ad8fb493a977617e4d3b34f6649dc71722f5ca458c57dfadc5d5ac426aefa5976d2c5da5092a419d438b435c5aa032d559fcecdababe0d28af06b1f84ab8c2f0b5e2e59310c6df57dc074811339958c2c5196a234083edb462f7824569ec7525f972c235a548453a24e012e2937bd2dff4a343ccd8d82a5b5a48654880fc3cf1e2252ef0f809be282d1431cd1ea8329053fdaa131133f2079b0e2f9fc6abdb114daa637a055bedcc959afbe6d3d2abf609ecccc1c5938ec10d71c24091e5ab8a1cbe830ac7c28532d5eef059192f6d04da7cf38004360501759e6c3c9480ecd955f8f190c770e8d57103c5dc718d989764aa07d85f4b995a0131b647baef2aaed5e833a658c311b88b2033e77b2b7aa7131ade2ff519fb4b411c439f86029e21517bfb811698796b219b8f91819e6745db5f09f1205caca2d6a75da5e41ebfdf28b363cf4f2eaab12cb2d67fb83eb221b455a3785d32b556742071f179e08c39aa0ba7e9be8b12dc30910e3ebbdc0e1e401c6c7177b8e2b7412dae3ab2a2c42f7161881b3452a3e74a48924c7474b0042df00a91df8a56201de8b4b02ebd1e389526b08557cf8bced96f5a46fb2d54150173c1ac5eb6a3eae6364f51d21976120f7c9e730301124f9bc502df8b4ce2ebed9b0d3c1fc7ed70d3c08c13bb60694e567decaecb721837cf41ff3b8a5d01f7d95670dd3deec2bb5fec9df8bb7bb61b8f51f931a5981fed69521ffaee66ee36203dcb6c125d25d4737ee06188e5dd6b067bdf405681e26ac350f590a01b515ab955fc91afac05cf0b3a6c1691b38d55dead2f83158c2ff2711d\"\n\n\thexSignature1 = \"0e49fe1706d9e93b3793e1057f328c4206632da58c13b1aa3c95158c1a68b8b5d9b4fb001100e13cdac760febf755faeefc44667db4983225c5db714516b867a806f8f883330d5acff28b097f440b75d914b65454169126a7805b6118ad1c7671e28d88aa59d7761c0f92cad83ef4fc21ee97c09a81e5ae20a4475b68935c3ec4d06c1d2a2165505b667b2741a5311d2a78d99cb46163b8b6d65d04ee40c2d3e2289b0d981a5813fcb4b3f3fc6b11230fd4cffd3b910d7f766ddc09e95d3dd6fe7232b5e9cd52d09b87a8025e9841d2fc2b890fe0a0f3c4c2c8ee7b464f4e1fa0c0b8f4c57d0a3c94604ba22fa6cba188d776bf9e9e9e6471c61b8ccfba14fd9489fe795c8afde07ecaa802f05f1cb6945558d8840321302ff4d536e6eb5cfc89dbbf5c9c883587a3ad43770222cbee2dc5ee22f0050d9490a4b1a278206cac70754d4196ea1982eb72df2d285f27d774947a05708003f449cdf19d8aaf8e63d4339b9eca58b2cf9168fbbc27ea6f9b65af1651193370f70e3af4d1cafa7a2db7fd122cc34fc07fea2ecdeb168949e83a3389bb58bce50aff380c707a2b6f66492258e6a8108630e683a51d9bbd15b78c313e5f3b808ffd904ae27a55fc8ae8a21c4e1518267745f3358430e3df11391875e30fbf191648db283dbd98ec0451fab47d94079e2092a0a1879a6516dd0a50c1ec4f4e85545c59526e049a8d5431198a01440cd228c3c1e6120dc73accec5cff2a083caab20729ac2f0008276bb424c796ad7d4ffb9d4b5d213450e81d0a5cc25cb65fb469853ba75f400aea5b7b95882add53b72cf21b27c018938fe705b74a8ae2bcc2c80b0904dbe447968e66c0522c866c31109e6a055fc03a1696e350da0d21ba59fd7d530628fe6ff8ebb9e402216ce5ff3550db5eb38b5e0f7964afcf2c0a9f4b7e4693f90df9c58bcf2170a240489f62ef7ef8196bbfd162e13d8fec57d81ed815569640c9b2f09f9435f1b01380dd6e54408fef2a6644435af3abfd854f4cfc58031e90480ab3d0aa406139812bf64e075b39674d09bc544f1481769bd2088bc04ee2e7e8a7ab910c83ccf4030adff9a0501d2704256c2c12001d2773fefa7b580472eea8b3cd1b289092645293e7c27a5aa0e4de5b95f50cf943bf5b71b9c4a81906407b5d3b6fe59cada698bad7930b1d93e98ead0b5d467f8a41c239c05f715172dabdacce8ce9a663815a53ffb1ba4770b98136adfaea685d5ab01b60acb0aceb21537b701d104f96edc2a60cab5e866c7686c57e1bac8632cac62832894efe0c075e2ae689a86b87ead4432cede9fb6058f80bb6c9d52b2be420d09a2c847fa695a8c8d37047d4df7bc153ca9c955e0485aee8dda93fd2f4eb7910b484fecb1481c82f651d41e4374c128268218fdb52258f257c4caf22f2337c6c62ec1f67c423e19a61687325897f25e249a3973456198ed516c52f17d306146c2fbb6822e5650e6212a19984d388718a745fe87bb127c0a4b390bb8c865513d2cfc0063c38a41f4aa01591901009a6c0b0354c42ed55a6da166d7c109c676779e83a2dfab81392cd55cf1262b7782562a455606713df9ec9af4bac25c9b8854c15a4423062847691c691bb63082c0ac79c9e7e00a0e06e850128996bf24ce742c8c85c939ae497ad0d1d4a9f7e51db85b22857f5690c4b833439109d4effc166dd522dc0d2bcea10d401248d764a37cf39cf08e86bd71accce49b233789f54b4b891c2214da4d1778d4d26955dc7535aa3b5cf4f71c63f654c4a16e800946590aadde41356f98b9c6b98940b56b2933830e0556da48de6f71766a4a7722776342af68edfc0938d8eb825a8f82042cd0f915357e4c8c1b86fe92398382634d54d2dc93c42891dc8b193f9790fe54ee58537157d29af2bf1c1c6b667c365b1768079053dd1a9a4617a511ab7f4008548022542ffdf697e78d93240bd63d13977cdf39ef936bf0f8a464dc7f9fb2b742f61f1a7ddcc88a83d96ca7c65b094c49af7099c084bc53a2f20f88f9cf10565839f8ecee01ade85508634a27e58bca4c4d224b26a4c9b897514254ab0f1e297f48d063804d4dd60f63d08db985c0bf8852f8d8296eb92f2adb3e607bde0a9d9ede0d8328769ed2b6fb3c00db50c2539a034b7c960da37eb6717fb3c71cc47aa25fdd9b27c8ab24455c9dfa934267d101de0197480a2820b5c59597930675a1d3269f7c3e033cb41dc08001dec66224a3d2364f6f14b3991ca4726907a5a12f8f5701b08c9e916523dccd74c0e6bfaf55fcf544c3a22eee9415c15113d1db15c9379f9f481e4a427d5b9bdc3f2e0ab5288a1f0b46e8e4c4af023f65c4d7ca13f0ec4bdd50821f90ab8806f5d33689de6aad54c4d9a8236023635164b6400199218e3dfb4ee7aa179987b1d4e4893a190962a881db6b91a0c3268f6354e9a0ae04924667f65b834ce30067c988019ff86984bbddeb211b3d942f1eaab6d213fec08c7ab30842ba11221ff29044e4e9660f0796b437d3d0d8fe9e2fc60e67db187109b7aa35b30eb38fd6252b35d2f5c3cdaf7e1f2311ea6ce6a6de6d1b681ede35078ac0a08cb79f74ba2fadd768b35ab789f83b9f9a5059e500de88a401d8a612e7740ff9aec5d1bf78e1cdd485e01b5f45da6e409b1372fa0b52e3918c6952c0f4058357aeee776b1eb0fe31615ae1a995dac73fc84068233b5b3d4d2c04b475a293c7ccfb6a2a6eb6e080a95e3ff88db38b60ba8127cd04abdd9055ba27cc8e878ad05df4b22f92cd5858864fbb7edb8442d1045b53374f24a6a233a1b9193c552c3c845457734f8486352a3b9b11b513ac232f66050b8720af60aadff5b2edd1ab0ac51e5f46eb1cbcec86e0a3acab54fda2eaf244590390c4a16367274bcdf1edecccd71af0bdf568bc6a2a143c0323f6e16d24e4e4ef647483a73c2358579e1ecdad38ce68ed42f2f86d2fbe8f3cddd60b07a21d9099c6b08f22b97e1a022af285740932927bc88c834dfc33036ce86f095f5bba0bc4cb37d330acb59d6570a8e28297952cf4ed05134678605e420db31471b08cd6e4471637b8437f8880266f3dcfab80c22dc93b842abc923fbb12643f3ad3c68ec2ded37c1dba3eff45c9106db11535b14da39fc268f127d06a6a4da2c20090db3fb4cf35bcc74aa8627240b9fd9964939f984332217bcc00b579e87c912114ecaa2180b6d3c3a42c3bfe24fe4e0795fc16e166fed94f3655932a6c3e2fa1d44e2f9a95e16a744fc5c15ce84abea3d040f77404c9ed1630f27cc11d1f885e56bd94703869989bfbd5247b0cb67243061a827a575b6958ba2ed809c55d75f898eb3074de5e490f43dcea4bd1e8019683b07f7270b3610e57837d57fb6a84e06ffedf589744b84e190a8e6407440d53c9ef7a50d179e2e273d35e37529b8ee1b3f0227f91cb1889cd25601fe685b858710da059cdfa4e84bd125529f866a349a22deda060d4a1eb59100fdf22a1ffc1324473596f988a372273d8f593ed3477f2cf4d035f8e5c46e91a6067e270d84d6246df36b516bf49979c37f8e7eaf8f38bc173685c76db015af86b5cd34825dcf70d3b54efa55e9163f25c1de29c1ff2a2a84ed008722c913343e727b6812216f4d0e0212359d5df3761129b4a95d8d7405e34017f60516d4c675df3f08a00e62f03010fc9d049ccf8b0a676c6f1603959e1202a6319706fcd28ea42d691283cafd925fe7cad83ded6f8e79ffea0704e84850d6f1d695e1cdbd335e11ac75abfc6ce977b28688242fef27de931c52732b6eb1d39020f49f5c5cf48878896de5d412435c79a810a5ccff084c97e441ffa159170347b72d67abb6f15b14def092b67083b0a9ab5ba31c9490e19266cd029c4b91f8c49365ae03a9494463a23a9effbedaf2c11592724098e357e50a2cbe3a1523fae9a7a045c773a578fd59c413d664d66a9cbb5927a237360184a0e0e36f0c274948a12c2aebfca648ddc0dee4164975b4cb0e5cfe686086197aabc88d6daa70fe992d48b86b224a8b123daec21352c2bf4b08664e5b90fe20dc7b378767306e9e86f570c82d53d025babbc546fc7094c067da9836e189140bd43734ef9834be3e25e235dd9a3a306045ac98a244c25c472dbc226505c8cd8da89f68641ec3932a18b720bbda0d072bbae4ae404cf4b8bb1f17f2eeee0a15cd61d53775909b0d1eb879422b87069afa96bbf82b938312b8231b9f29191c4c5983e3f596984494f3ac9c8bdf17316967be9ba0a9ebb299c17a9f411d9fb0f89385b0f5f1a2fa863b07a9a556c3485601ab9e775638c09ee62ac56321b213cca5376cb77d2ae0ee9d188c77d7732fadb726965921212b47be2619a7800fd2431ad104bab4b0ffef4b657c03e0cb96a3931440ab20c977e8be1186b090dfcd054abb01018aef8047dd1d5b1fb046240cc7c8d03f8cdf1246708b03b4d0f4b4b1f2fa5c40c7b9c8d680b65727059503754c136e4491c4043babe09c5d0a54cd5ca94553103ebdce73650677096271f573e7ca3d9ab7189ed95808e934e94b7047a22c8d070ced1a2748176b4d1eba8486eef5b2ffcdf76c944cee8a9afdd7dc7c97aa3782cf8e87019c27b6d69e7cabda0afbc60d16df6c446bc84dad548c698caf8671c30e1480ad5ac40c1bcfe9a16b7240b59dc34b5a56b4a619f348727b1f215ee0943b90257cf776b1ed1ede3daf2bd1c1a70bd6236caf450b5172542fb1dfa9a0f15e7ea9de63c516a5ed937b2a6cf53db75817127c893184b7e2f2e12bad7b726ce8f06493e3c6324602c149228c93c99b6333521055908e91d311b84cbe4bcdc333dabd3592ec8b988a34b6bd7cc92dae7915096e9644176c84c5e6709edfec3404337e37fe11ce676bd2aa1a4e9a58d025142875bd52f8359434f6cddf05450ce870997f038a80b3eb1c0d8f0e469e2d08e9ae6f9cf0bb61cfdf18f332bc035ce8452435649f54fc83bd912be0651670dc0ce4baafd1ad4fcc9f5290b8f2ba0ff44696c9132dd52eac26b95931c06b2be6afa51e1d7602a3827a8a6f074fbbc2492f752eb8a59ba96365e39f281a22a59099e25a2fe6e3371747d733f9865a6509078ab2528bf74b196652e3fc5d884a0d198d02d51a60f705615679edc6cda6ddba41afacff5a776db11f72f6ab8ad6d9a9c936615cf37c349e627dc3e91bf354a08b84448234fa2ec9c6d54cd9738d9dcbf1c8b91a3c2c2d912576e4e6e35cdf35c092202f772e7c33895f64fa899d2280f5206759029df5cbaefc2b61e40bd148c611a6a21728345b40bf6a2475bced235e48a34907fa47edbca39e8f9a0e0ece57b6bea14efe79649d6a538fd5114163b5db44ff90e7fbd493ee902b6c275a9cddc129bf8e99b74c7f26aa8114d0f2c65188c2e913c003669b26ab3f22d4082198f9484772a4f3eb8f9d9d2936926642a413577c8a472c611a60d55bc30d2a7b74eb57f95ed836585845b68fd5bb145ea20350d6e06535778aa7d606a924a3c9619a4501015f7bfc720f0eac1b60592f1deebf47d5ac143865323931cc470fea2e060379629bc341c59e071e3ae145a93a49838e4938f4f60673893da07a52407eb4de538bfee99de63a85ce06db231c77dfd033b974513938644b7fd19f2bed75a4da4a5f3ce71834624b2b307494598b39dcac86b7642f02bf25559915cd42ed57180bee8cc4323eedd3a4c40720c1a07c940472d386e637f6003e2252d1310a71f0ec0d3d43016ba2e1a102abcac4238aea9ec272c8d8b91aacd87802874795164c0d14bc5bb0bf1c67179620d45f11151c74a6b3c872a5f2690f6344c0214f2e0560ffc7aa7f7dd067f4d7b4478a2db3430aadb8ebde065c0de928d57509368ef3ac33a116bf34fe364b188159ff9c72177f61844807c331da92fa7eb0b6308c1705b60106235c27c49385e6e750ae9323c39ef2ef9f0eef7a653e8115367d9769518837538a8b809ef42b04b9dceba2a88d5a20e2a2b23b8288057e9e7034ee34f1e8bc8f90b3edd5c0e73f9140d1802ac19cb0ec060d2c0670e116886b4bfd0bfbd8ec2b525abd01e4446093f9c2064581b0736cf28c93d5cd11d1f80ab7d64faed8a99f5ad8038c086df5a3c34f9909f4b0740bbfbe446cb84df3b5bd0ba2ec5901a74f20f22893167be220a7a304c1cff622d8b606bd3068f7c01adc39fd127d97acd6474bfbd4f0dc87e71a3ecedf7290041f0c591547a63ba0b4267c1e6ef7c679d077dac782f235d0460ba8da668837008eb7006865a4c50a09130e27d26aab97c9c4997576083cdcc1c524ac4fc9743e739c2dd6b8eb41d3e6a801fb4c6113ee32e0da6dc2aa94cdc4bad2f32892f33505cffef9597b2ca3720c983cc4ce21df1c9250d3bb3a4cab2131a836be7ae46f89ca2749be1a23cabac7fae8c70655d955f9d2bfc62156ecce51e3a54cbb5667387cbf8ba3b4b15e4f8032944ba0638df2e0dda6713824282fcaf4684c49b2081fdc82a707a93bd62a1c679c22199e5c1253d9542c7761467bc815e8f72c4fd870341fd028e0a558df0fd49a8841aec8255c6de16088a74018a8ce2e5521f262117179c9e71300f789164581f2bf33f9a618d9245b5afbfc2e0be97a2fb86e2f228289d191544c286f2ccaeffe54263c41af856699643b225b0574a6addb63cc6c9d6607fc4dfe4af97630873b6bde63c2ac39c0f2a82a1040ed69cc759414bfa67791ba6b477b2e9e9114ac23c5aa921f27d327089e183477dfd0fe89c61204b423e95db8011c43b4e517dc84d11691cb815530b972cb8d6846d0ebdd04dd74bec66404854b21d95ca506240caf063b20b3c178a8745d42f9dbdd5ab8af3c711350f70bbc33067472e24220071d05aea31db665cb4c3ba0f26eae37634f9b19e91854687e9262ee86f4a0662716f4d4ce07fd57c0bd79313eb8eeb1a8db89a545b29f862abdff05175df4601c0ce84f4e33e85afea12c95de543eece7368d445f0f48165c4420e760f8cd1e84e25710c7717e657bc138f432c3ba856c9a243f6388bd0ca6bf324ce41fe161f05a93e0bffc2cd353fa4edd4f100fab04e6054687ea1623859b5238f16b0456f03b06d911b120b8499fb65dc57ca7e253f41ee9147f96c35d318dcc50cc766b6d6e2a48e0849051bcc5b2bdf65f060218a0fd8aa3634315ffd1f49473d06e6391aa358279a559935b58aed7c03037349af452fcf230dc2c385c48cf667d6681141dbe584a7092745699cfa499de75538dd0f742e97b9ec0e1fe7f6de187216707865239cd7f9b175fdeecf5a49d97e3e9fa8209a3bba26e59fd8605402ab6b21cc5aa68b2ad69be80419c53e81542c12a3458b6f90c60c2e25d0ec44b87ecf7e10da4bbbe6a115db4ee52abbc81e54204c5bf2ff9c52db92c908cd41551c4ba882c864f9d4128963b3cf41504023735348fc232495d24ea23c539b635f536ed2973ef9854d19b73cf83c0e5bc35cafddfdca42590a8d3268b11e12d74fd1065e901f86789fa6fb73c1d4575520656eb7bbf5ca80b27fed31dd526e61ec0e40810358b70b295aed8d08a03bccdd84ff5c3409a1f23a9278600fee178a97acf5c0ecb81ff68d27ab3ff0676dff99ab77313457e44792de597e7d6df62addfff4a341eabf9926ebbfb55b5a7b3118aa3730d48334ebec98dcf8c243c283d1a726407fc70ffc0eb268fe4409167da69df498ea17c9e35cdeaaad0033cb18ed62cc1dc5cbcd13d076aad20110b636032ccb575134feda04401f09b05f686aa3bfad9949cb775ed4c23e6065044cad620c50d3d5d6229a569ea1004391c9c62882c33e448077266fa9d461d71040abf778a0345d22c9745b4b266e9fae6930c92217bd41d966d1d391a0009d336ab8864ad4ec5c727f05e44d039e7e4fa29e5c6e46340cc37bd380b564333cd4891a00c5990b3782c86ac745b6292f6623dbd2fb730bb7aa518564125c56ee126e83f3538c98c453b8a87c79cf4285f8377ea8469806c3f99fde2d4225510724d9fdbc6d9d41b01ff70804e5b8e6286d5a0135e256d8725eb32b95c1582f0f296fe3296453e4407d72d474d459bfa4d3a2852e1289f8a7d1a04ef42c14704b577be4448454dfb08ec645cef675f81b1d3547497615508121fea69085017f43874ece7c54b6e5bfc6307a5231cafe2f5191ae5c136876427542f73439cf2aa69f521c69cab2ec89bcd6a290c594de1d951396d36f9162daabd3c789ffaf8527c39dd66697a1592ab8af20dd9b0da37295615bc0ec7fec67825878abbef553c04c384ba67508e444d60a95969a13b952b6a7e890f9becb83a09f097c40cc8813adcc055264024b327386e3ff6d942c2fc43325da26110af27cb8e701bb943920da9345d0f2c80464152a32ea0422f6647ee48a0e7522bfd32471f6e6f455078428eab0f9eff43afa68d92bce3afd5dd0ec87ffa63d7d079213f8ade4538454a9363fe9082dc4ee98fbc2caea6f686775ef35f450e8e0b335f93bdbdfa0ee2b2481ad33c3e1d514ee029ba6ba9e5e8bdb746bd3bc376e201bdd6d1b3a9b6cb53da23262087a7ed64f6bde2b73c2dc3c538a94c3b9a3a163ac85a181c7e8866fc19052474076a8a6a6af50fed2065554619f2fc0a38653d941d9fb4df3b74768bfe3d5a4be245ad7a8a002a62edb0d514e08aa3af1626e963e0217c1f2657c4908a49db4414c3e07c086309a2e4676ba79d310f283a38c1f14534ff39e6c744ea72ddec43b0107a8604b5f34bc9a31f200befd27a9bee1091e2deb2f8f089aa1bc76f4b09fd21886062959db554d28f328cc5e1d2ce22f055b1d105a52336d0e7b8e6e26c3d872d9ca713f51196e2e0cd1d1c33dd933115579c484097dd4351645aa1fe004a9c8b42a2a3fe4a4140c0af8686eaa68f5dbcb5a14a35cb91213c30531f6113adc5b5b48483f9239a8f8686d875bb06d190237fa3d92928c9455d21b15c0dd801e07141e300b6e116d39a4ad00b698f39092e3520f813a68b56263cc7012175c1d1ce708d8969773ac35a175f1679f03b248a38ed8519d1b48d8ea55ca82dec86b0c32235c689748e29adf0ffe8e04dc823a67a1bd220b98493e91bd614661b3673f146c68b3062c78e9c839701319f179f36d682610ef7fd96df532b48dfd93ae2df01bb8e67360e1c3b08caa8674af3d01cc044a8da821ff2e3b8e595e7ac4c16330e00dd0ebac867feeb40c8080e2a02a42517fde15fae36c6fee9e3afdd4ff3dd9b8e0c8927b0ccf47fd2cd4a421d239143e0f0b0058159175230720d8e954e45b91c83ff48269291e678fe705fa95e6f49d5eed7b32f60a66bd2a5961afe862e40acfaf45c56ed39250b49cc152c33e90bad4bb9d3caddd0bc9cb0d39cabea9627691055c1f226a905922ef23ee145029258a2c18d54b77b91efe9e560b38d3544812b8a40909dba0d18ce662dcf3db27e9fb38b056976efad122110b45ab87c0ce9130581cc2026fb8713d08ba9605a97c2a6956d906af1b41d5bf77581815ea61873692d32d2f35a5fc1db551659dfd241cdb75d8167658d8663519c05d3446280c059b9fe898ecbadbf763e346b469a22ad95fcbd67cd50faecacccb346aa5ebeb05d79a91f796a2e1b93539fa7a45aea2435fc301ffeb0ca21220b0fcb62c0cb48f1d113034a471a8bad131e3701176957f828aec5a0eb0fcd96028ea3f39d464560a891fc0303c2f0ffb17c384e640c5ac0286ad10ed83f8ec310a886e501d8a88f12b2aaa3e12063a9801ca75278756f316a1cbd21b1e41994f7ed5dce24388f210a2887d103abb1a13456bd8668bd924a3b30abb678b9816b82af7e956b64f5556b72c38b3cb1ce5a83e5952b18f42e34e561a90daa9072a908cea034bbc8708c57d7cab14fb53ea24dfa16f895c3b34b46875f8744b159d77ac59588cb85d55a07114ec002d14e5a9e7769dd75fbd52b36ded9d6391111ee24c8aea92b1d6934efe840cf65258652ee471ad64a648c286775cb5d1bccea27dcd5c01c31eae56ccc18b197aa409818c49b961c8920094528f49b8f62d12c1ca37fed2b69b47d9829d182c1ab6bfa01ae420921873da71f13e3f074048e79c0fb0e364752d7ca59d98a8dde86df0bc388b6cfa855ac319f8f801677bf89c060362ec61582d121f4dadfe9c8da63f89a99493f380a611718835b6d3b07663a35a467a4b8c9c2032757dfcd169b0e1b59096286a426e6d1e35f4371ddd415e1d7d1cf101e5d9eaa1be9d0727c764b061f67a304a1279aac6a8dc6613d6195e52e47dd47ae64a56537c8e1551c92c9dd7d13a39b4a358a430f57c91f14c8069717edd89ed3a39a0da23e4650016ec25e005636ebde04e9a2338187bf07f7f204232aafb81c9d4780938b0d969bf8720054abcb8d445d44ec8c2243c4c51cce7a668b7c9adeb4bb306c4cd94cb3fc187caf136a1ab6464428a883185f05e605e4ccdfe04c9262f60e9fb0eeff75881f687e2974e7b978d61aa06b04ff68aff6b591eeaa1f2a8bc49969681d6e9d10d25933c507a9d93a535c3a5e306705b60748c07e07f1093357255cc188463e4fb4c34cf285ef62e969753226e95250828c21b8dc015cb11ecd026e5e32375e03128df4ff32789003e16f88513a3c68abee111bfacb470caaaa31430e0bb5bac07cde029a21fa67e9842d4a6d7964b6d9037f6c000b2c480dc68667c6446d1e050f9e7a43f9df958c28471ed0e33709deeb264091bb83bc7f27c15b231cab7ee92968f269de7838eec01ac9e3e03bc2d20104e3684aaefe2251891b2da54f3354dd08fbc2ba537f35c85e2e5217a6be19ba8aa17cdd2ae81cf202086ca2f06767eaf5cf85fc5060b528b5b6ce6e359ae8e9ce89da320cc8e99cf83776edf3add4ba00ce49cbfbc6d0775bfe728e48934ba99c7d7512799a9fc6b24fba716616a6fca70ea5b039c37d51f1f43a83219c6f1a6a404a3401fdb778dc336b8913c2d89cd1a5b806cf679b915608f4d4dec8de7c3457533f023222440cb7c7b1c3a3a22feb2c639b954238074dea7c9da9fd43b85a3c3a80635da520ab8810251a840143d9a31564912408efe5faa2db3df744d00cb9cd50efcabb609e068306ea9f4b68f1c7ba59d6c4cb65f90a90850dc3dfa09150f1f24f26878292c6015bae8a24fbdf2e4a012736f7d02a0fe11bac9826fb26e012485b476cb006de9680176d16f3ea9c5e73ebe8607f0f77bc40688774698f9be590979678808bdabc8549be9b4beb31a25149080e1b38d7a4dc3408cec5859756e9325283e8b312541a7e703c75b73e40c108fec13413a259f0e3a0f83bcd751bf006328c061ce8efda3bed6a5febd16be95cf955b1463177264aa14c2ef20e2a98b1784a3d82a2b65b5fb0960558b942c7abee33b4c1eae8ec37254224e6118c943e724db9b414312242752de2d9dcbd8475e2d8c3914964c73dc4cceabceb357a2d96790e678451364230425295b7cc3b1b20f3dc92daf4203f1b5bb58e115d2c97f1508db724e4ebb629ebb73dd5e0913a76f2dc16274546d70c1b691a3fae03bc6db9f11cbb7e39756d112443848d51b69c14313cfe276d3\"\n\thexSignature2 = \"f4f5d9964a5af379594b9872aea6c65b51c28d089e59b307ef53bcb9550ddb27d9b4fb001100e13cdac760febf755faeefc44667db4983225c5db714516b867a557e6eb0210d40649a0242f8602e2def3ce8a9fa2d82439554eb21c5bbd96d13e08cb70083a011d1075b36a09dcba1efe2a36888049c65211229d3ec780f6912c19ff7e1bb8f75c7cc8b8a42e5aa18084ec5ccd44221802598cfa8577e04befa5af2b3bbb2aa44181c012f253b1ef7700114b4e505e4c0a672c7ae8b893eb0560adcc53d5c3adbf424601324d08e61980062e79d7506afdef5b4660e7b7d4700d6c891d95339ed8598f7c4be13dbd5ac404b0a655756ac020aa827612b4145cd96f2b242832c9a0aa14aa957c192f52642e947390c188e0e441c43f458dd1aa289eb0a45c4d6bd0ae47ee2dffe1f03e21e0057907ac06c9afbf6c94933a831cfa2917be304c3c23a9e49574fa2d26786beb9948831cebcc198b2755bad06684c371a61ef01a4e6b684afd53d3aa4f4398506e7d300e2713b05aa7f4818c5490a7fd122cc34fc07fea2ecdeb168949e83a3389bb58bce50aff380c707a2b6f664e92476b46ba85148f4dddb5fa371eb28e50cf2800965c214d74298972cbee99621c4e1518267745f3358430e3df11391875e30fbf191648db283dbd98ec0451f07410cd571fe51bf34ad00d04389013c7652af126d5fdb61f67b1d5ff2bb4e31c714b992cb9a865f7cce66c0d420fbc3d586cc45ae651d3098b96481e69af0fac22cad38db480a711acac3196440d2811ccfbda72551bb9fac7aaa3fb8ceb35690922c9b5b3717c3ec3a97a0aa8d0b42f5a4eaba8f7f2e6312e4f4dd239f76870522c866c31109e6a055fc03a1696e350da0d21ba59fd7d530628fe6ff8ebb9e70959c50215dcedf3039da142d07e5a5b8df4914f5cccce3e96c4ada2d7839ad65491e9bf1019bfca3c4e0cd52b9762011ec92e941c4749d34e3fcd04719535d1b01380dd6e54408fef2a6644435af3abfd854f4cfc58031e90480ab3d0aa406139812bf64e075b39674d09bc544f1481769bd2088bc04ee2e7e8a7ab910c83ccf4030adff9a0501d2704256c2c12001d2773fefa7b580472eea8b3cd1b28909ee7bba83256096d63dacda76d4757a1655098b96b93da7290c1c56607e9028a6da698bad7930b1d93e98ead0b5d467f8a41c239c05f715172dabdacce8ce9a663815a53ffb1ba4770b98136adfaea685d5ab01b60acb0aceb21537b701d104f9af07dc0d97832a56da92394c96df87259da1e201e65bda1383fe1528fb8c98ca7ead4432cede9fb6058f80bb6c9d52b2be420d09a2c847fa695a8c8d37047d4df7bc153ca9c955e0485aee8dda93fd2f4eb7910b484fecb1481c82f651d41e435ee9cbaa9047eb76a33ea0d7b8c71ddc53cf3e75f15d688add87cd3b27eaae2694c01c5b436d8b2ec934f800bbd13b87c5a5c7bbe0a471496953de8c6fc5acaa4372463691f8d0603ed916840677091a8c04f2b5b35e0b2325788777457de896009a6c0b0354c42ed55a6da166d7c109c676779e83a2dfab81392cd55cf1262b55aafa031b7cdea8b2c1506143ca8eb261f52fd87a36b00afd7c7e69e28e33ed5d978a3e1bc2743fcf09dd6c9cf6931e8a53c18f184e12f3b8c10f117f43664ee51db85b22857f5690c4b833439109d4effc166dd522dc0d2bcea10d401248d764a37cf39cf08e86bd71accce49b233789f54b4b891c2214da4d1778d4d26955330c28ae9a061f156b048dcc34683becc0cd9ce5ffbd2968bb4f1445f742212a6b2933830e0556da48de6f71766a4a7722776342af68edfc0938d8eb825a8f82ef5a90a6d68e0f333b0d187eab74cefc1a58ed59e69742ea1cb0b7e4fbe79dca3daa73bc4af1c019d28b59071289a6c4f480141d274ebc0249f3105c61746b2208548022542ffdf697e78d93240bd63d13977cdf39ef936bf0f8a464dc7f9fb289b694ad4543f90b1338dbed53341053916cbb8f645a29524dcb865022db71e6565839f8ecee01ade85508634a27e58bca4c4d224b26a4c9b897514254ab0f1eb5f4b487a5a2e35cc0a7bb111a5c9313e99eec8ae21cadf27f40cdc7cad2c2429d9ede0d8328769ed2b6fb3c00db50c2539a034b7c960da37eb6717fb3c71cc4a12722104fa705b73730a66cb82b2f9512b22dce3cd8337029dd824bbf7dc3037efb28453ad2ef6b37d3e12021a834ca7bde41355661044575593234c76bb99f0e5216d735603faf966e7d44ea86d49fca2e31e613ce0eab7ba2e90c3f33978b15c9379f9f481e4a427d5b9bdc3f2e0ab5288a1f0b46e8e4c4af023f65c4d7ca9f1f7cc59437bfaa2e4dd20611b29a7bab93dfbde99b62575df8cc6a140da24a99218e3dfb4ee7aa179987b1d4e4893a190962a881db6b91a0c3268f6354e9a06d8ff3789b242fc5b699879a9033ffab65ffc6e1bcbf96ee9ef41085b11fc362fec08c7ab30842ba11221ff29044e4e9660f0796b437d3d0d8fe9e2fc60e67db187109b7aa35b30eb38fd6252b35d2f5c3cdaf7e1f2311ea6ce6a6de6d1b681ede35078ac0a08cb79f74ba2fadd768b35ab789f83b9f9a5059e500de88a401d8a612e7740ff9aec5d1bf78e1cdd485e01b5f45da6e409b1372fa0b52e3918c6952c0f4058357aeee776b1eb0fe31615ae1a995dac73fc84068233b5b3d4d2c0443995b3442b1589f1f57f26667135442e41c7606997f4ad481a018401cd99a376e677488e1f5076c82ab2e194f0b7b369cac2261bfbc2dc749e5644e4cac3aec5db648707ebae08d1b43e1e08266b4b6c8d183b337f920868783cc194efa6d55bad9ccab2309e55426e95cae55c5bf20260389f052b6fc7d796d43a02bfc8f294bcdf1edecccd71af0bdf568bc6a2a143c0323f6e16d24e4e4ef647483a73c2358376daaa34b9478f095940a9201bf2f43ef7c6fa25e19c45eb874b54fa52ccbd478ded0e3de953f0a84237e3ecfbf4a9a21d6b8f6a97ebd3856a0b4b89ed4947e8311a33bdc959fe95d9724af0acf8a89cc6f5ffba212b9211363c6f004e7925526f1ea38e89ec23b3aae4a1efb05b11b2d8a5f4b337241533e38baa6907e14d6c31f1b11350435d4c5a9b8e851386cfcba6c3ce500ad123830108c4e2a5edda8627240b9fd9964939f984332217bcc00b579e87c912114ecaa2180b6d3c3a436e0ffaf9955d1707942930299d124a429d26c07bd349a0bb132bfdff861bd5bc5c15ce84abea3d040f77404c9ed1630f27cc11d1f885e56bd94703869989bfb52c008c287fc503b42fbc6a8f5f74b46f5844fd2dbca13d690f9bc2b620964a4dcea4bd1e8019683b07f7270b3610e57837d57fb6a84e06ffedf589744b84e19fe6aae8693eadcde28cd2be2990ff247ef0ef3f7fa70f83f3d67098b8502df4625601fe685b858710da059cdfa4e84bd125529f866a349a22deda060d4a1eb59428ff5aa0bee006eb191650cbbebfe34b618bef661fae3411220328547c1fc2a1a6067e270d84d6246df36b516bf49979c37f8e7eaf8f38bc173685c76db015af86b5cd34825dcf70d3b54efa55e9163f25c1de29c1ff2a2a84ed008722c9133f3f989f37e8f2227a43c5206d98fa1ad33894acc45e4ad6aa71c74df1f00efd3bd69f11b67626a15d60e1b86ee5716469e2d4af236d50e8f8a3dc38d754964a828ea42d691283cafd925fe7cad83ded6f8e79ffea0704e84850d6f1d695e1cdb28927721e0bde319feb8bf68acbd041c2464b30674c0f473ab857844a1f28292b34d9212765ae4077bd3f380c52e66552fe60a393607ea2f8c4cff65255e3a856f15b14def092b67083b0a9ab5ba31c9490e19266cd029c4b91f8c49365ae03a9494463a23a9effbedaf2c11592724098e357e50a2cbe3a1523fae9a7a045c775d29ed6066a7f4e65d30ad9f8b626ad3b205b6bf60e22a8cb59d250580441628ca648ddc0dee4164975b4cb0e5cfe686086197aabc88d6daa70fe992d48b86b224a8b123daec21352c2bf4b08664e5b90fe20dc7b378767306e9e86f570c82d5f05c2bb266ad577c451e95d68acd7ac57ae60744ad9f4161996fcad0d9fc471ba89a8c8f40b6d688286859f8c70bb9d2064391006767fb48b4b601450d2e58885399a6b24ebd12cf7e759dcb8fd30978d2a1ea467a5d24b1ea2863c63e5d8c16d608eb0a91605a89801f37844c782cbb91dbeaaedab476f8c41a5bd06f6c4e5515c2d9767a560b07e6c681c4308fac2222892bb349df2cf7331de0894d7ae6134da12da5807aeb7b685ec821d16e82e5c9b05e2cd79cf6c815fa66cac917b16ffadb726965921212b47be2619a7800fd2431ad104bab4b0ffef4b657c03e0cb9a8a66f88ed8a62eec2654bae77c21b3f301b06dccfc7a87dddd94bc53c65df57b2ef5c6fb2050e685546cc0097db0e5d75dc09901adf32bd868b9176b60ca4aeaa3283decacc3c174029a2e51a94311087ca4b9d7d611df8f0f79c8cf917cee6573e7ca3d9ab7189ed95808e934e94b7047a22c8d070ced1a2748176b4d1eba8500a73ef3d858964143536734d45a9895a15977d2ec80df408da20b2d516620dbda0afbc60d16df6c446bc84dad548c698caf8671c30e1480ad5ac40c1bcfe9a16b7240b59dc34b5a56b4a619f348727b1f215ee0943b90257cf776b1ed1ede32cb6bd379ffc698220ec2e1b293992cf790defb28b56fd37394bc88cf04efcf92033f0ce3f34a6283ef7dc837ad9065ac6f70a941c99a3dabd217bbab8da3c269228c93c99b6333521055908e91d311b84cbe4bcdc333dabd3592ec8b988a34b6bd7cc92dae7915096e9644176c84c5e6709edfec3404337e37fe11ce676bd2aa1a4e9a58d025142875bd52f8359434f6cddf05450ce870997f038a80b3eb1c0d8f0e469e2d08e9ae6f9cf0bb61cfdf18f332bc035ce8452435649f54fc83bd912be0651670dc0ce4baafd1ad4fcc9f5290b8f2ba0ff44696c9132dd52eac26bf147206c09b530a96404f122be01bdc9635df50fccd36c6f94dfec1e4e627e7639f281a22a59099e25a2fe6e3371747d733f9865a6509078ab2528bf74b19665c86eae5fb9b025279bf1059cf4d6ee8f4e12d08b0c2f46caf6e682f8ef6717ffc965959cc9eed146fa5fc6882d10f271c96fd8c399debe6eb5d4ca153913c22e6d54cd9738d9dcbf1c8b91a3c2c2d912576e4e6e35cdf35c092202f772e7c33895f64fa899d2280f5206759029df5cbaefc2b61e40bd148c611a6a21728345b40bf6a2475bced235e48a34907fa47edbca39e8f9a0e0ece57b6bea14efe79649f75379e554c41d8c7017ae0c43495e5c5adbbe14875f3527638c7acc56266907f26aa8114d0f2c65188c2e913c003669b26ab3f22d4082198f9484772a4f3eb8f9d9d2936926642a413577c8a472c611a60d55bc30d2a7b74eb57f95ed83658528d15483386844674b42f8f20621c4c9b14d0c7c5aa6cda1c90fa904d6c5164320f0eac1b60592f1deebf47d5ac143865323931cc470fea2e060379629bc341c2d74abda1ec4e1bc8891c75f0e94cbb9f7588884f88b156f61dcb0419108923f63a85ce06db231c77dfd033b974513938644b7fd19f2bed75a4da4a5f3ce71830c1b806e814efea3ce26291740c46ce267e4d8a7e90ef6e34adb0a45e84abc76eedd3a4c40720c1a07c940472d386e637f6003e2252d1310a71f0ec0d3d43016ba2e1a102abcac4238aea9ec272c8d8b91aacd87802874795164c0d14bc5bb0bf1c67179620d45f11151c74a6b3c872a5f2690f6344c0214f2e0560ffc7aa7f7a2223b53210249af1ebed29afe7610b9b80c5a38b8a11b8e017bce930d00a3874fe364b188159ff9c72177f61844807c331da92fa7eb0b6308c1705b60106235c27c49385e6e750ae9323c39ef2ef9f0eef7a653e8115367d9769518837538a8b809ef42b04b9dceba2a88d5a20e2a2b23b8288057e9e7034ee34f1e8bc8f90bf3a08d58f1a2982d031da996d0e350f28fe3c3dab8ac5f37131e95b1052632628df08d6f0686fd0c0a1a32b6277a7cbee4997823d6327cf6e6a72dd0abdbfa908038c086df5a3c34f9909f4b0740bbfbe446cb84df3b5bd0ba2ec5901a74f20f22893167be220a7a304c1cff622d8b606bd3068f7c01adc39fd127d97acd6474bfbd4f0dc87e71a3ecedf7290041f0c591547a63ba0b4267c1e6ef7c679d077dfaa4977d70e2397a773b72bc0cbafd92389e8cc9a8ecb70e531236929ed8b8d8909accb8aa00a3de64d8819a086b8d0fe0ef6ad491315cde572ccdf7119a1353a6dc2aa94cdc4bad2f32892f33505cffef9597b2ca3720c983cc4ce21df1c9250d3bb3a4cab2131a836be7ae46f89ca2749be1a23cabac7fae8c70655d955f9d2bfc62156ecce51e3a54cbb5667387cbf8ba3b4b15e4f8032944ba0638df2e0d68f6e1cbfa180e398dc90c9eee07a70fec91a7db7d5e4bd92ef9dbb1af1481df13c6fc89483f5abc76564e658b33245e7035b464a1ee48c5a38fbbd6c5017c91de16088a74018a8ce2e5521f262117179c9e71300f789164581f2bf33f9a618d3aa2acdf4f596ffa8016c586809a332c88e9824267fc2ba18a8c7901d86cc53f56699643b225b0574a6addb63cc6c9d6607fc4dfe4af97630873b6bde63c2ac39c0f2a82a1040ed69cc759414bfa67791ba6b477b2e9e9114ac23c5aa921f27d327089e183477dfd0fe89c61204b423e95db8011c43b4e517dc84d11691cb8157c8b9a62fa317610b9558977657bfcb0b7b7a1d2aa56f10c13f95226d73d15cb677a94337b7ecacbe108d058b1ea79be9682f1556475626b6f9269bf3c39fe16665cb4c3ba0f26eae37634f9b19e91854687e9262ee86f4a0662716f4d4ce07fd57c0bd79313eb8eeb1a8db89a545b29f862abdff05175df4601c0ce84f4e33edeceb8e15d919227ccd57421bd41c6ee5a480cca27b34350654192341161fc89b54fa2c79f0c9c1c6a998cddaa76030984a3854f94e93c92bf2ecb1278aa5a19cd353fa4edd4f100fab04e6054687ea1623859b5238f16b0456f03b06d911b120b8499fb65dc57ca7e253f41ee9147f96c35d318dcc50cc766b6d6e2a48e0849060378d74ba6d639a8597a8985ad3d75ac43a1cb33b5a2a89afb4b2dbe1c96e89935b58aed7c03037349af452fcf230dc2c385c48cf667d6681141dbe584a7092745699cfa499de75538dd0f742e97b9ec0e1fe7f6de187216707865239cd7f9b175fdeecf5a49d97e3e9fa8209a3bba26e59fd8605402ab6b21cc5aa68b2ad69be80419c53e81542c12a3458b6f90c60c2e25d0ec44b87ecf7e10da4bbbe6a160d84a155007e89fa119fd813495a87c058ed945434aa2ace46bf0d23965c0cc8963b3cf41504023735348fc232495d24ea23c539b635f536ed2973ef9854d1988cf9777f426a53c59a9c259b5af30853d0b4b55151e0c48e81122c7c5178320fb73c1d4575520656eb7bbf5ca80b27fed31dd526e61ec0e40810358b70b295aed8d08a03bccdd84ff5c3409a1f23a9278600fee178a97acf5c0ecb81ff68d270c73d111eeac68b6f531005d63daae7324aec31630051428266a40ee56e3ac6115477f99c3d8c4975331a95d7f7762ef9a8b809c181dbf1d2e8c81be8066fd259e61588061002f4844000c8867ea4761366a790e7ecfab71d57c06b629693f13aad20110b636032ccb575134feda04401f09b05f686aa3bfad9949cb775ed4c2e320afb26f4fc4a2564c593a52c3db150df73939ff164bfed288fd442cece64ad461d71040abf778a0345d22c9745b4b266e9fae6930c92217bd41d966d1d3911945317a53b9216190fd188adacbe84d57a3a600ac1cb50e361b27ecd9d116d264333cd4891a00c5990b3782c86ac745b6292f6623dbd2fb730bb7aa518564125c56ee126e83f3538c98c453b8a87c79cf4285f8377ea8469806c3f99fde2d4225510724d9fdbc6d9d41b01ff70804e5b8e6286d5a0135e256d8725eb32b95c1582f0f296fe3296453e4407d72d474d459bfa4d3a2852e1289f8a7d1a04ef42c14704b577be4448454dfb08ec645cef675f81b1d3547497615508121fea69085017f43874ece7c54b6e5bfc6307a5231cafe2f5191ae5c136876427542f73439cf2aa69f521c69cab2ec89bcd6a290c594de1d951396d36f9162daabd3c789ff63c5f3f5be741dffa162efaa8f2702131d473f1b724b858f8aac130f0c8139c7f553c04c384ba67508e444d60a95969a13b952b6a7e890f9becb83a09f097c40baf5954352c1987b5b9db451e526fa4d83f122f996383b3b582977faf402c393cbbfa45581eea8957ea3da64d49d94157ffba4169d2362aa9b472180d737bc0a55078428eab0f9eff43afa68d92bce3afd5dd0ec87ffa63d7d079213f8ade4536fa7f926bf59dfc4a1a1bdba630ce72e103e18292b5dfef65d6bc7d8e118296ee2c0a6db412662bbf353948b9ba88cc8339ba90370ba7316b33069ed08d822926cb53da23262087a7ed64f6bde2b73c2dc3c538a94c3b9a3a163ac85a181c7e8866fc19052474076a8a6a6af50fed2065554619f2fc0a38653d941d9fb4df3b74ab6e877baddd9f8cb915cf3b2b899960190c7f8caf3ec6c7ccb3e7cbe2bc6547c4908a49db4414c3e07c086309a2e4676ba79d310f283a38c1f14534ff39e6c744ea72ddec43b0107a8604b5f34bc9a31f200befd27a9bee1091e2deb2f8f089aa1bc76f4b09fd21886062959db554d28f328cc5e1d2ce22f055b1d105a5233394247c0ce50b78a1b0298e5114bbdca643c717a8271de9b822971d1810d97660f1d6150a9d0b95d1c227e763c3e302c1fefd3f656f96aa4c63ad340b5b4380513c30531f6113adc5b5b48483f9239a8f8686d875bb06d190237fa3d92928c941fc1384317b35e902f5b04d0cc5f58c8d4d9a96dc68e4240487b1fd01208b35d6263cc7012175c1d1ce708d8969773ac35a175f1679f03b248a38ed8519d1b48d8ea55ca82dec86b0c32235c689748e29adf0ffe8e04dc823a67a1bd220b98493e91bd614661b3673f146c68b3062c78e9c839701319f179f36d682610ef7fd929095b2d763231843af417e228e551357da3e8ffc465b474bc930fbe6a66ad442e3b8e595e7ac4c16330e00dd0ebac867feeb40c8080e2a02a42517fde15fae36c6fee9e3afdd4ff3dd9b8e0c8927b0ccf47fd2cd4a421d239143e0f0b0058156b69c1e64e776b86d4cbbba54fef97baab2853f7965cb2fbab3201a8bc5d3df40a66bd2a5961afe862e40acfaf45c56ed39250b49cc152c33e90bad4bb9d3caddd0bc9cb0d39cabea9627691055c1f226a905922ef23ee145029258a2c18d54b77b91efe9e560b38d3544812b8a40909dba0d18ce662dcf3db27e9fb38b056976efad122110b45ab87c0ce9130581cc2026fb8713d08ba9605a97c2a6956d90668d6a48ea0e052177eab58464407ec2cc3d8049928b1b605fe71b55f693f9cef163e5de1f576dc8f3ba5b7f9948602deddf8bb7d7e58873f25e9c119275366f07cd50faecacccb346aa5ebeb05d79a91f796a2e1b93539fa7a45aea2435fc30124112ca6096c24f6e807ccd68fc1b19b9671832b15ca8f557d22f141172529ea5a0eb0fcd96028ea3f39d464560a891fc0303c2f0ffb17c384e640c5ac0286ad10ed83f8ec310a886e501d8a88f12b2aaa3e12063a9801ca75278756f316a1cbebd51cc8179c24fa4f7005fb299c9b5276c693d04dd710ea50361004520f182cbb678b9816b82af7e956b64f5556b72c38b3cb1ce5a83e5952b18f42e34e561a57ff95d7ea53dca061a724bf8a4a72a253695d1aa90682b41f51827716a3354c1db501d49f53c101b1cd036f8a5ed1148c8f7a92fe63600ab357796ff10287f49d6391111ee24c8aea92b1d6934efe840cf65258652ee471ad64a648c286775cb5d1bccea27dcd5c01c31eae56ccc18b197aa409818c49b961c8920094528f49786f33184c52888bc3cf7a448e0e9445919343f3302244d6e671136dd32b0cad87d2e445e479cbd18b7d3b6997a2a2cd9c8bbd632692367847795bc8532e5bbb677bf89c060362ec61582d121f4dadfe9c8da63f89a99493f380a611718835b6dc9e37ae9c713f292ed074bfc770d79e467c510b112b57fa0defcd44c5bab5281ddd415e1d7d1cf101e5d9eaa1be9d0727c764b061f67a304a1279aac6a8dc66bc65149076b73753677ced828d0075e1739eaff6edb59b99e8bc3c62a200566d08da84065127a5eb1ce6e9b9320b2d3ef42d33c07fa4d765c29871fe552466bff07f7f204232aafb81c9d4780938b0d969bf8720054abcb8d445d44ec8c2243cc8de44b82024374aa6852994678f2d38cfff9cac17561e6fb44540a4c6ab2fb0d4b2046134b2b4ccf4ba8c6006d4245857fdc8a72209e5fd6c667514bc03350aab2f1faa19fb1d8a340f5704a38d2cf800f994fbaaf0d50ed24d4666e72757d9705b60748c07e07f1093357255cc188463e4fb4c34cf285ef62e969753226e95250828c21b8dc015cb11ecd026e5e32375e03128df4ff32789003e16f88513a3ef9d6174d93e2a011af1a0809a3c0d13a3f88c107fa8601ed05134a4eb1c3f634b6d9037f6c000b2c480dc68667c6446d1e050f9e7a43f9df958c28471ed0e335ec681b3e8824b8649f32575d46f1eb98d86a23200ed92454ec1b079947439b1bc2d20104e3684aaefe2251891b2da54f3354dd08fbc2ba537f35c85e2e5217a6be19ba8aa17cdd2ae81cf202086ca2f06767eaf5cf85fc5060b528b5b6ce6e33f213bd82319376cf28e055ad28900922396b465beaed7203ccf4699e937a3c997639c25a9cfef601bdb6b34c5e56cd0f586a20fc2e75bbc49492220bd7ca9e5e95d19afbe7a923e02e81f024c2aec62f7ad986d67f637dee4108658c663abbe718912b2629290595716a291b6ba209f655a0d465e7307dd36fbec72abd38ccf9fd43b85a3c3a80635da520ab8810251a840143d9a31564912408efe5faa2db3df744d00cb9cd50efcabb609e068306ea9f4b68f1c7ba59d6c4cb65f90a90850dc3dfa09150f1f24f26878292c6015bae8a24fbdf2e4a012736f7d02a0fe11bac9826fb26e012485b476cb006de9680176d16f3ea9c5e73ebe8607f0f77bc40688774698f9be590979678808bdabc8549be9b4beb31a25149080e1b38d7a4dc329a2a0aaf72074d8a1170ac9fc72860bea7ccb2c7aa10aac3e4f847218564b33764db0b796104e04ebeca4724496321996167f8ead4269f9b6b81209c6cf3687f4bc733978496fa5453bede0e5bb914e299d1759929a64bdf07545920ecfcb44747f3e49fa50901a73dd9a291bbed0344535d28b009d864411f471366eb511edf587fefd70887c9f77f6b0d031260907c33941fdfe4b1eb51d28c0ae0dd607b09ae45d66979bfe470524e11a80c89209450a36f44c0e6dc2db7a8979258c204d70c1b691a3fae03bc6db9f11cbb7e39756d112443848d51b69c14313cfe276d3\"\n\thexSignature3 = \"0e49fe1706d9e93b3793e1057f328c4206632da58c13b1aa3c95158c1a68b8b5d9b4fb001100e13cdac760febf755faeefc44667db4983225c5db714516b867a557e6eb0210d40649a0242f8602e2def3ce8a9fa2d82439554eb21c5bbd96d131e28d88aa59d7761c0f92cad83ef4fc21ee97c09a81e5ae20a4475b68935c3ec4d06c1d2a2165505b667b2741a5311d2a78d99cb46163b8b6d65d04ee40c2d3e5af2b3bbb2aa44181c012f253b1ef7700114b4e505e4c0a672c7ae8b893eb056e7232b5e9cd52d09b87a8025e9841d2fc2b890fe0a0f3c4c2c8ee7b464f4e1fad6c891d95339ed8598f7c4be13dbd5ac404b0a655756ac020aa827612b4145cd96f2b242832c9a0aa14aa957c192f52642e947390c188e0e441c43f458dd1aa29dbbf5c9c883587a3ad43770222cbee2dc5ee22f0050d9490a4b1a278206cac70754d4196ea1982eb72df2d285f27d774947a05708003f449cdf19d8aaf8e63d4339b9eca58b2cf9168fbbc27ea6f9b65af1651193370f70e3af4d1cafa7a2db7fd122cc34fc07fea2ecdeb168949e83a3389bb58bce50aff380c707a2b6f66492258e6a8108630e683a51d9bbd15b78c313e5f3b808ffd904ae27a55fc8ae8a21c4e1518267745f3358430e3df11391875e30fbf191648db283dbd98ec0451f07410cd571fe51bf34ad00d04389013c7652af126d5fdb61f67b1d5ff2bb4e31c714b992cb9a865f7cce66c0d420fbc3d586cc45ae651d3098b96481e69af0fac22cad38db480a711acac3196440d2811ccfbda72551bb9fac7aaa3fb8ceb35690922c9b5b3717c3ec3a97a0aa8d0b42f5a4eaba8f7f2e6312e4f4dd239f76870b177feafdd612a25edf25943ac9f3c7dab34947d728029ff5d2bb0d01e79784402216ce5ff3550db5eb38b5e0f7964afcf2c0a9f4b7e4693f90df9c58bcf2170a240489f62ef7ef8196bbfd162e13d8fec57d81ed815569640c9b2f09f9435fc2ddef0cee72cee5513e8e4d16b245ff83ce64e1c2f8c098164c193f951591d5139812bf64e075b39674d09bc544f1481769bd2088bc04ee2e7e8a7ab910c83c5d87cf998c66ae4b85cb147bfbbd46dfc33f762a5e8575853cb7b96291d54d4fee7bba83256096d63dacda76d4757a1655098b96b93da7290c1c56607e9028a6fbd60a04d800a39c35ef641fc20b91e2ef296b67ba58c3c9418544965df7fff2ecb73de99c214dbd4574e84414c6ef628b087c9811bb93e97c987d805df599616edc2a60cab5e866c7686c57e1bac8632cac62832894efe0c075e2ae689a86b8346bd6f553a11824edccefc08b03cab4beac4cc10d77555ce484655a7ffea197cdc93c34c5d7df96d4bd92c0a3516cc277ffa1a14d23ad64fe7609dcb9f34bde74c128268218fdb52258f257c4caf22f2337c6c62ec1f67c423e19a61687325894c01c5b436d8b2ec934f800bbd13b87c5a5c7bbe0a471496953de8c6fc5acaa388718a745fe87bb127c0a4b390bb8c865513d2cfc0063c38a41f4aa01591901009a6c0b0354c42ed55a6da166d7c109c676779e83a2dfab81392cd55cf1262b55aafa031b7cdea8b2c1506143ca8eb261f52fd87a36b00afd7c7e69e28e33ed5d978a3e1bc2743fcf09dd6c9cf6931e8a53c18f184e12f3b8c10f117f43664edbcf5aba63ab383397ff2348450530f986bafab58e2f5d99a80bb854c6eef15364a37cf39cf08e86bd71accce49b233789f54b4b891c2214da4d1778d4d26955330c28ae9a061f156b048dcc34683becc0cd9ce5ffbd2968bb4f1445f742212a0b49536cb2e8d03dd8af882ec87ad0d08f9681ced02a23889aa2396d133b2a13042cd0f915357e4c8c1b86fe92398382634d54d2dc93c42891dc8b193f9790fe54ee58537157d29af2bf1c1c6b667c365b1768079053dd1a9a4617a511ab7f4008548022542ffdf697e78d93240bd63d13977cdf39ef936bf0f8a464dc7f9fb289b694ad4543f90b1338dbed53341053916cbb8f645a29524dcb865022db71e6565839f8ecee01ade85508634a27e58bca4c4d224b26a4c9b897514254ab0f1eb5f4b487a5a2e35cc0a7bb111a5c9313e99eec8ae21cadf27f40cdc7cad2c2429d9ede0d8328769ed2b6fb3c00db50c2539a034b7c960da37eb6717fb3c71cc47aa25fdd9b27c8ab24455c9dfa934267d101de0197480a2820b5c59597930675a1d3269f7c3e033cb41dc08001dec66224a3d2364f6f14b3991ca4726907a5a10e5216d735603faf966e7d44ea86d49fca2e31e613ce0eab7ba2e90c3f33978b15c9379f9f481e4a427d5b9bdc3f2e0ab5288a1f0b46e8e4c4af023f65c4d7ca13f0ec4bdd50821f90ab8806f5d33689de6aad54c4d9a8236023635164b64001c63a3569316ac5c16ecf2a7678e9bfe1dd3f1e3c213955895ecd8d4897b200f86d8ff3789b242fc5b699879a9033ffab65ffc6e1bcbf96ee9ef41085b11fc362ce9df7c76ba2d66a0fcf10dfd14bbfe75498e8e0e87ff12ed1d4e9a250fca71e187109b7aa35b30eb38fd6252b35d2f5c3cdaf7e1f2311ea6ce6a6de6d1b681ebd6af74469fa25656dc38b1dc7408c81acef402c74fc23be353d4fe5b606bdfbe22e621f76c581a9f85b0d7ae39e58c078534ec76682067e0ab85f2aa6c9d46452c0f4058357aeee776b1eb0fe31615ae1a995dac73fc84068233b5b3d4d2c0443995b3442b1589f1f57f26667135442e41c7606997f4ad481a018401cd99a37cc8e878ad05df4b22f92cd5858864fbb7edb8442d1045b53374f24a6a233a1b95db648707ebae08d1b43e1e08266b4b6c8d183b337f920868783cc194efa6d55b2edd1ab0ac51e5f46eb1cbcec86e0a3acab54fda2eaf244590390c4a163672778d39db4b4baa340d9eb4eb0b7aff432ca76552b5092c0cfc1ea55c702b2c5ac58376daaa34b9478f095940a9201bf2f43ef7c6fa25e19c45eb874b54fa52ccbd478ded0e3de953f0a84237e3ecfbf4a9a21d6b8f6a97ebd3856a0b4b89ed4947e8311a33bdc959fe95d9724af0acf8a89cc6f5ffba212b9211363c6f004e7925526f1ea38e89ec23b3aae4a1efb05b11b2d8a5f4b337241533e38baa6907e14d6c31f1b11350435d4c5a9b8e851386cfcba6c3ce500ad123830108c4e2a5edda8627240b9fd9964939f984332217bcc00b579e87c912114ecaa2180b6d3c3a436e0ffaf9955d1707942930299d124a429d26c07bd349a0bb132bfdff861bd5b692badf468e8f4d346c015bcf2f3c26cb6ef7729a66cce2358c024581877294bd5247b0cb67243061a827a575b6958ba2ed809c55d75f898eb3074de5e490f43452e4e8efb7aa763c26a45bda0d99a1e4b0be489f528f6d6bf83e6dffc2094490a8e6407440d53c9ef7a50d179e2e273d35e37529b8ee1b3f0227f91cb1889cd25601fe685b858710da059cdfa4e84bd125529f866a349a22deda060d4a1eb59428ff5aa0bee006eb191650cbbebfe34b618bef661fae3411220328547c1fc2a1a6067e270d84d6246df36b516bf49979c37f8e7eaf8f38bc173685c76db015aadcf93b7e7ef105be8c4e89df168487d9dab0bd9dc6b972f4ec071242f901841f3f989f37e8f2227a43c5206d98fa1ad33894acc45e4ad6aa71c74df1f00efd3675df3f08a00e62f03010fc9d049ccf8b0a676c6f1603959e1202a6319706fcd28ea42d691283cafd925fe7cad83ded6f8e79ffea0704e84850d6f1d695e1cdbd335e11ac75abfc6ce977b28688242fef27de931c52732b6eb1d39020f49f5c5cf48878896de5d412435c79a810a5ccff084c97e441ffa159170347b72d67abb1b51d636b6e1d2e2dff08c96b2201afa84fc43143ad05d61f80302ce457aacee9494463a23a9effbedaf2c11592724098e357e50a2cbe3a1523fae9a7a045c775d29ed6066a7f4e65d30ad9f8b626ad3b205b6bf60e22a8cb59d2505804416281fe78c2abb72ac09b4d5d2237159f733b53a699041ff1800488ff3ac90739d2b24a8b123daec21352c2bf4b08664e5b90fe20dc7b378767306e9e86f570c82d53d025babbc546fc7094c067da9836e189140bd43734ef9834be3e25e235dd9a3a306045ac98a244c25c472dbc226505c8cd8da89f68641ec3932a18b720bbda05399a6b24ebd12cf7e759dcb8fd30978d2a1ea467a5d24b1ea2863c63e5d8c16d608eb0a91605a89801f37844c782cbb91dbeaaedab476f8c41a5bd06f6c4e5515c2d9767a560b07e6c681c4308fac2222892bb349df2cf7331de0894d7ae6134da12da5807aeb7b685ec821d16e82e5c9b05e2cd79cf6c815fa66cac917b16ffadb726965921212b47be2619a7800fd2431ad104bab4b0ffef4b657c03e0cb96a3931440ab20c977e8be1186b090dfcd054abb01018aef8047dd1d5b1fb0462b2ef5c6fb2050e685546cc0097db0e5d75dc09901adf32bd868b9176b60ca4ae3754c136e4491c4043babe09c5d0a54cd5ca94553103ebdce73650677096271f573e7ca3d9ab7189ed95808e934e94b7047a22c8d070ced1a2748176b4d1eba8486eef5b2ffcdf76c944cee8a9afdd7dc7c97aa3782cf8e87019c27b6d69e7cabda0afbc60d16df6c446bc84dad548c698caf8671c30e1480ad5ac40c1bcfe9af473503ae8b87cd84165716203f6d5432b972fab50932da8932bea64f00065b12cb6bd379ffc698220ec2e1b293992cf790defb28b56fd37394bc88cf04efcf9b2a6cf53db75817127c893184b7e2f2e12bad7b726ce8f06493e3c6324602c149228c93c99b6333521055908e91d311b84cbe4bcdc333dabd3592ec8b988a34bab8b8de5903914d0da7bcab87352ce9f88ad844097bd0a5ae40fb04c3194b72fa1a4e9a58d025142875bd52f8359434f6cddf05450ce870997f038a80b3eb1c05edfbdb0fdac634ec05c09e1bea594fcfab009edeafa0593ee7c335eb381cc4912be0651670dc0ce4baafd1ad4fcc9f5290b8f2ba0ff44696c9132dd52eac26bf147206c09b530a96404f122be01bdc9635df50fccd36c6f94dfec1e4e627e76dd0980572a80ef7e49f89c0d50ae10ac438a49efd1a895bf0c9a23d67272a3c2c86eae5fb9b025279bf1059cf4d6ee8f4e12d08b0c2f46caf6e682f8ef6717fff72f6ab8ad6d9a9c936615cf37c349e627dc3e91bf354a08b84448234fa2ec9cf6c545bbba9eb39d08688c53a3f2b60f9e5529f54526fb993fe2bb5a5fd367a80575e5100e36661a9874f3266d1ba90d46e3e7e2dc925dbacecb7491d96ed3fa996aaab025ad207e56fc8833bc58e25f395359af5f3493c1e127b8c75be5a208d6a538fd5114163b5db44ff90e7fbd493ee902b6c275a9cddc129bf8e99b74c7f26aa8114d0f2c65188c2e913c003669b26ab3f22d4082198f9484772a4f3eb8b0f65d734f6b8d6851bd1d26224c183d38acc7347f7277136aecd8efd7cc259028d15483386844674b42f8f20621c4c9b14d0c7c5aa6cda1c90fa904d6c51643c69f158576996f3b42bb079d1489b6723fb23ef7726a1a0c19c9fffbc9fcd8a52d74abda1ec4e1bc8891c75f0e94cbb9f7588884f88b156f61dcb0419108923ff4c90f28940dcd52b0e0eb5fd255b7b698358e1c13cf05cc6c2e7b89e25968d74624b2b307494598b39dcac86b7642f02bf25559915cd42ed57180bee8cc4323c365a7dd2fa9682e44b7f733d2a509568c43a0c484d28e5825291faab9ec21b6ba2e1a102abcac4238aea9ec272c8d8b91aacd87802874795164c0d14bc5bb0bf1c67179620d45f11151c74a6b3c872a5f2690f6344c0214f2e0560ffc7aa7f7a2223b53210249af1ebed29afe7610b9b80c5a38b8a11b8e017bce930d00a3874fe364b188159ff9c72177f61844807c331da92fa7eb0b6308c1705b60106235c682f824f0b37b8e0ccf895e7365ea3830877d879354785c62329c4fec12b825b809ef42b04b9dceba2a88d5a20e2a2b23b8288057e9e7034ee34f1e8bc8f90b3edd5c0e73f9140d1802ac19cb0ec060d2c0670e116886b4bfd0bfbd8ec2b525abd01e4446093f9c2064581b0736cf28c93d5cd11d1f80ab7d64faed8a99f5ad898a02b3c460dcf095adcae69b1791f319dec73568ea112497c7f861c437464a22893167be220a7a304c1cff622d8b606bd3068f7c01adc39fd127d97acd6474bfbd4f0dc87e71a3ecedf7290041f0c591547a63ba0b4267c1e6ef7c679d077dac782f235d0460ba8da668837008eb7006865a4c50a09130e27d26aab97c9c49909accb8aa00a3de64d8819a086b8d0fe0ef6ad491315cde572ccdf7119a13539eb6c7563356a29ef002cd70802e9110f770294c8255ef9ed86e612897a7de2f0d3bb3a4cab2131a836be7ae46f89ca2749be1a23cabac7fae8c70655d955f9d10ad64e0b91b5a387a40c660d6b5dd7d1a7d5939f72cd0a4e9f82d1277709569da6713824282fcaf4684c49b2081fdc82a707a93bd62a1c679c22199e5c1253d13c6fc89483f5abc76564e658b33245e7035b464a1ee48c5a38fbbd6c5017c91de16088a74018a8ce2e5521f262117179c9e71300f789164581f2bf33f9a618d9245b5afbfc2e0be97a2fb86e2f228289d191544c286f2ccaeffe54263c41af856699643b225b0574a6addb63cc6c9d6607fc4dfe4af97630873b6bde63c2ac39c0f2a82a1040ed69cc759414bfa67791ba6b477b2e9e9114ac23c5aa921f27d594629d55f2cb9ef4160fadeec9a3e8dc1a2c6b1569fcac431e447e1c89899c87c8b9a62fa317610b9558977657bfcb0b7b7a1d2aa56f10c13f95226d73d15cb178a8745d42f9dbdd5ab8af3c711350f70bbc33067472e24220071d05aea31db445a57eab0be0f7527180cc2b8283f978fe2da8e7f07b80b1c422225f6d66d8494ae8b3c72f8f785f306376143f2c483392f14b637706c7dd42afd0d3567c74d85afea12c95de543eece7368d445f0f48165c4420e760f8cd1e84e25710c7717b54fa2c79f0c9c1c6a998cddaa76030984a3854f94e93c92bf2ecb1278aa5a19b6c26ffb2efb9e31ac9ab7d85316a2d01c1737eae5b759ac378e7a49ddd97a440b8499fb65dc57ca7e253f41ee9147f96c35d318dcc50cc766b6d6e2a48e0849060378d74ba6d639a8597a8985ad3d75ac43a1cb33b5a2a89afb4b2dbe1c96e89935b58aed7c03037349af452fcf230dc2c385c48cf667d6681141dbe584a7092745699cfa499de75538dd0f742e97b9ec0e1fe7f6de187216707865239cd7f9b175fdeecf5a49d97e3e9fa8209a3bba26e59fd8605402ab6b21cc5aa68b2ad6cf1ec42a225a94f892f927a47da041cbe1f09fefde216f72f34aa3d3530bb44b60d84a155007e89fa119fd813495a87c058ed945434aa2ace46bf0d23965c0cc8963b3cf41504023735348fc232495d24ea23c539b635f536ed2973ef9854d1988cf9777f426a53c59a9c259b5af30853d0b4b55151e0c48e81122c7c5178320fb73c1d4575520656eb7bbf5ca80b27fed31dd526e61ec0e40810358b70b295aed8d08a03bccdd84ff5c3409a1f23a9278600fee178a97acf5c0ecb81ff68d27ab3ff0676dff99ab77313457e44792de597e7d6df62addfff4a341eabf9926eb15477f99c3d8c4975331a95d7f7762ef9a8b809c181dbf1d2e8c81be8066fd2568fe4409167da69df498ea17c9e35cdeaaad0033cb18ed62cc1dc5cbcd13d076a34d551096839b9d8e4db072c95a2149de3a18eea765155f69e927cc7ccebafa3e6065044cad620c50d3d5d6229a569ea1004391c9c62882c33e448077266fa9d461d71040abf778a0345d22c9745b4b266e9fae6930c92217bd41d966d1d3911945317a53b9216190fd188adacbe84d57a3a600ac1cb50e361b27ecd9d116d264333cd4891a00c5990b3782c86ac745b6292f6623dbd2fb730bb7aa51856412b347149e15f7c227d77721a736d92f52fbfa82fd83e7211ce2865845c2b2718cf40e337b5b9482202d67e90bdcd7255a4161f35c5592d2fa2f4dd6dfe0874b62ddfc0ccfc347b927cb85ccd274351bec258cd4f87d45c788c9c7fdf0d288d01bddc1118529dc5661589be8fef4a284c80e589d85f645984a3fee953c374de48ba4d948f2617b8f2f838ae46a3e9c4cd0bb740b5485bf90af1fea6948a229179177afc6e89932e6c1b41cc1b80ddd9203bef03bcc1a970eeb2db2b9dc9c7bb94daf8527c39dd66697a1592ab8af20dd9b0da37295615bc0ec7fec67825878abbe94b17e288adefe009cd89301a3a9c2668b26cceca6321afaafaeb543a2593f7ecc8813adcc055264024b327386e3ff6d942c2fc43325da26110af27cb8e701bbcbbfa45581eea8957ea3da64d49d94157ffba4169d2362aa9b472180d737bc0a55078428eab0f9eff43afa68d92bce3afd5dd0ec87ffa63d7d079213f8ade4536fa7f926bf59dfc4a1a1bdba630ce72e103e18292b5dfef65d6bc7d8e118296eee2b2481ad33c3e1d514ee029ba6ba9e5e8bdb746bd3bc376e201bdd6d1b3a9bc4daafdea39e90a7ff7841a4f85a4d0a5f68b1bba3a1db40dea7d29336718d6d99a05bdcedc42bc6f356441ece5ddd88a7acaf7f1df71a251405da9e7d259f814768bfe3d5a4be245ad7a8a002a62edb0d514e08aa3af1626e963e0217c1f26549f52f5e0f6ec3c62cd2b58cf021ac715f8f0de186fecaec97c3db9a15841bc1744ea72ddec43b0107a8604b5f34bc9a31f200befd27a9bee1091e2deb2f8f08188e097dfb69de474c4eb62878d0c7836582429fc4740185c09be235b7a1a3456d0e7b8e6e26c3d872d9ca713f51196e2e0cd1d1c33dd933115579c484097dd4351645aa1fe004a9c8b42a2a3fe4a4140c0af8686eaa68f5dbcb5a14a35cb912b11be046aa6820e924c4e37472d618210d3d562cfcfa59c4c529402d01cc79cc55d21b15c0dd801e07141e300b6e116d39a4ad00b698f39092e3520f813a68b56263cc7012175c1d1ce708d8969773ac35a175f1679f03b248a38ed8519d1b48d8ea55ca82dec86b0c32235c689748e29adf0ffe8e04dc823a67a1bd220b98493e91bd614661b3673f146c68b3062c78e9c839701319f179f36d682610ef7fd96df532b48dfd93ae2df01bb8e67360e1c3b08caa8674af3d01cc044a8da821ffb7ef0eadb15a7331d8ed6a9710a21bf5e60733af99401ffaae093bfbff02e45d6c6fee9e3afdd4ff3dd9b8e0c8927b0ccf47fd2cd4a421d239143e0f0b0058156b69c1e64e776b86d4cbbba54fef97baab2853f7965cb2fbab3201a8bc5d3df40a66bd2a5961afe862e40acfaf45c56ed39250b49cc152c33e90bad4bb9d3cad1d4c9e0d06b842635fa1ad7a27ef3f8e7451f1e36397f2bd7c9e5f46702bfd2777b91efe9e560b38d3544812b8a40909dba0d18ce662dcf3db27e9fb38b056976efad122110b45ab87c0ce9130581cc2026fb8713d08ba9605a97c2a6956d90668d6a48ea0e052177eab58464407ec2cc3d8049928b1b605fe71b55f693f9cef7658d8663519c05d3446280c059b9fe898ecbadbf763e346b469a22ad95fcbd66932a3368a1db50b5e73c9b66be6a3394ea2943e7b4811c5eeceb14ff5d5d9c324112ca6096c24f6e807ccd68fc1b19b9671832b15ca8f557d22f141172529ea5a0eb0fcd96028ea3f39d464560a891fc0303c2f0ffb17c384e640c5ac0286ad10ed83f8ec310a886e501d8a88f12b2aaa3e12063a9801ca75278756f316a1cbebd51cc8179c24fa4f7005fb299c9b5276c693d04dd710ea50361004520f182cbb678b9816b82af7e956b64f5556b72c38b3cb1ce5a83e5952b18f42e34e561a90daa9072a908cea034bbc8708c57d7cab14fb53ea24dfa16f895c3b34b468751db501d49f53c101b1cd036f8a5ed1148c8f7a92fe63600ab357796ff10287f40d03e0abd297fc419a8faea8a8eab64150c2ca54bcedae7c5c029da419398308b5d1bccea27dcd5c01c31eae56ccc18b197aa409818c49b961c8920094528f49786f33184c52888bc3cf7a448e0e9445919343f3302244d6e671136dd32b0cad074048e79c0fb0e364752d7ca59d98a8dde86df0bc388b6cfa855ac319f8f801aa72c003dce0485645353593d615b226e75acca063f311d7cd7e741614d69acfd3b07663a35a467a4b8c9c2032757dfcd169b0e1b59096286a426e6d1e35f4371ddd415e1d7d1cf101e5d9eaa1be9d0727c764b061f67a304a1279aac6a8dc66bc65149076b73753677ced828d0075e1739eaff6edb59b99e8bc3c62a200566d08da84065127a5eb1ce6e9b9320b2d3ef42d33c07fa4d765c29871fe552466bf55063b651b46821dbcff115928357d4481f04f0a82a918591c8b16dd91afbda8c8de44b82024374aa6852994678f2d38cfff9cac17561e6fb44540a4c6ab2fb0f05e605e4ccdfe04c9262f60e9fb0eeff75881f687e2974e7b978d61aa06b04ff68aff6b591eeaa1f2a8bc49969681d6e9d10d25933c507a9d93a535c3a5e306705b60748c07e07f1093357255cc188463e4fb4c34cf285ef62e969753226e9584dfd8da7d2b5808cca32a96ce455fbd1bedb2c5dbb6af25297d27b5e13b17c1ef9d6174d93e2a011af1a0809a3c0d13a3f88c107fa8601ed05134a4eb1c3f634b6d9037f6c000b2c480dc68667c6446d1e050f9e7a43f9df958c28471ed0e33709deeb264091bb83bc7f27c15b231cab7ee92968f269de7838eec01ac9e3e035f0e5ad991dbf614af42c543ac67b7abe46b7c4d9f4fbf3d2a45af33c7237dd32ddd69e522704b1c9dc726ac1e35ae57deb529a38fa572c7ace3f0cacbf3fc103f213bd82319376cf28e055ad28900922396b465beaed7203ccf4699e937a3c997639c25a9cfef601bdb6b34c5e56cd0f586a20fc2e75bbc49492220bd7ca9e519c6f1a6a404a3401fdb778dc336b8913c2d89cd1a5b806cf679b915608f4d4dec8de7c3457533f023222440cb7c7b1c3a3a22feb2c639b954238074dea7c9da9fd43b85a3c3a80635da520ab8810251a840143d9a31564912408efe5faa2db327b1abf2001d3c0d82df8c63afe6cae386820abac516a295f0fb0275cfbad22fdc3dfa09150f1f24f26878292c6015bae8a24fbdf2e4a012736f7d02a0fe11bac9826fb26e012485b476cb006de9680176d16f3ea9c5e73ebe8607f0f77bc406374948893913d128d2ab3831e65002019f67c49de1bda9d24f9236ca377c1133408cec5859756e9325283e8b312541a7e703c75b73e40c108fec13413a259f0e3a0f83bcd751bf006328c061ce8efda3bed6a5febd16be95cf955b1463177264aa14c2ef20e2a98b1784a3d82a2b65b5fb0960558b942c7abee33b4c1eae8ec37254224e6118c943e724db9b414312242752de2d9dcbd8475e2d8c3914964c73f587fefd70887c9f77f6b0d031260907c33941fdfe4b1eb51d28c0ae0dd607b0f1b5bb58e115d2c97f1508db724e4ebb629ebb73dd5e0913a76f2dc16274546dc3453ace2889935af52d947cf91b72e8d943909cf0b44369e68222586755533b\"\n\thexSignature4 = \"0e49fe1706d9e93b3793e1057f328c4206632da58c13b1aa3c95158c1a68b8b5d9b4fb001100e13cdac760febf755faeefc44667db4983225c5db714516b867a557e6eb0210d40649a0242f8602e2def3ce8a9fa2d82439554eb21c5bbd96d131e28d88aa59d7761c0f92cad83ef4fc21ee97c09a81e5ae20a4475b68935c3ec4d06c1d2a2165505b667b2741a5311d2a78d99cb46163b8b6d65d04ee40c2d3e2289b0d981a5813fcb4b3f3fc6b11230fd4cffd3b910d7f766ddc09e95d3dd6fe7232b5e9cd52d09b87a8025e9841d2fc2b890fe0a0f3c4c2c8ee7b464f4e1fa0c0b8f4c57d0a3c94604ba22fa6cba188d776bf9e9e9e6471c61b8ccfba14fd996f2b242832c9a0aa14aa957c192f52642e947390c188e0e441c43f458dd1aa29dbbf5c9c883587a3ad43770222cbee2dc5ee22f0050d9490a4b1a278206cac7a2917be304c3c23a9e49574fa2d26786beb9948831cebcc198b2755bad06684c4339b9eca58b2cf9168fbbc27ea6f9b65af1651193370f70e3af4d1cafa7a2db7fd122cc34fc07fea2ecdeb168949e83a3389bb58bce50aff380c707a2b6f664e92476b46ba85148f4dddb5fa371eb28e50cf2800965c214d74298972cbee99621c4e1518267745f3358430e3df11391875e30fbf191648db283dbd98ec0451fab47d94079e2092a0a1879a6516dd0a50c1ec4f4e85545c59526e049a8d54311c714b992cb9a865f7cce66c0d420fbc3d586cc45ae651d3098b96481e69af0fac22cad38db480a711acac3196440d2811ccfbda72551bb9fac7aaa3fb8ceb3565882add53b72cf21b27c018938fe705b74a8ae2bcc2c80b0904dbe447968e66c0522c866c31109e6a055fc03a1696e350da0d21ba59fd7d530628fe6ff8ebb9e402216ce5ff3550db5eb38b5e0f7964afcf2c0a9f4b7e4693f90df9c58bcf21765491e9bf1019bfca3c4e0cd52b9762011ec92e941c4749d34e3fcd04719535d1b01380dd6e54408fef2a6644435af3abfd854f4cfc58031e90480ab3d0aa4064846af0e855bde2f7fc89a4a662ffc6affb8abc6d60ad7304952e30a63db3835cf4030adff9a0501d2704256c2c12001d2773fefa7b580472eea8b3cd1b289092645293e7c27a5aa0e4de5b95f50cf943bf5b71b9c4a81906407b5d3b6fe59cada698bad7930b1d93e98ead0b5d467f8a41c239c05f715172dabdacce8ce9a663815a53ffb1ba4770b98136adfaea685d5ab01b60acb0aceb21537b701d104f96edc2a60cab5e866c7686c57e1bac8632cac62832894efe0c075e2ae689a86b8346bd6f553a11824edccefc08b03cab4beac4cc10d77555ce484655a7ffea197f7bc153ca9c955e0485aee8dda93fd2f4eb7910b484fecb1481c82f651d41e4374c128268218fdb52258f257c4caf22f2337c6c62ec1f67c423e19a61687325897f25e249a3973456198ed516c52f17d306146c2fbb6822e5650e6212a19984d388718a745fe87bb127c0a4b390bb8c865513d2cfc0063c38a41f4aa015919016e00e21723b2593d4c7da4d18481405db785cc5f54ac637946c057b73e0cf0267782562a455606713df9ec9af4bac25c9b8854c15a4423062847691c691bb6305d978a3e1bc2743fcf09dd6c9cf6931e8a53c18f184e12f3b8c10f117f43664ee51db85b22857f5690c4b833439109d4effc166dd522dc0d2bcea10d401248d72aa8071b70e2bd9d5e022c3bacd91bf3438bd397d84eb1fc94fe884a3750be94330c28ae9a061f156b048dcc34683becc0cd9ce5ffbd2968bb4f1445f742212a0b49536cb2e8d03dd8af882ec87ad0d08f9681ced02a23889aa2396d133b2a13ef5a90a6d68e0f333b0d187eab74cefc1a58ed59e69742ea1cb0b7e4fbe79dca3daa73bc4af1c019d28b59071289a6c4f480141d274ebc0249f3105c61746b2208548022542ffdf697e78d93240bd63d13977cdf39ef936bf0f8a464dc7f9fb289b694ad4543f90b1338dbed53341053916cbb8f645a29524dcb865022db71e6565839f8ecee01ade85508634a27e58bca4c4d224b26a4c9b897514254ab0f1e297f48d063804d4dd60f63d08db985c0bf8852f8d8296eb92f2adb3e607bde0a4be5c7790dcadbf66e9c619345bce4122f5f359a4e81ae228648a0b0843819f9a12722104fa705b73730a66cb82b2f9512b22dce3cd8337029dd824bbf7dc3037efb28453ad2ef6b37d3e12021a834ca7bde41355661044575593234c76bb99f0e5216d735603faf966e7d44ea86d49fca2e31e613ce0eab7ba2e90c3f33978b15c9379f9f481e4a427d5b9bdc3f2e0ab5288a1f0b46e8e4c4af023f65c4d7ca13f0ec4bdd50821f90ab8806f5d33689de6aad54c4d9a8236023635164b6400199218e3dfb4ee7aa179987b1d4e4893a190962a881db6b91a0c3268f6354e9a06d8ff3789b242fc5b699879a9033ffab65ffc6e1bcbf96ee9ef41085b11fc362ce9df7c76ba2d66a0fcf10dfd14bbfe75498e8e0e87ff12ed1d4e9a250fca71e187109b7aa35b30eb38fd6252b35d2f5c3cdaf7e1f2311ea6ce6a6de6d1b681ede35078ac0a08cb79f74ba2fadd768b35ab789f83b9f9a5059e500de88a401d8e22e621f76c581a9f85b0d7ae39e58c078534ec76682067e0ab85f2aa6c9d46452c0f4058357aeee776b1eb0fe31615ae1a995dac73fc84068233b5b3d4d2c04b475a293c7ccfb6a2a6eb6e080a95e3ff88db38b60ba8127cd04abdd9055ba276e677488e1f5076c82ab2e194f0b7b369cac2261bfbc2dc749e5644e4cac3aec5db648707ebae08d1b43e1e08266b4b6c8d183b337f920868783cc194efa6d55bad9ccab2309e55426e95cae55c5bf20260389f052b6fc7d796d43a02bfc8f2978d39db4b4baa340d9eb4eb0b7aff432ca76552b5092c0cfc1ea55c702b2c5ac58579e1ecdad38ce68ed42f2f86d2fbe8f3cddd60b07a21d9099c6b08f22b97e1a022af285740932927bc88c834dfc33036ce86f095f5bba0bc4cb37d330acb59d6570a8e28297952cf4ed05134678605e420db31471b08cd6e4471637b8437f8880266f3dcfab80c22dc93b842abc923fbb12643f3ad3c68ec2ded37c1dba3eff45c9106db11535b14da39fc268f127d06a6a4da2c20090db3fb4cf35bcc74aa8627240b9fd9964939f984332217bcc00b579e87c912114ecaa2180b6d3c3a436e0ffaf9955d1707942930299d124a429d26c07bd349a0bb132bfdff861bd5bc5c15ce84abea3d040f77404c9ed1630f27cc11d1f885e56bd94703869989bfbd5247b0cb67243061a827a575b6958ba2ed809c55d75f898eb3074de5e490f43dcea4bd1e8019683b07f7270b3610e57837d57fb6a84e06ffedf589744b84e190a8e6407440d53c9ef7a50d179e2e273d35e37529b8ee1b3f0227f91cb1889cd25601fe685b858710da059cdfa4e84bd125529f866a349a22deda060d4a1eb59428ff5aa0bee006eb191650cbbebfe34b618bef661fae3411220328547c1fc2a1a6067e270d84d6246df36b516bf49979c37f8e7eaf8f38bc173685c76db015af86b5cd34825dcf70d3b54efa55e9163f25c1de29c1ff2a2a84ed008722c913343e727b6812216f4d0e0212359d5df3761129b4a95d8d7405e34017f60516d4c675df3f08a00e62f03010fc9d049ccf8b0a676c6f1603959e1202a6319706fcd28ea42d691283cafd925fe7cad83ded6f8e79ffea0704e84850d6f1d695e1cdbd335e11ac75abfc6ce977b28688242fef27de931c52732b6eb1d39020f49f5c5b34d9212765ae4077bd3f380c52e66552fe60a393607ea2f8c4cff65255e3a856f15b14def092b67083b0a9ab5ba31c9490e19266cd029c4b91f8c49365ae03a9494463a23a9effbedaf2c11592724098e357e50a2cbe3a1523fae9a7a045c773a578fd59c413d664d66a9cbb5927a237360184a0e0e36f0c274948a12c2aebfca648ddc0dee4164975b4cb0e5cfe686086197aabc88d6daa70fe992d48b86b224a8b123daec21352c2bf4b08664e5b90fe20dc7b378767306e9e86f570c82d53d025babbc546fc7094c067da9836e189140bd43734ef9834be3e25e235dd9a3a306045ac98a244c25c472dbc226505c8cd8da89f68641ec3932a18b720bbda0d072bbae4ae404cf4b8bb1f17f2eeee0a15cd61d53775909b0d1eb879422b87069afa96bbf82b938312b8231b9f29191c4c5983e3f596984494f3ac9c8bdf17316967be9ba0a9ebb299c17a9f411d9fb0f89385b0f5f1a2fa863b07a9a556c344da12da5807aeb7b685ec821d16e82e5c9b05e2cd79cf6c815fa66cac917b16fcd0c1178add6c01a15ffa534eaa3e9a87e58e5c9e76ac1cda1fe1b44fee4e7026a3931440ab20c977e8be1186b090dfcd054abb01018aef8047dd1d5b1fb0462b2ef5c6fb2050e685546cc0097db0e5d75dc09901adf32bd868b9176b60ca4aeaa3283decacc3c174029a2e51a94311087ca4b9d7d611df8f0f79c8cf917cee6573e7ca3d9ab7189ed95808e934e94b7047a22c8d070ced1a2748176b4d1eba8500a73ef3d858964143536734d45a9895a15977d2ec80df408da20b2d516620d0afa8c8e422888ca569f9382277363e2cdef3d853bbd05175bcaf16537c48102f473503ae8b87cd84165716203f6d5432b972fab50932da8932bea64f00065b1daf2bd1c1a70bd6236caf450b5172542fb1dfa9a0f15e7ea9de63c516a5ed937b2a6cf53db75817127c893184b7e2f2e12bad7b726ce8f06493e3c6324602c14ac03810febf2af50479aab291e570d1e81e68ecc0853d636497f885822423989ab8b8de5903914d0da7bcab87352ce9f88ad844097bd0a5ae40fb04c3194b72f997e7638607b30edb15d4a19648503f0449dd39a8a8360d017fff78c6e8c1e035edfbdb0fdac634ec05c09e1bea594fcfab009edeafa0593ee7c335eb381cc4950bacc0821b7334f92ecf40535f34d9edea363d8e1d57f6a911f3201a52a73da95931c06b2be6afa51e1d7602a3827a8a6f074fbbc2492f752eb8a59ba96365e39f281a22a59099e25a2fe6e3371747d733f9865a6509078ab2528bf74b196652e3fc5d884a0d198d02d51a60f705615679edc6cda6ddba41afacff5a776db11c965959cc9eed146fa5fc6882d10f271c96fd8c399debe6eb5d4ca153913c22e6d54cd9738d9dcbf1c8b91a3c2c2d912576e4e6e35cdf35c092202f772e7c33895f64fa899d2280f5206759029df5cbaefc2b61e40bd148c611a6a21728345b40bf6a2475bced235e48a34907fa47edbca39e8f9a0e0ece57b6bea14efe79649f75379e554c41d8c7017ae0c43495e5c5adbbe14875f3527638c7acc56266907f26aa8114d0f2c65188c2e913c003669b26ab3f22d4082198f9484772a4f3eb8f9d9d2936926642a413577c8a472c611a60d55bc30d2a7b74eb57f95ed83658528d15483386844674b42f8f20621c4c9b14d0c7c5aa6cda1c90fa904d6c5164320f0eac1b60592f1deebf47d5ac143865323931cc470fea2e060379629bc341c2d74abda1ec4e1bc8891c75f0e94cbb9f7588884f88b156f61dcb0419108923f63a85ce06db231c77dfd033b974513938644b7fd19f2bed75a4da4a5f3ce71830c1b806e814efea3ce26291740c46ce267e4d8a7e90ef6e34adb0a45e84abc76eedd3a4c40720c1a07c940472d386e637f6003e2252d1310a71f0ec0d3d43016e129228dabf9a06b473753d34229e37dc6d396e2256c50c9ff2278efa698edaf577cfa8befb102fe32672117e72deb6be1fa1e093685c425df5923e7ca597de7a2223b53210249af1ebed29afe7610b9b80c5a38b8a11b8e017bce930d00a387c1cecd7270ce7a1dbf2995f314f0c82eb4c872d03dd485a61380996f552d58e2c682f824f0b37b8e0ccf895e7365ea3830877d879354785c62329c4fec12b825b809ef42b04b9dceba2a88d5a20e2a2b23b8288057e9e7034ee34f1e8bc8f90b3edd5c0e73f9140d1802ac19cb0ec060d2c0670e116886b4bfd0bfbd8ec2b5258df08d6f0686fd0c0a1a32b6277a7cbee4997823d6327cf6e6a72dd0abdbfa90898a02b3c460dcf095adcae69b1791f319dec73568ea112497c7f861c437464a22893167be220a7a304c1cff622d8b606bd3068f7c01adc39fd127d97acd6474fba33123281f451cc76d36feb69566e599ac57b5d587be9b4894d2c382b93eb4faa4977d70e2397a773b72bc0cbafd92389e8cc9a8ecb70e531236929ed8b8d8909accb8aa00a3de64d8819a086b8d0fe0ef6ad491315cde572ccdf7119a13539eb6c7563356a29ef002cd70802e9110f770294c8255ef9ed86e612897a7de2ff2f27a5e7c8d078145907a75056b0ccfccfbdd29cc8f111b1c2863e3eb6904b02bfc62156ecce51e3a54cbb5667387cbf8ba3b4b15e4f8032944ba0638df2e0dda6713824282fcaf4684c49b2081fdc82a707a93bd62a1c679c22199e5c1253d13c6fc89483f5abc76564e658b33245e7035b464a1ee48c5a38fbbd6c5017c91de16088a74018a8ce2e5521f262117179c9e71300f789164581f2bf33f9a618d9245b5afbfc2e0be97a2fb86e2f228289d191544c286f2ccaeffe54263c41af856699643b225b0574a6addb63cc6c9d6607fc4dfe4af97630873b6bde63c2ac39c0f2a82a1040ed69cc759414bfa67791ba6b477b2e9e9114ac23c5aa921f27d594629d55f2cb9ef4160fadeec9a3e8dc1a2c6b1569fcac431e447e1c89899c8530b972cb8d6846d0ebdd04dd74bec66404854b21d95ca506240caf063b20b3c677a94337b7ecacbe108d058b1ea79be9682f1556475626b6f9269bf3c39fe16665cb4c3ba0f26eae37634f9b19e91854687e9262ee86f4a0662716f4d4ce07fd57c0bd79313eb8eeb1a8db89a545b29f862abdff05175df4601c0ce84f4e33edeceb8e15d919227ccd57421bd41c6ee5a480cca27b34350654192341161fc89b54fa2c79f0c9c1c6a998cddaa76030984a3854f94e93c92bf2ecb1278aa5a19b6c26ffb2efb9e31ac9ab7d85316a2d01c1737eae5b759ac378e7a49ddd97a440b8499fb65dc57ca7e253f41ee9147f96c35d318dcc50cc766b6d6e2a48e0849051bcc5b2bdf65f060218a0fd8aa3634315ffd1f49473d06e6391aa358279a55f34dcaa68ab6b6c1fbade2320c41ec6249a49de647872d9e80056afc82d2292e2745699cfa499de75538dd0f742e97b9ec0e1fe7f6de187216707865239cd7f98dfde79a673bf8f5710bfde505b36377a775c86a639b54f7a9257ef3aaea5ddc9be80419c53e81542c12a3458b6f90c60c2e25d0ec44b87ecf7e10da4bbbe6a160d84a155007e89fa119fd813495a87c058ed945434aa2ace46bf0d23965c0cc2ca2e3a304006d6a0995ec29d27b6058c06b7392d0ee45c4f0cfc2da2f3f528588cf9777f426a53c59a9c259b5af30853d0b4b55151e0c48e81122c7c517832053ff141b0eb8fdd32df3bd8d6deb43f16d5a0309a8b591b553972298e2bf7acd1881b5f8280c14ceb3045f3938e07c898e8849b4da4ea177ed61b9bc6b91b9f1ab3ff0676dff99ab77313457e44792de597e7d6df62addfff4a341eabf9926ebbfb55b5a7b3118aa3730d48334ebec98dcf8c243c283d1a726407fc70ffc0eb268fe4409167da69df498ea17c9e35cdeaaad0033cb18ed62cc1dc5cbcd13d076a34d551096839b9d8e4db072c95a2149de3a18eea765155f69e927cc7ccebafae320afb26f4fc4a2564c593a52c3db150df73939ff164bfed288fd442cece64a07e55b78bcae2e2586263c1280aeb4f8b1659433ba93fb452c0f66a795af2693a0009d336ab8864ad4ec5c727f05e44d039e7e4fa29e5c6e46340cc37bd380b522512969e88dfbb09ab1c63fb941b43c0085511c13cb9be6598fb83b4ada5067b347149e15f7c227d77721a736d92f52fbfa82fd83e7211ce2865845c2b2718c25510724d9fdbc6d9d41b01ff70804e5b8e6286d5a0135e256d8725eb32b95c1582f0f296fe3296453e4407d72d474d459bfa4d3a2852e1289f8a7d1a04ef42cddc1118529dc5661589be8fef4a284c80e589d85f645984a3fee953c374de48b017f43874ece7c54b6e5bfc6307a5231cafe2f5191ae5c136876427542f73439cf2aa69f521c69cab2ec89bcd6a290c594de1d951396d36f9162daabd3c789ffaf8527c39dd66697a1592ab8af20dd9b0da37295615bc0ec7fec67825878abbe94b17e288adefe009cd89301a3a9c2668b26cceca6321afaafaeb543a2593f7ebaf5954352c1987b5b9db451e526fa4d83f122f996383b3b582977faf402c393cbbfa45581eea8957ea3da64d49d94157ffba4169d2362aa9b472180d737bc0a7e64efd1dbb8f2aef1949cac0f01b0c9d31c8c27054d07770b7a3c3d070caa256fa7f926bf59dfc4a1a1bdba630ce72e103e18292b5dfef65d6bc7d8e118296ee2c0a6db412662bbf353948b9ba88cc8339ba90370ba7316b33069ed08d822926cb53da23262087a7ed64f6bde2b73c2dc3c538a94c3b9a3a163ac85a181c7e8866fc19052474076a8a6a6af50fed2065554619f2fc0a38653d941d9fb4df3b74ab6e877baddd9f8cb915cf3b2b899960190c7f8caf3ec6c7ccb3e7cbe2bc6547c4908a49db4414c3e07c086309a2e4676ba79d310f283a38c1f14534ff39e6c50c7a218f60396dc5e5afb08f19121bd8a92ba9e8d96b7f5dd8ec5a265f4da039aa1bc76f4b09fd21886062959db554d28f328cc5e1d2ce22f055b1d105a52336d0e7b8e6e26c3d872d9ca713f51196e2e0cd1d1c33dd933115579c484097dd40f1d6150a9d0b95d1c227e763c3e302c1fefd3f656f96aa4c63ad340b5b4380513c30531f6113adc5b5b48483f9239a8f8686d875bb06d190237fa3d92928c941fc1384317b35e902f5b04d0cc5f58c8d4d9a96dc68e4240487b1fd01208b35d2610e5d7910f909eb822280b385947f38bfaf1729424e4b4ec108254cba47e7cd8ea55ca82dec86b0c32235c689748e29adf0ffe8e04dc823a67a1bd220b9849cf760d3226d4703fe4da970795d138a8be506d867c7ad0d081a22ec0bf01a46a6df532b48dfd93ae2df01bb8e67360e1c3b08caa8674af3d01cc044a8da821ff2e3b8e595e7ac4c16330e00dd0ebac867feeb40c8080e2a02a42517fde15fae309e76a664c3aa30ddcd78376089ff5e941e302b272411c2a013c492c1c64dea69175230720d8e954e45b91c83ff48269291e678fe705fa95e6f49d5eed7b32f6a5cfe22ac0dfaff9d88c8326ef6b07274815bd7f09be16969d660dbc8e4e117b1d4c9e0d06b842635fa1ad7a27ef3f8e7451f1e36397f2bd7c9e5f46702bfd2777b91efe9e560b38d3544812b8a40909dba0d18ce662dcf3db27e9fb38b056977adc77a39884273123937e5e8c5131b4cb587dec634e8bd0c599903683e689ba68d6a48ea0e052177eab58464407ec2cc3d8049928b1b605fe71b55f693f9cef7658d8663519c05d3446280c059b9fe898ecbadbf763e346b469a22ad95fcbd67cd50faecacccb346aa5ebeb05d79a91f796a2e1b93539fa7a45aea2435fc301ffeb0ca21220b0fcb62c0cb48f1d113034a471a8bad131e3701176957f828aecb0f9b5fe23276ba9f48e9f3edcf74e79230189afc6c05c077047f4d7512f978a4a72e7e300bbaf0f1d7472c6ca9afce885827f3092d305384baf9962e6272628d21b1e41994f7ed5dce24388f210a2887d103abb1a13456bd8668bd924a3b30abb678b9816b82af7e956b64f5556b72c38b3cb1ce5a83e5952b18f42e34e561a57ff95d7ea53dca061a724bf8a4a72a253695d1aa90682b41f51827716a3354cf8744b159d77ac59588cb85d55a07114ec002d14e5a9e7769dd75fbd52b36ded9d6391111ee24c8aea92b1d6934efe840cf65258652ee471ad64a648c286775cb5d1bccea27dcd5c01c31eae56ccc18b197aa409818c49b961c8920094528f49b8f62d12c1ca37fed2b69b47d9829d182c1ab6bfa01ae420921873da71f13e3f87d2e445e479cbd18b7d3b6997a2a2cd9c8bbd632692367847795bc8532e5bbb677bf89c060362ec61582d121f4dadfe9c8da63f89a99493f380a611718835b6d3b07663a35a467a4b8c9c2032757dfcd169b0e1b59096286a426e6d1e35f4371ddd415e1d7d1cf101e5d9eaa1be9d0727c764b061f67a304a1279aac6a8dc66bc65149076b73753677ced828d0075e1739eaff6edb59b99e8bc3c62a200566d08da84065127a5eb1ce6e9b9320b2d3ef42d33c07fa4d765c29871fe552466bff07f7f204232aafb81c9d4780938b0d969bf8720054abcb8d445d44ec8c2243cc8de44b82024374aa6852994678f2d38cfff9cac17561e6fb44540a4c6ab2fb0d4b2046134b2b4ccf4ba8c6006d4245857fdc8a72209e5fd6c667514bc03350af68aff6b591eeaa1f2a8bc49969681d6e9d10d25933c507a9d93a535c3a5e306958d3a23c14607a2c64cad2c3a74fc851e596e416e35c55d1e0263a2e6d57697250828c21b8dc015cb11ecd026e5e32375e03128df4ff32789003e16f88513a3ef9d6174d93e2a011af1a0809a3c0d13a3f88c107fa8601ed05134a4eb1c3f636f371e12a3763045eaf1f3c41ca99804c7987ced3c77d6f93f1e9d46aa4cb4035ec681b3e8824b8649f32575d46f1eb98d86a23200ed92454ec1b079947439b1bc2d20104e3684aaefe2251891b2da54f3354dd08fbc2ba537f35c85e2e5217a2ddd69e522704b1c9dc726ac1e35ae57deb529a38fa572c7ace3f0cacbf3fc103f213bd82319376cf28e055ad28900922396b465beaed7203ccf4699e937a3c997639c25a9cfef601bdb6b34c5e56cd0f586a20fc2e75bbc49492220bd7ca9e5e95d19afbe7a923e02e81f024c2aec62f7ad986d67f637dee4108658c663abbeec8de7c3457533f023222440cb7c7b1c3a3a22feb2c639b954238074dea7c9da9fd43b85a3c3a80635da520ab8810251a840143d9a31564912408efe5faa2db327b1abf2001d3c0d82df8c63afe6cae386820abac516a295f0fb0275cfbad22fdc3dfa09150f1f24f26878292c6015bae8a24fbdf2e4a012736f7d02a0fe11bac9826fb26e012485b476cb006de9680176d16f3ea9c5e73ebe8607f0f77bc406374948893913d128d2ab3831e65002019f67c49de1bda9d24f9236ca377c113329a2a0aaf72074d8a1170ac9fc72860bea7ccb2c7aa10aac3e4f847218564b333a0f83bcd751bf006328c061ce8efda3bed6a5febd16be95cf955b1463177264aa14c2ef20e2a98b1784a3d82a2b65b5fb0960558b942c7abee33b4c1eae8ec37254224e6118c943e724db9b414312242752de2d9dcbd8475e2d8c3914964c73dc4cceabceb357a2d96790e678451364230425295b7cc3b1b20f3dc92daf4203f1b5bb58e115d2c97f1508db724e4ebb629ebb73dd5e0913a76f2dc16274546dc3453ace2889935af52d947cf91b72e8d943909cf0b44369e68222586755533b\"\n)\n"
  },
  {
    "path": "pset02/README.md",
    "content": "\n# pset02 : NameChain\n\nMine your name into the blockchain.  This pset will use a mock blockchain which you can mine blocks into.  \n\nDue on the last second of the month of February: 2018-02-28 23:59:59 EST\n\n# Warning: centralized server\n\nThere is a server component to this pset, which might go down or crash.  This is not a decentralized network hardened by 9 years of open source improvements and worth hundreds of billions of dollars.  It's a server I coded just for this pset.  If it goes down, bug me on IRC and I'll try to fix it quickly so that you can increase your mining score.\n\nThe server, at hubris.media.mit.edu, should be up and running from the 20th to the 28th. \n\nServer is back up on 2018-02-22 10:45 EST\n\n## Block specifications\n\nBlocks are ASCII strings, with a maximum lenght of 100 characters. The block format is:\n\nprevhash name nonce\n\nprevhash: the ascii hexidecimal representation of the previous block hash.  Must be lowercase and in hex; do not use raw bytes.\nexample:\n\n00000000c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b\n\nname: the name you want to credit nameChain points to. Case sensitive.\nexample:\n\nminer2049\n\nnonce: a random nonce to satisfy the work requirement.\nexample:\n\nTWFuI3GlzIGR\n\nNote that names and nonces must be in the base64 character set:\n\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\n\nwhich is just caps, lowercase, numbers and + and /.  Can't have spaces; spaces separate the 3 different elements of the block.\nThis is to make everthing easy to run through terminals, let people use shell scripts and so on.\n\n## Client / Server connections\n\nThis pset has a server.  It's not a real decentralized system, as that's too much work to deal with for this early assignment.  There is a NameChain server which listens on a TCP port, and when a TCP connection is made to it, it sends the current blockchain tip.  Connected clients can send a new block to it, which, if valid, will be appended to the end of the blockchain.\n\nThe server is hard-coded into the pset code and lives at hubris.media.mit.edu.  It will probably go down for some time during this pset epoch, due to the fact that the DCI is moving to a new office this week.  We'll try to minimize downtime.  \n\nThe required work is 2^33, which is twice as difficult as the initial target for the Bitcoin network. (But nowhere near as difficult as the current Bitcoin target)\n\n## What to do:\n\nA bunch is already written for you.  The network functions are GetTipFromServer() and SendBlockToServer() and already implemented, so you don't have to deal with TCP.  \n\nYou need to write the Mine() function, and then SendBlockToServer() once you have mined a block.\n\nYou may need to poll the server for new blocks occasionally so that you don't submit \"stale\" blocks, where someone else submitted a block before you did with the same parent.  To not DDoS our server, please keep requests to 1 per second maximum.\n\nUsing go concurrency features is reccomended for this problem set.  The amount of work required to find a block is fairly high, and if you're mining using only 1 CPU core you will be at a disadvantage compared to multi-threaded, multi-core miners.\n\nHere is a [simple tutorial](https://gobyexample.com/channels) on go channels; they're not too hard to use, even if you haven't done multi-threaded programming before.  They allow you to pass messages between functions which are running at the same time.  There are also other possible methods like sync.WaitGroup, or in fact it's quite possible to mine without any synchronization between threads at all.\n\nThere will be a \"high score\" ranking with the number of blocks in the chain made by each user.  This is the same as getting more coins by mining more blocks.  To get a high score, mine a bunch of blocks with the same name.  We're using names instead of public keys which is not as decentralized but we know who you are already :)\n\nThe entire current blockchain can be downloaded from the server at port 6299.  Example code:\n\n```\n$ nc hubris.media.mit.edu 6299\n\n00000000722a3b3cabaac078bd4e15ce361312895cfef0494c9ffc75bedb82db adiabat 19579781213\n```\n\nThis if if you want to check how the blockchain is progressing.\n\nIf there are other server features wanted, let me know and I can code them up.  The server code is not public now, but I'll make it public after the assignment is over.\n\nHaving a server makes this pset somewhat more fragile so bear with us :)  We hope this assignment is fun and people can optimize and speed up their code, while getting the basics of blockchain design.\n"
  },
  {
    "path": "pset02/client.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n)\n\nvar (\n\t// note that this server is not up yet!  Will be soon!\n\tserverHostname = \"hubris.media.mit.edu:6262\"\n\n\t// uncomment for testing & running a server on localhost\n\t//\tserverHostname = \"127.0.0.1:6262\"\n)\n\n// The functions in this file are provided to give connectivity to the\n// NameChain server.  They aren't really the best way to transmit & receive\n// data over the internet, but it works OK, and we're not focused on the\n// network layer right now.  You shouldn't have to modify this code but\n// do let me know if it's not working properly.\n\n// GetTipFromServer connects to the server and gets the tip of the blockchain.\n// Can return an error if the connection doesn't work or the server is sending\n// invalid data that doesn't look like a block.\nfunc GetTipFromServer() (Block, error) {\n\tvar bl Block\n\n\tconnection, err := net.Dial(\"tcp\", serverHostname)\n\tif err != nil {\n\t\treturn bl, err\n\t}\n\tfmt.Printf(\"connected to server %s\\n\", connection.RemoteAddr().String())\n\n\t// send tip request to server\n\tsendbytes := []byte(\"TRQ\\n\")\n\n\t// write to server, error out if needed\n\t_, err = connection.Write(sendbytes)\n\tif err != nil {\n\t\treturn bl, err\n\t}\n\n\t// setup to read response\n\tbufReader := bufio.NewReader(connection)\n\n\t// read from TCP\n\tblockLine, err := bufReader.ReadBytes('\\n')\n\tif err != nil {\n\t\treturn bl, err\n\t}\n\n\tfmt.Printf(\"read from server:\\n%s\\n\", string(blockLine))\n\n\t// convert to block\n\tbl, err = BlockFromString(string(blockLine))\n\tif err != nil {\n\t\treturn bl, err\n\t}\n\n\t// return block\n\n\treturn bl, nil\n}\n\n// SendBlockToServer connects to the server and sends a block.  The server won't\n// respond at all! :(  But you can check for the tip by connecting again to see\n// if the server updated it's blockchain\nfunc SendBlockToServer(bl Block) error {\n\tconnection, err := net.Dial(\"tcp\", serverHostname)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Printf(\"connected to server %s\\n\", connection.RemoteAddr().String())\n\n\t// Server will send us data but we can ignore it and just send\n\n\t// use newline to indicate end of transmission.  A bit ugly but OK.\n\tsendbytes := []byte(fmt.Sprintf(\"%s\\n\", bl.ToString()))\n\n\t_, err = connection.Write(sendbytes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// read response from server and print out.\n\tbufReader := bufio.NewReader(connection)\n\tResponseLine, err := bufReader.ReadBytes('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Printf(\"Server resposnse: %s\\n\", string(ResponseLine))\n\n\treturn connection.Close()\n}\n"
  },
  {
    "path": "pset02/main.go",
    "content": "package main\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// A hash is a sha256 hash, as in pset01\ntype Hash [32]byte\n\n// ToString gives you a hex string of the hash\nfunc (self Hash) ToString() string {\n\treturn fmt.Sprintf(\"%x\", self)\n}\n\n// Blocks are what make the chain in this pset; different than just a 32 byte array\n// from last time.  Has a previous block hash, a name and a nonce.\ntype Block struct {\n\tPrevHash Hash\n\tName     string\n\tNonce    string\n}\n\n// ToString turns a block into an ascii string which can be sent over the\n// network or printed to the screen.\nfunc (self Block) ToString() string {\n\treturn fmt.Sprintf(\"%x %s %s\", self.PrevHash, self.Name, self.Nonce)\n}\n\n// Hash returns the sha256 hash of the block.  Hopefully starts with zeros!\nfunc (self Block) Hash() Hash {\n\treturn sha256.Sum256([]byte(self.ToString()))\n}\n\n// BlockFromString takes in a string and converts it to a block, if possible\nfunc BlockFromString(s string) (Block, error) {\n\tvar bl Block\n\n\t// check string length\n\tif len(s) < 66 || len(s) > 100 {\n\t\treturn bl, fmt.Errorf(\"Invalid string length %d, expect 66 to 100\", len(s))\n\t}\n\t// split into 3 substrings via spaces\n\tsubStrings := strings.Split(s, \" \")\n\n\tif len(subStrings) != 3 {\n\t\treturn bl, fmt.Errorf(\"got %d elements, expect 3\", len(subStrings))\n\t}\n\n\thashbytes, err := hex.DecodeString(subStrings[0])\n\tif err != nil {\n\t\treturn bl, err\n\t}\n\tif len(hashbytes) != 32 {\n\t\treturn bl, fmt.Errorf(\"got %d byte hash, expect 32\", len(hashbytes))\n\t}\n\n\tcopy(bl.PrevHash[:], hashbytes)\n\n\tbl.Name = subStrings[1]\n\n\t// remove trailing newline if there; the blocks don't include newlines, but\n\t// when transmitted over TCP there's a newline to signal end of block\n\tbl.Nonce = strings.TrimSpace(subStrings[2])\n\n\t// TODO add more checks on name/nonce ...?\n\n\treturn bl, nil\n}\n\nfunc main() {\n\n\tfmt.Printf(\"NameChain Miner v0.1\\n\")\n\n\t// Your code here!\n\n\t// Basic idea:\n\t// Get tip from server, mine a block pointing to that tip,\n\t// then submit to server.\n\t// To reduce stales, poll the server every so often and update the\n\t// tip you're mining off of if it has changed.\n\n\treturn\n}\n"
  },
  {
    "path": "pset02/miner.go",
    "content": "package main\n\n// This file is for the mining code.\n// Note that \"targetBits\" for this assignment, at least initially, is 33.\n// This could change during the assignment duration!  I will post if it does.\n\n// Mine mines a block by varying the nonce until the hash has targetBits 0s in\n// the beginning.  Could take forever if targetBits is too high.\n// Modifies a block in place by using a pointer receiver.\nfunc (self *Block) Mine(targetBits uint8) {\n\t// your mining code here\n\t// also feel free to get rid of this method entirely if you want to\n\t// organize things a different way; this is just a suggestion\n\n\treturn\n}\n\n// CheckWork checks if there's enough work\nfunc CheckWork(bl Block, targetBits uint8) bool {\n\t// your checkwork code here\n\t// feel free to inline this or do something else.  I just did it this way\n\t// so I'm giving empty functions here.\n\treturn false\n}\n"
  },
  {
    "path": "pset02/server/README.md",
    "content": "## Server code for pset02\n\nThis is a bare bones server that pset02 can connect to\n"
  },
  {
    "path": "pset02/server/server.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar (\n\tgenesisBlock     = \"0000000000000000000000000000000000000000000000000000000000000000 satoshi 11970128322\"\n\tchainFilename    = \"./chain.txt\"\n\tchainOldFilename = \"./chainreload.txt\"\n)\n\n// BlockChain is not actually a blockchain, it's just the tip.\n// The chain itself only exists in a file.\ntype BlockChain struct {\n\tmtx   sync.Mutex\n\ttip   Block\n\tbchan chan Block\n}\n\nfunc Server() error {\n\n\tf2, err := os.Create(chainFilename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tf2.Close()\n\n\tvar bc BlockChain\n\n\t// initialize channel\n\tbc.bchan = make(chan Block, 8)\n\n\t// Ignore errors here; it's hard-coded\n\t// this is kindof ugly as it doesn't show up anywhere so it's like height\n\t// negative 1.  Weird but whatever.\n\tbc.tip, _ = BlockFromString(genesisBlock)\n\n\t// start handler routine for accepting new blocks from clients\n\tgo HandleBlockSubmission(&bc)\n\n\t// handler is running, so feed it blocks from disk\n\terr = LoadChain(&bc)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tserverListener, err := net.Listen(\"tcp\", \":6262\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thiscoreListener, err := net.Listen(\"tcp\", \":6299\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgo ServeHiScores(hiscoreListener)\n\n\tfor {\n\t\t// blocks here\n\t\tserverConnection, err := serverListener.Accept()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tgo HandleServerConnection(serverConnection, &bc)\n\n\t}\n\n\treturn nil\n\n}\n\ntype Score struct {\n\tname   string\n\tpoints uint32\n}\ntype ScoreList []Score\n\nfunc (p ScoreList) Len() int           { return len(p) }\nfunc (p ScoreList) Less(i, j int) bool { return p[i].points < p[j].points }\nfunc (p ScoreList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\n\n// ServeHiScores listens for incoming TCP connections and sends them the high\n// scores of the blockchain.\nfunc ServeHiScores(l net.Listener) {\n\tfor {\n\t\thiCon, err := l.Accept()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Hi score server error: %s\\n\", err.Error())\n\t\t}\n\t\tchain, err := ioutil.ReadFile(chainFilename)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Hi score server error: %s\\n\", err.Error())\n\t\t}\n\n\t\tlines := strings.Split(string(chain), \"\\n\")\n\n\t\tscoreMap := make(map[string]uint32)\n\n\t\t// populate map with scores\n\t\tfor _, line := range lines {\n\t\t\t// assume all block strings are good, so name is [1]\n\t\t\tvals := strings.Split(line, \" \")\n\t\t\tif len(vals) < 3 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t_, valid := scoreMap[vals[1]]\n\t\t\tif !valid {\n\t\t\t\tscoreMap[vals[1]] = 1\n\t\t\t} else {\n\t\t\t\tscoreMap[vals[1]]++\n\t\t\t}\n\t\t}\n\n\t\t// make sortable score slice\n\t\tsl := make(ScoreList, len(scoreMap))\n\t\t// populate slice\n\t\tvar i uint32\n\t\tfor k, v := range scoreMap {\n\t\t\tsl[i] = Score{k, v}\n\t\t\ti++\n\t\t}\n\t\t// sort slice\n\t\tsort.Sort(sort.Reverse(sl))\n\n\t\tscoreReply := fmt.Sprintf(\"--- pset02 high score list ---\\n\")\n\t\tscoreReply += fmt.Sprintf(\"rank\\tpoints\\tname\\n\")\n\t\t// print in order to string\n\t\tfor i, sc := range sl {\n\t\t\tscoreReply += fmt.Sprintf(\"#%d\\t%d\\t%s\\n\", i, sc.points, sc.name)\n\t\t}\n\n\t\trecentReply := fmt.Sprintf(\"--- most recent blocks ---\\n\")\n\t\tfor i := len(lines) - 10; i < len(lines); i++ {\n\t\t\trecentReply += lines[i] + \"\\n\"\n\t\t}\n\n\t\t_, err = hiCon.Write([]byte(scoreReply + recentReply))\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Hi score server error: %s\\n\", err.Error())\n\t\t}\n\t\thiCon.Close()\n\t}\n}\n\n// LoadChain reloads an old chain from disk\nfunc LoadChain(bc *BlockChain) error {\n\n\tf, err := os.OpenFile(chainOldFilename, os.O_RDONLY, 0666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tscanner := bufio.NewScanner(f)\n\n\tfor scanner.Scan() {\n\t\tblockLine := scanner.Text()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnewBl, err := BlockFromString(string(blockLine))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// submit block to handler routine\n\t\tbc.bchan <- newBl\n\t}\n\treturn nil\n}\n\n/*\nServer protocol: listen for command.  Commands are \"TRQ\" or a block.\nRespond to TRQ with tip block.\nRespond to block with ACK message accepting block hash, or error.\nRespond to any other command with \"Unknown command\"\n*/\n\n// Handle the connection from clients.  Concurrent goroutine, so there\n// can be a bunch of these happening at once\nfunc HandleServerConnection(connection net.Conn, bc *BlockChain) {\n\n\tlog.Printf(\"Incoming connection from %s\\n\", connection.RemoteAddr().String())\n\n\t// First, read from them\n\tbufReader := bufio.NewReader(connection)\n\n\tblockLine, err := bufReader.ReadBytes('\\n')\n\tif err != nil {\n\t\tlog.Printf(\"TCP error: %s\\n\", err.Error())\n\t}\n\n\t// sendBytes is whatever we're going to send them\n\tvar sendBytes []byte\n\n\t// Now detect if it's a tip request\n\tif strings.HasPrefix(string(blockLine), \"TRQ\") {\n\t\t// ready tip for sending\n\t\t// lock mutex, get the string to send, and unlock\n\t\tbc.mtx.Lock()\n\t\tsendString := bc.tip.ToString()\n\t\tbc.mtx.Unlock()\n\n\t\t// use newline to indicate end of transmission.  A bit ugly but OK.\n\t\tsendBytes = []byte(fmt.Sprintf(\"%s\\n\", sendString))\n\t} else {\n\t\t// interpret as block submission\n\t\tnewBl, err := BlockFromString(string(blockLine))\n\t\tif err != nil {\n\t\t\t// neither TRQ nor block, send error message\n\t\t\tsendBytes = []byte(fmt.Sprintf(\n\t\t\t\t\"Malformed block error: %s\\n\", err.Error()))\n\t\t} else {\n\t\t\t// no error, absorb block\n\n\t\t\t// first check if it will append\n\t\t\tif !CheckNextBlock(bc.tip, newBl) {\n\t\t\t\tsendBytes = []byte(fmt.Sprintf(\n\t\t\t\t\t\"Block invalid: not enough work, or doesn't connect to tip\\n\"))\n\t\t\t} else {\n\t\t\t\tsendBytes = []byte(fmt.Sprintf(\n\t\t\t\t\t\"Block accepted\\n\"))\n\t\t\t}\n\t\t\t// submit block to handler routine\n\t\t\tbc.bchan <- newBl\n\t\t}\n\t}\n\n\t_, err = connection.Write(sendBytes)\n\tif err != nil {\n\t\tlog.Printf(\"TCP error: %s\\n\", err.Error())\n\t}\n\n\t// disconnect client\n\tconnection.Close()\n\n\treturn\n}\n\n// HandleBlockSubmission checks that the block is OK and fits on the end of the\n// chain, then adds it on at the end.\nfunc HandleBlockSubmission(bc *BlockChain) {\n\tvar blockHistory []Block\n\n\t// loop forever\n\tfor {\n\t\tproposedBlock := <-bc.bchan\n\t\tlog.Printf(\"got hash %x\\n\", proposedBlock.Hash())\n\n\t\t// TODO actually check stuff\n\n\t\t// Pretty sure I don't need a mutex here because I'm just reading\n\t\t// and this function is the only thing that can write.  Also there's\n\t\t// only 1 iteration of this loop happening at a time.\n\t\tif !CheckNextBlock(bc.tip, proposedBlock) {\n\t\t\tlog.Printf(\"Invalid block received:\\n%s\\n\", proposedBlock.ToString())\n\t\t\tcontinue\n\t\t}\n\n\t\t// this thing keeps history, maybe save to disk...\n\t\tblockHistory = append(blockHistory, proposedBlock)\n\n\t\t// use mutex and update tip\n\t\t// also append to file\n\t\tbc.mtx.Lock()\n\t\tbc.tip = proposedBlock\n\n\t\tf, err := os.OpenFile(chainFilename, os.O_APPEND|os.O_WRONLY, 0666)\n\t\tif err != nil {\n\t\t\t// crash if file doesn't work\n\t\t\tpanic(err)\n\t\t}\n\n\t\tf.WriteString(proposedBlock.ToString() + \"\\n\")\n\t\tf.Close()\n\n\t\tbc.mtx.Unlock()\n\n\t\tlog.Printf(\"Block accepted; height is now %d\\n\", len(blockHistory))\n\n\t}\n}\n\n// CheckNextBlock checks if the block attaches, has work, etc.\n// Assumes \"prev\" block is OK, but checks \"next\"\nfunc CheckNextBlock(prev, next Block) bool {\n\t// first check the work on the new block.  33 bits needed.\n\tif !CheckWork(next, 33) {\n\t\tlog.Printf(\"not enought work! \")\n\t\treturn false\n\t}\n\n\t// first, check that next points back to prev\n\tif prev.Hash() != next.PrevHash {\n\t\tlog.Printf(\"hashes don't chain up! \")\n\t\treturn false\n\t}\n\n\t// probably enough checks for now?\n\n\treturn true\n}\n\n// CheckWork checks if there's enough work\nfunc CheckWork(bl Block, targetBits uint8) bool {\n\th := bl.Hash()\n\n\tfor i := uint8(0); i < targetBits; i++ {\n\t\t// for every bit from the MSB down, check if it's a 1.\n\t\t// If it is, stop and fail.\n\t\t// Could definitely speed this up by checking bytes at a time.\n\t\t// Left as excercise for the reader...?\n\t\tif (h[i/8]>>(7-(i%8)))&0x01 == 1 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "pset03/README.md",
    "content": "# pset03\n\nIn this assignment, we'll make some transactions on the bitcoin (test) network.\n\n\n\n\nFor pset03, we're going to make some transactions on the Bitcoin test network.  This assignment uses btcd for libraries, which is a bitcoin implementation written in golang.  The goal is to understand how transactions are constructed and signed, and to become more familiar with the utxo model bitcoin uses.\n\nTestnet3 is a network for testing out bitcoin.  It works almost exactly like the regular bitcoin network (small changes to addresses, the difficulty of proof of work) but everyone agrees that the testnet coins are not worth anything.  This isn't enforced by anything on the network, it's just something people decide.  The fact that it's testnet3 indicates that this rule failed for testnets 1 and 2, when people started trading the testnet coins for mainnet coins.\n\nIn this pset you'll perform many of the functions of wallet software, by identifying outputs to spend, creating transactions, signing them, and broadcasting them to the network.  Most wallet software does this all automatically, but this assignment is more manual so you can see how it works.\n\n\n## Setup\n\nGet bitcoin core 0.16.0, available at https://bitcoincore.org/en/download/\n\nTo get on to the test network, make a bitcoin.conf file in your bitcoin folder (which is HOMEDIR/.bitcoin/bitcoin.conf) (In linux that's ~/.bitcoin/) and have the following line in the conf file:\n\ntestnet=1\n\nand then run\n\nbitcoind --daemon\n\nso that it runs in the background.  Syncing up to the testnet will require download of around 12 GB, and will take a few hours depending on your computer's speed.  Some MIT guest wifi will block outgoing connections to different ports, so try using wired ethernet or another SSID if it doesn't seem to download.\n\nOnce bitcoind is running, you can see what it's doing by looking at the /.bitcoin/testnet3/debug.log file, and issue commands with bitcoin-cli.\n\nIn this repo there are 4 files:\n```\nmain.go\naddrfrompriv.go  \neztxbuilder.go\nopreturn.go\n```\n\nHere's what they do\n\n#### main.go\nThis is the main function which is called when you run `./utxohunt`\n\nEdit this file to call functions from other files when you run the program.\n\n#### addrfrompriv.go\nCreates a public key and bitcoin address from a private key.  Addresses are copy&pastable encodings of public key hashes.\n\n#### eztxbuilder.go\nPuts a transaction together, signs it, and prints the tx hex to the screen.  This can then be sent to the network with the pushrawtransaction command in bitcoin-cli like , or to your own bitcoin node with `./bitcoin-cli pushrawtransaction (tx hex)`\n\n[https://testnet.smartbit.com.au/txs/pushtx](https://testnet.smartbit.com.au/txs/pushtx)\n\n#### opreturn.go\nSimilar to eztxbuilder.go, but creates a transaction with 1 input, and 2 outputs.  1 of the outputs is an \"OP_RETURN\" output which can contain arbitrary data.  Use this to submit your results to the blockchain.\n\n## Task 1: Create a Bitcoin Address\n\nFirst, look in utxohunt/main.go, and make a keypair.  The AddressFromPrivateKey() function will help you.  Put your own random string in to generate a private key.  If you call the AddressFromPrivateKey() function, it will return that address as a string, as well as give you the compressed public key and pay to witness pubkey hash script.\n\nSave this address (it starts with an \"m\").  You'll need this to send the money to yourself.\n\n## Task 2: Find the first treasure hunt transaction\n\nA _block explorer_ is a website which watches the blockchain and parses out information about blocks, addresses, and transactions.  You can use this blockexplorer to see what's happening on the Bitcoin testnet: [https://testnet.smartbit.com.au/](https://testnet.smartbit.com.au/).\n\nI've created a transaction with one 70 outputs.\n\n`1f497ac245eb25cd94157c290f62d042e3bdda1e57920b6d1d2c5cfa362c12da` is the txid, or unique identifier of this transaction.  (The txid is the hash of the serialized transaction)\n\nThe outputs of this transaction are all have the same address, which determines how they can be spent.  The private key for this pubkey-hash address is the double-sha256 of the string \"mas.s62\".  \n\nClaim an unspent output in this transaction.  Please be nice and leave the rest of the outputs for other classmates! :)\n\n## Task 3: Make a transaction\n\nUsing EZTxBuilder(), make a transaction sending from the up-for-grabs transaction to your own address.\n\nYou will need to modify \n\n\thashStr\n\n\toutPoint (output index number)\n\n\tsendToAddressString\n\n\tprevAddressString (the address of the \"BTC secret key\" pubkey)\n\n\twire.NewTxOut (change the amount to less than the input amount.  A few thousand less is enough of a fee)\n\n\nWhen you modify the code, you need to re-compile the code.  Run \"go build\" in that directory to compile.\n\nYou'll get a long hex string which you can test by running the transaction though bitcoin-cli's decoderawtransaction command `./bitcoin-cli decoderawtransaction (tx hex)`\n\nIf you get an error, it might be for one of the following reasons:\n\n1.  Someone has already claimed the output you are trying to get.  Go back and look at the transaction's page and see if the output is still available.  It will say \"inputs spent\" or equivalent.\t\n\n2.  64: non-mandatory-script-verify-flag (Signature must be zero for\nfailed CHECK(MULTI)SIG operation).  This means your signature was\ninvalid.  Often this is because the hash being signed was invalid.\nThis could be because the previous output you signed and the one you\nindicted don't match, the wrong amount is being sent to the\nWitnessScript function, or some other invalid data is in the\ntransaction prior to signing.  An invalid signature can also be caused\nby using the wrong key.  In that case, you will usually get this\nerror:\n\n3.  64: non-mandatory-script-verify-flag (Script failed an OP_EQUALVERIFY operation).  This means you're probably using the wrong key to sign with, as the public key used and public key hash in the previous output script don't match.\n\n4.  TX decode failed.  That means you're missing some characters, or the transaction is otherwise unintelligable to the bitcoin-cli parser.\n\nIf everything worked, the decoderawtransaction output will show you a json representation of the transaction you've created.  You can then send it to the network with the command sendrawtransaction.  If that works, it will return a txid. If that works and the transaction is confirmed (chechk with getrawtransaction), you've got some testnet coins!  You can use the same EZTxBuilder() to send that money somewhere else.\n\n\n## Further steps / bonus money\n\nTry to get some more money.  There are some coins stashed through the network, and I will add more over the week :)\n\nThe first output One has a private key which is the double-sha256 of the *address* from which you took the first coins.  \n\nTo grab these coins, you will need to use AddressFromPrivateKey() to generate that address, search the blockchain for the txid, and try to send an output to yourself, the same way as with the first transaction you created.\n\n[More coins for grabs will be added soon -- check back when this document is updated on github!]\n\nNote that in many cases, someone else in the class may have grabbed the coins before you.  That's OK, just write down where you found the coins to be and the private key you would have used to take them.\n\n\n## Submitting work\n\nSubmit your homework... ON THE BLOCKCHAIN!\n\n(note that you should also submit your code to the class github; the OP_RETURN is a fun way to try out this aspect, and everyone can see it)\n\nThe opreturn.go file will walk you through how to make an OP_RETURN transaction.\n\nThese transactions are on the public blockchain, and we'll find them there.\n\nOP_RETURN outputs start with a single opcode (OP_RETURN) which terminates script execution.  This output can never be spent, and is thus not added to the utxo database.  You can put whatever data you want after the OP_RETURN, though it's limited to 40 bytes in length.\n\nFor this assignment, sending your coins to an OP_RETURN output with your name or MIT ID number is cryptographic proof that you sent the coins (or someone else did, impersonating you!)\n\nUse opreturn.go to create transactions spending the outputs you sent to yourself using EZTxBuilder().  The created transaction will to an address as well as an OP_RETURN output.  Broadcast this to the network, hope it gets into a block, and you're done! \n\nTo parse other OP_RETURNs, or the one you made yourself, try using python.\n\nHere's an example transaction:\n`c29dc7b974901989c156578fc8dd341752bf28e415191bb1dc4b3aabc3ac11c5`\nthe OP_RETURN is 363839322054657374206f7574707574\n\nLoad up python in your terminal (most linux and mac terminals have it) by running ` $ python `\nfrom there:\n``` >>> \"363839322054657374206f7574707574\".decode(\"hex\")\n'6892 Test output' ```\n\nPrefix all your OP_RETURNs with s62 so it's easy to search for them.\n\nIf you only grab a little bit of money and send an OP_RETURN, that's fine.  If you manage to get some of the bonus utxos and send OP_RETURNs, even better!  If you want to get really fancy, try aggregating all your outputs into a single, higher value tx output. (Code left as excercise to the reader)\n"
  },
  {
    "path": "pset03/addrfrompriv.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcd/chaincfg/chainhash\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/btcsuite/btcutil\"\n)\n\nfunc AddressFromPrivateKey() (string, error) {\n\n\t// private key is the hash of some string (better to use real randomness\n\t// or a real KDF but this is OK for class.\n\t// Put any phrase you want here to make your own private key.\n\tphraseHash := chainhash.DoubleHashB([]byte(\"mpQQryVrYmGNPxVqNeE5RgoYAv2v66Psao\"))\n\n\t// make a new private key struct.  Private key structs also have a pubkey in them\n\tpriv, _ := btcec.PrivKeyFromBytes(btcec.S256(), phraseHash)\n\n\t// print out what it looks like in hex, compressed (x-coordinate, y-sign only)\n\n\tfmt.Printf(\"pubkey is %x\\n\", priv.PubKey().SerializeCompressed())\n\n\thash160 := btcutil.Hash160(priv.PubKey().SerializeCompressed())\n\n\tadr, err := btcutil.NewAddressPubKeyHash(hash160, testnet3Parameters)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tscript, err := txscript.PayToAddrScript(adr)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tfmt.Printf(\"script is: %x\\n\", script)\n\treturn adr.String(), nil\n}\n"
  },
  {
    "path": "pset03/eztxbuilder.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcd/chaincfg/chainhash\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/btcsuite/btcd/wire\"\n\t\"github.com/btcsuite/btcutil\"\n)\n\n// TxToHex takes a transaction and outputs the serialized tx in hex.\n// Provided to make things easier.  Returns an empty string if there's an error.\nfunc TxToHex(tx *wire.MsgTx) string {\n\tif tx == nil {\n\t\treturn \"\"\n\t}\n\tbuf := new(bytes.Buffer)\n\ttx.Serialize(buf)\n\treturn fmt.Sprintf(\"%x\", buf.Bytes())\n}\n\nfunc EZTxBuilder() *wire.MsgTx {\n\n\t// create a new, empty transaction, set version to 2\n\ttx := wire.NewMsgTx(2)\n\n\t// we need to add at least one input and one output.  Lets build the input first\n\t// inputs consist of a previous output point, and a witness (signature data)\n\t// output points (out points) are a transaction hash (txid) and an index number\n\t// indicating which output for that transaction is being consumed.\n\t// since txids are unique, this will not be replayable.  pick a tx output\n\t// that has not yet been consumed by someone else.\n\n\thashStr := \"\" // put the input txid here\n\n\t// it'll work\n\t// also note that in bitcoin, all the 32-byte strings are displayed backwards.\n\t// who knows why.\n\toutpointTxid, err := chainhash.NewHashFromStr(hashStr)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// let's try to spend output index 7\n\toutPoint := wire.NewOutPoint(\n\t\toutpointTxid, 0) // replace 0 with the output you want to spend\n\n\t// create the TxIn, with empty sigscript field\n\tinput := wire.NewTxIn(outPoint, nil, nil)\n\n\t// Next, we create the output.  Outputs are [amount, address] pairs, where\n\t// amounts are 64-bit signed integers, and addresses are scripts that run on the\n\t// bitcoin stack interpreter\n\n\t// Put your wallet address as a string here, and it will be decoded into a 20-byte\n\t// hash.  That hash is used in the standard \"pay to pubkey hash\" (p2pkh) script\n\n\tsendToAddressString := \"\" // put the address you're sending to here\n\tsendToAddress, err := btcutil.DecodeAddress(sendToAddressString, testnet3Parameters)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// this builds an output script.\n\n\tsendToScript, err := txscript.PayToAddrScript(sendToAddress)\n\n\t// amounts in bitcoin are integers, but \"one bitcoin\" is actually 100 million of the\n\t// base unit, often called \"satoshis\".  If the output amount is greater than the\n\t// input amount, the transaction is invalid (because it's creating more coins)\n\t// ( this check is performed over the sum of the inputs and outputs.  There is an\n\t// exception for the coinbase transaction.)\n\toutput := wire.NewTxOut(0, sendToScript) // replace 0 with the output value\n\n\t// put the inputs and outputs into the transaction\n\n\ttx.AddTxIn(input)\n\ttx.AddTxOut(output)\n\n\t// the transaction now has the inputs and outputs, but is missing the signature.\n\t// We need a private key to sign with\n\t// Hash any phrase to make a private key\n\tphraseHash := chainhash.DoubleHashB([]byte(\"secret phrase here\"))\n\n\t// make a new private key struct.  Private key structs also have a pubkey in them\n\tpriv, _ := btcec.PrivKeyFromBytes(btcec.S256(), phraseHash)\n\n\tfmt.Printf(\"my pubkey: %x\\n\", priv.PubKey().SerializeCompressed())\n\t// we also need the script from the previous transaction.  This is redundant as it\n\t// is covered by the txid\n\n\tprevAddressString := \"\" // put the address you're sending \"from\" here\n\tprevAddress, err := btcutil.DecodeAddress(prevAddressString, testnet3Parameters)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tspendFromScript, err := txscript.PayToAddrScript(prevAddress)\n\n\t// SignatureScript takes a bunch of arguments.  In this case:\n\t// tx: transaction itself\n\t// hcahce: the hash cache\n\t// 0: which input to sign\n\t// spendFromScript: the previous output script (redundant, covered by input txid)\n\t// txscript.SigHashAll: the signature hash type.  usually \"all\", meaning the\n\t// signature covers all inputs and outputs in the transaction.\n\t// true: the previous script has a compressed public key hash.\n\n\tpubSig, err := txscript.SignatureScript(\n\t\ttx, 0, spendFromScript, txscript.SigHashAll, priv, true)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// once the signature has been created, we put the signature onto the\n\t// \"witness stack\" of the input.\n\n\ttx.TxIn[0].SignatureScript = pubSig\n\n\treturn tx\n}\n"
  },
  {
    "path": "pset03/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/btcsuite/btcd/chaincfg\"\n)\n\nvar (\n\t// we're running on testnet3\n\ttestnet3Parameters = &chaincfg.TestNet3Params\n)\n\nfunc main() {\n\tfmt.Printf(\"mas.s62 pset03 - utxohunt\\n\")\n\n\t// Task #1 make an address pair\n\t// Call AddressFrom PrivateKey() to make a keypair\n\n\t// Task #2 make a transaction\n\t// Call EZTxBuilder to make a transaction\n\n\t// task 3, call OpReturnTxBuilder() the same way EZTxBuilder() was used\n\n\treturn\n}\n"
  },
  {
    "path": "pset03/opreturn.go",
    "content": "package main\n\nimport (\n\t\"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcd/chaincfg/chainhash\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/btcsuite/btcd/wire\"\n\t\"github.com/btcsuite/btcutil\"\n)\n\nfunc OpReturnTxBuilder() *wire.MsgTx {\n\n\t// this function is similar to EZTxBuilder in that it builds a transaction.\n\t// however, it has 2 outputs.  One is just sending money back to the same address,\n\t// and the other is an \"op_return\" output, which cannot be spent, but can\n\t// include arbitrary data that will be saved but ignored by the bitcoin network\n\n\t// create a new, empty transaction, set version to 2. Same as EZ\n\ttx := wire.NewMsgTx(2)\n\n\t// put the input txid here (your own)\n\thashStr := \"\"\n\n\toutpointTxid, err := chainhash.NewHashFromStr(hashStr)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// spend output index 0, which is the only output for that tx\n\toutPoint := wire.NewOutPoint(outpointTxid, 0)\n\n\t// create the TxIn, with empty sigscript field\n\tinput := wire.NewTxIn(outPoint, nil, nil)\n\n\t// done with inputs for now.  Build outputs.  There will be 2 outputs,\n\t// the OP_RETURN output and the normal pubkey hash output.\n\t// The OP_RETURN output will be unspendable, so we should put 0 coins there.\n\n\t// Put a message here with your name or MIT ID number so I can find your\n\t// submission on the blockchain.\n\topReturnData := []byte(\"your message here\")\n\t// build the op_return output script\n\t// this is the OP_RETURN opcode, followed by a data push opcode, then the data.\n\topReturnScript, err :=\n\t\ttxscript.NewScriptBuilder().AddOp(txscript.OP_RETURN).AddData(opReturnData).Script()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// build the op_return output.\n\topReturnOutput := wire.NewTxOut(0, opReturnScript) // keep it as 0 value\n\n\t// next, build the pubkey hash output.  This the same as before in the EZ function.\n\t// put the address you're sending to here.  It's the same as the address you're\n\t// spending from!\n\tsendToAddressString := \"\"\n\tsendToAddress, err := btcutil.DecodeAddress(sendToAddressString, testnet3Parameters)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tsendToScript, err := txscript.PayToAddrScript(sendToAddress)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// put a bit less than your input amount, so that there is a fee for the miners\n\t// this will ensure miners put your transaction in a block.\n\tp2pkhOutput := wire.NewTxOut(123450000, sendToScript)\n\n\t// put the tx together, 1 input, 2 outputs.\n\ttx.AddTxIn(input)\n\ttx.AddTxOut(opReturnOutput)\n\ttx.AddTxOut(p2pkhOutput)\n\n\t// finally we need to sign.  Same as EZ func.\n\t// we already know the address you're sending from\n\tspendFromScript, err := txscript.PayToAddrScript(sendToAddress)\n\n\tphraseHash := chainhash.DoubleHashB([]byte(\"private key here\"))\n\tpriv, _ := btcec.PrivKeyFromBytes(btcec.S256(), phraseHash)\n\n\tpubSig, err := txscript.SignatureScript(\n\t\ttx, 0, spendFromScript, txscript.SigHashAll, priv, true)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\ttx.TxIn[0].SignatureScript = pubSig\n\n\treturn tx\n}\n"
  }
]