From 4be3551c4ca20acafdcead7e9c594e84412d4518 Mon Sep 17 00:00:00 2001 From: zhangxuxutm <951937200@qq.com> Date: Tue, 5 Sep 2023 09:14:33 +0800 Subject: [PATCH] 0905 --- UI/DelAreaWidget.py | 55 ++-- UI/MainWindow.py | 256 ++++++++++-------- bin.py | 4 +- model/ClientModel/Client.py | 4 +- .../__pycache__/Client.cpython-310.pyc | Bin 1061 -> 1058 bytes model/ProjectModel/AreaManage.py | 16 +- model/ProjectModel/DeviceManage.py | 90 +++++- .../__pycache__/DeviceManage.cpython-310.pyc | Bin 2993 -> 4884 bytes utils/DBModels/DeviceModels.py | 11 +- 9 files changed, 289 insertions(+), 147 deletions(-) diff --git a/UI/DelAreaWidget.py b/UI/DelAreaWidget.py index 985be5b..163d771 100644 --- a/UI/DelAreaWidget.py +++ b/UI/DelAreaWidget.py @@ -5,36 +5,50 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QPixmap, QIcon import sys - +from model.ProjectModel.DeviceManage import Device class DelAreaWidget(QDialog): - def __init__(self, areaLabel, deviceName): + def __init__(self, deviceName): super().__init__() self.checkbox_data ={} - self.areaLabel = areaLabel self.deviceName = deviceName self.delAreaRowAndColunm = [] self.initUI() def initUI(self): - vorlayout = QVBoxLayout() #主布局 - layout = QGridLayout() - - for i in self.areaLabel: - if self.deviceName in i: - widget = i[2] - row = i[3] - text = widget.text() - column = i[4] + # layout = QGridLayout() + jsonCons = Device().getAreaJson(self.deviceName) + row = 1 + if jsonCons is None: + return + else: + for jsoncon in jsonCons: + varType = jsoncon["type"] + channelNums = jsoncon["nums"] + channelBytes = jsoncon["bytes"] + text = varType + ": " + channelBytes + 'Byte' + '数量:'+ channelNums checkbox = QCheckBox(text) + vorlayout.addWidget(checkbox) checkbox.stateChanged.connect(self.checkbox_state_changed) - if column > 0: - layout.addWidget(checkbox, row, 1) - self.checkbox_data[checkbox] = [row, 1] - else: - layout.addWidget(checkbox, row, column) - self.checkbox_data[checkbox] = [row, column] + self.checkbox_data[checkbox] = row + row += 1 + + + # for i in self.areaLabel: + # if self.deviceName in i: + # widget = i[2] + # row = i[3] + # text = widget.text() + # column = i[4] + # checkbox = QCheckBox(text) + # + # if column > 0: + # vorlayout.addWidget(checkbox) + # + # else: + # vorlayout.addWidget(checkbox) + # self.checkbox_data[checkbox] = [row, column] button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) ok_button = button_box.button(QDialogButtonBox.Ok) @@ -44,14 +58,13 @@ class DelAreaWidget(QDialog): button_box.accepted.connect(self.getDelAreaRowAndColunm) button_box.rejected.connect(self.reject) - vorlayout.addLayout(layout) vorlayout.addWidget(button_box) self.setWindowIcon(QIcon('Static/zhjt.ico')) self.setWindowTitle("删除通道") self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)#去掉标题栏的问号 self.setLayout(vorlayout) - self.exec_() + def checkbox_state_changed(self, state): sender = self.sender() # 获取触发信号的对象 @@ -63,7 +76,7 @@ class DelAreaWidget(QDialog): self.delAreaRowAndColunm.remove(self.checkbox_data[sender]) def getDelAreaRowAndColunm(self): - self.close() + self.accept() return self.delAreaRowAndColunm diff --git a/UI/MainWindow.py b/UI/MainWindow.py index 1e825b7..4321308 100644 --- a/UI/MainWindow.py +++ b/UI/MainWindow.py @@ -10,11 +10,11 @@ from PyQt5.QtGui import QPixmap, QIcon from UI.DeviceWidget import DeviceDialog from UI.AreaSettingWidget import AreaSettingWidget from UI.DelAreaWidget import DelAreaWidget -# from model.ProjectModel.AreaManage import Devices, DevicesManange, Area +from model.ProjectModel.DeviceManage import DevicesManange, Device from protocol.ModBus.ModBusThread import MyThread from utils.DBModels.BaseModel import * -# from utils.DBModels.ClientModels import DeviceDB -# from model.ClientModel.Client import Client +from utils.DBModels.DeviceModels import DeviceDB +from model.ClientModel.Client import Client class CommonHelper: def __init__(self): pass @@ -33,10 +33,12 @@ class MainWindow(QMainWindow): self.sub_windows = [] #存储设备widget self.nowValue = [] #储存当前值 self.areaLabel = [] #存储通道信息文本 - # self.initAreaWidget() - - self.number = 0 + self.arealist = {} + self.widgetList= [] self.initUI() + self.initAreaWidget() + + def initUI(self): self.toolbar = QToolBar() @@ -68,46 +70,6 @@ class MainWindow(QMainWindow): self.setWindowTitle("PROFIBUS") self.setGeometry(1000, 500, 800, 600) - # def initAreaWidget(self): - # alldevices = Devices().getAllDevice() - # - # for devices in alldevices: - # layout = self.deviceWidget(devices[0]).widget().widget().layout().itemAt(1).widget().layout() - # areas = devices[3] - # number = 0 - # masterSlaveModel = devices[2] - # if areas is not None: - # areas = json.loads(areas) - # for area in areas: - # varType = area["type"] - # channelNums = area["nums"] - # channelBytes = area["bytes"] - # for i in range(int(channelNums)): - # if masterSlaveModel == '主站': - # if (i + number) % 2 == 0: - # layout.addWidget(QLabel(varType + str(i + 1) + ": " + channelBytes + 'Byte'), (i + number) // 2, - # (i + number) % 2) - # layout.addWidget(QLabel('0'), (i + number) // 2, (i + number) % 2 + 1) - # layout.addWidget(QLineEdit('0'), (i + number) // 2, (i + number) % 2 + 2) - # - # else: - # layout.addWidget(QLabel(varType + str(i + 1) + ": " + channelBytes + 'Byte'), (i + number) // 2, - # (i + number) % 2 + 3) - # layout.addWidget(QLabel('0'), (i + number) // 2, (i + number) % 2 + 4) - # layout.addWidget(QLineEdit('0'), (i + number) // 2, (i + number) % 2 + 5) - # else: - # if (i + number) % 2 == 0: - # layout.addWidget(QLabel(varType + str(i + 1) + ": " + channelBytes + 'Byte'), (i + number) // 2, - # (i + number) % 2) - # layout.addWidget(QLabel('0'), (i + number) // 2, (i + number) % 2 + 1) - # layout.addWidget(QLineEdit('0'), (i + number) // 2, (i + number) % 2 + 2) - # else: - # layout.addWidget(QLabel(varType + str(i + 1) + ": " + channelBytes + 'Byte'), (i + number) // 2, - # (i + number) % 2 + 3) - # layout.addWidget(QLabel('0'), (i + number) // 2, (i + number) % 2 + 4) - # layout.addWidget(QLineEdit('0'), (i + number) // 2, (i + number) % 2 + 5) - # - # number = number + int(channelNums) def deviceWidget(self, windowTitle): @@ -164,13 +126,37 @@ class MainWindow(QMainWindow): return sub_window + def initAreaWidget(self): + alldevices = DevicesManange().getAllDevice() + + for devices in alldevices: + layout = self.deviceWidget(devices[0]).widget().widget().layout().itemAt(1).widget().layout() + areas = devices[3] + number = 0 + masterSlaveModel = devices[2] + deviceName = devices[0] + if areas is not None: + areas = json.loads(areas) + for area in areas: + varType = area["type"] + channelNums = area["nums"] + channelBytes = area["bytes"] + areaID = area['id'] + + if masterSlaveModel == '主站': + self.addChannelWidget(deviceName, number, channelNums, channelBytes, varType, layout, areaID) + else: + self.addChannelWidget(deviceName, number, channelNums, channelBytes, varType, layout, areaID) + number = number + int(channelNums) + + def createDeciveWidget(self): dialog = DeviceDialog() if dialog.exec_() == QDialog.Accepted: deviceName, proType, masterSlaveModel, pvUpperLimit, pvLowerLimit, pvUnit = dialog.getParameters() windowTitle = deviceName + ' ' + proType + masterSlaveModel + ' ' + pvLowerLimit + '-' + pvUpperLimit + pvUnit - # DeviceDB().createDevice(deviceName = windowTitle, proType = proType, masterSlaveModel = masterSlaveModel, pvUpperLimit=pvUpperLimit, pvLowerLimit=pvLowerLimit, pvUnit=pvUnit) + DeviceDB().addDevice(deviceName = windowTitle, proType = proType, masterSlaveModel = masterSlaveModel, pvUpperLimit=pvUpperLimit, pvLowerLimit=pvLowerLimit, pvUnit=pvUnit) else: return @@ -184,34 +170,54 @@ class MainWindow(QMainWindow): dialog = AreaSettingWidget() if dialog.exec_() == QDialog.Accepted: varType, channelNums, channelBytes = dialog.getParameters() - # devices = Devices() - # number = devices.getValueLength(deviceName) - # devices.addAreas(varType, channelNums, channelBytes, deviceName) - # self.devicesmanage.addDevice(deviceName, channelNums, channelBytes) + number = DevicesManange.getChannelLength(deviceName) + Device().addAreas(varType, channelNums, channelBytes, deviceName) + areaId = Device().getAreaID(deviceName)[-1] + # Device().addDevice(deviceName, channelNums, channelBytes) else: return layout = sub_window.widget().widget().layout().itemAt(1).widget().layout() #获取sub_window的widgetArea的areaLayout2 - number = self.number #待从数据库获取具体的数据 - for i in range(int(channelNums)): + self.addChannelWidget(deviceName, number, channelNums, channelBytes, varType, layout, areaId) + number += int(channelNums) + + + + + + def addChannelWidget(self,deviceNames, numbers, channelNums, channelBytes , varTypes, layouts ,ID): + deviceName = deviceNames + number = numbers + channelNum = channelNums + channelByte = channelBytes + varType = varTypes + layout = layouts + ID = ID + widgetList = [] + arealists = [] + + for i in range(int(channelNum)): if (i + number) % 2 == 0: - areaLabel = QLabel(varType + str(i + 1 ) + ": " + channelBytes + 'Byte' ) + areaLabel = QLabel(varType + str(i + 1 ) + ": " + channelByte + 'Byte' ) areaLabel2 =QLabel('0') areaLineEdit = QLineEdit('0') editbtn = QPushButton('强制') - layout.addWidget(areaLabel , (i + number)//2, (i + number) % 2) + layout.addWidget(areaLabel, (i + number)//2, (i + number) % 2) layout.addWidget(areaLabel2, (i + number)//2, (i + number) % 2 + 1 ) layout.addWidget(areaLineEdit, (i + number)//2, (i + number) % 2 + 2 ) layout.addWidget(editbtn, (i + number) // 2, (i + number) % 2 + 3) editbtn.clicked.connect(lambda checked, btn=editbtn: self.forceEdit(btn)) + widgetList.append([layout, ID, editbtn, areaLabel, areaLabel2, areaLineEdit]) + + + + # self.nowValue.append([deviceName, layout, ID, editbtn, areaLabel, areaLabel2, areaLineEdit, (i + number)//2, (i + number) % 2 + 1]) - self.nowValue.append([deviceName, layout, i+1, editbtn, areaLabel2, areaLineEdit, (i + number)//2, (i + number) % 2 + 1]) - self.areaLabel.append([deviceName, i+1, areaLabel, (i + number)//2, (i + number) % 2]) else: - areaLabel = QLabel(varType + str(i + 1) + ": " + channelBytes + 'Byte') + areaLabel = QLabel(varType + str(i + 1) + ": " + channelByte + 'Byte') areaLabel2 = QLabel('0') areaLineEdit = QLineEdit('0') editbtn = QPushButton('强制') @@ -222,70 +228,105 @@ class MainWindow(QMainWindow): layout.addWidget(editbtn, (i + number) // 2, (i + number) % 2 + 6) editbtn.clicked.connect(lambda checked, btn=editbtn: self.forceEdit(btn)) - self.nowValue.append([deviceName, layout, i + 1, editbtn, areaLabel2, areaLineEdit, (i + number) // 2, (i + number) % 2 + 4]) - self.areaLabel.append([deviceName, i + 1, areaLabel, (i + number) // 2, (i + number) % 2 + 3]) - self.number += int(channelNums) + widgetList.append([layout, ID, editbtn, areaLabel, areaLabel2, areaLineEdit]) + arealists.append(widgetList) + self.arealist[deviceName] = arealists - def forceEdit(self, btn): - for item in self.nowValue: - if btn in item: - item[4].setText(item[5].text()) + # self.nowValue.append([deviceName, layout, ID, editbtn, areaLabel, areaLabel2, areaLineEdit, (i + number) // 2, (i + number) % 2 + 4]) + self.nowValue.append(self.arealist) + print(self.nowValue,'aaaaaa') + + + def forceEdit(self, btn): + pass + # for item in self.nowValue: + # if btn in item: + # item[4].setText(item[5].text()) def delAreaWidget(self, sub_window): subwindow = sub_window - if self.areaLabel: + if self.nowValue: self.deviceName = subwindow.windowTitle() - delAreaWidget = DelAreaWidget(self.areaLabel, self.deviceName) - rowAndColumn = delAreaWidget.getDelAreaRowAndColunm() - self.getAreaWidget(rowAndColumn, subwindow) + delAreaWidget = DelAreaWidget(self.deviceName) + if delAreaWidget.exec_() == QDialog.Accepted: + rowAndColumn = delAreaWidget.getDelAreaRowAndColunm() + if rowAndColumn == []: + return + else: + self.getAreaWidget(rowAndColumn, subwindow) + Device().delAreas(self.deviceName,rowAndColumn) + else: + return else: return - - def getAreaWidget(self, rowAndColumn, sub_window): - rowAndColumns = rowAndColumn subwindow = sub_window areaLayout = subwindow.widget().widget().layout().itemAt(1).widget().layout() - - for rowAndColumn in rowAndColumns: - print(rowAndColumn) - row = rowAndColumn[0] - column = rowAndColumn[1] - if column == 0: - for i in range(4): - widget = areaLayout.itemAtPosition(row, i).widget() - areaLayout.removeWidget(widget) - widget.deleteLater() - #删除self.areaLabel列表中的对象 - for label in self.areaLabel: - if widget in label: - self.areaLabel.remove(label) - else: - for i in range(4,8): - widget = areaLayout.itemAtPosition(row, i).widget() - areaLayout.removeWidget(widget) - widget.deleteLater() - # 删除self.areaLabel列表中的对象 - for label in self.areaLabel: - if widget in label: - self.areaLabel.remove(label) - - - - - + deviceName = subwindow.windowTitle() + for areaId in rowAndColumn: + for devicelist in self.nowValue: + areas = devicelist[deviceName] + print(areas,'sssss') + area = areas[areaId - 1] + index = areas.index(area) + print(index,'index') + print(area,'ssss') + + # for area in areas: + # for widget in range(2, 6): + # print(widget) + # print(area[widget]) + # area[widget].deleteLater() + # areaLayout.removeWidget(area[widget]) + # self.nowValue.remove(areaS) + # # print(self.nowValue) + + + + # print(rowAndColumn,'sssss') + # for areaId in rowAndColumn: + # for nowWidget in self.nowValue: + # if nowWidget[0] == deviceName and nowWidget[2] == areaId: + # for widget in range(3, 7): + # + # areaLayout.removeWidget(nowWidget[widget]) + # nowWidget[widget].deleteLater() + # delAreaWidgetList.append(nowWidget) + + + + # for widget in delAreaWidgetList: #从列表中删除已删除的部件 + # self.nowValue.remove(widget) + + + #重置area的id + # i = 1 + # j = 1 + # for nowWidget in self.nowValue: + # if nowWidget[0] == deviceName: + # if nowWidget[2] == j: + # index = nowWidget.index(nowWidget[2]) + # nowWidget[index] = i + # else: + # j = nowWidget[2] + # i += 1 + # index = nowWidget.index(nowWidget[2]) + # nowWidget[index] = i def startProtocol(self): - if self.areaLabel: - print(1) - else: - print(2) - return + a = [] + for i in range(len(self.nowValue)): + a.append(i) + + for i in a : + for j in self.nowValue: + j[5].setText(str(i)) + print(a) def closeEvent(self, event): @@ -302,8 +343,7 @@ class AreaQMdiSubWindow(QMdiSubWindow): super().__init__() self.number = 0 def closeEvent(self, event): - pass - # self.devicedb.deleteDevice(deviceName = self.windowTitle()) + DeviceDB.deleteDevice(deviceName = self.windowTitle()) @@ -312,7 +352,7 @@ class AreaQMdiSubWindow(QMdiSubWindow): if __name__ == '__main__': app = QApplication(sys.argv) - # Client.initDB() + Client.initDB() window = MainWindow() window.show() diff --git a/bin.py b/bin.py index 34de450..d0259db 100644 --- a/bin.py +++ b/bin.py @@ -1,6 +1,6 @@ from PyQt5.QtWidgets import QApplication, QStyleFactory from UI.MainWindow import MainWindow, CommonHelper -# from model.ClientModel.Client import Client +from model.ClientModel.Client import Client import time import sys @@ -10,7 +10,7 @@ if __name__ == '__main__': app = QApplication(sys.argv) # app.setStyle(QStyleFactory.create('Fusion')) app.setStyleSheet(CommonHelper.readQss('static/main.qss')) - # Client.initDB() + Client.initDB() window = MainWindow() window.show() sys.exit(app.exec_()) \ No newline at end of file diff --git a/model/ClientModel/Client.py b/model/ClientModel/Client.py index 89c4ebc..44c662a 100644 --- a/model/ClientModel/Client.py +++ b/model/ClientModel/Client.py @@ -2,10 +2,10 @@ import os import sys from peewee import * from utils.DBModels.BaseModel import * -from utils.DBModels.ClientModels import * +from utils.DBModels.DeviceModels import * class Client(object): def __init__(self): - super(Device, self).__init__() + super(Client, self).__init__() @classmethod def initDB(self): diff --git a/model/ClientModel/__pycache__/Client.cpython-310.pyc b/model/ClientModel/__pycache__/Client.cpython-310.pyc index a238958771f703b91e2e8b62232056302ca44db0..2a17bb7524fc8737d814a219f31573d5f7297c19 100644 GIT binary patch delta 205 zcmZ3=v512^pO=@50SIQ7f1SwvgSChm$ezs2Sjxz{xslO@QJD?Mk77$n3P>!;h~mu6 zPf5)wb}T9?;slCA2(HO5nBvS>f&5$C$vKI|#kr{^8Tlzi;vf;;_;|2ba%xUad_0ma zc94Fq$u-Q1jJ%WQF>6^zNtc#n<`nC>IQfDt(Q`>H%S=v%aBi{XCuOB3mw=szWD3|7 JT$7nulmK??H3t9y delta 207 zcmZ3)v6O>5pO=@50SF!le4fbtgX0#POKMqWa_VFb#!^PM&2@|}jLPgl=_t08q=3Yd zj400B{FKz3V#lJQB9J}^!9DpYQ=AzakbjFiIVZ8WI5)K}p&gZ4_0gK~=>IDpb2XAXQc0EBe4cz#~ud3IXzr@>U7H?~cdb^(M3uGnzB^ z-nl=|`OZ1tbSEZ!3)lO9eWac{Zdre0W$$I9vWO>KfKZkaZL6BTMOC0K+j7mW+QNFx zQnqsLTFTj$RR=X!JmF6v0*fnD zWz(wKN>m*@n5mk>lUGvNcde?Y9OdF&P&t*y+gF|{;9XR{D&k#IB{hNfgql=Scu$(0 zOeeW?2bG4vI@!fCp9^^Y?La7N+4@*iK88q~FlgVeYigT&8J zh~<*?^HY607JZ;?M?`Yf9w5^p;v!%UsFcU7Icpo}0^)$Ktc7^nkg?meZb|*J0wOU! zALo>9FeeXUPRV{gcCn`4_u_nv_^@CBqw*!IpWj%(4vGf5Upi0Ot!Vn6o}`$ipvlW6 zeU#;66vU-ILSYc;uIpAON^&|_>)sCZ34S<9L2T)-Q6Rut<$?iVQXKh3nAj~9rl>QW zzs}BPQqijVbOj>wq8f*ThhSn1^lc0XxtJ#%IV+~ctn>iIdEwyg2_N?!C}yJ?JVAC5 zZUmn(-Rmg8WYPo(nFbOV(Kf+kiq6gO5!*1K)3gvc9H_jI1q>zUEMvN3v5PQZ4^(Ls zm>W~u9(~SX(Q-a@PlIgZl*NHlhRcyoysVNc%jjtslT#OEprB4JE-hldklyWxNhrY) zzI5=Wk8Vwm{3Y$YPZ!h!VQqBrJPKb`7qNr$%JjTt_lZZvCliE*r_{#7%2;XK#KpmJ z-T(kD;d@9_?mf`f%>JXWV|j{Mq=R5tt0jJ|hOEQ;DimHTnL4gtA?W-vmY&w}tbr>=WcbdV0xJgGbV33;jlbpqubpL%33njo3d^&b4;L7*(u;XF;2g5xShI_cbZx2s@=^oyB!X66g z9%9d|U)X5I1*~64*N=R&7t~c@+a7Qmzmm9t)?NLG8vXlcpa1id-)bs*L@FMd1i=K7 z_WAtR=+k4uc<}DM2k(CJuRs6h!G|ARJ@?>)_m-|c_|qRVs*{Jy*Xr$dGMze{aW}&i z(^SI5FbbQ<9i2#jk8R(lI1N$u(;SmmhI@sHxTAlB_UdFh<9YC{OWjU05t~UK6zn=k ztl>e4Ln>CC2}_Rlt)Yf8E1`!5cB zH{(q|tZ_pk0OczBWt=I+k6|1yvHC-ZvaJ_b9vZmpq`4zajt%^Ibb@w;G`cjX&~D+F z(UJoAXR7OWFkKpa2S)P6X_(_Q40Q|-OlEH#8#Bvr@PRZrqzp_>Dx(aD$ish+i5N#5 z{%s7tfH=T(h#Nj53Rs|{Y(@-tzucJPh_X{j^}&Q^oT~gkxC3>RWmTh@TncNw$kE@T zpr59KC{Cu~WfxNIrDXbjw1!l^BWD0)GAO>cPL1heeB6O#!6-nSeicIR2PzHrLHHqu z7&1RMw&JMIzO{Iuq56M?3e=B4-j^--03L==3o4!i%?7@=MQq3Jf`u~LV-uibf!{ok z@~lP4Z3)UPQxbz6k zP6}iLX+|m&vtU@#p^RV**@sDsS?y37x(3xttuU%i@9n^r#J&}5jvIOg1~Z||{4y<* z>wJXOj0@x;~6O*+GP>U!$F1Laz!}+1uDWG5OKy~;V zvR6T*SMkrYnrkALLj98l|DcgSz&v2YCXbv&S(73U{#8NE$jVGyH~$J*VE8fmB%-Yu zoyT=i!YR(R+v(9hMF#_T&-^Tq8=oZLPaHh?a7+bB>UmE50>v2$!vmQU^b!PEPrDw5 zYe96gtMsdEevRTH1!KgXEg6qADdju(a1D>4>mHMe>wQDc_`>r&yELWw9Vq!O$MXj) vInj$+?eNUfd6O4WFo`a$r24Yim*XC{VB#&LocI-@G~^MuYDrAmGgtl#YXk%_ delta 1116 zcma)5%TE(Q7~kpcw$ttQ0X9^y_y8rYBp$RFNqhieOc1L{6ArzYm6>48wk0zQDhD~h z#bX^W98C02Fr0{2{{<5>7tfqEa`pRWQNVCuH}l)?{h06D_hX+cg>F9YS@5)~KiNpJ zSE$x51IH{zBCBaVuvm)On-;S-QcVJ!!(8B8;8KhZ zcBX+9Y0!xzK2j7w(~vP#${cVq1yCYu#aX`ETI5$zr#kl8o0!vtPTY?RR9NEiLKv;^ zdEQxypBK@?Q(x`c{0W@Bm!cJOQ^zUe2(Z?-U&Vng@YVOs#j?O!wJ+mP#M6ukE~Qre zG^l6Mw}4>M;{_e+*L03e3v3gQECW!>A%9;=s7)Q;F%~$Rn%beG11!VnrqxWdEc4)- zVL6zVuhQAa#8C^`xxr&DL|`$M?VaovDQl;*(w5qN_B!Tr7c=h?wU`@U*EH#Ic1CC5 z{+@Ai$Mr1h5)p? zEI<%=B7GEF>vr)LyPk&MDs?EFWD9aR$t)+mrqia_u~j0vAtQKo~|C z0SIhy1?hiT1IMHjW9m!(+|bd0It#m$^mL zYH*VDrjT(o!1jZ*$f&oahq*&Fs2`;YSx|eW`|I_9iaxaMM=<+l76*G4*AZ$6HxLdY z7|LwV04VTCAAnl0GcFyaW#1Mkg=?w6$83-h{2yaD`R{JEyKE)mckpH