@jr0cket/

ClojureBridge London exercises

Clojure

No description

fork
loading
Files
  • main.clj
  • target

This Plugin Crashed!

Error: Error: must not create an existing file {"type":"CREATE_FILE","wid":"0.7086802561814105","path":"main.clj","file":{"path":"main.clj","content":{"asEncoding":{"base64":"KG5zIGNsb2p1cmUtdGhyb3VnaC1jb2RlLmNsb2p1cmVicmlkZ2UtZXhlcmNpc2VzKQoKOzsgMDEgQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgeWVhcnMgZnJvbSBhbGwgdGhlIGZvbGxvd2luZyBsYW5ndWFnZXMKOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Cjs7IENsb2p1cmUgKDEwIHllYXJzKQo7OyBIYXNrZWxsICgyNyB5ZWFycykKOzsgUHl0aG9uICgyNiB5ZWFycykKOzsgSmF2YXNjcmlwdCAoMjEgeWVhcnMpCjs7IEphdmEgKDIyIHllYXJzKQo7OyBSdWJ5ICgyMiB5ZWFycykKOzsgQyAoNDUgeWVhcnMpCjs7IEMrKyAoMzQgeWVhcnMpCjs7IExpc3AgKDU5IHllYXJzKQo7OyBGb3J0cmFuICg2MCB5ZWFycykKOzsgWW91IGNhbiB1c2UgdGhlIGxpc3Qgb2YgeWVhcnMgaGVyZSBhcyBhIGNvbnZlbmllbmNlIDEwIDI3IDI2IDIxIDIyIDIyIDQ1IDM0IDU5IDYwCgo7OyBjYWxjdWxhdGUgdGhlIHRvdGFsIGJ5IGFkZGluZyB0aGUgYWdlIG9mIGVhY2ggbGFuZ3VhZ2UgdG9nZXRoZXIKCigrIDEwIDI3IDI2IDIxIDIyIDIyIDM0IDQ1IDU5IDYwKQoKOzsgVGhlcmUgYXJlIHR3byB2YWx1ZXMgdGhlIHNhbWUsIHNvIHdlIGNvdWxkIGNhbGN1bGF0ZSB0aGUgdG90YWwgYXMgZm9sbG93cwoKKCsgMTAgMjcgMjYgMjEgKCogMjIgMikgMzQgNDUgNTkgNjApCgo7OyBGaW5kIHRoZSBhdmVyYWdlIGFnZSBvZiBsYW5ndWFnZXMgYnkgYWRkaW5nIHRoZSBhZ2VzIG9mIGFsbCB0aGUgbGFuZ3VhZ2UgYWdlcywgdGhlbiBkaXZpZGUgdGhhdCB0b3RhbCBhZ2Ugd2l0aCB0aGUgbnVtYmVyIG9mIGxhbmd1YWdlcwoKKC8gKCsgMTAgMjcgMjYgIDIxIDIyIDIyIDQ1IDM0IDU5IDYwKQogICAxMCkKCgo7OyBXZSBjYW4gdXNlIHRoZSBjb3VudCBmdW5jdGlvbiB0byBmaW5kIG91dCBob3cgbWFueSBsYW5ndWFnZSBhZ2VzIHdlIGhhdmUKKC8gKCsgMTAgMjcgMjYgIDIxIDIyIDIyIDQ1IDM0IDU5IDYwKQogICBjb3VudCAoMTAgMjcgMjYgIDIxIDIyIDIyIDQ1IDM0IDU5IDYwKSkKCgoKOzsgMDIgQ29udmVydCBiZXR3ZWVuIHRpbWUgYW5kIG51bWJlcnMKOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Cgo7OyBBc3N1bWluZyBpdHMgYmVlbiAyIGhvdXJzIGFuZCAyMCBtaW51dGVzIHNpbmNlIHlvdSB3b2tlIHVwLCBsZXRzIGNhbGN1bGF0ZSB0aGUgdGltZSBpbiBtaW51dGVzOgoKOzsgV2UgYWRkIHRoZSByZXN1bHQgb2YgbXVsdGlwbHlpbmcgMiBob3VycyBieSA2MCB0byBnZXQgdGhlIG51bWJlciBvZiBtaW51dGVzIHdpdGggdGhlIDI1IG1pbnV0ZXMKKCsgKCogMiA2MCkgMjUpCgoKOzsgVG8gZ2V0IHRoZSB0aW1lIGluIHNlY29uZHMsIHdlIGNhbiB0YWtlIHRoZSBwcmV2aW91cyBleHByZXNzaW9uIGFuZCB3cmFwIGl0IHdpdGggYW5vdGhlciBleHByZXNzaW9uIHRoYXQgbXVsdGlwbGllcyB0aGUgcmVzdWx0IGJ5IDYwLgooKiAoKyAoKiAyIDYwKSAyNSkgNjApCgoKOzsgQXNzdW1pbmcgaXQgaGFzIGJlZW4gNDI4IHNlY29uZHMgc2luY2UgdGhlIHdvcmtzaG9wIHN0YXJ0ZWQsIHRoZSBudW1iZXIgb2YgbWludXRlcyBjb3VsZCBiZSBjYWxjdWxhdGVkIGxpa2UgdGhpczoKKHF1b3QgNDI4IDYwKQoKCjs7IEFuZCB0aGUgbnVtYmVyIG9mIHNlY29uZHMgY2FsY3VsYXRlZCBsaWtlIHRoaXM6CihyZW0gNDI4IDYwKQoKCjs7IDcgaG91cnMgaXMgNDIwIG1pbnV0ZXMsIHNvIHRoZXJlIGFyZSA4IG1pbnV0ZXMgcmVtYWluaW5nIHRoYXQgZG8gbm90IGZpdCBpbnRvIGEgd2hvbGUgaG91ci4KOzsgU28gNDI4IG1pbnV0ZXMgaXMgdGhlIHNhbWUgYXMgNyBob3VycyBhbmQgOCBtaW51dGVzCgoKOzsgMDMgU3RyaW5ncwo7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsKCjs7IFVzaW5nIGEgZnVuY3Rpb24geW91IGNhbiBjcmVhdGUgYSBzdHJpbmcgYW5kIGpvaW4gdmFsdWVzIHRvIGNyZWF0ZSBhIHN0cmluZwooc3RyICJNeSBmYXZvcml0ZSBjb2xvdXJzIGFyZSIgIiAiICJncmVlbiIgIiAiICJhbmQiICIgIiJwdXJwbGUiKQoKCjs7IFVzZSBhIGZ1bmN0aW9uIHRvIHNlZSBpZiBhIHN0cmluZyBjb250YWlucyBhIGNvbG91ci4gU2VlIHRoZSBIaW50IGJlbG93IGlmIHlvdSBhcmUgbm90IHN1cmUgaG93IHRvIHN0YXJ0Cjs7IERvZXMgdGhlIHN0cmluZyAiUmFjaGVsIG9mIFlvcmsgZ2F2ZSBicm93biBicmVhZCBpbiB2YW5zIiBjb250YWluIHRoZSBjb2xvdXIgYnJvd24/CgooY2xvanVyZS5zdHJpbmcvaW5jbHVkZXM/ICJSYWNoZWwgb2YgWW9yayBnYXZlIGJyb3duIGJyZWFkIGluIHZhbnMiICJicm93biIpCgoKOzsgRml4aW5nIHNwZWxsaW5nIG1pc3Rha2VzCjs7IE9uZSBhc3BlY3Qgb2YgZml4aW5nIHNwZWxsaW5nIG1pc3Rha2VzIGlzIHRvIGZpbmQgYW5kIHJlcGxhY2UgaW5jb3JyZWN0IHdvcmRzLgo7OyBUaGUgY2xvanVyZS5zdHJpbmcgbGlicmFyeSBwcm92aWRlcyB0aGUgcmVwbGFjZSBmdW5jdGlvbi4KCjs7IFJlcGxhY2UgaW4gdGhpcyBzdHJpbmcgdGhlIGNoYXJhY3RlcnMgb3ZyIHdpdGggdGhlIGNoYXJhY3RlcnMgb3ZlcgoKKGNsb2p1cmUuc3RyaW5nL3JlcGxhY2UgInNpbXBsaWNpdHkgb3ZyIGNvbXBsZXhpdHkiICJvdnIiICJvdmVyIikKCgooY2xvanVyZS5zdHJpbmcvcmVwbGFjZSAiY29lZCBhcyBkYXRhIGFzIGNvZWQiICJjb2VkIiAiY29kZSIpCgoKOzsgTk9URTogQnJpZWZseSBkaXNjdXNzIGxpYnJhcmllcyBhbmQgbmFtZXNwYWNlcwo7OyBjbG9qdXJlLmNvcmUgaXMgaW5jbHVkZWQgYnkgZGVmYXVsdCBpbiBhbGwgcHJvamVjdHMKOzsgb24gdGhlIEpWTSBob3N0LCBzbyBpcyBqYXZhLmxhbmcKOzsgY2xvanVyZS54eHggbGlicmFyaWVzIGNhbiBiZSB1c2VkIGJ5IGZ1bGx5IHF1YWxpZnlpbmcgdGhlaXIgbmFtZXNwYWNlCjs7IE90aGVyIENsb2p1cmUgbGlicmFyaWVzIG5lZWQgdG8gYmUgYWRkZWQgYXMgYSBwcm9qZWN0IGRlcGVuZGVuY3kgdG9vLgoKCgo7OyBTaW1wbGUgUGFsZW5kcm9tZSBDaGVja2VyCjs7IEEgUGFsaW5kcm9tZSBpcyBhIHdvcmQgdGhhdCBpcyBzcGVsdCB0aGUgc2FtZSB3aGV0aGVyIGl0IGlzIHdyaXR0ZW4gYmFja3dhcmRzIG9yIGZvcndhcmRzLiBTbyB3aGVuIHlvdSByZXZlcnNlIHRoZSB3b3JkIGl0IHNob3VsZCBzdGlsbCBsb29rIHRoZSBzYW1lLgoKOzsgVXNpbmcgZnVuY3Rpb25zIG9uIHN0cmluZ3MgdGhhdCBhcmUgbm90IHBhcnQgb2YgdGhlIGNsb2p1cmUuc3RyaW5nIGxpYnJhcnkgY2FuIGdpdmUgJ2ludGVyZXN0aW5nJyByZXN1bHRzLgooPSAicmFkYXIiIChyZXZlcnNlICJyYWRhciIpKQoKCjs7IFRoZSBjbG9qdXJlLmNvcmUvcmV2ZXJzZSBmdW5jdGlvbiByZXR1cm5zIGEgbGlzdCB0aGUgaW5kaXZpZHVhbCBjaGFyYWN0ZXJzIGluIHJldmVyc2Ugb3JkZXIsIHJhdGhlciB0aGFuIHJldmVyc2luZyB0aGUgc3RyaW5nIGFzIGEgc2luZ2xlIHZhbHVlLgoKOzsgVXNpbmcgdGhlIGNsb2p1cmUuc3RyaW5nL3JldmVyc2UgZnVuY3Rpb24ga2VlcHMgdGhlIHZhbHVlIGFzIGEgc3RyaW5nCig9ICJyYWRhciIgKGNsb2p1cmUuc3RyaW5nL3JldmVyc2UgInJhZGFyIikpCgoKCgo7OyAwNCBBc3NpZ25tZW50IChiaW5kaW5nIHN5bWJvbHMgdG8gdmFsdWVzKQo7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsKCjs7IFRoZSA9IGZ1bmN0aW9uIGlzIHVzZWQgdG8gY29tcGFyZSB2YWx1ZXMKCjs7IFdlIGNhbiB1c2UgZGVmIHRvIGdpdmUgYSBuYW1lIHRvIHNvbWV0aGluZyB3ZSBhbHJlYWR5IGtub3csIGxpa2UgYSBzdHJpbmcKCihkZWYgamVubnktbG92ZXMgIkplbm55IGxvdmVzIHJ1YmFyYiBjcnVtYmxlIGFuZCB2YW5pbGxhIGN1c3RhcmQiKQoKOzsgV2UgY2FuIGFsc28gdXNlIGRlZiB0byBnaXZlIGEgbmFtZSB0byBzb21ldGhpbmcgd2UgZG9udCBrbm93IHlldCwgZWcuIGEgY2FsY3VsYXRpb24uCgooZGVmIG1hbmdvZXMgNCkKKGRlZiBvcmFuZ2VzIDEyKQooZGVmIHRvdGFsLWZydWl0ICgrIG1hbmdvZXMgb3JhbmdlcykpCihkZWYgYXZlcmFnZS1mcnVpdC1hbW91bnQgKC8gdG90YWwtZnJ1aXQgMikpCmF2ZXJhZ2UtZnJ1aXQtYW1vdW50CgoKOzsgTk9URTogSXRzIGNvbW1vbiB0byB1c2UgYSBtYXAgdG8gZGVmaW5lIG11bHRpcGxlIHZhbHVlcyBpbiBhIG5hbWVzcGFjZSwKOzsgcmF0aGVyIHRoYW4gbXVsdGlwbGUgaW5kaXZpZHVhbCBkZWYgZnVuY3Rpb25zCgooZGVmIGZydWl0LXN0b2NrIHs6bWFuZ29zICAgNAogICAgICAgICAgICAgICAgICA6b3JhbmdlcyAxMn0pCgoKOzsgMDUgQ29sbGVjdGlvbnMgLSBWZWN0b3JzCjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OwoKOzsgQSB2ZWN0b3Igb2YgdGhlIHRlbXBlcmF0dXJlcyBmb3IgdGhlIG5leHQgd2VlawpbOSAyIC0zIDQgNSA5IDRdCgo7OyBhc3N1bWluZyB0aGUgZmlyc3QgdGVtcGVyYXR1cmUgaXMgZm9yIE1vbmRheSwgdGhlbiB0byBnZXQgVGh1cnNkYXkgd2UgY2FuIHdyaXRlCjs7IFRoZSBpbmRleCBvZiBhIHZlY3RvciBzdGFydHMgYXQgemVybwoKKG50aCBbOSAyIC0zIDQgNSA5IDRdIDMpCgoKOzsgU2VxdWVuY2VzIC0gYW4gYWJzdHJhY3Rpb24gb3ZlciBjb2xsZWN0aW9ucwoKKGZpcnN0ICBbOSAyIC0zIDQgNSA5IDRdKQooc2Vjb25kIFs5IDIgLTMgNCA1IDkgNF0pCihsYXN0ICAgWzkgMiAtMyA0IDUgOSA0XSkKKHJlc3QgICBbOSAyIC0zIDQgNSA5IDRdKQoKOzsgaG93IHRvIHdlIGdldCB0aGUgdGhpcmQgdmFsdWUgZnJvbSB0aGUgdmVjdG9yIFsiQmlydGhkYXlzIGFyZSIgImZ1bGwgb2YiICJwcmVzZW50cyIgInRoYXQgeW91IiAiYWx3YXlzIGRyZWFtZCIgIm9mIGhhdmluZyJdCgo7OyBXZSBjYW4gY2FsbCBvbmUgZnVuY3Rpb24gYW5kIHVzZSBpdHMgcmV0dXJuIHZhbHVlIGFzIGFuIGFyZ3VtZW50IHRvIGFub3RoZXIgZnVuY3Rpb24uCgo7OyByZXN0IGZ1bmN0aW9uIHJldHVybnMgYWxsIHZhbHVlcyBidXQgdGhlIGZpcnN0IG9uZS4KOzsgdGhlIHNlY29uZCB2YWx1ZSBjYW4gdGhlbiBiZSByZXR1cm5lZCBmcm9tIHRoZSBjb2xsZWN0aW9uCihzZWNvbmQKIChyZXN0CiAgWyJCaXJ0aGRheXMgYXJlIiAiZnVsbCBvZiIgInByZXNlbnRzIiAidGhhdCB5b3UiICJhbHdheXMgZHJlYW1kIiAib2YgaGF2aW5nIl0pKQoKCjs7IFVzaW5nIExvY2FsIEFzc2lnbm1lbnQKOzsgVXNlIGEgbG9jYWwgbmFtZSB0byBob2xkIGludGVybWVkaWFyeSB2YWx1ZXMgaW4gdGhlIHByb2Nlc3Npbmcgb2YgdGhlIGNvbGxlY3Rpb24uCgo7OyB0aGUgbGV0IGZ1bmN0aW9uIGFzc2lnbmVzIGEgbmFtZSB0byBvdXIgY29sbGVjdGlvbiBvZiB2YWx1ZXMKOzsgdGhlbiB3ZSBnZXQgdGhlIHZhbHVlIGluIHRoaXJkIHBsYWNlIGJ5IHVzaW5nIHRoZSBuYW1lLgoKKGxldCBbcmVzdC1vZi1zdHJpbmdzCiAgICAgIChyZXN0IFsiQmlydGhkYXlzIGFyZSIgImZ1bGwgb2YiICJwcmVzZW50cyIgInRoYXQgeW91IiAiYWx3YXlzIGRyZWFtZCIgIm9mIGhhdmluZyJdKV0KICAoc2Vjb25kIHJlc3Qtb2Ytc3RyaW5ncykpCgoKCjs7IEZpbmQgdGhlIGFnZSBvZiB0aGUgeW91bmdlc3QgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UKOzsgVGhlIGFnZXMgYXJlIG5vdCBpbiBvcmRlciwgc28geW91IGNhbnQganVzdCBnZXQgdGhlIGZpcnN0IHZhbHVlLgoKKGZpcnN0IChzb3J0IFsxMCAyNyAyNiAyMSAyMiAyMiA0NSAzNCA1OSA2MF0pKQoKOzsgVGhlIG1pbiBmdW5jdGlvbiB3aWxsIHNpbXBsaWZ5IG91ciBleHByZXNzaW9uCihtaW4gWzEwIDI3IDI2IDIxIDIyIDIyIDQ1IDM0IDU5IDYwXSkKCjs7IE5PVEUgdGhlcmUgYXJlIG92ZXIgNjAwIGZ1bmN0aW9ucyBpbiBjbG9qdXJlLmNvcmUgc28gdGhlcmUgaXMgb2Z0ZW4gYSBmdW5jdGlvbiB5b3UgYXJlIGxvb2tpbmcgZm9yIHRvIHNpbXBsaWZ5IHlvdSBjb2RlCgoKCjs7IENsb2p1cmUgY29tcGFyZXMgdmFsdWVzIHJhdGhlciB0aGFuIHR5cGVzIChpbiBnZW5lcmFsKQoKKD0gWzEgMiAzXSBbMSAyIDNdKQooPSBbMSAyIDNdIFs0IDUgNl0pCig9IFsxIDIgM10gWzMgMiAxXSkKKD0gWyJIZWxsbyIgIldvcmxkIl0gWyJIZWxsbyIgIldvcmxkIiAiV2lkZSIgIldlYiJdKQooPSAnKDEgMiAzKSBbMSAyIDNdKQoKCgoKOzsgMDYgQ29sbGVjdGlvbnMgLSBNYXBzCjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OwoKOzsgTWFwcyBhcmUga2V5LXZhbHVlIHBhaXJzCjs7IE1hcHMgY2FuIGJlIHNlbGYgZGVzY3JpYmluZyBpZiB5b3UgdXNlIG1lYW5pbmdmdWwgbmFtZXMgZm9yIHRoZSBrZXlzCgooY291bnQgezpmaXJzdG5hbWUgIlNhbGx5IiA6bGFzdG5hbWUgIkJyb3duIn0pCgoKKG1lcmdlIHs6Zmlyc3QgIlNhbGx5In0gezpsYXN0ICJCcm93biJ9KQoKKGFzc29jIHs6Zmlyc3QgIlNhbGx5In0gOmxhc3QgIkJyb3duIikKCihkaXNzb2MgezpmaXJzdCAiU2FsbHkiIDpsYXN0ICJCcm93biJ9IDpsYXN0KQoKCjs7IG1lcmdlIC0gam9pbiB0d28gbWFwcyB0b2dldGhlcgo7OyBhc3NvYyAtIGFkZCBhIGtleS12YWx1ZSB0byBhIG1hcAo7OyBhc3NvYy1pbiAtIGFkZCBhIGtleS12YWx1ZSB0byBhIG5lc3RlZCBtYXAKOzsgdXBkYXRlIC0gY2hhbmdlIGFuIGV4aXN0aW5nIHZhbHVlIGluIGEgbWFwIHVzaW5nIGEgZnVuY3Rpb24KOzsgdXBkYXRlIC0gY2hhbmdlIGFuIGV4aXN0aW5nIHZhbHVlIGluIGEgbmVzdGVkIG1hcCB1c2luZyBhIGZ1bmN0aW9uCgo7OyBrZXlzIC0gcmV0dXJuIHRoZSBrZXlzIG9mIGEgbWFwCjs7IHZhbHMgLSByZXR1cm4gdGhlIHZhbHVlcyBvZiBhIG1hcAoKCjs7IFRoZSBhc3NvYyBmdW5jdGlvbiBjYW4gYmUgdXNlZCBieSBhc3NpZ25pbmcgYSBuZXcgdmFsdWUgdG8gYW4gZXhpc3Rpbmcga2V5LgoKKGRlZiBoZWxsbyB7OmNvdW50IDEgOndvcmRzICJoZWxsbyJ9KQoKKGFzc29jIGhlbGxvIDpjb3VudCAwKQoKKGFzc29jIGhlbGxvIDp3b3JkcyAiSGVsbG8gQ2xvanVyZSBXb3JsZCIpCgoKCjs7IFRoZSB1cGRhdGUgZnVuY3Rpb24gYXBwbGllcyBhIGZ1bmN0aW9uIHRvIHRoZSBleGlzdGluZyB2YWx1ZSB0byBjcmVhdGUgYSBuZXcgdmFsdWUgZm9yIGEgc3BlY2lmaWMga2V5CgooZGVmIGhlbGxvLXVwZGF0ZSB7OmNvdW50IDEgOndvcmRzICJoZWxsbyJ9KQoKKHVwZGF0ZSBoZWxsby11cGRhdGUgOmNvdW50IGluYykKCgoodXBkYXRlIGhlbGxvLXVwZGF0ZSA6d29yZHMgc3RyICIsIHdvcmxkIikKCgo7OyBUaGUgdXBkYXRlLWluIGZ1bmN0aW9uIHdvcmtzIGxpa2UgdXBkYXRlLCBidXQgdGFrZXMgYSB2ZWN0b3Igb2Yga2V5cyB0byB1cGRhdGUgYXQgYSBwYXRoIHRvIGEgbmVzdGVkIG1hcC4KCihkZWYgc3RhcnRyZWstY2F0CiAgezpwZXQKICAgezphZ2UgNSA6bmFtZSAiS2hhbiJ9fSkKCih1cGRhdGUtaW4gc3RhcnRyZWstY2F0IFs6cGV0IDphZ2VdICsgMSkKCgoKOzsgTWFwIGV4dHJhY3Rpb24gd2l0aCBnZXQKOzsgQSBtYXAgaXMgYSBrZXktdmFsdWUgcGFpciwgdGhlIGtleSBpcyB1c2VkIHRvIGdldCBhIHZhbHVlIGZyb20gYSBtYXAuCgo7OyBJZiB0aGUga2V5IGRvZXMgbm90IGV4aXN0LCB0aGVuIGEgbmlsIHZhbHVlIGlzIHJldHVybmVkLgoKKGdldCB7OmZpcnN0bmFtZSAiU2FsbHkiIDpsYXN0bmFtZSAiQnJvd24ifSA6Zmlyc3RuYW1lKQoKCihnZXQgezpmaXJzdG5hbWUgIlNhbGx5In0gOmxhc3RuYW1lKQoKOzsgQSBkZWZhdWx0IHZhbHVlIGNhbiBiZSBpbmNsdWRlZCB3aXRoIHRoZSBnZXQgZnVuY3Rpb24sIHNvIGlmIGEga2V5IGlzIG5vdCBmb3VuZCBpbiB0aGUgbWFwLCB0aGF0IGRlZmF1bHQgdmFsdWUgaXMgcmV0dXJuZWQuCgooZ2V0IHs6Zmlyc3RuYW1lICJTYWxseSJ9IDpsYXN0bmFtZSAiVW5rbm93biIpCgoKOzsgS2V5d29yZCBrZXlzIGJlaGF2ZSBsaWtlIGZ1bmN0aW9ucywgYXMgdG8gbWFwcwo7OyBXaGVuIGEga2V5IGlzIGEga2V5d29yZCB0aGVuIHRoYXQga2V5d29yZCBjYW4gYmUgdXNlZCBhcyBhIGZ1bmN0aW9uIHRvIGxvb2t1cCB2YWx1ZXMgaW4gYSBtYXAuCgooOmZpcnN0bmFtZSB7OmZpcnN0bmFtZSAiU2FsbHkiIDpsYXN0bmFtZSAiQnJvd24ifSkKCjs7IEEgbWFwIGNhbiBhbHNvIGFjdCBsaWtlIGEgZnVuY3Rpb24gd2hlbiBnaXZlbiBhIGtleXdvcmQgYXMgYW4gYXJndW1lbnQKCih7OmZpcnN0bmFtZSAiU2FsbHkiIDpsYXN0bmFtZSAiQnJvd24ifSA6Zmlyc3RuYW1lKQoKCgoKCjs7IDA3IC0gRmlsdGVyaW5nIENvbGxlY3Rpb25zIGFuZCBhbm9ueW1vdXMgZnVuY3Rpb25zCjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OwoKKGZpbHRlciBvZGQ/IFsxIDIgMyA0XSkKCjs7IFdyaXRlIGEgZnVuY3Rpb24gdG8gdXNlIHdpdGggZmlsdGVyIHRoYXQgd2lsbCByZW1vdmUgdGhlIHdvcmQgIndlIiBmcm9tIHRoZSBjb2xsZWN0aW9uOiBbImFyZSIgIndlIiAidGhlcmUiICJ5ZXQiXQoKKGZpbHRlciAoZm4gW3dvcmRdICg9ICJ3ZSIgd29yZCkpIFsiYXJlIiAid2UiICJ0aGVyZSIgInlldCJdKQoKCihmaWx0ZXIgKGZuIFt3b3JkXSAobm90PSAid2UiIHdvcmQpKSBbImFyZSIgIndlIiAidGhlcmUiICJ5ZXQiXSkKCgo7OyBPciB0aGUgc2hvcnQtaGFuZCBmb3JtIG9mIGFub255bW91cyBmdW5jdGlvbi4gVGhlICUgYWN0cyBhcyBhIHBsYWNlaG9sZGVyIGZvciB0aGUgZnVuY3Rpb24gYXJndW1lbnQKCihmaWx0ZXIgIyhub3Q9ICJ3ZSIgJSkgWyJhcmUiICJ3ZSIgInRoZXJlIiAieWV0Il0pCgoKOzsgUmF0aGVyIHRoYW4gdXNlIGZpbHRlciwgd2UgY2FuIHVzZSByZW1vdmUgd2hpY2ggaXMgdGhlIGludmVyc2UKCihyZW1vdmUgIyg9ICJ3ZSIgJSkgWyJhcmUiICJ3ZSIgInRoZXJlIiAieWV0Il0pCgoKCjs7IDA4IC0gRmlyc3QgQ2xhc3MgRnVuY3Rpb25zIChtYXAgYW5kIHJlZHVjZSkKOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Cgo7OyBtYXAgaXMgYSBmdW5jdGlvbiB0aGF0IHRha2VzIGFub3RoZXIgZnVuY3Rpb24gYXMgYW4gYXJndW1lbnQsIGFsb25nIHdpdGggYSBjb2xsZWN0aW9uLgo7OyBtYXAgY2FsbHMgdGhlIGZ1bmN0aW9uIHByb3ZpZGVkIHRvIGl0IG9uIGVhY2ggbWVtYmVyIG9mIHRoZSBjb2xsZWN0aW9uLCB0aGVuIHJldHVybnMgYSBuZXcgY29sbGVjdGlvbiB3aXRoIHRoZSByZXN1bHRzIG9mIHRob3NlIGZ1bmN0aW9uIGNhbGxzLgoKKG1hcCBldmVuPyBbMCAxIDIgMyA0XSkKCjs7IENvdW50IHRoZSBudW1iZXIgb2YgY2hhcmFjdGVycyBpbiBlYWNoIHdvcmQgZm9yIGEgY29sbGVjdGlvbiBvZiBzdHJpbmdzIGVnLiBbImEiICJhYmMiICJhYmNkZWZnIl0KCihtYXAgY291bnQgWyJhIiAiYWJjIiAiYWJjZGVmZyJdKQoKCgo7OyByZWR1Y2UgaXMgYW5vdGhlciBmdW5jdGlvbiB0aGF0IHRha2VzIGEgZnVuY3Rpb24gYW5kIGNvbGxlY3Rpb24gYXMgYXJndW1lbnRzLgo7OyAocmVkdWNlIHNvbWUtZm4gWyJteSIgImNvbGxlY3Rpb24iICJvZiIgInZhbHVlcyJdKQoKOzsgVXNlIHJlZHVjZSB3aXRoIGEgZnVuY3Rpb24gdGhhdCBhZGRzIG51bWJlcnMgdG9nZXRoZXIsIGVnLiBbMTAgMjAgMzAgNDAgNTBdCgoocmVkdWNlICsgWzMwIDYwIDkwXSkKCjs7IFRoaW5rIG9mIGEgZnVuY3Rpb24gdGhhdCBqb2lucyBzdHJpbmdzIHRvZ2V0aGVyIGFuZCB1c2UgaXQgd2l0aCByZWR1Y2UgdG8gam9pbiB0aGUgd29yZHMgaW4gYSBjb2xsZWN0aW9uIGVnIFsiaCIgImUiICJsIiAibCIgIm8iICIgIiAiQ2xvanVyZSJdCgoocmVkdWNlIHN0ciBbImgiICJlIiAibCIgImwiICJvIl0pCgoocmVkdWNlIHN0ciBbImgiICJlIiAibCIgImwiICJvIiAiICIgIkNsb2p1cmUiXSkKCgoKCgo7OyBXcml0ZSBtYXAgYW5kIHJlZHVjZSBmdW5jdGlvbnMgdG8gY3JlYXRlIHRoZSBtYXAgcmVkdWNlIHNhbmR3aWNoCgo7OyBDcmVhdGUgYSBjb2xsZWN0aW9uIG9mIHRoZSByYXcgaW5ncmVkaWVudHMgZm9yIG91ciBzYW5kd2ljaAoKKGRlZiByYXctaW5ncmVkaWVudHMgWyJicmVhZCIgImN1Y3VtYmVyIiAicGVwcGVyIiAidG9tYXRvIiAibGV0dHVjZSIgIm9uaW9uIl0pCgoKOzsgQ3JlYXRlIGEgZnVuY3Rpb24gdG8gInNsaWNlIiB0aGUgcmF3IGluZ3JlZGllbnRzIHNvIHRvIHByZXBhcmUgdG8gYmUgbWFkZSBpbnRvIGEgc2FuZHdpY2guCgooZGVmbiBwcmVwYXJlIFthbGwtaW5ncmVkaWVudHNdCiAgKG1hcCAoZm4gW2luZ3JlZGllbnRdIChzdHIgInNsaWRlZCAiKSBpbmdyZWRpZW50KSBhbGwtaW5ncmVkaWVudHMpKQoKKHByZXBhcmUgcmF3LWluZ3JlZGllbnRzKQoKCjs7IFJlZHVjZSBvdXIgaW5ncmVkaWVudHMgdG8gYSBzYW5kd2ljaAoKKGRlZm4gbWFrZS1zYW5kd2ljaCBbcHJlcGFyZWQtaW5ncmVkaWVuY2VdCiAgKHJlZHVjZSBzdHIgKGludGVycG9zZSAiLCAiIHByZXBhcmVkLWluZ3JlZGllbmNlKSkpCgoKKHN0ciAiQSB0YXN0eSBzYW5kd2ljaCBtYWRlIHdpdGggIiAobWFrZS1zYW5kd2ljaCAocHJlcGFyZSByYXctaW5ncmVkaWVudHMpKSkKCgo7OyBUaGUgc2FtZSB0aGluZyBjYW4gYmUgd3JpdHRlbiBzZXF1ZW50aWFsbHkgdXNpbmcgdGhlIHRocmVhZGluZyBtYWNybwooLT4+IFsiYnJlYWQiICJjdWN1bWJlciIgInBlcHBlciIgInRvbWF0byIgImxldHR1Y2UiICJvbmlvbiJdCiAgICAgKG1hcCAjKHN0ciAic2xpY2VkICIgJSkgLCwsKQogICAgIChpbnRlcnBvc2UgIiwgIiAsLCwpCiAgICAgKHJlZHVjZSBzdHIgLCwsKQogICAgIChzdHIgIkkgaGF2ZSBhIHRhc3R5IHNhbmR3aWNoIG1hZGUgd2l0aCAiICwsLCkpCgoKCjs7IE5hbWUgU21hc2gKOzsgVGFrZSB0d28gbmFtZXMgYW5kIHNtYXNoIHRoZW0gdG9nZXRoZXIgdG8gY3JlYXRlIGEgbmV3IG5hbWUKCihkZWYgc3R1ZGVudHMgWyJKb2huIFN0ZXZlbnNvbiIgIk1hbmkgU2Fya2FyIl0pCgoKOzsgU3BsaXQgZWFjaCBzdHJpbmcgdXNpbmcgdGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBmb3Igc3BhY2UgY2hhcmFjdGVyLgo7OyBNYXAgc3BsaXQgYXMgYW4gYW5vbnltb3VzIGZ1bmN0aW9uIG92ZXIgdGhlIHN0dWRlbnQgY29sbGVjdGlvbgoKKG1hcCAjKGNsb2p1cmUuc3RyaW5nL3NwbGl0ICUgIyIgIikgc3R1ZGVudHMpCgoKOzsgV2UgY2FuIGFsc28gZmxhdHRlbiB0aGUgcmVzdWx0IHRvIG1ha2UgaXQgbG9vayBuaWNlcgoKKGZsYXR0ZW4gKG1hcCAjKGNsb2p1cmUuc3RyaW5nL3NwbGl0ICUgIyIgIikgc3R1ZGVudHMpKQoKCgoKCjs7IFdyaXRlIGEgZnVuY3Rpb24gY2FsbGVkIG5hbWUtc3BsaXQgdGhhdCBhIGZ1bGwgbmFtZSBhcyBhIHN0cmluZyBhbmQgcmV0dXJuIHR3byBzZXBlcmF0ZSBzdHJpbmdzLCBvbmUgZm9yIHRoZSBmaXJzdCBuYW1lIGFuZCBvbmUgZm9yIHRoZSBsYXN0IG5hbWUuCgooZGVmbiBuYW1lLXNwbGl0CiAgIlNwbGl0cyBhIG5hbWUgaW50byBmaXJzdCAmIGxhc3QgbmFtZXMiCiAgW25hbWVdCiAgKGNsb2p1cmUuc3RyaW5nL3NwbGl0IG5hbWUgIyIgIikpCgoKOzsgIEp1bWJsZSB0aGUgbmFtZXMKOzsgRm9yIGV4YW1wbGUsIHRha2UgdGhlIGZpcnN0IG5hbWUgZnJvbSB0aGUgZmlyc3QgcGVyc29uIGFuZCBqb2luIGl0IHdpdGggdGhlIGxhc3QgbmFtZSBmcm9tIHRoZSBzZWNvbmQgcGVyc29uCgooZGVmbiBqdW1ibGUtbmFtZXMgW25hbWVzXQogIChsZXQgW2ZpcnN0LXBlcnNvbiAoZmlyc3QgbmFtZXMpCiAgICAgICAgc2Vjb25kLXBlcnNvbiAoc2Vjb25kIG5hbWVzKQogICAgICAgIGZpcnN0LXBlcnNvbi1maXJzdC1uYW1lIChmaXJzdCAobmFtZS1zcGxpdCBmaXJzdC1wZXJzb24pKQogICAgICAgIHNlY29uZC1wZXJzb24tc2Vjb25kLW5hbWUgKHNlY29uZCAobmFtZS1zcGxpdCBzZWNvbmQtcGVyc29uKSldCiAgICAoc3RyICJIZWxsbyAiIGZpcnN0LXBlcnNvbi1maXJzdC1uYW1lIHNlY29uZC1wZXJzb24tc2Vjb25kLW5hbWUpKSkKCjs7IENhbGwgb3VyIGZ1bmN0aW9uIHdpdGggYW4gYXJndW1lbnQgb2YgdGhlIHN0dWRlbnQgY29sbGVjdGlvbi4KKGp1bWJsZS1uYW1lcyBzdHVkZW50cykKCgoKCjs7IDA5IENvbmRpdGlvbmFscwo7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsKCjs7IEluIEVuZ2xpc2ggd2Ugc2F5IHNvbWVvbmUgY2FtZSAxc3QsIHJhdGhlciB0aGFuIHNvbWVvbmUgY2FtZSAxLgo7OyBXcml0ZSBhIGZ1bmN0aW9uIGNhbGxlZCBwb3NpdGlvbiB3aXRoIGFuIGFyZ3VtZW50IGNhbGxlZCBudW1iZXIKOzsgaWYgdGhlIG51bWJlciBlcXVhbHMgMSwgdGhlbiB0aGUgZnVuY3Rpb24gc2hvdWxkIHJldHVybiAiMXN0IiBJZiBudW1iZXIgaXMgbm90IDEsIHRoZW4gcmV0dXJuIGFuIGVycm9yIG1lc3NhZ2UsIHN1Y2ggYXM6ICJTb3JyeSwgdGhlIG51bWJlciBpcyBub3Qgc3VwcG9ydGVkIgoKOzsgVXNpbmcgaWYgZnVuY3Rpb24gZm9yIGEgc2luZ2xlIGNvbmRpdGlvbgoKKGRlZm4gcG9zaXRpb24gW251bWJlcl0KICAoaWYgKD0gbnVtYmVyIDEpCiAgICAoc3RyIG51bWJlciAic3QiKQogICAgKHN0ciAiU29ycnksIHRoZSBudW1iZXIgIiBudW1iZXIgIiBpcyBub3Qgc3VwcG9ydGVkIikpKQoKKHBvc2l0aW9uIDEpCgoKOzsgVE9ETyBmaXggaW4gQ2xvanVyZUJyaWRnZSBMb25kb24gd29ya3Nob3AgY29udGVudAoKCgo7OyBjb25kIGZ1bmN0aW9uIGNhbiBldmFsdWF0ZSBtdWx0aXBsZSBjb25kaXRpb25zCgo7OyAoY29uZAo7OyAgIHByZWRpY2F0ZTEgZXhwcmVzc2lvbi10by1ldmFsdWF0ZS13aGVuLXByZWRpY2F0ZTEtaXMtdHJ1ZQo7OyAgIHByZWRpY2F0ZTIgZXhwcmVzc2lvbi10by1ldmFsdWF0ZS13aGVuLXByZWRpY2F0ZTItaXMtdHJ1ZQo7OyAgIC4uLgo7OyAgIDplbHNlICAgICAgZXhwcmVzc2lvbi10by1ldmFsdWF0ZS13aGVuLWFsbC1hYm92ZS1hcmUtZmFsc2UpCgo7OyBUbyBjcmVhdGUgdGhlIHBvc2l0aW9uIGZ1bmN0aW9uIHdpdGggY29uZAoKCihkZWZuIHBvc2l0aW9ucyBbbnVtYmVyXQogIChjb25kCiAgICAoPSBudW1iZXIgMSkgIjFzdCIKICAgICg9IG51bWJlciAyKSAiMm5kIgogICAgKD0gbnVtYmVyIDMpICIzcmQiCiAgICA6ZWxzZSAgIChzdHIgbnVtYmVyICJ0aCIpKSkKCihwb3NpdGlvbnMgMykKKHBvc2l0aW9ucyA0KQoKCgo7OyBUZW1wZXJhdHVyZSBjb252ZXJzaW9uIHdpdGggY29uZAo7OyAgV3JpdGUgYSBmdW5jdGlvbiB3aGljaCBjb252ZXJ0cyB0ZW1wZXJhdHVyZXMKCjs7ICh0ZW1wZXJhdHVyZS1pbi1jZWxjaXVzIDMyLjAgOmZhaHJlbmhlaXQpICAgIDs9PiAwLjAKOzsgKHRlbXBlcmF0dXJlLWluLWNlbGNpdXMgMzAwICA6a2VsdmluKSAgICAgICAgOz0+IDI2Ljg1Cjs7ICh0ZW1wZXJhdHVyZS1pbi1jZWxjaXVzIDIyLjUgOmNlbGNpdXMpICAgICAgIDs9PiAyMi41Cjs7ICh0ZW1wZXJhdHVyZS1pbi1jZWxjaXVzIDIyLjUgOmZha2UpICAgICAgICAgIDs9PiAiVW5rbm93biBzY2FsZTogOmZha2UiCjs7IElmIGFuIHVua25vd24gdGVtcGVyYXR1cmUgc2NhbGUgaXMgdXNlZCwgYW4gZXJyb3IgbWVzc2FnZSBzaG91bGQgYmUgcmV0dXJuZWQKCgo7OyBGb3JtdWxhcyB0byBjb252ZXJ0IHRlbXBlcmF0dXJlcwo7OyBGYWhyZW5oZWl0IHRvIENlbGNpdXM6ICgqICgtIEZhaHJlbmhlaXQgMzIpIDUvOSkgPSBDZWxjaXVzCjs7IEtlbHZpbiB0byBDZWxjaXVzOiAoKyBLZWx2aW4gMjczLjE1KSA9IENlbGNpdXMKCihkZWZuIHRlbXBlcmF0dXJlLWluLWNlbGNpdXMgW3RlbXBlcmF0dXJlIHNjYWxlXQogIChjb25kCiAgICAoPSBzY2FsZSA6Y2VsY2l1cykgICAgdGVtcGVyYXR1cmUKICAgICg9IHNjYWxlIDpmYWhyZW5oZWl0KSAoKiAoLSB0ZW1wZXJhdHVyZSAzMikgNS85KQogICAgKD0gc2NhbGUgOmtlbHZpbikgICAgICgtIHRlbXBlcmF0dXJlIDI3My4xNSkKICAgIDplbHNlICAgICAgICAgICAgICAgICAoc3RyICJVbmtub3duIHNjYWxlOiAiIHNjYWxlKSkpCgoodGVtcGVyYXR1cmUtaW4tY2VsY2l1cyAzMi4wIDpmYWhyZW5oZWl0KQoodGVtcGVyYXR1cmUtaW4tY2VsY2l1cyAzMDAgIDprZWx2aW4pCih0ZW1wZXJhdHVyZS1pbi1jZWxjaXVzIDIyLjUgOmNlbGNpdXMpCih0ZW1wZXJhdHVyZS1pbi1jZWxjaXVzIDIyLjUgOmdpYmJlcmlzaCkKCgo7OyAxMCBpdGVyYXRlIHdpdGggZm9yIChsaXN0IGNvbXByZWhlbnNpb24pCjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OwoKOzsgQ3JlYXRlIGEgY29tYmluYXRpb24gbG9jawoKOzsgR2VuZXJhdGUgbnVtYmVycyB3aXRoIHJhbmdlCihyYW5nZSAxMCkKCgo7OyBVc2UgZm9yIHRvIGNyZWF0ZSBhIHJhbmdlIG9mIG51bWJlcnMgZm9yIGVhY2ggY29tYmluYXRpb24gdHVtYmxlcgo7OyB0aGVuIGNvbWJpbmUgdGhlbSB0b2dldGhlcgoKKGZvciBbdHVtYmxlci0xIChyYW5nZSAxMCkKICAgICAgdHVtYmxlci0yIChyYW5nZSAxMCkKICAgICAgdHVtYmxlci0zIChyYW5nZSAxMCldCiBbdHVtYmxlci0xIHR1bWJsZXItMiB0dW1ibGVyLTNdKQoKCjs7IENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIGNvbWJpbmF0aW9ucwoKKGNvdW50CiAgKGZvciBbdHVtYmxlci0xIChyYW5nZSAxMCkKICAgICAgICB0dW1ibGVyLTIgKHJhbmdlIDEwKQogICAgICAgIHR1bWJsZXItMyAocmFuZ2UgMTApXQogICBbdHVtYmxlci0xIHR1bWJsZXItMiB0dW1ibGVyLTNdKSkKCgoKOzsgTWFrZSB0aGUgY29tYmluYXRpb25zIGhhcmRlciB0byBndWVzcwo7OyBvbmx5IGFsbG93IHRoZSBjb21iaW5hdGlvbnMgd2hlcmUgZWFjaCB0dW1ibGVyIHdoZWVsIGhhcyBhIGRpZmZlcmVudCBudW1iZXIsIHNvIGV4Y2x1ZGUgY29tYmluYXRpb25zIGxpa2UgMS0xLTEsIDEtMi0yLCAxLTItMSwgZXRjLgo7OyBIb3cgbWFueSBjb21iaW5hdGlvbnMgZG9lcyB0aGF0IGdpdmUgdXM/Cgo7OyBmb3IgY2FuIHNldCBjb25kaXRpb25zIHRoYXQKCihmb3IgW3R1bWJsZXItMSAocmFuZ2UgMTApCiAgICAgIHR1bWJsZXItMiAocmFuZ2UgMTApCiAgICAgIHR1bWJsZXItMyAocmFuZ2UgMTApCiAgICAgIDp3aGVuIChvciAobm90PSB0dW1ibGVyLTEgdHVtYmxlci0yKQogICAgICAgICAgICAgICAgKG5vdD0gdHVtYmxlci0yIHR1bWJsZXItMykKICAgICAgICAgICAgICAgIChub3Q9IHR1bWJsZXItMyB0dW1ibGVyLTEpKV0KICBbdHVtYmxlci0xIHR1bWJsZXItMiB0dW1ibGVyLTNdKQoKCjs7IE5PVEUgZWRpdG9yIHRydW5jYXRlcyB0byBmaXJzdCAxMDAgcmVzdWx0cwoKCihmb3IgW3R1bWJsZXItMSAocmFuZ2UgMTApCiAgICAgIHR1bWJsZXItMiAocmFuZ2UgMTApCiAgICAgIHR1bWJsZXItMyAocmFuZ2UgMTApCiAgICAgIDp3aGVuIChvciAoPSB0dW1ibGVyLTEgdHVtYmxlci0yKQogICAgICAgICAgICAgICAgKD0gdHVtYmxlci0yIHR1bWJsZXItMykKICAgICAgICAgICAgICAgICg9IHR1bWJsZXItMyB0dW1ibGVyLTEpKV0KICBbdHVtYmxlci0xIHR1bWJsZXItMiB0dW1ibGVyLTNdKQo="},"asBuffer":null},"loaded":true}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
(ns clojure-through-code.clojurebridge-exercises)

;; 01 Calculate the total number of years from all the following languages
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Clojure (10 years)
;; Haskell (27 years)
;; Python (26 years)
;; Javascript (21 years)
;; Java (22 years)
;; Ruby (22 years)
;; C (45 years)
;; C++ (34 years)
;; Lisp (59 years)
;; Fortran (60 years)
;; You can use the list of years here as a convenience 10 27 26 21 22 22 45 34 59 60

;; calculate the total by adding the age of each language together

(+ 10 27 26 21 22 22 34 45 59 60)

;; There are two values the same, so we could calculate the total as follows

(+ 10 27 26 21 (* 22 2) 34 45 59 60)

;; Find the average age of languages by adding the ages of all the language ages, then divide that total age with the number of languages

(/ (+ 10 27 26  21 22 22 45 34 59 60)
   10)


;; We can use the count function to find out how many language ages we have
(/ (+ 10 27 26  21 22 22 45 34 59 60)
   count (10 27 26  21 22 22 45 34 59 60))



;; 02 Convert between time and numbers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Assuming its been 2 hours and 20 minutes since you woke up, lets calculate the time in minutes:

;; We add the result of multiplying 2 hours by 60 to get the number of minutes with the 25 minutes
(+ (* 2 60) 25)


;; To get the time in seconds, we can take the previous expression and wrap it with another expression that multiplies the result by 60.
(* (+ (* 2 60) 25) 60)


;; Assuming it has been 428 seconds since the workshop started, the number of minutes could be calculated like this:
(quot 428 60)


;; And the number of seconds calculated like this:
(rem 428 60)


;; 7 hours is 420 minutes, so there are 8 minutes remaining that do not fit into a whole hour.
;; So 428 minutes is the same as 7 hours and 8 minutes


;; 03 Strings
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Using a function you can create a string and join values to create a string
(str "My favorite colours are" " " "green" " " "and" " ""purple")


;; Use a function to see if a string contains a colour. See the Hint below if you are not sure how to start
;; Does the string "Rachel of York gave brown bread in vans" contain the colour brown?

(clojure.string/includes? "Rachel of York gave brown bread in vans" "brown")


;; Fixing spelling mistakes
;; One aspect of fixing spelling mistakes is to find and replace incorrect words.
;; The clojure.string library provides the replace function.

;; Replace in this string the characters ovr with the characters over

(clojure.string/replace "simplicity ovr complexity" "ovr" "over")


(clojure.string/replace "coed as data as coed" "coed" "code")


;; NOTE: Briefly discuss libraries and namespaces
;; clojure.core is included by default in all projects
;; on the JVM host, so is java.lang
;; clojure.xxx libraries can be used by fully qualifying their namespace
;; Other Clojure libraries need to be added as a project dependency too.



;; Simple Palendrome Checker
;; A Palindrome is a word that is spelt the same whether it is written backwards or forwards. So when you reverse the word it should still look the same.

;; Using functions on strings that are not part of the clojure.string library can give 'interesting' results.
(= "radar" (reverse "radar"))


;; The clojure.core/reverse function returns a list the individual characters in reverse order, rather than reversing the string as a single value.

;; Using the clojure.string/reverse function keeps the value as a string
(= "radar" (clojure.string/reverse "radar"))




;; 04 Assignment (binding symbols to values)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; The = function is used to compare values

;; We can use def to give a name to something we already know, like a string

(def jenny-loves "Jenny loves rubarb crumble and vanilla custard")

;; We can also use def to give a name to something we dont know yet, eg. a calculation.

(def mangoes 4)
(def oranges 12)
(def total-fruit (+ mangoes oranges))
(def average-fruit-amount (/ total-fruit 2))
average-fruit-amount


;; NOTE: Its common to use a map to define multiple values in a namespace,
;; rather than multiple individual def functions

(def fruit-stock {:mangos   4
                  :oranges 12})


;; 05 Collections - Vectors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; A vector of the temperatures for the next week
[9 2 -3 4 5 9 4]

;; assuming the first temperature is for Monday, then to get Thursday we can write
;; The index of a vector starts at zero

(nth [9 2 -3 4 5 9 4] 3)


;; Sequences - an abstraction over collections

(first  [9 2 -3 4 5 9 4])
(second [9 2 -3 4 5 9 4])
(last   [9 2 -3 4 5 9 4])
(rest   [9 2 -3 4 5 9 4])

;; how to we get the third value from the vector ["Birthdays are" "full of" "presents" "that you" "always dreamd" "of having"]

;; We can call one function and use its return value as an argument to another function.

;; rest function returns all values but the first one.
;; the second value can then be returned from the collection
(second
 (rest
  ["Birthdays are" "full of" "presents" "that you" "always dreamd" "of having"]))


;; Using Local Assignment
;; Use a local name to hold intermediary values in the processing of the collection.

;; the let function assignes a name to our collection of values
;; then we get the value in third place by using the name.

(let [rest-of-strings
      (rest ["Birthdays are" "full of" "presents" "that you" "always dreamd" "of having"])]
  (second rest-of-strings))



;; Find the age of the youngest programming language
;; The ages are not in order, so you cant just get the first value.

(first (sort [10 27 26 21 22 22 45 34 59 60]))

;; The min function will simplify our expression
(min [10 27 26 21 22 22 45 34 59 60])

;; NOTE there are over 600 functions in clojure.core so there is often a function you are looking for to simplify you code



;; Clojure compares values rather than types (in general)

(= [1 2 3] [1 2 3])
(= [1 2 3] [4 5 6])
(= [1 2 3] [3 2 1])
(= ["Hello" "World"] ["Hello" "World" "Wide" "Web"])
(= '(1 2 3) [1 2 3])




;; 06 Collections - Maps
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Maps are key-value pairs
;; Maps can be self describing if you use meaningful names for the keys

(count {:firstname "Sally" :lastname "Brown"})


(merge {:first "Sally"} {:last "Brown"})

(assoc {:first "Sally"} :last "Brown")

(dissoc {:first "Sally" :last "Brown"} :last)


;; merge - join two maps together
;; assoc - add a key-value to a map
;; assoc-in - add a key-value to a nested map
;; update - change an existing value in a map using a function
;; update - change an existing value in a nested map using a function

;; keys - return the keys of a map
;; vals - return the values of a map


;; The assoc function can be used by assigning a new value to an existing key.

(def hello {:count 1 :words "hello"})

(assoc hello :count 0)

(assoc hello :words "Hello Clojure World")



;; The update function applies a function to the existing value to create a new value for a specific key

(def hello-update {:count 1 :words "hello"})

(update hello-update :count inc)


(update hello-update :words str ", world")


;; The update-in function works like update, but takes a vector of keys to update at a path to a nested map.

(def startrek-cat
  {:pet
   {:age 5 :name "Khan"}})

(update-in startrek-cat [:pet :age] + 1)



;; Map extraction with get
;; A map is a key-value pair, the key is used to get a value from a map.

;; If the key does not exist, then a nil value is returned.

(get {:firstname "Sally" :lastname "Brown"} :firstname)


(get {:firstname "Sally"} :lastname)

;; A default value can be included with the get function, so if a key is not found in the map, that default value is returned.

(get {:firstname "Sally"} :lastname "Unknown")


;; Keyword keys behave like functions, as to maps
;; When a key is a keyword then that keyword can be used as a function to lookup values in a map.

(:firstname {:firstname "Sally" :lastname "Brown"})

;; A map can also act like a function when given a keyword as an argument

({:firstname "Sally" :lastname "Brown"} :firstname)





;; 07 - Filtering Collections and anonymous functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(filter odd? [1 2 3 4])

;; Write a function to use with filter that will remove the word "we" from the collection: ["are" "we" "there" "yet"]

(filter (fn [word] (= "we" word)) ["are" "we" "there" "yet"])


(filter (fn [word] (not= "we" word)) ["are" "we" "there" "yet"])


;; Or the short-hand form of anonymous function. The % acts as a placeholder for the function argument

(filter #(not= "we" %) ["are" "we" "there" "yet"])


;; Rather than use filter, we can use remove which is the inverse

(remove #(= "we" %) ["are" "we" "there" "yet"])



;; 08 - First Class Functions (map and reduce)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; map is a function that takes another function as an argument, along with a collection.
;; map calls the function provided to it on each member of the collection, then returns a new collection with the results of those function calls.

(map even? [0 1 2 3 4])

;; Count the number of characters in each word for a collection of strings eg. ["a" "abc" "abcdefg"]

(map count ["a" "abc" "abcdefg"])



;; reduce is another function that takes a function and collection as arguments.
;; (reduce some-fn ["my" "collection" "of" "values"])

;; Use reduce with a function that adds numbers together, eg. [10 20 30 40 50]

(reduce + [30 60 90])

;; Think of a function that joins strings together and use it with reduce to join the words in a collection eg ["h" "e" "l" "l" "o" " " "Clojure"]

(reduce str ["h" "e" "l" "l" "o"])

(reduce str ["h" "e" "l" "l" "o" " " "Clojure"])





;; Write map and reduce functions to create the map reduce sandwich

;; Create a collection of the raw ingredients for our sandwich

(def raw-ingredients ["bread" "cucumber" "pepper" "tomato" "lettuce" "onion"])


;; Create a function to "slice" the raw ingredients so to prepare to be made into a sandwich.

(defn prepare [all-ingredients]
  (map (fn [ingredient] (str "slided ") ingredient) all-ingredients))

(prepare raw-ingredients)


;; Reduce our ingredients to a sandwich

(defn make-sandwich [prepared-ingredience]
  (reduce str (interpose ", " prepared-ingredience)))


(str "A tasty sandwich made with " (make-sandwich (prepare raw-ingredients)))


;; The same thing can be written sequentially using the threading macro
(->> ["bread" "cucumber" "pepper" "tomato" "lettuce" "onion"]
     (map #(str "sliced " %) ,,,)
     (interpose ", " ,,,)
     (reduce str ,,,)
     (str "I have a tasty sandwich made with " ,,,))



;; Name Smash
;; Take two names and smash them together to create a new name

(def students ["John Stevenson" "Mani Sarkar"])


;; Split each string using the regular expression for space character.
;; Map split as an anonymous function over the student collection

(map #(clojure.string/split % #" ") students)


;; We can also flatten the result to make it look nicer

(flatten (map #(clojure.string/split % #" ") students))





;; Write a function called name-split that a full name as a string and return two seperate strings, one for the first name and one for the last name.

(defn name-split
  "Splits a name into first & last names"
  [name]
  (clojure.string/split name #" "))


;;  Jumble the names
;; For example, take the first name from the first person and join it with the last name from the second person

(defn jumble-names [names]
  (let [first-person (first names)
        second-person (second names)
        first-person-first-name (first (name-split first-person))
        second-person-second-name (second (name-split second-person))]
    (str "Hello " first-person-first-name second-person-second-name)))

;; Call our function with an argument of the student collection.
(jumble-names students)




;; 09 Conditionals
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; In English we say someone came 1st, rather than someone came 1.
;; Write a function called position with an argument called number
;; if the number equals 1, then the function should return "1st" If number is not 1, then return an error message, such as: "Sorry, the number is not supported"

;; Using if function for a single condition

(defn position [number]
  (if (= number 1)
    (str number "st")
    (str "Sorry, the number " number " is not supported")))

(position 1)


;; TODO fix in ClojureBridge London workshop content



;; cond function can evaluate multiple conditions

;; (cond
;;   predicate1 expression-to-evaluate-when-predicate1-is-true
;;   predicate2 expression-to-evaluate-when-predicate2-is-true
;;   ...
;;   :else      expression-to-evaluate-when-all-above-are-false)

;; To create the position function with cond


(defn positions [number]
  (cond
    (= number 1) "1st"
    (= number 2) "2nd"
    (= number 3) "3rd"
    :else   (str number "th")))

(positions 3)
(positions 4)



;; Temperature conversion with cond
;;  Write a function which converts temperatures

;; (temperature-in-celcius 32.0 :fahrenheit)    ;=> 0.0
;; (temperature-in-celcius 300  :kelvin)        ;=> 26.85
;; (temperature-in-celcius 22.5 :celcius)       ;=> 22.5
;; (temperature-in-celcius 22.5 :fake)          ;=> "Unknown scale: :fake"
;; If an unknown temperature scale is used, an error message should be returned


;; Formulas to convert temperatures
;; Fahrenheit to Celcius: (* (- Fahrenheit 32) 5/9) = Celcius
;; Kelvin to Celcius: (+ Kelvin 273.15) = Celcius

(defn temperature-in-celcius [temperature scale]
  (cond
    (= scale :celcius)    temperature
    (= scale :fahrenheit) (* (- temperature 32) 5/9)
    (= scale :kelvin)     (- temperature 273.15)
    :else                 (str "Unknown scale: " scale)))

(temperature-in-celcius 32.0 :fahrenheit)
(temperature-in-celcius 300  :kelvin)
(temperature-in-celcius 22.5 :celcius)
(temperature-in-celcius 22.5 :gibberish)


;; 10 iterate with for (list comprehension)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Create a combination lock

;; Generate numbers with range
(range 10)


;; Use for to create a range of numbers for each combination tumbler
;; then combine them together

(for [tumbler-1 (range 10)
      tumbler-2 (range 10)
      tumbler-3 (range 10)]
 [tumbler-1 tumbler-2 tumbler-3])


;; Calculate the total number of combinations

(count
  (for [tumbler-1 (range 10)
        tumbler-2 (range 10)
        tumbler-3 (range 10)]
   [tumbler-1 tumbler-2 tumbler-3]))



;; Make the combinations harder to guess
;; only allow the combinations where each tumbler wheel has a different number, so exclude combinations like 1-1-1, 1-2-2, 1-2-1, etc.
;; How many combinations does that give us?

;; for can set conditions that

(for [tumbler-1 (range 10)
      tumbler-2 (range 10)
      tumbler-3 (range 10)
      :when (or (not= tumbler-1 tumbler-2)
                (not= tumbler-2 tumbler-3)
                (not= tumbler-3 tumbler-1))]
  [tumbler-1 tumbler-2 tumbler-3])


;; NOTE editor truncates to first 100 results


(for [tumbler-1 (range 10)
      tumbler-2 (range 10)
      tumbler-3 (range 10)
      :when (or (= tumbler-1 tumbler-2)
                (= tumbler-2 tumbler-3)
                (= tumbler-3 tumbler-1))]
  [tumbler-1 tumbler-2 tumbler-3])
Clojure 1.8.0 Java HotSpot(TM) 64-Bit Server VM 1.8.0_91-b14