diff --git a/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUd.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUp.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/KV1s2Ld-0W0hjFA0isrLMMo5kjUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAd.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osd.xml similarity index 77% rename from resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAd.xml rename to resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osd.xml index 7de97d4..7a6326b 100644 --- a/resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAd.xml +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osd.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osp.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osp.xml new file mode 100644 index 0000000..a584d3e --- /dev/null +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/n9uG-vwYfcNNBDUlsES42alQ7osp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMd.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMp.xml b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMp.xml new file mode 100644 index 0000000..e088033 --- /dev/null +++ b/resources/project/-JxYjHfIG2f0LqYcrgF19Tk99yE/pOTCnqYsmD7OkuVKeieTVCdAGbMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYd.xml b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYp.xml b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/Nzh9vZQ1tYYzIxcLd9gRb2x6LDYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMd.xml b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMp.xml b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMp.xml new file mode 100644 index 0000000..1289cd3 --- /dev/null +++ b/resources/project/6HGJ4oAVUNiKqcphEyZLEi-vhA0/lWv1ZHtgNlIm2Vk_PwH8_N2dVzMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQd.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQd.xml new file mode 100644 index 0000000..f5e8559 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQp.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQp.xml new file mode 100644 index 0000000..36a7893 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/dUNZ2ztS0NUboxJMwhCN7xU8RfQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8d.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8p.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8p.xml new file mode 100644 index 0000000..69c9318 --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4Mf16AqQMryVgg9Qb5BFcQZ8Ah8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSod.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSod.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSod.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSop.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSop.xml new file mode 100644 index 0000000..3c31afd --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/4nnQ4IhT4MRhI0R7xrST8iJ4vSop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTod.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTop.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTop.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/nAHYfd_rS38BFe70duAyYGHwlTop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcd.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcp.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcp.xml new file mode 100644 index 0000000..b35188c --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/rS-SrVQGG9QJaPff44wrg-lIEqcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Ud.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Ud.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Ud.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Up.xml b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Up.xml new file mode 100644 index 0000000..8e96cf7 --- /dev/null +++ b/resources/project/GkZhPrjzHBlWmLhS_XdEzkI_pOg/vRX84xNPpvmouhyyGH1JtM3RJ9Up.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0p.xml new file mode 100644 index 0000000..fb98125 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-LnRzEgZw3B4JXNVolYe4KUTiL0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYp.xml new file mode 100644 index 0000000..c0cdb06 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/-ZPV7X_Lt6R9QuONLQN99Oj2_RYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgIp.xml new file mode 100644 index 0000000..1e205e8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/0shsyGoE68Bo8bSojwutQWXocgIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gp.xml new file mode 100644 index 0000000..c3f01e6 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1eNuiaSkxaLdrcX-v3j3-GPWN4gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0p.xml new file mode 100644 index 0000000..d90e985 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/1xDXObTIu2CLt1MVtuFggij9GL0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00p.xml new file mode 100644 index 0000000..1b9dbea --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/2PI5OkJxG9HjUYsxAgjvT3nmA00p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAp.xml new file mode 100644 index 0000000..21ef7a0 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/3D3wsejxqYHjHLpaic1ItgbIVsAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNood.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNood.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNood.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNoop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNoop.xml new file mode 100644 index 0000000..edae1f9 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4NXRl71D8ugF2LP8xSuTkZtyNoop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0p.xml new file mode 100644 index 0000000..aa26902 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/4XFPz491HcVI4Kr8IvUoV26wEz0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0p.xml new file mode 100644 index 0000000..787ff4f --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/5tIKUM03_-xHyswlx4zyohiVhW0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yp.xml new file mode 100644 index 0000000..2a612de --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6FTJ9XNlyrBACyE8gyZYYwXYr9Yp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wop.xml new file mode 100644 index 0000000..95363f2 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6_P8NovWN4YmAflXvfM0h26m5wop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMp.xml new file mode 100644 index 0000000..8a459eb --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/6rpQ2aC93RgG2XwTQ3ORxGonSTMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMp.xml new file mode 100644 index 0000000..a5d0727 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78YuO6zagmOinhPRwH2BpQTgGaMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzIp.xml new file mode 100644 index 0000000..27cf1eb --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/78huPeom40gRvk5uAP7g3m0cWzIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8p.xml new file mode 100644 index 0000000..4b6ebce --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/8cKjCNQoMzHWkhnSecTD3kV-CL8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQp.xml new file mode 100644 index 0000000..7fb3cc2 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/9Exi8u4R-Ab4__OikrLvnAGGMpQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQp.xml new file mode 100644 index 0000000..94714a4 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/AYthqDS45-wCWmxeCv1PqVNKZKQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEp.xml new file mode 100644 index 0000000..22a01b5 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/A_mw4eLKCluI7Q0aXNAQ9ex9fDEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8p.xml new file mode 100644 index 0000000..3462d67 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BBEDV9cg1vJAgIViHAfmzh29wB8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0p.xml new file mode 100644 index 0000000..73cd84d --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/BjNBOXRl4_VbY2DOEa-t3E5Hqx0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcp.xml new file mode 100644 index 0000000..ea55ba4 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CDf_fWX7tbO59rt_VX8OlU1DoCcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ed.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ed.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ed.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ep.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ep.xml new file mode 100644 index 0000000..e913f5c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/CjCq8BE9QlohkHN8Yuou_4DGp1Ep.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcp.xml new file mode 100644 index 0000000..9af1a6c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DD0IbcPWlmkRipINXMGuPdrwlUcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkp.xml new file mode 100644 index 0000000..5ae6034 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/DK_9YRSnKxtDcR5D7SNdZYk3Cwkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgp.xml new file mode 100644 index 0000000..36250c3 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/E0zR8L7qTIRduBJqIjs51H-lOKgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qp.xml new file mode 100644 index 0000000..20d5797 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Ehg5ssigxuKYX4nWHdFawaDBM9Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4p.xml new file mode 100644 index 0000000..3d9e580 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EildXD-TnQKgBVerLQ_iLW6mqW4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgp.xml new file mode 100644 index 0000000..bcdfa8b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/EngcY-lnzU-enZDZocG9-dW2NHgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkp.xml new file mode 100644 index 0000000..0efa537 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Eu1sbk12e_8ToscQX3YuiAjmJYkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkp.xml new file mode 100644 index 0000000..23c4dc2 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FfXf71tvJ32oWJsmHgNlC7GPgJkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78p.xml new file mode 100644 index 0000000..f0c7519 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Fo4SM-xe91kNLH409aYhjjx8j78p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEp.xml new file mode 100644 index 0000000..606363b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FrdlvTUafDHBz9vt7RogD9H2ttEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQp.xml new file mode 100644 index 0000000..41a0c73 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/FtYLilYu5C_-iCD-DTNKT7LY8wQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikp.xml new file mode 100644 index 0000000..aae9b40 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/GDb-RrdmK14KvebvJ-hHRTpN_Ikp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kp.xml new file mode 100644 index 0000000..1cd979b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/HdoPdpxGmhVNBe0LSaNx0Fktm3kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEp.xml new file mode 100644 index 0000000..4a2c48f --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/I7KgxYhGQInX7Zya2CqKwODpgLEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUp.xml new file mode 100644 index 0000000..22ca9a4 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IFqBAfshXYyTN0QR2d1NLVJ4ypUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEp.xml new file mode 100644 index 0000000..04877af --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IWvlU7eT2evXTsEglz5pcrBZvWEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMp.xml new file mode 100644 index 0000000..c913c8b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IcMei0b4FmboSA72EOY1dPkfVvMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGop.xml new file mode 100644 index 0000000..fd3571a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/IfiJNwpQKfX_iW3-Srb8ty_nLGop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0p.xml new file mode 100644 index 0000000..7d72a89 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JHQKzZs3BC3-UScXrVH0eWpjEl0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akp.xml new file mode 100644 index 0000000..d49550d --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JIHnkj8gJDj-AiiCGSV8kA568Akp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8p.xml new file mode 100644 index 0000000..a941c46 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JPfCEMRxhg3MfKNuAHpntpVtIv8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUp.xml new file mode 100644 index 0000000..0ce4cc7 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnTTTkpQ-UC7nE2JHCq-VrqmPqUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcp.xml new file mode 100644 index 0000000..bf0c7dc --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/JnV4WfEjjQjZjScWr_xuUOWHstcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Id.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Id.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Id.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Ip.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Ip.xml new file mode 100644 index 0000000..2d255a5 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Jyt6TV5Cy1cZzs9H7IXLfVBDe-Ip.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8p.xml new file mode 100644 index 0000000..7d60c2b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/K126bYYl-m9ywjL6EvIhUjhFqu8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgp.xml new file mode 100644 index 0000000..d301b08 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KH3A6-vDo63PdT55J-vi08I_kIgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qp.xml new file mode 100644 index 0000000..3f2c8e3 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/KNxWYsum9GL_OnbVxgsCAgrB7_Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsp.xml new file mode 100644 index 0000000..407d8c1 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kr4b9Qk0I3K1xly2a8XuERsK6zsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEp.xml new file mode 100644 index 0000000..0417980 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Kup8sOk-ZDjgFhlIgqmVd478GPEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUp.xml new file mode 100644 index 0000000..2d201ef --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LAoJMKbsG49-30hJn9YvsBBPuEUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gp.xml new file mode 100644 index 0000000..46fcb09 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/LnSdN0twT038lDg3oOzlNT8_J4gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wp.xml new file mode 100644 index 0000000..70c09c9 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Lv6NG40AEOTx3jcC5tJ0NH_dr2wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0p.xml new file mode 100644 index 0000000..884d545 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MDaxLkfI7JUlk1vLy5DoHcuaan0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwp.xml new file mode 100644 index 0000000..cef8b9e --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/MhEGG76ZnWvZzklMGdi5ffgnWlwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAp.xml new file mode 100644 index 0000000..b2cdcea --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nfo4HzuAOjBvx3yDQc2eROzCvCAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwp.xml new file mode 100644 index 0000000..8bb3ee7 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Nk13NV76jk7CDb_1zAC3u-v-mFwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEp.xml new file mode 100644 index 0000000..1dcb9ac --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OIGQ5QWbMwSdQgkCps783q-poBEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmop.xml new file mode 100644 index 0000000..d5a2d53 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OveCAgQEkDd-qB8IiIYWPCBiBmop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38p.xml new file mode 100644 index 0000000..e936148 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/OyG2IaQcOphjOSJDUvJMNgVQB38p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEp.xml new file mode 100644 index 0000000..9d27898 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/P26KqFjr3ni3tMbIUwZ--cGN1EEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEp.xml new file mode 100644 index 0000000..481b409 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RROQndlobe8Nt1bz3S4gkGEcNtEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0p.xml new file mode 100644 index 0000000..618219f --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/RgyPztRvTld5qteGIcTyZcjLVx0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAp.xml new file mode 100644 index 0000000..78d9343 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/S4aOftBX1aER9ZCkU3NoZjupayAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94p.xml new file mode 100644 index 0000000..385ee81 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SEzduMqOjDte-HGsUKkov5Wzg94p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEp.xml new file mode 100644 index 0000000..6eaee37 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SInRnpxCZu17UI0oYRfsRBsa8dEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMp.xml new file mode 100644 index 0000000..8a3091a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/SM_m5wWQDiuVal1R787O0IstkQMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wp.xml new file mode 100644 index 0000000..d4633a9 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TM5PCqnzOnrpCgUxSNPSvaFxC_wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUp.xml new file mode 100644 index 0000000..b7eb815 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TQn4vLvTZg8c0ZpRqY_MO8YtoBUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEop.xml new file mode 100644 index 0000000..a23c345 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ThvjIAM900cyvB3sK8UhqzTNwEop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMp.xml new file mode 100644 index 0000000..c6a361a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/TpO43nC8CleC8ICIyIBEM9PmpnMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8p.xml new file mode 100644 index 0000000..e70e0f3 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/UVULaZTb-3XYLmGolCfk0lSzlL8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gp.xml new file mode 100644 index 0000000..955a710 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/V2m0w0LuJD0aWiOhsZj7UZkKe0gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYp.xml new file mode 100644 index 0000000..41b7c69 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WMKR2BPH9zErg6KqBPGZHojWnqYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0p.xml new file mode 100644 index 0000000..535ad47 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WQMW1Kj9YgiLAU5TWphB5bmpnK0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhIp.xml new file mode 100644 index 0000000..b94415a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/WmOcWFwF5CwLLBPB31rwjYpCYhIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkp.xml new file mode 100644 index 0000000..0531b9b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/XV5AqYe0wPAkQCa6oxYxw8vbAbkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLop.xml new file mode 100644 index 0000000..93741c6 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/Y5zxLbQGpW0_ZG8UdMsIFrbsDLop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8p.xml new file mode 100644 index 0000000..0c36665 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/YmawGbMNhNN8o0dFSdxrkWDjQq8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Id.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Id.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Id.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Ip.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Ip.xml new file mode 100644 index 0000000..949321f --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/_tNTJ6CzCJJ2QQsVTFNWIvRiZ0Ip.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwp.xml new file mode 100644 index 0000000..0ba390b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/avuM3n-wIEFUNiD3cGFkqefQrzwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEp.xml new file mode 100644 index 0000000..44a464c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4-6FXjycg0qJUvyMRBOTqEm0SEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ad.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ad.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ad.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ap.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ap.xml new file mode 100644 index 0000000..8a457ed --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/d4V63nzxnUq4Tg8oA0h_tjmUc-Ap.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookp.xml new file mode 100644 index 0000000..ca695ef --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/e39mGRi0p_oi6XXNtWgbWQN-Ookp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrIp.xml new file mode 100644 index 0000000..e817990 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gZmcfFSZa0N48NpNZO54H9_dfrIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gp.xml new file mode 100644 index 0000000..2e1c9ff --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/gzoP_Nuv2MX746HxcIYnylPH81gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qp.xml new file mode 100644 index 0000000..b4ad982 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hV3KClyFfr8d21rPlDsajnc2N5Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkp.xml new file mode 100644 index 0000000..4c6b939 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hthC8sA4V56DA6quP21QaMGJ5Nkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYp.xml new file mode 100644 index 0000000..9103ddf --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/hz57_J-BrWMaKrdTzfp44ArFJqYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ed.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ed.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ed.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ep.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ep.xml new file mode 100644 index 0000000..7f5c4bc --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j0LunrHNRGqhmkJjHDfV2Sev-7Ep.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwp.xml new file mode 100644 index 0000000..237442b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/j9s61eqDqWM70kVkvBnVoO-HnDwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQp.xml new file mode 100644 index 0000000..4920ef2 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jd9M9mvXdG8MwShRMdZ6TNXArOQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kp.xml new file mode 100644 index 0000000..c26c4fd --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/jvaTQuMAkn9USfgJdmqQqUwxN_kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8p.xml new file mode 100644 index 0000000..3e5d125 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kDeg2zoipVruEYdMy86dHEFL9T8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMp.xml new file mode 100644 index 0000000..cc479f5 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kLvmxdMAJI4hKG08o1_zsyktUkMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYp.xml new file mode 100644 index 0000000..d1a8c1c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/kx7DemnB9kkjc72NiPggv2wUBJYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMp.xml new file mode 100644 index 0000000..f443990 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/l7r1LHQv1w0B82Xu-LcRl1usyyMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgp.xml new file mode 100644 index 0000000..ec23465 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/la2mT-dAbNjlviaG-iwITaEsHAgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAp.xml new file mode 100644 index 0000000..832d1f6 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/mVZHI7_rQt5phCaz3ALeCvgC8eAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLop.xml new file mode 100644 index 0000000..cb83a03 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nF_p0cRlzyLEf6Zs7fPHmmsvTLop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMp.xml new file mode 100644 index 0000000..4fc6627 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/nGC8nilmkdwYzkPZgBSxpyImVIMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcp.xml new file mode 100644 index 0000000..e460f2a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/o0XVdTDgCyyKcGMT6m_qWVxT5kcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMp.xml new file mode 100644 index 0000000..b95270c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/of52PojRlvtFYvcuwH6LSS845DMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsp.xml new file mode 100644 index 0000000..8b239f8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/om07cewA8BMSHssjdix9KsKqqbsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYp.xml new file mode 100644 index 0000000..a2f4455 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p3L-1OpFTacwKfni1FuVcoHH6fYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEp.xml new file mode 100644 index 0000000..432f876 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/p6DkNRiNB3cTVxykfSLZGBqk5TEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAp.xml new file mode 100644 index 0000000..adf11d7 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/pB68nYd4ltvd4VTs5ryMVGmnoBAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4p.xml new file mode 100644 index 0000000..2b834d2 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/plfEyEPtfun_ZrWg7c51jrVZlY4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQp.xml new file mode 100644 index 0000000..5cb7341 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/prqUb8L1rmKQaSZDLv8LDT2tWyQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkp.xml new file mode 100644 index 0000000..e2f79d6 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rOfyIIF_rPLhy3jdH7-zqPuMhbkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8p.xml new file mode 100644 index 0000000..f492463 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/rRMQby8U52npG_sDJKZjdcoBlz8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cp.xml new file mode 100644 index 0000000..2c44923 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/sbLpKCAlGY6igStniCoIvzZNZ0cp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsp.xml new file mode 100644 index 0000000..04293ae --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/secoX6VKFdXeTlZ20EO8GA-Chmsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQp.xml new file mode 100644 index 0000000..1d4cf87 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/t8ow2ztLXo-URRX08-OdIkX67VQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdod.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdop.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdop.xml new file mode 100644 index 0000000..af15dce --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/tRRA2GFpDQa60fgbah90kaTLUdop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0p.xml new file mode 100644 index 0000000..97d9880 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/u_mOz_MGJrkh2IEfHmnRpSmUNU0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsp.xml new file mode 100644 index 0000000..dbab3ef --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/udrG90zlRnO1vIQ4F2XUQoE4NPsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qp.xml new file mode 100644 index 0000000..36527ea --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vCELhankjnwH8RjXSz7H0wgz3_Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFIp.xml new file mode 100644 index 0000000..960d50b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vFswKJ-mtxArgnkmCRY5Z03xgFIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0p.xml new file mode 100644 index 0000000..2c34449 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/va0v0WdxN1aYqRr7mP81i-mOMb0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYp.xml new file mode 100644 index 0000000..f7d031c --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/vqCvOwVWDyiKdQZVGOEXUO4jccYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcp.xml new file mode 100644 index 0000000..91d4c09 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/w-t6lMAOZhsTeBJOJZkFSUMelPcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8p.xml new file mode 100644 index 0000000..6983c4b --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wIoFgfA318Hck6iYy2de-v-RcX8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsp.xml new file mode 100644 index 0000000..57af596 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/wUpnm4YgmzfKK3EBpkG_EVVRhMsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4p.xml new file mode 100644 index 0000000..653f44e --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/we0YXrZqVC0rUz_VawVDXuU1nC4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwp.xml new file mode 100644 index 0000000..11946bb --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/x8myECENnywqDcJvB0swmLYPLDwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4d.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4p.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4p.xml new file mode 100644 index 0000000..07667ad --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xNFz-HKBOzlCFrfPjATX_xGojR4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYp.xml new file mode 100644 index 0000000..937d058 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/xdYUSiR_eIWaWfhJgCOD62b-oeYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwp.xml new file mode 100644 index 0000000..29a4308 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/yPGBAA34c6UAwnpNU0giF---7jwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnId.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnIp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnIp.xml new file mode 100644 index 0000000..2b5c35a --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/ya8LLCmIUyUwVfyHMXYulp6eKnIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEp.xml new file mode 100644 index 0000000..617a025 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zegYqUShx3X4UGRhX5BJ10pnmsEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScd.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScp.xml b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScp.xml new file mode 100644 index 0000000..d4f684f --- /dev/null +++ b/resources/project/NdsL0Nh4wtc5dxoI0TU1uVF-B00/zlD0syXMGImuHb7B-RSc5GhuAScp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0d.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0d.xml new file mode 100644 index 0000000..fda6c04 --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0d.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0p.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0p.xml new file mode 100644 index 0000000..c897a45 --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/-t1vhuWhXfd2_bA01rA9UGacBr0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8d.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8d.xml new file mode 100644 index 0000000..fda6c04 --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8d.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8p.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8p.xml new file mode 100644 index 0000000..f615625 --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/B-j2AtgQvcSYyFI6QRtcq2_ysF8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4d.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4p.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4p.xml new file mode 100644 index 0000000..93ddaf0 --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/Uka6WspLurK62WWVnPA5yb3a2h4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkd.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkp.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkp.xml new file mode 100644 index 0000000..b9f9c7d --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/ZFweRNDkNTjqNE1bFowTK-Lg4zkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoId.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoId.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoId.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoIp.xml b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoIp.xml new file mode 100644 index 0000000..a6450ba --- /dev/null +++ b/resources/project/NlKaXP0P62kRJDmjZSzGu8Jf--k/j8WKtWk7xdSV1Qd2-XfSC0ibMoIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Id.xml b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Id.xml new file mode 100644 index 0000000..fda6c04 --- /dev/null +++ b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Id.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Ip.xml b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Ip.xml new file mode 100644 index 0000000..484b934 --- /dev/null +++ b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/ObrY62phP-WFAZae6jPcfXGw95Ip.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcd.xml b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcp.xml b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcp.xml new file mode 100644 index 0000000..7f3d8ed --- /dev/null +++ b/resources/project/QfRan8VIS8FJWu9sq7_nfr0NcFw/tK-YwJbBDUqTl5ur7TuyAPLEvPcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0d.xml b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0p.xml b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0p.xml new file mode 100644 index 0000000..b5009ac --- /dev/null +++ b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/14cfwHWYtO3bIZIAHJel6xwvZs0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMd.xml b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMd.xml new file mode 100644 index 0000000..fda6c04 --- /dev/null +++ b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMd.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMp.xml b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMp.xml new file mode 100644 index 0000000..220b869 --- /dev/null +++ b/resources/project/Wqze2RguMm8RygQI0Uykdot17AI/hMUzYmljSfZyrsNbSqvVBNLDdhMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54d.xml b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54p.xml b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54p.xml new file mode 100644 index 0000000..f56cf74 --- /dev/null +++ b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/ZbkytE2NTET5HAXLROq1rMk8J54p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskd.xml b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskp.xml b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskp.xml new file mode 100644 index 0000000..c998200 --- /dev/null +++ b/resources/project/a4NMXOJuMxY6ZPdF7LtPbcqgbXg/nL7mB0EmM1_sBoQbu4NkUq5XMskp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4d.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4p.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4p.xml new file mode 100644 index 0000000..8e96cf7 --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/YJG70BwMlTL8C7mo8z7rvPqvGD4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgd.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgp.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgp.xml new file mode 100644 index 0000000..b35188c --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/_CMbxM7vtC88Y5Ls4F-uYYiBRJgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qd.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qp.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qp.xml new file mode 100644 index 0000000..3c31afd --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/ik1NGaL_boPxdnGHUZzao7SQI_Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sd.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sp.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sp.xml new file mode 100644 index 0000000..69c9318 --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/nlpXlc0mTyZKSdK7BLQRqEHlo5sp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanod.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanop.xml b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanop.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/ceaVDhqtkvV5Y52oIQ7MOhken3g/xoiWFrkA2etXA6qNdFk8c9nfanop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgd.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgp.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgp.xml new file mode 100644 index 0000000..294f1fe --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/GkZhPrjzHBlWmLhS_XdEzkI_pOgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMd.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMp.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/NAPgIqrfihsMqVIaUxFYn_Xa9AMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gd.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gp.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gp.xml new file mode 100644 index 0000000..d3b8d29 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/ceaVDhqtkvV5Y52oIQ7MOhken3gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAd.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAp.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAp.xml new file mode 100644 index 0000000..3c5a2d4 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/f5W54yNk0Zwx1sRFz0ew04MdvIAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUd.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUp.xml b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUp.xml new file mode 100644 index 0000000..e063699 --- /dev/null +++ b/resources/project/eZzARIDvGAmYNGp0Fs2mKSIexRI/qu_tzR5t8eCCr9qrIOIGQzeETHUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEd.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEp.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEp.xml new file mode 100644 index 0000000..ecb9eb0 --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/4x-ApT8Yg6aSjIQrWyFYNMrfxTEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ed.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ed.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ed.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ep.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ep.xml new file mode 100644 index 0000000..bc347d9 --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/6PB0bNcC4OKMWt_Jcxs-0G2F97Ep.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMd.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMp.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMp.xml new file mode 100644 index 0000000..c2122be --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/OkKnC53-0i7wo8Q4f4beGgufowMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qd.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qp.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qp.xml new file mode 100644 index 0000000..3b75ea5 --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/akT1M2pPrNZecPRn_5INVNLnJ6Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgd.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgp.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgp.xml new file mode 100644 index 0000000..3fb94a6 --- /dev/null +++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/uEFXjvRtQDk4x1ZiSQvTrGr2Rxgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0d.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0p.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0p.xml new file mode 100644 index 0000000..c35bbac --- /dev/null +++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/6HGJ4oAVUNiKqcphEyZLEi-vhA0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4d.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4d.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4p.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4p.xml new file mode 100644 index 0000000..34481fc --- /dev/null +++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/fn6KZr3pcEU2sl9hG31V-_Ooyd4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAp.xml b/resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAp.xml deleted file mode 100644 index b9746d6..0000000 --- a/resources/project/f5U-zHPhyZJzGDBuc9waDwYOGcw/j7l-39BD8pCe4pVJ3Zpcd_p-AoAp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Md.xml b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Md.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Md.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Mp.xml b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Mp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/jAqnBtSIGPSIhf1xA5V9AYXWT8Mp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMd.xml b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMp.xml b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMp.xml new file mode 100644 index 0000000..75c5c21 --- /dev/null +++ b/resources/project/f5W54yNk0Zwx1sRFz0ew04MdvIA/o-Tn-s1SXrdT10aw7MmQ3hd2SHMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20d.xml b/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20d.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20p.xml b/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20p.xml new file mode 100644 index 0000000..488e3fa --- /dev/null +++ b/resources/project/gdDuiZdBOBh_KnGn-recV21_YgU/NpKBafCNzwt46UIiL2e9Xk0Mk20p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wp.xml new file mode 100644 index 0000000..984d014 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/5ieMYPaQnclp-AlvUjRy9zy7M1wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/9uFFpKlODWvDmfdiNnQW-nfkIZkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4d.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4p.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4p.xml new file mode 100644 index 0000000..28f8a34 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/DFOXQaY1rRKQpyipTH_8fEHeQR4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkp.xml new file mode 100644 index 0000000..5f29378 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/G94UrlDDT_1aS6UphEDyzkzRBzkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Ud.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Ud.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Ud.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Up.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Up.xml new file mode 100644 index 0000000..4b85246 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/HJYQYiX9gQ8ZqJsNXQvKTneIb-Up.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wd.xml new file mode 100644 index 0000000..7a6326b --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wp.xml new file mode 100644 index 0000000..1f37a43 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/VV30ODzqIaFizzJ8PKhtDADLI1wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0d.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0p.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0p.xml new file mode 100644 index 0000000..bf5bbd1 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/ZZmsNADUtYutDnr-aIgn-OnfSI0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRId.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRId.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRIp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRIp.xml new file mode 100644 index 0000000..c6dbd8f --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/eZzARIDvGAmYNGp0Fs2mKSIexRIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsp.xml new file mode 100644 index 0000000..1b0b774 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/hgg1-jCGTS4UMZSE4YfJsf2oaMsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwp.xml new file mode 100644 index 0000000..78401bd --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/jaceHlD4clVEUhekbOMrwJ0qvtwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7od.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7od.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7od.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7op.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7op.xml new file mode 100644 index 0000000..81bca21 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mCtrcvUKYUQmJExj9-qq672xa7op.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwp.xml new file mode 100644 index 0000000..f19c21d --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/mPOr8vFJdzcvPj0dogVlQGxmkvwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kd.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kp.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kp.xml new file mode 100644 index 0000000..e8ae89f --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/sIfkSL1IZsp3jKR-0Arx8WdFz8kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4d.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4d.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4p.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4p.xml new file mode 100644 index 0000000..4ff9c3d --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/uTxIUYmJ5r_akB8kb_pv9GQm8S4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sod.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sod.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sop.xml b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sop.xml new file mode 100644 index 0000000..5532f65 --- /dev/null +++ b/resources/project/lWv1ZHtgNlIm2Vk_PwH8_N2dVzM/xsU64DkOPl8llhmBp3e8It6w4Sop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEd.xml b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEp.xml b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEp.xml new file mode 100644 index 0000000..da29615 --- /dev/null +++ b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/-JxYjHfIG2f0LqYcrgF19Tk99yEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcd.xml b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcd.xml new file mode 100644 index 0000000..a75f7a8 --- /dev/null +++ b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcp.xml b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcp.xml new file mode 100644 index 0000000..842de6a --- /dev/null +++ b/resources/project/qu_tzR5t8eCCr9qrIOIGQzeETHU/nXflqEnMMNVwCQ0tHjs5QFskfmcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/+wt/+test/ColorSelector.m b/test/+wt/+test/ColorSelector.m index fa21a7a..336d286 100644 --- a/test/+wt/+test/ColorSelector.m +++ b/test/+wt/+test/ColorSelector.m @@ -34,7 +34,7 @@ function testValueProperty(testCase) % Test an invalid color newColor = [-1 0 1]; - errorID = 'wt:validators:mustBeBetween'; + errorID = 'MATLAB:validators:mustBeInRange'; testCase.verifySetPropertyError("Value", newColor, errorID); % Test an invalid color diff --git a/widgets/+wt/+abstract/BaseViewChart.m b/widgets/+wt/+abstract/BaseViewChart.m new file mode 100644 index 0000000..7192d51 --- /dev/null +++ b/widgets/+wt/+abstract/BaseViewChart.m @@ -0,0 +1,142 @@ +classdef BaseViewChart < matlab.graphics.chartcontainer.ChartContainer & ... + wt.mixin.ModelObserver + % Base class for view charts referencing a BaseModel class + + % Copyright 2024 The MathWorks Inc. + + + %% Public Properties + properties (AbortSet) + + % The default title prefix to display + TitlePrefix (1,1) string + + end %properties + + + %% Internal Properties + properties (Transient, NonCopyable, Hidden, SetAccess = protected) + + % TiledLayout for axes + TiledLayout matlab.graphics.layout.TiledChartLayout + + % Axes to display the signal + Axes (1,:) matlab.graphics.axis.Axes + + % Legend of each axes + Legend (1,:) matlab.graphics.illustration.Legend + + end %properties + + + properties (Transient, NonCopyable, UsedInUpdate = true, ... + GetAccess = private, SetAccess = protected) + + % Internal flag to trigger an update call + TriggerUpdate_BVC (1,1) logical = false + + end %properties + + + %% Constructor + methods + function obj = BaseViewChart(parent, varargin) + % Constructor + + if nargin < 1 + fig = uifigure(); + parent = uigridlayout(fig,[1,1]); + end + + % Call superclass constructors + obj = obj@matlab.graphics.chartcontainer.ChartContainer(parent, varargin{:}); + obj@wt.mixin.ModelObserver(); + + end %function + end %methods + + + %% Debugging Methods + methods + + function forceUpdateChart(obj) + % Forces update to run (For debugging only!) + + obj.update(); + + end %function + + end %methods + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + % Create the underlying components + + % Configure Layout + obj.TiledLayout = getLayout(obj); + obj.TiledLayout.Padding = "compact"; + obj.TiledLayout.TileSpacing = "compact"; + + % Name the panel with the view's class name by default + obj.TitlePrefix = extract(string(class(obj)), ... + alphanumericsPattern + textBoundary); + obj.TiledLayout.Title.String = obj.TitlePrefix; + + end %function + + + function update(obj) + + % Get the model to display + [model, validToDisplay] = obj.getScalarModelToDisplay(); + + % Prepare default name of the panel + if validToDisplay && strlength(model.Name) + groupTitle = obj.TitlePrefix + ": " + model.Name; + else + groupTitle = obj.TitlePrefix; + end + + % Update the panel name + obj.TiledLayout.Title.String = groupTitle; + + end %function + + + function requestUpdate(obj) + % Request update to occur at next drawnow cycle + + obj.TriggerUpdate_BVC = ~obj.TriggerUpdate_BVC; + + end %function + + + function onModelSet(obj) + % Triggered when Model has been set to a new value + + % Request an update + obj.requestUpdate(); + + % Call superclass method + obj.onModelSet@wt.mixin.ModelObserver() + + end %function + + + function onModelChanged(obj,evt) + % Triggered when a property within the model has changed + + % Request an update + obj.requestUpdate(); + + % Call superclass method + obj.onModelChanged@wt.mixin.ModelObserver(evt) + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+abstract/BaseViewController.m b/widgets/+wt/+abstract/BaseViewController.m new file mode 100644 index 0000000..928babe --- /dev/null +++ b/widgets/+wt/+abstract/BaseViewController.m @@ -0,0 +1,202 @@ +classdef BaseViewController < wt.mixin.ModelObserver & ... + matlab.ui.componentcontainer.ComponentContainer + % Base class for views/controllers referencing a BaseModel class + + % Copyright 2024 The MathWorks Inc. + + + %% Public Properties + properties (AbortSet) + + % The default panel name prefix to display + PanelNamePrefix (1,1) string + + end %properties + + + %% Internal Properties + properties (Hidden, SetAccess = protected) + + % Internal grid to place outer panel contents + OuterGrid matlab.ui.container.GridLayout + + % Outer panel with optional title + OuterPanel matlab.ui.container.Panel + + % The internal grid to manage contents + Grid matlab.ui.container.GridLayout + + end %properties + + + properties (Transient, NonCopyable, UsedInUpdate = true, ... + GetAccess = private, SetAccess = protected) + + % Internal flag to trigger an update call + TriggerUpdate_BVC (1,1) logical = false + + end %properties + + + %% Constructor + methods + function obj = BaseViewController(varargin) + % Constructor + + % Call superclass constructors + obj = obj@matlab.ui.componentcontainer.ComponentContainer(varargin{:}); + obj@wt.mixin.ModelObserver(); + + end %function + end %methods + + + %% Debugging Methods + methods + + function forceUpdate(obj) + % Forces update to run (For debugging only!) + + obj.update(); + + end %function + + end %methods + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + % Configure the widget + + % Set default positioning + warnState = warning('off','MATLAB:ui:components:noPositionSetWhenInLayoutContainer'); + obj.Units = "normalized"; + obj.Position = [0 0 1 1]; + warning(warnState); + + % Outer grid to place the outer panel + obj.OuterGrid = uigridlayout(obj, [1 1]); + obj.OuterGrid.Padding = [0 0 0 0]; + + % Make an outer panel + obj.OuterPanel = uipanel(obj.OuterGrid); + + % Name the panel with the view's class name by default + obj.PanelNamePrefix = extract(string(class(obj)), ... + alphanumericsPattern + textBoundary); + obj.OuterPanel.Title = obj.PanelNamePrefix; + + % Grid Layout to manage contents + obj.Grid = uigridlayout(obj.OuterPanel,[5 2]); + obj.Grid.Padding = 10; + obj.Grid.ColumnWidth = {'fit','1x'}; + obj.Grid.RowHeight = {'fit','fit','fit','fit','fit'}; + obj.Grid.ColumnSpacing = 5; + obj.Grid.RowSpacing = 10; + obj.Grid.Scrollable = true; + + end %function + + + function update(obj) + + % Get the model to display + [model, validToDisplay] = obj.getScalarModelToDisplay(); + + % Prepare default name of the panel + if validToDisplay && strlength(model.Name) + panelTitle = obj.PanelNamePrefix + ": " + model.Name; + else + panelTitle = obj.PanelNamePrefix; + end + + % Update the panel name + obj.OuterPanel.Title = panelTitle; + + end %function + + + function requestUpdate(obj) + % Request update to occur at next drawnow cycle + + obj.TriggerUpdate_BVC = ~obj.TriggerUpdate_BVC; + + end %function + + + function onModelSet(obj) + % Triggered when Model has been changed + + % Request an update + obj.requestUpdate(); + + % Call superclass method + obj.onModelSet@wt.mixin.ModelObserver() + + end %function + + function onModelChanged(obj,evt) + % Triggered when a property within the model has changed + + % Request an update + obj.requestUpdate(); + + % Call superclass method + obj.onModelChanged@wt.mixin.ModelObserver(evt) + + end %function + + + function onFieldEdited(obj,evt,fieldName,index) + % This is a generic callback that simple controls may use. For + % example, the ValueChangedFcn for an edit field may call this + % directly with the Model's property name that should be + % updated. Use this for callbacks of simple controls that can + % set a field simply by name. + + arguments + obj (1,1) wt.abstract.BaseViewController + evt + fieldName (1,1) string + index (1,:) double {mustBeInteger,mustBePositive} = zeros(1,0) + end + + if ~isscalar(obj.Model) + warning("wt:BaseViewController:onFieldEdited:NonScalarModel",... + "The onFieldEdited method is unable to set new " + ... + "value to an empty or nonscalar model.") + return + end + + % Get the new value + newValue = evt.Value; + + % Treat char as string + if ischar(newValue) + newValue = string(newValue); + end + + % Handle array values with the index input indicating what + % index of the newValue was changed + if ~isscalar(newValue) && ~isempty(index) && ... + isscalar(obj.Model.(fieldName)(index)) + + % We have one index of an array being set + obj.Model.(fieldName)(index) = newValue(index); + + else + + % We are setting the entire array + obj.Model.(fieldName) = newValue; + + end + + % Set the new value + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+abstract/BaseWidget.m b/widgets/+wt/+abstract/BaseWidget.m index 55cc044..f140057 100644 --- a/widgets/+wt/+abstract/BaseWidget.m +++ b/widgets/+wt/+abstract/BaseWidget.m @@ -38,7 +38,7 @@ properties (Transient, Access = private) % Flag to indicate earlier release (to be updated during setup) - IsPre21a (1,1) logical = verLessThan('matlab','9.10') + IsPre21a (1,1) logical = isMATLABReleaseOlderThan("R2021a") end %properties diff --git a/widgets/+wt/+apps/AbstractSessionApp.m b/widgets/+wt/+apps/AbstractSessionApp.m new file mode 100644 index 0000000..708225e --- /dev/null +++ b/widgets/+wt/+apps/AbstractSessionApp.m @@ -0,0 +1,431 @@ +classdef (Abstract, AllowedSubclasses = {?wt.apps.BaseSingleSessionApp, ... + ?wt.apps.BaseMultiSessionApp}) AbstractSessionApp < wt.apps.BaseApp + % Abstract base class for Widgets Toolbox app with 1+ sessions + + % Copyright 2024 The MathWorks Inc. + + + %% Abstract Public Properties + properties (Abstract, AbortSet, SetObservable) + + % Session data for the app (must be subclass of wt.model.BaseSession) + Session (1,:) wt.model.BaseSession + + end %properties + + + + %% Abstract Methods (subclass must implement these) + methods (Abstract, Access = protected) + + % Creates a new session object for the app. It must return a + % subclass of wt.model.BaseSession + sessionObj = createNewSession(app) + + end %methods + + + + %% Internal properties + properties (Transient, NonCopyable, Access = private) + + % Listener to Session property being set + SessionSetListener event.listener + + % Listener to changes within Session object + SessionChangedListener event.listener + + % Listeners to session marked clean/dirty + SessionDirtyListener event.listener + + end %properties + + + properties (Dependent, SetAccess = immutable) + + % Indicates a valid session is present + HasValidSession (1,1) logical + + % Indicates if session is dirty + Dirty (1,1) logical + + end %properties + + + % Accessors + methods + + function value = get.HasValidSession(app) + value = ~isempty(app.Session) && any(isvalid(app.Session)); + end + + function value = get.Dirty(app) + value = ~isempty(app.Session) && ... + any( app.Session(isvalid(app.Session)).Dirty ); + end + + end %methods + + + + %% Constructor + methods (Access = public) + + function app = AbstractSessionApp(varargin) + % Constructor + + % Call superclass constructor + app@wt.apps.BaseApp(varargin{:}); + + % Attach listeners to Session being set + app.SessionSetListener = listener(app,"Session","PostSet",... + @(~,~)app.onSessionSet_Private()); + + end %function + + end %methods + + + %% Internal Protected Methods + methods (Access = {?wt.apps.BaseSingleSessionApp, ?wt.apps.BaseMultiSessionApp}) + + function close_Internal(app) + % Close the app + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + end + + % Show output if Debug is on + app.displayDebugText(); + + % Freeze the figure with a progress dialog + dlg = app.showIndeterminateProgress("Closing"); + cleanupObj = onCleanup(@()delete(dlg)); + + % Delete the app + app.delete(); + + end %function + + + function isCancelled = closeSession_Internal(app, session) + % Close a session + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + session wt.model.BaseSession + end + + % Show output if Debug is on + app.displayDebugText(); + + % Prompt to save existing session if dirty + isCancelled = promptToSaveSession(app, session); + + % Close the session + if ~isCancelled + + % Remove session from the app + isMatch = app.Session == session; + app.Session(isMatch) = []; + + end %if + + end %function + + + function saveSession_Internal(app, useSaveAs, session) + % Save the session to a file + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + useSaveAs (1,1) logical + session wt.model.BaseSession + end + + % Show output if Debug is on + app.displayDebugText(); + + % Check/prep the session path + sessionPath = app.checkSessionPath_Internal(session); + + % Prompt for "save as" if needed + if useSaveAs || ~isfile(sessionPath) + sessionPath = app.promptToSaveAs(sessionPath); + end + + % Save the file (unless path is empty indicating cancel) + if strlength(sessionPath) + + % Freeze the figure with a progress dialog + dlg = app.showIndeterminateProgress("Saving Session"); + cleanupObj = onCleanup(@()delete(dlg)); + + % Save the session + session.save(sessionPath); + + % Update the app in case filepath changed + app.updateTitle() + app.update() + + end %if strlength(sessionPath) + + end %function + + + function sessionPath = checkSessionPath_Internal(app, session) + % Check / prepare the session path + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + session wt.model.BaseSession + end + + % Get the session info + sessionPath = session.FilePath; + sessionFolder = fileparts(sessionPath); + sessionName = session.FileName; + lastFolder = app.LastFolder; + + % If file does not already exist, make default path + if isfile(sessionPath) + % Do nothing special + elseif isfolder(sessionFolder) + % File not found but folder was + sessionPath = fullfile(sessionFolder,sessionName); + else + % Neither file nor folder give, so use defaults + sessionPath = fullfile(lastFolder,sessionName); + end + + end %function + + + function session = loadSession_Internal(app, sessionPath) + % Load a session from a file + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + sessionPath (1,1) string = "" + end + + % Show output if Debug is on + app.displayDebugText(); + + % Unless a file was already specified, prompt to load + if ~isfile(sessionPath) + sessionPath = app.promptToLoad(); + end + + % Check the file name of this session + [~,sessionFileName,sessionFileExt] = fileparts(sessionPath); + sessionFileName = sessionFileName + sessionFileExt; + if isempty(app.Session) + isAlreadyOpen = false; + else + existingSessionFiles = vertcat( app.Session.FileName ); + isAlreadyOpen = any( matches(sessionFileName, ... + existingSessionFiles, "IgnoreCase", true) ); + end + + % How should we proceed? + if isAlreadyOpen + + % Return an empty session of correct type + session = app.getEmptySession(); + + % Throw an error + title = "Load Session"; + message = sprintf("""%s"" is already open.", ... + sessionFileName); + app.throwError(message, title); + + elseif isfile(sessionPath) + % Load the file + + % Freeze the figure with a progress dialog + dlg = app.showIndeterminateProgress("Loading Session"); + cleanupObj = onCleanup(@()delete(dlg)); + + % Load the session + try + session = wt.model.BaseSession.open(sessionPath); + catch err + session = app.getEmptySession(); + app.throwError(err) + end + + else + + % Return an empty session of correct type + session = app.getEmptySession(); + + end %if + + end %function + + + function isCancelled = promptToSaveSession(app, session) + % Prompt the user to save their session before losing it + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + session (1,1) wt.model.BaseSession = app.Session + end + + % Show output if Debug is on + app.displayDebugText(); + + % Default output + isCancelled = false; + + % Don't save and return now if session is invalid or clean + if ~isvalid(session) || ~session.Dirty + return + end + + % Prompt whether to save + message = sprintf("Save changes to '%s'?",session.FileName); + title = "Load Session"; + selection = app.promptYesNoCancel(message, title); + + % If Yes, prompt to save the existing session first + if selection == "Yes" + sessionSavePath = app.saveSession(); + if ~strlength(sessionSavePath) + isCancelled = true; + end + elseif selection == "Cancel" + isCancelled = true; + end + + end %function + + end %methods + + + %% Sealed Protected Methods + methods (Sealed, Access = protected) + + function session = getEmptySession(app) + % Returns an empty session of the same type as Session property + + session = app.Session(1,[]); + + end %function + + end %methods + + + %% Protected Methods + methods (Access = protected) + + function onSessionSet(app) + % Triggered when a SetObservable property in the session has + % changed. May be overridden for custom behavior using incoming + % event data. + + % Show output if Debug is on + app.displayDebugText(); + + % Trigger updates + if app.SetupComplete + app.update(); + app.updateTitle(); + end + + end %function + + function onSessionChanged(app,~) + % Triggered when a SetObservable property in the session has + % changed. May be overridden for custom behavior using incoming + % event data. + + % Show output if Debug is on + app.displayDebugText(); + + % Update the app + if app.SetupComplete + app.update(); + app.updateTitle(); + end + + end %function + + + function onSessionDirty(app,~) + % Triggered when the session's MarkedDirty event fires + + % Show output if Debug is on + app.displayDebugText(); + + % Update the title only + % (prop change should have triggered update already) + if app.SetupComplete + app.updateTitle(); + end + + end %function + + + function onSessionClean(app,~) + % Triggered when the session's MarkedClean event fires + + % Show output if Debug is on + app.displayDebugText(); + + % Update the app + if app.SetupComplete + app.update(); + app.updateTitle(); + end + + end %function + + end %methods + + + %% Private Methods + methods (Access = private) + + function onSessionChanged_Private(app,evt) + % Triggered when attached Session has a ModelChanged event + + % Show output if Debug is on + app.displayDebugText(evt); + + % Call the app's session changed method + app.onSessionChanged(evt); + + end %function + + + function onSessionSet_Private(app) + % Triggered after Session property is set + + % Show output if Debug is on + app.displayDebugText(); + + app.SessionChangedListener = listener(app.Session,... + 'ModelChanged',@(~,evt)app.onSessionChanged_Private(evt)); + + app.SessionDirtyListener = [ + listener(app.Session,'MarkedDirty',@(~,evt)app.onSessionDirty(evt)) + listener(app.Session,'MarkedClean',@(~,evt)app.onSessionClean(evt)) + ]; + + % Call the app's session set method + app.onSessionSet(); + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+apps/BaseApp.m b/widgets/+wt/+apps/BaseApp.m index 696fca1..fcfee02 100644 --- a/widgets/+wt/+apps/BaseApp.m +++ b/widgets/+wt/+apps/BaseApp.m @@ -1,101 +1,165 @@ -classdef BaseApp < matlab.apps.AppBase & matlab.mixin.SetGetExactNames & ... +classdef BaseApp < matlab.apps.AppBase & ... + matlab.mixin.SetGetExactNames & ... + matlab.mixin.CustomDisplay & ... wt.mixin.ErrorHandling % Base class for Widgets Toolbox apps - - % Copyright 2020-2023 The MathWorks, Inc. - - + + % Copyright 2020-2024 The MathWorks, Inc. + + %% Properties properties (AbortSet) - + % Name of the app Name (1,1) string = "My App" - + end %properties - - + + properties (SetAccess = protected) - + % Model class for App preferences %(may subclass wt.model.Preferences to add more prefs) Preferences (1,1) wt.model.Preferences - + % Name of group to store preferences (defaults to class name) PreferenceGroup (1,1) string - + end %properties - - + + properties (AbortSet, Dependent) - + % Position of the app window Position - + % Visibility of the app window Visible - + % State of the app window WindowState - + end %properties - - - + + + % Accessors + methods + + function set.Name(app,value) + app.Name = value; + app.updateTitle(); + end + + + function value = get.PreferenceGroup(app) + value = app.PreferenceGroup; + if ~strlength(value) + value = class(app); + end + value = matlab.lang.makeValidName(value); + end + + + function value = get.Position(app) + value = app.Figure.Position; + end + + function set.Position(app,value) + app.Figure.Position = value; + end + + + function value = get.Visible(app) + value = app.Figure.Visible; + end + + function set.Visible(app,value) + app.Figure.Visible = value; + end + + + function value = get.WindowState(app) + value = app.Figure.WindowState; + end + + function set.WindowState(app,value) + app.Figure.WindowState = value; + end + + end %methods + + + %% Internal properties - properties (Hidden, Transient, NonCopyable, SetAccess = immutable) - + properties (Transient, NonCopyable, SetAccess = immutable) + % Figure window of the app Figure matlab.ui.Figure - + % Primary grid to place contents Grid matlab.ui.container.GridLayout - + end %properties - - - properties (Transient, NonCopyable, Hidden, SetAccess = protected) - + + + properties (Transient, NonCopyable, SetAccess = protected) + % Last used folder (for file operations) LastFolder (1,1) string = pwd - + % Is setup complete? SetupComplete (1,1) logical = false; - + end %properties - - - + + + %% Abstract methods (subclass must implement these) methods (Abstract, Access = protected) - + setup(app) - update(app) - + + end %methods + + methods (Abstract, Access = public) + + close(app) + + end %methods + + + + %% Debugging + properties (Transient) + + % Toggle true to enable debugging display + Debug (1,1) logical = false + end %methods - - - - %% Debugging Methods + + methods - + function forceUpdate(app) % Forces update to run (For debugging only!) - + app.update(); - + + drawnow + end %function - + end %methods - - - + + + %% Constructor / destructor methods (Access = public) - + function app = BaseApp(varargin) % Constructor - + % Create the figure and hide until components are created app.Figure = uifigure( ... 'AutoResizeChildren','off',... @@ -103,21 +167,21 @@ function forceUpdate(app) 'DeleteFcn',@(h,e)delete(app), ... 'CloseRequestFcn',@(h,e)close(app), ... 'Visible','off'); - + % Create MainGridLayout app.Grid = uigridlayout(app.Figure,[1 1]); app.Grid.Padding = [0 0 0 0]; - + % Check for preference input and assign it first, in case % Preferences was subclassed % [splitArgs,varargin] = app.splitArgs('Preferences', varargin{:}); % if ~isempty(splitArgs) % app.Preferences = splitArgs{2}; % end - + % Retrieve preferences app.loadPreferences(); - + % Load last figure position % Note app.Figure.Position is inner position, where % app.Position is outer position. Inner position is the same @@ -126,74 +190,72 @@ function forceUpdate(app) % purpose so it does not depend on if/when any menubar or % toolbar is added to the figure. app.Figure.Position = app.getPreference('Position',[100 100 1000 700]); - + % Set up components app.setup_internal(); app.setup(); - + % Set any P-V pairs if ~isempty(varargin) set(app, varargin{:}); end - + + % Show output if Debug is on + app.displayDebugText(); + % Register the app with App Designer registerApp(app, app.Figure) - + % Ensure it's on screen app.moveOnScreen(); - + % Mark the setup complete app.SetupComplete = true; - + % Update the app app.update(); - + % Update the title app.updateTitle(); - + % Force drawing to finish - drawnow - + drawnow('limitrate') + % Now, make it visible app.Figure.Visible = 'on'; - + end %function - - + + function delete(app) % Destructor - + + % Show output if Debug is on + app.displayDebugText(); + % Store last position in preferences if isscalar(app.Figure) && isvalid(app.Figure) app.setPreference('Position',app.Figure.Position) end - + % Save preferences app.savePreferences(); - + % Now, delete the figure delete(app.Figure) - + end %function - + end %methods - - - + + + %% Public Methods methods - - function close(app) - % Triggered on figure closed - - app.delete(); - - end %function - - + function selection = promptYesNoCancel(app, message, title, default, icon) % Prompt the user with a yes/no/cancel selection - + % Define arguments arguments app (1,1) wt.apps.BaseApp @@ -202,20 +264,23 @@ function close(app) default (1,1) string = "Cancel" icon (1,1) string = "question" end - + + % Show output if Debug is on + app.displayDebugText(); + % Launch the prompt selection = uiconfirm(app.Figure, message, title,... "Options",["Yes","No","Cancel"],... "DefaultOption",default,... "CancelOption","Cancel",... "Icon",icon); - + end %function - - + + function filePath = promptToSaveAs(app, filePath, filter, title) % Prompt the user to save a file - + % Define arguments arguments app (1,1) wt.apps.BaseApp @@ -223,10 +288,13 @@ function close(app) filter = ["*.mat","MATLAB MAT File"]; title (1,1) string = "Save as" end - + + % Show output if Debug is on + app.displayDebugText(); + % Prompt for the file [fileName,pathName] = uiputfile(filter, title, filePath); - + % Did the user cancel? if isequal(fileName,0) filePath = string.empty(0); @@ -234,43 +302,46 @@ function close(app) filePath = fullfile(pathName,fileName); app.LastFolder = pathName; end %if isequal(fileName,0) - + end %function - - + + function filePath = promptToLoad(app, filter, title) % Prompt the user to load a file - + % Define arguments arguments app (1,1) wt.apps.BaseApp filter = ["*.mat","MATLAB MAT File"]; title (1,1) string = "Open" end - + + % Show output if Debug is on + app.displayDebugText(); + % Prompt for the file [fileName,pathName] = uigetfile(filter, title, app.LastFolder); - + % Did the user cancel? if isequal(fileName,0) filePath = string.empty(0); else - filePath = fullfile(pathName,fileName); + filePath = string( fullfile(pathName,fileName) ); app.LastFolder = pathName; end %if isequal(fileName,0) - + end %function - + end %methods - - - + + + %% Sealed Public methods methods (Sealed) - + function value = getPreference(app,propName,defaultValue) % Get an app preference from the Preferences object - + if isprop(app.Preferences, propName) value = app.Preferences.(propName); elseif nargin>2 @@ -278,188 +349,234 @@ function close(app) else value = []; end - + end %function - - + + function setPreference(app,propName,value) % Set an app preference in the Preferences object - + if ~isprop(app.Preferences,propName) addprop(app.Preferences,propName); end app.Preferences.(propName) = value; - + end %function - - + + function moveOnScreen(app) % Ensure the figure is placed on screen - + + % Show output if Debug is on + app.displayDebugText(); + if strcmp(app.Figure.Units,'pixels') - + % Get the corners of each screen g = groot; screenPos = g.MonitorPositions; screenCornerA = screenPos(:,1:2); screenCornerB = screenPos(:,1:2) + screenPos(:,3:4) - 1; - + % Buffer for title bar titleBarHeight = 30; - + % Get the corners of the figure (bottom left and top right) figPos = app.Figure.OuterPosition; figCornerA = figPos(1:2); figCornerB = figPos(1:2) + figPos(:,3:4) - 1; - + % Are the corners on any screen? aIsOnScreen = all( figCornerA >= screenCornerA & ... figCornerA <= screenCornerB, 2 ); bIsOnScreen = all( figCornerB >= screenCornerA & ... figCornerB <= screenCornerB, 2); - + % Are corners on a screen? - + % Are both corners fully on any screen? if any(aIsOnScreen) && any(bIsOnScreen) % Yes - do nothing - + elseif any(bIsOnScreen) % No - only upper right corner is on a screen - + % Calculate the adjustment needed, and make it figAdjust = max(figCornerA, screenCornerA(bIsOnScreen,:)) ... - figCornerA; figPos(1:2) = figPos(1:2) + figAdjust; - + % Ensure the upper right corner still fits figPos(3:4) = min(figPos(3:4), ... screenCornerB(bIsOnScreen,:) - figPos(1:2) - [0 titleBarHeight] + 1); - + % Move the figure app.Figure.Position = figPos; - + elseif any(aIsOnScreen) % No - only lower left corner is on a screen - + % Calculate the adjustment needed, and make it figAdjust = min(figCornerB, screenCornerB(aIsOnScreen,:)) ... - figCornerB; figPos(1:2) = max( screenCornerA(aIsOnScreen,:),... figPos(1:2) + figAdjust ); - + % Ensure the upper right corner still fits figPos(3:4) = min(figPos(3:4), ... screenCornerB(aIsOnScreen,:) - figPos(1:2) - [0 titleBarHeight] + 1); - + % Move the figure app.Figure.Position = figPos; - + else % No - Not on any screen - + % This is slower, but uncommon anyway movegui(app.Figure,'onscreen'); - + end %if any( all(aIsOnScreen,2) & all(bIsOnScreen,2) ) - + else - + % This is slower, but uncommon anyway movegui(app.Figure,'onscreen'); - + end %if strcmp(app.Figure.Units,'pixels') - + end %function - + end %methods - - - + + + %% Protected Methods methods (Access = protected) - function setup_internal(~) + function displayDebugText(app, evt) + % Display the path to the caller function in the command window + + if app.Debug + + stackInfo = dbstack(1,'-completenames'); + fcnName = string(stackInfo(1).name); + filePath = string( stackInfo(1).file ); + namespaces = extractBetween(filePath, "+", "\"); + classname = extractBetween(filePath, "@", "\"); + pathParts = vertcat(namespaces, classname, fcnName); + dispPath = join(pathParts, "."); + appClass = class(app); + + formatStr = ' [%s] %s\n'; + fprintf(formatStr, appClass, filePath, dispPath); + + if nargin >= 2 + fprintf(' --------------------\n Event Data:\n\n'); + disp(evt); + fprintf(' --------------------\n') + end + + end %if + + end %function + + + function setup_internal(app) % Preform internal pre-setup necessary - + + % Show output if Debug is on + app.displayDebugText(); + % This is used for session managed apps - + end %function - - + + function loadPreferences(app) % Load stored preferences - + + % Show output if Debug is on + app.displayDebugText(); + app.Preferences.load(app.PreferenceGroup); - + end %function - - + + function savePreferences(app) % Save preferences - + + % Show output if Debug is on + app.displayDebugText(); + app.Preferences.save(app.PreferenceGroup); - + end %function - - + + function updateTitle(app) % Update the figure title - + + % Show output if Debug is on + app.displayDebugText(); + app.Figure.Name = app.Name; - + end %function - + end %methods - - - - %% Accessors - methods - - function set.Name(app,value) - app.Name = value; - app.updateTitle(); - end - - - function value = get.PreferenceGroup(app) - value = app.PreferenceGroup; - if isempty(value) - value = class(app); - end - value = matlab.lang.makeValidName(value); - end - - - function value = get.Position(app) - value = app.Figure.Position; - end - - function set.Position(app,value) - app.Figure.Position = value; - end - - - function value = get.Visible(app) - value = app.Figure.Visible; - end - - function set.Visible(app,value) - app.Figure.Visible = value; - end - - - function value = get.WindowState(app) - value = app.Figure.WindowState; - end - - function set.WindowState(app,value) - app.Figure.WindowState = value; - end - + + + + %% Display Customization + methods (Access = protected) + + function propGroups = getPropertyGroups(app) + % Customize how the properties are displayed + + import matlab.mixin.util.PropertyGroup + + persistent pGroups + if isempty(pGroups) + + % BaseApp properties + baseAppTitle = " ------ BaseApp Properties ------"; + baseAppProperties = properties("wt.apps.BaseApp"); + usedProps = baseAppProperties; + + % Get properties for concrete class + mc = metaclass(app); + propInfo = mc.PropertyList; + + % Filter out used properties + [~,idxA] = setdiff({propInfo.Name}, usedProps, "stable"); + propInfo = propInfo(idxA); + + % Split out read-only properties + getInfo = {propInfo.GetAccess}; + setInfo = {propInfo.SetAccess}; + isPublicGet = cellfun(@(x)isequal(x,'public'), getInfo); + isPublicSet = cellfun(@(x)isequal(x,'public'), setInfo); + concPublicSetProps = {propInfo(isPublicGet & isPublicSet).Name}; + concProtectedSetProps = {propInfo(isPublicGet & ~isPublicSet).Name}; + + % Set titles + concPublicTitle = " ------ " + app.Name + " Public Properties ------"; + concProtectedTitle = " ------ " + app.Name + " Read-Only Properties ------"; + + pGroups = [ + PropertyGroup(concProtectedSetProps, concProtectedTitle) + PropertyGroup(concPublicSetProps, concPublicTitle) + PropertyGroup(baseAppProperties, baseAppTitle) + ]; + + end %if + + propGroups = pGroups; + + end %function + end %methods - - -end % classdef + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+apps/BaseMultiSessionApp.m b/widgets/+wt/+apps/BaseMultiSessionApp.m new file mode 100644 index 0000000..81ccf41 --- /dev/null +++ b/widgets/+wt/+apps/BaseMultiSessionApp.m @@ -0,0 +1,363 @@ +classdef BaseMultiSessionApp < wt.apps.AbstractSessionApp + % Base class for Widgets Toolbox app with multiple managed sessions + + % Copyright 2024 The MathWorks Inc. + + + %% Properties + properties (AbortSet, SetObservable) + + % Session data for the app (must be subclass of wt.model.BaseSession) + Session + + end %properties + + + %% Read-Only Properties + properties (AbortSet, SetAccess = private) + + % Index of currently selected session + SelectedSessionIndex double ... + {mustBeInteger, mustBePositive, mustBeScalarOrEmpty} = [] + + end %properties + + + properties (AbortSet, Dependent, SetAccess = private) + + % Number of sessions loaded + NumSessions (1,1) double + + % Currently selected session + SelectedSession wt.model.BaseSession + + % Name of the currently selected session + SelectedSessionName + + % File path of the currently selected session + SelectedSessionPath + + end %properties + + + % Accessors + methods + + function value = get.SelectedSessionIndex(app) + value = app.SelectedSessionIndex; + numSessions = app.NumSessions; + if numSessions == 0 + value = []; + elseif value > numSessions + value = app.NumSessions; + end + end + + function value = get.NumSessions(app) + value = numel(app.Session); + end + + function value = get.SelectedSession(app) + value = app.Session( app.SelectedSessionIndex ); + end + + function value = get.SelectedSessionName(app) + session = app.SelectedSession; + if ~isempty(session) && isvalid(session) + value = session.FileName; + else + value = ""; + end + end + + function value = get.SelectedSessionPath(app) + session = app.SelectedSession; + if ~isempty(session) && isvalid(session) + value = session.FilePath; + else + value = ""; + end + end + + end %methods + + + %% Sealed Public methods + methods (Sealed) + + function close(app) + % Close the app + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + end + + % Show output if Debug is on + app.displayDebugText(); + + % Prompt to save existing sessions + for session = app.Session + isCancelled = promptToSaveSession(app, session); + if isCancelled + return + end %if + end %for + + % Close the app + app.close_Internal(); + + end %function + + + function session = newSession(app) + % Start a new session + + % Show output if Debug is on + app.displayDebugText(); + + % Freeze the figure with a progress dialog + dlg = app.showIndeterminateProgress(); + cleanupObj = onCleanup(@()delete(dlg)); + + % Instantiate the new session + session = app.createNewSession(); + + % Store the session + % This also triggers app.update(), app.updateTitle() + if isempty(app.Session) + app.Session = session; + else + app.Session(end+1) = session; + % Don't select by default, but concrete app may do this + end + + end %function + + + function sessionPath = saveSession(app, useSaveAs, session) + % Save the session to a file + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + useSaveAs (1,1) logical = false + session wt.model.BaseSession = app.SelectedSession + end + + % Show output if Debug is on + app.displayDebugText(); + + % Confirm scalar session + if isscalar(session) + + % Call superclass method + app.saveSession_Internal(useSaveAs, session); + + % Populate output + sessionPath = session.FilePath; + + else + + % Throw an error + title = "Save Session"; + message = "No session was selected."; + app.throwError(message, title); + + sessionPath = ""; + + end %if + + end %function + + + function session = loadSession(app, sessionPath) + % Load a session from a file + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + sessionPath (1,1) string = "" + end + + % Show output if Debug is on + app.displayDebugText(); + + % Call superclass internal load method + session = app.loadSession_Internal(sessionPath); + + % Store the session + % This also triggers app.update(), app.updateTitle() + if ~isscalar(session) + % User cancelled + return + elseif isempty(app.Session) + app.Session = session; + else + app.Session(end+1) = session; + % Don't select by default, but concrete app may do this + end + + end %function + + + function closeSession(app, session) + % Close the specified session + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + session wt.model.BaseSession = app.SelectedSession + end + + % Show output if Debug is on + app.displayDebugText(); + + % Exit if session is empty + if isempty(session) || ~isvalid(session) + return + end + + % Call superclass internal close method + isCancelled = app.closeSession_Internal(session); + + % Deselect the closed session + if ~isCancelled + if isequal(app.SelectedSession, session) + emptySession = app.getEmptySession(); + app.selectSession(emptySession) + end + end + + end %function + + + function selectSession(app, session) + % Select the specified session + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + session wt.model.BaseSession + end + + % Was a scalar session given? + if isscalar(session) + + % Which index is the session? + selIdx = find(session == app.Session, 1); + + % Select it + app.SelectedSessionIndex = selIdx; + + else + + % Empty selection + app.SelectedSessionIndex = []; + + end + + % Update the title + app.updateTitle() + + end %function + + end %methods + + + %% Protected Methods + methods (Access = protected) + + function setup_internal(app) + % Preform internal pre-setup necessary + + % Show output if Debug is on + app.displayDebugText(); + + % Instantiate empty session to start + session = app.createNewSession(); + app.Session = session(1,[]); + + end %function + + + function updateTitle(app) + % Update the app title, showing the session name and dirty flag + + % Show output if Debug is on + app.displayDebugText(); + + % Decide on the figure title + session = app.SelectedSession; + if isempty(session) || ~isvalid(session) + app.Figure.Name = app.Name; + elseif session.Dirty + app.Figure.Name = app.Name + " - " + session.FileName + " *"; + else + app.Figure.Name = app.Name + " - " + session.FileName; + end + + end %function + + end %methods + + + %% Display Customization + methods (Access = protected) + + function propGroups = getPropertyGroups(app) + % Customize how the properties are displayed + + import matlab.mixin.util.PropertyGroup + + persistent pGroups + if isempty(pGroups) + + % BaseApp properties + baseAppTitle = " ------ BaseApp Properties ------"; + baseAppProperties = properties("wt.apps.BaseApp"); + usedProps = baseAppProperties; + + % BaseMultiSessionApp Properties + sessionTitle = " ------ BaseMultiSessionApp Properties ------"; + sessionProperties = setdiff(... + properties("wt.apps.BaseMultiSessionApp"), usedProps); + usedProps = [baseAppProperties; sessionProperties]; + + % Get properties for concrete class + mc = metaclass(app); + propInfo = mc.PropertyList; + + % Filter out used properties + [~,idxA] = setdiff({propInfo.Name}, usedProps, "stable"); + propInfo = propInfo(idxA); + + % Split out read-only properties + getInfo = {propInfo.GetAccess}; + setInfo = {propInfo.SetAccess}; + isPublicGet = cellfun(@(x)isequal(x,'public'), getInfo); + isPublicSet = cellfun(@(x)isequal(x,'public'), setInfo); + concPublicSetProps = {propInfo(isPublicGet & isPublicSet).Name}; + concProtectedSetProps = {propInfo(isPublicGet & ~isPublicSet).Name}; + + % Set titles + concPublicTitle = " ------ " + app.Name + " Public Properties ------"; + concProtectedTitle = " ------ " + app.Name + " Read-Only Properties ------"; + + pGroups = [ + PropertyGroup(concProtectedSetProps, concProtectedTitle) + PropertyGroup(concPublicSetProps, concPublicTitle) + PropertyGroup(baseAppProperties, baseAppTitle) + PropertyGroup(sessionProperties, sessionTitle) + ]; + + end %if + + propGroups = pGroups; + + end %function + + end %methods + + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+apps/BaseSingleSessionApp.m b/widgets/+wt/+apps/BaseSingleSessionApp.m index 9168cdd..955841c 100644 --- a/widgets/+wt/+apps/BaseSingleSessionApp.m +++ b/widgets/+wt/+apps/BaseSingleSessionApp.m @@ -1,240 +1,130 @@ -classdef (Abstract) BaseSingleSessionApp < wt.apps.BaseApp +classdef (Abstract) BaseSingleSessionApp < wt.apps.AbstractSessionApp % Base class for Widgets Toolbox app with a managed single session - % Copyright 2020-2021 The MathWorks Inc. + % Copyright 2020-2024 The MathWorks Inc. %% Properties - - properties (AbortSet) + properties (AbortSet, SetObservable) % Session data for the app (must be subclass of wt.model.BaseSession) - Session (1,1) wt.model.BaseSession {mustBeScalarOrEmpty} ... - = wt.model.BaseSession; - - end %properties - - - - %% Internal properties - properties (Dependent, SetAccess = immutable) - - % Indicates if any session is dirty - Dirty (1,1) logical - - % Last used folder (for file operations) - HasValidSession (1,1) logical - - end %properties - - - properties (Transient, NonCopyable, Access = private) - - % Listener to changes within Session object - SessionChangedListener event.listener + Session end %properties - - - - %% Abstract Methods (subclass must implement these) - methods (Abstract, Access = protected) - - % Creates a new session object for the app. It must return a - % subclass of wt.model.BaseSession - sessionObj = createNewSession(app) + + + % Accessors + methods + function set.Session(app,value) + mustBeScalarOrEmpty(value); % Single Session only + app.Session = value; + end + end %methods - - %% Public methods + %% Sealed Public methods methods (Sealed) - function newSession(app) + function close(app) + % Close the app + + % Define arguments + arguments + app (1,1) wt.apps.BaseApp + end + + % Show output if Debug is on + app.displayDebugText(); + + % Prompt to save existing session + isCancelled = promptToSaveSession(app, app.Session); + if isCancelled + return + end %if + + % Close the app + app.close_Internal(); + + end %function + + + function session = newSession(app) % Start a new session + + % Show output if Debug is on + app.displayDebugText(); - % If an existing session is dirty, give the user a chance to - % save before loading another session - if app.Dirty - isCancelled = promptToSaveFirst(app); - if isCancelled - return; - end - end %if app.Dirty + % Prompt to save existing session + isCancelled = promptToSaveSession(app, app.Session); + if isCancelled + session = app.getEmptySession(); + return + end %if % Freeze the figure with a progress dialog - dlg = uiprogressdlg(app.Figure); - dlg.Title = "New Session"; - dlg.Indeterminate = true; + dlg = app.showIndeterminateProgress(); cleanupObj = onCleanup(@()delete(dlg)); % Instantiate the new session - sessionObj = app.createNewSession(); - app.Session = sessionObj; - app.updateTitle(); - - % Force an update prior to the progress dialog closing - drawnow + session = app.createNewSession(); + + % Store the session + % This also triggers app.update(), app.updateTitle() + app.Session = session; end %function - function sessionPath = saveSession(app, useSaveAs) + function sessionPath = saveSession(app, useSaveAs, session) % Save the session to a file % Define arguments arguments app (1,1) wt.apps.BaseApp useSaveAs (1,1) logical = false + session wt.model.BaseSession = app.Session end - - % We must have a session to save! - if ~app.HasValidSession - error("Session does not exist."); - end - - % Get the session info - sessionPath = app.Session.FilePath; - sessionName = app.Session.FileName; - lastFolder = app.LastFolder; - - % Does the session file already exist? - fileExists = exist(sessionPath,"file"); - if ~fileExists - % It doesn't exist - prompt with a default path - useSaveAs = true; - sessionPath = fullfile(lastFolder,sessionName); - end - - % Prompt for "save as" if needed - if useSaveAs - sessionPath = app.promptToSaveAs(sessionPath); - if ~isempty( sessionPath ) - app.Session.FilePath = sessionPath; - end - end - - % Save the file - if strlength(sessionPath) - - % Freeze the figure with a progress dialog - dlg = uiprogressdlg(app.Figure); - dlg.Title = "Save Session"; - dlg.Message = sessionPath; - dlg.Indeterminate = true; - cleanupObj = onCleanup(@()delete(dlg)); - - % Save the session - app.Session.save(); - app.Session.FilePath = sessionPath; - app.Session.Dirty = false; - app.updateTitle(); - - % Force an update prior to the progress dialog closing - drawnow - - end %if strlength(sessionPath) - + + % Show output if Debug is on + app.displayDebugText(); + + % Call superclass internal save method + app.saveSession_Internal(useSaveAs, session); + + % Populate output + sessionPath = session.FilePath; + end %function - - - function loadSession(app, sessionPath) + + + function session = loadSession(app, sessionPath) % Load a session from a file - + % Define arguments arguments app (1,1) wt.apps.BaseApp sessionPath (1,1) string = "" end - - % If an existing session is dirty, give the user a chance to - % save before loading another session - if app.Dirty - isCancelled = promptToSaveFirst(app); - if isCancelled - return; - end - end %if app.Dirty - - % Unless a file was already specified, prompt to load - if ~exist(sessionPath,"file") - sessionPath = app.promptToLoad(); - end - - % Load the file - if strlength(sessionPath) - - % Freeze the figure with a progress dialog - dlg = uiprogressdlg(app.Figure); - dlg.Title = "Load Session"; - dlg.Message = sessionPath; - dlg.Indeterminate = true; - cleanupObj = onCleanup(@()delete(dlg)); - - % Load the session - sessionObj = wt.model.BaseSession.open(sessionPath); - sessionObj.FilePath = sessionPath; - - % Store the session - triggers app.update() - app.Session = sessionObj; - - % Update the title - app.updateTitle(); - - % Force an update prior to the progress dialog closing - drawnow - - end %if strlength(sessionPath) - - end %function - - - function isCancelled = promptToSaveFirst(app) - % Prompt the user to save a file - - % Default output - isCancelled = false; - - % Prompt whether to save - message = sprintf("Save changes to '%s'?",app.Session.FileName); - title = "Load Session"; - selection = app.promptYesNoCancel(message, title); - - % If Yes, prompt to save the existing session first - if selection == "Yes" - sessionSavePath = app.saveSession(); - if ~strlength(sessionSavePath) - isCancelled = true; - end - elseif selection == "Cancel" - isCancelled = true; - end - - end %function - - - function close(app) - % Triggered on figure closed - - % If an existing session is dirty, give the user a chance to - % save before loading another session - if app.Dirty - isCancelled = promptToSaveFirst(app); - if isCancelled - return; - end - end %if app.Dirty - - - % Freeze the figure with a progress dialog - dlg = uiprogressdlg(app.Figure); - dlg.Message = "Closing"; - dlg.Indeterminate = true; - - % Delete the app - app.delete(); - + + % Show output if Debug is on + app.displayDebugText(); + + % Prompt to save existing session + isCancelled = promptToSaveSession(app, app.Session); + if isCancelled + session = app.getEmptySession(); + return + end %if + + % Call superclass internal load method + session = app.loadSession_Internal(sessionPath); + + % Store the session + % This also triggers app.update(), app.updateTitle() + app.Session = session; + end %function end %methods @@ -246,6 +136,9 @@ function close(app) function setup_internal(app) % Preform internal pre-setup necessary + + % Show output if Debug is on + app.displayDebugText(); % Instantiate initial session app.Session = app.createNewSession(); @@ -255,7 +148,11 @@ function setup_internal(app) function updateTitle(app) % Update the app title, showing the session name and dirty flag + + % Show output if Debug is on + app.displayDebugText(); + % Decide on the figure title if ~app.HasValidSession app.Figure.Name = app.Name; elseif app.Session.Dirty @@ -267,65 +164,65 @@ function updateTitle(app) end %function end %methods - - - - %% Private Methods - methods (Access = private) - - function onSessionChanged(app,~) - % Triggered when a SetObservable property in the session has - % changed. May be overridden for custom behavior using incoming - % event data. - - % Trigger an update - app.update(); - - end %function - - - function onSessionChanged_private(app,e) - - % Update the app title - app.updateTitle(); - - % Call the app's session changed method - app.onSessionChanged(e); - - end %function - - - function attachSessionListeners(app) - - app.SessionChangedListener = event.listener(app.Session,... - 'PropertyChanged',@(h,e)onSessionChanged_private(app,e)); - + + + + %% Display Customization + methods (Access = protected) + + function propGroups = getPropertyGroups(app) + % Customize how the properties are displayed + + import matlab.mixin.util.PropertyGroup + + persistent pGroups + if isempty(pGroups) + + % BaseApp properties + baseAppTitle = " ------ BaseApp Properties ------"; + baseAppProperties = properties("wt.apps.BaseApp"); + usedProps = baseAppProperties; + + % BaseSingleSessionApp Properties + sessionTitle = " ------ BaseSingleSessionApp Properties ------"; + sessionProperties = setdiff(... + properties("wt.apps.BaseSingleSessionApp"), usedProps); + usedProps = [baseAppProperties; sessionProperties]; + + % Get properties for concrete class + mc = metaclass(app); + propInfo = mc.PropertyList; + + % Filter out used properties + [~,idxA] = setdiff({propInfo.Name}, usedProps, "stable"); + propInfo = propInfo(idxA); + + % Split out read-only properties + getInfo = {propInfo.GetAccess}; + setInfo = {propInfo.SetAccess}; + isPublicGet = cellfun(@(x)isequal(x,'public'), getInfo); + isPublicSet = cellfun(@(x)isequal(x,'public'), setInfo); + concPublicSetProps = {propInfo(isPublicGet & isPublicSet).Name}; + concProtectedSetProps = {propInfo(isPublicGet & ~isPublicSet).Name}; + + % Set titles + concPublicTitle = " ------ " + app.Name + " Public Properties ------"; + concProtectedTitle = " ------ " + app.Name + " Read-Only Properties ------"; + + pGroups = [ + PropertyGroup(concProtectedSetProps, concProtectedTitle) + PropertyGroup(concPublicSetProps, concPublicTitle) + PropertyGroup(baseAppProperties, baseAppTitle) + PropertyGroup(sessionProperties, sessionTitle) + ]; + + end %if + + propGroups = pGroups; + end %function - + end %methods - - - - %% Accessors - methods - - function set.Session(app,value) - app.Session = value; - if app.SetupComplete - app.update(); - end - app.attachSessionListeners(); - end - - function value = get.HasValidSession(app) - value = ~isempty(app.Session) && isvalid(app.Session); - end - - function value = get.Dirty(app) - value = app.HasValidSession && app.Session.Dirty; - end - - end %methods - - -end %classdef + + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+enum/ArrayRestriction.m b/widgets/+wt/+enum/ArrayRestriction.m new file mode 100644 index 0000000..62091b6 --- /dev/null +++ b/widgets/+wt/+enum/ArrayRestriction.m @@ -0,0 +1,15 @@ +classdef ArrayRestriction + %ARRAYRESTRICTION Represent array restriction selections + % Enumerates a list of choices + + % Copyright 2024 The MathWorks Inc. + + + %% Enumerations + enumeration + none + increasing + decreasing + end %enumeration + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/ListManagerEventData.m b/widgets/+wt/+eventdata/ListManagerEventData.m new file mode 100644 index 0000000..511ed2c --- /dev/null +++ b/widgets/+wt/+eventdata/ListManagerEventData.m @@ -0,0 +1,14 @@ +classdef ListManagerEventData < event.EventData + % Event data for list manager change events + + % Copyright 2024 The MathWorks, Inc. + + %% Properties + properties + Action (1,1) string + Item (1,1) string + ItemData + Index double {mustBeInteger, mustBeNonnegative, mustBeScalarOrEmpty} + end %properties + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/ModelChangedData.m b/widgets/+wt/+eventdata/ModelChangedData.m new file mode 100644 index 0000000..08df238 --- /dev/null +++ b/widgets/+wt/+eventdata/ModelChangedData.m @@ -0,0 +1,15 @@ +classdef ModelChangedData < event.EventData + % Event data for model changes + + % Copyright 2024 The MathWorks, Inc. + + %% Properties + properties %(SetAccess = ?wt.model.BaseModel) + Model + Property string {mustBeScalarOrEmpty} + Value + Stack (1,:) cell + ClassStack (1,:) string + end %properties + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/ModelSetData.m b/widgets/+wt/+eventdata/ModelSetData.m new file mode 100644 index 0000000..38edbe0 --- /dev/null +++ b/widgets/+wt/+eventdata/ModelSetData.m @@ -0,0 +1,12 @@ +classdef ModelSetData < event.EventData + % Event data for model set + + % Copyright 2024 The MathWorks, Inc. + + %% Properties + properties + Model + Controller + end %properties + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/PropertyChangedData.m b/widgets/+wt/+eventdata/PropertyChangedData.m index b83d1ef..1a3e0a6 100644 --- a/widgets/+wt/+eventdata/PropertyChangedData.m +++ b/widgets/+wt/+eventdata/PropertyChangedData.m @@ -7,7 +7,7 @@ % obj = wt.eventdata.PropertyChangedData(...,'p1',v1,...) % - % Copyright 2020-2021 The MathWorks, Inc. + % Copyright 2020-2024 The MathWorks, Inc. %% Properties properties (SetAccess = protected) @@ -23,33 +23,40 @@ % Set the changed property name obj.Property = propName; - + % Is input a MATLAB eventdata? if isa(newValue,'matlab.ui.eventdata.ValueChangedData') + obj.Value = newValue.Value; obj.PreviousValue = newValue.PreviousValue; + elseif isa(newValue,'matlab.ui.eventdata.ValueChangingData') + obj.Value = newValue.Value; + else + % No - use the value directly obj.Value = newValue; - end - - % Was a previous value provided? - if mod(numel(varargin),2) - obj.PreviousValue = varargin{1}; - varargin(1) = []; - end - + + % Was a previous value provided? + if mod(numel(varargin),2) + obj.PreviousValue = varargin{1}; + varargin(1) = []; + end + + end %if + % Any remaining varargin are dynamic property-value pairs - for idx=1:numel(varargin) + for idx=1:2:numel(varargin) thisProp = varargin{idx}; - thisValue = remArgs.(thisProp); + thisValue = varargin{idx+1}; obj.addprop(thisProp); obj.(thisProp) = thisValue; end end %constructor + end %methods end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/RowEntriesTableChangedData.m b/widgets/+wt/+eventdata/RowEntriesTableChangedData.m new file mode 100644 index 0000000..91157b4 --- /dev/null +++ b/widgets/+wt/+eventdata/RowEntriesTableChangedData.m @@ -0,0 +1,19 @@ +classdef RowEntriesTableChangedData < event.EventData + % Event data for table changed events + + % Copyright 2024 The MathWorks, Inc. + + %% Properties + properties + Action (1,1) string + Row double + Column double + EditValue string {mustBeScalarOrEmpty} + Value + PreviousValue + TableData + PreviousTableData + Error + end %properties + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/SliderCheckboxChangedData.m b/widgets/+wt/+eventdata/SliderCheckboxChangedData.m index f2427e3..02b66de 100644 --- a/widgets/+wt/+eventdata/SliderCheckboxChangedData.m +++ b/widgets/+wt/+eventdata/SliderCheckboxChangedData.m @@ -5,7 +5,7 @@ % obj = wt.eventdata.SliderCheckboxChangedData(name,index,prop,state,value) % - % Copyright 2020-2021 The MathWorks, Inc. + % Copyright 2020-2024 The MathWorks, Inc. %% Properties properties (SetAccess = protected) diff --git a/widgets/+wt/+eventdata/TreeModelSingleSelectionData.m b/widgets/+wt/+eventdata/TreeModelSingleSelectionData.m new file mode 100644 index 0000000..8604e06 --- /dev/null +++ b/widgets/+wt/+eventdata/TreeModelSingleSelectionData.m @@ -0,0 +1,90 @@ +classdef TreeModelSingleSelectionData < event.EventData + % Event data for tree model selection for a single-node selection tree + + % Copyright 2024 The MathWorks, Inc. + + + %% Properties + properties + Node matlab.ui.container.TreeNode {mustBeScalarOrEmpty} + end %properties + + properties (SetAccess = protected) + NodeTag (1,1) string = "" + SelectionPath (1,:) matlab.ui.container.TreeNode + SelectionPathTag (1,:) string + end %properties + + properties + Model wt.model.BaseModel {mustBeScalarOrEmpty} + Session wt.model.BaseSession {mustBeScalarOrEmpty} + end %properties + + + % Accessors + methods + function set.Node(obj, value) + obj.Node = value; + obj.findNodeTag(value); + obj.findSelectionPath(value); + end + end + + + %% Dependent Properties + properties (Dependent, SetAccess = protected) + ModelClass (1,1) string + ModelType (1,1) string + end %properties + + % Accessors + methods + function value = get.ModelClass(obj) + value = string(class(obj.Model)); + end + function value = get.ModelType(obj) + value = extract(obj.ModelClass, alphanumericsPattern + textBoundary); + end + end + + + %% Methods + methods (Access = private) + + function findNodeTag(obj, node) + % Populates the tag of selected node(s) + + if isempty(node) + obj.NodeTag = ""; + else + obj.NodeTag = string(node.Tag); + end + + end %function + + + function pathOut = findSelectionPath(obj, pathIn) + % Find the full selection path from a given node + + if isempty(pathIn) || ~isa(pathIn, "matlab.ui.container.TreeNode") + pathOut = matlab.ui.container.TreeNode.empty(1,0); + elseif isa(pathIn.Parent, "matlab.ui.container.TreeNode") + pathOut = horzcat(obj.findSelectionPath(pathIn.Parent), pathIn); + else + pathOut = pathIn; + end + + if ~nargout + obj.SelectionPath = pathOut; + if isempty(pathOut) + obj.SelectionPathTag = string.empty(1,0); + else + obj.SelectionPathTag = string({pathOut.Tag}'); + end + end + + end %function + + end %methods + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/+eventdata/ValueChangedData.m b/widgets/+wt/+eventdata/ValueChangedData.m index ed8d763..341fd2a 100644 --- a/widgets/+wt/+eventdata/ValueChangedData.m +++ b/widgets/+wt/+eventdata/ValueChangedData.m @@ -7,7 +7,7 @@ % obj = wt.eventdata.ValueChangedData(...,'p1',v1,...) % - % Copyright 2020-2021 The MathWorks, Inc. + % Copyright 2020-2024 The MathWorks, Inc. %% Properties properties (SetAccess = protected) @@ -18,26 +18,41 @@ %% Constructor / destructor methods - function obj = ValueChangedData(newValue, previousValue) - - arguments - newValue - previousValue = [] - end - + function obj = ValueChangedData(newValue,varargin) + % Is input a MATLAB eventdata? if isa(newValue,'matlab.ui.eventdata.ValueChangedData') + obj.Value = newValue.Value; obj.PreviousValue = newValue.PreviousValue; + elseif isa(newValue,'matlab.ui.eventdata.ValueChangingData') + obj.Value = newValue.Value; + else + % No - use the value directly obj.Value = newValue; - obj.PreviousValue = previousValue; + + % Was a previous value provided? + if mod(numel(varargin),2) + obj.PreviousValue = varargin{1}; + varargin(1) = []; + end + + end %if + + % Any remaining varargin are dynamic property-value pairs + for idx=1:2:numel(varargin) + thisProp = varargin{idx}; + thisValue = varargin{idx+1}; + obj.addprop(thisProp); + obj.(thisProp) = thisValue; end - + end %constructor + end %methods end % classdef \ No newline at end of file diff --git a/widgets/+wt/+mixin/ButtonColorable.m b/widgets/+wt/+mixin/ButtonColorable.m index 21e1463..0a31b64 100644 --- a/widgets/+wt/+mixin/ButtonColorable.m +++ b/widgets/+wt/+mixin/ButtonColorable.m @@ -8,7 +8,7 @@ properties (AbortSet) % Button Color - ButtonColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [1 1 1] * 0.96 + ButtonColor (1,3) double {mustBeInRange(ButtonColor,0,1)} = [1 1 1] * 0.96 end %properties diff --git a/widgets/+wt/+mixin/DisplayNonScalarObjectAsTable.m b/widgets/+wt/+mixin/DisplayNonScalarObjectAsTable.m index 5c15c4e..e156bc6 100644 --- a/widgets/+wt/+mixin/DisplayNonScalarObjectAsTable.m +++ b/widgets/+wt/+mixin/DisplayNonScalarObjectAsTable.m @@ -5,13 +5,7 @@ % display an array of objects as a table. % - % Copyright 2018-2019 The MathWorks, Inc. - % - % Auth/Revision: - % MathWorks Consulting - % $Author: rjackey $ - % $Revision: 348 $ $Date: 2018-03-02 15:51:54 -0500 (Fri, 02 Mar 2018) $ - % --------------------------------------------------------------------- + % Copyright 2018-2024 The MathWorks, Inc. %% Public Methods @@ -80,7 +74,7 @@ function displayNonScalarObject(obj) % Show the group list in a table disp( obj.toDisplayTable() ); - if isa(obj,'handle') && any(~isvalid(obj)) + if isa(obj,'handle') && any(~isvalid(obj(:))) fprintf(' Object array contains deleted handles.\n'); end diff --git a/widgets/+wt/+mixin/ErrorHandling.m b/widgets/+wt/+mixin/ErrorHandling.m index 93e023f..5e8600d 100644 --- a/widgets/+wt/+mixin/ErrorHandling.m +++ b/widgets/+wt/+mixin/ErrorHandling.m @@ -12,7 +12,7 @@ function throwError(obj,err,title) arguments obj (1,1) wt.mixin.ErrorHandling err % string or MException - title (1,1) string = "Error" + title (1,1) string = "Internal Error in " + class(obj) end % Prepare the message @@ -25,7 +25,7 @@ function throwError(obj,err,title) % Locate ancestor figure if isprop(obj,"Figure") - fig = obj.Figure; + fig = obj.Figure; %#ok else fig = ancestor(obj,'figure'); end @@ -55,7 +55,7 @@ function throwError(obj,err,title) % Locate ancestor figure if isprop(obj,"Figure") - fig = obj.Figure; + fig = obj.Figure; %#ok else fig = ancestor(obj,'figure'); end @@ -76,12 +76,61 @@ function throwError(obj,err,title) function dlg = showIndeterminateProgress(obj,title,message,cancelOn) % Places an indeterminate progress dialog in the widget's figure + % Validate arguments + arguments + obj (1,1) wt.mixin.ErrorHandling + title (1,1) string = "Please Wait" + message (1,1) string = "" + cancelOn (1,1) logical = false + end + dlg = showProgress(obj,title,message,cancelOn); dlg.Indeterminate = true; end %function - end%methods + + function result = promptForConfirmation(obj,message,title,buttonNames) + % Places an indeterminate progress dialog in the widget's figure + + % Validate arguments + arguments (Input) + obj (1,1) wt.mixin.ErrorHandling + message (1,1) string = "Are you sure?" + title (1,1) string = "" + buttonNames (1,2) string = ["Yes","Cancel"] + end + + arguments (Output) + result (1,1) logical + end + + % Locate ancestor figure + if isprop(obj,"Figure") + fig = obj.Figure; %#ok + else + fig = ancestor(obj,'figure'); + end + + % Place in a dialog if possible + if isempty(fig) + + id = "wt:mixin:ErrorHandling:NoFigure"; + msg = "No figure is present to place the dialog."; + warning(id,msg); + result = false; + + else + + selection = uiconfirm(fig, message, title,... + "Options", buttonNames, "DefaultOption", 2); + result = matches(buttonNames(1), selection); + + end + + end %function + + end %methods end %classdef diff --git a/widgets/+wt/+mixin/FieldColorable.m b/widgets/+wt/+mixin/FieldColorable.m index e94ce97..5bc67ed 100644 --- a/widgets/+wt/+mixin/FieldColorable.m +++ b/widgets/+wt/+mixin/FieldColorable.m @@ -8,7 +8,7 @@ properties (AbortSet) % Field Color - FieldColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [1 1 1] + FieldColor (1,3) double {mustBeInRange(FieldColor,0,1)} = [1 1 1] end %properties diff --git a/widgets/+wt/+mixin/FontColorable.m b/widgets/+wt/+mixin/FontColorable.m index df51f0e..ac95146 100644 --- a/widgets/+wt/+mixin/FontColorable.m +++ b/widgets/+wt/+mixin/FontColorable.m @@ -8,7 +8,7 @@ properties (AbortSet) % Font color - FontColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [0 0 0] + FontColor (1,3) double {mustBeInRange(FontColor,0,1)} = [0 0 0] end %properties diff --git a/widgets/+wt/+mixin/FontStyled.m b/widgets/+wt/+mixin/FontStyled.m index abe3235..4606209 100644 --- a/widgets/+wt/+mixin/FontStyled.m +++ b/widgets/+wt/+mixin/FontStyled.m @@ -20,7 +20,7 @@ FontAngle {mustBeMember(FontAngle,{'normal','italic'})} = 'normal' % Font color - FontColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [0 0 0] + FontColor (1,3) double {mustBeInRange(FontColor,0,1)} = [0 0 0] end %properties diff --git a/widgets/+wt/+mixin/ModelObserver.m b/widgets/+wt/+mixin/ModelObserver.m new file mode 100644 index 0000000..9521624 --- /dev/null +++ b/widgets/+wt/+mixin/ModelObserver.m @@ -0,0 +1,162 @@ +classdef (Abstract, AllowedSubclasses = ... + {?wt.abstract.BaseViewController, ?wt.abstract.BaseViewChart})... + ModelObserver < handle + % Mixin for components using a model that observe changes + + + %% Abstract Properties + % Subclass must define these + properties (Abstract, AbortSet, SetObservable) + + % Model class containing data to display in the pane + Model wt.model.BaseModel + + end %properties + + + %% Events + events (NotifyAccess = protected) + + % Triggered when the Model has changed + ModelSet + + % Triggered when a property within the model has changed + ModelChanged + + end %events + + + %% Internal Properties + properties (SetAccess = protected) + + % Listener for a new model being attached + ModelSetListener event.listener + + % Listener for property changes within the model + ModelChangedListener event.listener + + end %properties + + + %% Constructor + methods + function obj = ModelObserver() + % Constructor + + % Listen to Model property being set + obj.ModelSetListener = listener(obj,"Model","PostSet",@(~,~)onModelSet(obj)); + + % Listen to model changes + obj.attachModelListeners(); + + end %function + end %methods + + + + %% Protected Methods + methods (Access = protected) + + function onModelSet(obj) + % Triggered when Model has been changed + + % Listen to model property changes + obj.attachModelListeners(); + + % Prepare event data + evtOut = wt.eventdata.ModelSetData(); + evtOut.Model = obj.Model; + evtOut.Controller = obj; + + % Notify listeners + notify(obj,"ModelSet",evtOut) + + end %function + + + function attachModelListeners(obj) + % Triggered when Model has been changed + + % Listen to model property changes + obj.ModelChangedListener = listener(obj.Model,... + "ModelChanged", @(~,evt)onModelChanged(obj,evt)); + + end %function + + + function onModelChanged(obj,evt) + % Triggered when a property within the model has changed + + arguments + obj (1,1) wt.mixin.ModelObserver + evt (1,1) wt.eventdata.ModelChangedData + end + + % Prepare eventdata + evtOut = wt.eventdata.ModelChangedData; + evtOut.Model = evt.Model; + evtOut.Property = evt.Property; + evtOut.Value = evt.Value; + evtOut.Stack = [{obj}, evt.Stack]; + evtOut.ClassStack = [class(obj), evt.ClassStack]; + + % Notify listeners + notify(obj,"ModelChanged",evtOut) + + end %function + + + function className = getModelClassName(obj) + % Returns the class name of the Model property contents + + arguments (Input) + obj (1,1) wt.mixin.ModelObserver + end + + arguments (Output) + className (1,1) string + end + + % Get the class of the Model array + className = string( class( obj.Model ) ); + + end %function + + + function newModel = constructDefaultModel(obj) + % Generates a scalar object instance of the class name used in + % the Model property. The model must be instantiated with no + % input arguments + + arguments + obj (1,1) wt.mixin.ModelObserver + end + + % Construct a new object + className = getModelClassName(obj); + fcnConstruct = str2func(className); + newModel = fcnConstruct(); + + end %function + + + function [model, validToDisplay] = getScalarModelToDisplay(obj) + + % Get a single instance of the correct model type and indicate + % if it's found and valid. This is useful in case obj.Model is + % empty, it will still return a scalar instance to show default + % values and the modelValid flag will be false, indicating to + % disable the fields. + model = obj.Model; + validToDisplay = isscalar(model) && isvalid(model); + if ~validToDisplay + model = obj.constructDefaultModel(); + end + validToDisplay = matlab.lang.OnOffSwitchState(validToDisplay); + + end %function + + end %methods + + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+mixin/Orderable.m b/widgets/+wt/+mixin/Orderable.m new file mode 100644 index 0000000..188f980 --- /dev/null +++ b/widgets/+wt/+mixin/Orderable.m @@ -0,0 +1,138 @@ +classdef (HandleCompatible) Orderable + % Implements functionality for orderable lists + + + %% Internal Static methods + methods (Static, Access = protected) + + function [idxNew, idxSelAfter] = shiftListIndices(shift, numItems, idxSel) + % Shift the selected indices up/down within a list + + % Define arguments + arguments (Input) + % Shift amount and direction (typically 1 or -1) + shift (1,1) double {mustBeInteger} + + % Total number of items in the list + numItems (1,1) double {mustBeInteger, mustBeNonnegative} + + % Selected indices to move + idxSel (1,:) double {mustBeInteger, mustBePositive, mustBeLessThanOrEqual(idxSel,numItems)} + end + + arguments (Output) + % Indices of the complete list after re-ordering + idxNew (1,:) double {mustBeInteger, mustBePositive} + + % Indices where the selected data end up after the move + idxSelAfter (1,:) double {mustBeInteger, mustBePositive} + end + + % Make indices to all items as they are now + idxNew = 1:numItems; + + % Allocate the final indices + idxSelAfter = idxSel; + + % Find the last stable item that doesn't move + [~,idxStable] = setdiff(idxNew, idxSel, 'stable'); + if ~isempty(idxStable) + idxFirstStable = idxStable(1); + idxLastStable = idxStable(end); + else + idxFirstStable = inf; + idxLastStable = 0; + end + + % Which way do we loop? + if shift > 0 %Shift to end + + for idxToMove = numel(idxSel):-1:1 + + % Calculate if there's room to move this item + idxThisBefore = idxSel(idxToMove); + thisShift = max( min(idxLastStable-idxThisBefore, shift), 0 ); + + % Where does this item move from/to + idxThisAfter = idxThisBefore + thisShift; + idxSelAfter(idxToMove) = idxThisAfter; + + % Where do other items move from/to + idxOthersBefore = idxSel(idxToMove)+1:1:idxThisAfter; + idxOthersAfter = idxOthersBefore - thisShift; + + % Move the items + idxNew([idxThisAfter idxOthersAfter]) = idxNew([idxThisBefore idxOthersBefore]); + + end + + elseif shift < 0 %Shift to start + + for idxToMove = 1:numel(idxSel) + + % Calculate if there's room to move this item + idxThisBefore = idxSel(idxToMove); + thisShift = min( max(idxFirstStable-idxThisBefore, shift), 0 ); + + % Where does this item move from/to + idxThisAfter = idxThisBefore + thisShift; + idxSelAfter(idxToMove) = idxThisAfter; + + % Where do other items move from/to + idxOthersBefore = idxThisAfter:1:idxSel(idxToMove)-1; + idxOthersAfter = idxOthersBefore - thisShift; + + % Move the items + idxNew([idxThisAfter idxOthersAfter]) = idxNew([idxThisBefore idxOthersBefore]); + + end + + end %if shift > 0 + + end %function + + + function [backEnabled, fwdEnabled] = areOrderButtonsEnabled(numItems, idxSel, allowSortItem) + % Determine whether back/forward (down/up) buttons should be + % enabled or not given the selection index + + % Define arguments + arguments (Input) + % Total number of items in the list + numItems (1,1) double {mustBeInteger, mustBeNonnegative} + + % Selected indices + idxSel (1,:) double {mustBeInteger, mustBePositive, mustBeLessThanOrEqual(idxSel,numItems)} + + % Indicates whether each individual item may be sorted + allowSortItem (1,:) logical = true(1, numItems); + end + + arguments (Output) + % Should back (up) button be enabled? + backEnabled (1,1) logical + + % Should forward (down) button be enabled? + fwdEnabled (1,1) logical + end + + % How many items selected? + numSel = numel(idxSel); + + % Only sortable items selected + selIsSortable = (numSel > 0) && all( allowSortItem(idxSel) ); + + % Enable back (up)? + idxMinSortable = find(allowSortItem,1,"first"); + backEnabled = selIsSortable && (max(idxSel) > (numSel + idxMinSortable - 1) ); + + % Enable forward (down)? + idxMaxSortable = find(allowSortItem,1,"last"); + fwdEnabled = selIsSortable && (min(idxSel) <= (idxMaxSortable - numSel)); + + end %function + + end %methods + + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+mixin/TitleColorable.m b/widgets/+wt/+mixin/TitleColorable.m index 76d7001..9fa8e68 100644 --- a/widgets/+wt/+mixin/TitleColorable.m +++ b/widgets/+wt/+mixin/TitleColorable.m @@ -8,7 +8,7 @@ properties (AbortSet) % Title color - TitleColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [0 0 0] + TitleColor (1,3) double {mustBeInRange(TitleColor,0,1)} = [0 0 0] end %properties diff --git a/widgets/+wt/+model/BaseModel.m b/widgets/+wt/+model/BaseModel.m index 9efc058..39af8b2 100644 --- a/widgets/+wt/+model/BaseModel.m +++ b/widgets/+wt/+model/BaseModel.m @@ -1,98 +1,269 @@ -classdef (Abstract) BaseModel < handle & ... +classdef BaseModel < handle & ... matlab.mixin.SetGetExactNames & ... + matlab.mixin.Copyable & ... wt.mixin.DisplayNonScalarObjectAsTable % Base model class for apps that provides: % PV pairs assignment on construction + % % Display nonscalar arrays in table format + % % Public PropertyChanged event for properties tagged as SetObservable % to enable apps/widgets to listen to model changes - % + % + % Public ModelChanged event for recursive property change + % notifications in a hierarchy of BaseWidget classes + % + + % Copyright 2020-2024 The MathWorks, Inc. + - % Copyright 2020-2023 The MathWorks, Inc. - - %% Events events - + % Triggered when SetObservable properties are changed - PropertyChanged - + PropertyChanged + + % Triggered when an aggregated / nested model has changed + ModelChanged + end %events - - - + + + %% Inputs - Public Properties + properties (AbortSet, SetObservable) + + % Name of this item + Name (1,1) string = "" + + end %properties + + + % Accessors + methods + + function value = get.Name(obj) + % If a name has been specified, use it. Else, the concrete + % class may customize what the default name should be. + if strlength(obj.Name) > 0 + value = obj.Name; + else + value = obj.getDefaultName(); + end + end %function + + end %methods + + + %% Internal Properties + properties (Transient, Hidden) + + % Toggle true in each instance to enable debugging display + Debug (1,1) logical = false + + end %properties + + properties (Transient, NonCopyable, Hidden, SetAccess = private) - + % Listeners to public properties PropListeners - + + end %properties + + + properties (Transient, NonCopyable, Access = private) + + % Listeners to any aggregated / nested handle class models + AggregatedModelListeners + end %properties - - - + + + properties (Hidden, AbortSet) + % These are used internally and functionality may change in the + % future + + % Enables change listeners + EnableChangeListeners (1,1) logical = true + + % Enables nested model listeners to trigger onModelChanged event + EnableAggregatedModelListeners (1,1) logical = true + + end %properties + + + % Accessors + methods + function set.EnableAggregatedModelListeners(obj,value) + obj.EnableAggregatedModelListeners = value; + if value + obj.attachModelListeners() + else + obj.clearModelListeners() + end + end + end %methods + + %% Constructor methods function obj = BaseModel(varargin) % Constructor - + % Populate public properties from P-V input pairs if nargin obj.assignPVPairs(varargin{:}); end - + % Create listeners to public properties obj.createPropListeners(); - - end %function obj = ObjectModel(varargin) + + % Create listeners to aggregated model classes that may have + % property change events + for idx = 1:numel(obj) + if obj(idx).EnableAggregatedModelListeners + obj(idx).attachModelListeners(); + end + end + + end %function end %methods - - - + + + %% Static methods methods (Static) - + function obj = loadobj(obj) % Customize loading from file - + if isstruct(obj) error('Unable to load object.'); end - + % Need to recreate listeners obj.createPropListeners(); - + + for idx = 1:numel(obj) + if obj(idx).EnableAggregatedModelListeners + obj(idx).attachModelListeners(); + end + end + end %function - + end %methods - - - + + + + %% Public methods + methods + + function debugAggregatedModels(obj, value) + % Recursively set debug on aggregated models in the hierarchy + + arguments + obj (1,1) wt.model.BaseModel + value (1,1) logical = true; + end + + % Debug this model + obj.Debug = value; + + % Loop on aggregated models and set debug + aggProps = obj.getAggregatedModelProperties(); + for thisProp = aggProps + thisModel = obj.(thisProp); + if ~isempty(thisModel) && all(isa(thisModel,"handle")) + thisModel(~isvalid(thisModel)) = []; + for idx = 1:numel(thisModel) + thisModel(idx).debugAggregatedModels(value); + end + end + end + + end %function + + end %methods + + + %% Protected Methods - - methods (Access=protected) + methods (Access = protected) + + function name = getDefaultName(~) + % Defines what the default name should be. A subclass may + % override this to customize the default name. + + name = ""; + + end %function - % This method is similar to - % matlab.io.internal.mixin.HasPropertiesAsNVPairs, but this one - % generally performs faster. + + function props = getAggregatedModelProperties(~) + % Returns a list of aggregated model property names + % + % This overridable method lists properties containing + % aggregated BaseModel classes to listen for hierarchical + % ModelChanged events. Use this cautiously if model class + % references are used repeatedly. The intended purpose is to + % pass notifications up the hierarchy to the top level, so the + % session can be marked dirty. + + arguments(Output) + props (1,:) string + end + + props = string.empty(1,0); + end %function + + + function cpObj = copyElement(obj) + % Override copyElement method + + if obj.Debug + disp("wt.model.BaseModel.copyElement " + class(obj)); + end + + % Call superclass method + cpObj = copyElement@matlab.mixin.Copyable(obj); + + % Perform deep copy of any aggregated handle properties + props = obj.getAggregatedModelProperties(); + for thisProp = props + cpObj.(thisProp) = copy( obj.(thisProp) ); + end + + % Create listeners + cpObj.createPropListeners(); + cpObj.attachModelListeners(); + + end %function + + function varargout = assignPVPairs(obj,varargin) % Assign the specified property-value pairs - + + % This method is similar to + % matlab.io.internal.mixin.HasPropertiesAsNVPairs, but this one + % generally performs faster. + if nargin > 1 - + % Get a singleton parser for this class keepUnmatched = nargout > 0; p = getParser(obj, keepUnmatched); - + % Parse the P-V pairs p.parse(varargin{:}); - + % Set just the parameters the user passed in - ParamNamesToSet = varargin(1:2:end); + ParamNamesToSet = p.Parameters; ParamsInResults = fieldnames(p.Results); - + % Assign properties for ThisName = ParamNamesToSet isSettable = any(strcmpi(ThisName,ParamsInResults)); @@ -100,66 +271,223 @@ obj.(ThisName{1}) = p.Results.(ThisName{1}); end end - + % Return unmatched pairs if nargout varargout{1} = p.Unmatched; end - + elseif nargout - + varargout{1} = struct; - + end %if nargin > 1 - + end %function - - + + function createPropListeners(obj) - + % Create listeners to SetObservable properties in this class + + if obj.Debug + disp("wt.model.BaseModel.createPropListeners " + class(obj)); + end + + % Loop on each instance (typically scalar though) for idx = 1:numel(obj) - mc = metaclass(obj(idx)); + + % Get one instance + thisObj = obj(idx); + + % Which properties are observable? + mc = metaclass(thisObj); isObservable = [mc.PropertyList.SetObservable]; - props = mc.PropertyList(isObservable); - obj(idx).PropListeners = event.proplistener(obj(idx),props,... - 'PostSet',@(h,e)onPropChanged(obj(idx),e) ); + propInfo = mc.PropertyList(isObservable); + + % Attach listeners to observable properties + thisObj.PropListeners = event.proplistener(thisObj, propInfo,... + 'PostSet',@(~,e)onPropChanged(thisObj,e) ); + end %for - + end %function - - - function onPropChanged(obj,e) - - evt = wt.eventdata.PropertyChangedData(e.Source.Name, obj.(e.Source.Name)); - obj.notify('PropertyChanged',evt) - + + + function onPropChanged(obj,evt) + + arguments + obj (1,1) wt.model.BaseModel + evt (1,1) event.PropertyEvent + end + + if obj.Debug + disp("wt.model.BaseModel.onPropChanged " + ... + " Model: " + class(evt.AffectedObject) + ... + " Prop: " + evt.Source.Name + ... + " Class: " + class(obj)); + end + + % Return now if disabled + if ~obj.EnableChangeListeners + return + end + + % Notify listeners + evtOutP = wt.eventdata.PropertyChangedData(... + evt.Source.Name, obj.(evt.Source.Name)); + obj.notify("PropertyChanged",evtOutP) + + % Prepare model change eventdata + evtOutM = wt.eventdata.ModelChangedData; + evtOutM.Property = evt.Source.Name; + evtOutM.Model = evt.AffectedObject; + evtOutM.Value = evtOutM.Model.(evtOutM.Property); + % evtOutM.Stack = {obj}; + % evtOutM.ClassStack = class(obj); + + % Revise listeners for model changes given the new value + if isa(evtOutM.Value, "wt.model.BaseModel") + evtOutM.Model.attachModelListeners(); + end + + % Call onModelChanged method + obj.onModelChanged(evtOutM); + end %function - + + + function onModelChanged(obj,evt) + % Runs on property changes to this class or an aggregated BaseModel + % class + + arguments + obj (1,1) wt.model.BaseModel + evt (1,1) wt.eventdata.ModelChangedData + end + + % Return now if disabled + if ~obj.EnableChangeListeners + return + end + + % Prepare eventdata + evtOut = wt.eventdata.ModelChangedData; + evtOut.Model = evt.Model; + evtOut.Property = evt.Property; + evtOut.Value = evt.Value; + evtOut.Stack = [{obj}, evt.Stack]; + evtOut.ClassStack = [class(obj), evt.ClassStack]; + + if obj.Debug + disp("wt.model.BaseModel.onModelChanged " + ... + " Model: " + evtOut.ClassStack(end) + ... + " Prop: " + evtOut.Property + ... + " ClassStack: " + join(evtOut.ClassStack, " <- ") ); + end + + % Notify listeners + obj.notify("ModelChanged",evtOut) + + + end %function + end %methods - - - + + %% Private methods - methods (Access=private) - + methods (Access = private) + + function attachModelListeners(obj) + % Attach listeners to aggregated BaseModel changes + + arguments + obj (1,1) wt.model.BaseModel + end + + % Get the properties to listen for + propNames = obj.getAggregatedModelProperties(); + + if obj.Debug + if isempty(propNames) + propDisp = ""; + else + propDisp = join(propNames, ", "); + end + disp("wt.model.BaseModel.attachModelListeners " + ... + class(obj) + " Prop: " + propDisp); + end + + % Preallocate array of listeners + numProps = numel(propNames); + newPropListeners = repmat({event.listener.empty(0,1)}, numProps, 1); + + % Loop on each property requested, in case of multiple + % properties having aggregated handle objects + for idx = 1:numProps + + % Get the current property + thisProp = propNames(idx); + + % Get the model(s) to listen to + aggregatedObjects = obj.(thisProp); + + % Skip this property if empty + if isempty(aggregatedObjects) + continue + end + + % These objects must be handle! + allAreHandle = all(isa(aggregatedObjects, "wt.model.BaseModel")); + assert(allAreHandle,... + "Expected %s to contain a handle class object.",... + thisProp); + + % Clear any invalid objects + aggregatedObjects(~isvalid(aggregatedObjects)) = []; + + % Create listener to property changes within the model(s) + fcnModelChange = @(src,evt)onModelChanged(obj,evt); + newPropListeners{idx} = event.listener(aggregatedObjects,... + 'ModelChanged',fcnModelChange); + + end %for + + % Flatten the lists + newPropListeners = vertcat(newPropListeners{:}); + + % Store the results + obj.AggregatedModelListeners = newPropListeners; + + end %function + + + function clearModelListeners(obj) + % Removes aggregated model listeners + + delete(obj.AggregatedModelListeners); + obj.AggregatedModelListeners(:) = []; + + end %function + + function thisParser = getParser(obj,keepUnmatched) - + % What class is this? className = class(obj); - + % Keep a list of reusable parsers for each class persistent allParsers if isempty(allParsers) allParsers = containers.Map('KeyType','char','ValueType','any'); end - + % Get or make a custom parser for this class try - + thisParser = allParsers(className); - + catch - + % Get a list of public properties metaObj = metaclass(obj); isSettableProp = strcmp({metaObj.PropertyList.SetAccess}','public'); @@ -168,25 +496,25 @@ function onPropChanged(obj,e) hasDefault = [settableProps.HasDefault]'; defaultValues = repmat({[]},size(hasDefault)); defaultValues(hasDefault) = {settableProps(hasDefault).DefaultValue}; - + % Create custom parser for this class thisParser = inputParser; thisParser.KeepUnmatched = keepUnmatched; thisParser.FunctionName = className; - + % Add each public property to the parser for pIdx = 1:numel(publicPropNames) thisParser.addParameter(publicPropNames{pIdx}, defaultValues{pIdx}); end - + % Add this parser to the map allParsers(className) = thisParser; - + end %if allParsers.isKey(className) - + end %function - + end %methods - - -end %classdef + + +end %classdef \ No newline at end of file diff --git a/widgets/+wt/+model/BaseSession.m b/widgets/+wt/+model/BaseSession.m index c87f80e..6910e87 100644 --- a/widgets/+wt/+model/BaseSession.m +++ b/widgets/+wt/+model/BaseSession.m @@ -5,93 +5,201 @@ % data. Any properties tagged with the "SetObservable" attribute will % trigger a public event "PropertyChanged" when value is set. The app % will listen for these changes. - - % Copyright 2020-2021 The MathWorks, Inc. - - + + % Copyright 2020-2024 The MathWorks, Inc. + + + %% Events + events + + % Triggered when dirty flag toggles + MarkedDirty + + % Triggered when dirty flag toggles + MarkedClean + + end %events + + %% Properties properties (Dependent, SetAccess = immutable) - + % FileName of the session (dependent on FileName) FileName (1,1) string - + end %properties - - - properties (AbortSet, Transient) - + + + properties (AbortSet, SetObservable) + % Path to store the session file FilePath (1,1) string - - % Indicates modifications have not been saved - Dirty (1,1) logical = false - - end %properties - - - properties - + % Description of the session (optional) Description (1,1) string - + + end %properties + + + properties (AbortSet, Transient) + + % Indicates modifications have not been saved + Dirty (1,1) logical = false + end %properties - - + + + % Accessors + methods + function set.Dirty(obj,value) + + if obj.Debug + disp("wt.model.BaseSession.set.Dirty = " + string(value)); + end + + obj.Dirty = value; + if value + obj.notify("MarkedDirty") + else + obj.notify("MarkedClean") + end + end + end + + %% Public methods (subclass may override these) methods - - function save(session) + + function save(session, filePath) % Save a session object into a MAT file - - if ~strlength(session.FilePath) - error('Session FilePath is empty.'); + + % Define arguments + arguments + session (1,1) wt.model.BaseSession + filePath (1,1) string = session.FilePath end - save(session.FilePath,'session'); - + + if session.Debug + disp("wt.model.BaseSession.save"); + end + + if ~strlength(filePath) + error("Session FilePath is empty."); + end + + session.FilePath = filePath; + session.Dirty = false; + save(filePath,'session'); + end %function - + end %methods - - + + %% Public static methods methods (Static, Sealed) - - function sessionObj = open(sessionPath) + + function session = open(sessionPath) % Load a session object from a MAT file - subclass may override - - contents = load(sessionPath,"session"); - sessionObj = contents.session; - + + % Attempt to load + try + contents = load(sessionPath,"session"); + catch + % Throw an error + id = "wt:BaseSession:InvalidSessionFile"; + msg = "Invalid session file: %s"; + error(id, msg, sessionPath); + end + + % Is it a valid file? + if isfield(contents,'session') ... + && isa(contents.session, "wt.model.BaseSession") ... + && isscalar(contents.session) + + % Get the session + session = contents.session; + + % Update file path if changed + session.FilePath = sessionPath; + session.Dirty = false; + + else + + % Throw an error + id = "wt:BaseSession:InvalidSessionFile"; + msg = "Invalid session file: %s"; + error(id, msg, sessionPath); + + end + end %function - + end %methods - + + + % %% Hidden methods + % methods (Hidden) + % + % function setFilePathSilently(obj, filePath) + % % Set FilePath without triggering change notifications + % + % % Define arguments + % arguments + % obj (1,1) wt.model.BaseModel + % filePath (1,1) string + % end + % + % oldValue = obj.EnableChangeListeners; + % obj.EnableChangeListeners = false; + % obj.FilePath = filePath; + % obj.EnableChangeListeners = oldValue; + % + % end %function + % + % end %methods + %% Protected methods (subclass may override these) methods (Access = protected) + function name = getDefaultName(obj) + % Defines what the default name should be. A subclass may + % override this to customize the default name. + + [~,name,~] = fileparts(obj.FileName); + + end %function + + + function onModelChanged(obj,evt) + % Triggered when the Session or any aggregated BaseModel + % classes have triggered a ModelChanged event (typically when + % SetObservable properties have changed) + + if obj.Debug + classStack = [class(obj), evt.ClassStack]; + disp("wt.model.BaseSession.onModelChanged " + ... + " Model: " + class(evt.Model) + ... + " Prop: " + evt.Property + ... + " ClassStack: " + join(classStack, " <- ") + ... + " (sets Session.Dirty = true)"); + end - function onPropChanged(obj,e) - % Triggered when SetObservable properties have changed - % Mark the session dirty obj.Dirty = true; - + % Call superclass method to notify PropertyChanged event - obj.onPropChanged@wt.model.BaseModel(e); - + obj.onModelChanged@wt.model.BaseModel(evt); + end %function - + end %methods - - - - - - + + %% Accessors methods - + function value = get.FileName(obj) if strlength(obj.FilePath) [~,name,ext] = fileparts(obj.FilePath); @@ -100,8 +208,8 @@ function onPropChanged(obj,e) value = "untitled"; end end %function - + end %methods - - + + end % classdef diff --git a/widgets/+wt/+toolbar/HorizontalSection.m b/widgets/+wt/+toolbar/HorizontalSection.m index d57d1de..10be7ab 100644 --- a/widgets/+wt/+toolbar/HorizontalSection.m +++ b/widgets/+wt/+toolbar/HorizontalSection.m @@ -109,22 +109,22 @@ function onButtonPushed(obj,evt) % Use custom event data if isa(evt,'matlab.ui.eventdata.ButtonPushedData') % Push button - evt = wt.eventdata.ButtonPushedData(evt.Source); + evtOut = wt.eventdata.ButtonPushedData(evt.Source); elseif isa(evt,'matlab.ui.eventdata.ValueChangedData') % State button - evt = wt.eventdata.ButtonPushedData(evt.Source, evt.Source.Value); + evtOut = wt.eventdata.ButtonPushedData(evt.Source, evt.Source.Value); end % Add section name to event data - addprop(evt,'Section'); - evt.Section = obj.Title; + addprop(evtOut,'Section'); + evtOut.Section = obj.Title; % Trigger event - notify(obj,"ButtonPushed",evt); + notify(obj,"ButtonPushed",evtOut); % Trigger callback if ~isempty(obj.ButtonPushedFcn) - feval(obj.ButtonPushedFcn, obj, evt); + feval(obj.ButtonPushedFcn, obj, evtOut); end end %function @@ -146,9 +146,9 @@ function onButtonPushed(obj,evt) end function set.ComponentWidth(obj,value) - evt = wt.eventdata.PropertyChangedData('ComponentWidth',value,obj.ComponentWidth); + evtOut = wt.eventdata.PropertyChangedData('ComponentWidth',value,obj.ComponentWidth); obj.ComponentWidth = value; - notify(obj,'PropertyChanged',evt) + notify(obj,'PropertyChanged',evtOut) end @@ -171,16 +171,16 @@ function onButtonPushed(obj,evt) function set.Title(obj,value) - evt = wt.eventdata.PropertyChangedData('Title',value,obj.Title); + evtOut = wt.eventdata.PropertyChangedData('Title',value,obj.Title); obj.Title = value; - notify(obj,'PropertyChanged',evt) + notify(obj,'PropertyChanged',evtOut) end function set.MinimizedWidth(obj,value) - evt = wt.eventdata.PropertyChangedData('MinimizedWidth',value,obj.MinimizedWidth); + evtOut = wt.eventdata.PropertyChangedData('MinimizedWidth',value,obj.MinimizedWidth); obj.MinimizedWidth = value; - notify(obj,'PropertyChanged',evt) + notify(obj,'PropertyChanged',evtOut) end end %methods diff --git a/widgets/+wt/+toolbar/VerticalSection.m b/widgets/+wt/+toolbar/VerticalSection.m index 5480df1..e1dc215 100644 --- a/widgets/+wt/+toolbar/VerticalSection.m +++ b/widgets/+wt/+toolbar/VerticalSection.m @@ -82,18 +82,18 @@ function onButtonPushed(obj,evt) % Use custom event data if isa(evt,'matlab.ui.eventdata.ButtonPushedData') % Push button - evt = wt.eventdata.ButtonPushedData(evt.Source); + evtOut = wt.eventdata.ButtonPushedData(evt.Source); elseif isa(evt,'matlab.ui.eventdata.ValueChangedData') % State button - evt = wt.eventdata.ButtonPushedData(evt.Source, evt.Source.Value); + evtOut = wt.eventdata.ButtonPushedData(evt.Source, evt.Source.Value); end % Trigger event - notify(obj,"ButtonPushed",evt); + notify(obj,"ButtonPushed",evtOut); % Trigger callback if ~isempty(obj.ButtonPushedFcn) - feval(obj.ButtonPushedFcn, obj, evt); + feval(obj.ButtonPushedFcn, obj, evtOut); end end %function diff --git a/widgets/+wt/+utility/setStylePropsInPriority.m b/widgets/+wt/+utility/setStylePropsInPriority.m index 1d9c142..54113d7 100644 --- a/widgets/+wt/+utility/setStylePropsInPriority.m +++ b/widgets/+wt/+utility/setStylePropsInPriority.m @@ -30,6 +30,17 @@ function setStylePropsInPriority(comps, propNames, value) isDone(needsSet) = true; end + %RJ - Tried this but still the default componentcontainer has wuite + %background color. Need to investigate more. + % Also need to change BackgroundColorableComponents (:,1) to row vector + % Set as needed + % for thisComp = comps(needsSet) + % if ~isequal(thisComp.(thisProp), value) + % thisComp.(thisProp) = value; + % end + % end + % isDone(needsSet) = true; + % Return early if complete if all(isDone) return; diff --git a/widgets/+wt/ColorSelector.m b/widgets/+wt/ColorSelector.m index 4875c7b..aea41fa 100644 --- a/widgets/+wt/ColorSelector.m +++ b/widgets/+wt/ColorSelector.m @@ -1,203 +1,195 @@ classdef ColorSelector < matlab.ui.componentcontainer.ComponentContainer & ... wt.mixin.BackgroundColorable & ... - wt.mixin.Enableable & wt.mixin.FontStyled & wt.mixin.Tooltipable & ... - wt.mixin.FieldColorable & wt.mixin.PropertyViewable - + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Tooltipable + % Color selection control with browse button - - % Copyright 2020-2022 The MathWorks Inc. - - + + % Copyright 2020-2024 The MathWorks Inc. + + %% Public properties properties (AbortSet) - + % The current value shown - Value (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [0 1 0] - + Value (1,3) double {mustBeInRange(Value,0,1)} = [0 1 0] + end %properties - - + + % These properties do not trigger the update method properties (AbortSet, UsedInUpdate = false) - + % Indicates whether to show the edit field ShowEditField (1,1) matlab.lang.OnOffSwitchState = true - + end %properties - - + + %% Events events (HasCallbackProperty, NotifyAccess = protected) - + % Triggered on value changed, has companion callback ValueChanged - + end %events - - - + + + %% Internal Properties properties (Transient, NonCopyable, Hidden, SetAccess = protected) - + % Button ButtonControl (1,1) matlab.ui.control.Button % Grid Grid (1,1) matlab.ui.container.GridLayout - + % Edit control EditControl (1,1) matlab.ui.control.EditField - + end %properties - - - + + %% Protected methods methods (Access = protected) - + function setup(obj) - + % Construct Grid Layout to Manage Building Blocks obj.Grid = uigridlayout(obj); obj.Grid.ColumnWidth = {'1x'}; obj.Grid.RowHeight = {'1x'}; obj.Grid.RowSpacing = 2; obj.Grid.ColumnSpacing = 2; - obj.Grid.Padding = 0; - + obj.Grid.Padding = 0; + % Set default size obj.Position(3:4) = [100 25]; - + % Configure Grid obj.Grid.ColumnWidth = {'1x',25}; obj.Grid.RowHeight = {'1x'}; - + % Create the standard edit control obj.EditControl = matlab.ui.control.EditField(... "Parent",obj.Grid,... "ValueChangedFcn",@(h,e)obj.onTextChanged(e)); - + % Create Button obj.ButtonControl = matlab.ui.control.Button(... "Parent",obj.Grid,... "Text","",... "ButtonPushedFcn",@(h,e)obj.onButtonPushed(e)); - + % Update the internal component lists obj.FontStyledComponents = [obj.EditControl]; obj.FieldColorableComponents = [obj.EditControl]; obj.EnableableComponents = [obj.EditControl, obj.ButtonControl]; obj.TooltipableComponents = [obj.EditControl, obj.ButtonControl]; obj.BackgroundColorableComponents = obj.Grid; - + end %function - - + + function update(obj) - + % Update the edit control text obj.EditControl.Value = mat2str(obj.Value,2); - + % Update the button color obj.ButtonControl.BackgroundColor = obj.Value; - - end %function - - function propGroups = getPropertyGroups(obj) - % Override the ComponentContainer GetPropertyGroups with newly - % customiziable mixin. This can probably also be specific to each control. + end %function - propGroups = getPropertyGroups@wt.mixin.PropertyViewable(obj); - end %function - - function updateFieldVisibility(obj) - + % Is history being shown? If so, update history and items if obj.ShowEditField % Showing edit field - + if isempty(obj.EditControl.Parent) obj.ButtonControl.Layout.Column = 2; obj.EditControl.Parent = obj.Grid; obj.EditControl.Layout.Column = 1; obj.EditControl.Layout.Row = 1; end - + else % Hiding edit field - + if ~isempty(obj.EditControl.Parent) obj.EditControl.Parent = []; obj.ButtonControl.Layout.Column = [1 2]; end - + end %if - + end %function - - + + function onButtonPushed(obj,~) % Triggered on button pushed - + % Get prior value oldValue = obj.Value; - + % Prompt for a new color newColor = uisetcolor(oldValue); - + % Did user make a choice or cancel? if ~isequal(newColor,0) % Update the color obj.Value = newColor; end - + % Trigger event evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue); notify(obj,"ValueChanged",evtOut); - + end %function - - + + function onTextChanged(obj,evt) % Triggered on text interaction - subclass may override - + % Get prior value oldValue = obj.Value; - + % Trap errors try - + % Store new result obj.Value = str2num(evt.Value); %#ok - + % Trigger event evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue); notify(obj,"ValueChanged",evtOut); - + catch - + % Restore original value obj.update(); - + end %try - + end %function - + end %methods - - + + %% Accessors methods - + function set.ShowEditField(obj,value) obj.ShowEditField = value; obj.updateFieldVisibility() end - + end % methods - - + + end % classdef \ No newline at end of file diff --git a/widgets/+wt/ContextualView.m b/widgets/+wt/ContextualView.m new file mode 100644 index 0000000..6025a4e --- /dev/null +++ b/widgets/+wt/ContextualView.m @@ -0,0 +1,613 @@ +classdef ContextualView < matlab.ui.componentcontainer.ComponentContainer & ... + wt.mixin.BackgroundColorable & wt.mixin.ErrorHandling + % wt.mixin.Enableable & wt.mixin.FontStyled & wt.mixin.Tooltipable & ... + % wt.mixin.FieldColorable & wt.mixin.PropertyViewable + + % Contextual View/Controller pane that can present varied views + % This pane can switch its contents between multiple different + % contextual components inside. It is much like a tabpanel, but without + % the tab headers and it's optimized to only render one view at a time. + % This is useful in design patterns such as when you have a tree on the + % left and on the right a contextual view that displays different + % content determined by the selected tree node. + % + % Content views that are placed in this ContextualView should + % inherit the following classes: + % matlab.ui.componentcontainer.ComponentContainer + % wt.mixin.ContextualView (if auto-populating Model property) + + % Copyright 2024 The MathWorks Inc. + + + %% Events + events (HasCallbackProperty, NotifyAccess = protected) + + % Triggered when the Model has changed + ModelSet + + % Triggered when a property within the model has changed + ModelChanged + + end %events + + + %% Public Properties + properties (AbortSet, Access = public) + + % Block while loading + BlockWhileLoading (1,1) logical = true + + % Image to use on loading screen + LoadingImageSource (1,1) string = "loading_32.gif" + + end %properties + + + %% Internal Properties + properties (AbortSet, Transient, NonCopyable, Hidden, ... + SetAccess = protected, UsedInUpdate = false) + + % Top-level grid to manage content vs. loading + MainGrid matlab.ui.container.GridLayout + + % The internal grid to manage contents + ContentGrid matlab.ui.container.GridLayout + + % Image to show when loading a pane + LoadingImage matlab.ui.control.Image + + % Listener for a new model being attached + ModelSetListener event.listener + + % Listener for property changes within the model + ModelPropertyChangedListener event.listener + + end %properties + + + properties (SetAccess = private, UsedInUpdate = false) + + % The currently active view, or empty if none + ActiveView (:,1) matlab.graphics.Graphics ... + {mustBeScalarOrEmpty, mustBeValidView(ActiveView)} = ... + wt.abstract.BaseViewController.empty(0,1) + + % The array of views loaded into memory + LoadedViews (:,1) matlab.graphics.Graphics ... + {mustBeValidView(LoadedViews)} = ... + wt.abstract.BaseViewController.empty(0,1) + + end %properties + + + % Accessors + methods + + function value = get.ActiveView(obj) + value = obj.ActiveView; + % Remove view if deleted + value(~isvalid(value)) = []; + end + + function set.ActiveView(obj,value) + % Remove view if deleted + value(~isvalid(value)) = []; + obj.ActiveView = value; + end + + function value = get.LoadedViews(obj) + value = obj.LoadedViews; + % Remove any deleted views from the list + keepItems = arrayfun(@isvalid, value); + value(~keepItems) = []; + end + + function set.LoadedViews(obj,value) + % Remove any deleted views from the list + keepItems = arrayfun(@isvalid, value); + value(~keepItems) = []; + obj.LoadedViews = value; + end + + end %methods + + + %% Public Methods + methods + + function varargout = launchView(obj, viewClass, model) + % This method may be overloaded as needed + + arguments + obj (1,1) wt.ContextualView + viewClass (1,1) string + model wt.model.BaseModel = wt.model.BaseModel.empty + end + + % After launch is complete, toggle off loading image + cleanupObj = onCleanup(@()set(obj.LoadingImage,"Visible","off")); + + % Is the loading image non-visible? + if ~obj.LoadingImage.Visible + + % If the view will change, show the loading image + obj.prepareToLaunchView(viewClass) + + end %if + + % Was a view provided? + if strlength(viewClass) + + % Validate view class + view = validateViewClass(obj, viewClass); + + % If no existing view found, instantiate the view + if isempty(view) + obj.instantiateView_Private(viewClass, model); + else + obj.activateView_Private(view, model) + end + + else + + % Empty view, clear the contents + obj.clearView(); + + end %if + + % Return the active view + if nargout + varargout{1} = obj.ActiveView; + end + + end %function + + + function prepareToLaunchView(objArray, viewClassArray) + % Puts the ContextualView in a loading state if a different + % view is about to be launched. Use this if your app has + % multiple ContextualView instances and you need to potentially + % load multiple simultaneously. You can provide an array of + % views here to turn them to loading state together. + + arguments + objArray wt.ContextualView + viewClassArray string + end + + for idx = 1:numel(objArray) + + % Get one at a time + obj = objArray(idx); + viewClass = viewClassArray(idx); + + % Is the view class going to change? + willLaunchView = isempty(obj.ActiveView) && strlength(viewClass); + willChangeView = isscalar(obj.ActiveView) && ... + class(obj.ActiveView) ~= viewClass; + + % If the view will change, show the loading image + if obj.BlockWhileLoading && (willLaunchView || willChangeView) + + % Prevent interaction during launch + obj.LoadingImage.Visible = "on"; + + end %if + + end %for + + % Enable them all to update + drawnow + + end %function + + + function clearView(obj) + % This method may be overloaded as needed + + arguments + obj (1,1) wt.ContextualView + end + + % Remove listeners + obj.ModelSetListener(:) = []; + obj.ModelPropertyChangedListener(:) = []; + + % Clear the view + obj.deactivateView_Private(); + + % Delete any orphaned children + delete(obj.ContentGrid.Children); + + end %function + + + function relaunchActiveView(obj) + % Delete and reload the active view + + % Is there an active view? If no, return early + activeView = obj.ActiveView; + if isempty(activeView) + warning("wt:ContextualView:noActiveView",... + "No active view is present.") + return + end + + % Get the current view and model + viewClass = class(activeView); + model = activeView.Model; + + % Deactivate the active view + obj.clearView(); + + % Delete the previously active view + delete(activeView); + obj.LoadedViews(obj.LoadedViews == activeView) = []; + + % Launch the same view again + obj.launchView(viewClass, model); + + end %function + + + function reset(obj) + % Reset the control by deactivating current view and delete loaded views + + % Remove listeners + obj.ModelSetListener(:) = []; + obj.ModelPropertyChangedListener(:) = []; + + % Deactivate any active view + obj.deactivateView_Private(); + + % Delete any loaded views + delete(obj.LoadedViews); + obj.LoadedViews(:) = []; + + % Delete any orphaned children + delete(obj.ContentGrid.Children); + + % Reset the layout state + obj.ContentGrid.ColumnWidth = {'1x'}; + obj.ContentGrid.RowHeight = {'1x'}; + + end %function + + end %methods + + + %% Protected Methods + methods (Access=protected) + + function setup(obj) + % Configure the widget + + obj.MainGrid = uigridlayout(obj,[1 1]); + obj.MainGrid.Padding = [0 0 0 0]; + + % Grid Layout to place the contents + obj.ContentGrid = uigridlayout(obj.MainGrid,[1 1]); + obj.ContentGrid.Padding = [0 0 0 0]; + obj.ContentGrid.Layout.Row = 1; + obj.ContentGrid.Layout.Column = 1; + + % Image to display while loading content + obj.LoadingImage = uiimage(obj.MainGrid); + obj.LoadingImage.Layout.Row = 1; + obj.LoadingImage.Layout.Column = 1; + obj.LoadingImage.Visible = "off"; + obj.LoadingImage.ScaleMethod = "none"; + + % Components to apply background color + obj.BackgroundColorableComponents = ... + [obj.ContentGrid, obj.MainGrid, obj.LoadingImage]; + + end %function + + + function update(obj) + + % Configure the loading image + obj.LoadingImage.Visible = "off"; + obj.LoadingImage.ImageSource = obj.LoadingImageSource; + + end %function + + end %methods + + + %% Private methods + methods (Access=private) + + function view = validateViewClass(obj, viewClass) + % This validates the view class and check for existing + % instances. If an existing instance is found, it is returned. + % Otherwise, an empty view is returned + + arguments (Input) + obj (1,1) wt.ContextualView + viewClass (1,1) string + end + + arguments (Output) + view (:,1) {mustBeScalarOrEmpty, mustBeValidView(view)} + end + + % Try to locate a valid view + if ~exist(viewClass,"class") + + % Throw an error and return + id = "wt:ContextualView:InvalidPaneType"; + message = "Invalid view type (%s). The viewClass " + ... + "must be a valid class path."; + error(id, message, viewClass); + + elseif isequal(viewClass, class(obj.ActiveView)) + + % Pane is already active + view = obj.ActiveView; + + else + + % Check if the view already exists + view = wt.abstract.BaseViewController.empty(0,1); + for thisView = obj.LoadedViews' + if viewClass == class(thisView) + view = thisView; + break + end + end + + end %if + + end %function + + + function view = instantiateView_Private(obj, viewClass, model) + % Launch a view based on the class path + + arguments (Input) + obj (1,1) wt.ContextualView + viewClass (1,1) string + model wt.model.BaseModel %= wt.model.BaseModel.empty(0) + end + + arguments (Output) + view (:,1) {mustBeScalarOrEmpty, mustBeValidView(view)} + end + + % Trap errors + % try + + % Get function handle to the view's constructor + viewConstructorFcn = str2func(viewClass); + + % Launch the view + view = viewConstructorFcn(obj.ContentGrid); + % view = viewConstructorFcn("Parent",obj.Grid); + + % Position the view in the single grid cell + view.Layout.Row = 1; + view.Layout.Column = 1; + + % Add the new view to the list + obj.LoadedViews = vertcat(obj.LoadedViews, view); + + % catch err + % + % % Clean up partially loaded children + % delete(obj.Grid.Children(2:end)) + % + % % Throw an error + % message = sprintf("Error launching view (%s).\n\n%s",... + % viewClass, err.message); + % obj.throwError(message); + % + % % Deactivate current pane + % obj.deactivateView_Private(); + % + % % Rethrow the error to the command window + % rethrow(err) + % + % end %try + + % Activate the view + obj.activateView_Private(view, model) + + end %function + + + function activateView_Private(obj, view, model) + % Activate a view, placing it in view and attaching a model + + arguments + obj (1,1) wt.ContextualView + view (1,1) {mustBeValidView(view)} + model wt.model.BaseModel + end + + % Does this view need to be made active? + needToMarkActive = ~isequal(obj.ActiveView, view); + if needToMarkActive + + % Remove the old view at the end of this function + oldView = obj.ActiveView; + cleanupObj = onCleanup(@()obj.deactivateView_Private(oldView)); + + % Assign parent + if ~isequal(view.Parent, obj.ContentGrid) + view.Parent = obj.ContentGrid; + end + view.Visible = true; + + % Store this view as active view + obj.ActiveView = view; + + end %if + + % Attach model + if ~isempty(model) && all(isvalid(model(:))) + + % Attach the model + obj.attachModel_Private(view, model) + + end %if + + % Did this view need to be made active? + if needToMarkActive + + % Listen to the active view indicating that its model has been + % set or changed + obj.ModelSetListener = listener(view,... + "ModelSet",@(~,evt)obj.onModelSet(evt)); + + obj.ModelPropertyChangedListener = listener(view,... + "ModelChanged",@(~,evt)obj.onModelChanged(evt)); + + end %if + + end %function + + + % function attachModelPropertyChangedListener(obj) + % + % % Listen to the active view indicating model changes + % model = obj.ActiveView.Model; + % obj.ModelPropertyChangedListener = listener(model,... + % "ModelChanged",@(~,evt)obj.onModelChanged(evt)); + % + % end %function + + + function deactivateView_Private(obj, view) + % Deactivate a view, removing from view and removing model + arguments + obj (1,1) wt.ContextualView + view {mustBeValidView(view)} = obj.ActiveView + end + + % Return now if view provided is empty + if isempty(view) || ~isvalid(view) + return + end + + % Enable any prior view changes to finish, avoiding any + % "flashing" effects during the change + % drawnow + % drawnow('nocallbacks','limitrate') + + % Remove any listeners on the view + obj.ModelSetListener = obj.deleteListenersForSource(... + obj.ModelSetListener, view); + obj.ModelPropertyChangedListener = obj.deleteListenersForSource(... + obj.ModelPropertyChangedListener, view); + + % Deactivate the view, removing model and parent + view.Model(:) = []; + view.Parent(:) = []; + + % Remove view from the active view property + if isequal(obj.ActiveView, view) + obj.ActiveView(:) = []; + end + + % Clean up partially loaded children + delete(obj.ContentGrid.Children(2:end)) + + end %function + + + function modelListener = deleteListenersForSource(~, modelListener, source) + % Deletes listeners with the given source + + deleteListener = false(size(modelListener)); + for idx = numel(modelListener) : -1 : 1 + thisListener = modelListener(idx); + for sIdx = 1:numel(thisListener.Source) + thisSrc = thisListener.Source{sIdx}; + if thisSrc == source + deleteListener(idx) = true; + end + end + end + delete(modelListener(deleteListener)) + modelListener(deleteListener) = []; + + end %function + + + function attachModel_Private(obj, view, model) + % Attach model to the active view + + arguments + obj (1,1) wt.ContextualView + view (1,1) {mustBeValidView(view)} + model wt.model.BaseModel + end + + % Trap errors during model assignment + if ~isempty(model) && all(isvalid(model(:))) + + try + % Assign model + view.Model = model; + + % Listen to model changes + % obj.attachModelPropertyChangedListener(); + + catch err + + message = sprintf("Unable to assign model (%s) " + ... + "to view/controller (%s).\n\n%s",... + class(model), class(view), err.message); + obj.throwError(message); + + end %try + + end %if + + end %function + + + function onModelSet(obj,evt) + + % Prepare eventdata + evtOut = wt.eventdata.ModelSetData; + evtOut.Model = evt.Model; + evtOut.Controller = evt.Controller; + + % Notify listeners + obj.notify("ModelSet",evtOut); + + end %function + + + function onModelChanged(obj,evt) + + % Prepare eventdata + evtOut = wt.eventdata.ModelChangedData; + evtOut.Model = evt.Model; + evtOut.Property = evt.Property; + evtOut.Value = evt.Value; + evtOut.Stack = [{obj}, evt.Stack]; + evtOut.ClassStack = [class(obj), evt.ClassStack]; + + % Notify listeners + obj.notify("ModelChanged",evtOut); + + end %function + + end %methods + +end %classdef + + +% Validation function +function mustBeValidView(view) + +for idx = 1:numel(view) + mustBeA(view(idx), "wt.mixin.ModelObserver") + mustBeA(view(idx), ["wt.abstract.BaseViewController", "wt.abstract.BaseViewChart"]) +end + +end %function \ No newline at end of file diff --git a/widgets/+wt/DropDownListManager.m b/widgets/+wt/DropDownListManager.m new file mode 100644 index 0000000..68e6698 --- /dev/null +++ b/widgets/+wt/DropDownListManager.m @@ -0,0 +1,545 @@ +classdef DropDownListManager < matlab.ui.componentcontainer.ComponentContainer & ... + wt.mixin.BackgroundColorable & ... + wt.mixin.ButtonColorable &... + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Tooltipable + % Manage a list of text entries using a dropdown control + + % Copyright 2024 The MathWorks Inc. + + %RJ - supports R2023b and later, but test in earlier releases + + + %% Events + events (HasCallbackProperty, NotifyAccess = protected) + + % Triggered when the value of the list selection changes + ItemsChanged + + end %events + + + %% Public properties + properties (AbortSet, Dependent, UsedInUpdate = false) + + % Index of selected list item + Index {mustBeNonnegative, mustBeInteger, mustBeScalarOrEmpty} + + % The current selection + Value (1,:) + + % List of items in the dropdown + Items (1,:) string + + end %properties + + + properties (AbortSet) + + % Data associated with items (optional) + ItemsData (1,:) + + end %properties + + + properties (AbortSet) + + % Show the remove button? + AllowRemove (1,1) matlab.lang.OnOffSwitchState = true + + % Show the rename button? + AllowRename (1,1) matlab.lang.OnOffSwitchState = true + + % Can each item be removed? + AllowItemRemove (1,:) logical + + % Can each item be renamed? + AllowItemRename (1,:) logical + + % List of items to add to the list + NewItemName (1,1) string = "" + + end %properties + + + % Accessors + methods + + function value = get.Items(obj) + value = string(obj.DropDown.Items); + end + + function set.Items(obj,value) + obj.DropDown.Items = value; + obj.DropDown.ItemsData = 1:numel(value); + end + + function value = get.Index(obj) + if isMATLABReleaseOlderThan("R2023b") + warnState = warning('off','MATLAB:structOnObject'); + s = struct(obj.DropDown); + warning(warnState); + value = s.SelectedIndex; + else + value = obj.DropDown.ValueIndex; + end + end + + function set.Index(obj,value) + if isMATLABReleaseOlderThan("R2023b") + obj.DropDown.Value = obj.DropDown.ItemsData(value); + else + obj.DropDown.ValueIndex = value; + end + end + + function value = get.Value(obj) + value = obj.DropDown.Value; + end + + function set.Value(obj,value) + obj.DropDown.Value = value; + end + + function set.AllowRemove(obj,value) + obj.AllowRemove = value; + obj.updateButtonVisibilities(); + end + + function set.AllowRename(obj,value) + obj.AllowRename = value; + obj.updateButtonVisibilities(); + end + + function value = get.AllowItemRemove(obj) + value = resize(obj.AllowItemRemove, numel(obj.Items), ... + "FillValue", true); + end + + function value = get.AllowItemRename(obj) + value = resize(obj.AllowItemRename, numel(obj.Items), ... + "FillValue", true); + end + + end %methods + + + + %% Internal Properties + properties (UsedInUpdate, SetAccess = protected) + + % Indicates when new item is being entered + IsAddingNewItem (1,1) logical = false + + % Indicates when an item is being renamed + IsRenamingItem (1,1) logical = false + + end %properties + + + properties (Transient, NonCopyable, Hidden, SetAccess = protected) + + % The dropdown control + DropDown (1,1) matlab.ui.control.DropDown + + % The edit field + EditField (1,1) matlab.ui.control.EditField + + % Grid + Grid (1,1) matlab.ui.container.GridLayout + + % The list sorting buttons + ListButtons wt.ButtonGrid + + % Buttons + AddButton matlab.ui.control.Button + RenameButton matlab.ui.control.Button + RemoveButton matlab.ui.control.Button + + % Listeners to enable editing to stop + StopEditingListeners event.listener + + end %properties + + + + + %% Protected methods + methods (Access = protected) + + function setup(obj) + + % Set default size + obj.Position(3:4) = [250 30]; + + % Construct Default Grid Layout to Manage Building Blocks + obj.Grid = uigridlayout(obj,[1 3]); + obj.Grid.ColumnWidth = {'1x',30,30,30}; + obj.Grid.RowHeight = {'1x'}; + obj.Grid.ColumnSpacing = 2; + obj.Grid.Padding = 0; + + % Create the DropDown + obj.DropDown = uidropdown(obj.Grid); + obj.DropDown.Items ={'Item One','Item Two'}; + obj.DropDown.ItemsData = [1 2]; + obj.DropDown.ValueChangedFcn = @(~,evt)obj.onValueChanged(evt); + obj.DropDown.Layout.Column = 1; + obj.DropDown.Layout.Row = 1; + + % Create the EditField + obj.EditField = uieditfield(obj.Grid); + obj.EditField.Value = ""; + obj.EditField.ValueChangedFcn = @(~,evt)obj.onEditFieldChanged(evt); + obj.EditField.Layout.Column = 1; + obj.EditField.Layout.Row = 1; + obj.EditField.Visible = false; + + % Create the buttons + obj.AddButton = uibutton(obj.Grid); + obj.AddButton.Icon = "addYellow_24.png"; + obj.AddButton.Text = ""; + obj.AddButton.Layout.Column = 2; + obj.AddButton.Layout.Row = 1; + obj.AddButton.ButtonPushedFcn = @(~,~)obj.onAddButton(); + + obj.RenameButton = uibutton(obj.Grid); + obj.RenameButton.Icon = "edit_24.png"; + obj.RenameButton.Text = ""; + obj.RenameButton.Layout.Column = 3; + obj.RenameButton.Layout.Row = 1; + obj.RenameButton.ButtonPushedFcn = @(~,~)obj.onRenameButton(); + + obj.RemoveButton = uibutton(obj.Grid); + obj.RemoveButton.Icon = "delete_24.png"; + obj.RemoveButton.Text = ""; + obj.RemoveButton.Layout.Column = 4; + obj.RemoveButton.Layout.Row = 1; + obj.RemoveButton.ButtonPushedFcn = @(~,~)obj.onRemoveButton(); + + % Update the internal component lists + obj.BackgroundColorableComponents = obj.Grid; + obj.ButtonColorableComponents = [obj.AddButton, ... + obj.RenameButton, obj.RemoveButton]; + obj.EnableableComponents = [obj.DropDown, obj.EditField, ... + obj.AddButton, obj.RenameButton, obj.RemoveButton]; + obj.FieldColorableComponents = [obj.DropDown, obj.EditField]; + obj.FontStyledComponents = [obj.DropDown, obj.EditField]; + obj.TooltipableComponents = [obj.DropDown]; + + end %function + + + function update(obj) + + % Toggle between dropdown and edit field + isEditMode = obj.IsAddingNewItem || obj.IsRenamingItem; + obj.EditField.Visible = isEditMode; + obj.DropDown.Visible = ~isEditMode; + + % Remove any listeners if no longer editing + if ~isEditMode + obj.StopEditingListeners(:) = []; + end + + % Update button enable states + obj.updateEnableableComponents(); + + end %function + + + function onEditFieldChanged(obj,evt) + % Triggered when editing in edit field mode + + if obj.IsRenamingItem + + % Data for this event + action = "Renamed"; + item = string(evt.Value); + index = obj.Index; + data = obj.getItemDataByIndex(index); + + % Strip off any whitespace + item = strip(item); + + % Update the list item and select it + obj.Items(index) = item; + obj.Index = index; + + % Toggle mode OFF + obj.IsRenamingItem = false; + + elseif obj.IsAddingNewItem + + % Data for this event + action = "Added"; + item = string(evt.Value); + index = numel(obj.Items) + 1; + data = []; + + % Strip off any whitespace + item = strip(item); + + % Add the new item to the list and select it + obj.Items(index) = item; + obj.Index = index; + + % Toggle mode OFF + obj.IsAddingNewItem = false; + + else + % Should not get here + + % Toggle mode OFF + obj.IsRenamingItem = false; + obj.IsAddingNewItem = false; + + % Exit + return + + end %if + + % Prepare event data + evtOut = wt.eventdata.ListManagerEventData(); + evtOut.Action = action; + evtOut.Item = item; + evtOut.ItemData = data; + evtOut.Index = index; + + % Notify listeners + notify(obj,"ItemsChanged",evtOut); + + end %function + + + function onValueChanged(obj,evt) + % Triggered on dropdown selection + + % Prepare event data + evtOut = wt.eventdata.ListManagerEventData(); + evtOut.Action = "Selected"; + evtOut.Item = obj.Items(evt.Value); + evtOut.ItemData = obj.getItemDataByIndex(evt.Value); + evtOut.Index = evt.Value; + + % Notify listeners + notify(obj,"ItemsChanged",evtOut); + + % Update button enable states + obj.updateEnableableComponents(); + + end %function + + + function data = getItemDataByIndex(obj,index) + % Retrieve the ItemsData value for a given index + + itemsData = obj.ItemsData; + if isnumeric(index) && isscalar(index) && ... + index <= numel(itemsData) + data = itemsData(index); + else + data = []; + end + + end %function + + + function onAddButton(obj) + + % Toggle mode ON + obj.IsAddingNewItem = true; + + % Configure the edit field + obj.EditField.Value = obj.NewItemName; + drawnow + obj.EditField.focus(); + + % Attach figure listeners to stop editing in special + % circumstances + obj.attachStopEditingListeners(); + + end %function + + + function onRenameButton(obj) + + % Toggle mode ON + obj.IsRenamingItem = true; + + % Get the item being edited + item = obj.Items(obj.Index); + + % Configure the edit field + obj.EditField.Value = item; + drawnow + obj.EditField.focus(); + + % Attach figure listeners to stop editing in special + % circumstances + obj.attachStopEditingListeners(); + + end %function + + + function onRemoveButton(obj) + % Removes selcted item + + % Data for this event + action = "Removed"; + index = obj.Index; + item = obj.Items(index); + data = obj.getItemDataByIndex(index); + + % Remove the item from the list + obj.Items(index) = []; + if index <= numel(obj.ItemsData) + obj.ItemsData(index) = []; + end + + % Prepare event data + evtOut = wt.eventdata.ListManagerEventData(); + evtOut.Action = action; + evtOut.Item = item; + evtOut.ItemData = data; + evtOut.Index = index; + + % Notify listeners + notify(obj,"ItemsChanged",evtOut); + + end %function + + + function attachStopEditingListeners(obj) + % Attach listeners to enable stop editing under special + % circumstances + + % Find the figure + fig = ancestor(obj,'figure'); + + % If no figure, just exit + if isempty(fig) + return + end + + % Create listeners + obj.StopEditingListeners = [ + listener(fig,"WindowKeyPress",@(src,evt)obj.onWindowKeyPress(evt)) + listener(fig,"WindowMousePress",@(src,evt)obj.onWindowMousePress(evt)) + ]; + + end %function + + + function onWindowKeyPress(obj,evt) + % Triggered on key presses while editing + + % If the user pressed Escape, cancel editing + if strcmp(evt.Key, 'escape') + + % Toggle mode OFF + obj.IsRenamingItem = false; + obj.IsAddingNewItem = false; + + end + + end %function + + + function onWindowMousePress(obj,evt) + % Triggered on mouse presses while editing + + % If the user clicked anywhere except the edit field, cancel + % editing. + if ~isequal(evt.HitObject, obj.EditField) + + % Toggle mode OFF + obj.IsRenamingItem = false; + obj.IsAddingNewItem = false; + + end + + + end %function + + + function updateEnableableComponents(obj) + % Handle changes to Enable flag + + % What item is selected? + hasEntries = ~isempty(obj.Items); + valIdx = obj.Index; + + % Can we add an item? + isEditMode = obj.IsAddingNewItem || obj.IsRenamingItem; + canAddItem = obj.Enable && ~isEditMode; + + % Can we rename or remove given the current selection? + canRenameItem = obj.Enable && hasEntries && ... + obj.AllowItemRename(valIdx) && ~isEditMode; + canRemoveItem = obj.Enable && hasEntries && ... + obj.AllowItemRemove(valIdx) && ~isEditMode; + + % Update buttons + obj.AddButton.Enable = canAddItem; + obj.RenameButton.Enable = canRenameItem; + obj.RemoveButton.Enable = canRemoveItem; + + % Update fields + obj.EditField.Enable = obj.Enable; + obj.DropDown.Enable = obj.Enable && hasEntries; + + end %function + + + function updateButtonVisibilities(obj) + % Update button visibilities + + if obj.AllowRename && obj.AllowRemove + + obj.Grid.ColumnWidth = {'1x',30,30,30}; + + obj.RenameButton.Parent = obj.Grid; + obj.RenameButton.Layout.Column = 3; + obj.RenameButton.Layout.Row = 1; + + obj.RemoveButton.Parent = obj.Grid; + obj.RemoveButton.Layout.Column = 4; + obj.RemoveButton.Layout.Row = 1; + + elseif obj.AllowRename + + obj.RemoveButton.Parent(:) = []; + + obj.Grid.ColumnWidth = {'1x',30,30}; + + obj.RenameButton.Parent = obj.Grid; + obj.RenameButton.Layout.Column = 3; + obj.RenameButton.Layout.Row = 1; + + elseif obj.AllowRemove + + obj.RenameButton.Parent(:) = []; + + obj.Grid.ColumnWidth = {'1x',30,30}; + + obj.RemoveButton.Parent = obj.Grid; + obj.RemoveButton.Layout.Column = 3; + obj.RemoveButton.Layout.Row = 1; + + else + + obj.RenameButton.Parent(:) = []; + obj.RemoveButton.Parent(:) = []; + + obj.Grid.ColumnWidth = {'1x',30}; + + end + + end %function + + end %methods + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/ListSelector.m b/widgets/+wt/ListSelector.m index 9de02ae..48598d5 100644 --- a/widgets/+wt/ListSelector.m +++ b/widgets/+wt/ListSelector.m @@ -1,12 +1,17 @@ classdef ListSelector < matlab.ui.componentcontainer.ComponentContainer & ... - wt.mixin.BackgroundColorable & wt.mixin.Enableable &... - wt.mixin.FontStyled & wt.mixin.ButtonColorable &... - wt.mixin.FieldColorable & wt.mixin.PropertyViewable - + wt.mixin.BackgroundColorable & ... + wt.mixin.ButtonColorable &... + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Orderable & ... + wt.mixin.PropertyViewable + % Select from an array of items and add them to a list % Copyright 2020-2023 The MathWorks Inc. + %RJ - add unit test for ValueIndex vs SelectedIndex %% Events events (HasCallbackProperty, NotifyAccess = protected) @@ -49,7 +54,7 @@ properties (AbortSet, Dependent) % Indices of displayed items that are currently added to the list - SelectedIndex (1,:) + ValueIndex (1,:) % The current selection Value (1,:) @@ -60,6 +65,14 @@ end %properties + properties (AbortSet, Dependent, Hidden) + + % Indices of displayed items that are currently added to the list (for backward compatibility - use ValueIndex instead) + SelectedIndex (1,:) + + end %properties + + properties (AbortSet, Dependent, UsedInUpdate = false) % Width of the buttons @@ -81,7 +94,7 @@ %% Internal Properties properties (Transient, NonCopyable, Hidden, SetAccess = protected) - + % The ListBox control ListBox (1,1) matlab.ui.control.ListBox @@ -187,20 +200,22 @@ function updateEnables(obj) % What is selected? selIdx = obj.SelectedIndex; + numRows = numel(selIdx); % Highlighted selection in list? hiliteIdx = obj.getListBoxSelectedIndex(); + % Should the sort buttons be enabled? + [backEnabled, fwdEnabled] = obj.areOrderButtonsEnabled(numRows, hiliteIdx); + % How many items selected into list - numRows = numel(selIdx); - numHilite = numel(hiliteIdx); % Toggle button enables obj.ListButtons.ButtonEnable = [ obj.AllowDuplicates || ( numel(selIdx) < numel(obj.Items) ) %Add Button ~isempty(hiliteIdx) % Delete Button - numHilite && ( hiliteIdx(end) > numHilite ) %Up Button - numHilite && ( hiliteIdx(1) <= (numRows - numHilite) ) %Down Button + backEnabled %Up Button + fwdEnabled %Down Button ]; end %if obj.Enable @@ -317,12 +332,16 @@ function promptToAddListItems(obj) function selIdx = getListBoxSelectedIndex(obj) % Get the current selected row indices in the listbox - warnState = warning('off','MATLAB:structOnObject'); - s = struct(obj.ListBox); - warning(warnState); - selIdx = s.SelectedIndex; - if isequal(selIdx, -1) - selIdx = []; + if isMATLABReleaseOlderThan("R2023b") + warnState = warning('off','MATLAB:structOnObject'); + s = struct(obj.ListBox); + warning(warnState); + selIdx = s.SelectedIndex; + if isequal(selIdx, -1) + selIdx = []; + end + else + selIdx = obj.ListBox.ValueIndex; end end %function @@ -357,81 +376,27 @@ function shiftListBoxIndex(obj, shift) % Shift selected items up/down within a listbox % This assumes ItemsData contains unique values - % What is the current order? - selIdx = obj.getListBoxSelectedIndex(); - - % Make indices to all items as they are now - idxNew = 1:numel(obj.ListBox.Items); - idxOld = idxNew; - - % Find the last stable item that doesn't move - [~,idxStable] = setdiff(idxNew, selIdx, 'stable'); - if ~isempty(idxStable) - idxFirstStable = idxStable(1); - idxLastStable = idxStable(end); - else - idxFirstStable = inf; - idxLastStable = 0; - end - - % Which way do we loop? - if shift > 0 %Shift to end - - for idxToMove = numel(selIdx):-1:1 - - % Calculate if there's room to move this item - idxThisBefore = selIdx(idxToMove); - thisShift = max( min(idxLastStable-idxThisBefore, shift), 0 ); - - % Where does this item move from/to - idxThisAfter = idxThisBefore + thisShift; - - % Where do other items move from/to - idxOthersBefore = selIdx(idxToMove)+1:1:idxThisAfter; - idxOthersAfter = idxOthersBefore - thisShift; - - % Move the items - idxNew([idxThisAfter idxOthersAfter]) = idxNew([idxThisBefore idxOthersBefore]); - - end - - elseif shift < 0 %Shift to start - - for idxToMove = 1:numel(selIdx) - - % Calculate if there's room to move this item - idxThisBefore = selIdx(idxToMove); - thisShift = min( max(idxFirstStable-idxThisBefore, shift), 0 ); - - % Where does this item move from/to - idxThisAfter = idxThisBefore + thisShift; - - % Where do other items move from/to - idxOthersBefore = idxThisAfter:1:selIdx(idxToMove)-1; - idxOthersAfter = idxOthersBefore - thisShift; - - % Move the items - idxNew([idxThisAfter idxOthersAfter]) = idxNew([idxThisBefore idxOthersBefore]); - - end + % What is the current order and total items? + idxSel = obj.getListBoxSelectedIndex(); + numItems = numel(obj.ListBox.Items); - end %if shift > 0 + % Shift the list indices + [idxNew, idxSelAfter] = obj.shiftListIndices(shift, numItems, idxSel); - % Was a change made? - if ~isequal(idxOld, idxNew) + % Get the original value + oldValue = obj.Value; - % Get the original value - oldValue = obj.Value; + % Make the shift + obj.ListBox.Items = obj.ListBox.Items(idxNew); + obj.ListBox.ItemsData = obj.ListBox.ItemsData(idxNew); + % obj.ListBox.Selection = idxSelAfter; - % Make the shift - obj.ListBox.Items = obj.ListBox.Items(idxNew); - obj.ListBox.ItemsData = obj.ListBox.ItemsData(idxNew); - - % Trigger event - evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue); - notify(obj,"ValueChanged",evtOut); + % Trigger event + evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue); + notify(obj,"ValueChanged",evtOut); - end %if + % Update buttons + obj.updateEnables() end %function @@ -445,11 +410,21 @@ function shiftListBoxIndex(obj, shift) function value = get.SelectedIndex(obj) value = obj.ListBox.ItemsData; end + function set.SelectedIndex(obj,value) obj.ListBox.Items = obj.Items(value); obj.ListBox.ItemsData = value; end + function value = get.ValueIndex(obj) + value = obj.ListBox.ItemsData; + end + + function set.ValueIndex(obj,value) + obj.ListBox.Items = obj.Items(value); + obj.ListBox.ItemsData = value; + end + function value = get.Value(obj) if isempty(obj.ItemsData) value = obj.Items(:,obj.ListBox.ItemsData); @@ -457,6 +432,7 @@ function shiftListBoxIndex(obj, shift) value = obj.ItemsData(:,obj.ListBox.ItemsData); end end + function set.Value(obj,value) if isempty(value) obj.SelectedIndex = []; @@ -486,6 +462,7 @@ function shiftListBoxIndex(obj, shift) value = obj.ItemsData(:,selIdx); end end + function set.HighlightedValue(obj,value) if isempty(obj.ItemsData) [~, obj.ListBox.Value] = ismember(value, obj.Items); @@ -497,6 +474,7 @@ function shiftListBoxIndex(obj, shift) function value = get.ButtonWidth(obj) value = obj.Grid.ColumnWidth{2}; end + function set.ButtonWidth(obj,value) obj.Grid.ColumnWidth{2} = value; end diff --git a/widgets/+wt/NumericArray.m b/widgets/+wt/NumericArray.m new file mode 100644 index 0000000..590a051 --- /dev/null +++ b/widgets/+wt/NumericArray.m @@ -0,0 +1,199 @@ +classdef NumericArray < matlab.ui.componentcontainer.ComponentContainer & ... + wt.mixin.BackgroundColorable & ... + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Tooltipable + % Set of N numeric edit fields for small numeric arrays + + % Copyright 2024 The MathWorks Inc. + + %RJ - Need unit tests + %RJ - need to limit max array size and incorporate pagination or + %similar + %RJ - Improve error if a restriction needs enforcement. Like display a + % message but still accept their input? + + %% Public properties + properties (AbortSet) + + % Values of the range (min/max) + Value (1,:) double = [1 2 3] + + % Optional limits of the entries (min/max) + Limits (1,2) double = [-inf inf] + + % Is the lower limit inclusive? + LowerLimitInclusive (1,1) matlab.lang.OnOffSwitchState = true + + % Is the upper limit inclusive? + UpperLimitInclusive (1,1) matlab.lang.OnOffSwitchState = true + + % Restriction on array order + Restriction (1,1) wt.enum.ArrayRestriction = "none" + + % Orientation of the fields + Orientation (1,1) wt.enum.HorizontalVerticalState = "horizontal" + + end %properties + + + %% Events + events (HasCallbackProperty, NotifyAccess = protected) + + % Triggered on value changed, has companion callback + ValueChanged + + end %events + + + %% Internal Properties + properties (Transient, NonCopyable, Hidden, SetAccess = protected) + + % Grid + Grid (1,1) matlab.ui.container.GridLayout + + % Edit fields + EditField (1,:) matlab.ui.control.NumericEditField + + end %properties + + + %% Protected methods + methods (Access = protected) + + function setup(obj) + + % Construct Grid Layout to Manage Building Blocks + obj.Grid = uigridlayout(obj); + obj.Grid.ColumnWidth = {'1x','1x','1x'}; + obj.Grid.RowHeight = {'1x'}; + obj.Grid.ColumnSpacing = 5; + obj.Grid.RowSpacing = 5; + obj.Grid.Padding = 0; + + % Set default size + obj.Position(3:4) = [100 25]; + + % Update the internal component lists + obj.BackgroundColorableComponents = obj.Grid; + + end %function + + + function update(obj) + + % How many fields? + numElements = numel(obj.Value); + numFields = numel(obj.EditField); + numRows = numel(obj.Grid.RowHeight); + numCols = numel(obj.Grid.ColumnWidth); + if numFields ~= numElements || ... + numRows > 1 && numElements > 1 && obj.Orientation == "horizontal" || ... + numCols > 1 && numElements > 1 && obj.Orientation == "vertical" + obj.createEditFields(numElements); + end + + % Loop on each edit field to update it + for idx = 1:numElements + + % Calculate limits + lowerLimit = obj.Limits(1); + upperLimit = obj.Limits(2); + lowerLimitInclusive = obj.LowerLimitInclusive; + upperLimitInclusive = obj.UpperLimitInclusive; + + switch (obj.Restriction) + + case wt.enum.ArrayRestriction.increasing + + if idx > 1 + lowerLimit = obj.Value(idx-1); + lowerLimitInclusive = false; + end + + if idx < numElements + upperLimit = obj.Value(idx+1); + upperLimitInclusive = false; + end + + case wt.enum.ArrayRestriction.decreasing + + if idx > 1 + upperLimit = obj.Value(idx-1); + upperLimitInclusive = false; + end + + if idx < numElements + lowerLimit = obj.Value(idx+1); + lowerLimitInclusive = false; + end + + end %switch + + % Apply restrictions + % obj.EditField(idx).Limits = [lowerLimit upperLimit]; + % obj.EditField(idx).LowerLimitInclusive = lowerLimitInclusive; + % obj.EditField(idx).UpperLimitInclusive = upperLimitInclusive; + + % Update the edit fields values + obj.EditField(idx).Value = obj.Value(idx); + + end %for + + end %function + + + function createEditFields(obj, numFields) + + % Delete existing content + delete(obj.EditField); + obj.EditField(:) = []; + + % Configure Grid + gridRep = repmat({'1x'},1,numFields); + if obj.Orientation == wt.enum.HorizontalVerticalState.vertical + obj.Grid.ColumnWidth = {'1x'}; + obj.Grid.RowHeight = gridRep; + else + obj.Grid.ColumnWidth = gridRep; + obj.Grid.RowHeight = {'1x'}; + end + + % Create edit fields + for idx = 1:numFields + obj.EditField(idx) = uieditfield(obj.Grid,'numeric'); + end %for + set(obj.EditField,"ValueChangedFcn",@(h,e)obj.onValueChanged(e)); + + % Update the internal component lists + obj.FontStyledComponents = obj.EditField; + obj.FieldColorableComponents = obj.EditField; + obj.EnableableComponents = obj.EditField; + obj.TooltipableComponents = obj.EditField; + + end %function + + + function onValueChanged(obj,~) + % Triggered on edit field interaction + + % Get prior value + oldValue = obj.Value; + + % Get new value + newValue = [obj.EditField.Value]; + + % Store new result + obj.Value = newValue; + + % Trigger event + evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue); + notify(obj,"ValueChanged",evtOut); + + end %function + + end %methods + + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/ProgressBar.m b/widgets/+wt/ProgressBar.m index 76c33c1..b379e1c 100644 --- a/widgets/+wt/ProgressBar.m +++ b/widgets/+wt/ProgressBar.m @@ -31,7 +31,7 @@ properties (Dependent, UsedInUpdate = false) % Bar color - BarColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} + BarColor (1,3) double {mustBeInRange(BarColor,0,1)} end %properties @@ -41,7 +41,7 @@ properties (SetAccess = protected, UsedInUpdate = false) % Current progress value - Value (1,1) double {mustBeNonnegative, mustBeLessThanOrEqual(Value,1)} = 0 + Value (1,1) double {mustBeInRange(Value,0,1)} = 0 % Current status text displayed StatusText (1,1) string @@ -182,8 +182,8 @@ function cancel(obj) drawnow % Trigger event - evt = wt.eventdata.ButtonPushedData(obj.CancelButton, "Cancel"); - notify(obj,"CancelPressed",evt); + evtOut = wt.eventdata.ButtonPushedData(obj.CancelButton, "Cancel"); + notify(obj,"CancelPressed",evtOut); end %function diff --git a/widgets/+wt/RangeField.m b/widgets/+wt/RangeField.m new file mode 100644 index 0000000..0f2f654 --- /dev/null +++ b/widgets/+wt/RangeField.m @@ -0,0 +1,139 @@ +classdef RangeField < matlab.ui.componentcontainer.ComponentContainer & ... + wt.mixin.BackgroundColorable & ... + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Tooltipable + % Pair of numeric edit fields for range selection + + % Copyright 2024 The MathWorks Inc. + + %RJ - Need unit tests + %RJ - Improve error if a restriction needs enforcement. Like display a + % message but still accept their input? + + + %% Public properties + properties (AbortSet) + + % Values of the range (min/max) + Value (1,2) double = [0 1] + + % Optional limits of the range (min/max) + Limits (1,2) double = [-inf inf] + + % Is the lower limit inclusive? + LowerLimitInclusive (1,1) matlab.lang.OnOffSwitchState = true + + % Is the upper limit inclusive? + UpperLimitInclusive (1,1) matlab.lang.OnOffSwitchState = true + + end %properties + + + methods + function set.Value(obj,value) + validateattributes(value,{'double'},{'increasing'}) + obj.Value = value; + end + function set.Limits(obj,value) + validateattributes(value,{'double'},{'increasing'}) + obj.Limits = value; + end + end + + + %% Events + events (HasCallbackProperty, NotifyAccess = protected) + + % Triggered on value changed, has companion callback + ValueChanged + + end %events + + + %% Internal Properties + properties (Transient, NonCopyable, Hidden, SetAccess = protected) + + % Grid + Grid (1,1) matlab.ui.container.GridLayout + + % Edit fields + EditField (1,2) matlab.ui.control.NumericEditField + + end %properties + + + %% Protected methods + methods (Access = protected) + + function setup(obj) + + % Construct Grid Layout to Manage Building Blocks + obj.Grid = uigridlayout(obj); + obj.Grid.ColumnWidth = {'1x','1x'}; + obj.Grid.RowHeight = {'1x'}; + obj.Grid.ColumnSpacing = 5; + obj.Grid.Padding = 0; + + % Set default size + obj.Position(3:4) = [100 25]; + + % Create the edit field + obj.EditField = [... + uieditfield(obj.Grid,'numeric'), ... + uieditfield(obj.Grid,'numeric') ]; + obj.EditField(1).UpperLimitInclusive = false; + obj.EditField(2).LowerLimitInclusive = false; + set(obj.EditField,"ValueChangedFcn",@(h,e)obj.onValueChanged(e)); + + % Update the internal component lists + obj.BackgroundColorableComponents = obj.Grid; + obj.EnableableComponents = obj.EditField; + obj.FieldColorableComponents = obj.EditField; + obj.FontStyledComponents = obj.EditField; + obj.TooltipableComponents = obj.EditField; + + end %function + + + function update(obj) + + % Update the edit field limits + obj.EditField(1).LowerLimitInclusive = obj.LowerLimitInclusive; + obj.EditField(1).Limits = [obj.Limits(1) obj.Value(2)]; + + obj.EditField(2).UpperLimitInclusive = obj.UpperLimitInclusive; + obj.EditField(2).Limits = [obj.Value(1) obj.Limits(2)]; + + % Update the edit field values + obj.EditField(1).Value = obj.Value(1); + obj.EditField(2).Value = obj.Value(2); + + end %function + + + function onValueChanged(obj,evt) + % Triggered on edit field interaction + + % Get prior value + oldValue = obj.Value; + + % Get new value + newValue = [obj.EditField.Value]; + index = find(evt.Source == obj.EditField, 1); + + % Store new result + obj.Value = newValue; + + % Trigger event + evtOut = wt.eventdata.ValueChangedData(obj.Value, oldValue,... + "Index", index); + notify(obj,"ValueChanged",evtOut); + + end %function + + end %methods + + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/RowEntriesTable.m b/widgets/+wt/RowEntriesTable.m new file mode 100644 index 0000000..726ac5a --- /dev/null +++ b/widgets/+wt/RowEntriesTable.m @@ -0,0 +1,482 @@ +classdef RowEntriesTable < matlab.ui.componentcontainer.ComponentContainer & ... + wt.mixin.BackgroundColorable & ... + wt.mixin.ButtonColorable &... + wt.mixin.Enableable & ... + wt.mixin.FieldColorable & ... + wt.mixin.FontStyled & ... + wt.mixin.Orderable & ... + wt.mixin.Tooltipable + % A table showing status of multiple tasks + + % Copyright 2024 The MathWorks Inc. + + + %RJ - Need unit tests + %RJ - Connect ordering buttons and make them optional + %RJ - Table enable didn't work + + + %% Public properties + properties (AbortSet) + + % Table entries + Data table + + % Format for new table row + NewRowFormat (1,:) cell = {"NewRow",0} + + % Indicates whether to allow sort controls + Sortable (1,1) matlab.lang.OnOffSwitchState = false + + % Can each item be removed? + AllowItemRemove (1,:) logical + + % Can each item be sorted/ordered? + AllowItemSort (1,:) logical + + end %properties + + + % Accessors + methods + + function value = get.AllowItemRemove(obj) + value = resize(obj.AllowItemRemove, height(obj.Data), ... + "FillValue", true); + end + + function value = get.AllowItemSort(obj) + value = resize(obj.AllowItemSort, height(obj.Data), ... + "FillValue", true); + end + + end %methods + + + %% Dependent properties + properties (Dependent, SetAccess = private) + + StyleConfigurations + + end %properties + + properties (Dependent) + + TableWidth + + TableHeight + + end %properties + + + methods + + function value = get.TableWidth(obj) + value = obj.Grid.ColumnWidth{1}; + end + function set.TableWidth(obj, value) + obj.Grid.ColumnWidth{1} = value; + end + + function value = get.TableHeight(obj) + value = obj.Grid.RowHeight{end}; + end + function set.TableHeight(obj, value) + obj.Grid.RowHeight{end} = value; + end + + function value = get.StyleConfigurations(obj) + value = obj.Table.StyleConfigurations; + end + + end %methods + + + %% Events + events (HasCallbackProperty, NotifyAccess = protected) + + % Triggered on value changed, has companion callback + ValueChanged + + end %events + + + %% Internal Properties + properties (Transient, NonCopyable, Hidden, SetAccess = protected) + + % Grid + Grid matlab.ui.container.GridLayout + + % Table for entries + Table matlab.ui.control.Table + + % Buttons + AddButton matlab.ui.control.Button + RemoveButton matlab.ui.control.Button + UpButton matlab.ui.control.Button + DownButton matlab.ui.control.Button + + end %properties + + + %% Public methods + methods + + function addStyle(obj,s,tableTarget,tableIndex) + % Add a style to the table + + arguments (Input) + obj (1,1) wt.RowEntriesTable + s (1,1) matlab.ui.style.Style + tableTarget (1,1) string {mustBeMember(tableTarget,... + ["table","row","column","cell"])} = "table" + tableIndex = "" + end + + % Add the style to the internal table + addStyle(obj.Table, s, tableTarget, tableIndex) + + end %function + + + function removeStyle(obj,orderNum) + % Add a style to the table + + arguments (Input) + obj (1,1) wt.RowEntriesTable + orderNum = [] + end + + % Remove the style from the internal table + if isempty(orderNum) + removeStyle(obj.Table) + else + removeStyle(obj.Table, orderNum) + end + + end %function + + end %methods + + + %% Protected methods + methods (Access = protected) + + function setup(obj) + + % Construct Grid Layout to Manage Building Blocks + obj.Grid = uigridlayout(obj,[5,2]); + obj.Grid.ColumnWidth = {'1x',30}; + obj.Grid.RowHeight = {30,30,30,30,'1x'}; + obj.Grid.Padding = 0; + obj.Grid.ColumnSpacing = 2; + obj.Grid.RowSpacing = 5; + + % Set default size + obj.Position(3:4) = [300 200]; + + % Create the Table + obj.Table = uitable(obj.Grid); + obj.Table.ColumnEditable = true; + obj.Table.SelectionType = 'row'; + obj.Table.Layout.Column = 1; + obj.Table.Layout.Row = [1 5]; + obj.Table.CellEditCallback = @(src,evt)obj.onCellEdited(evt); + obj.Table.SelectionChangedFcn = @(src,evt)obj.onSelectionChanged(evt); + + % Create the buttons + obj.AddButton = uibutton(obj.Grid); + obj.AddButton.Icon = "addYellow_24.png"; + obj.AddButton.Text = ""; + obj.AddButton.Layout.Column = 2; + obj.AddButton.Layout.Row = 1; + obj.AddButton.ButtonPushedFcn = @(src,evt)obj.onAddButton(evt); + + obj.RemoveButton = uibutton(obj.Grid); + obj.RemoveButton.Icon = "delete_24.png"; + obj.RemoveButton.Text = ""; + obj.RemoveButton.Layout.Column = 2; + obj.RemoveButton.Layout.Row = 2; + obj.RemoveButton.ButtonPushedFcn = @(src,evt)obj.onRemoveButton(evt); + + obj.UpButton = uibutton(obj.Grid); + obj.UpButton.Icon = "up_24.png"; + obj.UpButton.Text = ""; + obj.UpButton.Layout.Column = 2; + obj.UpButton.Layout.Row = 3; + obj.UpButton.ButtonPushedFcn = @(src,evt)obj.onUpButton(evt); + + obj.DownButton = uibutton(obj.Grid); + obj.DownButton.Icon = "down_24.png"; + obj.DownButton.Text = ""; + obj.DownButton.Layout.Column = 2; + obj.DownButton.Layout.Row = 4; + obj.DownButton.ButtonPushedFcn = @(src,evt)obj.onDownButton(evt); + + % Update the internal component lists + obj.BackgroundColorableComponents = obj.Grid; + obj.ButtonColorableComponents = [obj.AddButton, ... + obj.RemoveButton, obj.UpButton, obj.DownButton]; + obj.EnableableComponents = [obj.Table, obj.AddButton, ... + obj.RemoveButton, obj.UpButton, obj.DownButton]; + obj.FieldColorableComponents = obj.Table; + obj.FontStyledComponents = obj.Table; + obj.TooltipableComponents = obj.Table; + + end %function + + + function update(obj) + + % Get the data + data = obj.Data; + + % If empty and no vars, use NewRowFormat + if width(data) == 0 + data = cell(0, numel(obj.NewRowFormat)); + end + + % Update the table content + obj.Table.Data = data; + + % Update sort buttons + obj.updateSortButtons(); + + end %function + + + function updateEnableableComponents(obj) + % Handle changes to Enable flag + + % Update sort buttons + obj.updateSortButtons(); + + % Update fields + obj.Table.Enable = string(obj.Enable); + + end %function + + + function updateSortButtons(obj) + + % Which rows are selected? + numItems = height(obj.Data); + idxSel = obj.Table.Selection; + + % Which items allow removal? + allowRemove = obj.AllowItemRemove(idxSel); + canRemove = obj.Enable && ~isempty(idxSel) && all(allowRemove); + + % Which items allow sorting + alloItemSort = obj.AllowItemSort; + % canSort = obj.Enable && obj.Sortable && all(allowSort(idxSel)); + + % Toggle sorting button visibility + obj.UpButton.Visible = obj.Sortable; + obj.DownButton.Visible = obj.Sortable; + + % Update button enables + obj.AddButton.Enable = obj.Enable; + obj.RemoveButton.Enable = canRemove; + if obj.Sortable + [backEnabled, fwdEnabled] = obj.areOrderButtonsEnabled(... + numItems, idxSel, alloItemSort); + obj.UpButton.Enable = backEnabled; + obj.DownButton.Enable = fwdEnabled; + end + + end %function + + + function onAddButton(obj,~) + % Triggered on button pushed + + % Get old/new data + oldData = obj.Data; + newRowData = obj.NewRowFormat; + numOldRows = height(oldData); + numNewRows = numOldRows + 1; + numOldCols = width(oldData); + + % Determine placement + selRowIdx = obj.Table.Selection; + if isempty(selRowIdx) + selRowIdx = numOldRows; + end + newRowIdx = selRowIdx + 1; + + % Does table already have columns? + if numOldCols > 0 + + % New row must be same width as table + newRowData = resize(newRowData, [1 numOldCols]); + + % Add content to table + newData = paddata(oldData,numNewRows,"FillValue",newRowData); + + end + + % Order new data + newData = [ + newData(1:selRowIdx,:) + newData(end,:) + newData(newRowIdx:numOldRows,:) + ]; + + % Prepare event data + evtOut = wt.eventdata.RowEntriesTableChangedData(); + evtOut.Action = "RowAdded"; + evtOut.Row = newRowIdx; + evtOut.Column = 1:size(newData,2); + evtOut.Value = newData(newRowIdx,:); + evtOut.PreviousValue = oldData([],:); + evtOut.TableData = newData; + evtOut.PreviousTableData = oldData; + + % Store new result and select it + obj.Table.Data = newData; + obj.Table.Selection = newRowIdx; + obj.Data = newData; + + % Trigger event + notify(obj,"ValueChanged",evtOut); + + end %function + + + function onRemoveButton(obj,~) + % Triggered on button pushed + + % Get the selection and total rows + selRows = obj.Table.Selection; + if isempty(selRows) + return + end + numSelRows = numel(selRows); + numRows = height(obj.Data); + + % Prepare the new data + oldData = obj.Data; + removedData = oldData(selRows,:); + newData = oldData; + newData(selRows,:) = []; + + % Calculate new row selection + newSelRows = selRows; + newNumRows = numRows - numSelRows; + isOver = newSelRows > newNumRows; + newSelRows(isOver) = newSelRows(isOver) - numSelRows; + newSelRows(newSelRows < 1 | newSelRows > newNumRows) = []; + newSelRows = unique(newSelRows); + + % Prepare event data + evtOut = wt.eventdata.RowEntriesTableChangedData(); + evtOut.Action = "RowRemoved"; + evtOut.Row = selRows; + evtOut.Column = 1:size(oldData,2); + evtOut.Value = removedData([],:); + evtOut.PreviousValue = removedData; + evtOut.TableData = newData; + evtOut.PreviousTableData = oldData; + + % Store new result and update selection + obj.Table.Data = newData; + obj.Table.Selection = newSelRows; + obj.Data = newData; + + % Trigger event + notify(obj,"ValueChanged",evtOut); + + end %function + + + function onUpButton(obj,~) + % Triggered on button pushed + + obj.shiftSelectedRows(-1); + + end %function + + + function onDownButton(obj,~) + % Triggered on button pushed + + obj.shiftSelectedRows(1); + + end %function + + + function shiftSelectedRows(obj,shift) + % Shift the selected rows up/down + + numItems = height(obj.Data); + idxSel = obj.Table.Selection; + + % Shift the list indices + [idxNew, idxSelAfter] = obj.shiftListIndices(shift, numItems, idxSel); + + % Get the original value + oldData = obj.Table.Data; + + % Make the shift + newData = oldData(idxNew,:); + + % Prepare event data + evtOut = wt.eventdata.RowEntriesTableChangedData(); + evtOut.Action = "RowOrdered"; + % evtOut.Row = + % evtOut.Column = + evtOut.Value = idxNew; + % evtOut.PreviousValue = + evtOut.TableData = newData; + evtOut.PreviousTableData = oldData; + + % Update the table + obj.Data = newData; + obj.Table.Selection = idxSelAfter; + + % Trigger event + notify(obj,"ValueChanged",evtOut); + + % Update buttons + obj.updateSortButtons() + + end %function + + + function onSelectionChanged(obj,~) + % Triggered on table selection changed + + % Update button enables + obj.updateEnableableComponents(); + + end %function + + + function onCellEdited(obj,evt) + % Triggered on cell edited + + % Prepare event data + evtOut = wt.eventdata.RowEntriesTableChangedData(); + evtOut.Action = "CellEdited"; + evtOut.Row = evt.Indices(1); + evtOut.Column = evt.Indices(2); + evtOut.Value = evt.NewData; + evtOut.PreviousValue = evt.PreviousData; + evtOut.EditValue = evt.EditData; + evtOut.TableData = [obj.Table.Data]; + evtOut.PreviousTableData = obj.Data; + evtOut.Error = evt.Error; + + % Store new result + obj.Data = [obj.Table.Data]; + + % Trigger event + notify(obj,"ValueChanged",evtOut); + + end %function + + end %methods + + +end % classdef \ No newline at end of file diff --git a/widgets/+wt/SliderCheckboxGroup.m b/widgets/+wt/SliderCheckboxGroup.m index 741e07c..db949f0 100644 --- a/widgets/+wt/SliderCheckboxGroup.m +++ b/widgets/+wt/SliderCheckboxGroup.m @@ -175,42 +175,42 @@ function updateEnableableComponents(obj) end %function - function onSliderChanged(obj,e) + function onSliderChanged(obj,evt) % Triggered on button pushed % What changed? - newValue = e.Value; - idx = find(e.Source == obj.Slider, 1); + newValue = evt.Value; + idx = find(evt.Source == obj.Slider, 1); % Update the state obj.Value(idx) = newValue; % Create event data - evt = wt.eventdata.SliderCheckboxChangedData(... + evtOut = wt.eventdata.SliderCheckboxChangedData(... obj.Name(idx), idx, "Value", obj.State(idx), obj.Value(idx) ); % Trigger event - notify(obj,"ValueChanged",evt); + notify(obj,"ValueChanged",evtOut); end %function - function onCheckboxChanged(obj,e) + function onCheckboxChanged(obj,evtOut) % Triggered on button pushed % What changed? - newValue = e.Value; - idx = find(e.Source == obj.Checkbox, 1); + newValue = evtOut.Value; + idx = find(evtOut.Source == obj.Checkbox, 1); % Update the state obj.State(idx) = newValue; % Create event data - evt = wt.eventdata.SliderCheckboxChangedData(... + evtOut = wt.eventdata.SliderCheckboxChangedData(... obj.Name(idx), idx, "State", obj.State(idx), obj.Value(idx) ); % Trigger event - notify(obj,"ValueChanged",evt); + notify(obj,"ValueChanged",evtOut); end %function diff --git a/widgets/+wt/SliderSpinner.m b/widgets/+wt/SliderSpinner.m index 8b97dde..d7fe09a 100644 --- a/widgets/+wt/SliderSpinner.m +++ b/widgets/+wt/SliderSpinner.m @@ -155,11 +155,11 @@ function updateLayout(obj) end %function - function onSliderChanged(obj,e) + function onSliderChanged(obj,evt) % Triggered on button pushed % What changed? - newValue = e.Value; + newValue = evt.Value; oldValue = obj.Spinner.Value; % Round? @@ -178,16 +178,16 @@ function onSliderChanged(obj,e) end % Trigger event ("ValueChanged" or "ValueChanging") - notify(obj, e.EventName, evtOut); + notify(obj, evt.EventName, evtOut); end %function - function onSliderChanging(obj,e) + function onSliderChanging(obj,evt) % Triggered on button pushed % What changed? - newValue = e.Value; + newValue = evt.Value; oldValue = obj.Spinner.Value; % Round? @@ -203,7 +203,7 @@ function onSliderChanging(obj,e) obj.Spinner.Value = newValue; % Trigger event ("ValueChanging") - notify(obj, e.EventName, evtOut); + notify(obj, evt.EventName, evtOut); end %function diff --git a/widgets/+wt/TaskStatusTable.m b/widgets/+wt/TaskStatusTable.m index ba2aed1..de3f4ff 100644 --- a/widgets/+wt/TaskStatusTable.m +++ b/widgets/+wt/TaskStatusTable.m @@ -34,7 +34,7 @@ % Selection color SelectionColor (1,3) double ... - {wt.validators.mustBeBetweenZeroAndOne} = [.8 .8 1]; + {mustBeInRange(SelectionColor,0,1)} = [.8 .8 1]; % Enables button and status row to display ShowButtonRow (1,1) matlab.lang.OnOffSwitchState = true diff --git a/widgets/examples/ZooAppExample.m b/widgets/examples/ZooAppExample.m new file mode 100644 index 0000000..4b1b1b9 --- /dev/null +++ b/widgets/examples/ZooAppExample.m @@ -0,0 +1,30 @@ +function varargout = ZooAppExample(varargin) +% Launch app + +% Default +varargout{1} = []; + + +%% Check dependencies +if ~exist("wt.apps.BaseApp","class") + error("Widgets Toolbox is required to run this app. " + ... + "Install from Add-Ons browser."); +end + + +%% Bugfixes + + + +%% Instantiate the application +app = wtexample.app.ContextualViewExample(varargin{:}); + + +%% Load default session +app.loadSession(which("robyn_session.mat")) + + +%% Collect output +if nargout + varargout{1} = app; +end diff --git a/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/ContextualViewExample.m b/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/ContextualViewExample.m new file mode 100644 index 0000000..8446381 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/ContextualViewExample.m @@ -0,0 +1,316 @@ +classdef ContextualViewExample < wt.apps.BaseMultiSessionApp + % Example app showing a tree with contextual views + + % Copyright 2024 The MathWorks Inc. + + + %% Internal properties + properties (Hidden, Transient, SetAccess = private) + + % Toolbar at top of the app window + Toolbar wt.Toolbar + + % Navigation tree on the left of the app + Tree matlab.ui.container.Tree + + % Contextual pane to show view/controller for selected tree node + ContextualView wt.ContextualView + + ExhibitAddButton + ExhibitDeleteButton + + + % NewSelection (:,1) wt.model.BaseModel {mustBeScalarOrEmpty} + + end %properties + + + %% Protected Methods + methods (Access = protected) + + % Declarations for methods in separate files + updateTreeHierarchy(app) + + + function session = createNewSession(app) + + % Show output if Debug is on + app.displayDebugText(); + + session = wtexample.model.Session; + + end %function + + + function setup(app) + % Initial setup / creation of the app + + % Show output if Debug is on + app.displayDebugText(); + + % Set the name + app.Name = "Contextual View Example"; + + % Configure the main grid + app.Grid.Padding = 10; + app.Grid.ColumnSpacing = 10; + app.Grid.RowHeight = {90,'1x'}; + app.Grid.ColumnWidth = {250,'1x'}; + + % Create toolbar file section + fileSection = wt.toolbar.HorizontalSection(); + fileSection.Title = "FILE"; + fileSection.addButton("new_24.png","New"); + fileSection.addButton("open_24.png","Open"); + fileSection.addButton("saveClean_24.png","Save"); + fileSection.addButton("saveClean_24.png","Save As"); + fileSection.addButton("import_24.png","Import"); + fileSection.ButtonPushedFcn = @(~,evt)onFileButtonPushed(app,evt); + + % Create exhibit section + exhibitSection = wt.toolbar.HorizontalSection(); + exhibitSection.Title = "EXHIBIT"; + app.ExhibitAddButton = exhibitSection.addButton("addGreen_24.png","New"); + app.ExhibitDeleteButton = exhibitSection.addButton("delete_24.png","Delete"); + exhibitSection.ButtonPushedFcn = @(~,evt)onExhibitButtonPushed(app,evt); + + % Add toolbar + app.Toolbar = wt.Toolbar(app.Grid); + app.Toolbar.DividerColor = [.8 .8 .8]; + app.Toolbar.Layout.Row = 1; + app.Toolbar.Layout.Column = [1 2]; + app.Toolbar.Section = [fileSection, exhibitSection]; + + % Create navigation tree + app.Tree = uitree(app.Grid); + app.Tree.SelectionChangedFcn = @(~,evt)onTreeSelection(app,evt); + app.Tree.FontSize = 14; + app.Tree.Layout.Row = 2; + app.Tree.Layout.Column = 1; + + % Create contextual view pane + app.ContextualView = wt.ContextualView(app.Grid); + app.ContextualView.Layout.Row = 2; + app.ContextualView.Layout.Column = 2; + + end %function + + + function update(app) + + % Show output if Debug is on + app.displayDebugText(); + + % Update the tree hierarchy + app.updateTreeHierarchy() + + % If a new selection is requested, change it now + % if isscalar(app.NewSelection) && isvalid(app.NewSelection) + % + % end + + % Select the new node + % app.Tree.SelectedNodes = app.Tree.Children(end); + %RJ - need to add selection states in the session! That + %way, update can properly select the tree choice. + + end %function + + + function session = getSessionFromTreeNode(app,node) + % Determines the session of the selected tree node + + arguments + app (1,1) wt.apps.BaseApp + node (1,1) matlab.ui.container.TreeNode + end + + nodeData = node.NodeData; + if ~isscalar(nodeData) + + % Shouldn't happen, but return empty + session = wtexample.model.Session.empty(1,0); + + elseif isa(nodeData, "wt.model.BaseSession") + + % Found it! + session = nodeData; + + elseif isa(nodeData, "wt.model.BaseModel") && ~isempty(node.Parent) + + % Look to parent + session = app.getSessionFromTreeNode(node.Parent); + + else + + % Can't find, return empty + session = getEmptySession(); + + end %if + + end %function + + + function onTreeSelection(app,evt) + % On selected tree node changed + + % Show output if Debug is on + app.displayDebugText(); + + % What node(s) are selected? + selNode = evt.SelectedNodes; + + % Is it a scalar selection? + if isscalar(selNode) + + % Set the selected session + session = app.getSessionFromTreeNode(selNode); + app.selectSession(session); + + % Get the data model, which is attached to this node + model = selNode.NodeData; + modelClass = class(model); + + % Which view to launch? + viewClass = replace(modelClass,".model.",".viewcontroller."); + + % Launch the contextual pane for the selected data type + app.ContextualView.launchView(viewClass, model); + + else + + % Clear the contextual pane + app.ContextualView.clearView(); + + end %if + + end %function + + + function onFileButtonPushed(app,evt) + + % Show output if Debug is on + app.displayDebugText(); + + % Get the selected session + session = app.SelectedSession; + + switch evt.Text + + case 'New' + + % Add a new session + session = app.newSession(); + + % Select the new session + if ~isempty(session) + app.selectSession(session); + end + + case 'Open' + + % Prompt and load a session + session = app.loadSession(); + + % Select the new session + if ~isempty(session) + app.selectSession(session); + end + + case 'Save' + + % Save the session + app.saveSession(false, session); + + case 'Save As' + + % Save the session as different file + app.saveSession(true, session); + + case 'Import' + + filter = ["*.xlsx","Excel Document"]; + title = "Select spreadsheet to import"; + filePath = app.promptToLoad(filter,title); + + if isfile(filePath) + try + session.importManifest(filePath); + catch err + message = sprintf("Unable to load " + ... + "manifest: %s\n\n%s",filePath,err.message); + app.throwError(message) + end + end + + end %switch + + % Update the app + app.update() + + end %function + + + function onExhibitButtonPushed(app,evt) + + % Show output if Debug is on + app.displayDebugText(); + + % Get the selected session + session = app.SelectedSession; + + % Which button was pressed? + switch evt.Text + + case 'New' + + % Add a new exhibit + newItem = wtexample.model.Exhibit; + newItem.Name = "New Exhibit"; + + % Add the new exhibit + session.Exhibit(end+1) = newItem; + + % Indicate the new exhibit should be selected at the next update + % app.NewSelection = newItem; + + case 'Delete' + + % Get the selected node + selNode = app.Tree.SelectedNodes; + + % Return if nonscalar node + if ~isscalar(selNode) || ~isvalid(selNode) + return + end + + % Get the data model, which is attached to this node + model = selNode.NodeData; + modelClass = class(model); + + % Is the selected node a valid exhibit? + if modelClass == "wtexample.model.Exhibit" + + % Prompt user before deleting + message = "Are you sure you want to delete the exhibit """... + + model.Name + """?"; + response = app.promptYesNoCancel(message); + if matches(response,"yes","IgnoreCase",true) + + % Delete the exhibit + isMatch = session.Exhibit == model; + session.Exhibit(isMatch) = []; + + end %if + + end %if + + end %switch + + app.update() + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/updateTreeHierarchy.m b/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/updateTreeHierarchy.m new file mode 100644 index 0000000..217fbc4 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+app/@ContextualViewExample/updateTreeHierarchy.m @@ -0,0 +1,215 @@ +function updateTreeHierarchy(app) +% Creates/updates the tree hierarchy by synchronizing each level + +% Copyright 2024 The MathWorks Inc. + +% Show output if Debug is on +app.displayDebugText(); + +% Sync session nodes +syncSessionNodes(app.Tree, app.Session) + + +end %function + + +%% Sync Session Nodes +function syncSessionNodes(parentNode,model) +% Synchronizes child nodes to a model array + +arguments + parentNode (1,1) matlab.ui.container.Tree + model (1,:) wtexample.model.Session +end + +% Capture existing session nodes +oldSessionNodes = parentNode.Children; + +% Sync nodes at this level +sessionNodes = syncNodes(parentNode, model); + +% Loop on each model +for idx = 1:numel(model) + + % Get current node/model pair + thisNode = sessionNodes(idx); + thisModel = model(idx); + + % Update the node's text and icon + nodeText = "Session: " + thisModel.FileName; + if thisModel.Dirty + nodeText = nodeText + " *"; + end + thisNode.Text = nodeText; + thisNode.Icon = "document2_24.png"; + + % Sync children of node + syncExhibitNodes(thisNode, thisModel.Exhibit) + +end %for + +% Expand any new session nodes +isNew = ~ismember(sessionNodes, oldSessionNodes); +if any(isNew) + expand(sessionNodes(isNew)) +end + +end %function + + +%% Sync Exhibit Nodes +function syncExhibitNodes(parentNode,model) +% Synchronizes child nodes to a model array + +arguments + parentNode (1,1) matlab.ui.container.TreeNode + model (1,:) wtexample.model.Exhibit +end + +% Sync nodes at this level +exhibitNodes = syncNodes(parentNode, model); + +% Loop on each model +for idx = 1:numel(model) + + % Get current node/model pair + thisNode = exhibitNodes(idx); + thisModel = model(idx); + + % Update the node's text and icon + thisNode.Text = "Exhibit: " + thisModel.Name; + thisNode.Icon = "exhibit.png"; + + % Sync children of node + syncEnclosureNodes(thisNode, thisModel.Enclosure) + +end %for + +end %function + + +%% Sync Enclosure Nodes +function syncEnclosureNodes(parentNode,model) +% Synchronizes child nodes to a model array + +arguments + parentNode (1,1) matlab.ui.container.TreeNode + model (1,:) wtexample.model.Enclosure +end + +% Sync nodes at this level +enclosureNodes = syncNodes(parentNode, model); + +% Loop on each model +for idx = 1:numel(model) + + % Get current node/model pair + thisNode = enclosureNodes(idx); + thisModel = model(idx); + + % Update the node's text and icon + thisNode.Text = "Enclosure: " + thisModel.Name; + thisNode.Icon = "enclosure.png"; + + % Sync children of node + syncAnimalNodes(thisNode, thisModel.Animal) + +end %for + +end %function + + +%% Sync Animal Nodes +function syncAnimalNodes(parentNode,model) +% Synchronizes child nodes to a model array + +arguments + parentNode (1,1) matlab.ui.container.TreeNode + model (1,:) wtexample.model.Animal +end + +% Sync nodes at this level +animalNodes = syncNodes(parentNode, model); + +% Loop on each model +for idx = 1:numel(model) + + % Get current node/model pair + thisNode = animalNodes(idx); + thisModel = model(idx); + + % Update the node's text and icon + thisNode.Text = "Animal: " + thisModel.Name; + thisNode.Icon = "animal.png"; + + % This is the lowest level - no children to sync + +end %for + +end %function + + + +%% Synchronize one level of tree nodes with a model class +function newNodeList = syncNodes(parentNode, model) +% Synchronizes nodes for one level of hierarchy + +arguments + parentNode % matlab.ui.container.TreeNode or matlab.ui.container.Tree + model (1,:) wt.model.BaseModel +end + +% Get existing child nodes +childNodes = parentNode.Children; + +% Get the models they reference +if isempty(childNodes) + % Empty of same type as input + childNodeData = model([]); +else + childNodeData = horzcat(childNodes.NodeData); +end + +% Preallocate new node list +persistent dummyNode emptyNodeList +if isempty(dummyNode) + dummyNode = matlab.ui.container.TreeNode; + emptyNodeList = matlab.ui.container.TreeNode.empty(1,0); +end +numModels = numel(model); +if numModels > 0 + newNodeList(1, numModels) = dummyNode; +else + newNodeList = emptyNodeList; +end + +% Track which existing child nodes are updated so we can +% remove old ones later +childNodeUpdated = false(size(childNodes)); + +% Loop on each model +for idx = 1:numModels + + % Does this model already have a node? + isMatch = model(idx) == childNodeData; + idxMatch = find(isMatch, 1); + if isempty(idxMatch) + % NO - Create a new node + newNode = uitreenode(parentNode); + newNode.NodeData = model(idx); + else + % YES - Use existing node + newNode = childNodes(idxMatch); + childNodeUpdated(idxMatch) = true; + end + + % Store tne new node + newNodeList(idx) = newNode; + +end %for + +% Remove any unused nodes +unusedNodes = childNodes(~childNodeUpdated); +delete(unusedNodes) + +end %function \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+enum/Sex.m b/widgets/examples/apps/contextual_view/+wtexample/+enum/Sex.m new file mode 100644 index 0000000..380a352 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+enum/Sex.m @@ -0,0 +1,11 @@ +classdef Sex + % Implements a selection list + + enumeration + unspecified + male + female + other + end + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+model/Animal.m b/widgets/examples/apps/contextual_view/+wtexample/+model/Animal.m new file mode 100644 index 0000000..1a36ce7 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+model/Animal.m @@ -0,0 +1,53 @@ +classdef Animal < wt.model.BaseModel + % Implements the model class for a zoo animal + + + %% Public Properties + properties (AbortSet, SetObservable) + + % Species of the animal + Species (1,1) string + + % Birth date of the animal + BirthDate (1,1) datetime = NaT + + % Sex of the animal + Sex (1,1) wtexample.enum.Sex = wtexample.enum.Sex.unspecified + + end %properties + + + %% Read-Only Properties + properties (Dependent, SetAccess = immutable) + + % Birth date of the animal (years) + Age (1,1) double + + end %properties + + + % Accessors + methods + + function value = get.Age(obj) + value = years(datetime("now") - obj.BirthDate); + end + + end %methods + + + %% Constructor + methods + function obj = Animal(varargin) + % Constructor + + % Call superclass method + % obj@wt.model.BaseModel(varargin{:}); + + % Debug instead + obj@wt.model.BaseModel(varargin{:},"Debug",true); + + end %function + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+model/Enclosure.m b/widgets/examples/apps/contextual_view/+wtexample/+model/Enclosure.m new file mode 100644 index 0000000..6fd3bef --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+model/Enclosure.m @@ -0,0 +1,48 @@ +classdef Enclosure < wt.model.BaseModel + % Implements the model class for an enclosure + + + %% Public Properties + properties (AbortSet, SetObservable) + + % Point location of the enclosure on the map + Location (1,2) double + + % Animals within this enclosure + Animal (1,:) wtexample.model.Animal + + end %properties + + + % Accessors + % methods + % function set.Animal(obj,value) + % obj.Animal = value; + % obj.attachModelListeners("Animal"); + % end + % end %methods + + + %% Constructor + methods + function obj = Enclosure(varargin) + % Constructor + + + + % Call superclass method + % obj@wt.model.BaseModel(varargin{:}); + + % Debug instead + obj@wt.model.BaseModel(... + "Debug",true,... + varargin{:}); + + % obj@wt.model.BaseModel(... + % "AggregatedModelProperties","Animal",... + % "Debug",true,... + % varargin{:}); + end %function + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+model/Exhibit.m b/widgets/examples/apps/contextual_view/+wtexample/+model/Exhibit.m new file mode 100644 index 0000000..21a8f80 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+model/Exhibit.m @@ -0,0 +1,40 @@ +classdef Exhibit < wt.model.BaseModel + % Implements the model class for an exhibit + + + %% Public Properties + properties (AbortSet, SetObservable) + + % Point location of the exhibit on the map + Location (1,2) double + + % Enclosures within this exhibit + Enclosure (1,:) wtexample.model.Enclosure + + end %properties + + + % Accessors + % methods + % function set.Enclosure(obj,value) + % obj.Enclosure = value; + % obj.attachModelListeners("Enclosure"); + % end + % end %methods + + + %% Constructor + methods + function obj = Exhibit(varargin) + % Constructor + + % Call superclass method + % obj@wt.model.BaseModel(varargin{:}); + + % Debug instead + obj@wt.model.BaseModel(varargin{:},"Debug",true); + + end %function + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+model/Session.m b/widgets/examples/apps/contextual_view/+wtexample/+model/Session.m new file mode 100644 index 0000000..2e8bcd1 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+model/Session.m @@ -0,0 +1,135 @@ +classdef Session < wt.model.BaseSession + % Implements the session class for the app + + + %% Public Properties + properties (SetObservable) + + % The array of all exhibits + Exhibit (1,:) wtexample.model.Exhibit + + % Selected indices + % SelectedIndices (1,3) {mustBeInteger} + + end %properties + + + % Accessors + % methods + % function set.Exhibit(obj,value) + % obj.Exhibit = value; + % obj.attachModelListeners("Exhibit"); + % end + % end %methods + + + + %% Methods + methods + + function importManifest(session, filePath) + + arguments + session (1,1) wtexample.model.Session + filePath (1,1) string {mustBeFile} + end + + % Import data + animalTable = readtable(filePath,"Sheet","Animals","TextType","string"); + enclosureTable = readtable(filePath,"Sheet","Enclosures","TextType","string"); + exhibitTable = readtable(filePath,"Sheet","Exhibits","TextType","string"); + + + % === Parse Animals into objects === + + % Get data + thisTable = animalTable; + numRows = height(thisTable); + + % Preallocate output + animal(numRows,1) = wtexample.model.Animal; + + for idx = 1:numRows + + % Create a new instance + newItem = wtexample.model.Animal; + + % Populate data + newItem.Name = thisTable.Name(idx); + newItem.Species = thisTable.Species(idx); + newItem.BirthDate = thisTable.BirthDate(idx); + try + newItem.Sex = thisTable.Sex(idx); + catch + newItem.Sex = 'unspecified'; + end + + % Place in the list + animal(idx) = newItem; + + end %for + + + % === Parse Enclosures into objects === + + % Get data + thisTable = enclosureTable; + numRows = height(thisTable); + + % Preallocate output + enclosure(numRows,1) = wtexample.model.Enclosure; + + for idx = 1:numRows + + % Create a new instance + newItem = wtexample.model.Enclosure; + + % Populate data + newItem.Name = thisTable.Name(idx); + newItem.Location = [thisTable.LocationX(idx), thisTable.LocationY(idx)]; + + % Attach animals belonging to this enclosure + isMatch = matches(animalTable.Enclosure, newItem.Name); + newItem.Animal = animal(isMatch); + + % Place in the list + enclosure(idx) = newItem; + + end %for + + + % === Parse Exhibits into objects === + + % Get data + thisTable = exhibitTable; + numRows = height(thisTable); + + % Preallocate output + exhibit(numRows,1) = wtexample.model.Exhibit; + + for idx = 1:numRows + + % Create a new instance + newItem = wtexample.model.Exhibit; + + % Populate data + newItem.Name = thisTable.Name(idx); + newItem.Location = [thisTable.LocationX(idx), thisTable.LocationY(idx)]; + + % Attach enclosures belonging to this exhibit + isMatch = matches(enclosureTable.Exhibit, newItem.Name); + newItem.Enclosure = enclosure(isMatch); + + % Place in the list + exhibit(idx) = newItem; + + end %for + + % Add to session + session.Exhibit = vertcat(session.Exhibit, exhibit); + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Animal.m b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Animal.m new file mode 100644 index 0000000..c215cc4 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Animal.m @@ -0,0 +1,158 @@ +classdef Animal < wt.abstract.BaseViewController + % View/Controller for Exhibit + + %% Properties + properties (AbortSet, SetObservable) + + % Model class + Model = wtexample.model.Animal.empty(0,0) + + end %properties + + + %% Internal Components + properties (Transient, Hidden, SetAccess = protected) + + SpeciesLabel matlab.ui.control.Label + SpeciesField matlab.ui.control.Label + + NameLabel matlab.ui.control.Label + NameField matlab.ui.control.EditField + + BirthDateLabel matlab.ui.control.Label + BirthDateField matlab.ui.control.DatePicker + + AgeLabel matlab.ui.control.Label + AgeField matlab.ui.control.Label + + SexLabel matlab.ui.control.Label + SexField matlab.ui.control.DropDown + + end %properties + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + + % Call superclass setup first + obj.setup@wt.abstract.BaseViewController(); + + % Configure grid + obj.Grid.ColumnWidth = {'fit','1x'}; + obj.Grid.RowHeight = {'fit','fit','fit','fit','fit'}; + + + % Species field + tooltip = "Species of the animal"; + + obj.SpeciesLabel = uilabel(obj.Grid,... + "Text","Species:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + + obj.SpeciesField = uilabel(obj.Grid,... + "Text","",... + "Tooltip",tooltip); + + + % Name field + tooltip = "Name of the animal"; + + obj.NameLabel = uilabel(obj.Grid,... + "Text","Name:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + + obj.NameField = uieditfield(obj.Grid,... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Name")); + + + % BirthDate field + tooltip = "Birthdate of the animal"; + + obj.BirthDateLabel = uilabel(obj.Grid,... + "Text","BirthDate:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + + obj.BirthDateField = uidatepicker(obj.Grid,... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"BirthDate")); + + + % Age field + tooltip = "Age of the animal"; + + obj.AgeLabel = uilabel(obj.Grid,... + "Text","Age:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + + obj.AgeField = uilabel(obj.Grid,... + "Text","",... + "Tooltip",tooltip); + + + % Sex field + tooltip = "Sex of the animal"; + + obj.SexLabel = uilabel(obj.Grid,... + "Text","Sex:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + + items = string(enumeration("wtexample.enum.Sex")); + obj.SexField = uidropdown(obj.Grid,... + "Tooltip",tooltip,... + "Items",items,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Sex")); + + end %function + + + function update(obj) + + % Call superclass method + obj.update@wt.abstract.BaseViewController(); + + % Is there a valid model? + if isscalar(obj.Model) && isvalid(obj.Model) + % YES - enable controls and get the model + enable = true; + model = obj.Model; + else + % NO - disable controls, show default model values + enable = false; + model = wtexample.model.Animal; + end + + % Update the fields + species = model.Species; + obj.SpeciesField.Text = species; + obj.SpeciesField.Enable = enable; + + name = model.Name; + obj.NameField.Value = name; + obj.NameField.Enable = enable; + + birthDate = model.BirthDate; + obj.BirthDateField.Value = birthDate; + obj.BirthDateField.Enable = enable; + + age = model.Age; + obj.AgeField.Text = string(age); + obj.AgeField.Enable = enable; + + sex = model.Sex; + obj.SexField.Value = sex; + obj.SexField.Enable = enable; + + end %function + + end %methods + +end %classdef + diff --git a/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Enclosure.m b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Enclosure.m new file mode 100644 index 0000000..a208c91 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Enclosure.m @@ -0,0 +1,116 @@ +classdef Enclosure < wt.abstract.BaseViewController + % View/Controller for Exhibit + + %% Properties + properties (AbortSet, SetObservable) + + % Model class + Model = wtexample.model.Enclosure.empty(0,0) + + end %properties + + + %% Internal Components + properties (Transient, Hidden, SetAccess = protected) + + NameLabel matlab.ui.control.Label + NameField matlab.ui.control.EditField + + LocationLabel matlab.ui.control.Label + LocationFieldX matlab.ui.control.NumericEditField + LocationFieldY matlab.ui.control.NumericEditField + + end %properties + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + + % Call superclass setup first + obj.setup@wt.abstract.BaseViewController(); + + % Configure grid + obj.Grid.ColumnWidth = {'fit','1x','1x'}; + obj.Grid.RowHeight = {'fit','fit'}; + + + % Name field + tooltip = "Name of the enclosure"; + + obj.NameLabel = uilabel(obj.Grid,... + "Text","Name:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + obj.NameLabel.Layout.Row = 1; + obj.NameLabel.Layout.Column = 1; + + obj.NameField = uieditfield(obj.Grid,... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Name")); + obj.NameField.Layout.Row = 1; + obj.NameField.Layout.Column = [2 3]; + + + % Location fields + tooltip = "Point location of the enclosure"; + + obj.LocationLabel = uilabel(obj.Grid,... + "Text","Location:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + obj.LocationLabel.Layout.Row = 2; + obj.LocationLabel.Layout.Column = 1; + + + obj.LocationFieldX = uieditfield(obj.Grid,'numeric',... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Location",1)); + obj.LocationFieldX.Layout.Row = 2; + obj.LocationFieldX.Layout.Column = 2; + + obj.LocationFieldY = uieditfield(obj.Grid,'numeric',... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Location",2)); + obj.LocationFieldY.Layout.Row = 2; + obj.LocationFieldY.Layout.Column = 3; + + end %function + + + function update(obj) + + % Call superclass method + obj.update@wt.abstract.BaseViewController(); + + % Is there a valid model? + if isscalar(obj.Model) && isvalid(obj.Model) + % YES - enable controls and get the model + enable = true; + model = obj.Model; + else + % NO - disable controls, show default model values + enable = false; + model = wtexample.model.Enclosure; + end + + % Update the fields + name = model.Name; + obj.NameField.Value = name; + obj.NameField.Enable = enable; + + locX = model.Location(1); + obj.LocationFieldX.Value = locX; + obj.LocationFieldX.Enable = enable; + + locY = model.Location(2); + obj.LocationFieldY.Value = locY; + obj.LocationFieldY.Enable = enable; + + end %function + + end %methods + +end %classdef + diff --git a/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Exhibit.m b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Exhibit.m new file mode 100644 index 0000000..527cd83 --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Exhibit.m @@ -0,0 +1,116 @@ +classdef Exhibit < wt.abstract.BaseViewController + % View/Controller for Exhibit + + %% Properties + properties (AbortSet, SetObservable) + + % Model class + Model = wtexample.model.Exhibit.empty(0,0) + + end %properties + + + %% Internal Components + properties (Transient, Hidden, SetAccess = protected) + + NameLabel matlab.ui.control.Label + NameField matlab.ui.control.EditField + + LocationLabel matlab.ui.control.Label + LocationFieldX matlab.ui.control.NumericEditField + LocationFieldY matlab.ui.control.NumericEditField + + end %properties + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + + % Call superclass setup first + obj.setup@wt.abstract.BaseViewController(); + + % Configure grid + obj.Grid.ColumnWidth = {'fit','1x','1x'}; + obj.Grid.RowHeight = {'fit','fit'}; + + + % Name field + tooltip = "Name of the exhibit"; + + obj.NameLabel = uilabel(obj.Grid,... + "Text","Name:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + obj.NameLabel.Layout.Row = 1; + obj.NameLabel.Layout.Column = 1; + + obj.NameField = uieditfield(obj.Grid,... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Name")); + obj.NameField.Layout.Row = 1; + obj.NameField.Layout.Column = [2 3]; + + + % Location fields + tooltip = "Point location of the exhibit"; + + obj.LocationLabel = uilabel(obj.Grid,... + "Text","Location:",... + "Tooltip",tooltip,... + "HorizontalAlignment","right"); + obj.LocationLabel.Layout.Row = 2; + obj.LocationLabel.Layout.Column = 1; + + + obj.LocationFieldX = uieditfield(obj.Grid,'numeric',... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Location",1)); + obj.LocationFieldX.Layout.Row = 2; + obj.LocationFieldX.Layout.Column = 2; + + obj.LocationFieldY = uieditfield(obj.Grid,'numeric',... + "Tooltip",tooltip,... + "ValueChangedFcn",@(~,evt)onFieldEdited(obj,evt,"Location",2)); + obj.LocationFieldY.Layout.Row = 2; + obj.LocationFieldY.Layout.Column = 3; + + end %function + + + function update(obj) + + % Call superclass method + obj.update@wt.abstract.BaseViewController(); + + % Is there a valid model? + if isscalar(obj.Model) && isvalid(obj.Model) + % YES - enable controls and get the model + enable = true; + model = obj.Model; + else + % NO - disable controls, show default model values + enable = false; + model = wtexample.model.Exhibit; + end + + % Update the fields + name = model.Name; + obj.NameField.Value = name; + obj.NameField.Enable = enable; + + locX = model.Location(1); + obj.LocationFieldX.Value = locX; + obj.LocationFieldX.Enable = enable; + + locY = model.Location(2); + obj.LocationFieldY.Value = locY; + obj.LocationFieldY.Enable = enable; + + end %function + + end %methods + +end %classdef + diff --git a/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Session.m b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Session.m new file mode 100644 index 0000000..91a067f --- /dev/null +++ b/widgets/examples/apps/contextual_view/+wtexample/+viewcontroller/Session.m @@ -0,0 +1,112 @@ +classdef Session < wt.abstract.BaseViewController + % View for wtexample.model.Session + + %% Properties + properties (SetObservable) + Model = wtexample.model.Session.empty(0,0) + end + + + %% Internal Properties + properties (Transient, Hidden, SetAccess = protected) + + FileNameLabel matlab.ui.control.Label + FileNameField matlab.ui.control.Label + + FilePathLabel matlab.ui.control.Label + FilePathField matlab.ui.control.Label + + DescriptionLabel matlab.ui.control.Label + DescriptionField matlab.ui.control.EditField + + end %properties + + + %% Protected Methods + methods (Access = protected) + + function setup(obj) + + % Call superclass setup first + obj.setup@wt.abstract.BaseViewController(); + + % Configure grid + obj.Grid.ColumnWidth = {'fit','1x'}; + obj.Grid.RowHeight = {'fit','fit','fit'}; + + % Add fields + + % --- Height --- % + tooltip = "File name of the session"; + + obj.FileNameLabel = uilabel(obj.Grid); + obj.FileNameLabel.Text = "File Name:"; + obj.FileNameLabel.Tooltip = tooltip; + obj.FileNameLabel.HorizontalAlignment = "right"; + + obj.FileNameField = uilabel(obj.Grid); + obj.FileNameField.Text = ""; + obj.FileNameField.Tooltip = tooltip; + obj.FileNameField.HorizontalAlignment = "left"; + + + % --- FilePath --- % + tooltip = "File path of the session"; + + obj.FilePathLabel = uilabel(obj.Grid); + obj.FilePathLabel.Text = "File Path:"; + obj.FilePathLabel.Tooltip = tooltip; + obj.FilePathLabel.HorizontalAlignment = "right"; + + obj.FilePathField = uilabel(obj.Grid); + obj.FilePathField.Text = ""; + obj.FilePathField.Tooltip = tooltip; + obj.FilePathField.HorizontalAlignment = "left"; + + + % --- Description --- % + tooltip = "Description of the session"; + + obj.DescriptionLabel = uilabel(obj.Grid); + obj.DescriptionLabel.Text = "Description:"; + obj.DescriptionLabel.Tooltip = tooltip; + obj.DescriptionLabel.HorizontalAlignment = "right"; + + obj.DescriptionField = uieditfield(obj.Grid); + obj.DescriptionField.Tooltip = tooltip; + obj.DescriptionField.ValueChangedFcn = ... + @(~,evt)onFieldEdited(obj,evt,"Description"); + + end %function + + + function update(obj) + + % Call superclass method first + obj.update@wt.abstract.BaseViewController(); + + % Get the model to display + [model, validToDisplay] = obj.getScalarModelToDisplay(); + + % Update the fields + obj.FileNameField.Enable = validToDisplay; + obj.FilePathField.Enable = validToDisplay; + obj.DescriptionField.Enable = validToDisplay; + + obj.FileNameField.Text = model.FileName; + obj.FilePathField.Text = model.FilePath; + obj.DescriptionField.Value = model.Description; + + end %function + + + function onDescriptionEdited(obj,evt) + + newValue = evt.Value; + obj.Model.Description = newValue; + + end %function + + end %methods + +end %classdef \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/ExampleZooManifest.xlsx b/widgets/examples/apps/contextual_view/ExampleZooManifest.xlsx new file mode 100644 index 0000000..8b92d4d Binary files /dev/null and b/widgets/examples/apps/contextual_view/ExampleZooManifest.xlsx differ diff --git a/widgets/examples/apps/contextual_view/UML_Backend.mldatx b/widgets/examples/apps/contextual_view/UML_Backend.mldatx new file mode 100644 index 0000000..3eda413 Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_Backend.mldatx differ diff --git a/widgets/examples/apps/contextual_view/UML_Backend.png b/widgets/examples/apps/contextual_view/UML_Backend.png new file mode 100644 index 0000000..85fed0a Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_Backend.png differ diff --git a/widgets/examples/apps/contextual_view/UML_ContextualViewPane.mldatx b/widgets/examples/apps/contextual_view/UML_ContextualViewPane.mldatx new file mode 100644 index 0000000..d3050b3 Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_ContextualViewPane.mldatx differ diff --git a/widgets/examples/apps/contextual_view/UML_ContextualViewPane.png b/widgets/examples/apps/contextual_view/UML_ContextualViewPane.png new file mode 100644 index 0000000..d44bd4b Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_ContextualViewPane.png differ diff --git a/widgets/examples/apps/contextual_view/UML_Frontend.mldatx b/widgets/examples/apps/contextual_view/UML_Frontend.mldatx new file mode 100644 index 0000000..66526e5 Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_Frontend.mldatx differ diff --git a/widgets/examples/apps/contextual_view/UML_Frontend_ViewControllers.png b/widgets/examples/apps/contextual_view/UML_Frontend_ViewControllers.png new file mode 100644 index 0000000..ff32084 Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_Frontend_ViewControllers.png differ diff --git a/widgets/examples/apps/contextual_view/UML_all.mldatx b/widgets/examples/apps/contextual_view/UML_all.mldatx new file mode 100644 index 0000000..18dcb70 Binary files /dev/null and b/widgets/examples/apps/contextual_view/UML_all.mldatx differ diff --git a/widgets/examples/apps/contextual_view/animal.png b/widgets/examples/apps/contextual_view/animal.png new file mode 100644 index 0000000..44bb930 Binary files /dev/null and b/widgets/examples/apps/contextual_view/animal.png differ diff --git a/widgets/examples/apps/contextual_view/enclosure.png b/widgets/examples/apps/contextual_view/enclosure.png new file mode 100644 index 0000000..ae4970a Binary files /dev/null and b/widgets/examples/apps/contextual_view/enclosure.png differ diff --git a/widgets/examples/apps/contextual_view/example_rj.m b/widgets/examples/apps/contextual_view/example_rj.m new file mode 100644 index 0000000..73c18c2 --- /dev/null +++ b/widgets/examples/apps/contextual_view/example_rj.m @@ -0,0 +1,33 @@ +%% Create animal +a = wtexample.model.Animal("Debug",true); +a.Name = "Giraffe X"; +a.BirthDate = datetime("today") - years(7.5); +a.Species = "giraffe"; + +%% Create enclosure, add animal to it +n = wtexample.model.Enclosure("Debug",true); +n.Name = "Giraffe Pen"; +n.Animal = a; + +%% Create exhibit, add enclosure to it +x = wtexample.model.Exhibit("Debug",true); +x.Name = "African Safari"; +x.Enclosure = n; + +%% Add another animal to the enclosure +a2 = wtexample.model.Animal("Debug",true); +a2.Name = "Giraffe Y"; +a2.Species = "giraffe"; +a2.BirthDate = datetime("today") - years(4); +a2.Sex = "male"; +n.Animal(end+1) = a2; + +%% Attach to session +s = wtexample.model.Session("Debug",true,"Exhibit",x); + + +%% Change a property +a.Sex = "female"; + +%% Investigate listener/event issue: +a.BirthDate = a.BirthDate - days(1); \ No newline at end of file diff --git a/widgets/examples/apps/contextual_view/exhibit.png b/widgets/examples/apps/contextual_view/exhibit.png new file mode 100644 index 0000000..532b8ac Binary files /dev/null and b/widgets/examples/apps/contextual_view/exhibit.png differ diff --git a/widgets/examples/apps/contextual_view/robyn_session.mat b/widgets/examples/apps/contextual_view/robyn_session.mat new file mode 100644 index 0000000..f12ec13 Binary files /dev/null and b/widgets/examples/apps/contextual_view/robyn_session.mat differ diff --git a/widgets/icons/abort_24.png b/widgets/icons/abort_24.png new file mode 100644 index 0000000..f5d19ad Binary files /dev/null and b/widgets/icons/abort_24.png differ diff --git a/widgets/icons/addBlue_24.png b/widgets/icons/addBlue_24.png new file mode 100644 index 0000000..99c1777 Binary files /dev/null and b/widgets/icons/addBlue_24.png differ diff --git a/widgets/icons/addColumn_24.png b/widgets/icons/addColumn_24.png new file mode 100644 index 0000000..6462765 Binary files /dev/null and b/widgets/icons/addColumn_24.png differ diff --git a/widgets/icons/addGreen_24.png b/widgets/icons/addGreen_24.png new file mode 100644 index 0000000..1a19846 Binary files /dev/null and b/widgets/icons/addGreen_24.png differ diff --git a/widgets/icons/addRow_24.png b/widgets/icons/addRow_24.png new file mode 100644 index 0000000..4383be1 Binary files /dev/null and b/widgets/icons/addRow_24.png differ diff --git a/widgets/icons/addYellow_24.png b/widgets/icons/addYellow_24.png new file mode 100644 index 0000000..fe72d3d Binary files /dev/null and b/widgets/icons/addYellow_24.png differ diff --git a/widgets/icons/add_plot_24.png b/widgets/icons/add_plot_24.png new file mode 100644 index 0000000..0d329fb Binary files /dev/null and b/widgets/icons/add_plot_24.png differ diff --git a/widgets/icons/adjustSliders_24.png b/widgets/icons/adjustSliders_24.png new file mode 100644 index 0000000..d803e2e Binary files /dev/null and b/widgets/icons/adjustSliders_24.png differ diff --git a/widgets/icons/adjust_24.png b/widgets/icons/adjust_24.png new file mode 100644 index 0000000..4833266 Binary files /dev/null and b/widgets/icons/adjust_24.png differ diff --git a/widgets/icons/annotation_24.png b/widgets/icons/annotation_24.png new file mode 100644 index 0000000..5f673b1 Binary files /dev/null and b/widgets/icons/annotation_24.png differ diff --git a/widgets/icons/architecture_24.png b/widgets/icons/architecture_24.png new file mode 100644 index 0000000..f86c269 Binary files /dev/null and b/widgets/icons/architecture_24.png differ diff --git a/widgets/icons/archive_24.png b/widgets/icons/archive_24.png new file mode 100644 index 0000000..4c6b1e7 Binary files /dev/null and b/widgets/icons/archive_24.png differ diff --git a/widgets/icons/auto_order_24.png b/widgets/icons/auto_order_24.png new file mode 100644 index 0000000..afc0b45 Binary files /dev/null and b/widgets/icons/auto_order_24.png differ diff --git a/widgets/icons/back_24.png b/widgets/icons/back_24.png new file mode 100644 index 0000000..4bb09f5 Binary files /dev/null and b/widgets/icons/back_24.png differ diff --git a/widgets/icons/bar_plot_24.png b/widgets/icons/bar_plot_24.png new file mode 100644 index 0000000..a4c80b3 Binary files /dev/null and b/widgets/icons/bar_plot_24.png differ diff --git a/widgets/icons/box_24.png b/widgets/icons/box_24.png new file mode 100644 index 0000000..d93b9d9 Binary files /dev/null and b/widgets/icons/box_24.png differ diff --git a/widgets/icons/browseFolder_24.png b/widgets/icons/browseFolder_24.png new file mode 100644 index 0000000..de6b487 Binary files /dev/null and b/widgets/icons/browseFolder_24.png differ diff --git a/widgets/icons/brush_24.png b/widgets/icons/brush_24.png new file mode 100644 index 0000000..7314b20 Binary files /dev/null and b/widgets/icons/brush_24.png differ diff --git a/widgets/icons/build_24.png b/widgets/icons/build_24.png new file mode 100644 index 0000000..7c98f9e Binary files /dev/null and b/widgets/icons/build_24.png differ diff --git a/widgets/icons/calendar_24.png b/widgets/icons/calendar_24.png new file mode 100644 index 0000000..920ae6a Binary files /dev/null and b/widgets/icons/calendar_24.png differ diff --git a/widgets/icons/check_24.png b/widgets/icons/check_24.png index 8cab0d5..3c9b4c3 100644 Binary files a/widgets/icons/check_24.png and b/widgets/icons/check_24.png differ diff --git a/widgets/icons/chevronDownBlack_24.png b/widgets/icons/chevronDownBlack_24.png new file mode 100644 index 0000000..670b6b5 Binary files /dev/null and b/widgets/icons/chevronDownBlack_24.png differ diff --git a/widgets/icons/chevronLeftBlack_24.png b/widgets/icons/chevronLeftBlack_24.png new file mode 100644 index 0000000..a354ced Binary files /dev/null and b/widgets/icons/chevronLeftBlack_24.png differ diff --git a/widgets/icons/chevronRightBlack_24.png b/widgets/icons/chevronRightBlack_24.png new file mode 100644 index 0000000..24ce308 Binary files /dev/null and b/widgets/icons/chevronRightBlack_24.png differ diff --git a/widgets/icons/chevronUpBlack_24.png b/widgets/icons/chevronUpBlack_24.png new file mode 100644 index 0000000..e41230a Binary files /dev/null and b/widgets/icons/chevronUpBlack_24.png differ diff --git a/widgets/icons/clock_24.png b/widgets/icons/clock_24.png index ba8df84..4faf07f 100644 Binary files a/widgets/icons/clock_24.png and b/widgets/icons/clock_24.png differ diff --git a/widgets/icons/clock_digital_24.png b/widgets/icons/clock_digital_24.png new file mode 100644 index 0000000..ce26ada Binary files /dev/null and b/widgets/icons/clock_digital_24.png differ diff --git a/widgets/icons/closeBlack_12.png b/widgets/icons/closeBlack_12.png new file mode 100644 index 0000000..7320bad Binary files /dev/null and b/widgets/icons/closeBlack_12.png differ diff --git a/widgets/icons/close_24.png b/widgets/icons/close_24.png index 1c6a51e..cee8126 100644 Binary files a/widgets/icons/close_24.png and b/widgets/icons/close_24.png differ diff --git a/widgets/icons/code_24.png b/widgets/icons/code_24.png new file mode 100644 index 0000000..f82cf05 Binary files /dev/null and b/widgets/icons/code_24.png differ diff --git a/widgets/icons/collapseView.png b/widgets/icons/collapseView.png new file mode 100644 index 0000000..c8070a0 Binary files /dev/null and b/widgets/icons/collapseView.png differ diff --git a/widgets/icons/collapsedownBlack.png b/widgets/icons/collapsedownBlack.png new file mode 100644 index 0000000..f7cf321 Binary files /dev/null and b/widgets/icons/collapsedownBlack.png differ diff --git a/widgets/icons/collapseleftBlack.png b/widgets/icons/collapseleftBlack.png new file mode 100644 index 0000000..8c67730 Binary files /dev/null and b/widgets/icons/collapseleftBlack.png differ diff --git a/widgets/icons/collapserightBlack.png b/widgets/icons/collapserightBlack.png new file mode 100644 index 0000000..46930d1 Binary files /dev/null and b/widgets/icons/collapserightBlack.png differ diff --git a/widgets/icons/collapseupBlack.png b/widgets/icons/collapseupBlack.png new file mode 100644 index 0000000..04e8d93 Binary files /dev/null and b/widgets/icons/collapseupBlack.png differ diff --git a/widgets/icons/colorbar_24.png b/widgets/icons/colorbar_24.png new file mode 100644 index 0000000..ca845b0 Binary files /dev/null and b/widgets/icons/colorbar_24.png differ diff --git a/widgets/icons/compare_24.png b/widgets/icons/compare_24.png new file mode 100644 index 0000000..c81abb9 Binary files /dev/null and b/widgets/icons/compare_24.png differ diff --git a/widgets/icons/complete_16.png b/widgets/icons/complete_16.png index c5b73cd..ff4d296 100644 Binary files a/widgets/icons/complete_16.png and b/widgets/icons/complete_16.png differ diff --git a/widgets/icons/configuration_24.png b/widgets/icons/configuration_24.png new file mode 100644 index 0000000..25242db Binary files /dev/null and b/widgets/icons/configuration_24.png differ diff --git a/widgets/icons/configure_view_24.png b/widgets/icons/configure_view_24.png new file mode 100644 index 0000000..b5889c7 Binary files /dev/null and b/widgets/icons/configure_view_24.png differ diff --git a/widgets/icons/copy_24.png b/widgets/icons/copy_24.png index fbeb1f7..1d5fb7e 100644 Binary files a/widgets/icons/copy_24.png and b/widgets/icons/copy_24.png differ diff --git a/widgets/icons/curveFit_22.png b/widgets/icons/curveFit_22.png new file mode 100644 index 0000000..c4e0a27 Binary files /dev/null and b/widgets/icons/curveFit_22.png differ diff --git a/widgets/icons/curveFittingApp_24.png b/widgets/icons/curveFittingApp_24.png new file mode 100644 index 0000000..8d771fb Binary files /dev/null and b/widgets/icons/curveFittingApp_24.png differ diff --git a/widgets/icons/cut_blue_24.png b/widgets/icons/cut_blue_24.png new file mode 100644 index 0000000..658aa00 Binary files /dev/null and b/widgets/icons/cut_blue_24.png differ diff --git a/widgets/icons/database_24.png b/widgets/icons/database_24.png new file mode 100644 index 0000000..0506e98 Binary files /dev/null and b/widgets/icons/database_24.png differ diff --git a/widgets/icons/database_find_24.png b/widgets/icons/database_find_24.png new file mode 100644 index 0000000..ae1e56f Binary files /dev/null and b/widgets/icons/database_find_24.png differ diff --git a/widgets/icons/deleteColumn_24.png b/widgets/icons/deleteColumn_24.png new file mode 100644 index 0000000..194a25e Binary files /dev/null and b/widgets/icons/deleteColumn_24.png differ diff --git a/widgets/icons/deleteRow_24.png b/widgets/icons/deleteRow_24.png new file mode 100644 index 0000000..859605f Binary files /dev/null and b/widgets/icons/deleteRow_24.png differ diff --git a/widgets/icons/digitalClock_24.png b/widgets/icons/digitalClock_24.png new file mode 100644 index 0000000..e6439af Binary files /dev/null and b/widgets/icons/digitalClock_24.png differ diff --git a/widgets/icons/document2_24.png b/widgets/icons/document2_24.png new file mode 100644 index 0000000..6ca3d0e Binary files /dev/null and b/widgets/icons/document2_24.png differ diff --git a/widgets/icons/document_24.png b/widgets/icons/document_24.png new file mode 100644 index 0000000..963a567 Binary files /dev/null and b/widgets/icons/document_24.png differ diff --git a/widgets/icons/down_24.png b/widgets/icons/down_24.png index 808619a..961b1f4 100644 Binary files a/widgets/icons/down_24.png and b/widgets/icons/down_24.png differ diff --git a/widgets/icons/download_24.png b/widgets/icons/download_24.png new file mode 100644 index 0000000..a50ddfd Binary files /dev/null and b/widgets/icons/download_24.png differ diff --git a/widgets/icons/editDocument_24.png b/widgets/icons/editDocument_24.png new file mode 100644 index 0000000..7be1670 Binary files /dev/null and b/widgets/icons/editDocument_24.png differ diff --git a/widgets/icons/edit_24.png b/widgets/icons/edit_24.png index 128f6a6..3b94788 100644 Binary files a/widgets/icons/edit_24.png and b/widgets/icons/edit_24.png differ diff --git a/widgets/icons/erase_24.png b/widgets/icons/erase_24.png index eece103..f9704a6 100644 Binary files a/widgets/icons/erase_24.png and b/widgets/icons/erase_24.png differ diff --git a/widgets/icons/error_16.png b/widgets/icons/error_16.png index 3bffbc8..47877fc 100644 Binary files a/widgets/icons/error_16.png and b/widgets/icons/error_16.png differ diff --git a/widgets/icons/error_24.png b/widgets/icons/error_24.png new file mode 100644 index 0000000..6011bd4 Binary files /dev/null and b/widgets/icons/error_24.png differ diff --git a/widgets/icons/expandView.png b/widgets/icons/expandView.png new file mode 100644 index 0000000..3b90f9d Binary files /dev/null and b/widgets/icons/expandView.png differ diff --git a/widgets/icons/exportVariable_24.png b/widgets/icons/exportVariable_24.png new file mode 100644 index 0000000..6c85c84 Binary files /dev/null and b/widgets/icons/exportVariable_24.png differ diff --git a/widgets/icons/export_24.png b/widgets/icons/export_24.png index 2385c33..456fd4d 100644 Binary files a/widgets/icons/export_24.png and b/widgets/icons/export_24.png differ diff --git a/widgets/icons/export_plot_24.png b/widgets/icons/export_plot_24.png new file mode 100644 index 0000000..1f03250 Binary files /dev/null and b/widgets/icons/export_plot_24.png differ diff --git a/widgets/icons/failed_24.png b/widgets/icons/failed_24.png new file mode 100644 index 0000000..c43ce43 Binary files /dev/null and b/widgets/icons/failed_24.png differ diff --git a/widgets/icons/figure_24.png b/widgets/icons/figure_24.png new file mode 100644 index 0000000..42c4e4d Binary files /dev/null and b/widgets/icons/figure_24.png differ diff --git a/widgets/icons/filter_clear_24.png b/widgets/icons/filter_clear_24.png new file mode 100644 index 0000000..fc8b706 Binary files /dev/null and b/widgets/icons/filter_clear_24.png differ diff --git a/widgets/icons/filter_info_24.png b/widgets/icons/filter_info_24.png new file mode 100644 index 0000000..3b72278 Binary files /dev/null and b/widgets/icons/filter_info_24.png differ diff --git a/widgets/icons/findFiles_24.png b/widgets/icons/findFiles_24.png new file mode 100644 index 0000000..e7a1a92 Binary files /dev/null and b/widgets/icons/findFiles_24.png differ diff --git a/widgets/icons/find_files_24.png b/widgets/icons/find_files_24.png new file mode 100644 index 0000000..1e163eb Binary files /dev/null and b/widgets/icons/find_files_24.png differ diff --git a/widgets/icons/fitLine_24.png b/widgets/icons/fitLine_24.png new file mode 100644 index 0000000..952da65 Binary files /dev/null and b/widgets/icons/fitLine_24.png differ diff --git a/widgets/icons/fit_curve_24.png b/widgets/icons/fit_curve_24.png new file mode 100644 index 0000000..8aaa739 Binary files /dev/null and b/widgets/icons/fit_curve_24.png differ diff --git a/widgets/icons/fit_line_24.png b/widgets/icons/fit_line_24.png new file mode 100644 index 0000000..a314771 Binary files /dev/null and b/widgets/icons/fit_line_24.png differ diff --git a/widgets/icons/fit_view_24.png b/widgets/icons/fit_view_24.png new file mode 100644 index 0000000..01fd8b6 Binary files /dev/null and b/widgets/icons/fit_view_24.png differ diff --git a/widgets/icons/floodFill_24.png b/widgets/icons/floodFill_24.png new file mode 100644 index 0000000..41cbce3 Binary files /dev/null and b/widgets/icons/floodFill_24.png differ diff --git a/widgets/icons/forward_24.png b/widgets/icons/forward_24.png new file mode 100644 index 0000000..095d787 Binary files /dev/null and b/widgets/icons/forward_24.png differ diff --git a/widgets/icons/function_24.png b/widgets/icons/function_24.png new file mode 100644 index 0000000..3a44908 Binary files /dev/null and b/widgets/icons/function_24.png differ diff --git a/widgets/icons/function_add_24.png b/widgets/icons/function_add_24.png new file mode 100644 index 0000000..8d5fe9d Binary files /dev/null and b/widgets/icons/function_add_24.png differ diff --git a/widgets/icons/globe_24.png b/widgets/icons/globe_24.png new file mode 100644 index 0000000..6f9ffd3 Binary files /dev/null and b/widgets/icons/globe_24.png differ diff --git a/widgets/icons/goToEnd_24.png b/widgets/icons/goToEnd_24.png new file mode 100644 index 0000000..c44fcff Binary files /dev/null and b/widgets/icons/goToEnd_24.png differ diff --git a/widgets/icons/goToStart_24.png b/widgets/icons/goToStart_24.png new file mode 100644 index 0000000..7fba17b Binary files /dev/null and b/widgets/icons/goToStart_24.png differ diff --git a/widgets/icons/grid_24.png b/widgets/icons/grid_24.png new file mode 100644 index 0000000..6a7f2f9 Binary files /dev/null and b/widgets/icons/grid_24.png differ diff --git a/widgets/icons/historyDelete_24.png b/widgets/icons/historyDelete_24.png new file mode 100644 index 0000000..92b3694 Binary files /dev/null and b/widgets/icons/historyDelete_24.png differ diff --git a/widgets/icons/history_24.png b/widgets/icons/history_24.png new file mode 100644 index 0000000..4faf07f Binary files /dev/null and b/widgets/icons/history_24.png differ diff --git a/widgets/icons/home_24.png b/widgets/icons/home_24.png new file mode 100644 index 0000000..33d418c Binary files /dev/null and b/widgets/icons/home_24.png differ diff --git a/widgets/icons/import_24.png b/widgets/icons/import_24.png index f8b4d1d..1bfa8fa 100644 Binary files a/widgets/icons/import_24.png and b/widgets/icons/import_24.png differ diff --git a/widgets/icons/info_16.png b/widgets/icons/info_16.png index 3893572..cc80c8f 100644 Binary files a/widgets/icons/info_16.png and b/widgets/icons/info_16.png differ diff --git a/widgets/icons/info_24.png b/widgets/icons/info_24.png index 7f1c838..ee7119a 100644 Binary files a/widgets/icons/info_24.png and b/widgets/icons/info_24.png differ diff --git a/widgets/icons/insertColumn_24.png b/widgets/icons/insertColumn_24.png new file mode 100644 index 0000000..4ec2f07 Binary files /dev/null and b/widgets/icons/insertColumn_24.png differ diff --git a/widgets/icons/insertRow_24.png b/widgets/icons/insertRow_24.png new file mode 100644 index 0000000..33177b7 Binary files /dev/null and b/widgets/icons/insertRow_24.png differ diff --git a/widgets/icons/invertMask_24.png b/widgets/icons/invertMask_24.png new file mode 100644 index 0000000..0a96c02 Binary files /dev/null and b/widgets/icons/invertMask_24.png differ diff --git a/widgets/icons/left_24.png b/widgets/icons/left_24.png index 784fe72..48f4f2b 100644 Binary files a/widgets/icons/left_24.png and b/widgets/icons/left_24.png differ diff --git a/widgets/icons/legend_24.png b/widgets/icons/legend_24.png new file mode 100644 index 0000000..f6993b1 Binary files /dev/null and b/widgets/icons/legend_24.png differ diff --git a/widgets/icons/loading_32.gif b/widgets/icons/loading_32.gif new file mode 100644 index 0000000..e4ab783 Binary files /dev/null and b/widgets/icons/loading_32.gif differ diff --git a/widgets/icons/locked_24.png b/widgets/icons/locked_24.png new file mode 100644 index 0000000..ae0a8d3 Binary files /dev/null and b/widgets/icons/locked_24.png differ diff --git a/widgets/icons/map_marker_24.png b/widgets/icons/map_marker_24.png new file mode 100644 index 0000000..45c18cd Binary files /dev/null and b/widgets/icons/map_marker_24.png differ diff --git a/widgets/icons/merge_24.png b/widgets/icons/merge_24.png new file mode 100644 index 0000000..4168886 Binary files /dev/null and b/widgets/icons/merge_24.png differ diff --git a/widgets/icons/minusBlue_24.png b/widgets/icons/minusBlue_24.png new file mode 100644 index 0000000..8dd44bc Binary files /dev/null and b/widgets/icons/minusBlue_24.png differ diff --git a/widgets/icons/new_24.png b/widgets/icons/new_24.png new file mode 100644 index 0000000..6539c13 Binary files /dev/null and b/widgets/icons/new_24.png differ diff --git a/widgets/icons/new_chart_24.png b/widgets/icons/new_chart_24.png new file mode 100644 index 0000000..9ad4833 Binary files /dev/null and b/widgets/icons/new_chart_24.png differ diff --git a/widgets/icons/new_script_24.png b/widgets/icons/new_script_24.png new file mode 100644 index 0000000..752fa5b Binary files /dev/null and b/widgets/icons/new_script_24.png differ diff --git a/widgets/icons/openDocument_24.png b/widgets/icons/openDocument_24.png new file mode 100644 index 0000000..8ddad4b Binary files /dev/null and b/widgets/icons/openDocument_24.png differ diff --git a/widgets/icons/open_24.png b/widgets/icons/open_24.png index 0c1664a..a1e929a 100644 Binary files a/widgets/icons/open_24.png and b/widgets/icons/open_24.png differ diff --git a/widgets/icons/optimize_24.png b/widgets/icons/optimize_24.png new file mode 100644 index 0000000..d375cb9 Binary files /dev/null and b/widgets/icons/optimize_24.png differ diff --git a/widgets/icons/package_24.png b/widgets/icons/package_24.png new file mode 100644 index 0000000..12705da Binary files /dev/null and b/widgets/icons/package_24.png differ diff --git a/widgets/icons/panBlue_30.png b/widgets/icons/panBlue_30.png new file mode 100644 index 0000000..4c1be33 Binary files /dev/null and b/widgets/icons/panBlue_30.png differ diff --git a/widgets/icons/people_24.png b/widgets/icons/people_24.png new file mode 100644 index 0000000..c485942 Binary files /dev/null and b/widgets/icons/people_24.png differ diff --git a/widgets/icons/play_24.png b/widgets/icons/play_24.png index be5a346..0161264 100644 Binary files a/widgets/icons/play_24.png and b/widgets/icons/play_24.png differ diff --git a/widgets/icons/play_32.png b/widgets/icons/play_32.png new file mode 100644 index 0000000..9947229 Binary files /dev/null and b/widgets/icons/play_32.png differ diff --git a/widgets/icons/playerSquare_24.png b/widgets/icons/playerSquare_24.png new file mode 100644 index 0000000..2ce42d6 Binary files /dev/null and b/widgets/icons/playerSquare_24.png differ diff --git a/widgets/icons/plotInfo_24.png b/widgets/icons/plotInfo_24.png new file mode 100644 index 0000000..00fbd1b Binary files /dev/null and b/widgets/icons/plotInfo_24.png differ diff --git a/widgets/icons/plot_clear_24.png b/widgets/icons/plot_clear_24.png new file mode 100644 index 0000000..28acf69 Binary files /dev/null and b/widgets/icons/plot_clear_24.png differ diff --git a/widgets/icons/plot_curve_24.png b/widgets/icons/plot_curve_24.png new file mode 100644 index 0000000..9fbba7c Binary files /dev/null and b/widgets/icons/plot_curve_24.png differ diff --git a/widgets/icons/plot_scatter_24.png b/widgets/icons/plot_scatter_24.png new file mode 100644 index 0000000..47841ed Binary files /dev/null and b/widgets/icons/plot_scatter_24.png differ diff --git a/widgets/icons/publishHTML_24.png b/widgets/icons/publishHTML_24.png new file mode 100644 index 0000000..0bfa045 Binary files /dev/null and b/widgets/icons/publishHTML_24.png differ diff --git a/widgets/icons/publishPDF_24.png b/widgets/icons/publishPDF_24.png new file mode 100644 index 0000000..2fdac3b Binary files /dev/null and b/widgets/icons/publishPDF_24.png differ diff --git a/widgets/icons/refreshDouble_24.png b/widgets/icons/refreshDouble_24.png new file mode 100644 index 0000000..1978a5c Binary files /dev/null and b/widgets/icons/refreshDouble_24.png differ diff --git a/widgets/icons/refresh_24.png b/widgets/icons/refresh_24.png index 56bd2d3..39b950c 100644 Binary files a/widgets/icons/refresh_24.png and b/widgets/icons/refresh_24.png differ diff --git a/widgets/icons/repeat_24.png b/widgets/icons/repeat_24.png new file mode 100644 index 0000000..f1066bc Binary files /dev/null and b/widgets/icons/repeat_24.png differ diff --git a/widgets/icons/restore_24.png b/widgets/icons/restore_24.png new file mode 100644 index 0000000..0912f8c Binary files /dev/null and b/widgets/icons/restore_24.png differ diff --git a/widgets/icons/results_24.png b/widgets/icons/results_24.png new file mode 100644 index 0000000..0003fd2 Binary files /dev/null and b/widgets/icons/results_24.png differ diff --git a/widgets/icons/right_24.png b/widgets/icons/right_24.png index 07f60f4..8d01424 100644 Binary files a/widgets/icons/right_24.png and b/widgets/icons/right_24.png differ diff --git a/widgets/icons/roi_24.png b/widgets/icons/roi_24.png new file mode 100644 index 0000000..96eaaf9 Binary files /dev/null and b/widgets/icons/roi_24.png differ diff --git a/widgets/icons/ruler_24.png b/widgets/icons/ruler_24.png new file mode 100644 index 0000000..ec6134f Binary files /dev/null and b/widgets/icons/ruler_24.png differ diff --git a/widgets/icons/run3_24.png b/widgets/icons/run3_24.png new file mode 100644 index 0000000..4131783 Binary files /dev/null and b/widgets/icons/run3_24.png differ diff --git a/widgets/icons/runCode_24.png b/widgets/icons/runCode_24.png new file mode 100644 index 0000000..ae2182f Binary files /dev/null and b/widgets/icons/runCode_24.png differ diff --git a/widgets/icons/run_24.png b/widgets/icons/run_24.png new file mode 100644 index 0000000..8248c06 Binary files /dev/null and b/widgets/icons/run_24.png differ diff --git a/widgets/icons/run_sequence_24.png b/widgets/icons/run_sequence_24.png new file mode 100644 index 0000000..8156082 Binary files /dev/null and b/widgets/icons/run_sequence_24.png differ diff --git a/widgets/icons/saveAllData_24.png b/widgets/icons/saveAllData_24.png new file mode 100644 index 0000000..f7469ed Binary files /dev/null and b/widgets/icons/saveAllData_24.png differ diff --git a/widgets/icons/saveAs_24.png b/widgets/icons/saveAs_24.png new file mode 100644 index 0000000..aa2be59 Binary files /dev/null and b/widgets/icons/saveAs_24.png differ diff --git a/widgets/icons/saveClean_24.png b/widgets/icons/saveClean_24.png new file mode 100644 index 0000000..01e741c Binary files /dev/null and b/widgets/icons/saveClean_24.png differ diff --git a/widgets/icons/saveCopyAs_24.png b/widgets/icons/saveCopyAs_24.png new file mode 100644 index 0000000..8ea4ede Binary files /dev/null and b/widgets/icons/saveCopyAs_24.png differ diff --git a/widgets/icons/saveDirty_24.png b/widgets/icons/saveDirty_24.png new file mode 100644 index 0000000..6c7a0c8 Binary files /dev/null and b/widgets/icons/saveDirty_24.png differ diff --git a/widgets/icons/sessionSaveAs_24.png b/widgets/icons/sessionSaveAs_24.png new file mode 100644 index 0000000..3c8e9df Binary files /dev/null and b/widgets/icons/sessionSaveAs_24.png differ diff --git a/widgets/icons/settings_24.png b/widgets/icons/settings_24.png index df3b79d..32d0c5f 100644 Binary files a/widgets/icons/settings_24.png and b/widgets/icons/settings_24.png differ diff --git a/widgets/icons/simulink_24.png b/widgets/icons/simulink_24.png new file mode 100644 index 0000000..26d7924 Binary files /dev/null and b/widgets/icons/simulink_24.png differ diff --git a/widgets/icons/sortAZ_24.png b/widgets/icons/sortAZ_24.png new file mode 100644 index 0000000..ce689da Binary files /dev/null and b/widgets/icons/sortAZ_24.png differ diff --git a/widgets/icons/stats_24.png b/widgets/icons/stats_24.png new file mode 100644 index 0000000..252c78e Binary files /dev/null and b/widgets/icons/stats_24.png differ diff --git a/widgets/icons/stepBack_24.png b/widgets/icons/stepBack_24.png new file mode 100644 index 0000000..3a51519 Binary files /dev/null and b/widgets/icons/stepBack_24.png differ diff --git a/widgets/icons/stepForward_24.png b/widgets/icons/stepForward_24.png new file mode 100644 index 0000000..7eae57f Binary files /dev/null and b/widgets/icons/stepForward_24.png differ diff --git a/widgets/icons/stop_24.png b/widgets/icons/stop_24.png index 0eb96cf..53b7a5e 100644 Binary files a/widgets/icons/stop_24.png and b/widgets/icons/stop_24.png differ diff --git a/widgets/icons/swapLR_24.png b/widgets/icons/swapLR_24.png new file mode 100644 index 0000000..c7328ec Binary files /dev/null and b/widgets/icons/swapLR_24.png differ diff --git a/widgets/icons/tableSettings_24.png b/widgets/icons/tableSettings_24.png new file mode 100644 index 0000000..bd55805 Binary files /dev/null and b/widgets/icons/tableSettings_24.png differ diff --git a/widgets/icons/table_24.png b/widgets/icons/table_24.png new file mode 100644 index 0000000..eebbe47 Binary files /dev/null and b/widgets/icons/table_24.png differ diff --git a/widgets/icons/target_24.png b/widgets/icons/target_24.png new file mode 100644 index 0000000..d004d6d Binary files /dev/null and b/widgets/icons/target_24.png differ diff --git a/widgets/icons/title_24.png b/widgets/icons/title_24.png new file mode 100644 index 0000000..a0f1a90 Binary files /dev/null and b/widgets/icons/title_24.png differ diff --git a/widgets/icons/tools_24.png b/widgets/icons/tools_24.png new file mode 100644 index 0000000..ba07e89 Binary files /dev/null and b/widgets/icons/tools_24.png differ diff --git a/widgets/icons/undo_24.png b/widgets/icons/undo_24.png new file mode 100644 index 0000000..9b26b04 Binary files /dev/null and b/widgets/icons/undo_24.png differ diff --git a/widgets/icons/unlocked_24.png b/widgets/icons/unlocked_24.png new file mode 100644 index 0000000..9191973 Binary files /dev/null and b/widgets/icons/unlocked_24.png differ diff --git a/widgets/icons/up_24.png b/widgets/icons/up_24.png index 8f9d73c..7945557 100644 Binary files a/widgets/icons/up_24.png and b/widgets/icons/up_24.png differ diff --git a/widgets/icons/upload_24.png b/widgets/icons/upload_24.png new file mode 100644 index 0000000..46ae628 Binary files /dev/null and b/widgets/icons/upload_24.png differ diff --git a/widgets/icons/verify_24.png b/widgets/icons/verify_24.png new file mode 100644 index 0000000..b460990 Binary files /dev/null and b/widgets/icons/verify_24.png differ diff --git a/widgets/icons/warning_16.png b/widgets/icons/warning_16.png index 4b0e0da..471df91 100644 Binary files a/widgets/icons/warning_16.png and b/widgets/icons/warning_16.png differ diff --git a/widgets/icons/warning_24.png b/widgets/icons/warning_24.png new file mode 100644 index 0000000..b79c354 Binary files /dev/null and b/widgets/icons/warning_24.png differ diff --git a/widgets/icons/window_24.png b/widgets/icons/window_24.png new file mode 100644 index 0000000..240ab65 Binary files /dev/null and b/widgets/icons/window_24.png differ diff --git a/widgets/icons/zoomFit_24.png b/widgets/icons/zoomFit_24.png new file mode 100644 index 0000000..f8b05a2 Binary files /dev/null and b/widgets/icons/zoomFit_24.png differ diff --git a/widgets/icons/zoomIn_24.png b/widgets/icons/zoomIn_24.png new file mode 100644 index 0000000..49b39f2 Binary files /dev/null and b/widgets/icons/zoomIn_24.png differ diff --git a/widgets/icons/zoomOut_24.png b/widgets/icons/zoomOut_24.png new file mode 100644 index 0000000..a56203e Binary files /dev/null and b/widgets/icons/zoomOut_24.png differ