第14章4节《MonkeyRunner源代码剖析》 HierarchyViewer实现原理-装备ViewServer-port转发
在初始化HierarchyViewer的实例过程中,HierarchyViewer会调用自己的成员方法setupViewServer来把ViewServer装备好,那么我们这里先看下这种方法:
39 private void setupViewServer() {
40 DeviceBridge.setupDeviceForward(mDevice);
41 if (!DeviceBridge.isViewServerRunning(mDevice)) {
42 if (!DeviceBridge.startViewServer(mDevice)) {
43 // TODO: Get rid of this delay.
44 try {
45 Thread.sleep(2000);
46 } catch (InterruptedException e) {
47 }
48 if (!DeviceBridge.startViewServer(mDevice)) {
49 Log.e(TAG, "Unable to debug device " + mDevice);
50 throw new RuntimeException("Could not connect to the view server");
51 }
52 return;
53 }
54 }
55 DeviceBridge.loadViewServerInfo(mDevice);
56 }
代码14-4-1 HierarchyViewer-setupViewServer
从以上代码中我们能够看到该方法去装备ViewServer主要做的事情有例如以下几点:
- 40行:设置本地port到目标机器端ViewServer监听port的port转发
- 41-54行:确定ViewServer线程是否已经启动,没有的话就启动它。
- 55行:获取ViewServer的版本号以及其支持的协议版本号
本小节我们先描写叙述第一点,看HierarchyViewer是怎样设置本地port到目标机器端ViewServer监听port的port转发的。在第13章第2小节我们也手动做过这个事情,当时发送的命令是:
adb forward tcp:4939 tcp:4939
那么HierarchyViewer是不是也是通过代码做同样的事情呢?那么我们带着这个疑问来进入深入的代码分析。我们进入setupDeviceForward这种方法:
110 /**
111 * Sets up a just-connected device to work with the view server.
112 * <p/>
113 * This starts a port forwarding between a local port and a port on the
114 * device.
115 *
116 * @param device
117 */
118 public static void setupDeviceForward(IDevice device) {
119 synchronized (sDevicePortMap) {
120 if (device.getState() == IDevice.DeviceState.ONLINE) {
121 int localPort = sNextLocalPort++;
122 try {
123 device.createForward(localPort, DEFAULT_SERVER_PORT);
124 sDevicePortMap.put(device, localPort);
125 } catch (TimeoutException e) {
126 Log.e(TAG, "Timeout setting up port forwarding for " + device);
127 } catch (AdbCommandRejectedException e) {
128 Log.e(TAG, String.format("Adb rejected forward command for device %1$s: %2$s",
129 device, e.getMessage()));
130 } catch (IOException e) {
131 Log.e(TAG, String.format("Failed to create forward for device %1$s: %2$s",
132 device, e.getMessage()));
133 }
134 }
135 }
136 }
代码14-4-2 DeviceBridge - setupDeviceForward
这个处理port转发的方法主要分3步走:
- 第1步:获得本地ViewServer转发port号
- 第2步:通过Device类发送adb命令创建本地到ViewServerport转发
- 第3步:把本地port号和相应的设备序列号保存起来以便查找
我们先看第1步,就是121行,这里要注意”sNextLocalPort”这个变量。事实上它是个静态变量:
private static int sNextLocalPort = 4939;
代码14-4-3 DeviceBridge - sNextLocalPort
所以代码14-4-2中121行所代表的意思是:
- 第一个建立的ViewServerport转发的本地port是4939
- 下一个建立的ViewServerport转发的本地port是在4939的基础自添加1
注意这里自添加的写法是”sNextLocalPort ++”。假设反过来写成”++sNextLocalPort”, 那么第一个本地port就会变成4940了。这些都是Java的基本的语法了,这里以防我们做測试的没有太多编程经验,所以指出来。
好我们继续分析第2步port转发相应代码, 这种方法传入的參数就是HierarchyViewer的成员变量mDevice,依据本章第3小节的描写叙述,这个变量是ddmlib中的Device类的一个实例,所以以上调用”device.createForward”方法实际上调用的就是Device的createForward方法:
644 @Override
645 public void createForward(int localPort, int remotePort)
646 throws TimeoutException, AdbCommandRejectedException, IOException {
647 AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this,
648 String.format("tcp:%d", localPort), //$NON-NLS-1$
649 String.format("tcp:%d", remotePort)); //$NON-NLS-1$
650 }
代码14-4-3 Device - createForward
像第10章《MonkeyDevice实现原理基础》所描写叙述的那样。Device终于直接调用AdbHelper静态类的createForward方法来设置port转发:
549 public static void createForward(InetSocketAddress adbSockAddr, Device device,
550 String localPortSpec, String remotePortSpec)
551 throws TimeoutException, AdbCommandRejectedException, IOException {
552
553 SocketChannel adbChan = null;
554 try {
555 adbChan = SocketChannel.open(adbSockAddr);
556 adbChan.configureBlocking(false);
557
558 byte[] request = formAdbRequest(String.format(
559 "host-serial:%1$s:forward:%2$s;%3$s", //$NON-NLS-1$
560 device.getSerialNumber(), localPortSpec, remotePortSpec));
561
562 write(adbChan, request);
563
564 AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
565 if (!resp.okay) {
566 Log.w("create-forward", "Error creating forward: " + resp.message);
567 throw new AdbCommandRejectedException(resp.message);
568 }
569 } finally {
570 if (adbChan != null) {
571 adbChan.close();
572 }
573 }
574 }
代码14-4-4 AdbHelper - createForward
formAdbRequest我们在之前已经分析过。做的事情就是组建好ADB协议的命令以待发送给ADB服务器,在我们558行中终于组建好的ADB协议命令将会例如以下:
“host-serial:xxx:forward:localPortSpec;remotePortSpec”
当中xxx就是代表目标设备的序列号,能够通过”adb devices -l”获得:
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgYAAAAzCAYAAADsF8CXAAAgAElEQVR4AeydB3xV5fn4v3fk3tzsTQYJkEHCCoQ9FHCPCq5qrdba2p+ttlartlVb96oibquALJUlG2QTIANCBiMkJISQkL1vbpK79/l/zklAAqlV+2v/P+25n09yzzn3fd/zvt/nPed93vU8CkEQBOSPTEAmIBOQCcgEZAIyAUApU5AJyARkAjIBmYBMQCZwjsD/mmJgNxvp7jLj9Z5L+h9/e91WLE73AAEEHHYrLo8Agger2Yb3G45neN0uTEYjRpMZp+cbZKLv7l6nA7vdOUBeLrgkeLGKaRuNWK3/JOwF0f6vHtrOyeqfsPV6PLjdnu9UDK9LlLFHkqPZYvnGaXhcVqyub3dPSYYO1ze+x78S0G4x0W0w8i2q2L9yOzmuTEAmIBP4jxO4RDHwetw4HI7exlnKjoB4zel0nm+kBcGL2+3Ceb5x91J+YBOvPbOGlq6vGnxBSuureGJyYjrt5ZtZc6Syt7CCgFO6nxcEB1lfLuVIbRf2rho+XbiZFpMbweuRwjgvaqRcTidOpwuxfeuoOMZnCxax7POVHDzZcD6vLqcDp/sCRcHrldI6d6n92GFyco8hhnB7Bm6QnMZm1r//AUuXLmXdpkOY7L1lFLxePG6RTW8eQEC8n6tfqyHguUhb8rhcOBz9uXjFfDmdFzTEAk4xrYvKfGEN+UeyclwoK+8Astq3gb898wWt3V+V92JZeZx2asvKOH60DKvjK5leeH+pvC4njvPl7/1VLEdD2XrWn2jAbWlhxep12KSyXSCH/gkhpiXGqy1Zy4aSpt5fhT5ZiYqiGOICLVFk33eR1uIi8o9USPWg9yJIdcN1Ti7gFZn3y2evrMQ6/E/0o3NJSt/Vh3bw1vOLqWm297sun8gEZAIygR8KgUsUg46G0+Tm5lJ4ug6nR8Bp6aGy7CTZhwqpau6WGlBDQy2lx4+TnX8Cg1XsqSlJmpRBVVkXre0OiY3X7aSptJjc3INUtxilhtpq1pN3KJ+9O/dytN4AeDG11pGfk8uR8gYcLhf7P36MNXv2kJO7jd8/9T4dZi+WziZyc3PIKa7A3KeM2K0GjuQf4mDRMSwuL2eKjtPYrGBEnJH5b3xKhwVsZj3HsnM4eOL0+d5rR/0ZcnJzKKlvxy2ApeEE1TUVOC1mSiobsQ3Qdlnaq9ixeTeJo1M4smUhX+aISo1Aa20dJWXF5B46jsUlYO1qozA7h0NlNVhdvQnZe/ScOlWDo6/18TpslBfkkZt7mJZOq8TKae2h9nQlh/IOU1pRL7aAWLvbyMvJoehkJfYB8iRGbK/vlVVRZZ+szN1UnjxJzqFCqlt6emXVWEtpsSirEgy2XlklT86g8mQX7R29svK4nTSWHu+VVWuvrGoObef1Z5/hlZdeILusZcD67nVYOFGUR87Bw9R19ZbF0tPGwdw89m7fS3GTEcHew4mN2RzML+TYicYLFM7+SZq728jJPszuHZmUNJulkYbuumoO5uZSXNWK2y3Q1tqEwSKWwU3DmUZsbnBaujjb2oM2MACFlKSA1djO4UM5HD5WKoVxO21UH8knJ7eQlu7eBt2qb6UoK5dDBWVY/5He0z+L0ll8xjgsBgd1DbJiMAAe+ZJMQCbwAyCg7l8GL6eP5rH94ElalFZ++8jbjDTk8+bf1hKSGoMx5wwv/fFn5C58j11GHYEaO/kNd/LMPdMJjo4jLCYYRV//q/F0EQvnL8QWGYJpRyOvP38bO1d+QmaFEXfhGeJ+pwZbO0vnzaPOo6XdGcb/3HcXI8aO4mjTcbLPGBmaNBgUHtqrS9ix7QCtrkYq7niFh2cNZs8X77L9pJvIkBCGjExHq9NgcrTR0QU6nzA0Sjc7Fi2ioLIDg85C1dyn+OVYNYveeJfuQC1t2Xk89fAzBAb54m0zsG31Go5Y43k6MQ67pQd3X6/fR+OLx6sgeFA0Y8dOpj51HyZzD+Di05dfoyw+kQSvluSMNHI//pCTrXbaNDaafvwk90xNoP3EAV59L5u3Vv+dWA20F+zn7++tJDAxFZ9BqcRF+NFVfYzn/7qUwFGJpI+YxojBKtZ+9gFFtSpiE0eSlJyMb4BPf1Hh5fSRQ2zPO0mLys7Dj7zFcH0e897YQGhKDKbcal76491kL3iXPWZ/AtR2Chvu5C/3TCM4Jo5QUVZ9606bKvJZ8OYS7FFBmLY38trLd1O4aQvJ067mltSRjE4Iu+jevaf2nnYO7N5JQ0cDztM38+6vb2X10gXk1TqxHTpL6kgFPmolzs4KdhzYT0+NlweefoRpqRenZ+XTBR9wrBWMOTVMmKjG2V3Pgjf+RptvEJ22Y/z5jw9QkbMGS/y1/HSChg8X7eWPrzyMn7WLol27CL3Kn2npw/DaOti84m1yq2DQoFhSRo2h8/gOPvt4K67wYHYd7OG152+kYOF7LK4wkpQylmHpo/EPVl1URgGLqQervXeKQqFUERIWRlBkNFGDI1BeHPyi2PKpTEAmIBP4vhLoP2LgstDtDGD8lEmEGqvIL+3A7nAyJG0Wb738Cp7TxZQ1tmPQw5w7H+Tdv/6U3HU7MEml9+ANciOoe7vGZQUHOGIPZ+bMSaAvpcPUzK7dAn96+jVef2kOCp0P9o7TfJ5bS/rlM0gL7KSqphpd8ESuSAnFb/BlTJuQgMtupq1HQfrESaSH9LB7XxkeSyO7Nx7lz2+8xivP/omhQVocTg9h4ZEkDRuJ1qTHaqxn3W4HD857m5fuuoKdnxXR1nyK44ZJvDnvXaaqBfKOteEXrmPX6uUs3X6Y+38ym2BHKwvffY2//vWv0t+ClevxaALoOV3CSy8+Tz2jufmaCZJiYOpS8vvfPc6rrzxOvLKV9dm+PPXefB67Kp0tnx2VqESOmsHTf/kN4X3tuldhRJc2iqlXTiHEr7faWM0OwgOSeP9vL/Lgz6+nvfIIhw+18cZbr/OX391LhN8ArZDLRLcrgAlTJhPcLcpKj93qYljabN565RWcp45R3qTH0AFz73qId/96J9nrd2KWbilAsBtvX55KDmdz1BkmyUrQF9NmdnHVbx7EVpLHwk82k3P4zIDD7V1GC5EJo5mUMZgj2QWYTa3s3avlhZdf4eXnbsSjUuB2uwmMS+PN557jqvE+7DtU1lvoC/+72sjMCuL1N17h+b9ejVOhwtRQzBdHDEydeRnxPg1U603MGBdHcVERWRuyCUgYTJivgoCoZG67KhmPuVlKsavhFDmZ1bz41uu88OTvifH3sn9HJk1hqVw2NZWehkJMXnDrbMRPnsHkqcn4CAMMGXjt7Nuw+Hw9eG3+OzSZxLot4A1wIai/moa5sCjysUxAJiAT+L4T6Ddi4DaeYcmKo/ztw4foPLkPj9eDSinQ3dlCY0s9Kk8QQWotaoWDxoZ66vy7CdEOord98SdWqOPs2SpGxI9GHRDHyDHDmDJtNiMzriJ5sIbQ4G4a6s+ib2lG7e8BdSDxwyYybdo0NBMn4u+vYvuR5cy4/Y/cqjNw708KUdPNwqX7uPnRB4h2jqSoSoHCx4/wQTrOVDcSEKjGPyIchUJDVHgESakZRGgKsHsVBIXbqK9pQNuiJywmGY1vAAp1K81tTRjdHpKCfHCaHVxx5z2EeNv5YksWf/zV1Tz65IvSNIPYo1b6aDHXHSZyzESe+eAjBvWOVwN2fLXRROl6G22l1g+/YBNna5tp0RuJiEmW6oa9s468Q1UkjEtHq4LQjBv4XWQtWz5/mwM1Vj787W14FT6EB0ZzThgBAaEEhEBlYzuRSi/hEZH4aftXNVdPFUtWHuf1Dx+kvSQTheBBpYauzlYaW+pQeUVZaVAp7ZKsajR6grVR52UV4xFldYbU2NH4BMYyakwyU6bNlGQ1NEpNlzCUGx74PUOOHWbzhjzumDMOTb8sCOTv20dZZwKPzpnKiqxjeJVaQsMM1NbVY2trQh3tRalU47Z6qW5qprvTTXh0QL9UpBMxXnAnZ2uaaGttxSfFi9cnlMTkyUyZNp2JYycSERNDsM+1BL70NPOVGp58/nnUCnBau2kzm+ix+NJtNOGrCyI4TEVlbQtuLYRHhaILHUZGSgZTZ49g3Ew1oUqBST97goiaKt5562XaQ1Zy/+TY/vlS+HLdXQ9xxe0CClHmCiVanXjgS6TSSH3NaSxpE/H360+lfyLymUxAJiAT+P4RUL3wwgsvnMu2QqPFUZ/D5j05WPx8GTv1GoYIrXzy8QpKzp5m1Iw53DRrBCU7NrHp8GFKy7u5+6FfMCI+CNCQEGli+fJNaCNHMHPmGEoLNrN9eyZ57V5mTJ7MiBgDyz/9nKKTLUyYdSMTRqbiJ1Ty6ecbOHyiiphR4wi1tBE9fhZBPh4qKzoYO2My8d4KNu3MpMNuJnb8bK5ITyMm0s3KhZ+z/2g1QydOJU5oZePWTWQfPkHa7Fu4cno6Q6N6WPTJckpOa/jt43eTNDgWu/4gK774Ep/Qqfzizsl4OprxRqRw29zbyNz2BVFpk4mPCESr0aDRavFRq/DYjbS2Ghk/+zK+ap/dNJ5uJmV6OoEaJagDGBTQxIJFK6ltCePhx+8gMkCNoTaXNetPMXPOVQSoobsqlwWL1tDWHcyPfnQzKYNDsBt76DZC+tRUSRS6sFiC1W0sWbSOnFoL4yeMJUTbf3BH4aPFXpfNlr25WP39GDf1GuI9TSxeuJKS6tOMuXwuP7o8jRPbRFnlc7K8m3t/+wtSz8uqm6XLN6Eb1CurE/mb2LE9k8MdMGvKGNpKc3h/wVJKq1X8+rGfkTJYnCa68KMgSG0iP3MbhafK0Q0fx3WXXcbwyFYWL1lJcUUH066+mTHx/hTt+JLtBUV4dIn86hc34n9RWVD6ExPcwKIlqzhZ3cNl19xERloyHtMRVq3ZSt6pRpIzJhEdGESIsoo6RwS/+tmVkpJzctcCFu44QX1DE61GOzNmX0VUgJFPF6wh62QTIyZOZ8rocHZuWcWB/TmUecK4emwiJ7Z9zKfbjhAUPJlbb55NhN85tayvjAoFarUGrVaDRqwLGh9UEgA1cYMEPv90Fd7AZEYmRV4IRT6WCcgEZALfewKKgQwcOV0eND69PeETWdvZd9LGow//mN4rAvMee46J997H7IwklFJ36h9xEHA5nKg12t5el7hszOlEqdH0M6DgdjpQKH1Qqfs3fhem6nS58fFR92ucxB0BXoUKn9439oXBzx97XQ4Etbbvpd57WdwFITb6/46PuHUOHy3K/q1ov1u5xdXyYr6/prxiBJfLhVJ9rkHql8T5kwtldWz/VrLLXTzy8O19svLy+qPPM+X+XzIrfdi3llVHXT09NiXJaYPP3+/iA3FUSRBUqC+Y7RB3BKgulrHLicJH05evi1PpPRfjqTWafjKW6oY08vE1QAdITpzCQCHm61w8cWeLB432qx6+uAtCvN8/rnUDJCxfkgnIBGQCP3ACAyoGF5bZ2NNOh9lNUtxXQ63VZysIioonMsD/wqDy8f9nAsbuNvQWD4kXyqq6gqBBCUQG9C1o+BZ59Ho90m4SteqCVv9bxJeDygRkAjIBmcD3j8AlioEg7uVXqfr12sRiuR0OlFrt1/auxKVZ5/pn3waF2+3E6fKi1WpRfU1XW/C4cCOOEHzzPp64P1+0WSCONvwnPgICiosofFsuot0G0RaCxufinQgDl0DcbigoNfyTAYiBI8tXZQIyAZmATEAmcAGBi1pYgdaqEsyu3p0FX4VzU5lfQOc/2lAPeBxWurp67Rx8Fe+bHHk5efQQ63dk0txp+9oI3c1F5Nd0fG2Yi3801ddw6nSdtKf/4t/+t89F2w1dHZ3SwsVzaTtM3fSYevf4n7v2z74N+jryio4PuBNgoLh1VYc480/YDRRPviYTkAnIBGQCMoGLCVykGDg58NGLVBn7b9+ymXuoOX4SY++WbsR59G69Hn2HAYdoJUjw0FhwkA0rttDa0y310C++kXguWtPr6min3dCFQ7Jm58XSU88rLy4js6gKs2PgLWAuh5X2Dj0nD37GyuJaKWmHxUSnXo+hxyoNd9ttFuyiCV4EzEaLZLJW8Lpor6mmpq7tvGLgdlrR6zvQG7qkfIq9c7PBgF5vwCxazBFHR+xWDB0d6Dt7/mFZxNGLLkMn+k5Dnwlfgc7TpWx8bwF1XV043QKC20n5lxvZuisPo8kkNfTiNUOnHr3hXDzwehxSWh16PXaXh5aKElZ9sh69Xk+3qVdZEpUOoxivsxtbHyebxUh7Rwf7M5dyqPnrlSqpYPI/mYBMQCYgE5AJ/BMCl4yvC0rlRQPhDg7v3kNJm5mxfUP4bUX7eW/RWox+Cdz3xyeYMsjEio8+ZEeDmy51J3fc+TDDwr9a5NWbB4FTh3eyevk26sPC+Mkvn+CmNB2Zn39CdV0T10yfifciNaU3nofDmetYsvkYxuIyxjztC04jmUs/Yu+pejzRU3ny13dQUbgJa9R0bpoQzGcff8mcB+8lwlXLtt2Hib96Tu9WQK+DEwfX88m6QnzDYvjDn/5EgKmS1W9+xCmXlrQZd/PQzyZRvXMDf9+QhTJyJL9/9hGSwy4d0je1nOaddxfS6nAz+SeP8KtpcWxcvIDPth2hIULBrT9+lETPGRZ88DFVsWk4nfXcedf9CM2nmP/uJ7R7BGb+9BF+PjWVpvJ9fLgiC5PVzY8fepKRgVqoKeXZ518mNGU2zzxyC23FOWxYuJYzvpFcdt19/OyGODas+IgDR1qpK2vj0asHhPdPxC//LBOQCcgEZAIygf4EBmxN+k/za5l10w3ENhzE0OfcpunQLkxDJ/LAQz8mLlgBAXH88sGfc+c1l/HrB/5AQuilDSmYWfj+Xmb87iVevDWWhQt2I6iDmfvrXzNy+C3cdedPGBEzwB53wcBHnxzhN08/yx9/kiHl3tZ6nHkrdjNz7i341R5kT0EDUQFWcg8f4GxBPmXdVgJ9VegiUvhRRgQdFScQxxLsXWdZvmgl9/zlNV7+44NE+sLeL5Zy0B7OrT8aw55P19HhgrO5u/CdMZdf/8/1BPlcPK3SC9Ah6Jhx1VyuGqNg+RebcKiCuOvB+7nzstE88NunGBPjT9CQDH57/8389Obb+Pld9xGoArvXj5nX3MKVaW6WrN2JgINV779N3A0P8c4bLzAmSodDHBGIGMnLL/2e2qYTVLWbWfLB+5yNHsNNkwPYsHQLPYbTrNxs4I23XuTu6fF9IzD9hSufyQRkAjIBmYBM4NsSuFQx8Ao4nBZ6enqwOpyS3X6HS4E6UoXHbZZs3af96jHuvno4qxe9zOo+S3a+ITq8gQIeqzifPtASRAcmRRRBgX4ERaSg7nFLjbVCIy6a88VP6zPwdjrBiUYRQ6ivmqARoYgr7FzitrOIGaQkDuGu3/2aay+PIX36tXCkmjeW5jBl2uWEaMWtkVY0QWrQebFZrXgddlRCMJGBAl6VFo0GjM5wEpMySEiZyovzfkaoSmDqn57l+iQlH7zzHPsq2gZg6mHnpi85Xu8gcegYtD1qaV2B1l+HKlqBx2Y9P3XhF+mLU+PFIXlwdLJt/RYqWj0kDhmJtluFR3DjNOkYOjgE0VeRf5AfDreWwZHDiQwfQmhbLO7WboyK4aQljyRl4k28+NJtqF02/H3iEQ1NBqUFyd7+BpCSfEkmIBOQCcgEvj2BixQDJSpfN+sWLWDpJ4vIOnoSp93AnnWLyDqjZ8PiZZztNNNVd4rSk6fRuv0I0vlKdw1ISMLR3sgnKzbSaupbjNAvP+Fce52WtZ+9z3sL9nLFbZP6LP0pCIrXofIZSJkQ/TNFMntWD0sXf8TiFTmEapT4DhrOpLFmdu3eS1bRSQwOBfgO5brUHkrrW5l95Rjpzs0lmazYXcDhQ4f5ck8W6ogkpl+ZwCfvf8KSFeup7fIy+YoxGDsL2Lv3ALk1XZKlx9ZTxymvrCNQGYLvBfvevyqOl6ggLfqqcgqPFKEb5CvZLdCGxRAU5M/iBSupbO9dcBg1aix1eftYs+MANkFgUIgvTZUnKTpa3BfPn6vvvIwvl81n2bIVZFW04eenIyBAJzmZCoz2Q6EL4fobh1Jdkc2+fQcobDbhF5bM2FEn+PCTRWzfV0nkQGaTv8qwfCQTkAnIBGQCMoFvROCS7YrdrdXUSt4QBcKi44mPDODs6VPYFL54HHYSUkfh72inrLIJryaS9NFJnGs7uxpqqTdYSEwbQeDF1u3E7Hgdkqc/G5FMyEjqMzrkolVvIzQkEK1o43agj8vE0eNlKLRBDE1KIixAi83YQUn5GRS+IaSMSCVUq8Jl76G9y01cTLiUirG1iuo2q3QfH50/w1OSUDmNlJacwqoOIm1EKsFaJbVV5bS296CLTSR96CBMLWcor9PjG5BA+qi4AY0Vee0GSk5WgS6AsEGDGRwRJG3ltOrbOdPQTGzySCIDe9dZNJ8up1PQkpaahMrRyYnSapT+ffHCg1Dgoq68hBazksGpI4nWeujpcRE+KIi2TiOBgUH4aQQqyk7QbXQQPCSVEbGh2I1tFJfX4hcSSUriUHSiBUb5IxOQCcgEZAIygX+BwCWKwb+QlhxVJiATkAnIBGQCMoHvOQG5i/k9F6CU/T73yd+qKIJoiuk/8xG+S/7+M1n7z9/l38DiP8H3P3GPi4Xxdah6rXL+p2rwxTm78FygXz77PVeXPmOC4MXr9V6YwA/iuB+Db1iif2ed+nem/Q2L970O1s+JEl4nXUYnOl8fnDYrVocHr91EV48Ro9GC3W5DUGvwWEzoO7uwOFz4aLWolQqc4t5/gwGlj+95y4Qeh5nObjM6Px14XHQbDBhNZiwWK3anC7VaQWenAYvFLvk80IrWCQUPxq4uDD0mKS2NWom1y0CXyYTVasXH10+yjmg399DRacAlqNBpffB6nBj0HXT1WFBpfBHjOWwm9O0dmEWrir6+/fwlfK+ldlHmjd0tWAUdOp9vrueZ9e3YBDW+mkt2rF6U+r926nHbaG7TExAYOOCS1HOpu0UbF10G3IIK7QV5spp7MFo8+Ok0CF43pp5uTFY7Op1OSs/tsNLZocfqEvD17fVRYTV299qpUKjRaXzA66arU0+P2YZKo5Xqp9tuoVPfeUE8AWtPN/qubjxKn38bF9O3lZXXg9PpRnWhM4pz0Pq+21qbQeuP5kKLoB43TrcH1f+GOWuvC0NrO+qAwP/YMyQ4e2jushHkL6616f8RPE5azlbTbvAQHj7ATiYpuCDZJzF0m7DYHfj46qT3VP+U/vUzt7mDdquXQF2v7xXxubKjwVejwmzsosfixL9vHZZ4N6uhjbNnG1HrgtBpv/mz57CZpXputNhRa756x15YAtHWiWgjpbvHhFeqwyq6u7owmc2YjSZcSo003Wizmunq6jn/LhWfj24x3gXPx4Xp/rNjwdFDc7eNIPE9/w0/XqcNQ5cJjb/ua63pfsPkLgom0NXSisIvULYGexGZb3raTzFw6k/w9DsnufHKFAr3bmBTvgF32Ube+WQ5Hy/YzImTBbhihtO6bQUfrN3Ixp25BA6fSGqUmtw9m3jxmefwS51B2uDeOf4ze5fy6CurmHnzjWjbK/ng1Vf4eNkqNmzNprSpkbhBGp743fMczDlGi1PF6FHJeLtqee+5l/l8007a/YcwJTWWjX95inc2biMvL48hGZcT7edhx0fv8faK1WSdsTBrxji6zuTx3Cvz2L8ni87goUxIjGDXFx8zf9FaMvNPMGTsJOKC/j2Ok74p7P/tcKIpZLPZStaulyj1mc7YKB1umxWzzQ4qH+mhEBsVpVKFQiHgdPQ2MF63i/K1q6jWRpMYEyJlS3ypmMwWyaCTRlLQvNjMZmwuLz4+PuedYF1YBq/Hg2inSqkUHT55UIoNk9fTG8/hlhwUmfWnefnVxcy8fCpuj+K8cy6Py4nT7UUtNXgCZYVZvPHqCzS4Q5mantKbJ5eDdYv+xicbmpl7YwaGxkoWfDSfdVtymTXnOnwRKNvxBa++vYD1eRWMmTqVSJWN9e/M4++r11DYrGDW1NHYak8w79lXWbX9AMSNZkx8KMc2fc5r7y1mc2E146ZNIcxrZM1b8/ho9TqOdqi5fOJIBtKzXA47doddMmAlcRINd7lcOF1OrFY7Ssnhk4DNZMYmls9H3G0jhnFgttjYt+slyjSXMSbCB49HQKlU4nKJMlJKjJ12GxarDZRqSX49VeXkHa8iOjZC8vYo+iwTZeVwnWPnZf6zzxGQOpZgtRq1xgclHgwVJRwureuL1ys/kbnZYpFk5qO+tFHyetyIO5JVKgVet1va6SLK1tHdwb4VmwidNIlApReHy4NalLXgPa+0iMbLzBYrHoX6fMfgwroihrVYzIjO0NxOF27J+ZkSt8OOWdwxpDwXz4vFbMFWt4OXcuu5Nn0kCq8bq8mMuItXZO51Wcj59H3e+KCTW+8df95ducvpwC16c5cUJBvr3niVp1//hOwTZxg++TJi/FWI8rNY7QioUffZEHc6epmLjs3EuJJJcqdTkoOASgrnslmxnH+uFFIHRnxe2oo/4J1yf64bkYDH7aJszUrO+seROCiY/D0b2FvcyMjEeBRKtcS19VQ+rz/xMe6IqaSPEL3SgrdPLm5BiWZABdBN5uZlzPv75xzM2Yf/sMkkRwf2wyue1J/K47lX55Obk0WLJ5zJI8L4+L15rN24jTUfLqQ6eCJXpOjYvmEFr782n8RZcxkcpMVYV8obz77Gqm2ZeGJGkD4kQnqOReb2PuYDr/46J6ttvHSwievTR4DHjdVsRrQ1J5qhF981bq9C6syJz4mgUErPg6nmNPsOHCdhbFqfx1ovVosFm8OBykcj7VBz222YrXZQ+px3hibKz4NSSk/sKLjcAiqVErHuSs+TSonTbiFnyQq0GVMJ1QhSHVVKZv4veAeeY84/Yn4J3v+qC/26mILXRt2ZFrq6umhvrKepzchl9z3J60/fT1jIzcyf/za3jUsg7pqbeUKJmvwAACAASURBVP2dD/htqpc1uwpBsFNeZ2S4vxK3zdQL0Gtjx64yuvXt5B1sRhubyiN/e4vbr7qeWVc9xrynHiXOx4LK9zbeeO1XHN+7kqxyPaX7MzFGTuUXNwxnwXurMHs9NHQouP3eB/nzE0+ROigQc0sFmzJb+dNj93P8i08pPGsgN/MgMeN/xfznb2P35j2YbHqWr67i8Zfe5v5xdj5Zd/yHJVjBTdnRHJYsXcmXe9rwV4ovWStHt29m6bJlZBbU4HLbyCs4SrvFjdfaxuGsE4i2HTubq6jwBhIbFSoxEdx2KkvyWL50GVuzCnAgYGw9y65lS1i8ehsVjX0yvYhgR81ZKs+0ihYiKCisxOoCY20F6xcvYfnn22kxutEqFKgqa1m+di0bNhaet25ZezyHXdklfds6XZyubCA0NBJfU0fvNcFL84ksDuSUoWzrkba2tjfUY/aJYqijFZs4iuztYcknWdzxxOPoyvexaGsZXWePseeoi8cf+jGZS5dQ0Wkma9NOwqbfzs2jtLz70Vbcrh6WL8/jZ39+HO/RHSzbVUl7ZSFZJxX84YEfsXvRUio6nBeVVjx1cHTPTtZu2sjnm7Mw2Hp335wpKmLnrl0sXbqas20mTG21bP98GYvXbqWywwKCm1JJVivYvqeNALUCc0sTp041Ak6Kik7TZfbgtHZyaP8Oli1bRn5FA4LDwPoPP2DBx0v5cv9u9OZey6DNZQVszyzk3N6fsE4bh/dsY/HCdZxps+KxdPDFu++xcMEydu3fjcEm4HXZqCjOZenSZWzLOcZApTO2V5NzrFKaYqo9WULl2c7e/BUeg8ThBInmSZxd5OYdw+oRsOhrKTh0GrEHfzJ3L8uWLmFL4Unsl5hUB6+1gxUrl/PZytVsXrGWPYVncbsdlGaJ3JbyZeEpnGKanU2sXrOGBcuysRgElAi0nS5m0+IlfLrpAE2ddlTaIG564D5UWj8uHJUvz9nN/sIzfXLTcceTj5AYdQX33fMI46J1mDsayN69i88+W8WeQxXSFmOX1UD+gV0S80NlvVZVja117NudyfLPV5JXfFZqaI5u28jSpcvZX1iD2+Olva6cTz9bzZLPy8De+xrVN1RyRhFEbESwlIdAp4fGvHyWLltDdkG9pHQnTLiSq+bOpqvLIYURrbOePZLLyqVL+WLXEcnIWV8BvvoSRHf1edz9yF95/ZVnSI0aaJTEy77tewhPvYk33niNaycOR8CfXz/8FPPnv8y4sEBGDI/Ea+vkVLub4RoHFnE7OgKZ67cTPGEOt44L4O0PN+IUvLRXlbDpkyUsW7+PBv3AVlVN+kZWrV7Dx0tzsXaJm9S9tJ0+zqbFS1m+KYvWbjvt9RXkl9RLO6wqjxXT2GYFt4mC4kqCExPPu7EX69LmtWtYtmItDQZr77ts2ybpXba3sBqnVKe8FB/YRdGpJomNo6uBrIJy6X3RVn2Kk6fEd5GH0oICLIOTCBHXfrtMHDx8FIPVg8fUTH52qbRFvOpINp8tXcranGNYnT+8qZ2vKs93O+qnGCiVPvS07uD9j/7O+jW70ap80fr4EBQaiE4bREhQAFrfANJHjSRIYaTM4GWa6JJXGcJvf/sgcycMwaPoNSvsairnBEP5n7uuozxrGy6FCv+AYALEFfZ+4jCaOAWhxEflx6CEMdwydTQlBSXUO/zx0Wgpr6jD3y3Q2GkhITWE3RuX89LT88kq68Ru68IUOZbSfZnEJA+jqrSOYF00XrONRqODjiIjFpuHWM0gOjraaDep6SjQfzdC/0djubpP8/K8taSlpxFucKBRq6kt2sR7q3YTFqrmo5cWUdnsJG/rx2SW1VKTtZ4v8mulYTv/kEicOZsprRIfWOg6k83by9cTP2YSMaIXRsHOh688y6FmB8q2Al59YaPUMF+MoqLoMNnZJwELi987RIcVihe/R06rh7TkQYhvbYXCQ7etnbjkZCqPbGLzwd571h/eT052fp9i4MOP77ufR380BaWvV2qYbD2NLNp6iJt+83uGBYDb7WXE9Gt59Xf3EB2hlBQc3AaagsdiKM7DNz6B5iOVtNrs2MLTOJGbR3zSEOpKz1LnDUcwdXOm2QQGEx09bbSHZNB5LBe/hKHU55fTbPNgCxtOyaEi4hLjqD3TcnFxpXKufX8Z1pAhuBpzWL6jXApzaMUy1hQ2M27ccHRaF0ve/Ih6IYYk1VFe/ngnTlMVr7y5jrT0EYR32tH6qGg+fZzMPaKy6uKzDw/S0ClwbP1rrCpqYdKkDLSi22iVH8kjhjI0NoKUlBH49m3pbT6aw4E9ub0MxKZT6MLkG0uM6hDzdhxHqQkgZeQQhg2OJCllJDof0Jft4p2VX5I8bhKD/DTSCM/FBXTbO/ls8VvoTVa2f/E5lUYxhIqYIA0Vaz+jS3x/qtTsWDWf/EYTpdtW8WWlEWP9Ud77aBfpGWnkbvo7Wae6L04ae+sJdrXoKSuto/Kslfovc6mtPsqHi/eRMS6JfRs+orihh82rP6PGGkhacDA+Fg9KTxcvP/s8dYI/LQXbmP9ujpS2gBelP/12DJXv3Up+kVgfxY8CjS4QX79ggsUpEKUCfeVRVq7LZ3hKKMt2buCszUPx5jf47HAdEyaNx0/oVbz0pwp5/9M9xKaNIjxUR0nWet5fk0lYmIIPX1rM2ZYO5r+5CHdYAkMEBSqpgYWAsCisBzZQdra34VKrzLQ5PIwdO4iFiz6nSm+Xcub1EVD2DV7aWkt47vnXEYJDyF/3ORv2VPdmv9//QK5IT2T3lq3sOFgKA+7eUpAxYiStp46weksmBptTcjsuvm+9dcXUJ83gxtExqEITefrxR7g8LYxe/c1JgzMEbBbONPag7rZhMHfy+rPPUO3RoT+xgzfnZ/XLTe+Jh7WffUqdM5i00CBJVgpPFy89+zz1+NGc/yXvvJeP1VjN8s8X0NXZwvo1a2gV9SGllnCMFO/agUREsLPq/aep8Yln0uhkcLmpLNzCe6t2ERbqw8cvLaS4RqyMXkp3bKDkdJ2UBQUOVi95nXqznf1rP6NYL7Y9SgYNCqVm/XIk3V6lIWvj+xw43UT1vvV8cawFd/cZ3nxzHcMz0qnY/wkbC0SFQv5cSKCfYiAOx4QG/IjHHn+cO+++AbfQ2ycRvAJecdFMX0xrTyvbFr9Ledzl3H5NunRVjGtxOHC7BTweL2ePl2IozaeqspSc0tM0W8WHTsDjFdM5l5LYdrix2Sz0dLvw14UQGGxm+9bdRN3+P6SLW/KsCm7589P8/YP3uP9GK0s25+Mb6EtVyVbODL6Sm2aNw+3Sctns8fi7TpGZVUyPDygDYrn/jgSOFORysLQZTcRA1hgvRPH9OvZY9Lid05k9fSrTb0/D7vWgb+nCqB1MUHA4s6+Mlebv7pszhcIvc1n5xVmuuzZDUgy0fkEkDtchCDbcHg/NVXWEBQ7juhkTmDI5Ha3CQnmjGt+ISKITEpkxI7CvEerPSCOoUbkE7DYjVqUVhddL/I2zSIzx42hpPvX6HnEEmYioRK6fMpm0YVHU1fY+1BPvfpgnHv7JeVsW4vCt0WbD4/TgcXloPLGXw0dbqC7JJqu0iNMN4qiFIA1HO1wCHodYN32wG/L48rSKuffMwV+hwT9ASfmRLXSNvYVrJgxHEHzw92tnw84iRv/qQRKD/FEpfTC25rCtxo9b7roenVJLQICXksKt2KbfwdVjhyEMZJ/bK+DrH8+NV0xhSmoy9adqJCBOTxT333ANs2fPJiFcRVl9OGOmX82119+M5aQBk7kDwTVDktW020dgEadnxCFqt4DdbsaisqL1dVN6uJ5pU6czYcIUxo0aisLHj9ETR5OcFsPwoUkE+vY+rqNv/hVP/emXfb0tDy5lItdfPpMb5t6O8VAHCk0A6RNGkJQaR9rQRPx8FNSdqiE6IpWrpk1g8qQx+Plc6ko7Im4Ulw8OZsXn26lrCeLyjEgQlMQnDyUs3IbT6ZSsld577Ti2r9jD9n0d/HjOWAytHZj9ZzFt6hWMDE6m8eylSrjH7SYtbRxTp17GhIlTSElQ0d5mwB54BVOnXU2KbihttY3o24KZmn4d19w1Fb/YQDzWLk53BBMSKW5LTmZ8Ru9zrBDnOLRGrHaH5CtFFMT1f3iOB++55nwldTud0vC+y+3u9afi0jBu1GSuvW4u4V1hWNqclOXVMmH8FCZNmEzG6CQprtmp5cbJs/jxVZczdng8+jY9Zt94goIjmH1lHDpfE/rWJK6YOotr752E0r93W7KvfzBJKeIohl0aVbA5VYwbncG0qVehs7bR0W2WFBalxo0Li6ScWXs6qLHEERwUSMakJOLjL5ULCl/ue/ZxHrp1ApUHN/Dqh73K0fmCSgcKxlx3K6/+5af4Wyt49sVVGBxeaYt45tYcMjKmEartnRAQpyCtDheiTLyCGr8APRt25DPy/t+QEhYE9m4q2oMJiQglKSWZ8RM0AyxUttDZEsi0Mddz7Z1T0cX44bEYON0RQkhkKCkjkxgzVk1i2gRG+7pZ8dkejPZYRg/1l6ZxElPj8fPvq1OebqpOmLjpxplMmDyV+Kgg2pr1GDXiuyyM2VfGEyjNuqiZ++Qr/PjqXgu42vAkbhoTz7qVezhRruTqGUPEVwSDhiUSHe3G4XLgVfjyyzlTyd2Uw+pNNcy5YTwOQxsdiqlcPnUG42PH0nR6oE5Af7r/bWf9FAMUAj7BAQTp/AgMEuew+hpwBSgCzs0yedm94AVe3XSWWcMjqDnTLDHraDhFYXUzxw8XUNfSyfHycibMeYC59/6CRJ9uTpQ19D0USpR9Ng5ELb7beJKdWzZystbMrCvTGREZzpDoQHxP5uJMjSU+QkP+wRz2Z2eTX+Nm+KgY/IPjmB7rQ6y9g4rmWkZNGobvoGgunzaCSJcPc388nkA1RE8czdTkGIbowrnujlE/KNmqA+OIDM9m+7695GSdIEClJHjwMAYP1hESGk3a9MuJCvQhdsZP8c1cQKYmmssyhkkybSzPp/BsKyVHiqisb2HIiFGYXGfYmJnDzoPHsQk6Ro0eTGCIHzGDUxk9ZdL5Ib8LIUYP0nD2zCH27ViPXteMUqPALyqVSSMSMJzMIr+mE19fHzobatiwK5OKSgOjhop5gIIVz/HMi6vOj0RYOus5ePwkJSUnOVbWRNzIK5j/6oOMik8gNDSMsDBfBFsPRYWHOVnTRG5WOTZ1FNcO0RASoOPM4RzSbp5IXHAUE2LUROirOWPsIGXccCbEhBIbFYxQtBe/KclEhsRyxRA1YToNp4/kMWruRIaERDIhWk1Y8ymqbCbSRsRdWNTeY4USW/cpVq/byeEjNYxJTu29rvJDKZx7PgJJG9VDTvYmtqzbzeAJcQQGxBIWeoAd+/ZIsvJXqwgN09FSl0/m7rU0K2rw6jRMvWochwp3k51zgJwTZ6W0fSPDaGk6y+6DR+mx9T6PJZtf56mnFvVNBwiolL6oEPAqNGhcvQ2nb3QUDXWn2XXoGCaHQHL6GPSmMrbuy2X3oRNY3F7EFfLi6u1zf2iCuWLKZFa8/iyRt99DuAqc5jYK8g5S3qQnP+cQXTY3I6+8G/2yZykdOpkJcf74D4pBpdjPvgO7qO7sJGV45CXsFEoVgqAgQueHv8KBW6EgMi4GvJns27+DBksPCcMSGDLMQsHRtWzalImjx4zSN4xRoyLwCwoiPmUMI8f3Gi9T+EWTqi5iw/ZcOk1iN1Rgy7xHeP2DvX33dlFZkEdDSymFx/LosnlRi+tuFL18fDy+uJ0qJl8zniPFe8nKOUDW8SoprgI1KsVXvl4ihiQSF+dLaGgMI6ZfzqCIWJKTq9m7fwtbtmSjcok9VYGGsnyKatsoOVJIdZNoqMyXwvw8MvduRa0ZTFyIOAWgICVWR83R9RwprkUTEk9qWjDBYREkjZ1E0rC48/I4JxfBbSR3535qu2FEYhoBLvVFYUQ5ejhbfJjDJ1tJGJJMrCpQWtNj66wiu76G6ddM6+UieKmvOMLx2jYKDuTS1uVkYkIEg6MCEQr3oZ2YRFRIFGmjotAFBxCfks7oCekDLBwOYGiyhYIjq9m4ORNXjxWlLpyRI3tllTB8LCMzRqDwjeOylAQWfLCAUT+/B3/JNH0DhwuPUF5dS/6Ro9gVoYyfEceGzVvIycrmTHsP4QlJxA3WEdz3LosOFdsjJ2tffJBPN56bFvZhxhXX8eWrf8J73W0M1oLX3kXxoX2UNHWSn5VNu8nG0Jl3o9z+Nll+w5g+MgZtaBzBAYfZsS+Tkrpaho8e4Fm/pAb/d13ot/hQrLTq8GBGJkUhzu6FRseTFB8mEVFHhDAyKVIyxlPZbCAkUIu+qR6r3xAmpkZTV5JLcY8OrcdN2KBhxEWqmX7THNKGxDJa50U1KJ64yCDQQGT8IAZH+iEuCOk0nKCu2c2dv3uQjCGBBMcnoXY3cvy0hfvuu4+UQRoKD+6n8MgJSLyWJ+6ajU4bQlJaBAcPFTBq5s+4dUo8dn0t2zdvp0YTw/888BOidGqai/ezJfs44TNv4hfXZTCALv69lbb4whweq2LX3nz8h4znysumkJKSjLurmtxDRTQTzMQxqfj76IhKCmNsxgzGJkVJc3BlORsod0WjdpjRhsWSPn4qKX5m9h8opE0ZwZSxo7h8QjL5WZmUV1ajSBhFRnzvgtILgYXEDqKh/iQ1LQ4mXTGHySMHYzyTw5a9R9FFXc0vbp9JgK8ah7GTspqzDB4zk5/cNlGSg9NlRBsygvT0BOml011fwv7yDvz9fPEqopg4OZ3o6FjiEwYTE5VA+tgheG16MrPzEcISsHV6GT99HOMmjeBE/gEYfA2P3jEJbUA08Ql+HCwoYdoNv+LKERFEp6RhbjvBqdZAfnf/nUQE6kgbn8qJ/Cx8k27g97dmoA2OIyZWzaHCU8yccz+zRlxaXnEtxa7P92D3c+EXMY5f/GIWok0pUSWIGz6E0BA/aShz/JhESguzqOuM47e/uY3I8EhSYlTsyiwgcOgErrpsCjHxg2htOU3F2S4mXjWHSckJDEufiG9jEdlFVSjiRjFhWCSakBjU7W0cragnbewEgnUq3G4TioAUxmUkSiwVCtEw1lCC/NX4RIUxMjEMbXgcyqZGjte0MGLsBKLikxmm7iQz+widvtFMTIygtbEJQ3c3XQYDPRYbOv9AIuPC8Q+PZc6NMwn2VWHvPMuefYfxRAyju7WFlIypRIaFEDEknKnTZzIsOhj/0FgGB9rYl3WEMZN/wtzZvcrfhXUFcWFfQDjDosMJiwohJDyIlDHjGaTtYX9uMeOn3cXV0xJIShrKqSO51Hb7cvnsKxkxJIGMtEHs2b6Ls00dhAwfR2pkACh1DEnQkZtdSuLocUQGabE7ugmJG8+o1EHSFM3hrZmoY9R4vDaSx0wgKlCNb0gYcQnhiD2H5MQokjMmE9BazIHC03ijRzFJfEYUEBgeTmx8hFSE2KFJODqqOJh3hBZFMBPGjGL6qDgOZR2gWz2Yq66+mmGR/pRmraPCE4vKZkQXHc+oxCF0ttRQUdfG3J//lIlSviAmYTAtdRU0GXRcNnMKw2NU7Ni5j3q9naT0kXj1zXQYuqS1XobuLtAG0F5cQPaRo3S543n4sTl4jG00t3XQLcmvC5tXjaK7hcwDBzhdb+OuB+5iZEIwFnMXFlGBnjK6b/W/i5MF+6j1RqIwWUlITWfc9ElYOkopb/bjoV/dSVRwIONHxfYyr2slMHUcaVEXL3ZUkJIyjLKiXOp6dMy84krShiQwbkQUe7bt4myjnuDUXllFxIcTNGgoc6+fik4FpuaT7M6rxCcwjJ7ObtInTWfcmFGcyd1DydluEtInMXH0SLzn32VBTEpPxV8NVruJiGETSUroXTQdEB6Kf1g41103m8hALS5TM5k792ALS8LYUs+wMRMZFBpO1LAwMiZNZ9TQCNS6cJJjVOzde5D41Dn8dM6oPjb9aux/9Yls4Oi/Wvxy4b8VAU83L778MY+98DS968m/Vez/U4Ebj2Xx9oJViIPb4sc3NoXHHnuCYcH9BxH7fpa//lME7G28++eXKZd8q4gDDGpueuhZ5o6LuSAHXna8P5/NouXVvs/wa+7hj3fMOncqf8sE/iUCsmLwL+GTI/93ERCwOxz4aMWhe/kjE5AJyAR+mARkxeCHKVe5VDIBmYBMQCYgE/hOBORxw++ETY4kE5AJyARkAjKBHyYBWTH4YcpVLpVMQCYgE5AJyAS+EwFZMfhO2ORIMgGZgExAJiAT+GESkBWDH6Zc5VLJBGQCMgGZgEzgOxGQFYPvhE2OJBOQCcgEZAIygR8mAVkx+GHKVS6VTEAmIBOQCcgEvhOBS32vfqdk5Ej/jQS8F7q2E22xKBTS338jC7nMMgGZgEzgh0JAVgx+KJL8D5dDtOPe0tKC2+1GqVQiKgl+fn5ERl5qJ/8/nDX5djIBmYBMQCbwLxD4X1MM3A47Lo8CX50WxTl/Mv8gY6IPcpegQqO6dCbD6/GAUoVSIeBxe1GqVQM48BggYcGLy+XGK7pb1fh8szii6xOPB48AavXX2bITcLtcku93pdoHteqfFHCA7P1funReVn7af85JkPy+XJJ9URHYtm0bdnuvK1lRQUhJSWHu3LmXhJUvyARkAjIBmcD3h8ClLfN3yruX6iPZrF+TQ4/kXvnrEzE1H6WgaiBXl26qKopo6nbgtvdw9HAZJrvYMv3zj7m9kbzsbHLzCqjtMA/gJnTgNHpqKik7Vfu14b12E8VZ2WTnZHO8pA6n+5vlaeA7/v++6uVMURbrv8jFaPmacggejO0dtDTrcbq/cpN9Ye7FkQJx+kD8Pnd84e/ysUxAJiATkAl8/whcohg4rCb0ej2dRpPUk/a6nXQbDHToO+mxiO5NwWE2YTAYaNcbsLnERkOBx97JJ2/up7bZJYURXbpaurvQ6zsxWpzSNZfTSkeHntOHV7C8z8Wp02LGoNdj6LHg8VpY8vQdLM8s4kzxLm6d82eqO524HTY69Xo6urpxiN17wO2ySfnUd3bh9gqc2reDD95cxJcbF/LqxxsQb+l2WDG0t9Pe1Y3TK8YTsJm66ehox2C2SspAR9E+8nIP4XE5MBit5xxNS/c498/ccpK/PfQoW3dt5Z0X53HsTIf0k9VopFMqYxeiruCyW+hs76CjuwdXX5vrcdowGHrOpyu4XfR06iUuNqdHSscrXuvqpkOvp8dola45HRY6Ojow9JjO+5s/l59z3/ZLZOU4Lyuj9VJZ2ftkJdj0LHpjP3VtvWEGklVX/WmWvjOfefPeoqy+89wt5W+ZgExAJiAT+IETuGgqQaBozxes2nsMT/ww/vTgI4S3H+Xtv6+nVQEJY2/kD/deSeGKhWw7047RruS6e37DndOHMfKqHzEyw4ZX8k0Opo561r75HscsTuLG3slj982gNGczH20owHSimJTf3wseMwdWLGTX8WocURN5/Jc/Ij7MQ0n5AbafasWiBpVKQVPJfuYv3YExxJ97fvlnrh0eQvnhTSxcm4cqIILHnn4ar6Bl7Iwbuf4qgZffacXm9FKZu5k1X+ynNTqa+x94gplxCrZ8/A4HqpvQjrmcZ+7/OZpgJRqXl7L8g3xxwsaffn0jGqeopPS27Cq1D06nk0FjJ/HK86/wxbwnOXysnKkjwtjw/ocUerwIBvjTS3+mee8q1m0vwpAwhIf+52GmxAfTVnKAvy0r4pl3n2eQDxirSnj7jY/o8A3njoce44r0GESXw+99sJ4Gj5Mxo2fx6H2zyN+7hs+2Hic6dRKPPPRLovwu1uEEinauZvX+43gSknjywUcIaTnC2x9toFUhkDBuDk/cO5u8zxewo1pPj13BDff8hjumDWPkNTcxMsOJ4OpVTIzttax9832OW90MHnsnj/7yMvZ9+BYdijhGpsSjUn7dNMsP/AmRiycTkAnIBP7LCPRvbbwu/MKSmTP3RnwbNvPl0XYchla6XLG8+fKTnMraRWlzN1XHKhg67U5e//00li7cSO8sswOnzonCp3f+/ei+L9hS6+T2W6+gcP16ajua+PiTfH7+yF/5y91TUCrArS/j9aVfMvXmWwhrL+TLPSeITbyKdKWe6s5YrpydhsNuxquJ5ke33EKG9igfb8pHcLSxbMFSbn38Ff721COEawClk1PlR9m/rwB1sAqV18DHH+dy6/Pz+MNlWj5afIjuxuNsPCzw5tvziGrKZ29xN37BOo7sWscb767nhstnEOI2sG3TapYuXSr9bduXi6DRYawq46PlSyjVD2LK+JGSv/fSQ8WMufanvPnK74igmb8vLuaBefO5J9nEh0uLpKrko/UnKTYMTd+yhM7SPNrCk7n/t/eROMhPCmPpaOVUeSdPP/8C9981m46qQlau2c0Tr73DH+6Zg7/SfWm19Lrwj0yRZKWp38zWo+3YO1voFuKY/8qTVBzYQWlrD9VHKkicfidv/HYKSxZu+kpW/6+ds41p6zrj+O/aXN9rbF/b2OAXDMaE95eGkEVswBqUtJR0TaqutNqUfWg1Jeu3Lh+iaYo27dvWbdqmdhVptqVVEkVrGqotH9YkVNraSU2TdmVZIBAo6QaExCEYMMZg/DbZMBLKpGlaVY3oHMnSueee6/uc3/9K9/Hz+DnqEvxLq57XOTOW5MknHuT906e4PhWjqKERKXSbT0YzDsS/uf96i8SIICAICAKCwH1AYI1jkAwP8/PD57G7C/FYKkiFF0hIMh6HHSmlYIpKxOYXkXQmfHkWZEs+8nSU5USBgdxEkJnILLGlJPOLJryBbRQH6vjeC/sIFOjRp13YFAPmKhuoeuKLcfT2L1Ie8NP5rX083u5ndjbFg88e4NDBr2PSpclJzfBy15vMShp+Vz266QSpxCL6uIbbLpHQyRgVmcUllUfaO3nu2y/gmxrnzswkEb0XW64Oq7MC3cwi84kUKdVPOqHHaioiF6FdqQAABOpJREFUHo6SlkB1uCgqXWQsFCQhGymvqKGhoSH7ydiWiYIY81x8oaWNA4eep7m6IOsYmLVKdm0OYLTYMclJIrIXm5zGlleBFJrPPh5mTyktO1swrpD2djzFs0820fPGixw99352TiylsjnQSLnDglXTSC7EUCQ7tpw4OSYTqkFe96glZq/xs663sbt9eExlpOZWtLLnIaVUjBmtojEk2YTPoS1rFYqynOhRyE0FmZ0LZ7Wai5nxlWylOFDP93/4Tfx5eur37KXj0UfQdLf40U9/t6LxOjPEgCAgCAgCgsB9RmBNKiGtV/CoUS79+R1uzN6h1q6i5qR4t6cb2T6J2VdLjSef6+nbHHv1MEPFKi07H8OShWLj0VY93cePYHxmP9VNjZzt7+bc2Qjz9k1UNVSyY0eU3554ieTHf8T11C4M+eW0bFui52wPiiGX1vY2NIsJS34JPmUai8WOZDBQqElcu3wJ/eR1NM8u9KZCmjvK+fWLr1CS56R979dw2nW83v0m06FLSOXVOB1+Ht4R51ddXaihIA9/9XkKvDn4Pac4cvQO41Pw3BYX8SsSze2dtAVsfOelV9lW/wMam1rXyBwamaKgNEDT1ka01TMSZs1MKpEJx+vA6KWteZZfvHyEVPAWHU8fyM4M9p3h0HcvcPRPJ/ApEAn+nb6/DpCK5mAzm7JzcmQDqknJ/uchE1hwVzRQ13iOXx4+isXpZ+/TX6FIy4RF7rZ0jopbneeDjFbhEJvtRtScBO+eP41sC6IV11HtcjCcDPLab7oY8Cm0PrTnrlbNEqeOvYLyzH5qmhroGfj9qlaVjbUMfXCR8xf/wtRkkoZtFYhkwl32oicICAKCwP1MQEpnCtLvadMTAwyORnAWunE63UxcPMuxM4N0fuMh/KWVFNiM/GT/QbTtX2ZrdQX1DVUombxApiWi9PWNYC8soTDfwsTYx4yO3caQX0xtmQ8lOU9v7xVSsgX/pk04LSqxSIjLfYOgWNlUWYYyH8Lg8GDQJbk5MY29wIkUGaV38CbWfCdWhwevLRfiEfr/dpU5nZmqmirMiTDDI/9gIaGjpKySvMyLNBGl96PLpBUvWzb7s6V5c1M36B8axeWrJVCkEY/MEE3qsFo1xsc/wZznw5a79hd6MrZAaGqGPK/nnhdkiqmJEJrLgbxSvpiKhfmotx+DpZgHaguzSOIL09y6HcNd7M5G7pfmJukfGCEmaTxQX02uKrG0EGUuvITDZVvmCCSjU1y+MkxS81BX7se4xoVbnha6cZVrY/M4fW7yHW7G3nuLE38YonPvTvylVRTYVH687yC2HW00VpZRv6UKZUWq9IpWjsIA3nwzE6PDjI5PYigopq7MR2J2kgvvXGBm0cpjndtR1sSWIJlMZlMt0Wg0W5GQKVcsKytj9+7dq2sQHUFAEBAEBIGNR2CdY/DpJVwf+pC+m0vs2d68eqr79HGqvtRBbaHYzGYVyv9BZ2TwEleDCXbfo9XpN45T07qLGo/zv7YwHltkKQEmk7ru2oxjcPLkSWKx5cqGzHEgEKC9vX3dXDEgCAgCgoAgsHEI/EfHYOMsRVj6eRLIBJrC4XB2x8PMXgaZY1mWMZvNn6cZ4l6CgCAgCAgCnzEB4Rh8xkDF1wkCgoAgIAgIAhuZwKcyxxt5KcJ2QUAQEAQEAUFAEPhfCfwTf2cGUkofufIAAAAASUVORK5CYII=" alt="" />
图14-4-1获取设备序列号
所以在终于这个ADB协议命令字串将会变成:
“host-serial:HT21ATD05099:foward:4939;4939”
而參照ADB协议,实际上就相当于ADB命令行client命令的:
“adb -s HT21ATD05099 forward tcp:4939 tcp:4939”
这事实上跟第13章第2小节手动发送ViewServerport转发命令是一样的,仅仅是这里多了个-s參数来指定要转发的port属于哪个设备上的ViewServer而已。
到如今为止我们已经完毕了port转发的第2步了,那么我们往下看第3步,做的事情就是把代表目标设备的Device实例和本地ViewServer的转发port做为键值对给保存起来到sDevicePortMap这个成员变量里面:
sDevicePortMap.put(device, Integer.valueOf(localPort));
sDevicePortMap这个成员变量是个HashMap:
55 private static final HashMap<IDevice, Integer> sDevicePortMap = new HashMap();
代码14-4-5 DeviceBridge - sDevicePortmap
注意这个变量是非常重要的,由于HierarchyViewer连接相应的设备的socket就是靠它来提供相应的本地ViewServer转发port号的。
注:很多其它文章请关注公众号:techgogogo或个人博客http://techgogogo.com。
当然,也非常欢迎您直接微信(zhubaitian1)勾搭。
本文由天地会珠海分舵原创。转载请自觉,是否投诉维权看心情。
第14章4节《MonkeyRunner源代码剖析》 HierarchyViewer实现原理-装备ViewServer-port转发的更多相关文章
- 老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 3
formAdbRequest我们在之前已经分析过,做的事情就是组建好ADB协议的命令以待发送给ADB服务器,在我们558行中最终组建好的ADB协议命令将会如下: “host-serial:xxx:fo ...
- 第6章1节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览
在上一章中我们有简要的介绍了事件源是怎么一回事.可是并没有进行详细的描写叙述.那么往下的这几个小节我们就须要把这方面的知识给补充完整. 这一节我们先主要环绕MonkeySourceNetwork这个事 ...
- 第6章8节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-小结
本章我们重点环绕处理网络过来的命令的MonkeySourceNetwork这个事件源来阐述学习Monkey是怎样处理MonkeyRunner过来的命令的.以下总结下MonkeyRunner从启动Mon ...
- 第6章4节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-翻译命令字串
在第2节中我们看到了MonkeySourceNetwork是怎样从Socket中获取MonkeyRunner发送过来的命令字串的,可是最后怎样将它翻译成事件的代码我们还没有进行分析,由于在那之前我们还 ...
- 第6章7节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-注入按键事件实例
在事件生成并放入到命令队列后,Monkey类的runMonkeyCycles就会去调用相应事件源的getNextEvent来获的事件来运行事件注入,那么这一小节我们通过MonkeyKeyEvent这个 ...
- 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件
老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...
- 老李推荐:第14章5节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态
老李推荐:第14章5节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态 poptest是国内唯一 ...
- 老李推荐:第14章6节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-启动ViewServer
老李推荐:第14章6节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-启动ViewServer poptest是国内唯一一家培养 ...
- 老李推荐:第14章3节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-HierarchyViewer实例化
老李推荐:第14章3节<MonkeyRunner源码剖析> HierarchyViewer实现原理-HierarchyViewer实例化 poptest是国内唯一一家培养测试开发工程师的培 ...
- 老李推荐: 第14章2节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-HierarchyViewer架构概述
老李推荐: 第14章2节<MonkeyRunner源码剖析> HierarchyViewer实现原理-HierarchyViewer架构概述 HierarchyViewer库的引入让M ...
随机推荐
- Windows开源Web服务器性能和压力测试工具
linux有很多开源工具用来测试服务器负载,而windows上非常少,几乎没有除了几个复杂的JMeter WET等 将两个好用的工具是Linux版本通过Cygwin移植过来,方便广大windows人员 ...
- AMH V4.5 – 基于AMH4.2的第三方开发版
AMH V4.5[基于AMH4.2第三方开发版]重新部署了一次安装脚本,修改一系列BUG,已完美支持CENTOS7,树莓派,Fedora,Aliyun,Amazon,debian,Ubuntu,Ras ...
- [leetcode]Add Two Numbers——JS实现
Javascript的结构体应用,如下: function station(name, latitude, longitude){ this.name = name; ...
- KM算法(Kuhn-Munkres)
算法理论基础: 可行顶点标号 用l(v)表示顶点v的标号,w(uv)表示边(u,v)的权,对于赋权二分图G=(X,Y),若对每条边e=xy,均有l(x)+l(y)>=w(xy),则称这个标号为G ...
- dom4j使用方法详解
本文先做知识点的简单介绍,最后附完整案例. 一.解析XML文件 public class Foo { //url为XML文档地址 //自己封装了一个工具类 返回解析完成的document public ...
- 洛谷——P2047 [NOI2007]社交网络
P2047 [NOI2007]社交网络 $Floyd$,一眼看到就是他(博主是不小心瞄到了这个题的标签吧qwq) 这个题目只要预处理出$S$到$T$的最短路的条数即可,类似$Spfa$的更新方法 如果 ...
- Radar Installation POJ - 1328 (贪心)
题目大意(vj上的翻译版本) 假定海岸线是无限长的直线.陆地位于海岸线的一侧,海洋位于另一侧.每个小岛是位于海洋中的一个点.对于任何一个雷达的安装 (均位于海岸线上),只能覆盖 d 距离,因此海洋中的 ...
- js中匿名函数的N种写法
匿名函数没有实际名字,也没有指针,怎么执行? 关于匿名函数写法,很发散~ +号是让函数声明转换为函数表达式.汇总一下 最常见的用法: 代码如下: (function() { alert('water ...
- 程序员如何在百忙中更有效地利用时间,如何不走岔路,不白忙(忙得要有效率,要有收获)-----https://www.cnblogs.com/JavaArchitect/p/9080484.html
https://www.cnblogs.com/JavaArchitect/p/9080484.html 程序员如何在百忙中更有效地利用时间,如何不走岔路,不白忙(忙得要有效率,要有收获)
- Spring常用注解总结 hibernate注解
1.@Resource和@Autowired @Resource和@Autowired功能一样在容器查找匹配的Bean @Autowired默认按照byType方式进行bean匹配,@Resource ...