From 5dc6fc4657ae82f0e193b2e85800f968c115d12f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 25 May 2016 00:02:28 -0700 Subject: [PATCH] Cleanup of style and simplifications. (#378) * Cleanup of style and simplifications. * Removing unused addClass function. --- accessible/appview.component.js | 8 ++- accessible/clipboard.service.js | 3 +- accessible/fieldview.component.js | 57 ++++++++--------- accessible/toolbox_treeview.component.js | 63 ++++++++---------- accessible/toolboxview.component.js | 18 +++--- accessible/tree.service.js | 40 +++++------- accessible/utils.service.js | 8 +-- accessible/workspace_treeview.component.js | 71 +++++++++++---------- accessible/workspaceview.component.js | 23 +++---- demos/accessible/icon.png | Bin 939 -> 1416 bytes 10 files changed, 138 insertions(+), 153 deletions(-) diff --git a/accessible/appview.component.js b/accessible/appview.component.js index 1dee0d09a..aa8e620f3 100644 --- a/accessible/appview.component.js +++ b/accessible/appview.component.js @@ -22,7 +22,9 @@ * app is rendered on the page. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.workspace = new Blockly.Workspace(); + // If the debug flag is true, print console.logs to help with debugging. blocklyApp.debug = false; @@ -51,7 +53,7 @@ blocklyApp.AppView = ng.core `, directives: [blocklyApp.ToolboxView, blocklyApp.WorkspaceView], - // ClipboardService declared here so that all components are using the same + // ClipboardService declared here so that all components are using the same // instance of the clipboard. // https://www.sitepoint.com/angular-2-components-providers-classes-factories-values/ providers: [blocklyApp.ClipboardService] @@ -60,7 +62,7 @@ blocklyApp.AppView = ng.core constructor: function() { this.stringMap = { ['TOOLBOX_LOAD']: Blockly.Msg.TOOLBOX_LOAD_MSG, - ['WORKSPACE_LOAD']: Blockly.Msg.WORKSPACE_LOAD_MSG, + ['WORKSPACE_LOAD']: Blockly.Msg.WORKSPACE_LOAD_MSG, ['BLOCK_SUMMARY']: Blockly.Msg.BLOCK_SUMMARY, ['BLOCK_ACTION_LIST']: Blockly.Msg.BLOCK_ACTION_LIST, ['OPTION_LIST']: Blockly.Msg.OPTION_LIST, @@ -69,7 +71,7 @@ blocklyApp.AppView = ng.core ['BUTTON']: Blockly.Msg.BUTTON, ['TEXT']: Blockly.Msg.TEXT, ['ARGUMENT_BLOCK_ACTION_LIST']: Blockly.Msg.ARGUMENT_BLOCK_ACTION_LIST, - ['ARGUMENT_INPUT']: Blockly.Msg.ARGUMENT_INPUT, + ['ARGUMENT_INPUT']: Blockly.Msg.ARGUMENT_INPUT }; } }); diff --git a/accessible/clipboard.service.js b/accessible/clipboard.service.js index f509cfb7e..2caf8d627 100644 --- a/accessible/clipboard.service.js +++ b/accessible/clipboard.service.js @@ -21,6 +21,7 @@ * @fileoverview Angular2 Service that handles the clipboard and marked spots. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.ClipboardService = ng.core .Class({ constructor: function() { @@ -71,7 +72,7 @@ blocklyApp.ClipboardService = ng.core reconstitutedBlock.previousConnection); blocklyApp.debug && console.log('paste to marked connection'); if (announce) { - alert(Blockly.Msg.PASTED_BLOCK_TO_MARKED_SPOT_MSG + block.toString()); + alert(Blockly.Msg.PASTED_BLOCK_TO_MARKED_SPOT_MSG + block.toString()); } }, markConnection: function(connection) { diff --git a/accessible/fieldview.component.js b/accessible/fieldview.component.js index 3d834bb0c..3fbe06f6f 100644 --- a/accessible/fieldview.component.js +++ b/accessible/fieldview.component.js @@ -23,22 +23,23 @@ * with the field. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.FieldView = ng.core .Component({ selector: 'field-view', template: ` -
    1. -
  • -
  • // Checkboxes not currently supported.
  • -
  • `, inputs: ['field', 'level', 'index', 'parentId'], - providers: [blocklyApp.TreeService, blocklyApp.UtilsService], + providers: [blocklyApp.TreeService, blocklyApp.UtilsService] }) .Class({ - constructor: [blocklyApp.TreeService, blocklyApp.UtilsService, + constructor: [blocklyApp.TreeService, blocklyApp.UtilsService, function(_treeService, _utilsService) { this.optionText = { keys: [] @@ -72,7 +73,7 @@ blocklyApp.FieldView = ng.core this.treeService = _treeService; this.utilsService = _utilsService; this.stringMap = { - 'CURRENT_ARGUMENT_VALUE': Blockly.Msg.CURRENT_ARGUMENT_VALUE, + 'CURRENT_ARGUMENT_VALUE': Blockly.Msg.CURRENT_ARGUMENT_VALUE }; }], ngOnInit: function() { @@ -80,27 +81,21 @@ blocklyApp.FieldView = ng.core this.idMap = this.utilsService.generateIds(elementsNeedingIds); }, generateAriaLabelledByAttr: function() { - return this.utilsService.generateAriaLabelledByAttr.apply(this,arguments); + return this.utilsService.generateAriaLabelledByAttr.apply(this, + arguments); }, generateElementNames: function() { var elementNames = ['listItem']; - switch(true) { - case this.isTextInput(): - elementNames.push('input'); - break; - case this.isDropdown(): - elementNames.push('label'); - var keys = this.getOptions(); - for (var i = 0; i < keys.length; i++){ - elementNames.push(keys[i]); - elementNames.push(keys[i] + 'Button'); - } - break; - case this.isTextField() && this.hasVisibleText(): - elementNames.push('label'); - break; - default: - break; + if (this.isTextInput()) { + elementNames.push('input'); + } else if (this.isDropdown()) { + elementNames.push('label'); + var keys = this.getOptions(); + for (var i = 0; i < keys.length; i++){ + elementNames.push(keys[i], keys[i] + 'Button'); + } + } else if (this.isTextField() && this.hasVisibleText()) { + elementNames.push('label'); } return elementNames; }, diff --git a/accessible/toolbox_treeview.component.js b/accessible/toolbox_treeview.component.js index a1d25a3fe..b1e03a899 100644 --- a/accessible/toolbox_treeview.component.js +++ b/accessible/toolbox_treeview.component.js @@ -23,14 +23,15 @@ * with the blocks. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.ToolboxTreeView = ng.core .Component({ selector: 'toolbox-tree-view', template: `
  • {{setActiveDesc(parentList)}} @@ -38,22 +39,22 @@ blocklyApp.ToolboxTreeView = ng.core
    1. -
    2. -
    3. -
    4. -
    5. -
    6. -
    7. @@ -62,9 +63,9 @@ blocklyApp.ToolboxTreeView = ng.core
      -
    8. @@ -77,8 +78,9 @@ blocklyApp.ToolboxTreeView = ng.core directives: [ng.core.forwardRef( function() { return blocklyApp.ToolboxTreeView; }), blocklyApp.FieldView], - inputs: ['block', 'displayBlockMenu', 'level', 'index', 'tree', 'noCategories'], - providers: [blocklyApp.TreeService, blocklyApp.UtilsService], + inputs: ['block', 'displayBlockMenu', 'level', 'index', 'tree', + 'noCategories'], + providers: [blocklyApp.TreeService, blocklyApp.UtilsService] }) .Class({ constructor: [blocklyApp.ClipboardService, blocklyApp.TreeService, @@ -92,15 +94,15 @@ blocklyApp.ToolboxTreeView = ng.core 'BLOCK_ACTION_LIST': Blockly.Msg.BLOCK_ACTION_LIST, 'COPY_TO_CLIPBOARD': Blockly.Msg.COPY_TO_CLIPBOARD, 'COPY_TO_WORKSPACE': Blockly.Msg.COPY_TO_WORKSPACE, - 'COPY_TO_MARKED_SPOT': Blockly.Msg.COPY_TO_MARKED_SPOT, + 'COPY_TO_MARKED_SPOT': Blockly.Msg.COPY_TO_MARKED_SPOT }; }], ngOnInit: function() { var elementsNeedingIds = ['blockSummaryLabel']; if (this.displayBlockMenu || this.block.inputList.length){ - elementsNeedingIds = elementsNeedingIds.concat(['listItem', 'label', 'workspaceCopy', - 'workspaceCopyButton', 'blockCopy', 'blockCopyButton', - 'sendToSelected', 'sendToSelectedButton']); + elementsNeedingIds = elementsNeedingIds.concat(['listItem', 'label', + 'workspaceCopy', 'workspaceCopyButton', 'blockCopy', + 'blockCopyButton', 'sendToSelected', 'sendToSelectedButton']); } for (var i = 0; i < this.block.inputList.length; i++){ elementsNeedingIds.push('listItem' + i); @@ -114,10 +116,12 @@ blocklyApp.ToolboxTreeView = ng.core } }, getMarkedBlockCompatibilityHTMLText: function(isCompatible) { - return this.utilsService.getMarkedBlockCompatibilityHTMLText(isCompatible); + return this.utilsService.getMarkedBlockCompatibilityHTMLText( + isCompatible); }, generateAriaLabelledByAttr: function() { - return this.utilsService.generateAriaLabelledByAttr.apply(this,arguments); + return this.utilsService.generateAriaLabelledByAttr.apply(this, + arguments); }, setActiveDesc: function(parentList) { // If this is the first child of the toolbox and the @@ -128,19 +132,6 @@ blocklyApp.ToolboxTreeView = ng.core this.treeService.setActiveDesc(parentList, this.tree.id); } }, - addClass: function(node, classText) { - // Ensure that node doesn't have class already in it. - var classList = (node.className || '').split(' '); - var canAdd = classList.indexOf(classText) == -1; - // Add class if it doesn't. - if (canAdd) { - if (classList.length) { - node.className += ' ' + classText; - } else { - node.className = classText; - } - } - }, copyToWorkspace: function(block) { var xml = Blockly.Xml.blockToDom(block); Blockly.Xml.domToBlock(blocklyApp.workspace, xml); diff --git a/accessible/toolboxview.component.js b/accessible/toolboxview.component.js index 647ddc64d..abb71bec0 100644 --- a/accessible/toolboxview.component.js +++ b/accessible/toolboxview.component.js @@ -22,22 +22,23 @@ * in AccessibleBlockly. Also handles any interactions with the toolbox. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.ToolboxView = ng.core .Component({ selector: 'toolbox-view', template: `

      Toolbox

        -
      1. -
        @@ -87,7 +88,7 @@ blocklyApp.ToolboxView = ng.core parent.setAttribute('aria-label', label.innerText); parent.id = 'blockly-toolbox-tree-node' + i; if (i == 0 && tree.getAttribute('aria-activedescendant') == - 'blockly-toolbox-tree-node0') { + 'blockly-toolbox-tree-node0') { this.treeService.setActiveDesc(parent, tree.id); parent.setAttribute('aria-selected', 'true'); } @@ -131,4 +132,3 @@ blocklyApp.ToolboxView = ng.core } } }); - diff --git a/accessible/tree.service.js b/accessible/tree.service.js index c4ddfe1bc..27c38ce02 100644 --- a/accessible/tree.service.js +++ b/accessible/tree.service.js @@ -21,6 +21,7 @@ * @fileoverview Angular2 Service that handles all tree keyboard navigation. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.TreeService = ng.core .Class({ constructor: function() { @@ -46,7 +47,8 @@ blocklyApp.TreeService = ng.core this.activeDesc_[id] = node; }, getActiveDesc: function(id) { - return this.activeDesc_[id] || document.getElementById((document.getElementById(id)).getAttribute('aria-activedescendant')); + return this.activeDesc_[id] || + document.getElementById((document.getElementById(id)).getAttribute('aria-activedescendant')); }, // Makes a given node the active descendant of a given tree. updateSelectedNode: function(node, tree, keepFocus) { @@ -80,16 +82,12 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('shifttabbing'); // If the previous key is shift, we're shift-tabbing mode. this.goToPreviousTree(treeId); - e.preventDefault(); - e.stopPropagation(); } else { // If previous key isn't shift, we're tabbing. this.goToNextTree(treeId); - e.preventDefault(); - e.stopPropagation(); } - break; - default: + e.preventDefault(); + e.stopPropagation(); break; } }, @@ -131,24 +129,20 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('shifttabbing'); // If the previous key is shift, we're shift-tabbing. this.goToPreviousTree(treeId); - e.preventDefault(); - e.stopPropagation(); } else { // If previous key isn't shift, we're tabbing // we want to go to the run code button. this.goToNextTree(treeId); - e.preventDefault(); - e.stopPropagation(); } // Setting the previous key variable in each case because // we only want to save the previous navigation keystroke, // not any typing. this.previousKey_ = e.keyCode; + e.preventDefault(); + e.stopPropagation(); break; case 37: // Left-facing arrow: go out a level, if possible. If not, do nothing. - e.preventDefault(); - e.stopPropagation(); blocklyApp.debug && console.log('in left arrow section'); var nextNode = node.parentNode; if (node.tagName == 'BUTTON' || node.tagName == 'INPUT') { @@ -163,11 +157,11 @@ blocklyApp.TreeService = ng.core } this.updateSelectedNode(nextNode, tree, keepFocus); this.previousKey_ = e.keyCode; + e.preventDefault(); + e.stopPropagation(); break; case 38: // Up-facing arrow: go up a level, if possible. If not, do nothing. - e.preventDefault(); - e.stopPropagation(); blocklyApp.debug && console.log('node passed in: ' + node.id); var prevSibling = this.getPreviousSibling(node); if (prevSibling && prevSibling.tagName != 'H1') { @@ -176,10 +170,10 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('no previous sibling'); } this.previousKey_ = e.keyCode; - break; - case 39: e.preventDefault(); e.stopPropagation(); + break; + case 39: blocklyApp.debug && console.log('in right arrow section'); var firstChild = this.getFirstChild(node); if (firstChild) { @@ -188,13 +182,13 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('no valid child'); } this.previousKey_ = e.keyCode; + e.preventDefault(); + e.stopPropagation(); break; case 40: // Down-facing arrow: go down a level, if possible. // If not, do nothing. blocklyApp.debug && console.log('preventing propogation'); - e.preventDefault(); - e.stopPropagation(); var nextSibling = this.getNextSibling(node); if (nextSibling) { this.updateSelectedNode(nextSibling, tree, keepFocus); @@ -202,6 +196,8 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('no next sibling'); } this.previousKey_ = e.keyCode; + e.preventDefault(); + e.stopPropagation(); break; case 13: // If I've pressed enter, I want to interact with a child. @@ -224,8 +220,6 @@ blocklyApp.TreeService = ng.core } this.previousKey_ = e.keyCode; break; - default: - break; } }, getFirstChild: function(element) { @@ -285,7 +279,7 @@ blocklyApp.TreeService = ng.core } } else { var parent = element.parentNode; - while (parent != null) { + while (parent) { blocklyApp.debug && console.log('looping'); if (parent.tagName == 'OL') { break; @@ -327,5 +321,5 @@ blocklyApp.TreeService = ng.core blocklyApp.debug && console.log('no last child'); return null; } - }, + } }); diff --git a/accessible/utils.service.js b/accessible/utils.service.js index f0c2d5e13..fddb47ded 100644 --- a/accessible/utils.service.js +++ b/accessible/utils.service.js @@ -22,7 +22,9 @@ * components. * @author madeeha@google.com (Madeeha Ghori) */ + var blocklyApp = {}; + blocklyApp.UtilsService = ng.core .Class({ constructor: function() { @@ -38,11 +40,7 @@ blocklyApp.UtilsService = ng.core return idMap; }, generateAriaLabelledByAttr: function() { - var labels = arguments[0]; - for (i = 1; i < arguments.length; i++) { - labels += ' ' + arguments[i]; - } - return labels.trim(); + return Array.from(arguments).join(' ').trim(); }, getInputTypeLabel: function(connection) { // Returns an upper case string in the case of official input type names. diff --git a/accessible/workspace_treeview.component.js b/accessible/workspace_treeview.component.js index 7a9114f44..9246ce3a5 100644 --- a/accessible/workspace_treeview.component.js +++ b/accessible/workspace_treeview.component.js @@ -23,59 +23,60 @@ * interactions with the blocks. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.WorkspaceTreeView = ng.core .Component({ selector: 'tree-view', template: ` -
      2. {{checkParentList(parentList)}}
          -
          1. -
          2. -
          3. -
          4. -
          5. -
          6. -
          7. -
          8. -
          9. -
          10. -
          11. -
          12. -
          13. @@ -86,21 +87,21 @@ blocklyApp.WorkspaceTreeView = ng.core
            -
            1. -
            2. -
            3. -
            @@ -134,13 +135,13 @@ blocklyApp.WorkspaceTreeView = ng.core 'CUT_BLOCK': Blockly.Msg.CUT_BLOCK, 'COPY_BLOCK': Blockly.Msg.COPY_BLOCK, 'MOVE_TO_MARKED_SPOT': Blockly.Msg.MOVE_TO_MARKED_SPOT, - 'DELETE': Blockly.Msg.DELETE, + 'DELETE': Blockly.Msg.DELETE }; }], deleteBlock: function(block) { // If this is the top block, we should shift focus to the previous tree var topBlocks = blocklyApp.workspace.topBlocks_; - for (var i=0; i < topBlocks.length; i++) { + for (var i = 0; i < topBlocks.length; i++) { if (topBlocks[i].id == block.id) { this.treeService.goToPreviousTree(this.parentId); break; @@ -154,7 +155,8 @@ blocklyApp.WorkspaceTreeView = ng.core return this.utilsService.getMarkedBlockCompatibilityHTMLText(isCompatible); }, generateAriaLabelledByAttr: function() { - return this.utilsService.generateAriaLabelledByAttr.apply(this,arguments); + return this.utilsService.generateAriaLabelledByAttr.apply(this, + arguments); }, ngOnInit: function() { var elementsNeedingIds = ['blockSummary', 'listItem', 'label', @@ -166,7 +168,8 @@ blocklyApp.WorkspaceTreeView = ng.core for (var i = 0; i < this.block.inputList.length; i++) { var inputBlock = this.block.inputList[i]; if (inputBlock.connection && !inputBlock.connection.targetBlock()) { - elementsNeedingIds = elementsNeedingIds.concat(['inputList' + i, 'inputMenuLabel' + i, 'markSpot' + i, + elementsNeedingIds = elementsNeedingIds.concat( + ['inputList' + i, 'inputMenuLabel' + i, 'markSpot' + i, 'markSpotButton' + i, 'paste' + i, 'pasteButton' + i]); } } diff --git a/accessible/workspaceview.component.js b/accessible/workspaceview.component.js index b0e5bd5da..322b0a4a4 100644 --- a/accessible/workspaceview.component.js +++ b/accessible/workspaceview.component.js @@ -22,6 +22,7 @@ * rendered in AccessibleBlockly. * @author madeeha@google.com (Madeeha Ghori) */ + blocklyApp.WorkspaceView = ng.core .Component({ selector: 'workspace-view', @@ -31,22 +32,22 @@ blocklyApp.WorkspaceView = ng.core

            {{stringMap['WORKSPACE']}}

            - -
            -
            `, directives: [blocklyApp.WorkspaceTreeView], - providers: [blocklyApp.TreeService], + providers: [blocklyApp.TreeService] }) .Class({ constructor: [blocklyApp.TreeService, function(_treeService) { @@ -57,7 +58,7 @@ blocklyApp.WorkspaceView = ng.core this.stringMap = { 'WORKSPACE': Blockly.Msg.WORKSPACE, 'RUN_CODE': Blockly.Msg.RUN_CODE, - 'CLEAR_WORKSPACE': Blockly.Msg.CLEAR_WORKSPACE, + 'CLEAR_WORKSPACE': Blockly.Msg.CLEAR_WORKSPACE }; }], onWorkspaceToolbarKeypress: function(event, id) { @@ -76,10 +77,10 @@ blocklyApp.WorkspaceView = ng.core runCode(); }, disableRunCode: function() { - if (blocklyApp.workspace.topBlocks_.length == 0){ - return 'blockly-disabled'; - } else { + if (blocklyApp.workspace.topBlocks_.length){ return undefined; + } else { + return 'blockly-disabled'; } - }, + } }); diff --git a/demos/accessible/icon.png b/demos/accessible/icon.png index 449981f95958dda94a3a4742c652c8fc6bc6a8f5..3ea238c448b2d00cbf3fc425b9fdf6ccd6706429 100644 GIT binary patch delta 1381 zcmai!i#ro~7{`Bc+#b?gOAX^h>zpORblgHDgig$*<#JqdX+thEx2@PCI`t$wp(Zh{ z$*tVW*p${Va#_NJTym*qid=GLXXg(%&w1bHdB1qg3+KzGzu!WGS%*~93Vz4VPkeC z=L`=A#I%mqL_HHVR9Dl8@6^weapgzDTXO>@D*h_)X!SMUqn&wlH9SF0#wm_nn5pkU zd-K{PVl1a~G3!8YO+u#=^if~_tXnO7@q<~J`c_7XksOniKzw6ku~B>hkRT57djEaS zZY3rq_2p8FbhNZmvXNG1W^0Xuk!_kvvYzY^lLEuExh|D5CUYmDYB=@l+7i!}&m8CT zCslu%PBq()9puZ(%4WM8@^-VP#6#qI8ylO@@s?OtZDlku6GAOtN{){1F>o0g4mN&v znqouTNxzBU3i+7k*pNCuze~QTBv%MY$Y^bSZKv)e1s*mxuba4EcF1`VQg=ZH%p_X6 zz}07>zI93l*nunf_Q~JwVf1g0R)wR{Xs`1O1b3qm=a3^hp_yOjhbRPB_92+#4_SoHe6bfZ*Y57CNeSNN*9F*EV`5?(syQpuzun9-! zZS4nkUS2%&>_3)w(8#-IRO!4F6+rCx7(d|`7|8VGB_D^DEF4#cDmxPhgdK!CE-r3G zu6z*h`DA1v>%|9O_Vy-BH5VZbR;y4CMfI0|2x&6rxjZRQ=7`@qMq@Z_)1nE2# z)Ix$(;U-2#IO^jVwo}T?h5YV^-VUtSs`I_owY59u%cl>%1YmA8Wp50z6rC4?!Sucx zA0OAdJ`-(uKaj4lYR$r4y!dEJxUt~lm+ZvxI zSYDpI)G+qT(9&8~{98;^l*;Va%~I~iR%zP@!b1Q?V2RQE2PK@@lmj4VIJ$jmbTks4 z6fEh#9wx5^U^=&m3vYeWGt<)2g2Ma@;-Jot=ybGejkEmp7u>dJ<`k>THg&B_3gmT% zK^xie&x`5!C_|DlO}X|g9K-z>j{tT^O3nN0iZ6|CoP(Zct zG{tSMOjl6hLIc%YV=N7CZDfH&GIf=&Iro@PYg^%N5Wn!7KKH(QMQTG$t@icxMckuM zBDkp7;9%H8c+c1@=ayXDUJ+|)aj^obt2+{VkUS$}%6crcGA@PyZ670k#3lxjkW83S3sx!267#Fomv9UxS2-R!J#adVsaDp#$a7j{I`jp0G(N`c$qTN(n-=N|O!^3A2W z!rfxWec9cv`D=&!S36e!4rfdRmUeG^{~qu}!qG(7u^Mx8^CQ@IneUkyl&<>XFn`Tz zpU=srrlzc+xeVJWiiUI)keC#>IC(hMIs|9_0|KC*_W%F@ delta 928 zcmV;R17G}z3#$i^8Gi%-002b*7-Rqd0McngLr_UWLm*IcZ)Rz1WdHyem1AIFtVk>< z$YBy-V93oYDRK{TjEsnkQeeNzz|O$P00xQ4#RZN50X_^k!MAG=wU>24X5m(c6|khF z7AFJgEkInFTu@ZPz`&>jWUH5#6oA+vK( zf_qV7rGj&QPJU5wL1J<$iLM|5l%!UafN1CZg36-I^o$Y(N1$(0fp+E=l$N9x=_q*S zCF?OTfWi-=<8vT5To}d9B$pPIL5*Q#GG<@^01;g@#T|LmkpKVy0%A)?L;(MXkIcUS z000SaNLh0L0DlV;000XU0RWnu7ytkO2XskIMF-#o7yt$eF;Wk@0007BNklf}!(HX&9qH zL>D~>QGZF`iNq1NJjsoSYJNK{Nmj6%J|~{0jD@^Kx`(*T%t@U?Gd3dYD#WX>8AjNGIPAF#2O=(e zPFW!KdU}SLNNhwbBl_Ii5#n^{_@B9ruU3=n=Rw{<8YrW!h!bgM50CTqzd<=4iY(uM zUxr#<1ne?Jjki93P{+ereWeyIlJfNE-~vf}Pe6R?huTCf{ZVsOB1Ct=rJO*BUMKG+ zLVvst-b(f^ox*)Ab|E%+Ud-C574{;;`JDE7xoK-8?bFhN3s@)VkQO`fm68@{dGL9Z zs8rH=CqDoBW=Y$%DEW8GYDrtQL?zlLX>Ih-9SjD1&&gPO#Q&w6+5JC;Y4<+k<9y_& zccf0fku9>$Ie*oSF~%5Uj4{R-V~jDz7#U;C|KtycAB4k>;Vt9<0000