From 466b6521d538149ebee897123aa1e0db0d0fe1c1 Mon Sep 17 00:00:00 2001 From: Giancarlo Panichi Date: Thu, 8 May 2014 13:20:56 +0000 Subject: [PATCH] Added TreeGrid Validation git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/user/tabular-data-table-widget@95436 82a268e6-3cf1-43bd-a215-b396298e98cf --- .../client/resources/ResourceBundle.java | 6 + .../client/resources/table-validation.png | Bin 0 -> 881 bytes .../client/resources/table-validation_32.png | Bin 0 -> 1740 bytes .../validation/ValidationsTasksPanel.java | 269 ++++++++++++++++++ .../client/validation/tree/BaseDto.java | 32 +++ .../client/validation/tree/FolderDto.java | 55 ++++ .../validation/tree/TreeDataGenerator.java | 46 +++ .../client/validation/tree/ValidationDto.java | 49 ++++ .../client/resources/table-validation.png | Bin 0 -> 881 bytes .../client/resources/table-validation_32.png | Bin 0 -> 1740 bytes 10 files changed, 457 insertions(+) create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/ValidationsTasksPanel.java create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/BaseDto.java create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/FolderDto.java create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/TreeDataGenerator.java create mode 100644 src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/ValidationDto.java create mode 100644 src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png create mode 100644 src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/ResourceBundle.java b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/ResourceBundle.java index a83a35a..8a0c18f 100644 --- a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/ResourceBundle.java +++ b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/ResourceBundle.java @@ -69,5 +69,11 @@ public interface ResourceBundle extends ClientBundle { @Source("arrow-undo-all_32.png") ImageResource undoAll32(); + + @Source("table-validation.png") + ImageResource tableValidation(); + + @Source("table-validation_32.png") + ImageResource tableValidation32(); } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png new file mode 100644 index 0000000000000000000000000000000000000000..eee1001c248f2dd3c0bd0016489a9676fe5e4c0f GIT binary patch literal 881 zcmV-%1CIQOP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n` z4g()melqz000QwzL_t(I%Waa)YusfJ$3M?+e@S*XyKT+J#1(wcL3{GisDkJrSP*lOCJ`*fXlfDhB`pzcvNg>MX_C$Uo@ZV>Y;tp8 zm|XRpcX3745jE5e5ku7wGt8VMj-z3BSK1%F_25>Rm|m@C!Kaqi z;)t2Ks3WR~b(=-^T)IOfAv%^|f8?j9U)2X_a$v73QA zUhS)K{KGl!yt!P>Rou_cES>XR|ukHrw5>%9AO0N4iCuQpAb^hIqG-^3(+d>`!Sq6vtbJlkfr4Z=J z122vaAZnOFF8c}t*ES<3o@p|1uEmLGn{1`)w2OkXKP>awlTCJtND^cD#-jIBTD?|o z9mw}l;ZCF0!^F83wMx$T>?ID}bA|H3euf?qzS;T*bs<_pGY!wbUJU#(zc8NfqXO92 zNxboNlQT2dc;!fg+4fa_{B8zHfsRI^Ml#PZbI)pd@Dg`ty2sfa8nqtI%(SSNOMLPD zGUiJ3L=h4igpJ(|Ub_DnC!abM+MPD3h-CW@1F*537(3czyHH*|d<)SNYDS|nNT-O5 z4v%u=t|$2V(pQKGqKVwh5i=ZU)N?+YZE>KS^X2&^>JJHx@*r=HzRkk*KN;#DVsUkm z3zyH6H!2jdLzbkA(ZO%*3S&oar6b)93XlA?zR1O^^V~ahAHxTmO#k*R>)Y!ji6l+r zj)o#?sPy%6?D2++r10{i4HnmacgsB#vE!f5eHs>5uJFL^4|8^Yl9HE58c8CAljFbC zLzYb~EbWXC+*OpMPNn{L-*aQ_n|{6U6Cq@DQipbIlZO&Tiu4cGSzTUP4gl|baY4!wQhW00000NkvXX Hu0mjfA_kdb literal 0 HcmV?d00001 diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c253439bd781138517e8133632a95e1361cefacf GIT binary patch literal 1740 zcmV;-1~d7IP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n` z4gxUev_9bg00vA+L_t(o!_Al9Z(K(e$3JuT?yl`PP8>VbaZBo|t&n08XruzAiK&Px z-U_@_w51^6iAp?F;)w^82VRQAUjUH+l?o#9!zHLl4N=onDMX0U1Se6NrcqKgmfP6f zIQH({JLeo8X72Uf^-2f{5Gza9XJ+o4GvD()-!m8fAAUy{?0@d_@X-YTTru#olQ$n$ zwRu&WFf&vQHBeK`h;|q^tk<@RZ5G#Sc)yspa@_|8U;NRxW={j8MF55KPFGFMT;+wh zkq+2AJWUlbdIB*u#0;}yjUlSmtk))0WgghsAHYPXtM<$nCS2wX!XKDXB*^;5;zY5+ zO1oI&;#gQQTumaTuPx4&ug@F{_OAtih4_cG$I=-V6#L=CFYK zR%ew)l5cEgh7s~fd~P`DoeM!k+mv-#k9;r4=mrI#XxNo@p7FhhfAAkIyK76Uj5JeB z4Xr?sP$8HWx&ANIy_t(?vxw9n4#dcsX~K_>-=JP|K`2~BFd~?)GBD`>>X@i;Xm$)L zda?AOcoNfdewHeEpFr0Dk_; zBF@3npPL#8@h@Ht^G_ZeJb!g@l{8J!=xehM5K~Z8f&*uRVFuyy@@3vxc^ef02OqMA znsRKRiC2vhu81gxaceyz0k-a3!C`#+=-0lPGy2m$9oP^M2Q=zQdGcmG!2!>oT%?np zr`vdw#?UaT9x=s@Do&NRZVPIHiXtY63ZjadAg1ixEr_ahI@^v&t2LSSa6mPxUPyxL z%O?&<6iKc#wtWZFGxr8(gcB=eoKK7{xz!_><@971mS~iv<4b{@y z2sY*zqtkBV3#gsoH3TE7h!v8~!> zxvkjcX)(lUFVwBhBljO7NfI26x8Hw@v+uqc0=4j79|shR-LP=j zs3*K|s=@&WzkKaImexBAHw_^W?Y5DV{hGIMDUVR}S3C_?8-?g2&_4bNtdD zIdk>(GFf+y-^ECC3kIyLuWDE#tYapyys06S5WvGFKxi=o&JBArtTe^)Ie110A zS8lXe&vK*@nJ*y?YjT_Uh2OH4ukp~#XBnyw^UjA?IC0^4xVB3y(L$`PPY2Axy?wZz zIBesFTdUQ2Zn#NO11l7t0H+A%jm$b6`};ggYfC(~?@PRN_7CKe2i;J`ixd(ZwLp3T zxY?}NCZ0WV(JX$L6sQy$p=y{@w(VMD*H|qynOx9(g.panichi@isti.cnr.it + * + */ +public class ValidationsTasksPanel extends FramedPanel { + protected String WIDTH = "298px"; + protected String HEIGHT = "520px"; + + protected TRId trId; + protected VerticalLayoutContainer vl; + protected EventBus eventBus; + protected ValidationsTasksMetadata validationsTasksMetadata; + + protected TreeDataGenerator gen; + protected TreeStore store; + + class KeyProvider implements ModelKeyProvider { + @Override + public String getKey(BaseDto item) { + return (item instanceof FolderDto ? "f-" : "m-") + + item.getId().toString(); + } + } + + public ValidationsTasksPanel(EventBus eventBus) { + super(); + this.eventBus = eventBus; + forceLayoutOnResize = true; + retrieveCurrentTR(); + + } + + public ValidationsTasksPanel(TRId trId, EventBus eventBus) { + super(); + this.trId = trId; + this.eventBus = eventBus; + forceLayoutOnResize = true; + draw(); + } + + protected void draw() { + init(); + retrieveValidations(); + } + + protected void init() { + setWidth(WIDTH); + setHeight(HEIGHT); + setHeaderVisible(false); + setBodyBorder(false); + } + + protected void createTreeData(){ + gen=new TreeDataGenerator(validationsTasksMetadata); + create(); + } + + protected void create() { + vl = new VerticalLayoutContainer(); + vl.setScrollMode(ScrollMode.AUTO); + vl.setAdjustForScroll(true); + this.add(vl); + + store = new TreeStore(new KeyProvider()); + + FolderDto root = gen.getRoot(); + for (BaseDto base : root.getChildren()) { + store.add(base); + if (base instanceof FolderDto) { + processFolder(store, (FolderDto) base); + } + } + + ColumnConfig cc1 = new ColumnConfig( + new ToStringValueProvider("task")); + cc1.setHeader("Task"); + + ColumnConfig cc2 = new ColumnConfig( + new ValueProvider() { + + @Override + public String getValue(BaseDto object) { + return object instanceof ValidationDto ? ((ValidationDto) object) + .getDescription() : ""; + } + + @Override + public void setValue(BaseDto object, String value) { + if (object instanceof ValidationDto) { + ((ValidationDto) object).setDescription(value); + } + } + + @Override + public String getPath() { + return "description"; + } + }); + cc2.setHeader("Description"); + + ColumnConfig cc3 = new ColumnConfig( + new ValueProvider() { + + @Override + public Boolean getValue(BaseDto object) { + return object instanceof ValidationDto ? ((ValidationDto) object) + .getValid() : false; + } + + @Override + public void setValue(BaseDto object, Boolean value) { + if (object instanceof ValidationDto) { + ((ValidationDto) object).setValid(value); + } + } + + @Override + public String getPath() { + return "valid"; + } + }); + cc3.setHeader("Valid"); + cc3.setCell(new AbstractCell() { + + @Override + public void render(Context context, Boolean value, + SafeHtmlBuilder sb) { + + if (value) { + sb.appendHtmlConstant("true"); + + } else { + sb.appendHtmlConstant("true"); + + } + + } + }); + + List> l = new ArrayList>(); + l.add(cc1); + l.add(cc2); + l.add(cc3); + ColumnModel cm = new ColumnModel(l); + + final TreeGrid tree = new TreeGrid(store, cm, cc1); + tree.getStyle().setLeafIcon(ResourceBundle.INSTANCE.tableValidation()); + tree.getView().setAutoExpandColumn(cc1); + /* + * ToolBar buttonBar = new ToolBar(); + * + * buttonBar.add(new TextButton("Expand All", new SelectHandler() { + * + * @Override public void onSelect(SelectEvent event) { tree.expandAll(); + * } })); buttonBar.add(new TextButton("Collapse All", new + * SelectHandler() { + * + * @Override public void onSelect(SelectEvent event) { + * tree.collapseAll(); } })); + * + * v.add(buttonBar, new VerticalLayoutData(1, -1)); + */ + vl.add(tree, new VerticalLayoutData(1, 1)); + + } + + protected void retrieveValidations() { + + TDGWTServiceAsync.INSTANCE.getValidationsTasksMetadata(trId, + new AsyncCallback() { + + public void onFailure(Throwable caught) { + Log.error("Load validations metadata failure: " + + caught.getLocalizedMessage()); + UtilsGXT3.alert( + "Error retrieving validations metadata", + "Error retrieving validations metadata"); + + } + + public void onSuccess(ValidationsTasksMetadata result) { + Log.debug("loaded " + result.getId()); + validationsTasksMetadata = result; + createTreeData(); + + } + + }); + + } + + public void update() { + retrieveCurrentTR(); + } + + public void update(TRId trId) { + this.trId = trId; + draw(); + } + + protected void retrieveCurrentTR() { + TDGWTServiceAsync.INSTANCE.getCurrentTRId(new AsyncCallback() { + + public void onFailure(Throwable caught) { + Log.error("Error retrieving current TRId: " + + caught.getLocalizedMessage()); + UtilsGXT3.alert("Error", + "Error retrieving current tabular resource id"); + + } + + public void onSuccess(TRId result) { + Log.debug("retrieved " + result); + trId = result; + draw(); + + } + + }); + } + + private void processFolder(TreeStore store, FolderDto folder) { + for (BaseDto child : folder.getChildren()) { + store.add(folder, child); + if (child instanceof FolderDto) { + processFolder(store, (FolderDto) child); + } + } + } + +} diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/BaseDto.java b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/BaseDto.java new file mode 100644 index 0000000..da6ca47 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/BaseDto.java @@ -0,0 +1,32 @@ +package org.gcube.portlets.user.td.tablewidget.client.validation.tree; + +import java.io.Serializable; + +/** + * + * @author "Giancarlo Panichi" + * + */ +public class BaseDto implements Serializable { + + private static final long serialVersionUID = -5535466371215737037L; + protected String id; + + public BaseDto(){ + + } + + public BaseDto(String id){ + this.id=id; + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + +} diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/FolderDto.java b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/FolderDto.java new file mode 100644 index 0000000..547a1e6 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/FolderDto.java @@ -0,0 +1,55 @@ +package org.gcube.portlets.user.td.tablewidget.client.validation.tree; + + + +import java.util.ArrayList; + +/** + * + * @author "Giancarlo Panichi" + * + */ +public class FolderDto extends BaseDto { + + private static final long serialVersionUID = 4644048540524701598L; + protected String description; + protected ArrayList childrens; + + + public FolderDto(){ + + } + + public FolderDto(String id,String description, ArrayList childrens){ + super(id); + this.description=description; + this.childrens=childrens; + } + + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ArrayList getChildren() { + return childrens; + } + + public void setChildren(ArrayList children) { + this.childrens = children; + } + + @Override + public String toString() { + return "FolderDto [id="+id+", description=" + description + ", childrens=" + + childrens + "]"; + } + + + + +} diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/TreeDataGenerator.java b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/TreeDataGenerator.java new file mode 100644 index 0000000..9e7625c --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/TreeDataGenerator.java @@ -0,0 +1,46 @@ +package org.gcube.portlets.user.td.tablewidget.client.validation.tree; + +import java.util.ArrayList; + +import org.gcube.portlets.user.td.gwtservice.shared.task.JobS; +import org.gcube.portlets.user.td.gwtservice.shared.task.TaskS; +import org.gcube.portlets.user.td.gwtservice.shared.task.ValidationsTasksMetadata; +import org.gcube.portlets.user.td.gwtservice.shared.tr.table.Validations; + +import com.google.gwt.i18n.client.DateTimeFormat; + +public class TreeDataGenerator { + protected DateTimeFormat sdf = DateTimeFormat + .getFormat("yyyy-MM-dd HH:mm:ss"); + + protected FolderDto root; + + public TreeDataGenerator(ValidationsTasksMetadata validationsTasksMetadata) { + if (validationsTasksMetadata.getTasks().size() > 0) { + ArrayList childrens = new ArrayList(); + for (TaskS task : validationsTasksMetadata.getTasks()) { + ArrayList jobs = new ArrayList(); + for (JobS job : task.getJobs()) { + ArrayList validations = new ArrayList(); + for (Validations v : job.getValidations()) { + ValidationDto validationDto = new ValidationDto( + v.getDescription(), v.isValid()); + validations.add(validationDto); + } + FolderDto foldJob = new FolderDto(job.getId(), + job.getDescription(), validations); + jobs.add(foldJob); + } + FolderDto foldTask = new FolderDto(task.getId(), + sdf.format(task.getStartTime()), jobs); + childrens.add(foldTask); + } + root = new FolderDto("0", "root", childrens); + } + } + + public FolderDto getRoot() { + return root; + } + +} diff --git a/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/ValidationDto.java b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/ValidationDto.java new file mode 100644 index 0000000..0a88338 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/tablewidget/client/validation/tree/ValidationDto.java @@ -0,0 +1,49 @@ +package org.gcube.portlets.user.td.tablewidget.client.validation.tree; + +/** + * + * @author "Giancarlo Panichi" + * + */ +public class ValidationDto extends BaseDto { + + private static final long serialVersionUID = -4353641080571614057L; + + protected String description; + protected Boolean valid; + + public ValidationDto(){ + + } + + public ValidationDto(String description, Boolean valid){ + this.description=description; + this.valid=valid; + } + + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getValid() { + return valid; + } + + public void setValid(Boolean valid) { + this.valid = valid; + } + + @Override + public String toString() { + return "ValidationDto [description=" + description + ", valid=" + valid + + "]"; + } + + + +} diff --git a/src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png b/src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation.png new file mode 100644 index 0000000000000000000000000000000000000000..eee1001c248f2dd3c0bd0016489a9676fe5e4c0f GIT binary patch literal 881 zcmV-%1CIQOP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n` z4g()melqz000QwzL_t(I%Waa)YusfJ$3M?+e@S*XyKT+J#1(wcL3{GisDkJrSP*lOCJ`*fXlfDhB`pzcvNg>MX_C$Uo@ZV>Y;tp8 zm|XRpcX3745jE5e5ku7wGt8VMj-z3BSK1%F_25>Rm|m@C!Kaqi z;)t2Ks3WR~b(=-^T)IOfAv%^|f8?j9U)2X_a$v73QA zUhS)K{KGl!yt!P>Rou_cES>XR|ukHrw5>%9AO0N4iCuQpAb^hIqG-^3(+d>`!Sq6vtbJlkfr4Z=J z122vaAZnOFF8c}t*ES<3o@p|1uEmLGn{1`)w2OkXKP>awlTCJtND^cD#-jIBTD?|o z9mw}l;ZCF0!^F83wMx$T>?ID}bA|H3euf?qzS;T*bs<_pGY!wbUJU#(zc8NfqXO92 zNxboNlQT2dc;!fg+4fa_{B8zHfsRI^Ml#PZbI)pd@Dg`ty2sfa8nqtI%(SSNOMLPD zGUiJ3L=h4igpJ(|Ub_DnC!abM+MPD3h-CW@1F*537(3czyHH*|d<)SNYDS|nNT-O5 z4v%u=t|$2V(pQKGqKVwh5i=ZU)N?+YZE>KS^X2&^>JJHx@*r=HzRkk*KN;#DVsUkm z3zyH6H!2jdLzbkA(ZO%*3S&oar6b)93XlA?zR1O^^V~ahAHxTmO#k*R>)Y!ji6l+r zj)o#?sPy%6?D2++r10{i4HnmacgsB#vE!f5eHs>5uJFL^4|8^Yl9HE58c8CAljFbC zLzYb~EbWXC+*OpMPNn{L-*aQ_n|{6U6Cq@DQipbIlZO&Tiu4cGSzTUP4gl|baY4!wQhW00000NkvXX Hu0mjfA_kdb literal 0 HcmV?d00001 diff --git a/src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png b/src/main/resources/org/gcube/portlets/user/td/tablewidget/client/resources/table-validation_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c253439bd781138517e8133632a95e1361cefacf GIT binary patch literal 1740 zcmV;-1~d7IP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^n` z4gxUev_9bg00vA+L_t(o!_Al9Z(K(e$3JuT?yl`PP8>VbaZBo|t&n08XruzAiK&Px z-U_@_w51^6iAp?F;)w^82VRQAUjUH+l?o#9!zHLl4N=onDMX0U1Se6NrcqKgmfP6f zIQH({JLeo8X72Uf^-2f{5Gza9XJ+o4GvD()-!m8fAAUy{?0@d_@X-YTTru#olQ$n$ zwRu&WFf&vQHBeK`h;|q^tk<@RZ5G#Sc)yspa@_|8U;NRxW={j8MF55KPFGFMT;+wh zkq+2AJWUlbdIB*u#0;}yjUlSmtk))0WgghsAHYPXtM<$nCS2wX!XKDXB*^;5;zY5+ zO1oI&;#gQQTumaTuPx4&ug@F{_OAtih4_cG$I=-V6#L=CFYK zR%ew)l5cEgh7s~fd~P`DoeM!k+mv-#k9;r4=mrI#XxNo@p7FhhfAAkIyK76Uj5JeB z4Xr?sP$8HWx&ANIy_t(?vxw9n4#dcsX~K_>-=JP|K`2~BFd~?)GBD`>>X@i;Xm$)L zda?AOcoNfdewHeEpFr0Dk_; zBF@3npPL#8@h@Ht^G_ZeJb!g@l{8J!=xehM5K~Z8f&*uRVFuyy@@3vxc^ef02OqMA znsRKRiC2vhu81gxaceyz0k-a3!C`#+=-0lPGy2m$9oP^M2Q=zQdGcmG!2!>oT%?np zr`vdw#?UaT9x=s@Do&NRZVPIHiXtY63ZjadAg1ixEr_ahI@^v&t2LSSa6mPxUPyxL z%O?&<6iKc#wtWZFGxr8(gcB=eoKK7{xz!_><@971mS~iv<4b{@y z2sY*zqtkBV3#gsoH3TE7h!v8~!> zxvkjcX)(lUFVwBhBljO7NfI26x8Hw@v+uqc0=4j79|shR-LP=j zs3*K|s=@&WzkKaImexBAHw_^W?Y5DV{hGIMDUVR}S3C_?8-?g2&_4bNtdD zIdk>(GFf+y-^ECC3kIyLuWDE#tYapyys06S5WvGFKxi=o&JBArtTe^)Ie110A zS8lXe&vK*@nJ*y?YjT_Uh2OH4ukp~#XBnyw^UjA?IC0^4xVB3y(L$`PPY2Axy?wZz zIBesFTdUQ2Zn#NO11l7t0H+A%jm$b6`};ggYfC(~?@PRN_7CKe2i;J`ixd(ZwLp3T zxY?}NCZ0WV(JX$L6sQy$p=y{@w(VMD*H|qynOx9(