diff --git a/sig/ConfidentialComputing/assets/confidential_mcp.png b/sig/ConfidentialComputing/assets/confidential_mcp.png new file mode 100644 index 0000000000000000000000000000000000000000..4d7c6c331216b4f2ba31182ee95b329aa86e6f21 Binary files /dev/null and b/sig/ConfidentialComputing/assets/confidential_mcp.png differ diff --git "a/sig/ConfidentialComputing/content/Confidential_AI/\345\237\272\344\272\216Confidential\302\240AI\350\247\243\345\206\263\346\226\271\346\241\210\345\234\250Anolis\302\24023\344\270\212\346\236\204\345\273\272\346\234\272\345\257\206MCP\346\234\215\345\212\241.md" "b/sig/ConfidentialComputing/content/Confidential_AI/\345\237\272\344\272\216Confidential\302\240AI\350\247\243\345\206\263\346\226\271\346\241\210\345\234\250Anolis\302\24023\344\270\212\346\236\204\345\273\272\346\234\272\345\257\206MCP\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..c7e508d8b841ffb62a8a0d05e6130a95555b46df --- /dev/null +++ "b/sig/ConfidentialComputing/content/Confidential_AI/\345\237\272\344\272\216Confidential\302\240AI\350\247\243\345\206\263\346\226\271\346\241\210\345\234\250Anolis\302\24023\344\270\212\346\236\204\345\273\272\346\234\272\345\257\206MCP\346\234\215\345\212\241.md" @@ -0,0 +1,251 @@ +# 基于Confidential AI解决方案在Anolis 23上构建机密MCP服务 + +# MCP服务面临的安全威胁 + +MCP(Model Context Protocol,模型上下文协议)是一种开放的标准化协议,用于在AI应用与外部数据源、工具之间建立安全、可扩展的集成机制。MCP服务作为AI应用生态系统的关键组件,主要承担以下职责: + +* **上下文管理**: 为大语言模型(LLM)提供外部知识和实时数据访问能力 + +* **工具集成**: 连接各类API、数据库、文件系统等外部资源 + +* **会话协调**: 管理多轮对话中的状态和上下文信息 + +* **数据转换**: 在不同数据格式和协议之间进行转换适配 + + +MCP服务通常会处理大量敏感的用户数据、业务逻辑和知识库内容,其安全性直接关系到整个AI应用系统的可信度。 + +MCP服务面临的安全威胁主要来自以下几个方面: + +* **运行环境威胁:**基础设施提供商(云平台等)的特权用户可能通过Hypervisor层访问虚拟机内存,窃取MCP服务处理的敏感数据 + +* **供应链攻击:**恶意的固件、驱动或操作系统组件被植入,在MCP服务运行时窃取密钥和数据 + +* **网络传输威胁:**数据在网络传输的过程中被截获窥探 + + +# 方案架构 + +![image](../../assets/confidential_mcp.png) + +在机密计算环境中,隐私数据的处理安全已由硬件环境本身提供保障,但在网络传输环节,数据的安全性仍然存在不足。传统网络安全技术通常依赖基于公钥基础设施(PKI)的TLS证书来确保传输中的数据安全(例如HTTPS、OpenVPN等协议)。然而,TLS证书的管理与部署流程复杂且容易成为信任链中的薄弱环节。 + +对于机密实例中运行的网络服务,其身份可以通过机密实例的实例状态信息(包括运行代码和执行环境)来进行标识。通过在通信双方的密钥协商过程中引入远程证明(Remote Attestation)机制,配合适当的远程证明策略(Policy),可以实现对服务端运行环境的完整性验证以及安全性检查。这种方法能够有效补足传统的PKI信任体系的缺陷,消除其潜在的信任弱点,从而弥补数据传输安全的短板,显著提升整体安全水平。 + +TNG(Trusted Network Gateway)是一个专为机密计算场景设计的网络组件,支持在多种应用场景下构建安全通信信道。它不仅能够实现端到端的数据加密与解密,还通过远程证明机制确保通信双方的身份可信,从而保障整个通信链路的安全性。 + +TNG 的设计目标是一个高度可扩展、易于集成的安全通信基础设施,使其能够广泛适用于云原生、边缘计算、隐私计算等对数据安全性要求极高的场景。目前TNG可以灵活适配不同的网络架构和部署模式,包括集群内部的安全 Mesh 网络、客户端与服务端之间的点对点通信等多种场景。其核心能力包括: + +* **多协议支持**:TNG 在远程证明的基础上,支持不同层级传输协议安全增强,包括面向TCP流负载的机密完整性保护,以及特殊针对L7无状态HTTP负载的数据源隐藏技术。确保在不依赖传统证书体系的前提下,也能建立高安全性的通信通道。 + +* **多部署形态**: + + * 在 IaaS 场景中,TNG 可作为守护进程运行于虚拟机或容器实例中; + + * 在 Kubernetes 或 Service Mesh 集群中,TNG 可以部署为 Sidecar 容器,为每个服务Pod提供透明的安全通信能力; + + * 对于客户端应用或 Web 应用,TNG 提供了相应的 SDK,开发者可轻松集成 TNG 的安全功能至应用程序中,实现客户端侧的安全通信处理。 + +* **支持双向远程证明**:通过 TNG 进行通信的节点可灵活配置远程证明模式,除了单向远程证明验证,在机密计算实例集群场景,还支持通信双方的双向验证。系统同时兼容“护照模型”与“背调模型”,确保通信双方的身份可信性,从而实现安全可靠的节点间通信。 + +* **业务应用无修改接入**:TNG 通过提供透明代理(Transparent Proxy)等机制,使得上层业务无需进行任何代码或配置修改即可接入安全通信链路。开发者仅需在部署层面配置 TNG 的网络代理策略,原有业务逻辑、接口调用方式和协议格式均可保持不变。TNG 在底层自动完成远程证明、身份验证、加密传输等安全处理流程,实现对业务层“零感知”的安全增强。这种设计大幅降低了安全能力集成的复杂度与成本,特别适用于大规模微服务架构、遗留系统升级以及多语言异构环境下的快速部署。 + + +通过在MCP服务上使用TNG构建安全通信信道,一方面可以满足网络通信中数据的机密性和完整性保护的要求,另一方面可以实时对MCP服务运行的软硬件环境进行验证,保障起真实性和完整性。 + +# 环境准备 + +请参考[AnolisOS23物理机构建TDX环境并启动TDVM实践](../Intel_TDX/AnolisOS23物理机构建TDX环境并启动TDVM实践.md)完成物理机环境准备并启动TDX机密虚拟机 + +# 部署实践 + +## 在用户可信域内部署attestation service(Trustee) + +```shell +# 安装trustee +yum install trustee +systemctl start trustee +``` + +## 在机密虚拟机内部署MCP Server和TNG Server + +```shell +# 安装attestation-agent +yum install attestation-agent +``` + +配置trustee地址 + +```toml +[token_configs] + +[token_configs.coco_as] +url = "http://[trustee_ip]:8081/api/attestation-service" + +[token_configs.kbs] +url = "http://[trustee_ip]:8081/api" + +# KBS certificate +# cert = + +[eventlog_config] +enable_eventlog = false +eventlog_algorithm = "sha256" +init_pcr = 16 + +``` +```shell +# 重启attestation agent +systemctl restart attestation-agent + +# 使用everything mcp server作为示例,mcp server会运行在3001端口 +yum install git npm +git clone https://github.com/modelcontextprotocol/servers.git +cd servers/src/everything +npm install +npm run start:streamableHttp + +# 安装TNG +yum install trusted-network-gateway +``` + +配置TNG代理mcp server,此处代理到13001端口 + +```json +{ + "add_egress": [ + { + "mapping": { + "in": { + "host": "0.0.0.0", + "port": 13001 + }, + "out": { + "host": "127.0.0.1", + "port": 3001 + } + }, + "attest": { + "aa_addr": "unix:///run/confidential-containers/attestation-agent/attestation-agent.sock" + } + } + ] +} +``` +```shell +# 重启TNG +systemctl restart trusted-network-gateway +``` + +## 在MCP Client侧部署TNG Client + +```shell +# 安装TNG +yum install trusted-network-gateway +``` + +配置TNG,此处配置映射到13002端口 + +```json +{ + "add_ingress": [ + { + "mapping": { + "in": { + "host": "0.0.0.0", + "port": 13002 + }, + "out": { + "host": "127.0.0.1", + "port": 13001 + } + }, + "verify": { + "as_addr": "http://[trustee_ip]:8081/api/attestation-service", + "policy_ids": [ + "default" + ] + } + } + ] +} +``` +```shell +# 重启TNG +systemctl restart trusted-network-gateway +``` + +## 检查传输加密和远程认证是否生效 + +### 远程认证 + +```shell +# 查看trustee日志中的远程认证结果 +curl -k http://[trustee_ip]:8081/api/audit/attestation?limit=1 +``` +```json + +{"data":[{"ID":53,"CreatedAt":"2025-11-20T10:00:00.443149214+08:00","UpdatedAt":"2025-11-20T10:00:00.443149214+08:00","DeletedAt":null,"client_ip":"127.0.0.1","session_id":"","request_body":"","claims":"{\"customized_claims\":{\"init_data\":null,\"runtime_data\":{\"pubkey-hash\":\"ggFYIAGDH/JrbI6vondtLK9dH9ikS0BtjM0yXcGHt1oysHrD\"}},\"evaluation-reports\":[{\"policy-hash\":\"f5abdc02716d85a5ab28cf43500201591bbe4e5600751039462e5ec2e0ae2698d637c1f487f58bca182244eefdf3b4b1\",\"policy-id\":\"default\"}],\"exp\":1763604300,\"iat\":1763604000,\"iss\":\"CoCo-Attestation-Service\",\"jti\":\"ULb0OBRqZ5\",\"nbf\":1763604000,\"tcb-status\":\"{\\"init_data\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"report_data\\":\\"dbfac4b097bbf815e9f0afc8790689ae7c6d885152604073169ef7d8facb2a8ece2172d8ba19e42d04c6389003554cc000000000000000000000000000000000\\",\\"tdx.ccel.kernel_cmdline\\":\\"grub_kernel_cmdline (hd0,gpt3)/boot/vmlinuz-5.10.134-19.1.al8.x86_64 root=UUID=33b46ac5-7482-4aa5-8de0-60ab4c3a4c78 ro rhgb quiet cgroup.memory=nokmem crashkernel=0M-2G:0M,2G-8G:192M,8G-128G:256M,128G-376G:384M,376G-:448M spec_rstack_overflow=off vring_force_dma_api kfence.sample_interval=100 kfence.booting_max=0-2G:0,2G-32G:2M,32G-:32M preempt=none biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8 noibrs nvme_core.io_timeout=4294967295 nvme_core.admin_timeout=4294967295 cryptomgr.notests rcupdate.rcu_cpu_stall_timeout=300\\u0000_\\",\\"tdx.ccel.measurement.grub.SHA384\\":\\"1c6b41cc5f1e08dff906e381580dc5c200b3c4785f3910682c74fd2ac0421f324216165478595b5e799d2b2134d22b75\\",\\"tdx.ccel.measurement.initrd.SHA384\\":\\"7de50181f02be7ff689b04a54d2ee3ac78cb5ac3fbc9e07bac7d0e75c27c21ee7d40cc3500dfe2fa17036567273cd777\\",\\"tdx.ccel.measurement.kernel.SHA384\\":\\"7ecde58258fb08dfd147cfdba2443ecfeae8b97fed8efe0cee199cd71dcc2fb7ff3d23e7ebcb24965186524c9904b84c\\",\\"tdx.ccel.measurement.kernel_cmdline.SHA384\\":\\"6a3d314eb16073a6c426173723c0a57a1e5c4efe9b355730d2c80be1026f8d03493355c5077c81f69fa05571406b96f8\\",\\"tdx.ccel.measurement.shim.SHA384\\":\\"06647f7cd6b1f00433713e895077c986641bfb6bdd3de989575b4fdc34fe557f26990c414158c772393a27732f959dc5\\",\\"tdx.quote.body.mr_config_id\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"tdx.quote.body.mr_owner\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"tdx.quote.body.mr_owner_config\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"tdx.quote.body.mr_seam\\":\\"1cc6a17ab799e9a693fac7536be61c12ee1e0fabada82d0c999e08ccee2aa86de77b0870f558c570e7ffe55d6d47fa04\\",\\"tdx.quote.body.mr_servicetd\\":\\"383c87d3bbb047b2d171eaca95312ede99f258088dc788f6ae2ccf8b6dd848fe8d47629e08b3f6cbd4a00dd47a5a033d\\",\\"tdx.quote.body.mr_td\\":\\"157768a71a6a31f5561978c4cde665809d22976ef5dead2952839b7b3ea23b6c2931c9148fe1d117c99faefac18bb73b\\",\\"tdx.quote.body.mrsigner_seam\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"tdx.quote.body.report_data\\":\\"dbfac4b097bbf815e9f0afc8790689ae7c6d885152604073169ef7d8facb2a8ece2172d8ba19e42d04c6389003554cc000000000000000000000000000000000\\",\\"tdx.quote.body.rtmr_0\\":\\"132387204c4e221bf2db110cf339fb8a52357f62fcc468ca904aa1fbcf9c79c47133778ebb46779156ec9022a5c76906\\",\\"tdx.quote.body.rtmr_1\\":\\"f7c13e6c58c517f1bd382999b51349ecd59058d41ed90ebce05cfb82a376b00a25062f1fc9789b8ccafd0d6df3a20802\\",\\"tdx.quote.body.rtmr_2\\":\\"feebe81bf2c8d15e445c87051f34c2aa33e48e2bc1510cfb4227c1411c6a87b019a64da431c369cd19f0ce85e7001ce7\\",\\"tdx.quote.body.rtmr_3\\":\\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\",\\"tdx.quote.body.seam_attributes\\":\\"0000000000000000\\",\\"tdx.quote.body.tcb_svn\\":\\"05010200000000000000000000000000\\",\\"tdx.quote.body.td_attributes\\":\\"0000001000000000\\",\\"tdx.quote.body.tee_tcb_svn2\\":\\"05010200000000000000000000000000\\",\\"tdx.quote.body.xfam\\":\\"e742060000000000\\",\\"tdx.quote.header.att_key_type\\":\\"0200\\",\\"tdx.quote.header.reserved\\":\\"00000000\\",\\"tdx.quote.header.tee_type\\":\\"81000000\\",\\"tdx.quote.header.user_data\\":\\"63a211aad38b56c044c45af44f5c2db300000000\\",\\"tdx.quote.header.vendor_id\\":\\"939a7233f79c4ca9940a0db3957f0607\\",\\"tdx.quote.header.version\\":\\"0500\\",\\"tdx.quote.size\\":\\"88020000\\",\\"tdx.quote.type\\":\\"0300\\"}\",\"tee\":\"tdx\"}","status":200,"successful":true,"timestamp":"2025-11-20T10:00:00.44298704+08:00","source_service":"attestation-service","instance_id":"","image_id":"","instance_name":"","owner_account_id":""}],"total":1} +``` + +### 传输加密 + +```shell +# 对比3001(非加密端口)和13001(加密端口)的tcpdump结果 +tcpdump -i lo -n -A 'port 3001' > 3001.txt +tcpdump -i lo -n -A 'port 13001' > 13001.txt +``` +```shell +10:09:14.944981 IP 127.0.0.1.45632 > 127.0.0.1.origo-native: Flags [P.], seq 1:413, ack 1, win 512, options [nop,nop,TS val 1081300955 ecr 1081300954], length 412 +E.....@.@.2l.........@..Z..Q............... +@sW.@sW.POST /mcp HTTP/1.1 +host: localhost:3001 +connection: keep-alive +mcp-session-id: 8cac1a3c-fe43-45cc-9598-1a82786e4ceb +mcp-protocol-version: 2025-03-26 +User-Agent: Cursor/2.0.77 (linux x64) +content-type: application/json +accept: application/json, text/event-stream +accept-language: * +sec-fetch-mode: cors +accept-encoding: gzip, deflate +content-length: 46 + +{"method":"tools/list","jsonrpc":"2.0","id":1} +10:09:14.944986 IP 127.0.0.1.origo-native > 127.0.0.1.45632: Flags [.], ack 413, win 509, options [nop,nop,TS val 1081300955 ecr 1081300955], length 0 +E..4./@.@.v............@....Z........(..... +@sW.@sW. +10:09:14.945929 IP 127.0.0.1.origo-native > 127.0.0.1.45632: Flags [P.], seq 1:4537, ack 413, win 512, options [nop,nop,TS val 1081300956 ecr 1081300955], length 4536 +E....0@.@.d............@....Z.............. +@sW.@sW.HTTP/1.1 200 OK +X-Powered-By: Express +Content-Type: text/event-stream +Cache-Control: no-cache +Connection: keep-alive +mcp-session-id: 8cac1a3c-fe43-45cc-9598-1a82786e4ceb +Date: Thu, 20 Nov 2025 02:09:14 GMT +Transfer-Encoding: chunked + +10b8 +event: message +id: 807842b1-fac6-49eb-9343-5caaec1e2489_1763604554945_niyh31ox +data: {"result":{"tools":[{"name":"echo","description":"Echoes back the input","inputSchema":{"type":"object","properties":{"message":{"type":"string","description":"Message to echo"}},"required":["message"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"add","description":"Adds two numbers","inputSchema":{"type":"object","properties":{"a":{"type":"number","description":"First number"},"b":{"type":"number","description":"Second number"}},"required":["a","b"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"longRunningOperation","description":"Demonstrates a long running operation with progress updates","inputSchema":{"type":"object","properties":{"duration":{"type":"number","default":10,"description":"Duration of the operation in seconds"},"steps":{"type":"number","default":5,"description":"Number of steps in the operation"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"printEnv","description":"Prints all environment variables, helpful for debugging MCP server configuration","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"sampleLLM","description":"Samples from an LLM using MCP's sampling feature","inputSchema":{"type":"object","properties":{"prompt":{"type":"string","description":"The prompt to send to the LLM"},"maxTokens":{"type":"number","default":100,"description":"Maximum number of tokens to generate"}},"required":["prompt"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getTinyImage","description":"Returns the MCP_TINY_IMAGE","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"annotatedMessage","description":"Demonstrates how annotations can be used to provide metadata about content","inputSchema":{"type":"object","properties":{"messageType":{"type":"string","enum":["error","success","debug"],"description":"Type of message to demonstrate different annotation patterns"},"includeImage":{"type":"boolean","default":false,"description":"Whether to include an example image"}},"required":["messageType"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getResourceReference","description":"Returns a resource reference that can be used by MCP clients","inputSchema":{"type":"object","properties":{"resourceId":{"type":"number","minimum":1,"maximum":100,"description":"ID of the resource to reference (1-100)"}},"required":["resourceId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"startElicitation","description":"Demonstrates the Elicitation feature by asking the user to provide information about their favorite color, number, and pets.","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getResourceLinks","description":"Returns multiple resource links that reference different types of resources","inputSchema":{"type":"object","properties":{"count":{"type":"number","minimum":1,"maximum":10,"default":3,"description":"Number of resource links to return (1-10)"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"structuredContent","description":"Returns structured content along with an output schema for client data validation","inputSchema":{"type":"object","properties":{"location":{"type":"string","minLength":1,"description":"City name or zip code"}},"required":["location"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"outputSchema":{"type":"object","properties":{"temperature":{"type":"number","description":"Temperature in celsius"},"conditions":{"type":"string","description":"Weather conditions description"},"humidity":{"type":"number","description":"Humidity percentage"}},"required":["temperature","conditions","humidity"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}]},"jsonrpc":"2.0","id":1} +``` +```shell +09:57:31.774345 IP 127.0.0.1.48638 > 127.0.0.1.13001: Flags [P.], seq 33:613, ack 58, win 512, options [nop,nop,TS val 1080597784 ecr 1080597784], length 580 +E..x.C@.@.P:..........2...#..........m..... +@h..@h......?.@.....O27.N\..0..e..A........x....0..P.F,1X.....^.H...l...Z....Dp-.z.[x....Ni3Z.D..E....b..=.M...+&x.V.T.5....s..4_.....{#oHs.|.>9m..d.........&\.....c+D....s..D.e....WP2l....,..p,{l.C.3.UR.?fG.a +..6.+..#cRKl... .-...c.,.....m6.....nr..j.a..H.. +..f.%/t..^0..P...*K......!a=k.H.Q..'.......Y;.....*[...P.NL;< .K...t1...`..x ..}IX.........d..B#.....MM.......7.A.....?..^.^.....Cg........e..1].....\.....4..`U.....}h.....l.g.q .Y.s. .T.x...-..'.4....N..)...t.. .......g..|.4.h...G6.. .e......]y.%...............8.q...y.....v..}:.$.....5.b...7r.*~.....ty.)E..|.p....[.. +09:57:31.775585 IP 127.0.0.1.13001 > 127.0.0.1.48638: Flags [P.], seq 58:2073, ack 613, win 512, options [nop,nop,TS val 1080597785 ecr 1080597784], length 2015 +E...p.@.@...........2.........%............ +@h..@h............l~.u.Cj.=.&&...e......}............Yv.........l.... ..UF,..DB..E......O.d.:l3...'M.Q*.B....K~..L.:|......dfx.wDr.d...=.z!.,...P.\....-V.0EP.......m...4..|.A6..q....].1.uc...sfHw....c.Y...*....,...9.. +h.t......@.....0.'rMU;.......L/\....Jb....X.v..-@&.......c..?u!...7\jB..zw.,T...>0.......t.......?X.?....f'........B..ooI.....I..H,...-.RBA.>..z..ky...#n..J3..5.....i............*....N).TY...[.>.`....I.._.\.]v....C.w.xBq.W.|.u....>..6...4.......gt.........w..6.......?....(..)......s..?%.j...E0..Rp..Q.....F.,..\.C.T..m.....G...G..........(.g..W02.h...[[..b.\.`A.......e3.....p...3..O{nR.d.....;c.u.(....g..G-... ".9=."8.7.}. .'x*..t.'n. +..s^.....Od|..9L.. T..jzz(....u.. +.EOe.Lh.g.Se A.....[lNT....7...L...i...]...@....!E..C. .....P.!..w..p..ir..k`XX+.&...'.-.}.@l...-Q.n..e........AY.1..[.6!...8=8EX.........N.y9D..en.I%..|V2...OL..&>.B7b..W..fh.Y..1.6....ZU.U.q.K5 ..u.`.WQA..F... Pt.....n1M. .{.B..A..&~..~...nB.......-.......#]i../..o.e...&.. .....G..f....b.a....._...Y.n....?........B../........M.UOB}....).B}...i.[4.y2....7B1..W.C1..2*..%...i.&..z\A..tl...*k.a..w......$..V.......R._.+.........o.I{;...F...Fm.o.Y.I4Y..........%1..}i.......0.K.q.U ....gWiw.og...5...R.b.B........A....&..g.....?.N.=h.m..|...{..]..2I..b\....*...Pu.&[\zg.Kc.....7..........n....d..`..o..mg.a~...QL...D.Y>..y1P.M.......>.... +mC...QY:".P...;.;K..ps.V6.?.z[|_k..t.#<.8ew....|.A.... >w`....L'/.e.Y.}?..i/c....e...|......v...o9........Ju^.........vL.....1..L(J..s.F..x.t.@...\....%...~..w..~v.......c..o.A.']..+B1...n..e........J..O...O.,JS6APp...:b....Qp.3.n. ..5....2.......WX.+Q..L....Frt...i....~......V../.!c?..M.4.^..;S..~9.zw..D._..M..T...u..Q..+.Z..AZ.......a$....b.*b.....on....p;2?..h.LG...l..a....T.}.?..yZ$wN0t..gr.....F.\:..0.A........x>..t+..s.Y......Zt..@^.v...Y...a..,...#c. <.6z4.7#X...,.............}..".,.1.Q.. ...l.{..... +.......