Phase 1S
This commit is contained in:
parent
4c8f97d048
commit
480b557f81
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HVTL+JFWvRGcUa2EC21oKhNA2P/e0DtBol7600Y6J0ZPvPOvJHoD0g6cns8/nLCmBdSkzxuIcGEpkxTxvdcdkJ3zDVWSN4y8Q+pyfiIX0lHjAqBB4dUokaqgLW0l0OgAOg448BEq0pO/7KQ7o34sQE8jQGbefmEaRnnSDry1xhh/lJq+7EJ07xCk+YJH+KSfQylmT8f7h7pH7e7/dPu8teCSxE3I5COKOTCKXSUSWeoEopRJ9BQVBDc4Kw2Hi6yMWZM0U/NAp9/1Ic5R8yhE42QDaPCkXNNwGdfWu79gvuvx9LFhui+xOstvH12b+SEiXSi/g7zku4mTONNno8TnnA6+rRgugnz4eBj6eWY5iOmPOKGZXvpNPk8zrG6FrubRoyZ1OTpudpNPg9zOrxj9XxB8PA/CJww9aQjkrVSG4NKSumd7gVDMDpoLfrgmRl6gTwga50yjhvGpRPMyVYba8AzF0hNXqa599Pvy8bPCdZbYEZogQqdUFq7wFBaHFqDDLzWvbbBgbRGKAtWeuc9dz2a4HQoBvngw+sYsXq4Jx1hHAVIi3QQXFNlwVPfSke1lnpAHpwRnNTkbo55jOu8LtVDzPiSNn6kI7/6acELudsUXseMIa+pQP1bl2K7NMMacvXDAZw1rJGMFdGaj2uuPiKMCUPGgnef1mu+/0iEFpvobk0JY652Pr9Wv/nltVDxNnDvylN1CAO2DAcGzGtmADVoBCXAgHIKtHIsaOV7rsC3vB9KhNQEi+Gqi8fBgrBqoEbalqpWC+p4MNT32DMwPPTSvONYPU1F54NlCkFShwNQ5binTklJQbbeCD0YI4afkFzNx1kBDHi6bOvWgQawCJpToXhLlXOcWtca2hvbu15bbEPp+RFTxOknUB/GkOZlHnJ19W71Dt3HNZaLU20+/jJG+u82o/s5fMZUlRn7MZYFu471XJMD+mVNeNgOVvdGdmW7qv12t4RutDW2Js/Zp7wer2FpGy21OZ/P528AAAD//wMAx6rPOvUEAAA=
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUy27jNhSGX0XgWlR4EyVqlzod1MhkYkzcadEdRR45RGTSoKhMg8DvPqDsIM4MuuhOOOJ/Lt/5yVfk9R5Qh64Ph9+fwacJlSi5JcQIk5hITOiW8o7JjqiqbduGUfYPKpG7hRfUoUYYQ40CzEECFpbUuOeDwdaCooRawmqRc+rdhLpXpF1l4dkZqML0DeLkgkcd+st5G77n2tpVZgyzrWIYYe2npL3JzXxZr27x5+vN9n5zOjXBlMWVs6hDAihTAhQmXDVYMEGwYtBgENaoQbWy0fYkcz5B9HqsJvv0Xt+G5CGZjlWMVwQzhY4lsjrp3HKvJ9i+HHIXC6KbHC+X8PLZvaJniKhj5RvMU7orM7qr/dTPbrRXY9jtnN+tgh/cbo465cIlOsRwgJgcLHB+c17Hl89ht8v50Cc9ToBKtIW4d16Ppx83MOh5TA9hjguZyT791xnUIT2ngEq0kBzHpWxxHmY1OvDpF+1F4fuHYjPqNIS4/7CkhxP79f9Af6fNo/NQrG9QhwgFZnkLeGBUYtFajXXNFZaSywGoUQ2jqESr4JPzc5inYu0T7M7UPvR3Hc2jS2DSHPNMf8tstk0MdjapeF8wJRWpOCFZNKfDnIqvYF0EkyAPsY3zOd9PEibZIvrkRvgFz2qOEXwqNjo9Fn/o6RF1SOnWUK200loaM0BNYCCWaEkaC9JKsILZxgolrBSKGCl0T4XVNe2HHEElgmyyYvE114JzzgxWVgxY1I3B2vYNplwYRikTgvQf4Bb3Y9Zp0xIBlmMFg8VCUY2V4BxbXuuGyaFp2HDB6WwISjL1SxP+OYE9e+nLydpvs1t4Pt3jpU9pbQtWUswErbFQiuJW1Q3um7ZXvWyhNnmyVfBTeAP5DWIfJpfyI3LnvNvr8ecj75u5hehhvNjOnTMxTGFIxdmWxYd9fZ19fsWKxaLfncf/Lsa4CeYJYpGNpZ2/WObxeDz+AAAA//8DACYP7R0MBQAA
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUTW/bOBD9KwLPpkJSFCUK2IPhtFgjTWMk7u5ibxQ5jInIokFRToMi/31BWa6dooe9CaP5ePPeG/5AvdoDatDycPh0hD4OaIGim0KMMIGJwIRuadEw0VCSs4oVhIt/0QK5O3hDDaq41lRLwAUIwNyQEreF1dgYkJRQQ1jJU0/1PKDmB1IuN3B0GnI//AVhcL5HDfrb9ca/ptnK5brzo8mD72DdD1H1OoH5ul7d4S/LzfZhc8oaYEjFuTOoQRwokxwkJoWsMGecYMmgwsCNllbWolLmVOb6CKFXXT6Yl8t842MPUTcsZ0VOMJPofYGMiipBbtUA27dDQjFRdJviiyk8fTY/0BECatjiTOap3Y3u3M1+aEfXmZuowjNEG9QeXn14gaPq0AIdgj9AiA4mbh6esgskSnKSM8EIQQt0r/TO9ZCtb7OHLi2sdE04mAJLsAZzSRWWvCiwKUpVMWGrilm0QHcQeuiuut47HfzgbcxmyrMPc1a+j64f/Thk6z7Cc1DxVPdZdQOgBdqMbeeG3SMo87b1j2P6149d2mU1hgB9zDYq7rI/1bBDDZKq1lRJJZUSWlsoCVhiiBKkMiCMAMOZqQyX3AguiRZctZQbVdLWpghaoIcxHsZ45v/7FYhtcPs9mAuC7cTxplPR+rBfG+ijsy5Jc86YDNV101bZ3HPVOejjB5JRgwgFZooasGVUYF4bhVVZSCxEISxQLStGT4RZ9zz+5IlYa3hhy7oWrWwpAWarmpPKtsRoW2hpyhYqVpGqhlpqQtqS07qVmhigJU8m3QRvRh1/tUIxCfQ49uk6s3Va+9X1+LvgF0Y2wUevfZcEcx08vQ0R9r9TbeX3Bz+4mPa3s7TfBrj3ffo73//M2Vy89PESg3QH2XR6FZjC8gqwaVmBOSdwOj3DWjC1rkXNkoy3Xr9AyJLBlOsnTc6eenjKlkHvXAQdx5Am/zMtdZLz8/lkLnzkXz9tVz7A8nBYzNE/jomkU7OzAT68K9+GlL7zQ7xaeV7tCTp7BnZlJwPH01PlUlAYU4MRFDNOS8ylpLiWZYXbqm5lK2oo9cWu2SMYF0DHqd82jGnazOzvfLkM0Vml45CO54vXk51mf84pv4K8ku1n9Wn4lXSzleZOlCTLPp0ezslB/+vdfH9/f/8PAAD//wMAGp/mGygGAAA=
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTTW/cNhD9K8KcRZmkKErUzVin6MJNvEgWadEbxRnFhGVqQVFOAmP/e0DtBol764UgBnwz72P4CsE+E/Rwezq9e6GQFigh+a0kudSMa8bFUdS91L1oKt3JRhv+L5Tg7+k79NAq54QzxGrSxBTyhg316BgiGcEFctmo3NN+WaB/BesrpBfvqJqXzxQXPwfo4W8fcP6aZ1tfuWlesYrzRPuwJBtcJvNhv7tnf90ejg+Hy6uFlgyuPEIPioQ0igzjtWmZkoozI6llpNCZ0XS6tXiB+ZAoBjtVCz79mo9zCpRcLytZV5xJA+cS0CabKQ92oeP3U2axWXSX6+VW3q79K7xQhF6WP828tLtxk795XobVT3hzOZNdnrLKU5xPFJOnzZNN5jTZ5OdQXCftJk8hQQkPn4rDZNM4x+c3Rn266N//D/nHPP3dN3JrItzNa0jQg6gNlPDeukcfqNjfQQ9ckMS6IzZKoZnq0DLb1IZpXeuRhDOtFFDCbg7Jh3Vel2IfEn2JmwDo4Q87LXShfhvdo0/k0hqzqn903oVDnHF1qfjlv+AVr2rOM2hNpzUVHwl9JJco6zvG9drvPxCp5QbarTFSSMXBpsfiT7s8Qg/Gdk5YY4212rmRGk4jR241b5E0akIlsUVlFGpluNPKDkKhbcQw5gqUQDnuYtuwUdVcSeKMj9IwNVrJhq6VbJCtEELrpnVvfSwepoyzruOKsGaGRmTKCMuMqmuGdWNbqce2leNvllzTFzwbjPRy+SsbA43YEWrBpBINU8YI1pmmZUPbDWbQHTUbg3uKgabfjHrvXZyXeUzFdXmKN9Z9XEP+78W2SF99YN+2jO5m90SxyBlbH/J6X2M9n8/nHwAAAP//AwDZhTs/NgQAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4owZ1HmlyhRN2OdoAs39SJZpEVvFDmKCcvUgqScGMb+94LaDVKfil4IYsR3+M4zQ71BMM8IA9yeTh9eMOQENWS/hTjlilBFKDsyMXA1sLZRPZW6a/+GGvw9vsIAnbSWWY1EoEIiHW3JKCZLnEPNKHOUt7LkNN8SDG9gfOPwxVtslvQVY/JLgAH+9MEt38vdxjd2XlbXxGXGfUjZBFvM/LHf3ZPfbw/Hh8PlVMJUxI13MIBExrVETajQHZFcUqI5dgSls3rSveqMu8h8yBiDmZvknn7d75YcMNuBN1w0lHAN5xqcyaZYHk3C4+upuNgQ3ZV4vYW37fAGLxhh4PVPmJd0N3b2N89pXP3sbi5rNukpbetkbF7iK9RwissJY/a48blNCZ/H+fVo0tPHy5myTR9+oF0zut2yhgwDMKGghg3QPJvsl1BdPe5mjyFvH3P0IXn7X7kE1PDwpTrMJk9LfH7Xjy8XzPv/QfmTsY8+YLW/gwEoQ+5Ej2TiTBHZO0NMKzRRSqgJmdUdZ1DDbgnZh3VZU7UPGb/FrSQY4KOZE1783Ub76DPavMZS51+qzNUhLm61ufrVS0Yb2ghKi2jNpzVXn9H5iDZjKeIY12u+r+8lXPFNtFtjxJCrg8mP1W8mPcIA2vSWGW20McraCVuKE3XUKNo5VE6hk9x1TmrplNTUKmlGJp1p2TiVCNSAZXSqbVrbzhReLUE6CiKtEkQLIwgy17GxxZGa6R3H6mEuOmN7KtEJonFyRGpmiJZCECda03E1dR0vup9IrvPAaAHs8OXy7jYHyrkenWKES9YSqTUjvW47Mnb9qEfVY2uL53uMAed/gfrkbVzSMuXqOiHVO3Sf11D+HdU2Ld99ID+2Ht0t9gljVXpsfChP5drW8/l8/gcAAP//AwAKlhXBggQAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTwY7cKBD9FYuz8QDG2Pg26tlVWpPstJJRstobpoo0igdaGE8SjfrfV7g7Sia33NCDV/XqveKFBPOEZCS3p9NfzxjyQmqS/QYJJhRlijL+yNtRqJF3jRpk1w/6P1ITf4/fyUh6aS23GmmLCqkE1tGpdZYCoOaMAxOdLDXN54WML8T4BvDZW2zi8hHT4mMgI/nkA8SvpbfxjZ3jCk2KM+7Dkk2wRcw/+909fXt7eHw4XF4tuBRy44GMRCIXWqKmrNU9lUIyqgX2FCVY7fSgegMXmg8ZUzBzs8CXn/0h5oDZjqIRbcOo0ORcEzDZFMmTWfDx+6mo2Cy6K3i9wdtxfCHPmMgo6h9mXsrd2Nnf2Pj0ZALcOB/8ciQ1OaV4wpQ9bnZsE86zyT6G6tpkN3sMmdTk4UN1mE12MT298ujDZfT9H0z+ztijD1jt78hIGEcB7YDUCa6oHMBQ07WaKtUqh9zqXnBSk10M2Yc1rku1Dxk/p00lGcnfZl7wou822aPPaPOaivR/Vckav/m8i1AARmpySBFWm6ufdnPWsKZl5fJhzac1V+8RfEKbscz0mNZr+d8oQomNtFtTwpCrg8nH6o1ZjmQk2gyWG220Mcpahx1Dx4AZxXpABQpBCuhBaglKamaVNBOXYDo+uYIU3SXdaluorp/aaeiQOhwclWZAOijXUauB9cw4kCBe2Vo9zIVn7MAkQks1OqBSc0O1bFsKbWd6oVzfC/eLJdfEOSt+Az5fvsamQAEMCIpTIXlHpdacDrrr6dQPk57UgJ0tmu8xBZx/Meqdtyku0eXqujDVK+ver6F872pbnq8+0G9bZHfRfsFUlciND2Wbrymfz+fz/wAAAP//AwBHtmfAJQQAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAs6jwS/zQzbBb1HBTL2KjLXobcUaxEK20oKhNA8P/vaB2i8S99SIIA87wnWdeziub4UisYzen009nmvPKapbHPaSEslxYLuSz1J2ynWkbb5TxPvzFajY+0DfWMWdilDEQ12SJGxQt7/UQOSIFKSQK1ZpSEz6vrHtlMDZI5zFSs6y/U1rHZWYd+2Occfla7oaxidOyYZOWie7nNcMci5jf7m8f+K83h+fHw+XUSmtJbkZkHQvBOYyt5KF8jO4VD70HrlRPZHsTpBWXtHHOlGaYmhW/fL8flzxTjp1qlG4EV4G91QwhQ5Hcw0rP305FxY7orsTrPbz/dq/sTIl1qv4X5qXchziNH9atn+hM0wnSSulDXI5HmJHV7JSWE6U80o7lTKlf1jEXojE68F5K9OBM69DrVmmHWhB64VoMGMAaO6jYtgP2PjgzGFTSoCVjesdqtoObJsjjMldX7bfTSHNmNXt8qg4T5GFJx3fony5E7/8H0CKbdUyLVlvnyGitIdheCUJno7WqjyDc0CuSkUQbjAvSCamDEkG31nmHIEJkNfsI8WWcqbq/Yx0TkhRqT3xQ0nLjETi0OnBrtR1IxuCUZDW7XeY8ztuyrdX9nOlz2vtlHfsZppUund6k+DJminlLBcKftpjxkBbcYq6+G0CKRjRalJ4et3zacvWJcEwUMxUcz2m71vtPirJqT7rdUqI5VwfIL9UvsL4UhuCjhAABwMY4UCtoECjACodk0RIahQ5NMGhNENEa6KVBaGU/lAirGRW/VbvFXYhRhmHgwaHiZgjEYegVp9a46ACs8fSOY/U4lTyIXhhCzQMNyE2QwIPRmqNuwSk7OKeGH5BczSJFAYx0vjzWXYFF9IRWcmVky00IkvvQOt4734feempj0fxAaabpB1Afx5iWdRlydfVa9Q7dp20uC6faffd1nPnf+4zulviFUlVmDONc3td1rG81OxKsW6Ljvq+6V3Yoj6t63teW8o1U1tbsKUPK2+ka1m3jvHNvb29v/wAAAP//AwB1G8B29AQAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUS2/cNhDHv4rAsyjz/dDNsFvUdVMv4kVa9MbHyBaipRYUtWlg7HcPqN0gcW+9EMSA8+Bv/jNvKLkDoB7dHo+/nCCVBbWojJuJEaYwUZjQPeU9U72QnSGCU2n+QS0aH+Er6pEWIdBgAXNQgEUkEns+BBwjWEpoJEyKGtO9LKh/Q27sIpzGAN28fIK8jHNCPfprTHH+UnO7sQvTvMYuzxM8pKW4FGoxfz7cPeI/bnf7p93l1QJLde7GiHpkrdYxSIptPQT3DFtvHGbMAygvLFXk4jamAjm5qVvi5x/541wSlNCzjvGOYGbRuUXRFVdL9m6B/ddjrWJDdF/t7Wberv0bOkFGPWu/w7yEuwnTeFPm4wQnmI4uL5Bvwnw4uBRRi455PkIuI2xYtp9OkyvjnJprsrtphFRQi56em93kyjDnwztWzxcED/+DwAmyRz3iRHKlNQjOubPKMwJRq6AU88ERPXgGNACRVmhLNaHcMmK5VNro6IgNqEUv0+zd9Puy8bOMeBOJZoqBAMuEUjYQ4AYGqYFEp5RXJtjIjWbCRMOddY5aDzpYFapAPrjwOiZoHu5RjwgFFrkBPDCqsDDRYSe5xUpxNQANVjOKWnQ3pzKmdV6X5iEVeMkbP9SjX920wIXcbQ6vY4FQ1lyh/q1qsl2e4xpK80MBlHSk46QyelrLcS3NR4hjhlCg4t3n9RrvPy5Msc3pbs0ZUml2rrw2v7nltVJxJlBn61dVCANIAgOJxCmiI6ioIAoWdRRWRCUsCUo4T0V0kvqhWlCLoAqu2TRuiDSKS4epBo+FdB4bIQR2SkrFSIyR2nccm6ep+rlgiIDIsYUhYmGpw1ZwjiOXTjM1aM2Gn5BcxUdJBRzhdJnWrQIVo4GoKGaCSiyspdhYqbHXxluvDMhQK3iEnGD6CdSHMeR5mYfSXLXbvEP3cU114zSbjr+MCf+79eh+Dp8hN7XHbkx1wK5tPbfoAG5ZMxy2hdW/oV2drma/7S1mOsqUatFzcbmsx6uZy04brc/n8/kbAAAA//8DAMMGw8r1BAAA
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUXW/jKBSG/4rFtXEBY2x81013tFGn02ianV3tHYbjFNWBCHBnqyr/fYSTqumM9mJvLOuY8/W8r3lFTu0B9ej6cPj9GVyKqETJLiFGmMBEYEK3tO6Z6HlTdS2lTUf/QSWyt/CCetRyramWgGsQgLkhDR7qUWNjQFJCDWENzzXVLqL+FSlbGXi2Giofv0GI1jvUo7+sM/577q1spSc/myr4CdYuJuV0HubLenWLP19vtveb06kIMSdX1qAeSdm2RjcUy/zg9cCwHDqFGRsAxMAlFeSUZl2C4NRURfP03t/45CDpnlWsrghmEh1LZFRSeeRBRdi+HPIUC6KbHC+X8PLav6JnCKhn5RvMU7krPdmrfRxmO5mrye921u1W3o12NweVcuMSHYI/QEgWFji/WafCy2e/2+V66JOaIqASbSHsrVPT6cMNjGqe0oOfw0Immqf/OoN6pObkUYkWktO0tC3Oy6wmCy79knvR+P6h2EwqjT7sP4j0cGK//h/o75R+tA6K9Q3qEaHATN0BHhkVmHdGYdXUEgtRixGoli2jqEQr75J1s59jsXYJdmdqH+a7DvrRJtBpDnmnv0U22yZ4M+tUvAtMSUWqmuRJ7ud0mFPxFYwNoBPkJbZhPtf7KYUJtiR9shP8gmc1hwAuFRuVHos/VHzMOFSnqZJKKiW0HqEhMBJDlCCtAWEEGM5Ma7jkRnBJtOBqoNyohg5jjqASQTZZsfgaajaKWkmsx85gLroGSzXUWFLWSC1ZI4bxA9zifsp5SneEg6mxhNFgLqnCktc1NnWjWibGtmXjBaezISjJ1C9N+GcEc/bSl5O133Y38Hz6j5c5hTEdGEEx47TBXEqKO9m0eGi7QQ6ig0bnzVbeRf8G8huEwUeb8iVyZ53dq+nnI+/K3EJwMF2oc2d18NGPqTjbsvig19fZ5VusWCz63Tr872KMG6+fIBTZWMq6CzGPx+PxBwAAAP//AwA/OrCDDAUAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUwW7bOBD9FYFnUyEpihIF7MFwWqyRpjESd3exN4ocxkRk0aAop0GRf19Qlmun6GEvgjDkzLx57w1/oF7tATVoeTh8OkIfB7RA0U0hRpjARGBCt7RomGi4yFnJK0H4v2iB3B28oQZVXGuqJeACBGBuSInbwmpsDEhKqCGs5Kmmeh5Q8wMplxs4Og25H/6CMDjfowb97XrjX1Nv5XLd+dHkwXew7oeoep3AfF2v7vCX5Wb7sDndGmBIybkzqEFSVpXRJcUyfXjRMizbWmHGWgDRckkFOaW5PkLoVZcP5uXS3/jYQ9QNy1mRE8wkel8go6JKkFs1wPbtkFBMFN2m+GIKT7/ND3SEgBq2OJN5KnejO3ezH9rRdeYmqvAM0Qa1h1cfXuCoOrRAh+APEKKDiZuHp+wCiZKc5EwwkoDfK71zPWTr2+yhSwMrXRMOpsASrMFcUoUlLwpsilJVTNiqYhYt0B2EHrqrqvdOBz94G7OZ8uxDn5Xvo+tHPw7Zuo/wHFQ85X1W3QBogTZj27lh9wjKvG3945jO+rFLs6zGEKCP2UbFXfanGnZJF1VrqqSSSgmtLZQELDFECVIZEEaA4cxUhktuBJdEC65ayo0qaWtTBC3QwxgPYzzz//0KxDa4/R7MBcF24njTqWh92K8N9NFZl6Q535gM1XXTVNlcc9U56OMHklGDCAVmihqwZVRgXhuFVVlILEQhLFAtK0ZPhFn3PP7kiVhreGHLuhatbCkBZquak8q2xGhbaGnKFipWkaqGWmpC2pLTupWaGKAlN2m64M2o469WKCaBHsc+bWe2TmO/uh5/F/zCyCb46LXvkmCug6e3IcL+d6qt/P7gBxfT/HaW9tsA975Pp/P+z5zNyUsfLzFIe5BNq2dKSgjhGhNVl5iXosWKVwWmINqqJEChSDLeev0CIUsGU66fNDl76uEpWwa9cxF0HEPq/M801EnOz+eVufCRf/20XfkAy8NhMUf/OCaSTsXOBvjwrnwb0vWdH+LVyPNoT9DZM7ArOxk4np4ql4LCmBqMoJhxWmIuJcW1LCvcVnUrW1FDqS92zR7BuAA6TvW2YUzdZmZ/58tliM4qHYe0PF+8nuw0+3O+8ivIK9l+Zp+aX0k3W2muREmy7NPp4Zwc9L/ezff39/f/AAAA//8DAHaYtSMoBgAA
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSTQW/cNhCF/4rAsyiTFEWJuhnrFF24iRfJIi16G3FGMWGZWlCUk8DY/x5Qu4GT3nohhIGG8943j68swDOxnt2eTu9eKKSFlSz5raSEMlwYLuRR1r0yfSOrphG6M82/rGT+nr6znrXaOeks8ZoMcY2i4UM9Oo5IVgqJQjU63wlfFta/MvAV0ot3VM3LZ4qLnwPr2d8+4Pw1zwZfuWlesYrzRPuwJAgui/mw393zv24Px4fD5a+FltxceWQ9s7Zt0TWS23zoelDcDh1wpQYiM2grjbi0+ZAoBpiqBZ/e5uOcAiXXq0rVleDKsnPJEBJkyQMsdPx+yio2RHe5Xm7l7bN/ZS8UWa/KnzAv1924yd88L8PqJ7y5nAmWp+zyFOcTxeRpY7LZnCZIfg7FddJu8hQSK9nDp+IwQRrn+PwbqE8X//v/Yf+Yp7/7Rm5NhLt5DYn1TNaWlew9uEcfqNjfsZ4JSQrrjviopOG6Q+DQ1JYbU5uRpLOtkqxkuzkkH9Z5XYp9SPQlbgZYz/6AaaGL9NvoHn0il9aYXf1jchYOccbVpeKNvxSVqGqRRT6s6bSm4iOhj+QSZX/HuF7v+0+LMmpr2q0xUkjFAdJj8ScsjxkKdE6CBQtgnBupETQKFGBEi2TQEGqFLWqr0WgrnNEwSI3QyGHMFVYyyusutoQ16JpukC0ni8C1GiQHJztOVA/KEIxa5FC8cSweptwHrhOasOaWRuTaSuBW1zXHuoFWmbFt1fgLkuv2pciAkV4ub2VTYBA7QiO50rLh2lrJO9u0fGi7wQ6mo8ZlzfcUA02/gHrvXZyXeUzFNTzFb+g+riG/92IL0lcf+LdtR3eze6JY5B2DDzne17Wez+fzDwAAAP//AwBiE6abNgQAAA==
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRU0W7cKhD9FYtn4wDG2Pgt2rS6q9w2q3bVVn0bw7hBcfAKcNoo2n+vsLdK83R1X0Zo4Axnzhx4IR4ekfTk+nR694Q+RVKS5NaUYEJRpijjR173QvUNrxrZMaXb76Qk7hafSU9aaQw3GmmNCqm0rKFDPRpqLWrOuGWikbkm/IikfyHgKotPzmA1xy8Yops96clX5+38M98NrjLTvNgqzBPufUzgTSbzcb+7pf9eH453h+1UxJjBlbOkJ1q3rTUNpzoHWQ+C6qEDKsSAqAapuWIbzPmEwcNURfvwer+dk8dkelGJumJUaHIuiYUEmfIAEY/Pp8xilegm58s1vS77F/KEgfSi/CPmVu7KTO7qMQ6Lm+zVFhPEh7jGEUyawzMpySnMJwzJ4arPdYz4OEzPR4gP77czeRnf/UKzJLS7efGJ9ITXipRkFWiaILnZFxeOu8mhT+tmCs5HZ/6rVk1Kcve5OEyQxjk8vpnH503m/f9Q+QOYe+ex2N+QnjCOwtYd0lFwRWVngUJTa6pUrUbkRreCk5LsZp+cX+YlFnuf8EdYWyI9eQ9TxI3fdTD3LqFJS8h9flPZV4cw28Wk4nWWnFWsqllmcrek05KKT2hdQJMwN3EMy6Xel7cQocQK2i0hoE/FAdJ98Q/E+9w5dIaDBg2gjBmxYTgyy0Cx1qKyCq0UtrVSS6ukZkZJGLi00PBhzBlSEszWKTa3Am90yxQFZWoqrVYUYJQUAczQqrZudUa86ljcTRkHpmMSbU01jpZKzYFqWdfU1g20Qo1tK8a/JLn4gbMssMWn7d2tDJS1HVrFqZC8oVJrTjvdtHRou0EPqsPGZAa3GDxOfwn1wZkwx3lMxcUhxRvpPi0+/x3F6pafztNf64xuZvOAocgzBufzU7mM9Xw+n38DAAD//wMAXVqRGIIEAAA=
|
||||
@ -1,5 +0,0 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSTT2/cIBDFv4rFeXEAY2x8izatukrTrJqorXrDzDiL4sAK4/xRtN+9wrtVkt56sayxH/Pm94ZX4s0Dko6c7/efHtGniaxIcktJMKEoU5TxW151QnU1L+tatLzRv8mKuEt8IR1ppLXcaqQVKqQSWE37arAUADVnHJioZT7T3E2keyXGlYCPzmIZph8YJxc86chP5yE85d7GlXYMM5QxjLjxUzLeZjPfNutL+vV8e3u9Pf414ZTFpQPSEa2bBmzNqc4PWfWC6r41VIgeUfVSc8WOMucTRm/GcoL7t/4QksdkO1GKqmRUaHJYETDJZMu9mfD2ZZ9dLIgucn21lJfX7pU8YiSdWP2FeTzuzI7uzIaHB+PhbHDeTTuyIvsY9hiTwwXHMuE4muSCL05N1qNDn8iKXN8U29GkIcSHD4xujqNv/mPyK2N3zmOxuSAdYRwFVC3SQXBFZQuGmrrSVKlKDcitbgQnK7IOPjk/h3kqNj7hXVxcko58NuOER3/n0e5cQpvmmK3/UjlrfHZpHSAXcu9tDDDbVLzh5qxkZcXyx+s57edUfEdwEW3CPNNtnE/H/yMRSiyi9Rwj+lRsTdoVX8y0yyBMa7nRRhujrB2wZjgwYEaxBlCBQpACGpBagpKaWSVNzyWYmvdDrmTfOd1iWSg0rGGqQdrKvNUWDO11P1DAQbRaDapts+INa3E9Zp2xLZMIFdU4AJWaG6plVVGoatMINTSNGN4hOSXOWeYN+Hi8GosDBdAiKE6F5DWVWnPa6rqhfdP2ulct1jY7uMTocXwH6srZGKYwpOK0MMUHdN9nn693sSzPk/P0eYnsIth7jEWO3Dift/mU8uFwOPwBAAD//wMAq0uqsyUEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HDTLGKjLXobcUaxEK20oKhNA2P/e0F5i8S99UYMOMOXz7wzr2yGI7GO3Z5OP51pziurWR73kBLKcmG5kM9Sd0Z22jVBt0p5+xer2fhI31jHnIlRxkBckyVuULS810PkiBSkkChUa0pN+Lyy7pXB2CCdx0jNsv5OaR2XmXXsj3HG5Wt5G8YmTsuGTVomepjXDHMsYn57uHvkv94enj8e3m6ttJbkZkTWMe+dbTFaboIibgwoDrEduJM6RDMIGkIRAWMzzpnSDFOz4pfv7+OSZ8qxU43SjeAqsEvNEDIUyT2s9PztVFTsiO5LvN7D+7F7ZWdKrFP1vzDfyt3EabxZt36iM00nSCulm7gcjzAjq9kpLSdKeaQdy5lSv6xjLkRjdOC9lOjBmdah163SDrUg9MK1GDCANXZQsW0H7H1wZjCopEFLxvSO1WwHN02Qx2WurtrvppHmzGr28ak6TJCHJR3foX96I/rwP4AW2axjWrTaOkdGaw3B9koQOhutVX0E4YZekYwk2mBckE5IHZQIurXOOwQRIqvZB4gv40zVwz3rmJCkUHvig5KWG4/AodWBW6vtQDIGpySr2d0y53Helm2tHuZMn9P+X9axn2Fa6e2ntym+jJli3lKB8Kctsg9pwS3m6rsBpGhEo4UoSVs+bbn6RDgmipkKjue0Xev9J0VZtSfdbSnRnKsD5JfqF1hfWMcC+CghQACwMQ7UChoECrDCIVm0hEahQxMMWhNEtAZ6aRBa2Q8lwmpGxW/VbnHprAERFMdge24iIPeD1Vy23htpBGjh33GsPk4lD6IXhlDzQANyEyTwYLTmqFtwyg7OqeEHJFezSFEAI53fhnVXYBE9oZVcGdlyE4LkPrSO9873obee2lg0P1KaafoB1IcxpmVdhlxdvVa9Q/dpm8vCqXbffR1n/vfeo/slfqFUlR7DOJf5urb1UrMjwbolOu77qntlhzJc1fO+tpRrrBehZk8ZUt5O17AOjQxBXy6Xyz8AAAD//wMA9VbUEPQEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUzW7bOBB+FYFnUSElihIF7MFwWtRI0xiJu7vojSKHMRFZNCjKaRD43ReU5dopetibMCJnvr/hO+rlDlCDFvv9pwP0YUApCnYq5STnmHBM6IYWDaNNUWdFWRLCqx8oRfYO3lCDKqYUVQJwARww06TEbWEU1hoEJVSTvGSxp3weUPOOpM00HKyCzA1/gx+s61GD/rG9dq9xtrSZ6tyoM+86WPVDkL2KYL6tlnf462K9eVifTg0wxMuZ1ahBdV3xUiuOmcgBMyZzLFVpcEULoZghYEQEIW1m+wC+l1026JfLfO1CD0E1eZYXGcG5QMcUaRlkhNzKATZv+4hikug21tOpPH027+gAHjV5ehbz1O5GdfZmN7Sj7fRNkP4ZgvFyB6/Ov8BBdihFe+/24IOFSZuHp+QCiZKMZDnPCUEpupdqa3tIVrfJQxcJS1UTBrrAAozGTFCJBSsKrItSVjk3VZUblKI78D10V13vrfJucCYks+TJhzlL1wfbj24cklUf4NnLcLr3WXYDoBStx7azw/YRpH7buMcx/uvHLnJZjt5DH5K1DNvkixy2qEFC1opKIYWUXCkDJQFDNJGcVBq45qBZrivNBNOcCaI4ky1lWpa0NbGCUvQwhv0Yzvr/vAKx8Xa3A31BsJk0XncyGOd3Kw19sMZGa84npkB13cQqmXsuOwt9+CAyahChkOuiBmxyyjGrtcSyLATmvOAGqBJVTk+CGfs8/tKJGKNZYcq65q1oKYHcVDUjlWmJVqZQQpctVHlFqhpqoQhpS0brViiigZZMR3be6VGF36NQTAY9jn3czmQVab/aHv/k7KLI2rvglOuiYbaDp7chwO5Pri3dbu8GGyJ/M1v7fYB718e/8/7Pms2XFy5cahD3IJlWj1U0B8E5JlLVmGlJcVtrgxUtSpkXpKW6RCm6deoFfBIDJm0/eXLO1MNTsvBqawOoMPo4+d+J1MnOz+eVueiRffu0WToPi/0+nat/HaJIp2bnAHx4V74P8fjWDeGK8kztCTpzBnYVJw2H01NlY5FrXYPmFOeMlpgJQXEtygq3Vd2KltdQqktck0fQ1oMKU7+NH+O0Wdk/5XLhgzVShSEuz1enpjjN+ZyP/A7yyrZft0/Dr6ybozR3oiRG9un0cE4J+l/v5vF4PP4HAAD//wMABRuhhygGAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSTwY7cKBCGX8XibDyAARvfRj27SmuSnVYySlZ7w1Q5jeKBFsaTRKN+9xXujpLJLTf0Q1X99VXxQoJ9QjKQ29Ppr2cMeSE1yX6TBBOaMk0Zf+TtIPkgZSM4U8zw/0hN/D1+JwPppHPcGaQtaqQSmKJjOzkKgIYzDkwoWXLazwsZXoj1DeCzd9jE5SOmxcdABvLJB4hfS23rGzfHFZoUZ9yHJdvgipl/9rt7+vb28PhwuLxacCnBjQcykL7vtAKnqTQCqZRWUOvURDveGicnhpMpJqxvfMiYgp2bBb78rA8xB8xuEI1oG0aFIeeagM22WB7tgo/fT8XFhuiu6PUmb8fhhTxjIoOof8C8pLtxs79x8enJBriZfPDLkdTklOIJU/a44dg6nGebfQzVtchu9hgyqcnDh+ow2zzF9PSK0YdL6/s/6PyddUcfsNrfkYEwjgLaHukkuKayB0utag3VutUTcmc6wUlNdjFkH9a4LtU+ZPycNpdkIH/becGLv9vkjj6jy2sq1v/VpRh+83kXoQiM1OSQIqwuVz9xc9awpmXl8mHNpzVX7xF8Qpex9PSY1mv630KEFlvQbk0JQ64ONh+rN3Y5koEY2ztujTXWaucmVAwnBsxq1gFq0AhSQAfSSNDSMKelHbkEq/g4FaX4LtOttoVCkK1QI9IRlaKyd46OvFO04+U971Q7ja+wVg9zibOuZxKhpQYnoNJwS41sWwqtsp3QU9eJ6Rck14lzVngDPl++xuZAA/QImlMhuaLSGE57ozo6dv1oRt2jcsXzPaaA8y+g3nmX4hKnXF0XpnqF7v0ayveutuX56gP9to3sLrovmKoycutD2ebrlM/n8/l/AAAA//8DAO33rqElBAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUUW/cKBDHv4rFs3EAY2z8Fm1a3SrXy6pd9U73NoZxg+LACnDaKNrvfsK7pzZPp3tBaGBm/vObgTfi4RnJSG5Ppw8v6HMiNcluMwkmFGWKMn7k7Sj5KGUjWNdxrf8mNXH3+EpG0ktjuNFIW1RIpWUdndrZUGtRc8YtE50sMeFbIuMbAddYfHEGm5C+YkwueDKSP5234XvJDa4xS1htE8OCe58yeFPE/LHf3dPfbw/Hh8PlVsJUnBtnyUiGoVedNYpKLZBKCYKC6Wba81YbOTOcdREBrnE+Y/SwNMk+/cxvQ/aYzSga0TaMCk3ONbGQoUieIOHx9VRUbIjuir3ezNt2fCMvGMko6n9hXsLdmMXdPKdpdYu9uawZ0lPa1hlMDvGV1OQUwwljdrjxuU0Jn6fl9Qjp6ePlTtmmDz/QrBntLqw+k5HwVpGabICWBbILvrpq3C0Ofd4Oc3Q+OfNfsVpSk4cv1WGBPIf4/K4fXy6Y9/+D8icwj85jtb8jI2EchW0HpLPgisrBAoWu1VSpVs3Ije4FJzXZBZ+dX8Oaqr3P+C1uJZGRfIQl4UXfbTSPLqPJayx1/qVKskMMdjW5+tlLzhrWtIwVpzWf1lx9RusimoyliGNcr/G+vncRSmxOuzVG9Lk6QH6sfoP0SEaiYTAcNGgAZcyMHcOZWQaK9RaVVWilsL2VWlolNTNKwsSlhY5Pc7GQmmAZnWqbVrRopIGOzgonKqeuoxMOQGHgyGduWC/ec6weluIHZmASbUs1zpZKzYFq2bbUth30Qs19L+ZfkFzngbMC2OLL5d1tCpS1A1rFqZC8o1JrTgfd9XTqh0lPasDOFM33GD0uv4D65EwMKcy5uk5I9Q7d59WXv6PapuW78/TH1qO7YJ4wVqXH4Hx5Kte2ns/n8z8AAAD//wMAE1/rSoIEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPosyXKFE3Y52iCzfxIlmkRW8jchgTlqkFRTkJjP3vAbUbJO6tF4IY8Jv5HsNXEuEZyUBuT6d3LxjzQmqSw1YSTGjKNGX8yOWg+KBUI1jPW8X/JTUJ9/idDKRT1nJrkErUSJVjLR2lt9Q5NJxxx0SrSk/4spDhlUBoHL4Ei828fMa0hDmSgfwdopu/ltkQGjvNq2vSPOE+LhmiLWQ+7Hf39K/bw/HhcHm14FLATXBkIH3f6dZZTZURSJUCQcG2nnZcGqs8Q28KCQhNiBlThKlZ3NOv+W7OEbMdRCNkw6gw5FwTBxkK5REWPH4/FRabRXelXm/l7Tq8khdMZBD1TzMv7W7sFG6el3ENk7u5nBmWp6LylOYTphxw82STOU2Qwxyr66TdFDBmUpOHT9Vhguzn9PzGqE8X/fv/If9Ypr/7hnbN6HbzGjMZCJeG1OQ92McQsdrfkYEwjsLJHqkXXFPVO6DQSkO1ltojt6YTnNRkN8cc4jqvS7WPGb+kTQAZyB8wLXihfpvsY8ho85qKqn904XFIs1ttrn75z1nDGslYAa35tObqI7qQ0GYs+o5pvfb7D0RosYF2a0oYc3WA/Fj9CcsjGYiB3nIwYAC0tR5bhp45Bpp1DrXT6JRwnVNGOa0Ms1rByJWDlo++VEhNsMRdbRsmZQe9B0k77wRVnUDaOwTq1WgFiHZUKN/4WD1MBQe2ZwqdpAa9o8pwoEZJSZ1soRPad53wv1lyTZ+zYrDDl8tf2Rho53p0mlOheEuVMZz2pu3o2PWjGXWPrS2c7zFFnH4z6n2waV5mn6vr8lRvrPu4xvLfq22RvoZIv20Z3c32CVNVMoYQy3pfYz2fz+cfAAAA//8DANVoRU82BAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUXW/jKBSG/4rFtXEBY2x81013tFGn02ianV3tHYbjFNWBCHBnqyr/fYSTqumM9mLvrGPe8/GcF16RU3tAPbo+HH5/BpciKlGyS4gRJjARmNAtrXvO+rqpBCed5OIfVCJ7Cy+oRy3XmmoJuAYBmBvS4KEeNTYGJCXUENbwnFPtIupfkbKVgWerofLxG4RovUM9+ss647/n2spWevKzqYKfYO1iUk7nZr6sV7f48/Vme785nYoQs7iyBvVoGLnhghisBRsxJx3BHSiBFVDgpqMSWHOSWZcgODVV0Ty91zc+OUi6ZxWrK4KZRMcSGZVUbnlQEbYvh9zFgugmx8slvHz2r+gZAupZ+QbzlO5KT/ZqH4fZTuZq8ruddbuVd6PdzUGlXLhEh+APEJKFBc5v1qnw8tnvdjkf+qSmCKhEWwh769R0+nEDo5qn9ODnsJCJ5um/zqAeqTl5VKKF5DQtZYvzMKvJgku/aC8K3z8Um0ml0Yf9hyU9nNiv/wf6O6UfrYNifYN6RCgwU3eAR0YF5p1RWDW1xELUYgSqZcsoKtHKu2Td7OdYrF2C3Znah/6ug360CXSaQ57pb5HNtgnezDoV7wumpCJVTUgWzekwp+IrGBtAJ8hDbMN8zveThAm2iD7ZCX7Bs5pDAJeKjUqPxR8qPqIeSdVpqqSSSgmtR2gIjMQQJUhrQBgBhjPTGi65EVwSLbgaKDeqocOYI6hEkE1WLL4momasIxLX1HSY12ODpaoHzIWghOpRctZ+gFvcT1mndEc4mBpLGA3mkioseV1jUzeqZWJsWzZecDobgpJM/dKEf0YwZy99OVn7bXYDz6d7vPQpjOnACIoZpw3mUlLcyabFQ9sNchAdNDpPtvIu+jeQ3yAMPtqUH5E76+xeTT8fed/MLQQH08V27qwOPvoxFWdbFh/29XV2+RUrFot+tw7/uxjjxusnCEU2lrLuYpnH4/H4AwAA//8DACOBIt4MBQAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1Hm/aI3w27RhZt6ES/aoG8UZxQL0UoLito0MPa/F9RukbhveRMGOsPDb87wjUzhiKQl96fTL2ec8kJqkoetJJgwlBnK+IHLVolW6sYw77TWf5OaDE/4jbTEqhh59EglGqQKmKad7CMFQM8ZBya0Kj3D54W0byQMDeB5iNjMy5+YlmGeSEv+GiaYv5azw9DEcV6hSfOIu2nJYYrFzB+7hyf6+/3+8Ly//rXgUsTNAKQlXa9AGQY0GtFTxRyjDoOhATkqcNyj0FfZMGVMUxibBb58Px/mPGGOrWiEbBgVnlxqAiGHYrkLCx6+nYqLDdFjqddbefts38gZE2lF/R/Ma7u7OA53y9qNeMbxFNKC6S7Ox2OYgNTklOYTpjzghuWMqZuXIReiMdrgHOfgglXagpNaSAuSIThmNXjwwSjTi6h1D53zVvUKBFdgUKnOkpps4MYx5GGeqpv3h3HAKZOaPL9U+zHkfk7Hd+hfrkR3PwG02CYtkUxLYy0qKWXwphMMwZpojOhiYLbvBPKITHtlPbeMSy+Yl9pYZyEwH0lNPoT4OkxY7R5JSxhHAdIh7QU3VDkINGjpqTHS9Mijt4KTmjzMUx6mdV6Xajdl/Jy2+5KW/BrGBa83vU/xdcgY85oKhE+mhHGfZlhjrr4HgLOGNZKxIlrzac3VR4QhYcxYcBzSeuv3P4kwYhM9rCnhlKt9yK/Vb2F5JS3xwUUefPAhmBh71Ax7BiwYZgENGAQlwILyCozyLBoVOq4gaN71pUJqgiVv1RZxzXoudadpj6ipYr2gnjFHey6CdMZaUPIdx+p5LLoQHVMIknrsgSrPA/VKSgpSBytMb63of0ByCwtnBTDg+bqsmwMD4BAMp0JxTZX3nDqvLe2s63xnHOpYPD9hmnD8AdSHIaZ5mftc3bJWvUP3cZ3Kg1Ntufs6TPSfbUaPc/yCqSozDsNU9us21ktNjhiWNeFxe6/aN7Ivy1UdtmdL6IZ5J2rykkPK6+lW1rKxzrjL5XL5FwAA//8DAPYEweL0BAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HVTL+JFWvQ2Ike2EC21oKhNA2P/e0DtBol7600Y6J0ZPvPOvJEIByQduT0efzlhzAupSR63kGBCU6Yp43suOyU62Tat4cpq9w+pyfiIX0lHjPKee4dUokaqAmtpLwdPQ0DHGQ9MtKrkhJeFdG8ExibgafTYzMsnTMs4R9KRv8YY5i+lNoyNn+Y1NGme8CEuGaIvzfz5cPdI/7jd7Z92l78WXIq4GQPpSD+ooDQL1GsxUMUsoxZBU0COKljuULQX2RgzpghTs4TPP+qHOUfMvhONkA2jwpFzTQJkKC33sOD+67F0sSG6L/F6C2+f3Rs5YSKdqL/DvKS78dN4k+fjhCecjpAWTDd+PhwgBlKTY5qPmPKIG5btpdMEeZxjdS12N40YM6nJ03O1myAPczq8Y/V8QfDwPwicMPWkI5K1UhuDSkoJTveCYTDaay16D8wMvUDukbVOGccN49IJ5mSrjTUBmPOkJi/T3MP0+7Lxc4L1NjAjtECFTiitnWcoLQ6tQRZA615b74K0RigbrAQHwF2Pxjvti0E+gH8dI1YP96QjjKMI0iIdBNdU2QAUWumo1lIPyL0zgpOa3M0xj3Gd16V6iBlf0saPdORXmBa8kLtN/nXM6POaCtS/dSm2S3NYfa5+OICzhjWSsSJa83HN1UcMY0KfseDdp/Wa7z8SocUmultTwpirHeTX6jdYXgsVsJ6DK0/V3g/YMhxYYKCZCaiDxqBEMEE5FbRyzGsFPVcBWt4PJUJqgsVw1eZxqSQGNgBtfQtUoeYUmDXUh9aI4EQ/wHuO1dNUdOAtUxgkdTgEqhwH6pSUNMgWjNCDMWL4CcnVfJwVwAFPl23dOtAhWAyaU6F4S5VznFrXGtob27teW2x96fkRU8TpJ1AfRp/mZR5ydfVu9Q7dxzWWi1NtPv4yRvrvNqP72X/GVJUZwxjLgl3Heq7JAWFZEx62g9W9kV3Zrmq/3S3RNsxZUZPnDCmvx2u4lY2x2p7P5/M3AAAA//8DADaVhNr1BAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJSFCUK2IPhtFgjTWMk7u5ibxQ5jInIokFRToMi/31BWa6dooe9CaN5fY/hD9SrPaAGLQ+HT0fo44AWKLopxAgTmAhM6JYWDWdNIXJS0IrW7F+0QO4O3lCDKq411RJwAQIwN6TEbWE1NgYkJdQQVvLUUz0PqPmBlMsNHJ2G3A9/QRic71GD/na98a9ptnK57vxo8uA7WPdDVL1Oy3xdr+7wl+Vm+7A5ZQ0wpOLcGdSg1nLDBTFYC2YxJzXBNSiBFVDgpqYSWHkqc32E0KsuH8zLZb7xsYeoG5azIieYSfS+QEZFlVZu1QDbt0PaYqLoNsUXU3j6bH6gIwTUsMWZzFO7G925m/3Qjq4zN1GFZ4g2qD28+vACR9WhBToEf4AQHUzcPDxll5UoyUnOBCMELdC90jvXQ7a+zR66BFjpmnAwBZZgDeaSKix5UWBTlKpiwlYVs2iB7iD00F11vXc6+MHbmM2UZx/mrHwfXT/6ccjWfYTnoOKp7rPqBkALtBnbzg27R1Dmbesfx/SvH7uEZTWGAH3MNirusj/VsEMNkqrWVEkllRJaWygJWGKIEqQyIIwAw5mpDJfcCC6JFly1lBtV0tamCFqghzEexnjm//vVEtvg9nswlw22E8ebTkXrw35toI/OuiTNOWMyVNdNqLK556pz0McPJKMGEQrMFDVgy6jAvDYKq7KQWIhCWKBaVoyeCLPuefzJE7HW8MKWdS1a2VICzFY1J5VtidG20NKULVSsIlUNtdSEtCWndSs1MUBLbhK64M2o469WKCaBHsc+XWe2TrBfXY+/C35hZBN89Np3STDXwdPbEGH/O9VWfn/wg4sJv52l/TbAve/T3/n+Z87m4qWPlxikO8im0yuZopYwiRWnBea20LjmdYsVU9TQtpVGJxlvvX6BkCWDKddPmpw99fCULYPeuQg6jiFN/mcCdZLz8/lkLnzkXz9tVz7A8nBYzNE/jomkU7OzAT68K9+GlL7zQ7yCPEN7gs6eF7uyk4Hj6alyKSiMqcEIihmnJeZSUlzLssJtVbeyFTWUE86TXbNHMC6AjlO/bRjTtJnZ3/lyGaKzSschHc8Xryc7zf6cU35d8kq2n9Wn4VfSzVaaO1GSLPt0ejgnB/2vd/P9/f39PwAAAP//AwC2uuIgKAYAAA==
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxU227cNhD9FYGvFRXeRJF6c20HXaSOjeyiLfo2Ikc2a5laUJSTwPC/F9TauaJAXwRhSM45c+bMPJEID0h6cnY8Xj5izAupSQ5bSDChKdOU8QOXvRK94o0xgivd/U1qEt7hZ9KTTjnHnUUqUSNVnrV0kKOj3qPljHsmWlVywu1C+icCofH4GBw28/IHpiXMkfTkzxD9/LFgQ2jcNK++SfOEu7hkiK6Qeb87f0d/P7s5XN+cbi24lMdN8KQnw6i80sxTp8VIFTOMGgRNATkqb7hF0Z6ehZgxRZiaxd9/xfdzjphdLxohG0aFJc818ZChUB5gwcPnY2GxSXRR4vUW3n77J/KIifSifhXzlO6Nm8Kbh2VYw+TfbF9Sk2Oaj5hywE2N6331lQRnDWuEFoyRmlyBuwsRq91FdT2VEsEZptBLanH0VFkO1CopqZctdEKPXSdGUpN3mCJO32S9Ci7Nyzzm6kXk6juc/dn5ZYRhwoLxFqYFSU12yz5D9DDNES8/oVvzKdchreX4fI45xHVel2oXM94meDl/fX++poQxVzeQ76rfYLkjPbFgHAcLFkA7N2LLcGSegWadR+01eiV855VVXivLnFYwcOWh5cNYIqQmvxYN96tzuCxf2WwmmaaNQ/XSp/MpYMzfyUh6wjgKLw3SUXBNlfFAoZWWai31iNzZTvBXmAOkW8ykJ6MZhoE5NwhluQNhQfqRSa9HK0TXgRpl2ymhdcs6cL7rBFdeduhAjpIZQWpyk2a/uvxjq+XWgJs0/4MuF6lITzRrW+NgGIRW3IA1qLhWRlvsrBqBKekG4K2BYeAMWuasEQ64tqAG345fVLqMtyHiRViOE3z+Btc0upG/OADDR1A/XH+b4AE/zun+/cnGzfvLA6nJhzWWjVDtikU+hkg/6TLRV+uUw+EuIXj0V7PHn32EZVyqbUJH27pRGks96DKhbKAwGEalYcC1VErpov3F7O4xVcVhEGKZqi/JrvfVWXJ3IaPLayr8/tp4XO+rmwnyOKeH7zbJN4X9KEAjJGelMx4fT9to46i9N+g1p0LxliprOTW27ejQmcEO2mDrimLXaz6uufqAPiR0eav4xYsb5vkduvufxXh1wYtFOSv17k9bbJP2fy2x55o8ICxrwodtW/dPZBcjpg35Yj2N4i5ehWkKC7o5+oX0WijTdK1WLwz/855kvOmkUs/Pz8//AgAA//8DAEDMGTMbBgAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTTW/cNhD9K8KcRZmkKErUzVin6MJNvEgWadEbxRnFhGVqQVFOAmP/e0DtBk5664UgBnwz72P4CsE+E/Rwezq9e6GQFigh+a0kudSMa8bFUdS9kr0SVdd2XKruXyjB39N36KFVzglniNWkiSnkDRvq0TFEMoIL5LJRuaf9skD/CtZXSC/eUTUvnykufg7Qw98+4Pw1z7a+ctO8YhXnifZhSTa4TObDfnfP/ro9HB8Ol1cLLRlceYQehlGh0hyZ03JkinecdWQ1syRIYScMyeYC8yFRDHaqFnx6m49zCpRcLytZV5xJA+cS0CabKQ92oeP3U2axWXSX6+VW3q79K7xQhF6WP828tLtxk795XobVT3hzOZNdnrLKU5xPFJOnzZNN5jTZ5OdQXCftJk8hQQkPn4rDZNM4x+ffjPp00b//H/KPefq7b+TWRLib15CgB1EbKOG9dY8+ULG/gx64IIl1R2yUQjPVoWW2qQ3TutYjCWdaKaCE3RySD+u8LsU+JPoSNwHQwx92WuhC/Ta6R5/IpTVmVf/ovAuHOOPqUvHmv+AVr2rOM2hNpzUVHwl9JJco6zvG9drvPxCp5QbarTFSSMXBpsfiT7s8Qg/Gdk5YY4212rmRGk4jR241b5E0akIlsUVlFGpluNPKDkKhbcQw5gqUQDnuYtswIdRQu4GYbCRnCp1idqCWNdia0TnpBpspvvlYPEwZZ13HFWHNDI3IlBGWGVXXDOvGtlKPbSvHXyy5pi94Nhjp5fJXNgYasSPUgkklGqaMEawzTcuGthvMoDtqXOZ8TzHQ9ItR772L8zKPqbguT/GbdR/XkP97sS3SVx/Yty2ju9k9USxyxtaHvN7XWM/n8/kHAAAA//8DAOoNqD02BAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRUwW7cNhD9FWHOokxSFCXqZqwTdOGmXiSLtOiN4oxiwjK1ICknhrH/Xki7ReJT0QtBjPiGb9571BsE+0zQw+3p9OGFQk5QQvZbSXKpGdeMi6OoeyV7JaquVa1q6r+hBH9Pr9BDq5wTzhCrSRNTyBs21KNjiGQEF8hlo9ae9luC/g2sr5BevKNqTl8pJj8H6OFPH3D+vt5tfeWmecEqzhPtQ8o2uJXMH/vdPfv99nB8OFxOJUoruPIIPQyjQqU5MqflyBTvOOvIamZJkMJOGJLNBeZDphjsVCV8+nk/zjlQdr2sZF1xJg2cS0Cb7Up5sImOr6eVxSbR3Vovt/K27d/ghSL0svxXzEu7Gzf5m+c0LH7Cm8uabXpK2zpal+f4CiWc4nyimD1t+tymRM/D9Hq06enj5cy6TR9+kFsy4W5eQoYeRK2hhE2gabLZz6G4ctxNnkLePuboQ/Luv3rVUMLDl+Iw2TzO8fmdH18uMu//h8qfrHv0gYr9HfTABUmsO2KjFJqpDi2zTW2Y1rUeSTjTSgEl7OaQfVjmJRX7kOlb3EaCHj7aKdGF3210jz6Ty0tc5/xLr7k6xBkXl4ufXgpe8armfAUt+bTk4jOhj+QyrUMc43Lt9/U9RGq5gXZLjBRycbD5sfjNpkfowdjOCWussVY7N1LDaeTIreYtkkZNqCS2qIxCrQx3WtlBKLSNGMa1AiXQGp1iS6uVjZAtR9Y5NTJFamRdKw3ruNNScMnR4Dsdi4dpw7mOK8KaGRqRKSMsM6quGdaNbaUe21aOv0hyzYPgq8BIL5d3tzHQiB2hFkwq0TBljGCdaVo2tN1gBt1R41bO9xQDTb8I9cm7OKd5zMU1IcU76T4vYf13FFtavvvAfmwe3c3uiWKxemx9WJ/K1dbz+Xz+BwAA//8DAELILvyCBAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1Hm/aI3w27RhZt6ES/aoG8UZxQL0UoLito0MPa/F9RukLpveRMGOjOH3xzyjUzhiKQl96fTL2ec8kJqkoetJJgwlBnK+IHLVslW8EZK75R2f5OaDE/4jbTEqhh59EglGqQKmKad7CMFQM8ZBya0Kj3D54W0byQMDeB5iNjMy5+YlmGeSEv+GiaYv5bZYWjiOK/QpHnE3bTkMMVi5o/dwxP9/X5/eN5f/1pwKeJmANIS1wsTQtdR77tAFaCjgXtOueaopFYBFb/KhiljmsLYLPDlx3yY84Q5tqIRsmFUeHKpCYQciuUuLHj4diouNkSPpV5v5e2zfSNnTKQV9XeY13Z3cRzulrUb8YzjKaQF012cj8cwAanJKc0nTHnADcsZUzcvQy5EY7TBOc7BBau0BSe1kBYkQ3DMavDgg1GmF1HrHjrnreoVCK7AoFKdJTXZwI1jyMM8VTfvD+OAUyY1eX6p9mPI/ZyO79C/XInufgJosU1aIpmWxlpUUsrgTScYgjXRGNHFwGzfCeQRmfbKem4Zl14wL7WxzkJgPpKafAjxdZiw2j2SljCOAqRD2gtuqHIQaNDSU2Ok6ZFHb0WZ/jBPeZjWeV2q3ZTxc9rOS1ryaxgXvJ70PsXXIWPMayoQPpkSxn2aYY25+hEAzhrWSMaKaM2nNVcfEYaEMWPBcUjrrd//JMKITfSwpoRTrvYhv1a/heWVtMQHF3nwwYdgYuxRM+wZsGCYBTRgEJQAC8orMMqzaFTouIKgedeXCqkJlrxVW8SNFyxy1VOuvKLKR0+d95zqTisP6KXD/h3H6nksuhAdUwiSeuyBKs8D9UpKClIHK0xvrSi670huYeGsAAY8Xy/r1QGAQzCcCsU1VWW489rSzrrOd8ahjsXzE6YJx/+A+jDENC9zn6tb1qp36D6uU3lwqi13X4eJ/rPt6HGOXzBVZcdhmMr9uq31UpMjhmVNeNzeq/aN7Mvlqg7bsyV0Y73zNXnJIeX1dCtb2Xjv3OVyufwLAAD//wMAMacs9fQEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJKFCUK2IPhtFgjTWMk7u5ibxQ5jInIpEFRToMi/31BWa6dooe9CaN5fY/hD+TkHlCLlofDpyO4OKAFinYKFaTgmHBM6JaWLSvbguZNwTgvxL9ogewdvKEW1UwpqgTgEjhgpkmFu9IorDUISqgmRcVST/k8oPYHkjbXcLQKcj/8BWGw3qEW/W2d9q9ptrS56v2o8+B7WLshSqfSMl/Xqzv8ZbnZPmxOWQMMqTi3GrWoMQWXsuuwEJ3ETEODJRUU04oCKysmgdFTmXURgpN9PuiXy3zto4Oo2iIvypzgQqD3BdIyyrRyJwfYvh3SFhNFtym+mMLTZ/sDHSGgtlicyTy1u1G9vdkP3Wh7fRNleIZogtzDqw8vcJQ9WqBD8AcI0cLEzcNTdlmJkpzkBS8IQQt0L9XOOsjWt9lDnwBL1RAGusQCjMZMUIkFK0usy0rWBTd1XRi0QHcQHPRXXe+tCn7wJmYz5dmHOSvvonWjH4ds7SI8BxlPdZ9lPwBaoM3Y9XbYPYLUb1v/OKZ/buwTltUYAriYbWTcZX/KYYdaJGSjqBRSSMmVMlARMEQTyUmtgWsOmhW61kwwzZkgijPZUaZlRTuTImiBHsZ4GOOZ/+9XS2yD3e9BXzbYThxvehmND/u1BhetsUmac8ZkqL6fUGVzz1VvwcUPJKMWEQqFLhvApqAcs0ZLLKtSYM5LboAqURfJUSvvjH0ef/JEjNGsNFXT8E50lEBh6oaR2nREK1MqoasO6qImdQONUIR0FaNNJxTRQCumE7rg9ajir1YoJ4EeR5euM1sn2K/W4e+cXRjZBB+98n0SzPbw9DZE2P9OtZXfH/xgY8JvZmm/DXDvXfo73//M2Vy89PESg3QH2XR6siLSlCXHomQCM91JLIhssDGkNgZ0WUOJFujWqxcIWTKYtG7S5Oyph6dsGdTORlBxDGnyPxOok5yfzydz4SP/+mm78gGWh8Nijv5xTCSdmp0N8OFd+Tak9J0f4hXkGdoT9Oa82JWdNBxPT5VNQa51A5pTXDBaYSYExY2oatzVTSc63kClLnbNHkHbACpO/bZhTNNmZn/ny2WI1kgVh3Q8X7ya7DT7c075dckr2X5Wn4ZfSTdbae5ESbLs0+nhnBz0v97N9/f39/8AAAD//wMAM2qugCgGAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSU227cNhCGX0XgtSjzJB50Z9gt6rqpF/EiLXo3JEe2EK20oKhNA2PfPaB2g8S9650w0D+Hb/7hG5nggKQjt8fjLyec8kJqkoctJJjQlGnK+J7LTslO8EY4boXl/5CaDI/4lXTEqBB4cEglaqQqspZ62QcaIzrOeGSiVSUnvCykeyMwNBFPQ8BmXj5hWoZ5Ih35a5ji/KXUhqEJ47zGJs0jPkxLhimUZv58uHukf9zu9k+7y18LLkXcDJF0xPZCA3hPnfNAVURLgTtOectRyVYBKn6RDVPGNMHYLPHzj/pxzhPm0IlGyIZR4ci5JhEylJY9LLj/eixdbIjuS7zewttn90ZOmEgn6u8wL+luwjjc5Pk44gnHI6QF002YDweYIqnJMc1HTHnADcs26ThCHuapuha7GwecMqnJ03O1GyH3czq8Y/V8QfDwPwicMHnSEclaqY1BJaUEp71gGI0OWgsfgJneC+QBWeuUcdwwLp1gTrbaWBOBuUBq8jLOHsbfl42fE8zbyIzQAhU6obR2gaG02LcGWQStvbbBRWmNUDZaCQ6AO48mOB2KQT5AeB0mrB7uSUcYRxGlRdoLrqmyESi00lGtpe6RB2dEmeZunvIwrfO6VA9Txpe08SMd+RXGBS/kblN4HTKGvKYC9W9diu3SHNeQqx8O4KxhjWSsiNZ8XHP1EeOQMGQsePdpveb7j0RosYnu1pRwytUO8mv1GyyvhQrYwMGVUXUIPbYMexYZaGYi6qgxKhFNVE5FrRwLWoHnKkLLfV8ipCZYDFdtHjcsGghtT73RLVWtZ9RxISj4wGPfC2Xb9h3H6mksOgiWKYySOuwjVY4DdUpKGmULRujeGNH/hORqPs4K4Iiny7VuHegYLUbNqVC8pco5Tq1rDfXGeue1xTaUnh8xTTj+BOrDENK8zH2urt6t3qH7uE7lxak2H38ZJvrvtqP7OXzGVJUdwzCVA7uu9VyTA8KyJjxsD1b3Rnbluqr99m6JtjHOupo8Z0h5PV7DRjbOWXs+n8/fAAAA//8DALmMltD1BAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/jNhCG/4rAs6mQFEWZuqVOFzWy2Rgbd1v0NiJHDhGZNCgq2yDwf19QdhBnFz30Joz4zsczL/lKPOyRtOT6cPj9GX0ayYIkN4cEE4oyRRnf8qqVVSt4WSnBlBD/kAVxt/hCWtJIY7jRSCtUSKVlNe2q3lBrUXPGLRO1zDlhN5L2lYArLT47g2UYv2EcXfCkJX85b8P3XBtcaYYw2TKGAdd+TOBNbubLenVLP19vtveb06kRxywunSUtWfZCAXQd1boDKi0uKXDNKa85yqqWgJKfZM4njB6GcrRP7/VtSB6TaUUpqpJRoclxQSwkyC13MOL25ZC7mBHd5PhiDs+f7St5xkhasXiDeUp3ZQZ3tR+7yQ32agi7nfO7VfC9200RUi68IIcYDhiTwxnOb85DfPkcdrucj3yCYUSyIFuMe+dhOP24wR6mIT2EKc5kRvv0X2dIS2BKgSzITHIY5rLFeZjV4NCnX7QXhe8fis0AqQ9x/2FJDyf26/+B/g7Mo/NYrG9ISxhHYasl0l5wReXSAoW60lSpSvXIjW5E1qyCT85PYRqLtU+4O1P70N91NI8uoUlTzDP9rbLZNjHYyaTifcGclaysGMuiKR2mVHxF6yKahHmIbZzO+X6SCCVm0Sc34C94VlOM6FOxgfRY/AHjI2mJhqXhoEEDKGN6rBn2zDJQrLGorEIrhW2s1NIqqZlREjouLdS863OELAhmkxWzr1HpjlVNTbUGQWUvO6pr2dAKGmGENpxVH+EW90PWgVkyibaiGntLpeZAtawqaqsaGqH6phH9BaezITjLyS5N+OeI9uylLydrv81u8fl0j+c+lbVLtIpTIXlNpdacLnXd0K5ZdrpTS6xNnmwV/BjeQH7D2IXRpfyI3Dnv9jD8fOR9M7cYPQ4X27lzJoYx9Kk427L4sK+vk8+vWDFb9Lvz9N/ZGDfBPGEssrHA+YtlHo/H4w8AAAD//wMA2IvlogwFAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTwW7UMBD9lcjndWo7jhPnVm1BrAp0RStA3CaeCWuROivHKaBq/x05uwjKjZv17Dfz5r3xMwvwSKxj18fjqycKaWYblvwKKaEMF4YL+SCrTledsmUjhGis+sI2zN/ST9axRjsnnSVekSGuUdS8rwbHEclKIVGoWuea8HVm3TMDXyI9eUflNH+kOPspsI598gGn77k3+NKN04JlnEbahTlBcFnM+932lr+93j/c7c+vZpozufTIOtYOygD0Pbe2B66RWg7SSi5rSbqqNZCWZ5oPiWKAsZzx25/+OKVAyXWqVFUpuLLstGEICbLkHmZ6+HnMKlaLbjK+WeH12D2zJ4qsU5vfZp7LXbnRX7np8RECXg0++PnANuwYpyPF5Gm1Y51wHCH5KRSXJtvRU0hsw+7ui/0IaZji4wuP7s+j7/5j8nfgDj5QsbthHROSFFYt8UFJw3WLwKGuLDemMgNJZxuVOdspJB+WaZmLXUj0Na4qWcdewzjTWd91dAefyKUlZumfTc6afvi0nTADgm3YPk64uFT8sVuKUpSVyJd3SzouqfhA6CO5RHmmh7hcyv9DUUatpO0SI4VU7CEdijcwH1jHLLROggULYJwbqBY0CBRgRINk0BBqhQ1qq9FoK5zR0EuNUMt+yEjWndMt1oXSUuKAdcO1A8216DXvexq4rYwZemtb0eMLW4u7MfPAtUITVtzSgFxbCdzqquJY1dAoMzSNGv6y5JK4FNlvpKfz11gVGMSW0EiutKy5tlby1tYN75u2t71pqXZZ8y3FQONfRr3zLk7zNKTisjDFC+s+LCF/72Jdnu8+8B9rZDeT+0axyJGDD3mbLymfTqfTLwAAAP//AwAqQNGLJQQAAA==
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRUTW/cNhT8KwLPS5lfokTdjHWCLtzUi2SRFr09kU8xYZlakJQTw9j/XlDaIPWp6IUgnjiP82aGeiMBnpH05PZ8/vCCISeyI9mvJcGEpkxTxk9c9kr2wtTaKK2N+JvsiL/HV9KTVlnLrUEqUSNVjjV0kKOlzqHhjDsmGlV6wrdE+jcCvnb44i3Wc/qKMfk5kJ786YObv5e7wdd2mhdXx3nCQ0gZgi1k/jjs7+nvt8fTw3E7lTAVcO0d6Uk3Cg0wDNSYAahy2FHghlPecFSyUYCKbzAfMsYAU53c06/73ZwDZtuLWsiaUWHIZUccZCiUB0h4ej0XFqtEd6W+W8vrtn8jLxhJL3Y/xdza3djJ3zynYfGTu9nWDOkpresINs/xlezIOc5njNnjqs9tSvg8TK8nSE8ftzNlmz78QLtkdPt5CZn0hEtNdmQVaJog+zlUV477yWPI68ccfUje/lcvSXbk4Ut1nCCPc3x+58eXTebD/1D5E9hHH7A63JGeMI7CyQ7pKLimqnNAoZGGai31iNyaVhTMfg7Zh2VeUnUIGb/FdSTSk48wJdz43Ub76DPavMQy51+65OoYZ7fYXP3ykrOa1ZKxAlryecnVZ3Q+os1YhjjF5drv63uI0GIF7ZcYMeTqCPmx+g3SI+mJgc5yMGAAtLUjNgxH5hho1jrUTqNTwrVOGeW0MsxqBQNXDho+jKVCdgRLdKotrUK2jbSKIraWKmY5NdIyqgE1ArDOmPGdjtXDVHBgO6bQSWpwdFQZDtQoKamTDbRCj20rCu6nJNc8cFYEdviyvbuVgXauQ6c5FYo3VBnDaWealg5tN5hBd9jYwvkeY8DpX0J98jbOaR5zdU1I9U66z0so/45qTct3H+iP1aO72T5hrIrH4EN5KldbL5fL5R8AAAD//wMAoRyWV4IEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPS5kvUaJuxjpFF27qRbJoi95GnFFMWKYWFOUkMPzfC2o3SN1bLwQx4DfzPYavLMIzsZ7dns8fXijmhe1YDltJCWW5sFzIk9S90b1ytXVtq1X3N9uxcE/fWc9a4730jrgmS9ygaPigR88RyUkhUajGlJ7wZWH9K4NQI70ET/W8/EFpCXNkPfszRJy/ltkQaj/NK9ZpnugQlwzRFzK/H/b3/Lfb4+nheHm10FLAdUDWs25UFmAYuHMDcIPUcZBOctlIMroxQEZeYCFmShGmesGnn/NxzpGy71WtdC24cuxtxxAyFMoDLHT6fi4sNovuSn23lbdr/8peKLFe7X6YeWl346dw87wMa5jw5nJmWJ6KynOaz5RyoM2TTeY0QQ5zrK6T9lOgmNmOPXyujhPkcU7P74z6fNF/+B/yT2X6h2/k10y4n9eYWc+kdmzHPoJ/DJGqwx3rmZCkUHfERyUtNx0Ch0Y7bq22I0nvWlXa7eeYQ1zndakOMdOXtAlgPfsFpoUu1G+TfwyZfF5TUfWXLbtwTDOuPlc//ZeiFrUWooDWfF5z9YkwJPKZir5TWq/9/gNRVm2g/ZoSxVwdIT9Wv8LyyHrmoPMSHDgA6/1IjaBRoAArWiSLltAobNE4g9Y44a2BQRqERg5jqbAdoxJ3tW0YaAckoOPK6ZabDog77DQfpDANYmPGcXznY/UwbTjfCUOouaMRuXESuDNac9QNtMqObasK7ocl1/SlKAYjvVz+ysbAInaEVnJlZMONc5J3rmn50HaDG2xHjS+c7ylFmv5l1Mfg07zMY66uy1O9s+7TGst/r7ZF+hoi/7ZldDf7J0pVyRhCLOt9jfXt7e3tHwAAAP//AwDn5IjHNgQAAA==
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxU227jNhD9FYGvFRXeRIl6S50saqRJjLXRFn0bkaOYjUwZFJXsIsi/F5KTzWVRoC+CMCTnnDlzZp5IgAOShpwfj5cPGNJIcpL8EhJMaMo0ZXzHZaNkI0xRMc60qP4mOfFX+J00pFLWcmuQStRIlWMlbWVnqXNoOOOOiVLNOeFuJM0TAV84fPAWi2H8A+Poh0Aa8qcPbnicscEXth8mV8Shx3UYEwQ7k7lZr67o7+eb3e3mdGvEcX5ceEcaUndCA7QtNaYFqhzWFLjhlJcclSwVoOKnZz4kjAH6YnT3b/huSAGTbUQhZMGoMOQ5Jw4SzJRbGHH3/TizWCS6mOP5El5+myfygJE0In8V85TuzPb+7DC2k+/d2fIlOTnG4YgxeVzUuN1mbyQ4K1ghtGCM5OQa7N4HzNYX2W0/lwi2ZgqdpAY7R5XhQI2SkjpZQiV0V1WiIzm5whiwf5f12ts4jEOXsheRsw842/PVZYC2xxnjC/Qjkpysx22C4KAfAl5+QzulU65dnObj1RCSD9Mwjdk6JLyL8HL++n41xYghZRtI++w3GPekIQZqy8GAAdDWdlgy7JhjoFnlUDuNTglXOWWU08owqxW0XDkoedvNEZKTX2cNt5O1OI5vbBaT9P3CIXvp06r3GNIHGUlDGEfhZI20E1xTVTugUEpDtZa6Q25NJfgrzA7iHSbSkK5u25ZZ2wpluAVhQLqOSac7I0RVgepkWSmhdckqsK6qBFdOVmhBdpLVguRkEwc32fS51XJpwCYO/6BNs1SkIZqVZW2hbYVWvAZTo+Ja1dpgZVQHTEnbAi9raFvOoGTW1MIC1wZU68ruh0qX4c4HvPDjsYfv73DrQhfyFwtQ8w7Up+tfIhzwcYj3NycbFzeXO5KTr1OYN0K2ni3y6AP9pueJvp765Hf7iODQXQ8Of/YRzuOSLRNaCle7sgTKVN1RBVpSkAopZ2WHyuqKYUVycjHYe4zZ7DDwYZ6qH8lut9l5tHuf0KYpzvz+WnjcbrNND6kb4uHDJnlX2GcBCiE5mzvj8OG0jRaO2rkaneZUKF5SZQyntSkr2lZ1a1pdY2lnxW6ndJxS9hWdj2jTUvGLFxfM1R7t/c9ivLrgxaKczV7bnrbYIu3/WmLPOTkgjFPEw7KtmyeyDgHjgnwxnUZxHa593/sR7RDcSJpaqrqodGVeGP7nPcVEURrGn5+fn/8FAAD//wMAys86yBsGAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUW2/cNhCF/4rAZ1HmTbzozbBbdOGmXsSLNugbxRnGQrTSgqI2DYz97wW1G6TuW96Egc7w8JszfCOTPyLpyP3p9MsZp7yQmuRhKwkmNGWaMn7gslOqY65h1iij2d+kJsMTfiMdMSoEHhxSiRqpAtbSXsZAAdBxxoGJVpWe/vNCujfihwbwPARs5uVPTMswT6Qjfw0TzF/L2X5owjiv0KR5xN20ZD+FYuaP3cMT/f1+f3jeX/9acCniZgDSERukQotIdXSRKt621FkZKbjeCS1chBivsmHKmCY/Ngt8+XE+zHnCHDrRCNkwKhy51AR89sVy7xc8fDsVFxuix1Kvt/L22b2RMybSifo7zGu7uzAOd8vaj3jG8eTTgukuzMejn4DU5JTmE6Y84IbljKmflyEXoiEYby3nYL1RrQErWyENSIZgmWnBgfNa6ShC20borTMqKhBcgUalekNqsoEbR5+Heapu3h/GAadMavL8Uu1Hn+Ocju/Qv1yJ7n4CaLFNOiJZK7UxqKSU3uleMASjg9aiD56Z2AvkAVnrlHHcMC6dYE622lgDnrlAavLBh9dhwmr3SDrCOAqQFmkUXFNlwVPfSke1ljoiD84ITmryME95mNZ5XardlPFz2u5LOvKrHxe83vQ+hdchY8hrKhA+6RLGfZphDbn6EQDOGtZIxopozac1Vx8RhoQhY8FxSOut3/8kQotN9LCmhFOu9j6/Vr/55ZV0xHkbuHfeea9DiNgyjAyY18wAatAISoAB5RRo5VjQyvdcgW95H0uF1ARL3qot4kE538uoKVihqWLcUseNp4Frbr0B6eR7jtXzWHQ+WKYQJHUYgSrHPXVKSgqy9UboaIwok/yO5BYWzgpgwPN1WTcHGsAiaE6F4i1VznFqXWtob2zvem2xDcXzE6YJx/+A+jCENC9zzNUta9U7dB/XqTw41Za7r8NE/9lm9DiHL5iqMmM/TGW/bmO91OSIflkTHrf3qnsj+7Jc1WF7tiRrHBemJi/Zp7yebmXjGqWFuVwul38BAAD//wMACyupKPQEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUXW/jKBSG/4rFtXEBY2x81013tFGn02ianV3tHYZDiupAhHFnqyr/fYSTqumM9mLvrGPe8/GcF16RV3tAPbo+HH5/Bp8mVKLklhAjTGAiMKFbWvec90RWlJG2IfwfVCJ3Cy+oRy3XmmoJuAYBmBvS4KG2GhsDkhJqCGt4zql2E+pfkXKVgWenoQrTN4iTCx716C/nTfieaytX6THMpophhLWfkvI6N/NlvbrFn6832/vN6dQEUxZXzqAedbrm0AFgYaXFnDYNll1tsZGDZIJJa6w9yZxPEL0aq8k8vdc3IXlIumcVqyuCmUTHEhmVVG55UBNsXw65iwXRTY6XS3j57F/RM0TUs/IN5indlR7d1X4aZjeaqzHsds7vVsFbt5ujSrlwiQ4xHCAmBwuc35xX8eVz2O1yPvRJjROgEm0h7p1X4+nHDVg1j+khzHEhM5mn/zqDeqTmFFCJFpLjuJQtzsOsRgc+/aK9KHz/UGxGlWyI+w9LejixX/8P9HdKPzoPxfoG9YhQYKbuAFtGBeadUVg1tcRC1MIC1bJlFJVoFXxyfg7zVKx9gt2Z2of+rqN+dAl0mmOe6W+RzbaJwcw6Fe8LpqQiVU1IFs3pMKfiKxgXQSfIQ2zjfM73k4QJtog+uRF+wbOaYwSfio1Kj8UfanpEPZKq01RJJZUSWltoCFhiiBKkNSCMAMOZaQ2X3AguiRZcDZQb1dDB5ggqEWSTFYuv684CpR3BkrUK8xYkHngjMWmM0o1iurbtB7jF/Zh1SneEg6mxBGswl1Rhyesam7pRLRO2bZm94HQ2BCWZ+qUJ/5zAnL305WTtt9kNPJ/u8dKnMKYDIyhmnDaYS0lxJ5sWD203yEF00Og82Sr4KbyB/AZxCJNL+RG5c97t1fjzkffN3EL0MF5s587pGKZgU3G2ZfFhX19nn1+xYrHod+fxv4sxboJ+glhkYynnL5Z5PB6PPwAAAP//AwBHon9jDAUAAA==
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUTW/cNhCG/4rAsyjzS/zQzbBb1HVTL+JFWvRGcUa2EC21oKhNA2P/e0DtBol7600Y6J0ZPvPOvJHoD0g6cns8/nLCmBdSkzxuIcGEpkxTxvdcdkp1zDVMOWmF+YfUZHzEr6QjRoXAg0MqUSNVwFrayyFQAHSccWCiVSWnf1lI90b82ACexoDNvHzCtIxzJB35a4wwfym1/diEaV6hSfOED3HJPobSzJ8Pd4/0j9vd/ml3+WvBpYibEUhHbJAKLSLVgxuo4m1LnZUDBdc7oYUbYBgusjFmTNFPzQKff9SHOUfMoRONkA2jwpFzTcBnX1ru/YL7r8fSxYbovsTrLbx9dm/khIl0ov4O85LuJkzjTZ6PE55wOvq0YLoJ8+HgI5CaHNN8xJRH3LBsL50mn8c5Vtdid9OIMZOaPD1Xu8nnYU6Hd6yeLwge/geBE6aedESyVmpjUEkpvdO9YAhGB61FHzwzQy+QB2StU8Zxw7h0gjnZamMNeOYCqcnLNPd++n3Z+DnBegvMCC1QoRNKaxcYSotDa5CB17rXNjiQ1ghlwUrvvOeuRxOcDsUgH3x4HSNWD/ekI4yjAGmRDoJrqix46lvpqNZSD8iDM4KTmtzNMY9xndeleogZX9LGj3TkVz8teCF3m8LrmDHkNRWof+tSbJdmWEOufjiAs4Y1krEiWvNxzdVHhDFhyFjw7tN6zfcfidBiE92tKWHM1c7n1+o3v7wWKt4G7l15qg5hwJbhwIB5zQygBo2gBBhQToFWjgWtfM8V+Jb3Q4mQmmAxXLV5nPUoglWCGi0GqqyQ1AcItDUBNXBtPLB3HKunqeh8sEwhSOpwAKoc99QpKSnI1huhB2NEccZ3JFfzcVYAA54u27p1oAEsguZUKN5S5Ryn1rWG9sb2rtcW21B6fsQUcfoJ1IcxpHmZh1xdvVu9Q/dxjeXiVJuPv4yR/rvN6H4OnzFVZcZ+jGXBrmM91+SAflkTHraD1b2RXdmuar/dLckax4WpyXP2Ka/Ha9i4Rmlhzufz+RsAAAD//wMAolJWbPUEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUS2/bOBD+KwLPpkJKFCUK2IPhtFgjTWMk7u5ibxQ5jInIpEFRToMi/31BWa6dooe9CaN5fY/hD+TkHlCLlofDpyO4OKAFinYKFaTgmHBM6JaWLWMtEXnVkJKX9F+0QPYO3lCLaqYUVQJwCRww06TCXWkU1hoEJVSTomKpp3weUPsDSZtrOFoFuR/+gjBY71CL/rZO+9c0W9pc9X7UefA9rN0QpVNpma/r1R3+stxsHzanrAGGVJxbjVrUqJJBA4C5EQYzWlVYNKXBWnSi4IUw2phTmXURgpN9PuiXy3zto4Oo2iIvypzgQqD3BdIyyrRyJwfYvh3SFhNFtym+mMLTZ/sDHSGgtlicyTy1u1G9vdkP3Wh7fRNleIZogtzDqw8vcJQ9WqBD8AcI0cLEzcNTdlmJkpzkBS8IQQt0L9XOOsjWt9lDnwBL1RAGusQCjMZMUIkFK0usy0rWBTd1XSTAdxAc9Fdd760KfvAmZjPl2Yc5K++idaMfh2ztIjwHGU91n2U/AFqgzdj1dtg9gtRvW/84pn9u7BOW1RgCuJhtZNxlf8phh1okZKOoFFJIyZUyUBEwRBPJSa2Baw6aFbrWTDDNmSCKM9lRpmVFO5MiaIEexngY45n/71dLbIPd70FfNthOHG96GY0P+7UGF62xSZpzxmSovp9QZXPPVW/BxQ8koxYRCoUuG8CmoByzRkssq1JgzktugCpRF/REmLHP40+eiDGalaZqGt6JjhIoTN0wUpuOaGVKJXTVQV3UpG6gEYqQrmK06YQiGmjFdEIXvB5V/NUK5STQ4+jSdWbrBPvVOvydswsjm+CjV75Pgtkent6GCPvfqbby+4MfbEz4zSzttwHuvUt/5/ufOZuLlz5eYpDuIJtOT3ZUdU1dYN5phZksBW50TXHZ1YqKQiqA1P3WqxcIWTKYtG7S5Oyph6dsGdTORlBxDGnyPxOok5yfzydz4SP/+mm78gGWh8Nijv5xTCSdmp0N8OFd+Tak9J0f4hXkGdoT9Oa82JWdNBxPT5VNQa51A5pTXDBaYSYExY2oatzVTSc63kClLnbNHkHbACpO/bZhTNNmZn/ny2WI1kgVh3Q8X7ya7DT7c075dckr2X5Wn4ZfSTdbae5ESbLs0+nhnBz0v97N9/f39/8AAAD//wMAkjOOpigGAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACoxUy27kNhD8FYHXiDLfEnVzbC8ycPzAziAJcmuRLZuxTA0oyt6F4X8PpLHXj0WAXAShSXZVV1f3E4lwj6Qlx/v92QPGPJGS5LCGBBOGMkMZ33HZKtVyXdVMas7s36Qk4Ry/k5bUyjnuLFKJBqnyTNNO9o56j5Yz7pnQaskJNxNpnwiEyuNDcFiN0x+YpjBG0pI/Q/Tj44INoXLDOPsqjQNu4pQhuoXM5ebknP5+fL27uj7cmnBaHlfBk5Y0TipsEKnpbU8V15raRvbU284KI2zv+/7wLMSMKcJQTf7uDd+POWJ2raiErBgVljyXxEOGhXIHE+6+7xcWq0SnS7xcw+tv+0QeMJFWlK9iHtIduSEc3U/dHAZ/tH5JSfZp3GPKAVc1rrbFGwnOKlYJIxgjJbkAdxsiFpvT4mpYSgTXMIVeUou9p8pyoFZJSb3UUAvT17VYSjzHFHF4l/UiuDROY5+LF5GLDzjb45OzCN2AC8YXGCYkJdlM2wzRwzBGPPuGbs6HXLs0L8cnY8whzuM8FZuY8SbBy/nr+5M5JYy5uIZ8W/wG0y1piYXGcbBgAYxzPWqGPfMMDKs9Gm/QK+Frr6zyRlnmjIKOKw+ad/0SISX5ddFwOzuH0/TGZjXJMKwcipc+nQwBY/4gI2kJ4yi8bJD2ghuqGg8UtLTUGGl65M7Wgr/C7CDdYCYt6Zuu65hznVCWOxAWpO+Z9Ka3QtQ1qF7qWgljNKvB+boWXHlZowPZS9YIUpLrNPrZ5c+tlmsDrtP4D7q8SEVaYpjWjYOuE0bxBmyDihvVGIu1VT0wJV0HXDfQdZyBZs42wgE3FlTndf9DpbN4EyKehmk/wPd3uE1lKvmLA2h4D+rT9S8J7vFxTHeXBxtXl2c7UpKvc1w2QrFZLPIYIv1mlom+mIccdrcJwaO/GD3+7CNcxqVYJ5R3EpxWkkqsHVXC1LRzhlENrPNSauSdJCU5Hd0dpmJxGIS4TNWPZFfb4ji525DR5Tkt/P5aeVxti+sBcj+m+w+b5F1hnwWohORs6YzHh8M2Wjka7xv0hlOhuKbKWk4bq2va1U1nO9OgdotiV3Pez7n4ij4kdHmt+MWLK+bJLbq7n8V4dcGLRTlbvLY9bLFV2v+1xJ5Lco8wzQnv123dPpFNjJhW5NP5MIqbeBGGIUzoxugn0hrd6IpJo18Y/uc9I+uKa2Gen5+f/wUAAP//AwBHzZ1MGwYAAA==
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpSUUW/cKBDHv4rFs3EAY2z8Fm1a3SrXy6pd9aq+YWZoUBy8Apw2ivLdT3i3yuXpdC8IjZnhP7/54xcSzCOSkVyfTh+eMOREapL9FhJMKMoUZfzI21HKkXeN0px1SnwnNfG3+ExG0ktrudVIW1RIJbCOTq2zFAA1ZxyY6GSpaX4kMr4Q4xvAJ2+xWdJXjMkvgYzkbx9g+VnuNr6x87JCE5cZ9yFlE2wR89d+d0v/vD4c7w7nUwlTSW48kJEMtpU4IFLltKOSdx3VQ+so6EkLJbQD585pPmSMwcxNgoe3+2HJAbMdRSPahlGhyWtNwGRTJE8m4fH5VFRsiG5KvN7C23Z8IU8YySjq3zDP5a7s7K8e07T6Ga7OazbpIW2rMzYv8ZnU5BSXE8bsceNznRI+TvPz0aSHj+czZZs+/EK7ZoTdsoZMRsJbRWqyAZpnk/0SqovG3ewx5O1jjj4kb/+rVktqcvelOswmuyU+vpvHlzPm/f+g/MnYex+w2t+QkTCOAtoBqRNcUTmAoaZrNVWqVQ651b3gpCa7JWQf1mVN1T5k/BG3lshIPpo54VnfdbT3PqPNayx9flPFV4e4wGpz9TZLzhrWtIyVpDWf1lx9RvARbcbSxDGul3pf36cIJbak3RojhlwdTL6v/jDpnoxEm8Fyo402RlnrsGPoGDCjWA+oQCFIAT1ILUFJzaySZuISTMcnVyKkJlisU53dKmFwTABFzg2Vreup6TpDlbAC5AB66AuTN47V3VzyjB2YRGipRgdUam6olm1Loe1ML5Tre1H4/0Zy8QNnpRjg0/ndbQoUwICgOBWSd1Rqzemgu55O/TDpSQ3Y2aL5FmPA+V+gPnkbl7S4XF0cUr1D93kN5d9RbW756QP9tc3oZrEPGKsyY+NDeSqXsb6+vr7+AwAA//8DAEkVCfaCBAAA
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTwY7cKBD9FYuz8QDG2Pg26tlVWpPstJJRstobpoo0igdaGE8SjfrfV7g7Sia33NCDV/XqveKFBPOEZCS3p9NfzxjyQmqS/QYJJhRlijL+yNtRypF3jdID01r9R2ri7/E7GUkvreVWI21RIZXAOjq1zlIA1JxxYKKTpab5vJDxhRjfAD57i01cPmJafAxkJJ98gPi19Da+sXNcoUlxxn1Ysgm2iPlnv7unb28Pjw+Hy6sFl0JuPJCRDLaVOCBS5bSjkncd1UPrKOhJCyW0A+cuNB8ypmDmZoEvP/tDzAGzHUUj2oZRocm5JmCyKZIns+Dj91NRsVl0V/B6g7fj+EKeMZFR1D/MvJS7sbO/sfHpyQS4cT745UhqckrxhCl73OzYJpxnk30M1bXJbvYYMqnJw4fqMJvsYnp65dGHy+j7P5j8nbFHH7Da35GRMI4C2gGpE1xROYChpms1VapVDrnVveCkJrsYsg9rXJdqHzJ+TptKMpK/zbzgRd9tskef0eY1Fen/qpI1fvN5F6EAjNTkkCKsNlc/7easYU3LyuXDmk9rrt4j+IQ2Y5npMa3X8r9RhBIbabemhCFXB5OP1RuzHMlItBksN9poY5S1DjuGjgEzivWAChSCFNCD1BKU1MwqaSYuwXR8cgUpuku61bZQ0LvJ9SCosb2iEruBGhgstZOVPWNge9e/srV6mAvP2IFJhJZqdECl5oZq2bYU2s70Qrm+FyWOH5ZcE+es+A34fPkamwIFMCAoToXkHZVaczrorqdTP0x6UgN2tmi+xxRw/sWod96muESXq+vCVK+se7+G8r2rbXm++kC/bZHdRfsFU1UiNz6Ubb6mfD6fz/8DAAD//wMAry4kfSUEAAA=
|
||||
@ -0,0 +1,5 @@
|
||||
https://dc.services.visualstudio.com/v2/track
|
||||
Content-Type:application/x-json-stream
|
||||
Content-Encoding:gzip
|
||||
|
||||
H4sIAAAAAAAACpRTS2/cNhD+KwLPosyXKFE3Y52iCzfxIlmkRW8UZxgTlqkFRTkJjP3vAbUbJO6tF4IY8Jv5HsNXEu0zkoHcnk7vXjDmhdQkh60kmNCUacr4kctBqYG3jTad1Fz8S2oS7vE7GUinnOPOIJWokSpgLR2ldxQADWccmGhV6Wm/LGR4JTY0gC/BYTMvnzEtYY5kIH+HCPPXMtuGxk3zCk2aJ9zHJdvoCpkP+909/ev2cHw4XF4tuBRwE4AMpHdSYY9ItTeeKt621PTSUzCjEVoYD95fYCFmTNFOzQJPv+bDnCNmN4hGyIZRYci5JmCzLZRHu+Dx+6mw2Cy6K/V6K2/X4ZW8YCKDqH+aeWl346Zw87yMa5jg5nJmuzwVlac0nzDlgJsnm8xpsjnMsbpO2k0BYyY1efhUHSab/Zye3xj16aJ//z/kH8v0d9/QrRlhN68xk4FwaUhN3lv3GCJW+zsyEMZRgOyResE1VT1YaltpqNZSe+TOdIKTmuzmmENc53Wp9jHjl7QJIAP5w04LXqjfJvcYMrq8pqLqH1124ZBmWF2ufvnPWcMayVgBrfm05uojQkjoMhZ9x7Re+/0HIrTYQLs1JYy5Otj8WP1pl0cyEGN7x62xxlrtnMeWoWfArGYdoAaNoAR0oIwCrQxzWtmRK7AtH32pkJpgibvaNsxbBcIqR1s7Mqp639PeW0cVWt9p7FCq/o2P1cNUcNb1TCFIatADVYZbapSUFGRrO6F914kSzU9LrulzVgwGfLn8lY2BBugRNKdC8ZYqYzjtTdvRsetHM+oeW1c432OKOP1m1Pvg0rzMPlfX5aneWPdxjeW/V9sifQ2RftsyupvdE6aqZGxDLOt9jfV8Pp9/AAAA//8DAOIvUl42BAAA
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
88
PlotLine/Controllers/ScenariosController.cs
Normal file
88
PlotLine/Controllers/ScenariosController.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PlotLine.Services;
|
||||
using PlotLine.ViewModels;
|
||||
|
||||
namespace PlotLine.Controllers;
|
||||
|
||||
public sealed class ScenariosController(IScenarioService scenarios) : Controller
|
||||
{
|
||||
public async Task<IActionResult> Index(int projectId)
|
||||
{
|
||||
var model = await scenarios.ListAsync(projectId);
|
||||
return model is null ? NotFound() : View(model);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Create(int projectId, int? bookId)
|
||||
{
|
||||
var model = await scenarios.GetCreateAsync(projectId, bookId);
|
||||
return model is null ? NotFound() : View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Create(ScenarioCreateViewModel model)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(model.ScenarioName))
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.ScenarioName), "Scenario name is required.");
|
||||
var repopulated = await scenarios.GetCreateAsync(model.ProjectID, model.BookID);
|
||||
model.BookOptions = repopulated?.BookOptions ?? [];
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var scenarioId = await scenarios.CreateAsync(model);
|
||||
return RedirectToAction(nameof(Timeline), new { id = scenarioId });
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Timeline(int id)
|
||||
{
|
||||
var model = await scenarios.GetTimelineAsync(id);
|
||||
return model is null ? NotFound() : View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> MoveScene(int scenarioId, int sceneId, int? anchorSceneId, int? targetChapterId, string position)
|
||||
{
|
||||
await scenarios.MoveSceneAsync(scenarioId, sceneId, anchorSceneId, targetChapterId, position);
|
||||
return RedirectToAction(nameof(Timeline), new { id = scenarioId });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Validate(int id)
|
||||
{
|
||||
var warningCount = await scenarios.ValidateAsync(id);
|
||||
TempData["ScenarioMessage"] = $"Scenario validation found {warningCount} warning{(warningCount == 1 ? "" : "s")}.";
|
||||
return RedirectToAction(nameof(Timeline), new { id });
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Compare(int id)
|
||||
{
|
||||
var model = await scenarios.CompareAsync(id);
|
||||
return model is null ? NotFound() : View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Apply(int id, string confirmation)
|
||||
{
|
||||
if (!string.Equals(confirmation, "This will replace the current scene order with the scenario order. Continue?", StringComparison.Ordinal))
|
||||
{
|
||||
TempData["ScenarioMessage"] = "Scenario was not applied. Use the exact confirmation text.";
|
||||
return RedirectToAction(nameof(Compare), new { id });
|
||||
}
|
||||
|
||||
await scenarios.ApplyAsync(id);
|
||||
TempData["ScenarioMessage"] = "Scenario applied to the main story order.";
|
||||
return RedirectToAction(nameof(Timeline), new { id });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Archive(int id, int projectId)
|
||||
{
|
||||
await scenarios.ArchiveAsync(id);
|
||||
return RedirectToAction(nameof(Index), new { projectId });
|
||||
}
|
||||
}
|
||||
@ -233,6 +233,19 @@ public interface IDynamicsRepository
|
||||
Task RunContinuityChecksAsync(int projectId, int? bookId, int? sceneId);
|
||||
}
|
||||
|
||||
public interface IScenarioRepository
|
||||
{
|
||||
Task<IReadOnlyList<Scenario>> ListAsync(int projectId);
|
||||
Task<Scenario?> GetAsync(int scenarioId);
|
||||
Task<int> CreateAsync(int projectId, int? bookId, string scenarioName, string? description);
|
||||
Task<(IReadOnlyList<Book> Books, IReadOnlyList<Chapter> Chapters, IReadOnlyList<ScenarioScene> Scenes, IReadOnlyList<ScenarioWarning> Warnings)> GetTimelineAsync(int scenarioId);
|
||||
Task MoveSceneAsync(int scenarioId, int sceneId, int? anchorSceneId, int? targetChapterId, string position);
|
||||
Task<int> ValidateAsync(int scenarioId);
|
||||
Task<(IReadOnlyList<ScenarioComparisonRow> MovedScenes, IReadOnlyList<ScenarioWarning> Warnings)> CompareAsync(int scenarioId);
|
||||
Task ApplyAsync(int scenarioId);
|
||||
Task ArchiveAsync(int scenarioId);
|
||||
}
|
||||
|
||||
public sealed class TimelineData
|
||||
{
|
||||
public Project? Project { get; init; }
|
||||
@ -895,6 +908,76 @@ public sealed class DynamicsRepository(ISqlConnectionFactory connectionFactory)
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ScenarioRepository(ISqlConnectionFactory connectionFactory) : IScenarioRepository
|
||||
{
|
||||
public async Task<IReadOnlyList<Scenario>> ListAsync(int projectId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
var rows = await connection.QueryAsync<Scenario>("dbo.Scenario_List", new { ProjectID = projectId }, commandType: CommandType.StoredProcedure);
|
||||
return rows.ToList();
|
||||
}
|
||||
|
||||
public async Task<Scenario?> GetAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
return await connection.QuerySingleOrDefaultAsync<Scenario>("dbo.Scenario_Get", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
|
||||
public async Task<int> CreateAsync(int projectId, int? bookId, string scenarioName, string? description)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
return await connection.QuerySingleAsync<int>(
|
||||
"dbo.Scenario_Create",
|
||||
new { ProjectID = projectId, BookID = bookId, ScenarioName = scenarioName, Description = description },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyList<Book> Books, IReadOnlyList<Chapter> Chapters, IReadOnlyList<ScenarioScene> Scenes, IReadOnlyList<ScenarioWarning> Warnings)> GetTimelineAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
using var result = await connection.QueryMultipleAsync("dbo.Scenario_Timeline", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
return (
|
||||
(await result.ReadAsync<Book>()).ToList(),
|
||||
(await result.ReadAsync<Chapter>()).ToList(),
|
||||
(await result.ReadAsync<ScenarioScene>()).ToList(),
|
||||
(await result.ReadAsync<ScenarioWarning>()).ToList());
|
||||
}
|
||||
|
||||
public async Task MoveSceneAsync(int scenarioId, int sceneId, int? anchorSceneId, int? targetChapterId, string position)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
await connection.ExecuteAsync(
|
||||
"dbo.Scenario_MoveScene",
|
||||
new { ScenarioID = scenarioId, SceneID = sceneId, AnchorSceneID = anchorSceneId, TargetChapterID = targetChapterId, Position = position },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
|
||||
public async Task<int> ValidateAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
return await connection.QuerySingleAsync<int>("dbo.Scenario_Validate", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyList<ScenarioComparisonRow> MovedScenes, IReadOnlyList<ScenarioWarning> Warnings)> CompareAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
using var result = await connection.QueryMultipleAsync("dbo.Scenario_Compare", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
return ((await result.ReadAsync<ScenarioComparisonRow>()).ToList(), (await result.ReadAsync<ScenarioWarning>()).ToList());
|
||||
}
|
||||
|
||||
public async Task ApplyAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
await connection.ExecuteAsync("dbo.Scenario_ApplyToMain", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
|
||||
public async Task ArchiveAsync(int scenarioId)
|
||||
{
|
||||
using var connection = connectionFactory.CreateConnection();
|
||||
await connection.ExecuteAsync("dbo.Scenario_Archive", new { ScenarioID = scenarioId }, commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SceneDependencyRepository(ISqlConnectionFactory connectionFactory) : ISceneDependencyRepository
|
||||
{
|
||||
public async Task<SceneDependencyLookupData> GetLookupsAsync()
|
||||
|
||||
@ -1426,6 +1426,73 @@ public sealed class DynamicsIssue
|
||||
public string? EntityType { get; set; }
|
||||
}
|
||||
|
||||
public sealed class Scenario
|
||||
{
|
||||
public int ScenarioID { get; set; }
|
||||
public int ProjectID { get; set; }
|
||||
public int? BookID { get; set; }
|
||||
public string ScenarioName { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public DateTime BaseCreatedDate { get; set; }
|
||||
public bool IsAppliedToMain { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime UpdatedDate { get; set; }
|
||||
public string ProjectName { get; set; } = string.Empty;
|
||||
public string? BookTitle { get; set; }
|
||||
public int SceneCount { get; set; }
|
||||
public int WarningCount { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ScenarioScene
|
||||
{
|
||||
public int ScenarioSceneOrderID { get; set; }
|
||||
public int ScenarioID { get; set; }
|
||||
public int SceneID { get; set; }
|
||||
public int OriginalChapterID { get; set; }
|
||||
public int ProposedChapterID { get; set; }
|
||||
public int ProposedSortOrder { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public decimal ChapterNumber { get; set; }
|
||||
public string ChapterTitle { get; set; } = string.Empty;
|
||||
public decimal SceneNumber { get; set; }
|
||||
public string SceneTitle { get; set; } = string.Empty;
|
||||
public string? Summary { get; set; }
|
||||
public string RevisionStatusName { get; set; } = string.Empty;
|
||||
public string TimeLabel { get; set; } = string.Empty;
|
||||
public string? ThreadLabels { get; set; }
|
||||
public string? AssetLabels { get; set; }
|
||||
public string? CharacterLabels { get; set; }
|
||||
public string? LocationLabel { get; set; }
|
||||
public int WarningCount { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ScenarioWarning
|
||||
{
|
||||
public int ScenarioWarningID { get; set; }
|
||||
public int ScenarioValidationRunID { get; set; }
|
||||
public int ScenarioID { get; set; }
|
||||
public int? SceneID { get; set; }
|
||||
public string EntityType { get; set; } = string.Empty;
|
||||
public int? EntityID { get; set; }
|
||||
public string WarningTypeName { get; set; } = string.Empty;
|
||||
public string SeverityName { get; set; } = "Info";
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public string? Details { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ScenarioComparisonRow
|
||||
{
|
||||
public int SceneID { get; set; }
|
||||
public string SceneTitle { get; set; } = string.Empty;
|
||||
public string MainPosition { get; set; } = string.Empty;
|
||||
public string ScenarioPosition { get; set; } = string.Empty;
|
||||
public int MainIndex { get; set; }
|
||||
public int ScenarioIndex { get; set; }
|
||||
public bool HasMoved { get; set; }
|
||||
}
|
||||
|
||||
public sealed class AnalyticsBusyScene
|
||||
{
|
||||
public int SceneID { get; set; }
|
||||
|
||||
@ -36,6 +36,7 @@ public class Program
|
||||
builder.Services.AddScoped<IWriterWorkspaceRepository, WriterWorkspaceRepository>();
|
||||
builder.Services.AddScoped<IExportRepository, ExportRepository>();
|
||||
builder.Services.AddScoped<IDynamicsRepository, DynamicsRepository>();
|
||||
builder.Services.AddScoped<IScenarioRepository, ScenarioRepository>();
|
||||
builder.Services.AddScoped<IProjectService, ProjectService>();
|
||||
builder.Services.AddScoped<IBookService, BookService>();
|
||||
builder.Services.AddScoped<IChapterService, ChapterService>();
|
||||
@ -51,6 +52,7 @@ public class Program
|
||||
builder.Services.AddScoped<IWriterWorkspaceService, WriterWorkspaceService>();
|
||||
builder.Services.AddScoped<IExportService, ExportService>();
|
||||
builder.Services.AddScoped<IDynamicsService, DynamicsService>();
|
||||
builder.Services.AddScoped<IScenarioService, ScenarioService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
@ -187,6 +187,19 @@ public interface IDynamicsService
|
||||
Task RunContinuityChecksAsync(int projectId, int? bookId, int? sceneId);
|
||||
}
|
||||
|
||||
public interface IScenarioService
|
||||
{
|
||||
Task<ScenarioListViewModel?> ListAsync(int projectId);
|
||||
Task<ScenarioCreateViewModel?> GetCreateAsync(int projectId, int? bookId);
|
||||
Task<int> CreateAsync(ScenarioCreateViewModel model);
|
||||
Task<ScenarioTimelineViewModel?> GetTimelineAsync(int scenarioId);
|
||||
Task MoveSceneAsync(int scenarioId, int sceneId, int? anchorSceneId, int? targetChapterId, string position);
|
||||
Task<int> ValidateAsync(int scenarioId);
|
||||
Task<ScenarioCompareViewModel?> CompareAsync(int scenarioId);
|
||||
Task ApplyAsync(int scenarioId);
|
||||
Task ArchiveAsync(int scenarioId);
|
||||
}
|
||||
|
||||
public sealed class ProjectService(IProjectRepository projects, IBookRepository books) : IProjectService
|
||||
{
|
||||
public Task<IReadOnlyList<Project>> ListAsync() => projects.ListAsync();
|
||||
@ -2287,6 +2300,108 @@ public sealed class DynamicsService(IProjectRepository projects, IDynamicsReposi
|
||||
dynamics.RunContinuityChecksAsync(projectId, bookId, sceneId);
|
||||
}
|
||||
|
||||
public sealed class ScenarioService(IProjectRepository projects, IBookRepository books, IScenarioRepository scenarios, IContinuityValidationService validation) : IScenarioService
|
||||
{
|
||||
public async Task<ScenarioListViewModel?> ListAsync(int projectId)
|
||||
{
|
||||
var project = await projects.GetAsync(projectId);
|
||||
return project is null ? null : new ScenarioListViewModel
|
||||
{
|
||||
Project = project,
|
||||
Scenarios = await scenarios.ListAsync(projectId)
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ScenarioCreateViewModel?> GetCreateAsync(int projectId, int? bookId)
|
||||
{
|
||||
var project = await projects.GetAsync(projectId);
|
||||
if (project is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ScenarioCreateViewModel
|
||||
{
|
||||
ProjectID = projectId,
|
||||
BookID = bookId,
|
||||
BookOptions = (await books.ListByProjectAsync(projectId))
|
||||
.Select(x => new SelectListItem($"Book {x.BookNumber}: {x.BookTitle}", x.BookID.ToString(), x.BookID == bookId))
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public Task<int> CreateAsync(ScenarioCreateViewModel model) =>
|
||||
scenarios.CreateAsync(model.ProjectID, model.BookID, model.ScenarioName, model.Description);
|
||||
|
||||
public async Task<ScenarioTimelineViewModel?> GetTimelineAsync(int scenarioId)
|
||||
{
|
||||
var scenario = await scenarios.GetAsync(scenarioId);
|
||||
if (scenario is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var project = await projects.GetAsync(scenario.ProjectID);
|
||||
if (project is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = await scenarios.GetTimelineAsync(scenarioId);
|
||||
return new ScenarioTimelineViewModel
|
||||
{
|
||||
Project = project,
|
||||
Scenario = scenario,
|
||||
Books = data.Books,
|
||||
Chapters = data.Chapters,
|
||||
Scenes = data.Scenes,
|
||||
Warnings = data.Warnings,
|
||||
ChapterOptions = data.Chapters.Select(x => new SelectListItem($"Ch {x.ChapterNumber:g}: {x.ChapterTitle}", x.ChapterID.ToString())).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public Task MoveSceneAsync(int scenarioId, int sceneId, int? anchorSceneId, int? targetChapterId, string position) =>
|
||||
scenarios.MoveSceneAsync(scenarioId, sceneId, anchorSceneId, targetChapterId, position);
|
||||
|
||||
public Task<int> ValidateAsync(int scenarioId) => scenarios.ValidateAsync(scenarioId);
|
||||
|
||||
public async Task<ScenarioCompareViewModel?> CompareAsync(int scenarioId)
|
||||
{
|
||||
var scenario = await scenarios.GetAsync(scenarioId);
|
||||
if (scenario is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var project = await projects.GetAsync(scenario.ProjectID);
|
||||
if (project is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = await scenarios.CompareAsync(scenarioId);
|
||||
return new ScenarioCompareViewModel
|
||||
{
|
||||
Project = project,
|
||||
Scenario = scenario,
|
||||
MovedScenes = data.MovedScenes,
|
||||
ScenarioWarnings = data.Warnings
|
||||
};
|
||||
}
|
||||
|
||||
public async Task ApplyAsync(int scenarioId)
|
||||
{
|
||||
var scenario = await scenarios.GetAsync(scenarioId);
|
||||
await scenarios.ApplyAsync(scenarioId);
|
||||
if (scenario is not null)
|
||||
{
|
||||
await validation.ValidateProjectAsync(scenario.ProjectID);
|
||||
}
|
||||
}
|
||||
|
||||
public Task ArchiveAsync(int scenarioId) => scenarios.ArchiveAsync(scenarioId);
|
||||
}
|
||||
|
||||
public sealed class AssetService(IProjectRepository projects, IAssetRepository assets, ILocationRepository locations) : IAssetService
|
||||
{
|
||||
public async Task<StoryAssetListViewModel?> GetAssetsAsync(int projectId)
|
||||
|
||||
493
PlotLine/Sql/019_Phase1S_Scenarios.sql
Normal file
493
PlotLine/Sql/019_Phase1S_Scenarios.sql
Normal file
@ -0,0 +1,493 @@
|
||||
SET ANSI_NULLS ON;
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON;
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'dbo.Scenarios', N'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE dbo.Scenarios
|
||||
(
|
||||
ScenarioID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Scenarios PRIMARY KEY,
|
||||
ProjectID int NOT NULL,
|
||||
BookID int NULL,
|
||||
ScenarioName nvarchar(200) NOT NULL,
|
||||
Description nvarchar(max) NULL,
|
||||
BaseCreatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_BaseCreatedDate DEFAULT SYSUTCDATETIME(),
|
||||
IsAppliedToMain bit NOT NULL CONSTRAINT DF_Scenarios_IsAppliedToMain DEFAULT 0,
|
||||
IsArchived bit NOT NULL CONSTRAINT DF_Scenarios_IsArchived DEFAULT 0,
|
||||
CreatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_CreatedDate DEFAULT SYSUTCDATETIME(),
|
||||
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_Scenarios_UpdatedDate DEFAULT SYSUTCDATETIME(),
|
||||
CONSTRAINT FK_Scenarios_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
|
||||
CONSTRAINT FK_Scenarios_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID)
|
||||
);
|
||||
END;
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'dbo.ScenarioSceneOrder', N'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE dbo.ScenarioSceneOrder
|
||||
(
|
||||
ScenarioSceneOrderID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioSceneOrder PRIMARY KEY,
|
||||
ScenarioID int NOT NULL,
|
||||
SceneID int NOT NULL,
|
||||
ProposedChapterID int NULL,
|
||||
ProposedSortOrder int NOT NULL,
|
||||
Notes nvarchar(max) NULL,
|
||||
CreatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioSceneOrder_CreatedDate DEFAULT SYSUTCDATETIME(),
|
||||
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioSceneOrder_UpdatedDate DEFAULT SYSUTCDATETIME(),
|
||||
CONSTRAINT FK_ScenarioSceneOrder_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID),
|
||||
CONSTRAINT FK_ScenarioSceneOrder_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
|
||||
CONSTRAINT FK_ScenarioSceneOrder_Chapters FOREIGN KEY (ProposedChapterID) REFERENCES dbo.Chapters(ChapterID),
|
||||
CONSTRAINT UQ_ScenarioSceneOrder_ScenarioScene UNIQUE (ScenarioID, SceneID)
|
||||
);
|
||||
END;
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'dbo.ScenarioValidationRuns', N'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE dbo.ScenarioValidationRuns
|
||||
(
|
||||
ScenarioValidationRunID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioValidationRuns PRIMARY KEY,
|
||||
ScenarioID int NOT NULL,
|
||||
StartedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioValidationRuns_StartedDate DEFAULT SYSUTCDATETIME(),
|
||||
CompletedDate datetime2 NULL,
|
||||
WarningCount int NOT NULL CONSTRAINT DF_ScenarioValidationRuns_WarningCount DEFAULT 0,
|
||||
CONSTRAINT FK_ScenarioValidationRuns_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID)
|
||||
);
|
||||
END;
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'dbo.ScenarioWarnings', N'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE dbo.ScenarioWarnings
|
||||
(
|
||||
ScenarioWarningID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ScenarioWarnings PRIMARY KEY,
|
||||
ScenarioValidationRunID int NOT NULL,
|
||||
ScenarioID int NOT NULL,
|
||||
SceneID int NULL,
|
||||
EntityType nvarchar(80) NOT NULL,
|
||||
EntityID int NULL,
|
||||
WarningTypeName nvarchar(150) NOT NULL,
|
||||
SeverityName nvarchar(50) NOT NULL,
|
||||
Message nvarchar(500) NOT NULL,
|
||||
Details nvarchar(max) NULL,
|
||||
CreatedDate datetime2 NOT NULL CONSTRAINT DF_ScenarioWarnings_CreatedDate DEFAULT SYSUTCDATETIME(),
|
||||
CONSTRAINT FK_ScenarioWarnings_Runs FOREIGN KEY (ScenarioValidationRunID) REFERENCES dbo.ScenarioValidationRuns(ScenarioValidationRunID),
|
||||
CONSTRAINT FK_ScenarioWarnings_Scenarios FOREIGN KEY (ScenarioID) REFERENCES dbo.Scenarios(ScenarioID),
|
||||
CONSTRAINT FK_ScenarioWarnings_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID)
|
||||
);
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_List
|
||||
@ProjectID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
SELECT sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
||||
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate,
|
||||
p.ProjectName, b.BookTitle,
|
||||
COUNT(DISTINCT sso.SceneID) AS SceneCount,
|
||||
COUNT(DISTINCT sw.ScenarioWarningID) AS WarningCount
|
||||
FROM dbo.Scenarios sc
|
||||
INNER JOIN dbo.Projects p ON p.ProjectID = sc.ProjectID
|
||||
LEFT JOIN dbo.Books b ON b.BookID = sc.BookID
|
||||
LEFT JOIN dbo.ScenarioSceneOrder sso ON sso.ScenarioID = sc.ScenarioID
|
||||
LEFT JOIN dbo.ScenarioWarnings sw ON sw.ScenarioID = sc.ScenarioID
|
||||
WHERE sc.ProjectID = @ProjectID AND sc.IsArchived = 0
|
||||
GROUP BY sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
||||
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate, p.ProjectName, b.BookTitle
|
||||
ORDER BY sc.UpdatedDate DESC, sc.ScenarioName;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Get
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
SELECT sc.ScenarioID, sc.ProjectID, sc.BookID, sc.ScenarioName, sc.Description, sc.BaseCreatedDate,
|
||||
sc.IsAppliedToMain, sc.IsArchived, sc.CreatedDate, sc.UpdatedDate,
|
||||
p.ProjectName, b.BookTitle,
|
||||
(SELECT COUNT(*) FROM dbo.ScenarioSceneOrder WHERE ScenarioID = sc.ScenarioID) AS SceneCount,
|
||||
(SELECT COUNT(*) FROM dbo.ScenarioWarnings WHERE ScenarioID = sc.ScenarioID) AS WarningCount
|
||||
FROM dbo.Scenarios sc
|
||||
INNER JOIN dbo.Projects p ON p.ProjectID = sc.ProjectID
|
||||
LEFT JOIN dbo.Books b ON b.BookID = sc.BookID
|
||||
WHERE sc.ScenarioID = @ScenarioID AND sc.IsArchived = 0;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Create
|
||||
@ProjectID int,
|
||||
@BookID int = NULL,
|
||||
@ScenarioName nvarchar(200),
|
||||
@Description nvarchar(max) = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
INSERT dbo.Scenarios (ProjectID, BookID, ScenarioName, Description)
|
||||
VALUES (@ProjectID, @BookID, @ScenarioName, @Description);
|
||||
|
||||
DECLARE @ScenarioID int = CAST(SCOPE_IDENTITY() AS int);
|
||||
|
||||
INSERT dbo.ScenarioSceneOrder (ScenarioID, SceneID, ProposedChapterID, ProposedSortOrder)
|
||||
SELECT @ScenarioID, nso.SceneID, nso.ChapterID,
|
||||
ROW_NUMBER() OVER (ORDER BY nso.GlobalSceneIndex) * 10
|
||||
FROM dbo.NarrativeSceneOrder nso
|
||||
WHERE nso.ProjectID = @ProjectID AND (@BookID IS NULL OR nso.BookID = @BookID)
|
||||
ORDER BY nso.GlobalSceneIndex;
|
||||
|
||||
SELECT @ScenarioID;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Timeline
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @ProjectID int = (SELECT ProjectID FROM dbo.Scenarios WHERE ScenarioID = @ScenarioID);
|
||||
DECLARE @BookID int = (SELECT BookID FROM dbo.Scenarios WHERE ScenarioID = @ScenarioID);
|
||||
|
||||
SELECT BookID, ProjectID, BookTitle, BookNumber, Description, SortOrder, CreatedDate, UpdatedDate, IsArchived
|
||||
FROM dbo.Books
|
||||
WHERE ProjectID = @ProjectID AND IsArchived = 0 AND (@BookID IS NULL OR BookID = @BookID)
|
||||
ORDER BY SortOrder, BookNumber;
|
||||
|
||||
SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, c.Summary, c.SortOrder,
|
||||
c.RevisionStatusID, rs.StatusName AS RevisionStatusName, c.CreatedDate, c.UpdatedDate, c.IsArchived
|
||||
FROM dbo.Chapters c
|
||||
INNER JOIN dbo.Books b ON b.BookID = c.BookID
|
||||
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID
|
||||
WHERE b.ProjectID = @ProjectID AND c.IsArchived = 0 AND b.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
|
||||
ORDER BY b.SortOrder, c.SortOrder, c.ChapterNumber;
|
||||
|
||||
SELECT sso.ScenarioSceneOrderID, sso.ScenarioID, sso.SceneID, s.ChapterID AS OriginalChapterID,
|
||||
ISNULL(sso.ProposedChapterID, s.ChapterID) AS ProposedChapterID, sso.ProposedSortOrder, sso.Notes,
|
||||
ch.ChapterNumber, ch.ChapterTitle, s.SceneNumber, s.SceneTitle, s.Summary, rs.StatusName AS RevisionStatusName,
|
||||
COALESCE(NULLIF(s.RelativeTimeText, N''), CONVERT(nvarchar(20), s.StartDateTime, 106), tm.TimeModeName) AS TimeLabel,
|
||||
threadData.ThreadLabels, assetData.AssetLabels, characterData.CharacterLabels, loc.LocationPath AS LocationLabel,
|
||||
(SELECT COUNT(*) FROM dbo.ScenarioWarnings sw WHERE sw.ScenarioID = @ScenarioID AND sw.SceneID = s.SceneID) AS WarningCount
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
|
||||
INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
|
||||
LEFT JOIN dbo.LocationPaths loc ON loc.LocationID = s.PrimaryLocationID
|
||||
OUTER APPLY
|
||||
(
|
||||
SELECT STRING_AGG(CONVERT(nvarchar(max), pt.ThreadTitle), N', ') AS ThreadLabels
|
||||
FROM dbo.ThreadEvents te INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
|
||||
WHERE te.SceneID = s.SceneID
|
||||
) threadData
|
||||
OUTER APPLY
|
||||
(
|
||||
SELECT STRING_AGG(CONVERT(nvarchar(max), sa.AssetName), N', ') AS AssetLabels
|
||||
FROM dbo.AssetEvents ae INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID
|
||||
WHERE ae.SceneID = s.SceneID
|
||||
) assetData
|
||||
OUTER APPLY
|
||||
(
|
||||
SELECT STRING_AGG(CONVERT(nvarchar(max), c.CharacterName), N', ') AS CharacterLabels
|
||||
FROM dbo.SceneCharacters sc INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
|
||||
WHERE sc.SceneID = s.SceneID
|
||||
) characterData
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
ORDER BY ch.SortOrder, ch.ChapterNumber, sso.ProposedSortOrder, s.SceneID;
|
||||
|
||||
SELECT ScenarioWarningID, ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details, CreatedDate
|
||||
FROM dbo.ScenarioWarnings
|
||||
WHERE ScenarioID = @ScenarioID
|
||||
ORDER BY CASE SeverityName WHEN N'Critical' THEN 4 WHEN N'Warning' THEN 3 WHEN N'Info' THEN 2 ELSE 1 END DESC, CreatedDate DESC;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_MoveScene
|
||||
@ScenarioID int,
|
||||
@SceneID int,
|
||||
@AnchorSceneID int = NULL,
|
||||
@TargetChapterID int = NULL,
|
||||
@Position nvarchar(20)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @ChapterID int;
|
||||
DECLARE @NewSortOrder int;
|
||||
DECLARE @AnchorSortOrder int;
|
||||
|
||||
IF @AnchorSceneID IS NOT NULL
|
||||
BEGIN
|
||||
SELECT @ChapterID = ISNULL(ProposedChapterID, s.ChapterID), @AnchorSortOrder = ProposedSortOrder
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
WHERE sso.ScenarioID = @ScenarioID AND sso.SceneID = @AnchorSceneID;
|
||||
|
||||
IF @Position = N'Before'
|
||||
SELECT @NewSortOrder = ISNULL(MAX(ProposedSortOrder), @AnchorSortOrder - 20) + ((@AnchorSortOrder - ISNULL(MAX(ProposedSortOrder), @AnchorSortOrder - 20)) / 2)
|
||||
FROM dbo.ScenarioSceneOrder
|
||||
WHERE ScenarioID = @ScenarioID AND ISNULL(ProposedChapterID, 0) = ISNULL(@ChapterID, 0) AND ProposedSortOrder < @AnchorSortOrder;
|
||||
ELSE
|
||||
SELECT @NewSortOrder = (@AnchorSortOrder + ISNULL(MIN(ProposedSortOrder), @AnchorSortOrder + 20)) / 2
|
||||
FROM dbo.ScenarioSceneOrder
|
||||
WHERE ScenarioID = @ScenarioID AND ISNULL(ProposedChapterID, 0) = ISNULL(@ChapterID, 0) AND ProposedSortOrder > @AnchorSortOrder;
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
SET @ChapterID = @TargetChapterID;
|
||||
SELECT @NewSortOrder = ISNULL(MAX(ProposedSortOrder), 0) + 10
|
||||
FROM dbo.ScenarioSceneOrder
|
||||
WHERE ScenarioID = @ScenarioID AND ProposedChapterID = @ChapterID;
|
||||
END;
|
||||
|
||||
UPDATE dbo.ScenarioSceneOrder
|
||||
SET ProposedChapterID = @ChapterID,
|
||||
ProposedSortOrder = ISNULL(@NewSortOrder, ProposedSortOrder),
|
||||
UpdatedDate = SYSUTCDATETIME()
|
||||
WHERE ScenarioID = @ScenarioID AND SceneID = @SceneID;
|
||||
|
||||
;WITH ordered AS
|
||||
(
|
||||
SELECT ScenarioSceneOrderID,
|
||||
ROW_NUMBER() OVER (PARTITION BY ProposedChapterID ORDER BY ProposedSortOrder, ScenarioSceneOrderID) * 10 AS NextSortOrder
|
||||
FROM dbo.ScenarioSceneOrder
|
||||
WHERE ScenarioID = @ScenarioID
|
||||
)
|
||||
UPDATE sso
|
||||
SET ProposedSortOrder = ordered.NextSortOrder,
|
||||
UpdatedDate = SYSUTCDATETIME()
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN ordered ON ordered.ScenarioSceneOrderID = sso.ScenarioSceneOrderID;
|
||||
|
||||
UPDATE dbo.Scenarios SET UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @ScenarioID;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Validate
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DELETE FROM dbo.ScenarioWarnings WHERE ScenarioID = @ScenarioID;
|
||||
|
||||
INSERT dbo.ScenarioValidationRuns (ScenarioID)
|
||||
VALUES (@ScenarioID);
|
||||
|
||||
DECLARE @RunID int = CAST(SCOPE_IDENTITY() AS int);
|
||||
|
||||
;WITH ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID, sso.ScenarioID, ISNULL(sso.ProposedChapterID, s.ChapterID) AS ChapterID,
|
||||
ch.BookID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
||||
s.SceneTitle, s.StartDateTime
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
)
|
||||
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
||||
SELECT @RunID, @ScenarioID, targetScene.SceneID, N'SceneDependency', sd.SceneDependencyID, N'Scene Dependency Broken', N'Warning',
|
||||
N'Scenario warning: a required scene dependency is out of order.',
|
||||
CONCAT(sourceScene.SceneTitle, N' should occur before ', targetScene.SceneTitle, N'.')
|
||||
FROM dbo.SceneDependencies sd
|
||||
INNER JOIN dbo.SceneDependencyTypes sdt ON sdt.SceneDependencyTypeID = sd.SceneDependencyTypeID
|
||||
INNER JOIN ScenarioOrder sourceScene ON sourceScene.SceneID = sd.SourceSceneID
|
||||
INNER JOIN ScenarioOrder targetScene ON targetScene.SceneID = sd.TargetSceneID
|
||||
WHERE sd.IsArchived = 0 AND sdt.TypeName = N'Must Occur Before' AND sourceScene.ScenarioIndex >= targetScene.ScenarioIndex;
|
||||
|
||||
;WITH ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID, sso.ScenarioID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
||||
s.SceneTitle, s.StartDateTime
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
)
|
||||
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
||||
SELECT @RunID, @ScenarioID, later.SceneID, N'Scene', later.SceneID, N'Date / Order Conflict', N'Info',
|
||||
N'Scenario warning: an exact scene date appears earlier than a previous scenario scene.',
|
||||
CONCAT(later.SceneTitle, N' is dated before ', earlier.SceneTitle, N'.')
|
||||
FROM ScenarioOrder earlier
|
||||
INNER JOIN ScenarioOrder later ON later.ScenarioIndex = earlier.ScenarioIndex + 1
|
||||
WHERE earlier.StartDateTime IS NOT NULL AND later.StartDateTime IS NOT NULL AND later.StartDateTime < earlier.StartDateTime;
|
||||
|
||||
;WITH ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
),
|
||||
ThreadEventsOrdered AS
|
||||
(
|
||||
SELECT te.PlotThreadID, te.ThreadEventID, te.SceneID, pt.ThreadTitle, tet.TypeName,
|
||||
so.ScenarioIndex,
|
||||
MIN(CASE WHEN tet.TypeName LIKE N'%Setup%' THEN so.ScenarioIndex END) OVER (PARTITION BY te.PlotThreadID) AS FirstSetupIndex
|
||||
FROM dbo.ThreadEvents te
|
||||
INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
|
||||
INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
|
||||
INNER JOIN ScenarioOrder so ON so.SceneID = te.SceneID
|
||||
)
|
||||
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
||||
SELECT @RunID, @ScenarioID, SceneID, N'PlotThread', PlotThreadID, N'Plot Thread Order', N'Warning',
|
||||
N'Scenario warning: a reveal or payoff may occur before its setup.',
|
||||
CONCAT(ThreadTitle, N' has ', TypeName, N' before the first setup beat.')
|
||||
FROM ThreadEventsOrdered
|
||||
WHERE (TypeName LIKE N'%Reveal%' OR TypeName LIKE N'%Payoff%')
|
||||
AND FirstSetupIndex IS NOT NULL AND ScenarioIndex < FirstSetupIndex;
|
||||
|
||||
;WITH ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
),
|
||||
AssetFirstSeen AS
|
||||
(
|
||||
SELECT ae.StoryAssetID, MIN(so.ScenarioIndex) AS FirstSeenIndex
|
||||
FROM dbo.AssetEvents ae
|
||||
INNER JOIN ScenarioOrder so ON so.SceneID = ae.SceneID
|
||||
GROUP BY ae.StoryAssetID
|
||||
)
|
||||
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
||||
SELECT @RunID, @ScenarioID, NULL, N'AssetDependency', ad.AssetDependencyID, N'Asset Dependency Order', N'Info',
|
||||
N'Scenario warning: an asset appears before a validating dependency source appears.',
|
||||
CONCAT(target.AssetName, N' appears before ', source.AssetName, N'.')
|
||||
FROM dbo.AssetDependencies ad
|
||||
INNER JOIN dbo.AssetDependencyTypes adt ON adt.AssetDependencyTypeID = ad.AssetDependencyTypeID
|
||||
INNER JOIN dbo.StoryAssets source ON source.StoryAssetID = ad.SourceAssetID
|
||||
INNER JOIN dbo.StoryAssets target ON target.StoryAssetID = ad.TargetAssetID
|
||||
INNER JOIN AssetFirstSeen sourceSeen ON sourceSeen.StoryAssetID = ad.SourceAssetID
|
||||
INNER JOIN AssetFirstSeen targetSeen ON targetSeen.StoryAssetID = ad.TargetAssetID
|
||||
WHERE ad.IsArchived = 0 AND adt.IsValidatingDependency = 1 AND targetSeen.FirstSeenIndex < sourceSeen.FirstSeenIndex;
|
||||
|
||||
;WITH ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID, ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
),
|
||||
MetricSteps AS
|
||||
(
|
||||
SELECT smv.SceneID, smt.MetricName, smv.Value, so.ScenarioIndex,
|
||||
LAG(smv.Value) OVER (PARTITION BY smt.MetricName ORDER BY so.ScenarioIndex) AS PreviousValue
|
||||
FROM dbo.SceneMetricValues smv
|
||||
INNER JOIN dbo.SceneMetricTypes smt ON smt.MetricTypeID = smv.MetricTypeID
|
||||
INNER JOIN ScenarioOrder so ON so.SceneID = smv.SceneID
|
||||
WHERE smt.MetricName IN (N'Overall Intensity', N'Tension', N'Emotional Weight')
|
||||
)
|
||||
INSERT dbo.ScenarioWarnings (ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details)
|
||||
SELECT @RunID, @ScenarioID, SceneID, N'Scene', SceneID, N'Pacing Jump', N'Info',
|
||||
N'Scenario warning: a pacing/emotional metric changes sharply after this move.',
|
||||
CONCAT(MetricName, N' changes from ', PreviousValue, N' to ', Value, N'.')
|
||||
FROM MetricSteps
|
||||
WHERE PreviousValue IS NOT NULL AND ABS(Value - PreviousValue) >= 6;
|
||||
|
||||
DECLARE @WarningCount int = (SELECT COUNT(*) FROM dbo.ScenarioWarnings WHERE ScenarioValidationRunID = @RunID);
|
||||
UPDATE dbo.ScenarioValidationRuns SET CompletedDate = SYSUTCDATETIME(), WarningCount = @WarningCount WHERE ScenarioValidationRunID = @RunID;
|
||||
SELECT @WarningCount;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Compare
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
;WITH MainOrder AS
|
||||
(
|
||||
SELECT nso.SceneID, nso.GlobalSceneIndex,
|
||||
CONCAT(nso.BookTitle, N' / Ch ', nso.ChapterNumber, N' / Scene ', nso.SceneNumber) AS MainPosition
|
||||
FROM dbo.NarrativeSceneOrder nso
|
||||
INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = nso.SceneID AND sso.ScenarioID = @ScenarioID
|
||||
),
|
||||
ScenarioOrder AS
|
||||
(
|
||||
SELECT sso.SceneID,
|
||||
ROW_NUMBER() OVER (ORDER BY b.SortOrder, ch.SortOrder, sso.ProposedSortOrder, s.SceneID) AS ScenarioIndex,
|
||||
CONCAT(b.BookTitle, N' / Ch ', ch.ChapterNumber, N' / Scene ', s.SceneNumber) AS ScenarioPosition,
|
||||
s.SceneTitle
|
||||
FROM dbo.ScenarioSceneOrder sso
|
||||
INNER JOIN dbo.Scenes s ON s.SceneID = sso.SceneID
|
||||
INNER JOIN dbo.Chapters ch ON ch.ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID)
|
||||
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
|
||||
WHERE sso.ScenarioID = @ScenarioID
|
||||
)
|
||||
SELECT so.SceneID, so.SceneTitle, mo.MainPosition, so.ScenarioPosition,
|
||||
mo.GlobalSceneIndex AS MainIndex, so.ScenarioIndex, CAST(CASE WHEN mo.GlobalSceneIndex <> so.ScenarioIndex OR mo.MainPosition <> so.ScenarioPosition THEN 1 ELSE 0 END AS bit) AS HasMoved
|
||||
FROM ScenarioOrder so
|
||||
INNER JOIN MainOrder mo ON mo.SceneID = so.SceneID
|
||||
WHERE mo.GlobalSceneIndex <> so.ScenarioIndex OR mo.MainPosition <> so.ScenarioPosition
|
||||
ORDER BY so.ScenarioIndex;
|
||||
|
||||
SELECT ScenarioWarningID, ScenarioValidationRunID, ScenarioID, SceneID, EntityType, EntityID, WarningTypeName, SeverityName, Message, Details, CreatedDate
|
||||
FROM dbo.ScenarioWarnings
|
||||
WHERE ScenarioID = @ScenarioID
|
||||
ORDER BY CASE SeverityName WHEN N'Critical' THEN 4 WHEN N'Warning' THEN 3 WHEN N'Info' THEN 2 ELSE 1 END DESC, CreatedDate DESC;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_ApplyToMain
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
UPDATE s
|
||||
SET ChapterID = ISNULL(sso.ProposedChapterID, s.ChapterID),
|
||||
SortOrder = sso.ProposedSortOrder,
|
||||
UpdatedDate = SYSUTCDATETIME()
|
||||
FROM dbo.Scenes s
|
||||
INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = s.SceneID
|
||||
WHERE sso.ScenarioID = @ScenarioID;
|
||||
|
||||
;WITH affected AS
|
||||
(
|
||||
SELECT DISTINCT ChapterID FROM dbo.Scenes s INNER JOIN dbo.ScenarioSceneOrder sso ON sso.SceneID = s.SceneID WHERE sso.ScenarioID = @ScenarioID
|
||||
),
|
||||
ordered AS
|
||||
(
|
||||
SELECT s.SceneID, ROW_NUMBER() OVER (PARTITION BY s.ChapterID ORDER BY s.SortOrder, s.SceneID) * 10 AS NextSortOrder
|
||||
FROM dbo.Scenes s
|
||||
INNER JOIN affected a ON a.ChapterID = s.ChapterID
|
||||
WHERE s.IsArchived = 0
|
||||
)
|
||||
UPDATE s
|
||||
SET SortOrder = ordered.NextSortOrder,
|
||||
UpdatedDate = SYSUTCDATETIME()
|
||||
FROM dbo.Scenes s
|
||||
INNER JOIN ordered ON ordered.SceneID = s.SceneID;
|
||||
|
||||
UPDATE dbo.Scenarios
|
||||
SET IsAppliedToMain = 1,
|
||||
UpdatedDate = SYSUTCDATETIME()
|
||||
WHERE ScenarioID = @ScenarioID;
|
||||
END;
|
||||
GO
|
||||
|
||||
CREATE OR ALTER PROCEDURE dbo.Scenario_Archive
|
||||
@ScenarioID int
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
UPDATE dbo.Scenarios SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE ScenarioID = @ScenarioID;
|
||||
END;
|
||||
GO
|
||||
@ -317,6 +317,40 @@ public sealed class StoryDynamicsViewModel
|
||||
public IReadOnlyList<DynamicsIssue> Issues { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ScenarioListViewModel
|
||||
{
|
||||
public Project Project { get; set; } = new();
|
||||
public IReadOnlyList<Scenario> Scenarios { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ScenarioCreateViewModel
|
||||
{
|
||||
public int ProjectID { get; set; }
|
||||
public int? BookID { get; set; }
|
||||
public string ScenarioName { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ScenarioTimelineViewModel
|
||||
{
|
||||
public Project Project { get; set; } = new();
|
||||
public Scenario Scenario { get; set; } = new();
|
||||
public IReadOnlyList<Book> Books { get; set; } = [];
|
||||
public IReadOnlyList<Chapter> Chapters { get; set; } = [];
|
||||
public IReadOnlyList<ScenarioScene> Scenes { get; set; } = [];
|
||||
public IReadOnlyList<ScenarioWarning> Warnings { get; set; } = [];
|
||||
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ScenarioCompareViewModel
|
||||
{
|
||||
public Project Project { get; set; } = new();
|
||||
public Scenario Scenario { get; set; } = new();
|
||||
public IReadOnlyList<ScenarioComparisonRow> MovedScenes { get; set; } = [];
|
||||
public IReadOnlyList<ScenarioWarning> ScenarioWarnings { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class TimelineViewModel
|
||||
{
|
||||
public Project Project { get; set; } = new();
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
</div>
|
||||
<nav class="context-nav" aria-label="Project navigation">
|
||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Timeline</a>
|
||||
<a asp-controller="Scenarios" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Scenarios</a>
|
||||
<a asp-controller="Writer" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Writer Workspace</a>
|
||||
<a asp-controller="StoryBible" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story Bible</a>
|
||||
<a asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
||||
@ -39,6 +40,7 @@
|
||||
<div class="button-row">
|
||||
<a class="btn btn-outline-secondary" asp-action="Edit" asp-route-id="@Model.Project.ProjectID">Edit project</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Timeline</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="Scenarios" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Scenarios</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="Writer" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Writer Workspace</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="StoryBible" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story Bible</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="PlotLines" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Plot lines</a>
|
||||
|
||||
90
PlotLine/Views/Scenarios/Compare.cshtml
Normal file
90
PlotLine/Views/Scenarios/Compare.cshtml
Normal file
@ -0,0 +1,90 @@
|
||||
@model ScenarioCompareViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Compare Scenario";
|
||||
}
|
||||
|
||||
<section class="scenario-banner">
|
||||
<div>
|
||||
<p class="eyebrow">Scenario Comparison</p>
|
||||
<h1>@Model.Scenario.ScenarioName</h1>
|
||||
<p>Review moved scenes and sandbox warnings before applying anything to the main order.</p>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<a class="btn btn-outline-secondary" asp-action="Timeline" asp-route-id="@Model.Scenario.ScenarioID">Back to scenario</a>
|
||||
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Scenario.BookID">Main timeline</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@if (TempData["ScenarioMessage"] is string message)
|
||||
{
|
||||
<div class="alert alert-warning">@message</div>
|
||||
}
|
||||
|
||||
<section class="story-bible-section">
|
||||
<div class="story-bible-section-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Moved scenes</p>
|
||||
<h2>Main vs Scenario</h2>
|
||||
</div>
|
||||
<span class="soft-count">@Model.MovedScenes.Count moved</span>
|
||||
</div>
|
||||
@if (!Model.MovedScenes.Any())
|
||||
{
|
||||
<p class="muted">No scene movements yet.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="scenario-compare-list">
|
||||
@foreach (var row in Model.MovedScenes)
|
||||
{
|
||||
<article>
|
||||
<strong>@row.SceneTitle</strong>
|
||||
<span>Main: @row.MainPosition</span>
|
||||
<span>Scenario: @row.ScenarioPosition</span>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section class="story-bible-section">
|
||||
<div class="story-bible-section-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Warnings added</p>
|
||||
<h2>Scenario Warnings</h2>
|
||||
</div>
|
||||
<span class="soft-count">@Model.ScenarioWarnings.Count</span>
|
||||
</div>
|
||||
@if (!Model.ScenarioWarnings.Any())
|
||||
{
|
||||
<p class="muted">No scenario warnings currently recorded.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="attention-list">
|
||||
@foreach (var warning in Model.ScenarioWarnings)
|
||||
{
|
||||
<article>
|
||||
<span class="badge text-bg-light">@warning.SeverityName</span>
|
||||
<strong>@warning.WarningTypeName</strong>
|
||||
<p>@warning.Message</p>
|
||||
@if (!string.IsNullOrWhiteSpace(warning.Details))
|
||||
{
|
||||
<p class="muted">@warning.Details</p>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section class="story-bible-section danger-zone">
|
||||
<h2>Apply Scenario To Main</h2>
|
||||
<p class="muted">This updates the real scene chapter/order using the scenario order. Linked story data stays attached to the same scenes.</p>
|
||||
<form asp-action="Apply" method="post" class="plotline-form">
|
||||
<input type="hidden" name="id" value="@Model.Scenario.ScenarioID" />
|
||||
<label class="form-label">Confirmation text</label>
|
||||
<input name="confirmation" class="form-control" value="" placeholder="This will replace the current scene order with the scenario order. Continue?" />
|
||||
<button class="btn btn-danger mt-2" type="submit">Apply Scenario</button>
|
||||
</form>
|
||||
</section>
|
||||
37
PlotLine/Views/Scenarios/Create.cshtml
Normal file
37
PlotLine/Views/Scenarios/Create.cshtml
Normal file
@ -0,0 +1,37 @@
|
||||
@model ScenarioCreateViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Create Scenario";
|
||||
}
|
||||
|
||||
<div class="page-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Scenario Sandbox</p>
|
||||
<h1>Create Scenario</h1>
|
||||
<p class="lead-text">Copies the current scene order into a sandbox. Scenes and story data are not duplicated.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="story-bible-section">
|
||||
<form asp-action="Create" method="post" class="plotline-form">
|
||||
<input type="hidden" asp-for="ProjectID" />
|
||||
<div class="mb-3">
|
||||
<label asp-for="ScenarioName" class="form-label">Scenario name</label>
|
||||
<input asp-for="ScenarioName" class="form-control" placeholder="Reveal Later Draft" />
|
||||
<span asp-validation-for="ScenarioName" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label asp-for="BookID" class="form-label">Scope</label>
|
||||
<select asp-for="BookID" asp-items="Model.BookOptions" class="form-select">
|
||||
<option value="">Whole project</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label asp-for="Description" class="form-label">Description</label>
|
||||
<textarea asp-for="Description" class="form-control" rows="4"></textarea>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="btn btn-primary" type="submit">Create Scenario</button>
|
||||
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
67
PlotLine/Views/Scenarios/Index.cshtml
Normal file
67
PlotLine/Views/Scenarios/Index.cshtml
Normal file
@ -0,0 +1,67 @@
|
||||
@model ScenarioListViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Scenarios";
|
||||
}
|
||||
|
||||
<section class="context-header">
|
||||
<div class="context-title">
|
||||
<span class="eyebrow">Scenario Sandbox</span>
|
||||
<strong>@Model.Project.ProjectName</strong>
|
||||
</div>
|
||||
<nav class="context-nav" aria-label="Workspace navigation">
|
||||
<a asp-controller="Projects" asp-action="Details" asp-route-id="@Model.Project.ProjectID">Project</a>
|
||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Main timeline</a>
|
||||
<a asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Story health</a>
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<div class="page-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Planning sandbox</p>
|
||||
<h1>Scenarios</h1>
|
||||
<p class="lead-text">Test structural changes without changing the main story order.</p>
|
||||
</div>
|
||||
<a class="btn btn-primary" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID">Create Scenario</a>
|
||||
</div>
|
||||
|
||||
<section class="story-bible-section">
|
||||
@if (!Model.Scenarios.Any())
|
||||
{
|
||||
<p class="muted">No scenarios yet. Create one from the current order to test a structural idea.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="story-bible-grid story-bible-grid-compact">
|
||||
@foreach (var scenario in Model.Scenarios)
|
||||
{
|
||||
<article class="story-bible-card scenario-card">
|
||||
<div class="story-bible-card-title">
|
||||
<h3>@scenario.ScenarioName</h3>
|
||||
@if (scenario.IsAppliedToMain)
|
||||
{
|
||||
<span>Applied</span>
|
||||
}
|
||||
</div>
|
||||
<p class="muted">@scenario.Description</p>
|
||||
<div class="story-bible-meta">
|
||||
<span>@scenario.SceneCount scenes</span>
|
||||
<span>@scenario.WarningCount warnings</span>
|
||||
@if (!string.IsNullOrWhiteSpace(scenario.BookTitle))
|
||||
{
|
||||
<span>@scenario.BookTitle</span>
|
||||
}
|
||||
</div>
|
||||
<div class="button-row mt-2">
|
||||
<a class="btn btn-outline-primary btn-sm" asp-action="Timeline" asp-route-id="@scenario.ScenarioID">Open timeline</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" asp-action="Compare" asp-route-id="@scenario.ScenarioID">Compare</a>
|
||||
<form asp-action="Archive" method="post">
|
||||
<input type="hidden" name="id" value="@scenario.ScenarioID" />
|
||||
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||
<button class="btn btn-outline-danger btn-sm" type="submit">Archive</button>
|
||||
</form>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
152
PlotLine/Views/Scenarios/Timeline.cshtml
Normal file
152
PlotLine/Views/Scenarios/Timeline.cshtml
Normal file
@ -0,0 +1,152 @@
|
||||
@model ScenarioTimelineViewModel
|
||||
@{
|
||||
ViewData["Title"] = $"{Model.Scenario.ScenarioName} Scenario";
|
||||
ViewData["ShellClass"] = "plotline-shell-wide";
|
||||
var scenesByChapter = Model.Scenes.GroupBy(x => x.ProposedChapterID).ToDictionary(x => x.Key, x => x.OrderBy(s => s.ProposedSortOrder).ToList());
|
||||
var orderedScenes = Model.Scenes.OrderBy(x => x.ProposedSortOrder).ToList();
|
||||
}
|
||||
|
||||
<section class="scenario-banner">
|
||||
<div>
|
||||
<p class="eyebrow">Scenario Mode</p>
|
||||
<h1>@Model.Scenario.ScenarioName</h1>
|
||||
<p>@Model.Scenario.Description</p>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<a class="btn btn-outline-secondary" asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.Scenario.BookID">Return to Main Timeline</a>
|
||||
<form asp-action="Validate" method="post">
|
||||
<input type="hidden" name="id" value="@Model.Scenario.ScenarioID" />
|
||||
<button class="btn btn-outline-primary" type="submit">Validate Scenario</button>
|
||||
</form>
|
||||
<a class="btn btn-outline-primary" asp-action="Compare" asp-route-id="@Model.Scenario.ScenarioID">Compare</a>
|
||||
<form asp-action="Archive" method="post">
|
||||
<input type="hidden" name="id" value="@Model.Scenario.ScenarioID" />
|
||||
<input type="hidden" name="projectId" value="@Model.Project.ProjectID" />
|
||||
<button class="btn btn-outline-danger" type="submit">Archive Scenario</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@if (TempData["ScenarioMessage"] is string message)
|
||||
{
|
||||
<div class="alert alert-info">@message</div>
|
||||
}
|
||||
|
||||
<section class="scenario-warning-strip">
|
||||
<strong>@Model.Warnings.Count scenario warning@(Model.Warnings.Count == 1 ? "" : "s")</strong>
|
||||
<span>These warnings belong to the sandbox and do not affect the main warning board.</span>
|
||||
</section>
|
||||
|
||||
<section class="scenario-board">
|
||||
<div class="scenario-scroll">
|
||||
@foreach (var chapter in Model.Chapters)
|
||||
{
|
||||
var chapterScenes = scenesByChapter.GetValueOrDefault(chapter.ChapterID, []);
|
||||
if (!chapterScenes.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
<article class="scenario-chapter">
|
||||
<header>
|
||||
<span>Chapter @chapter.ChapterNumber:g</span>
|
||||
<strong>@chapter.ChapterTitle</strong>
|
||||
</header>
|
||||
<div class="scenario-scene-row">
|
||||
@foreach (var scene in chapterScenes)
|
||||
{
|
||||
var previous = orderedScenes.TakeWhile(x => x.SceneID != scene.SceneID).LastOrDefault();
|
||||
var next = orderedScenes.SkipWhile(x => x.SceneID != scene.SceneID).Skip(1).FirstOrDefault();
|
||||
<article class="scenario-scene-card">
|
||||
<div class="scenario-scene-title">
|
||||
<span>Scene @scene.SceneNumber:g</span>
|
||||
<strong>@scene.SceneTitle</strong>
|
||||
</div>
|
||||
<div class="story-bible-meta">
|
||||
<span>@scene.RevisionStatusName</span>
|
||||
<span>@scene.TimeLabel</span>
|
||||
@if (scene.WarningCount > 0)
|
||||
{
|
||||
<span class="text-danger">@scene.WarningCount warning@(scene.WarningCount == 1 ? "" : "s")</span>
|
||||
}
|
||||
</div>
|
||||
<p>@scene.Summary</p>
|
||||
<div class="scenario-mini-data">
|
||||
@if (!string.IsNullOrWhiteSpace(scene.ThreadLabels)) { <span>Threads: @scene.ThreadLabels</span> }
|
||||
@if (!string.IsNullOrWhiteSpace(scene.AssetLabels)) { <span>Assets: @scene.AssetLabels</span> }
|
||||
@if (!string.IsNullOrWhiteSpace(scene.CharacterLabels)) { <span>Characters: @scene.CharacterLabels</span> }
|
||||
@if (!string.IsNullOrWhiteSpace(scene.LocationLabel)) { <span>Location: @scene.LocationLabel</span> }
|
||||
</div>
|
||||
<div class="scenario-move-actions">
|
||||
@if (previous is not null)
|
||||
{
|
||||
<form asp-action="MoveScene" method="post">
|
||||
<input type="hidden" name="scenarioId" value="@Model.Scenario.ScenarioID" />
|
||||
<input type="hidden" name="sceneId" value="@scene.SceneID" />
|
||||
<input type="hidden" name="anchorSceneId" value="@previous.SceneID" />
|
||||
<input type="hidden" name="position" value="Before" />
|
||||
<button class="btn btn-outline-secondary btn-sm" type="submit">Move up</button>
|
||||
</form>
|
||||
}
|
||||
@if (next is not null)
|
||||
{
|
||||
<form asp-action="MoveScene" method="post">
|
||||
<input type="hidden" name="scenarioId" value="@Model.Scenario.ScenarioID" />
|
||||
<input type="hidden" name="sceneId" value="@scene.SceneID" />
|
||||
<input type="hidden" name="anchorSceneId" value="@next.SceneID" />
|
||||
<input type="hidden" name="position" value="After" />
|
||||
<button class="btn btn-outline-secondary btn-sm" type="submit">Move down</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
<form asp-action="MoveScene" method="post" class="scenario-chapter-form">
|
||||
<input type="hidden" name="scenarioId" value="@Model.Scenario.ScenarioID" />
|
||||
<input type="hidden" name="sceneId" value="@scene.SceneID" />
|
||||
<input type="hidden" name="position" value="End" />
|
||||
<select name="targetChapterId" class="form-select form-select-sm">
|
||||
@foreach (var chapterOption in Model.Chapters)
|
||||
{
|
||||
<option value="@chapterOption.ChapterID" selected="@(chapterOption.ChapterID == scene.ProposedChapterID)">Ch @chapterOption.ChapterNumber:g</option>
|
||||
}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary btn-sm" type="submit">Move to chapter</button>
|
||||
</form>
|
||||
<a asp-controller="Scenes" asp-action="Edit" asp-route-id="@scene.SceneID">Open scene</a>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="story-bible-section">
|
||||
<div class="story-bible-section-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Scenario warnings</p>
|
||||
<h2>Validation Notes</h2>
|
||||
</div>
|
||||
<span class="soft-count">@Model.Warnings.Count</span>
|
||||
</div>
|
||||
@if (!Model.Warnings.Any())
|
||||
{
|
||||
<p class="muted">Run scenario validation to check this order.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="attention-list">
|
||||
@foreach (var warning in Model.Warnings)
|
||||
{
|
||||
<article>
|
||||
<span class="badge text-bg-light">Scenario warning</span>
|
||||
<strong>@warning.WarningTypeName</strong>
|
||||
<p>@warning.Message</p>
|
||||
@if (!string.IsNullOrWhiteSpace(warning.Details))
|
||||
{
|
||||
<p class="muted">@warning.Details</p>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
@ -36,6 +36,7 @@
|
||||
<nav class="context-nav" aria-label="Workspace navigation">
|
||||
<a asp-controller="Projects" asp-action="Details" asp-route-id="@Model.Project.ProjectID">Project</a>
|
||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Timeline</a>
|
||||
<a asp-controller="Scenarios" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Scenarios</a>
|
||||
<a asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Story health</a>
|
||||
<a asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Warnings</a>
|
||||
<a asp-controller="Characters" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID">Characters</a>
|
||||
@ -73,6 +74,7 @@
|
||||
}
|
||||
<a class="btn btn-outline-secondary" asp-controller="Warnings" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Warnings</a>
|
||||
<a class="btn btn-outline-secondary" asp-controller="Analytics" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Story health</a>
|
||||
<a class="btn btn-outline-primary" asp-controller="Scenarios" asp-action="Create" asp-route-projectId="@Model.Project.ProjectID" asp-route-bookId="@Model.SelectedBookID">Create Scenario</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -2794,6 +2794,148 @@ body.dragging-location [data-drag-type="location"] {
|
||||
background: #7c5fb0;
|
||||
}
|
||||
|
||||
.scenario-banner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
align-items: flex-start;
|
||||
border: 1px solid rgba(103, 80, 164, 0.22);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
background: linear-gradient(135deg, rgba(103, 80, 164, 0.10), rgba(255, 255, 255, 0.86));
|
||||
box-shadow: 0 12px 28px rgba(36, 32, 26, 0.08);
|
||||
}
|
||||
|
||||
.scenario-banner h1 {
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
|
||||
.scenario-banner p {
|
||||
margin: 0;
|
||||
color: var(--plotline-muted);
|
||||
}
|
||||
|
||||
.scenario-card {
|
||||
border-color: rgba(103, 80, 164, 0.18);
|
||||
}
|
||||
|
||||
.scenario-warning-strip {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
border: 1px solid var(--plotline-line);
|
||||
border-radius: 10px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 14px;
|
||||
background: rgba(255, 255, 255, 0.76);
|
||||
color: var(--plotline-muted);
|
||||
}
|
||||
|
||||
.scenario-warning-strip strong {
|
||||
color: var(--plotline-ink);
|
||||
}
|
||||
|
||||
.scenario-board {
|
||||
border: 1px solid var(--plotline-line);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
background: rgba(247, 245, 240, 0.74);
|
||||
overflow: hidden;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.scenario-scroll {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.scenario-chapter {
|
||||
min-width: 360px;
|
||||
max-width: 520px;
|
||||
border: 1px solid rgba(82, 75, 65, 0.14);
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
}
|
||||
|
||||
.scenario-chapter header {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
border-bottom: 1px solid var(--plotline-line);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.scenario-chapter header span {
|
||||
color: var(--plotline-muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.scenario-scene-row {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.scenario-scene-card {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
border: 1px solid rgba(82, 75, 65, 0.12);
|
||||
border-radius: 9px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.scenario-scene-title {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.scenario-scene-title span,
|
||||
.scenario-mini-data {
|
||||
color: var(--plotline-muted);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.scenario-mini-data {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.scenario-move-actions,
|
||||
.scenario-chapter-form,
|
||||
.scenario-compare-list article {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.scenario-chapter-form select {
|
||||
min-width: 160px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.scenario-compare-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.scenario-compare-list article {
|
||||
justify-content: space-between;
|
||||
border: 1px solid var(--plotline-line);
|
||||
border-radius: 9px;
|
||||
padding: 10px;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
}
|
||||
|
||||
.danger-zone {
|
||||
border-color: rgba(163, 61, 61, 0.24);
|
||||
}
|
||||
|
||||
@media print {
|
||||
header,
|
||||
.breadcrumb-trail,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user