diff --git a/web-ui/Dockerfile b/web-ui/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..aa9e782f8a7f67f3e0eea6c4c596e4621e57b47f --- /dev/null +++ b/web-ui/Dockerfile @@ -0,0 +1,29 @@ +FROM node:alpine as Builder + +MAINTAINER zhangxiaopan + +RUN mkdir -p /home/openeuler/web +WORKDIR /home/openeuler/web +COPY . /home/openeuler/web + +RUN rm -rf ./docs/ru +RUN cp ./docs/.vuepress/config.zh.js ./docs/.vuepress/config.js + +RUN npm install + +RUN mv /home/openeuler/web/script/update-build-script.js /home/openeuler/web/node_modules/@vuepress/core/lib/node/build/index.js +RUN mv /home/openeuler/web/script/add-worker-script.js /home/openeuler/web/node_modules/@vuepress/core/lib/node/build/worker.js +RUN node --openssl-legacy-provider --max_old_space_size=9216 /home/openeuler/web/node_modules/vuepress/cli.js build docs + +FROM swr.cn-north-4.myhuaweicloud.com/opensourceway/openeuler/nginx:1.16.1-20.03-lts-sp2 + +COPY --from=Builder /home/openeuler/web/docs/.vuepress/dist/ /usr/share/nginx/html/ +RUN chmod -R 755 /usr/share/nginx/html +COPY ./deploy/nginx/nginx.conf /etc/nginx/nginx.conf + +ENV RUN_USER nginx +ENV RUN_GROUP nginx +EXPOSE 8080 +ENTRYPOINT ["nginx", "-g", "daemon off;"] + + diff --git a/web-ui/README.md b/web-ui/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cc3e2df9954b0dec491b13eccf5c5375e859a290 --- /dev/null +++ b/web-ui/README.md @@ -0,0 +1,59 @@ +# website + +### Brief Introduction + +Website is openEuler community contents management system base on [Vuepress](https://www.vuepress.cn/) framework, [default Theme for Vuepress](https://www.vuepress.cn/theme/default-theme-config.html) theme, which publish on https://www.openeuler.org. Now we are under developing. you are welcome to join us. + +### directory structure +docs + ├─ .vuepress + │ ├── api // api + │ ├── component // vue component + │ ├── data // data maintained + │ ├── lang // language module + │ ├── libs // common utils + │ ├── public // static resources + │ ├── style // common style + │ ├── theme // theme default options + │ ├── config.js // global config + │ ├── enhanceApp.js // app level enhancements + │ ├── sitePlugin.js // plugin + ├─ en // English content + ├─ zh // Chinese content + +### Debug + +1. Install dependencies + +``` +npm install +``` + +2. Run Vuepress development + +``` +npm run dev +``` + +The website will serving on http://your-server-ip:8080, any change will take effect here. + +3. Run Vuepress production + +``` +npm run build + +``` + +Copy dist folder to web container + +### Contribution + +1. Fork the repository +2. Create Feature_xxx branch +3. Commit your code +4. Create Pull Request + +### Get Help + +- IRC: #openeuler-infra +- Mail: infra@openeuler.org diff --git a/web-ui/deploy/nginx/nginx.conf b/web-ui/deploy/nginx/nginx.conf new file mode 100644 index 0000000000000000000000000000000000000000..1323a7b5a74db90a1edde25a531f9eea98baf6ad --- /dev/null +++ b/web-ui/deploy/nginx/nginx.conf @@ -0,0 +1,140 @@ + +worker_processes auto; + +error_log /var/log/nginx/error.log warn; + +pid /var/run/nginx.pid; + +worker_rlimit_nofile 4096; +events { + use epoll; + worker_connections 4096; +} + + +http { + include /etc/nginx/mime.types; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + autoindex off; + sendfile on; + + keepalive_timeout 300; + keepalive_requests 100; + proxy_read_timeout 900; + proxy_connect_timeout 60; + + proxy_send_timeout 60; + client_header_timeout 60; + client_header_buffer_size 1k; + large_client_header_buffers 4 64k; + client_body_buffer_size 16K; + client_body_timeout 60; + send_timeout 60; + server_tokens off; + port_in_redirect off; + limit_conn_zone $binary_remote_addr zone=conn_zone:10m; + limit_conn_zone $server_name zone=perserver:10m; + limit_req_zone global zone=req_zone:1m rate=1000r/s; + limit_req_zone $binary_remote_addr zone=event_zone:10m rate=20r/s; + + proxy_request_buffering off; + client_max_body_size 50m; + + proxy_hide_header X-Powered-By; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE_ADDR $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + + gzip on; + gzip_min_length 1k; + gzip_buffers 4 16k; + gzip_http_version 1.0; + gzip_comp_level 5; + gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript application/x-httpd-php application/json; + gzip_vary on; + + server { + # listen 443 ssl; + # server_name localhost; + # charset utf-8; + + listen 8080; + server_name localhost; + charset utf-8; + limit_conn perserver 50; + if ($request_method = 'OPTIONS') { + return 401; + } + + location = / { + # 只匹配"/". + rewrite ^/$ /zh last; + } + + location / { + location /assets { + # publish every two weeks + expires 14d; + add_header Cache-Control public; + } + location / { + add_header Cache-Control no-cache; + } + root /usr/share/nginx/html; + index /zh/index.html; + # error_page 404 /404.html; + } + + location ~* (/en/cla.html|/zh/cla.html) { + rewrite ^ https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI= permanent; + } + + location /api-sig/ { + proxy_pass https://api.openeuler.org/meetings/; + } + + location /api-mirror/ { + proxy_pass https://api.openeuler.org/mirrors/; + } + + location /api-rank/ { + proxy_pass https://api.openeuler.org/osi-task-manager/; + } + + location /api-certification/ { + proxy_pass https://ccs.openeuler.org/ccs/base/; + } + + location /api-approve/ { + proxy_pass https://cvesa.test.osinfra.cn/; + } + + error_page 500 501 502 503 504 505 /500.html; + error_page 401 /401.html; + error_page 404 /404.html; + + location = /401.html { + root /usr/share/nginx/html; + } + + location = /404.html { + root /usr/share/nginx/html; + } + + location = /500.html { + root /usr/share/nginx/html; + } + + location ~ /\. { + deny all; + return 404; + } + } +} diff --git a/web-ui/deploy/nginx/nginx.ru.conf b/web-ui/deploy/nginx/nginx.ru.conf new file mode 100644 index 0000000000000000000000000000000000000000..1bb242fa17032973a3840d84772afe298017c56b --- /dev/null +++ b/web-ui/deploy/nginx/nginx.ru.conf @@ -0,0 +1,148 @@ + +worker_processes auto; + +error_log /var/log/nginx/error.log warn; + +pid /var/run/nginx.pid; + +worker_rlimit_nofile 4096; +events { + use epoll; + worker_connections 4096; +} + + +http { + include /etc/nginx/mime.types; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + autoindex off; + sendfile on; + + keepalive_timeout 300; + keepalive_requests 100; + proxy_read_timeout 900; + proxy_connect_timeout 60; + + proxy_send_timeout 60; + client_header_timeout 60; + client_header_buffer_size 1k; + large_client_header_buffers 4 64k; + client_body_buffer_size 16K; + client_body_timeout 60; + send_timeout 60; + server_tokens off; + port_in_redirect off; + limit_conn_zone $binary_remote_addr zone=conn_zone:10m; + limit_conn_zone $server_name zone=perserver:10m; + limit_req_zone global zone=req_zone:1m rate=1000r/s; + limit_req_zone $binary_remote_addr zone=event_zone:10m rate=20r/s; + + proxy_request_buffering off; + client_max_body_size 50m; + + proxy_hide_header X-Powered-By; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE_ADDR $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + + gzip on; + gzip_min_length 1k; + gzip_buffers 4 16k; + gzip_http_version 1.0; + gzip_comp_level 5; + gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript application/x-httpd-php application/json; + gzip_vary on; + + server { + # listen 443 ssl; + # server_name localhost; + # charset utf-8; + + listen 8080; + server_name localhost; + charset utf-8; + limit_conn perserver 50; + if ($request_method = 'OPTIONS') { + return 401; + } + + location = / { + # 只匹配"/". + rewrite ^/$ /ru last; + } + + location / { + location /assets { + # publish every two weeks + expires 14d; + add_header Cache-Control public; + } + location / { + add_header Cache-Control no-cache; + } + root /usr/share/nginx/html; + index /ru/index.html; + # error_page 404 /404.html; + } + + location ~* (/en/cla.html|/ru/cla.html) { + rewrite ^ https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI= permanent; + } + + location /api/ { + proxy_pass https://www.openeuler.org/api/; + } + + location /api-cve/ { + proxy_pass https://www.openeuler.org/api-cve/; + } + + location /api-sig/ { + proxy_pass https://api.openeuler.org/meetings/; + } + + location /api-mirror/ { + proxy_pass https://api.openeuler.org/mirrors/; + } + + location /api-rank/ { + proxy_pass https://api.openeuler.org/osi-task-manager/; + } + + location /api-certification/ { + proxy_pass https://ccs.openeuler.org/ccs/base/; + } + + location /api-approve/ { + proxy_pass https://cvesa.test.osinfra.cn/; + } + + error_page 500 501 502 503 504 505 /500.html; + error_page 401 /401.html; + error_page 404 /404.html; + + location = /401.html { + root /usr/share/nginx/html; + } + + location = /404.html { + root /usr/share/nginx/html; + } + + location = /500.html { + root /usr/share/nginx/html; + } + + location ~ /\. { + deny all; + return 404; + } + } +} diff --git a/web-ui/docs/.vuepress/api/approve.js b/web-ui/docs/.vuepress/api/approve.js new file mode 100644 index 0000000000000000000000000000000000000000..5957446ff610cc71240ac8750b769a71df47b92d --- /dev/null +++ b/web-ui/docs/.vuepress/api/approve.js @@ -0,0 +1,117 @@ +/** + * @file OSV认证相关接口 + * */ + + import appAjax from '../libs/ajax-utils'; + const cveApi = '-approve'; + + export const osvList = ({ + keyword, + osvName, + type, + page, + pageSize, +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/osv/findAll', + type: 'post', + data: { + keyword, + osvName: osvName === 'all' ? '' : osvName, + type: type === 'all' ? '' : type, + pages: { + page, + size: pageSize + }, + }, + success(result) { + let res = { + totalRecords: result.result.totalCount, + list: result.result.osvList + } + if (result) { + resolve(res); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +} + +//获取OS厂商选项 +export const getOsName = () => { + return new Promise((resolve,reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/osv/getOsName', + type: 'get', + success(result) { + if(result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }) + }); +}; + +//获取分类选项 +export const getType = () => { + return new Promise((resolve,reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/osv/getType', + type: 'get', + success(result) { + if(result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }) + }); +}; + + //点击查看报告 + export const getApproveReport = ({ + id +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: 'cve-security-notice-server/osv/getOne', + type: 'get', + params: { + id: id + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/blogCount.js b/web-ui/docs/.vuepress/api/blogCount.js new file mode 100644 index 0000000000000000000000000000000000000000..56d223ecda8d9ad770d9473f444c978f1df42b28 --- /dev/null +++ b/web-ui/docs/.vuepress/api/blogCount.js @@ -0,0 +1,85 @@ +/** + * @file 博客页浏览次数接口配置文件 + * */ + +import appAjax from '../libs/ajax-utils'; +//1 博客访问量列表 +export const blogVisitList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/blog/list', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + + }); +}; +//2 博客访问量详情 +export const blogVisitDetail = ({ + title, + date, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/blog/one', + type: 'post', + data: { + title, + date, + lang + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +// 3增加博客访问量 +export const addVisit = ({ + title, + date, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/blog/visit', + type: 'post', + data: { + title, + date, + lang + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/common.js b/web-ui/docs/.vuepress/api/common.js new file mode 100644 index 0000000000000000000000000000000000000000..063c9a7266dcea058d45a47401b713ab970a94d9 --- /dev/null +++ b/web-ui/docs/.vuepress/api/common.js @@ -0,0 +1,24 @@ +/** + * @file 活动相关接口 + * */ + +import appAjax from '../libs/ajax-utils'; + +export const getGiteeJson = (url) => { + return new Promise((resolve,reject) => { + appAjax.postJson({ + url: `get/json/?path=${url}`, + type: 'get', + success(result) { + if(result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }) + }); +}; diff --git a/web-ui/docs/.vuepress/api/communityService.js b/web-ui/docs/.vuepress/api/communityService.js new file mode 100644 index 0000000000000000000000000000000000000000..09af0faa8985a0a85b8507b7ac967e46731d57eb --- /dev/null +++ b/web-ui/docs/.vuepress/api/communityService.js @@ -0,0 +1,125 @@ +/** + *社区认证请求接口 + * */ + +import appAjax from './../libs/ajax-utils'; +const authApi = '-certification'; +const pravacyMethods = { + resolveLang(lang) { + return (lang == "zh"?false:lang == "en"?"en-US":"ru-RU"); + } +} +export const getCode = (email,lang) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + notAuthorization: true, + otherBaseUrl: authApi, + url: '/certification/list/verifyCode', + type: 'GET', + params:{ + email, + }, + headLanguage: pravacyMethods.resolveLang(lang), + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + + }); +}; + +export const searchCard = (params,lang) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + notAuthorization: true, + otherBaseUrl: authApi, + url: '/certification/list', + type: 'GET', + params, + headLanguage: pravacyMethods.resolveLang(lang), + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + }); +}; +export const downCard = (params,lang) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + notAuthorization: true, + otherBaseUrl: authApi, + url: '/certification', + type: 'GET', + params, + headLanguage: pravacyMethods.resolveLang(lang), + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + }); +}; +export const refleshDownUrl = (params,lang) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + notAuthorization: true, + otherBaseUrl: authApi, + url: '/refreshDonwnurl', + type: 'GET', + params, + headLanguage: pravacyMethods.resolveLang(lang), + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + }); +}; +export const refleshDownCard = (params,lang) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + notAuthorization: true, + otherBaseUrl: authApi, + url: '/refreshDonwnurl', + type: 'PATCH', + params, + headLanguage: pravacyMethods.resolveLang(lang), + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/compatibility.js b/web-ui/docs/.vuepress/api/compatibility.js new file mode 100644 index 0000000000000000000000000000000000000000..96319802f76570525b8773e096b1f1061521b71d --- /dev/null +++ b/web-ui/docs/.vuepress/api/compatibility.js @@ -0,0 +1,403 @@ +/** + * @file 兼容性页面及详情接口配置文件 + * */ + +import appAjax from '../libs/ajax-utils'; +const cveApi = '-cve'; + +// 1. 硬件列表 +export const hardwareList = ({ + keyword, + os, + architecture, + page, + cpu, + pageSize, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/findAll', + type: 'post', + data: { + keyword, + os: os === 'all' ? '' : os, + cpu: cpu === 'all' ? '' : cpu, + architecture: architecture === 'all' ? '' : architecture, + pages: { + page, + size: pageSize + }, + lang + }, + success(result) { + let res = { + totalRecords: result.result.totalCount, + list: result.result.hardwareCompList + } + if (result) { + resolve(res); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +} + +// 2. 驱动列表 +export const driverList = ({ + keyword, + os, + architecture, + page, + pageSize, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/drivercomp/findAll', + type: 'post', + data: { + keyword, + os: os === 'all' ? '' : os, + architecture: architecture === 'all' ? '' : architecture, + pages: { + page, + size: pageSize + }, + lang + }, + success(result) { + let res = { + totalRecords: result.result.totalCount, + list: result.result.driverCompList + } + if (result) { + resolve(res); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +} + + +// 3. 驱动--操作系统的下拉列表 +export const driverOSOptions = ({ + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/drivercomp/getOS', + type: 'get', + params: { + lang: lang + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +// 4. 驱动--架构的下拉列表 +export const driverArchitectureOptions = ({ + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/drivercomp/getArchitecture', + type: 'get', + params: { + lang: lang + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +// 5. 硬件--操作系统的下拉列表 +export const hardwareOSOptions = ({ + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/getOS', + type: 'get', + params: { + lang: lang + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +// 6. 硬件--架构的下拉列表 +export const hardwareArchitectureOptions = ({ + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/getArchitecture', + type: 'get', + params: { + lang: lang + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + + +// 7. 详情页查询 +export const detailList = ({ + id +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/getOne', + type: 'get', + params: { + id: id + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +// 8. 详情页查询--列表 +export const detailAapterList = ({ + id +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/getAdapterList', + type: 'get', + params: { + hardwareId: id + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +//9. 软件列表 +export const softwareList = ({ + keyword, + os, + architecture, + page, + type, + lang +}) => { + return new Promise((resolve, reject) => { + os = os ? `&os=${os}` : ""; + architecture = architecture ? `&arch=${architecture}` : ""; + type = type ? `&type=${type}` : ""; + keyword = keyword ? `&keyword=${keyword}` :""; + appAjax.postJson({ + url: `https://api.compass-ci.openeuler.org/web_backend/compat_software_info?page_size=10&page_num=${page}${type}${architecture}${os}${keyword}`, + type: 'get', + notAuthorization:true, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +} +// 10. 软件--操作系统的下拉列表 +export const softwareOptions = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: 'https://api.compass-ci.openeuler.org/web_backend/query_compat_software', + type: 'get', + notAuthorization:true, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +//11. 硬件cpu 下拉选项获取 +export const hardwareCpuOptions = ({ + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/hardwarecomp/getCpu', + type: 'get', + params: { + lang: lang + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +//12. 商业软件列表 +export const businessSoftwareList = ({ + keyword, + osName, + page, + testOrganization, + lang +}) => { + return new Promise((resolve, reject) => { + osName = osName ? `&osName=${osName}` : ""; + testOrganization = testOrganization ? `&testOrganization=${testOrganization}` : ""; + keyword = keyword ? `&keyword=${keyword}` :""; + appAjax.postJson({ + url: `https://shanhaitujian.cn/certification/software/communityChecklist?pageSize=10&pageNo=${page}${testOrganization}${osName}${keyword}`, + type: 'get', + timeout: 3000, + notAuthorization:true, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +//13. 商业软件--筛选框下拉列表 +export const businessSoftwareOptions = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: 'https://shanhaitujian.cn/certification/software/filterCriteria', + type: 'get', + timeout: 3000, + notAuthorization:true, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/docDetail.js b/web-ui/docs/.vuepress/api/docDetail.js new file mode 100644 index 0000000000000000000000000000000000000000..c1f5f00b3029586a4bac1465093e7a40cf348b4c --- /dev/null +++ b/web-ui/docs/.vuepress/api/docDetail.js @@ -0,0 +1,25 @@ +//获取文档目录配置接口 +import appAjax from './../libs/ajax-utils'; +export const catalogList = ( + versionType, + langType +) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: `/docs/menu?version=${versionType}&lang=${langType}/`, + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/home.js b/web-ui/docs/.vuepress/api/home.js new file mode 100644 index 0000000000000000000000000000000000000000..d6a720a9f1f3717098815f42160ca50db3b56f5b --- /dev/null +++ b/web-ui/docs/.vuepress/api/home.js @@ -0,0 +1,50 @@ +/** + * @file 首页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +const sigApi = '-sig'; +export const meetingList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: '/meetingsdata/', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +export const statisticsList = ({ + type +}) => { + return new Promise((resolve,reject) => { + appAjax.postJson({ + url: '/search/statistics', + type: 'get', + params: { + type + }, + success(result) { + if(result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + }); +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/internship.js b/web-ui/docs/.vuepress/api/internship.js new file mode 100644 index 0000000000000000000000000000000000000000..b470d01d40c1c65de9a18e01c541c13420b3a8c0 --- /dev/null +++ b/web-ui/docs/.vuepress/api/internship.js @@ -0,0 +1,95 @@ +/** + * @file 实习页面gitee积分接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +const rankApi = '-rank'; +export const getToken = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: rankApi, + url: '/intern/admin/login', + type: 'post', + data: { + userName: "admin", + passWord:"admin" + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +export const getRank = ({ + token, + userId, + pageSize, + currentPage +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: rankApi, + url: `/intern/points/lists`, + type: 'get', + params: { + token:token, + currentPage:1, + pageSize, + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +export const getRankDetail = ({ + token, + userId, + pageSize, + currentPage +}) => { + return new Promise((resolve, reject) => { + console.log(token,pageSize); + appAjax.postJson({ + otherBaseUrl: rankApi, + url: '/intern/user/points', + type: 'get', + params: { + token:token, + currentPage:1, + pageSize:10, + userId:userId + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/maillist.js b/web-ui/docs/.vuepress/api/maillist.js new file mode 100644 index 0000000000000000000000000000000000000000..e1576850ef0b700c9c642b01c622f6472abe31fd --- /dev/null +++ b/web-ui/docs/.vuepress/api/maillist.js @@ -0,0 +1,25 @@ +/** + * @file 邮件列表页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +export const mailList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/mail/list', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/mailsubscribe.js b/web-ui/docs/.vuepress/api/mailsubscribe.js new file mode 100644 index 0000000000000000000000000000000000000000..d5b8727c3f50fcf2d97c78f9ed5057d7a0f52188 --- /dev/null +++ b/web-ui/docs/.vuepress/api/mailsubscribe.js @@ -0,0 +1,34 @@ +/** + * @file 邮件列表页订阅接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +export const subscribe = ({ + list_id, + subscriber, + display_name +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/mail/add', + type: 'post', + data: { + list_id, + subscriber, + display_name + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/meetup.js b/web-ui/docs/.vuepress/api/meetup.js new file mode 100644 index 0000000000000000000000000000000000000000..b39dcd052900505aef3e12e740eec7e71cf66d29 --- /dev/null +++ b/web-ui/docs/.vuepress/api/meetup.js @@ -0,0 +1,49 @@ +/** + * @file 沙龙页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +const sigApi = '-sig'; +export const eventsList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: '/activities/', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const eventDetail = (id) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: `/activity/${id}/`, + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/mirror.js b/web-ui/docs/.vuepress/api/mirror.js new file mode 100644 index 0000000000000000000000000000000000000000..f4bd292bbe9f75fd0543c0c8d6e103a5e1d8a42f --- /dev/null +++ b/web-ui/docs/.vuepress/api/mirror.js @@ -0,0 +1,67 @@ +/** + * @file 镜像获取接口配置文件 + * */ + + import appAjax from '../libs/ajax-utils'; + const mirrorApi = '-mirror'; + + export const getAllMirror = () => { + return new Promise((resolve,reject) => { + appAjax.postJson({ + otherBaseUrl: mirrorApi, + url: '/?mirrorstats=true', + type: 'get', + success(result) { + if(result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }) + }); + }; + //百度地图ak注册脚本 + export const loadBMap = (ak)=> { + return new Promise(function(resolve, reject) { + if (typeof BMap !== 'undefined') { + resolve(BMap) + return true + } + window.onBMapCallback = function() { + resolve(BMap) + } + let script = document.createElement('script') + script.type = 'text/javascript' + script.src = + 'https://api.map.baidu.com/api?v=2.0&ak=' + ak + '&callback=onBMapCallback' + script.onerror = reject + document.head.appendChild(script) + }) +} +// 镜像选择 +export const selectMirror = ({version}) => { + let env = window.location.host; + let url = null; + env.includes('openeuler') ? url = `https://api.openeuler.org/mirrors/openEuler-${version}/ISO/`:url =`/openEuler-${version}/ISO/` + return new Promise((resolve,reject) => { + appAjax.postJson({ + otherBaseUrl: mirrorApi, + url: url, + type: 'get', + success(result) { + if(result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }) + }); + }; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/newsCount.js b/web-ui/docs/.vuepress/api/newsCount.js new file mode 100644 index 0000000000000000000000000000000000000000..eb9a9da63527867011efa14da2b6c8b0332ea8da --- /dev/null +++ b/web-ui/docs/.vuepress/api/newsCount.js @@ -0,0 +1,85 @@ +/** + * @file 新闻页浏览次数接口配置文件 + * */ + +import appAjax from '../libs/ajax-utils'; +//1 新闻访问量列表 +export const newsVisitList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/news/list', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + }); + + }); +}; +//2 新闻访问量详情 +export const newsVisitDetail = ({ + title, + date, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/news/one', + type: 'post', + data: { + title, + date, + lang + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; +// 3增加新闻访问量 +export const addVisit = ({ + title, + date, + lang +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/news/visit', + type: 'post', + data: { + title, + date, + lang + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/search.js b/web-ui/docs/.vuepress/api/search.js new file mode 100644 index 0000000000000000000000000000000000000000..2ee79e5137fd2cf68d9ee744df196d03668cb65b --- /dev/null +++ b/web-ui/docs/.vuepress/api/search.js @@ -0,0 +1,64 @@ +/** + * @file 搜索页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +export const search = ({ + keyword, + model, + indexEs, + version, + page, +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/search/keyword', + type: 'post', + data: { + keyword, + model: model == 'all' ? '' : model, + indexEs, + version, + page, + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const repoSearch = ({ + keyword + }) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + url: '/repo/search', + type: 'get', + params: { + keyword + }, + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); + }; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/security.js b/web-ui/docs/.vuepress/api/security.js new file mode 100644 index 0000000000000000000000000000000000000000..ca4645d0428c989cf89c84c9bb77f5603a3986f7 --- /dev/null +++ b/web-ui/docs/.vuepress/api/security.js @@ -0,0 +1,228 @@ +/** + * @file 安全页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +const cveApi = '-cve'; +export const securityList = ({ + keyword, + page, + pageSize, + type, + year +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/securitynotice/findAll', + type: 'post', + data: { + keyword, + type, + year: year === '0' ? '' : year, + pages: { + page, + size: pageSize + } + }, + success(result) { + let res = { + totalRecords: result.result.totalCount, + list: result.result.securityNoticeList + } + if (result) { + resolve(res); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + + +export const cveList = ({ + keyword, + page, + pageSize, + status +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/cvedatabase/findAll', + type: 'post', + data: { + keyword, + status, + pages: { + page, + size: pageSize + } + }, + success(result) { + let res = { + totalRecords: result.result.totalCount, + list: result.result.cveDatabaseList + } + if (result) { + resolve(res); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const securityDetail = ({ + sn +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/securitynotice/getBySecurityNoticeNo', + type: 'get', + params: { + securityNoticeNo: sn + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const cveDetail = ({ + cveId, + packageName +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/cvedatabase/getByCveIdAndPackageName', + type: 'get', + params: { + cveId, + packageName + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const getAffectedProduct = ({ + cveId, + affectedComponent +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/securitynotice/byCveIdAndAffectedComponent', + type: 'get', + params: { + cveId, + affectedComponent + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const getPackage = ({ + cveId, + packageName +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/cvedatabase/getCVEProductPackageList', + type: 'get', + params: { + cveId, + packageName + + }, + success(result) { + if (result) { + resolve(result.result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const getDownloadUrl = ({ + id +}) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: cveApi, + url: '/cve-security-notice-server/securitynotice/getPackageLink', + type: 'post', + data: { + packageName: id + }, + success(result) { + if (result) { + resolve(result.result[0]); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/api/sig.js b/web-ui/docs/.vuepress/api/sig.js new file mode 100644 index 0000000000000000000000000000000000000000..9fab5bd74f85817c5d52576308381a34d0e8499e --- /dev/null +++ b/web-ui/docs/.vuepress/api/sig.js @@ -0,0 +1,71 @@ +/** + * @file 安全页接口配置文件 + * */ + +import appAjax from './../libs/ajax-utils'; +const sigApi = '-sig'; +export const sigList = () => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: '/sigs/', + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const sigDetail = (id) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: `/sigmeetingsdata/${id}/`, + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; + +export const sigMember = (id) => { + return new Promise((resolve, reject) => { + appAjax.postJson({ + otherBaseUrl: sigApi, + url: `/groups/${id}/`, + type: 'get', + success(result) { + if (result) { + resolve(result); + return; + } + reject(result); + }, + error(msg) { + reject(msg); + } + + }); + + }); +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/activities/activities.vue b/web-ui/docs/.vuepress/components/activities/activities.vue new file mode 100644 index 0000000000000000000000000000000000000000..bb1255fb35199eccf712b1d4facde11ee9bb0684 --- /dev/null +++ b/web-ui/docs/.vuepress/components/activities/activities.vue @@ -0,0 +1,979 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/activities/newyear.vue b/web-ui/docs/.vuepress/components/activities/newyear.vue new file mode 100644 index 0000000000000000000000000000000000000000..093b829e9ea797024217e93f7b24f9f0430a7dce --- /dev/null +++ b/web-ui/docs/.vuepress/components/activities/newyear.vue @@ -0,0 +1,830 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/approve/approve.vue b/web-ui/docs/.vuepress/components/approve/approve.vue new file mode 100644 index 0000000000000000000000000000000000000000..c5ae7642e7373eb6b96f6fbd3e3c706ee8baee00 --- /dev/null +++ b/web-ui/docs/.vuepress/components/approve/approve.vue @@ -0,0 +1,533 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/approve/approveInfo.vue b/web-ui/docs/.vuepress/components/approve/approveInfo.vue new file mode 100644 index 0000000000000000000000000000000000000000..69df67ff63a655b09bc6fbe5ee5d3e69838e1056 --- /dev/null +++ b/web-ui/docs/.vuepress/components/approve/approveInfo.vue @@ -0,0 +1,335 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/approve/approveStep.vue b/web-ui/docs/.vuepress/components/approve/approveStep.vue new file mode 100644 index 0000000000000000000000000000000000000000..917a1ded8e4c90b94e03938d831cdb5576f931b8 --- /dev/null +++ b/web-ui/docs/.vuepress/components/approve/approveStep.vue @@ -0,0 +1,249 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/blog/blogList.vue b/web-ui/docs/.vuepress/components/blog/blogList.vue new file mode 100644 index 0000000000000000000000000000000000000000..573259a33c365ed06f753f2d078addb902f9212a --- /dev/null +++ b/web-ui/docs/.vuepress/components/blog/blogList.vue @@ -0,0 +1,948 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/blog/postBlog.vue b/web-ui/docs/.vuepress/components/blog/postBlog.vue new file mode 100644 index 0000000000000000000000000000000000000000..e5588cbf18b676d7021c6c90017a7158b8ae7748 --- /dev/null +++ b/web-ui/docs/.vuepress/components/blog/postBlog.vue @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/brand/brand.vue b/web-ui/docs/.vuepress/components/brand/brand.vue new file mode 100644 index 0000000000000000000000000000000000000000..2d1bad71c84ff581e0e7d9d700b9260becade0ac --- /dev/null +++ b/web-ui/docs/.vuepress/components/brand/brand.vue @@ -0,0 +1,251 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/building/building.vue b/web-ui/docs/.vuepress/components/building/building.vue new file mode 100644 index 0000000000000000000000000000000000000000..1f01c6b9e711ab579e7501b04bc52e41635056b8 --- /dev/null +++ b/web-ui/docs/.vuepress/components/building/building.vue @@ -0,0 +1,36 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/common/anchor.vue b/web-ui/docs/.vuepress/components/common/anchor.vue new file mode 100644 index 0000000000000000000000000000000000000000..b1aea8b284f8a187ae89784bb8b4b439e210f1ab --- /dev/null +++ b/web-ui/docs/.vuepress/components/common/anchor.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/common/banner.vue b/web-ui/docs/.vuepress/components/common/banner.vue new file mode 100644 index 0000000000000000000000000000000000000000..5306502402f578f4184bb0c0d2b3a9c6e5eaa056 --- /dev/null +++ b/web-ui/docs/.vuepress/components/common/banner.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/common/mesbanner.vue b/web-ui/docs/.vuepress/components/common/mesbanner.vue new file mode 100644 index 0000000000000000000000000000000000000000..77e3b305ae38f8a553ffb922755a164c08b0ef5c --- /dev/null +++ b/web-ui/docs/.vuepress/components/common/mesbanner.vue @@ -0,0 +1,122 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/community/conduct.vue b/web-ui/docs/.vuepress/components/community/conduct.vue new file mode 100644 index 0000000000000000000000000000000000000000..55c31a7d5b614bde6a5071d5b124ace09acc7ea0 --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/conduct.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/community/contribution.vue b/web-ui/docs/.vuepress/components/community/contribution.vue new file mode 100644 index 0000000000000000000000000000000000000000..396ae06c276005519f0074e716facce4b624f23b --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/contribution.vue @@ -0,0 +1,798 @@ + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/community/contributionDetail.vue b/web-ui/docs/.vuepress/components/community/contributionDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..abc9cf59d03c654e638881bc36305c58fc7ac316 --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/contributionDetail.vue @@ -0,0 +1,50 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/community/down.vue b/web-ui/docs/.vuepress/components/community/down.vue new file mode 100644 index 0000000000000000000000000000000000000000..30b507d878fc84b92a05145aa765a39d6482479e --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/down.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/community/maillist.vue b/web-ui/docs/.vuepress/components/community/maillist.vue new file mode 100644 index 0000000000000000000000000000000000000000..d4007ac712623e1b7932da5a9a3cf8c82f4006d8 --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/maillist.vue @@ -0,0 +1,800 @@ + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/community/search.vue b/web-ui/docs/.vuepress/components/community/search.vue new file mode 100644 index 0000000000000000000000000000000000000000..16453800c19dea40a0934a805ac451863845e18d --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/search.vue @@ -0,0 +1,421 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/community/service.vue b/web-ui/docs/.vuepress/components/community/service.vue new file mode 100644 index 0000000000000000000000000000000000000000..d2436111c2660159385261c0ac811d74401feb3e --- /dev/null +++ b/web-ui/docs/.vuepress/components/community/service.vue @@ -0,0 +1,230 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/compatibility/compatibility.vue b/web-ui/docs/.vuepress/components/compatibility/compatibility.vue new file mode 100644 index 0000000000000000000000000000000000000000..5ae20d28646d637b5e84377c07f198811a89f48b --- /dev/null +++ b/web-ui/docs/.vuepress/components/compatibility/compatibility.vue @@ -0,0 +1,1144 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/compatibility/hardware.vue b/web-ui/docs/.vuepress/components/compatibility/hardware.vue new file mode 100644 index 0000000000000000000000000000000000000000..60b3f0d14ab9485cb5b2a7c407f3a13d884ec366 --- /dev/null +++ b/web-ui/docs/.vuepress/components/compatibility/hardware.vue @@ -0,0 +1,293 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/compatibility/hardwareInfo.vue b/web-ui/docs/.vuepress/components/compatibility/hardwareInfo.vue new file mode 100644 index 0000000000000000000000000000000000000000..53bd8eaa9a65733fed942d50f15f3ed3d1bbfafa --- /dev/null +++ b/web-ui/docs/.vuepress/components/compatibility/hardwareInfo.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/compatibility/software.vue b/web-ui/docs/.vuepress/components/compatibility/software.vue new file mode 100644 index 0000000000000000000000000000000000000000..7176933d4e3a5f9bdb9674205e5c4c7e581d4b0c --- /dev/null +++ b/web-ui/docs/.vuepress/components/compatibility/software.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/controll/videoctrl.vue b/web-ui/docs/.vuepress/components/controll/videoctrl.vue new file mode 100644 index 0000000000000000000000000000000000000000..f8c777bd0f5d3e55aa6316920fd6e6262f1be1d4 --- /dev/null +++ b/web-ui/docs/.vuepress/components/controll/videoctrl.vue @@ -0,0 +1,172 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/download/download.vue b/web-ui/docs/.vuepress/components/download/download.vue new file mode 100644 index 0000000000000000000000000000000000000000..4cfe7ec00bd86fb9ed4c6c87c8d931953ff34840 --- /dev/null +++ b/web-ui/docs/.vuepress/components/download/download.vue @@ -0,0 +1,682 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/download/map.vue b/web-ui/docs/.vuepress/components/download/map.vue new file mode 100644 index 0000000000000000000000000000000000000000..f1833bfeb9abec4aa27d92a7969025c83e779299 --- /dev/null +++ b/web-ui/docs/.vuepress/components/download/map.vue @@ -0,0 +1,336 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/download/mirList.vue b/web-ui/docs/.vuepress/components/download/mirList.vue new file mode 100644 index 0000000000000000000000000000000000000000..31034f670e4c0ca5d546a87c2ba647af55356761 --- /dev/null +++ b/web-ui/docs/.vuepress/components/download/mirList.vue @@ -0,0 +1,315 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/download/mirSelect.vue b/web-ui/docs/.vuepress/components/download/mirSelect.vue new file mode 100644 index 0000000000000000000000000000000000000000..995f272c1b16e559a7b4dd887781e698b977169a --- /dev/null +++ b/web-ui/docs/.vuepress/components/download/mirSelect.vue @@ -0,0 +1,332 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/home/calender.vue b/web-ui/docs/.vuepress/components/home/calender.vue new file mode 100644 index 0000000000000000000000000000000000000000..a8ab76f3fa011d7e105b082769121c3e52623069 --- /dev/null +++ b/web-ui/docs/.vuepress/components/home/calender.vue @@ -0,0 +1,714 @@ + + + diff --git a/web-ui/docs/.vuepress/components/home/calenderDetail.vue b/web-ui/docs/.vuepress/components/home/calenderDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..8623acf29c6b3c74cbd6f5be26a7e4e78b052efa --- /dev/null +++ b/web-ui/docs/.vuepress/components/home/calenderDetail.vue @@ -0,0 +1,161 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/home/home.vue b/web-ui/docs/.vuepress/components/home/home.vue new file mode 100644 index 0000000000000000000000000000000000000000..d8d701bc8dcf3003675f4bcef27315bfeca197cd --- /dev/null +++ b/web-ui/docs/.vuepress/components/home/home.vue @@ -0,0 +1,2358 @@ + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/internship/internship.vue b/web-ui/docs/.vuepress/components/internship/internship.vue new file mode 100644 index 0000000000000000000000000000000000000000..238a0fb75eae3ba6438367c3f815be8064baf128 --- /dev/null +++ b/web-ui/docs/.vuepress/components/internship/internship.vue @@ -0,0 +1,1654 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/learn/moocDetail.vue b/web-ui/docs/.vuepress/components/learn/moocDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..4c1349ec005849773ed801b5f87592f04d956864 --- /dev/null +++ b/web-ui/docs/.vuepress/components/learn/moocDetail.vue @@ -0,0 +1,632 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/learn/moocList.vue b/web-ui/docs/.vuepress/components/learn/moocList.vue new file mode 100644 index 0000000000000000000000000000000000000000..7e7227efec27bbed12b62367f33696845b78f51f --- /dev/null +++ b/web-ui/docs/.vuepress/components/learn/moocList.vue @@ -0,0 +1,151 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/live/liveList.vue b/web-ui/docs/.vuepress/components/live/liveList.vue new file mode 100644 index 0000000000000000000000000000000000000000..c5d831bf82ef62e4b334307faaf256bc1a9e3105 --- /dev/null +++ b/web-ui/docs/.vuepress/components/live/liveList.vue @@ -0,0 +1,386 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/meetups/meetUpDetail.vue b/web-ui/docs/.vuepress/components/meetups/meetUpDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..bd077af16eb62b514afa1fe8439bd7d72772259d --- /dev/null +++ b/web-ui/docs/.vuepress/components/meetups/meetUpDetail.vue @@ -0,0 +1,656 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/meetups/meetUps.vue b/web-ui/docs/.vuepress/components/meetups/meetUps.vue new file mode 100644 index 0000000000000000000000000000000000000000..d70f0f4f788d0995434b7b7907fb42b15daccb28 --- /dev/null +++ b/web-ui/docs/.vuepress/components/meetups/meetUps.vue @@ -0,0 +1,367 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/minisite/SourceDownload.vue b/web-ui/docs/.vuepress/components/minisite/SourceDownload.vue new file mode 100644 index 0000000000000000000000000000000000000000..74505de578b08d779e19d5a9720c47c1a20da554 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/SourceDownload.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/minisite/aTune.vue b/web-ui/docs/.vuepress/components/minisite/aTune.vue new file mode 100644 index 0000000000000000000000000000000000000000..ca3d55a8716300e114eee5a910bca1b933ddf366 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/aTune.vue @@ -0,0 +1,219 @@ + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/banner.vue b/web-ui/docs/.vuepress/components/minisite/banner.vue new file mode 100644 index 0000000000000000000000000000000000000000..b21a8e192f9d511951d41af46bf99a590dc85491 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/banner.vue @@ -0,0 +1,84 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/bisheng.vue b/web-ui/docs/.vuepress/components/minisite/bisheng.vue new file mode 100644 index 0000000000000000000000000000000000000000..fd92938054a150b13a40acea79a3689b9edd0043 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/bisheng.vue @@ -0,0 +1,381 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/content.vue b/web-ui/docs/.vuepress/components/minisite/content.vue new file mode 100644 index 0000000000000000000000000000000000000000..2a1fb0008b3d7ec82a0f508541014a0b21c5179c --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/content.vue @@ -0,0 +1,108 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/description.vue b/web-ui/docs/.vuepress/components/minisite/description.vue new file mode 100644 index 0000000000000000000000000000000000000000..63fbe5cdc5a27542329c4298101dcf1409f29cda --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/description.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/document.vue b/web-ui/docs/.vuepress/components/minisite/document.vue new file mode 100644 index 0000000000000000000000000000000000000000..376a1192b7cb913382e66d7ea023768de786312b --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/document.vue @@ -0,0 +1,134 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/framework.vue b/web-ui/docs/.vuepress/components/minisite/framework.vue new file mode 100644 index 0000000000000000000000000000000000000000..8bbcb1baea570f81a34877e9e744e658a29133f7 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/framework.vue @@ -0,0 +1,91 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/iSula.vue b/web-ui/docs/.vuepress/components/minisite/iSula.vue new file mode 100644 index 0000000000000000000000000000000000000000..335f829cfed8da6e9ad85695a32d89cbefa43d7c --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/iSula.vue @@ -0,0 +1,425 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/imglink.vue b/web-ui/docs/.vuepress/components/minisite/imglink.vue new file mode 100644 index 0000000000000000000000000000000000000000..54d6ba0b5b05d5749d4d3dcae37a984988a48015 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/imglink.vue @@ -0,0 +1,114 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/migration.vue b/web-ui/docs/.vuepress/components/minisite/migration.vue new file mode 100644 index 0000000000000000000000000000000000000000..9d2f2bbf88d15227728d114f5f8c5e89b9e7b9f2 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/migration.vue @@ -0,0 +1,711 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/minisite/scheme.vue b/web-ui/docs/.vuepress/components/minisite/scheme.vue new file mode 100644 index 0000000000000000000000000000000000000000..d4bde1a08bccbf80182bc2a700ba0f5979501d64 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/scheme.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/minisite/secgear.vue b/web-ui/docs/.vuepress/components/minisite/secgear.vue new file mode 100644 index 0000000000000000000000000000000000000000..618596c078fe9bbaa7c2882b6c5e617ad49dfe41 --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/secgear.vue @@ -0,0 +1,133 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/minisite/stratoVirt.vue b/web-ui/docs/.vuepress/components/minisite/stratoVirt.vue new file mode 100644 index 0000000000000000000000000000000000000000..983a0e8954adce0111f6387f986cacff664b1e9a --- /dev/null +++ b/web-ui/docs/.vuepress/components/minisite/stratoVirt.vue @@ -0,0 +1,376 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/news/newsHeader.vue b/web-ui/docs/.vuepress/components/news/newsHeader.vue new file mode 100644 index 0000000000000000000000000000000000000000..7d53dcddd2b59b6cc4fcefe743685515dbf871b5 --- /dev/null +++ b/web-ui/docs/.vuepress/components/news/newsHeader.vue @@ -0,0 +1,149 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/news/newsList.vue b/web-ui/docs/.vuepress/components/news/newsList.vue new file mode 100644 index 0000000000000000000000000000000000000000..2da9d6c0cce1e7c6337f49748196abe455a07287 --- /dev/null +++ b/web-ui/docs/.vuepress/components/news/newsList.vue @@ -0,0 +1,353 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/news/postNews.vue b/web-ui/docs/.vuepress/components/news/postNews.vue new file mode 100644 index 0000000000000000000000000000000000000000..d95d3ce4672998bb8620b38643597490046d6f95 --- /dev/null +++ b/web-ui/docs/.vuepress/components/news/postNews.vue @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/other/search.vue b/web-ui/docs/.vuepress/components/other/search.vue new file mode 100644 index 0000000000000000000000000000000000000000..5da7bbe3de4bc5b668ca5b40e4a153911a43c237 --- /dev/null +++ b/web-ui/docs/.vuepress/components/other/search.vue @@ -0,0 +1,415 @@ + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/round/round.vue b/web-ui/docs/.vuepress/components/round/round.vue new file mode 100644 index 0000000000000000000000000000000000000000..309a29224980f19391d27736ecbf54da5ba8cf7f --- /dev/null +++ b/web-ui/docs/.vuepress/components/round/round.vue @@ -0,0 +1,106 @@ + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/security/bulletinDetail.vue b/web-ui/docs/.vuepress/components/security/bulletinDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..81f0e6de487046503c906f8c6d6ec57236ef2953 --- /dev/null +++ b/web-ui/docs/.vuepress/components/security/bulletinDetail.vue @@ -0,0 +1,328 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/security/cveDetail.vue b/web-ui/docs/.vuepress/components/security/cveDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..2b5f4fcf5a109c834624d169c30ffa54bdd3f9e2 --- /dev/null +++ b/web-ui/docs/.vuepress/components/security/cveDetail.vue @@ -0,0 +1,439 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/security/cveList.vue b/web-ui/docs/.vuepress/components/security/cveList.vue new file mode 100644 index 0000000000000000000000000000000000000000..1cf8d08f73d3103eed7df6dc7df1b1bf79e57698 --- /dev/null +++ b/web-ui/docs/.vuepress/components/security/cveList.vue @@ -0,0 +1,547 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/security/reporting.vue b/web-ui/docs/.vuepress/components/security/reporting.vue new file mode 100644 index 0000000000000000000000000000000000000000..05e41c2388299b864ce2247bc6a3d9312b00df18 --- /dev/null +++ b/web-ui/docs/.vuepress/components/security/reporting.vue @@ -0,0 +1,66 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/security/safetyBulletin.vue b/web-ui/docs/.vuepress/components/security/safetyBulletin.vue new file mode 100644 index 0000000000000000000000000000000000000000..b78ae1c26668f42c2299bc73eda47ba003b222f2 --- /dev/null +++ b/web-ui/docs/.vuepress/components/security/safetyBulletin.vue @@ -0,0 +1,443 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/sig/detail.vue b/web-ui/docs/.vuepress/components/sig/detail.vue new file mode 100644 index 0000000000000000000000000000000000000000..98f70ab009a46b06a2e9e58eef0f06285c61baaf --- /dev/null +++ b/web-ui/docs/.vuepress/components/sig/detail.vue @@ -0,0 +1,492 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/sig/guidance.vue b/web-ui/docs/.vuepress/components/sig/guidance.vue new file mode 100644 index 0000000000000000000000000000000000000000..be43157b561bb9f46aef51d1aa0b5e86d6187c8f --- /dev/null +++ b/web-ui/docs/.vuepress/components/sig/guidance.vue @@ -0,0 +1,303 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/sig/list.vue b/web-ui/docs/.vuepress/components/sig/list.vue new file mode 100644 index 0000000000000000000000000000000000000000..e157afd243a684889b9acd1613de0ef691cd31d6 --- /dev/null +++ b/web-ui/docs/.vuepress/components/sig/list.vue @@ -0,0 +1,556 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/sig/role-description.vue b/web-ui/docs/.vuepress/components/sig/role-description.vue new file mode 100644 index 0000000000000000000000000000000000000000..0f8c31885feb88cb587f127b5dcf7106f65b4bfc --- /dev/null +++ b/web-ui/docs/.vuepress/components/sig/role-description.vue @@ -0,0 +1,217 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/sig/role.vue b/web-ui/docs/.vuepress/components/sig/role.vue new file mode 100644 index 0000000000000000000000000000000000000000..5e3d8c501ace41fc27a4e30186c6ddf13c8a8870 --- /dev/null +++ b/web-ui/docs/.vuepress/components/sig/role.vue @@ -0,0 +1,59 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/summit/carousel-2022.vue b/web-ui/docs/.vuepress/components/summit/carousel-2022.vue new file mode 100644 index 0000000000000000000000000000000000000000..4ad0bf6f8ce3b8b6ba2c21a95ecb1b09d773520a --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/carousel-2022.vue @@ -0,0 +1,566 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/summit/carousel.vue b/web-ui/docs/.vuepress/components/summit/carousel.vue new file mode 100644 index 0000000000000000000000000000000000000000..1026fcba721d0d23cc792a449d69072f0ae86ea9 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/carousel.vue @@ -0,0 +1,754 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/summit/devday-2021.vue b/web-ui/docs/.vuepress/components/summit/devday-2021.vue new file mode 100644 index 0000000000000000000000000000000000000000..35a1c88c48d12f30984b1023374fe863495dfe39 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/devday-2021.vue @@ -0,0 +1,1392 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/summit/devday-2022.vue b/web-ui/docs/.vuepress/components/summit/devday-2022.vue new file mode 100644 index 0000000000000000000000000000000000000000..bca11e1316b8e2b5b69b65cb6aa6aa5b1a85ff7d --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/devday-2022.vue @@ -0,0 +1,1798 @@ + + + + diff --git a/web-ui/docs/.vuepress/components/summit/exhibition.vue b/web-ui/docs/.vuepress/components/summit/exhibition.vue new file mode 100644 index 0000000000000000000000000000000000000000..f4d53964d1cdb21b7390bb4736522ff040225b10 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/exhibition.vue @@ -0,0 +1,433 @@ + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/summit/liveroom.vue b/web-ui/docs/.vuepress/components/summit/liveroom.vue new file mode 100644 index 0000000000000000000000000000000000000000..47f5fed65bbf79da35d7d076bb389c4073e7a5f2 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/liveroom.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/summit/summit-home.vue b/web-ui/docs/.vuepress/components/summit/summit-home.vue new file mode 100644 index 0000000000000000000000000000000000000000..4d0e81d923658fe8af9d649c394c0f835a65ecc2 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/summit-home.vue @@ -0,0 +1,856 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/summit/summit-list.vue b/web-ui/docs/.vuepress/components/summit/summit-list.vue new file mode 100644 index 0000000000000000000000000000000000000000..ab8f55b8ff1fa52e23d547f7ff49a8e9a666649e --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/summit-list.vue @@ -0,0 +1,726 @@ + + + + + + diff --git a/web-ui/docs/.vuepress/components/summit/summit-summit.vue b/web-ui/docs/.vuepress/components/summit/summit-summit.vue new file mode 100644 index 0000000000000000000000000000000000000000..917ed64e6fa00ca564d309c1b1a0229cf34a924d --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/summit-summit.vue @@ -0,0 +1,1263 @@ + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/components/summit/titleNav.vue b/web-ui/docs/.vuepress/components/summit/titleNav.vue new file mode 100644 index 0000000000000000000000000000000000000000..1a2898f005b51d8a1027fb0737f28763d7e8a002 --- /dev/null +++ b/web-ui/docs/.vuepress/components/summit/titleNav.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/web-ui/docs/.vuepress/components/timer/countdown.vue b/web-ui/docs/.vuepress/components/timer/countdown.vue new file mode 100644 index 0000000000000000000000000000000000000000..6a7806e961b87db7e038cf633dbfdcf953fd3f07 --- /dev/null +++ b/web-ui/docs/.vuepress/components/timer/countdown.vue @@ -0,0 +1,201 @@ + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/config.js b/web-ui/docs/.vuepress/config.js new file mode 100644 index 0000000000000000000000000000000000000000..690d61711ad19ce85a01361e24952b5b995186bb --- /dev/null +++ b/web-ui/docs/.vuepress/config.js @@ -0,0 +1,136 @@ +module.exports = { + home: false, + title: '', + description: '', + head: [ + ['link', { + rel: 'icon', + href: '/favicon.ico' + }], + ['meta', { + name: 'viewport', + content: 'width=device-width,initial-scale=1,user-scalable=no' + }], + ['script', { + src: '/js/analytics.js' + }], + ['meta', { name: 'keywords', content: 'openEuler, 操作系统, 开放, 生态, 开源, Linux 开源, OS, open, ecosystem, open source, Linux open source'}], + ['meta', { name: 'baidu-site-verification', content: 'code-EWzbQRssNU'}] + ], + markdown: { + lineNumbers: false, + extendMarkdown: md => { + md.disable('emoji'); + } + }, + plugins: [ + ['@vuepress/search', false], + ['@vuepress/active-header-links', false], + ['vuepress-plugin-code-copy', true], + ['sitemap', { + hostname: "https://openeuler.org/" + } + ] + ], + shouldPrefetch: () => { + return false; + }, + locales: { + '/': { + lang: 'zh', + title: '', + description: '' + }, + '/en/': { + lang: 'en', + title: '', + description: 'openEuler is an open source, free Linux distribution platform. The platform provides an open community for global developers to build an open, diversified, and architecture-inclusive software ecosystem. openEuler is also an innovative platform that encourages everyone to propose new ideas, explore new approaches, and practice new solutions.' }, + '/zh/': { + lang: 'zh', + title: '', + description: 'openEuler 是一个开源、免费的 Linux 发行版平台,将通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。同时,openEuler 也是一个创新的平台,鼓励任何人在该平台上提出新想法、开拓新思路、实践新方案。' }, + '/ru/': { + lang: 'ru', + title: '', + description: 'openEuler is an open source, free Linux distribution platform. The platform provides an open community for global developers to build an open, diversified, and architecture-inclusive software ecosystem. openEuler is also an innovative platform that encourages everyone to propose new ideas, explore new approaches, and practice new solutions.' + }, + }, + themeConfig: { + dateFormat: 'YYYY-MM-DD', + locales: { + 'en': { + lang: require('./lang/en.js') + }, + 'zh': { + lang: require('./lang/zh.js') + }, + 'ru': { + lang: require('./lang/ru.js') + } + }, + smoothScroll: true, + docsUrl: 'https://docs.openeuler.org' + + }, + devServer: { + proxy: { + '/api-sig/': { + target: 'https://api.openeuler.org/meetings/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-sig/': '' + } + }, + '/api-cve/': { + target: 'https://www.openeuler.org/api-cve/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-cve/': '' + } + }, + '/api-mirror/': { + target: 'https://api.openeuler.org/mirrors/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-mirror/': '' + } + }, + '/api-rank/': { + target: 'https://api.openeuler.org/osi-task-manager/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-rank/': '' + } + }, + '/api/': { + target: 'https://www.openeuler.org/api/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api/': '' + } + }, + '/api-certification/': { + target: 'https://ccs.openeuler.org/ccs/base/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-certification/': '' + } + }, + '/api-approve/': { + target: 'https://cvesa.test.osinfra.cn/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-approve/': '' + } + }, + } + + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/config.ru.js b/web-ui/docs/.vuepress/config.ru.js new file mode 100644 index 0000000000000000000000000000000000000000..33c91795c13d615f0295a6a6b7f629105c7418e7 --- /dev/null +++ b/web-ui/docs/.vuepress/config.ru.js @@ -0,0 +1,113 @@ +module.exports = { + home: false, + title: '', + description: '', + head: [ + ['link', { + rel: 'icon', + href: '/favicon.ico' + }], + ['meta', { + name: 'viewport', + content: 'width=device-width,initial-scale=1,user-scalable=no' + }], + ['script', { + src: '/js/analytics-ru.js' + }], + ['meta', { name: 'keywords', content: 'openEuler, 操作系统, 开放, 生态, 开源, Linux 开源, OS, open, ecosystem, open source, Linux open source'}], + ['meta', { name: 'baidu-site-verification', content: 'code-EWzbQRssNU'}] + ], + markdown: { + lineNumbers: false, + extendMarkdown: md => { + md.disable('emoji'); + } + }, + plugins: [ + ['@vuepress/search', false], + ['@vuepress/active-header-links', false], + ['vuepress-plugin-code-copy', true], + ['sitemap', { + hostname: "https://ru.openeuler.org/" + } + ] + ], + shouldPrefetch: () => { + return false; + }, + locales: { + '/': { + lang: 'ru', + title: '', + description: '' + }, + '/ru/': { + lang: 'ru', + title: '', + description: 'openEuler is an open source, free Linux distribution platform. The platform provides an open community for global developers to build an open, diversified, and architecture-inclusive software ecosystem. openEuler is also an innovative platform that encourages everyone to propose new ideas, explore new approaches, and practice new solutions.' + }, + }, + themeConfig: { + dateFormat: 'YYYY-MM-DD', + locales: { + 'ru': { + lang: require('./lang/ru.js') + } + }, + smoothScroll: true, + docsUrl: 'https://docs.ru.openeuler.org' + + }, + devServer: { + proxy: { + '/api-sig/': { + target: 'https://api.openeuler.org/meetings/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-sig/': '' + } + }, + '/api-cve/': { + target: 'https://www.openeuler.org/api-cve/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-cve/': '' + } + }, + '/api-mirror': { + target: 'https://api.openeuler.org/mirrors', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-mirror': '' + } + }, + '/api-rank': { + target: 'https://api.openeuler.org/osi-task-manager/', + changeOrigin: true, + pathRewrite: { + '^/api-rank': '' + } + }, + '/api/': { + target: 'https://www.openeuler.org/api/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api/': '' + } + }, + '/api-approve/': { + target: 'https://cvesa.test.osinfra.cn', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-approve/': '' + } + }, + } + + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/config.zh.js b/web-ui/docs/.vuepress/config.zh.js new file mode 100644 index 0000000000000000000000000000000000000000..04a68d023dff5ce9b07697684447b018e937deed --- /dev/null +++ b/web-ui/docs/.vuepress/config.zh.js @@ -0,0 +1,120 @@ +module.exports = { + home: false, + title: '', + description: '', + head: [ + ['link', { + rel: 'icon', + href: '/favicon.ico' + }], + ['meta', { + name: 'viewport', + content: 'width=device-width,initial-scale=1,user-scalable=no' + }], + ['script', { + src: '/js/analytics.js' + }], + ['meta', { name: 'keywords', content: 'openEuler, 操作系统, 开放, 生态, 开源, Linux 开源, OS, open, ecosystem, open source, Linux open source'}], + ['meta', { name: 'baidu-site-verification', content: 'code-EWzbQRssNU'}] + ], + markdown: { + lineNumbers: false, + extendMarkdown: md => { + md.disable('emoji'); + } + }, + plugins: [ + ['@vuepress/search', false], + ['@vuepress/active-header-links', false], + ['vuepress-plugin-code-copy', true], + ['sitemap', { + hostname: "https://openeuler.org/" + } + ] + ], + shouldPrefetch: () => { + return false; + }, + locales: { + '/': { + lang: 'zh', + title: '', + description: '' + }, + '/en/': { + lang: 'en', + title: '', + description: 'openEuler is an open source, free Linux distribution platform. The platform provides an open community for global developers to build an open, diversified, and architecture-inclusive software ecosystem. openEuler is also an innovative platform that encourages everyone to propose new ideas, explore new approaches, and practice new solutions.' }, + '/zh/': { + lang: 'zh', + title: '', + description: 'openEuler 是一个开源、免费的 Linux 发行版平台,将通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。同时,openEuler 也是一个创新的平台,鼓励任何人在该平台上提出新想法、开拓新思路、实践新方案。' } + }, + themeConfig: { + dateFormat: 'YYYY-MM-DD', + locales: { + 'en': { + lang: require('./lang/en.js') + }, + 'zh': { + lang: require('./lang/zh.js') + } + }, + smoothScroll: true, + docsUrl: 'https://docs.openeuler.org' + + }, + devServer: { + proxy: { + '/api-sig/': { + target: 'https://api.openeuler.org/meetings/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-sig/': '' + } + }, + '/api-cve/': { + target: 'https://openeuler.org/api-cve/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-cve/': '' + } + }, + '/api-mirror': { + target: 'https://api.openeuler.org/mirrors', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-mirror': '' + } + }, + '/api-rank': { + target: 'https://api.openeuler.org/osi-task-manager/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-rank': '' + } + }, + '/api/': { + target: 'https://openeuler.org/api/', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api/': '' + } + }, + '/api-approve/': { + target: 'https://cvesa.test.osinfra.cn', + ws: true, + changeOrigin: true, + pathRewrite: { + '^/api-approve/': '' + } + }, + } + + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/data/activities/zh.json b/web-ui/docs/.vuepress/data/activities/zh.json new file mode 100644 index 0000000000000000000000000000000000000000..e0aab286c8a67e89328bd254c71e4e041531408a --- /dev/null +++ b/web-ui/docs/.vuepress/data/activities/zh.json @@ -0,0 +1,698 @@ +[ + { + "ID": 1, + "NAME": "面向overlay文件系统的细粒度化写时拷贝机制", + "LINK" : "https://gitee.com/openeuler/open-source-summer-2022/issues/I5317N?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY":"进阶" + }, + { + "ID": 2, + "NAME": "HPC软件scanorama迁移至openEuler平台", + "LINK" : "https://gitee.com/openeuler/open-source-summer-2022/issues/I53HG0?from=project-issue", + "TECHNOLOGY_FIELD": "HPC", + "TECHNICAL_LABELS": "C,C++,python,Shell", + "DIFFICULTY": "进阶" + }, + { + "ID": 3, + "NAME": "openEuler支持OpenStack-helm", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I53JFV?from=project-issue", + "TECHNOLOGY_FIELD": "云计算", + "TECHNICAL_LABELS": "python", + "DIFFICULTY": "进阶" + }, + { + "ID": 4, + "NAME": "完善 libcareplus 的测试用例", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I546QH?from=project-issue", + "TECHNOLOGY_FIELD": "用户态", + "TECHNICAL_LABELS": "C", + "DIFFICULTY":"基础" + }, + { + "ID": 5, + "NAME": "实现Gazelle 示例程序", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I54B78?from=project-issue", + "TECHNOLOGY_FIELD": "用户态", + "TECHNICAL_LABELS": "C,", + "DIFFICULTY": "进阶" + }, + { + "ID": 6, + "NAME": "使用 Rust 编程语言实现基于 SAT 算法的软件包依赖分析库", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I54DG1?from=project-issue", + "TECHNOLOGY_FIELD": "Rust,软件包依赖", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 7, + "NAME": "基于ebpf的高性能可视化存储IO栈监测分析工具", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I54ES8?from=project-issue", + "TECHNOLOGY_FIELD": "存储,内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 8, + "NAME": "HPC软件OpenLB迁移至openEuler平台", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I54KGB?from=project-issue", + "TECHNOLOGY_FIELD": "HPC", + "TECHNICAL_LABELS": "C,C++,Fortran,python,Shell", + "DIFFICULTY":"进阶" + }, + { + "ID": 9, + "NAME": "基于openEuler构建大数据体验平台", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I54V5D?from=project-issue", + "TECHNOLOGY_FIELD": "大数据", + "TECHNICAL_LABELS": "java,scala", + "DIFFICULTY": "进阶" + }, + { + "ID": 10, + "NAME": "实现镜像体积可视化脚本", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I54S1W?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "python,Shell", + "DIFFICULTY": "基础" + }, + { + "ID": 11, + "NAME": "迁移基于ROS的VIO算法至openEuler平台", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I551XE?from=project-issue", + "TECHNOLOGY_FIELD": "ROS", + "TECHNICAL_LABELS": "C++,CMake", + "DIFFICULTY": "进阶" + }, + { + "ID": 12, + "NAME": "secGear集成UT测试框架,并开发测试用例", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I553LL?from=project-issue", + "TECHNOLOGY_FIELD": "机密计算", + "TECHNICAL_LABELS": "C,CMake", + "DIFFICULTY":"基础" + }, + { + "ID": 13, + "NAME": "开发secGear安全文件系统接口", + "LINK" : "https://gitee.com/openeuler/open-source-summer/issues/I553UC?from=project-issue", + "TECHNOLOGY_FIELD": "机密计算", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 14, + "NAME": "迁移基于ROS2和深度学习的目标检测的算法至openEuler21.03平台", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I555LC?from=project-issue", + "TECHNOLOGY_FIELD": "ROS", + "TECHNICAL_LABELS": "C++,CMake", + "DIFFICULTY": "进阶" + }, + { + "ID": 15, + "NAME": "overlayfs 添加sysfs文件显示载挂载信息", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I558NT?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 16, + "NAME": "基于openEuler gopher的完成应用故障特征向量建模", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I558WC?from=project-issue", + "TECHNOLOGY_FIELD": "智能运维", + "TECHNICAL_LABELS": "C,不限", + "DIFFICULTY": "进阶" + }, + { + "ID": 17, + "NAME": "设计并实现PilotGo的插件方案", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55DPJ?from=project-issue", + "TECHNOLOGY_FIELD": "智能运维", + "TECHNICAL_LABELS": "Vue,golang", + "DIFFICULTY": "进阶" + }, + { + "ID": 18, + "NAME": "用Rust实现RDMA的Linux内核驱动", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55EL7?from=project-issue", + "TECHNOLOGY_FIELD": "Rust,存储", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 19, + "NAME": "实现通过ebpf修改寄存器的接口并给出demo", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55FLX?from=project-issue", + "TECHNOLOGY_FIELD": "ebpf", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 20, + "NAME": "迁移基于ROS2和激光导航的算法至openEuler21.03平台", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55G5F?from=project-issue", + "TECHNOLOGY_FIELD": "ROS", + "TECHNICAL_LABELS": "C++,CMake", + "DIFFICULTY": "进阶" + }, + { + "ID": 21, + "NAME": "为openEuler Embedded新增嵌入式图形栈", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55NIS?from=project-issue", + "TECHNOLOGY_FIELD": "嵌入式", + "TECHNICAL_LABELS": "Qt", + "DIFFICULTY": "进阶" + }, + { + "ID": 22, + "NAME": "为openEuler Embedded集成RISC-V架构支持", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55NQW?from=project-issue", + "TECHNOLOGY_FIELD": "嵌入式", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 23, + "NAME": "用Rust实现高性能网络协议栈DPDK编程接口的封装", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55OX7?from=project-issue", + "TECHNOLOGY_FIELD": "Rust,存储", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 24, + "NAME": "在线业务QoS量化工具", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55Q90?from=project-issue", + "TECHNOLOGY_FIELD": "云原生,容器", + "TECHNICAL_LABELS": "Go,Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 25, + "NAME": "容器事件管理机制重构", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55QBK?from=project-issue", + "TECHNOLOGY_FIELD": "云原生,容器", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + } , + { + "ID": 26, + "NAME": "利用cephfs提供k8s的数据存储能力", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55QQ9?from=project-issue", + "TECHNOLOGY_FIELD": "基础设施,存储,kubernetes", + "TECHNICAL_LABELS": "Python,Go", + "DIFFICULTY": "基础" + }, + { + "ID": 27, + "NAME": "密码策略编辑桌面应用", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55QTM?from=project-issue", + "TECHNOLOGY_FIELD": "桌面应用", + "TECHNICAL_LABELS": "Python,Go,C,C++", + "DIFFICULTY": "进阶" + }, + { + "ID": 28, + "NAME": "基于anchore/syft开源项目生成openEuler SBOM", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55QV1?from=project-issue", + "TECHNOLOGY_FIELD": "安全,rpm", + "TECHNICAL_LABELS": "Python,golang", + "DIFFICULTY": "进阶" + }, + { + "ID": 29, + "NAME": "openEuler会议预定小程序支持多种第三方会议接入", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55RIR?from=project-issue", + "TECHNOLOGY_FIELD": "基础设施,小程序", + "TECHNICAL_LABELS": "python3", + "DIFFICULTY": "基础" + }, + { + "ID": 30, + "NAME": "软件包安装器 优化", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55RK2?from=project-issue", + "TECHNOLOGY_FIELD": "桌面应用,rpm", + "TECHNICAL_LABELS": "Python,Qt", + "DIFFICULTY": "进阶" + }, + { + "ID": 31, + "NAME": "在离线业务(容器)L3 Cache缓存带宽及MBA内存带宽动态隔离", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55RV6?from=project-issue", + "TECHNOLOGY_FIELD": "云原生,容器", + "TECHNICAL_LABELS": "Go,Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 32, + "NAME": "多社区仓库代码备份并定期刷新代码", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55SDG?from=project-issue", + "TECHNOLOGY_FIELD": "基础设施,kubernetes", + "TECHNICAL_LABELS": "golang", + "DIFFICULTY": "基础" + }, + { + "ID": 33, + "NAME": "将vagrant及相关组件引入openEuler", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55T5H?from=project-issue", + "TECHNOLOGY_FIELD": "软件移植,虚拟化", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 34, + "NAME": "StratoVirt trace点优化", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55TE5?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "基础" + }, + { + "ID": 35, + "NAME": "实现KubeOS支持物理机部署", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55UFN?from=project-issue", + "TECHNOLOGY_FIELD": "云原生,容器,kubernetes", + "TECHNICAL_LABELS": "Shell,Go", + "DIFFICULTY": "进阶" + } , + { + "ID": 36, + "NAME": "实现一个类似开源ROW的IO调度器", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55UHJ?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 37, + "NAME": "为openEuler操作系统引入libvirt 8.2.0版本", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55ULJ?from=project-issue", + "TECHNOLOGY_FIELD": "软件移植,虚拟化", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 38, + "NAME": "实现direct-thread-switch轻量级线程切换", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55XHR?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 39, + "NAME": "基于openEuler gopher的openGauss场景SLI测量", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55YNO?from=project-issue", + "TECHNOLOGY_FIELD": "智能运维,ebpf", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 40, + "NAME": "在openEuler中支持Multi-Gen LRU", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I55Z0L?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + } , + { + "ID": 41, + "NAME": "基于secGear实现部分国密算法", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I5606T?from=project-issue", + "TECHNOLOGY_FIELD": "安全,机密计算", + "TECHNICAL_LABELS": "C,C++", + "DIFFICULTY": "基础" + }, + { + "ID": 42, + "NAME": "arm64可靠推栈验证测试", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I561RH?from=project-issue", + "TECHNOLOGY_FIELD": "内核,测试", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 43, + "NAME": "构建SDK工具包采集openEuler官网的埋点数据", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I562PF?from=project-issue", + "TECHNOLOGY_FIELD": "数据埋点,SDK", + "TECHNICAL_LABELS": "JavaScript,Go,Python", + "DIFFICULTY": "基础" + }, + { + "ID": 44, + "NAME": "开发者技能提取", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I563MW?from=project-issue", + "TECHNOLOGY_FIELD": "数据分析,NLP", + "TECHNICAL_LABELS": "python3", + "DIFFICULTY": "基础" + }, + { + "ID": 45, + "NAME": "实现A-Tune服务解耦", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I563WS?from=project-issue", + "TECHNOLOGY_FIELD": "AI,性能调优", + "TECHNICAL_LABELS": "Go", + "DIFFICULTY": "进阶" + } , + { + "ID": 46, + "NAME": "实现A-Tune集群调优", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I563X0?from=project-issue", + "TECHNOLOGY_FIELD": "AI,性能调优", + "TECHNICAL_LABELS": "Go", + "DIFFICULTY": "基础" + }, + { + "ID": 47, + "NAME": "A-Tune-UI后端功能开发", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I563XJ?from=project-issue", + "TECHNOLOGY_FIELD": "后端,AI,性能调优", + "TECHNICAL_LABELS": "Python,Go,js", + "DIFFICULTY": "进阶" + }, + { + "ID": 48, + "NAME": "面向操作系统的智能异常检测方案", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I563XS?from=project-issue", + "TECHNOLOGY_FIELD": "智能运维", + "TECHNICAL_LABELS": "Python", + "DIFFICULTY": "进阶" + }, + { + "ID": 49, + "NAME": "Preempt_RT的实时性瓶颈探针工具", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I564OW?from=project-issue", + "TECHNOLOGY_FIELD": "eBPF,Linux实时性优化", + "TECHNICAL_LABELS": "C,Python", + "DIFFICULTY": "进阶" + }, + { + "ID": 50, + "NAME": "为 StratoVirt 增加 PMU(Performance Monitor Unit) 性能监测特性", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I5653U?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + } , + { + "ID": 51, + "NAME": "优化StratoVirt的错误处理", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56543?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "基础" + }, + { + "ID": 52, + "NAME": "毕昇Fortran编译器内联动态库函数str_copy", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I5662Z?from=project-issue", + "TECHNOLOGY_FIELD": "编译器", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 53, + "NAME": "openEuler Embedded软件包模板实现", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I566AO?from=project-issue", + "TECHNOLOGY_FIELD": "嵌入式", + "TECHNICAL_LABELS": "C,Shell,Python", + "DIFFICULTY": "进阶" + }, + { + "ID": 54, + "NAME": "云原生的ResearchOps/MLops流水线平台构建", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I566CL?from=project-issue", + "TECHNOLOGY_FIELD": "数据分析,kubernetes", + "TECHNICAL_LABELS": "Go,k8s", + "DIFFICULTY": "进阶" + }, + { + "ID": 55, + "NAME": "StratoVirt支持vhost-user-blk磁盘", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I566V4?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + } , + { + "ID": 56, + "NAME": "StratoVirt支持acpi机制的热插拔", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I566W0?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 57, + "NAME": "tomcat性能调优", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I5674S?from=project-issue", + "TECHNOLOGY_FIELD": "AI,性能调优", + "TECHNICAL_LABELS": "Python,Java", + "DIFFICULTY": "进阶" + }, + { + "ID": 58, + "NAME": "基于ResearchOps平台建设社区问答&资源推荐机器人", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I568R4?from=project-issue", + "TECHNOLOGY_FIELD": "AI,NLP", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 59, + "NAME": "基于misc cgroup子系统实现对于cgroup级别的打开文件数的限制", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I569WP?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 60, + "NAME": "实现基于EBPF的TCP数据压缩机制和EBPF策略demo", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56AOJ?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + } , + { + "ID": 61, + "NAME": "多默认网关情况下,DNS报文源IP地址与路由选择的网络接口不匹配问题解决方案", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56B67?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 62, + "NAME": "nfs 增加耗时统计信息", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56B6O?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 63, + "NAME": "StratoVirt支持虚拟机内核调测功能", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56BB8?from=project-issue", + "TECHNOLOGY_FIELD": "虚拟化", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 64, + "NAME": "毕昇编译器应用迁移兼容性问题的解决", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56BLI?from=project-issue", + "TECHNOLOGY_FIELD": "编译器", + "TECHNICAL_LABELS": "C,C++,Fortran", + "DIFFICULTY": "基础" + }, + { + "ID": 65, + "NAME": "源码中矩阵乘识别", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56BNH?from=project-issue", + "TECHNOLOGY_FIELD": "编译器", + "TECHNICAL_LABELS": "C,C++", + "DIFFICULTY": "进阶" + } , + { + "ID": 66, + "NAME": "f2fs 工具 dump 损坏文件", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56BOW?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 67, + "NAME": "openEuler中F2FS压缩算法使能以及优化", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56BQA?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 68, + "NAME": "用Rust for Linux实现内核模块", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56DEQ?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 69, + "NAME": "使用eBPF技术实现Linux内核FUSE模块并支持零拷贝", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56DF5?from=project-issue", + "TECHNOLOGY_FIELD": "内核,eBPF", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 70, + "NAME": "用Rust实现无锁并发Index tree", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56DPB?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + } , + { + "ID": 71, + "NAME": "在BGMProvider中使用Java实现国密相关算法以及国密证书解析", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56E8A?from=project-issue", + "TECHNOLOGY_FIELD": "编译器", + "TECHNICAL_LABELS": "Java", + "DIFFICULTY": "进阶" + }, + { + "ID": 72, + "NAME": "openEuler官网搜索优化", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56ERT?from=project-issue", + "TECHNOLOGY_FIELD": "基础设施,SEO", + "TECHNICAL_LABELS": "ava,springboot,elasticsearch", + "DIFFICULTY": "进阶" + }, + { + "ID": 73, + "NAME": "轻量级死锁检测", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56EZG?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 74, + "NAME": "统计调度各阶段的性能分布", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56F6P?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 75, + "NAME": "xfs文件系统提供一套故障注入机制", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56FCV?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + } , + { + "ID": 76, + "NAME": "openEuler5.10内核支持页表检查功能(page table check)", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56FG1?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "基础" + }, + { + "ID": 77, + "NAME": "实现openEuler和OpenHarmony之间的设备认证", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56I4V?from=project-issue", + "TECHNOLOGY_FIELD": "嵌入式", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 78, + "NAME": "构建/移植基于openEuler的一站式机器学习开发体验生产平台", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56JJN?from=project-issue", + "TECHNOLOGY_FIELD": "软件移植,NLP", + "TECHNICAL_LABELS": "Python,Java,js", + "DIFFICULTY": "进阶" + }, + { + "ID": 79, + "NAME": "openEuler-5.10 支持audit日志批量落盘", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56K30?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 80, + "NAME": "openEuler 移植到 RK3588", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56KG9?from=project-issue", + "TECHNOLOGY_FIELD": "软件移植", + "TECHNICAL_LABELS": "Python,Bash script", + "DIFFICULTY": "进阶" + } , + { + "ID": 81, + "NAME": "为riscv的内核实现kprobe optimizer", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56L2I?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 82, + "NAME": "为openEuler Embedded内核新增Rust语言支持", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56L6F?from=project-issue", + "TECHNOLOGY_FIELD": "嵌入式,RISC-V", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 83, + "NAME": "利用bpf统计内核中alloc_page内存信息", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56LAR?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + }, + { + "ID": 84, + "NAME": "为Rust for Linux增强函数式编程特性", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56LOY?from=project-issue", + "TECHNOLOGY_FIELD": "内核", + "TECHNICAL_LABELS": "Rust", + "DIFFICULTY": "进阶" + }, + { + "ID": 85, + "NAME": "将大数据常用组件impala引入到openEuler", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56QDR?from=project-issue", + "TECHNOLOGY_FIELD": "大数据,软件移植", + "TECHNICAL_LABELS": "Shell", + "DIFFICULTY": "基础" + } , + { + "ID": 86, + "NAME": "将大数据常用组件ambari引入到openEuler", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I56R1J?from=project-issue", + "TECHNOLOGY_FIELD": "大数据,软件移植", + "TECHNICAL_LABELS": "Java", + "DIFFICULTY": "基础" + }, + { + "ID": 87, + "NAME": "支持EFI文件国密签名", + "LINK": "https://gitee.com/openeuler/open-source-summer/issues/I572B7?from=project-issue", + "TECHNOLOGY_FIELD": "安全,基础设施", + "TECHNICAL_LABELS": "C", + "DIFFICULTY": "进阶" + } +] \ No newline at end of file diff --git a/web-ui/docs/.vuepress/data/download.js b/web-ui/docs/.vuepress/data/download.js new file mode 100644 index 0000000000000000000000000000000000000000..6fc566823757aef2735763416759def257c2d30e --- /dev/null +++ b/web-ui/docs/.vuepress/data/download.js @@ -0,0 +1,679 @@ +/** + * @file 资料组维护数据文件 + * */ + +module.exports = { + cn: { + DOWNLOAD_LIST : [ + { + NAME: 'openEuler 22.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-22.03-LTS/', + DESC: 'openEuler 22.03-LTS 是基于5.10内核构建,实现了服务器、云、边缘和嵌入式的全场景支持', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/22.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/22.03_LTS/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WHITE_PAPER: "/whitepaper/openEuler-whitepaper-2203.pdf", + WEBSITE_SELECT: "/zh/mirror/select/?version=22.03-LTS", + SERVER_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + CLOUD_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/virtual_machine_img/', + EDGE_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/edge_img/', + EMBEDDEN_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/embedded_img/', + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2022/03', + LTS: true + }, + { + NAME: 'openEuler 20.03 LTS SP3', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP3/', + DESC: 'openEuler 20.03 LTS SP3 是openEuler 20.03 LTS的补丁版本,生命周期与LTS版本相同', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP3/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP3/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP3/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WEBSITE_SELECT: "/zh/mirror/select/?version=20.03-LTS-SP3", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2021/12', + LTS: true + }, + { + NAME: 'openEuler 21.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.09/', + DESC: 'openEuler 21.09创新版是欧拉全新发布后的第一个社区版本,实现了全场景支持。增强服务器和云计算的特性,发布面向云原生的业务混部CPU调度算法、容器化操作系统KubeOS等关键技术;同时发布边缘和嵌入式版本。', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/21.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/21.09/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.09/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WHITE_PAPER: "https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/pdf/openEuler%2021.09%20%E6%8A%80%E6%9C%AF%E7%99%BD%E7%9A%AE%E4%B9%A6.pdf", + WEBSITE_SELECT: "/zh/mirror/select/?version=21.09", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2021/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP2', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/', + DESC: 'openEuler 20.03 LTS SP2 是openEuler 20.03 LTS的补丁版本,生命周期与LTS版本相同', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP2/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP2/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WEBSITE_SELECT: "/zh/mirror/select/?version=20.03-LTS-SP2", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2021/07', + LTS: true + }, + { + NAME: 'openEuler 21.03', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.03/', + DESC: 'openEuler 21.03 版本是满足开放场景的创新发行版,生命周期六个月。', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/21.03/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/21.03/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.03/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WHITE_PAPER: "/whitepaper/openEuler-whitepaper-2103.pdf", + WEBSITE_SELECT: "/zh/mirror/select/?version=21.03", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2021/03', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP1', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/', + DESC: 'openEuler 20.03 LTS SP1 是openEuler 20.03 LTS的补丁版本,生命周期与LTS版本相同', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP1/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WEBSITE_SELECT: "/zh/mirror/select/?version=20.03-LTS-SP1", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2020/12', + LTS: true + }, + { + NAME: 'openEuler 20.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.09/', + DESC: 'openEuler 20.09 版本是满足开放场景的创新发行版,生命周期六个月。', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/20.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/20.09/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.09/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WHITE_PAPER: "/whitepaper/openEuler-whitepaper-2009.pdf", + WEBSITE_SELECT: "/zh/mirror/select/?version=20.09", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS/', + DESC: 'openEuler 20.03 LTS 版本是满足开放场景的标准发行版,生命周期四年。', + RELEASE_DESC_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS/ISO/', + LIFE_CYCLE_URL: '/zh/other/lifecycle/', + WEBSITE_SELECT: "/zh/mirror/select/?version=20.03-LTS", + MANUFACTURER: 'openEuler社区', + PUBLISH_DATE: '2020/03', + LTS: true + }, + { + NAME: '麒麟信安 Kylinsec', + DOWNLOAD_URL : 'https://mirrors.kylinsec.com.cn/V3.4-4/', + DESC: '暂无描述', + RELEASE_DESC_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846656373a.pdf', + INSTALL_GUIDENCE_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846807a00f.pdf', + SEEK_HELP_URL: '', + GET_ISO_URL: 'https://mirrors.kylinsec.com.cn/V3.4-4/isos/', + LIFE_CYCLE_URL: '', + MANUFACTURER: '麒麟信安 Kylinsec', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'HopeEdge', + DOWNLOAD_URL : 'http://webapp.hoperun.com:8007/', + DESC: '物联网边缘计算操作系统HopeEdge是基于openEuler构建的、面向IoT场景的边缘计算操作系统,具备轻量安全、自主创新、高效互联、快速部署四大关键特性;提供设备管理、数据采集、云边协同、人工智能等功能。', + RELEASE_DESC_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://webapp.hoperun.com:8007/HopeStage/', + LIFE_CYCLE_URL: '', + MANUFACTURER: '江苏润和', + PUBLISH_DATE: '2020/07', + LTS: false + }, + { + NAME: '中科傲来服务器操作系统', + DOWNLOAD_URL : 'https://eulixos.com/#/download', + DESC: '中科傲来服务器操作系统是一款基于openEuler操作系统打造的服务器操作系统发行版,支持X86_64、AArch64、RISC-V等多种处理器架构,适用于数据库、云计算、大数据、人工智能、分布式计算等多种应用场景,具备高安全、高可靠、高性能、跨平台等特点,旨在为各类应用及解决方案提供标准、安全、可靠的操作系统及服务。', + RELEASE_DESC_URL: 'https://eulixos.com/userguide/%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E/%E7%89%88%E6%9C%AC%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E.html', + INSTALL_GUIDENCE_URL: 'https://eulixos.com/userguide/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E5%89%8D%E8%A8%80.html', + SEEK_HELP_URL: 'https://eulixos.com/#/feedback', + GET_ISO_URL: 'https://eulixos.com/#/download', + LIFE_CYCLE_URL: '', + MANUFACTURER: '中科院软件所', + PUBLISH_DATE: '2020/05', + LTS: false + }, + { + NAME: '普华服务器操作系统v5.1', + DOWNLOAD_URL : 'http://www.i-soft.com.cn/type/4/714.jhtml', + DESC: '暂无描述', + RELEASE_DESC_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml', + INSTALL_GUIDENCE_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml ', + SEEK_HELP_URL: 'https://p.qiao.baidu.com/cps4/chatIndex?siteToken=9a45f9cee67affa160b6addd06e07a8d&speedLogId=160067949693727da_1600679496937_87121&eid=30746007&reqParam=%7B%22from%22%3A0%2C%22sid%22%3A%22-100%22%2C%22tid%22%3A%22-1%22%2C%22ttype%22%3A1%2C%22siteId%22%3A%2215215804%22%2C%22userId%22%3A%2230746007%22%2C%22pageId%22%3A0%7D ', + GET_ISO_URL: 'http://www.i-soft.com.cn/type/4/714.jhtml ', + LIFE_CYCLE_URL: '', + MANUFACTURER: '普华软件', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'openEuler Preview', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-preview/', + DESC: 'openEuler Preview 为社区制作的尝鲜版,旨在对于新技术的探索,当前包含了对于RISC-V架构的支持。', + INSTALL_GUIDENCE_URL: 'https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md', + SEEK_HELP_URL: 'https://gitee.com/openeuler/RISC-V/issues', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-preview/RISC-V/Image/', + MANUFACTURER: 'openEuler RISC-V SIG组', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: '拓林思企业级服务器操作系统', + DOWNLOAD_URL : 'http://download.turbolinux.com.cn:8011/', + DESC: ' 拓林思企业级服务器操作系统是一款基于openEuler操作系统打造的针对AArch64处理器架构的操作系统发行版,适用于数据库、云计算、大数据、分布式计算等多种应用场景,为客户提供安全、可靠的解决系统方案,为各类应用提供标准、稳定的运行环境。', + INSTALL_GUIDENCE_URL: 'http://download.turbolinux.com.cn:8011/docs/TurboLinux15-Aarch64-Installation.pdf', + SEEK_HELP_URL: 'http://forum.turbolinux.com.cn/ ', + GET_ISO_URL: 'http://download.turbolinux.com.cn:8011/', + MANUFACTURER: 'TurboLinux', + PUBLISH_DATE: '2020/04', + LIFE_CYCLE_URL: 'http://download.turbolinux.com.cn:8011/docs/TLES-OS-PLANNING.pdf', + RELEASE_DESC_URL: 'http://www.turbolinux.com.cn/index.php/pages/cat_id/2.html', + LTS: false + }, + { + NAME: '同源OS 8.1欧拉发行版', + DOWNLOAD_URL : 'http://repo.tongyuanos.com/TongyuanOS8.1-euler/', + DESC: '内核源码来自于欧拉开源社区中,其它软件包来自于CentOS8.1的aarch64版,完全兼容CentOS8.1,产品发布物为标准启动安装ISO。', + INSTALL_GUIDENCE_URL: 'http://repo.tongyuanos.com/TongyuanOS8.1-euler/8.1/%e5%90%8c%e6%ba%90OS%208.1%e6%ac%a7%e6%8b%89%e5%8f%91%e8%a1%8c%e7%89%88%e5%bf%ab%e9%80%9f%e5%ae%89%e8%a3%85%e6%8c%87%e5%8d%971.0.docx', + SEEK_HELP_URL: 'mailto:youliang.wu@tongyuanos.com', + GET_ISO_URL: 'http://repo.tongyuanos.com/TongyuanOS8.1-euler/', + MANUFACTURER: '同源OS', + PUBLISH_DATE: '2020/04', + LIFE_CYCLE_URL: '', + RELEASE_DESC_URL: 'http://repo.tongyuanos.com/TongyuanOS8.1-euler/8.1/%e5%90%8c%e6%ba%90OS%208.1%e6%ac%a7%e6%8b%89%e5%8f%91%e8%a1%8c%e7%89%88%e5%8f%91%e8%a1%8c%e6%b3%a8%e8%ae%b0-release-notes.docx', + LTS: false + }, + { + NAME: 'HopeStage', + DOWNLOAD_URL : 'http://download.hopeinfra.com/HopeStage/ISO/', + DESC: '企业级通用操作系统HopeStage是基于openEuler构建的企业级Linux操作系统,具备高效、稳定、安全的特性,致力于为企业级的数据库、大数据、云计算、人工智能平台提供安全稳定的运行基础。', + RELEASE_DESC_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://download.hopeinfra.com/HopeStage/ISO/', + LIFE_CYCLE_URL: '', + MANUFACTURER: '江苏润和', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: '红旗Asianux服务器操作系统V8.1', + DOWNLOAD_URL : 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + DESC: '红旗Asianux服务器操作系统(欧拉版)是基于openEuler20.03 LTS SP1进行二次开发的商业发行版,目前内核版本为4.19。', + RELEASE_DESC_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + INSTALL_GUIDENCE_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + SEEK_HELP_URL: '', + GET_ISO_URL: 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + LIFE_CYCLE_URL: '', + MANUFACTURER: '中科红旗(北京)信息科技有限公司', + PUBLISH_DATE: '2021/03', + LTS: false + } + ] + }, + en: { + DOWNLOAD_LIST : [ + { + NAME: 'openEuler 22.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-22.03-LTS/', + DESC: 'openEuler 22.03-LTS is based on the 5.10 kernel and supports all scenarios of server, cloud, edge and embedded', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/22.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/22.03_LTS/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=22.03-LTS", + SERVER_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + CLOUD_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/virtual_machine_img/', + EDGE_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/edge_img/', + EMBEDDEN_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/embedded_img/', + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2022/03', + LTS: true + }, + { + NAME: 'openEuler 20.03 LTS SP3', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP3/', + DESC: 'openEuler 20.03 LTS SP3 is the patch version of openEuler 20.03 LTS, and both versions have the same lifecycle.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP3/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP3/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP3/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=20.03-LTS-SP3", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/12', + LTS: true + }, + { + NAME: 'openEuler 21.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.09/', + DESC: 'openEuler 21.09 is an innovative version for all scenarios, including edge and embedded devices. It enhances server and cloud computing features, and incorporates key technologies including cloud-native scheduling algorithms for hybrid service deployments and the container operating system KubeOS.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/21.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/21.09/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.09/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WHITE_PAPER: "https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/pdf/openEuler%2021.09%20%E6%8A%80%E6%9C%AF%E7%99%BD%E7%9A%AE%E4%B9%A6-en.pdf", + WEBSITE_SELECT: "/en/mirror/select/?version=21.09", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP2', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/', + DESC: 'openEuler 20.03 LTS SP2 is the patch version of openEuler 20.03 LTS,and both versions have the same lifecycle.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP2/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP2/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=20.03-LTS-SP2", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/07', + LTS: true + }, + { + NAME: 'openEuler 21.03', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.03/', + DESC: 'The openEuler 21.03 version is an innovative release for open scenarios,with a lifecycle of six months.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/21.03/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/21.03/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.03/ISO/', + WHITE_PAPER: "/whitepaper/en/openEuler-21.03-Technical-White-Paper.pdf", + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=21.03", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/03', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP1', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/', + DESC: 'openEuler 20.03 LTS SP1 is the patch version of openEuler 20.03 LTS,and both versions have the same lifecycle.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=20.03-LTS-SP1", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/12', + LTS: true + }, + { + NAME: 'openEuler 20.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.09/', + DESC: 'The openEuler 20.09 LTS version is an innovative release for open scenarios,with a lifecycle of six months.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.09/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.09/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=20.09", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS/', + DESC: 'The openEuler 20.03 LTS edition, with a four-year lifecycle, is a standard distribution that meets open scenario requirements, which has a lifecycle of four years.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=20.03-LTS", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/03', + LTS: true + }, + { + NAME: 'Kylinsec', + DOWNLOAD_URL : 'https://mirrors.kylinsec.com.cn/V3.4-4/', + GET_ISO_URL: 'https://mirrors.kylinsec.com.cn/V3.4-4/isos/', + DESC: 'No description available', + RELEASE_DESC_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846656373a.pdf', + INSTALL_GUIDENCE_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846807a00f.pdf', + SEEK_HELP_URL: '', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'Kylinsec', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'HopeEdge', + DESC: 'HopeEdge Linux for Edge Computing is an edge computing operating system based on openEuler, which is oriented to IoT scenarios. It has four key characteristics: lightweight security, independent innovation, efficient interconnection and rapid deployment. HopeEdge also provides equipment management, data acquisition, cloud-edge collaboration, artificial intelligence and other characteristics.', + DOWNLOAD_URL : 'http://webapp.hoperun.com:8007/', + RELEASE_DESC_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://webapp.hoperun.com:8007/HopeStage/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'HOPERUN', + PUBLISH_DATE: '2020/07', + LTS: false + }, + { + NAME: 'EulixOS Server', + DOWNLOAD_URL : 'https://eulixos.com/#/download', + DESC: 'The EulixOS is a server OS distribution based on the openEuler OS. The EulixOS supports multiple processor architectures, such as x86_64, AArch64, and RISC-V, and is ideal for various application scenarios, including databases, cloud computing, big data, AI, and distributed computing. It combines high security and reliability with the ultimate performance across platforms, aiming to provide a standard, secure, and reliable operating system and quality services for diverse applications and solutions.', + RELEASE_DESC_URL: 'https://eulixos.com/userguide/%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E/%E7%89%88%E6%9C%AC%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E.html', + INSTALL_GUIDENCE_URL: 'https://eulixos.com/userguide/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E5%89%8D%E8%A8%80.html', + SEEK_HELP_URL: 'https://eulixos.com/#/feedback', + GET_ISO_URL: 'https://eulixos.com/#/download', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'ISCAS', + PUBLISH_DATE: '2020/05', + LTS: false + }, + { + NAME: 'iSoftServerOS-Kunpeng-5.1', + DOWNLOAD_URL : 'http://www.i-soft.com.cn/type/4/714.jhtml', + DESC: 'No description available', + RELEASE_DESC_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml', + INSTALL_GUIDENCE_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml ', + SEEK_HELP_URL: 'https://p.qiao.baidu.com/cps4/chatIndex?siteToken=9a45f9cee67affa160b6addd06e07a8d&speedLogId=160067949693727da_1600679496937_87121&eid=30746007&reqParam=%7B%22from%22%3A0%2C%22sid%22%3A%22-100%22%2C%22tid%22%3A%22-1%22%2C%22ttype%22%3A1%2C%22siteId%22%3A%2215215804%22%2C%22userId%22%3A%2230746007%22%2C%22pageId%22%3A0%7D ', + GET_ISO_URL: 'http://www.i-soft.com.cn/type/4/714.jhtml ', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'iSoft', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'openEuler Preview', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-preview/', + DESC: 'openEuler Preview is a trial version of the community designed to explore new technologies and currently includes support for the RISC-V architecture.', + INSTALL_GUIDENCE_URL: 'https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md', + SEEK_HELP_URL: 'https://gitee.com/openeuler/RISC-V/issues', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-preview/RISC-V/Image/', + MANUFACTURER: 'openEuler RISC-V SIG group', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'TurboLinux Enterprise server v15', + DOWNLOAD_URL : 'http://download.turbolinux.com.cn:8011/', + DESC: 'Turbolinux Enterprise Server 15 (TLES15) is the enterprise commercial Linux distribution based on the openEuler community, designed for the AArch64 processor architecture.', + INSTALL_GUIDENCE_URL: 'http://download.turbolinux.com.cn:8011/docs/TurboLinux15-Aarch64-Installation.pdf', + SEEK_HELP_URL: 'http://forum.turbolinux.com.cn/ ', + GET_ISO_URL: 'http://download.turbolinux.com.cn:8011/', + MANUFACTURER: 'TurboLinux', + PUBLISH_DATE: '2020/04', + LIFE_CYCLE_URL: 'http://download.turbolinux.com.cn:8011/docs/TLES-OS-PLANNING.pdf', + RELEASE_DESC_URL: 'http://www.turbolinux.com.cn/index.php/pages/cat_id/2.html', + LTS: false + }, + { + NAME: 'HopeStage', + DOWNLOAD_URL : 'http://download.hopeinfra.com/HopeStage/ISO/', + DESC: 'HopeStage Enterprise Linux is an enterprise-level Linux operating system based on openEuler, which has the advantages of high efficiency, stability and security. HopeStage is committed to providing a safe and stable operating basis for enterprise-level databases, big data, cloud computing and artificial intelligence platforms.', + RELEASE_DESC_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://download.hopeinfra.com/HopeStage/ISO/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'HOPERUN', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'RedFlag Asianux Server - 8.1', + DOWNLOAD_URL : 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + DESC: 'Red Flag Asianux Server OS (openEuler) is a commercial release based on the secondary development of openEuler 20.03 LTS SP1. The current kernel version is 4.19.', + RELEASE_DESC_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + INSTALL_GUIDENCE_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + SEEK_HELP_URL: '', + GET_ISO_URL: 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'Red Flag Asianux Server', + PUBLISH_DATE: '2021/03', + LTS: false + } + ] + }, + ru: { + DOWNLOAD_LIST : [ + { + NAME: 'openEuler 22.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-22.03-LTS/', + DESC: 'openEuler 22.03-LTS is based on the 5.10 kernel and supports all scenarios of server, cloud, edge and embedded', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/22.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/22.03_LTS/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + LIFE_CYCLE_URL: '/en/other/lifecycle/', + WEBSITE_SELECT: "/en/mirror/select/?version=22.03-LTS", + SERVER_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/ISO/', + CLOUD_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/virtual_machine_img/', + EDGE_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/edge_img/', + EMBEDDEN_IMAGE:'https://repo.openeuler.org/openEuler-22.03-LTS/embedded_img/', + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2022/03', + LTS: true + }, + { + NAME: 'openEuler 21.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.09/', + DESC: 'openEuler 21.09 is an innovative version for all scenarios, including edge and embedded devices. It enhances server and cloud computing features, and incorporates key technologies including cloud-native scheduling algorithms for hybrid service deployments and the container operating system KubeOS.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/21.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/21.09/docs/Installation/installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.09/ISO/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WHITE_PAPER: "https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/pdf/openEuler%2021.09%20%E6%8A%80%E6%9C%AF%E7%99%BD%E7%9A%AE%E4%B9%A6-ru.pdf", + WEBSITE_SELECT: "/ru/mirror/select/?version=21.09", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP2', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/', + DESC: 'openEuler 20.03 LTS SP2 — это версия патча openEuler 20.03 LTS, и обе версии имеют одинаковый жизненный цикл.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP2/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP2/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP2/ISO/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WEBSITE_SELECT: "/ru/mirror/select/?version=20.03-LTS-SP2", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/07', + LTS: true + }, + { + NAME: 'openEuler 21.03', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-21.03/', + DESC: 'The openEuler 21.03 version is an innovative release for open scenarios,with a lifecycle of six months.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/21.03/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/21.03/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-21.03/ISO/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WHITE_PAPER: "/whitepaper/ru/openEuler-21.03-Технический-информационный-документ.pdf", + WEBSITE_SELECT: "/ru/mirror/select/?version=21.03", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2021/03', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS SP1', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/', + DESC: 'openEuler 20.03 LTS SP1 — это версия патча openEuler 20.03 LTS, и обе версии имеют одинаковый жизненный цикл.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS-SP1/ISO/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WEBSITE_SELECT: "/ru/mirror/select/?version=20.03-LTS-SP1", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/12', + LTS: true + }, + { + NAME: 'openEuler 20.09', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.09/', + DESC: 'openEuler 20.09 LTS — это инновационный релиз для сценариев использования программного обеспечения с открытым исходным кодом с жизненным циклом шесть месяцев.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.09/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.09/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.09/ISO/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WEBSITE_SELECT: "/ru/mirror/select/?version=20.09", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'openEuler 20.03 LTS', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-20.03-LTS/', + DESC: 'openEuler 20.03 LTS — это стандартный релиз для сценариев использования программного обеспечения с открытым исходным кодом с жизненным циклом четыре года.', + RELEASE_DESC_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Releasenotes/release_notes.html', + INSTALL_GUIDENCE_URL: 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Installation/Installation.html', + SEEK_HELP_URL: 'https://gitee.com/openeuler/community-issue/blob/master/README.md', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-20.03-LTS/', + LIFE_CYCLE_URL: '/ru/other/lifecycle/', + WEBSITE_SELECT: "/ru/mirror/select/?version=20.03-LTS", + MANUFACTURER: 'openEuler community', + PUBLISH_DATE: '2020/03', + LTS: true + }, + { + NAME: 'Kylinsec', + DOWNLOAD_URL : 'https://mirrors.kylinsec.com.cn/V3.4-4/', + DESC: 'Описание недоступно', + RELEASE_DESC_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846656373a.pdf', + INSTALL_GUIDENCE_URL: 'http://www.kylinsec.com.cn/Uploads/Download/2020-09-21/5f6846807a00f.pdf', + SEEK_HELP_URL: '', + GET_ISO_URL: 'https://mirrors.kylinsec.com.cn/V3.4-4/isos/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'Kylinsec', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'HopeEdge', + DOWNLOAD_URL : 'http://webapp.hoperun.com:8007/', + DESC: 'HopeEdge Linux for Edge Computing is an edge computing operating system based on openEuler, which is oriented to IoT scenarios. It has four key characteristics: lightweight security, independent innovation, efficient interconnection and rapid deployment. HopeEdge also provides equipment management, data acquisition, cloud-edge collaboration, artificial intelligence and other characteristics.', + RELEASE_DESC_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://webapp.hoperun.com:8007/HopeStage/HopeStage-Enterprise-Linux_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://webapp.hoperun.com:8007/HopeStage/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'HOPERUN', + PUBLISH_DATE: '2020/07', + LTS: false + }, + { + NAME: 'EulixOS Server', + DOWNLOAD_URL : 'https://eulixos.com/#/download', + DESC: 'EulixOS — это дистрибутив серверной операционной системы, основанный на ОС openEuler. Поддерживая такие процессорные архитектуры, как x86_64, AArch64 и RISC-V, EulixOS идеально подходит для применения в различных сценариях, в том числе в базах данных, облачных вычислениях, больших данных, системах искусственного интеллекта и распределенных вычислениях. Сочетая свойства высокой безопасности и надежности, а также превосходной производительности, которая отличает все платформы, данный дистрибутив обеспечит стандартную, безопасную и надежную операционную систему и качественные сервисы, применимые в различных приложениях и решениях.', + RELEASE_DESC_URL: 'https://eulixos.com/userguide/%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E/%E7%89%88%E6%9C%AC%E5%8F%91%E8%A1%8C%E8%AF%B4%E6%98%8E.html', + INSTALL_GUIDENCE_URL: 'https://eulixos.com/userguide/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E5%89%8D%E8%A8%80.html', + SEEK_HELP_URL: 'https://eulixos.com/#/feedback', + GET_ISO_URL: 'https://eulixos.com/#/download', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'ISCAS', + PUBLISH_DATE: '2020/05', + LTS: false + }, + { + NAME: 'iSoftServerOS-Kunpeng-5.1', + DOWNLOAD_URL : 'http://www.i-soft.com.cn/type/4/714.jhtml', + DESC: 'Описание недоступно', + RELEASE_DESC_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml', + INSTALL_GUIDENCE_URL: 'http://www.i-soft.com.cn/type/4/716.jhtml ', + SEEK_HELP_URL: 'https://p.qiao.baidu.com/cps4/chatIndex?siteToken=9a45f9cee67affa160b6addd06e07a8d&speedLogId=160067949693727da_1600679496937_87121&eid=30746007&reqParam=%7B%22from%22%3A0%2C%22sid%22%3A%22-100%22%2C%22tid%22%3A%22-1%22%2C%22ttype%22%3A1%2C%22siteId%22%3A%2215215804%22%2C%22userId%22%3A%2230746007%22%2C%22pageId%22%3A0%7D ', + GET_ISO_URL: 'http://www.i-soft.com.cn/type/4/714.jhtml ', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'iSoft', + PUBLISH_DATE: '', + LTS: false + }, + { + NAME: 'openEuler Preview', + DOWNLOAD_URL : 'https://repo.openeuler.org/openEuler-preview/', + DESC: 'Демо-версия openEuler Preview данного сообщества, разработанная в целях изучения новых технологий, в текущий момент поддерживает архитектуру RISC-V.', + INSTALL_GUIDENCE_URL: 'https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md', + SEEK_HELP_URL: 'https://gitee.com/openeuler/RISC-V/issues', + GET_ISO_URL: 'https://repo.openeuler.org/openEuler-preview/RISC-V/Image/', + MANUFACTURER: 'openEuler RISC-V SIG group', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'TurboLinux Enterprise server v15', + DOWNLOAD_URL : 'http://download.turbolinux.com.cn:8011/', + DESC: 'Turbolinux Enterprise Server 15 (TLES15) is the enterprise commercial Linux distribution based on the openEuler community, designed for the AArch64 processor architecture.', + INSTALL_GUIDENCE_URL: 'http://download.turbolinux.com.cn:8011/docs/TurboLinux15-Aarch64-Installation.pdf', + SEEK_HELP_URL: 'http://forum.turbolinux.com.cn/ ', + GET_ISO_URL: 'http://download.turbolinux.com.cn:8011/', + MANUFACTURER: 'TurboLinux', + PUBLISH_DATE: '2020/04', + LIFE_CYCLE_URL: 'http://download.turbolinux.com.cn:8011/docs/TLES-OS-PLANNING.pdf', + RELEASE_DESC_URL: 'http://www.turbolinux.com.cn/index.php/pages/cat_id/2.html', + LTS: false + }, + { + NAME: 'HopeStage', + DOWNLOAD_URL : 'http://download.hopeinfra.com/HopeStage/ISO/', + DESC: 'HopeStage Enterprise Linux is an enterprise-level Linux operating system based on openEuler, which has the advantages of high efficiency, stability and security. HopeStage is committed to providing a safe and stable operating basis for enterprise-level databases, big data, cloud computing and artificial intelligence platforms.', + RELEASE_DESC_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage-Enterprise-Linux_ReleaseNotes.pdf', + INSTALL_GUIDENCE_URL: 'http://download.hopeinfra.com/HopeStage/References/HopeStage_Installation_Guide.pdf', + SEEK_HELP_URL: 'http://www.hopeinfra.com/contactus.html', + GET_ISO_URL: 'http://download.hopeinfra.com/HopeStage/ISO/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'HOPERUN', + PUBLISH_DATE: '2020/09', + LTS: false + }, + { + NAME: 'RedFlag Asianux Server - 8.1', + DOWNLOAD_URL : 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + DESC: 'Red Flag Asianux Server OS (openEuler) is a commercial release based on the secondary development of openEuler 20.03 LTS SP1. The current kernel version is 4.19.', + RELEASE_DESC_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + INSTALL_GUIDENCE_URL: 'http://www.linuxsir.cn/?product.htm&pid=2', + SEEK_HELP_URL: '', + GET_ISO_URL: 'http://pan.chinaredflag.cn/d/d3041d958a8d4da1881d/', + LIFE_CYCLE_URL: '', + MANUFACTURER: 'Red Flag Asianux Server', + PUBLISH_DATE: '2021/03', + LTS: false + } + ] + } +}; diff --git a/web-ui/docs/.vuepress/data/learn.js b/web-ui/docs/.vuepress/data/learn.js new file mode 100644 index 0000000000000000000000000000000000000000..0346e0986777cc5cdb20bd0320b1dd3152610196 --- /dev/null +++ b/web-ui/docs/.vuepress/data/learn.js @@ -0,0 +1,1420 @@ +/** + * @file 资料组维护数据文件 + * */ + + module.exports = { + cn: { + COURSE_LIST: [ + { + ID: 1, + COURSE_H1: 'HCIA-openEuler 认证培训课程', + NAV_DATA: [ + { + label: '课程导读', + key: 'introduction0', + introduction: [ + '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + 'OpenEuler是一个开源免费的Linux发行版系统,通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。openEuler同时是一个创新的系统,倡导客户在系统上提出创新想法、开拓新思路、实践新方案。', + 'HCIA-openEuler华为认证openEuler工程师在线课程定位于培养和认证具备企业数据中心核心操作系统基础操作与管理能力的工程师。', + '通过HCIA-OpenEuler V1.0 认证,您将掌握openEuler操作系统基础命令,掌握openEuler用户管理、网络管理、权限管理,掌握shell基础知识;具备企业数据中心核心操作系统基础操作与管理能力;能够胜任Linux系统运维工程师等岗位。', + '本次课程我们首先需要系统地了解openEuler是什么,对openEuler进行初步的了解。', + '然后会依次学习并了解:', + '1、操作系统发展史', + '2、openEuler基础命令如目录操作、文件查看等', + '3、vi与vim文本编辑器', + '4、openEuler用户、用户组与权限管理', + '5、openEuler操作系统应用软件安装', + '6、openEuler存储空间管理', + '7、openEuler系统计划任务、网络与服务管理', + '8、shell脚本基础', + '9、Samba文件共享服务器' + ], + teacher: [ + { + img: '/img/learn/hcia/yanglei.png', + position: '华为认证高级讲师', + name: '杨磊' + }, + { + img: '/img/learn/hcia/zhongyunan.png', + position: '华为认证高级讲师', + name: '钟育楠' + } + ] + }, + { + label: '1 openEuler操作系统入门', + children: [ + { + label: '本章导读', + key: 'introduction1', + introduction: [ + '本章《openEuler操作系统入门》作为课程的第一章,将帮助大家快速了解什么是openEuler。本章课程主要介绍了GNU自由软件基金会、Linux起源、openEuler操作系统以及它们之间的关系,并且演示了如何安装openEuler操作系统,以及如何登录使用openEuler操作系统。', + '以理论加实验的方式,更加生动地引领大家进入openEuler之旅。', + '本章主要内容包括:', + '1、Linux介绍', + '2、openEuler安装', + '3、openEuler入门级操作' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx' + }, + { + label: '1.1 Linux介绍', + key: '1.1 Linux介绍', + desc: '这一单元我们主要介绍Linux操作系统的入门知识。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.1%2Blinux%E4%BB%8B%E7%BB%8D.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.2 openEuler安装', + key: '1.2 openEuler安装', + desc: '这一单元我们主要介绍如何安装openEuler。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.2%2BopenEuler%E5%AE%89%E8%A3%85.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.3 openEuler入门级操作', + key: '1.3 openEuler入门级操作', + desc: '这一单元我们主要介绍如何使用openEuler操作系统。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.3%2BopenEuler%E5%85%A5%E9%97%A8%E7%BA%A7%E6%93%8D%E4%BD%9C.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + } + ] + }, + { + label: '2 命令行操作基础', + children: [ + { + label: '本章导读', + key: 'introduction2', + introduction: [ + '本章我们主要介绍命令行的一些基础操作,包括入门级命令行代码,以及如何使用命令行管理文件。', + '我们的课程分为理论和实验两部分,理论部分介绍命令行,实验部分加深印象。通过本章的学习,希望大家可以掌握Linux命令的基础知识、Linux系统登录命令、系统电源管理命令、系统帮助命令和文件管理命令。', + '本章主要内容包括:', + '1、Linux命令基础知识。', + '2、Linux系统中的目录操作、文件操作和文件查看操作。', + '3、文件的分页查看操作和查找操作。', + '4、文件的压缩和打包操作。' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + }, + { + label: '2.1 Linux命令行基础', + key: '2.1 Linux命令行基础', + desc: '这一单元我们主要介绍Linux命令行操作基础,包括命令行入门和使用命令行管理文件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94.mp4' + }, + { + label: '2.2 目录操作、文件操作和查看操作', + key: '2.2 目录操作、文件操作和查看操作', + desc: '这一单元我们主要介绍Linux系统中的目录操作、文件操作、和文件查看操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.3 分页查看操作和查找操作', + key: '2.3 分页查看操作和查找操作', + desc: '这一单元我们主要介绍文件的分页查看操作和查找操作。 ', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.4 压缩和打包操作', + key: '2.4 压缩和打包操作', + desc: '这一单元我们主要介绍文件的压缩和打包操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C.mp4' + } + ] + }, + { + label: '3 文本编辑器及文本处理', + children: [ + { + label: '本章导读', + key: 'introduction3', + introduction: [ + '本章课程我们将了解Linux系统中常见的文本编辑器,以及对应的文本处理方式,常见的文本编辑器包括Emacs、nano、gedit、vi和vim等等,本章我们将重点介绍vi和vim编辑器,以及它们的三种主要模式。通过本章的学习,希望大家可以掌握vim文本编辑器的常用操作,包括如何使用vim打开文件、修改文件、保存文件,以及vim文本编辑器的常用快捷操作等等。', + '本章我们依然分理论和实验两部分进行讲解。理论部分我们主要讲解Linux文本编辑器的作用、架构、原理和流程。实验部分主要锻炼大家理论联系实际的能力,真正地掌握和理解文本编辑器的日常运维操作。', + '本章主要内容包括:', + '1、常见文本编辑器,以及VIM打开文件和移动光标', + '2、如何使用VIM编辑器', + '3、如何在Linux中查看文件', + '4、文件摘选和字段提取' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx' + }, + { + label: '3.1 常见文本编辑器', + key: '3.1 常见文本编辑器', + desc: '这一单元我们主要介绍Linux系统中常用的文本编辑器,包括Emacs、nano、gedit、vi和vim,以及如何使用vim文本编辑器打开文件,如何在vim中移动光标等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87.mp4' + }, + { + label: '3.2 如何使用VIM编辑器', + key: '3.2 如何使用VIM编辑器', + desc: '这一单元我们主要介绍如何使用vim文本编辑器,包括数据操作,行号的显示和取消,vim中的查找与替换,设置搜索高亮,修改文件撤销或重做,以及如何保存文件并退出等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8.mp4' + }, + { + label: '3.3 在Linux查看文件-cat、more、less', + key: '3.3 在Linux查看文件-cat、more、less', + desc: '这一单元我们主要介绍文本处理的命令,包括如何查看文件,如何筛选文件,如何提取列或者字段,以及如何提取关键字。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less.mp4' + }, + { + label: '3.4 文件摘选和字段提取', + key: '3.4 文件摘选和字段提取', + desc: '这一单元我们主要介绍查看文件的命令:cat、more和less。Linux文件的摘选命令:head和tail。提取文件中列或者字段的命令:cut。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96.mp4' + } + ] + }, + { + label: '4 用户和权限管理', + children: [ + { + label: '本章导读', + key: 'introduction4', + introduction: [ + '本章我们将学习用户和权限管理,帮助大家了解用户和组的基础概念,掌握文件和目录的命令行和权限管理操作,以及文件的特殊访问权限管理。', + '本章我们在介绍时仍然会分为两个部分,理论部分主要讲解用户、用户组和文件权限的基本概念,实验部分会重点锻炼大家对相关管理命令的操作,帮助大家理论联系实际,真正了解和掌握用户和权限管理。', + '本章主要内容包括:', + '1、用户的概念和用户相关的管理命令', + '2、用户组的概念和相关的管理命令', + '3、文件权限的基础概念' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '4.1 用户的概念和相关管理命令', + key: '4.1 用户的概念和相关管理命令', + desc: '这一单元我们主要介绍用户的概念,以及useradd、usermod、passwd等用户相关的管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4.mp4', + + }, + { + label: '4.2 用户的管理文件', + key: '4.2 用户的管理文件', + desc: '这一单元我们主要介绍用户组的概念,以及groupadd、groupmod等用户组管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6.mp4', + + }, + { + label: '4.3 文件权限的概念及相关操作', + key: '4.3 文件权限的概念及相关操作', + desc: '这一单元我们主要介绍在openEuler系统中,用户和用户组的基础概念、它们的相关命令、相关文件等等,还将了解到常见的读写权限、执行权限,以及如何针对文件或者目录进行权限的修改。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + } + ] + }, + { + label: '5 安装软件并管理服务', + children: [ + { + label: '本章导读', + key: 'introduction5', + introduction: [ + '本章我们将主要介绍如何在Linux中安装软件并管理服务,帮助大家了解安装软件的两种方式:RPM包安装和源代码安装。', + '理论部分主要讲解两种安装方式的优缺点及特性,实验部分将辅助大家更深入的了解RPM和DNF的操作命令和systemd的管理服务命令。', + '本章主要内容包括:', + '1、RPM、DNF概念和操作命令', + '1、RPM、DNF概念和操作命令', + '3、systemd管理服务' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx' + }, + { + label: '5.1 RPM的概念和操作命令', + key: '5.1 RPM的概念和操作命令', + desc: '这一单元我们主要介绍RPM的概念,以及如何使用RPM命令进行安装、卸载、升级和查询等操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.2 DNF的概念和操作命令', + key: '5.2 DNF的概念和操作命令', + desc: '这一单元我们主要介绍DNF的概念,以及如何添加和启动软件源,如何配置DNF,如何使用DNF查询、安装、删除、升级软件包和软件包组。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.3 RPM和DNF的操作实验', + key: '5.3 RPM和DNF的操作实验', + desc: '这一单元我们主要介绍配置软件源的实验,以及如何使用RPM命令和DNF命令管理软件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C.mp4', + + }, + { + label: '5.4 源代码软件及其安装方法', + key: '5.4 源代码软件及其安装方法', + desc: '这一单元我们主要介绍源代码软件的概念,以及使用源码安装软件的方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95.mp4', + + }, + { + label: '5.5 systemd管理服务', + key: '5.5 systemd管理服务', + desc: '这一单元我们主要介绍systemd管理服务的概念,以及systemd的主命令systemctl的用法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.mp4', + + } + ] + }, + { + label: '6 管理文件系统及存储', + children: [ + { + label: '本章导读', + key: 'introduction6', + introduction: [ + '存储是IT领域中非常重要的一部分,它被用来保存各种各样的数据,本章的课程将会在理论部分介绍与存储相关的一些概念,包括文件系统、磁盘类型、逻辑卷等,同时也会在实验部分演示如何使用它们对数据进行保存。', + '本章主要内容包括:', + '1、文件系统简介', + '2、openEuler文件系统及相关操作', + '3、MBR操作演示', + '4、GPT分区演示', + '5、逻辑卷管理和操作演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx' + }, + { + label: '6.1 文件系统简介', + key: '6.1 文件系统简介', + desc: '这一单元我们主要介绍文件系统的基本概念,以及分区的含义。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B.mp4', + + }, + { + label: '6.2 openEuler文件系统及相关操作', + key: '6.2 openEuler文件系统及相关操作', + desc: '这一单元我们主要介绍文件系统和存储相关的知识,以及磁盘存储的挂载和使用方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + }, + { + label: '6.3 MBR操作演示', + key: '6.3 MBR操作演示', + desc: '这一单元我们主要介绍如何进行MBR的分区的实验操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.4 GPT分区演示', + key: '6.4 GPT分区演示', + desc: '这一单元我们主要介绍如何进行GPT的分区模式。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.5 逻辑卷管理', + key: '6.5 逻辑卷管理', + desc: '这一单元我们主要介绍逻辑卷相关的一些概念,以及如何管理逻辑卷和动态调整逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86.mp4', + + }, + { + label: '6.6 逻辑卷管理操作演示', + key: '6.6 逻辑卷管理操作演示', + desc: '这一单元我们主要介绍如何创建一个LV,也就是如何创建一个逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + } + ] + }, + { + label: '7 系统管理', + children: [ + { + label: '本章导读', + key: 'introduction7', + introduction: [ + '在Linux系统中你可能已经发现了为什么系统常常会自动地进行一些任务?这些任务到底是谁在支配他们工作的?本章的课程将简单介绍几个系统管理的操作,包括计划任务、网络管理及进程管理。', + '我们同样会采用理论加实验的方式,帮助大家更直观地理解系统管理,并掌握它的操作。', + '本章主要内容包括:', + '1、计划任务管理', + '2、at和crontab演示', + '3、网络管理和演示', + '4、进程管理和演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.1 计划任务管理', + key: '7.1 计划任务管理', + desc: '这一单元我们主要介绍计划任务管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.1%20%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86/7.1%20%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86.mp4' + }, + { + label: '7.2 at和crontab演示', + key: '7.2 at和crontab演示', + desc: '这一单元我们主要介绍计划任务管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.2%20at%E5%92%8Ccrontab%E6%BC%94%E7%A4%BA/7.2%20at%E5%92%8Ccrontab%E6%BC%94%E7%A4%BA.mp4' + }, + { + label: '7.3 网络管理', + key: '7.3 网络管理', + desc: '这一单元我们主要介绍网络管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.3%20%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/7.3%20%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86.mp4' + }, + { + label: '7.4 网络管理演示', + key: '7.4 网络管理演示', + desc: '这一单元我们主要介绍网络管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website.obs.ap-southeast-1.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.4%20%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA/7.4%20%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA.mp4' + }, + { + label: '7.5 进程管理', + key: '7.5 进程管理', + desc: '这一单元我们主要介绍进程管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86.mp4' + }, + { + label: '7.6 进程管理演示', + key: '7.6 进程管理演示', + desc: '这一单元我们主要介绍进程管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + { + label: '8 使用shell脚本', + children: [ + { + label: '本章导读', + key: 'introduction8', + introduction: [ + '在这一章课程中,我们将会学习如何使用shell脚本,首先是shell基础知识,包括shell脚本的定义,构成等等内容,其次我们会介绍一些shell编程基础,包括标准输入、标准输出,管道、运算、变量、字符等等内容 ,我们还将学习如何编写常用的shell脚本,包括如何调试shell脚本,以及shell脚本的编写风格等等内容。', + '本章我们将同样按照之前的课程设计,分为理论和实验两个部分,理论部分我们将简单介绍shell脚本的作用,并基于基本架构,对其架构进行讲解,然后会对其工作原理和流程进行深入学习。实验部分主要锻炼学员对于shell编程的基本运用,帮助大家理论联系实际,真正掌握shell脚本知识。', + '本章主要内容包括:', + '1、shell编程的基础,包括shell脚本输入、输出、重定向和管道等等', + '2、shell编程中的字符、变量和运算', + '3、shell编程的语句,包括循环语句和条件语句等等' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx' + }, + { + label: '8.1 Shell编程基础', + key: '8.1 Shell编程基础', + desc: '这一单元我们主要介绍shell编程的基础,包括shell脚本输入、输出、重定向和管道等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80.mp4', + + }, + { + label: '8.2 字符、变量和运算', + key: '8.2 字符、变量和运算', + desc: '这一单元我们主要介绍shell编程中的字符、变量和运算。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97.mp4', + + }, + { + label: '8.3 Shell编程语句', + key: '8.3 Shell编程语句', + desc: '这一单元我们主要介绍shell编程的语句,包括循环语句和条件语句等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5.mp4', + + } + ] + }, + { + label: '9 Samba文件共享服务器管理', + children: [ + { + label: '本章导读', + key: 'introduction9', + introduction: [ + '本章是整个课程的最后一章,将为大家演示整个综合实验。通过对前几章内容的综合运用,来完成Samba文件共享服务的搭建和使用。', + '本章主要内容包括:', + '1、综合实验背景介绍', + '2、综合实验演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '9.1 综合实验背景介绍', + key: '9.1 综合实验背景介绍', + desc: '这一单元我们主要介绍Samba服务器的架构和工作原理,了解如何配置Samba对应的目录的一些用户以及权限,并使用前八章学习的知识做一些简单的运维工作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D.mp4' + }, + { + label: '9.2 综合实验演示', + key: '9.2 综合实验演示', + desc: '这一单元我们主要介绍如何搭建Samba文件共享服务器。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + ] + } + ] + }, + en: { + COURSE_LIST: [ + { + ID: 1, + COURSE_H1: 'HCIA-openEuler 认证培训课程', + NAV_DATA: [ + { + label: '课程导读', + key: 'introduction0', + introduction: [ + '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + 'OpenEuler是一个开源免费的Linux发行版系统,通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。openEuler同时是一个创新的系统,倡导客户在系统上提出创新想法、开拓新思路、实践新方案。', + 'HCIA-openEuler华为认证openEuler工程师在线课程定位于培养和认证具备企业数据中心核心操作系统基础操作与管理能力的工程师。', + '通过HCIA-OpenEuler V1.0 认证,您将掌握openEuler操作系统基础命令,掌握openEuler用户管理、网络管理、权限管理,掌握shell基础知识;具备企业数据中心核心操作系统基础操作与管理能力;能够胜任Linux系统运维工程师等岗位。', + '本次课程我们首先需要系统地了解openEuler是什么,对openEuler进行初步的了解。', + '然后会依次学习并了解:', + '1、操作系统发展史', + '2、openEuler基础命令如目录操作、文件查看等', + '3、vi与vim文本编辑器', + '4、openEuler用户、用户组与权限管理', + '5、openEuler操作系统应用软件安装', + '6、openEuler存储空间管理', + '7、openEuler系统计划任务、网络与服务管理', + '8、shell脚本基础', + '9、Samba文件共享服务器' + ], + teacher: [ + { + img: '/img/learn/hcia/yanglei.png', + position: '华为认证高级讲师', + name: '杨磊' + }, + { + img: '/img/learn/hcia/zhongyunan.png', + position: '华为认证高级讲师', + name: '钟育楠' + } + ] + }, + { + label: '1 openEuler操作系统入门', + children: [ + { + label: '本章导读', + key: 'introduction1', + introduction: [ + '本章《openEuler操作系统入门》作为课程的第一章,将帮助大家快速了解什么是openEuler。本章课程主要介绍了GNU自由软件基金会、Linux起源、openEuler操作系统以及它们之间的关系,并且演示了如何安装openEuler操作系统,以及如何登录使用openEuler操作系统。', + '以理论加实验的方式,更加生动地引领大家进入openEuler之旅。', + '本章主要内容包括:', + '1、Linux介绍', + '2、openEuler安装', + '3、openEuler入门级操作' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx' + }, + { + label: '1.1 Linux介绍', + key: '1.1 Linux介绍', + desc: '这一单元我们主要介绍Linux操作系统的入门知识。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.1%2Blinux%E4%BB%8B%E7%BB%8D.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.2 openEuler安装', + key: '1.2 openEuler安装', + desc: '这一单元我们主要介绍如何安装openEuler。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.2%2BopenEuler%E5%AE%89%E8%A3%85.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.3 openEuler入门级操作', + key: '1.3 openEuler入门级操作', + desc: '这一单元我们主要介绍如何使用openEuler操作系统。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.3%2BopenEuler%E5%85%A5%E9%97%A8%E7%BA%A7%E6%93%8D%E4%BD%9C.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + } + ] + }, + { + label: '2 命令行操作基础', + children: [ + { + label: '本章导读', + key: 'introduction2', + introduction: [ + '本章我们主要介绍命令行的一些基础操作,包括入门级命令行代码,以及如何使用命令行管理文件。', + '我们的课程分为理论和实验两部分,理论部分介绍命令行,实验部分加深印象。通过本章的学习,希望大家可以掌握Linux命令的基础知识、Linux系统登录命令、系统电源管理命令、系统帮助命令和文件管理命令。', + '本章主要内容包括:', + '1、Linux命令基础知识。', + '2、Linux系统中的目录操作、文件操作和文件查看操作。', + '3、文件的分页查看操作和查找操作。', + '4、文件的压缩和打包操作。' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + }, + { + label: '2.1 Linux命令行基础', + key: '2.1 Linux命令行基础', + desc: '这一单元我们主要介绍Linux命令行操作基础,包括命令行入门和使用命令行管理文件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94.mp4' + }, + { + label: '2.2 目录操作、文件操作和查看操作', + key: '2.2 目录操作、文件操作和查看操作', + desc: '这一单元我们主要介绍Linux系统中的目录操作、文件操作、和文件查看操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.3 分页查看操作和查找操作', + key: '2.3 分页查看操作和查找操作', + desc: '这一单元我们主要介绍文件的分页查看操作和查找操作。 ', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.4 压缩和打包操作', + key: '2.4 压缩和打包操作', + desc: '这一单元我们主要介绍文件的压缩和打包操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C.mp4' + } + ] + }, + { + label: '3 文本编辑器及文本处理', + children: [ + { + label: '本章导读', + key: 'introduction3', + introduction: [ + '本章课程我们将了解Linux系统中常见的文本编辑器,以及对应的文本处理方式,常见的文本编辑器包括Emacs、nano、gedit、vi和vim等等,本章我们将重点介绍vi和vim编辑器,以及它们的三种主要模式。通过本章的学习,希望大家可以掌握vim文本编辑器的常用操作,包括如何使用vim打开文件、修改文件、保存文件,以及vim文本编辑器的常用快捷操作等等。', + '本章我们依然分理论和实验两部分进行讲解。理论部分我们主要讲解Linux文本编辑器的作用、架构、原理和流程。实验部分主要锻炼大家理论联系实际的能力,真正地掌握和理解文本编辑器的日常运维操作。', + '本章主要内容包括:', + '1、常见文本编辑器,以及VIM打开文件和移动光标', + '2、如何使用VIM编辑器', + '3、如何在Linux中查看文件', + '4、文件摘选和字段提取' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx' + }, + { + label: '3.1 常见文本编辑器', + key: '3.1 常见文本编辑器', + desc: '这一单元我们主要介绍Linux系统中常用的文本编辑器,包括Emacs、nano、gedit、vi和vim,以及如何使用vim文本编辑器打开文件,如何在vim中移动光标等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87.mp4' + }, + { + label: '3.2 如何使用VIM编辑器', + key: '3.2 如何使用VIM编辑器', + desc: '这一单元我们主要介绍如何使用vim文本编辑器,包括数据操作,行号的显示和取消,vim中的查找与替换,设置搜索高亮,修改文件撤销或重做,以及如何保存文件并退出等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8.mp4' + }, + { + label: '3.3 在Linux查看文件-cat、more、less', + key: '3.3 在Linux查看文件-cat、more、less', + desc: '这一单元我们主要介绍文本处理的命令,包括如何查看文件,如何筛选文件,如何提取列或者字段,以及如何提取关键字。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less.mp4' + }, + { + label: '3.4 文件摘选和字段提取', + key: '3.4 文件摘选和字段提取', + desc: '这一单元我们主要介绍查看文件的命令:cat、more和less。Linux文件的摘选命令:head和tail。提取文件中列或者字段的命令:cut。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96.mp4' + } + ] + }, + { + label: '4 用户和权限管理', + children: [ + { + label: '本章导读', + key: 'introduction4', + introduction: [ + '本章我们将学习用户和权限管理,帮助大家了解用户和组的基础概念,掌握文件和目录的命令行和权限管理操作,以及文件的特殊访问权限管理。', + '本章我们在介绍时仍然会分为两个部分,理论部分主要讲解用户、用户组和文件权限的基本概念,实验部分会重点锻炼大家对相关管理命令的操作,帮助大家理论联系实际,真正了解和掌握用户和权限管理。', + '本章主要内容包括:', + '1、用户的概念和用户相关的管理命令', + '2、用户组的概念和相关的管理命令', + '3、文件权限的基础概念' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '4.1 用户的概念和相关管理命令', + key: '4.1 用户的概念和相关管理命令', + desc: '这一单元我们主要介绍用户的概念,以及useradd、usermod、passwd等用户相关的管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4.mp4', + + }, + { + label: '4.2 用户的管理文件', + key: '4.2 用户的管理文件', + desc: '这一单元我们主要介绍用户组的概念,以及groupadd、groupmod等用户组管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6.mp4', + + }, + { + label: '4.3 文件权限的概念及相关操作', + key: '4.3 文件权限的概念及相关操作', + desc: '这一单元我们主要介绍在openEuler系统中,用户和用户组的基础概念、它们的相关命令、相关文件等等,还将了解到常见的读写权限、执行权限,以及如何针对文件或者目录进行权限的修改。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + } + ] + }, + { + label: '5 安装软件并管理服务', + children: [ + { + label: '本章导读', + key: 'introduction5', + introduction: [ + '本章我们将主要介绍如何在Linux中安装软件并管理服务,帮助大家了解安装软件的两种方式:RPM包安装和源代码安装。', + '理论部分主要讲解两种安装方式的优缺点及特性,实验部分将辅助大家更深入的了解RPM和DNF的操作命令和systemd的管理服务命令。', + '本章主要内容包括:', + '1、RPM、DNF概念和操作命令', + '1、RPM、DNF概念和操作命令', + '3、systemd管理服务' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx' + }, + { + label: '5.1 RPM的概念和操作命令', + key: '5.1 RPM的概念和操作命令', + desc: '这一单元我们主要介绍RPM的概念,以及如何使用RPM命令进行安装、卸载、升级和查询等操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.2 DNF的概念和操作命令', + key: '5.2 DNF的概念和操作命令', + desc: '这一单元我们主要介绍DNF的概念,以及如何添加和启动软件源,如何配置DNF,如何使用DNF查询、安装、删除、升级软件包和软件包组。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.3 RPM和DNF的操作实验', + key: '5.3 RPM和DNF的操作实验', + desc: '这一单元我们主要介绍配置软件源的实验,以及如何使用RPM命令和DNF命令管理软件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C.mp4', + + }, + { + label: '5.4 源代码软件及其安装方法', + key: '5.4 源代码软件及其安装方法', + desc: '这一单元我们主要介绍源代码软件的概念,以及使用源码安装软件的方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95.mp4', + + }, + { + label: '5.5 systemd管理服务', + key: '5.5 systemd管理服务', + desc: '这一单元我们主要介绍systemd管理服务的概念,以及systemd的主命令systemctl的用法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.mp4', + + } + ] + }, + { + label: '6 管理文件系统及存储', + children: [ + { + label: '本章导读', + key: 'introduction6', + introduction: [ + '存储是IT领域中非常重要的一部分,它被用来保存各种各样的数据,本章的课程将会在理论部分介绍与存储相关的一些概念,包括文件系统、磁盘类型、逻辑卷等,同时也会在实验部分演示如何使用它们对数据进行保存。', + '本章主要内容包括:', + '1、文件系统简介', + '2、openEuler文件系统及相关操作', + '3、MBR操作演示', + '4、GPT分区演示', + '5、逻辑卷管理和操作演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx' + }, + { + label: '6.1 文件系统简介', + key: '6.1 文件系统简介', + desc: '这一单元我们主要介绍文件系统的基本概念,以及分区的含义。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B.mp4', + + }, + { + label: '6.2 openEuler文件系统及相关操作', + key: '6.2 openEuler文件系统及相关操作', + desc: '这一单元我们主要介绍文件系统和存储相关的知识,以及磁盘存储的挂载和使用方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + }, + { + label: '6.3 MBR操作演示', + key: '6.3 MBR操作演示', + desc: '这一单元我们主要介绍如何进行MBR的分区的实验操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.4 GPT分区演示', + key: '6.4 GPT分区演示', + desc: '这一单元我们主要介绍如何进行GPT的分区模式。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.5 逻辑卷管理', + key: '6.5 逻辑卷管理', + desc: '这一单元我们主要介绍逻辑卷相关的一些概念,以及如何管理逻辑卷和动态调整逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86.mp4', + + }, + { + label: '6.6 逻辑卷管理操作演示', + key: '6.6 逻辑卷管理操作演示', + desc: '这一单元我们主要介绍如何创建一个LV,也就是如何创建一个逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + } + ] + }, + { + label: '7 系统管理', + children: [ + { + label: '本章导读', + key: 'introduction7', + introduction: [ + '在Linux系统中你可能已经发现了为什么系统常常会自动地进行一些任务?这些任务到底是谁在支配他们工作的?本章的课程将简单介绍几个系统管理的操作,包括计划任务、网络管理及进程管理。', + '我们同样会采用理论加实验的方式,帮助大家更直观地理解系统管理,并掌握它的操作。', + '本章主要内容包括:', + '1、计划任务管理', + '2、at和crontab演示', + '3、网络管理和演示', + '4、进程管理和演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.1 计划任务管理', + key: '7.1 计划任务管理', + desc: '这一单元我们主要介绍计划任务管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.2 at和crontab演示', + key: '7.2 at和crontab演示', + desc: '这一单元我们主要介绍计划任务管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.3 网络管理', + key: '7.3 网络管理', + desc: '这一单元我们主要介绍网络管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.4 网络管理演示', + key: '7.4 网络管理演示', + desc: '这一单元我们主要介绍网络管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.5 进程管理', + key: '7.5 进程管理', + desc: '这一单元我们主要介绍进程管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86.mp4' + }, + { + label: '7.6 进程管理演示', + key: '7.6 进程管理演示', + desc: '这一单元我们主要介绍进程管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + { + label: '8 使用shell脚本', + children: [ + { + label: '本章导读', + key: 'introduction8', + introduction: [ + '在这一章课程中,我们将会学习如何使用shell脚本,首先是shell基础知识,包括shell脚本的定义,构成等等内容,其次我们会介绍一些shell编程基础,包括标准输入、标准输出,管道、运算、变量、字符等等内容 ,我们还将学习如何编写常用的shell脚本,包括如何调试shell脚本,以及shell脚本的编写风格等等内容。', + '本章我们将同样按照之前的课程设计,分为理论和实验两个部分,理论部分我们将简单介绍shell脚本的作用,并基于基本架构,对其架构进行讲解,然后会对其工作原理和流程进行深入学习。实验部分主要锻炼学员对于shell编程的基本运用,帮助大家理论联系实际,真正掌握shell脚本知识。', + '本章主要内容包括:', + '1、shell编程的基础,包括shell脚本输入、输出、重定向和管道等等', + '2、shell编程中的字符、变量和运算', + '3、shell编程的语句,包括循环语句和条件语句等等' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx' + }, + { + label: '8.1 Shell编程基础', + key: '8.1 Shell编程基础', + desc: '这一单元我们主要介绍shell编程的基础,包括shell脚本输入、输出、重定向和管道等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80.mp4', + + }, + { + label: '8.2 字符、变量和运算', + key: '8.2 字符、变量和运算', + desc: '这一单元我们主要介绍shell编程中的字符、变量和运算。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97.mp4', + + }, + { + label: '8.3 Shell编程语句', + key: '8.3 Shell编程语句', + desc: '这一单元我们主要介绍shell编程的语句,包括循环语句和条件语句等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5.mp4', + + } + ] + }, + { + label: '9 Samba文件共享服务器管理', + children: [ + { + label: '本章导读', + key: 'introduction9', + introduction: [ + '本章是整个课程的最后一章,将为大家演示整个综合实验。通过对前几章内容的综合运用,来完成Samba文件共享服务的搭建和使用。', + '本章主要内容包括:', + '1、综合实验背景介绍', + '2、综合实验演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '9.1 综合实验背景介绍', + key: '9.1 综合实验背景介绍', + desc: '这一单元我们主要介绍Samba服务器的架构和工作原理,了解如何配置Samba对应的目录的一些用户以及权限,并使用前八章学习的知识做一些简单的运维工作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D.mp4' + }, + { + label: '9.2 综合实验演示', + key: '9.2 综合实验演示', + desc: '这一单元我们主要介绍如何搭建Samba文件共享服务器。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + ] + } + ] + }, + ru: { + COURSE_LIST: [ + { + ID: 1, + COURSE_H1: 'HCIA-openEuler 认证培训课程', + NAV_DATA: [ + { + label: '课程导读', + key: 'introduction0', + introduction: [ + '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + 'OpenEuler是一个开源免费的Linux发行版系统,通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。openEuler同时是一个创新的系统,倡导客户在系统上提出创新想法、开拓新思路、实践新方案。', + 'HCIA-openEuler华为认证openEuler工程师在线课程定位于培养和认证具备企业数据中心核心操作系统基础操作与管理能力的工程师。', + '通过HCIA-OpenEuler V1.0 认证,您将掌握openEuler操作系统基础命令,掌握openEuler用户管理、网络管理、权限管理,掌握shell基础知识;具备企业数据中心核心操作系统基础操作与管理能力;能够胜任Linux系统运维工程师等岗位。', + '本次课程我们首先需要系统地了解openEuler是什么,对openEuler进行初步的了解。', + '然后会依次学习并了解:', + '1、操作系统发展史', + '2、openEuler基础命令如目录操作、文件查看等', + '3、vi与vim文本编辑器', + '4、openEuler用户、用户组与权限管理', + '5、openEuler操作系统应用软件安装', + '6、openEuler存储空间管理', + '7、openEuler系统计划任务、网络与服务管理', + '8、shell脚本基础', + '9、Samba文件共享服务器' + ], + teacher: [ + { + img: '/img/learn/hcia/yanglei.png', + position: '华为认证高级讲师', + name: '杨磊' + }, + { + img: '/img/learn/hcia/zhongyunan.png', + position: '华为认证高级讲师', + name: '钟育楠' + } + ] + }, + { + label: '1 openEuler操作系统入门', + children: [ + { + label: '本章导读', + key: 'introduction1', + introduction: [ + '本章《openEuler操作系统入门》作为课程的第一章,将帮助大家快速了解什么是openEuler。本章课程主要介绍了GNU自由软件基金会、Linux起源、openEuler操作系统以及它们之间的关系,并且演示了如何安装openEuler操作系统,以及如何登录使用openEuler操作系统。', + '以理论加实验的方式,更加生动地引领大家进入openEuler之旅。', + '本章主要内容包括:', + '1、Linux介绍', + '2、openEuler安装', + '3、openEuler入门级操作' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx' + }, + { + label: '1.1 Linux介绍', + key: '1.1 Linux介绍', + desc: '这一单元我们主要介绍Linux操作系统的入门知识。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.1%2Blinux%E4%BB%8B%E7%BB%8D.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.2 openEuler安装', + key: '1.2 openEuler安装', + desc: '这一单元我们主要介绍如何安装openEuler。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.2%2BopenEuler%E5%AE%89%E8%A3%85.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + }, + { + label: '1.3 openEuler入门级操作', + key: '1.3 openEuler入门级操作', + desc: '这一单元我们主要介绍如何使用openEuler操作系统。', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%80%E7%AB%A0/1.3%2BopenEuler%E5%85%A5%E9%97%A8%E7%BA%A7%E6%93%8D%E4%BD%9C.mp4', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/01%20openEuler%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8.pptx', + } + ] + }, + { + label: '2 命令行操作基础', + children: [ + { + label: '本章导读', + key: 'introduction2', + introduction: [ + '本章我们主要介绍命令行的一些基础操作,包括入门级命令行代码,以及如何使用命令行管理文件。', + '我们的课程分为理论和实验两部分,理论部分介绍命令行,实验部分加深印象。通过本章的学习,希望大家可以掌握Linux命令的基础知识、Linux系统登录命令、系统电源管理命令、系统帮助命令和文件管理命令。', + '本章主要内容包括:', + '1、Linux命令基础知识。', + '2、Linux系统中的目录操作、文件操作和文件查看操作。', + '3、文件的分页查看操作和查找操作。', + '4、文件的压缩和打包操作。' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + }, + { + label: '2.1 Linux命令行基础', + key: '2.1 Linux命令行基础', + desc: '这一单元我们主要介绍Linux命令行操作基础,包括命令行入门和使用命令行管理文件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94/2.1%20Linux%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%9F%BA%E7%A1%80%E3%80%81%E7%99%BB%E5%BD%95%E5%92%8C%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E4%BB%A5%E5%8F%8A%E4%B8%BB%E8%A6%81%E7%9B%AE%E5%BD%95%E7%9A%84%E7%94%A8%E9%80%94.mp4' + }, + { + label: '2.2 目录操作、文件操作和查看操作', + key: '2.2 目录操作、文件操作和查看操作', + desc: '这一单元我们主要介绍Linux系统中的目录操作、文件操作、和文件查看操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C/2.2%20%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C%E3%80%81%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.3 分页查看操作和查找操作', + key: '2.3 分页查看操作和查找操作', + desc: '这一单元我们主要介绍文件的分页查看操作和查找操作。 ', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C/2.3%20%E5%88%86%E9%A1%B5%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E5%92%8C%E6%9F%A5%E6%89%BE%E6%93%8D%E4%BD%9C.mp4' + }, + { + label: '2.4 压缩和打包操作', + key: '2.4 压缩和打包操作', + desc: '这一单元我们主要介绍文件的压缩和打包操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/02%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%93%8D%E4%BD%9C%E5%9F%BA%E7%A1%80.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%8C%E7%AB%A0/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C/2.4%20%E5%8E%8B%E7%BC%A9%E5%92%8C%E6%89%93%E5%8C%85%E6%93%8D%E4%BD%9C.mp4' + } + ] + }, + { + label: '3 文本编辑器及文本处理', + children: [ + { + label: '本章导读', + key: 'introduction3', + introduction: [ + '本章课程我们将了解Linux系统中常见的文本编辑器,以及对应的文本处理方式,常见的文本编辑器包括Emacs、nano、gedit、vi和vim等等,本章我们将重点介绍vi和vim编辑器,以及它们的三种主要模式。通过本章的学习,希望大家可以掌握vim文本编辑器的常用操作,包括如何使用vim打开文件、修改文件、保存文件,以及vim文本编辑器的常用快捷操作等等。', + '本章我们依然分理论和实验两部分进行讲解。理论部分我们主要讲解Linux文本编辑器的作用、架构、原理和流程。实验部分主要锻炼大家理论联系实际的能力,真正地掌握和理解文本编辑器的日常运维操作。', + '本章主要内容包括:', + '1、常见文本编辑器,以及VIM打开文件和移动光标', + '2、如何使用VIM编辑器', + '3、如何在Linux中查看文件', + '4、文件摘选和字段提取' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx' + }, + { + label: '3.1 常见文本编辑器', + key: '3.1 常见文本编辑器', + desc: '这一单元我们主要介绍Linux系统中常用的文本编辑器,包括Emacs、nano、gedit、vi和vim,以及如何使用vim文本编辑器打开文件,如何在vim中移动光标等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87/3.1%20%E5%B8%B8%E8%A7%81%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%8C%E4%BB%A5%E5%8F%8AVIM%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%92%8C%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87.mp4' + }, + { + label: '3.2 如何使用VIM编辑器', + key: '3.2 如何使用VIM编辑器', + desc: '这一单元我们主要介绍如何使用vim文本编辑器,包括数据操作,行号的显示和取消,vim中的查找与替换,设置搜索高亮,修改文件撤销或重做,以及如何保存文件并退出等内容。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8/3.2%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8VIM%E7%BC%96%E8%BE%91%E5%99%A8.mp4' + }, + { + label: '3.3 在Linux查看文件-cat、more、less', + key: '3.3 在Linux查看文件-cat、more、less', + desc: '这一单元我们主要介绍文本处理的命令,包括如何查看文件,如何筛选文件,如何提取列或者字段,以及如何提取关键字。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less/3.3%20%E5%9C%A8Linux%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6-cat%E3%80%81more%E3%80%81less.mp4' + }, + { + label: '3.4 文件摘选和字段提取', + key: '3.4 文件摘选和字段提取', + desc: '这一单元我们主要介绍查看文件的命令:cat、more和less。Linux文件的摘选命令:head和tail。提取文件中列或者字段的命令:cut。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/03%20%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E5%8F%8A%E6%96%87%E6%9C%AC%E5%A4%84%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%89%E7%AB%A0/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96/3.4%20%E6%96%87%E4%BB%B6%E6%91%98%E9%80%89%E5%92%8C%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96.mp4' + } + ] + }, + { + label: '4 用户和权限管理', + children: [ + { + label: '本章导读', + key: 'introduction4', + introduction: [ + '本章我们将学习用户和权限管理,帮助大家了解用户和组的基础概念,掌握文件和目录的命令行和权限管理操作,以及文件的特殊访问权限管理。', + '本章我们在介绍时仍然会分为两个部分,理论部分主要讲解用户、用户组和文件权限的基本概念,实验部分会重点锻炼大家对相关管理命令的操作,帮助大家理论联系实际,真正了解和掌握用户和权限管理。', + '本章主要内容包括:', + '1、用户的概念和用户相关的管理命令', + '2、用户组的概念和相关的管理命令', + '3、文件权限的基础概念' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '4.1 用户的概念和相关管理命令', + key: '4.1 用户的概念和相关管理命令', + desc: '这一单元我们主要介绍用户的概念,以及useradd、usermod、passwd等用户相关的管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4/4.1%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4.mp4', + + }, + { + label: '4.2 用户的管理文件', + key: '4.2 用户的管理文件', + desc: '这一单元我们主要介绍用户组的概念,以及groupadd、groupmod等用户组管理命令。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6/4.2%20%E7%94%A8%E6%88%B7%E7%BB%84%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%9B%B8%E5%85%B3%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6.mp4', + + }, + { + label: '4.3 文件权限的概念及相关操作', + key: '4.3 文件权限的概念及相关操作', + desc: '这一单元我们主要介绍在openEuler系统中,用户和用户组的基础概念、它们的相关命令、相关文件等等,还将了解到常见的读写权限、执行权限,以及如何针对文件或者目录进行权限的修改。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/04%20%E7%94%A8%E6%88%B7%E5%92%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%9B%9B%E7%AB%A0/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/4.3%20%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E7%9A%84%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + } + ] + }, + { + label: '5 安装软件并管理服务', + children: [ + { + label: '本章导读', + key: 'introduction5', + introduction: [ + '本章我们将主要介绍如何在Linux中安装软件并管理服务,帮助大家了解安装软件的两种方式:RPM包安装和源代码安装。', + '理论部分主要讲解两种安装方式的优缺点及特性,实验部分将辅助大家更深入的了解RPM和DNF的操作命令和systemd的管理服务命令。', + '本章主要内容包括:', + '1、RPM、DNF概念和操作命令', + '1、RPM、DNF概念和操作命令', + '3、systemd管理服务' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx' + }, + { + label: '5.1 RPM的概念和操作命令', + key: '5.1 RPM的概念和操作命令', + desc: '这一单元我们主要介绍RPM的概念,以及如何使用RPM命令进行安装、卸载、升级和查询等操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.1%20RPM%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.2 DNF的概念和操作命令', + key: '5.2 DNF的概念和操作命令', + desc: '这一单元我们主要介绍DNF的概念,以及如何添加和启动软件源,如何配置DNF,如何使用DNF查询、安装、删除、升级软件包和软件包组。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/5.2%20DNF%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4.mp4' + }, + { + label: '5.3 RPM和DNF的操作实验', + key: '5.3 RPM和DNF的操作实验', + desc: '这一单元我们主要介绍配置软件源的实验,以及如何使用RPM命令和DNF命令管理软件。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C/5.3%20RPM%E5%92%8CDNF%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E9%AA%8C.mp4', + + }, + { + label: '5.4 源代码软件及其安装方法', + key: '5.4 源代码软件及其安装方法', + desc: '这一单元我们主要介绍源代码软件的概念,以及使用源码安装软件的方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95/5.4%20%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6%E5%8F%8A%E5%85%B6%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95.mp4', + + }, + { + label: '5.5 systemd管理服务', + key: '5.5 systemd管理服务', + desc: '这一单元我们主要介绍systemd管理服务的概念,以及systemd的主命令systemctl的用法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/05%20%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%B9%B6%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%BA%94%E7%AB%A0/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1/5.5%20systemd%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1.mp4', + + } + ] + }, + { + label: '6 管理文件系统及存储', + children: [ + { + label: '本章导读', + key: 'introduction6', + introduction: [ + '存储是IT领域中非常重要的一部分,它被用来保存各种各样的数据,本章的课程将会在理论部分介绍与存储相关的一些概念,包括文件系统、磁盘类型、逻辑卷等,同时也会在实验部分演示如何使用它们对数据进行保存。', + '本章主要内容包括:', + '1、文件系统简介', + '2、openEuler文件系统及相关操作', + '3、MBR操作演示', + '4、GPT分区演示', + '5、逻辑卷管理和操作演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx' + }, + { + label: '6.1 文件系统简介', + key: '6.1 文件系统简介', + desc: '这一单元我们主要介绍文件系统的基本概念,以及分区的含义。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B/6.1%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%AE%80%E4%BB%8B.mp4', + + }, + { + label: '6.2 openEuler文件系统及相关操作', + key: '6.2 openEuler文件系统及相关操作', + desc: '这一单元我们主要介绍文件系统和存储相关的知识,以及磁盘存储的挂载和使用方法。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C/6.2%20openEuler%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C.mp4', + + }, + { + label: '6.3 MBR操作演示', + key: '6.3 MBR操作演示', + desc: '这一单元我们主要介绍如何进行MBR的分区的实验操作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.3%20MBR%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.4 GPT分区演示', + key: '6.4 GPT分区演示', + desc: '这一单元我们主要介绍如何进行GPT的分区模式。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA/6.4%20GPT%E5%88%86%E5%8C%BA%E6%BC%94%E7%A4%BA.mp4', + + }, + { + label: '6.5 逻辑卷管理', + key: '6.5 逻辑卷管理', + desc: '这一单元我们主要介绍逻辑卷相关的一些概念,以及如何管理逻辑卷和动态调整逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86/6.5%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86.mp4', + + }, + { + label: '6.6 逻辑卷管理操作演示', + key: '6.6 逻辑卷管理操作演示', + desc: '这一单元我们主要介绍如何创建一个LV,也就是如何创建一个逻辑卷。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/06%20%E7%AE%A1%E7%90%86%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%8F%8A%E5%AD%98%E5%82%A8.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AD%E7%AB%A0/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA/6.6%20%E9%80%BB%E8%BE%91%E5%8D%B7%E7%AE%A1%E7%90%86%E6%93%8D%E4%BD%9C%E6%BC%94%E7%A4%BA.mp4', + + } + ] + }, + { + label: '7 系统管理', + children: [ + { + label: '本章导读', + key: 'introduction7', + introduction: [ + '在Linux系统中你可能已经发现了为什么系统常常会自动地进行一些任务?这些任务到底是谁在支配他们工作的?本章的课程将简单介绍几个系统管理的操作,包括计划任务、网络管理及进程管理。', + '我们同样会采用理论加实验的方式,帮助大家更直观地理解系统管理,并掌握它的操作。', + '本章主要内容包括:', + '1、计划任务管理', + '2、at和crontab演示', + '3、网络管理和演示', + '4、进程管理和演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.1 计划任务管理', + key: '7.1 计划任务管理', + desc: '这一单元我们主要介绍计划任务管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.2 at和crontab演示', + key: '7.2 at和crontab演示', + desc: '这一单元我们主要介绍计划任务管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.3 网络管理', + key: '7.3 网络管理', + desc: '这一单元我们主要介绍网络管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.4 网络管理演示', + key: '7.4 网络管理演示', + desc: '这一单元我们主要介绍网络管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '7.5 进程管理', + key: '7.5 进程管理', + desc: '这一单元我们主要介绍进程管理的理论部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/7.5%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86.mp4' + }, + { + label: '7.6 进程管理演示', + key: '7.6 进程管理演示', + desc: '这一单元我们主要介绍进程管理的实验部分。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/07%20%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B8%83%E7%AB%A0/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA/7.6%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + { + label: '8 使用shell脚本', + children: [ + { + label: '本章导读', + key: 'introduction8', + introduction: [ + '在这一章课程中,我们将会学习如何使用shell脚本,首先是shell基础知识,包括shell脚本的定义,构成等等内容,其次我们会介绍一些shell编程基础,包括标准输入、标准输出,管道、运算、变量、字符等等内容 ,我们还将学习如何编写常用的shell脚本,包括如何调试shell脚本,以及shell脚本的编写风格等等内容。', + '本章我们将同样按照之前的课程设计,分为理论和实验两个部分,理论部分我们将简单介绍shell脚本的作用,并基于基本架构,对其架构进行讲解,然后会对其工作原理和流程进行深入学习。实验部分主要锻炼学员对于shell编程的基本运用,帮助大家理论联系实际,真正掌握shell脚本知识。', + '本章主要内容包括:', + '1、shell编程的基础,包括shell脚本输入、输出、重定向和管道等等', + '2、shell编程中的字符、变量和运算', + '3、shell编程的语句,包括循环语句和条件语句等等' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx' + }, + { + label: '8.1 Shell编程基础', + key: '8.1 Shell编程基础', + desc: '这一单元我们主要介绍shell编程的基础,包括shell脚本输入、输出、重定向和管道等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/8.1%20Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80.mp4', + + }, + { + label: '8.2 字符、变量和运算', + key: '8.2 字符、变量和运算', + desc: '这一单元我们主要介绍shell编程中的字符、变量和运算。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97/8.2%20%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%98%E9%87%8F%E5%92%8C%E8%BF%90%E7%AE%97.mp4', + + }, + { + label: '8.3 Shell编程语句', + key: '8.3 Shell编程语句', + desc: '这一单元我们主要介绍shell编程的语句,包括循环语句和条件语句等等。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/08%20%E4%BD%BF%E7%94%A8shell%E8%84%9A%E6%9C%AC.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E5%85%AB%E7%AB%A0/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5/8.3%20Shell%E7%BC%96%E7%A8%8B%E8%AF%AD%E5%8F%A5.mp4', + + } + ] + }, + { + label: '9 Samba文件共享服务器管理', + children: [ + { + label: '本章导读', + key: 'introduction9', + introduction: [ + '本章是整个课程的最后一章,将为大家演示整个综合实验。通过对前几章内容的综合运用,来完成Samba文件共享服务的搭建和使用。', + '本章主要内容包括:', + '1、综合实验背景介绍', + '2、综合实验演示' + ], + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx' + }, + { + label: '9.1 综合实验背景介绍', + key: '9.1 综合实验背景介绍', + desc: '这一单元我们主要介绍Samba服务器的架构和工作原理,了解如何配置Samba对应的目录的一些用户以及权限,并使用前八章学习的知识做一些简单的运维工作。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D/9.1%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D.mp4' + }, + { + label: '9.2 综合实验演示', + key: '9.2 综合实验演示', + desc: '这一单元我们主要介绍如何搭建Samba文件共享服务器。', + ppt_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/PPT/09%20Samba%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86.pptx', + video_link: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A7%86%E9%A2%91%E5%8F%8A%E5%AD%97%E5%B9%95%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/%E7%AC%AC%E4%B9%9D%E7%AB%A0/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA/9.2%20%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%BC%94%E7%A4%BA.mp4' + } + ] + }, + ] + } + ] + } + } \ No newline at end of file diff --git a/web-ui/docs/.vuepress/data/salon.js b/web-ui/docs/.vuepress/data/salon.js new file mode 100644 index 0000000000000000000000000000000000000000..47f7388400fe17bc7c0604501b6d2629ab6d0b4b --- /dev/null +++ b/web-ui/docs/.vuepress/data/salon.js @@ -0,0 +1,1280 @@ +/** + * @file 资料组维护数据文件 + * */ + +module.exports = { + cn: { + MEETUPS_LIST : [ + { + ID: 1, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E5%8D%97%E4%BA%AC%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review1.png', + MEETUPS_TITLE: '开源操作系统 金陵技术论坛', + TITLE_LIST: ['开源操作系统 金陵技术论坛'], + MEETUPS_IMG: '/img/meetups/1.png', + MEETUPS_DATE: '2020-10-24', + MEETUPS_MONTH: '十月', + MEETUPS_DESC: ['进入2020年,信创产业飞速发展,以操作系统为代表的基础软件迎来快速发展机遇,此次论坛聚集国内开源操作系统的技术大咖,分享以HopeEdge,openEuler为代表的操作系统的发展现状,并与硬件厂商、解决方案伙伴们一起探讨未来,携手共建繁荣的信创生态。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30', + SPEAKER: '' + }, + { + THEME: '开幕', + TIME: '13:55', + SPEAKER: '' + }, + { + THEME: 'iSula与轻量化操作系统HopeEdge', + TIME: '14 : 00', + SPEAKER: '' + }, + { + THEME: 'Linux内核安全系统设计与演化', + TIME: '14 : 35', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '15 : 10', + SPEAKER: '' + }, + { + THEME: '操作系统可信技术的发展', + TIME: '15 : 25', + SPEAKER: '' + }, + { + THEME: '开源性能调优工具A-tune的原理和实践', + TIME: '14:45~15:05', + SPEAKER: '' + }, + { + THEME: 'openEuler轻量级虚拟化引擎StratoVirt', + TIME: '16 : 00', + SPEAKER: '' + }, + { + THEME: '伙伴案例分享', + TIME: '16 : 35', + SPEAKER: '' + }, + { + THEME: 'openGauss企业级开源数据库特性解读', + TIME: '17 : 00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address1.png', + ADDRESS_UP: '润和创智中心', + ADDRESS_DOWN: [ + '南京市雨花区软件大道168号','润和创智中心二楼会议大厅' + ], + APPLY_QRCODE: '/img/meetups/qrcode1.png', + ADDRESS_LOCATION: ['118.76466','31.979428'], + } + }, + { + ID: 2, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E9%95%BF%E6%B2%99%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review2.png', + MEETUPS_TITLE: '长沙 Meetup', + TITLE_LIST: ['长沙 Meetup'], + MEETUPS_IMG: '/img/meetups/2.png', + MEETUPS_DATE: '2020-10-31', + MEETUPS_MONTH: '十月', + MEETUPS_DESC: ['围绕openEuler社区、鲲鹏架构、麒麟信安操作系统(欧拉版)进行经验分享和技术交流。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30~14:00', + SPEAKER: '' + }, + { + THEME: '主持人开场', + TIME: '14:00~14:05', + SPEAKER: '' + }, + { + THEME: '开场致辞', + TIME: '14:05~14:10', + SPEAKER: '麒麟信安' + }, + { + THEME: 'openEuler和社区基本情况介绍', + TIME: '14:10~14:15', + SPEAKER: '华为' + }, + { + THEME: '基于麒麟信安操作系统(欧拉版)V3的应用迁移和适配', + TIME: '14:15~14:30', + SPEAKER: '麒麟信安' + }, + { + THEME: '基于鲲鹏架构的云桌面调优和实践', + TIME: '14:30~14:45', + SPEAKER: '麒麟信安' + }, + { + THEME: '开源性能调优工具A-tune的原理和实践', + TIME: '14:45~15:05', + SPEAKER: '华为' + }, + { + THEME: '华为Hadoop ARM64优化探索之路', + TIME: '15:05~15:30', + SPEAKER: '华为' + }, + { + THEME: '参观湖南鲲鹏生态展厅、合影及茶歇', + TIME: '15:30~15:55', + SPEAKER: '湖南省鲲鹏生态创新中心' + }, + { + THEME: 'openGauss企业级开源数据库特性解读', + TIME: '15:55~16:20', + SPEAKER: '华为' + }, + { + THEME: '基于openGauss的实验数据分析平台', + TIME: '16:20~16:45', + SPEAKER: '国防科大' + }, + { + THEME: '现场观众Q&A', + TIME: '16:45~17:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address2.png', + ADDRESS_UP: '鲲鹏生态创新中心培训室', + ADDRESS_DOWN: [ + '金茂北塔47楼','湖南省鲲鹏生态创新中心培训室' + ], + APPLY_QRCODE: '/img/meetups/qrcode2.png', + ADDRESS_LOCATION: ['112.910516','28.202771'], + } + }, + { + ID: 3, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A5%BF%E5%AE%89%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review3.png', + MEETUPS_TITLE: '共创·共赢 统信UOS & openEuler开源社区技术研讨论坛', + TITLE_LIST: ['共创·共赢','统信UOS & openEuler开源社区技术研讨论坛'], + MEETUPS_IMG: '/img/meetups/3.png', + MEETUPS_DATE: '2020-11-28', + MEETUPS_MONTH: '十一月', + MEETUPS_DESC: ['本次活动旨在通过社区合作,打造创新平台,构建支持多处理器构架、统一和开放的操作系统,推动软硬件应用生态繁荣发展。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到区签到', + TIME: '14 : 00', + SPEAKER: '' + }, + { + THEME: '开场', + TIME: '14 : 30', + SPEAKER: '' + }, + { + THEME: '领导致辞', + TIME: '14 : 35', + SPEAKER: '金奇才' + }, + { + THEME: 'uos欧拉版系统介绍及性能优化', + TIME: '14 : 45 ', + SPEAKER: '叶青龙' + }, + { + THEME: 'uos欧拉版生态适配', + TIME: '15 : 15', + SPEAKER: '潘晨博' + }, + { + THEME: '问答+互动环节', + TIME: '15 : 45', + SPEAKER: '' + }, + { + THEME: '高校教授分享', + TIME: '15 : 55', + SPEAKER: '陈莉君 西安邮电大学教授' + }, + { + THEME: 'openEuler+ARM64在云计算与大数据开源领域的最佳实践', + TIME: '16 : 05 ', + SPEAKER: '郑振宇、姜逸坤' + }, + { + THEME: 'StratoVirt:openEuler下一代开放虚拟化平台StratoVirt', + TIME: '16 : 25 ', + SPEAKER: '陈振东' + }, + { + THEME: '问答+抽奖环节', + TIME: '16 : 45 ', + SPEAKER: '' + }, + { + THEME: '闭幕', + TIME: '16 : 55 ', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address3.png', + ADDRESS_UP: '西安软件新城', + ADDRESS_DOWN: [ + '西安市雁塔区','西安软件新城软件研发基地2期C2栋3层' + ], + APPLY_QRCODE: '/img/meetups/qrcode3.png', + ADDRESS_LOCATION: ['108.841531','34.213187'], + } + }, + { + ID: 4, + MEETUPS_TITLE: '数字中国创新大赛 鲲鹏赛道训练营,第十五期--openEuler专场', + TITLE_LIST: ['数字中国创新大赛 鲲鹏赛道训练营','第十五期--openEuler专场'], + MEETUPS_IMG: '/img/meetups/4.png', + MEETUPS_DATE: '2020-12-18', + MEETUPS_MONTH: '十二月', + MEETUPS_DESC: ['数字中国创新大赛·鲲鹏赛道作为国家互联网信息办公室、国家发展和改革委员会、工业和信息化部、福建省人民政府主办的数字中国建设峰会的重要赛道之一,为积极响应国家和省市发展数字技术的相关决策部署和政策导向,推进数字产业生态建设。鲲鹏训练营第十五期将在福建软件园进行举办,邀请华为、统信软件、江苏润和软件等技术专家围绕openEuler开展系列主题演讲培训。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '入场签到', + TIME: '08:30-09:00', + SPEAKER: '' + }, + { + THEME: '领导致辞', + TIME: '09:00-09:15', + SPEAKER: '' + }, + { + THEME: 'HopeEdge:操作系统在边缘计算的实践', + TIME: '09:15-09:45', + SPEAKER: '' + }, + { + THEME: '携手openEuler,共创开源新生态', + TIME: '09:45-10:15', + SPEAKER: '' + }, + { + THEME: 'openEuler操作系统介绍', + TIME: '10:15-10:40', + SPEAKER: '' + }, + { + THEME: 'StratoVirt:openEuler下一代开放虚拟化平台', + TIME: '10:40-11:10', + SPEAKER: '' + }, + { + THEME: 'iSula容器解决方案介绍和规划', + TIME: '11:10-11:40', + SPEAKER: '' + }, + { + THEME: '原子基金议题', + TIME: '11:40-12:00', + SPEAKER: '' + }, + { + THEME: '云原生主题闭门会', + TIME: '15:00-17:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address4.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '上午:福州软件园A区双创新城1号楼1层','下午:郊野公园' + ], + APPLY_QRCODE: '/img/meetups/qrcode4.png', + ADDRESS_LOCATION: ['119.276427','26.117974'], + } + }, + { + ID: 5, + MEETUPS_TITLE: 'openEuler MIC meetup', + TITLE_LIST: ['openEuler MIC meetup','谁说不写代码就不能玩开源?'], + MEETUPS_IMG: '/img/meetups/5.png', + MEETUPS_DATE: '2021-03-20', + MEETUPS_MONTH: '三月', + MEETUPS_DESC: ['openEuler MIC meetup,度量(metrics)、基础设施(infrastructure)、合规(compliance)。', '开源项目健康运作离不开度量,openEuler联合Linux基金会顶级项目CHAOSS,共同探讨社区健康度量体系;合规是开源项目的底线,忽视许可、版权将带来法务风险,让我们打开主流开源license,逐条分析它们的权利、义务和限制。','打造超强社区工具,分享社区度量看板、Licence许可分析器等工具开发的点点滴滴,让工具会成为社区健康运营的助力。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: 'CHAOSS社区度量体系介绍', + TIME: '14:00-14:15', + SPEAKER: '' + }, + { + THEME: '2020 GitHub数字洞察', + TIME: '14:15-14:30', + SPEAKER: '' + }, + { + THEME: '开源社区大数据分析:从度量到洞察', + TIME: '14:30-15:00', + SPEAKER: '' + }, + { + THEME: 'openEuler社区运营看板', + TIME: '15:00-15:30', + SPEAKER: '' + }, + { + THEME: '利用开源构建 openEuler 基础设施', + TIME: '15:30-16:00', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '16:00-16:15', + SPEAKER: '' + }, + { + THEME: 'openEuler体验设计', + TIME: '16:15-16:45', + SPEAKER: '' + }, + { + THEME: '开源CLA解密', + TIME: '16:45-17:10', + SPEAKER: '' + }, + { + THEME: 'openEuler合规的探索和实践', + TIME: '17:10-17:30', + SPEAKER: '' + }, + { + THEME: '开源许可证识别以及许可证条款冲突自动化检测', + TIME: '17:30-18:00', + SPEAKER: '' + }, + { + THEME: '晚餐', + TIME: '18:00-18:30', + SPEAKER: '' + }, + { + THEME: '开源party', + TIME: '18:30-18:40', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address5.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '上海市浦东新区博云路111号爱酷空间B1' + ], + APPLY_QRCODE: '/img/meetups/qrcode5.png', + ADDRESS_LOCATION: ['121.613359','31.208858'], + } + }, + { + ID: 6, + MEETUPS_TITLE: 'Rust Meetup 深圳站', + TITLE_LIST: ['Rust Meetup 深圳站'], + MEETUPS_IMG: '/img/meetups/6.png', + MEETUPS_DATE: '2021-03-27', + MEETUPS_MONTH: '三月', + MEETUPS_DESC: ['3月27日,由华为、openEuler 、Netwarps、开源中国和Rust中文社区联合主办的Rust Meetup将在深圳举行,此次Meetup将围绕Rust语言无栈协程、Rust实际应用、Rust科学计算等方向进行分享,届时我们会邀请华为、Netwarps、PingCAP等相关应用企业,openEuler、Rust中文社区、开源中国等技术社区,以及行业内Rust开发者参与到此次分享中。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:00-13:30', + SPEAKER: '' + }, + { + THEME: '从libp2p-rs到IPFS  谢敬伟@Netwarps', + TIME: '13:00-14:10', + SPEAKER: '' + }, + { + THEME: 'Rust科学计算多维数组运算库的分析与实践 李原@华为', + TIME: '14:10-14:50', + SPEAKER: '' + }, + { + THEME: '深度剖析Rust异步编程/无栈协程  何元勋@Netwarps', + TIME: '14:50-15:30', + SPEAKER: '' + }, + { + THEME: '休息/自由交流', + TIME: '15:30-15:40', + SPEAKER: '' + }, + { + THEME: 'Rust FFI 跨语言代码复用的方法和实践  骆迪安@TiKV', + TIME: '15:40-16:20', + SPEAKER: '' + }, + { + THEME: 'Rust语言在系统开发(虚拟化平台StratoVirt)的实践与应用 张亮@华为', + TIME: '16:20-17:00', + SPEAKER: '' + }, + { + THEME: '基于TVM Rust Runtime和WASM沙箱运行AI模型 王辉@华为', + TIME: '17:00-17:40', + SPEAKER: '' + }, + { + THEME: 'QA/自由交流', + TIME: '17:40-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address6.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '深圳市福田区中康路136号新一代产业园4栋19楼' + ], + APPLY_QRCODE: '/img/meetups/qrcode6.png', + ADDRESS_LOCATION: ['114.067925','22.578717'], + } + }, + { + ID: 7, + MEETUPS_TITLE: 'AI-OPS Meetup', + TITLE_LIST: ['AI-OPS Meetup'], + MEETUPS_IMG: '/img/meetups/7.png', + MEETUPS_DATE: '2021-04-08', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['AI-OPS致力于推动系统运维的可视化、自动化、智能化,打造高可靠性、高性能、永不中断的基础设施;','构建系统数据信息体系,使数据能跨组件,跨平台共享,使上层业务更易于创新开发,保证全栈操作系统运维成为可能,打造开源/开放的操作系统;','提供基础设施热补丁、热替换软件技术,保证基础设施不中断在线服务; 提供问题诊断、性能分析、系统调测等技术,提供系统运维过程中必须的可视化、自动化、智能化调试必须工具。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '开场', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: '操作系统智能运维', + TIME: '14:00-14:30', + SPEAKER: '华为/栾建海' + }, + { + THEME: '系统升级方案-内核热替换', + TIME: '14:35-15:05', + SPEAKER: '华为/朱玲' + }, + { + THEME: '运维定位工具 - Crash/Bcc', + TIME: '15:10-15:40', + SPEAKER: '华为/桑琰' + }, + { + THEME: 'DevSecOps for Kubernetes-based Applications', + TIME: '15:45-16:15', + SPEAKER: 'JFrogs/高欣' + }, + { + THEME: '中国移动云原生gitops落地实践', + TIME: '16:20-16:50', + SPEAKER: '中国移动/张一波' + }, + { + THEME: '开源运维系统分析及PilotGo项目讨论', + TIME: '16:55-17:25', + SPEAKER: '麒麟软件/侯健' + }, + { + THEME: '自由交流', + TIME: '17:35-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '北京市海淀区北四环西路9号银谷大厦12层东侧' + ], + APPLY_QRCODE: '/img/meetups/qrcode7.png', + ADDRESS_LOCATION: ['116.340773','39.992655'], + } + }, + { + ID: 8, + MEETUPS_TITLE: 'openEuler X OpenStack X Arm Meetup', + TITLE_LIST: ['openEuler X OpenStack X Arm Meetup','跨界全栈,技术盛宴'], + MEETUPS_IMG: '/img/meetups/8.png', + MEETUPS_DATE: '2021-04-10', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['云计算、处理器、操作系统是上层业务的基石,开源云计算的事实标准OpenStack,旨在打造最具活力开源社区的openEuler,风头正劲的Arm架构所组成的跨界全栈,能碰撞出怎样的火花?技术分享、头脑风暴、大咖圆桌、现场Q&A,一站式的技术盛宴等你享用。'], + MEETUPS_FLOW_PATH: [ + { + THEME: 'PTG议程', + TIME: '09:00-12:00', + SPEAKER: '' + }, + { + THEME: '签到', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: 'openEuler OpenStack SIG介绍与进展', + TIME: '14:00-14:30', + SPEAKER: '' + }, + { + THEME: 'openEuler 20.03 LTS 在联通沃云的适配', + TIME: '14:35-15:05', + SPEAKER: '' + }, + { + THEME: 'Arm落地实践和云计算在信创产业的发展情况', + TIME: '15:10-15:40', + SPEAKER: '' + }, + { + THEME: 'OpenStack Arm CI介绍以及openEuler在OpenStack CI的支持进展', + TIME: '15:45-16:15', + SPEAKER: '' + }, + { + THEME: '业务软件在Arm平台上的优化', + TIME: '16:20-16:50', + SPEAKER: '' + }, + { + THEME: 'Panel Discussion', + TIME: '16:55-17:25', + SPEAKER: '' + }, + { + THEME: '合影、自由讨论', + TIME: '17:30-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '北京市海淀区中关村创业大街昊海楼5号楼103怡仁空间' + ], + APPLY_QRCODE: '/img/meetups/qrcode8.png', + ADDRESS_LOCATION: ['116.313623','39.990418'], + } + }, + { + ID: 9, + MEETUPS_TITLE: 'openEuler Cloud Native Meetup', + TITLE_LIST: ['openEuler Cloud Native Meetup'], + MEETUPS_IMG: '/img/meetups/9.png', + MEETUPS_DATE: '2021-04-17', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['本次会议openEuler围绕系统、存储、网络、云原生、kubernetes等多个领域话题展开分享。届时将邀请LGT俱乐部相关领域资深技术专家,就行业动态、技术创新、高端应用等方面开展精彩分享,会后将以论坛和体验式沙龙形式与大咖近距离面对面交流。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '12:30-13:00', + SPEAKER: '' + }, + { + THEME: '极简kubernetes发行版-k8e介绍', + TIME: '13:00-13:15', + SPEAKER: '' + }, + { + THEME: '云原生安全初探', + TIME: '13:15-13:45', + SPEAKER: '' + }, + { + THEME: 'K8S扩展开发-CRD与Controller', + TIME: '13:45-14:15', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '14:15-14:30', + SPEAKER: '' + }, + { + THEME: '用WebAssembly快速把AI推理带到生产环境', + TIME: '14:30-15:00', + SPEAKER: '' + }, + { + THEME: '打造比Nginx还快的web服务器', + TIME: '15:00-15:30', + SPEAKER: '' + }, + { + THEME: '互动交流', + TIME: '15:30-16:00', + SPEAKER: '' + }, + { + THEME: '活动抽奖', + TIME: '16:00-16:15', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '高新园区黄浦路507号','海创(大连)科技交流中心三楼海创厅B' + ], + APPLY_QRCODE: '/img/meetups/qrcode9.png', + ADDRESS_LOCATION: ['121.540054','38.872889'], + } + }, + ] + }, + en: { + MEETUPS_LIST : [ + { + ID: 1, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E5%8D%97%E4%BA%AC%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review1.png', + MEETUPS_TITLE: '开源操作系统 金陵技术论坛', + TITLE_LIST: ['开源操作系统 金陵技术论坛'], + MEETUPS_IMG: '/img/meetups/1.png', + MEETUPS_DATE: '2020-10-24', + MEETUPS_MONTH: '十月', + MEETUPS_DESC: ['进入2020年,信创产业飞速发展,以操作系统为代表的基础软件迎来快速发展机遇,此次论坛聚集国内开源操作系统的技术大咖,分享以HopeEdge,openEuler为代表的操作系统的发展现状,并与硬件厂商、解决方案伙伴们一起探讨未来,携手共建繁荣的信创生态。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30', + SPEAKER: '' + }, + { + THEME: '开幕', + TIME: '13:55', + SPEAKER: '' + }, + { + THEME: 'iSula与轻量化操作系统HopeEdge', + TIME: '14 : 00', + SPEAKER: '' + }, + { + THEME: 'Linux内核安全系统设计与演化', + TIME: '14 : 35', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '15 : 10', + SPEAKER: '' + }, + { + THEME: '操作系统可信技术的发展', + TIME: '15 : 25', + SPEAKER: '' + }, + { + THEME: '开源性能调优工具A-tune的原理和实践', + TIME: '14:45~15:05', + SPEAKER: '' + }, + { + THEME: 'openEuler轻量级虚拟化引擎StratoVirt', + TIME: '16 : 00', + SPEAKER: '' + }, + { + THEME: '伙伴案例分享', + TIME: '16 : 35', + SPEAKER: '' + }, + { + THEME: 'openGauss企业级开源数据库特性解读', + TIME: '17 : 00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address1.png', + ADDRESS_UP: '润和创智中心', + ADDRESS_DOWN: [ + '南京市雨花区软件大道168号','润和创智中心二楼会议大厅' + ], + APPLY_QRCODE: '/img/meetups/qrcode1.png', + ADDRESS_LOCATION: ['118.76466','31.979428'], + } + }, + { + ID: 2, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E9%95%BF%E6%B2%99%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review2.png', + MEETUPS_TITLE: '长沙 Meetup', + TITLE_LIST: ['长沙 Meetup'], + MEETUPS_IMG: '/img/meetups/2.png', + MEETUPS_DATE: '2020-10-31', + MEETUPS_MONTH: '十月', + MEETUPS_DESC: ['围绕openEuler社区、鲲鹏架构、麒麟信安操作系统(欧拉版)进行经验分享和技术交流。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30~14:00', + SPEAKER: '' + }, + { + THEME: '主持人开场', + TIME: '14:00~14:05', + SPEAKER: '' + }, + { + THEME: '开场致辞', + TIME: '14:05~14:10', + SPEAKER: '麒麟信安' + }, + { + THEME: 'openEuler和社区基本情况介绍', + TIME: '14:10~14:15', + SPEAKER: '华为' + }, + { + THEME: '基于麒麟信安操作系统(欧拉版)V3的应用迁移和适配', + TIME: '14:15~14:30', + SPEAKER: '麒麟信安' + }, + { + THEME: '基于鲲鹏架构的云桌面调优和实践', + TIME: '14:30~14:45', + SPEAKER: '麒麟信安' + }, + { + THEME: '开源性能调优工具A-tune的原理和实践', + TIME: '14:45~15:05', + SPEAKER: '华为' + }, + { + THEME: '华为Hadoop ARM64优化探索之路', + TIME: '15:05~15:30', + SPEAKER: '华为' + }, + { + THEME: '参观湖南鲲鹏生态展厅、合影及茶歇', + TIME: '15:30~15:55', + SPEAKER: '湖南省鲲鹏生态创新中心' + }, + { + THEME: 'openGauss企业级开源数据库特性解读', + TIME: '15:55~16:20', + SPEAKER: '华为' + }, + { + THEME: '基于openGauss的实验数据分析平台', + TIME: '16:20~16:45', + SPEAKER: '国防科大' + }, + { + THEME: '现场观众Q&A', + TIME: '16:45~17:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address2.png', + ADDRESS_UP: '鲲鹏生态创新中心培训室', + ADDRESS_DOWN: [ + '金茂北塔47楼','湖南省鲲鹏生态创新中心培训室' + ], + APPLY_QRCODE: '/img/meetups/qrcode2.png', + ADDRESS_LOCATION: ['112.910516','28.202771'], + } + }, + { + ID: 3, + MEETUPS_VIDEO_LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%A5%BF%E5%AE%89%E5%BF%AB%E9%97%AA.mp4', + MEETUPS_VIDEO_COVER: '/img/meetups/review3.png', + MEETUPS_TITLE: '共创·共赢 统信UOS & openEuler开源社区技术研讨论坛', + TITLE_LIST: ['共创·共赢','统信UOS & openEuler开源社区技术研讨论坛'], + MEETUPS_IMG: '/img/meetups/3.png', + MEETUPS_DATE: '2020-11-28', + MEETUPS_MONTH: '十一月', + MEETUPS_DESC: ['本次活动旨在通过社区合作,打造创新平台,构建支持多处理器构架、统一和开放的操作系统,推动软硬件应用生态繁荣发展。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到区签到', + TIME: '14 : 00', + SPEAKER: '' + }, + { + THEME: '开场', + TIME: '14 : 30', + SPEAKER: '' + }, + { + THEME: '领导致辞', + TIME: '14 : 35', + SPEAKER: '金奇才' + }, + { + THEME: 'uos欧拉版系统介绍及性能优化', + TIME: '14 : 45 ', + SPEAKER: '叶青龙' + }, + { + THEME: 'uos欧拉版生态适配', + TIME: '15 : 15', + SPEAKER: '潘晨博' + }, + { + THEME: '问答+互动环节', + TIME: '15 : 45', + SPEAKER: '' + }, + { + THEME: '高校教授分享', + TIME: '15 : 55', + SPEAKER: '陈莉君 西安邮电大学教授' + }, + { + THEME: 'openEuler+ARM64在云计算与大数据开源领域的最佳实践', + TIME: '16 : 05 ', + SPEAKER: '郑振宇、姜逸坤' + }, + { + THEME: 'StratoVirt:openEuler下一代开放虚拟化平台StratoVirt', + TIME: '16 : 25 ', + SPEAKER: '陈振东' + }, + { + THEME: '问答+抽奖环节', + TIME: '16 : 45 ', + SPEAKER: '' + }, + { + THEME: '闭幕', + TIME: '16 : 55 ', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address3.png', + ADDRESS_UP: '西安软件新城', + ADDRESS_DOWN: [ + '西安市雁塔区','西安软件新城软件研发基地2期C2栋3层' + ], + APPLY_QRCODE: '/img/meetups/qrcode3.png', + ADDRESS_LOCATION: ['108.841531','34.213187'], + } + }, + { + ID: 4, + MEETUPS_TITLE: '数字中国创新大赛 鲲鹏赛道训练营,第十五期--openEuler专场', + TITLE_LIST: ['数字中国创新大赛 鲲鹏赛道训练营','第十五期--openEuler专场'], + MEETUPS_IMG: '/img/meetups/4.png', + MEETUPS_DATE: '2020-12-18', + MEETUPS_MONTH: '十二月', + MEETUPS_DESC: ['数字中国创新大赛·鲲鹏赛道作为国家互联网信息办公室、国家发展和改革委员会、工业和信息化部、福建省人民政府主办的数字中国建设峰会的重要赛道之一,为积极响应国家和省市发展数字技术的相关决策部署和政策导向,推进数字产业生态建设。鲲鹏训练营第十五期将在福建软件园进行举办,邀请华为、统信软件、江苏润和软件等技术专家围绕openEuler开展系列主题演讲培训。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '入场签到', + TIME: '08:30-09:00', + SPEAKER: '' + }, + { + THEME: '领导致辞', + TIME: '09:00-09:15', + SPEAKER: '' + }, + { + THEME: 'HopeEdge:操作系统在边缘计算的实践', + TIME: '09:15-09:45', + SPEAKER: '' + }, + { + THEME: '携手openEuler,共创开源新生态', + TIME: '09:45-10:15', + SPEAKER: '' + }, + { + THEME: 'openEuler操作系统介绍', + TIME: '10:15-10:40', + SPEAKER: '' + }, + { + THEME: 'StratoVirt:openEuler下一代开放虚拟化平台', + TIME: '10:40-11:10', + SPEAKER: '' + }, + { + THEME: 'iSula容器解决方案介绍和规划', + TIME: '11:10-11:40', + SPEAKER: '' + }, + { + THEME: '原子基金议题', + TIME: '11:40-12:00', + SPEAKER: '' + }, + { + THEME: '云原生主题闭门会', + TIME: '15:00-17:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address4.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '上午:福州软件园A区双创新城1号楼1层','下午:郊野公园' + ], + APPLY_QRCODE: '/img/meetups/qrcode4.png', + ADDRESS_LOCATION: ['119.276427','26.117974'], + } + }, + { + ID: 5, + MEETUPS_TITLE: 'openEuler MIC meetup', + TITLE_LIST: ['openEuler MIC meetup','谁说不写代码就不能玩开源?'], + MEETUPS_IMG: '/img/meetups/5.png', + MEETUPS_DATE: '2021-03-20', + MEETUPS_MONTH: '三月', + MEETUPS_DESC: ['openEuler MIC meetup,度量(metrics)、基础设施(infrastructure)、合规(compliance)。', '开源项目健康运作离不开度量,openEuler联合Linux基金会顶级项目CHAOSS,共同探讨社区健康度量体系;合规是开源项目的底线,忽视许可、版权将带来法务风险,让我们打开主流开源license,逐条分析它们的权利、义务和限制。','打造超强社区工具,分享社区度量看板、Licence许可分析器等工具开发的点点滴滴,让工具会成为社区健康运营的助力。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: 'CHAOSS社区度量体系介绍', + TIME: '14:00-14:15', + SPEAKER: '' + }, + { + THEME: '2020 GitHub数字洞察', + TIME: '14:15-14:30', + SPEAKER: '' + }, + { + THEME: '开源社区大数据分析:从度量到洞察', + TIME: '14:30-15:00', + SPEAKER: '' + }, + { + THEME: 'openEuler社区运营看板', + TIME: '15:00-15:30', + SPEAKER: '' + }, + { + THEME: '利用开源构建 openEuler 基础设施', + TIME: '15:30-16:00', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '16:00-16:15', + SPEAKER: '' + }, + { + THEME: 'openEuler体验设计', + TIME: '16:15-16:45', + SPEAKER: '' + }, + { + THEME: '开源CLA解密', + TIME: '16:45-17:10', + SPEAKER: '' + }, + { + THEME: 'openEuler合规的探索和实践', + TIME: '17:10-17:30', + SPEAKER: '' + }, + { + THEME: '开源许可证识别以及许可证条款冲突自动化检测', + TIME: '17:30-18:00', + SPEAKER: '' + }, + { + THEME: '晚餐', + TIME: '18:00-18:30', + SPEAKER: '' + }, + { + THEME: '开源party', + TIME: '18:30-18:40', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address5.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '上海市浦东新区博云路111号爱酷空间B1' + ], + APPLY_QRCODE: '/img/meetups/qrcode5.png', + ADDRESS_LOCATION: ['121.613359','31.208858'], + } + }, + { + ID: 6, + MEETUPS_TITLE: 'Rust Meetup 深圳站', + TITLE_LIST: ['Rust Meetup 深圳站'], + MEETUPS_IMG: '/img/meetups/6.png', + MEETUPS_DATE: '2021-03-27', + MEETUPS_MONTH: '三月', + MEETUPS_DESC: ['3月27日,由华为、openEuler 、Netwarps、开源中国和Rust中文社区联合主办的Rust Meetup将在深圳举行,此次Meetup将围绕Rust语言无栈协程、Rust实际应用、Rust科学计算等方向进行分享,届时我们会邀请华为、Netwarps、PingCAP等相关应用企业,openEuler、Rust中文社区、开源中国等技术社区,以及行业内Rust开发者参与到此次分享中。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '13:00-13:30', + SPEAKER: '' + }, + { + THEME: '从libp2p-rs到IPFS  谢敬伟@Netwarps', + TIME: '13:00-14:10', + SPEAKER: '' + }, + { + THEME: 'Rust科学计算多维数组运算库的分析与实践 李原@华为', + TIME: '14:10-14:50', + SPEAKER: '' + }, + { + THEME: '深度剖析Rust异步编程/无栈协程  何元勋@Netwarps', + TIME: '14:50-15:30', + SPEAKER: '' + }, + { + THEME: '休息/自由交流', + TIME: '15:30-15:40', + SPEAKER: '' + }, + { + THEME: 'Rust FFI 跨语言代码复用的方法和实践  骆迪安@TiKV', + TIME: '15:40-16:20', + SPEAKER: '' + }, + { + THEME: 'Rust语言在系统开发(虚拟化平台StratoVirt)的实践与应用 张亮@华为', + TIME: '16:20-17:00', + SPEAKER: '' + }, + { + THEME: '基于TVM Rust Runtime和WASM沙箱运行AI模型 王辉@华为', + TIME: '17:00-17:40', + SPEAKER: '' + }, + { + THEME: 'QA/自由交流', + TIME: '17:40-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_IMG: '/img/meetups/address6.png', + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '深圳市福田区中康路136号新一代产业园4栋19楼' + ], + APPLY_QRCODE: '/img/meetups/qrcode6.png', + ADDRESS_LOCATION: ['114.067925','22.578717'], + } + }, + { + ID: 7, + MEETUPS_TITLE: 'AI-OPS Meetup', + TITLE_LIST: ['AI-OPS Meetup'], + MEETUPS_IMG: '/img/meetups/7.png', + MEETUPS_DATE: '2021-04-08', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['AI-OPS致力于推动系统运维的可视化、自动化、智能化,打造高可靠性、高性能、永不中断的基础设施;','构建系统数据信息体系,使数据能跨组件,跨平台共享,使上层业务更易于创新开发,保证全栈操作系统运维成为可能,打造开源/开放的操作系统;','提供基础设施热补丁、热替换软件技术,保证基础设施不中断在线服务; 提供问题诊断、性能分析、系统调测等技术,提供系统运维过程中必须的可视化、自动化、智能化调试必须工具。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '开场', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: '操作系统智能运维', + TIME: '14:00-14:30', + SPEAKER: '华为/栾建海' + }, + { + THEME: '系统升级方案-内核热替换', + TIME: '14:35-15:05', + SPEAKER: '华为/朱玲' + }, + { + THEME: '运维定位工具 - Crash/Bcc', + TIME: '15:10-15:40', + SPEAKER: '华为/桑琰' + }, + { + THEME: 'DevSecOps for Kubernetes-based Applications', + TIME: '15:45-16:15', + SPEAKER: 'JFrogs/高欣' + }, + { + THEME: '中国移动云原生gitops落地实践', + TIME: '16:20-16:50', + SPEAKER: '中国移动/张一波' + }, + { + THEME: '开源运维系统分析及PilotGo项目讨论', + TIME: '16:55-17:25', + SPEAKER: '麒麟软件/侯健' + }, + { + THEME: '自由交流', + TIME: '17:35-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '北京市海淀区北四环西路9号银谷大厦12层东侧' + ], + APPLY_QRCODE: '/img/meetups/qrcode7.png', + ADDRESS_LOCATION: ['116.340773','39.992655'], + } + }, + { + ID: 8, + MEETUPS_TITLE: 'openEuler X OpenStack X Arm Meetup', + TITLE_LIST: ['openEuler X OpenStack X Arm Meetup','跨界全栈,技术盛宴'], + MEETUPS_IMG: '/img/meetups/8.png', + MEETUPS_DATE: '2021-04-10', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['云计算、处理器、操作系统是上层业务的基石,开源云计算的事实标准OpenStack,旨在打造最具活力开源社区的openEuler,风头正劲的Arm架构所组成的跨界全栈,能碰撞出怎样的火花?技术分享、头脑风暴、大咖圆桌、现场Q&A,一站式的技术盛宴等你享用。'], + MEETUPS_FLOW_PATH: [ + { + THEME: 'PTG议程', + TIME: '09:00-12:00', + SPEAKER: '' + }, + { + THEME: '签到', + TIME: '13:30-14:00', + SPEAKER: '' + }, + { + THEME: 'openEuler OpenStack SIG介绍与进展', + TIME: '14:00-14:30', + SPEAKER: '' + }, + { + THEME: 'openEuler 20.03 LTS 在联通沃云的适配', + TIME: '14:35-15:05', + SPEAKER: '' + }, + { + THEME: 'Arm落地实践和云计算在信创产业的发展情况', + TIME: '15:10-15:40', + SPEAKER: '' + }, + { + THEME: 'OpenStack Arm CI介绍以及openEuler在OpenStack CI的支持进展', + TIME: '15:45-16:15', + SPEAKER: '' + }, + { + THEME: '业务软件在Arm平台上的优化', + TIME: '16:20-16:50', + SPEAKER: '' + }, + { + THEME: 'Panel Discussion', + TIME: '16:55-17:25', + SPEAKER: '' + }, + { + THEME: '合影、自由讨论', + TIME: '17:30-18:00', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '北京市海淀区中关村创业大街昊海楼5号楼103怡仁空间' + ], + APPLY_QRCODE: '/img/meetups/qrcode8.png', + ADDRESS_LOCATION: ['116.313623','39.990418'], + } + }, + { + ID: 9, + MEETUPS_TITLE: 'openEuler Cloud Native Meetup', + TITLE_LIST: ['openEuler Cloud Native Meetup'], + MEETUPS_IMG: '/img/meetups/9.png', + MEETUPS_DATE: '2021-04-17', + MEETUPS_MONTH: '四月', + MEETUPS_DESC: ['本次会议openEuler围绕系统、存储、网络、云原生、kubernetes等多个领域话题展开分享。届时将邀请LGT俱乐部相关领域资深技术专家,就行业动态、技术创新、高端应用等方面开展精彩分享,会后将以论坛和体验式沙龙形式与大咖近距离面对面交流。'], + MEETUPS_FLOW_PATH: [ + { + THEME: '签到', + TIME: '12:30-13:00', + SPEAKER: '' + }, + { + THEME: '极简kubernetes发行版-k8e介绍', + TIME: '13:00-13:15', + SPEAKER: '' + }, + { + THEME: '云原生安全初探', + TIME: '13:15-13:45', + SPEAKER: '' + }, + { + THEME: 'K8S扩展开发-CRD与Controller', + TIME: '13:45-14:15', + SPEAKER: '' + }, + { + THEME: '茶歇', + TIME: '14:15-14:30', + SPEAKER: '' + }, + { + THEME: '用WebAssembly快速把AI推理带到生产环境', + TIME: '14:30-15:00', + SPEAKER: '' + }, + { + THEME: '打造比Nginx还快的web服务器', + TIME: '15:00-15:30', + SPEAKER: '' + }, + { + THEME: '互动交流', + TIME: '15:30-16:00', + SPEAKER: '' + }, + { + THEME: '活动抽奖', + TIME: '16:00-16:15', + SPEAKER: '' + } + ], + MEETINGS_INFO: { + ADDRESS_UP: '地址', + ADDRESS_DOWN: [ + '高新园区黄浦路507号','海创(大连)科技交流中心三楼海创厅B' + ], + APPLY_QRCODE: '/img/meetups/qrcode9.png', + ADDRESS_LOCATION: ['121.540054','38.872889'], + } + }, + ] + } +}; diff --git a/web-ui/docs/.vuepress/data/sig/sig-list.js b/web-ui/docs/.vuepress/data/sig/sig-list.js new file mode 100644 index 0000000000000000000000000000000000000000..952a4cea935bf08aa814253d3ad76458854048ca --- /dev/null +++ b/web-ui/docs/.vuepress/data/sig/sig-list.js @@ -0,0 +1,946 @@ +/** + * @file sig相关数据 + * */ + +module.exports = { + zh: { + SIG_LIST: [{ + CATEGORY_NAME: '代码仓管理/技术创新', + SUB_LIST: [{ + SUB_CATEGORY_NAME: '行业解决方案/应用', + COLOR: '#7f6ffe', + LIST: [{ + NAME: 'sig-bio' + }, + { + NAME: 'sig-ROS' + }, + { + NAME: 'sig-android-middleware' + }, + { + NAME: 'Application' + }, + { + NAME: 'sig-industrial-control' + } + ] + }, + { + SUB_CATEGORY_NAME: '通用中间组件', + COLOR: '#db7c61', + LIST: [{ + NAME: 'sig-embedded' + }, + { + NAME: 'sig-OpenResty' + }, + { + NAME: 'sig-cms' + }, + { + NAME: 'DB' + }, + { + NAME: 'sig-Ha' + }, + { + NAME: 'sig-ai-bigdata' + }, + { + NAME: 'sig-compat-winapp' + }, + { + NAME: 'sig-ceph' + } + ] + }, + { + SUB_CATEGORY_NAME: '工具链/语言/运行', + COLOR: '#505d75', + LIST: [{ + NAME: 'sig-Rust' + }, + { + NAME: 'sig-perl-modules' + }, + { + NAME: 'sig-python-modules' + }, + { + NAME: 'sig-Java' + }, + { + NAME: 'sig-nodejs' + }, + { + NAME: 'dev-utils' + }, + { + NAME: 'Runtime' + }, + { + NAME: 'sig-libboundscheck' + }, + { + NAME: 'System-tool' + }, + { + NAME: 'sig-golang' + }, + { + NAME: 'sig-ruby' + }, + { + NAME: 'Compiler' + }, + { + NAME: 'Programming-language', + IS_WIDER: 1 + } + ] + }, + { + SUB_CATEGORY_NAME: '架构/处理器/内核/驱动', + COLOR: '#fec456', + LIST: [{ + NAME: 'sig-RaspberryPi' + }, + { + NAME: 'sig-RISC-V' + }, + { + NAME: 'sig-aarch32' + }, + { + NAME: 'Kernel' + }, + { + NAME: 'sig-WayCa' + }, + { + NAME: 'sig-DyscheOS' + }, + { + NAME: 'sig-REDF' + } + ] + }, + { + SUB_CATEGORY_NAME: '云原生基础设施', + COLOR: '#4d7dff', + LIST: [{ + NAME: 'sig-CloudNative' + }, + { + NAME: 'sig-ONL' + }, + { + NAME: 'sig-openstack' + }, + { + NAME: 'sig-OKD' + }, + { + NAME: 'Virt' + }, + { + NAME: 'iSulad' + }, + { + NAME: 'oVirt' + }, + { + NAME: 'sig-KubeSphere' + } + ] + }, + { + SUB_CATEGORY_NAME: '桌面/图形系统', + COLOR: '#8e9aaf', + LIST: [{ + NAME: 'sig-mate-desktop' + }, + { + NAME: 'sig-desktop-apps' + }, + { + NAME: 'Desktop' + }, + { + NAME: 'GNOME' + }, + { + NAME: 'sig-KDE' + }, + { + NAME: 'xfce' + }, + { + NAME: 'sig-DDE' + }, + { + NAME: 'sig-UKUI' + }, + { + NAME: 'sig-KIRAN-DESKTOP' + } + ] + }, + { + SUB_CATEGORY_NAME: '基础功能/特性/工具', + COLOR: '#2a9d8f', + LIST: [{ + NAME: 'A-Tune' + }, + { + NAME: 'Storage' + }, + { + NAME: 'Base-service' + }, + { + NAME: 'Computing' + }, + { + NAME: 'sig-ops' + }, + { + NAME: 'sig-bootstrap' + }, + { + NAME: 'Networking' + }, + { + NAME: 'sig-security-facility' + }, + { + NAME: 'sig-high-performance-network', + IS_WIDER: 1 + }, + { + NAME: 'sig-confidential-computing', + IS_WIDER: 1 + } + ] + } + ] + }, + { + CATEGORY_NAME: '社区治理运营', + SUB_LIST: [{ + SUB_CATEGORY_NAME: '社区生态进展', + COLOR: '#8e583d', + LIST: [{ + NAME: 'Marketing' + }, + { + NAME: 'sig-minzuchess' + }, + { + NAME: 'sig-Compatibility-Infra' + } + ] + }, + { + SUB_CATEGORY_NAME: '版本发行相关', + COLOR: '#cec79a', + LIST: [{ + NAME: 'sig-QA' + }, + { + NAME: 'doc' + }, + { + NAME: 'sig-release-management' + } + ] + }, + { + SUB_CATEGORY_NAME: '构建系统/工具/依赖', + COLOR: '#19647e', + LIST: [{ + NAME: 'sig-OS-Builder' + }, + { + NAME: 'sig-Ostree-Assembly' + } + ] + }, + { + SUB_CATEGORY_NAME: '安全委员会/技术委员会/社区秘书处', + COLOR: '#73c0de', + LIST: [{ + NAME: 'TC' + }, + { + NAME: 'sig-Community' + }, + { + NAME: 'security-committee' + } + ] + }, + { + SUB_CATEGORY_NAME: '软件包管理相关', + COLOR: '#4c3e72', + LIST: [{ + NAME: 'Packaging' + }, + { + NAME: 'sig-recycle' + }, + { + NAME: 'sig-EasyLife' + } + ] + }, + { + SUB_CATEGORY_NAME: '社区基础设施', + COLOR: '#c44e4e', + LIST: [{ + NAME: 'Infrastructure' + }, + { + NAME: 'sig-CICD' + }, + { + NAME: 'sig-Gatekeeper' + }, + { + NAME: 'security-committee' + } + ] + } + ] + } + ] + }, + en: { + SIG_LIST: [{ + CATEGORY_NAME: 'Code Repository Management/Technology Innovation', + SUB_LIST: [{ + SUB_CATEGORY_NAME: 'Industry Solutions/Applications', + COLOR: '#7f6ffe', + LIST: [{ + NAME: 'sig-bio' + }, + { + NAME: 'sig-ROS' + }, + { + NAME: 'sig-android-middleware' + }, + { + NAME: 'Application' + }, + { + NAME: 'sig-industrial-control' + } + ] + }, + { + SUB_CATEGORY_NAME: 'General-Purpose Middleware', + COLOR: '#db7c61', + LIST: [{ + NAME: 'sig-embedded' + }, + { + NAME: 'sig-OpenResty' + }, + { + NAME: 'sig-cms' + }, + { + NAME: 'DB' + }, + { + NAME: 'sig-Ha' + }, + { + NAME: 'sig-ai-bigdata' + }, + { + NAME: 'sig-compat-winapp' + }, + { + NAME: 'sig-ceph' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Toolchains/Languages/Running', + COLOR: '#505d75', + LIST: [{ + NAME: 'sig-Rust' + }, + { + NAME: 'sig-perl-modules' + }, + { + NAME: 'sig-python-modules' + }, + { + NAME: 'sig-Java' + }, + { + NAME: 'sig-nodejs' + }, + { + NAME: 'dev-utils' + }, + { + NAME: 'Runtime' + }, + { + NAME: 'sig-libboundscheck' + }, + { + NAME: 'System-tool' + }, + { + NAME: 'sig-golang' + }, + { + NAME: 'sig-ruby' + }, + { + NAME: 'Compiler' + }, + { + NAME: 'Programming-language', + IS_WIDER: 1 + } + ] + }, + { + SUB_CATEGORY_NAME: 'Architecture/Processor/Core/Driver', + COLOR: '#fec456', + LIST: [{ + NAME: 'sig-RaspberryPi' + }, + { + NAME: 'sig-RISC-V' + }, + { + NAME: 'sig-aarch32' + }, + { + NAME: 'Kernel' + }, + { + NAME: 'sig-WayCa' + }, + { + NAME: 'sig-DyscheOS' + }, + { + NAME: 'sig-REDF' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Cloud Native Infrastructure', + COLOR: '#4d7dff', + LIST: [{ + NAME: 'sig-CloudNative' + }, + { + NAME: 'sig-ONL' + }, + { + NAME: 'sig-openstack' + }, + { + NAME: 'sig-OKD' + }, + { + NAME: 'Virt' + }, + { + NAME: 'iSulad' + }, + { + NAME: 'oVirt' + }, + { + NAME: 'sig-KubeSphere' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Desktop/Graphics System', + COLOR: '#8e9aaf', + LIST: [{ + NAME: 'sig-mate-desktop' + }, + { + NAME: 'sig-desktop-apps' + }, + { + NAME: 'Desktop' + }, + { + NAME: 'GNOME' + }, + { + NAME: 'sig-KDE' + }, + { + NAME: 'xfce' + }, + { + NAME: 'sig-DDE' + }, + { + NAME: 'sig-UKUI' + }, + { + NAME: 'sig-KIRAN-DESKTOP' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Basic Functions/Features/Tools', + COLOR: '#2a9d8f', + LIST: [{ + NAME: 'A-Tune' + }, + { + NAME: 'Storage' + }, + { + NAME: 'Base-service' + }, + { + NAME: 'Computing' + }, + { + NAME: 'sig-ops' + }, + { + NAME: 'sig-bootstrap' + }, + { + NAME: 'Networking' + }, + { + NAME: 'sig-security-facility' + }, + { + NAME: 'sig-high-performance-network', + IS_WIDER: 1 + }, + { + NAME: 'sig-confidential-computing', + IS_WIDER: 1 + } + ] + } + ] + }, + { + CATEGORY_NAME: 'Community Governance and Operations', + SUB_LIST: [{ + SUB_CATEGORY_NAME: 'Community Ecological Progress', + COLOR: '#8e583d', + LIST: [{ + NAME: 'Marketing' + }, + { + NAME: 'sig-minzuchess' + }, + { + NAME: 'sig-Compatibility-Infra' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Version Release Related', + COLOR: '#cec79a', + LIST: [{ + NAME: 'sig-QA' + }, + { + NAME: 'doc' + }, + { + NAME: 'sig-release-management' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Build Systems/Tools/Dependencies', + COLOR: '#19647e', + LIST: [{ + NAME: 'sig-OS-Builder' + }, + { + NAME: 'sig-Ostree-Assembly' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Security Committee/Technical Committee/Community Secretariat', + COLOR: '#73c0de', + LIST: [{ + NAME: 'TC' + }, + { + NAME: 'sig-Community' + }, + { + NAME: 'security-committee' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Software Package Management', + COLOR: '#4c3e72', + LIST: [{ + NAME: 'Packaging' + }, + { + NAME: 'sig-recycle' + }, + { + NAME: 'sig-EasyLife' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Community Infrastructure', + COLOR: '#c44e4e', + LIST: [{ + NAME: 'Infrastructure' + }, + { + NAME: 'sig-CICD' + }, + { + NAME: 'sig-Gatekeeper' + }, + { + NAME: 'security-committee' + } + ] + } + ] + } + ] + + }, + ru: { + SIG_LIST: [{ + CATEGORY_NAME: 'Code Repository Management/Technology Innovation', + SUB_LIST: [{ + SUB_CATEGORY_NAME: 'Industry Solutions/Applications', + COLOR: '#7f6ffe', + LIST: [{ + NAME: 'sig-bio' + }, + { + NAME: 'sig-ROS' + }, + { + NAME: 'sig-android-middleware' + }, + { + NAME: 'Application' + }, + { + NAME: 'sig-industrial-control' + } + ] + }, + { + SUB_CATEGORY_NAME: 'General-Purpose Middleware', + COLOR: '#db7c61', + LIST: [{ + NAME: 'sig-embedded' + }, + { + NAME: 'sig-OpenResty' + }, + { + NAME: 'sig-cms' + }, + { + NAME: 'DB' + }, + { + NAME: 'sig-Ha' + }, + { + NAME: 'sig-ai-bigdata' + }, + { + NAME: 'sig-compat-winapp' + }, + { + NAME: 'sig-ceph' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Toolchains/Languages/Running', + COLOR: '#505d75', + LIST: [{ + NAME: 'sig-Rust' + }, + { + NAME: 'sig-perl-modules' + }, + { + NAME: 'sig-python-modules' + }, + { + NAME: 'sig-Java' + }, + { + NAME: 'sig-nodejs' + }, + { + NAME: 'dev-utils' + }, + { + NAME: 'Runtime' + }, + { + NAME: 'sig-libboundscheck' + }, + { + NAME: 'System-tool' + }, + { + NAME: 'sig-golang' + }, + { + NAME: 'sig-ruby' + }, + { + NAME: 'Compiler' + }, + { + NAME: 'Programming-language', + IS_WIDER: 1 + } + ] + }, + { + SUB_CATEGORY_NAME: 'Architecture/Processor/Core/Driver', + COLOR: '#fec456', + LIST: [{ + NAME: 'sig-RaspberryPi' + }, + { + NAME: 'sig-RISC-V' + }, + { + NAME: 'sig-aarch32' + }, + { + NAME: 'Kernel' + }, + { + NAME: 'sig-WayCa' + }, + { + NAME: 'sig-DyscheOS' + }, + { + NAME: 'sig-REDF' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Cloud Native Infrastructure', + COLOR: '#4d7dff', + LIST: [{ + NAME: 'sig-CloudNative' + }, + { + NAME: 'sig-ONL' + }, + { + NAME: 'sig-openstack' + }, + { + NAME: 'sig-OKD' + }, + { + NAME: 'Virt' + }, + { + NAME: 'iSulad' + }, + { + NAME: 'oVirt' + }, + { + NAME: 'sig-KubeSphere' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Desktop/Graphics System', + COLOR: '#8e9aaf', + LIST: [{ + NAME: 'sig-mate-desktop' + }, + { + NAME: 'sig-desktop-apps' + }, + { + NAME: 'Desktop' + }, + { + NAME: 'GNOME' + }, + { + NAME: 'sig-KDE' + }, + { + NAME: 'xfce' + }, + { + NAME: 'sig-DDE' + }, + { + NAME: 'sig-UKUI' + }, + { + NAME: 'sig-KIRAN-DESKTOP' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Basic Functions/Features/Tools', + COLOR: '#2a9d8f', + LIST: [{ + NAME: 'A-Tune' + }, + { + NAME: 'Storage' + }, + { + NAME: 'Base-service' + }, + { + NAME: 'Computing' + }, + { + NAME: 'sig-ops' + }, + { + NAME: 'sig-bootstrap' + }, + { + NAME: 'Networking' + }, + { + NAME: 'sig-security-facility' + }, + { + NAME: 'sig-high-performance-network', + IS_WIDER: 1 + }, + { + NAME: 'sig-confidential-computing', + IS_WIDER: 1 + } + ] + } + ] + }, + { + CATEGORY_NAME: 'Community Governance and Operations', + SUB_LIST: [{ + SUB_CATEGORY_NAME: 'Community Ecological Progress', + COLOR: '#8e583d', + LIST: [{ + NAME: 'Marketing' + }, + { + NAME: 'sig-minzuchess' + }, + { + NAME: 'sig-Compatibility-Infra' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Version Release Related', + COLOR: '#cec79a', + LIST: [{ + NAME: 'sig-QA' + }, + { + NAME: 'doc' + }, + { + NAME: 'sig-release-management' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Build Systems/Tools/Dependencies', + COLOR: '#19647e', + LIST: [{ + NAME: 'sig-OS-Builder' + }, + { + NAME: 'sig-Ostree-Assembly' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Security Committee/Technical Committee/Community Secretariat', + COLOR: '#73c0de', + LIST: [{ + NAME: 'TC' + }, + { + NAME: 'sig-Community' + }, + { + NAME: 'security-committee' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Software Package Management', + COLOR: '#4c3e72', + LIST: [{ + NAME: 'Packaging' + }, + { + NAME: 'sig-recycle' + }, + { + NAME: 'sig-EasyLife' + } + ] + }, + { + SUB_CATEGORY_NAME: 'Community Infrastructure', + COLOR: '#c44e4e', + LIST: [{ + NAME: 'Infrastructure' + }, + { + NAME: 'sig-CICD' + }, + { + NAME: 'sig-Gatekeeper' + }, + { + NAME: 'security-committee' + } + ] + } + ] + } + ] + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/enhanceApp.js b/web-ui/docs/.vuepress/enhanceApp.js new file mode 100644 index 0000000000000000000000000000000000000000..11b19b498d7d1fdb7b14332ad3d36f69fdb23f3f --- /dev/null +++ b/web-ui/docs/.vuepress/enhanceApp.js @@ -0,0 +1,130 @@ +import ElementUI from 'element-ui'; +import './public/style/theme/index.css'; +import './public/style/base.css'; +import enlocale from 'element-ui/lib/locale/lang/en'; +import rulocale from 'element-ui/lib/locale/lang/ru-RU'; +import locale from 'element-ui/lib/locale'; +import'./public/style/markdown.less'; +import directive from './libs/directive'; +import VueLazyload from 'vue-lazyload'; +// import tracing from 'web-tracing' +import eularTrace from '../../packages/eularTrace/eularTrace' + + +export default ({ + Vue, + siteData, + isServer +}) => { + Vue.directive('fade', directive.fade); + Vue.use(VueLazyload, { + preLoad: 1.3, + attempt: 1 + }); + Vue.use(eularTrace, { + requestUrl: 'http://123456webservertest/traceTest', + appName: 'website-v2', + event: true, + performance: true, + pv: true, + error: true, + }); + if(!isServer){ + window.global = (() => { +     if (typeof self !== 'undefined') { return self; } +     if (typeof window !== 'undefined') { return window; } +     if (typeof global !== 'undefined') { return global; } +     if (typeof globalThis !== 'undefined') { return globalThis; } +     throw new Error('unable to locate global object'); + })(); + let $lang = ''; + if(window.location.href.includes('/en/')) { + $lang = 'en'; + }else if(window.location.href.includes('/zh/')) { + $lang = 'zh'; + }else { + $lang = 'ru'; + } + let screenWidth = document.body.clientWidth; + Vue.prototype.isShowH5 = false; + Vue.prototype.paginationLayout = "total,prev, pager, next" + if(screenWidth <= 1000){ + Vue.prototype.isShowH5 = true; + Vue.prototype.paginationLayout = "total, prev, jumper, next" + } + if (window.location.href.includes('/en/')) { + Vue.use(ElementUI); + locale.use(enlocale); + Vue.prototype.$isCn = false; + } else if(window.location.href.includes('/ru/')) { + Vue.use(ElementUI); + locale.use(rulocale); + Vue.prototype.$isCn = false; + }else { + Vue.use(ElementUI); + Vue.prototype.$isCn = true; + } + let pagesArr = []; + siteData.pages.forEach(item => { + if($lang === 'zh' && item.path.includes('/zh/')) { + pagesArr.push(item); + } else if($lang === 'en' && item.path.includes('/en/')) { + pagesArr.push(item); + }else if($lang === 'ru' && item.path.includes('/ru/')){ + pagesArr.push(item); + } + }) + Vue.prototype.$sitePages = pagesArr; + let instance = new Vue({ + data () { + return { + i18n: siteData.themeConfig.locales[$lang].lang + } + } + }) + Vue.prototype.i18n = instance.i18n; + }else{ + Vue.use(ElementUI); + } + let checkLoop = false; + Vue.mixin({ + data () { + return isServer ? {i18n: {}} : {} + }, + mounted () { + if(this.$router && this.$frontmatter) { + document.title = this.$frontmatter.title || 'openEuler'; + } + }, + created () { + if(!checkLoop){ + checkLoop = true; + const originalPush = this.$router.push; + this.$router.push = function push(location) { + return originalPush.call(this, location).catch(err => err); + } + } + if(isServer){ + this.i18n = siteData.themeConfig.locales[this.$lang].lang + } + }, + methods : { + resolvePath(path){ + if(path){ + let targetLocale = ''; + if(this.$lang === 'en') { + targetLocale = '/en'; + }else if(this.$lang === 'zh') { + targetLocale = '/zh'; + }else { + targetLocale = '/ru'; + } + return targetLocale + path; + } + + } + } + }) + + +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/en.js b/web-ui/docs/.vuepress/lang/en.js new file mode 100644 index 0000000000000000000000000000000000000000..51fedca0b081d2709ad23fb5e52f5a69ec64ef18 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/en.js @@ -0,0 +1,25 @@ +/** + * @file 国际化英文配置主入口 + * */ + +module.exports = { + common: require('./lang-modules/common').en, + home: require('./lang-modules/home').en, + download: require('./lang-modules/download').en, + documentation: require('./lang-modules/documentation').en, + community: require('./lang-modules/community').en, + sig: require('./lang-modules/sig').en, + authentication: require('./lang-modules/authentication').en, + security: require('./lang-modules/security').en, + interaction: require('./lang-modules/interaction').en, + brand: require('./lang-modules/brand').en, + search: require('./lang-modules/search').en, + minisite: require('./lang-modules/minisite').en, + scheme: require('./lang-modules/scheme').en, + learn: require('./lang-modules/learn').en, + compatibility: require('./lang-modules/compatibility').en, + summit: require('./lang-modules/summit').en, + activities: require('./lang-modules/activities').cn, + questionnaire: require('./lang-modules/questionnaire').en, + devday2022: require('./lang-modules/devday2022').en, +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/activities.js b/web-ui/docs/.vuepress/lang/lang-modules/activities.js new file mode 100644 index 0000000000000000000000000000000000000000..f9ca2ff2425c95bc533ec849a7fd0693903cb742 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/activities.js @@ -0,0 +1,68 @@ +/** + * @file 下载模块国际化配置入口 + * */ + +module.exports = { + cn: { + NO_DATA_INFO: '还没有符合条件的任务呢,请持续关注哦!', + BANNER_TITLE: '开源软件供应链点亮计划', + BANNER_BTN: '创建任务', + DESCRIPTION_1: '开源之夏是开源软件供应链点亮计划下的暑期活动,活动时间覆盖每年暑期前后,已开展至第三届,旨在鼓励在校学生积极参与开源软件的开发维护,促进优秀开源软件社区的蓬勃发展。活动联合各大开源社区,针对开源项目的开发与维护提供mini任务,开放给全球高校学生报名申请。', + DESCRIPTION_2: '学生自由选择项目任务,与社区导师沟通实现方案并撰写项目计划书。被选中的学生将在社区导师指导下,按计划完成开发工作,并将成果贡献给社区。在所承担的项目任务成功结项后,参与者将获得开源之夏活动奖金和结项证书。(奖金:基础项目 8000元 进阶项目 12000元)', + DESCRIPTION_3: 'openEuler 社区已发布', + DESCRIPTION_5: '87个项目任务', + DESCRIPTION_6: '供大家选择,涉及到openEuler 操作系统底层开发、新特性开发、开源基础设施建设等多样的项目任务,openEuler社区欢迎你的参与!', + STEP_TITLE: '参与步骤', + NAV_TEXT: ['参与步骤', '选择任务'], + STEP_1: { + CONTENT_1: '了解自己感兴趣的任务。', + CONTENT_2: '可在', + A_LINK: '本页面', + CONTENT_3: '根据不同方向、标签、难度查找任务,点击任务卡片查看详情。可通过邮件向对应的任务导师进一步咨询你感兴趣的任务。', + TITLE: '邮件格式:', + TITLE_TITLE: '标题:', + TITLE_CONTENT: '【开源之夏项目咨询】学生姓名+ 咨询项目任务名称', + MAIL_TITLE: '邮件内容:', + MAIL_CONTENT_1: '介绍自己的基本情况,包括学校、专业、年级;', + MAIL_CONTENT_2: '清楚描述你想咨询的问题。' + }, + STEP_2: { + CONTENT_1: '确定自己想选择的项目,并开始准备项目申请方案。', + CONTENT_2: '可参照', + A_LINK: '项目申请模板' + }, + STEP_3: { + CONTENT_1: '报名并提交项目申请方案。在', + A_LINK: '开源之夏官网项目列表页', + CONTENT_2: '找到对应的项目,点击申请按钮提交项目申请方案。', + TITLE: '申请开放时间:', + TIME: '2022年5月20日-2022年6月4日。' + }, + STEP_4: { + CONTENT: '等待方案评选结果。中选结果公布后开始进行项目开发。', + TITLE: '中选公布:', + TIME: '2022年6月15日', + TITLE1: '开发周期:', + TIME1: '2022年7月1日-2022年9月30日。', + }, + STEP_5: { + CONTENT: '向社区提交PR。项目任务完成后,将成果以PR形式向社区仓库提交,成果被社区仓库合入并通过导师及组委会评审后,即可成功结项。' + }, + GUIDE_LABEL: '学生参与详情可进一步查看活动官方的', + GUIDE_LINK: '学生指南', + OFFICIAL_WEBSITE_LABLE: '活动整体详情可访问', + OFFICIAL_WEBSITE_LINK: '开源之夏2022官网', + PERIOD: '。', + DESCRIPTION_4: '扫码添加openEuler小助手微信,添加备注“开源之夏”,邀请你进开源之夏2022 openEuler 项目交流群,活动重要信息将第一时间在群内通知。', + FILTER_TITLE: '选择任务', + FILTER: { + LABEL_1: '技术方向', + LABEL_2: '技术语言', + LABEL_3: '难度', + DIFFICULTY_OPTIONS: ['基础', '进阶'] + }, + ACTIVITIES_LIST: require('././../../data/activities/zh.json'), + ACTIVETIES_LIST_LABLE_1: '技术方向', + ACTIVETIES_LIST_LABLE_2: '技术语言' + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/approve.js b/web-ui/docs/.vuepress/lang/lang-modules/approve.js new file mode 100644 index 0000000000000000000000000000000000000000..5d1291ee3545edd158c5e7bc2ba17695ac76ddf0 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/approve.js @@ -0,0 +1,132 @@ +/** + * @file 下载模块国际化配置入口 + * */ + + module.exports = { + cn: { + TITLE: 'OSV技术测评列表', + SUMMARY: { + TITLE: 'OSV技术测评简介', + CONTENT: '工具聚焦openEuler内核和基础包,检测伙伴二次发行版生态核心特性不丢失,关键配置不更改 结合社区选包策略及软件包等级策略,检查L1、L2软件包版本、打包方式、接口一致性,KABI白名单,架构特性(如ARM/X86特性)使能,性能优化配置,牵引实现扩展仓库openEuler系共享、共用,主流行业应用在openEuler系不同的OSV生态复用度。' + }, + TO_STEP:{ + TEXT_1:'关于OSV技术测评,openEuler提供了完整的测试流程和工具,详见', + LINK_1:' openEuler OSV技术测评整体介绍' + }, + STEP_HEAD: 'openEuler OSV技术测评整体介绍', + STEP_TITLE: 'OSV技术测评步骤', + STEP_CONTENT: [ + { + ID:'01', + TITLE:'申请加入openEuler社区', + TEXT_1:'您需要在Gitee平台申请加入openEuler社区,成为组织成员。申请地址:', + LINK_1:'https://github.com/GeorgeCao-hw/georgedoc/blob/master/openEuler-Infra-FAQ.md' + }, + { + ID:'02', + TITLE:'了解OSV技术测评策略', + TEXT_1:'开展OSV技术测评之前,您需要了解OSV技术测评策略,测评标准,以及使用OSV技术测评工具进行自验证。地址如下:', + LINK_1:'https://gitee.com/openeuler/oecp' + }, + { + ID:'03', + TITLE:'申请OSV技术测评', + TEXT_1:'您需要向公共邮箱( ', + LINK_1:'oecompatibility@openeuler.org', + TEXT_2:')发送OSV技术测评申请,邮件标题需要注明“申请OSV技术测评”。收到邮件后,openEuler团队中sig组会与您沟通进行协议签署,如果已经签署,请忽略。', + TEXT_3:'tips:如果没有签署CLA,请先签署:', + LINK_2:'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=' + }, + { + ID:'04', + TITLE:'提交OSV技术测评申请issue', + TEXT_1:'完成协议签署后,您需要在openEuler社区(', + LINK_1:'https://gitee.com/openeuler/oecp/issues', + TEXT_2:')的OSV技术测评项目下创建issue,将所需要测评的操作系统信息在issue中明确,以及ISO镜像地址。openEuler团队会及时了解issue的信息,并提出建议。' + }, + { + ID:'05', + TITLE:'OSV技术测评', + TEXT_1:'openEuler社区会第一时间对提供的ISO进行OSV技术测评,测评之后会联系您进行部分结果确认以及审核,之后,会将测评结果发布到 ', + LINK_TEXT:'openEuler官网', + LINK_1:'https://www.openeuler.org/zh/', + TEXT_2:' 上。', + }, + { + ID:'06', + TITLE:'OSV技术测评结果发布', + TEXT_1:'openEuler团队会针对提交结果进行审核,如果通过,会将OSV技术测评结果添加到OSV技术测评列表中。', + }, + ], + TABLE_TITLE: 'OSV技术测评结果', + SELECT_PLACEHOLDER: '请选择', + SELECT_COMPANY: 'OS厂商', + SELECT_TYPE: '分类', + SELECT_ALL: '全部', + SEARCH_PLACEHOLDER: 'OS厂商、OS版本、分类', + SEARCH_TEXT: '搜索', + TABLE_COLUMN: { + ARCHITECTURE: '架构', + COMPANY: 'OS厂商', + VERSION: 'OS版本', + DOWNLOAD: 'OS下载地址', + TYPE: '分类', + DATE: '测评日期', + DETAILS: '测评详情', + LINK: '友情链接', + REPORT: '查看报告' + }, + SUBTITLE_REPORT:'OSV技术测评报告', + ADOPT:'通过', + FAIL:'不通过', + ASSESS_LIST:{ + ASSESS_INFO:'评估信息', + OSV:'系统版本', + ARCHITECTURE: '架构', + PUBLISH_ADDRESS:'发布地址', + CHECKSUM:'checksum', + OPENEULER_EDITION:'基于openEuler的版本', + COMPATIBLE:'COMPATIBLE' + }, + TOOL_LIST:{ + TOOL_DETECT:'工具检测', + TEST_ITEM:'检测项', + DETECTION_DESC:'检测点描述', + TEST_RESULT:'测试结果', + CONCLUSION:'结论' + }, + PLATFORM_DESCRIBE:{ + REPO:'EPOL仓/软件所仓库在OSV版本上安装成功比例', + BASE:'社区AT用例运行结果', + PERFORMANCE:'基础性能测试结果', + RUNNING:'OSV版本运行时默认配置一致性' + }, + TOOL_DESCRIBE:{ + CORE_PKG:'核心包一致性比例', + SOFT_PKG:'L1/L2 软件包一致性比例', + KABI:'OSV内核KABI接口白名单与openEuler内核KABI接口白名单一致性比例', + ABI:'OSV软件包ABI接口与openEuler软件包ABI一致性比例', + SERVICE:'OSV软件包Service文件与openEuler软件包Service文件一致性比例', + SOFT_CONFIG:'OSV软件包配置文件与openEuler软件包配置文件一致性比例', + KARNEL_CONFIG:'OSV的内核配置与openEuler一致性比例' + }, + TOOL_NAME:{ + CORE_PKG:'核心包', + SOFT_PKG:'软件包', + KABI:'内核KABI接口', + ABI:'用户态ABI接口', + SERVICE:'Service默认配置', + SOFT_CONFIG:'软件包默认配置', + KARNEL_CONFIG:'内核特性配置' + }, + PLATFORM_NAME:{ + REPO:'仓库', + BASE:'基本功能', + PERFORMANCE:'基础性能', + RUNNING:'运行时默认配置' + }, + PLATFORM_LIST:{ + PLATFORM_VERIFY:'平台验证' + }, + }, +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/authentication.js b/web-ui/docs/.vuepress/lang/lang-modules/authentication.js new file mode 100644 index 0000000000000000000000000000000000000000..0a714a201c34baac2557fa9fb20189d58ec194e8 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/authentication.js @@ -0,0 +1,12 @@ +/** + * @file 认证模块国际化配置入口 + * */ + +module.exports = { + cn: { + test: '测试' + }, + en: { + test: 'test' + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/brand.js b/web-ui/docs/.vuepress/lang/lang-modules/brand.js new file mode 100644 index 0000000000000000000000000000000000000000..e8ea4357cf0b5ecee05b9a96fef418754a423a96 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/brand.js @@ -0,0 +1,237 @@ +/** + * @file 品牌模块国际化配置入口 + * */ + +module.exports = { + cn: { + BRAND: '品牌', + WORDS:'openEuler网站上使用和显示的所有商标、标志皆属openEuler社区所有,但注明属于其他方拥有的商标、标志除外。未经openEuler社区或其他方书面许可,openEuler网站所载的任何内容不应被视作以暗示、不反对或其他形式授予使用前述任何商标、标志的许可或权利。未经事先书面许可,任何人不得以任何方式使用openEuler社区的名称及openEuler社区的商标、标记,除非你使用前述名称、商标和标记是出于个人、教育和非商业目的。任何人不得在未获得第三方同意的情况下使用第三方拥有的商标和标志。', + MOBILETITLE:'商标', + PPT_TEXT: 'PPT模板', + PICTURE_TITLE:['Standard','Monochrome','Black','Standard','Monochrome','Black'], + VERTICAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-left.svg' + }], + VERTICAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-center.svg' + }], + VERTICAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-right.svg' + }], + HORIZONTAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-left.svg' + }], + HORIZONTAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-center.svg' + }], + HORIZONTAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-right.svg' + }], + PPT_LIST: [ + { + URL: '/img/other/brand/euler-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_Blue.pptx' + }, + { + URL: '/img/other/brand/euler-white-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_White.pptx' + } + ] + }, + en: { + BRAND: 'Brand', + WORDS:'Notice: All logos and trademarks used on this website are the properties of openEuler community or other third parties as stated if applicable. No content provided on the openEuler community website shall be deemed as granting approval or the right to use any trademark or logo aforesaid by implication, lack of objection, or other means without the prior written consent of openEuler community or any third party which may own the mark. No individual shall use the name, trademark, and logo of openEuler community by any means without the prior written consent of openEuler community, except that your use of the name, trademark, and logo aforesaid is solely for personal, educational and non-commercial purpose. No individual shall use trademarks and logos owned by third parties without getting their approval.', + MOBILETITLE:'Trademark', + PPT_TEXT: 'PPT Templates', + PICTURE_TITLE:['Standard','Monochrome','Black','Standard','Monochrome','Black'], + VERTICAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-left.svg' + }], + VERTICAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-center.svg' + }], + VERTICAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-right.svg' + }], + HORIZONTAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-left.svg' + }], + HORIZONTAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-center.svg' + }], + HORIZONTAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-right.svg' + }], + PPT_LIST: [ + { + URL: '/img/other/brand/euler-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_Blue.pptx' + }, + { + URL: '/img/other/brand/euler-white-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_White.pptx' + } + ] + }, + ru: { + BRAND: 'Бренд', + WORDS:'Примечание. Все используемые на этом веб-сайте логотипы и товарные знаки являются собственностью сообщества openEuler или других указанных третьих лиц, если это применимо. Размещенные на веб-сайте сообщества openEuler материалы не должны рассматриваться как предоставленное разрешение или право использовать любой такой товарный знак или логотип косвенным путем, в силу отсутствия возражений или по другой причине без предварительного письменного согласия сообщества openEuler или любого третьего лица, которое может владеть данным товарным знаком. Запрещается кому-бы то ни было использовать любым способом название, товарный знак и логотип сообщества openEuler без предварительного письменного согласия последнего в любых целях, кроме личных, образовательных и некоммерческих. Запрещается кому-бы то ни было использовать товарные знаки и логотипы, принадлежащие третьим лицам, без их согласия.', + MOBILETITLE:'Trademark', + PPT_TEXT: 'PPT Templates', + PICTURE_TITLE:['Стандартный','Черно-белый','Черный','Стандартный','Черно-белый','Черный'], + VERTICAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-left.svg' + }], + VERTICAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-center.svg' + }], + VERTICAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/vertical-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/vertical-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/vertical-right.svg' + }], + HORIZONTAL_LEFT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-left.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-left.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-left.svg' + }], + HORIZONTAL_CENTER_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-center.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-center.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-center.svg' + }], + HORIZONTAL_RIGHT_IMAGE:[{ + STYLE:'JPG', + URL:'/img/other/brand/horizontal-right.jpg' + },{ + STYLE:'PNG', + URL:'/img/other/brand/horizontal-right.png' + },{ + STYLE:'SVG', + URL:'/img/other/brand/horizontal-right.svg' + }], + PPT_LIST: [ + { + URL: '/img/other/brand/euler-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_Blue.pptx' + }, + { + URL: '/img/other/brand/euler-white-ppt.png', + LINK: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler_PPT_White.pptx' + } + ] + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/common.js b/web-ui/docs/.vuepress/lang/lang-modules/common.js new file mode 100644 index 0000000000000000000000000000000000000000..a581f1500bd52d47c34fb4ab0e6543af030eee2c --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/common.js @@ -0,0 +1,680 @@ +/** + * @file 公共模块国际化配置入口 + * */ + +module.exports = { + cn: { + MEETINGS_TIME: '会议时间:', + MEETINGS_REPLAY: '回放链接', + SEARCH_PLACE_HOLDER: '输入内容', + COOKIE_LEGAL_TEXT: '本站点使用Cookies,继续浏览表示您同意我们使用Cookies。', + COOKIE_LEGAL_LINK_TEXT: 'Cookies和隐私政策>', + NAV_ROUTER_CONFIG: [{ + PATH: '', + NAME: '下载', + CHILDREN: [ + { + NAME: 'ISO', + PATH: '/download/' + }, + { + NAME: '镜像仓列表', + PATH: '/mirror/list/' + } + ], + CLASS: [] + }, + { + NAME: '学习', + CHILDREN: [ + { + NAME: '文档', + PATH: '/zh/', + IS_OPEN_WINDOW: 1 + }, + { + NAME: '慕课', + PATH: '/learn/mooc/' + }, + { + NAME: '实习', + PATH: '/internship/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: '互动', + CHILDREN: [{ + NAME: '新闻', + PATH: '/interaction/news-list/' + }, + { + NAME: '博客', + PATH: '/interaction/blog-list/' + }, + { + NAME: '直播', + PATH: '/interaction/live-list/' + }, + { + NAME: '沙龙', + PATH: '/interaction/salon-list/' + }, + { + NAME: '峰会', + PATH: '/interaction/summit-list/devday2022/' + } + ], + OTHER_CHILDREN: [ + { + PATH: '/news/' + }, + { + PATH: '/blog/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: '社区', + CHILDREN: [{ + NAME: '贡献攻略', + PATH: '/community/contribution/' + }, + { + NAME: '行为守则', + PATH: '/community/conduct/' + }, + { + NAME: '邮件列表', + PATH: '/community/mailing-list/' + }, + { + NAME: '个人认证', + PATH: '/community/certification-services/' + }, + { + NAME: '贡献看板', + PATH: 'https://datastat.openeuler.org/zh/overview', + IS_OPEN_MINISITE_WINDOW: 1 + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'SIG', + CHILDREN: [{ + NAME: '查看SIG', + PATH: '/sig/sig-list/' + }, + { + NAME: '申请流程', + PATH: '/sig/sig-guidance/' + }, + { + NAME: '角色说明', + PATH: '/sig/role-description/' + }, + { + NAME: '会议指南', + PATH: '/sig/meeting-guide/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: '探索', + CHILDREN: [{ + NAME: 'A-Tune', + PATH: '/other/projects/atune' + }, + { + NAME: 'BiSheng JDK', + PATH: '/other/projects/bishengjdk' + }, + { + NAME: 'iSula', + PATH: '/other/projects/isula' + }, + { + NAME: 'secGear', + PATH: '/other/projects/secgear' + }, + { + NAME: 'StratoVirt', + PATH: '/other/projects/stratovirt' + }, + { + NAME: 'Compass-CI', + PATH: 'https://compass-ci.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + }, + { + NAME: 'Compliance', + PATH: 'https://compliance.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + }, + { + NAME: 'Pkgship', + PATH: 'https://pkgmanage.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: '支持', + CHILDREN: [{ + NAME: '漏洞管理', + PATH: '/security/vulnerability-reporting/' + }, + { + NAME: '安全公告', + PATH: '/security/safety-bulletin/' + }, + { + NAME: 'CVE', + PATH: '/security/cve/' + }, + { + NAME: 'OSV技术测评', + PATH: '/approve/' + }, + { + NAME: '兼容性技术测评', + PATH: 'https://certification.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + }, + { + NAME: '兼容性列表', + PATH: '/compatibility/' + }, + { + NAME: '迁移指南', + PATH: '/other/migration/' + } + ], + CLASS: [] + } + ], + LANG: '中文', + LANG_LIST: ['中文','English','Русский'], + GITTE: '源码', + CODE: '代码', + GITTE_RESOURCE_LIST: [{ + NAME: '代码仓', + URL: 'https://gitee.com/openeuler' + }, + { + NAME: '软件包仓', + URL: 'https://gitee.com/src-openeuler' + }, + { + NAME: 'GitHub镜像仓', + URL: 'https://github.com/openeuler-mirror' + } + ], + FOOTER: { + ATOM_TEXT:'openEuler 是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目', + ATOM_PC:'/atom-pc.png', + ATOM_MO:'/atom-mo.png', + MAIL: 'contact@openeuler.io', + COPY_RIGHT: '版权所有 © 2022 openEuler 保留一切权利', + RIGHT_LIST: [{ + NAME: '品牌', + URL: '/other/brand/' + }, + { + NAME: '隐私政策', + URL: '/other/privacy/' + }, + { + NAME: '法律声明', + URL: '/other/legal/' + }, + { + NAME: '服务状态', + URL: 'https://status.openeuler.org/' + }, + ], + QR_CODE: '扫码关注公众号' + }, + BUILDING:{ + BUILDING:'建设中', + BUILDINGMES:'敬请期待...' + } + }, + en: { + MEETINGS_TIME: 'Time: ', + MEETINGS_REPLAY: 'Replay', + SEARCH_PLACE_HOLDER: 'Input content', + COOKIE_LEGAL_TEXT: 'This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies.', + COOKIE_LEGAL_LINK_TEXT: 'Read our privacy policy>', + NAV_ROUTER_CONFIG: [{ + PATH: '', + NAME: 'Download', + CHILDREN: [ + { + NAME: 'Software Packages', + PATH: '/download/' + }, + { + NAME: 'Mirrors', + PATH: '/mirror/list/' + } + ], + CLASS: [] + }, + { + NAME: 'Learning', + CHILDREN: [ + { + NAME: 'Documentation', + PATH: '/en/', + IS_OPEN_WINDOW: 1 + }, + { + NAME: 'MOOC', + PATH: '/learn/mooc/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Connect', + CHILDREN: [{ + NAME: 'News', + PATH: '/interaction/news-list/' + }, + { + NAME: 'Blog', + PATH: '/interaction/blog-list/' + }, + { + NAME: 'Live', + PATH: '/interaction/live-list/' + }, + { + NAME: 'Meetups', + PATH: '/interaction/salon-list/' + }, + { + NAME: 'Summit', + PATH: '/interaction/summit-list/devday2022/' + } + ], + OTHER_CHILDREN: [ + { + PATH: '/news/' + }, + { + PATH: '/blog/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Community', + CHILDREN: [{ + NAME: 'Contribution', + PATH: '/community/contribution/' + }, + { + NAME: 'Convention', + PATH: '/community/conduct/' + }, + { + NAME: 'Mailing Lists', + PATH: '/community/mailing-list/' + }, + { + NAME: 'Certification', + PATH: '/community/certification-services/' + }, + { + NAME: 'Statistics', + PATH: 'https://datastat.openeuler.org/en/overview', + IS_OPEN_MINISITE_WINDOW: 1 + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'SIG', + CHILDREN: [{ + NAME: 'SIG Lists', + PATH: '/sig/sig-list/' + }, + { + NAME: 'Application', + PATH: '/sig/sig-guidance/' + }, + { + NAME: 'Roles', + PATH: '/sig/role-description/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Discovery', + CHILDREN: [{ + NAME: 'A-Tune', + PATH: '/other/projects/atune' + }, + { + NAME: 'BiSheng JDK', + PATH: '/other/projects/bishengjdk' + }, + { + NAME: 'iSula', + PATH: '/other/projects/isula' + }, + { + NAME: 'secGear', + PATH: '/other/projects/secgear' + }, + { + NAME: 'StratoVirt', + PATH: '/other/projects/stratovirt' + }, + { + NAME: 'Compass-CI', + PATH: 'https://compass-ci.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + }, + { + NAME: 'Compliance', + PATH: 'https://compliance.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + }, + { + NAME: 'Pkgship', + PATH: 'https://pkgmanage.openeuler.org/', + IS_OPEN_MINISITE_WINDOW: 1 + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Support', + CHILDREN: [{ + NAME: 'Vulnerability Management', + PATH: '/security/vulnerability-reporting/' + }, + { + NAME: 'Security Advisories', + PATH: '/security/safety-bulletin/' + }, + { + NAME: 'CVE', + PATH: '/security/cve/' + }, + { + NAME: 'Compatibility List', + PATH: '/compatibility/' + }, + ], + CLASS: [] + } + ], + LANG: 'English', + LANG_LIST: ['中文','English','Русский'], + GITTE: 'Source code', + CODE: 'CODE', + GITTE_RESOURCE_LIST: [{ + NAME: 'Code Sources', + URL: 'https://gitee.com/openeuler' + }, + { + NAME: 'Package Sources', + URL: 'https://gitee.com/src-openeuler' + }, + { + NAME: 'GitHub Mirror', + URL: 'https://github.com/openeuler-mirror' + } + ], + FOOTER: { + ATOM_TEXT:'openEuler is an open source project incubated and operated by the OpenAtom Foundation.', + ATOM_PC:'/atom-pc.png', + ATOM_MO:'/atom-mo.png', + MAIL: 'contact@openeuler.io', + COPY_RIGHT: 'Copyright © 2022 openEuler. All rights reserved.', + RIGHT_LIST: [{ + NAME: 'Trademark', + URL: '/other/brand/' + }, + { + NAME: 'Privacy Policy', + URL: '/other/privacy/' + }, + { + NAME: 'Legal Notice', + URL: '/other/legal/' + }, + { + NAME: 'Service Status', + URL: 'https://status.openeuler.org/' + } + ], + QR_CODE: 'WeChat Subscription' + }, + BUILDING:{ + BUILDING:'Building', + BUILDINGMES:'Coming soon…' + } + }, + ru: { + MEETINGS_TIME: 'Time: ', + MEETINGS_REPLAY: 'Воспроизведение', + SEARCH_PLACE_HOLDER: 'Введите текст', + COOKIE_LEGAL_TEXT: 'Продолжая просмотр сайта и(или) нажимая X, я соглашаюсь с использованием файлов cookie владельцем сайта в соответствии с ', + COOKIE_LEGAL_TEXT_OTHER: 'в том числе на передачу данных, указанных в Политике, третьим лицам (статистическим службам сети Интернет), в соответствии с ', + COOKIE_LEGAL_LINK_TEXT: 'Политикой в отношении файлов cookie ', + COOKIE_LEGAL_LINK_TEXT_OTHER: 'Пользовательским соглашением >', + NAV_ROUTER_CONFIG: [{ + PATH: '', + NAME: 'Загрузить', + CHILDREN: [ + { + NAME: 'Software Packages', + PATH: '/download/' + }, + { + NAME: 'Mirrors', + PATH: '/mirror/list/' + } + ], + CLASS: [] + }, + { + NAME: 'Обучение', + CHILDREN: [ + { + NAME: 'Документация', + PATH: '/ru/', + IS_OPEN_WINDOW: 1 + }, + { + NAME: 'МООК', + PATH: '/learn/mooc/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Подключиться', + CHILDREN: [{ + NAME: 'Новости', + PATH: '/interaction/news-list/' + }, + { + NAME: 'Блог', + PATH: '/interaction/blog-list/' + }, + { + NAME: 'Прямой эфир', + PATH: '/interaction/live-list/' + }, + { + NAME: 'Семинары', + PATH: '/interaction/salon-list/' + }, + { + NAME: 'Саммит', + PATH: '/interaction/summit-list/devday2022/' + } + ], + OTHER_CHILDREN: [ + { + PATH: '/news/' + }, + { + PATH: '/blog/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Сообщество', + CHILDREN: [ + { + NAME: 'Кодекс', + PATH: '/community/conduct/' + }, + { + NAME: 'Сертификация', + PATH: '/community/certification-services/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'SIG', + CHILDREN: [{ + NAME: 'Списки SIG', + PATH: '/sig/sig-list/' + }, + { + NAME: 'Заявка', + PATH: '/sig/sig-guidance/' + }, + { + NAME: 'Роли', + PATH: '/sig/role-description/' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Открытие', + CHILDREN: [{ + NAME: 'A-Tune', + PATH: '/other/projects/atune' + }, + { + NAME: 'BiSheng JDK', + PATH: '/other/projects/bishengjdk' + }, + { + NAME: 'iSula', + PATH: '/other/projects/isula' + }, + { + NAME: 'secGear', + PATH: '/other/projects/secgear' + }, + { + NAME: 'StratoVirt', + PATH: '/other/projects/stratovirt' + } + ], + CLASS: [] + }, + { + PATH: '', + NAME: 'Поддержка', + CHILDREN: [{ + NAME: 'Управление уязвимостями', + PATH: '/security/vulnerability-reporting/' + }, + { + NAME: 'Консультанты по безопасности', + PATH: '/security/safety-bulletin/' + }, + { + NAME: 'CVE', + PATH: '/security/cve/' + }, + { + NAME: 'Список совместимости', + PATH: '/compatibility/' + }, + ], + CLASS: [] + } + ], + LANG: 'Русский', + LANG_LIST: ['中文','English','Русский'], + GITTE: 'Source code', + CODE: 'Код', + GITTE_RESOURCE_LIST: [{ + NAME: 'Источники кода', + URL: 'https://gitee.com/openeuler' + }, + { + NAME: 'Источники пакетов', + URL: 'https://gitee.com/src-openeuler' + }, + { + NAME: 'Зеркало GitHub', + URL: 'https://github.com/openeuler-mirror' + } + ], + FOOTER: { + ATOM_TEXT:'openEuler - это проект с открытым исходным кодом, созданный и управляемый фондом OpenAtom.', + ATOM_PC:'/atom-pc.png', + ATOM_MO:'/atom-mo.png', + MAIL: 'contact@openeuler.io', + COPY_RIGHT: 'Авторские права © openEuler 2022. Все права защищены.', + RIGHT_LIST: [{ + NAME: 'Товарный знак', + URL: '/other/brand/' + }, + { + NAME: 'Политика конфиденциальности', + URL: '/other/privacy/' + }, + { + NAME: 'Правовое уведомление', + URL: '/other/legal/' + }, + { + NAME: 'Статус сервиса', + URL: 'https://status.openeuler.org/' + } + ], + QR_CODE: 'Подписка на WeChat' + }, + BUILDING:{ + BUILDING:'Создание', + BUILDINGMES:'Ожидается...' + } + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/community.js b/web-ui/docs/.vuepress/lang/lang-modules/community.js new file mode 100644 index 0000000000000000000000000000000000000000..841fb6f2f9e85ba21dcac488887f00f06ca0acfb --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/community.js @@ -0,0 +1,721 @@ +/** + * @file 社区模块国际化中文配置入口 + * */ + +module.exports = { + cn: { + NEWS: { + NEWS: '新闻', + MONTHS: ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'], + }, + BLOG: { + BLOG: '博客', + LABEL: '标签', + FILE: '发布时间', + AUTHOR: '作者', + BLOGGING: '发博攻略', + READ_MORE: '查看全文 >>', + DISCLAIMER: '【免责声明】本文仅代表作者本人观点,与本网站无关。本网站对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文仅供读者参考,由此产生的所有法律责任均由读者本人承担。', + COPYRIGHT_1: "【版权声明】Copyright © 2021 openEuler Community。本文由openEuler社区首发,欢迎遵照", + COPYRIGHT_2: "协议规定转载。转载时敬请在正文注明并保留原文链接和作者信息。", + OTHER_BLOG: "Ta的其他博文", + CELECT_LABEL: "选择标签", + CELECT_FILE: "选择发布时间", + SELECT_AUTHOR: "请选择作者", + BROWSE: "浏览", + VIEWED: "次", + ALL: "全部" + }, + MAILING_LIST: { + TITLE: "邮件列表", + GUIDE_CONTENT: [ + { + LEFT: { + LEFT_INFO: "在邮件列表页面选择要订阅的邮件列表", + LEFT_CIRCLE: "选择", + LEFT_IMG: "/img/community/maillist/mail1.png" + }, + RIGHT: { + RIGHT_INFO: "填入邮件地址和名字,名字可选,点击订阅", + RIGHT_CIRCLE: "订阅", + LEFT_IMG: "/img/community/maillist/mail2.png" + } + }, + { + LEFT: { + LEFT_INFO: "您的邮箱将收到一封来自邮件列表的电子邮件,要求您确认订阅了邮件列表,回复该电子邮件确认订阅", + LEFT_CIRCLE: "确认", + LEFT_IMG: "/img/community/maillist/mail3.png" + }, + RIGHT: { + RIGHT_INFO: "您的邮箱收到来自一封来自邮件列表的欢迎邮件,即成功订阅该邮件列表。如需退订,请参考", + DO_THIS:"此操作", + LINK:"/blog/liuqi/2021-10-14-unsubscribe-mailing-list.html", + RIGHT_CIRCLE: "成功", + LEFT_IMG: "/img/community/maillist/mail4.png" + } + }, + ], + SUBSCRIBE: { + TITLE: "概要", + PART_ONE: "openEuler社区的主要联系方式", + PART_TWO: "要联系列表所有者,请试用以下电子邮件地址:community-owner@openeuler.org", + PART_THREE: "要查看次列表及以往的邮件,请访问归档。", + REMIND: "您不创建也可订阅。如果您愿意,请使用下面的表格。", + INPUT_ADD: "您的电子邮件地址", + INPUT_NAME: "您的名字(选填)", + BUTTON: "订阅", + }, + TABLE: { + NAME: "列表名称", + EMAIL_ADDRESS: "邮件地址", + ARCHIVE: "归档路径", + DESCRIPTION: "描述", + NAME_H5: "名称", + ARCHIVE_H5: "归档" + }, + MAIL_ERROR: "邮件列表发生错误", + SUBSCRIBE_ERROR: "邮件订阅发生错误", + SUBSCRIBE_SUCCESS: "订阅请求已发送,稍后订阅确认邮件会发送到您的邮箱,请按邮件提示回复确认邮件后,订阅才能生效。", + MAIL_ERROR: "邮箱填写错误", + SUBSCRIBE_ALREADY_SUCCESS: '您已订阅成功', + SUBSCRIBE_HAS_SENT: '订阅确认邮件已发送到您的邮箱,请按邮件提示回复确认邮件后,订阅才能生效。如您没有收到邮件,请确认是否被您的邮箱服务器拦截或者归类到垃圾邮件。' + }, + CONTRIBUTION_H5: { + TITLE: "贡献攻略", + MOBILE_TITLE: "社区贡献攻略", + GUIDE_CONTENT: [ + { + BUTTON: "签署CLA", + IMG: "/img/community/contribution/cla.png", + MOBILEIMG:'/img/community/contribution/mobile-img/cla.png', + VIDEO: "/img/community/contribution/cla.gif", + LINK: "https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=" + }, + { + BUTTON: "提出Issue", + IMG: "/img/community/contribution/issue.png", + MOBILEIMG:'/img/community/contribution/mobile-img/issue.png', + VIDEO: "/img/community/contribution/issue.gif", + LINK: "", + LINKADRESSLIST:{ + TITLE:'请选择跳转的链接:', + LINKMESSAGE:[ + { + ICONIMAGE:"url('/img/community/contribution/icon/wechat.png')", + TEXT:'微信', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/email.png')", + TEXT:'邮件', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/gitee.png')", + TEXT:'Gitee', + LINKADRESS:'/building/' + } + ] + } + }, + { + BUTTON: "贡献代码", + IMG: "/img/community/contribution/contribution.png", + MOBILEIMG:'/img/community/contribution/mobile-img/contribution.png', + VIDEO: "/img/community/contribution/contribution.gif", + LINK: "https://gitee.com/openeuler" + }, + { + BUTTON: "加入SIG", + IMG: "/img/community/contribution/sig.png", + MOBILEIMG:'/img/community/contribution/mobile-img/sig.png', + VIDEO: "/img/community/contribution/sig.gif", + LINK: "/sig/sig-list/" + }, + { + BUTTON: "参选技术委员会", + IMG: "/img/community/contribution/commit.png", + MOBILEIMG:'/img/community/contribution/mobile-img/commit.png', + VIDEO: "/img/community/contribution/commit.gif", + LINK: "/sig/sig-list/sig-detail.html?id=21&name=TC&mail=tc%40openeuler.org" + }, + ] + }, + CONTRIBUTION: { + DOWLOAD_PDF_URL: '/openeuler-trail-chess.pdf', + BACKGROUND_IMG_H5: ' https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_zh_mo.png', + BACKGROUND_IMG: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_zh.png', + LOOK_DESC: '查看文字版攻略', + PRINT_MAP: '打印攻略地图', + LINK_LIST: [ + 'https://huaweicloud.com/product/ecs.html', + 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Virtualization/virtualization.html', + 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Installation/installation.html', + 'https://gitee.com/openeuler/raspberrypi', + '/zh/other/projects/stratovirt/', + '/zh/other/projects/atune/', + '/zh/other/projects/isula/', + '/zh/other/projects/secgear/', + 'https://pkgmanage.openeuler.org/', + '/zh/other/projects/bishengjdk/', + 'https://compass-ci.openeuler.org/', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + '/zh/#meeting', + '/zh/interaction/salon-list/', + '/zh/interaction/live-list/', + '/zh/interaction/summit-list/devday2022/', + '/zh/sig/sig-list/', + '/zh/sig/sig-guidance/', + 'https://gitee.com/openeuler/community/issues', + '/zh/community/contribution/detail.html#_2-贡献编码', + '/zh/community/contribution/detail.html#_3-贡献软件包', + '/zh/community/contribution/detail.html#_4-贡献原创开源项目', + '/zh/community/contribution/detail.html#_5-检视代码', + 'https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md', + 'https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md', + 'https://gitee.com/openeuler/community/blob/master/zh/contributors/non-code-contributions.md', + 'https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md', + 'https://gitee.com/openeuler/community/blob/master/community-membership_cn.md', + '/zh/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org' + ] + }, + CONDUCT: { + TITLE: "行为守则" + }, + SERVICE: { + TITLE:"openEuler 证书", + DOWN:{ + DPSCRIPT_ONE:"openEuler 认证是面向对 openEuler 操作系统感兴趣的IT专业人员或学生 ,证明其对 openEuler 开发、技术支持、运维能力的一种认证。", + GET_CARD:"证书获取", + GET_CARD_DISC:"openEuler-HCIA /openEuler-HCIP/openEuler-HCIE 认证是 openEuler 社区承认的不同等级的能力认证,如果您有兴趣获取相应证书,可点击下列项目进行报名培训与认证考试,通过考试后,您即可同步获得对应等级的证书。", + NOT_CARDURL:"敬请期待", + OUTLINE_DOWN_TIP:"验证码已发送至您的邮箱,请输入验证码以获取证书", + CARD_MODEL:[ + { + DISC:"openEuler-HCIA", + NAME:"认证工程师", + IMG:"/img/community/conduct/hcia-icon.png", + NEXT_URL:"https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0", + }, + { + DISC:"openEuler-HCIP", + NAME:"认证高级工程师", + IMG:"/img/community/conduct/hcip-icon.png", + NEXT_URL:"" + }, + { + DISC:"openEuler-HCIE", + NAME:"认证专家", + IMG:"/img/community/conduct/hcie-icon.png", + NEXT_URL:"" + }, + ], + DOWN_CARD:"证书下载", + DOWN_CHOOSE_CARD:"下载选中证书", + DOWN_CARD_DISC:"通过认证考试后可在此处下载证书。", + SEARCH_RESULTS:"您的证书信息如下:", + NO_CARD:"当前无可下载证书!", + DOWN_FAIL_DISC_LEFT:"您的下载链接已过期,请点击", + DOWN_FAIL_DISC_RIGHT:"重新获取下载链接。", + DOWNCREDENT:[{ + NAME:"证书下载", + IMG:"/img/community/conduct/down-card-icon.png", + }] + }, + SEARCH:{ + SEARCH:"证书查询", + SEARCH_DISC:"请输入认证考试所用的邮箱以获取验证码,查询您的证书。", + SEND_CODE:"发送验证码", + SEND_AGAIN:"重新发送", + EMAIL_ERROR:"您输入的邮箱有误", + EMAIL_PLAHD:"您绑定的邮箱", + CODE_PLAHD:"输入您获取的验证码", + CODE_ERROR:"您输入的验证码有误!", + SHOW_TEMPLATE:"/img/community/conduct/showtemplate.png" + }, + BTNSURE:"确定" + } + }, + en: { + NEWS: { + NEWS: 'News', + MONTHS: ['January','February','March','April','May','June','July','August','September','October','November','December'], + }, + BLOG: { + BLOG: 'Blog', + LABEL: 'Label', + AUTHOR: "Author", + FILE: 'Date of Release', + BLOGGING: 'Guidance to post a blog', + READ_MORE: 'Read more >>', + DISCLAIMER: "[Disclaimer] This article only represents the author's opinions, and is irrelevant to this website. This website is neutral in terms of the statements and opinions in this article, and does not provide any express or implied warranty of accuracy, reliability, or completeness of the contents contained therein. This article is for readers' reference only, and all legal responsibilities arising therefrom are borne by the reader himself.", + COPYRIGHT_1: "[Copyright] Copyright © 2021 openEuler Community. This article is first released by the openEuler community. Please reproduce it in compliance with the", + COPYRIGHT_2: "license. Please note the text and keep the original link and author information when reproducing the article.", + OTHER_BLOG: "Other blogs", + CELECT_LABEL: "Select tag", + CELECT_FILE: "Select date", + SELECT_AUTHOR: "Select author", + BROWSE: "", + VIEWED: " Viewed", + ALL: "All" + }, + MAILING_LIST: { + TITLE: "Mailing Lists", + GUIDE_CONTENT: [ + { + LEFT: { + LEFT_INFO: "Select the mailing list to be subscribed to on the Mailing Lists page.", + LEFT_CIRCLE: "Select", + LEFT_IMG: "/img/community/maillist/mail1.png", + INDEX: '01' + }, + RIGHT: { + RIGHT_INFO: "Enter the e-mail address and name (optional), and click Subscribe. ", + RIGHT_CIRCLE: "Subscribe ", + LEFT_IMG: "/img/community/maillist/mail2.png", + INDEX: '02' + } + }, + { + LEFT: { + LEFT_INFO: "Your mailbox will receive an e-mail from the mailing list, asking you to confirm that you have subscribed to the mailing list. Reply to the e-mail to confirm the subscription.", + LEFT_CIRCLE: "Confirm ", + LEFT_IMG: "/img/community/maillist/mail3.png", + INDEX: '03' + }, + RIGHT: { + RIGHT_INFO: "Your mailbox receives a welcome e-mail from the mailing list, indicating that you have subscribed to the mailing list successfully.", + RIGHT_CIRCLE: "Succeed", + LEFT_IMG: "/img/community/maillist/mail4.png", + INDEX: '04' + } + }, + ], + SUBSCRIBE: { + TITLE: "Summary", + PART_ONE: "The main contact endpoint of openEuler community", + PART_TWO: "To contact the list owners, use the following email address: community-owner@openeuler.org", + PART_THREE: "To see the prior posting to the list, visit the archives.", + REMIND: "You can also subscribe without creating an account. If you wish to do so, please use the form below.", + INPUT_ADD: "Your email address", + INPUT_NAME: "Your name(optional)", + BUTTON: "Subscribe" + }, + TABLE: { + NAME: "Name", + EMAIL_ADDRESS: "Mailing List", + ARCHIVE: "Archive", + DESCRIPTION: "Description", + NAME_H5: "Name", + ARCHIVE_H5: "Archive" + }, + MAIL_ERROR: "Error in mailing list", + SUBSCRIBE_ERROR: "Mail subscription error", + SUBSCRIBE_SUCCESS: "The subscription request has been sent. A subscription confirmation e-mail will be sent to your mailbox later. please replay to the confirmation e-mail as prompted to make the subscription take effect.", + MAIL_ERROR: "Email error", + SUBSCRIBE_ALREADY_SUCCESS: 'Member already subscribed', + SUBSCRIBE_HAS_SENT: 'The subscription confirmation e-mail has been sent to your mailbox. Please replay to the e-mail as prompted to make the subscription take effect. if you do not receive the e-mail, check whether the e-mail is blocked by your e-mail server or classified as spam.' + }, + CONTRIBUTION_H5: { + TITLE: "How to Contribute", + MOBILE_TITLE: "How to Contribute", + GUIDE_CONTENT: [ + { + BUTTON: "Sign CLA", + IMG: "/img/community/contribution/cla.png", + VIDEO: "/img/community/contribution/cla.gif", + MOBILEIMG:'/img/community/contribution/mobile-img/cla.png', + LINK: "https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=" + }, + { + BUTTON: "Submit an Issue", + IMG: "/img/community/contribution/issue.png", + MOBILEIMG:'/img/community/contribution/mobile-img/issue.png', + VIDEO: "/img/community/contribution/issue.gif", + LINK: "", + LINKADRESSLIST:{ + TITLE:'Choose your link:', + LINKMESSAGE:[ + { + ICONIMAGE:"url('/img/community/contribution/icon/wechat.png')", + TEXT:'Wechat', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/email.png')", + TEXT:'Email', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/gitee.png')", + TEXT:'Gitee', + LINKADRESS:'/building/' + } + ] + } + }, + { + BUTTON: "Contribute Code", + IMG: "/img/community/contribution/contribution.png", + MOBILEIMG:'/img/community/contribution/mobile-img/contribution.png', + VIDEO: "/img/community/contribution/contribution.gif", + LINK: "https://gitee.com/openeuler" + }, + { + BUTTON: "Join SIG", + IMG: "/img/community/contribution/sig.png", + MOBILEIMG:'/img/community/contribution/mobile-img/sig.png', + VIDEO: "/img/community/contribution/sig.gif", + LINK: "/sig/sig-list/" + }, + { + BUTTON: "Participate in Technical Committee Election", + IMG: "/img/community/contribution/commit.png", + MOBILEIMG:'/img/community/contribution/mobile-img/commit.png', + VIDEO: "/img/community/contribution/commit.gif", + LINK: "/sig/sig-list/sig-detail.html?id=21&name=TC&mail=tc%40openeuler.org" + }, + ] + }, + CONTRIBUTION: { + DOWLOAD_PDF_URL: '/openeuler-trail-chess-en.pdf', + BACKGROUND_IMG_H5: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_en_mo.png', + BACKGROUND_IMG: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_en.png', + LOOK_DESC: 'View Details', + PRINT_MAP: 'Download', + LINK_LIST: [ + 'https://huaweicloud.com/intl/en-us/product/ecs.html', + 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Virtualization/virtualization.html', + 'https://docs.openeuler.org/en/docs/20.03_LTS/docs/Installation/Installation.html', + 'https://gitee.com/openeuler/raspberrypi', + '/en/other/projects/stratovirt/', + '/en/other/projects/atune/', + '/en/other/projects/isula/', + '/en/other/projects/secgear/', + 'https://pkgmanage.openeuler.org/', + '/en/other/projects/bishengjdk/', + 'https://compass-ci.openeuler.org/', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + '/en/#meeting', + '/en/interaction/salon-list/', + '/en/interaction/live-list/', + '/en/interaction/summit-list/devday2022/', + '/en/sig/sig-list/', + '/en/sig/sig-guidance/', + 'https://gitee.com/openeuler/community/issues', + '/en/community/contribution/detail.html#_2-contribute-code', + '/en/community/contribution/detail.html#_3-contribute-a-package', + '/en/community/contribution/detail.html#_4-contribute-original-open-source-projects', + '/en/community/contribution/detail.html#__5-review-code', + 'https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md', + 'https://gitee.com/openeuler/community/blob/master/en/contributors/packaging.md', + 'https://gitee.com/openeuler/community/blob/master/en/contributors/non-code-contributions.md', + 'https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md', + 'https://gitee.com/openeuler/community/blob/master/community-membership.md', + '/en/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org' + ] + }, + CONDUCT: { + TITLE: "Code of Covenant" + }, + SERVICE: { + TITLE:"openEuler Certification", + DOWN:{ + DPSCRIPT_ONE:"openEuler certification is intended for IT professionals or students interested in the openEuler OS to prove their capabilities in openEuler development, technical support, and O&M.", + GET_CARD:"Take Exams", + GET_CARD_DISC:"openEuler-HCIA, openEuler-HCIP and openEuler-HCIE are the capability certifications at different levels recognized by the openEuler community. If you are interested in obtaining any of these certificates, click the following items to sign up for the trainings and tests.", + NOT_CARDURL:"Coming soon", + OUTLINE_DOWN_TIP:"The verification code has been sent to your email address. Enter the verification code to obtain the certificate.", + CARD_MODEL:[ + { + DISC:"openEuler-HCIA", + NAME:"Certified Engineer", + IMG:"/img/community/conduct/hcia-icon.png", + NEXT_URL:"https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0", + }, + { + DISC:"openEuler-HCIP", + NAME:"Certified Senior Enginee", + IMG:"/img/community/conduct/hcip-icon.png", + NEXT_URL:"" + }, + { + DISC:"openEuler-HCIE", + NAME:"Certified Expert", + IMG:"/img/community/conduct/hcie-icon.png", + NEXT_URL:"" + }, + ], + DOWN_CARD:"Download Certificates", + DOWN_CHOOSE_CARD:"Download Selected Certificates", + DOWN_CARD_DISC:"Click to download the certificate after passing the exam.", + SEARCH_RESULTS:"The information of your certificates is as follows:", + NO_CARD:"No certificate is available for download.", + DOWN_FAIL_DISC_LEFT:"Your download link has expired. Click ", + DOWN_FAIL_DISC_RIGHT:" to obtain a new link.", + DOWNCREDENT:[{ + NAME:"Download Certificates", + IMG:"/img/community/conduct/down-card-icon.png", + }] + }, + SEARCH:{ + SEARCH:"Query Certificates", + SEARCH_DISC:"Enter the email address used for the certification exam to obtain the verification code and query your certificate.", + SEND_CODE:"Send a verification code", + SEND_AGAIN:"Resend", + EMAIL_ERROR:"The email address is incorrect.", + EMAIL_PLAHD:"Your email address", + CODE_PLAHD:"Enter the verification code.", + CODE_ERROR:"The verification code is incorrect.", + SHOW_TEMPLATE:"/img/community/conduct/showtemplate.png" + }, + BTNSURE:"Confirm" + } + }, + ru: { + NEWS: { + NEWS: 'Новости', + MONTHS: ['January','February','March','April','May','June','July','August','September','October','November','December'], + }, + BLOG: { + BLOG: 'Блог', + LABEL: 'Метка', + AUTHOR: "Author", + FILE: 'Дата выпуска релиза', + BLOGGING: 'Ведение блога', + READ_MORE: 'Еще >>', + DISCLAIMER: "[Заявление об отсутствии гарантий] Данная статья представляет только мнения автора и не имеет отношения к данному веб-сайту. Данный веб-сайт является нейтральным с точки зрения заявлений и мнений, содержащихся в данной статье, и отказывается от всех явно выраженных или подразумеваемых гарантий точности, надежности и полноты содержащейся информации. Информация, содержащаяся в данной статье, предназначена только для справки, и все юридические обязательства, вытекающие из нее, несет сам читатель.", + COPYRIGHT_1: "[Заявление об авторском праве]Copyright © 2021 openEuler Community. Данная статья была впервые опубликована сообществом openEuler. Пожалуйста, копируйте и распространяйте ее в соответствии с лицензией", + COPYRIGHT_2: "При перепечатке необходимо указать в тексте исходную ссылку и информацию об авторе.", + OTHER_BLOG: "Other blogs", + CELECT_LABEL: "Выбрать", + CELECT_FILE: "Выбрать", + SELECT_AUTHOR: "Select author", + BROWSE: "", + VIEWED: "Просмотрено", + ALL: "Все" + }, + MAILING_LIST: { + TITLE: "Списки рассылок", + GUIDE_CONTENT: [ + { + LEFT: { + LEFT_INFO: "На странице Списки рассылок выберите рассылку, на которую хотите подписаться.", + LEFT_CIRCLE: "Выбрать", + LEFT_IMG: "/img/community/maillist/mail1.png", + INDEX: '01' + }, + RIGHT: { + RIGHT_INFO: "Введите адрес электронной почты и имя (необязательно), нажмите Подписаться.", + RIGHT_CIRCLE: "Подписаться ", + LEFT_IMG: "/img/community/maillist/mail2.png", + INDEX: '02' + } + }, + { + LEFT: { + LEFT_INFO: "На ваш почтовый ящик поступит электронное письмо с запросом на подтверждение, что вы подписались на данную рассылку. Для подтверждения подписки ответьте на данное электронное письмо.", + LEFT_CIRCLE: "Подтвердить ", + LEFT_IMG: "/img/community/maillist/mail3.png", + INDEX: '03' + }, + RIGHT: { + RIGHT_INFO: "На ваш почтовый ящик поступит электронное письмо с сообщением, что вы успешно подписались на данную рассылку.", + RIGHT_CIRCLE: "Успешно", + LEFT_IMG: "/img/community/maillist/mail4.png", + INDEX: '04' + } + }, + ], + SUBSCRIBE: { + TITLE: "Summary", + PART_ONE: "The main contact endpoint of openEuler community", + PART_TWO: "To contact the list owners, use the following email address: community-owner@openeuler.org", + PART_THREE: "To see the prior posting to the list, visit the archives.", + REMIND: "You can also subscribe without creating an account. If you wish to do so, please use the form below.", + INPUT_ADD: "Your email address", + INPUT_NAME: "Your name(optional)", + BUTTON: "Subscribe" + }, + TABLE: { + NAME: "Наименование", + EMAIL_ADDRESS: "Списки рассылок", + ARCHIVE: "Архив", + DESCRIPTION: "Описание", + NAME_H5: "Наименование", + ARCHIVE_H5: "Архив" + }, + MAIL_ERROR: "Error in mailing list", + SUBSCRIBE_ERROR: "Mail subscription error", + SUBSCRIBE_SUCCESS: "The subscription request has been sent. A subscription confirmation e-mail will be sent to your mailbox later. please replay to the confirmation e-mail as prompted to make the subscription take effect.", + MAIL_ERROR: "Email error", + SUBSCRIBE_ALREADY_SUCCESS: 'Member already subscribed', + SUBSCRIBE_HAS_SENT: 'The subscription confirmation e-mail has been sent to your mailbox. Please replay to the e-mail as prompted to make the subscription take effect. if you do not receive the e-mail, check whether the e-mail is blocked by your e-mail server or classified as spam.' + }, + CONTRIBUTION_H5: { + TITLE: "Как принять участие", + MOBILE_TITLE: "Как принять участие", + GUIDE_CONTENT: [ + { + BUTTON: "Подписать CLA", + IMG: "/img/community/contribution/cla.png", + VIDEO: "/img/community/contribution/cla.gif", + MOBILEIMG:'/img/community/contribution/mobile-img/cla.png', + LINK: "https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=" + }, + { + BUTTON: "Отправить вопрос", + IMG: "/img/community/contribution/issue.png", + MOBILEIMG:'/img/community/contribution/mobile-img/issue.png', + VIDEO: "/img/community/contribution/issue.gif", + LINK: "", + LINKADRESSLIST:{ + TITLE:'Выберите ссылку:', + LINKMESSAGE:[ + { + ICONIMAGE:"url('/img/community/contribution/icon/wechat.png')", + TEXT:'Wechat', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/email.png')", + TEXT:'Эл. почта', + LINKADRESS:'/building/' + }, + { + ICONIMAGE:"url('/img/community/contribution/icon/gitee.png')", + TEXT:'Gitee', + LINKADRESS:'/building/' + } + ] + } + }, + { + BUTTON: "Включить код в проект", + IMG: "/img/community/contribution/contribution.png", + MOBILEIMG:'/img/community/contribution/mobile-img/contribution.png', + VIDEO: "/img/community/contribution/contribution.gif", + LINK: "https://gitee.com/openeuler" + }, + { + BUTTON: "Присоединиться к группе SIG", + IMG: "/img/community/contribution/sig.png", + MOBILEIMG:'/img/community/contribution/mobile-img/sig.png', + VIDEO: "/img/community/contribution/sig.gif", + LINK: "/sig/sig-list/" + }, + { + BUTTON: "Участвовать в выборах в Технический комитет", + IMG: "/img/community/contribution/commit.png", + MOBILEIMG:'/img/community/contribution/mobile-img/commit.png', + VIDEO: "/img/community/contribution/commit.gif", + LINK: "/sig/sig-list/sig-detail.html?id=21&name=TC&mail=tc%40openeuler.org" + }, + ] + }, + CONTRIBUTION: { + DOWLOAD_PDF_URL: '/openeuler-trail-chess-en.pdf', + BACKGROUND_IMG_H5: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_en_mo.png', + BACKGROUND_IMG: 'https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/%E8%B4%A1%E7%8C%AE%E5%9C%B0%E5%9B%BE/webtrailchess_en.png', + LOOK_DESC: 'View Details', + PRINT_MAP: 'Download', + LINK_LIST: [ + 'https://huaweicloud.com/product/ecs.html', + 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Virtualization/virtualization.html', + 'https://docs.openeuler.org/zh/docs/20.03_LTS/docs/Installation/installation.html', + 'https://gitee.com/openeuler/raspberrypi', + '/ru/other/projects/stratovirt/', + '/ru/other/projects/atune/', + '/ru/other/projects/isula/', + '/ru/other/projects/secgear/', + 'https://pkgmanage.openeuler.org/', + '/ru/other/projects/bishengjdk/', + 'https://compass-ci.openeuler.org/', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=', + '/ru/#meeting', + '/ru/interaction/salon-list/', + '/ru/interaction/live-list/', + '/ru/interaction/summit-list/devday2022/', + '/ru/sig/sig-list/', + '/ru/sig/sig-guidance/', + 'https://gitee.com/openeuler/community/issues', + '/ru/community/contribution/detail.html#_2-贡献编码', + '/ru/community/contribution/detail.html#_3-贡献软件包', + '/ru/community/contribution/detail.html#_4-贡献原创开源项目', + '/ru/community/contribution/detail.html#_5-检视代码', + 'https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md', + 'https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md', + 'https://gitee.com/openeuler/community/blob/master/zh/contributors/non-code-contributions.md', + 'https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md', + 'https://gitee.com/openeuler/community/blob/master/community-membership.md', + '/ru/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org' + ] + }, + CONDUCT: { + TITLE: "Кодекс поведения" + }, + SERVICE: { + TITLE:"сертификаты openEuler", + DOWN:{ + DPSCRIPT_ONE:"Сертификация openEuler предназначена для ИТ-профессионалов или студентов, интересующихся ОС openEuler, чтобы они могли подтвердить свои способности в разработке, технической поддержке и эксплуатации openEuler.", + GET_CARD:"Сдавать экзамены", + GET_CARD_DISC:"openEuler-HCIA, openEuler-HCIP и openEuler-HCIE являются сертификатами, доказывающими возможности различных уровней, признанными сообществом openEuler. Если вы заинтересованы в получении сертификата, щелкните по следующим пунктам, чтобы зарегистрироваться для прохождения обучения и сертификационного экзамена.", + NOT_CARDURL:"Скоро", + OUTLINE_DOWN_TIP:"Проверочный код был отправлен на вашу электронную почту. Введите проверочный код для получения сертификата.", + CARD_MODEL:[ + { + DISC:"openEuler-HCIA", + NAME:"Сертифицированный инженер", + IMG:"/img/community/conduct/hcia-icon.png", + NEXT_URL:"https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0", + }, + { + DISC:"openEuler-HCIP", + NAME:"Сертифицированный старший инженер", + IMG:"/img/community/conduct/hcip-icon.png", + NEXT_URL:"" + }, + { + DISC:"openEuler-HCIE", + NAME:"Сертифицированный эксперт", + IMG:"/img/community/conduct/hcie-icon.png", + NEXT_URL:"" + }, + ], + DOWN_CARD:"Загрузить сертификаты", + DOWN_CHOOSE_CARD:"Загрузить выбранные сертификаты", + DOWN_CARD_DISC:"Нажмите и загрузите сертификат после сдачи экзамена.", + SEARCH_RESULTS:"Ниже приведена информация о ваших сертификатах:", + NO_CARD:"Нет сертификата, доступного для загрузки.", + DOWN_FAIL_DISC_LEFT:"Срок действия ссылки на загрузку истек. Нажмите Загрузить сертификаты ", + DOWN_FAIL_DISC_RIGHT:" чтобы получить новую ссылку.", + DOWNCREDENT:[{ + NAME:"Загрузить сертификаты", + IMG:"/img/community/conduct/down-card-icon.png", + }] + }, + SEARCH:{ + SEARCH:"Запросить сертификаты", + SEARCH_DISC:"Введите адрес электронной почты, используемый при проведении сертификационного экзамена, для получения проверочного кода и запроса сертификата.", + SEND_CODE:"Отправить проверочный код", + SEND_AGAIN:"Отправить заново", + EMAIL_ERROR:"Неверный адрес электронной почты.", + EMAIL_PLAHD:"Ваш адрес электронной почты", + CODE_PLAHD:"Введите проверочный код.", + CODE_ERROR:"Неверный проверочный код.", + SHOW_TEMPLATE:"/img/community/conduct/showtemplate.png" + }, + BTNSURE:"Подтвердить" + } + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/compatibility.js b/web-ui/docs/.vuepress/lang/lang-modules/compatibility.js new file mode 100644 index 0000000000000000000000000000000000000000..e9f87ef1aa9d3e1b428f212b388e76f37d131fce --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/compatibility.js @@ -0,0 +1,497 @@ +/** + * @file 下载模块国际化配置入口 + * */ + +module.exports = { + cn: { + COMPATIBILITY: '兼容性列表', + HARDWARE: '整机', + DRIVE: '板卡', + SOFTWARE:'开源软件', + BUSINESS_SOFTWARE:'商业软件', + SOFTWARETYPE:'软件类型', + ADAPTIVE:'操作系统', + OS: '操作系统', + ARCHITECTURE: '架构', + SELECT_PLACEHOLDER: '请选择', + SEARCH_ALL:'全部', + SEARCH_LABEL: "搜索", + HARDWARE_SEARCH_PLACEHOLDER: "厂家、型号、CPU、操作系统", + SOFTWARE_SEARCH_PLACEHOLDER: "软件名称", + DRIVE_SEARCH_PLACEHOLDER:'驱动名称、板卡型号、芯片厂家', + LINK: 'link', + BUSINESS_TESTING_ORGANIZATION: '测试机构', + HARDWARE_TABLE_COLUMN: { + VENDOR: '硬件厂家', + MODEL: '硬件型号', + OS: '操作系统', + DATE: '日期', + COMPATIBILITY_CONFIGURATION: '兼容性配置', + COMPATIBILITY_CONFIGURATION2: 'Compatibility Configuration', + REFERRENCE: '友情链接' + }, + DRIVE_TABLE_COLUMN: { + ARCHITECTURE: '架构', + DRIVE_NAME: '驱动名称', + DRIVE_OS: '操作系统', + VERSION: '版本', + TYPE: '类型', + DRIVE_DATE: '日期', + SHA_256_DRIVER: 'SHA 256 Driver', + SIZE: '大小 (Byte)', + CHIP_VENDOR: '芯片厂家', + BOARD_MODEL: '板卡型号', + CHIP_MODEL: '芯片型号' + }, + SOFTWARE_TABLE_COLUMN: { + ARCHITECTURE: '架构', + SOFTWARETYPE: '软件类型', + SOFTWARENAME: '软件名称', + VERSION: '版本', + PROPERTIES: '软件属性', + DOWNLOADLINK: '下载地址', + SYSTEM: '操作系统', + PUBLICKLICENSE: '开源协议' + }, + BUSINESS_SOFTWARE_TABLE_COLUMN: { + ARCHITECTURE: '架构', + SOFTWARENAME: '软件名称', + VERSION: '版本', + VENDOR: '厂家名称', + SYSTEM: '操作系统', + SERVER_NAME: '服务器型号', + TESTING_ORGANIZATION: '测试机构', + CERTIFICATE: '证书' + }, + HARDWARE_DETAIL: { + TITLE_1: 'Product Information', + TITLE_2: 'Configuration', + TITLE_3: 'Adapter and Drivers', + TIP_LABEL: '此配置为兼容性测试时的配置信息,更多的配置差异兼容性参考', + TIP_LINK: '《openEuler 兼容性策略文档》', + LABELS: { + OS: 'OS/OS Version', + VENDOR: 'Vendor', + TEST_TIME: 'Test Time', + COMMIT_ID: 'Commit ID', + ARCHITECTURE: 'Architecture', + MOTHER_BOARD_REVISION: 'Mother Board Revision', + BIOS_UEFI: 'BIOS/UEFI', + CPU: 'CPU', + RAM: 'RAM', + PORTS_AND_BUS_TYPES: 'Ports and Bus Types', + VIDEO_ADAPTER: 'Video Adapter', + HOST_BUS_ADAPTER: 'Host Bus Adapter', + HARD_DISK_DRIVE: 'Hard Disk Drive', + }, + TABLE_CULUMN: { + DRIVE_NAME: 'Driver Name', + VERSION: 'Version', + TYPE: 'Type', + DRIVE_DATE: 'Driver Date', + DRIVE_CHIP_VENDOR: 'Chip Vendor', + DRIVE_BOARD_MODEL: 'Board Model', + DRIVE_CHIP_MODEL: 'Chip Model' + } + }, + HARDWARE_OEC_DETAIL: { + TEXT:'关于硬件兼容性测试,openEuler提供了完整的测试流程和工具,详见', + TITLE: 'openEuler 硬件兼容性测试整体介绍', + DISCRIPTION_TITLE: '简介', + DISCRIPTION_CONTENT: 'openEuler提供了一系列的工具、文档和操作流程帮助用户测试openEuler与硬件的兼容性。如果您需要对服务器等硬件展开兼容性测试,下文提供了兼容性测试流程,并且每个阶段提供了预计需要的时间供参考。', + PROCESS_TITLE:'兼容性测试流程', + ITEM_ARR: [ + { + ID:'01', + TITLE:'申请加入openEuler社区(0.5天)', + DESCRIPTION_1:'您需要在Gitee平台申请加入openEuler社区,成为组织成员。申请地址:', + A_TEXT:'https://github.com/GeorgeCao-hw/georgedoc/blob/master/openEuler-Infra-FAQ.md', + DESCRIPTION_2:'。' + }, + { + ID:'02', + TITLE:'申请兼容性测试(0.5天)', + DESCRIPTION_1:'您需要向公共邮箱(', + A_TEXT:'oecompatibility@openeuler.org', + DESCRIPTION_2:')发送兼容性申请,邮件标题需要注明“申请硬件兼容性测试”。收到邮件后,openEuler团队中sig组会与您沟通进行协议签署(敬请期待)。', + DESCRIPTION_3:'tips:如果没有签署CLA,请先签署:', + A_TEXT2: 'https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=' + }, + { + ID:'03', + TITLE:'了解兼容性策略(0.5天)', + DESCRIPTION_1:'在开展兼容性测试前,您需要了解openEuler硬件兼容性策略,', + A_TEXT:'点击此处获取文档。', + },{ + ID:'04', + TITLE:'创建issue(0.5天)', + DESCRIPTION_1:'完成协议签署后,您需要在openEuler社区(', + A_TEXT:'https://gitee.com/openeuler/oec-hardware', + DESCRIPTION_2:')的oec-hardware项目下创建issue,将所需要认证的硬件信息在issue中明确。openEuler团队会及时了解issue的信息,并提出建议。' + },{ + ID:'05', + TITLE:'测试兼容性(10天)', + DESCRIPTION_1:'完成issue创建后,即可开展兼容性测试。openEuler团队提供了兼容性测试框架以及使用指南,您可以根据使用指南自助完成兼容性测试。点击下载', + A_TEXT:'兼容性测试工具套件', + A_TEXT_2:'使用指南', + DESCRIPTION_2:'|' + }, { + ID:'06', + TITLE:'提交结果审核(2天)', + DESCRIPTION_1:'完成兼容性测试并通过后,需要您把测试结果更新到issue中。并且按照使用指南将对应测试结果发送给公共邮箱:您需要向公共邮箱(', + A_TEXT2:'', + DESCRIPTION_3: '', + A_TEXT:'oecompatibility@openeuler.org', + DESCRIPTION_2:')发送兼容性结果审核申请,邮件标题需要注明“xxx硬件兼容性测试结果信息”(其中xxx为社区issue ID)。' + }, { + ID:'07', + TITLE:'结果发布(2天)', + DESCRIPTION_1:'openEuler团队会针对提交结果进行审核,如果通过,会将硬件添加到', + A_TEXT:'兼容性列表', + DESCRIPTION_2:'中。' + }] + }, + SOFTWARE_OEC_DETAIL: { + TEXT:'关于软件兼容性测试,openEuler提供了完整的测试流程和工具,详见', + TITLE: 'openEuler 软件兼容性测试整体介绍', + DISCRIPTION_TITLE: '简介', + DISCRIPTION_CONTENT: 'openEuler提供了一系列的工具、文档和操作流程帮助用户测试openEuler与软件的兼容性。如果您需要对某款软件展开兼容性测试,可参考下文进行。', + PROCESS_TITLE:'兼容性测试流程', + ITEM_ARR: [{ + ID:'01', + TITLE:'创建issue', + DESCRIPTION_1:'您需要在openEuler社区(', + A_TEXT:'https://gitee.com/openeuler/oec-application', + DESCRIPTION_2:')的oec-application项目下创建issue,将所需认证的软件信息在issue中明确。openEuler团队会及时了解issue信息,并给出建议。' + },{ + ID:'02', + TITLE:'兼容性测试', + DESCRIPTION_1:'完成issue创建后,即可开展兼容性测试。openEuler团队提供了', + A_TEXT:'自动化测试平台 compass-ci', + DESCRIPTION_2:'以及使用指南,根据使用指南自助完成兼容性测试。' + },{ + ID:'03', + TITLE:'提交结果审核', + DESCRIPTION_1:'完成兼容性测试并通过后,需要您把测试结果更新到issue中。issue中需要给出 group_id。', + }, + { + ID:'04', + TITLE:'结果发布', + DESCRIPTION_1:'openEuler团队会针对提交结果进行审核,如果通过,会将软件添加到', + A_TEXT:'兼容性列表', + DESCRIPTION_2:'中。' + }] + }, + USINESS_SOFTWARE_OEC_DETAIL: { + TEXT:'关于商业软件兼容性技术测评,openEuler提供了完整的测试流程和工具,详见', + TITLE: 'openEuler兼容性技术测评整体介绍', + DISCRIPTION_TITLE: '简介', + DISCRIPTION_CONTENT: 'openEuler提供了一系列的工具、文档和操作流程帮助用户进行软件的兼容性技术测评。如果您需要对某款软件展开兼容性测评,可参考下文进行。', + PROCESS_TITLE:'兼容性技术测评流程' + }, + }, + en: { + COMPATIBILITY: 'Compatibility List', + HARDWARE: 'Server', + DRIVE: 'Card', + OS: 'OS', + ARCHITECTURE: 'Architecture', + SELECT_PLACEHOLDER: 'Select', + SEARCH_ALL:'ALL', + SEARCH_LABEL: "Search", + HARDWARE_SEARCH_PLACEHOLDER:'Vendor, CPU, Model or OS', + SOFTWARE_SEARCH_PLACEHOLDER: "软件名称", + DRIVE_SEARCH_PLACEHOLDER:'Driver Name, Card Model, or Chip Vendor', + LINK: 'link', + HARDWARE_TABLE_COLUMN: { + VENDOR: 'Vendor', + MODEL: 'Model', + OS: 'OS', + DATE: 'Date', + COMPATIBILITY_CONFIGURATION: 'Compatibility Configuration', + COMPATIBILITY_CONFIGURATION2: 'Compatibility Configuration', + REFERRENCE: 'Reference' + }, + SOFTWARE_TABLE_COLUMN: { + ARCHITECTURE: '架构', + SOFTWARETYPE: '软件类型', + SOFTWARENAME: '软件名称', + VERSION: '版本', + PROPERTIES: '软件属性', + DOWNLOADLINK: '下载地址', + SYSTEM: '操作系统', + PUBLICKLICENSE: '开源协议' + }, + DRIVE_TABLE_COLUMN: { + ARCHITECTURE: 'Architecture', + DRIVE_NAME: 'Driver Name', + DRIVE_OS: 'OS', + VERSION: 'Version', + TYPE: 'Type', + DRIVE_DATE: 'Date', + SHA_256_DRIVER: 'SHA 256 Driver', + SIZE: 'Size (Byte)', + CHIP_VENDOR: 'Chip Vendor', + BOARD_MODEL: 'Plug-in Card Model', + CHIP_MODEL: 'Chip Model' + }, + HARDWARE_DETAIL: { + TITLE_1: 'Product Information', + TITLE_2: 'Configuration', + TITLE_3: 'Adapter and Drivers', + TIP_LABEL: 'This configuration is used during the compatibility test. For details about the configuration differences and the compatibility, see the ', + TIP_LINK: 'openEuler Compatibility Policy', + LABELS: { + OS: 'OS/OS Version', + VENDOR: 'Vendor', + TEST_TIME: 'Test Time', + COMMIT_ID: 'Commit ID', + ARCHITECTURE: 'Architecture', + MOTHER_BOARD_REVISION: 'Mother Board Revision', + BIOS_UEFI: 'BIOS/UEFI', + CPU: 'CPU', + RAM: 'RAM', + PORTS_AND_BUS_TYPES: 'Ports and Bus Types', + VIDEO_ADAPTER: 'Video Adapter', + HOST_BUS_ADAPTER: 'Host Bus Adapter', + HARD_DISK_DRIVE: 'Hard Disk Drive', + }, + TABLE_CULUMN: { + DRIVE_NAME: 'Driver Name', + VERSION: 'Version', + TYPE: 'Type', + DRIVE_DATE: 'Driver Date', + DRIVE_CHIP_VENDOR: 'Chip Vendor', + DRIVE_BOARD_MODEL: 'Board Model', + DRIVE_CHIP_MODEL: 'Chip Model' + } + }, + SOFTWARE_OEC_DETAIL: { + TEXT:'关于软件兼容性测试,openEuler提供了完整的测试流程和工具,详见', + TITLE: 'openEuler 软件兼容性测试整体介绍', + DISCRIPTION_TITLE: '简介', + DISCRIPTION_CONTENT: 'openEuler提供了一系列的工具、文档和操作流程帮助用户测试openEuler与软件的兼容性。如果您需要对某款软件展开兼容性测试,可参考下文进行。', + PROCESS_TITLE:'兼容性测试流程', + ITEM_ARR: [{ + ID:'01', + TITLE:'创建issue', + DESCRIPTION_1:'您需要在openEuler社区(', + A_TEXT:'https://gitee.com/openeuler/oec-application', + DESCRIPTION_2:')的oec-application项目下创建issue,将所需认证的软件信息在issue中明确。openEuler团队会及时了解issue信息,并给出建议。' + },{ + ID:'02', + TITLE:'兼容性测试', + DESCRIPTION_1:'完成issue创建后,即可开展兼容性测试。openEuler团队提供了', + A_TEXT:'自动化测试平台 compass-ci', + DESCRIPTION_2:'以及使用指南,根据使用指南自助完成兼容性测试。' + },{ + ID:'03', + TITLE:'提交结果审核', + DESCRIPTION_1:'完成兼容性测试并通过后,需要您把测试结果更新到issue中。issue中需要给出 group_id。', + }, + { + ID:'04', + TITLE:'结果发布', + DESCRIPTION_1:'openEuler团队会针对提交结果进行审核,如果通过,会将软件添加到', + A_TEXT:'兼容性列表', + DESCRIPTION_2:'中。' + }] + }, + HARDWARE_OEC_DETAIL: { + TEXT:'openEuler provides a complete process and tools for hardware compatibility test. For details, see the ', + TITLE: 'Overall Introduction to the openEuler Hardware Compatibility Test', + DISCRIPTION_TITLE: 'Introduction', + DISCRIPTION_CONTENT: 'Openeuler provides a series of tools, documents and operation procedures to help you test the compatibility between openEuler and hardware. If you need to perform compatibility tests on hardware such as servers, perform the following process:', + PROCESS_TITLE:'Compatibility Test Process', + ITEM_ARR: [{ + ID:'01', + TITLE:'Apply for a compatibility test.', + DESCRIPTION_1:'Send a compatibility test application to the public mailbox (', + A_TEXT:'oecompatibility@openeuler.org', + DESCRIPTION_2:'). The email subject must contain "Apply for a Hardware Compatibility Test". After receiving the email, the sig team of openEuler will contact you and sign an agreement with you offline.' + },{ + ID:'02', + TITLE:'Learn about the compatibility test policies.', + DESCRIPTION_1:'Before performing the compatibility test, learn about the openEuler hardware compatibility policies.', + A_TEXT:'Click here to obtain the document.', + },{ + ID:'03', + TITLE:'Create an issue.', + DESCRIPTION_1:'After signing the agreement, create an issue under the oec-hardware project in the openEuler community (', + A_TEXT:'https://gitee.com/openeuler/oec-hardware', + DESCRIPTION_2:') and specify the hardware information in the issue. The openEuler team will give feedback on the issue in a timely manner.' + },{ + ID:'04', + TITLE:'Perform the compatibility test.', + DESCRIPTION_1:'After the issue is created, you can perform the compatibility test. The openEuler team provides the compatibility test framework and user guide that help you complete the test. Click here to download:', + A_TEXT:'Compatibility test tool suite', + A_TEXT_2:'User guide.', + DESCRIPTION_2:' | ' + }, { + ID:'05', + TITLE:'Submit the result for review.', + DESCRIPTION_1:'After the compatibility test is completed and passed, update the test result to the issue. Send the test result to the public mailbox as instructed by the user guide. Send the application for reviewing the compatibility result to ', + A_TEXT:'oecompatibility@openeuler.org.', + DESCRIPTION_2:' The email subject must contain "xxx Hardware Compatibility Test Result", where xxx indicates the community issue ID.' + }, { + ID:'06', + TITLE:'Release the result.', + DESCRIPTION_1:'The openEuler team will review the submitted result and add the hardware to the ', + A_TEXT:'Compatibility List', + DESCRIPTION_2:' after it is approved.' + }] + }, + }, + ru: { + COMPATIBILITY: 'Compatibility List', + HARDWARE: 'Server', + DRIVE: 'Card', + OS: 'OS', + ARCHITECTURE: 'Architecture', + SELECT_PLACEHOLDER: 'Select', + SEARCH_ALL:'ALL', + SEARCH_LABEL: "Search", + SOFTWARE_SEARCH_PLACEHOLDER: "软件名称", + HARDWARE_SEARCH_PLACEHOLDER:'Vendor, CPU, Model or OS', + DRIVE_SEARCH_PLACEHOLDER:'Driver Name, Card Model or Chip Vendor', + LINK: 'link', + HARDWARE_TABLE_COLUMN: { + VENDOR: 'Vendor', + MODEL: 'Model', + OS: 'OS', + DATE: 'Date', + COMPATIBILITY_CONFIGURATION: 'Compatibility Configuration', + COMPATIBILITY_CONFIGURATION2: 'Compatibility Configuration', + REFERRENCE: 'Reference' + }, + SOFTWARE_TABLE_COLUMN: { + ARCHITECTURE: '架构', + SOFTWARETYPE: '软件类型', + SOFTWARENAME: '软件名称', + VERSION: '版本', + PROPERTIES: '软件属性', + DOWNLOADLINK: '下载地址', + SYSTEM: '操作系统', + PUBLICKLICENSE: '开源协议' + }, + DRIVE_TABLE_COLUMN: { + ARCHITECTURE: 'Architecture', + DRIVE_NAME: 'Driver Name', + DRIVE_OS: 'OS', + VERSION: 'Version', + TYPE: 'Type', + DRIVE_DATE: 'Date', + SHA_256_DRIVER: 'SHA 256 Driver', + SIZE: 'Size (Byte)', + CHIP_VENDOR: 'Chip Vendor', + BOARD_MODEL: 'Plug-in Card Model', + CHIP_MODEL: 'Chip Model' + }, + HARDWARE_DETAIL: { + TITLE_1: 'Product Information', + TITLE_2: 'Configuration', + TITLE_3: 'Adapter and Drivers', + TIP_LABEL: 'This configuration is used during the compatibility test. For details about the configuration differences and the compatibility, see the ', + TIP_LINK: 'openEuler Compatibility Policy', + LABELS: { + OS: 'OS/OS Version', + VENDOR: 'Vendor', + TEST_TIME: 'Test Time', + COMMIT_ID: 'Commit ID', + ARCHITECTURE: 'Architecture', + MOTHER_BOARD_REVISION: 'Mother Board Revision', + BIOS_UEFI: 'BIOS/UEFI', + CPU: 'CPU', + RAM: 'RAM', + PORTS_AND_BUS_TYPES: 'Ports and Bus Types', + VIDEO_ADAPTER: 'Video Adapter', + HOST_BUS_ADAPTER: 'Host Bus Adapter', + HARD_DISK_DRIVE: 'Hard Disk Drive', + }, + TABLE_CULUMN: { + DRIVE_NAME: 'Driver Name', + VERSION: 'Version', + TYPE: 'Type', + DRIVE_DATE: 'Driver Date', + DRIVE_CHIP_VENDOR: 'Chip Vendor', + DRIVE_BOARD_MODEL: 'Board Model', + DRIVE_CHIP_MODEL: 'Chip Model' + } + }, + SOFTWARE_OEC_DETAIL: { + TEXT:'关于软件兼容性测试,openEuler提供了完整的测试流程和工具,详见', + TITLE: 'openEuler 软件兼容性测试整体介绍', + DISCRIPTION_TITLE: '简介', + DISCRIPTION_CONTENT: 'openEuler提供了一系列的工具、文档和操作流程帮助用户测试openEuler与软件的兼容性。如果您需要对某款软件展开兼容性测试,可参考下文进行。', + PROCESS_TITLE:'兼容性测试流程', + ITEM_ARR: [{ + ID:'01', + TITLE:'创建issue', + DESCRIPTION_1:'您需要在openEuler社区(', + A_TEXT:'https://gitee.com/openeuler/oec-application', + DESCRIPTION_2:')的oec-application项目下创建issue,将所需认证的软件信息在issue中明确。openEuler团队会及时了解issue信息,并给出建议。' + },{ + ID:'02', + TITLE:'兼容性测试', + DESCRIPTION_1:'完成issue创建后,即可开展兼容性测试。openEuler团队提供了', + A_TEXT:'自动化测试平台 compass-ci', + DESCRIPTION_2:'以及使用指南,根据使用指南自助完成兼容性测试。' + },{ + ID:'03', + TITLE:'提交结果审核', + DESCRIPTION_1:'完成兼容性测试并通过后,需要您把测试结果更新到issue中。issue中需要给出 group_id。', + }, + { + ID:'04', + TITLE:'结果发布', + DESCRIPTION_1:'openEuler团队会针对提交结果进行审核,如果通过,会将软件添加到', + A_TEXT:'兼容性列表', + DESCRIPTION_2:'中。' + }] + }, + HARDWARE_OEC_DETAIL: { + TEXT:'openEuler provides a complete process and tools for hardware compatibility test. For details, see the ', + TITLE: 'Overall Introduction to the openEuler Hardware Compatibility Test', + DISCRIPTION_TITLE: 'Introduction', + DISCRIPTION_CONTENT: 'Openeuler provides a series of tools, documents and operation procedures to help you test the compatibility between openEuler and hardware. If you need to perform compatibility tests on hardware such as servers, perform the following process:', + PROCESS_TITLE:'Compatibility Test Process', + ITEM_ARR: [{ + ID:'01', + TITLE:'Apply for a compatibility test.', + DESCRIPTION_1:'Send a compatibility test application to the public mailbox (', + A_TEXT:'oecompatibility@openeuler.org', + DESCRIPTION_2:'). The email subject must contain "Apply for a Hardware Compatibility Test". After receiving the email, the sig team of openEuler will contact you and sign an agreement with you offline.' + },{ + ID:'02', + TITLE:'Learn about the compatibility test policies.', + DESCRIPTION_1:'Before performing the compatibility test, learn about the openEuler hardware compatibility policies.', + A_TEXT:'Click here to obtain the document.', + },{ + ID:'03', + TITLE:'Create an issue.', + DESCRIPTION_1:'After signing the agreement, create an issue under the oec-hardware project in the openEuler community (', + A_TEXT:'https://gitee.com/openeuler/oec-hardware', + DESCRIPTION_2:') and specify the hardware information in the issue. The openEuler team will give feedback on the issue in a timely manner.' + },{ + ID:'04', + TITLE:'Perform the compatibility test.', + DESCRIPTION_1:'After the issue is created, you can perform the compatibility test. The openEuler team provides the compatibility test framework and user guide that help you complete the test. Click here to download:', + A_TEXT:'Compatibility test tool suite', + A_TEXT_2:'User guide.', + DESCRIPTION_2:' | ' + }, { + ID:'05', + TITLE:'Submit the result for review.', + DESCRIPTION_1:'After the compatibility test is completed and passed, update the test result to the issue. Send the test result to the public mailbox as instructed by the user guide. Send the application for reviewing the compatibility result to ', + A_TEXT:'oecompatibility@openeuler.org.', + DESCRIPTION_2:' The email subject must contain "xxx Hardware Compatibility Test Result", where xxx indicates the community issue ID.' + }, { + ID:'06', + TITLE:'Release the result.', + DESCRIPTION_1:'The openEuler team will review the submitted result and add the hardware to the ', + A_TEXT:'Compatibility List', + DESCRIPTION_2:' after it is approved.' + }] + }, + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/devday2022.js b/web-ui/docs/.vuepress/lang/lang-modules/devday2022.js new file mode 100644 index 0000000000000000000000000000000000000000..44e44941de03fa6150b6f37e91eefb59edbaf778 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/devday2022.js @@ -0,0 +1,4988 @@ +module.exports = { + cn: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_mo.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_pc.png", + LINK: "https://e-campaign.huawei.com/m/uMNFji" + }, + COLLECT_LIST: [{ + IMG: "/img/summit/devday-2022/CALLFORSPEAKER.png", + LINK: "https://shimo.im/forms/7DO3Fg79JSAfaflt/fill" + }, + { + IMG: "/img/summit/devday-2022/SIG1.png", + LINK: "https://shimo.im/forms/o0SfA0pfVmMlXEfi/fill" + }, + { + IMG: "/img/summit/devday-2022/CALLFORSPENSOR.png", + LINK: "https://shimo.im/forms/sspw0eU78rE9ra79/fill" + }, + ], + NAV_LIST: [ + { + key: '#liveroom', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#construction-unit', + name: '共建单位' + } + ], + LIVEDATA: { + RENDERDATA: [ + { + ID: 10392, + THEME: 'openEuler Developer Day 2022', + OPTION: 'openEuler Developer Day 2022', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10392?lang=zh&thirdId=' + }, + { + ID: 10393, + THEME: '内核', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 内核', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10393?lang=zh&thirdId=' + }, + { + ID: 10399, + THEME: '多样性计算', + TIME: '14:00-14:45', + OPTION: '14:00-14:45 多样性计算', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10399?lang=zh&thirdId=' + }, + { + ID: 10394, + THEME: '云原生&虚拟化', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 云原生&虚拟化', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10394?lang=zh&thirdId=' + }, + { + ID: 10398, + THEME: '边缘&嵌入式', + TIME: '14:00-15:30', + OPTION: '14:00-15:30 边缘&嵌入式', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10398?lang=zh&thirdId=' + }, + { + ID: 10400, + THEME: '大数据存储', + TIME: '15:15-17:00', + OPTION: '15:15-17:00 大数据存储', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10400?lang=zh&thirdId=' + }, + { + ID: 10397, + THEME: '开源雨林', + TIME: '14:45-16:00', + OPTION: '14:45-16:00 开源雨林', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10397?lang=zh&thirdId=' + }, + { + ID: 10395, + THEME: '安全分论坛', + TIME: '15:00-16:30', + OPTION: '15:00-16:30 安全', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10395?lang=zh&thirdId=' + }, + { + ID: 10396, + THEME: 'Devkit 工具集', + TIME: '15:30-17:15', + OPTION: '15:30-17:15 Devkit 工具集', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10396?lang=zh&thirdId=' + }, + ], + LIVETITLE: "openEuler Developer Day 2022直播间" + }, + SUMMIT_INTRODUCE: "openEuler Developer Day 2022 (简称 ODD 2022)是开放原子开源基金会的 openEuler 社区发起的开发者大会。旨在推动 openEuler 在服务器、云计算、边缘计算和嵌入式四大场景的技术探索和创新。本次 ODD 2022 正式发布 openEuler 22.03 全场景长周期版本,展示社区伙伴联合创新成果,分享多行业使用 openEuler 规模部署的商业案例,举办社区治理机构的线上工作会议。openEuler 始终与开发者在一起,开创新境,共创未来。", + AGENDA: { + CONFERENCE_LINK: "会议链接", + TITLE_IMG_PC: "/img/summit/devday-2022/zh-pc-devday2022.png", + TITLE_IMG_MO: "/img/summit/devday-2022/zh-mobile-devday2022.png", + AGENDA_DATA_TITLE: ['13', '14', '15'], + AGENDA_DATA_13: { + TITLE: "4月13日", + SCHEDULE: [ + { TIME: '16:00 - 17:30', SCHEDULE_LIST: ['用户委员会工作会议', '技术委员会工作会议', '品牌委员会工作会议', '理事会工作会议'] }, + { TIME: '15:30 - 17:30', SCHEDULE_LIST: ['用户圆桌'] } + ] + }, + AGENDA_DATA_14: { + MO_TITLE: "SIG 组开放工作会议", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + }, { + ZH: '晚上', + EN: 'night' + }], + TITLE: ['09:00 - 10:00', '10:00 - 11:00', '11:00 - 12:00'], + TITLE_AFTERNOON: ['14:00 - 15:00', '15:00 - 16:00', '16:00 - 17:00', '17:00 - 18:00'], + TITLE_NIGHT: ['19:00 - 20:00', '20:00 - 21:00'], + RIGHT_TEXT: ['回看', '笔记'], + SCHEDULE: [ + { + TITLE: { + ZH: "高校", + EN: "Education" + }, + SCHEDULE_CARD: [{ + TEXT: "高校开发者专场 sig-OSCourse", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1V3411T7Rq?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OSCourse-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "OpenStack DPU", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1SY4y1h7cM?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-openstack-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Industrial-Control", + TIME: "09:00 - 10:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1uZ4y1m7rz?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Industrial-Control-22.09-planning" + }, { + TEXT: "sig-AccLib", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1v44y137ZH?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/openEuler2209-sig-AccLib-ODD" + }, { + TEXT: "sig-Embedded Yocto", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1K94y1o7WL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-embedded-22.09-planning" + }] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-AI-BigData", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1X44y137XX?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-AI-BigData-22.09-planning" + }, { + TEXT: "sig-OPS", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dZ4y127Ux?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OPS-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-ceph", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1y94y1d7Gj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Ceph-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "Infrastructure sig-Gatekeeper", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1kF411g7TJ?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Infrastructure-22.09-planning" + }, { + TEXT: "sig-OS-Builder", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV12T4y1h7dB?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OS-Builder-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "Release", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1bF411g7Lk?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-release-22.09-planning" + }, { + TEXT: "Compiler", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dY4y1e76P?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compiler-22.09-planning" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-UKUI", + TIME: "9:00 - 09:30", + ZOOM_LINK: "https://www.bilibili.com/video/BV1N94y1o7cx?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-UKUI-planning" + }, { + TEXT: "sig-CICD", + TIME: "09:30 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1t34y1v7Lo?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CICD-planning" + }, { + TEXT: "Application System-tools", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1U94y1d743?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-application-systemtools-planning" + }] + }, + ], + SCHEDULE_AFTERNOON: [ + { + TITLE: { + ZH: "内核", + EN: "Kernel" + }, + SCHEDULE_CARD: [{ + TEXT: "Kernel", + TIME: "14:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1wL4y1L7T3?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-kernel-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-CloudNative iSula、golang", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1TB4y1U7ba?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CloudNative-22.09-planning" + }, { + TEXT: "Virt ovirt", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1fS4y1w72V?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Virt-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Intel-Arch", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV14F411g7oj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/intel-arch-sig-odd" + }, { + TEXT: "sig-sw-arch", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1aB4y1U7Kp?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-sw-arch-planning" + }, { + TEXT: "sig-ROS", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1cu411y7oS?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-ROS-22.09-planning" + } + ] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-HPC", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ku411C7ya?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-hpc-22.09-planning" + }, { + TEXT: "DB", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1EZ4y1m72F?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-DB-22.09-planning" + }, { + TEXT: "A-Tune", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1YS4y1Y7YE?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-A-Tune-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Networking", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ET4y1e7qe?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/Networking-plan-3.30" + }, + { + TEXT: "sig-Edge", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1q5411273v?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Edge-22.09-planning" + }, { + TEXT: "sig-high-performance-network", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1o44y1V7ao?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-high-performance-networking-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-security-facility security-committee", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1C34y1v7Zr?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-security-facility_and_sc-22.09-planning" + }, { + TEXT: "sig-Compatibility-Infra devkit", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV19u411C7fL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compatibility-Infra" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-QA GNOME", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1HZ4y1m71Q?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-QA-22.09-planning" + }, + { + TEXT: "sig HA", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Nr4y1H7N5?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-HA-22.09-planning" + }, { + TEXT: "sig-reproducible-builds", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1qi4y1U79W?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-reproducible-builds-22.09-planning" + }, { + TEXT: "sig-compliance", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY4y1e7T6?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-compliance-22.09-planing" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OpenDesign", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1s3411n75L?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OpenDesign-22.09-planning" + }, { + TEXT: "Doc G11N", + TIME: "15:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ua411v7Vy?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Doc-G11N-planning" + }, { + TEXT: "sig-Migration", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oT4y1Y7ep?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Migration-planning" + }] + }, + ], + SCHEDULE_NIGHT: [ + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OKD", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1RB4y1m79Z?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OKD-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Storage", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Gr4y1H7Mv?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Storage-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Java", + TIME: "19:00 - 20:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY411j7PY?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Java-22.09-planning" + }] + }, + ], + COLUMN_TITLE: [ + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "高校", + EN: "Education" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "内核", + EN: "Kernel" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "工具", + EN: "Tooling" + }, + ] + }, + ] + }, + AGENDA_DATA_15: { + TITLE: "4月15日 周五(线上直播)", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + },], + SCHEDULE: [ + { + TIME: "10:00 - 10:03", + TEXT: "开幕致辞", + SPEAKER: [ + { + NAME: '孙文龙', + POSITION: '开放原子开源基金会秘书长', + } + ] + }, + { + TIME: "10:03 - 10:06", + TEXT: "院士致辞", + SPEAKER: [ + { + NAME: '倪光南', + POSITION: '中国工程院院士', + } + ] + }, + { + TIME: "10:06 - 10:15", + TEXT: "一起创未来 欧拉更精彩", + SPEAKER: [ + { + NAME: '江大勇', + POSITION: 'openEuler社区理事长', + } + ] + }, + { + TIME: "10:15 - 10:30", + TEXT: "openEuler 22.03 LTS:新征程,再出发", + SPEAKER: [ + { + NAME: '胡欣蔚', + POSITION: 'openEuler社区技术委员会主席', + } + ] + }, + { + TIME: "10:30 - 10:34", + TEXT: "openEuler商业发行版发布计划及欧拉技术认证颁发仪式", + SPEAKER: [ + { + NAME: '邱成锋', + POSITION: 'openEuler社区秘书长', + } + ] + }, + { + TIME: "10:34 - 10:42", + TEXT: "携手openEuler ,共筑天翼云数字底座 ", + SPEAKER: [ + { + NAME: '广小明', + POSITION: '天翼云科技有限公司 副总经理 兼首席技术官' + } + ] + }, + { + TIME: "10:42 - 10:50", + TEXT: "基于openEuler全栈创新,赋能数智新在线", + SPEAKER: [ + { + NAME: '李康', + POSITION: '中国移动在线营销服务中心副总经理', + } + ] + }, + { + TIME: "10:50 - 10:58", + TEXT: "openEuler+CULinux 打造联通云新一代基础设施", + SPEAKER: [ + { + NAME: '钟忻', + POSITION: '联通云CTO', + } + ] + }, + { + TIME: "10:58 - 11:06", + TEXT: "云原生时代中信银行开源技术实践", + SPEAKER: [ + { + NAME: '周海鹏 ', + POSITION: '中信IT资深架构师', + } + ] + }, + { + TIME: "11:06 - 11:14", + TEXT: "数字赋能 守正创新 - 上交所技术基于欧拉的原生应用实践", + SPEAKER: [ + { + NAME: '刘凯', + POSITION: '上交所技术公司下一代交易研发部副总经理', + } + ] + }, + { + TIME: "11:14 - 11:32", + TEXT: "圆桌会议:如何构建支持多样性计算的OS生态", + SPEAKER: [ + { + NAME: '武延军', + POSITION: 'openEuler社区副理事长', + }, + { + NAME: '堵俊平', + POSITION: '华为计算开源总经理', + }, + { + NAME: '杨继国', + POSITION: 'Intel开源技术中心总监', + }, + { + NAME: '李铭', + POSITION: '英伟达亚太区生态伙伴发展总监', + }, + { + NAME: '唐丹', + POSITION: '北京开源芯片研究院副院长', + }, + { + NAME: '姜振华', + POSITION: '超聚变操作系统业务总经理', + }, + { + NAME: '焦旭坡', + POSITION: '新华三集团操作系统开发部部长', + }, + ] + }, + { + TIME: "11:32 - 11:50", + TEXT: "圆桌会议:凡是未来 皆有可期-社区运作版本规划", + SPEAKER: [ + { + NAME: '熊伟', + POSITION: 'openEuler社区技术委员会委员', + }, + { + NAME: '谢秀奇', + POSITION: 'Kernel', + }, + { + NAME: '席静', + POSITION: 'sig-RISC-V', + }, + { + NAME: '田俊', + POSITION: 'sig-Intel-Arch', + }, + { + NAME: '金小贤', + POSITION: 'sig-AI', + }, + { + NAME: '陈硕', + POSITION: 'sig-openstack', + }, + { + NAME: '曹志', + POSITION: 'Infrastructure', + }, + { + NAME: '马文', + POSITION: 'sig-embedded/sig-Yocto', + }, + ] + }, + { + TIME: "11:50 - 11:55", + TEXT: "展望致辞:欧拉社区志高远 开源汇智向未来", + SPEAKER: [ + { + NAME: '韩乃平', + POSITION: 'openEuler社区副理事长', + } + ] + }, + ], + HOST: ['主持人:', '嘉宾:'], + STICKY_TITLE: ['大数据存储分论坛', '开源雨林分论坛', '安全分论坛', 'Devkit 工具集分论坛'], + SCHEDULE_AFTERNOON: { + TIME_LIST: ['上半场', '14:00 - 14:15', '14:15 - 14:30', '14:30 - 14:45', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30'], + CARD_LIST: [ + { + TITLE: ['内核分论坛'], + ITEM_LIST: [ + { + TIME: '14:00 - 14:15', + THEME: '轻量级内存异常检测工具— KFence', + SPEAKER: ['刘云 麒麟软件'], + DESC: ['KFENCE,克服了KASAN等工具需要占用大量内存且影响运行时性能的缺点,是一个有效地运行时内存访问错误检测工具。'] + }, + { + TIME: '14:15-14:30', + THEME: 'User Interrupts - 用户中断', + SPEAKER: ['孙运营 Intel'], + DESC: ['用户中断,是一种可以直接向用户空间发送中断的新的硬件特性。如今,几乎所有跨越权限边界的通信都是通过内核进行的,而用户中断提供了一种可以避免通过内核的通信方式,可以在提供低延迟通信的同时降低CPU使用率。'] + }, + { + TIME: '14:30-14:45', + THEME: '工程实践分享 | 企业级 Linux 内核维护', + SPEAKER: ['江国庆 SUSE'], + DESC: ['企业发行版的 Linux 内核维护是一个非常大的长期挑战。在整个产品生命周期内,技术团队可能会需要移植数万个代码补丁来确保高质量的内核运作。因此,如何高效的移植、管理和维护补丁,解决它们之间的冲突,是工程师们关心的技术难题。本次演讲中,SUSE 资深内核技术专家江国庆将介绍 SUSE 企业级内核是如何从开源内核演进而来,以及 SUSE 是如何采用相关工具对内核补丁进行维护,并以 SUSE Euler 内核为例来展示相关的工程实践。'] + }, + { + // TIME: '14:45-15:00', + // THEME: '使用 Arm SVE 向量指令为高性能计算库加速', + // SPEAKER: ['徐国栋 Linaro Ltd.'], + // DESC: ['面向高性能计算(HPC)领域,Arm 推出了 SVE (Scalable Vector Extenstion),至今演进有 SVE2, SME (armv9)。本演讲介绍SVE 演进,工具链支持,软件适配状况。最后结合在ISA-L, XXHash 的编码,讲解SVE的优势,同时介绍开发技术要点。'] + }, + { + TIME: '15:00-15:15', + THEME: '可编程内核调度框架', + SPEAKER: ['陈辉 华为'], + DESC: ['不同领域的业务模型不同,对性能的需求(时延、吞吐、功耗)不同,所需的调度策略也不同。业界存在很多优秀的调度策略,这些调度策略针对某一类场景而设计,难以多场景共享;目前ebpf技术兴起,可编程调度框架,基于ebpf技术打造一套调度框架,致力于让开发人员简单、高效的定制调度策略,降低验证和部署成本。'] + }, + ] + }, + { + TITLE: ['多样性计算分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'Accelerating openEuler ecosystem with heterogeneous computing', + SPEAKER: ['田俊 Intel'], + DESC: ["Based on Intel's recently technologies of heterogeneous connection standards, new hardware accelerators, new platforms and software frameworks to support various different platforms, this presentation will discuss the industry's direction of data center centralized heterogeneous computing and the technologies to enable the openEuler OS framework to support heterogeneous ecosystems."] + }, + { + TIME: '14:15-14:30', + THEME: '多样性算力的未来与当前产业责任', + SPEAKER: ['姚嘉伟 普华基础软件'], + DESC: ['根植于多架构平台的同源操作系统,在提供标准化底层模块的前提下,不断演进优化多样性的系统架构平台与产业生态,进一步完善一致性的评测工具与指标体系,深入筑牢多样性算力服务体系基础平台,为下一代信息化变革赋予新动能。'] + }, + { + TIME: '14:30-14:45', + THEME: 'openEuler 在RISC-V的生态建设和展望', + SPEAKER: ['吴伟 中科院软件所'], + DESC: ['介绍软件所在openEuler RISC-V 所做的软件包移植,维护,构建和在RISC-V 国际基金会的相关工作,以及展望。'] + }, + ] + }, + { + TITLE: ['云原生&虚拟化分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '虚拟化场景下内存故障处理优化和实践', + SPEAKER: ['罗飞 紫光云'], + DESC: ['介绍紫光云和新华三集团在使用open Euler实现虚拟化场景下内存优化的工作实践'] + }, + { + TIME: '14:15-14:30', + THEME: '鲲鹏加速器虚拟化热迁移', + SPEAKER: ['刘龙芳 华为'], + DESC: ['1. 社区虚拟化热迁移的协议与近期热点', '2. 鲲鹏加速器的支持热迁移的硬件方案', '3. 鲲鹏加速器的热迁移的软件方案'] + }, + { + TIME: '14:30-14:45', + THEME: 'Capsule - 高安全 & 全场景的下一代Hypervisor', + SPEAKER: ['张波,野震宇 华为'], + DESC: ['虚拟化通过复用与共享硬件资源来达到节省成本与使用灵活的目的,但同时牺牲了部分安全与性能。为达成更高安全与性能。华为欧拉虚拟化在stratovirt替代qemu的同时,capsule.替代kvm,均基于rust语言,杜绝绝大多数内存漏洞,同时capsule支持分区能力,快速部署全隔离虚拟机,达到接近物理机的时延与抖动,满足确定性诉求。'] + }, + { + TIME: '14:45-15:00', + THEME: '以openEuler为基础构建高性能同源异构一云多芯云平台', + SPEAKER: ['王江涛 普华基础软件'], + DESC: ['以基础软件厂商为视角介绍国产架构服务器的引入为行业领域信息化建设带来的冲击,介绍如何使用NUMA、RDM、SR-IOV技术减少宿主机资源开销,接近裸机部署效果。通过基于openEuler申威版、ARM版、X86版构建的异构虚拟化成功案例'] + }, + { + TIME: '15:00-15:15', + THEME: '欧拉生态蓬勃发展,NestOS扬帆起航', + SPEAKER: ['王悦良 麒麟软件'], + DESC: ['基于openEuler生态的云底座操作系统NestOS正式发布,本议题将分享其主要特性针对性解决支撑云上业务时常见的各类痛点,openEuler sig-OKD基于NestOS对其具体应用场景进行的探索,同时也将分享NestOS未来发展规划以及如何与openEuler生态进行组合创新,共同激发openEuler社区创新活力。'] + }, + ] + }, + { + TITLE: ['边缘&嵌入式分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '在openEuler Embedded上进行多OS混合部署', + SPEAKER: ['任慰 华为'], + DESC: ['现在随着硬件技术的快速发展,片上系统的集成度越来越高,同时集成多核、异构多核已经很常见,这就带了在软件上同时部署多个OS的需求。openEuler Embedded的混合部署框架就是为了解决这一问题而推出的,目的是通过一套框架实现Linux和其他OS的便捷地混合部署,依托硬件上的多核能力使得Linux和实时操作系统有效互补,从而达到全系统兼具Linux的富生态和实时操作系统的高实时。'] + }, + { + TIME: '14:15-14:30', + THEME: '基于OpenEuler在嵌入式和实时性方面的思考与实践', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['介绍基于OpenEuler的GearOS系统现状,分享Xenomai编程经验', '介绍基于openEuler的Preempt_RT现状及使用方法,分享Preempt_RT相关技术经验'] + }, + { + TIME: '14:30-14:45', + THEME: '基于openEuler的EdgeX设备接入与控制', + SPEAKER: ['贺朝阳 中科创达'], + DESC: ['详细介绍基于openEuler运行EdgeX的过程;以ESP32芯片为例,结合EdgeX的架构,介绍南桥设备利用蓝牙、AP、mDNS、MQTT等技术自动接入openEuler上的EdgeX,继而以实际落地方案为例,介绍设备接入后利用EdgeX的Rules Engine和API等进行边缘侧和云端控制。'] + }, + { + TIME: '14:45-15:00', + THEME: 'openEuler Embedded基于yocto的演进', + SPEAKER: ['李思敏 华为'], + DESC: ['1. openEuler Embedded 的总体架构;', '2. openEuler Embedded 的开发实践;', '3. openEuler Embedded 的未来演进。'] + }, + { + TIME: '15:00-15:15', + THEME: 'openEuler上支持分布式软总线的进展与展望', + SPEAKER: ['谢焜勋 华为'], + DESC: ['介绍在openEuler嵌入式版本上,对openHarmony分布式软总线进行移植和支持的工作进展和下一步计划。'] + }, + { + TIME: '15:15-15:30', + THEME: 'Zephyr RTOS进展及中国社区推广', + SPEAKER: ['王洪波 Intel'], + DESC: ['Zephyr是在Linux基金会下开源的实时操作系统,它旨在成为这个物联网时代里,专门用于资源受限的中小型设备上最好的开源软件平台,同时强调安全设计。除了介绍Zephyr这个项目,重点会介绍一下最新的开发进展,以及新成立的SIG-Zephyr如何帮助进行中国社区的推广和应用。'] + }, + ] + }, + ] + }, + SCHEDULE_AFTERNOON_LAST: { + TIME_LIST: ['下半场', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30', '15:30 - 15:45', '15:45 - 16:00', '16:00 - 16:15', '16:15 - 16:30', '16:30 - 16:45', '16:45 - 17:00', '17:00 - 17:15'], + CARD_LIST: [ + { + TITLE: ['大数据存储分论坛'], + ITEM_LIST: [ + {}, + {}, + { + TIME: '15:15-15:30', + THEME: '缓存策略对CEPH性能的影响', + SPEAKER: ['池信泽 XSKY'], + DESC: ['主要是介绍CEPH RADOS架构下各级缓存策略对性能的影响'] + }, + { + TIME: '15:30-15:45', + THEME: '基于UADK加速器提升Ceph与大数据应用性能', + SPEAKER: ['戴志威 华为'], + DESC: ['数据存储中的加密、压缩对CPU算力提出了更高的要求。UADK是鲲鹏CPU上基于SVA的用户态加速开发套件,支持加密、压缩的计算加速和卸载。介绍Ceph数据体系和压缩特性,以及UADK在Ceph和大数据应用上的适配进展,性能表现。'] + }, + { + TIME: '15:45-16:00', + THEME: 'Arm SVE 向量指令为⾼性能计算库加速', + SPEAKER: ['徐国栋,庄浩坚 Linaro'], + DESC: ['⾯向⾼性能计算( HPC )领域, Arm 推出了 SVE ( Scalable Vector Extenstion ),⾄今演进有 SVE2 ,SME (armv9)。本演讲介绍 SVE 演进,⼯具链⽀持,软件适配状况。最后结合在 ISA-L , XXHash 的编码,讲解SVE 的优势,同时介绍开发技术要点。'] + }, + { + TIME: '16:00-16:15', + THEME: 'Spark SQL引擎Native Codegen', + SPEAKER: ['陈强 华为'], + DESC: ['采用SparkSQL Native Codegen框架,重新实现Spark SQL执行层,基于列式内存布局实现向量化,使用LLVM动态优化生成代码提升Spark SQL的性能'] + }, + { + TIME: '16:15-16:30', + THEME: 'Arm64开源HPC文件系统状态与进展', + SPEAKER: ['刘新良 Linaro'], + DESC: ['当前主流开源HPC文件系统Lustre和BeeGFS在Arm64平台上的状态与进展。例如使能过程中碰到的困难和问题,bugfix,CI搭建,性能测试与调优等相关工作进展,以及后续工作计划。'] + }, + { + TIME: '16:30-16:45', + THEME: 'AiLPHA大数据智能安全平台基于鲲鹏Validated的金融解决方案', + SPEAKER: ['童嘉伟 安恒信息'], + DESC: ['针对金融行业日益复杂网络安全形势,安恒信息与华为鲲鹏携手共赢,在产品适配层面达成高度合作,AiLPHA大数据智能安全平台采用业界领先的大数据分析技术架构,以“数据驱动安全分析,构建智能自适应安全运营中心”为产品理念,为金融用户提供全局安全态势感知能力、为金融业务不间断稳定运行提供安全保障,为金融用户提供信息系统安全决策支撑,为金融用户提供一套完整的安全解决方案,助力安全中国,助推数字经济。'] + }, + { + TIME: '16:45-17:00', + THEME: '大数据+Ceph存算分离、算子下推提升计算存储效率', + SPEAKER: ['吴启庆 华为'], + DESC: ['大数据+Ceph采用数据直通和算子下推方案,实现存算分离,提升计算存储效率,性能和存储率优于HDFS存储,成为数据湖实现的解决方案之一。'] + }, + ] + }, + { + TITLE: ['开源雨林分论坛'], + ITEM_LIST: [ + { + TIME: '14:45-15:00', + THEME: '开源雨林赋能企业开源', + SPEAKER: ['马全一 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '安全合规在openEuler上的实践', + SPEAKER: ['高琨 华为'], + DESC: [''] + }, + { + TIME: '15:30-16:00', + THEME: '开源雨林赋能课程介绍', + SPEAKER: ['李自 华为'], + DESC: [''] + }, + ] + }, + { + TITLE: ['安全分论坛'], + ITEM_LIST: [ + {}, + { + TIME: '15:00-15:15', + THEME: '开源社区安全成熟度模型及实践', + SPEAKER: ['徐海云 Software Improvement Group'], + DESC: ['与常规软件开发相比,开源社区的开发模式有着自己的独特性。度量open欧拉的安全性需要结合开源社区软件开发以及基于Linux的操作系统开发维护的特性,建立适用于open欧拉社区的安全成熟度模型。演讲者将介绍针对开源社区制定的安全成熟度模型,并分享近期的模型应用实践与经验。'] + }, + { + TIME: '15:15-15:30', + THEME: '畅谈Intel SGX 原理及应用场景探索', + SPEAKER: ['杜凡 Intel'], + DESC: ['在用户数据隐私日益重要的今天,如何保证用户数据在使用过程中的机密性和完整性成为一项重要又有挑战的问题。Intel SGX 技术致力于提供应用程序层面的细粒度的硬件TEE功能,为保护云上用户数据提供强有力的支持。该主题抛砖引玉,讲解机密计算领域中SGX技术原理,以及相应的应用场景探索。'] + }, + { + TIME: '15:30-15:45', + THEME: ' 机密计算应用实践', + SPEAKER: ['顾嘉辉 华为'], + DESC: ['数据作为关键生产要素背景下,数据安全成为业务合规和数据资产价值发挥的关键技术。secGear作为机密计算开发框架,使能多种硬件机密计算能力,支撑多种上层应用。本议题介绍secGear的技术特点,以及在数据库、AI等领域的应用实践探索。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于SBOM的开源软件供应链安全解决方案', + SPEAKER: ['刘波 华为'], + DESC: ['1、行业背景:软件产品的“不透明”传递性依赖层次深,导致整个软件供应链的网络安全治理难度越来越大;', '2、SBOM能做什么:基于行业标准透明的数据底座、结合软件成分分析、漏洞管理等集成,实现漏洞分钟级感知、排查与修复', '3、SBOM格式洞察分析:CycloneDX、SPDX、SWID', '4、SBOM解决方案整体设计:从SBOM数据采集与存储、到License、Copyright、漏洞感知消费、到开源合规履行义务报告生成', '5、OpenEuler 关键问题: 部分高阶语言包管理传递性依赖未识别', '6 、OpenEuler SBOM落地方案与计划'] + }, + { + TIME: '16:00-16:15', + THEME: ' 基于openEuler的安全加固定制方案和实践', + SPEAKER: ['唐杰 麒麟信安'], + DESC: ['操作系统安全性和易用性是个矛盾体,为了增加系统安全性,openEuler和OSV商业版本都做了相应的安全增强,如强制访问控制、完整性控制、多因子验证、关键系统部件加固等,但增加了管理员和用户的维护难度,因此设计了一套系统安全加固方案来满足易操作、高效率和可定制的问题。管理员可以使用图形工具一键完成一系列加固功能。方案采用了并发的方式提高加固执行的效率,并可根据用户需要快速重新定制加固方案。另外,使用非对称加密技术来避免加固方案被篡改,保障加固方案的权威性。'] + }, + { + TIME: '16:15-16:30', + THEME: ' 操作系统安全漏洞及早感知和快速响应', + SPEAKER: ['曹文渊 统信软件'], + DESC: ['在安全风险持续增长的今天,针对不同的操作系统,如何去感知互联网上层出不穷的各种漏洞、如何去判断这些漏洞是否影响我们的操作系统,从而更好的保护我们的操作系统免受攻击,已经成为了安全工作中的重要一环。'] + }, + ] + }, + { + TITLE: ['Devkit 工具集分论坛'], + ITEM_LIST: [ + {}, + {}, + {}, + { + TIME: '15:30-15:45', + THEME: 'openEuler商业版自动化测试工具', + SPEAKER: ['刘佐 麒麟信安'], + DESC: ['LTF是一款使用Shell编写的轻量级自动化测试框架,该工具目前主要应用openEuler商业版本以及第三方测试中。目前开源的测试用例涵盖了:性能测试、命令测试、开发环境测试、文件系统测试、GJB命令测试、语言测试等。框架提供的API让我们可以方便、快捷的编写测试脚本。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于鲲鹏Devkit的HPC迁移调优实践', + SPEAKER: ['李成鹏 软通动力'], + DESC: ['软通动力作为华为ITS领域战略合作伙伴,积极拥抱鲲鹏生态战略,并在多个领域取得阶段进展,自2021年加入鲲鹏众智计划以来累计成功交付加速库、HPC迁移调优等多个领域的项目,本次分享主要是给伙伴介绍我们通过使用鲲鹏Devkit工具集完成HPC开源组件从X86平台到鲲鹏+openEuler平台的迁移调优实践,Devkit迁移调优工具助力我们高效完成软件迁移并且软件性能提升明显。'] + }, + { + TIME: '16:00-16:15', + THEME: '应对CentOS停服,UYi(有易)数字化转型方案', + SPEAKER: ['薛智鑫 统信软件'], + DESC: ['UYi(有易)是一款服务器系统迁移软件, 帮助用户从CentOS系列平台平滑迁移到统信服务器操作系统V20,在保证新的操作系统正常稳定运行的同时,也要保证业务在其上的正常运行。'] + }, + { + TIME: '16:15-16:30', + THEME: 'PilotGo运维管理平台介绍', + SPEAKER: ['杨昭 麒麟软件'], + DESC: ['PilotGo运维管理平台在社区孵化已有一段时间,即将发布1.0版本,本次会介绍PilotGo软件的基本情况。'] + }, + { + TIME: '16:30-16:45', + THEME: 'openEuler兼容性评估工具介绍', + SPEAKER: ['王执 华为'], + DESC: ['介绍OS迁移中,对软件,硬件,配置兼容性评估功能介绍'] + }, + { + TIME: '16:45-17:00', + THEME: '操作系统之间的差异比较及兼容性分析工具', + SPEAKER: ['朱泽旭 华为'], + DESC: ['OECP工具主要有以下2个功能:', '1.检测2个ISO(基于RPM)的软件包,软件包内文件,库文件接口(C/C++),内核KABI的变化差异,根据这些差异可以分析2个OS之间的兼容性,为软件移植提供了重要参考' + , '2.OECP还可以检测同一个软件(RPM包)在不同版本下的变化以及差异,判断软件包的文件,接口等变化,可以分析得出软件不同版本之间的兼容性'] + }, + { + TIME: '17:00-17:15', + THEME: 'openEuler构建及镜像裁剪工具介绍', + SPEAKER: ['朱春意 华为'], + DESC: ['openEuler iso构建、iso裁剪、镜像的文件级裁剪工具介绍'] + }, + ] + }, + ] + }, + } + }, + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + HOST: { + TEXT_TITLE: "主办方", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + UNION: { + TEXT_TITLE: "联办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/intel.png", + LINK: "" + }, + ] + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/fusion.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/yunhe.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/liguangnan.png', + NAME: '倪光南', + POSITION: ['中国工程院院士'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/sunwenlong.png', + NAME: '孙文龙', + POSITION: ['开放原子开源基金会秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: ['openEuler社区理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hannaiping.png', + NAME: '韩乃平', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: ['openEuler社区', '技术委员会主席'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/qiuchenfen.png', + NAME: '邱成锋', + POSITION: ['openEuler社区秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guangxiaoming.png', + NAME: '广小明', + POSITION: ['天翼云科技有限公司', '副总经理兼首席技术官'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/likang.png', + NAME: '李康', + POSITION: ['中国移动', '在线营销服务中心副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhongxing.png', + NAME: '钟忻', + POSITION: ['联通云CTO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhouhaipeng.png', + NAME: '周海鹏', + POSITION: ['中信IT资深架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liukai.png', + NAME: '刘凯', + POSITION: ['上交所技术公司', '下一代交易研发部副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiongwei.png', + NAME: '熊伟', + POSITION: ['openEuler社区', '技术委员会委员'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/caowenyuan.png', + NAME: '曹文渊', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenhui.png', + NAME: '陈辉', + POSITION: ['华为调度架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenqiang.png', + NAME: '陈强', + POSITION: ['华为大数据技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chixinze.png', + NAME: '池信泽', + POSITION: ['ceph-sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/daizhiwei.png', + NAME: '戴志威', + POSITION: ['华为存储技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/dufan.png', + NAME: '杜凡', + POSITION: ['Intel Cloud Architect'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gaokun.png', + NAME: '高琨', + POSITION: ['华为工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gujiahui.png', + NAME: '顾嘉辉', + POSITION: ['华为基础软件', '安全技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guohao.png', + NAME: '郭皓', + POSITION: ['麒麟软件内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hechaoyang.png', + NAME: '贺朝阳', + POSITION: ['中科创达', '创达边缘计算工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangguoqing.png', + NAME: '江国庆', + POSITION: ['SUSE资深内核技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lichengpeng.png', + NAME: '李成鹏', + POSITION: ['软通鲲鹏生态技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lisiming.png', + NAME: '李思敏', + POSITION: ['华为技术有限公司工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lizi.png', + NAME: '李自', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liubo.png', + NAME: '刘波', + POSITION: ['华为开源社区', '工具链总架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liulongfang.png', + NAME: '刘龙芳', + POSITION: [' 华为内核技术工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuxinliang.png', + NAME: '刘新良', + POSITION: [' Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuyun.png', + NAME: '刘云', + POSITION: ['麒麟软件资深内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuzuo.png', + NAME: '刘佐', + POSITION: ['麒麟信安测试工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/luofei.png', + NAME: '罗飞', + POSITION: ['虚拟化资深工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/maquanyi.png', + NAME: '马全一', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/renwei.png', + NAME: '任慰', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tangjie.png', + NAME: '唐杰', + POSITION: ['麒麟信安', '操作系统组件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tianjun.png', + NAME: '田俊', + POSITION: ['Intel Arch SIG负责人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tongjiawei.png', + NAME: '童嘉伟', + POSITION: ['安恒信息', '大数据信创产品总监'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wanghongbo.png', + NAME: '王洪波', + POSITION: ['英特尔亚太研发有限公司', '软件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangjiangtao.png', + NAME: '王江涛', + POSITION: ['普华基础软件', '资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangyueliang.png', + NAME: '王悦良', + POSITION: ['麒麟软件开源工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangzhi.png', + NAME: '王执', + POSITION: ['华为欧拉Devkit', '系统工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuqiqing.png', + NAME: '吴启庆', + POSITION: ['华为存储系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuwei.png', + NAME: '吴伟', + POSITION: ['中科院软件所', 'PLCT实验室创始人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuguodong.png', + NAME: '徐国栋', + POSITION: ['Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuhaiyun.png', + NAME: '徐海云', + POSITION: ['SIG CSO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuzhixing.png', + NAME: '薛智鑫', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangzhao.png', + NAME: '杨昭', + POSITION: ['麒麟软件高级软件工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yaojiawei.png', + NAME: '姚嘉伟', + POSITION: ['普华基础软件', '资深系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yezhenyu.png', + NAME: '野震宇', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhangbo.png', + NAME: '张波', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuchunyi.png', + NAME: '朱春意', + POSITION: ['OS-Builder、BaseService', 'sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuzexu.png', + NAME: '朱泽旭', + POSITION: [' openEuler兼容性工具', '开发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhuanghaojian.png', + NAME: '庄浩坚', + POSITION: ['Linaro资深技术专家'] + }, + ], + GUEST_LIST: [ + + ], + PUBLISHER_BANNER: { + web: '/img/summit/devday-2022/lecturer/publishertitle.png', + mobile: '/img/summit/devday-2022/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/devday-2022/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + FOOTER: [ + { SUMMIT: 'openEuler Summit 2021', LINK: '/interaction/summit-list/summit2021/' }, + { SUMMIT: 'openEuler Developer Day 2021', LINK: '/interaction/summit-list/devday2021/' }, + { SUMMIT: 'openEuler Summit 2020', LINK: '/interaction/summit-list/' }, + { SUMMIT: 'openEuler Virtual Summit 2020', LINK: '/interaction/summit-list/list/' }, + ] + }, + en: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_mo.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_pc.png", + LINK: "https://e-campaign.huawei.com/m/uMNFji" + }, + COLLECT_LIST: [{ + IMG: "/img/summit/devday-2022/CALLFORSPEAKER.png", + LINK: "https://shimo.im/forms/7DO3Fg79JSAfaflt/fill" + }, + { + IMG: "/img/summit/devday-2022/SIG1.png", + LINK: "https://shimo.im/forms/o0SfA0pfVmMlXEfi/fill" + }, + { + IMG: "/img/summit/devday-2022/CALLFORSPENSOR.png", + LINK: "https://shimo.im/forms/sspw0eU78rE9ra79/fill" + }, + ], + NAV_LIST: [ + { + key: '#liveroom', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#construction-unit', + name: '共建单位' + } + ], + LIVEDATA: { + RENDERDATA: [ + { + ID: 10392, + THEME: 'openEuler Developer Day 2022', + OPTION: 'openEuler Developer Day 2022', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10392?lang=zh&thirdId=' + }, + { + ID: 10393, + THEME: '内核', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 内核', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10393?lang=zh&thirdId=' + }, + { + ID: 10399, + THEME: '多样性计算', + TIME: '14:00-14:45', + OPTION: '14:00-14:45 多样性计算', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10399?lang=zh&thirdId=' + }, + { + ID: 10394, + THEME: '云原生&虚拟化', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 云原生&虚拟化', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10394?lang=zh&thirdId=' + }, + { + ID: 10398, + THEME: '边缘&嵌入式', + TIME: '14:00-15:30', + OPTION: '14:00-15:30 边缘&嵌入式', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10398?lang=zh&thirdId=' + }, + { + ID: 10400, + THEME: '大数据存储', + TIME: '15:15-17:00', + OPTION: '15:15-17:00 大数据存储', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10400?lang=zh&thirdId=' + }, + { + ID: 10397, + THEME: '开源雨林', + TIME: '14:45-16:00', + OPTION: '14:45-16:00 开源雨林', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10397?lang=zh&thirdId=' + }, + { + ID: 10395, + THEME: '安全分论坛', + TIME: '15:00-16:30', + OPTION: '15:00-16:30 安全', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10395?lang=zh&thirdId=' + }, + { + ID: 10396, + THEME: 'Devkit 工具集', + TIME: '15:30-17:15', + OPTION: '15:30-17:15 Devkit 工具集', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10396?lang=zh&thirdId=' + }, + ], + LIVETITLE: "openEuler Developer Day 2022直播间" + }, + SUMMIT_INTRODUCE: "openEuler Developer Day 2022 (简称 ODD 2022)是开放原子开源基金会的 openEuler 社区发起的开发者大会。旨在推动 openEuler 在服务器、云计算、边缘计算和嵌入式四大场景的技术探索和创新。本次 ODD 2022 正式发布 openEuler 22.03 全场景长周期版本,展示社区伙伴联合创新成果,分享多行业使用 openEuler 规模部署的商业案例,举办社区治理机构的线上工作会议。openEuler 始终与开发者在一起,开创新境,共创未来。", + AGENDA: { + CONFERENCE_LINK: "会议链接", + TITLE_IMG_PC: "/img/summit/devday-2022/zh-pc-devday2022.png", + TITLE_IMG_MO: "/img/summit/devday-2022/zh-mobile-devday2022.png", + AGENDA_DATA_TITLE: ['13', '14', '15'], + AGENDA_DATA_13: { + TITLE: "4月13日", + SCHEDULE: [ + { TIME: '16:00 - 17:30', SCHEDULE_LIST: ['用户委员会工作会议', '技术委员会工作会议', '品牌委员会工作会议', '理事会工作会议'] }, + { TIME: '15:30 - 17:30', SCHEDULE_LIST: ['用户圆桌'] } + ] + }, + AGENDA_DATA_14: { + MO_TITLE: "SIG 组开放工作会议", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + }, { + ZH: '晚上', + EN: 'night' + }], + TITLE: ['09:00 - 10:00', '10:00 - 11:00', '11:00 - 12:00'], + TITLE_AFTERNOON: ['14:00 - 15:00', '15:00 - 16:00', '16:00 - 17:00', '17:00 - 18:00'], + TITLE_NIGHT: ['19:00 - 20:00', '20:00 - 21:00'], + RIGHT_TEXT: ['回看', '笔记'], + SCHEDULE: [ + { + TITLE: { + ZH: "高校", + EN: "Education" + }, + SCHEDULE_CARD: [{ + TEXT: "高校开发者专场 sig-OSCourse", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1V3411T7Rq?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OSCourse-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "OpenStack DPU", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1SY4y1h7cM?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-openstack-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Industrial-Control", + TIME: "09:00 - 10:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1uZ4y1m7rz?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Industrial-Control-22.09-planning" + }, { + TEXT: "sig-AccLib", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1v44y137ZH?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/openEuler2209-sig-AccLib-ODD" + }, { + TEXT: "sig-Embedded Yocto", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1K94y1o7WL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-embedded-22.09-planning" + }] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-AI-BigData", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1X44y137XX?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-AI-BigData-22.09-planning" + }, { + TEXT: "sig-OPS", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dZ4y127Ux?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OPS-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-ceph", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1y94y1d7Gj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Ceph-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "Infrastructure sig-Gatekeeper", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1kF411g7TJ?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Infrastructure-22.09-planning" + }, { + TEXT: "sig-OS-Builder", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV12T4y1h7dB?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OS-Builder-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "Release", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1bF411g7Lk?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-release-22.09-planning" + }, { + TEXT: "Compiler", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dY4y1e76P?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compiler-22.09-planning" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-UKUI", + TIME: "9:00 - 09:30", + ZOOM_LINK: "https://www.bilibili.com/video/BV1N94y1o7cx?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-UKUI-planning" + }, { + TEXT: "sig-CICD", + TIME: "09:30 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1t34y1v7Lo?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CICD-planning" + }, { + TEXT: "Application System-tools", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1U94y1d743?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-application-systemtools-planning" + }] + }, + ], + SCHEDULE_AFTERNOON: [ + { + TITLE: { + ZH: "内核", + EN: "Kernel" + }, + SCHEDULE_CARD: [{ + TEXT: "Kernel", + TIME: "14:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1wL4y1L7T3?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-kernel-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-CloudNative iSula、golang", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1TB4y1U7ba?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CloudNative-22.09-planning" + }, { + TEXT: "Virt ovirt", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1fS4y1w72V?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Virt-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Intel-Arch", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV14F411g7oj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/intel-arch-sig-odd" + }, { + TEXT: "sig-sw-arch", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1aB4y1U7Kp?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-sw-arch-planning" + }, { + TEXT: "sig-ROS", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1cu411y7oS?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-ROS-22.09-planning" + } + ] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-HPC", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ku411C7ya?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-hpc-22.09-planning" + }, { + TEXT: "DB", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1EZ4y1m72F?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-DB-22.09-planning" + }, { + TEXT: "A-Tune", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1YS4y1Y7YE?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-A-Tune-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Networking", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ET4y1e7qe?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/Networking-plan-3.30" + }, + { + TEXT: "sig-Edge", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1q5411273v?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Edge-22.09-planning" + }, { + TEXT: "sig-high-performance-network", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1o44y1V7ao?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-high-performance-networking-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-security-facility security-committee", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1C34y1v7Zr?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-security-facility_and_sc-22.09-planning" + }, { + TEXT: "sig-Compatibility-Infra devkit", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV19u411C7fL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compatibility-Infra" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-QA GNOME", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1HZ4y1m71Q?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-QA-22.09-planning" + }, + { + TEXT: "sig HA", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Nr4y1H7N5?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-HA-22.09-planning" + }, { + TEXT: "sig-reproducible-builds", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1qi4y1U79W?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-reproducible-builds-22.09-planning" + }, { + TEXT: "sig-compliance", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY4y1e7T6?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-compliance-22.09-planing" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OpenDesign", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1s3411n75L?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OpenDesign-22.09-planning" + }, { + TEXT: "Doc G11N", + TIME: "15:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ua411v7Vy?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Doc-G11N-planning" + }, { + TEXT: "sig-Migration", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oT4y1Y7ep?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Migration-planning" + }] + }, + ], + SCHEDULE_NIGHT: [ + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OKD", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1RB4y1m79Z?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OKD-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Storage", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Gr4y1H7Mv?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Storage-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Java", + TIME: "19:00 - 20:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY411j7PY?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Java-22.09-planning" + }] + }, + ], + COLUMN_TITLE: [ + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "高校", + EN: "Education" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "内核", + EN: "Kernel" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "工具", + EN: "Tooling" + }, + ] + }, + ] + }, + AGENDA_DATA_15: { + TITLE: "4月15日 周五(线上直播)", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + },], + SCHEDULE: [ + { + TIME: "10:00 - 10:03", + TEXT: "开幕致辞", + SPEAKER: [ + { + NAME: '孙文龙', + POSITION: '开放原子开源基金会秘书长', + } + ] + }, + { + TIME: "10:03 - 10:06", + TEXT: "院士致辞", + SPEAKER: [ + { + NAME: '倪光南', + POSITION: '中国工程院院士', + } + ] + }, + { + TIME: "10:06 - 10:15", + TEXT: "一起创未来 欧拉更精彩", + SPEAKER: [ + { + NAME: '江大勇', + POSITION: 'openEuler社区理事长', + } + ] + }, + { + TIME: "10:15 - 10:30", + TEXT: "openEuler 22.03 LTS:新征程,再出发", + SPEAKER: [ + { + NAME: '胡欣蔚', + POSITION: 'openEuler社区技术委员会主席', + } + ] + }, + { + TIME: "10:30 - 10:34", + TEXT: "openEuler商业发行版发布计划及欧拉技术认证颁发仪式", + SPEAKER: [ + { + NAME: '邱成锋', + POSITION: 'openEuler社区秘书长', + } + ] + }, + { + TIME: "10:34 - 10:42", + TEXT: "携手openEuler ,共筑天翼云数字底座 ", + SPEAKER: [ + { + NAME: '广小明', + POSITION: '天翼云科技有限公司 副总经理 兼首席技术官' + } + ] + }, + { + TIME: "10:42 - 10:50", + TEXT: "基于openEuler全栈创新,赋能数智新在线", + SPEAKER: [ + { + NAME: '李康', + POSITION: '中国移动在线营销服务中心副总经理', + } + ] + }, + { + TIME: "10:50 - 10:58", + TEXT: "openEuler+CULinux 打造联通云新一代基础设施", + SPEAKER: [ + { + NAME: '钟忻', + POSITION: '联通云CTO', + } + ] + }, + { + TIME: "10:58 - 11:06", + TEXT: "云原生时代中信银行开源技术实践", + SPEAKER: [ + { + NAME: '周海鹏 ', + POSITION: '中信IT资深架构师', + } + ] + }, + { + TIME: "11:06 - 11:14", + TEXT: "数字赋能 守正创新 - 上交所技术基于欧拉的原生应用实践", + SPEAKER: [ + { + NAME: '刘凯', + POSITION: '上交所技术公司下一代交易研发部副总经理', + } + ] + }, + { + TIME: "11:14 - 11:32", + TEXT: "圆桌会议:如何构建支持多样性计算的OS生态", + SPEAKER: [ + { + NAME: '武延军', + POSITION: 'openEuler社区副理事长', + }, + { + NAME: '堵俊平', + POSITION: '华为计算开源总经理', + }, + { + NAME: '杨继国', + POSITION: 'Intel开源技术中心总监', + }, + { + NAME: '李铭', + POSITION: '英伟达亚太区生态伙伴发展总监', + }, + { + NAME: '唐丹', + POSITION: '北京开源芯片研究院副院长', + }, + { + NAME: '姜振华', + POSITION: '超聚变操作系统业务总经理', + }, + { + NAME: '焦旭坡', + POSITION: '新华三集团操作系统开发部部长', + }, + ] + }, + { + TIME: "11:32 - 11:50", + TEXT: "圆桌会议:凡是未来 皆有可期-社区运作版本规划", + SPEAKER: [ + { + NAME: '熊伟', + POSITION: 'openEuler社区技术委员会委员', + }, + { + NAME: '谢秀奇', + POSITION: 'Kernel', + }, + { + NAME: '席静', + POSITION: 'sig-RISC-V', + }, + { + NAME: '田俊', + POSITION: 'sig-Intel-Arch', + }, + { + NAME: '金小贤', + POSITION: 'sig-AI', + }, + { + NAME: '陈硕', + POSITION: 'sig-openstack', + }, + { + NAME: '曹志', + POSITION: 'Infrastructure', + }, + { + NAME: '马文', + POSITION: 'sig-embedded/sig-Yocto', + }, + ] + }, + { + TIME: "11:50 - 11:55", + TEXT: "展望致辞:欧拉社区志高远 开源汇智向未来", + SPEAKER: [ + { + NAME: '韩乃平', + POSITION: 'openEuler社区副理事长', + } + ] + }, + ], + HOST: ['主持人:', '嘉宾:'], + STICKY_TITLE: ['大数据存储分论坛', '开源雨林分论坛', '安全分论坛', 'Devkit 工具集分论坛'], + SCHEDULE_AFTERNOON: { + TIME_LIST: ['上半场', '14:00 - 14:15', '14:15 - 14:30', '14:30 - 14:45', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30'], + CARD_LIST: [ + { + TITLE: ['内核分论坛'], + ITEM_LIST: [ + { + TIME: '14:00 - 14:15', + THEME: '轻量级内存异常检测工具— KFence', + SPEAKER: ['刘云 麒麟软件'], + DESC: ['KFENCE,克服了KASAN等工具需要占用大量内存且影响运行时性能的缺点,是一个有效地运行时内存访问错误检测工具。'] + }, + { + TIME: '14:15-14:30', + THEME: 'User Interrupts - 用户中断', + SPEAKER: ['孙运营 Intel'], + DESC: ['用户中断,是一种可以直接向用户空间发送中断的新的硬件特性。如今,几乎所有跨越权限边界的通信都是通过内核进行的,而用户中断提供了一种可以避免通过内核的通信方式,可以在提供低延迟通信的同时降低CPU使用率。'] + }, + { + TIME: '14:30-14:45', + THEME: '工程实践分享 | 企业级 Linux 内核维护', + SPEAKER: ['江国庆 SUSE'], + DESC: ['企业发行版的 Linux 内核维护是一个非常大的长期挑战。在整个产品生命周期内,技术团队可能会需要移植数万个代码补丁来确保高质量的内核运作。因此,如何高效的移植、管理和维护补丁,解决它们之间的冲突,是工程师们关心的技术难题。本次演讲中,SUSE 资深内核技术专家江国庆将介绍 SUSE 企业级内核是如何从开源内核演进而来,以及 SUSE 是如何采用相关工具对内核补丁进行维护,并以 SUSE Euler 内核为例来展示相关的工程实践。'] + }, + { + // TIME: '14:45-15:00', + // THEME: '使用 Arm SVE 向量指令为高性能计算库加速', + // SPEAKER: ['徐国栋 Linaro Ltd.'], + // DESC: ['面向高性能计算(HPC)领域,Arm 推出了 SVE (Scalable Vector Extenstion),至今演进有 SVE2, SME (armv9)。本演讲介绍SVE 演进,工具链支持,软件适配状况。最后结合在ISA-L, XXHash 的编码,讲解SVE的优势,同时介绍开发技术要点。'] + }, + { + TIME: '15:00-15:15', + THEME: '可编程内核调度框架', + SPEAKER: ['陈辉 华为'], + DESC: ['不同领域的业务模型不同,对性能的需求(时延、吞吐、功耗)不同,所需的调度策略也不同。业界存在很多优秀的调度策略,这些调度策略针对某一类场景而设计,难以多场景共享;目前ebpf技术兴起,可编程调度框架,基于ebpf技术打造一套调度框架,致力于让开发人员简单、高效的定制调度策略,降低验证和部署成本。'] + }, + ] + }, + { + TITLE: ['多样性计算分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'Accelerating openEuler ecosystem with heterogeneous computing', + SPEAKER: ['田俊 Intel'], + DESC: ["Based on Intel's recently technologies of heterogeneous connection standards, new hardware accelerators, new platforms and software frameworks to support various different platforms, this presentation will discuss the industry's direction of data center centralized heterogeneous computing and the technologies to enable the openEuler OS framework to support heterogeneous ecosystems."] + }, + { + TIME: '14:15-14:30', + THEME: '多样性算力的未来与当前产业责任', + SPEAKER: ['姚嘉伟 普华基础软件'], + DESC: ['根植于多架构平台的同源操作系统,在提供标准化底层模块的前提下,不断演进优化多样性的系统架构平台与产业生态,进一步完善一致性的评测工具与指标体系,深入筑牢多样性算力服务体系基础平台,为下一代信息化变革赋予新动能。'] + }, + { + TIME: '14:30-14:45', + THEME: 'openEuler 在RISC-V的生态建设和展望', + SPEAKER: ['吴伟 中科院软件所'], + DESC: ['介绍软件所在openEuler RISC-V 所做的软件包移植,维护,构建和在RISC-V 国际基金会的相关工作,以及展望。'] + }, + ] + }, + { + TITLE: ['云原生&虚拟化分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '虚拟化场景下内存故障处理优化和实践', + SPEAKER: ['罗飞 紫光云'], + DESC: ['介绍紫光云和新华三集团在使用open Euler实现虚拟化场景下内存优化的工作实践'] + }, + { + TIME: '14:15-14:30', + THEME: '鲲鹏加速器虚拟化热迁移', + SPEAKER: ['刘龙芳 华为'], + DESC: ['1. 社区虚拟化热迁移的协议与近期热点', '2. 鲲鹏加速器的支持热迁移的硬件方案', '3. 鲲鹏加速器的热迁移的软件方案'] + }, + { + TIME: '14:30-14:45', + THEME: 'Capsule - 高安全 & 全场景的下一代Hypervisor', + SPEAKER: ['张波,野震宇 华为'], + DESC: ['虚拟化通过复用与共享硬件资源来达到节省成本与使用灵活的目的,但同时牺牲了部分安全与性能。为达成更高安全与性能。华为欧拉虚拟化在stratovirt替代qemu的同时,capsule.替代kvm,均基于rust语言,杜绝绝大多数内存漏洞,同时capsule支持分区能力,快速部署全隔离虚拟机,达到接近物理机的时延与抖动,满足确定性诉求。'] + }, + { + TIME: '14:45-15:00', + THEME: '以openEuler为基础构建高性能同源异构一云多芯云平台', + SPEAKER: ['王江涛 普华基础软件'], + DESC: ['以基础软件厂商为视角介绍国产架构服务器的引入为行业领域信息化建设带来的冲击,介绍如何使用NUMA、RDM、SR-IOV技术减少宿主机资源开销,接近裸机部署效果。通过基于openEuler申威版、ARM版、X86版构建的异构虚拟化成功案例'] + }, + { + TIME: '15:00-15:15', + THEME: '欧拉生态蓬勃发展,NestOS扬帆起航', + SPEAKER: ['王悦良 麒麟软件'], + DESC: ['基于openEuler生态的云底座操作系统NestOS正式发布,本议题将分享其主要特性针对性解决支撑云上业务时常见的各类痛点,openEuler sig-OKD基于NestOS对其具体应用场景进行的探索,同时也将分享NestOS未来发展规划以及如何与openEuler生态进行组合创新,共同激发openEuler社区创新活力。'] + }, + ] + }, + { + TITLE: ['边缘&嵌入式分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '在openEuler Embedded上进行多OS混合部署', + SPEAKER: ['任慰 华为'], + DESC: ['现在随着硬件技术的快速发展,片上系统的集成度越来越高,同时集成多核、异构多核已经很常见,这就带了在软件上同时部署多个OS的需求。openEuler Embedded的混合部署框架就是为了解决这一问题而推出的,目的是通过一套框架实现Linux和其他OS的便捷地混合部署,依托硬件上的多核能力使得Linux和实时操作系统有效互补,从而达到全系统兼具Linux的富生态和实时操作系统的高实时。'] + }, + { + TIME: '14:15-14:30', + THEME: '基于OpenEuler在嵌入式和实时性方面的思考与实践', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['介绍基于OpenEuler的GearOS系统现状,分享Xenomai编程经验', '介绍基于openEuler的Preempt_RT现状及使用方法,分享Preempt_RT相关技术经验'] + }, + { + TIME: '14:30-14:45', + THEME: '基于openEuler的EdgeX设备接入与控制', + SPEAKER: ['贺朝阳 中科创达'], + DESC: ['详细介绍基于openEuler运行EdgeX的过程;以ESP32芯片为例,结合EdgeX的架构,介绍南桥设备利用蓝牙、AP、mDNS、MQTT等技术自动接入openEuler上的EdgeX,继而以实际落地方案为例,介绍设备接入后利用EdgeX的Rules Engine和API等进行边缘侧和云端控制。'] + }, + { + TIME: '14:45-15:00', + THEME: 'openEuler Embedded基于yocto的演进', + SPEAKER: ['李思敏 华为'], + DESC: ['1. openEuler Embedded 的总体架构;', '2. openEuler Embedded 的开发实践;', '3. openEuler Embedded 的未来演进。'] + }, + { + TIME: '15:00-15:15', + THEME: 'openEuler上支持分布式软总线的进展与展望', + SPEAKER: ['谢焜勋 华为'], + DESC: ['介绍在openEuler嵌入式版本上,对openHarmony分布式软总线进行移植和支持的工作进展和下一步计划。'] + }, + { + TIME: '15:15-15:30', + THEME: 'Zephyr RTOS进展及中国社区推广', + SPEAKER: ['王洪波 Intel'], + DESC: ['Zephyr是在Linux基金会下开源的实时操作系统,它旨在成为这个物联网时代里,专门用于资源受限的中小型设备上最好的开源软件平台,同时强调安全设计。除了介绍Zephyr这个项目,重点会介绍一下最新的开发进展,以及新成立的SIG-Zephyr如何帮助进行中国社区的推广和应用。'] + }, + ] + }, + ] + }, + SCHEDULE_AFTERNOON_LAST: { + TIME_LIST: ['下半场', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30', '15:30 - 15:45', '15:45 - 16:00', '16:00 - 16:15', '16:15 - 16:30', '16:30 - 16:45', '16:45 - 17:00', '17:00 - 17:15'], + CARD_LIST: [ + { + TITLE: ['大数据存储分论坛'], + ITEM_LIST: [ + {}, + {}, + { + TIME: '15:15-15:30', + THEME: '缓存策略对CEPH性能的影响', + SPEAKER: ['池信泽 XSKY'], + DESC: ['主要是介绍CEPH RADOS架构下各级缓存策略对性能的影响'] + }, + { + TIME: '15:30-15:45', + THEME: '基于UADK加速器提升Ceph与大数据应用性能', + SPEAKER: ['戴志威 华为'], + DESC: ['数据存储中的加密、压缩对CPU算力提出了更高的要求。UADK是鲲鹏CPU上基于SVA的用户态加速开发套件,支持加密、压缩的计算加速和卸载。介绍Ceph数据体系和压缩特性,以及UADK在Ceph和大数据应用上的适配进展,性能表现。'] + }, + { + TIME: '15:45-16:00', + THEME: 'Arm SVE 向量指令为⾼性能计算库加速', + SPEAKER: ['徐国栋,庄浩坚 Linaro'], + DESC: ['⾯向⾼性能计算( HPC )领域, Arm 推出了 SVE ( Scalable Vector Extenstion ),⾄今演进有 SVE2 ,SME (armv9)。本演讲介绍 SVE 演进,⼯具链⽀持,软件适配状况。最后结合在 ISA-L , XXHash 的编码,讲解SVE 的优势,同时介绍开发技术要点。'] + }, + { + TIME: '16:00-16:15', + THEME: 'Spark SQL引擎Native Codegen', + SPEAKER: ['陈强 华为'], + DESC: ['采用SparkSQL Native Codegen框架,重新实现Spark SQL执行层,基于列式内存布局实现向量化,使用LLVM动态优化生成代码提升Spark SQL的性能'] + }, + { + TIME: '16:15-16:30', + THEME: 'Arm64开源HPC文件系统状态与进展', + SPEAKER: ['刘新良 Linaro'], + DESC: ['当前主流开源HPC文件系统Lustre和BeeGFS在Arm64平台上的状态与进展。例如使能过程中碰到的困难和问题,bugfix,CI搭建,性能测试与调优等相关工作进展,以及后续工作计划。'] + }, + { + TIME: '16:30-16:45', + THEME: 'AiLPHA大数据智能安全平台基于鲲鹏Validated的金融解决方案', + SPEAKER: ['童嘉伟 安恒信息'], + DESC: ['针对金融行业日益复杂网络安全形势,安恒信息与华为鲲鹏携手共赢,在产品适配层面达成高度合作,AiLPHA大数据智能安全平台采用业界领先的大数据分析技术架构,以“数据驱动安全分析,构建智能自适应安全运营中心”为产品理念,为金融用户提供全局安全态势感知能力、为金融业务不间断稳定运行提供安全保障,为金融用户提供信息系统安全决策支撑,为金融用户提供一套完整的安全解决方案,助力安全中国,助推数字经济。'] + }, + { + TIME: '16:45-17:00', + THEME: '大数据+Ceph存算分离、算子下推提升计算存储效率', + SPEAKER: ['吴启庆 华为'], + DESC: ['大数据+Ceph采用数据直通和算子下推方案,实现存算分离,提升计算存储效率,性能和存储率优于HDFS存储,成为数据湖实现的解决方案之一。'] + }, + ] + }, + { + TITLE: ['开源雨林分论坛'], + ITEM_LIST: [ + { + TIME: '14:45-15:00', + THEME: '开源雨林赋能企业开源', + SPEAKER: ['马全一 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '安全合规在openEuler上的实践', + SPEAKER: ['高琨 华为'], + DESC: [''] + }, + { + TIME: '15:30-16:00', + THEME: '开源雨林赋能课程介绍', + SPEAKER: ['李自 华为'], + DESC: [''] + }, + ] + }, + { + TITLE: ['安全分论坛'], + ITEM_LIST: [ + {}, + { + TIME: '15:00-15:15', + THEME: '开源社区安全成熟度模型及实践', + SPEAKER: ['徐海云 Software Improvement Group'], + DESC: ['与常规软件开发相比,开源社区的开发模式有着自己的独特性。度量open欧拉的安全性需要结合开源社区软件开发以及基于Linux的操作系统开发维护的特性,建立适用于open欧拉社区的安全成熟度模型。演讲者将介绍针对开源社区制定的安全成熟度模型,并分享近期的模型应用实践与经验。'] + }, + { + TIME: '15:15-15:30', + THEME: '畅谈Intel SGX 原理及应用场景探索', + SPEAKER: ['杜凡 Intel'], + DESC: ['在用户数据隐私日益重要的今天,如何保证用户数据在使用过程中的机密性和完整性成为一项重要又有挑战的问题。Intel SGX 技术致力于提供应用程序层面的细粒度的硬件TEE功能,为保护云上用户数据提供强有力的支持。该主题抛砖引玉,讲解机密计算领域中SGX技术原理,以及相应的应用场景探索。'] + }, + { + TIME: '15:30-15:45', + THEME: ' 机密计算应用实践', + SPEAKER: ['顾嘉辉 华为'], + DESC: ['数据作为关键生产要素背景下,数据安全成为业务合规和数据资产价值发挥的关键技术。secGear作为机密计算开发框架,使能多种硬件机密计算能力,支撑多种上层应用。本议题介绍secGear的技术特点,以及在数据库、AI等领域的应用实践探索。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于SBOM的开源软件供应链安全解决方案', + SPEAKER: ['刘波 华为'], + DESC: ['1、行业背景:软件产品的“不透明”传递性依赖层次深,导致整个软件供应链的网络安全治理难度越来越大;', '2、SBOM能做什么:基于行业标准透明的数据底座、结合软件成分分析、漏洞管理等集成,实现漏洞分钟级感知、排查与修复', '3、SBOM格式洞察分析:CycloneDX、SPDX、SWID', '4、SBOM解决方案整体设计:从SBOM数据采集与存储、到License、Copyright、漏洞感知消费、到开源合规履行义务报告生成', '5、OpenEuler 关键问题: 部分高阶语言包管理传递性依赖未识别', '6 、OpenEuler SBOM落地方案与计划'] + }, + { + TIME: '16:00-16:15', + THEME: ' 基于openEuler的安全加固定制方案和实践', + SPEAKER: ['唐杰 麒麟信安'], + DESC: ['操作系统安全性和易用性是个矛盾体,为了增加系统安全性,openEuler和OSV商业版本都做了相应的安全增强,如强制访问控制、完整性控制、多因子验证、关键系统部件加固等,但增加了管理员和用户的维护难度,因此设计了一套系统安全加固方案来满足易操作、高效率和可定制的问题。管理员可以使用图形工具一键完成一系列加固功能。方案采用了并发的方式提高加固执行的效率,并可根据用户需要快速重新定制加固方案。另外,使用非对称加密技术来避免加固方案被篡改,保障加固方案的权威性。'] + }, + { + TIME: '16:15-16:30', + THEME: ' 操作系统安全漏洞及早感知和快速响应', + SPEAKER: ['曹文渊 统信软件'], + DESC: ['在安全风险持续增长的今天,针对不同的操作系统,如何去感知互联网上层出不穷的各种漏洞、如何去判断这些漏洞是否影响我们的操作系统,从而更好的保护我们的操作系统免受攻击,已经成为了安全工作中的重要一环。'] + }, + ] + }, + { + TITLE: ['Devkit 工具集分论坛'], + ITEM_LIST: [ + {}, + {}, + {}, + { + TIME: '15:30-15:45', + THEME: 'openEuler商业版自动化测试工具', + SPEAKER: ['刘佐 麒麟信安'], + DESC: ['LTF是一款使用Shell编写的轻量级自动化测试框架,该工具目前主要应用openEuler商业版本以及第三方测试中。目前开源的测试用例涵盖了:性能测试、命令测试、开发环境测试、文件系统测试、GJB命令测试、语言测试等。框架提供的API让我们可以方便、快捷的编写测试脚本。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于鲲鹏Devkit的HPC迁移调优实践', + SPEAKER: ['李成鹏 软通动力'], + DESC: ['软通动力作为华为ITS领域战略合作伙伴,积极拥抱鲲鹏生态战略,并在多个领域取得阶段进展,自2021年加入鲲鹏众智计划以来累计成功交付加速库、HPC迁移调优等多个领域的项目,本次分享主要是给伙伴介绍我们通过使用鲲鹏Devkit工具集完成HPC开源组件从X86平台到鲲鹏+openEuler平台的迁移调优实践,Devkit迁移调优工具助力我们高效完成软件迁移并且软件性能提升明显。'] + }, + { + TIME: '16:00-16:15', + THEME: '应对CentOS停服,UYi(有易)数字化转型方案', + SPEAKER: ['薛智鑫 统信软件'], + DESC: ['UYi(有易)是一款服务器系统迁移软件, 帮助用户从CentOS系列平台平滑迁移到统信服务器操作系统V20,在保证新的操作系统正常稳定运行的同时,也要保证业务在其上的正常运行。'] + }, + { + TIME: '16:15-16:30', + THEME: 'PilotGo运维管理平台介绍', + SPEAKER: ['杨昭 麒麟软件'], + DESC: ['PilotGo运维管理平台在社区孵化已有一段时间,即将发布1.0版本,本次会介绍PilotGo软件的基本情况。'] + }, + { + TIME: '16:30-16:45', + THEME: 'openEuler兼容性评估工具介绍', + SPEAKER: ['王执 华为'], + DESC: ['介绍OS迁移中,对软件,硬件,配置兼容性评估功能介绍'] + }, + { + TIME: '16:45-17:00', + THEME: '操作系统之间的差异比较及兼容性分析工具', + SPEAKER: ['朱泽旭 华为'], + DESC: ['OECP工具主要有以下2个功能:', '1.检测2个ISO(基于RPM)的软件包,软件包内文件,库文件接口(C/C++),内核KABI的变化差异,根据这些差异可以分析2个OS之间的兼容性,为软件移植提供了重要参考' + , '2.OECP还可以检测同一个软件(RPM包)在不同版本下的变化以及差异,判断软件包的文件,接口等变化,可以分析得出软件不同版本之间的兼容性'] + }, + { + TIME: '17:00-17:15', + THEME: 'openEuler构建及镜像裁剪工具介绍', + SPEAKER: ['朱春意 华为'], + DESC: ['openEuler iso构建、iso裁剪、镜像的文件级裁剪工具介绍'] + }, + ] + }, + ] + }, + } + }, + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + HOST: { + TEXT_TITLE: "主办方", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + UNION: { + TEXT_TITLE: "联办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/intel.png", + LINK: "" + }, + ] + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/fusion.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/yunhe.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/liguangnan.png', + NAME: '倪光南', + POSITION: ['中国工程院院士'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/sunwenlong.png', + NAME: '孙文龙', + POSITION: ['开放原子开源基金会秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: ['openEuler社区理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hannaiping.png', + NAME: '韩乃平', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: ['openEuler社区', '技术委员会主席'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/qiuchenfen.png', + NAME: '邱成锋', + POSITION: ['openEuler社区秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guangxiaoming.png', + NAME: '广小明', + POSITION: ['天翼云科技有限公司', '副总经理兼首席技术官'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/likang.png', + NAME: '李康', + POSITION: ['中国移动', '在线营销服务中心副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhongxing.png', + NAME: '钟忻', + POSITION: ['联通云CTO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhouhaipeng.png', + NAME: '周海鹏', + POSITION: ['中信IT资深架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liukai.png', + NAME: '刘凯', + POSITION: ['上交所技术公司', '下一代交易研发部副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiongwei.png', + NAME: '熊伟', + POSITION: ['openEuler社区', '技术委员会委员'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/caowenyuan.png', + NAME: '曹文渊', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenhui.png', + NAME: '陈辉', + POSITION: ['华为调度架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenqiang.png', + NAME: '陈强', + POSITION: ['华为大数据技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chixinze.png', + NAME: '池信泽', + POSITION: ['ceph-sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/daizhiwei.png', + NAME: '戴志威', + POSITION: ['华为存储技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/dufan.png', + NAME: '杜凡', + POSITION: ['Intel Cloud Architect'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gaokun.png', + NAME: '高琨', + POSITION: ['华为工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gujiahui.png', + NAME: '顾嘉辉', + POSITION: ['华为基础软件', '安全技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guohao.png', + NAME: '郭皓', + POSITION: ['麒麟软件内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hechaoyang.png', + NAME: '贺朝阳', + POSITION: ['中科创达', '创达边缘计算工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangguoqing.png', + NAME: '江国庆', + POSITION: ['SUSE资深内核技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lichengpeng.png', + NAME: '李成鹏', + POSITION: ['软通鲲鹏生态技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lisiming.png', + NAME: '李思敏', + POSITION: ['华为技术有限公司工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lizi.png', + NAME: '李自', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liubo.png', + NAME: '刘波', + POSITION: ['华为开源社区', '工具链总架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liulongfang.png', + NAME: '刘龙芳', + POSITION: [' 华为内核技术工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuxinliang.png', + NAME: '刘新良', + POSITION: [' Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuyun.png', + NAME: '刘云', + POSITION: ['麒麟软件资深内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuzuo.png', + NAME: '刘佐', + POSITION: ['麒麟信安测试工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/luofei.png', + NAME: '罗飞', + POSITION: ['虚拟化资深工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/maquanyi.png', + NAME: '马全一', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/renwei.png', + NAME: '任慰', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tangjie.png', + NAME: '唐杰', + POSITION: ['麒麟信安', '操作系统组件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tianjun.png', + NAME: '田俊', + POSITION: ['Intel Arch SIG负责人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tongjiawei.png', + NAME: '童嘉伟', + POSITION: ['安恒信息', '大数据信创产品总监'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wanghongbo.png', + NAME: '王洪波', + POSITION: ['英特尔亚太研发有限公司', '软件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangjiangtao.png', + NAME: '王江涛', + POSITION: ['普华基础软件', '资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangyueliang.png', + NAME: '王悦良', + POSITION: ['麒麟软件开源工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangzhi.png', + NAME: '王执', + POSITION: ['华为欧拉Devkit', '系统工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuqiqing.png', + NAME: '吴启庆', + POSITION: ['华为存储系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuwei.png', + NAME: '吴伟', + POSITION: ['中科院软件所', 'PLCT实验室创始人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuguodong.png', + NAME: '徐国栋', + POSITION: ['Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuhaiyun.png', + NAME: '徐海云', + POSITION: ['SIG CSO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuzhixing.png', + NAME: '薛智鑫', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangzhao.png', + NAME: '杨昭', + POSITION: ['麒麟软件高级软件工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yaojiawei.png', + NAME: '姚嘉伟', + POSITION: ['普华基础软件', '资深系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yezhenyu.png', + NAME: '野震宇', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhangbo.png', + NAME: '张波', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuchunyi.png', + NAME: '朱春意', + POSITION: ['OS-Builder、BaseService', 'sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuzexu.png', + NAME: '朱泽旭', + POSITION: [' openEuler兼容性工具', '开发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhuanghaojian.png', + NAME: '庄浩坚', + POSITION: ['Linaro资深技术专家'] + }, + ], + GUEST_LIST: [ + + ], + PUBLISHER_BANNER: { + web: '/img/summit/devday-2022/lecturer/publishertitle.png', + mobile: '/img/summit/devday-2022/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/devday-2022/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + FOOTER: [ + { SUMMIT: 'openEuler Summit 2021', LINK: '/interaction/summit-list/summit2021/' }, + { SUMMIT: 'openEuler Developer Day 2021', LINK: '/interaction/summit-list/devday2021/' }, + { SUMMIT: 'openEuler Summit 2020', LINK: '/interaction/summit-list/' }, + { SUMMIT: 'openEuler Virtual Summit 2020', LINK: '/interaction/summit-list/list/' }, + ] + }, + ru: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_mo.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/devday_banner_pc.png", + LINK: "https://e-campaign.huawei.com/m/uMNFji" + }, + COLLECT_LIST: [{ + IMG: "/img/summit/devday-2022/CALLFORSPEAKER.png", + LINK: "https://shimo.im/forms/7DO3Fg79JSAfaflt/fill" + }, + { + IMG: "/img/summit/devday-2022/SIG1.png", + LINK: "https://shimo.im/forms/o0SfA0pfVmMlXEfi/fill" + }, + { + IMG: "/img/summit/devday-2022/CALLFORSPENSOR.png", + LINK: "https://shimo.im/forms/sspw0eU78rE9ra79/fill" + }, + ], + NAV_LIST: [ + { + key: '#liveroom', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#construction-unit', + name: '共建单位' + } + ], + LIVEDATA: { + RENDERDATA: [ + { + ID: 10392, + THEME: 'openEuler Developer Day 2022', + OPTION: 'openEuler Developer Day 2022', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10392?lang=zh&thirdId=' + }, + { + ID: 10393, + THEME: '内核', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 内核', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10393?lang=zh&thirdId=' + }, + { + ID: 10399, + THEME: '多样性计算', + TIME: '14:00-14:45', + OPTION: '14:00-14:45 多样性计算', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10399?lang=zh&thirdId=' + }, + { + ID: 10394, + THEME: '云原生&虚拟化', + TIME: '14:00-15:15', + OPTION: '14:00-15:15 云原生&虚拟化', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10394?lang=zh&thirdId=' + }, + { + ID: 10398, + THEME: '边缘&嵌入式', + TIME: '14:00-15:30', + OPTION: '14:00-15:30 边缘&嵌入式', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10398?lang=zh&thirdId=' + }, + { + ID: 10400, + THEME: '大数据存储', + TIME: '15:15-17:00', + OPTION: '15:15-17:00 大数据存储', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10400?lang=zh&thirdId=' + }, + { + ID: 10397, + THEME: '开源雨林', + TIME: '14:45-16:00', + OPTION: '14:45-16:00 开源雨林', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10397?lang=zh&thirdId=' + }, + { + ID: 10395, + THEME: '安全分论坛', + TIME: '15:00-16:30', + OPTION: '15:00-16:30 安全', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10395?lang=zh&thirdId=' + }, + { + ID: 10396, + THEME: 'Devkit 工具集', + TIME: '15:30-17:15', + OPTION: '15:30-17:15 Devkit 工具集', + LIVEURL: 'https://vhall.huawei.com/v2/watch/10396?lang=zh&thirdId=' + }, + ], + LIVETITLE: "openEuler Developer Day 2022直播间" + }, + SUMMIT_INTRODUCE: "openEuler Developer Day 2022 (简称 ODD 2022)是开放原子开源基金会的 openEuler 社区发起的开发者大会。旨在推动 openEuler 在服务器、云计算、边缘计算和嵌入式四大场景的技术探索和创新。本次 ODD 2022 正式发布 openEuler 22.03 全场景长周期版本,展示社区伙伴联合创新成果,分享多行业使用 openEuler 规模部署的商业案例,举办社区治理机构的线上工作会议。openEuler 始终与开发者在一起,开创新境,共创未来。", + AGENDA: { + CONFERENCE_LINK: "会议链接", + TITLE_IMG_PC: "/img/summit/devday-2022/zh-pc-devday2022.png", + TITLE_IMG_MO: "/img/summit/devday-2022/zh-mobile-devday2022.png", + AGENDA_DATA_TITLE: ['13', '14', '15'], + AGENDA_DATA_13: { + TITLE: "4月13日", + SCHEDULE: [ + { TIME: '16:00 - 17:30', SCHEDULE_LIST: ['用户委员会工作会议', '技术委员会工作会议', '品牌委员会工作会议', '理事会工作会议'] }, + { TIME: '15:30 - 17:30', SCHEDULE_LIST: ['用户圆桌'] } + ] + }, + AGENDA_DATA_14: { + MO_TITLE: "SIG 组开放工作会议", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + }, { + ZH: '晚上', + EN: 'night' + }], + TITLE: ['09:00 - 10:00', '10:00 - 11:00', '11:00 - 12:00'], + TITLE_AFTERNOON: ['14:00 - 15:00', '15:00 - 16:00', '16:00 - 17:00', '17:00 - 18:00'], + TITLE_NIGHT: ['19:00 - 20:00', '20:00 - 21:00'], + RIGHT_TEXT: ['回看', '笔记'], + SCHEDULE: [ + { + TITLE: { + ZH: "高校", + EN: "Education" + }, + SCHEDULE_CARD: [{ + TEXT: "高校开发者专场 sig-OSCourse", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1V3411T7Rq?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OSCourse-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "OpenStack DPU", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1SY4y1h7cM?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-openstack-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Industrial-Control", + TIME: "09:00 - 10:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1uZ4y1m7rz?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Industrial-Control-22.09-planning" + }, { + TEXT: "sig-AccLib", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1v44y137ZH?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/openEuler2209-sig-AccLib-ODD" + }, { + TEXT: "sig-Embedded Yocto", + TIME: "10:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1K94y1o7WL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-embedded-22.09-planning" + }] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-AI-BigData", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1X44y137XX?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-AI-BigData-22.09-planning" + }, { + TEXT: "sig-OPS", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dZ4y127Ux?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OPS-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-ceph", + TIME: "09:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1y94y1d7Gj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Ceph-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "Infrastructure sig-Gatekeeper", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1kF411g7TJ?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Infrastructure-22.09-planning" + }, { + TEXT: "sig-OS-Builder", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV12T4y1h7dB?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OS-Builder-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "Release", + TIME: "09:00 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1bF411g7Lk?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-release-22.09-planning" + }, { + TEXT: "Compiler", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1dY4y1e76P?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compiler-22.09-planning" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-UKUI", + TIME: "9:00 - 09:30", + ZOOM_LINK: "https://www.bilibili.com/video/BV1N94y1o7cx?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-UKUI-planning" + }, { + TEXT: "sig-CICD", + TIME: "09:30 - 11:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1t34y1v7Lo?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CICD-planning" + }, { + TEXT: "Application System-tools", + TIME: "11:00 - 12:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1U94y1d743?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-application-systemtools-planning" + }] + }, + ], + SCHEDULE_AFTERNOON: [ + { + TITLE: { + ZH: "内核", + EN: "Kernel" + }, + SCHEDULE_CARD: [{ + TEXT: "Kernel", + TIME: "14:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1wL4y1L7T3?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-kernel-22.09-planning" + }] + }, + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-CloudNative iSula、golang", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1TB4y1U7ba?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-CloudNative-22.09-planning" + }, { + TEXT: "Virt ovirt", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1fS4y1w72V?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Virt-22.09-planning" + }] + }, + { + TITLE: { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Intel-Arch", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV14F411g7oj?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/intel-arch-sig-odd" + }, { + TEXT: "sig-sw-arch", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1aB4y1U7Kp?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-sw-arch-planning" + }, { + TEXT: "sig-ROS", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1cu411y7oS?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-ROS-22.09-planning" + } + ] + }, + { + TITLE: { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-HPC", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ku411C7ya?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-hpc-22.09-planning" + }, { + TEXT: "DB", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1EZ4y1m72F?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-DB-22.09-planning" + }, { + TEXT: "A-Tune", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1YS4y1Y7YE?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-A-Tune-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Networking", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ET4y1e7qe?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/Networking-plan-3.30" + }, + { + TEXT: "sig-Edge", + TIME: "15:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1q5411273v?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Edge-22.09-planning" + }, { + TEXT: "sig-high-performance-network", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1o44y1V7ao?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-high-performance-networking-22.09-planning" + }] + }, + { + TITLE: { + ZH: "CI/CD", + EN: "CI/CD" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-security-facility security-committee", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1C34y1v7Zr?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-security-facility_and_sc-22.09-planning" + }, { + TEXT: "sig-Compatibility-Infra devkit", + TIME: "16:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV19u411C7fL?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Compatibility-Infra" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-QA GNOME", + TIME: "14:00 - 16:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1HZ4y1m71Q?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-QA-22.09-planning" + }, + { + TEXT: "sig HA", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Nr4y1H7N5?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-HA-22.09-planning" + }, { + TEXT: "sig-reproducible-builds", + TIME: "16:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1qi4y1U79W?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-reproducible-builds-22.09-planning" + }, { + TEXT: "sig-compliance", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY4y1e7T6?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-compliance-22.09-planing" + }] + }, + { + TITLE: { + ZH: "迁移", + EN: "Migration" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OpenDesign", + TIME: "14:00 - 15:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1s3411n75L?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OpenDesign-22.09-planning" + }, { + TEXT: "Doc G11N", + TIME: "15:00 - 17:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1ua411v7Vy?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Doc-G11N-planning" + }, { + TEXT: "sig-Migration", + TIME: "17:00 - 18:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oT4y1Y7ep?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Migration-planning" + }] + }, + ], + SCHEDULE_NIGHT: [ + { + TITLE: { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-OKD", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1RB4y1m79Z?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-OKD-22.09-planning" + }] + }, + { + TITLE: { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + SCHEDULE_CARD: [{ + TEXT: "Storage", + TIME: "19:00 - 21:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1Gr4y1H7Mv?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Storage-22.09-planning" + }] + }, + { + TITLE: { + ZH: "工具", + EN: "Tooling" + }, + SCHEDULE_CARD: [{ + TEXT: "sig-Java", + TIME: "19:00 - 20:00", + ZOOM_LINK: "https://www.bilibili.com/video/BV1oY411j7PY?spm_id_from=333.999.0.0", + ETHERPAD: "https://etherpad.openeuler.org/p/sig-Java-22.09-planning" + }] + }, + ], + COLUMN_TITLE: [ + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "高校", + EN: "Education" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "内核", + EN: "Kernel" + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "硬件使能", + EN: "Hardware Enable" + }, + { + ZH: "大数据 & AI", + EN: "Big Data & AI" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "CI/CD", + EN: "CI/CD" + }, + { + ZH: "工具", + EN: "Tooling" + }, + { + ZH: "迁移", + EN: "Migration" + },] + }, + { + TIME: [{ + ZH: "SIG 组开放工作会议", + }, + { + ZH: "云计算 & 云原生", + EN: "Cloud Computing & Cloud Native" + }, + { + ZH: "存储 & 网络", + EN: "Storage & Network" + }, + { + ZH: "工具", + EN: "Tooling" + }, + ] + }, + ] + }, + AGENDA_DATA_15: { + TITLE: "4月15日 周五(线上直播)", + TIME_TITLE: [{ + ZH: '上午', + EN: 'morning' + }, { + ZH: '下午', + EN: 'afternoon' + },], + SCHEDULE: [ + { + TIME: "10:00 - 10:03", + TEXT: "开幕致辞", + SPEAKER: [ + { + NAME: '孙文龙', + POSITION: '开放原子开源基金会秘书长', + } + ] + }, + { + TIME: "10:03 - 10:06", + TEXT: "院士致辞", + SPEAKER: [ + { + NAME: '倪光南', + POSITION: '中国工程院院士', + } + ] + }, + { + TIME: "10:06 - 10:15", + TEXT: "一起创未来 欧拉更精彩", + SPEAKER: [ + { + NAME: '江大勇', + POSITION: 'openEuler社区理事长', + } + ] + }, + { + TIME: "10:15 - 10:30", + TEXT: "openEuler 22.03 LTS:新征程,再出发", + SPEAKER: [ + { + NAME: '胡欣蔚', + POSITION: 'openEuler社区技术委员会主席', + } + ] + }, + { + TIME: "10:30 - 10:34", + TEXT: "openEuler商业发行版发布计划及欧拉技术认证颁发仪式", + SPEAKER: [ + { + NAME: '邱成锋', + POSITION: 'openEuler社区秘书长', + } + ] + }, + { + TIME: "10:34 - 10:42", + TEXT: "携手openEuler ,共筑天翼云数字底座 ", + SPEAKER: [ + { + NAME: '广小明', + POSITION: '天翼云科技有限公司 副总经理 兼首席技术官' + } + ] + }, + { + TIME: "10:42 - 10:50", + TEXT: "基于openEuler全栈创新,赋能数智新在线", + SPEAKER: [ + { + NAME: '李康', + POSITION: '中国移动在线营销服务中心副总经理', + } + ] + }, + { + TIME: "10:50 - 10:58", + TEXT: "openEuler+CULinux 打造联通云新一代基础设施", + SPEAKER: [ + { + NAME: '钟忻', + POSITION: '联通云CTO', + } + ] + }, + { + TIME: "10:58 - 11:06", + TEXT: "云原生时代中信银行开源技术实践", + SPEAKER: [ + { + NAME: '周海鹏 ', + POSITION: '中信IT资深架构师', + } + ] + }, + { + TIME: "11:06 - 11:14", + TEXT: "数字赋能 守正创新 - 上交所技术基于欧拉的原生应用实践", + SPEAKER: [ + { + NAME: '刘凯', + POSITION: '上交所技术公司下一代交易研发部副总经理', + } + ] + }, + { + TIME: "11:14 - 11:32", + TEXT: "圆桌会议:如何构建支持多样性计算的OS生态", + SPEAKER: [ + { + NAME: '武延军', + POSITION: 'openEuler社区副理事长', + }, + { + NAME: '堵俊平', + POSITION: '华为计算开源总经理', + }, + { + NAME: '杨继国', + POSITION: 'Intel开源技术中心总监', + }, + { + NAME: '李铭', + POSITION: '英伟达亚太区生态伙伴发展总监', + }, + { + NAME: '唐丹', + POSITION: '北京开源芯片研究院副院长', + }, + { + NAME: '姜振华', + POSITION: '超聚变操作系统业务总经理', + }, + { + NAME: '焦旭坡', + POSITION: '新华三集团操作系统开发部部长', + }, + ] + }, + { + TIME: "11:32 - 11:50", + TEXT: "圆桌会议:凡是未来 皆有可期-社区运作版本规划", + SPEAKER: [ + { + NAME: '熊伟', + POSITION: 'openEuler社区技术委员会委员', + }, + { + NAME: '谢秀奇', + POSITION: 'Kernel', + }, + { + NAME: '席静', + POSITION: 'sig-RISC-V', + }, + { + NAME: '田俊', + POSITION: 'sig-Intel-Arch', + }, + { + NAME: '金小贤', + POSITION: 'sig-AI', + }, + { + NAME: '陈硕', + POSITION: 'sig-openstack', + }, + { + NAME: '曹志', + POSITION: 'Infrastructure', + }, + { + NAME: '马文', + POSITION: 'sig-embedded/sig-Yocto', + }, + ] + }, + { + TIME: "11:50 - 11:55", + TEXT: "展望致辞:欧拉社区志高远 开源汇智向未来", + SPEAKER: [ + { + NAME: '韩乃平', + POSITION: 'openEuler社区副理事长', + } + ] + }, + ], + HOST: ['主持人:', '嘉宾:'], + STICKY_TITLE: ['大数据存储分论坛', '开源雨林分论坛', '安全分论坛', 'Devkit 工具集分论坛'], + SCHEDULE_AFTERNOON: { + TIME_LIST: ['上半场', '14:00 - 14:15', '14:15 - 14:30', '14:30 - 14:45', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30'], + CARD_LIST: [ + { + TITLE: ['内核分论坛'], + ITEM_LIST: [ + { + TIME: '14:00 - 14:15', + THEME: '轻量级内存异常检测工具— KFence', + SPEAKER: ['刘云 麒麟软件'], + DESC: ['KFENCE,克服了KASAN等工具需要占用大量内存且影响运行时性能的缺点,是一个有效地运行时内存访问错误检测工具。'] + }, + { + TIME: '14:15-14:30', + THEME: 'User Interrupts - 用户中断', + SPEAKER: ['孙运营 Intel'], + DESC: ['用户中断,是一种可以直接向用户空间发送中断的新的硬件特性。如今,几乎所有跨越权限边界的通信都是通过内核进行的,而用户中断提供了一种可以避免通过内核的通信方式,可以在提供低延迟通信的同时降低CPU使用率。'] + }, + { + TIME: '14:30-14:45', + THEME: '工程实践分享 | 企业级 Linux 内核维护', + SPEAKER: ['江国庆 SUSE'], + DESC: ['企业发行版的 Linux 内核维护是一个非常大的长期挑战。在整个产品生命周期内,技术团队可能会需要移植数万个代码补丁来确保高质量的内核运作。因此,如何高效的移植、管理和维护补丁,解决它们之间的冲突,是工程师们关心的技术难题。本次演讲中,SUSE 资深内核技术专家江国庆将介绍 SUSE 企业级内核是如何从开源内核演进而来,以及 SUSE 是如何采用相关工具对内核补丁进行维护,并以 SUSE Euler 内核为例来展示相关的工程实践。'] + }, + { + // TIME: '14:45-15:00', + // THEME: '使用 Arm SVE 向量指令为高性能计算库加速', + // SPEAKER: ['徐国栋 Linaro Ltd.'], + // DESC: ['面向高性能计算(HPC)领域,Arm 推出了 SVE (Scalable Vector Extenstion),至今演进有 SVE2, SME (armv9)。本演讲介绍SVE 演进,工具链支持,软件适配状况。最后结合在ISA-L, XXHash 的编码,讲解SVE的优势,同时介绍开发技术要点。'] + }, + { + TIME: '15:00-15:15', + THEME: '可编程内核调度框架', + SPEAKER: ['陈辉 华为'], + DESC: ['不同领域的业务模型不同,对性能的需求(时延、吞吐、功耗)不同,所需的调度策略也不同。业界存在很多优秀的调度策略,这些调度策略针对某一类场景而设计,难以多场景共享;目前ebpf技术兴起,可编程调度框架,基于ebpf技术打造一套调度框架,致力于让开发人员简单、高效的定制调度策略,降低验证和部署成本。'] + }, + ] + }, + { + TITLE: ['多样性计算分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'Accelerating openEuler ecosystem with heterogeneous computing', + SPEAKER: ['田俊 Intel'], + DESC: ["Based on Intel's recently technologies of heterogeneous connection standards, new hardware accelerators, new platforms and software frameworks to support various different platforms, this presentation will discuss the industry's direction of data center centralized heterogeneous computing and the technologies to enable the openEuler OS framework to support heterogeneous ecosystems."] + }, + { + TIME: '14:15-14:30', + THEME: '多样性算力的未来与当前产业责任', + SPEAKER: ['姚嘉伟 普华基础软件'], + DESC: ['根植于多架构平台的同源操作系统,在提供标准化底层模块的前提下,不断演进优化多样性的系统架构平台与产业生态,进一步完善一致性的评测工具与指标体系,深入筑牢多样性算力服务体系基础平台,为下一代信息化变革赋予新动能。'] + }, + { + TIME: '14:30-14:45', + THEME: 'openEuler 在RISC-V的生态建设和展望', + SPEAKER: ['吴伟 中科院软件所'], + DESC: ['介绍软件所在openEuler RISC-V 所做的软件包移植,维护,构建和在RISC-V 国际基金会的相关工作,以及展望。'] + }, + ] + }, + { + TITLE: ['云原生&虚拟化分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '虚拟化场景下内存故障处理优化和实践', + SPEAKER: ['罗飞 紫光云'], + DESC: ['介绍紫光云和新华三集团在使用open Euler实现虚拟化场景下内存优化的工作实践'] + }, + { + TIME: '14:15-14:30', + THEME: '鲲鹏加速器虚拟化热迁移', + SPEAKER: ['刘龙芳 华为'], + DESC: ['1. 社区虚拟化热迁移的协议与近期热点', '2. 鲲鹏加速器的支持热迁移的硬件方案', '3. 鲲鹏加速器的热迁移的软件方案'] + }, + { + TIME: '14:30-14:45', + THEME: 'Capsule - 高安全 & 全场景的下一代Hypervisor', + SPEAKER: ['张波,野震宇 华为'], + DESC: ['虚拟化通过复用与共享硬件资源来达到节省成本与使用灵活的目的,但同时牺牲了部分安全与性能。为达成更高安全与性能。华为欧拉虚拟化在stratovirt替代qemu的同时,capsule.替代kvm,均基于rust语言,杜绝绝大多数内存漏洞,同时capsule支持分区能力,快速部署全隔离虚拟机,达到接近物理机的时延与抖动,满足确定性诉求。'] + }, + { + TIME: '14:45-15:00', + THEME: '以openEuler为基础构建高性能同源异构一云多芯云平台', + SPEAKER: ['王江涛 普华基础软件'], + DESC: ['以基础软件厂商为视角介绍国产架构服务器的引入为行业领域信息化建设带来的冲击,介绍如何使用NUMA、RDM、SR-IOV技术减少宿主机资源开销,接近裸机部署效果。通过基于openEuler申威版、ARM版、X86版构建的异构虚拟化成功案例'] + }, + { + TIME: '15:00-15:15', + THEME: '欧拉生态蓬勃发展,NestOS扬帆起航', + SPEAKER: ['王悦良 麒麟软件'], + DESC: ['基于openEuler生态的云底座操作系统NestOS正式发布,本议题将分享其主要特性针对性解决支撑云上业务时常见的各类痛点,openEuler sig-OKD基于NestOS对其具体应用场景进行的探索,同时也将分享NestOS未来发展规划以及如何与openEuler生态进行组合创新,共同激发openEuler社区创新活力。'] + }, + ] + }, + { + TITLE: ['边缘&嵌入式分论坛'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: '在openEuler Embedded上进行多OS混合部署', + SPEAKER: ['任慰 华为'], + DESC: ['现在随着硬件技术的快速发展,片上系统的集成度越来越高,同时集成多核、异构多核已经很常见,这就带了在软件上同时部署多个OS的需求。openEuler Embedded的混合部署框架就是为了解决这一问题而推出的,目的是通过一套框架实现Linux和其他OS的便捷地混合部署,依托硬件上的多核能力使得Linux和实时操作系统有效互补,从而达到全系统兼具Linux的富生态和实时操作系统的高实时。'] + }, + { + TIME: '14:15-14:30', + THEME: '基于OpenEuler在嵌入式和实时性方面的思考与实践', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['介绍基于OpenEuler的GearOS系统现状,分享Xenomai编程经验', '介绍基于openEuler的Preempt_RT现状及使用方法,分享Preempt_RT相关技术经验'] + }, + { + TIME: '14:30-14:45', + THEME: '基于openEuler的EdgeX设备接入与控制', + SPEAKER: ['贺朝阳 中科创达'], + DESC: ['详细介绍基于openEuler运行EdgeX的过程;以ESP32芯片为例,结合EdgeX的架构,介绍南桥设备利用蓝牙、AP、mDNS、MQTT等技术自动接入openEuler上的EdgeX,继而以实际落地方案为例,介绍设备接入后利用EdgeX的Rules Engine和API等进行边缘侧和云端控制。'] + }, + { + TIME: '14:45-15:00', + THEME: 'openEuler Embedded基于yocto的演进', + SPEAKER: ['李思敏 华为'], + DESC: ['1. openEuler Embedded 的总体架构;', '2. openEuler Embedded 的开发实践;', '3. openEuler Embedded 的未来演进。'] + }, + { + TIME: '15:00-15:15', + THEME: 'openEuler上支持分布式软总线的进展与展望', + SPEAKER: ['谢焜勋 华为'], + DESC: ['介绍在openEuler嵌入式版本上,对openHarmony分布式软总线进行移植和支持的工作进展和下一步计划。'] + }, + { + TIME: '15:15-15:30', + THEME: 'Zephyr RTOS进展及中国社区推广', + SPEAKER: ['王洪波 Intel'], + DESC: ['Zephyr是在Linux基金会下开源的实时操作系统,它旨在成为这个物联网时代里,专门用于资源受限的中小型设备上最好的开源软件平台,同时强调安全设计。除了介绍Zephyr这个项目,重点会介绍一下最新的开发进展,以及新成立的SIG-Zephyr如何帮助进行中国社区的推广和应用。'] + }, + ] + }, + ] + }, + SCHEDULE_AFTERNOON_LAST: { + TIME_LIST: ['下半场', '14:45 - 15:00', '15:00 - 15:15', '15:15 - 15:30', '15:30 - 15:45', '15:45 - 16:00', '16:00 - 16:15', '16:15 - 16:30', '16:30 - 16:45', '16:45 - 17:00', '17:00 - 17:15'], + CARD_LIST: [ + { + TITLE: ['大数据存储分论坛'], + ITEM_LIST: [ + {}, + {}, + { + TIME: '15:15-15:30', + THEME: '缓存策略对CEPH性能的影响', + SPEAKER: ['池信泽 XSKY'], + DESC: ['主要是介绍CEPH RADOS架构下各级缓存策略对性能的影响'] + }, + { + TIME: '15:30-15:45', + THEME: '基于UADK加速器提升Ceph与大数据应用性能', + SPEAKER: ['戴志威 华为'], + DESC: ['数据存储中的加密、压缩对CPU算力提出了更高的要求。UADK是鲲鹏CPU上基于SVA的用户态加速开发套件,支持加密、压缩的计算加速和卸载。介绍Ceph数据体系和压缩特性,以及UADK在Ceph和大数据应用上的适配进展,性能表现。'] + }, + { + TIME: '15:45-16:00', + THEME: 'Arm SVE 向量指令为⾼性能计算库加速', + SPEAKER: ['徐国栋,庄浩坚 Linaro'], + DESC: ['⾯向⾼性能计算( HPC )领域, Arm 推出了 SVE ( Scalable Vector Extenstion ),⾄今演进有 SVE2 ,SME (armv9)。本演讲介绍 SVE 演进,⼯具链⽀持,软件适配状况。最后结合在 ISA-L , XXHash 的编码,讲解SVE 的优势,同时介绍开发技术要点。'] + }, + { + TIME: '16:00-16:15', + THEME: 'Spark SQL引擎Native Codegen', + SPEAKER: ['陈强 华为'], + DESC: ['采用SparkSQL Native Codegen框架,重新实现Spark SQL执行层,基于列式内存布局实现向量化,使用LLVM动态优化生成代码提升Spark SQL的性能'] + }, + { + TIME: '16:15-16:30', + THEME: 'Arm64开源HPC文件系统状态与进展', + SPEAKER: ['刘新良 Linaro'], + DESC: ['当前主流开源HPC文件系统Lustre和BeeGFS在Arm64平台上的状态与进展。例如使能过程中碰到的困难和问题,bugfix,CI搭建,性能测试与调优等相关工作进展,以及后续工作计划。'] + }, + { + TIME: '16:30-16:45', + THEME: 'AiLPHA大数据智能安全平台基于鲲鹏Validated的金融解决方案', + SPEAKER: ['童嘉伟 安恒信息'], + DESC: ['针对金融行业日益复杂网络安全形势,安恒信息与华为鲲鹏携手共赢,在产品适配层面达成高度合作,AiLPHA大数据智能安全平台采用业界领先的大数据分析技术架构,以“数据驱动安全分析,构建智能自适应安全运营中心”为产品理念,为金融用户提供全局安全态势感知能力、为金融业务不间断稳定运行提供安全保障,为金融用户提供信息系统安全决策支撑,为金融用户提供一套完整的安全解决方案,助力安全中国,助推数字经济。'] + }, + { + TIME: '16:45-17:00', + THEME: '大数据+Ceph存算分离、算子下推提升计算存储效率', + SPEAKER: ['吴启庆 华为'], + DESC: ['大数据+Ceph采用数据直通和算子下推方案,实现存算分离,提升计算存储效率,性能和存储率优于HDFS存储,成为数据湖实现的解决方案之一。'] + }, + ] + }, + { + TITLE: ['开源雨林分论坛'], + ITEM_LIST: [ + { + TIME: '14:45-15:00', + THEME: '开源雨林赋能企业开源', + SPEAKER: ['马全一 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '安全合规在openEuler上的实践', + SPEAKER: ['高琨 华为'], + DESC: [''] + }, + { + TIME: '15:30-16:00', + THEME: '开源雨林赋能课程介绍', + SPEAKER: ['李自 华为'], + DESC: [''] + }, + ] + }, + { + TITLE: ['安全分论坛'], + ITEM_LIST: [ + {}, + { + TIME: '15:00-15:15', + THEME: '开源社区安全成熟度模型及实践', + SPEAKER: ['徐海云 Software Improvement Group'], + DESC: ['与常规软件开发相比,开源社区的开发模式有着自己的独特性。度量open欧拉的安全性需要结合开源社区软件开发以及基于Linux的操作系统开发维护的特性,建立适用于open欧拉社区的安全成熟度模型。演讲者将介绍针对开源社区制定的安全成熟度模型,并分享近期的模型应用实践与经验。'] + }, + { + TIME: '15:15-15:30', + THEME: '畅谈Intel SGX 原理及应用场景探索', + SPEAKER: ['杜凡 Intel'], + DESC: ['在用户数据隐私日益重要的今天,如何保证用户数据在使用过程中的机密性和完整性成为一项重要又有挑战的问题。Intel SGX 技术致力于提供应用程序层面的细粒度的硬件TEE功能,为保护云上用户数据提供强有力的支持。该主题抛砖引玉,讲解机密计算领域中SGX技术原理,以及相应的应用场景探索。'] + }, + { + TIME: '15:30-15:45', + THEME: ' 机密计算应用实践', + SPEAKER: ['顾嘉辉 华为'], + DESC: ['数据作为关键生产要素背景下,数据安全成为业务合规和数据资产价值发挥的关键技术。secGear作为机密计算开发框架,使能多种硬件机密计算能力,支撑多种上层应用。本议题介绍secGear的技术特点,以及在数据库、AI等领域的应用实践探索。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于SBOM的开源软件供应链安全解决方案', + SPEAKER: ['刘波 华为'], + DESC: ['1、行业背景:软件产品的“不透明”传递性依赖层次深,导致整个软件供应链的网络安全治理难度越来越大;', '2、SBOM能做什么:基于行业标准透明的数据底座、结合软件成分分析、漏洞管理等集成,实现漏洞分钟级感知、排查与修复', '3、SBOM格式洞察分析:CycloneDX、SPDX、SWID', '4、SBOM解决方案整体设计:从SBOM数据采集与存储、到License、Copyright、漏洞感知消费、到开源合规履行义务报告生成', '5、OpenEuler 关键问题: 部分高阶语言包管理传递性依赖未识别', '6 、OpenEuler SBOM落地方案与计划'] + }, + { + TIME: '16:00-16:15', + THEME: ' 基于openEuler的安全加固定制方案和实践', + SPEAKER: ['唐杰 麒麟信安'], + DESC: ['操作系统安全性和易用性是个矛盾体,为了增加系统安全性,openEuler和OSV商业版本都做了相应的安全增强,如强制访问控制、完整性控制、多因子验证、关键系统部件加固等,但增加了管理员和用户的维护难度,因此设计了一套系统安全加固方案来满足易操作、高效率和可定制的问题。管理员可以使用图形工具一键完成一系列加固功能。方案采用了并发的方式提高加固执行的效率,并可根据用户需要快速重新定制加固方案。另外,使用非对称加密技术来避免加固方案被篡改,保障加固方案的权威性。'] + }, + { + TIME: '16:15-16:30', + THEME: ' 操作系统安全漏洞及早感知和快速响应', + SPEAKER: ['曹文渊 统信软件'], + DESC: ['在安全风险持续增长的今天,针对不同的操作系统,如何去感知互联网上层出不穷的各种漏洞、如何去判断这些漏洞是否影响我们的操作系统,从而更好的保护我们的操作系统免受攻击,已经成为了安全工作中的重要一环。'] + }, + ] + }, + { + TITLE: ['Devkit 工具集分论坛'], + ITEM_LIST: [ + {}, + {}, + {}, + { + TIME: '15:30-15:45', + THEME: 'openEuler商业版自动化测试工具', + SPEAKER: ['刘佐 麒麟信安'], + DESC: ['LTF是一款使用Shell编写的轻量级自动化测试框架,该工具目前主要应用openEuler商业版本以及第三方测试中。目前开源的测试用例涵盖了:性能测试、命令测试、开发环境测试、文件系统测试、GJB命令测试、语言测试等。框架提供的API让我们可以方便、快捷的编写测试脚本。'] + }, + { + TIME: '15:45-16:00', + THEME: '基于鲲鹏Devkit的HPC迁移调优实践', + SPEAKER: ['李成鹏 软通动力'], + DESC: ['软通动力作为华为ITS领域战略合作伙伴,积极拥抱鲲鹏生态战略,并在多个领域取得阶段进展,自2021年加入鲲鹏众智计划以来累计成功交付加速库、HPC迁移调优等多个领域的项目,本次分享主要是给伙伴介绍我们通过使用鲲鹏Devkit工具集完成HPC开源组件从X86平台到鲲鹏+openEuler平台的迁移调优实践,Devkit迁移调优工具助力我们高效完成软件迁移并且软件性能提升明显。'] + }, + { + TIME: '16:00-16:15', + THEME: '应对CentOS停服,UYi(有易)数字化转型方案', + SPEAKER: ['薛智鑫 统信软件'], + DESC: ['UYi(有易)是一款服务器系统迁移软件, 帮助用户从CentOS系列平台平滑迁移到统信服务器操作系统V20,在保证新的操作系统正常稳定运行的同时,也要保证业务在其上的正常运行。'] + }, + { + TIME: '16:15-16:30', + THEME: 'PilotGo运维管理平台介绍', + SPEAKER: ['杨昭 麒麟软件'], + DESC: ['PilotGo运维管理平台在社区孵化已有一段时间,即将发布1.0版本,本次会介绍PilotGo软件的基本情况。'] + }, + { + TIME: '16:30-16:45', + THEME: 'openEuler兼容性评估工具介绍', + SPEAKER: ['王执 华为'], + DESC: ['介绍OS迁移中,对软件,硬件,配置兼容性评估功能介绍'] + }, + { + TIME: '16:45-17:00', + THEME: '操作系统之间的差异比较及兼容性分析工具', + SPEAKER: ['朱泽旭 华为'], + DESC: ['OECP工具主要有以下2个功能:', '1.检测2个ISO(基于RPM)的软件包,软件包内文件,库文件接口(C/C++),内核KABI的变化差异,根据这些差异可以分析2个OS之间的兼容性,为软件移植提供了重要参考' + , '2.OECP还可以检测同一个软件(RPM包)在不同版本下的变化以及差异,判断软件包的文件,接口等变化,可以分析得出软件不同版本之间的兼容性'] + }, + { + TIME: '17:00-17:15', + THEME: 'openEuler构建及镜像裁剪工具介绍', + SPEAKER: ['朱春意 华为'], + DESC: ['openEuler iso构建、iso裁剪、镜像的文件级裁剪工具介绍'] + }, + ] + }, + ] + }, + } + }, + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + HOST: { + TEXT_TITLE: "主办方", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + UNION: { + TEXT_TITLE: "联办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/intel.png", + LINK: "" + }, + ] + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/fusion.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/yunhe.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/liguangnan.png', + NAME: '倪光南', + POSITION: ['中国工程院院士'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/sunwenlong.png', + NAME: '孙文龙', + POSITION: ['开放原子开源基金会秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: ['openEuler社区理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hannaiping.png', + NAME: '韩乃平', + POSITION: ['openEuler社区副理事长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: ['openEuler社区', '技术委员会主席'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/qiuchenfen.png', + NAME: '邱成锋', + POSITION: ['openEuler社区秘书长'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guangxiaoming.png', + NAME: '广小明', + POSITION: ['天翼云科技有限公司', '副总经理兼首席技术官'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/likang.png', + NAME: '李康', + POSITION: ['中国移动', '在线营销服务中心副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhongxing.png', + NAME: '钟忻', + POSITION: ['联通云CTO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhouhaipeng.png', + NAME: '周海鹏', + POSITION: ['中信IT资深架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liukai.png', + NAME: '刘凯', + POSITION: ['上交所技术公司', '下一代交易研发部副总经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiongwei.png', + NAME: '熊伟', + POSITION: ['openEuler社区', '技术委员会委员'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/caowenyuan.png', + NAME: '曹文渊', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenhui.png', + NAME: '陈辉', + POSITION: ['华为调度架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenqiang.png', + NAME: '陈强', + POSITION: ['华为大数据技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/chixinze.png', + NAME: '池信泽', + POSITION: ['ceph-sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/daizhiwei.png', + NAME: '戴志威', + POSITION: ['华为存储技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/dufan.png', + NAME: '杜凡', + POSITION: ['Intel Cloud Architect'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gaokun.png', + NAME: '高琨', + POSITION: ['华为工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/gujiahui.png', + NAME: '顾嘉辉', + POSITION: ['华为基础软件', '安全技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/guohao.png', + NAME: '郭皓', + POSITION: ['麒麟软件内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/hechaoyang.png', + NAME: '贺朝阳', + POSITION: ['中科创达', '创达边缘计算工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/jiangguoqing.png', + NAME: '江国庆', + POSITION: ['SUSE资深内核技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lichengpeng.png', + NAME: '李成鹏', + POSITION: ['软通鲲鹏生态技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lisiming.png', + NAME: '李思敏', + POSITION: ['华为技术有限公司工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/lizi.png', + NAME: '李自', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liubo.png', + NAME: '刘波', + POSITION: ['华为开源社区', '工具链总架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liulongfang.png', + NAME: '刘龙芳', + POSITION: [' 华为内核技术工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuxinliang.png', + NAME: '刘新良', + POSITION: [' Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuyun.png', + NAME: '刘云', + POSITION: ['麒麟软件资深内核专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/liuzuo.png', + NAME: '刘佐', + POSITION: ['麒麟信安测试工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/luofei.png', + NAME: '罗飞', + POSITION: ['虚拟化资深工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/maquanyi.png', + NAME: '马全一', + POSITION: ['华为'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/renwei.png', + NAME: '任慰', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tangjie.png', + NAME: '唐杰', + POSITION: ['麒麟信安', '操作系统组件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tianjun.png', + NAME: '田俊', + POSITION: ['Intel Arch SIG负责人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/tongjiawei.png', + NAME: '童嘉伟', + POSITION: ['安恒信息', '大数据信创产品总监'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wanghongbo.png', + NAME: '王洪波', + POSITION: ['英特尔亚太研发有限公司', '软件开发经理'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangjiangtao.png', + NAME: '王江涛', + POSITION: ['普华基础软件', '资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangyueliang.png', + NAME: '王悦良', + POSITION: ['麒麟软件开源工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wangzhi.png', + NAME: '王执', + POSITION: ['华为欧拉Devkit', '系统工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuqiqing.png', + NAME: '吴启庆', + POSITION: ['华为存储系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/wuwei.png', + NAME: '吴伟', + POSITION: ['中科院软件所', 'PLCT实验室创始人'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: ['华为操作系统技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuguodong.png', + NAME: '徐国栋', + POSITION: ['Linaro资深技术专家'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuhaiyun.png', + NAME: '徐海云', + POSITION: ['SIG CSO'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/xuzhixing.png', + NAME: '薛智鑫', + POSITION: ['统信软件研发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangzhao.png', + NAME: '杨昭', + POSITION: ['麒麟软件高级软件工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yaojiawei.png', + NAME: '姚嘉伟', + POSITION: ['普华基础软件', '资深系统架构师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/yezhenyu.png', + NAME: '野震宇', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhangbo.png', + NAME: '张波', + POSITION: ['华为虚拟化领域工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuchunyi.png', + NAME: '朱春意', + POSITION: ['OS-Builder、BaseService', 'sig maintainer'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zuzexu.png', + NAME: '朱泽旭', + POSITION: [' openEuler兼容性工具', '开发工程师'] + }, + { + IMG: '/img/summit/devday-2022/lecturer/zhuanghaojian.png', + NAME: '庄浩坚', + POSITION: ['Linaro资深技术专家'] + }, + ], + GUEST_LIST: [ + + ], + PUBLISHER_BANNER: { + web: '/img/summit/devday-2022/lecturer/publishertitle.png', + mobile: '/img/summit/devday-2022/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/devday-2022/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/devday-2022/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/devday-2022/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/devday-2022/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/devday-2022/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + FOOTER: [ + { SUMMIT: 'openEuler Summit 2021', LINK: '/interaction/summit-list/summit2021/' }, + { SUMMIT: 'openEuler Developer Day 2021', LINK: '/interaction/summit-list/devday2021/' }, + { SUMMIT: 'openEuler Summit 2020', LINK: '/interaction/summit-list/' }, + { SUMMIT: 'openEuler Virtual Summit 2020', LINK: '/interaction/summit-list/list/' }, + ] + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/documentation.js b/web-ui/docs/.vuepress/lang/lang-modules/documentation.js new file mode 100644 index 0000000000000000000000000000000000000000..3071b34a6f9cc776c55078fe01d7419feb95c702 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/documentation.js @@ -0,0 +1,33 @@ +/** + * @file 文档模块国际化配置入口 + * */ + +module.exports = { + cn: { + DOCS_LABEL: '文档', + VERSION: '版本', + SELECT_VERSION_LABLE: '选择版本', + PREVIOUS: '上一篇', + NEXT: '下一篇', + FEEDBACK: '意见反馈', + MENU: '目录', + }, + en: { + DOCS_LABEL: 'Docs', + VERSION: 'Version', + SELECT_VERSION_LABLE: 'Select Version', + PREVIOUS: 'Previous', + NEXT: 'Next', + FEEDBACK: 'Feedback', + MENU: 'Menu', + }, + ru: { + DOCS_LABEL: 'Документы', + VERSION: 'Версия', + SELECT_VERSION_LABLE: 'Select Version', + PREVIOUS: 'Previous', + NEXT: 'Next', + FEEDBACK: 'Feedback', + MENU: 'Menu', + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/download.js b/web-ui/docs/.vuepress/lang/lang-modules/download.js new file mode 100644 index 0000000000000000000000000000000000000000..4ffb1a9324515cedf3cb948634a99b00cbe0c2df --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/download.js @@ -0,0 +1,125 @@ +/** + * @file 下载模块国际化配置入口 + * */ + +module.exports = { + cn: { + RELEASE_DESC: '发行说明', + SERVER_IMAGE:'服务器镜像', + CLOUD_IMAGE:'云镜像', + EDGE_IMAGE:'边缘镜像', + EMBEDDEN_IMAGE:'嵌入式镜像', + INSTALL_GUIDENCE: '安装指南', + SEEK_HELP: '提问求助', + GET_ISO: '获取 ISO', + LIFE_CYCLE: '生命周期', + DOWNLOAD_BTN_NAME: '下载', + OUTSIDE_TITLE:'ISO', + MANUFACTURER: '厂商', + PUBLISH_DATE: '发行时间', + WHITE_PAPER: '白皮书', + WEBSITE_SELECT: '站点选择', + COPY_SUCCESSFULLY: '复制成功!', + DOWNLOAD_LIST : require('././../../data/download').cn.DOWNLOAD_LIST, + MIRROR_SELECT: { + TITLE: '优选镜像', + RANK: 'Rank:', + NAME: 'Mirror Name:', + URL: 'URL:', + COUNTRY: 'Area:', + CONTINENT: 'Continent:', + DISTANCE: 'Distance(KM):', + CONTENT: ['You are connecting from IP address: ',', which belongs to ','. We believe you are somewhere in ',' and have selected the applicable mirrors.'] + }, + MIRROR_ALL: { + TITLE: '镜像仓列表', + NAME: 'Mirror Name:', + LOCATION: 'Location:', + SPONSOR: 'Sponsor:', + HTTPS: 'Http(s):', + RSNC: 'RSYNC:', + FTP: 'FTP:', + Mbs: 'NetworkBandwidth(Mb/s):', + TIME: 'Last Sync time:', + CONTENT: ['openEuler welcomes new mirror sites. If you are considering to set up a public mirror site for openEuler, please follow the mirror guidelines to make sure that your mirror is consistent with the other mirror sites. Any questions, feel free to','contact us'] + } + }, + en: { + RELEASE_DESC: 'Release Description', + SERVER_IMAGE:'Server Image', + CLOUD_IMAGE:'Cloud Image', + EDGE_IMAGE:'Edeg Image', + EMBEDDEN_IMAGE:'Embedded Image', + INSTALL_GUIDENCE: 'Installation Guide', + SEEK_HELP: 'Seek Help', + GET_ISO: 'Get Iso', + LIFE_CYCLE: 'Lifecycle', + DOWNLOAD_BTN_NAME: 'Download', + OUTSIDE_TITLE:'ISO', + MANUFACTURER: 'Manufacturer', + WHITE_PAPER: 'White Paper', + PUBLISH_DATE: 'Date of Release', + WEBSITE_SELECT: 'Select Mirror', + COPY_SUCCESSFULLY: 'copied successfully.', + DOWNLOAD_LIST : require('././../../data/download').en.DOWNLOAD_LIST, + MIRROR_SELECT: { + TITLE: 'Selected Mirrors', + RANK: 'Rank:', + NAME: 'Mirror Name:', + URL: 'URL:', + COUNTRY: 'Area:', + CONTINENT: 'Continent:', + DISTANCE: 'Distance(KM):', + CONTENT: ['You are connecting from IP address: ',', which belongs to ','. We believe you are somewhere in ',' and have selected the applicable mirrors.'] + }, + MIRROR_ALL: { + TITLE: 'Mirrors', + NAME: 'Mirror Name:', + LOCATION: 'Location:', + SPONSOR: 'Sponsor:', + HTTPS: 'Http(s):', + RSNC: 'RSYNC:', + FTP: 'FTP:', + Mbs: 'NetworkBandwidth(Mb/s):', + TIME: 'Last Sync time:', + CONTENT: ['openEuler welcomes new mirror sites. If you are considering to set up a public mirror site for openEuler, please follow the mirror guidelines to make sure that your mirror is consistent with the other mirror sites. Any questions, feel free to','contact us'] + } + }, + ru: { + RELEASE_DESC: 'Описание релиза', + INSTALL_GUIDENCE: 'Руководство по установке', + SEEK_HELP: 'Справка', + GET_ISO: 'Получить ISO', + LIFE_CYCLE: 'Жизненный цикл', + DOWNLOAD_BTN_NAME: 'Загрузить', + OUTSIDE_TITLE:'ISO', + MANUFACTURER: 'Поставщик', + WHITE_PAPER: 'информационный документ', + PUBLISH_DATE: 'Дата выпуска релиза ', + WEBSITE_SELECT: 'Select Mirror', + COPY_SUCCESSFULLY: 'copied successfully.', + DOWNLOAD_LIST : require('././../../data/download').ru.DOWNLOAD_LIST, + MIRROR_SELECT: { + TITLE: 'Selected Mirrors', + RANK: 'Rank:', + NAME: 'Mirror Name:', + URL: 'URL:', + COUNTRY: 'Area:', + CONTINENT: 'Continent:', + DISTANCE: 'Distance(KM):', + CONTENT: ['You are connecting from IP address: ',', which belongs to ','. We believe you are somewhere in ',' and have selected the applicable mirrors.'] + }, + MIRROR_ALL: { + TITLE: 'Mirrors Lists', + NAME: 'Mirror Name:', + LOCATION: 'Location:', + SPONSOR: 'Sponsor:', + HTTPS: 'Http(s):', + RSNC: 'RSYNC:', + FTP: 'FTP:', + Mbs: 'NetworkBandwidth(Mb/s):', + TIME: 'Last Sync time:', + CONTENT: ['openEuler welcomes new mirror sites. If you are considering to set up a public mirror site for openEuler, please follow the mirror guidelines to make sure that your mirror is consistent with the other mirror sites. Any questions, feel free to','contact us'] + } + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/home.js b/web-ui/docs/.vuepress/lang/lang-modules/home.js new file mode 100644 index 0000000000000000000000000000000000000000..516f8706140ce5b8d13f2ba1aab55a3bc4e6f975 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/home.js @@ -0,0 +1,1758 @@ +/** + * @file 首页模块国际化配置入口 + * */ + +module.exports = { + cn: { + HOME_CAROUSEL_DATA: [ + { + TITLE: "iSula", + LINK: "/other/projects/isula", + DES: "小个头 大能量", + IMG: "/img/minisite/isula/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/iSula.mp4" + }, + { + TITLE: "A-Tune", + LINK: "/other/projects/atune", + DES: "一款基于AI开发的智能优化引擎", + IMG: "/img/minisite/atune/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/A-Tune.mp4" + }, + { + TITLE: "StratoVirt", + LINK: "/other/projects/stratovirt", + DES: "面向云数据中心的企业级虚拟化平台", + IMG: "/img/minisite/svirt/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/StratoVirt-minisite.mp4" + } + ], + ROOM_LEFT_IMG: [ + { + IMG: '/img/activities/internship.png', + LINK: '/internship/' + }, + { + IMG: '/img/activities/devday2022.png', + LINK: '/interaction/summit-list/devday2022/' + }, + { + IMG: '/img/activities/pc_home_bottom_banner.png', + LINK: '/activities/' + } + ], + HOME_NEWRELEASE: [ + { + MOBILE_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_mo.png')", + PC_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_pc.png')", + LINK: '/interaction/summit-list/devday2022/' + }, + ], + HOME_INTRODUCE: { + INTRO_TITLE: "The Most Innovative Open Source Community", + INTRO_HEAD: "开始openEuler之旅吧!", + INTRO_DESCRIPTION: "openEuler通过开放的社区形式与全球开发者共同构建一个开放、多元和架构包容的软件生态体系,孵化支持多种处理器架构、覆盖数字设施全场景,推动企业数字基础设施软硬件、应用生态繁荣发展。", + INTRO_IMG_URL: "", + INTRO_MAP: [ + { + NAME: "下载", + TITLE: "openEuler ISO", + IMG: "/img/home/step1.png", + GIF: "/img/home/step-move-1.gif", + LINK: "/download/", + }, + { + NAME: "体验", + TITLE: "openEuler系统", + IMG: "/img/home/step2.png", + GIF: "/img/home/step-move-2.gif", + LINK: "", + }, + { + NAME: "查阅", + TITLE: "openEuler文档", + IMG: "/img/home/step3.png", + GIF: "/img/home/step-move-3.gif", + LINK: "/docs/", + OTHER_LINK: "/zh/" + }, + { + NAME: "贡献", + TITLE: "openEuler社区", + IMG: "/img/home/step4.png", + GIF: "/img/home/step-move-4.gif", + LINK: "/community/contribution/", + }, + + ], + INTRO_MAP_SND: { + NAME: "体验", + TITLE: "openEuler系统", + IMG: "/img/home/step2.png", + LINK: "javascript:;", + GIF: "/img/home/step-move-2.gif" + }, + INTRO_GUIDE: { + INFO: "选择您喜欢的体验方式", + GUIDE_WAY: [ + { + TITLE: "树莓派", + IMG: "/img/home/areaPai.png", + LINK: "https://gitee.com/openeuler/raspberrypi" + }, + { + TITLE: "硬件", + IMG: "/img/home/areaHardware.svg", + LINK: "/zh/docs/20.03_LTS/docs/Installation/installation.html" + }, + { + TITLE: "虚拟机", + IMG: "/img/home/areaVirtual.svg", + LINK: "/zh/docs/20.03_LTS/docs/Virtualization/virtualization.html" + }, + { + TITLE: "ECS", + IMG: "/img/home/areaECS.svg", + LINK: "https://huaweicloud.com/product/ecs.html" + } + ] + } + }, + HOME_ACTIVE: { + ACTIVE_TITLE: "好玩的活动停不下来", + ACTIVE_DESCRIPTION: "openEuler社区不定期举办各种workshop、SIG讨论、线下活动、社区峰会,精彩动态随时掌握。" + }, + HOME_ROUND: { + ROUND_TITLE: '我们正在不断成长', + VIEW_DETAIL: '查看详情', + VIEW_DETAIL_LINK: 'https://datastat.openeuler.org/zh/overview', + ROUND_LIST: [ + { + ROUND_VALUE: '', + ROUND_KEY: 'contributors', + ROUND_IMG: '/img/round/contributer.png', + ROUND_TEXT: '贡献者', + ROUND_STYLE: { + backcolor: 'blue' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'repos', + ROUND_IMG: '/img/round/software.png', + ROUND_TEXT: '代码仓库', + ROUND_STYLE: { + backcolor: 'pink' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'sigs', + ROUND_IMG: '/img/round/sig.png', + ROUND_TEXT: '特别兴趣小组', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'users', + ROUND_IMG: '/img/round/user.png', + ROUND_TEXT: '社区用户', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'businessosv', + ROUND_IMG: '/img/round/osv.png', + ROUND_TEXT: '商用OSV', + ROUND_STYLE: { + backcolor: 'blue' + } + } + ] + }, + HOME_ROOMS: { + ROOM_NAME: ["最新活动", "博客", "新闻"], + EVENT_NAME: "最新活动", + BLOG_NAME: "博客", + NEWS_NAME: "新闻", + EVENT_LIST: [ + { + TAG: "事件", + DATE: "2020-06-07", + CONTENT: "吹响开源集结号——”点亮“暑假2020" + }, + { + TAG: "事件", + DATE: "2020-01-04", + CONTENT: "去HDC.Cloud 2020 参加黑客松, 玩儿openEuler,赢取大礼" + }, + { + TAG: "事件", + DATE: "2020-12-10", + CONTENT: "HDC.Cloud | openEuler黑客马拉松" + }, + ], + BLOG_LIST: [ + { + TAG: "openEuler Blog Maintainer", + DATE: "2020-05-08", + CONTENT: "A-Tune让系统更智能" + }, + { + TAG: "zhongjun", + DATE: "2020-05-07", + CONTENT: "浅谈openEuler开源社区经营度量分析系统选型" + }, + { + TAG: "Ivye", + DATE: "2020-05-06", + CONTENT: "HDC.Cloud | openEuler黑客马拉松" + }, + ], + NEWS_LIST: [ + { + TAG: "极云IT杂谈", + DATE: "2020-05-09", + CONTENT: "华为OpenEuler操作系统强势来袭,正式开源时代来了?" + }, + { + TAG: "中国网科学频道", + DATE: "2020-05-06", + CONTENT: "华为联合产业伙伴openEuler2020年峰会成功召开" + }, + { + TAG: "新浪", + DATE: "2020-04-12", + CONTENT: "openEuler开源路带来多样性计算计算技术与产业生态共荣" + }, + ], + }, + HOME_DEV: { + DEV_TITLE: "相见恨晚的Developer", + DEV_DESCRIPTION: "这里汇聚了无数精英大咖,快找找您感兴趣的Developer吧!", + DEV_INFO: [ + { + NAME: "冯涛", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "t.feng94@foxmail.com", + GITEE_LINK: "https://gitee.com/t_feng", + IMG: "/img/home/developer/fengtao.png" + }, + { + NAME: "郭歌", + TITLE: "", + RANK: "Compiler SIG Maintainer", + MAIL_LINK: "nobleprize@foxmail.com", + GITEE_LINK: "https://gitee.com/jdkboy", + IMG: "/img/home/developer/guoge.png" + }, + { + NAME: "杨丽", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "rainbow1981@163.com", + GITEE_LINK: "https://gitee.com/yangli69393", + IMG: "/img/home/developer/yangli.png" + }, + { + NAME: "张旭舟", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "whoisxxx@126.com", + GITEE_LINK: "https://gitee.com/whoisxxx", + IMG: "/img/home/developer/zhangxuzhou.png" + }, + { + NAME: "张芮", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "13851924834@139.com", + GITEE_LINK: "https://gitee.com/anonymous_z", + IMG: "/img/home/developer/zhangrui.png" + }, + { + NAME: "杨颖梁", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "zjutyyl@163.com", + GITEE_LINK: "https://gitee.com/yangyingliang", + IMG: "/img/home/developer/yangyingliang.png" + }, + { + NAME: "徐延东", + TITLE: "", + RANK: "Virt-Maintainer", + MAIL_LINK: "gwmxyd@163.com", + GITEE_LINK: "https://gitee.com/xydong", + IMG: "/img/home/developer/xuyandong.png" + }, + { + NAME: "夏森林", + TITLE: "", + RANK: "Desktop Maintainer", + MAIL_LINK: "13813374731@163.com", + GITEE_LINK: "https://gitee.com/small_leek", + IMG: "/img/home/developer/xiasenglin.png" + }, + { + NAME: "伍伯东", + TITLE: "", + RANK: "CICD SIG-Maintainer", + MAIL_LINK: "walkingwalk@163.com", + GITEE_LINK: "https://gitee.com/walkingwalk", + IMG: "/img/home/developer/wubodong.png" + }, + { + NAME: "王晓鹏", + TITLE: "", + RANK: "Networking SIG Maintainer", + MAIL_LINK: "wangxp006@163.com", + GITEE_LINK: "https://gitee.com/wangxp006", + IMG: "/img/home/developer/wangxiaopeng.png" + }, + { + NAME: "汪奕如", + TITLE: "", + RANK: "System-Tool Maintainer", + MAIL_LINK: "wangyiruapp@163.com", + GITEE_LINK: "https://gitee.com/ruebb", + IMG: "/img/home/developer/wangyiru.png" + }, + { + NAME: "林飞龙", + TITLE: "", + RANK: "Storage Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + { + NAME: "李清清", + TITLE: "", + RANK: "sig-RISC-V-Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/liqingqing.png" + }, + { + NAME: "李次华", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "lilin_0209@163.com", + GITEE_LINK: "https://gitee.com/licihua", + IMG: "/img/home/developer/licihua.png" + }, + { + NAME: "韩欣科", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "1152071778@qq.com", + GITEE_LINK: "https://gitee.com/hanxinke", + IMG: "/img/home/developer/hanxingke.png" + }, + { + NAME: "郭寒军", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "dileimao@126.com", + GITEE_LINK: "https://gitee.com/hanjun-guo", + IMG: "/img/home/developer/guohanjun.png" + }, + { + NAME: "胡峰", + TITLE: "Application, System-tool, ", + RANK: "Packaging SIG Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/hufen.png" + }, + { + NAME: "杜开田", + TITLE: "Compatibility, CICD", + RANK: "Application", + MAIL_LINK: "dukaitian@huawei.com", + GITEE_LINK: "https://gitee.com/jimmy_hero", + IMG: "/img/home/developer/dukaitian.png" + }, + { + NAME: "何晓文", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "hexiaowen@huawei.com", + GITEE_LINK: "https://gitee.com/overweight_co", + IMG: "/img/home/developer/hexiaowen.png" + }, + { + NAME: "朱春意", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "zhuchunyi@huawei.com", + GITEE_LINK: "https://gitee.com/zhuchunyi", + IMG: "/img/home/developer/zhuchunyi.png" + }, + { + NAME: "谢秀奇", + TITLE: "Kernel SIG", + RANK: "Maintainer", + MAIL_LINK: "xiexiuqi@huawei.com", + GITEE_LINK: "https://gitee.com/xiexiuqi", + IMG: "/img/home/developer/xiexiuqi.png" + }, + { + NAME: "董剑", + TITLE: "Packaging SIG", + RANK: "Maintainer", + MAIL_LINK: "dongjian13@huawei.com", + GITEE_LINK: "https://gitee.com/dogsheng", + IMG: "/img/home/developer/dongjian.png" + }, + { + NAME: "蔡灏旻", + TITLE: "iSulad SIG", + RANK: " Maintainer", + MAIL_LINK: "caihaomin@huawei.com", + GITEE_LINK: "https://gitee.com/caihaomin", + IMG: "/img/home/developer/caihaomin.png" + }, + { + NAME: "李峰", + TITLE: "Container SIG", + RANK: "Maintainer", + MAIL_LINK: "lifeng68@huawei.com", + GITEE_LINK: "https://gitee.com/lifeng2221dd1", + IMG: "/img/home/developer/lifeng.png" + }, + { + NAME: "张海亮", + TITLE: "Virt SIG", + RANK: "Maintainer", + MAIL_LINK: "zhang.zhanghailiang@huawei.com", + GITEE_LINK: "https://gitee.com/zhanghailiang_lucky", + IMG: "/img/home/developer/zhanghailiang.png" + }, + { + NAME: "郑弦", + TITLE: "sig-ai-bigdata SIG", + RANK: "Maintainer", + MAIL_LINK: "sinever@126.com", + GITEE_LINK: "gitee.com/sinever", + IMG: "/img/home/developer/zhengxian.png" + }, + { + NAME: "朱健伟", + TITLE: "Base-Service SIG", + RANK: "Maintainer", + MAIL_LINK: "zhujianwei7@huawei.com", + GITEE_LINK: "https://gitee.com/zhujianwei001", + IMG: "/img/home/developer/zhujianwei.png" + }, + { + NAME: "谢志鹏", + TITLE: "A-Tune SIG", + RANK: "Maintainer", + MAIL_LINK: "xiezhipeng1@huawei.com", + GITEE_LINK: "https://gitee.com/xiezhipeng1", + IMG: "/img/home/developer/xiezhipeng.png" + }, + { + NAME: "熊伟", + TITLE: "sig-perl-modules/ sig-perl-", + RANK: "modules SIG Maintainer", + MAIL_LINK: "xiongwei888@huawei.com", + GITEE_LINK: "https://gitee.com/myeuler", + IMG: "/img/home/developer/xiongwei.png" + }, + { + NAME: "朱延朋", + TITLE: "sig-release-management", + RANK: "SIG Maintainer", + MAIL_LINK: "zhuyanpeng@huawei.com", + GITEE_LINK: "https://gitee.com/zyp-rock", + IMG: "/img/home/developer/zhuyanpeng.png" + }, + { + NAME: "刘志强", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "lzhq28@mail.ustc.edu.cn", + GITEE_LINK: "https://gitee.com/liuzhiqiang26", + IMG: "/img/home/developer/liuzhiqiang.png" + }, + { + NAME: "林飞龙", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + ] + }, + HOME_SOURCE: { + SOURCE_TITLE: "获取更多资源", + SOURCE_APPLY: { + TITLE: "测试资源申请", + DES: "如果缺乏测试设备,可以尝试", + APPLY: "在此申请。", + SPONSOR: "感谢鹏城实验室赞助", + SPONSORLINK: 'https://dw.pcl.ac.cn/' + }, + SOURCE_MAIL: { + TITLE: "邮件订阅", + DES: "任何社区话题都可以在这里讨论。", + SUBSCRIBE: "更多订阅请点击", + LINK: "邮件列表", + MAIL: "community@openeuler.org" + }, + SOURCE_PUBLISH_TITLE: "发布 openEuler 商业发行版的厂商", + SOURCE_LINK_TITLE: "友情链接", + }, + HOME_SOURCE_EDITION: [ + { + LEFT_IMG_LINK: 'http://www.kylinsec.com.cn/', + LEFT_IMG_PC: '/img/home/link/xinan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xinan.png', + RIGHT_IMG_LINK: 'https://www.uniontech.com/', + RIGHT_IMG_PC: '/img/home/link/tongxin.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongxin.png' + }, + { + LEFT_IMG_LINK: 'https://www.kylinos.cn/', + LEFT_IMG_PC: '/img/home/link/qiling.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-qiling.png', + RIGHT_IMG_LINK: 'http://www.iscas.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/iscas.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-iscas.png', + }, + { + LEFT_IMG_LINK: 'http://www.i-soft.com.cn/', + LEFT_IMG_PC: '/img/home/link/cetc.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-cetc.png', + RIGHT_IMG_LINK: 'https://www.turbolinux.com.cn/', + RIGHT_IMG_PC: '/img/home/link/turbo.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-turbo.png' + }, + { + LEFT_IMG_LINK: 'http://www.hoperun.com/', + LEFT_IMG_PC: '/img/home/link/hopeRun.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-hopeRun.png', + RIGHT_IMG_LINK: 'http://www.tongyuanos.com/', + RIGHT_IMG_PC: '/img/home/link/tongYuan.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongYuan.png' + }, + { + LEFT_IMG_LINK: 'http://www.chinaredflag.cn/', + LEFT_IMG_PC: '/img/home/link/zhongkehongqi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkehongqi.png', + RIGHT_IMG_LINK: 'https://www.suse.com/', + RIGHT_IMG_PC: '/img/home/link/suse.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-suse.png' + }, + { + LEFT_IMG_LINK: 'http://www.nfs-china.com/index.html', + LEFT_IMG_PC: '/img/home/link/zhongkefangde.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkefangde.png', + RIGHT_IMG_LINK: 'https://www.xfusion.com/cn/', + RIGHT_IMG_PC: '/img/home/link/xfusion.png', + RIGHT_IMG_MOBILE: '/img/home/link/xfusion_mobile.png', + } + ], + FRIENDSHIP_LINK_LIST: [ + { + LEFT_IMG_LINK: 'http://www.mulanos.cn/', + LEFT_IMG_PC: '/img/home/link/mulan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-mulan.png', + RIGHT_IMG_LINK: 'https://kunpeng.huawei.com/', + RIGHT_IMG_PC: '/img/home/link/kunpeng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-kunpeng.png' + }, + { + LEFT_IMG_LINK: 'http://ic-openlabs.huawei.com/chat/#/', + LEFT_IMG_PC: '/img/home/link/xiaozhi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xiaozhi.png', + RIGHT_IMG_LINK: 'https://dw.pcl.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/pengcheng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-pengcheng.png' + }, + { + LEFT_IMG_LINK: 'https://www.infoq.cn/?utm_source=openeuler&utm_medium=youlian', + LEFT_IMG_PC: '/img/home/link/infoQ.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-infoQ.png', + RIGHT_IMG_LINK: 'https://kaiyuanshe.cn/', + RIGHT_IMG_PC: '/img/home/link/kaiyuanshe-logo.png', + RIGHT_IMG_MOBILE: '/img/home/link/kaiyuanshe-logo-mobile.png', + }, + { + LEFT_IMG_LINK: 'http://www.vulab.com.cn/', + LEFT_IMG_PC: '/img/home/link/zhongke_pc.png', + LEFT_IMG_MOBILE: '/img/home/link/zhongke_mo.png', + RIGHT_IMG_LINK: 'https://www.authing.cn/', + RIGHT_IMG_PC: '/img/home/link/Authing_pc.png', + RIGHT_IMG_MOBILE: '/img/home/link/Authing_mo.png', + }, + ], + MORE: "更多", + EXPAND: "展开全部", + RETRACT: "收起全部" + }, + en: { + HOME_CAROUSEL_DATA: [ + { + TITLE: "iSula", + LINK: "/other/projects/isula", + DES: "Packs a huge punch in a small size", + IMG: "/img/minisite/isula/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/iSula.mp4" + }, + { + TITLE: "A-Tune", + LINK: "/other/projects/atune", + DES: "AI-based Tuning Engine", + IMG: "/img/minisite/atune/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/A-Tune.mp4" + }, + { + TITLE: "StratoVirt", + LINK: "/other/projects/stratovirt", + DES: "Virtualization platform for cloud data centers", + IMG: "/img/minisite/svirt/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/StratoVirt-minisite.mp4" + } + ], + HOME_NEWRELEASE: [ + { + MOBILE_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_mo.png')", + PC_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_pc.png')", + LINK: '/interaction/summit-list/devday2022/' + }, + ], + ROOM_LEFT_IMG: [ + { + IMG: '/img/home/blogImg.png', + LINK: '/interaction/blog-list/' + }, + { + IMG: '/img/home/newsImg.png', + LINK: '/interaction/news-list/' + } + ], + HOME_LAST_BANNER: {}, + HOME_INTRODUCE: { + INTRO_TITLE: "The Most Innovative Open Source Community", + INTRO_HEAD: "Start your journey in openEuler", + INTRO_DESCRIPTION: "As an open community, openEuler works with global developers to build an open, diverse, and architecture-inclusive software ecosystem that supports multiple processor architectures and covers a full range of digital facilities. openEuler is committed to supercharging enterprise digital infrastructure and boosting the application ecosystem.", + INTRO_IMG_URL: "", + INTRO_MAP: [ + { + NAME: "01", + TITLE: " Download openEuler ISO", + IMG: "/img/home/step1.png", + GIF: "/img/home/step-move-1.gif", + LINK: "/download/", + }, + { + NAME: "02", + TITLE: "Use openEuler OS", + IMG: "/img/home/step2.png", + GIF: "/img/home/step-move-2.gif", + LINK: "", + }, + { + NAME: "03", + TITLE: "Read openEuler Documentation", + IMG: "/img/home/step3.png", + GIF: "/img/home/step-move-3.gif", + LINK: "/docs/", + OTHER_LINK: "/en/" + }, + { + NAME: "04", + TITLE: "Contribute to openEuler Community", + IMG: "/img/home/step4.png", + GIF: "/img/home/step-move-4.gif", + LINK: "/community/contribution/", + }, + + ], + INTRO_MAP_SND: { + NAME: "02", + TITLE: "Use openEuler OS", + IMG: "/img/home/step2.png", + LINK: "", + GIF: "/img/home/step-move-2.gif" + }, + INTRO_GUIDE: { + INFO: "Choose your favorite experience mode", + GUIDE_WAY: [ + { + TITLE: "Raspberry Pi", + IMG: "/img/home/areaPai.png", + LINK: "https://gitee.com/openeuler/raspberrypi" + }, + { + TITLE: "Hardware", + IMG: "/img/home/areaHardware.svg", + LINK: "/en/docs/20.03_LTS/docs/Installation/Installation.html" + }, + { + TITLE: "VM", + IMG: "/img/home/areaVirtual.svg", + LINK: "/en/docs/20.03_LTS/docs/Virtualization/virtualization.html" + }, + { + TITLE: "ECS", + IMG: "/img/home/areaECS.svg", + LINK: "https://huaweicloud.com/product/ecs.html" + } + ] + } + }, + HOME_ACTIVE: { + ACTIVE_TITLE: "Join Us in Community Activities", + ACTIVE_DESCRIPTION: "Join us in workshops, SIG discussions, offline activities, and community summits to keep abreast of the latest trend." + }, + HOME_ROUND: { + ROUND_TITLE: 'We Are Thriving', + VIEW_DETAIL: 'View details', + VIEW_DETAIL_LINK: 'https://datastat.openeuler.org/en/overview', + ROUND_LIST: [ + { + ROUND_VALUE: '', + ROUND_KEY: 'contributors', + ROUND_IMG: '/img/round/contributer.png', + ROUND_TEXT: 'Contributor', + ROUND_STYLE: { + backcolor: 'blue' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'repos', + ROUND_IMG: '/img/round/software.png', + ROUND_TEXT: 'Repository', + ROUND_STYLE: { + backcolor: 'pink' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'sigs', + ROUND_IMG: '/img/round/sig.png', + ROUND_TEXT: 'SIG', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'users', + ROUND_IMG: '/img/round/user.png', + ROUND_TEXT: 'User', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'businessosv', + ROUND_IMG: '/img/round/osv.png', + ROUND_TEXT: 'OS Vendor', + ROUND_STYLE: { + backcolor: 'blue' + } + } + ] + }, + HOME_ROOMS: { + ROOM_NAME: ["Latest Activity", "Blog", "News"], + EVENT_NAME: "Latest Activity", + BLOG_NAME: "Blog", + EVENT_LIST: [ + { + TAG: "事件", + DATE: "2020-06-07", + CONTENT: "吹响开源集结号——”点亮“暑假2020" + }, + { + TAG: "事件", + DATE: "2020-01-04", + CONTENT: "去HDC.Cloud 2020 参加黑客松, 玩儿openEuler,赢取大礼" + }, + { + TAG: "事件", + DATE: "2020-12-10", + CONTENT: "HDC.Cloud | openEuler黑客马拉松" + }, + ], + NEWS_LIST: [ + { + TAG: "极云IT杂谈", + DATE: "2020-05-09", + CONTENT: "华为OpenEuler操作系统强势来袭,正式开源时代来了?" + }, + { + TAG: "中国网科学频道", + DATE: "2020-05-06", + CONTENT: "华为联合产业伙伴openEuler2020年峰会成功召开" + }, + { + TAG: "新浪", + DATE: "2020-04-12", + CONTENT: "openEuler开源路带来多样性计算计算技术与产业生态共荣" + }, + ], + NEWS_NAME: "News" + }, + HOME_DEV: { + DEV_TITLE: "Like-Minded Developers", + DEV_DESCRIPTION: "The brightest minds of the development community gather here. Find the elite developers you are interested in.", + DEV_INFO: [ + { + NAME: "Tao Feng", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "t.feng94@foxmail.com", + GITEE_LINK: "https://gitee.com/t_feng", + IMG: "/img/home/developer/fengtao.png" + }, + { + NAME: "Ge Guo", + TITLE: "", + RANK: "Compiler SIG Maintainer", + MAIL_LINK: "nobleprize@foxmail.com", + GITEE_LINK: "https://gitee.com/jdkboy", + IMG: "/img/home/developer/guoge.png" + }, + { + NAME: "Li Yang", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "rainbow1981@163.com", + GITEE_LINK: "https://gitee.com/yangli69393", + IMG: "/img/home/developer/yangli.png" + }, + { + NAME: "Xuzhou Zhang", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "whoisxxx@126.com", + GITEE_LINK: "https://gitee.com/whoisxxx", + IMG: "/img/home/developer/zhangxuzhou.png" + }, + { + NAME: "Rui Zhang", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "13851924834@139.com", + GITEE_LINK: "https://gitee.com/anonymous_z", + IMG: "/img/home/developer/zhangrui.png" + }, + { + NAME: "Yingliang Yang", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "zjutyyl@163.com", + GITEE_LINK: "https://gitee.com/yangyingliang", + IMG: "/img/home/developer/yangyingliang.png" + }, + { + NAME: "Yandong Xu", + TITLE: "", + RANK: "Virt-Maintainer", + MAIL_LINK: "gwmxyd@163.com", + GITEE_LINK: "https://gitee.com/xydong", + IMG: "/img/home/developer/xuyandong.png" + }, + { + NAME: "Senglin Xia", + TITLE: "", + RANK: "Desktop Maintainer", + MAIL_LINK: "13813374731@163.com", + GITEE_LINK: "https://gitee.com/small_leek", + IMG: "/img/home/developer/xiasenglin.png" + }, + { + NAME: "Bodong Wu", + TITLE: "", + RANK: "CICD SIG-Maintainer", + MAIL_LINK: "walkingwalk@163.com", + GITEE_LINK: "https://gitee.com/walkingwalk", + IMG: "/img/home/developer/wubodong.png" + }, + { + NAME: "Xiaopeng Wang", + TITLE: "", + RANK: "Networking SIG Maintainer", + MAIL_LINK: "wangxp006@163.com", + GITEE_LINK: "https://gitee.com/wangxp006", + IMG: "/img/home/developer/wangxiaopeng.png" + }, + { + NAME: "Yiru Wang", + TITLE: "", + RANK: "System-Tool Maintainer", + MAIL_LINK: "wangyiruapp@163.com", + GITEE_LINK: "https://gitee.com/ruebb", + IMG: "/img/home/developer/wangyiru.png" + }, + { + NAME: "Feilong Lin", + TITLE: "", + RANK: "Storage Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + { + NAME: "Qingqing Li", + TITLE: "", + RANK: "sig-RISC-V-Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/liqingqing.png" + }, + { + NAME: "Cihua Li", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "lilin_0209@163.com", + GITEE_LINK: "https://gitee.com/licihua", + IMG: "/img/home/developer/licihua.png" + }, + { + NAME: "Xingke Han", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "1152071778@qq.com", + GITEE_LINK: "https://gitee.com/hanxinke", + IMG: "/img/home/developer/hanxingke.png" + }, + { + NAME: "Hanjun Guo", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "dileimao@126.com", + GITEE_LINK: "https://gitee.com/hanjun-guo", + IMG: "/img/home/developer/guohanjun.png" + }, + { + NAME: "Feng Hu", + TITLE: "Application, System-tool, ", + RANK: "Packaging SIG Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/hufen.png" + }, + { + NAME: "Kaitian Du", + TITLE: "Application, CICD SIG", + RANK: "Maintainer", + MAIL_LINK: "dukaitian@huawei.com", + GITEE_LINK: "https://gitee.com/jimmy_hero", + IMG: "/img/home/developer/dukaitian.png" + }, + { + NAME: "Xiaowen He", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "hexiaowen@huawei.com", + GITEE_LINK: "https://gitee.com/jimmy_hero", + IMG: "/img/home/developer/hexiaowen.png" + }, + { + NAME: "Chunyi Zhu", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "zhuchunyi@huawei.com", + GITEE_LINK: "https://gitee.com/zhuchunyi", + IMG: "/img/home/developer/zhuchunyi.png" + }, + { + NAME: "Xiuqi Xie", + TITLE: "Kernel SIG", + RANK: "Maintainer", + MAIL_LINK: "xiexiuqi@huawei.com", + GITEE_LINK: "https://gitee.com/xiexiuqi", + IMG: "/img/home/developer/xiexiuqi.png" + }, + { + NAME: "Jian Dong", + TITLE: "Packaging SIG", + RANK: "Maintainer", + MAIL_LINK: "dongjian13@huawei.com", + GITEE_LINK: "https://gitee.com/dogsheng", + IMG: "/img/home/developer/dongjian.png" + }, + { + NAME: "Haomin Tsai", + TITLE: "iSulad SIG", + RANK: " Maintainer", + MAIL_LINK: "caihaomin@huawei.com", + GITEE_LINK: "https://gitee.com/caihaomin", + IMG: "/img/home/developer/caihaomin.png" + }, + { + NAME: "Feng Li", + TITLE: "Container SIG", + RANK: "Maintainer", + MAIL_LINK: "lifeng68@huawei.com", + GITEE_LINK: "https://gitee.com/lifeng2221dd1", + IMG: "/img/home/developer/lifeng.png" + }, + { + NAME: "Hailiang Zhang", + TITLE: "Virt SIG", + RANK: "Maintainer", + MAIL_LINK: "zhang.zhanghailiang@huawei.com", + GITEE_LINK: "https://gitee.com/zhanghailiang_lucky", + IMG: "/img/home/developer/zhanghailiang.png" + }, + { + NAME: "Xuan Zheng", + TITLE: "sig-ai-bigdata SIG", + RANK: "Maintainer", + MAIL_LINK: "sinever@126.com", + GITEE_LINK: "gitee.com/sinever", + IMG: "/img/home/developer/zhengxian.png" + }, + { + NAME: "Jianwei Zhu", + TITLE: "Base-Service SIG", + RANK: "Maintainer", + MAIL_LINK: "zhujianwei7@huawei.com", + GITEE_LINK: "https://gitee.com/zhujianwei001", + IMG: "/img/home/developer/zhujianwei.png" + }, + { + NAME: "Zhipeng Xie", + TITLE: "A-Tune SIG", + RANK: "Maintainer", + MAIL_LINK: "xiezhipeng1@huawei.com", + GITEE_LINK: "https://gitee.com/xiezhipeng1", + IMG: "/img/home/developer/xiezhipeng.png" + }, + { + NAME: "Wei Xiong", + TITLE: "sig-perl-modules/ sig-perl-", + RANK: "Modules SIG Maintainer", + MAIL_LINK: "xiongwei888@huawei.com", + GITEE_LINK: "https://gitee.com/myeuler", + IMG: "/img/home/developer/xiongwei.png" + }, + { + NAME: "Yanpeng Zhu", + TITLE: "sig-release-management", + RANK: "SIG Maintainer", + MAIL_LINK: "zhuyanpeng@huawei.com", + GITEE_LINK: "https://gitee.com/zyp-rock", + IMG: "/img/home/developer/zhuyanpeng.png" + }, + { + NAME: "Zhiqiang Liu", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "lzhq28@mail.ustc.edu.cn", + GITEE_LINK: "https://gitee.com/liuzhiqiang26", + IMG: "/img/home/developer/liuzhiqiang.png" + }, + { + NAME: "Feilong Lin", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + ] + }, + HOME_SOURCE: { + SOURCE_TITLE: "More Resources", + SOURCE_APPLY: { + TITLE: "Test Resource Application", + DES: "If test devices are not available, you can", + APPLY: "apply for resources here.", + SPONSOR: "Thanks for the sponsorship of Peng Cheng Laboratory.", + SPONSORLINK: 'https://dw.pcl.ac.cn/' + }, + SOURCE_MAIL: { + TITLE: "E-mail Subscription", + DES: "Discuss any community topic here.", + SUBSCRIBE: "For more subscriptions, please click the ", + LINK: "Mailing Lists", + MAIL: "community@openeuler.org" + }, + SOURCE_PUBLISH_TITLE: "Vendors with openEuler-based Commercial Editions", + SOURCE_LINK_TITLE: "Reference Links", + }, + HOME_SOURCE_EDITION: [ + { + LEFT_IMG_LINK: 'http://www.kylinsec.com.cn/', + LEFT_IMG_PC: '/img/home/link/xinan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xinan.png', + RIGHT_IMG_LINK: 'https://www.uniontech.com/', + RIGHT_IMG_PC: '/img/home/link/tongxin.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongxin.png' + }, + { + LEFT_IMG_LINK: 'https://www.kylinos.cn/', + LEFT_IMG_PC: '/img/home/link/qiling.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-qiling.png', + RIGHT_IMG_LINK: 'http://www.iscas.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/iscas.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-iscas.png', + }, + { + LEFT_IMG_LINK: 'http://www.i-soft.com.cn/', + LEFT_IMG_PC: '/img/home/link/cetc.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-cetc.png', + RIGHT_IMG_LINK: 'https://www.turbolinux.com.cn/', + RIGHT_IMG_PC: '/img/home/link/turbo.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-turbo.png' + }, + { + LEFT_IMG_LINK: 'http://www.hoperun.com/', + LEFT_IMG_PC: '/img/home/link/hopeRun.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-hopeRun.png', + RIGHT_IMG_LINK: 'http://www.tongyuanos.com/', + RIGHT_IMG_PC: '/img/home/link/tongYuan.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongYuan.png' + }, + { + LEFT_IMG_LINK: 'http://www.chinaredflag.cn/', + LEFT_IMG_PC: '/img/home/link/zhongkehongqi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkehongqi.png', + RIGHT_IMG_LINK: 'https://www.suse.com/', + RIGHT_IMG_PC: '/img/home/link/suse.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-suse.png' + }, + { + LEFT_IMG_LINK: 'http://www.nfs-china.com/index.html', + LEFT_IMG_PC: '/img/home/link/zhongkefangde.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkefangde.png', + RIGHT_IMG_LINK: 'https://www.xfusion.com/en/', + RIGHT_IMG_PC: '/img/home/link/xfusion.png', + RIGHT_IMG_MOBILE: '/img/home/link/xfusion_mobile.png', + }, + ], + FRIENDSHIP_LINK_LIST: [ + { + LEFT_IMG_LINK: 'http://www.mulanos.cn/', + LEFT_IMG_PC: '/img/home/link/mulan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-mulan.png', + RIGHT_IMG_LINK: 'https://kunpeng.huawei.com/', + RIGHT_IMG_PC: '/img/home/link/kunpeng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-kunpeng.png' + }, + { + LEFT_IMG_LINK: 'http://ic-openlabs.huawei.com/chat/#/', + LEFT_IMG_PC: '/img/home/link/xiaozhi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xiaozhi.png', + RIGHT_IMG_LINK: 'https://dw.pcl.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/pengcheng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-pengcheng.png' + }, + { + LEFT_IMG_LINK: 'https://www.infoq.cn/?utm_source=openeuler&utm_medium=youlian', + LEFT_IMG_PC: '/img/home/link/infoQ.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-infoQ.png', + RIGHT_IMG_LINK: 'https://kaiyuanshe.cn/', + RIGHT_IMG_PC: '/img/home/link/kaiyuanshe-logo.png', + RIGHT_IMG_MOBILE: '/img/home/link/kaiyuanshe-logo-mobile.png', + }, + { + LEFT_IMG_LINK: 'http://www.vulab.com.cn/', + LEFT_IMG_PC: '/img/home/link/zhongke_pc.png', + LEFT_IMG_MOBILE: '/img/home/link/zhongke_mo.png', + RIGHT_IMG_LINK: 'https://www.authing.cn/', + RIGHT_IMG_PC: '/img/home/link/Authing_pc.png', + RIGHT_IMG_MOBILE: '/img/home/link/Authing_mo.png', + }, + ], + MORE: "Read More", + EXPAND: "Expand All", + RETRACT: "Collapse All" + }, + ru: { + HOME_CAROUSEL_DATA: [ + { + TITLE: "iSula", + LINK: "/other/projects/isula", + DES: "Ударная сила в компактном размере", + IMG: "/img/minisite/isula/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/iSula.mp4" + }, + { + TITLE: "A-Tune", + LINK: "/other/projects/atune", + DES: "инструмент настройки на базе ИИ", + IMG: "/img/minisite/atune/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/A-Tune.mp4" + }, + { + TITLE: "StratoVirt", + LINK: "/other/projects/stratovirt", + DES: "Платформа виртуализации для облачных центров обработки данных", + IMG: "/img/minisite/svirt/mobile-banner.png", + VIDEO_URL: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/StratoVirt-minisite.mp4" + } + ], + HOME_NEWRELEASE: [ + { + MOBILE_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_mo.png')", + PC_IMG: "url('https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-devday-2022/images/home_devday_pc.png')", + LINK: '/interaction/summit-list/devday2022/' + }, + ], + ROOM_LEFT_IMG: [ + { + IMG: '/img/home/blogImg.png', + LINK: '/interaction/blog-list/' + }, + { + IMG: '/img/home/newsImg.png', + LINK: '/interaction/news-list/' + } + ], + HOME_LAST_BANNER: {}, + HOME_INTRODUCE: { + INTRO_TITLE: "The Most Innovative Open Source Community", + INTRO_HEAD: "Начните свой путь в openEuler", + INTRO_DESCRIPTION: "Как открытое сообщество, openEuler работает с глобальными разработчиками, чтобы создать открытую, разнообразную и интегрированную с архитектурой экосистему программного обеспечения, которая поддерживает многопроцессорную архитектуру и охватывает весь спектр цифровых средств. openEuler стремится к эффективности корпоративной цифровой инфраструктуры и развитию экосистемы приложений.", + INTRO_IMG_URL: "", + INTRO_MAP: [ + { + NAME: "01", + TITLE: "Загрузить ISO openEuler", + IMG: "/img/home/step1.png", + GIF: "/img/home/step-move-1.gif", + LINK: "/download/", + }, + { + NAME: "02", + TITLE: "Использовать ОС openEuler", + IMG: "/img/home/step2.png", + GIF: "/img/home/step-move-2.gif", + LINK: "", + OTHER_LINK: "/ru/" + }, + { + NAME: "03", + TITLE: "Читать документацию openEuler", + IMG: "/img/home/step3.png", + GIF: "/img/home/step-move-3.gif", + LINK: "/docs/", + OTHER_LINK: "/en/" + }, + { + NAME: "04", + TITLE: "Участвовать в сообществе openEuler", + IMG: "/img/home/step4.png", + GIF: "/img/home/step-move-4.gif", + LINK: "/community/contribution/", + }, + + ], + INTRO_MAP_SND: { + NAME: "02", + TITLE: "Использовать ОС openEuler", + IMG: "/img/home/step2.png", + LINK: "", + GIF: "/img/home/step-move-2.gif" + }, + INTRO_GUIDE: { + INFO: "Choose your favorite experience mode", + GUIDE_WAY: [ + { + TITLE: "Raspberry Pi", + IMG: "/img/home/areaPai.png", + LINK: "https://gitee.com/openeuler/raspberrypi" + }, + { + TITLE: "Hardware", + IMG: "/img/home/areaHardware.svg", + LINK: "/en/docs/20.03_LTS/docs/Installation/Installation.html" + }, + { + TITLE: "VM", + IMG: "/img/home/areaVirtual.svg", + LINK: "/en/docs/20.03_LTS/docs/Virtualization/virtualization.html" + }, + { + TITLE: "ECS", + IMG: "/img/home/areaECS.svg", + LINK: "https://huaweicloud.com/product/ecs.html" + } + ] + } + }, + HOME_ACTIVE: { + ACTIVE_TITLE: "Присоединиться к сообществу", + ACTIVE_DESCRIPTION: "Присоединяйтесь к сообществу и участвуйте в семинарах, обсуждениях специальных групп (SIG), традиционных мероприятиях и саммитах сообщества, чтобы быть в курсе актуальных тенденций." + }, + HOME_ROUND: { + ROUND_TITLE: 'Мы процветаем', + VIEW_DETAIL: 'View details', + VIEW_DETAIL_LINK: 'https://datastat.openeuler.org/en/overview', + ROUND_LIST: [ + { + ROUND_VALUE: '', + ROUND_KEY: 'contributors', + ROUND_IMG: '/img/round/contributer.png', + ROUND_TEXT: 'участников', + ROUND_STYLE: { + backcolor: 'blue' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'repos', + ROUND_IMG: '/img/round/software.png', + ROUND_TEXT: 'программных продуктов', + ROUND_STYLE: { + backcolor: 'pink' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'sigs', + ROUND_IMG: '/img/round/sig.png', + ROUND_TEXT: 'групп SIG', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'users', + ROUND_IMG: '/img/round/user.png', + ROUND_TEXT: 'пользователей', + ROUND_STYLE: { + backcolor: 'yellow' + } + }, + { + ROUND_VALUE: '', + ROUND_KEY: 'businessosv', + ROUND_IMG: '/img/round/osv.png', + ROUND_TEXT: 'поставщиков ОС', + ROUND_STYLE: { + backcolor: 'blue' + } + } + ] + }, + HOME_ROOMS: { + ROOM_NAME: ["Новое мероприятие", "Блог", "Новости"], + EVENT_NAME: "Новое мероприятие", + BLOG_NAME: "Блог", + EVENT_LIST: [ + { + TAG: "事件", + DATE: "2020-06-07", + CONTENT: "吹响开源集结号——”点亮“暑假2020" + }, + { + TAG: "事件", + DATE: "2020-01-04", + CONTENT: "去HDC.Cloud 2020 参加黑客松, 玩儿openEuler,赢取大礼" + }, + { + TAG: "事件", + DATE: "2020-12-10", + CONTENT: "HDC.Cloud | openEuler黑客马拉松" + }, + ], + NEWS_LIST: [ + { + TAG: "极云IT杂谈", + DATE: "2020-05-09", + CONTENT: "华为OpenEuler操作系统强势来袭,正式开源时代来了?" + }, + { + TAG: "中国网科学频道", + DATE: "2020-05-06", + CONTENT: "华为联合产业伙伴openEuler2020年峰会成功召开" + }, + { + TAG: "新浪", + DATE: "2020-04-12", + CONTENT: "openEuler开源路带来多样性计算计算技术与产业生态共荣" + }, + ], + NEWS_NAME: "Новости" + }, + HOME_DEV: { + DEV_TITLE: "Разработчики-единомышленники", + DEV_DESCRIPTION: "Здесь собираются блестящие эксперты сообщества разработчиков. Найдите лучшего интересующего вас разработчика.", + DEV_INFO: [ + { + NAME: "Tao Feng", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "t.feng94@foxmail.com", + GITEE_LINK: "https://gitee.com/t_feng", + IMG: "/img/home/developer/fengtao.png" + }, + { + NAME: "Ge Guo", + TITLE: "", + RANK: "Compiler SIG Maintainer", + MAIL_LINK: "nobleprize@foxmail.com", + GITEE_LINK: "https://gitee.com/jdkboy", + IMG: "/img/home/developer/guoge.png" + }, + { + NAME: "Li Yang", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "rainbow1981@163.com", + GITEE_LINK: "https://gitee.com/yangli69393", + IMG: "/img/home/developer/yangli.png" + }, + { + NAME: "Xuzhou Zhang", + TITLE: "", + RANK: "Packaging Maintainer", + MAIL_LINK: "whoisxxx@126.com", + GITEE_LINK: "https://gitee.com/whoisxxx", + IMG: "/img/home/developer/zhangxuzhou.png" + }, + { + NAME: "Rui Zhang", + TITLE: "", + RANK: "sig-OS-Builder-Maintainer", + MAIL_LINK: "13851924834@139.com", + GITEE_LINK: "https://gitee.com/anonymous_z", + IMG: "/img/home/developer/zhangrui.png" + }, + { + NAME: "Yingliang Yang", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "zjutyyl@163.com", + GITEE_LINK: "https://gitee.com/yangyingliang", + IMG: "/img/home/developer/yangyingliang.png" + }, + { + NAME: "Yandong Xu", + TITLE: "", + RANK: "Virt-Maintainer", + MAIL_LINK: "gwmxyd@163.com", + GITEE_LINK: "https://gitee.com/xydong", + IMG: "/img/home/developer/xuyandong.png" + }, + { + NAME: "Senglin Xia", + TITLE: "", + RANK: "Desktop Maintainer", + MAIL_LINK: "13813374731@163.com", + GITEE_LINK: "https://gitee.com/small_leek", + IMG: "/img/home/developer/xiasenglin.png" + }, + { + NAME: "Bodong Wu", + TITLE: "", + RANK: "CICD SIG-Maintainer", + MAIL_LINK: "walkingwalk@163.com", + GITEE_LINK: "https://gitee.com/walkingwalk", + IMG: "/img/home/developer/wubodong.png" + }, + { + NAME: "Xiaopeng Wang", + TITLE: "", + RANK: "Networking SIG Maintainer", + MAIL_LINK: "wangxp006@163.com", + GITEE_LINK: "https://gitee.com/wangxp006", + IMG: "/img/home/developer/wangxiaopeng.png" + }, + { + NAME: "Yiru Wang", + TITLE: "", + RANK: "System-Tool Maintainer", + MAIL_LINK: "wangyiruapp@163.com", + GITEE_LINK: "https://gitee.com/ruebb", + IMG: "/img/home/developer/wangyiru.png" + }, + { + NAME: "Feilong Lin", + TITLE: "", + RANK: "Storage Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + { + NAME: "Qingqing Li", + TITLE: "", + RANK: "sig-RISC-V-Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/liqingqing.png" + }, + { + NAME: "Cihua Li", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "lilin_0209@163.com", + GITEE_LINK: "https://gitee.com/licihua", + IMG: "/img/home/developer/licihua.png" + }, + { + NAME: "Xingke Han", + TITLE: "", + RANK: "Base-Service Maintainer", + MAIL_LINK: "1152071778@qq.com", + GITEE_LINK: "https://gitee.com/hanxinke", + IMG: "/img/home/developer/hanxingke.png" + }, + { + NAME: "Hanjun Guo", + TITLE: "", + RANK: "Kernel Maintainer", + MAIL_LINK: "dileimao@126.com", + GITEE_LINK: "https://gitee.com/hanjun-guo", + IMG: "/img/home/developer/guohanjun.png" + }, + { + NAME: "Feng Hu", + TITLE: "Application, System-tool, ", + RANK: "Packaging SIG Maintainer", + MAIL_LINK: "solar.hu@huawei.com", + GITEE_LINK: "https://gitee.com/solarhu", + IMG: "/img/home/developer/hufen.png" + }, + { + NAME: "Kaitian Du", + TITLE: "Application, CICD SIG", + RANK: "Maintainer", + MAIL_LINK: "dukaitian@huawei.com", + GITEE_LINK: "https://gitee.com/jimmy_hero", + IMG: "/img/home/developer/dukaitian.png" + }, + { + NAME: "Xiaowen He", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "hexiaowen@huawei.com", + GITEE_LINK: "https://gitee.com/jimmy_hero", + IMG: "/img/home/developer/hexiaowen.png" + }, + { + NAME: "Chunyi Zhu", + TITLE: "Packaging SIG, Base-", + RANK: "service SIG Maintainer", + MAIL_LINK: "zhuchunyi@huawei.com", + GITEE_LINK: "https://gitee.com/zhuchunyi", + IMG: "/img/home/developer/zhuchunyi.png" + }, + { + NAME: "Xiuqi Xie", + TITLE: "Kernel SIG", + RANK: "Maintainer", + MAIL_LINK: "xiexiuqi@huawei.com", + GITEE_LINK: "https://gitee.com/xiexiuqi", + IMG: "/img/home/developer/xiexiuqi.png" + }, + { + NAME: "Jian Dong", + TITLE: "Packaging SIG", + RANK: "Maintainer", + MAIL_LINK: "dongjian13@huawei.com", + GITEE_LINK: "https://gitee.com/dogsheng", + IMG: "/img/home/developer/dongjian.png" + }, + { + NAME: "Haomin Tsai", + TITLE: "iSulad SIG", + RANK: " Maintainer", + MAIL_LINK: "caihaomin@huawei.com", + GITEE_LINK: "https://gitee.com/caihaomin", + IMG: "/img/home/developer/caihaomin.png" + }, + { + NAME: "Feng Li", + TITLE: "Container SIG", + RANK: "Maintainer", + MAIL_LINK: "lifeng68@huawei.com", + GITEE_LINK: "https://gitee.com/lifeng2221dd1", + IMG: "/img/home/developer/lifeng.png" + }, + { + NAME: "Hailiang Zhang", + TITLE: "Virt SIG", + RANK: "Maintainer", + MAIL_LINK: "zhang.zhanghailiang@huawei.com", + GITEE_LINK: "https://gitee.com/zhanghailiang_lucky", + IMG: "/img/home/developer/zhanghailiang.png" + }, + { + NAME: "Xuan Zheng", + TITLE: "sig-ai-bigdata SIG", + RANK: "Maintainer", + MAIL_LINK: "sinever@126.com", + GITEE_LINK: "gitee.com/sinever", + IMG: "/img/home/developer/zhengxian.png" + }, + { + NAME: "Jianwei Zhu", + TITLE: "Base-Service SIG", + RANK: "Maintainer", + MAIL_LINK: "zhujianwei7@huawei.com", + GITEE_LINK: "https://gitee.com/zhujianwei001", + IMG: "/img/home/developer/zhujianwei.png" + }, + { + NAME: "Zhipeng Xie", + TITLE: "A-Tune SIG", + RANK: "Maintainer", + MAIL_LINK: "xiezhipeng1@huawei.com", + GITEE_LINK: "https://gitee.com/xiezhipeng1", + IMG: "/img/home/developer/xiezhipeng.png" + }, + { + NAME: "Wei Xiong", + TITLE: "sig-perl-modules/ sig-perl-", + RANK: "Modules SIG Maintainer", + MAIL_LINK: "xiongwei888@huawei.com", + GITEE_LINK: "https://gitee.com/myeuler", + IMG: "/img/home/developer/xiongwei.png" + }, + { + NAME: "Yanpeng Zhu", + TITLE: "sig-release-management", + RANK: "SIG Maintainer", + MAIL_LINK: "zhuyanpeng@huawei.com", + GITEE_LINK: "https://gitee.com/zyp-rock", + IMG: "/img/home/developer/zhuyanpeng.png" + }, + { + NAME: "Zhiqiang Liu", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "lzhq28@mail.ustc.edu.cn", + GITEE_LINK: "https://gitee.com/liuzhiqiang26", + IMG: "/img/home/developer/liuzhiqiang.png" + }, + { + NAME: "Feilong Lin", + TITLE: "Storage SIG", + RANK: "Maintainer", + MAIL_LINK: "404544243@qq.com", + GITEE_LINK: "https://gitee.com/volcanodragon", + IMG: "/img/home/developer/linfeilong.png" + }, + ] + }, + HOME_SOURCE: { + SOURCE_TITLE: "Дополнительные ресурсы", + SOURCE_APPLY: { + TITLE: "Применение тестовых ресурсов", + DES: "Если нет тестовых устройств, вы можете подать", + APPLY: "здесь заявку на их получение.", + SPONSOR: "Благодарим лабораторию Peng Cheng Laboratory за спонсорскую поддержку.", + SPONSORLINK: 'https://dw.pcl.ac.cn/' + }, + SOURCE_MAIL: { + TITLE: "Подписка по электронной почте", + DES: "Вы можете обсудить здесь любую тему сообщества.", + SUBSCRIBE: "Для перехода на страницу с подписками нажмите ", + LINK: "Списки рассылок.", + MAIL: "community@openeuler.org" + }, + SOURCE_PUBLISH_TITLE: "Поставщики с коммерческими версиями на базе openEuler", + SOURCE_LINK_TITLE: "Ссылки", + }, + HOME_SOURCE_EDITION: [ + { + LEFT_IMG_LINK: 'http://www.kylinsec.com.cn/', + LEFT_IMG_PC: '/img/home/link/xinan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xinan.png', + RIGHT_IMG_LINK: 'https://www.uniontech.com/', + RIGHT_IMG_PC: '/img/home/link/tongxin.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongxin.png' + }, + { + LEFT_IMG_LINK: 'https://www.kylinos.cn/', + LEFT_IMG_PC: '/img/home/link/qiling.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-qiling.png', + RIGHT_IMG_LINK: 'http://www.iscas.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/iscas.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-iscas.png', + }, + { + LEFT_IMG_LINK: 'http://www.i-soft.com.cn/', + LEFT_IMG_PC: '/img/home/link/cetc.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-cetc.png', + RIGHT_IMG_LINK: 'https://www.turbolinux.com.cn/', + RIGHT_IMG_PC: '/img/home/link/turbo.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-turbo.png' + }, + { + LEFT_IMG_LINK: 'http://www.hoperun.com/', + LEFT_IMG_PC: '/img/home/link/hopeRun.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-hopeRun.png', + RIGHT_IMG_LINK: 'http://www.tongyuanos.com/', + RIGHT_IMG_PC: '/img/home/link/tongYuan.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-tongYuan.png' + }, + { + LEFT_IMG_LINK: 'http://www.chinaredflag.cn/', + LEFT_IMG_PC: '/img/home/link/zhongkehongqi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkehongqi.png', + RIGHT_IMG_LINK: 'https://www.suse.com/', + RIGHT_IMG_PC: '/img/home/link/suse.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-suse.png' + }, + { + LEFT_IMG_LINK: 'http://www.nfs-china.com/index.html', + LEFT_IMG_PC: '/img/home/link/zhongkefangde.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-zhongkefangde.png', + RIGHT_IMG_LINK: 'https://www.xfusion.com/en/', + RIGHT_IMG_PC: '/img/home/link/xfusion.png', + RIGHT_IMG_MOBILE: '/img/home/link/xfusion_mobile.png', + } + ], + FRIENDSHIP_LINK_LIST: [ + { + LEFT_IMG_LINK: 'http://www.mulanos.cn/', + LEFT_IMG_PC: '/img/home/link/mulan.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-mulan.png', + RIGHT_IMG_LINK: 'https://kunpeng.huawei.com/', + RIGHT_IMG_PC: '/img/home/link/kunpeng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-kunpeng.png' + }, + { + LEFT_IMG_LINK: 'http://ic-openlabs.huawei.com/chat/#/', + LEFT_IMG_PC: '/img/home/link/xiaozhi.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-xiaozhi.png', + RIGHT_IMG_LINK: 'https://dw.pcl.ac.cn/', + RIGHT_IMG_PC: '/img/home/link/pengcheng.png', + RIGHT_IMG_MOBILE: '/img/home/link/mobile-pengcheng.png' + }, + { + LEFT_IMG_LINK: 'https://www.infoq.cn/?utm_source=openeuler&utm_medium=youlian', + LEFT_IMG_PC: '/img/home/link/infoQ.png', + LEFT_IMG_MOBILE: '/img/home/link/mobile-infoQ.png', + RIGHT_IMG_LINK: 'https://kaiyuanshe.cn/', + RIGHT_IMG_PC: '/img/home/link/kaiyuanshe-logo.png', + RIGHT_IMG_MOBILE: '/img/home/link/kaiyuanshe-logo-mobile.png', + }, + { + LEFT_IMG_LINK: 'http://www.vulab.com.cn/', + LEFT_IMG_PC: '/img/home/link/zhongke_pc.png', + LEFT_IMG_MOBILE: '/img/home/link/zhongke_mo.png', + RIGHT_IMG_LINK: 'https://www.authing.cn/', + RIGHT_IMG_PC: '/img/home/link/Authing_pc.png', + RIGHT_IMG_MOBILE: '/img/home/link/Authing_mo.png', + }, + ], + MORE: "Read More", + EXPAND: "Expand All", + RETRACT: "Collapse All" + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/interaction.js b/web-ui/docs/.vuepress/lang/lang-modules/interaction.js new file mode 100644 index 0000000000000000000000000000000000000000..c22507ba29db3481917083c7e78a8de1519ee60c --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/interaction.js @@ -0,0 +1,4346 @@ +/** + * @file 互动模块国际化配置入口 + * */ +module.exports = { + cn: { + LIVE: { + LIVE: '直播', + WILLPLAYER: '即将开始', + REPLAYER: '精彩回顾', + LINKTIPS: '视频未上传,敬请期待!', + LIVENOW: [ + + ], + LIVEFORMERLY: [ + { + LIVETITLE: '手把手教你编写Avocado-VT用例', + LIVETEACHER: '讲师: 朱欢凯', + LIVETIME: '时间: 12月14日 20:00(周二)', + PHOTOPATH: '/img/live/zhuhuankai.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Vz4y1r7fk' + }, + { + LIVETITLE: '玩转虚拟化测试Avocado-VT', + LIVETEACHER: '讲师: 柯志明', + LIVETIME: '时间: 12月1日 20:00(周二)', + PHOTOPATH: '/img/live/kezhiming.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ey4y1S7xv' + }, + { + LIVETITLE: 'StratoVirt之IO子系统剖析', + LIVETEACHER: '讲师: 张亮', + LIVETIME: '时间: 11月17日 20:00(周二)', + PHOTOPATH: '/img/live/zhangliang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17z4y1y7ME' + }, + { + LIVETITLE: 'StratoVirt之内存子系统剖析', + LIVETEACHER: '讲师: 杨晓鹤', + LIVETIME: '时间: 11月10日 20:00(周二)', + PHOTOPATH: '/img/live/yangxiaohe.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1XV411y73z' + }, + { + LIVETITLE: 'StratoVirt之CPU子系统剖析', + LIVETEACHER: '讲师: 高玮', + LIVETIME: '时间: 11月3日 20:00(周二)', + PHOTOPATH: '/img/live/gaowei.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YA411j7Ws' + }, + { + LIVETITLE: '如何安装并使用StratoVirt', + LIVETEACHER: '讲师: 郭馨乐', + LIVETIME: '时间: 10月27日 20:00(周二)', + PHOTOPATH: '/img/live/guoxinle.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ji4y177NC' + }, + { + LIVETITLE: '下一代虚拟化技术StratoVirt介绍', + LIVETEACHER: '讲师: 王志钢', + LIVETIME: '时间: 10月20日 20:00(周二)', + PHOTOPATH: '/img/live/wangzhigang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1gv411C7sK' + }, + { + LIVETITLE: '手把手带你完成openEuler环境部署 K8S', + LIVETEACHER: '讲师: 夏丹妮', + LIVETIME: '时间: 9月17日 20:00(周四)', + PHOTOPATH: '/img/live/xiadanni.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1At4y1e7mq' + }, + { + LIVETITLE: 'iSula容器之安全容器', + LIVETEACHER: '讲师: 姜鹏飞', + LIVETIME: '时间: 9月15日 20:00(周二)', + PHOTOPATH: '/img/live/jiangpengfei.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV14r4y1F7Dp' + }, + { + LIVETITLE: 'iSula容器之系统容器', + LIVETEACHER: '讲师: 章松', + LIVETIME: '时间: 9月10日 20:00(周四)', + PHOTOPATH: '/img/live/zhangsong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之安全特性实现解析', + LIVETEACHER: '讲师: 吴景', + LIVETIME: '时间: 9月8日 20:00(周二)', + PHOTOPATH: '/img/live/wujing.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之性能测试、分析与比较', + LIVETEACHER: '讲师: 刘昊', + LIVETIME: '时间: 9月3日 20:00(周四)', + PHOTOPATH: '/img/live/liuhao.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Mf4y1q7Ek' + }, + { + LIVETITLE: '轻量级容器引擎iSulad之功能介绍及架构解析', + LIVETEACHER: '讲师: 李峰', + LIVETIME: '时间: 9月1日 20:00(周二)', + PHOTOPATH: '/img/live/lifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV12y4y1C7Gr' + }, + { + LIVETITLE: 'isula-build之架构介绍', + LIVETEACHER: '讲师: 刘泽坤', + LIVETIME: '时间: 8月25日 20:00(周二)', + PHOTOPATH: '/img/live/liuzekun.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Gp4y1i7Rs' + }, + { + LIVETITLE: 'isula-build之源码剖析', + LIVETEACHER: '讲师: 李翔', + LIVETIME: '时间: 8月27日 20:00(周四)', + PHOTOPATH: '/img/live/lixiang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ca4y177te' + }, + { + LIVETITLE: '虚拟化技术介绍', + LIVETEACHER: '讲师: 张海亮', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhanghailiang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1of4y1X7p1' + }, + { + LIVETITLE: '安装虚拟化&管理虚拟机', + LIVETEACHER: '讲师: 陈振东', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/chenzhendong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: '初始openEuler', + LIVETEACHER: '讲师: 朱延朋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuyanpeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1it4y197KQ' + }, + { + LIVETITLE: '安装openEuler', + LIVETEACHER: '讲师: 冯涛', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/fengtao.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1vK4y1s7QG' + }, + { + LIVETITLE: '使用openEuler', + LIVETEACHER: '讲师: 沈洋洋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/shenyangyang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV13z4y1D7mq' + }, + { + LIVETITLE: 'openEuler构建之OBS使用指导', + LIVETEACHER: '讲师: 朱春意', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuchunyi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YK411H7E2' + }, + { + LIVETITLE: 'openEuler软件包的构建、开发与维护', + LIVETEACHER: '讲师: 何晓文', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/hexiaowen.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1pK411J7R9' + }, + { + LIVETITLE: '如何参与openEuler内核开发', + LIVETEACHER: '讲师: 谢秀奇', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/xiexiuqi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV11i4y1u7r9' + }, + { + LIVETITLE: 'openEuler网络配置', + LIVETEACHER: '讲师: 马郡', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/majun.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17C4y187sM' + }, + { + LIVETITLE: '可信计算之内核完整性度量', + LIVETEACHER: '讲师: 张天行', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhangtianxing.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1dk4y1171e' + }, + { + LIVETITLE: '开源版权和License3', + LIVETEACHER: '讲师: 卜瑞峰', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/boruifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ty4y1y7eK' + }, + ] + }, + SUMMIT: { + SUMMIT: '峰会', + NAV_LIST: [ + { + key: '#liveroom', + name: '观看直播' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#host-unit', + name: '合作伙伴' + } + ], + SUMMITCONTENT: [ + 'openEuler Summit 是由 openEuler 社区举办的开发者交流会,首届线下 openEuler Summit 2020 将于 12 月 24-25 日在北京·望京凯悦酒店举办。openEuler 是一个面向未来的开源操作系统,依托于最具活力的 openEuler 社区,它的未来将不止于操作系统!', + 'openEuler Summit 2020 将聚焦于软硬件协同、云边端协同的技术趋势,万物互联的多算力场景,挖掘技术创新与社区生态的价值。开发者、用户、社区贡献者、软件爱好者在 openEuler Summit 上汇聚成海,连接行业上下游,让全产业链共享操作系统创新价值。' + ], + LIVETITLE: '峰会直播间', + PC_LIVEIMG: '/img/summit/home/zh-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/zh-mobile-liveroom.png', + SUMMITLIVE: { + RENDERDATA: [ + { + ID: 7095, + THEME: 'openEuler Summit 2020', + TIME: '09:30-11:55 ', + OPTION: '09:30-11:55 openEuler Summit 2020', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7095?lang=zh&thirdId=' + }, + { + ID: 7096, + THEME: '操作系统', + TIME: '14:00-17:20 ', + OPTION: '14:00-17:20 操作系统', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7096?lang=zh&thirdId=' + }, + { + ID: 7097, + THEME: '云和原生云', + TIME: '14:00-16:55 ', + OPTION: '14:00-16:55 云和原生云', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7097?lang=zh&thirdId=' + }, + { + ID: 7098, + THEME: '虚拟化', + TIME: '14:00-16:55 ', + OPTION: '14:00-16:55 虚拟化', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7098?lang=zh&thirdId=' + }, + { + ID: 7099, + THEME: '开源与基础建设', + TIME: '14:00-16:55 ', + OPTION: '14:00-16:55 开源与基础建设', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7099?lang=zh&thirdId=' + }, + { + ID: 7100, + THEME: '安全与可信', + TIME: '14:00-17:25 ', + OPTION: '14:00-17:25 安全与可信', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7100?lang=zh&thirdId=' + }, + { + ID: 7101, + THEME: '基础软件', + TIME: '14:00-17:25 ', + OPTION: '14:00-17:25 基础软件', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7101?lang=zh&thirdId=' + } + ], + LIVETITLE: '峰会直播间', + }, + SUMMIT_HOME_DATA: { + AGENDA: { + WEB_TITLE: '/img/summit/home/agenda/zh-pc-agenda.png', + MOBILE_TITLE: '/img/summit/home/agenda/zh-mobile-agenda.png', + DATE:['12月24日','12月25日(主会)','上午','下午'], + AFTERNOON_AGENDA_24: [ + { + TIME: '13:00-13:10', + THEME: '开场', + SPEAKER: '马全一', + POSITION: 'openEuler 技术委员会委员' + }, + { + TIME: '13:10-14:40', + THEME: '讨论 openEuler 支持 App Stream 机制' + }, + { + TIME: '13:10-14:40', + THEME: '申请成立智能运维 SIG' + }, + { + TIME: '13:10-14:40', + THEME: '讨论从 Gitee issue整体切换到 Bugzilla' + }, + { + TIME: '13:10-14:40', + THEME: '讨论 2021 年 TC 合作开展方式' + }, + { + TIME: '15:00-15:30', + THEME: '开场 & 颁发 Maintainer 纪念徽章', + SPEAKER: '马全一', + POSITION: 'openEuler 技术委员会委员' + }, + { + TIME: '15:30-15:50', + THEME: 'openEuler 社区运作分析', + SPEAKER: '周明辉', + POSITION: '北京大学博雅特聘教授' + }, + { + TIME: '15:50-16:00', + THEME: '我在 openEuler 社区担任 Maintainer 的那些事儿', + SPEAKER: '方亚芬', + POSITION: 'RaspberryPi SIG Maintainer' + }, + { + TIME: '16:00-16:10', + THEME: '我在 openEuler 社区担任 Maintainer 的那些事儿', + SPEAKER: '杨昭', + POSITION: 'Ha SIG Maintainer' + }, + { + TIME: '16:10-16:20', + THEME: '我在 openEuler 社区担任 Maintainer 的那些事儿', + SPEAKER: '郑弦', + POSITION: 'ai-bigdata SIG Maintainer' + }, + { + TIME: '16:20-17:00', + THEME: '自由问答' + }, + { + TIME: '17:00-17:30', + THEME: '总结', + SPEAKER: '胡欣蔚', + POSITION: 'openEuler 社区技术委员会主席' + } + ], + FORENOON_AGENDA_25: [ + { + TIME: '09:30-09:35', + THEME: '欢迎致辞' + }, + { + TIME: '09:35-09:50', + THEME: '全产业链共享操作系统创新价值', + SPEAKER: '江大勇', + POSITION: '华为计算基础软件总经理/openEuler 社区理事长' + }, + { + TIME: '09:50-09:55', + THEME: 'openEuler 社区技术委员会换届仪式', + SPEAKER: '邱成锋', + POSITION: 'openEuler 社区副理事长' + }, + { + TIME: '09:55-10:15', + THEME: '让技术的创新永无止境', + SPEAKER: '胡欣蔚', + POSITION: 'openEuler 社区技术委员会主席' + }, + { + TIME: '10:15-10:35', + THEME: '华为在 Linux 内核社区的历程与思考', + SPEAKER: '陈海波', + POSITION: '华为OS首席技术专家/上海交通大学特聘教授/博士生导师' + }, + { + TIME: '10:35-10:50', + THEME: '“飞行中换引擎”:建行信用卡核心系统创新实践', + SPEAKER: '彭云', + POSITION: '建信金融科技信用卡及开放银行负责人' + }, + { + TIME: '10:50-11:05', + THEME: '中国移动:云原生在混合架构上的实践', + SPEAKER: '张春', + POSITION: '中国移动信息技术中心研发创新中心副总经理' + }, + { + TIME: '11:05-11:20', + THEME: '银联:机密计算的理解与探索', + SPEAKER: '祖立军', + POSITION: '银联研究院电子支付研究院主管' + }, + { + TIME: '11:20-11:40', + THEME: 'openEuler&Friends 生态多样性场景展示', + SPEAKER: '熊伟和社区开发者' + }, + { + TIME: '11:40-11:50', + THEME: '开源精神与社区文化“共建 共享 共治”', + SPEAKER: '堵俊平', + POSITION: '华为云与计算开源业务总经理' + }, + { + TIME: '11:50-11:55', + THEME: 'openEuler 社区开发者大奖颁奖', + SPEAKER: '马全一', + POSITION: 'openEuler 社区 maintainer' + } + ], + AFTERNOON_AGENDA_25: { + TIME_LIST: ['14:00-14:40','14:40-15:10','15:10-15:40','15:55-16:25','16:25-16:55','16:55-17:25'], + CARD_LIST: [ + { + TITLE: ['Session 1','操作系统'], + ITEM_LIST: [ + { + TIME: '14:00-14:40', + THEME: '圆桌:一个面向未来的操作系统是怎样的', + SPEAKER: ['颜叶 鲲鹏计算研发部部长','包云岗 中科院计算所研究员','陈鲍孜博士 飞腾操作系统总监','费斐 安晟半导体首席软件工程师','张伟 上海兆芯集成电路高级产品经理 '], + }, + { + TIME: '14:40-15:10', + THEME: 'openEuler 下的应用性能调优', + SPEAKER: ['陈棋德 北京拓林思软件有限公司'], + DESC: ['数据库是企业级 Linux 的典型应用之一,我们在openEuler下开发分布式数据库时往往会关注函数调用耗时多少和调用是否频繁、哪个线程消耗更多磁盘时间、内存缓存了哪些数据、网络请求是否延迟等这些涉及性能的问题。在做数据库性能测试时,我们也会通过改进程序来尽可能的压榨硬件性能。本议题将以数据库研发过程中的性能调优为例来讲解openEuler下的应用程序性能调优。'] + }, + { + TIME: '15:10-15:40', + THEME: 'openEuler RISC-V 移植与对果壳(NutShell)处理器支持', + SPEAKER: ['周鹏 中国科学院软件研究所','张旭舟 华为技术有限公司'], + DESC: ['结合构建操作系统发行版的一般方法,介绍构建 openEuler 面向RISC-V的相关工作和对果壳(NutShell)处理器的适配支持工作;并进一步讨论操作系统版本构建面临挑战与机会,特别是操作系统包依赖管理现状和问题,以及一种新的操作系统依赖管理、分包管理模式、构建模式探索。'] + }, + { + TIME: '15:55-16:25', + THEME: '基于树莓派的 openEuler 镜像构建及 Kubernetes + iSula 容器集群部署实践 ', + SPEAKER: ['方亚芬 中国科学院软件研究所','李宝林 华为技术有限公司'], + DESC: ['1. openEuler 移植到树莓派并构建树莓派镜像实践','2. 树莓派(openEuler)上通过 kubernetes 部署 iSula 容器集群实践 '] + }, + { + TIME: '16:25-16:55', + THEME: '异构系统的通用加速器框架: UADK 生态及其开发进展', + SPEAKER: ['高章飞 Linaro','李国柱 华为技术有限公司'], + DESC: ['UACCE 是海思和 Lianro一起合作开发的,专门为异构系统设计的加速器框架.主要内核驱动已经合入 Linux Kernel 主线 ,目前我们正在开发用户态库UADK和openssl engine。目标是提供一套基于 IOMMU sva 的特性,更加安全的加速器方案,可以给加速器和主 CPU 共享统一的地址空间.希望更多伙伴加入一起合作开发。'] + }, + { + TIME: '16:55-17:25', + THEME: '使用 ebpf 技术实现高效无性能损失的网络监控系统替代编写内核模块', + SPEAKER: ['范彬 中国电信股份有限公司云计算分公司'], + DESC: ['传统网络监控系统大多数是通过编写内核模块或者从用户空间访问 proc 文件来实现。编写内核模块是危险的,并且不容易维护和调试。我们需要能够实现与内核模块类似的功能,而又不会损失性能。此次分享主要是描述如何使用ebpf技术实现高效无性能损失的网络监控系统,通过该系统可以实现对云原生数据中心网络进行监控和可观测性,对网络延迟、网络丢包等问题故障进行定位排查。'] + } + ] + }, + { + TITLE: ['Session 2','云和云原生'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: '中国移动基于 Kubernetes + openEuler + iSula 的 ARM、X86 双平面无感知调度实践之路', + SPEAKER: ['魏宝辉 中国移动信息技术中心'], + DESC: ['中国移动基于 Kubernetes + openEuler + iSula 的 ARM、X86 双平面无感知调度实践经验分享。'] + }, + { + TIME: '14:30-15:00', + THEME: 'OpenStack 在 openEuler 上的适配与集成实践', + SPEAKER: ['李昆山 联通云数据有限公司'], + DESC: ['本议题主要介绍在 openEuler 操作系统上适配 OpenStack 云平台的进展以及技术工作,并面向行业内其他公司提供 OpenStack 与 openEuler 集成相关的技术交流以及案例分享。'] + }, + { + TIME: '15:00-15:30', + THEME: 'iSula在边缘计算操作系统HopeEdge 中应用与实践', + SPEAKER: ['梁栋 江苏润和软件股份有限公司'], + DESC: ['介绍基于 openEuler 开发的边缘操作系统 HopeEdge , 在经过轻量化定制后,通过集成 iSula 容器引擎,实现应用的快速部署和快速升级。'] + }, + { + TIME: '15:45-16:15', + THEME: '华云 Kubernetes 在 openEuler 上的适配与实践', + SPEAKER: ['黄茂峰 华云数据控股集团有限公司'], + DESC: ['华云基于 Kubernetes 开发了华云安超云套件 CloudSuite 上的 PaaS 平台,同时华云也根据自己业务的需求对 Kubernetes 进行了改造和优化。华云 Kubernetes 在适配 openEuler 时遇到了很多的挑战,但在社区的帮助下,华云不仅攻克了这些困难,更收获了很多的实践经验。'] + }, + { + IME: '16:15-16:45', + THEME: 'openEuler 智能调优引擎 A-Tune原理与实践', + SPEAKER: ['谢志鹏 华为技术有限公司'], + DESC: ['A-Tune利用人工智能技术,对运行在操作系统上的业务建立精准模型,动态感知业务特征并推理出具体应用,根据业务负载情况动态调节并给出最佳的参数配置组合,从而使业务处于最佳运行状态。','本次议题主要介绍以下几个方面:','1.介绍A-Tune两大核心能力的实现原理:在线静态调优和离线动态调优能力','2.展示A-Tune在实际业务场景中的调优实践','3.探讨A-Tune的未来技术演进路线'] + }, + { + IME: '16:45-17:15', + THEME: 'Play Minikube On openEuler', + SPEAKER: ['赵帅 Linaro','刘新良 Linaro'], + DESC: ['Minikube 是一个将 Kubernetes 进行本地化部署的简单工具,它的出现解决了开发者一键拉起和简易运维K8s集群的诉求。在这个演讲中,我们会介绍 Minikube 的基本原理,以及为了使Minikube 支持 openEuler,我们在社区所做的工作。同时,我们还会涉及其他几个主流 k8s 部署工具对 openEuler 上的开发和支持情况。'] + } + ] + }, + { + TITLE: ['Session 3','虚拟化'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'StratoVirt:openEuler 下一代虚拟化平台', + SPEAKER: ['吴斌 华为技术有限公司'], + DESC: ['StratoVirt 是使用 Rust 语言编写的下一代 VMM 系统,它是面向云数据中心的企业级虚拟化平台,支持虚拟机、容器、Serverless 三种场景。本议题将介绍 StratoVirt 的功能特性、技术架构和 Roadmap。'] + }, + { + TIME: '14:30-15:00', + THEME: '面向云桌面的显示优化技术', + SPEAKER: ['孙利杰 湖南麒麟信安科技股份有限公司'], + DESC: ['在鲲鹏下基于KVM虚拟化实现云桌面产品时会遇到一些技术难题,本议题分享图形显示和优化相关问题的技术方案,如虚拟化显卡优化、显卡穿透、视频重定向等,其中涉及 openEuler 内核、解码库等相关组件的优化和功能增强。'] + }, + { + TIME: '15:00-15:30', + THEME: '基于 openEuler 的虚拟化和私有云落地实践', + SPEAKER: ['仇大玉 华云数据控股集团有限公司'], + DESC: ['ARM 平台下,尤其是 openEuler 体系下,虚拟化平台性能优化以及如何快速适配最新的 SAN 设备,如何为用户提供较高性能的的 vGPU 体验成为一个较为突出问题,本次将给大家带来华云数据在虚拟化下的适配调优,以及虚拟化对外设支撑上的一些创新和实践。'] + }, + { + TIME: '15:45-16:15', + THEME: '基于 openEuler 的虚拟化性能优化', + SPEAKER: ['庾志辉 深信服科技'], + DESC: ['介绍在 openEuler 系统上虚拟化性能的优化分享,包括存储、计算等性能的优化技术'] + }, + { + TIME: '16:15-16:45', + THEME: '基于鲲鹏 + openEuler 创新云实践分享', + SPEAKER: ['罗云 云宏信息科技股份有限公司'], + DESC: ['基于鲲鹏服务器和 openEuler 系统,我们研发了一款企业级服务器虚拟化和云管产品,赢得政府、金融、运营商等多个落地案例,从功能和性能上均收获了口碑,与各位同行分享'] + }, + ] + }, + { + TITLE: ['Session 4','开源和基础设施'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'openEuler 跨代码托管平台多协议 CLA 签署系统实践', + SPEAKER: ['袁志昌 ARM China','陈曾 华为技术有限公司'], + DESC: ['1. 作为开源社区,应给开发者提供 CLA 签署服务,但怎么提供?自研,采用开源项目?怎么做到签署的 CLA 具有法律效力?','2. 作为贡献者,应选择哪种角色来签署 CLA ?公司参与社区,怎么签署 CLA ? CLA 签署后,在后续的开发活动中如何保证自己的利益?'] + }, + { + TIME: '14:15-15:00', + THEME: 'Compass-CI: 开发者友好的测试系统', + SPEAKER: ['吴峰光 华为技术有限公司','杜开田 华为技术有限公司'], + DESC: ['Compass-CI 面向开源软件多架构、多系统生态测试服务能力构建和实践'] + }, + { + TIME: '15:00-15:30', + THEME: '构建 openEuler 社区开源基础设施和 oepkgs 开放软件包服务平台', + SPEAKER: ['殷佳毅 中国科学院软件研究所','曹志 华为技术有限公司'], + DESC: ['1. openEuler 社区开源基础设施构建的技术选型和实践 ','2. oepkgs 开放软件包服务平台包含 oepkgs 容器镜像仓库与 oepkgs RPM 软件包仓库,本次分享将阐述oepkgs 平台的成立背景和负责维护的两个仓库的基本架构与使用方式以及未来的发展方向'] + }, + { + TIME: '15:45-16:15', + THEME: '开源社区数据如何驱动 openEuler 社区运营', + SPEAKER: ['夏小雅 华东师范大学','钟君 华为技术有限公司'], + DESC: ['1. 为什么要做数字化运营','2. 数字化运营系统如何选型(choass、om、kibble...)','3. 运营系统的系统架构如何搭建 ','4. 运营数据如何展示 ','5. 开源数据指标体系,CHAOSS 指标如何落地','6. 如何用数字驱动运营并落地openEuler社区'] + }, + { + TIME: '16:15-16:45', + THEME: '开源项目的产品思维和 openEuler 开发者体验设计', + SPEAKER: ['张舒婷 华为技术有限公司','马全一 华为技术有限公司'], + DESC: ['1. 随着开源和商业结合的愈发紧密,成功的开源项目都会融入商业产品设计的一些理念。本议题第一部分就是从商业源头出发,阐述如何构建开源项目的产品设计思维。','2. 如何帮助开源开发者带来更好的交互体验和设计,是用户体验团队需要一直探索实践的,本议题第二部分主要讲述我们在 openEuler、openLooKeng 等开源社区通过产品思维,做出开发者体验提升所做的实践'] + } + ] + }, + { + TITLE: ['Session 5','安全和可信'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'openEuler 安全能力建设', + SPEAKER: ['魏刚 华为技术有限公司'], + DESC: ['从安全委员会的立场介绍 openEuler 社区安全能力建设的过去、现在和未来,向与会者呈现一个完整的社区安全能力框架。重点介绍社区在安全编码,安全设计以及漏洞收集、响应和处理上的最新进展和面临的问题和挑战'] + }, + { + TIME: '14:30-15:00', + THEME: '在 openEuler 中引入与性能和安全相关的 Arm-v8.x 关键特性的探讨', + SPEAKER: ['袁志昌 ARM China'], + DESC: ['介绍与性能和安全相关的 Arm-v8.x 的四个关键特性(LSE - Large System Extension,SVE - Scalable Vector Extension, PAuth - Pointer Authentication, BTI - Branch Target Identification),相关上游开源社区和各大操作系统开源社区对上述特性的最新支持状态,以及在 openEuler 中引入上述特性的探讨'] + }, + { + TIME: '15:00-15:30', + THEME: 'RAS 那些事儿 on ARM64', + SPEAKER: ['陈功 华为技术有限公司'], + DESC: ['可靠性是服务器平台的重要基石。从 IBM 50年前提出RAS这个概念,到 x86 XEON 平台一统服务器市场天下,再到新入局的ARM64平台,RAS能力的构建一直围绕左右。本议题围绕着RAS的前世今生以及当前基于openEuler的ARM64服务器RAS能力构建进行介绍。'] + }, + { + TIME: '15:45-16:15', + THEME: '如何提升开源社区的开源合规能力', + SPEAKER: ['卞乃猛 江苏润和软件股份有限公司','高琨 华为技术有限公司'], + DESC: ['开源项目最大的风险之一在于开源合规,无论是使用来源还是主动开源,代码质量是好是坏,但是开源合规只有 0 和 1 ,开源合规是开源的基础能力,也是开源社区发展的必要条件。议题将介绍如何提升开源社区的开源合规能力'] + }, + { + TIME: '16:15-16:45', + THEME: '基于 SELinux 的机密性和完整性安全策略实现', + SPEAKER: ['罗求 湖南麒麟信安科技股份有限公司'], + DESC: ['在 openEuler 上 SELinux 是一个标准的安全基础设施,对于特定的软件业务,如何使用 SELinux 来实现机密性控制和完整性控制的功能,保证信息流的方向,防止敏感信息泄漏和非授权修改。本议题就基于场景来解析如何利用 SELinux 来实现可信策略'] + }, + { + TIME: '16:45-17:15', + THEME: '操作系统内生安全', + SPEAKER: ['王江涛 普华基础软件有限公司'], + DESC: ['可信计算需要专用的硬件服务器,对应用软件改造较大。当前企、事业单位、IDC 存量服务器几乎是 X86 的天下,全面过渡软、硬件国产化迭代周期较长。解决方案是需要结合成熟硬件密码设备加密卡、加密机与操作系统深度融合,实现内生安全的操作系统'] + } + ] + }, + { + TITLE: ['Session 6','基础软件'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: '毕昇 JDK & 毕昇编译器技术架构及部署实践', + SPEAKER: ['郭歌 华为技术有限公司','魏伟 华为技术有限公司'], + DESC: ['议openEuler 20.09版本中正式发布了毕昇JDK和毕昇编译器,本议题主要介绍毕昇JDK和毕昇编译器的核心技术以及编译技术如何使能上层应用'] + }, + { + TIME: '14:30-15:00', + THEME: 'openGauss 数据库在 openEuler 平台的企业级高可用方案探讨与实践', + SPEAKER: ['刘伟 云和恩墨(北京)信息技术有限公司'], + DESC: ['议题将针对 openGauss 在 openEuler 平台,如何满足企业级双机,一主多备,跨机房的 HA 方案进行深入探讨,并分享具体的应用落地实践案例'] + }, + { + TIME: '15:00-15:30', + THEME: '基于 openEuler 和鲲鹏平台构建高性能 SDS', + SPEAKER: ['池信泽 星辰天合(北京)数据科技有限公司'], + DESC: ['1. 介绍把 XEDP 从 CentOS 7.6 + X86 移植到 openEuler + 鲲鹏上的过程','2. 介绍在移植过程中遇到的问题和解决的方案','3. 介绍 XEDP 针对于 openEuler + 鲲鹏架构上的性能优化方案和实际落地项目的情况'] + }, + { + TIME: '15:45-16:15', + THEME: 'DDE 桌面操作系统架构设计实践', + SPEAKER: ['王耀华 统信软件技术有限公司'], + DESC: ['统信软件基于 openEuler 操作系统,汲取社区在内核方面的优化,提供最优体验的 DDE 桌面操作系统。桌面操作系统对于用户而言一直是个黑盒子,本次分享就解密 DDE 桌面操作系统的基础架构,让你在熟悉 DDE 桌面的基本功能之外,更加深入的了解 DDE 桌面操作系统的技术原理和架构设计'] + }, + { + TIME: '16:15-16:45', + THEME: 'openGauss 基于鲲鹏平台的极致性能和应用实践', + SPEAKER: ['黄晓涛 北京海量数据技术股份有限公司','冯犇 华为技术有限公司','王俊捷 华为技术有限公司'], + DESC: ['1. 介绍 openGauss 在鲲鹏多核服务器上 OLTP 场景的优化实践,内容主要为优化瓶颈分析、优化手段及最终达成效果等。','2. 海量数据库 Vastbase 是海量数据基于多年对各行业应用场景的实践经验,倾力打造的企业级关系型数据库。议题将分享海量数据库 Vastbase 基于鲲鹏 + openEuler 操作系统数据迁移的应用实践'] + }, + { + TIME: '16:45-17:15', + THEME: 'UKUI - 文件管理器架构分析', + SPEAKER: ['李剑峰 麒麟软件有限公司'], + DESC: ['在 openEuler 20.09 和 20.03 SP1 版本中,已经可以下载安装全新设计的 UKUI 3.0 。本议题将对 UKUI 桌面环境中的文件管理器进行阐述,介绍目前 UKUI 的文件管理器从 2.0 到 3.0 的开发历程,以及新版本文件管理器的技术选型,整体架构设计和未来的发展方向'] + } + ] + } + ] + }, + SIG_CONTENT: { + TITLE: 'SIG 组开放工作会议', + SIG1_TIME: '16:00 - 16:10' , + SIG1_DETAIL: ['开场','马全一','openEuler 技术委员会委员'], + SIG2_TIME: '16:10 - 17:00', + SIG2_DETAIL: [ + { + THEME: 'SIG-DDE', + CONTENT: ['1) DDE 适配 openEuler 成果分享','2) DDE 版本更新计划讨论','3) 爱好者对桌面诉求收集和讨论'] + }, + { + THEME: 'SIG-UKUI', + CONTENT: ['1) UKUI 在 openEuler 20.03 LTS SP1 版本上的工作进展介绍','2) UKUI 后续发展方向讨论'] + }, + { + THEME: 'SIG-Ha', + CONTENT: ['1) Ha 项目进展介绍','2) Ha 项目近期在上游社区的合入计划讨论'] + }, + { + THEME: 'SIG-aarch32', + CONTENT: ['1) 当前 aarch32 与 openEuler 适配进展分享','2)aarch32 适配代码如何与主线共存讨论'] + }, + { + THEME: 'SIG-A-Tune', + CONTENT: ['1)A-Tune 2020年新特性和实践成果回顾','2)A-Tune 未来技术演进路线探讨','3)A-Tune & wisdom 社区开发流程介绍和重要 issue 分析讨论','4)业界最新调优技术论文观点分享和讨论'] + }, + { + THEME: 'SIG-iSulad & Container', + CONTENT: ['1)云原生相关技术讨论','2)云原生效能提升研讨','3)云原生应用过程中的问题讨论'] + }, + { + THEME: 'SIG-ai-bigdata', + CONTENT: ['1)sig-ai-bigdata 2020年成果和实践回顾','2)LTS 版本选型讨论','3)基于 openEuler 的大数据和 AI 平台探讨','4)SIG 技术范围和路标讨论'] + }, + { + THEME: 'SIG-security-facility & sig-confidential-computing', + CONTENT: ['1)sig-security-facility 已有安全技术分享','2)openEuler 安全技术方向和路标讨论','3)机密计算应用场景和安全相关技术讨论'] + }, + { + THEME: 'SIG-Compiler', + CONTENT: ['1) Compiler SIG 后续工作计划讨论,包括 JDK/GCC 支持路标','2) 对LLVM等其他编译器和Rust\Go语言的支持诉求收集和讨论','3)openJDK 对容器(如iSula)支持计划讨论'] + }, + { + THEME: 'SIG-doc', + CONTENT: ['1)openEuler 社区当前文档体系介绍','2)doc SIG 后续计划和重点方向讨论','3)如何激励参与社区贡献博客、视频等讨论'] + }, + { + THEME: 'SIG-Infrastructure', + CONTENT: ['1) openEuler 基础设施 2020 年实践回顾','2)openEuler 基础设施 2021 重点工作讨论','3)openEuler 基础设施从自动化转向智能化运维的一些想法与探讨'] + }, + { + THEME: 'SIG-security-committee', + CONTENT: ['1)openEuler 社区漏洞处理流程分析,包括漏洞感知能力、漏洞处理和漏洞披露三部分','2)安全补丁修复策略讨论','3)安全指南如何在社区中应用讨论','4)安全技术委员会如何与各 SIG 协同完成漏洞分析、修复和披露讨论'] + }, + { + THEME: 'SIG-Compatibility-Infra', + CONTENT: ['1)内核 KABI 与南向驱动兼容性讨论','2)软件包兼容性等级与北向应用兼容性讨论','3)版本间前后兼容策略讨论'] + }, + { + THEME: 'SIG-QA', + CONTENT: ['1)openEuler 社区质量度量体系如何构建讨论','2)openEuler 社区如何开展众测活动探讨','3) SIG 未来规划讨论'] + }, + { + THEME: 'SIG-release-management', + CONTENT: ['1)openEuler 社区各版本生命周期规划讨论,包括 20.03 的维护周期、SP2 的发布时间等','2)伙伴版本跟随、组件升级策略讨论,包括补丁回合、版本升级、组件方式、以及二次开发和回合时间等','3) 各 OSV、ISV 如何参与release sig,以及 release sig 运作讨论'] + }, + { + THEME: 'SIG-Kernel', + CONTENT: ['1)内核测试防护和稳定性保证讨论','2)如何通过社区的力量发现和修复 openEuler 内核 Bug ,保证 LTS 版本稳定性的讨论','3)创新版本特性合入策略讨论','4)对 openEuler 5.10 内核版本的诉求和期待收集和讨论'] + }, + { + THEME: 'SIG-Virt', + CONTENT: ['1)Virt SIG 2020 年技术和实践总结','2)Virt SIG 2021 年技术规划讨论','3)对 Virt SIG 的诉求收集和讨论,如新增特性、开发流程、问题解决等'] + } + ], + SIG3_TIME: '17:00 - 18:30', + SIG3_DETAIL: ['分享讨论成果 & 交流'] + } + }, + LECTURER: { + WEB_TITLE: '/img/summit/home/lecturer/zh-pc-lecturer.png', + MOBILE_TITLE: '/img/summit/home/lecturer/zh-mobile-lecturer.png', + LECTURERLIST: [ + { + IMG: '/img/summit/home/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: '华为计算基础软件总经理/openEuler 社区理事长' + }, + { + IMG: '/img/summit/home/lecturer/qiuchengfeng.png', + NAME: '邱成锋', + POSITION: 'openEuler 社区副理事长' + }, + { + IMG: '/img/summit/home/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: 'openEuler 社区技术委员会主席' + }, + { + IMG: '/img/summit/home/lecturer/chenhaibo.png', + NAME: '陈海波', + POSITION: '华为OS首席技术专家/上海交通大学特聘教授/博士生导师' + }, + { + IMG: '/img/summit/home/lecturer/zulijun.png', + NAME: '祖立军', + POSITION: '银联研究院电子支付研究院主管' + }, + { + IMG: '/img/summit/home/lecturer/xiongwei.png', + NAME: '熊伟', + POSITION: 'openEuler 社区技术委员会委员' + }, + { + IMG: '/img/summit/home/lecturer/dujunping.png', + NAME: '堵俊平', + POSITION: '华为 云与计算开源业务总经理' + }, + { + IMG: '/img/summit/home/lecturer/maquanyi.png', + NAME: '马全一', + POSITION: 'openEuler 社区 Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/chenqide.png', + NAME: '陈棋德', + POSITION: '北京拓林思软件有限公司 副总经理' + }, + { + IMG: '/img/summit/home/lecturer/zhoupeng.png', + NAME: '周鹏', + POSITION: '中科院软件所 助理研究员' + }, + { + IMG: '/img/summit/home/lecturer/zhangxuzhou.png', + NAME: '张旭舟', + POSITION: 'openEuler RISC-V SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/fangyafen.png', + NAME: '方亚芬', + POSITION: '中国科学院软件研究所 工程师' + }, + { + IMG: '/img/summit/home/lecturer/libaolin.png', + NAME: '李宝林', + POSITION: 'openEuler 社区运营工程师' + }, + { + IMG: '/img/summit/home/lecturer/zhaoshuai.png', + NAME: '赵帅', + POSITION: 'Linaro Tech Lead' + }, + { + IMG: '/img/summit/home/lecturer/liuxinliang.png', + NAME: '刘新良', + POSITION: 'Linaro 高级工程师' + }, + { + IMG: '/img/summit/home/lecturer/gaozhangfei.png', + NAME: '高章飞', + POSITION: 'Linaro Landing Team software engineer' + }, + { + IMG: '/img/summit/home/lecturer/fanbin.png', + NAME: '范彬', + POSITION: '中国电信股份有限公司云计算分公司 高级后端开发工程师' + }, + { + IMG: '/img/summit/home/lecturer/weibaohui.png', + NAME: '魏宝辉', + POSITION: '中国移动信息技术中心 PaaS研发经理' + }, + { + IMG: '/img/summit/home/lecturer/likunshan.png', + NAME: '李昆山', + POSITION: '中国联通云数据 OpenStack研发工程师' + }, + { + IMG: '/img/summit/home/lecturer/liangdong.png', + NAME: '梁栋', + POSITION: '江苏润和软件股份有限公司 高级工程师&HopeEdge版本经理' + }, + { + IMG: '/img/summit/home/lecturer/huangmaofeng.png', + NAME: '黄茂峰', + POSITION: '华云数据控股集团有限公司 高级技术经理' + }, + { + IMG: '/img/summit/home/lecturer/wubin.png', + NAME: '吴斌', + POSITION: 'openEuler 社区虚拟化SIG Maintainer/华为ICT领域虚拟化架构师' + }, + { + IMG: '/img/summit/home/lecturer/sunlijie.png', + NAME: '孙利杰', + POSITION: '湖南麒麟信安科技股份有限公司 研发部经理' + }, + { + IMG: '/img/summit/home/lecturer/qiudayu.png', + NAME: '仇大玉', + POSITION: '华云数据控股集团有限公司 高级技术总监' + }, + { + IMG: '/img/summit/home/lecturer/yuzhihui.png', + NAME: '庾志辉', + POSITION: '深信服科技股份有限公司 国产化信云研发负责人' + }, + { + IMG: '/img/summit/home/lecturer/luoyun.png', + NAME: '罗云', + POSITION: '云宏信息科技股份有限公司 虚拟化及云产品经理' + }, + { + IMG: '/img/summit/home/lecturer/chenzeng.png', + NAME: '陈曾', + POSITION: '华为 高级工程师' + }, + { + IMG: '/img/summit/home/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: 'openEuler 社区 Application、CICD SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/yinjiayi.png', + NAME: '殷佳毅', + POSITION: '中国科学院软件研究所 系统工程师' + }, + { + IMG: '/img/summit/home/lecturer/caozhi.png', + NAME: '曹志', + POSITION: 'openEuler 社区Infra-SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/xiaxiaoya.png', + NAME: '夏小雅', + POSITION: '华东师范大学 开源专家' + }, + { + IMG: '/img/summit/home/lecturer/zhongjun.png', + NAME: '钟君', + POSITION: '华为 开源高级工程师' + }, + { + IMG: '/img/summit/home/lecturer/zhangshuting.png', + NAME: '张舒婷', + POSITION: '华为 计算产品体验设计师' + }, + { + IMG: '/img/summit/home/lecturer/weigang.png', + NAME: '魏刚', + POSITION: '华为 计算产品线可信安全技术专家' + }, + { + IMG: '/img/summit/home/lecturer/yuanzhichang.png', + NAME: '袁志昌', + POSITION: 'Arm China 开源生态首席软件工程师' + }, + { + IMG: '/img/summit/home/lecturer/chengong.png', + NAME: '陈功', + POSITION: '华为 鲲鹏计算产品部技术专家' + }, + { + IMG: '/img/summit/home/lecturer/biannaimeng.png', + NAME: '卞乃猛', + POSITION: '润和 云计算事业部 产品研发总监' + }, + { + IMG: '/img/summit/home/lecturer/gaokun.png', + NAME: '高琨', + POSITION: '华为 开源能力中心工程师' + }, + { + IMG: '/img/summit/home/lecturer/luoqiu.png', + NAME: '罗求', + POSITION: '湖南麒麟信安科技股份有限公司 研发工程师' + }, + { + IMG: '/img/summit/home/lecturer/wangjiangtao.png', + NAME: '王江涛', + POSITION: '普华基础软件股份有限公司 高级安全专家' + }, + { + IMG: '/img/summit/home/lecturer/liuwei.png', + NAME: '刘伟', + POSITION: '云和恩墨 2020实验室研究员' + }, + { + IMG: '/img/summit/home/lecturer/chixinze.png', + NAME: '池信泽', + POSITION: '星辰天合(北京)数据科技有限公司 分布式系统架构师' + }, + { + IMG: '/img/summit/home/lecturer/huangxiaotao.png', + NAME: '黄晓涛', + POSITION: '北京海量数据技术股份有限公司 数据库研究院副院长' + }, + { + IMG: '/img/summit/home/lecturer/lijianfeng.png', + NAME: '李剑峰', + POSITION: '麒麟软件 桌面研发部社区主管' + }, + { + IMG: '/img/summit/home/lecturer/wangyaohua.png', + NAME: '王耀华', + POSITION: '统信软件技术有限公司 研发总监' + }, + { + IMG: '/img/summit/home/lecturer/fengben.png', + NAME: '冯犇', + POSITION: '华为 鲲鹏数据库优化专家' + }, + { + IMG: '/img/summit/home/lecturer/wangjunjie.png', + NAME: '王俊捷', + POSITION: '华为 鲲鹏数据库优化专家' + } + ] + }, + HOST: { + WEB_TITLE: '/img/summit/home/host-unit/zh-host-unit.png', + MOBILE_TITLE: '/img/summit/home/host-unit/zh-mobile-zhuban.png', + LIST: [ + { + IMG: '/img/summit/home/host-unit/openeuler.png' + } + ] + }, + UNDERTAKER: { + WEB_TITLE: '/img/summit/home/undertaker/zh-pc-undertaker.png', + MOBILE_TITLE: '/img/summit/home/undertaker/zh-mobile-undertaker.png', + LIST: [ + { + IMG: '/img/summit/home/undertaker/jikebang.png', + LINK: 'https://www.geekbang.org/' + } + ] + }, + CO_ORGANIZER: { + WEB_TITLE: '/img/summit/home/co-organizer/zh-co-organizer.png', + MOBILE_TITLE: '/img/summit/home/co-organizer/zh-mobile-xieban.png', + LIST: [ + { + IMG: '/img/summit/home/co-organizer/yidong.png', + LINK: 'http://it.10086.cn/indexc.html' + }, + { + IMG: '/img/summit/home/co-organizer/liantong.png', + LINK: 'https://www.woyun.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yinlian.png', + LINK: 'https://cn.unionpay.com/' + }, + { + IMG: '/img/summit/home/co-organizer/pengcheng.png', + LINK: 'https://www.pcl.ac.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/feiteng.png', + LINK: 'https://www.phytium.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/qilin.png', + LINK: 'http://www.kylinos.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/tongxin.png', + LINK: 'https://www.uniontech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/cetc.png', + LINK: 'http://www.i-soft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/xinan.png', + LINK: 'http://www.kylinsec.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/iscas.png', + LINK: 'http://www.iscas.ac.cn' + }, + { + IMG: '/img/summit/home/co-organizer/turbolinux.png', + LINK: 'http://www.turbolinux.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/beiming.png', + LINK: 'http://www.bmsoft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/runhe.png', + LINK: 'http://www.hopeedge.com' + }, + { + IMG: '/img/summit/home/co-organizer/xsky.png', + LINK: 'http://www.xsky.com' + }, + { + IMG: '/img/summit/home/co-organizer/huayun.png', + LINK: 'https://huayun.com/' + }, + { + IMG: '/img/summit/home/co-organizer/qingyun.png', + LINK: 'https://kubesphere.qingcloud.com/' + }, + { + IMG: '/img/summit/home/co-organizer/shenxinfu.png', + LINK: 'https://www.sangfor.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhong.png', + LINK: 'http://www.winhong.com/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhe.png', + LINK: 'https://enmotech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/hailiang.png', + LINK: 'http://www.vastdata.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/hangtian.png', + LINK: 'https://www.htzhiyun.cn' + }, + { + IMG: '/img/summit/home/co-organizer/langche.png', + LINK: 'https://lstack.com/' + } + ] + }, + FOUNDATION: { + WEB_TITLE: '/img/summit/home/foundation/zh-pc-foundation.png', + MOBILE_TITLE: '/img/summit/home/foundation/zh-mobile-foundation.png', + LIST: [ + { + IMG: '/img/summit/home/foundation/yuanzi.png', + LINK: 'https://www.openatom.org' + }, + { + IMG: '/img/summit/home/foundation/cloudnative.png', + LINK: 'https://www.cncf.io/' + }, + { + IMG: '/img/summit/home/foundation/linaro.png', + LINK: 'https://www.linaro.org/' + }, + { + IMG: '/img/summit/home/foundation/linux.png', + LINK: 'https://www.linuxfoundation.org/' + }, + { + IMG: '/img/summit/home/foundation/open.png', + LINK: 'https://www.openinfra.dev/' + } + ] + }, + MEDIA: { + WEB_TITLE: '/img/summit/home/media/zh-pc-media.png', + MOBILE_TITLE: '/img/summit/home/media/zh-mobile-media.png', + LIST: [ + { + IMG: '/img/summit/home/media/csdn.png', + LINK: 'https://www.csdn.net/' + }, + { + IMG: '/img/summit/home/media/sifou.png', + LINK: 'https://segmentfault.com/' + }, + { + IMG: '/img/summit/home/media/oschina.png', + LINK: 'https://www.oschina.net/' + }, + { + IMG: '/img/summit/home/media/51cto.png', + LINK: 'https://www.51cto.com/' + }, + { + IMG: '/img/summit/home/media/media-linux.png', + LINK: 'https://linux.cn/' + }, + { + IMG: '/img/summit/home/media/xianglingshuo.png', + LINK: 'qrcode' + }, + ] + }, + REVIEW: { + WEB_TITLE: '/img/summit/home/review/zh-pc-review.png', + MOBILE_TITLE: '/img/summit/home/review/zh-mobile-review.png', + WEB_BANNER: '/img/summit/home/review/web-review-banner.png', + MOBILE_BANNER: '/img/summit/home/review/h5-review-banner.png' + } + }, + LISTTITLE: '精彩回顾', + LISTNEWTITLE:'openEuler 峰会 2020', + LISTTIME: '2020年4月17-18日', + SPEECHTITLE: '主题演讲', + DESIGNTITLE: '设计峰会(项目组专题研讨)', + VIDEODOWNLOAD: '附件下载', + FRIENDSHIPLINK: '友情链接', + SUMMIT_WEB_IMG: '/img/summit/home/zh-pc-summit.png', + SUMMIT_H5_IMG: '/img/summit/home/zh-mobile-summit.png', + SPEECHLIST: [{ + SPEECHTIME: '4 月 17 日 09:30 - 09:40', + SPEECHTHEME: 'openEuler 加速多核异构计算产业发展', + SPEECHER: '江大勇', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/jiangdayong.png', + SPEECHERINFO: '', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 09:40 - 09:50', + SPEECHTHEME: 'openEuler,助推器,超级工坊', + SPEECHER: '王准', + SPEECHCONTENT: '关注于传统行业IT转型和工业互联网建设,多次主持全国级信息化项目的架构规划,为各大部委和央企提供咨询。作为企业架构师协会会员,致力于推动企业架构在中国的推广和落地。', + SPEECHERIMG: '/img/summit/wangzhun.jpg', + SPEECHERINFO: '清华同方计算机资深架构师', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 09:50 - 10:30', + SPEECHTHEME: 'Innovation Drives the Future of openEuler', + SPEECHER: '熊伟', + SPEECHCONTENT: '熊伟,2014年加入华为,现为2012实验室中央软件院服务器操作系统首席架构师,openEuler技术委员会委员;南开大学工学博士,曾在TurboLinux、WindRiver等公司担任研发负责人,具有长期的OS、底层软件工作经验和技术积累;对处理器、体系架构、OS、容器等具有广阔的技术视野,初步建立起鲲鹏基础软件栈服务器OS、容器引擎等基础设施的自研平台体系。', + SPEECHERIMG: '/img/summit/xiongwei.png', + SPEECHERINFO: 'openEuler技术委员会委员', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 10:30 - 10:40', + SPEECHTHEME: '从“共建”到“共赢” 推动 openEuler 成为全球领先社区', + SPEECHER: '宇亮', + SPEECHCONTENT: '基础操作系统领域从业20余年,见证了国产Linux操作系统发展历史。先后服务于中科红旗、中标软件等,2016年加入普华,任普华公司基础软件事业部营销副总。自国家电子政务内外网“12库3金”项目起至今,先后参与了大部分国产操作系统具有里程碑意义的重大项目。', + SPEECHERIMG: '/img/summit/yuliang.png', + SPEECHERINFO: '普华基础软件股份有限公司 基础软件事业部副总经理', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 10:40 - 10:50 ', + SPEECHTHEME: '麒麟遨天,助力鲲鹏展翅', + SPEECHER: '李震宁', + SPEECHCONTENT: '华为云及腾讯云最具价值专家;上海市基础软件工程技术研究中心主任、太原理工大学硕士生导师。李震宁先生在开源和操作系统领域服务了20年,服务客户包括全国多个政府机关、国防及航天、银行、证券、大学等,有着丰富的开源操作系统软件技术、市场营销和公关传播领域复合经验。目前在国家多个部委和省市担任操作系统和基础软件产业等相关领域专家。对行业宏观发展,技术趋势,标准政策等均有一定研究。目前兼任中日韩东北亚开源委员会中方委员、开源及基础软件通用技术创新战略联盟(优盟)秘书长;中国高端芯片联盟副秘书长、中国开源软件推进联盟副秘书长,中国开源云联盟副秘书长,中国大数据应用协同创新联盟副秘书长,TIAA车载联盟软件组组长;CCF 系统软件专委会委员;中国大数据与智能计算产业联盟开源软件工作委员会副主任等职务。', + SPEECHERIMG: '/img/summit/lizhenning.jpg', + SPEECHERINFO: '麒麟软件副总裁', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 10:50 - 11:00', + SPEECHTHEME: '点亮开源软件供应链,助力社区高质量发展', + SPEECHER: '武延军', + SPEECHCONTENT: '研究员、博士生导师,中科院软件所副总工程师,智能软件研究中心主任。毕业于清华大学计算机系,随后加入中科院软件所学习工作,长期从事操作系统相关研发工作。在相关学术顶级会议、核心期刊先后发表论文50余篇,申请专利与软著30余项。曾获北京市科技新星、中科院青促会优秀会员等荣誉。', + SPEECHERIMG: '/img/summit/wuyanjun.png', + SPEECHERINFO: '中科院软件所副总工程师,智能软件研究中心主任', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 11:00 - 11:10 ', + SPEECHTHEME: 'ARM服务器最佳MySQL平台', + SPEECHER: '丁文龙', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/dingwenlong.png', + SPEECHERINFO: '高级研发工程师', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 11:10 - 11:25 ', + SPEECHTHEME: 'How to Enjoy openEuler', + SPEECHER: '马俊杰', + SPEECHCONTENT: 'openEuler 社区 Infrastructure Committer、openEuler 社区 oVirt SIG组maintainer、oVirt 社区 Member、Istio 社区 Member', + SPEECHERIMG: '/img/summit/majunjie.png', + SPEECHERINFO: 'openEuler Infrastructure SIG Committer', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: ' 4 月 17 日 11:25 - 11:45 ', + SPEECHTHEME: 'openEuler Community Governance', + SPEECHER: '胡欣蔚', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/huxinwei.png', + SPEECHERINFO: 'openEuler 技术委员会主席', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + ], + TRACKLIST: ['Track 1', 'Track 2', 'Track 3'], + DESIGNLIST: [{ + DESIGNTIME: [{ + DAY: '4 月 17 日', + HOUR: '13:30 - 15:00' + }], + TRACK1: [{ + TRACK1TITLE: 'openEuler内核', + TRACK1TEACHER: '郭寒军', + TRACK1MAINTAINER: 'openEuler Kernel Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1E64y1T76a', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-kernel' + }], + TRACK2: [{ + TRACK2TITLE: 'RaspberryPi', + TRACK2TEACHER: '方亚芬', + TRACK2MAINTAINER: 'RaspberryPi Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1Ve411s74C', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-raspberrypi' + }], + TRACK3: [{ + TRACK3TITLE: 'UKUI', + TRACK3TEACHER: '窦龑', + TRACK3MAINTAINER: 'UKUI核心开发成员;麒麟软件开源小组成员', + TRACK3LINK:'https://www.bilibili.com/video/BV1ei4y187SD', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ukui' + }] + }, + { + DESIGNTIME: [{ + DAY: '4 月 17 日', + HOUR: '15:00 - 16:00' + } + + ], + TRACK1: [{ + TRACK1TITLE: 'Container & iSula', + TRACK1TEACHER: '蔡灏', + TRACK1MAINTAINER: 'Container & iSula SIG Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1A54y1R7iX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-container' + }], + TRACK2: [{ + TRACK2TITLE: 'Documentation', + TRACK2TEACHER: '谭志鹏', + TRACK2MAINTAINER: 'Documentation Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1yT4y1G78u', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-documentation' + }], + TRACK3: [{ + TRACK3TITLE: 'High Availability', + TRACK3TEACHER: '侯健 ', + TRACK3MAINTAINER: '', + TRACK3LINK:'https://www.bilibili.com/video/BV1Wt4y1272N', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ha' + }] + + }, + { + DESIGNTIME: [{ + DAY: '4 月 17 日', + HOUR: '16:00 - 17:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Packaging & Base Service', + TRACK1TEACHER: '何晓文', + TRACK1MAINTAINER: 'Packaging Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1we411s7rQ', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-packaging' + }], + TRACK3: [{ + TRACK3TITLE: 'oVirt', + TRACK3TEACHER: '付惠惠 ', + TRACK3MAINTAINER: 'oVirt Maintainer;麒麟软件oVirt负责人', + TRACK3LINK:'https://www.bilibili.com/video/BV1LK4y1k7Hv', + TRACK3DOWNLOAD:'hhttps://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ovirt' + }] + + }, + { + DESIGNTIME: [{ + DAY: '4 月 17 日', + HOUR: '17:00 - 18:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Kubernetes', + TRACK1TEACHER: '周鹏飞', + TRACK1MAINTAINER: 'SIG-Kubernetes Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1ak4y1R7Sq', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-kubernetes' + }], + TRACK2: [{ + TRACK2TITLE: 'Networking', + TRACK2TEACHER: '陆志浩', + TRACK2MAINTAINER: 'Networking Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1KV411Z7nR', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-networking' + }], + TRACK3: [{ + TRACK3TITLE: 'Virualization', + TRACK3TEACHER: '张海亮 ', + TRACK3MAINTAINER: 'Vir Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1q54y197CX', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-virtualization' + }] + }, + { + DESIGNTIME: [{ + DAY: '4 月 18 日', + HOUR: '09:00 - 10:00' + }], + TRACK1: [{ + TRACK1TITLE: '社区治理', + TRACK1TEACHER: '李永乐', + TRACK1MAINTAINER: 'openEuler社区秘书处负责人', + TRACK1LINK:'https://www.bilibili.com/video/BV1sA411b74z', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-governance' + }], + TRACK2: [{ + TRACK2TITLE: 'Compiler', + TRACK2TEACHER: '郭歌', + TRACK2MAINTAINER: 'Compiler Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV16Q4y1K7gV', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compiler' + }], + }, + { + DESIGNTIME: [{ + DAY: '4 月 18 日', + HOUR: '10:00 - 11:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Release Management', + TRACK1TEACHER: '马亮', + TRACK1MAINTAINER: 'openEuler 20.09 发布经理', + TRACK1LINK:'https://www.bilibili.com/video/BV1JA411b7tX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-release' + }], + TRACK2: [{ + TRACK2TITLE: 'Compatibility', + TRACK2TEACHER: '杜开田', + TRACK2MAINTAINER: 'Compatibility Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1F5411b7pJ', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compatibility' + }], + TRACK3: [{ + TRACK3TITLE: 'Dev-utils', + TRACK3TEACHER: '熊伟', + TRACK3MAINTAINER: 'openEuler TC member; Dev-utils Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1Ei4y1t7a8', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-dev-utils' + }] + + }, + { + DESIGNTIME: [{ + DAY: '4 月 18 日', + HOUR: '11:00 - 12:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Technical Committee', + TRACK1TEACHER: '胡欣蔚', + TRACK1MAINTAINER: 'openEuler 技术委员会主席', + TRACK1LINK:'https://www.bilibili.com/video/BV1rQ4y1K7L6', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-tc' + }], + TRACK2: [{ + TRACK2TITLE: 'Infrastructure', + TRACK2TEACHER: '李中华', + TRACK2MAINTAINER: 'openEuler Infrastructure Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1UT4y1G7fp', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-infrastructure' + }], + TRACK3: [{ + TRACK3TITLE: '安全委员会', + TRACK3TEACHER: '朱健伟', + TRACK3MAINTAINER: '操作系统安全领域专家', + TRACK3LINK:'https://www.bilibili.com/video/BV17Q4y1T7FN', + TRACK3DOWNLOAD:'https://etherpad.opendev.org/p/openeuler-virtual-summit-2020-security-committee' + }] + } + ], + OTHERLINK:[ + { + URL:'url("/img/home/link/mulan.png")', + LINK:'http://www.mulanos.cn/' + }, + { + URL:'url("/img/home/link/kunpeng.png")', + LINK:'https://kunpeng.huawei.com/' + }, + { + URL:'url("/img/home/link/pengcheng.png")', + LINK:'https://dw.pcl.ac.cn/dwmain/main/' + } + ] + }, + MEETUPS: { + MEETUPS: '沙龙', + DETAIL_DESC: '简介', + DETAIL_FLOW: '与会流程', + DETAIL_MEET: '参会信息', + DETAIL_REVIEW: '精彩回顾', + MORE_VIDEO: '更多视频', + DETAIL_QRCODE_TEXT: '扫码报名', + INSIDENAME: 'CONNECT', + DEFAULT_IMG: '/img/meetups/default-address.png', + MEETUPS_DATA: require('./../../data/salon').cn.MEETUPS_LIST + }, + DEVDAY_2021: { + PC_BANNER: '/img/summit/devday-2021/devday-2021-zh.png', + H5_BANNER: '/img/summit/devday-2021/banner-h5-zh.png' + }, + SUMMIT_2021: { + SPEACKER: '/img/summit/summit2021/call-speaker-zh.png', + SPEONSOR: '/img/summit/summit2021/call-sponsor-zh.png', + DEMO: '/img/summit/summit2021/call-demo-zh.png', + } + }, + en: { + LIVE: { + LIVE: 'Live', + WILLPLAYER: 'About to Begin', + REPLAYER: 'Wonderful Review', + LINKTIPS: 'The video is not uploaded yet', + LIVENOW: [ + + ], + LIVEFORMERLY: [ + { + LIVETITLE: '手把手教你编写Avocado-VT用例', + LIVETEACHER: '讲师: 朱欢凯', + LIVETIME: '时间: 12月14日 20:00(周二)', + PHOTOPATH: '/img/live/zhuhuankai.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Vz4y1r7fk' + }, + { + LIVETITLE: '玩转虚拟化测试Avocado-VT', + LIVETEACHER: '讲师: 柯志明', + LIVETIME: '时间: 12月1日 20:00(周二)', + PHOTOPATH: '/img/live/kezhiming.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ey4y1S7xv' + }, + { + LIVETITLE: 'StratoVirt之IO子系统剖析', + LIVETEACHER: '讲师: 张亮', + LIVETIME: '时间: 11月17日 20:00(周二)', + PHOTOPATH: '/img/live/zhangliang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17z4y1y7ME' + }, + { + LIVETITLE: 'StratoVirt之内存子系统剖析', + LIVETEACHER: '讲师: 杨晓鹤', + LIVETIME: '时间: 11月10日 20:00(周二)', + PHOTOPATH: '/img/live/yangxiaohe.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1XV411y73z' + }, + { + LIVETITLE: 'StratoVirt之CPU子系统剖析', + LIVETEACHER: '讲师: 高玮', + LIVETIME: '时间: 11月3日 20:00(周二)', + PHOTOPATH: '/img/live/gaowei.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YA411j7Ws' + }, + { + LIVETITLE: '如何安装并使用StratoVirt', + LIVETEACHER: '讲师: 郭馨乐', + LIVETIME: '时间: 10月27日 20:00(周二)', + PHOTOPATH: '/img/live/guoxinle.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ji4y177NC' + }, + { + LIVETITLE: '下一代虚拟化技术StratoVirt介绍', + LIVETEACHER: '讲师: 王志钢', + LIVETIME: '时间: 10月20日 20:00(周二)', + PHOTOPATH: '/img/live/wangzhigang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1gv411C7sK' + }, + { + LIVETITLE: '手把手带你完成openEuler环境部署 K8S', + LIVETEACHER: '讲师: 夏丹妮', + LIVETIME: '时间: 9月17日 20:00(周四)', + PHOTOPATH: '/img/live/xiadanni.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1At4y1e7mq' + }, + { + LIVETITLE: 'iSula容器之安全容器', + LIVETEACHER: '讲师: 姜鹏飞', + LIVETIME: '时间: 9月15日 20:00(周二)', + PHOTOPATH: '/img/live/jiangpengfei.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV14r4y1F7Dp' + }, + { + LIVETITLE: 'iSula容器之系统容器', + LIVETEACHER: '讲师: 章松', + LIVETIME: '时间: 9月10日 20:00(周四)', + PHOTOPATH: '/img/live/zhangsong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之安全特性实现解析', + LIVETEACHER: '讲师: 吴景', + LIVETIME: '时间: 9月8日 20:00(周二)', + PHOTOPATH: '/img/live/wujing.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之性能测试、分析与比较', + LIVETEACHER: '讲师: 刘昊', + LIVETIME: '时间: 9月3日 20:00(周四)', + PHOTOPATH: '/img/live/liuhao.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Mf4y1q7Ek' + }, + { + LIVETITLE: '轻量级容器引擎iSulad之功能介绍及架构解析', + LIVETEACHER: '讲师: 李峰', + LIVETIME: '时间: 9月1日 20:00(周二)', + PHOTOPATH: '/img/live/lifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV12y4y1C7Gr' + }, + { + LIVETITLE: 'isula-build之架构介绍', + LIVETEACHER: '讲师: 刘泽坤', + LIVETIME: '时间: 8月25日 20:00(周二)', + PHOTOPATH: '/img/live/liuzekun.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Gp4y1i7Rs' + }, + { + LIVETITLE: 'isula-build之源码剖析', + LIVETEACHER: '讲师: 李翔', + LIVETIME: '时间: 8月27日 20:00(周四)', + PHOTOPATH: '/img/live/lixiang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ca4y177te' + }, + { + LIVETITLE: '虚拟化技术介绍', + LIVETEACHER: '讲师: 张海亮', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhanghailiang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1of4y1X7p1' + }, + { + LIVETITLE: '安装虚拟化&管理虚拟机', + LIVETEACHER: '讲师: 陈振东', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/chenzhendong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: '初始openEuler', + LIVETEACHER: '讲师: 朱延朋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuyanpeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1it4y197KQ' + }, + { + LIVETITLE: '安装openEuler', + LIVETEACHER: '讲师: 冯涛', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/fengtao.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1vK4y1s7QG' + }, + { + LIVETITLE: '使用openEuler', + LIVETEACHER: '讲师: 沈洋洋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/shenyangyang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV13z4y1D7mq' + }, + { + LIVETITLE: 'openEuler构建之OBS使用指导', + LIVETEACHER: '讲师: 朱春意', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuchunyi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YK411H7E2' + }, + { + LIVETITLE: 'openEuler软件包的构建、开发与维护', + LIVETEACHER: '讲师: 何晓文', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/hexiaowen.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1pK411J7R9' + }, + { + LIVETITLE: '如何参与openEuler内核开发', + LIVETEACHER: '讲师: 谢秀奇', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/xiexiuqi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV11i4y1u7r9' + }, + { + LIVETITLE: 'openEuler网络配置', + LIVETEACHER: '讲师: 马郡', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/majun.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17C4y187sM' + }, + { + LIVETITLE: '可信计算之内核完整性度量', + LIVETEACHER: '讲师: 张天行', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhangtianxing.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1dk4y1171e' + }, + { + LIVETITLE: '开源版权和License', + LIVETEACHER: '讲师: 卜瑞峰', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/boruifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ty4y1y7eK' + }, + ] + }, + SUMMIT: { + SUMMIT: 'Summit', + NAV_LIST: [ + { + key: '#liveroom', + name: 'Live Broadcast' + }, + { + key: '#agenda', + name: 'Agenda' + }, + { + key: '#lecturer', + name: 'Speakers' + }, + { + key: '#host-unit', + name: 'Partners' + } + ], + SUMMITCONTENT: [ + 'The openEuler Summit 2020 will be held at Hyatt Regency Beijing Wangjing from December 24 to 25 in Beijing, China. The second summit this year, the event will dive deep into openEuler, the open source operating system of tomorrow and how it exceeds conventional technologies thanks to community participation. This openEuler event is an opportunity for developers to exchange the latest OS trends with like-minded individuals.', + 'The upcoming summit will focus on the collaboration across software-hardware and cloud-edge-device, as well as scenarios where all things are connected and diversified computing coexist. This event will discuss how to tap into technological innovation and build an open ecosystem. The summit provides an opportunity for streamlining the OS industry, and will consider how the openEuler OS can create shared value across the entire industry chain. The summit is only possible thanks to the participation of our developers, users, community contributors, and software enthusiasts, who have explored the latest OS developments. Together, we are on the cusp of the next breakthrough.' + ], + LIVETITLE: 'Live Broadcast', + PC_LIVEIMG: '/img/summit/home/en-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/en-mobile-liveroom.png', + SUMMITLIVE: [ + { + ID: 7095, + THEME: 'openEuler Summit 2020', + TIME: '09:30-11:55', + OPTION: '09:30-11:55 openEuler Summit 2020', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7095?lang=zh&thirdId=' + }, + { + ID: 7096, + THEME: 'Operating System', + TIME: '14:00-17:20', + OPTION: '14:00-17:20 Operating System', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7096?lang=zh&thirdId=' + }, + { + ID: 7097, + THEME: 'Cloud and Cloud Native', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Cloud and Cloud Native', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7097?lang=zh&thirdId=' + }, + { + ID: 7098, + THEME: 'Virtualization', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Virtualization', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7098?lang=zh&thirdId=' + }, + { + ID: 7099, + THEME: 'Open Source and Infrastructure', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Open Source and Infrastructure', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7099?lang=zh&thirdId=' + }, + { + ID: 7100, + THEME: 'Security & Trustworthiness', + TIME: '14:00-17:25', + OPTION: '14:00-17:25 Security & Trustworthiness', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7100?lang=zh&thirdId=' + }, + { + ID: 7101, + THEME: 'Basic Software', + TIME: '14:00-17:25', + OPTION: '14:00-17:25 Basic Software', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7101?lang=zh&thirdId=' + } + ], + SUMMIT_HOME_DATA: { + AGENDA: { + WEB_TITLE: '/img/summit/home/agenda/en-pc-agenda.png', + MOBILE_TITLE: '/img/summit/home/agenda/en-mobile-agenda.png', + DATE:['Dec 24','Dec 25','Morning','Afternoon'], + AFTERNOON_AGENDA_24: [ + { + TIME: '13:00-14:30', + THEME: 'Opening Speech', + SPEAKER: 'Ma Quanyi', + POSITION: 'Member, openEuler Technical Committee (TC)' + }, + { + TIME: '13:10-14:40', + THEME: 'Support of openEuler for the AppStream Mechanism' + }, + { + TIME: '13:10-14:40', + THEME: 'Applying for Establishing the Intelligent O&M SIG' + }, + { + TIME: '13:10-14:40', + THEME: 'Switching from Gitee Issues to Bugzilla' + }, + { + TIME: '13:10-14:40', + THEME: 'TC Collaboration Mode in 2021' + }, + { + TIME: '15:00-15:30', + THEME: 'Opening Speech & Maintainer Badge Awarding Ceremony', + SPEAKER: 'Ma Quanyi', + POSITION: 'Member, openEuler TC' + }, + { + TIME: '15:30-15:50', + THEME: 'openEuler Community Operation Analysis', + SPEAKER: 'Zhou Minghui', + POSITION: 'Boya Distinguished Professor, Peking University' + }, + { + TIME: '15:50-16:00', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Fang Yafen', + POSITION: 'Maintainer, RaspberryPi SIG' + }, + { + TIME: '16:00-16:10', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Yang Zhao', + POSITION: 'Maintainer, Ha SIG' + }, + { + TIME: '16:10-16:20', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Zheng Xian', + POSITION: 'Maintainer, ai-bigdata SIG' + }, + { + TIME: '16:20-17:00', + THEME: 'Q&A' + }, + { + TIME: '17:00-17:30', + THEME: 'Summary', + SPEAKER: 'Hu Xinwei', + POSITION: 'Chairman, openEuler TC' + } + ], + FORENOON_AGENDA_25: [ + { + TIME: '09:30-09:35', + THEME: 'Opening Speech' + }, + { + TIME: '09:35-09:50', + THEME: 'openEuler: Innovative OS for Industry Chain of Shared Value', + SPEAKER: 'Jiang Dayong', + POSITION: 'Director, openEuler Community' + }, + { + TIME: '09:50-09:55', + THEME: 'Establishment of the openEuler Technical Committee', + SPEAKER: 'Qiu Chengfeng', + POSITION: 'Vice Director, openEuler Community' + }, + { + TIME: '09:55-10:15', + THEME: 'openEuler Fuels Constant Technology Innovation', + SPEAKER: 'Hu Xinwei', + POSITION: 'Chairman, openEuler Technical Committee' + }, + { + TIME: '10:15-10:35', + THEME: "Huawei' s Contribution and Its Role in the Linux Kernel Community", + SPEAKER: 'Chen Haibo', + POSITION: 'Chief OS technical expert, Huawei; Distinguished Professor, Shanghai Jiao Tong University' + }, + { + TIME: '10:50-11:05', + THEME: 'Implementing Cloud Native Computing on Hybrid Architecture Platforms', + SPEAKER: 'Zhang Chun', + POSITION: 'Deputy General Manager, R&D Innovation Center, China Mobile Information Technology Center' + }, + { + TIME: '11:05-11:20', + THEME: 'Secure Mobile Edge Payment Powered by Confidential Computing', + SPEAKER: 'Zu Lijun', + POSITION: 'Director, National Engineering Laboratory for Electronic Commerce and Electronic Payment' + }, + { + TIME: '11:20-11:40', + THEME: 'openEuler & Friends: Diversified Ecosystem Scenarios', + SPEAKER: 'Xiong Wei and community developers' + }, + { + TIME: '11:40-11:50', + THEME: 'Open Source Promotes Shared Development and Governance for the Benefit of All', + SPEAKER: 'Du Junping', + POSITION: 'General Manager, Cloud & AI Open Source Business, Huawei' + }, + { + TIME: '11:50-11:55', + THEME: 'Awards Ceremony for openEuler Community Developers', + SPEAKER: 'Ma Quanyi', + POSITION: 'openEuler Maintainer' + } + ], + AFTERNOON_AGENDA_25: { + TIME_LIST: ['14:00-14:40','14:40-15:10','15:10-15:40','15:55-16:25','16:25-16:55','16:55-17:25'], + CARD_LIST: [ + { + TITLE: ['Session 1','Operating System'], + ITEM_LIST: [ + { + TIME: '14:00-14:40', + THEME: "Roundtable: The Operating System of Tomorrow, Unlocking Today's Diversified Computing" + }, + { + TIME: '14:40-15:10', + THEME: 'Application Performance Tuning of openEuler', + SPEAKER: ['Chen Qide, Beijing TurboLinux'], + DESC: ['Databases are one of the typical enterprise-grade Linux applications. To provide better database services for enterprises, we focus on performance indicators when developing distributed databases based on openEuler. These performance indicators include the duration and frequency of invoking functions, time-consuming thread processing, data types of memory cache, and network request delay. During database performance testing, we improve programs to squeeze the best hardware performance. This topic takes the performance tuning during database R&D as an example to describe the application performance tuning of openEuler.'] + }, + { + TIME: '15:10-15:40', + THEME: 'Community Helps Port RISC-V and NutShell Processors to openEuler OS', + SPEAKER: ['Zhou Peng, Institute of Software, Chinese Academy of Sciences (CAS)','Zhang Xuzhou, Huawei'], + DESC: ['In this topic, two speakers will use the general method for developing OS distributions to introduce how the openEuler Community helps port the RISC-V architecture and NutShell processors to openEuler OS. They will also discuss the challenges and opportunities for developing OS versions, in particular the status quo and problems of OS package dependency management. Furthermore, they will explore a new mode for managing OS dependencies and package distribution.'] + }, + { + TIME: '15:55-16:25', + THEME: 'Using Kubernetes to Deploy iSula Container Clusters on Raspberry Pi-based openEuler OS', + SPEAKER: ['Fang Yafen, Institute of Software, CAS','Li Baolin, Huawei'], + DESC: ['1. Porting the openEuler OS to Raspberry Pi as a Raspberry Pi-based image.','2. Using Kubernetes to deploy iSula container clusters on Raspberry Pi-based openEuler OS.'] + }, + { + TIME: '16:25-16:55', + THEME: 'General Accelerator Framework for Heterogeneous Systems: UADK Ecosystem and Development Progress', + SPEAKER: ['Gao Zhangfei, Linaro','Li Guozhu, Huawei'], + DESC: ['The Unified/User-space-access-intended Accelerator Framework (Uacce) is an accelerator framework jointly developed by Huawei HiSilicon and Linaro for heterogeneous systems. The main kernel drivers have been merged into the Linux kernel mainline, and we are developing the user-mode library UADK and OpenSSL engine. We aim to provide a more secure accelerator solution based on the IOMMU Shared Virtual Addressing (SVA) feature. The solution enables the accelerator and main CPU to share the unified address space. We hope to see more partners join us for development.'] + }, + { + TIME: '16:55-17:25', + THEME: 'Using eBPF to Replace the Kernel Module Compilation for an Efficient Network Monitoring System Without Performance Loss', + SPEAKER: ['Fan Bin, e Cloud'], + DESC: ['Traditional network monitoring systems are mostly implemented by compiling kernel modules or accessing proc files from user space. However, the kernel module compilation is complex and it is difficult to maintain and debug kernel modules. As a result, we need a solution that can implement functions similar to those of the kernel module without compromising performance. This presentation describes how to harness the eBPF technology for an efficient network monitoring system without performance loss. The system can be used to monitor and observe cloud native networks in data centers and locate faults such as network delay and package loss.'] + } + ] + }, + { + TITLE: ['Session 2','Cloud and Cloud Native'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'China Mobile: Kubernetes, openEuler, and iSula Empower the Smooth Scheduling Between ARM and x86', + SPEAKER: ['Wei Baohui, China Mobile Information Technology'], + DESC: ['In this presentation, Mr. Wei will tell us how China Mobile leverages the Kubernetes+openEuler+iSula for smooth scheduling between ARM and x86 architectures.'] + }, + { + TIME: '14:30-15:00', + THEME: 'Adapting and Integrating OpenStack to openEuler OS', + SPEAKER: ['Li Kunshan, China Unicom Cloud Data Company'], + DESC: ['This topic describes the progress and technology of adapting the OpenStack cloud platform to the openEuler OS, and shares technologies and cases in this regard.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Applying iSula to the Edge Computing OS HopeEdge', + SPEAKER: ['Liang Dong, Hoperun Information Technology'], + DESC: ['This topic describes the edge operating system developed based on openEuler. Thanks to the lightweight customization, the edge OS integrates the iSula container engine to quickly deploy and upgrade applications.'] + }, + { + TIME: '15:45-16:15', + THEME: 'Huayun Data: Adapting Kubernetes-based Platform to openEuler OS', + SPEAKER: ['Huang Maofeng, Huayun Data'], + DESC: ['Huayun Data develops the Kubernetes-based PaaS platform on Archer CloudSuite, and reconstructs and optimizes Kubernetes for different services. The adaptation to openEuler is highly challenging. Thanks to the openEuler Community, Huayun Data overcomes the difficulty and acquires abundant experience during the adaptation.'] + }, + { + IME: '16:15-16:45', + THEME: 'Working Principles and Practices of A-Tune: openEuler Intelligent Tuning Engine', + SPEAKER: ['Xie Zhipeng, Huawei'], + DESC: ['A-Tune adopts AI technologies to ensure the optimal service running. It builds precise models for services running on the operating system, understands service features and infers specific applications, and dynamically adjusts the parameters based on service loads to provide the optimal parameter configuration. ','This topic will discuss:','1. Implementing the core capabilities of A-Tune: online static tuning and offline dynamic tuning','2. Tuning cases of A-Tune','3. Technology roadmap of A-Tune'] + }, + { + IME: '16:45-17:15', + THEME: 'Playing minikube on openEuler', + SPEAKER: ['Zhao Shuai Linaro','Liu Xinliang Linaro'], + DESC: ['minikube is a simple tool for the local deployment of Kubernetes. It enables developers to start the Kubernetes cluster in one click and simplify the cluster O&M. In this presentation, two speakers will introduce the basic working principles of minikube and what we have done in the community to run minikube on openEuler. In addition to minikube, the compatibility of other mainstream Kubernetes deployment tools with openEuler will also be discussed in this topic.'] + } + ] + }, + { + TITLE: ['Session 3','Virtualization'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'StratoVirt: Next-Generation Virtualization Platform on openEuler', + SPEAKER: ['Wu Bin, Huawei'], + DESC: ['StratoVirt is a next-generation Rust-based Virtual Machine Manager (VMM). It is a virtualization platform oriented to enterprise cloud data centers and supports VM, container, and serverless scenarios. This topic describes the features, technical architecture, and roadmap of StratoVirt.'] + }, + { + TIME: '14:30-15:00', + THEME: 'Optimized Display Technology Tailored to Cloud Desktops', + SPEAKER: ['Sun Lijie, Hunan Kylinsec'], + DESC: ['Some technical issues may occur when cloud desktop products are implemented using the Kernel-based Virtual Machine (KVM). To deal with these issues, this topic describes technical solutions for graphics display and optimization, such as virtualized graphics card optimization, graphics card penetration, and video redirection. In addition, these solutions require the optimization and function enhancement of components such as the openEuler kernel and decoding library.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Implementing Virtualization and Private Cloud on openEuler', + SPEAKER: ['Qiu Dayu, Huayun Data'], + DESC: ['How to optimize the virtualization platform performance and quickly adapt it to the latest SAN devices, and how to provide high-performance virtual GPUs (vGPUs) are the major issues on the ARM-based platform, especially on the openEuler OS. This topic will show you how Huayun Data optimizes and adapts the virtualization platform to the openEuler OS, and how the company innovates the virtualization platform to support peripheral devices.'] + }, + { + TIME: '15:45-16:15', + THEME: 'Optimized Virtualization Performance Fueled by openEuler', + SPEAKER: ['Qi Zhihui, Sangfor Technologies'], + DESC: ['The topic presents the technologies for optimizing virtualization performance on openEuler, including storage and computing performance.'] + }, + { + TIME: '16:15-16:45', + THEME: 'Innovative Cloud Products Running on Kunpeng+openEuler', + SPEAKER: ['Luo Yun, Winhong Information Technology'], + DESC: ['Winhong has developed an enterprise-grade product powered by Kunpeng-based servers and the openEuler OS. This product supercharges server virtualization and cloud management of enterprises, and has earned good reputation in a wide range of industries, including governments, finance, and carriers. Today, we would like to present this product to our peers.'] + }, + {} + ] + }, + { + TITLE: ['Session 4','Open Source and Infrastructure'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'openEuler CLA Signing System for Multiple Code Hosting Platforms', + SPEAKER: ['Yuan Zhichang, ARM China','Chen Zeng, Huawei'], + DESC: ['This topic will discuss the following questions:','1. How does an open source community provide developer-friendly contribution license agreement (CLA) signing services? Which kind of services is better, self-developed services or services based on open source projects? How to ensure the legal force of the signed CLA? ','2. Which role does a contributor play in signing the CLA? How does an enterprise sign the CLA when participating in the community? After signing the CLA, how does the contributor protect the rights and interests in the subsequent development activities?'] + }, + { + TIME: '14:15-15:00', + THEME: 'Compass-CI: A Developer-Friendly Test System', + SPEAKER: ['Wu Fengguang, Huawei','Du Kaitian, Huawei'], + DESC: ['This topic presents how Compass-CI provides test services for the open source software ecosystem that supports multiple architectures and systems.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Building the Open Source Infrastructure and oepkgs Software Package Service Platform in openEuler Community', + SPEAKER: ['Yin Jiayi, Institute of Software, CAS','Cao Zhi, Huawei'], + DESC: ['1. Technology selection and practice of building openEuler Community infrastructure.','2. The oepkgs software package service platform consists of the oepkgs container image repository and oepkgs RedHat Package Manager (RPM) repository. In this topic, we will explain the background of building the oepkgs platform, as well as the basic architecture, usage, and developments of the two repositories for maintenance.'] + }, + { + TIME: '15:45-16:15', + THEME: 'How Open Source Community Data Drives the openEuler Operations', + SPEAKER: ['Xia Xiaoya, East China Normal University','Zhong Jun, Huawei'], + DESC: ['1. Why do we need digital operation?','2. How to select a proper digital operation system, such as the Community Health Analytics Open Source Software (CHAOSS), OM, and Kibble?','3. How to build the operation system architecture?','4. How to display operation data?','5. How to implement the CHAOSS indicator system?','6. How to drive digital operations in the openEuler Community?'] + }, + { + TIME: '16:15-16:45', + THEME: 'Insights into Open Source Products, Better Interactive Experience and Design for openEuler Developers', + SPEAKER: ['Zhang Shuting, Huawei','Ma Quanyi, Huawei'], + DESC: ['1. Open source projects and business are becoming interwoven. As a result, a successful open source project is only possible thanks to the innovative commercial product design. The first part of this topic describes how to design products in an open source project.','2. User experience teams are constantly striving to provide better interactive experience and design for open source developers. The second part of this topic describes how openEuler and openLooKeng communities provide developer-friendly products.'] + } + ] + }, + { + TITLE: ['Session 5','Security & Trustworthiness'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'openEuler Security Capability Development', + SPEAKER: ['Wei Gang, Huawei'], + DESC: ['A Security Committee member will tell you how the openEuler Community develops its security capabilities and the future plan for building a secure open source community. The topic will present a complete capability framework for community security. It focuses on the latest progress and challenges of the community in security coding, security design, and vulnerability collection, response, and handling.'] + }, + { + TIME: '14:30-15:00', + THEME: 'How Arm-v8.x Key Features Ensure Higher Performance and Security for openEuler', + SPEAKER: ['Yuan Zhichang, ARM China'], + DESC: ['This topic describes the four Arm-v8.x key features related to performance and security, including Large System Extension (LSE), Scalable Vector Extension (SVE), Pointer Authentication (PAuth), and Branch Target Identification (BTI). The topic will also discuss the support for the preceding features in upstream open source communities, OS open source communities, and openEuler Community.'] + }, + { + TIME: '15:00-15:30', + THEME: 'RAS on ARM64', + SPEAKER: ['Chen Gong, Huawei'], + DESC: ['Reliability is the cornerstone of server platforms. The concept of Reliability, Availability, and Serviceability (RAS) has been the focus of any server platform since it was proposed by IBM 50 years ago. RAS is an essential indicator for both the x86-based Xeon platform and the new ARM64-based platform. This topic will give you an overview of the RAS and present how the openEuler-based ARM64 servers enhance their RAS. '] + }, + { + TIME: '15:45-16:15', + THEME: 'How to Create a Compliant Open Source Community', + SPEAKER: ['Bian Naimeng, Hoperun Information Technology','Gao Kun, Huawei'], + DESC: ['One of the biggest risks of open source projects is non-compliance. To enhance open source compliance, communities need to ensure authorized code source and high code quality. An open source community would flourish only when it is fully compliant. Against this backdrop, the topic describes how to build a compliant open source community.'] + }, + { + TIME: '16:15-16:45', + THEME: 'SELinux-based Confidentiality and Integrity Policy', + SPEAKER: ['Luoqiu, Hunan Kylinsec'], + DESC: ['Security-Enhanced Linux (SELinux) is a standardized security infrastructure on the openEuler. For specific software services, SELinux controls confidentiality and integrity, ensures that the direction of information flows remains unchanged, and prevents sensitive information leakage and unauthorized modification. This topic analyzes how to implement trustworthiness policies in different scenarios using SELinux.'] + }, + { + TIME: '16:45-17:15', + THEME: 'OS Built on Intrinsic Security', + SPEAKER: ['Wang Jiangtao, iSoft Infrastructure Software'], + DESC: ['Trustworthy computing requires dedicated servers, which result in the huge workload of software architecture reconstruction. The existing servers of enterprises, public institutions, and Internet data centers are mostly x86-based. As a result, it takes a long time to replace all these x86-based servers with servers running on Chinese-made hardware and software. The solution for faster replacement is the operating system built on intrinsic security, which combines the mature encryption card with encryptor.'] + } + ] + }, + { + TITLE: ['Session 6','Basic Software'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'Technical Architecture and Deployment of the BiSheng JDK and BiSheng Compiler', + SPEAKER: ['Guo Ge, Huawei','Wei Wei, Huawei'], + DESC: ['The BiSheng JDK and BiSheng Compiler were officially released in the openEuler 20.09 version. This topic describes the core technologies of these two BiSheng software products and how the compilation technology enables upper-layer applications.'] + }, + { + TIME: '14:30-15:00', + THEME: 'HA Enterprise Solutions Powered by openGauss on openEuler', + SPEAKER: ['Liu Weiyun, Beijing Enmotech'], + DESC: ['The topic discusses how openGauss enables the HA solution on the openEuler platform, including the enterprise-grade two-node cluster, one active node and multiple standby nodes, and cross-equipment room deployment, as well as the success cases of the HA solution.'] + }, + { + TIME: '15:00-15:30', + THEME: 'High-Performance SDS Running on Kunpeng+openEuler', + SPEAKER: ['Chi Xinze, XSKY (Beijing) Data Technology'], + DESC: ['This topic introduces:','1. The process of porting XEDP from CentOS 7.6 + x86 to openEuler+Kunpeng','2. Problems during the porting and corresponding solutions','3. The performance tuning solution for XEDP on the openEuler+Kunpeng architecture, and the application cases of the solution'] + }, + { + TIME: '15:45-16:15', + THEME: 'DDE: Desktop OS Architecture Design', + SPEAKER: ['Wang Yaohua, Uniontech Software'], + DESC: ['Uniontech Software offers the ultimate DDE desktop OS, which is powered by the openEuler OS and the optimized kernel of the openEuler Community. This presentation will unveil the basic architecture of the DDE to help you dive deeper into the basic functions, technical principles, and architecture design of the DDE desktop OS.'] + }, + { + TIME: '16:15-16:45', + THEME: 'Ultimate Performance and Application Cases of openGauss on Kunpeng Platform', + SPEAKER: ['Huang Xiaotao, Beijing Vastdata Technology','Feng Jie, Huawei','Wang Junjie, Huawei'], + DESC: ['1. Speakers from Huawei will describe how openGauss on the multi-core Kunpeng server is optimized in the online transaction processing (OLTP) scenario, including bottleneck analysis, methods, and results of the optimization.','2. Vastbase is an enterprise-class relational database built on years of industry experience. The representative from Vastdata Technology will discuss how the massive Vastbase is ported to the Kunpeng + openEuler OS platform.'] + }, + { + TIME: '16:45-17:15', + THEME: 'UKUI: File Manager Architecture Analysis', + SPEAKER: ['Li Jianfeng, Kylinsoft'], + DESC: ['The newly designed UKUI 3.0 can be downloaded and installed in openEuler 20.03 SP1 and 20.09 versions. This topic describes the file manager in the UKUI desktop environment, including the upgrade from the UKUI file manager 2.0 to 3.0, technology selection and overall architecture design of the latest file manager, and future developments.'] + } + ] + } + ] + }, + SIG_CONTENT: { + TITLE: 'SIG Open Working Sessions', + SIG1_TIME: '16:00 - 16:10' , + SIG1_DETAIL: ['Opening Speech','Ma Quanyi','Member of openEuler TC'], + SIG2_TIME: '16:10 - 17:00', + SIG2_DETAIL: [ + { + THEME: 'SIG-DDE', + CONTENT: ['1) Achievements of Adapting DDE to openEuler','2) DDE Version Update Plan',"3) Discussion on Enthusiasts' Requirements for the Desktop"] + }, + { + THEME: 'SIG-UKUI', + CONTENT: ['1) Work Progress of UKUI for openEuler 20.03 LTS SP1','2) Discussion on the Future Development of UKUI'] + }, + { + THEME: 'SIG-Ha', + CONTENT: ['1) Progress of the Ha project','2) Discussion on the Plan for Merging the Ha Project into Upstream Community'] + }, + { + THEME: 'SIG-aarch32', + CONTENT: ['1) Work Progress of Adapting AArch32 to openEuler','2) Discussion on the Coexistence Between AArch32 Adapted Code and Mainline Versions'] + }, + { + THEME: 'SIG-A-Tune', + CONTENT: ['1) Review of New Features and Achievements of A-Tune in 2020','2) Discussion on Future Technology Evolution of A-Tune','3) Development Process of A-Tune and Wisdom in Community and Key Issue Analysis','4) Discussion on Papers of the Latest Tuning Technology'] + }, + { + THEME: 'SIG-iSulad & Container', + CONTENT: ['1) Cloud Native Technologies','2) Cloud Native Efficiency Improvement','3) Issues of Cloud Native Application'] + }, + { + THEME: 'SIG-ai-bigdata', + CONTENT: ['1) Review of Achievements of ai-bigdata SIG in 2020','2) Discussion on LTS Version Selection','3) Discussion on the openEuler-based Big Data and AI Platform',"4) Discussion on the SIG's Technical Scope and Roadmap"] + }, + { + THEME: 'SIG-security-facility & sig-confidential-computing', + CONTENT: ['1) Existing Security Technologies of security-facility SIG','2) Discussion on openEuler Security Technology Developments and Roadmap','3) Discussion on Confidential Computing Application Scenarios and Security Technologies'] + }, + { + THEME: 'SIG-Compiler', + CONTENT: ['1) Working plan of Compiler SIG, Including the JDK/GCC Support Roadmap','2) Discussion on Requirements for Supporting Compilers (LLVM) and Rust/Go Programming Languages','3) Discussion on the Plan for Supporting Containers (iSula) on openJDK'] + }, + { + THEME: 'SIG-doc', + CONTENT: ['1) Introduction to the Current Document System of openEuler Community','2) Discussion on the Plan and Focus of the Doc SIG','3) Discussion on Encouraging Developers to Contribute Blogs and Videos to Community'] + }, + { + THEME: 'SIG-Infrastructure', + CONTENT: ['1)Review of the openEuler Infrastructure in 2020','2)Discussion on the openEuler Infrastructure Key Priorities in 2021','3)Ideas of Promoting Intelligent O&M on openEuler Infrastructure'] + }, + { + THEME: 'SIG-security-committee', + CONTENT: ['1) Analysis of Vulnerability Handling Process of openEuler Community: Vulnerability Awareness, Handling, and Disclosure','2) Discussion on Security Vulnerability Patch Fix Policies','3) Discussion on Applying the Security Guide in Community','4) Discussion on Collaboration Between Security TC and SIGs for Vulnerability Analysis, Fix, and Disclosure'] + }, + { + THEME: 'SIG-Compatibility-Infra', + CONTENT: ['1) Kernel KABI and Southbound Driver Compatibility','2) Software Package Compatibility Level and Northbound Application Compatibility','3) Compatibility Policy Between Versions'] + }, + { + THEME: 'SIG-QA', + CONTENT: ['1) Discussion on Building the Quality Measurement System of openEuler Community','2) Discussion on Conducting Crowdtesting in openEuler Community','3) Discussion on the SIG Future Plan'] + }, + { + THEME: 'SIG-release-management', + CONTENT: ['1) Discussion on Version Lifecycle Plan of openEuler Community: 20.03 Maintenance Lifecycle and SP2 Release Time','2) Discussion on Policies of Partner Version Consistence and Component Upgrade: Patch Backporting, Version Upgrade, Component Mode, Secondary Development, and Backporting Time','3) Discussion on Participation of OSVs and ISVs in the release-management SIG and the SIG Operation'] + }, + { + THEME: 'SIG-Kernel', + CONTENT: ['1) Kernel Test Protection and Stability Assurance','2) Leveraging Community Expertise to Discover and Fix openEuler Kernel Bugs and Ensure Stability of LTS Versions','3) Discussion on the Policy for Merging Innovation Version Features','4) Discussion on Requirements for the openEuler 5.10 Kernel Version'] + }, + { + THEME: 'SIG-Virt', + CONTENT: ['1) Overview of New Technologies and Success Practices of Virt SIG in 2020','2) Discussion on the Technical Planning of Virt SIG in 2021','3) Discussion on Requirements for Virt SIG, such as New Features, Development Process, and Issue Resolution'] + } + ], + SIG3_TIME: '17:00 - 18:30', + SIG3_DETAIL: ['Presentation & Exchange of Discussion Results'] + } + }, + LECTURER: { + WEB_TITLE: '/img/summit/home/lecturer/en-pc-lecturer.png', + MOBILE_TITLE: '/img/summit/home/lecturer/en-mobile-lecturer.png', + LECTURERLIST: [ + { + IMG: '/img/summit/home/lecturer/jiangdayong.png', + NAME: 'Jiang Dayong', + POSITION: 'Director, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/qiuchengfeng.png', + NAME: 'Qiu Chengfeng', + POSITION: 'Vice Director, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/huxinwei.png', + NAME: 'Hu Xinwei', + POSITION: 'Chairman, openEuler Technical Committee' + }, + { + IMG: '/img/summit/home/lecturer/chenhaibo.png', + NAME: 'Chen Haibo', + POSITION: 'Chief OS Technical Expert, Huawei/Distinguished Professor, Shanghai Jiao Tong University' + }, + { + IMG: '/img/summit/home/lecturer/zulijun.png', + NAME: 'Zu Lijun', + POSITION: 'Director, National Engineering Laboratory for Electronic Commerce and Electronic Payment' + }, + { + IMG: '/img/summit/home/lecturer/xiongwei.png', + NAME: 'Dr. Xiong Wei', + POSITION: 'Member, openEuler Technical Committee' + }, + { + IMG: '/img/summit/home/lecturer/dujunping.png', + NAME: 'Du Junping', + POSITION: 'General Manager, Cloud & AI Open Source Business, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/maquanyi.png', + NAME: 'Ma Quanyi', + POSITION: 'openEuler Community Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/chenqide.png', + NAME: 'Chen Qide', + POSITION: 'Deputy General Manager, Beijing TurboLinux' + }, + { + IMG: '/img/summit/home/lecturer/zhoupeng.png', + NAME: 'Zhou Peng', + POSITION: 'Research Fellow, Institute of Software, Chinese Academy of Sciences (CAS)' + }, + { + IMG: '/img/summit/home/lecturer/zhangxuzhou.png', + NAME: 'Zhang Xuzhou', + POSITION: 'openEuler RISC-V SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/fangyafen.png', + NAME: 'Fang Yafen', + POSITION: 'Engineer, Institute of Software, CAS' + }, + { + IMG: '/img/summit/home/lecturer/libaolin.png', + NAME: 'Li Baolin', + POSITION: 'Operation Engineer, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/zhaoshuai.png', + NAME: 'Zhao Shuai', + POSITION: 'Tech Lead, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/liuxinliang.png', + NAME: 'Liu Xinliang', + POSITION: 'Senior Software Engineer, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/gaozhangfei.png', + NAME: 'Gao Zhangfei', + POSITION: 'Landing Team Software Engineer, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/fanbin.png', + NAME: 'Fan Bin', + POSITION: 'Senior Back-End Development Engineer, e Cloud' + }, + { + IMG: '/img/summit/home/lecturer/weibaohui.png', + NAME: 'Wei Baohui', + POSITION: 'PaaS R&D Manager, China Mobile Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/likunshan.png', + NAME: 'Li Kunshan', + POSITION: 'OpenStack R&D Engineer, China Unicom Cloud Data Company' + }, + { + IMG: '/img/summit/home/lecturer/liangdong.png', + NAME: 'Liang Dong', + POSITION: 'Senior Engineer & HopeEdge Version Manager, Hoperun Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/huangmaofeng.png', + NAME: 'Huang Maofeng', + POSITION: 'Senior Technical Manager, Huayun Data' + }, + { + IMG: '/img/summit/home/lecturer/wubin.png', + NAME: 'Wu Bin', + POSITION: 'openEuler Virtualization SIG Maintainer/ICT Virtualization Architect, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/sunlijie.png', + NAME: 'Sun Lijie', + POSITION: 'R&D Manager, Hunan Kylinsec' + }, + { + IMG: '/img/summit/home/lecturer/qiudayu.png', + NAME: 'Qiu Dayu', + POSITION: 'Senior Technical Director, Huayun Data' + }, + { + IMG: '/img/summit/home/lecturer/yuzhihui.png', + NAME: 'Qi Zhihui', + POSITION: 'Localized Trusted Cloud R&D Owner, Sangfor Technologies' + }, + { + IMG: '/img/summit/home/lecturer/luoyun.png', + NAME: 'Luo Yun', + POSITION: 'Virtualization & Cloud Product Manager, Winhong Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/chenzeng.png', + NAME: 'Chen Zeng', + POSITION: 'Senior Engineer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/dukaitian.png', + NAME: 'Du Kaitian', + POSITION: 'openEuler CICD SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/yinjiayi.png', + NAME: 'Yin Jiayi', + POSITION: 'System Engineer, Institute of Software, CAS' + }, + { + IMG: '/img/summit/home/lecturer/caozhi.png', + NAME: 'Cao Zhi', + POSITION: 'openEuler Infra SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/xiaxiaoya.png', + NAME: 'Xia Xiaoya', + POSITION: 'Open Source Expert, East China Normal University' + }, + { + IMG: '/img/summit/home/lecturer/zhongjun.png', + NAME: 'Zhong Jun', + POSITION: 'Senior Open Source Engineer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/zhangshuting.png', + NAME: 'Zhang Shuting', + POSITION: 'Computing Product Experience Designer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/weigang.png', + NAME: 'Wei Gang', + POSITION: 'Security & Trustworthiness Technical Expert, Computing Product Line, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/yuanzhichang.png', + NAME: 'Yuan Zhichang', + POSITION: 'Chief Software Engineer of Open Source Ecosystem, Arm China' + }, + { + IMG: '/img/summit/home/lecturer/chengong.png', + NAME: 'Chen Gong', + POSITION: 'Technical Expert, Kunpeng Computing PDU, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/biannaimeng.png', + NAME: 'Bian Naimeng', + POSITION: 'Product R&D Director, Cloud Computing Business Group, Hoperun Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/gaokun.png', + NAME: 'Gao Kun', + POSITION: 'Engineer, Open Source Software Competence Center, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/luoqiu.png', + NAME: 'Luo Qiu', + POSITION: 'R&D Engineer, Hunan Kylinsec' + }, + { + IMG: '/img/summit/home/lecturer/wangjiangtao.png', + NAME: 'Wang Jiangtao', + POSITION: 'Senior Security Expert, iSoft Infrastructure Software' + }, + { + IMG: '/img/summit/home/lecturer/liuwei.png', + NAME: 'Liu Wei', + POSITION: 'Researcher, 2020 Lab, Beijing Enmotech' + }, + { + IMG: '/img/summit/home/lecturer/chixinze.png', + NAME: 'Chi Xinze', + POSITION: 'Distributed System Architect, XSKY (Beijing) Data Technology' + }, + { + IMG: '/img/summit/home/lecturer/huangxiaotao.png', + NAME: 'Huang Xiaotao', + POSITION: 'Deputy Director, Database Research Institute, Beijing Vastdata Technology' + }, + { + IMG: '/img/summit/home/lecturer/lijianfeng.png', + NAME: 'Li Jianfeng', + POSITION: 'Director, Desktop R&D Community, Kylinsoft' + }, + { + IMG: '/img/summit/home/lecturer/wangyaohua.png', + NAME: 'Wang Yaohua', + POSITION: 'R&D Director, Uniontech Software' + }, + { + IMG: '/img/summit/home/lecturer/fengben.png', + NAME: 'Feng Ben', + POSITION: 'Expert of Kunpeng Database Optimization, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/wangjunjie.png', + NAME: 'Wang Junjie', + POSITION: 'Expert of Kunpeng Database Optimization, Huawei' + } + ] + }, + HOST: { + WEB_TITLE: '/img/summit/home/host-unit/en-host-unit.png', + MOBILE_TITLE: '/img/summit/home/host-unit/en-mobile-zhuban.png', + LIST: [ + { + IMG: '/img/summit/home/host-unit/openeuler.png' + } + ] + }, + UNDERTAKER: { + WEB_TITLE: '/img/summit/home/undertaker/en-pc-undertaker.png', + MOBILE_TITLE: '/img/summit/home/undertaker/en-mobile-undertaker.png', + LIST: [ + { + IMG: '/img/summit/home/undertaker/jikebang.png', + LINK: 'https://www.geekbang.org/' + } + ] + }, + CO_ORGANIZER: { + WEB_TITLE: '/img/summit/home/co-organizer/en-co-organizer.png', + MOBILE_TITLE: '/img/summit/home/co-organizer/en-mobile-xieban.png', + LIST: [ + { + IMG: '/img/summit/home/co-organizer/yidong.png', + LINK: 'http://it.10086.cn/indexc.html' + }, + { + IMG: '/img/summit/home/co-organizer/liantong.png', + LINK: 'https://www.woyun.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yinlian.png', + LINK: 'https://cn.unionpay.com/' + }, + { + IMG: '/img/summit/home/co-organizer/pengcheng.png', + LINK: 'https://www.pcl.ac.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/feiteng.png', + LINK: 'https://www.phytium.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/qilin.png', + LINK: 'http://www.kylinos.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/tongxin.png', + LINK: 'https://www.uniontech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/cetc.png', + LINK: 'http://www.i-soft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/xinan.png', + LINK: 'http://www.kylinsec.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/iscas.png', + LINK: 'http://www.iscas.ac.cn' + }, + { + IMG: '/img/summit/home/co-organizer/turbolinux.png', + LINK: 'http://www.turbolinux.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/beiming.png', + LINK: 'http://www.bmsoft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/runhe.png', + LINK: 'http://www.hopeedge.com' + }, + { + IMG: '/img/summit/home/co-organizer/xsky.png', + LINK: 'http://www.xsky.com' + }, + { + IMG: '/img/summit/home/co-organizer/huayun.png', + LINK: 'https://huayun.com/' + }, + { + IMG: '/img/summit/home/co-organizer/qingyun.png', + LINK: 'https://kubesphere.qingcloud.com/' + }, + { + IMG: '/img/summit/home/co-organizer/shenxinfu.png', + LINK: 'https://www.sangfor.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhong.png', + LINK: 'http://www.winhong.com/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhe.png', + LINK: 'https://enmotech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/hailiang.png', + LINK: 'http://www.vastdata.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/hangtian.png', + LINK: 'https://www.htzhiyun.cn' + }, + { + IMG: '/img/summit/home/co-organizer/langche.png', + LINK: 'https://lstack.com/' + } + ] + }, + FOUNDATION: { + WEB_TITLE: '/img/summit/home/foundation/en-pc-foundation.png', + MOBILE_TITLE: '/img/summit/home/foundation/en-mobile-foundation.png', + LIST: [ + { + IMG: '/img/summit/home/foundation/yuanzi.png', + LINK: 'https://www.openatom.org' + }, + { + IMG: '/img/summit/home/foundation/cloudnative.png', + LINK: 'https://www.cncf.io/' + }, + { + IMG: '/img/summit/home/foundation/linaro.png', + LINK: 'https://www.linaro.org/' + }, + { + IMG: '/img/summit/home/foundation/linux.png', + LINK: 'https://www.linuxfoundation.org/' + }, + { + IMG: '/img/summit/home/foundation/open.png', + LINK: 'https://www.openinfra.dev/' + } + ] + }, + MEDIA: { + WEB_TITLE: '/img/summit/home/media/en-pc-media.png', + MOBILE_TITLE: '/img/summit/home/media/en-mobile-media.png', + LIST: [ + { + IMG: '/img/summit/home/media/csdn.png', + LINK: 'https://www.csdn.net/' + }, + { + IMG: '/img/summit/home/media/sifou.png', + LINK: 'https://segmentfault.com/' + }, + { + IMG: '/img/summit/home/media/oschina.png', + LINK: 'https://www.oschina.net/' + }, + { + IMG: '/img/summit/home/media/51cto.png', + LINK: 'https://www.51cto.com/' + }, + { + IMG: '/img/summit/home/media/media-linux.png', + LINK: 'https://linux.cn/' + }, + { + IMG: '/img/summit/home/media/xianglingshuo.png', + LINK: 'qrcode' + }, + ] + }, + REVIEW: { + WEB_TITLE: '/img/summit/home/review/en-pc-review.png', + MOBILE_TITLE: '/img/summit/home/review/en-mobile-review.png', + WEB_BANNER: '/img/summit/home/review/web-review-banner.png', + MOBILE_BANNER: '/img/summit/home/review/h5-review-banner.png' + } + }, + LISTTITLE: 'Overview', + LISTNEWTITLE:'openEuler Virtual Summit 2020', + LISTTIME: 'Apr 17–18, 2020', + SPEECHTITLE: 'Keynotes', + DESIGNTITLE: 'Design Summit (SIG Workshop)', + VIDEODOWNLOAD: 'Slides', + FRIENDSHIPLINK: 'Links', + SUMMIT_WEB_IMG: '/img/summit/home/en-pc-summit.png', + SUMMIT_H5_IMG: '/img/summit/home/en-mobile-summit.png', + SPEECHLIST: [{ + SPEECHTIME: '09:30 - 09:40, 17th April', + SPEECHTHEME: 'openEuler Drives a Robust Multi-Core, Heterogeneous Computing Industry', + SPEECHER: 'Jiang Dayong', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/jiangdayong.png', + SPEECHERINFO: '', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '09:40 - 09:50, 17th April', + SPEECHTHEME: 'openEuler: The Industry Propeller and Super Workshop', + SPEECHER: 'WangZhun', + SPEECHCONTENT: 'Focusing on IT transformation and industrial Internet construction in traditional industries, he has chaired the architecture planning of national-level information technology projects and provided consulting services to major ministries and central enterprises. As a member of the Association of Enterprise Architect, he is committed to promoting the rollout and implementation of enterprise architecture in China.', + SPEECHERIMG: '/img/summit/wangzhun.jpg', + SPEECHERINFO: 'Senior Architect, Tongfang', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '09:50 - 10:30, 17th April', + SPEECHTHEME: 'Innovation Drives the Future of openEuler', + SPEECHER: 'Dr. Xiong Wei', + SPEECHCONTENT: 'Xiong Wei, joined Huawei in 2014, is now the 2012 laboratory Central Software Institute server operating system chief architect, openEuler technical committee member; Nankai University, doctor of engineering, in TurboLinux, WindRiver and other companies as R & D person in charge, has a long time OS, underlying software experience and technology accumulation; on the processor, architecture, OS, containers, etc. has a broad technical vision, initially established the Kunpeng basic software stack server OS, container engine and other infrastructure of the platform system of self- research.', + SPEECHERIMG: '/img/summit/xiongwei.png', + SPEECHERINFO: 'Member of openEuler Technical Committee', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:30 - 10:40, 17th April', + SPEECHTHEME: 'openEuler Leads the Way to a Co-Built, Win-Win Global Community', + SPEECHER: 'Yu Liang', + SPEECHCONTENT: 'More than 20 years in the field of basic operating system, witnessed the development history of domestic Linux operating system. In 2016, he joined Puhua as Vice President of Marketing in the Basic Software Division of Puhua Corporation. Since the national e-government intranet "12 banks and 3 gold" project, it has participated in most of the landmark projects of the domestic operating system.', + SPEECHERIMG: '/img/summit/yuliang.png', + SPEECHERINFO: 'Deputy GM, Basic Software Business Group, iSoft', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:40 - 10:50, 17th April', + SPEECHTHEME: 'Kylin: Scale New Heights on the Wings of Kunpeng', + SPEECHER: 'Li Zhenning', + SPEECHCONTENT: 'The most valuable expert of HUAWEI CLOUD and Tencent Cloud; Director of Shanghai Basic Software Engineering Technology Research Center and mentor of master students at Taiyuan University of Technology. Li Zhenning has served in the open source and operating system field for 20 years, and his clients include many government agencies, national defense and aerospace, banks, securities, universities, etc. He has rich experience in open source operating system software technology, marketing and PR communication. He is currently an expert in the operating system and basic software industry in several ministries, provinces and cities. Research on industry macro development, technology trends, standards policy, etc. Currently, he is also a member of the China-Japan-Korea Northeast Asia Open Source Committee, Secretary General of the Open Source and Basic Software General Technology Innovation Strategic Alliance (UU); Deputy Secretary General of the China High-end Chip Alliance, Deputy Secretary General of the China Open Source Software Promotion Alliance, Deputy Secretary General of the China Open Source Cloud Alliance, Deputy Secretary General of the China Big Data Application Collaboration and Innovation Alliance, Head of the TIAA Automotive Alliance Software Group; Member of the CCF System Software Committee; Deputy Director of the China Big Data and Intelligent Computing Industry Alliance Open Source Software Working Committee, etc.', + SPEECHERIMG: '/img/summit/lizhenning.jpg', + SPEECHERINFO: 'VP, Kylinsoft', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:50 - 11:00, 17th April', + SPEECHTHEME: ' Open Source Software Supply Lightening Program Boosts a Robust Community', + SPEECHER: 'Wu Yanjun', + SPEECHCONTENT: 'Researcher, Ph.D. supervisor, Deputy Chief Engineer, Institute of Software, Chinese Academy of Sciences, Director of Intelligent Software Research Center. After graduating from Tsinghua University, he joined the Software Institute of Chinese Academy of Sciences and has been working on operating system related research and development for a long time. He has published more than 50 papers in top academic conferences and core journals, and applied for more than 30 patents and softwares. He has been honored by the Beijing Science and Technology Rising Star and the Chinese Academy of Sciences Youth Promotion Association.', + SPEECHERIMG: '/img/summit/wuyanjun.png', + SPEECHERINFO: 'Deputy Chief Engineer, Director of Intelligent Software Research Center, ISCAS', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:00 - 11:10, 17th April', + SPEECHTHEME: 'openEuler: The Best MySQL Platform on Arm-based Servers', + SPEECHER: 'Ding Wenlong', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/dingwenlong.png', + SPEECHERINFO: 'Senior Engineer, Turbolinux', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:10 - 11:25, 17th,April', + SPEECHTHEME: 'How to Enjoy openEuler', + SPEECHER: 'Ma Junjie', + SPEECHCONTENT: 'openEuler Infrastructure Committer, openEuler oVirt SIG maintainer, oVirt Member, Istio community Member', + SPEECHERIMG: '/img/summit/majunjie.png', + SPEECHERINFO: 'openEuler Infrastructure SIG Committer', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:25 - 11:45, 17th,April', + SPEECHTHEME: 'openEuler Community Governance', + SPEECHER: 'Hu Xinwei', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/huxinwei.png', + SPEECHERINFO: 'Chairman of openEuler Technical Committee', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + ], + TRACKLIST: ['Track 1', 'Track 2', 'Track 3'], + DESIGNLIST: [{ + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '13:30 - 15:00' + }], + TRACK1: [{ + TRACK1TITLE: 'openEuler Kernel', + TRACK1TEACHER: 'Hanjun Guo', + TRACK1MAINTAINER: 'openEuler Kernel Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1E64y1T76a', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-kernel' + }], + TRACK2: [{ + TRACK2TITLE: 'RaspberryPi', + TRACK2TEACHER: 'Yafen Fang', + TRACK2MAINTAINER: 'RaspberryPi Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1Ve411s74C', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-raspberrypi' + }], + TRACK3: [{ + TRACK3TITLE: 'UKUI', + TRACK3TEACHER: 'Dou Yan', + TRACK3MAINTAINER: 'UKUI Maintainer, Member of KylinSoft open source community', + TRACK3LINK:'https://www.bilibili.com/video/BV1ei4y187SD', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ukui' + }] + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '15:00 - 16:00' + } + + ], + TRACK1: [{ + TRACK1TITLE: 'Container & iSula', + TRACK1TEACHER: 'Haomin Tsai', + TRACK1MAINTAINER: 'Container & iSula SIG Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1A54y1R7iX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-container' + }], + TRACK2: [{ + TRACK2TITLE: 'Documentation', + TRACK2TEACHER: 'Zhipeng Tan', + TRACK2MAINTAINER: 'Documentation Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1yT4y1G78u', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-documentation' + }], + TRACK3: [{ + TRACK3TITLE: 'High Availability', + TRACK3TEACHER: 'jian Hou ', + TRACK3MAINTAINER: 'HA Maintainer; KylinSoft', + TRACK3LINK:'https://www.bilibili.com/video/BV1Wt4y1272N', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ha' + }] + + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '16:00 - 17:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Packaging & Base Service', + TRACK1TEACHER: 'Xiaowen He', + TRACK1MAINTAINER: 'Packaging Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1we411s7rQ', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-packaging' + }], + TRACK3: [{ + TRACK3TITLE: 'oVirt', + TRACK3TEACHER: 'Huihui Fu ', + TRACK3MAINTAINER: 'oVirt Maintainer; KylinSoft', + TRACK3LINK:'https://www.bilibili.com/video/BV1LK4y1k7Hv', + TRACK3DOWNLOAD:'hhttps://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ovirt' + }] + + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '17:00 - 18:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Kubernetes', + TRACK1TEACHER: 'Pengfei Zhou', + TRACK1MAINTAINER: 'SIG-Kubernetes Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1ak4y1R7Sq', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-kubernetes' + }], + TRACK2: [{ + TRACK2TITLE: 'Networking', + TRACK2TEACHER: 'Zhihao Lu', + TRACK2MAINTAINER: 'Networking Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1KV411Z7nR', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-networking' + }], + TRACK3: [{ + TRACK3TITLE: 'Virualization', + TRACK3TEACHER: 'Hailiang Zhang ', + TRACK3MAINTAINER: 'Vir Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1q54y197CX', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-virtualization' + }] + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '09:00 - 10:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Community Governance', + TRACK1TEACHER: 'Fred Li', + TRACK1MAINTAINER: 'Head of openEuler Secretariat', + TRACK1LINK:'https://www.bilibili.com/video/BV1sA411b74z', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-governance' + }], + TRACK2: [{ + TRACK2TITLE: 'Compiler', + TRACK2TEACHER: 'Ge Guo', + TRACK2MAINTAINER: 'Compiler Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV16Q4y1K7gV', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compiler' + }], + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '10:00 - 11:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Release Management', + TRACK1TEACHER: 'Liang Ma', + TRACK1MAINTAINER: 'openEuler 20.09 Release Manager', + TRACK1LINK:'https://www.bilibili.com/video/BV1JA411b7tX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-release' + }], + TRACK2: [{ + TRACK2TITLE: 'Compatibility', + TRACK2TEACHER: 'Kaitian Du', + TRACK2MAINTAINER: 'Compatibility Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1F5411b7pJ', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compatibility' + }], + TRACK3: [{ + TRACK3TITLE: 'Dev-utils', + TRACK3TEACHER: 'Myeuler', + TRACK3MAINTAINER: 'openEuler TC member; Dev-utils Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1Ei4y1t7a8', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-dev-utils' + }] + + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '11:00 - 12:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Technical Committee', + TRACK1TEACHER: 'Shinwell Hu', + TRACK1MAINTAINER: 'Chairman of openEuler Technical Committee', + TRACK1LINK:'https://www.bilibili.com/video/BV1rQ4y1K7L6', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-tc' + }], + TRACK2: [{ + TRACK2TITLE: 'Infrastructure', + TRACK2TEACHER: 'freesky-edward', + TRACK2MAINTAINER: 'Infrastructure Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1UT4y1G7fp', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-infrastructure' + }], + TRACK3: [{ + TRACK3TITLE: 'Security Committee', + TRACK3TEACHER: 'Jianwen Zhu', + TRACK3MAINTAINER: 'Expert of operating system security', + TRACK3LINK:'https://www.bilibili.com/video/BV17Q4y1T7FN', + TRACK3DOWNLOAD:'https://etherpad.opendev.org/p/openeuler-virtual-summit-2020-security-committee' + }] + } + ], + OTHERLINK:[ + { + URL:'url("/img/home/link/mulan.png")', + LINK:'http://www.mulanos.cn/' + }, + { + URL:'url("/img/home/link/kunpeng.png")', + LINK:'https://kunpeng.huawei.com/' + }, + { + URL:'url("/img/home/link/pengcheng.png")', + LINK:'https://dw.pcl.ac.cn/dwmain/main/' + } + ] + }, + MEETUPS: { + MEETUPS: 'Meetups', + DETAIL_DESC: 'Introduction', + DETAIL_FLOW: 'Agenda', + DETAIL_REVIEW: 'Review', + MORE_VIDEO: 'More video', + DETAIL_MEET: 'How to attend the event', + DETAIL_QRCODE_TEXT: 'Scan the QR code', + INSIDENAME: 'CONNECT', + DEFAULT_IMG: '/img/meetups/default-address.png', + MEETUPS_DATA: require('./../../data/salon').en.MEETUPS_LIST + }, + DEVDAY_2021: { + PC_BANNER: '/img/summit/devday-2021/devday-2021-en.png', + H5_BANNER: '/img/summit/devday-2021/banner-h5-en.png' + }, + SUMMIT_2021: { + SPEACKER: '/img/summit/summit2021/call-speaker.png', + SPEONSOR: '/img/summit/summit2021/call-sponsor.png', + DEMO: '/img/summit/summit2021/call-demo.png', + } + }, + ru: { + LIVE: { + LIVE: 'Прямой эфир', + WILLPLAYER: 'About to Begin', + REPLAYER: 'Отличная рецензия', + LINKTIPS: 'The video is not uploaded yet', + LIVENOW: [ + + ], + LIVEFORMERLY: [ + { + LIVETITLE: '手把手教你编写Avocado-VT用例', + LIVETEACHER: '讲师: 朱欢凯', + LIVETIME: '时间: 12月14日 20:00(周二)', + PHOTOPATH: '/img/live/zhuhuankai.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Vz4y1r7fk' + }, + { + LIVETITLE: '玩转虚拟化测试Avocado-VT', + LIVETEACHER: '讲师: 柯志明', + LIVETIME: '时间: 12月1日 20:00(周二)', + PHOTOPATH: '/img/live/kezhiming.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ey4y1S7xv' + }, + { + LIVETITLE: 'StratoVirt之IO子系统剖析', + LIVETEACHER: '讲师: 张亮', + LIVETIME: '时间: 11月17日 20:00(周二)', + PHOTOPATH: '/img/live/zhangliang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17z4y1y7ME' + }, + { + LIVETITLE: 'StratoVirt之内存子系统剖析', + LIVETEACHER: '讲师: 杨晓鹤', + LIVETIME: '时间: 11月10日 20:00(周二)', + PHOTOPATH: '/img/live/yangxiaohe.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1XV411y73z' + }, + { + LIVETITLE: 'StratoVirt之CPU子系统剖析', + LIVETEACHER: '讲师: 高玮', + LIVETIME: '时间: 11月3日 20:00(周二)', + PHOTOPATH: '/img/live/gaowei.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YA411j7Ws' + }, + { + LIVETITLE: '如何安装并使用StratoVirt', + LIVETEACHER: '讲师: 郭馨乐', + LIVETIME: '时间: 10月27日 20:00(周二)', + PHOTOPATH: '/img/live/guoxinle.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ji4y177NC' + }, + { + LIVETITLE: '下一代虚拟化技术StratoVirt介绍', + LIVETEACHER: '讲师: 王志钢', + LIVETIME: '时间: 10月20日 20:00(周二)', + PHOTOPATH: '/img/live/wangzhigang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1gv411C7sK' + }, + { + LIVETITLE: '手把手带你完成openEuler环境部署 K8S', + LIVETEACHER: '讲师: 夏丹妮', + LIVETIME: '时间: 9月17日 20:00(周四)', + PHOTOPATH: '/img/live/xiadanni.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSula容器之安全容器', + LIVETEACHER: '讲师: 姜鹏飞', + LIVETIME: '时间: 9月15日 20:00(周二)', + PHOTOPATH: '/img/live/jiangpengfei.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSula容器之系统容器', + LIVETEACHER: '讲师: 章松', + LIVETIME: '时间: 9月10日 20:00(周四)', + PHOTOPATH: '/img/live/zhangsong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之安全特性实现解析', + LIVETEACHER: '讲师: 吴景', + LIVETIME: '时间: 9月8日 20:00(周二)', + PHOTOPATH: '/img/live/wujing.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: 'iSulad之性能测试、分析与比较', + LIVETEACHER: '讲师: 刘昊', + LIVETIME: '时间: 9月3日 20:00(周四)', + PHOTOPATH: '/img/live/liuhao.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: '轻量级容器引擎iSulad之功能介绍及架构解析', + LIVETEACHER: '讲师: 李峰', + LIVETIME: '时间: 9月1日 20:00(周二)', + PHOTOPATH: '/img/live/lifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV12y4y1C7Gr' + }, + { + LIVETITLE: '深入理解容器镜像构建工具', + LIVETEACHER: '讲师: 刘泽坤', + LIVETIME: '时间: 8月25日 20:00(周二)', + PHOTOPATH: '/img/live/liuzekun.png', + FORMERLYLINK: 'http://live.bilibili.com/22290444' + }, + { + LIVETITLE: 'isula-build之安全特性', + LIVETEACHER: '讲师: 李翔', + LIVETIME: '时间: 8月27日 20:00(周四)', + PHOTOPATH: '/img/live/lixiang.png', + FORMERLYLINK: 'http://live.bilibili.com/22290444' + }, + { + LIVETITLE: '虚拟化技术介绍', + LIVETEACHER: '讲师: 张海亮', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhanghailiang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1of4y1X7p1' + }, + { + LIVETITLE: '安装虚拟化&管理虚拟机', + LIVETEACHER: '讲师: 陈振东', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/chenzhendong.png', + FORMERLYLINK: '' + }, + { + LIVETITLE: '初始openEuler', + LIVETEACHER: '讲师: 朱延朋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuyanpeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1it4y197KQ' + }, + { + LIVETITLE: '安装openEuler', + LIVETEACHER: '讲师: 冯涛', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/fengtao.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1vK4y1s7QG' + }, + { + LIVETITLE: '使用openEuler', + LIVETEACHER: '讲师: 沈洋洋', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/shenyangyang.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV13z4y1D7mq' + }, + { + LIVETITLE: 'openEuler构建之OBS使用指导', + LIVETEACHER: '讲师: 朱春意', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/zhuchunyi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1YK411H7E2' + }, + { + LIVETITLE: 'openEuler软件包的构建、开发与维护', + LIVETEACHER: '讲师: 何晓文', + LIVETIME: '时间: 7月28日 20:00', + PHOTOPATH: '/img/live/hexiaowen.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1pK411J7R9' + }, + { + LIVETITLE: '如何参与openEuler内核开发', + LIVETEACHER: '讲师: 谢秀奇', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/xiexiuqi.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV11i4y1u7r9' + }, + { + LIVETITLE: 'openEuler网络配置', + LIVETEACHER: '讲师: 马郡', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/majun.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV17C4y187sM' + }, + { + LIVETITLE: '可信计算之内核完整性度量', + LIVETEACHER: '讲师: 张天行', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/zhangtianxing.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1dk4y1171e' + }, + { + LIVETITLE: '开源版权和License', + LIVETEACHER: '讲师: 卜瑞峰', + LIVETIME: '时间: 7月30日 20:00', + PHOTOPATH: '/img/live/boruifeng.png', + FORMERLYLINK: 'https://www.bilibili.com/video/BV1Ty4y1y7eK' + }, + ] + }, + SUMMIT: { + SUMMIT: 'Summit', + NAV_LIST: [ + { + key: '#liveroom', + name: 'Live Broadcast' + }, + { + key: '#agenda', + name: 'Agenda' + }, + { + key: '#lecturer', + name: 'Speakers' + }, + { + key: '#host-unit', + name: 'Partners' + } + ], + SUMMITCONTENT: [ + 'The openEuler Summit 2020 will be held at Hyatt Regency Beijing Wangjing from December 24 to 25 in Beijing, China. The second summit this year, the event will dive deep into openEuler, the open source operating system of tomorrow and how it exceeds conventional technologies thanks to community participation. This openEuler event is an opportunity for developers to exchange the latest OS trends with like-minded individuals.', + 'The upcoming summit will focus on the collaboration across software-hardware and cloud-edge-device, as well as scenarios where all things are connected and diversified computing coexist. This event will discuss how to tap into technological innovation and build an open ecosystem. The summit provides an opportunity for streamlining the OS industry, and will consider how the openEuler OS can create shared value across the entire industry chain. The summit is only possible thanks to the participation of our developers, users, community contributors, and software enthusiasts, who have explored the latest OS developments. Together, we are on the cusp of the next breakthrough.' + ], + LIVETITLE: 'Live Broadcast', + PC_LIVEIMG: '/img/summit/home/en-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/en-mobile-liveroom.png', + SUMMITLIVE: [ + { + ID: 7095, + THEME: 'openEuler Summit 2020', + TIME: '09:30-11:55', + OPTION: '09:30-11:55 openEuler Summit 2020', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7095?lang=zh&thirdId=' + }, + { + ID: 7096, + THEME: 'Operating System', + TIME: '14:00-17:20', + OPTION: '14:00-17:20 Operating System', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7096?lang=zh&thirdId=' + }, + { + ID: 7097, + THEME: 'Cloud and Cloud Native', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Cloud and Cloud Native', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7097?lang=zh&thirdId=' + }, + { + ID: 7098, + THEME: 'Virtualization', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Virtualization', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7098?lang=zh&thirdId=' + }, + { + ID: 7099, + THEME: 'Open Source and Infrastructure', + TIME: '14:00-16:55', + OPTION: '14:00-16:55 Open Source and Infrastructure', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7099?lang=zh&thirdId=' + }, + { + ID: 7100, + THEME: 'Security & Trustworthiness', + TIME: '14:00-17:25', + OPTION: '14:00-17:25 Security & Trustworthiness', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7100?lang=zh&thirdId=' + }, + { + ID: 7101, + THEME: 'Basic Software', + TIME: '14:00-17:25', + OPTION: '14:00-17:25 Basic Software', + LIVEURL: 'https://vhall.huawei.com/fe/embed/watch/7101?lang=zh&thirdId=' + } + ], + SUMMIT_HOME_DATA: { + AGENDA: { + WEB_TITLE: '/img/summit/home/agenda/en-pc-agenda.png', + MOBILE_TITLE: '/img/summit/home/agenda/en-mobile-agenda.png', + DATE:['Dec 24','Dec 25','Morning','Afternoon'], + AFTERNOON_AGENDA_24: [ + { + TIME: '13:00-14:30', + THEME: 'Opening Speech', + SPEAKER: 'Ma Quanyi', + POSITION: 'Member, openEuler Technical Committee (TC)' + }, + { + TIME: '13:10-14:40', + THEME: 'Support of openEuler for the AppStream Mechanism' + }, + { + TIME: '13:10-14:40', + THEME: 'Applying for Establishing the Intelligent O&M SIG' + }, + { + TIME: '13:10-14:40', + THEME: 'Switching from Gitee Issues to Bugzilla' + }, + { + TIME: '13:10-14:40', + THEME: 'TC Collaboration Mode in 2021' + }, + { + TIME: '15:00-15:30', + THEME: 'Opening Speech & Maintainer Badge Awarding Ceremony', + SPEAKER: 'Ma Quanyi', + POSITION: 'Member, openEuler TC' + }, + { + TIME: '15:30-15:50', + THEME: 'openEuler Community Operation Analysis', + SPEAKER: 'Zhou Minghui', + POSITION: 'Boya Distinguished Professor, Peking University' + }, + { + TIME: '15:50-16:00', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Fang Yafen', + POSITION: 'Maintainer, RaspberryPi SIG' + }, + { + TIME: '16:00-16:10', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Yang Zhao', + POSITION: 'Maintainer, Ha SIG' + }, + { + TIME: '16:10-16:20', + THEME: 'Meet Maintainers of openEuler Community', + SPEAKER: 'Zheng Xian', + POSITION: 'Maintainer, ai-bigdata SIG' + }, + { + TIME: '16:20-17:00', + THEME: 'Q&A' + }, + { + TIME: '17:00-17:30', + THEME: 'Summary', + SPEAKER: 'Hu Xinwei', + POSITION: 'Chairman, openEuler TC' + } + ], + FORENOON_AGENDA_25: [ + { + TIME: '09:30-09:35', + THEME: 'Opening Speech' + }, + { + TIME: '09:35-09:50', + THEME: 'openEuler: Innovative OS for Industry Chain of Shared Value', + SPEAKER: 'Jiang Dayong', + POSITION: 'Director, openEuler Community' + }, + { + TIME: '09:50-09:55', + THEME: 'Establishment of the openEuler Technical Committee', + SPEAKER: 'Qiu Chengfeng', + POSITION: 'Vice Director, openEuler Community' + }, + { + TIME: '09:55-10:15', + THEME: 'openEuler Fuels Constant Technology Innovation', + SPEAKER: 'Hu Xinwei', + POSITION: 'Chairman, openEuler Technical Committee' + }, + { + TIME: '10:15-10:35', + THEME: "Huawei' s Contribution and Its Role in the Linux Kernel Community", + SPEAKER: 'Chen Haibo', + POSITION: 'Chief OS technical expert, Huawei; Distinguished Professor, Shanghai Jiao Tong University' + }, + { + TIME: '10:50-11:05', + THEME: 'Implementing Cloud Native Computing on Hybrid Architecture Platforms', + SPEAKER: 'Zhang Chun', + POSITION: 'Deputy General Manager, R&D Innovation Center, China Mobile Information Technology Center' + }, + { + TIME: '11:05-11:20', + THEME: 'Secure Mobile Edge Payment Powered by Confidential Computing', + SPEAKER: 'Zu Lijun', + POSITION: 'Director, National Engineering Laboratory for Electronic Commerce and Electronic Payment' + }, + { + TIME: '11:20-11:40', + THEME: 'openEuler & Friends: Diversified Ecosystem Scenarios', + SPEAKER: 'Xiong Wei and community developers' + }, + { + TIME: '11:40-11:50', + THEME: 'Open Source Promotes Shared Development and Governance for the Benefit of All', + SPEAKER: 'Du Junping', + POSITION: 'General Manager, Cloud & AI Open Source Business, Huawei' + }, + { + TIME: '11:50-11:55', + THEME: 'Awards Ceremony for openEuler Community Developers', + SPEAKER: 'Ma Quanyi', + POSITION: 'openEuler Maintainer' + } + ], + AFTERNOON_AGENDA_25: { + TIME_LIST: ['14:00-14:40','14:40-15:10','15:10-15:40','15:55-16:25','16:25-16:55','16:55-17:25'], + CARD_LIST: [ + { + TITLE: ['Session 1','Operating System'], + ITEM_LIST: [ + { + TIME: '14:00-14:40', + THEME: "Roundtable: The Operating System of Tomorrow, Unlocking Today's Diversified Computing" + }, + { + TIME: '14:40-15:10', + THEME: 'Application Performance Tuning of openEuler', + SPEAKER: ['Chen Qide, Beijing TurboLinux'], + DESC: ['Databases are one of the typical enterprise-grade Linux applications. To provide better database services for enterprises, we focus on performance indicators when developing distributed databases based on openEuler. These performance indicators include the duration and frequency of invoking functions, time-consuming thread processing, data types of memory cache, and network request delay. During database performance testing, we improve programs to squeeze the best hardware performance. This topic takes the performance tuning during database R&D as an example to describe the application performance tuning of openEuler.'] + }, + { + TIME: '15:10-15:40', + THEME: 'Community Helps Port RISC-V and NutShell Processors to openEuler OS', + SPEAKER: ['Zhou Peng, Institute of Software, Chinese Academy of Sciences (CAS)','Zhang Xuzhou, Huawei'], + DESC: ['In this topic, two speakers will use the general method for developing OS distributions to introduce how the openEuler Community helps port the RISC-V architecture and NutShell processors to openEuler OS. They will also discuss the challenges and opportunities for developing OS versions, in particular the status quo and problems of OS package dependency management. Furthermore, they will explore a new mode for managing OS dependencies and package distribution.'] + }, + { + TIME: '15:55-16:25', + THEME: 'Using Kubernetes to Deploy iSula Container Clusters on Raspberry Pi-based openEuler OS', + SPEAKER: ['Fang Yafen, Institute of Software, CAS','Li Baolin, Huawei'], + DESC: ['1. Porting the openEuler OS to Raspberry Pi as a Raspberry Pi-based image.','2. Using Kubernetes to deploy iSula container clusters on Raspberry Pi-based openEuler OS.'] + }, + { + TIME: '16:25-16:55', + THEME: 'General Accelerator Framework for Heterogeneous Systems: UADK Ecosystem and Development Progress', + SPEAKER: ['Gao Zhangfei, Linaro','Li Guozhu, Huawei'], + DESC: ['The Unified/User-space-access-intended Accelerator Framework (Uacce) is an accelerator framework jointly developed by Huawei HiSilicon and Linaro for heterogeneous systems. The main kernel drivers have been merged into the Linux kernel mainline, and we are developing the user-mode library UADK and OpenSSL engine. We aim to provide a more secure accelerator solution based on the IOMMU Shared Virtual Addressing (SVA) feature. The solution enables the accelerator and main CPU to share the unified address space. We hope to see more partners join us for development.'] + }, + { + TIME: '16:55-17:25', + THEME: 'Using eBPF to Replace the Kernel Module Compilation for an Efficient Network Monitoring System Without Performance Loss', + SPEAKER: ['Fan Bin, e Cloud'], + DESC: ['Traditional network monitoring systems are mostly implemented by compiling kernel modules or accessing proc files from user space. However, the kernel module compilation is complex and it is difficult to maintain and debug kernel modules. As a result, we need a solution that can implement functions similar to those of the kernel module without compromising performance. This presentation describes how to harness the eBPF technology for an efficient network monitoring system without performance loss. The system can be used to monitor and observe cloud native networks in data centers and locate faults such as network delay and package loss.'] + } + ] + }, + { + TITLE: ['Session 2','Cloud and Cloud Native'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'China Mobile: Kubernetes, openEuler, and iSula Empower the Smooth Scheduling Between ARM and x86', + SPEAKER: ['Wei Baohui, China Mobile Information Technology'], + DESC: ['In this presentation, Mr. Wei will tell us how China Mobile leverages the Kubernetes+openEuler+iSula for smooth scheduling between ARM and x86 architectures.'] + }, + { + TIME: '14:30-15:00', + THEME: 'Adapting and Integrating OpenStack to openEuler OS', + SPEAKER: ['Li Kunshan, China Unicom Cloud Data Company'], + DESC: ['This topic describes the progress and technology of adapting the OpenStack cloud platform to the openEuler OS, and shares technologies and cases in this regard.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Applying iSula to the Edge Computing OS HopeEdge', + SPEAKER: ['Liang Dong, Hoperun Information Technology'], + DESC: ['This topic describes the edge operating system developed based on openEuler. Thanks to the lightweight customization, the edge OS integrates the iSula container engine to quickly deploy and upgrade applications.'] + }, + { + TIME: '15:45-16:15', + THEME: 'Huayun Data: Adapting Kubernetes-based Platform to openEuler OS', + SPEAKER: ['Huang Maofeng, Huayun Data'], + DESC: ['Huayun Data develops the Kubernetes-based PaaS platform on Archer CloudSuite, and reconstructs and optimizes Kubernetes for different services. The adaptation to openEuler is highly challenging. Thanks to the openEuler Community, Huayun Data overcomes the difficulty and acquires abundant experience during the adaptation.'] + }, + { + IME: '16:15-16:45', + THEME: 'Working Principles and Practices of A-Tune: openEuler Intelligent Tuning Engine', + SPEAKER: ['Xie Zhipeng, Huawei'], + DESC: ['A-Tune adopts AI technologies to ensure the optimal service running. It builds precise models for services running on the operating system, understands service features and infers specific applications, and dynamically adjusts the parameters based on service loads to provide the optimal parameter configuration. ','This topic will discuss:','1. Implementing the core capabilities of A-Tune: online static tuning and offline dynamic tuning','2. Tuning cases of A-Tune','3. Technology roadmap of A-Tune'] + }, + { + IME: '16:45-17:15', + THEME: 'Playing minikube on openEuler', + SPEAKER: ['Zhao Shuai Linaro','Liu Xinliang Linaro'], + DESC: ['minikube is a simple tool for the local deployment of Kubernetes. It enables developers to start the Kubernetes cluster in one click and simplify the cluster O&M. In this presentation, two speakers will introduce the basic working principles of minikube and what we have done in the community to run minikube on openEuler. In addition to minikube, the compatibility of other mainstream Kubernetes deployment tools with openEuler will also be discussed in this topic.'] + } + ] + }, + { + TITLE: ['Session 3','Virtualization'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'StratoVirt: Next-Generation Virtualization Platform on openEuler', + SPEAKER: ['Wu Bin, Huawei'], + DESC: ['StratoVirt is a next-generation Rust-based Virtual Machine Manager (VMM). It is a virtualization platform oriented to enterprise cloud data centers and supports VM, container, and serverless scenarios. This topic describes the features, technical architecture, and roadmap of StratoVirt.'] + }, + { + TIME: '14:30-15:00', + THEME: 'Optimized Display Technology Tailored to Cloud Desktops', + SPEAKER: ['Sun Lijie, Hunan Kylinsec'], + DESC: ['Some technical issues may occur when cloud desktop products are implemented using the Kernel-based Virtual Machine (KVM). To deal with these issues, this topic describes technical solutions for graphics display and optimization, such as virtualized graphics card optimization, graphics card penetration, and video redirection. In addition, these solutions require the optimization and function enhancement of components such as the openEuler kernel and decoding library.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Implementing Virtualization and Private Cloud on openEuler', + SPEAKER: ['Qiu Dayu, Huayun Data'], + DESC: ['How to optimize the virtualization platform performance and quickly adapt it to the latest SAN devices, and how to provide high-performance virtual GPUs (vGPUs) are the major issues on the ARM-based platform, especially on the openEuler OS. This topic will show you how Huayun Data optimizes and adapts the virtualization platform to the openEuler OS, and how the company innovates the virtualization platform to support peripheral devices.'] + }, + { + TIME: '15:45-16:15', + THEME: 'Optimized Virtualization Performance Fueled by openEuler', + SPEAKER: ['Qi Zhihui, Sangfor Technologies'], + DESC: ['The topic presents the technologies for optimizing virtualization performance on openEuler, including storage and computing performance.'] + }, + { + TIME: '16:15-16:45', + THEME: 'Innovative Cloud Products Running on Kunpeng+openEuler', + SPEAKER: ['Luo Yun, Winhong Information Technology'], + DESC: ['Winhong has developed an enterprise-grade product powered by Kunpeng-based servers and the openEuler OS. This product supercharges server virtualization and cloud management of enterprises, and has earned good reputation in a wide range of industries, including governments, finance, and carriers. Today, we would like to present this product to our peers.'] + }, + {} + ] + }, + { + TITLE: ['Session 4','Open Source and Infrastructure'], + ITEM_LIST: [ + { + TIME: '14:00-14:15', + THEME: 'openEuler CLA Signing System for Multiple Code Hosting Platforms', + SPEAKER: ['Yuan Zhichang, ARM China','Chen Zeng, Huawei'], + DESC: ['This topic will discuss the following questions:','1. How does an open source community provide developer-friendly contribution license agreement (CLA) signing services? Which kind of services is better, self-developed services or services based on open source projects? How to ensure the legal force of the signed CLA? ','2. Which role does a contributor play in signing the CLA? How does an enterprise sign the CLA when participating in the community? After signing the CLA, how does the contributor protect the rights and interests in the subsequent development activities?'] + }, + { + TIME: '14:15-15:00', + THEME: 'Compass-CI: A Developer-Friendly Test System', + SPEAKER: ['Wu Fengguang, Huawei','Du Kaitian, Huawei'], + DESC: ['This topic presents how Compass-CI provides test services for the open source software ecosystem that supports multiple architectures and systems.'] + }, + { + TIME: '15:00-15:30', + THEME: 'Building the Open Source Infrastructure and oepkgs Software Package Service Platform in openEuler Community', + SPEAKER: ['Yin Jiayi, Institute of Software, CAS','Cao Zhi, Huawei'], + DESC: ['1. Technology selection and practice of building openEuler Community infrastructure.','2. The oepkgs software package service platform consists of the oepkgs container image repository and oepkgs RedHat Package Manager (RPM) repository. In this topic, we will explain the background of building the oepkgs platform, as well as the basic architecture, usage, and developments of the two repositories for maintenance.'] + }, + { + TIME: '15:45-16:15', + THEME: 'How Open Source Community Data Drives the openEuler Operations', + SPEAKER: ['Xia Xiaoya, East China Normal University','Zhong Jun, Huawei'], + DESC: ['1. Why do we need digital operation?','2. How to select a proper digital operation system, such as the Community Health Analytics Open Source Software (CHAOSS), OM, and Kibble?','3. How to build the operation system architecture?','4. How to display operation data?','5. How to implement the CHAOSS indicator system?','6. How to drive digital operations in the openEuler Community?'] + }, + { + TIME: '16:15-16:45', + THEME: 'Insights into Open Source Products, Better Interactive Experience and Design for openEuler Developers', + SPEAKER: ['Zhang Shuting, Huawei','Ma Quanyi, Huawei'], + DESC: ['1. Open source projects and business are becoming interwoven. As a result, a successful open source project is only possible thanks to the innovative commercial product design. The first part of this topic describes how to design products in an open source project.','2. User experience teams are constantly striving to provide better interactive experience and design for open source developers. The second part of this topic describes how openEuler and openLooKeng communities provide developer-friendly products.'] + } + ] + }, + { + TITLE: ['Session 5','Security & Trustworthiness'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'openEuler Security Capability Development', + SPEAKER: ['Wei Gang, Huawei'], + DESC: ['A Security Committee member will tell you how the openEuler Community develops its security capabilities and the future plan for building a secure open source community. The topic will present a complete capability framework for community security. It focuses on the latest progress and challenges of the community in security coding, security design, and vulnerability collection, response, and handling.'] + }, + { + TIME: '14:30-15:00', + THEME: 'How Arm-v8.x Key Features Ensure Higher Performance and Security for openEuler', + SPEAKER: ['Yuan Zhichang, ARM China'], + DESC: ['This topic describes the four Arm-v8.x key features related to performance and security, including Large System Extension (LSE), Scalable Vector Extension (SVE), Pointer Authentication (PAuth), and Branch Target Identification (BTI). The topic will also discuss the support for the preceding features in upstream open source communities, OS open source communities, and openEuler Community.'] + }, + { + TIME: '15:00-15:30', + THEME: 'RAS on ARM64', + SPEAKER: ['Chen Gong, Huawei'], + DESC: ['Reliability is the cornerstone of server platforms. The concept of Reliability, Availability, and Serviceability (RAS) has been the focus of any server platform since it was proposed by IBM 50 years ago. RAS is an essential indicator for both the x86-based Xeon platform and the new ARM64-based platform. This topic will give you an overview of the RAS and present how the openEuler-based ARM64 servers enhance their RAS. '] + }, + { + TIME: '15:45-16:15', + THEME: 'How to Create a Compliant Open Source Community', + SPEAKER: ['Bian Naimeng, Hoperun Information Technology','Gao Kun, Huawei'], + DESC: ['One of the biggest risks of open source projects is non-compliance. To enhance open source compliance, communities need to ensure authorized code source and high code quality. An open source community would flourish only when it is fully compliant. Against this backdrop, the topic describes how to build a compliant open source community.'] + }, + { + TIME: '16:15-16:45', + THEME: 'SELinux-based Confidentiality and Integrity Policy', + SPEAKER: ['Luoqiu, Hunan Kylinsec'], + DESC: ['Security-Enhanced Linux (SELinux) is a standardized security infrastructure on the openEuler. For specific software services, SELinux controls confidentiality and integrity, ensures that the direction of information flows remains unchanged, and prevents sensitive information leakage and unauthorized modification. This topic analyzes how to implement trustworthiness policies in different scenarios using SELinux.'] + }, + { + TIME: '16:45-17:15', + THEME: 'OS Built on Intrinsic Security', + SPEAKER: ['Wang Jiangtao, iSoft Infrastructure Software'], + DESC: ['Trustworthy computing requires dedicated servers, which result in the huge workload of software architecture reconstruction. The existing servers of enterprises, public institutions, and Internet data centers are mostly x86-based. As a result, it takes a long time to replace all these x86-based servers with servers running on Chinese-made hardware and software. The solution for faster replacement is the operating system built on intrinsic security, which combines the mature encryption card with encryptor.'] + } + ] + }, + { + TITLE: ['Session 6','Basic Software'], + ITEM_LIST: [ + { + TIME: '14:00-14:30', + THEME: 'Technical Architecture and Deployment of the BiSheng JDK and BiSheng Compiler', + SPEAKER: ['Guo Ge, Huawei','Wei Wei, Huawei'], + DESC: ['The BiSheng JDK and BiSheng Compiler were officially released in the openEuler 20.09 version. This topic describes the core technologies of these two BiSheng software products and how the compilation technology enables upper-layer applications.'] + }, + { + TIME: '14:30-15:00', + THEME: 'HA Enterprise Solutions Powered by openGauss on openEuler', + SPEAKER: ['Liu Weiyun, Beijing Enmotech'], + DESC: ['The topic discusses how openGauss enables the HA solution on the openEuler platform, including the enterprise-grade two-node cluster, one active node and multiple standby nodes, and cross-equipment room deployment, as well as the success cases of the HA solution.'] + }, + { + TIME: '15:00-15:30', + THEME: 'High-Performance SDS Running on Kunpeng+openEuler', + SPEAKER: ['Chi Xinze, XSKY (Beijing) Data Technology'], + DESC: ['This topic introduces:','1. The process of porting XEDP from CentOS 7.6 + x86 to openEuler+Kunpeng','2. Problems during the porting and corresponding solutions','3. The performance tuning solution for XEDP on the openEuler+Kunpeng architecture, and the application cases of the solution'] + }, + { + TIME: '15:45-16:15', + THEME: 'DDE: Desktop OS Architecture Design', + SPEAKER: ['Wang Yaohua, Uniontech Software'], + DESC: ['Uniontech Software offers the ultimate DDE desktop OS, which is powered by the openEuler OS and the optimized kernel of the openEuler Community. This presentation will unveil the basic architecture of the DDE to help you dive deeper into the basic functions, technical principles, and architecture design of the DDE desktop OS.'] + }, + { + TIME: '16:15-16:45', + THEME: 'Ultimate Performance and Application Cases of openGauss on Kunpeng Platform', + SPEAKER: ['Huang Xiaotao, Beijing Vastdata Technology','Feng Jie, Huawei','Wang Junjie, Huawei'], + DESC: ['1. Speakers from Huawei will describe how openGauss on the multi-core Kunpeng server is optimized in the online transaction processing (OLTP) scenario, including bottleneck analysis, methods, and results of the optimization.','2. Vastbase is an enterprise-class relational database built on years of industry experience. The representative from Vastdata Technology will discuss how the massive Vastbase is ported to the Kunpeng + openEuler OS platform.'] + }, + { + TIME: '16:45-17:15', + THEME: 'UKUI: File Manager Architecture Analysis', + SPEAKER: ['Li Jianfeng, Kylinsoft'], + DESC: ['The newly designed UKUI 3.0 can be downloaded and installed in openEuler 20.03 SP1 and 20.09 versions. This topic describes the file manager in the UKUI desktop environment, including the upgrade from the UKUI file manager 2.0 to 3.0, technology selection and overall architecture design of the latest file manager, and future developments.'] + } + ] + } + ] + }, + SIG_CONTENT: { + TITLE: 'SIG Open Working Sessions', + SIG1_TIME: '16:00 - 16:10' , + SIG1_DETAIL: ['Opening Speech','Ma Quanyi','Member of openEuler TC'], + SIG2_TIME: '16:10 - 17:00', + SIG2_DETAIL: [ + { + THEME: 'SIG-DDE', + CONTENT: ['1) Achievements of Adapting DDE to openEuler','2) DDE Version Update Plan',"3) Discussion on Enthusiasts' Requirements for the Desktop"] + }, + { + THEME: 'SIG-UKUI', + CONTENT: ['1) Work Progress of UKUI for openEuler 20.03 LTS SP1','2) Discussion on the Future Development of UKUI'] + }, + { + THEME: 'SIG-Ha', + CONTENT: ['1) Progress of the Ha project','2) Discussion on the Plan for Merging the Ha Project into Upstream Community'] + }, + { + THEME: 'SIG-aarch32', + CONTENT: ['1) Work Progress of Adapting AArch32 to openEuler','2) Discussion on the Coexistence Between AArch32 Adapted Code and Mainline Versions'] + }, + { + THEME: 'SIG-A-Tune', + CONTENT: ['1) Review of New Features and Achievements of A-Tune in 2020','2) Discussion on Future Technology Evolution of A-Tune','3) Development Process of A-Tune and Wisdom in Community and Key Issue Analysis','4) Discussion on Papers of the Latest Tuning Technology'] + }, + { + THEME: 'SIG-iSulad & Container', + CONTENT: ['1) Cloud Native Technologies','2) Cloud Native Efficiency Improvement','3) Issues of Cloud Native Application'] + }, + { + THEME: 'SIG-ai-bigdata', + CONTENT: ['1) Review of Achievements of ai-bigdata SIG in 2020','2) Discussion on LTS Version Selection','3) Discussion on the openEuler-based Big Data and AI Platform',"4) Discussion on the SIG's Technical Scope and Roadmap"] + }, + { + THEME: 'SIG-security-facility & sig-confidential-computing', + CONTENT: ['1) Existing Security Technologies of security-facility SIG','2) Discussion on openEuler Security Technology Developments and Roadmap','3) Discussion on Confidential Computing Application Scenarios and Security Technologies'] + }, + { + THEME: 'SIG-Compiler', + CONTENT: ['1) Working plan of Compiler SIG, Including the JDK/GCC Support Roadmap','2) Discussion on Requirements for Supporting Compilers (LLVM) and Rust/Go Programming Languages','3) Discussion on the Plan for Supporting Containers (iSula) on openJDK'] + }, + { + THEME: 'SIG-doc', + CONTENT: ['1) Introduction to the Current Document System of openEuler Community','2) Discussion on the Plan and Focus of the Doc SIG','3) Discussion on Encouraging Developers to Contribute Blogs and Videos to Community'] + }, + { + THEME: 'SIG-Infrastructure', + CONTENT: ['1)Review of the openEuler Infrastructure in 2020','2)Discussion on the openEuler Infrastructure Key Priorities in 2021','3)Ideas of Promoting Intelligent O&M on openEuler Infrastructure'] + }, + { + THEME: 'SIG-security-committee', + CONTENT: ['1) Analysis of Vulnerability Handling Process of openEuler Community: Vulnerability Awareness, Handling, and Disclosure','2) Discussion on Security Vulnerability Patch Fix Policies','3) Discussion on Applying the Security Guide in Community','4) Discussion on Collaboration Between Security TC and SIGs for Vulnerability Analysis, Fix, and Disclosure'] + }, + { + THEME: 'SIG-Compatibility-Infra', + CONTENT: ['1) Kernel KABI and Southbound Driver Compatibility','2) Software Package Compatibility Level and Northbound Application Compatibility','3) Compatibility Policy Between Versions'] + }, + { + THEME: 'SIG-QA', + CONTENT: ['1) Discussion on Building the Quality Measurement System of openEuler Community','2) Discussion on Conducting Crowdtesting in openEuler Community','3) Discussion on the SIG Future Plan'] + }, + { + THEME: 'SIG-release-management', + CONTENT: ['1) Discussion on Version Lifecycle Plan of openEuler Community: 20.03 Maintenance Lifecycle and SP2 Release Time','2) Discussion on Policies of Partner Version Consistence and Component Upgrade: Patch Backporting, Version Upgrade, Component Mode, Secondary Development, and Backporting Time','3) Discussion on Participation of OSVs and ISVs in the release-management SIG and the SIG Operation'] + }, + { + THEME: 'SIG-Kernel', + CONTENT: ['1) Kernel Test Protection and Stability Assurance','2) Leveraging Community Expertise to Discover and Fix openEuler Kernel Bugs and Ensure Stability of LTS Versions','3) Discussion on the Policy for Merging Innovation Version Features','4) Discussion on Requirements for the openEuler 5.10 Kernel Version'] + }, + { + THEME: 'SIG-Virt', + CONTENT: ['1) Overview of New Technologies and Success Practices of Virt SIG in 2020','2) Discussion on the Technical Planning of Virt SIG in 2021','3) Discussion on Requirements for Virt SIG, such as New Features, Development Process, and Issue Resolution'] + } + ], + SIG3_TIME: '17:00 - 18:30', + SIG3_DETAIL: ['Presentation & Exchange of Discussion Results'] + } + }, + LECTURER: { + WEB_TITLE: '/img/summit/home/lecturer/en-pc-lecturer.png', + MOBILE_TITLE: '/img/summit/home/lecturer/en-mobile-lecturer.png', + LECTURERLIST: [ + { + IMG: '/img/summit/home/lecturer/jiangdayong.png', + NAME: 'Jiang Dayong', + POSITION: 'Director, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/qiuchengfeng.png', + NAME: 'Qiu Chengfeng', + POSITION: 'Vice Director, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/huxinwei.png', + NAME: 'Hu Xinwei', + POSITION: 'Chairman, openEuler Technical Committee' + }, + { + IMG: '/img/summit/home/lecturer/chenhaibo.png', + NAME: 'Chen Haibo', + POSITION: 'Chief OS Technical Expert, Huawei/Distinguished Professor, Shanghai Jiao Tong University' + }, + { + IMG: '/img/summit/home/lecturer/zulijun.png', + NAME: 'Zu Lijun', + POSITION: 'Director, National Engineering Laboratory for Electronic Commerce and Electronic Payment' + }, + { + IMG: '/img/summit/home/lecturer/xiongwei.png', + NAME: 'Dr. Xiong Wei', + POSITION: 'Member, openEuler Technical Committee' + }, + { + IMG: '/img/summit/home/lecturer/dujunping.png', + NAME: 'Du Junping', + POSITION: 'General Manager, Cloud & AI Open Source Business, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/maquanyi.png', + NAME: 'Ma Quanyi', + POSITION: 'openEuler Community Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/chenqide.png', + NAME: 'Chen Qide', + POSITION: 'Deputy General Manager, Beijing TurboLinux' + }, + { + IMG: '/img/summit/home/lecturer/zhoupeng.png', + NAME: 'Zhou Peng', + POSITION: 'Research Fellow, Institute of Software, Chinese Academy of Sciences (CAS)' + }, + { + IMG: '/img/summit/home/lecturer/zhangxuzhou.png', + NAME: 'Zhang Xuzhou', + POSITION: 'openEuler RISC-V SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/fangyafen.png', + NAME: 'Fang Yafen', + POSITION: 'Engineer, Institute of Software, CAS' + }, + { + IMG: '/img/summit/home/lecturer/libaolin.png', + NAME: 'Li Baolin', + POSITION: 'Operation Engineer, openEuler Community' + }, + { + IMG: '/img/summit/home/lecturer/zhaoshuai.png', + NAME: 'Zhao Shuai', + POSITION: 'Tech Lead, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/liuxinliang.png', + NAME: 'Liu Xinliang', + POSITION: 'Senior Software Engineer, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/gaozhangfei.png', + NAME: 'Gao Zhangfei', + POSITION: 'Landing Team Software Engineer, Linaro' + }, + { + IMG: '/img/summit/home/lecturer/fanbin.png', + NAME: 'Fan Bin', + POSITION: 'Senior Back-End Development Engineer, e Cloud' + }, + { + IMG: '/img/summit/home/lecturer/weibaohui.png', + NAME: 'Wei Baohui', + POSITION: 'PaaS R&D Manager, China Mobile Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/likunshan.png', + NAME: 'Li Kunshan', + POSITION: 'OpenStack R&D Engineer, China Unicom Cloud Data Company' + }, + { + IMG: '/img/summit/home/lecturer/liangdong.png', + NAME: 'Liang Dong', + POSITION: 'Senior Engineer & HopeEdge Version Manager, Hoperun Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/huangmaofeng.png', + NAME: 'Huang Maofeng', + POSITION: 'Senior Technical Manager, Huayun Data' + }, + { + IMG: '/img/summit/home/lecturer/wubin.png', + NAME: 'Wu Bin', + POSITION: 'openEuler Virtualization SIG Maintainer/ICT Virtualization Architect, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/sunlijie.png', + NAME: 'Sun Lijie', + POSITION: 'R&D Manager, Hunan Kylinsec' + }, + { + IMG: '/img/summit/home/lecturer/qiudayu.png', + NAME: 'Qiu Dayu', + POSITION: 'Senior Technical Director, Huayun Data' + }, + { + IMG: '/img/summit/home/lecturer/yuzhihui.png', + NAME: 'Qi Zhihui', + POSITION: 'Localized Trusted Cloud R&D Owner, Sangfor Technologies' + }, + { + IMG: '/img/summit/home/lecturer/luoyun.png', + NAME: 'Luo Yun', + POSITION: 'Virtualization & Cloud Product Manager, Winhong Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/chenzeng.png', + NAME: 'Chen Zeng', + POSITION: 'Senior Engineer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/dukaitian.png', + NAME: 'Du Kaitian', + POSITION: 'openEuler CICD SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/yinjiayi.png', + NAME: 'Yin Jiayi', + POSITION: 'System Engineer, Institute of Software, CAS' + }, + { + IMG: '/img/summit/home/lecturer/caozhi.png', + NAME: 'Cao Zhi', + POSITION: 'openEuler Infra SIG Maintainer' + }, + { + IMG: '/img/summit/home/lecturer/xiaxiaoya.png', + NAME: 'Xia Xiaoya', + POSITION: 'Open Source Expert, East China Normal University' + }, + { + IMG: '/img/summit/home/lecturer/zhongjun.png', + NAME: 'Zhong Jun', + POSITION: 'Senior Open Source Engineer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/zhangshuting.png', + NAME: 'Zhang Shuting', + POSITION: 'Computing Product Experience Designer, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/weigang.png', + NAME: 'Wei Gang', + POSITION: 'Security & Trustworthiness Technical Expert, Computing Product Line, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/yuanzhichang.png', + NAME: 'Yuan Zhichang', + POSITION: 'Chief Software Engineer of Open Source Ecosystem, Arm China' + }, + { + IMG: '/img/summit/home/lecturer/chengong.png', + NAME: 'Chen Gong', + POSITION: 'Technical Expert, Kunpeng Computing PDU, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/biannaimeng.png', + NAME: 'Bian Naimeng', + POSITION: 'Product R&D Director, Cloud Computing Business Group, Hoperun Information Technology' + }, + { + IMG: '/img/summit/home/lecturer/gaokun.png', + NAME: 'Gao Kun', + POSITION: 'Engineer, Open Source Software Competence Center, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/luoqiu.png', + NAME: 'Luo Qiu', + POSITION: 'R&D Engineer, Hunan Kylinsec' + }, + { + IMG: '/img/summit/home/lecturer/wangjiangtao.png', + NAME: 'Wang Jiangtao', + POSITION: 'Senior Security Expert, iSoft Infrastructure Software' + }, + { + IMG: '/img/summit/home/lecturer/liuwei.png', + NAME: 'Liu Wei', + POSITION: 'Researcher, 2020 Lab, Beijing Enmotech' + }, + { + IMG: '/img/summit/home/lecturer/chixinze.png', + NAME: 'Chi Xinze', + POSITION: 'Distributed System Architect, XSKY (Beijing) Data Technology' + }, + { + IMG: '/img/summit/home/lecturer/huangxiaotao.png', + NAME: 'Huang Xiaotao', + POSITION: 'Deputy Director, Database Research Institute, Beijing Vastdata Technology' + }, + { + IMG: '/img/summit/home/lecturer/lijianfeng.png', + NAME: 'Li Jianfeng', + POSITION: 'Director, Desktop R&D Community, Kylinsoft' + }, + { + IMG: '/img/summit/home/lecturer/wangyaohua.png', + NAME: 'Wang Yaohua', + POSITION: 'R&D Director, Uniontech Software' + }, + { + IMG: '/img/summit/home/lecturer/fengben.png', + NAME: 'Feng Ben', + POSITION: 'Expert of Kunpeng Database Optimization, Huawei' + }, + { + IMG: '/img/summit/home/lecturer/wangjunjie.png', + NAME: 'Wang Junjie', + POSITION: 'Expert of Kunpeng Database Optimization, Huawei' + } + ] + }, + HOST: { + WEB_TITLE: '/img/summit/home/host-unit/en-host-unit.png', + MOBILE_TITLE: '/img/summit/home/host-unit/en-mobile-zhuban.png', + LIST: [ + { + IMG: '/img/summit/home/host-unit/openeuler.png' + } + ] + }, + UNDERTAKER: { + WEB_TITLE: '/img/summit/home/undertaker/en-pc-undertaker.png', + MOBILE_TITLE: '/img/summit/home/undertaker/en-mobile-undertaker.png', + LIST: [ + { + IMG: '/img/summit/home/undertaker/jikebang.png', + LINK: 'https://www.geekbang.org/' + } + ] + }, + CO_ORGANIZER: { + WEB_TITLE: '/img/summit/home/co-organizer/en-co-organizer.png', + MOBILE_TITLE: '/img/summit/home/co-organizer/en-mobile-xieban.png', + LIST: [ + { + IMG: '/img/summit/home/co-organizer/yidong.png', + LINK: 'http://it.10086.cn/indexc.html' + }, + { + IMG: '/img/summit/home/co-organizer/liantong.png', + LINK: 'https://www.woyun.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yinlian.png', + LINK: 'https://cn.unionpay.com/' + }, + { + IMG: '/img/summit/home/co-organizer/pengcheng.png', + LINK: 'https://www.pcl.ac.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/feiteng.png', + LINK: 'https://www.phytium.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/qilin.png', + LINK: 'http://www.kylinos.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/tongxin.png', + LINK: 'https://www.uniontech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/cetc.png', + LINK: 'http://www.i-soft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/xinan.png', + LINK: 'http://www.kylinsec.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/iscas.png', + LINK: 'http://www.iscas.ac.cn' + }, + { + IMG: '/img/summit/home/co-organizer/turbolinux.png', + LINK: 'http://www.turbolinux.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/beiming.png', + LINK: 'http://www.bmsoft.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/runhe.png', + LINK: 'http://www.hopeedge.com' + }, + { + IMG: '/img/summit/home/co-organizer/xsky.png', + LINK: 'http://www.xsky.com' + }, + { + IMG: '/img/summit/home/co-organizer/huayun.png', + LINK: 'https://huayun.com/' + }, + { + IMG: '/img/summit/home/co-organizer/qingyun.png', + LINK: 'https://kubesphere.qingcloud.com/' + }, + { + IMG: '/img/summit/home/co-organizer/shenxinfu.png', + LINK: 'https://www.sangfor.com.cn/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhong.png', + LINK: 'http://www.winhong.com/' + }, + { + IMG: '/img/summit/home/co-organizer/yunhe.png', + LINK: 'https://enmotech.com/' + }, + { + IMG: '/img/summit/home/co-organizer/hailiang.png', + LINK: 'http://www.vastdata.com.cn' + }, + { + IMG: '/img/summit/home/co-organizer/hangtian.png', + LINK: 'https://www.htzhiyun.cn' + }, + { + IMG: '/img/summit/home/co-organizer/langche.png', + LINK: 'https://lstack.com/' + } + ] + }, + FOUNDATION: { + WEB_TITLE: '/img/summit/home/foundation/en-pc-foundation.png', + MOBILE_TITLE: '/img/summit/home/foundation/en-mobile-foundation.png', + LIST: [ + { + IMG: '/img/summit/home/foundation/yuanzi.png', + LINK: 'https://www.openatom.org' + }, + { + IMG: '/img/summit/home/foundation/cloudnative.png', + LINK: 'https://www.cncf.io/' + }, + { + IMG: '/img/summit/home/foundation/linaro.png', + LINK: 'https://www.linaro.org/' + }, + { + IMG: '/img/summit/home/foundation/linux.png', + LINK: 'https://www.linuxfoundation.org/' + }, + { + IMG: '/img/summit/home/foundation/open.png', + LINK: 'https://www.openinfra.dev/' + } + ] + }, + MEDIA: { + WEB_TITLE: '/img/summit/home/media/en-pc-media.png', + MOBILE_TITLE: '/img/summit/home/media/en-mobile-media.png', + LIST: [ + { + IMG: '/img/summit/home/media/csdn.png', + LINK: 'https://www.csdn.net/' + }, + { + IMG: '/img/summit/home/media/sifou.png', + LINK: 'https://segmentfault.com/' + }, + { + IMG: '/img/summit/home/media/oschina.png', + LINK: 'https://www.oschina.net/' + }, + { + IMG: '/img/summit/home/media/51cto.png', + LINK: 'https://www.51cto.com/' + }, + { + IMG: '/img/summit/home/media/media-linux.png', + LINK: 'https://linux.cn/' + }, + { + IMG: '/img/summit/home/media/xianglingshuo.png', + LINK: 'qrcode' + }, + ] + }, + REVIEW: { + WEB_TITLE: '/img/summit/home/review/en-pc-review.png', + MOBILE_TITLE: '/img/summit/home/review/en-mobile-review.png', + WEB_BANNER: '/img/summit/home/review/web-review-banner.png', + MOBILE_BANNER: '/img/summit/home/review/h5-review-banner.png' + } + }, + LISTTITLE: 'Overview', + LISTNEWTITLE:'openEuler Virtual Summit 2020', + LISTTIME: 'Apr 17–18, 2020', + SPEECHTITLE: 'Keynotes', + DESIGNTITLE: 'Design Summit (SIG Workshop)', + VIDEODOWNLOAD: 'Slides', + FRIENDSHIPLINK: 'Links', + SUMMIT_WEB_IMG: '/img/summit/home/en-pc-summit.png', + SUMMIT_H5_IMG: '/img/summit/home/en-mobile-summit.png', + SPEECHLIST: [{ + SPEECHTIME: '09:30 - 09:40, 17th April', + SPEECHTHEME: 'openEuler Drives a Robust Multi-Core, Heterogeneous Computing Industry', + SPEECHER: 'Jiang Dayong', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/jiangdayong.png', + SPEECHERINFO: '', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '09:40 - 09:50, 17th April', + SPEECHTHEME: 'openEuler: The Industry Propeller and Super Workshop', + SPEECHER: 'WangZhun', + SPEECHCONTENT: 'Focusing on IT transformation and industrial Internet construction in traditional industries, he has chaired the architecture planning of national-level information technology projects and provided consulting services to major ministries and central enterprises. As a member of the Association of Enterprise Architect, he is committed to promoting the rollout and implementation of enterprise architecture in China.', + SPEECHERIMG: '/img/summit/wangzhun.jpg', + SPEECHERINFO: 'Senior Architect, Tongfang', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '09:50 - 10:30, 17th April', + SPEECHTHEME: 'Innovation Drives the Future of openEuler', + SPEECHER: 'Dr. Xiong Wei', + SPEECHCONTENT: 'Xiong Wei, joined Huawei in 2014, is now the 2012 laboratory Central Software Institute server operating system chief architect, openEuler technical committee member; Nankai University, doctor of engineering, in TurboLinux, WindRiver and other companies as R & D person in charge, has a long time OS, underlying software experience and technology accumulation; on the processor, architecture, OS, containers, etc. has a broad technical vision, initially established the Kunpeng basic software stack server OS, container engine and other infrastructure of the platform system of self- research.', + SPEECHERIMG: '/img/summit/xiongwei.png', + SPEECHERINFO: 'Member of openEuler Technical Committee', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:30 - 10:40, 17th April', + SPEECHTHEME: 'openEuler Leads the Way to a Co-Built, Win-Win Global Community', + SPEECHER: 'Yu Liang', + SPEECHCONTENT: 'More than 20 years in the field of basic operating system, witnessed the development history of domestic Linux operating system. In 2016, he joined Puhua as Vice President of Marketing in the Basic Software Division of Puhua Corporation. Since the national e-government intranet "12 banks and 3 gold" project, it has participated in most of the landmark projects of the domestic operating system.', + SPEECHERIMG: '/img/summit/yuliang.png', + SPEECHERINFO: 'Deputy GM, Basic Software Business Group, iSoft', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:40 - 10:50, 17th April', + SPEECHTHEME: 'Kylin: Scale New Heights on the Wings of Kunpeng', + SPEECHER: 'Li Zhenning', + SPEECHCONTENT: 'The most valuable expert of HUAWEI CLOUD and Tencent Cloud; Director of Shanghai Basic Software Engineering Technology Research Center and mentor of master students at Taiyuan University of Technology. Li Zhenning has served in the open source and operating system field for 20 years, and his clients include many government agencies, national defense and aerospace, banks, securities, universities, etc. He has rich experience in open source operating system software technology, marketing and PR communication. He is currently an expert in the operating system and basic software industry in several ministries, provinces and cities. Research on industry macro development, technology trends, standards policy, etc. Currently, he is also a member of the China-Japan-Korea Northeast Asia Open Source Committee, Secretary General of the Open Source and Basic Software General Technology Innovation Strategic Alliance (UU); Deputy Secretary General of the China High-end Chip Alliance, Deputy Secretary General of the China Open Source Software Promotion Alliance, Deputy Secretary General of the China Open Source Cloud Alliance, Deputy Secretary General of the China Big Data Application Collaboration and Innovation Alliance, Head of the TIAA Automotive Alliance Software Group; Member of the CCF System Software Committee; Deputy Director of the China Big Data and Intelligent Computing Industry Alliance Open Source Software Working Committee, etc.', + SPEECHERIMG: '/img/summit/lizhenning.jpg', + SPEECHERINFO: 'VP, Kylinsoft', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '10:50 - 11:00, 17th April', + SPEECHTHEME: ' Open Source Software Supply Lightening Program Boosts a Robust Community', + SPEECHER: 'Wu Yanjun', + SPEECHCONTENT: 'Researcher, Ph.D. supervisor, Deputy Chief Engineer, Institute of Software, Chinese Academy of Sciences, Director of Intelligent Software Research Center. After graduating from Tsinghua University, he joined the Software Institute of Chinese Academy of Sciences and has been working on operating system related research and development for a long time. He has published more than 50 papers in top academic conferences and core journals, and applied for more than 30 patents and softwares. He has been honored by the Beijing Science and Technology Rising Star and the Chinese Academy of Sciences Youth Promotion Association.', + SPEECHERIMG: '/img/summit/wuyanjun.png', + SPEECHERINFO: 'Deputy Chief Engineer, Director of Intelligent Software Research Center, ISCAS', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:00 - 11:10, 17th April', + SPEECHTHEME: 'openEuler: The Best MySQL Platform on Arm-based Servers', + SPEECHER: 'Ding Wenlong', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/dingwenlong.png', + SPEECHERINFO: 'Senior Engineer, Turbolinux', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:10 - 11:25, 17th,April', + SPEECHTHEME: 'How to Enjoy openEuler', + SPEECHER: 'Ma Junjie', + SPEECHCONTENT: 'openEuler Infrastructure Committer, openEuler oVirt SIG maintainer, oVirt Member, Istio community Member', + SPEECHERIMG: '/img/summit/majunjie.png', + SPEECHERINFO: 'openEuler Infrastructure SIG Committer', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + { + SPEECHTIME: '11:25 - 11:45, 17th,April', + SPEECHTHEME: 'openEuler Community Governance', + SPEECHER: 'Hu Xinwei', + SPEECHCONTENT: '', + SPEECHERIMG: '/img/summit/huxinwei.png', + SPEECHERINFO: 'Chairman of openEuler Technical Committee', + SPEECHLINK: 'https://www.bilibili.com/video/BV1dg4y187cq' + }, + ], + TRACKLIST: ['Track 1', 'Track 2', 'Track 3'], + DESIGNLIST: [{ + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '13:30 - 15:00' + }], + TRACK1: [{ + TRACK1TITLE: 'openEuler Kernel', + TRACK1TEACHER: 'Hanjun Guo', + TRACK1MAINTAINER: 'openEuler Kernel Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1E64y1T76a', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-kernel' + }], + TRACK2: [{ + TRACK2TITLE: 'RaspberryPi', + TRACK2TEACHER: 'Yafen Fang', + TRACK2MAINTAINER: 'RaspberryPi Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1Ve411s74C', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-raspberrypi' + }], + TRACK3: [{ + TRACK3TITLE: 'UKUI', + TRACK3TEACHER: 'Dou Yan', + TRACK3MAINTAINER: 'UKUI Maintainer, Member of KylinSoft open source community', + TRACK3LINK:'https://www.bilibili.com/video/BV1ei4y187SD', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ukui' + }] + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '15:00 - 16:00' + } + + ], + TRACK1: [{ + TRACK1TITLE: 'Container & iSula', + TRACK1TEACHER: 'Haomin Tsai', + TRACK1MAINTAINER: 'Container & iSula SIG Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1A54y1R7iX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-container' + }], + TRACK2: [{ + TRACK2TITLE: 'Documentation', + TRACK2TEACHER: 'Zhipeng Tan', + TRACK2MAINTAINER: 'Documentation Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1yT4y1G78u', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-documentation' + }], + TRACK3: [{ + TRACK3TITLE: 'High Availability', + TRACK3TEACHER: 'jian Hou ', + TRACK3MAINTAINER: 'HA Maintainer; KylinSoft', + TRACK3LINK:'https://www.bilibili.com/video/BV1Wt4y1272N', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ha' + }] + + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '16:00 - 17:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Packaging & Base Service', + TRACK1TEACHER: 'Xiaowen He', + TRACK1MAINTAINER: 'Packaging Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1we411s7rQ', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-packaging' + }], + TRACK3: [{ + TRACK3TITLE: 'oVirt', + TRACK3TEACHER: 'Huihui Fu ', + TRACK3MAINTAINER: 'oVirt Maintainer; KylinSoft', + TRACK3LINK:'https://www.bilibili.com/video/BV1LK4y1k7Hv', + TRACK3DOWNLOAD:'hhttps://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-ovirt' + }] + + }, + { + DESIGNTIME: [{ + DAY: '17th April', + HOUR: '17:00 - 18:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Kubernetes', + TRACK1TEACHER: 'Pengfei Zhou', + TRACK1MAINTAINER: 'SIG-Kubernetes Maintainer', + TRACK1LINK:'https://www.bilibili.com/video/BV1ak4y1R7Sq', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-kubernetes' + }], + TRACK2: [{ + TRACK2TITLE: 'Networking', + TRACK2TEACHER: 'Zhihao Lu', + TRACK2MAINTAINER: 'Networking Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1KV411Z7nR', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-networking' + }], + TRACK3: [{ + TRACK3TITLE: 'Virualization', + TRACK3TEACHER: 'Hailiang Zhang ', + TRACK3MAINTAINER: 'Vir Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1q54y197CX', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-virtualization' + }] + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '09:00 - 10:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Community Governance', + TRACK1TEACHER: 'Fred Li', + TRACK1MAINTAINER: 'Head of openEuler Secretariat', + TRACK1LINK:'https://www.bilibili.com/video/BV1sA411b74z', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-community-governance' + }], + TRACK2: [{ + TRACK2TITLE: 'Compiler', + TRACK2TEACHER: 'Ge Guo', + TRACK2MAINTAINER: 'Compiler Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV16Q4y1K7gV', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compiler' + }], + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '10:00 - 11:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Release Management', + TRACK1TEACHER: 'Liang Ma', + TRACK1MAINTAINER: 'openEuler 20.09 Release Manager', + TRACK1LINK:'https://www.bilibili.com/video/BV1JA411b7tX', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-release' + }], + TRACK2: [{ + TRACK2TITLE: 'Compatibility', + TRACK2TEACHER: 'Kaitian Du', + TRACK2MAINTAINER: 'Compatibility Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1F5411b7pJ', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-compatibility' + }], + TRACK3: [{ + TRACK3TITLE: 'Dev-utils', + TRACK3TEACHER: 'Myeuler', + TRACK3MAINTAINER: 'openEuler TC member; Dev-utils Maintainer', + TRACK3LINK:'https://www.bilibili.com/video/BV1Ei4y1t7a8', + TRACK3DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-dev-utils' + }] + + }, + { + DESIGNTIME: [{ + DAY: '18th April', + HOUR: '11:00 - 12:00' + }], + TRACK1: [{ + TRACK1TITLE: 'Technical Committee', + TRACK1TEACHER: 'Shinwell Hu', + TRACK1MAINTAINER: 'Chairman of openEuler Technical Committee', + TRACK1LINK:'https://www.bilibili.com/video/BV1rQ4y1K7L6', + TRACK1DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-tc' + }], + TRACK2: [{ + TRACK2TITLE: 'Infrastructure', + TRACK2TEACHER: 'freesky-edward', + TRACK2MAINTAINER: 'Infrastructure Maintainer', + TRACK2LINK:'https://www.bilibili.com/video/BV1UT4y1G7fp', + TRACK2DOWNLOAD:'https://etherpad.openeuler.org/p/openeuler-virtual-summit-2020-infrastructure' + }], + TRACK3: [{ + TRACK3TITLE: 'Security Committee', + TRACK3TEACHER: 'Jianwen Zhu', + TRACK3MAINTAINER: 'Expert of operating system security', + TRACK3LINK:'https://www.bilibili.com/video/BV17Q4y1T7FN', + TRACK3DOWNLOAD:'https://etherpad.opendev.org/p/openeuler-virtual-summit-2020-security-committee' + }] + } + ], + OTHERLINK:[ + { + URL:'url("/img/home/link/mulan.png")', + LINK:'http://www.mulanos.cn/' + }, + { + URL:'url("/img/home/link/kunpeng.png")', + LINK:'https://kunpeng.huawei.com/' + }, + { + URL:'url("/img/home/link/pengcheng.png")', + LINK:'https://dw.pcl.ac.cn/dwmain/main/' + } + ] + }, + MEETUPS: { + MEETUPS: 'Семинары', + DETAIL_DESC: 'Introduction', + DETAIL_FLOW: 'Agenda', + DETAIL_REVIEW: 'Review', + MORE_VIDEO: 'More video', + DETAIL_MEET: 'How to attend the event', + DETAIL_QRCODE_TEXT: 'Scan the QR code', + INSIDENAME: 'CONNECT', + DEFAULT_IMG: '/img/meetups/default-address.png', + MEETUPS_DATA: require('./../../data/salon').en.MEETUPS_LIST + }, + DEVDAY_2021: { + PC_BANNER: '/img/summit/devday-2021/devday-2021-en.png', + H5_BANNER: '/img/summit/devday-2021/banner-h5-en.png' + }, + SUMMIT_2021: { + SPEACKER: '/img/summit/summit2021/call-speaker.png', + SPEONSOR: '/img/summit/summit2021/call-sponsor.png', + DEMO: '/img/summit/summit2021/call-demo.png', + } + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/learn.js b/web-ui/docs/.vuepress/lang/lang-modules/learn.js new file mode 100644 index 0000000000000000000000000000000000000000..cff3488b859106fa893a58321933dc1d53861d66 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/learn.js @@ -0,0 +1,915 @@ +/** + * @file 学习模块国际化配置入口 + * */ +module.exports = { + cn: { + MOOC: '慕课', + MOOC_COURSE: [ + { + ID: '1', + IMG: '/img/learn/hcia/hcia.png', + TITLE: 'HCIA-openEuler 认证培训课程', + DESC: '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + APPLY_LINK: 'https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0 ' + } + ], + BTN_LEARN: '课程学习', + BTN_APPLY: '考试报名', + MOOC_CATALOG: '目录', + COURSE_DOWNLOAD: '课件下载', + TEACHER_TEAM: '讲师团队', + MOOC_LIST_ROUTRE: '慕课', + PREV_TEXT: '上一篇', + NEXT_TEXT: '下一篇', + MOOC_DATA: require('./../../data/learn').cn.COURSE_LIST, + NAV_LIST: [ + { + key: "#introduce", + name: "活动介绍", + }, + { + key: "#step", + name: "申请步骤", + }, + { + key: "#task", + name: "实习任务", + }, + { + key: "#integral ", + name: "激励规则", + }, + { + key: "#rule", + name: "实习规则", + }, + { + key: "#partner", + name: "合作伙伴", + }, + { + key: "#help", + name: "帮助咨询", + }, + ], + INTRODUCE: + " openEuler开源实习是openEuler社区和社区合作单位共同发起的线上实习项目,旨在鼓励在校学生积极参与开源社区,在实际的开源环境中提升实践能力。由openEuler社区提供实习任务,并提供导师辅导,学生通过实习申请后,可在社区领取任务,每完成一个任务可获得相应积分,积分累计达规定量后,可获得实习证明和实习工资。", + STEP: { + TITLE:"/img/internship/step-title.png", + STEPNAV: [ + { + IMG: "/img/internship/step_1.png", + ACTIVE: "/img/internship/step_1active.png", + TEXT: "申请实习", + }, + { + IMG: "/img/internship/step_2.png", + ACTIVE: "/img/internship/step_2active.png", + TEXT: "领取任务", + }, + { + IMG: "/img/internship/step_3.png", + ACTIVE: "/img/internship/step_3active.png", + TEXT: "提交任务", + }, + { + IMG: "/img/internship/step_4.png", + ACTIVE: "/img/internship/step_4active.png", + TEXT: "工资与实习证明", + }, + ], + STEP_ONE: { + TITLE: "申请实习", + TEXT1: "(1)阅读并签署活动声明。(见申请材料模板里)", + TEXT2: "(2)完成", + LINK1: "实习测试任务", + TEXT3: "并提供PR链接。", + TEXT4: "(3)填写报名资料表。", + ATTENTION1: "将以上申请材料按照模板填写后发送至开源实习官方邮箱", + ATTENTION2: + "。发送后等待审核,组织方将以邮件反馈审核结果,审核通过后,签订劳务协议,用所分配的账号开始实习。", + DONWLOAD: "申请材料模板下载", + TIP: "(注:组织方会根据所提交的资料对报名学生进行一定的审核筛选)" + }, + ATTENTION: "注意", + STEP_TOW: { + TITLE: "领取任务", + P_TEXT: [ + "(1)在Gitee查看任务,找到你想做的任务issue。", + "(2)在任务issue下方评论区输入", + "/intern-assign", + "命令,认领该任务,然后发送邮件给任务导师请求审核。邮件需包括你的简历和该任务的开发方案。", + "(3)导师收到邮件后对申请人进行评审,在该任务issue评论下通过输入命令反馈结果,", + "/intern-approve", + "代表审核通过,学生成功领取任务,可以开始进行任务处理;", + "/intern-unapprove", + "代表领取失败,该学生可再去领取其他任务。", + "(4)如果领取后无法完成,可通过在issue下输入", + "/intern-unassign", + "放弃任务。", + "放弃超过3次,账号被限制一个月不能领取任务。", + ], + ATTENTION_TEXT: [ + "每个任务只能有一个人认领,每人一次最多只能有2个认领中的任务。", + "输入", + "/intern-assign", + "命令后两周内没有发简历和方案给导师的,认领自动失效,任务被释放。", + ], + DONWLOAD: "任务认领邮件模板下载", + }, + STEP_ThREE: { + TITLE: "提交任务", + P_TEXT: [ + "(1)任务处理完成后,提交pr,在pr描述里添加 ", + "#issue", + " 编号;", + "(2)提交pr后在任务issue评论区输入", + "/intern-completed", + "命令,表示当前任务已提交,然后等待审核。", + "(3)跟进导师和相关SIG maintainer审核PR,PR被合入后,导师确认任务完成即在issue下输入", + "/intern-done", + "命令,issue关闭,学生获得积分。" + ], + ATTENTION_TEXT: [ + "导师有不通过任务成果的权利,如学生提交的PR离实际所需太远,或未按时提交PR,可选择输入命令", + "/intern-fail", + ",不通过该任务,则无积分。", + ], + }, + STEP_FOUR: { + TITLE: "工资与实习证明", + P_TEXT1: [ + "(1)在实习合同里约定的6个月期限内,学生可凭积分获得实习工资。", + "(2)证明申请:在实习有效期6个月内满60分即可开具实习证明,如需开具实习证明,发送邮件给实习官方邮箱", + "intern@openeuler.sh", + "提出申请。", + ], + P_TEXT: [ + "满20分可获得工资总计1000元;", + "满40分可获得工资总计2500元;", + "满60分可获得工资总计4000元;", + "满80分可获得工资总计6000元;", + "满100分可获得工资总计8000元;", + ], + ATTENTION_TEXT: [ + "以上工资金额为总计金额,每月月初按上月积分结算一次应发工资,在月底发放到实习生账户。应发工资为达到相应积分标准的总计工资金额减去已结算金额。", + "总计100分为工资结算上限。超过100分不再计算工资,可选择结束实习,或继续贡献社区,满150分可获得“开源之星”荣誉。", + "证明开具后视为实习结束,不再计算实习工资。", + ], + DONWLOAD: "证明申请材料和邮件模板下载", + }, + }, + TASK: { + TITLE:"/img/internship/task-title.png", + INTRODUCE: + "SIG(Special Interest Group)是openEuler社区的组织形式,找到你感兴趣的SIG,点击下列“实习任务”到Gitee查看相关SIG的任务(需先保持Gitee在登陆状态)。", + EULER_TASK_ITEM: [ + { + NAME: "Kernel", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=10&name=Kernel", + INTRODUCE: "openEuler社区维护的Linux 内核", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590412&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590412&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/Kernel", + }, + { + NAME: "sig-QA", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=41&name=sig-QA", + INTRODUCE: "致力于持续提升openEuler社区发行版本质量", + TASK: "https://gitee.com/organizations/src-openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590164&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590164&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-QA", + }, + { + NAME: "sig-openstack", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=59&name=sig-openstack", + INTRODUCE: + "在openEuler之上提供原生的OpenStack,构建开放可靠的云计算技术栈", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590186&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590186&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/openstack", + }, + { + NAME: "A-tune", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=1&name=A-Tune", + INTRODUCE: "基于openEuler开发的自动化、智能化性能调优引擎", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590388&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590194&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/A-Tune", + }, + { + NAME: "sig-KIRAN-DESKTOP", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=37&name=sig-KIRAN-DESKTOP&mail=dev%40openeuler.org", + INTRODUCE: + "麒麟信安自主研发,致力于为用户提供更加美观,高效和易用的Linux桌面操作系统", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590528&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-KIRAN-DESKTOP", + }, + { + NAME: "sig-ops", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=83&name=sig-ops", + INTRODUCE: + "致力于运维工具的移植与开发,提升openEuler操作系统的运维能力", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590388&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590323&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-ops", + }, + { + NAME: "Cloud Native", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=85&name=sig-CloudNative", + INTRODUCE: + "提供便捷、易用的云原生基础设施,提供简单、高效的云原生应用开发托管环境,共建云原生生态", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590352&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-CloudNative", + }, + { + NAME: "G11N", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=98&name=G11N", + INTRODUCE: "致力于openEuler的国际化和本地化", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590388&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/G11N", + }, + { + NAME: "sig-UKUI", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=46&name=sig-UKUI", + INTRODUCE: "负责在openEuler上提供UKUI桌面环境,及相关软件包的规划、维护和升级", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590230&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-UKUI", + }, + { + NAME: "sig-OSCourse", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OSCourse", + INTRODUCE: "操作系统课程兴趣组", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=141433910&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-OSCourse", + }, + { + NAME: "sig-DDE", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-DDE", + INTRODUCE: "深度科技自主开发的美观易用、极简操作的桌面环境", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590403&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-DDE", + }, + { + NAME: "Infrastructure", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=Infrastructure", + INTRODUCE: "主要负责openEuler社区的基础设施功能开发、维护", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590142&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/Infrastructure", + }, + { + NAME: "sig-OS-Builder", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OS-Builder", + INTRODUCE: "维护openEuler业务软件包,提供更加方便的ISO构建/换标方案,提供更好的安装与升级方案", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=145511845&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-OS-Builder", + }, + { + NAME: "sig-CICD", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OS-Builder", + INTRODUCE: "致力于为开发者提供针对上游开源软件(来自Github、Gitee、Gitlab等托管平台)的测试服务、登录服务、故障辅助定界服务和基于历史数据的分析服务于一体的测试系统", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590412&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=146173410&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-CICD", + }, + { + NAME: "sig-HPC", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-HPC", + INTRODUCE: "建立HPC领域的高校、企业与工程师的交流圈,打造HPC快速部署调优平台,让HPC流行起来!", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=125219718&single_label_text=&state=&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-HPC", + }, + { + NAME: "其他", + INTRODUCE: "一些暂不属于任何SIG的任务,如Rust、存储等等", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=125884711&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&sort=&state=open&target_project&skip_mobile=true", + }, + { + INTRODUCE: "更多SIG任务,敬请期待", + }, + ], + LOOKENG_TASK_ITEM: [ + { + NAME_LINK: + "https://openlookeng.io", + NAME: "openLooKeng", + INTRODUCE: "一款超强易用的数据虚拟化引擎,让大数据更简单", + TASK: "https://gitee.com/openlookeng-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openlookeng-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=newest&state=open&target_project&skip_mobile=true", + GITEE: "https://openlookeng.io", + }, + ], + OPENGAUSS_TASK_ITEM: [ + { + NAME_LINK: + "https://opengauss.org/", + NAME: "openGauss", + INTRODUCE: "一款高性能、高安全、高可靠的企业级开源关系型数据库", + TASK: "https://gitee.com/opengauss/opensource-intership/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openlookeng-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=newest&state=open&target_project&skip_mobile=true", + GITEE: "https://opengauss.org/", + }, + ], + MINDSPORE_TASK_ITEM: [ + { + NAME: "MindSpore开源实习招聘要求(公开)", + TASK: "https://gitee.com/mindspore/community/issues/I55QGD?from=project-issue&skip_mobile=true", + GITEE: "https://www.mindspore.cn/", + TEXT_ARRAY:[ + '1、全日制大三大四本科生或在读研究生,计算机、软件、人工智能、电子信息、数学、计算物理、计算生物、计算化学等相关专业;', + '2、熟悉C++/Python编程,编码能力优秀,具有扎实的计算机基础;', + '3、至少熟悉一种主流深度学习框架,如MindSpore、Tensorflow、PyTorch等;', + '4、优选条件', + '(1)熟悉以下任一技术方向:分布式系统、并行计算、异构计算、深度学习编译优化、模型压缩、推理部署、算子开发、模型开发等;', + '(2)在高水平国际会议和学术期刊发表过相关论文或有高水平竞赛获奖经历;', + '(3)MindSpore社区优秀开发者、资深开发者、优秀布道师、资深布道师。' + ] + }, + ], + INTERNSHIP_TASK: "实习任务", + SIG_DETAIL: "SIG详情", + }, + INTEGRAL: { + TITLE:"/img/internship/integral-title.png", + REWARD: { + HEAD: "1、实习工资、", + TEXT: [ + "实习有效期6个月内满20分以上,可获得不同级别的实习工资。具体见以上“申请步骤4”里的工资说明。", + ], + SUPPLEMENT:"", + }, + HONOR: { + HEAD: "2、实习证明", + TEXT: [ + "实习有效期6个月内积分满60分", + "至少找一位导师写实习评语", + "提交实习报告", + ], + SUPPLEMENT:"满足以上3条,实习评语与实习报告经评审合格后发放实习证明。", + + }, + INTEGRAL_DATA:[ + { + HEAD: "1、实习工资、", + TEXT: [ + "实习有效期6个月内满20分以上,可获得不同级别的实习工资。具体见以上“申请步骤4”里的工资说明。", + ], + SUPPLEMENT:"", + }, + { + HEAD: "2、实习证明", + TEXT: [ + "实习有效期6个月内积分满60分", + "至少找一位导师写实习评语", + "开源实习报告模板", + ], + SUPPLEMENT:"满足以上3条,实习评语与实习报告经评审合格后发放实习证明。", + }, + { + HEAD: "3、优秀实习生证书", + TEXT: [ + "实习有效期6个月内积分满100分。(需包含有20及以上分值的任务)", + "至少找一位导师写优秀推荐评语。", + "完成优秀实习生线上公开答辩(直播形式)。", + ], + SUPPLEMENT:"满足以上3条,公开答辩获得评委打分80分以上后,发放优秀实习生证书。", + }, + { + HEAD: "4、开源之星", + TEXT: [ + "2022年内独在openEuler社区(或openGauss社区)积分满150分。", + "2022年内独在openEuler社区(或openGauss社区)满120分并在openEuler(或openGauss)公众号发布3篇以上实习项目相关文章及参与过一次实习直播主讲。", + ], + SUPPLEMENT:"满足以上一条可获得“开源之星”荣誉徽章,在openEuler(openGauss)官网展示,并获得参与2022年度实习优秀贡献者评选资格,评选上将获得奖金10000元。", + }, + ], + INTERNSHIP_COMMENT:{ + TEXT:'实习评语', + LINK:'/doc/导师实习评语.txt', + TITLE:'下载实习评语' + }, + SUPPLEMENT_GAUSS:"(仅针对openEuler与openGauss社区)" + }, + RULE: { + TITLE:"/img/internship/rule-title.png", + RULE_DATA: [ + { + QUESTION: "1、哪些人可以报名?", + ANSWER: + "A:开源实习面向全国范围内年满18周岁的全日制/非全日制在校学生招募,无专业年级限制,欢迎感兴趣的同学踊跃报名。", + }, + { + QUESTION: "2、实习有效期6个月是如何计算的?", + ANSWER: + "A:在申请实习时需签署实习劳务合同,实习有效期即劳务合同上填写的实习有效期,为6个月期限,6个月期限内未满60积分则不能获得实习证明。线上实习时间管理相对自由,可根据自身情况安排时间,可提前结束实习。", + }, + { + QUESTION: "3、超过了6个月或者完成了100积分还能继续在社区做任务吗?", + ANSWER: + "A:可以,但积分不能再用于领取证明和奖金,一年内累计到150积分可获得openEuler社区高校“开源之星”荣誉。 ", + }, + ], + MORE: ["更多问题,请移步", "本帖", "评论区提问。"], + }, + OFFICAL_WEB: '官网详情', + RANK: { + FIRST: "第一名", + SECOND: "第二名", + THIRD: "第三名", + SCORE: "积分", + VIEW_ALL: "查看全部", + PACK_UP: "收起全部", + }, + PARTNER_TITLE:"/img/internship/partner-title.png", + PARTNER_DATA: [ + { + IMG: "/img/internship/iscas.png", + LINK: "", + }, + { + IMG: "/img/internship/qilinsoft.png", + LINK: "", + }, + { + IMG: "/img/internship/tongxin.png", + LINK: "", + }, + { + IMG: "/img/internship/kylinsec.png", + LINK: "", + }, + { + IMG: "/img/internship/mindSpore.png", + LINK: "", + }, + { + IMG: "/img/internship/openEuler.png", + LINK: "", + }, + { + IMG: "/img/internship/openGauss.png", + LINK: "", + }, + { + IMG: "/img/internship/openLooKeng.png", + LINK: "", + }, + { + IMG: "/img/internship/gitee.png", + LINK: "", + }, + ], + HELP_TITLE:"/img/internship/help-title.png", + HELP: [ + "联系邮箱:", + "intern@openeuler.sh", + "扫码加入“开源实习”学生QQ群,更多问题群内咨询。", + "群号:526089131", + ], + }, + en: { + MOOC: '慕课', + MOOC_COURSE: [ + { + ID: '1', + IMG: '/img/learn/hcia/hcia.png', + TITLE: 'HCIA-openEuler 认证培训课程', + DESC: '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + APPLY_LINK: 'https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0 ' + } + ], + BTN_LEARN: '课程学习', + BTN_APPLY: '考试报名', + MOOC_CATALOG: '目录', + COURSE_DOWNLOAD: '课件下载', + TEACHER_TEAM: '讲师团队', + MOOC_LIST_ROUTRE: '慕课', + PREV_TEXT: '上一篇', + NEXT_TEXT: '下一篇', + MOOC_DATA: require('./../../data/learn').en.COURSE_LIST, + NAV_LIST: [ + { + key: "#introduce", + name: "Introduction", + }, + { + key: "#step", + name: "Procedure", + }, + { + key: "#task", + name: "Internship Tasks", + }, + { + key: "#integral ", + name: "Bonus Point Display", + }, + { + key: "#rule", + name: "FAQs", + }, + { + key: "#partner", + name: "Partners", + }, + { + key: "#help", + name: "Help and Consultation", + }, + ], + INTRODUCE: + "openEuler internship is an online internship project jointly initiated by the openEuler community and its partner. It aims to encourage students to join the open source community and improve their practical capabilities in open source projects. The openEuler community provides internship tasks and mentoring. If your application for the internship is approved, you can claim tasks in the community and earn a certain amount of bonus points upon completing each task. When you have accumulated the specified number of bonus points, you will be eligible to obtain an internship certificate and salary.", + STEP: { + TITLE:"/img/internship/step-title.png", + STEPNAV: [ + { + IMG: "/img/internship/step_1.png", + ACTIVE: "/img/internship/step_1active.png", + TEXT: "Apply for Internship", + }, + { + IMG: "/img/internship/step_2.png", + ACTIVE: "/img/internship/step_2active.png", + TEXT: "Claim a Task", + }, + { + IMG: "/img/internship/step_3.png", + ACTIVE: "/img/internship/step_3active.png", + TEXT: "Submit the Task", + }, + { + IMG: "/img/internship/step_4.png", + ACTIVE: "/img/internship/step_4active.png", + TEXT: "Obtain Salary and Internship Certificate", + }, + ], + STEP_ONE: { + TITLE: "Apply for Internship", + TEXT1: "(1)Read and sign the internship statement. (See the internship application template.)", + TEXT2: "(2)Complete the", + LINK1: " test task for internship ", + TEXT3: "and provide the pull request (PR) link.", + TEXT4: "(3)Fill in the internship application form.", + ATTENTION1: "Prepare the application materials in accordance with the template, and send them to ", + ATTENTION2: + ". Wait for the community to reply to your application by email. If you pass the review, sign the internship contract and use the allocated account to start the internship.", + DONWLOAD: "Download Internship Application Template", + TIP: "(Note: The community will review and screen applicants based on submitted materials.)" + }, + ATTENTION: "Notes:", + STEP_TOW: { + TITLE: "Claim a Task", + P_TEXT: [ + "(1)View the internship tasks, and find a task you are interested in.", + "(2)Enter the", + "/intern-assign", + "command in the comment area of the issue to claim the task, and send an email to the task mentor for approval. The email should include your resume and development plan for the task.", + "(3)The mentor will review the application, and provide feedback in the comment area of the issue.", + "/intern-approve", + "indicates that the task has been successfully claimed.", + " /intern-unapprove", + "indicates that the task has not been claimed, and that you can try claiming another task.", + "(4)If you are unable to complete the claimed task, enter", + " /intern-unassign", + "in the comment area of the issue to cancel the task.", + "If you cancel claimed tasks more than three times, your account will be blocked from claiming any task for 30 days.", + ], + ATTENTION_TEXT: [ + "Each task can only be claimed by a single intern. Each intern can claim a maximum of two tasks at a time.", + "If you do not send the resume and development plan to the task mentor within two weeks of having entered the", + "/intern-assign", + "command in the comment area of the issue, the claim will automatically become invalid, and the task will be released for others to claim.", + ], + DONWLOAD: "Download Task Claim Email Template", + }, + STEP_ThREE: { + TITLE: "Submit the Task", + P_TEXT: [ + "(1)After completing the task, submit a PR and add ", + "#issue_ID", + " to the PR description.", + "(2)After submitting the PR, enter the", + "/intern-completed", + "command in the comment area of the issue, indicating that the task has been submitted and is awaiting review.", + "(3)Follow up with the mentor and corresponding SIG maintainer on the PR review. After the PR is merged, the mentor will confirm that the task is completed, and enters the", + "/intern-done", + "command in the comment area of the issue. The issue will be closed and you will receive bonus points for the task." + ], + ATTENTION_TEXT: [ + "The mentor has the right to reject the PR. If the PR submitted by the intern does not meet the requirements, or the intern does not submit the PR in time, the mentor can enter the", + "/intern-fail ", + "command to reject the PR. In this case, no bonus points will be awarded.", + ], + }, + STEP_FOUR: { + TITLE: "Obtain Salary and Internship Certificate", + P_TEXT1: [ + "(1)Within the six-month period stipulated in the internship contract, you can claim an internship salary based on the number of bonus points you have earned.", + "(2)If you have earned 60 or more bonus points within the six-month internship, you can send an email to", + " intern@openeuler.sh ", + "to request an internship certificate.", + ], + P_TEXT: [ + "Earn 20 bonus points for CNY 1,000.", + "Earn 40 bonus points for CNY 2,500.", + "Earn 60 bonus points for CNY 4,000.", + "Earn 80 bonus points for CNY 6,000.", + "Earn 100 bonus points for CNY 8,000.", + ], + ATTENTION_TEXT: [ + "The above salary amounts are total amounts. At the beginning of each month, the payable salary is settled based on the bonus points earned the previous month. At the end of each month, the settled salary will be paid to your bank account. The salary to be paid is the total salary that can be obtained based on the accumulated bonus points minus the salary that had previously been paid to your account.", + "A maximum of 100 bonus points can be used for salary calculation purposes. If you have earned more than 100 bonus points, the extra bonus points will not be used to calculate your salary. You can choose to end your internship or continue to contribute to the community. If you earn 150 or more, you will be awarded the Open Source Star title.", + "Once the internship certificate is issued, the internship will be deemed to have ended, and no additional internship salary can be settled and paid.", + ], + DONWLOAD: "Download Certificate Application Email Template", + }, + }, + TASK: { + TITLE:"/img/internship/task-title.png", + INTRODUCE: + "The openEuler community is organized into Special Interest Groups (SIGs). Find the SIG that you are interested in, and click on View Internship Tasks to view internship tasks released by the SIG on Gitee (log in to Gitee in advance).", + EULER_TASK_ITEM: [ + { + NAME: "Kernel", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=10&name=Kernel", + INTRODUCE: "Maintains the Linux kernel of openEuler.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590412&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590412&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/Kernel", + }, + { + NAME: "sig-QA", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=41&name=sig-QA", + INTRODUCE: "Improves the quality of the openEuler releases on an ongoing basis.", + TASK: "https://gitee.com/organizations/src-openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590164&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590164&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-QA", + }, + { + NAME: "sig-openstack", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=59&name=sig-openstack", + INTRODUCE: + "Provides native OpenStack based on openEuler, to build an open and reliable cloud computing technology stack.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590186&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590186&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/openstack", + }, + { + NAME: "A-tune", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=1&name=A-Tune", + INTRODUCE: "Provides an automatic and intelligent performance tuning engine, based on openEuler.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590388&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590194&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/A-Tune", + }, + { + NAME: "sig-KIRAN-DESKTOP", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=37&name=sig-KIRAN-DESKTOP&mail=dev%40openeuler.org", + INTRODUCE: + "Provides a more appealing, efficient, and easy-to-use Linux desktop environment, developed by Kylinsec.", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590528&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-KIRAN-DESKTOP", + }, + { + NAME: "sig-ops", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=83&name=sig-ops", + INTRODUCE: + "Ports and develops O&M tools to improve the O&M capabilities of openEuler.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590388&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590323&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-ops", + }, + { + NAME: "Cloud Native", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=85&name=sig-CloudNative", + INTRODUCE: + "Provides convenient and easy-to-use cloud-native infrastructure, and a simple and efficient cloud-native application development and hosting environment, for the purpose of building a cloud-native ecosystem.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590352&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: + "https://gitee.com/openeuler/community/tree/master/sig/sig-CloudNative", + }, + { + NAME: "G11N", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=98&name=G11N", + INTRODUCE: "Dedicated to openEuler internationalization and localization.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590388&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/G11N", + }, + { + NAME: "sig-UKUI", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=46&name=sig-UKUI", + INTRODUCE: "Provides the UKUI desktop environment on openEuler, and plans, maintains, and upgrades related software packages.", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590230&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-UKUI", + }, + { + NAME: "sig-OSCourse", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OSCourse", + INTRODUCE: "Delivers OS-related courses.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590352&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=141433910&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-OSCourse", + }, + { + NAME: "sig-DDE", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-DDE", + INTRODUCE: "Provides an elegant, easy-to-use, and simple desktop environment developed by deepin.", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590403&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-DDE", + }, + { + NAME: "Infrastructure", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=Infrastructure", + INTRODUCE: "Develops and maintains the infrastructure features of openEuler.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=124590142&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/Infrastructure", + }, + { + NAME: "sig-OS-Builder", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OS-Builder", + INTRODUCE: "Maintains the openEuler service software packages, provides more convenient ISO image building solutions, and provides better installation and upgrade solutions.", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=145511845&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-OS-Builder", + }, + { + NAME: "sig-CICD", + NAME_LINK: + "https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=95&name=sig-OS-Builder", + INTRODUCE: "Provides developers with a test system featuring test, login, assistant fault demarcation, and historical data-based analysis services for upstream open source software.", + TASK: "https://gitee.com/organizations/openeuler/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=124590412&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=&project_type=&scope=&single_label_id=146173410&single_label_text=&sort=&state=open&target_project&skip_mobile=true", + GITEE: "https://gitee.com/openeuler/community/tree/master/sig/sig-CICD", + }, + { + NAME: "Other", + INTRODUCE: "Lists tasks that do not belong to any SIG, such as tasks related to Rust and storage.", + TASK: "https://gitee.com/openeuler-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=125884711&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openeuler-competition%2Fopensource-internship&project_type=&scope=&sort=&state=open&target_project&skip_mobile=true", + }, + { + INTRODUCE: "More SIG tasks are coming soon", + }, + ], + LOOKENG_TASK_ITEM: [ + { + NAME_LINK: + "https://openlookeng.io", + NAME: "openLooKeng", + INTRODUCE: "A powerful and easy-to-use data virtualization engine, simplifying big data application.", + TASK: "https://gitee.com/openlookeng-competition/opensource-internship/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openlookeng-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=newest&state=open&target_project&skip_mobile=true", + GITEE: "https://openlookeng.io", + }, + ], + OPENGAUSS_TASK_ITEM: [ + { + NAME_LINK: + "https://opengauss.org/", + NAME: "openGauss", + INTRODUCE: "一款高性能、高安全、高可靠的企业级开源关系型数据库", + TASK: "https://gitee.com/opengauss/opensource-intership/issues?assignee_id=&author_id=&branch=&collaborator_ids=&issue_search=&label_ids=&label_text=&milestone_id=&priority=&private_issue=&program_id=&project_id=openlookeng-competition%2Fopensource-internship&project_type=&scope=&single_label_id=&single_label_text=&sort=newest&state=open&target_project&skip_mobile=true", + GITEE: "https://opengauss.org/", + }, + ], + INTERNSHIP_TASK: "View Internship Tasks", + SIG_DETAIL: "View SIG Details", + }, + INTEGRAL: { + TITLE:"/img/internship/integral-title.png", + REWARD: { + HEAD: "Bonus Points and Rewards", + TEXT: [ + "If you have earned more than 20 bonus points during the 6-month internship, you can obtain differing amounts of salary based on your bonus points.", + "If you accumulate 150 or more bonus points within one year, you will be awarded the Open Source Star title for college contributors by the openEuler community.", + ], + }, + HONOR: { + HEAD: "Honorary rights and interests of the Open Source Star:", + TEXT: [ + "Obtain the Open Source Star badge issued by the openEuler community.", + "Extended showcase on the openEuler official website as a college contributor, and PR reports issued by the official community channel.", + "Invitation to the annual openEuler summit (transportation and accommodation included).", + ], + }, + }, + RULE: { + TITLE:"/img/internship/rule-title.png", + RULE_DATA: [ + { + QUESTION: "1. Who Is Eligible to Apply for the openEuler Internship?", + ANSWER: + "The openEuler internship is intended for full- and part-time college/university students aged 18 or above. There are no restrictions based on majors or grades. Students who are interested in the internship project are welcome to apply for the internship.", + }, + { + QUESTION: "2. How Is the Six Month Validity Period for the Internship Calculated?", + ANSWER: + "When applying for the internship, you'll need to sign an internship contract. The validity period of six months states on the date specified in the contract. If you do not earn 60 bonus points within the six-month period, you will not be able to obtain the internship certificate. You can set aside time for the internship based on your needs, and end the internship in advance whenever you would like, and in accordance with requirements.", + }, + { + QUESTION: "3. Can I Continue to Claim Tasks After This Six Months Has Elapsed, or After Having Earned 100 Bonus Points?", + ANSWER: + "Yes, you can. However, the extra bonus points will not be used to calculate salary, or for the purpose of obtaining additional internship certificates. If you accumulate 150 bonus points within one year, you will be awarded the Open Source Star title for college contributors by the openEuler community. ", + }, + ], + MORE: ["If you have other questions, feel free to contact us."], + }, + OFFICAL_WEB: '官网详情', + RANK: { + FIRST: "First", + SECOND: "Second", + THIRD: "Third", + SCORE: "Bonus Point", + VIEW_ALL: "Expand", + PACK_UP: "Collapse", + }, + PARTNER_TITLE:"/img/internship/partner-title.png", + PARTNER_DATA: [ + { + IMG: "/img/internship/iscas.png", + LINK: "", + }, + { + IMG: "/img/internship/qilinsoft.png", + LINK: "", + }, + { + IMG: "/img/internship/tongxin.png", + LINK: "", + }, + { + IMG: "/img/internship/kylinsec.png", + LINK: "", + }, + { + IMG: "/img/internship/mindSpore.png", + LINK: "", + }, + { + IMG: "/img/internship/openEuler.png", + LINK: "", + }, + { + IMG: "/img/internship/openGauss.png", + LINK: "", + }, + { + IMG: "/img/internship/openLooKeng.png", + LINK: "", + }, + { + IMG: "/img/internship/gitee.png", + LINK: "", + }, + ], + HELP_TITLE:"/img/internship/help-title.png", + HELP: [ + "Email:", + "intern@openeuler.sh", + "Scan the QR code to join the QQ group for the openEuler internship.", + "QQ group ID: 458603235", + ], + }, + ru: { + MOOC: '慕课', + MOOC_COURSE: [ + { + ID: '1', + IMG: '/img/learn/hcia/hcia.png', + TITLE: 'HCIA-openEuler 认证培训课程', + DESC: '欢迎学习HCIA-openEuler华为认证openEuler工程师在线课程。', + APPLY_LINK: 'https://e.huawei.com/cn/talent/#/cert/product-details?certifiedProductId=383&authenticationLevel=CTYPE_CARE_HCIA&technicalField=PSC&version=1.0 ' + } + ], + BTN_LEARN: '课程学习', + BTN_APPLY: '考试报名', + MOOC_CATALOG: '目录', + COURSE_DOWNLOAD: '课件下载', + TEACHER_TEAM: '讲师团队', + MOOC_LIST_ROUTRE: '慕课', + PREV_TEXT: '上一篇', + NEXT_TEXT: '下一篇', + MOOC_DATA: require('./../../data/learn').ru.COURSE_LIST + } +} diff --git a/web-ui/docs/.vuepress/lang/lang-modules/minisite.js b/web-ui/docs/.vuepress/lang/lang-modules/minisite.js new file mode 100644 index 0000000000000000000000000000000000000000..76cbea8e9eb31700848788458f699848366dfd39 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/minisite.js @@ -0,0 +1,2017 @@ +/** + * @file minisite页面国际化配置入口 + * */ + +module.exports = { + cn: { + MIGRATION_BANNER_TEXT: ["迁移指南"], + MIGRATION_DESC: [ + "随着数字化转型深入,操作系统正在向支持多样性计算、支持全场景的方向发展,在进行操作系统升级时,企业面临以下挑战:硬件兼容性、软件兼容性、升级后系统环境如何快速恢复?升级后如何能够更好发挥系统性能?openEuler 作为一款面向数字基础设施的开源操作系统,最优支持多样性计算,满足服务器、云、边缘和嵌入式全场景。针对企业在升级操作系统时的需求,推出这份升级指南,助力企业简单、平稳、高效进行操作系统升级。", + ], + MIGRATION_SOURCE_DOWNLOAD: { + TITLE: "资源下载", + SOURCES: [ + { + NAME: "oec-hardware", + DESCRIBE: "openEuler硬件兼容性验证测试框架", + DESCRIBE_DETAIL: + "oec-hardware是保证 openEuler 与硬件平台的兼容性,验证仅限于基本功能验证,不包括性能测试等其它测试", + VERSION: "1.0.0", + LINK_TITLE: "软件下载", + DOCUMENT_LINK: + "https://gitee.com/openeuler/oec-hardware/blob/master/README.md", + LINKS: [ + { + NAME: "获取源码", + LINK: "https://gitee.com/openeuler/oec-hardware", + }, + ], + }, + { + NAME: "Compass-CI", + DESCRIBE: "一个可持续集成的开源开放式测试服务平台", + DESCRIBE_DETAIL: + "集构建&测试系统、登录调测、测试分析比较、辅助定位于一体,旨在给社区开发者提供友好的开发体验,与社区开发者一起繁荣开源软件生态及提升开源软件质量。", + VERSION: "1.0.0", + LINK_TITLE: "开始使用", + DOCUMENT_LINK: + "https://gitee.com/openeuler/compass-ci/blob/master/README.zh.md", + LINKS: [ + { + NAME: "获取源码", + LINK: "https://gitee.com/openeuler/compass-ci", + }, + // { + // NAME: "平台使用指导", + // LINK: "https://gitee.com/openeuler/compass-ci/blob/master/README.zh.md", + // }, + ], + }, + { + NAME: "x2openEuler", + DESCRIBE: "从其他系统迁移到openEuler硬件和软件、配置兼容性评估", + DESCRIBE_DETAIL: + "软件评估,支持扫描并分析软件包、源码包,评估软件的兼容性及可移植性。配置评估,支持扫描并收集环境的操作系统配置信息,评估用户操作系统的配置兼容性。硬件评估,支持扫描并分析用户环境硬件信息,评估硬件兼容性。", + VERSION: "2.0.0", + LINK_TITLE: "软件下载", + DOCUMENT_LINK: + "https://docs.openeuler.org/zh/docs/20.03_LTS_SP1/docs/thirdparty_migration/x2openEuleruseguide.html", + LINKS: [ + { + NAME: "软件获取", + LINK: "https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/contrib/x2openEuler/", + }, + ], + }, + { + NAME: "oecp", + DESCRIBE: "操作系统之间的差异比较及兼容性分析工具", + DESCRIBE_DETAIL: + "1.检测2个ISO(基于RPM)的软件包,软件包内文件,库文件接口(C/C++),内核KABI的变化差异,根据这些差异可以分析2个OS之间的兼容性,为软件移植提供了重要参考\n2.OECP还可以检测同一个软件(RPM包)在不同版本下的变化以及差异,判断软件包的文件,接口等变化,可以分析得出软件不同版本之间的兼容性", + VERSION: "1.0.0", + LINK_TITLE: "软件下载", + DOCUMENT_LINK: + "https://toscode.gitee.com/openeuler/oecp/blob/master/README.md", + LINKS: [ + { + ID: 1, + NAME: "获取源码", + LINK: "https://toscode.gitee.com/openeuler/oecp/tree/master", + }, + ], + }, + ], + }, + MIGRATION_LISTCONTENT: [ + { + SUBTITLE: "数字化转型带来的操作系统变化及迁移诉求", + CONTENT: [ + "数字技术日益融入经济社会发展的各个领域和全过程,数字基础设施要面向 IT、CT 及 OT 等多种场景,要实现工业互联乃至万物智联,只有建立起强大的技术软件体系,才能够满足数字经济发展的需要;万物互联驱动多样性算力( CPU/GPU/XPU 等)发展,促使操作系统进行架构创新;同时随着企业产品持续创新、硬件算力的更新换代、操作系统版本生命周期演进,操作系统迁移的工作将成为常态;由于操作系统本身的差异带来软件、硬件、配置兼容性问题,影响了操作系统迁移进程。\n\n", + "面向数字化转型过程中,企业一方面需要做好操作系统选型(如:持续演进、全场景支持、可靠、稳定等),支撑企业持续发展、产品创新、数字化转型;另一方面需要有系统性的迁移方案及工具,保障迁移无忧。", + ], + }, + { + SUBTITLE: "openEuler 面向数字基础设施的开源操作系统", + LISTTITLE: "openEuler 面向数字基础设施的开源操作系统", + CONTENT: [ + "openEuler 开源操作系统是面向数字基础设施的开源操作系统,支持服务器、云计算、边缘计算、嵌入式等应用场景,支持多样性计算,致力于提供安全、稳定、易用的操作系统。", + "2021年11月9日在工信部的指导及产业力量的协同下,openEuler 社区捐赠给开放原子开源基金会,是当前唯一捐赠到开放原子开源基金会的数字基础设施开源操作系统项目。", + "当前国内外 14 家主流 OSV(麒麟、统信、麒麟信安、SUSE、普华等)均已发布了基于 openEuler 的操作系统商业发行版;且发行产品已经广泛进入了政府、运营商、金融、电力等多个行业的核心系统,实现了规模商用 100+万套,成为企业应用持续创新、稳定运行的首选。", + "社区当前已有超过 300+ 企业加入,汇聚了从处理器、整机、基础软件、应用软件、行业客户等全产业链伙伴,100% 兼容主流芯片,100% 支持主流场景,当前已经有近万名开源贡献者,100 多个 SIG 组,社区维护的软件包达到 8000+,是最具活力的开源社区。", + ], + }, + { + LISTTITLE: "openEuler 聚焦内核能力,释放多样性算力,引领操作系统创新", + CONTENT: [ + "openEuler 原生开源,独立演进,从三个层次实现持续发展,助力企业数字化转型。内核创新:在多核调度、多样性算力,以内存为中心新架构的支持等方面进行创新,自 2012 年以来向 Linux Kernel 社区持续贡献,在 Linux Kernel 5.10/5.14 版本中,内核代码贡献排名第一。核心模块:为用户提供“双平面”运行选择,通过原创 StratoVirt 提供类 QEMU 虚拟化能力,通过原创 iSulad 提供类 Docker 容器能力。全功能级:做到独立软件包选型,CVE 漏洞管理,Bug 快速修复 ,主要特性介绍如下:", + "1. 性能最优:通过千核调度、内核热升级、NUMA aware、免锁优化、PB级内存扩展等独特内核创新技术,软硬协同优化,最佳支持多样性算力,性能相比于主流 OS 提升 5%~20%。", + "2. 云原生“双平面”选择:iSula 和 StatioVirt 虚拟化技术及容器技术,提供从云,到边缘的安全、灵活业务部署,编排能力,应对复杂的业务场景。", + "3. 稳定可靠:A-tune 动态智能识別操作系业务场景,匹配场景参数模型,使系统都处在最佳的运行状态,从而提升业务性能。A-ops,从智能定位、配置溯源、架构感知,进行故障定界定位、配置管理、网络拓扑绘制,快速定位问题。", + ], + }, + { + LISTTITLE: "openEuler 产品架构介绍", + CONTENT: [ + "openEuler 创新架构,全栈优化,释放多样性算力,打造全场景协同的数字基础设施操作系统,包括基础加速库、虚拟化、内核、驱动、编译器、OS工具、OpenJDK等组件。\n\n", + "* 应用中间层 - 提供多种类型的中间件,提供数据库、桌面、机密计算等系统软件,支持其上的应用软件共享资源", + "* 运行时及加速库层 - 提供程序运行时库和加速库", + "* 虚拟化及容器层 - 提供虚拟化和容器能力,可以根据用户需求选择使用", + "* 内核层 - 提供多种为应用程序对计算机硬件进行安全访问的软件,负责管理系统的进程、内存、设备驱动程序、文件和网络系统等", + "* 芯片层 - 提供多种类型的驱动,提供硬件设备的访问和管理,支持硬件设备的访问和管理", + "* 工具链 - 提供开源项目中开发使用到的多种效率提升的工具", + ], + FRAMEWORK_IMG: "/img/minisite/migration/framework.png", + }, + ], + MIGRATION_REFERENCE: { + TITLE_OUTSIDE: "迁移文档", + TITLE_INSIDE: "DOCUMENTATION", + MENU_LIST: ["移植案例", "用户案例", "搬迁实施指导"], + LINK_LIST: [ + { + TEXT: "MySQL 5.7.21 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/MySQL%205-7-21-migrate-guide.html", + }, + { + TEXT: "Apache 2.4.39 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Apache%202-4-39-porting-guide.html", + }, + { + TEXT: "Dubbo 2.6.8 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Dubbo%202-6-8-porting-guide.html", + }, + { + TEXT: "Dubbo 2.7.5 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Dubbo%202-7-5-porting-guide.html", + }, + { + TEXT: "HAProxy 1.9.0 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/HAProxy%201-9-0-porting-guide.html", + }, + { + TEXT: "Lighttpd 1.4.53 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Lighttpd%201-4-53-porting-guide.html", + }, + { + TEXT: "Iok 2.1.3 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Iok%202.1.3-porting-guide.html", + }, + { + TEXT: "Memcached 1.5.12 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Memcached%201-5-12-porting-guide%EF%BC%89.html", + }, + { + TEXT: "Nginx 1.14.2 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Nginx%201-14-2-porting-guide.html", + }, + { + TEXT: "Tengine 2.2.2 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Tengine%202.2.2-porting-guide.html", + }, + { + TEXT: "Squid 4.8 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Squid%204.8-porting-guide.html", + }, + { + TEXT: "Varnish 6.2.0 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/Varnish%206-2-0-porting-guide.html", + }, + { + TEXT: "X86硬件兼容性移迁指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/X86%20hardware%20compatibility%20assessment%20migration%20guide.html", + }, + { + TEXT: "flask 1.1.2 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/flask%201-1-2-porting-guide.html", + }, + { + TEXT: "enca1.19 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/enca1-19-porting-guide.html", + }, + { + TEXT: "tornado 4.2.1 移植案例", + LINK: "https://www.openeuler.org/zh/blog/randy1568/tornado%204-2-1-porting-guide.html", + }, + { + TEXT: "pkgship 2.1.0 移植指南", + LINK: "https://www.openeuler.org/zh/blog/randy1568/pkgship%202-1-0-porting-guide.html", + }, + ], + }, + MOVE_CONTENT: { + DESCRIBE: + "为了减少操作系统迁移对业务的感知,浙江移动还在容器云底层增加了麒麟欧拉版操作系统的容器集群,并将应用重新发布至创新操作系统集群,实现应用在双平面的统一构建、统一编排、统一调度和统一运行。同时,浙江移动还集成了欧拉容器引擎iSulad,把容器应用的启动速度相比Docker提升了50%以上。", + IMG: "/img/minisite/migration/move.png", + SUBTITLE: "相关新闻:", + LINK_LIST: [ + "http://www.cnii.com.cn/rmydb/202109/t20210923_311404.html", + "https://www.ithome.com/0/573/057.html", + ], + }, + DIRECT_CONTENT: "https://gitee.com/openeuler/oec-application/issues", + ATUNE_BANNER_TEXT: ["A-Tune", "一款基于AI开发的智能优化引擎"], + ATUNE_BANNER_IMG: "/img/minisite/svirt/mobile-banner.png", + ATUNE_DESC: [ + "A-Tune是一款基于openEuler开发的,自动化、智能化性能调优引擎。它利用人工智能技术,对运行在操作系统上的业务建立精准模型,动态感知业务特征并推理出具体应用,根据业务负载情况动态调节并给出最佳的参数配置组合,从而使业务处于最佳运行状态。", + ], + ATUNE_MAIL: "mail to:a-tune@openeuler.org", + NAV_TEXT: [ + { + key: "#sourceDownload", + name: "资源下载", + }, + { + key: "#framework", + name: "背景", + }, + { + key: "#document", + name: "方案介绍", + children: [ + { name: "迁移面临的关键问题", key: "#h2-title-one" }, + { name: "迁移综合方案概述", key: "#h2-title-two" }, + { name: "OS基础兼容性", key: "#h2-title-three" }, + { name: "兼容性评估", key: "#h2-title-four" }, + { name: "移植适配", key: "#h2-title-five" }, + { name: "搬迁实施", key: "#h2-title-six" }, + { name: "迁移调优", key: "#h2-title-seven" }, + ], + }, + { + key: "#caseGuidance", + name: "案例指导", + }, + ], + ATUNE_LINK: [ + { + IMG: "/img/minisite/atune/zh-start.png", + LINK: "https://gitee.com/openeuler/A-Tune", + SHOW: false, + }, + { + IMG: "/img/minisite/atune/zh-speak.png", + LINK: "mail", + SHOW: true, + }, + { + IMG: "/img/minisite/atune/zh-join.png", + LINK: "https://gitee.com/openeuler/A-Tune-UI", + SHOW: false, + }, + ], + ATUNE_FRAMEWORK: { + TITLE_OUTSIDE: "架构", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "A-Tune主要包括在线时静态调优和离线时动态调优两大核心能力,整体架构包括智能决策、系统画像和交互系统三层。", + "智能决策层:包含感知和决策两个子系统,分别完成对应用的智能感知和对系统的调优决策。", + "系统画像层:主要包括自动特征工程和两层分类模型,自动特征工程用于业务特征的自动选择,两层分类模型用于业务模型的学习和分类。", + "交互系统层:用于各类系统资源的监控和配置,调优策略执行在本层进行。", + "优化模型库:包含10大类20+款应用场景的优化配置", + ], + FRAMEWORK_IMG: "/img/minisite/atune/framework.png", + }, + ATUNE_DOCUMENT: { + TITLE_OUTSIDE: "文档", + TITLE_INSIDE: "DOCUMENTATION", + DOCS_LIST: [ + { + IMG: "/img/minisite/atune/know.png", + TITLE: "认识A-Tune", + DESC: "查看A-Tune的简介、架构。了解其支持特性与业务模型。", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E8%AE%A4%E8%AF%86A-Tune.md", + }, + { + IMG: "/img/minisite/atune/install.png", + TITLE: "安装与部署", + DESC: "了解安装A-Tune的软硬件要求与环境准备,学习安装、部署和启动A-Tune。", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%AE%89%E8%A3%85%E4%B8%8E%E9%83%A8%E7%BD%B2.md", + }, + { + IMG: "/img/minisite/atune/use.png", + TITLE: "使用方法", + DESC: "本章介绍A-Tune客户端包含的功能和使用方法。学习用命令行使用A-Tune。", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95.md", + }, + { + IMG: "/img/minisite/atune/problem.png", + TITLE: "常见问题", + DESC: "点击查看A-Tune常见问题,在这里您可以获取解决方案。", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md", + }, + ], + }, + + ISULA_BANNER_TEXT: ["iSula", "小个头 大能量"], + ISULA_BANNER_IMG: "/img/minisite/isula/mobile-banner.png", + ISULA_LOGO: "/img/minisite/isula/isula-logo.png", + ISULA_DESC_UP: [ + "iSula /'i.zu.la/,华为容器技术方案品牌。其原意是一种非常强大的蚂蚁,学术上称为“子弹蚁”,因为被它咬一口,犹如被子弹打到那般疼痛。iSula是世界上强大的昆虫之一。华为容器技术方案品牌因其“小个头、大能量”的含义而取名。", + ], + ISULA_DESC_DOWN: [ + "目前 iSula 家族提供了如下组件:", + "iSulad:容器引擎,提供容器的全生命周期管理,北向兼容Kubernetes的CRI接口,南向兼容OCI 生态。", + "isula-build:容器镜像构建工具,提供快速构建容器镜像的能力。", + "isula-transform:容器迁移工具,提供Docker容器冷迁移至iSulad的能力。", + ], + ISULA_DESC_IMG: "/img/minisite/isula/zh-desc.png", + ISULA_MAIL: "mail to:isulad@openeuler.org", + ISULA_LINK: [ + { + IMG: "/img/minisite/isula/zh-start.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/iSulad", + SHOW: false, + }, + { + IMG: "/img/minisite/isula/zh-speak.png", + LINK: "mail", + SHOW: true, + }, + ], + ISULA_FRAMEWORK: { + TITLE_OUTSIDE: "架构", + TITLE_INSIDE: "ARCHITECTURE", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: { + DESC_LIST: [ + 'iSulad 是一个新的通用容器引擎,提供统一的架构设计来满足CT和IT领域的不同需求。它具有轻、快、 易、灵的特点,这与子弹蚂蚁"小个头、大能量"的形象不谋而合。', + "iSulad 的特点如下:", + "轻量语言:C/C++,Rust on the way", + "北向接口:提供CRI接口,支持对接Kubernets;同时提供便捷使用的命令行", + "南向接口:支持OCI runtime和镜像规范,支持平滑替换", + "容器形态:支持系统容器、虚机容器等多种容器形态", + "扩展能力:提供插件化架构,可根据用户需要开发定制化插件", + "以上的特点使得 iSulad 可以不受硬件规格和架构的限制,更小的底噪开销也使得它的可应用领域更为广泛。", + ], + FRAMEWORK_TITLE: "iSulad 系统架构如下:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-1.png", + }, + ISULAD_BUILD: { + DESC_LIST: [ + "isula-build 通常运行于构建侧环境,为运行侧环境提供构建好的容器镜像。", + "构建时,isula-build读取Dockerfile作为输入,快速构建符合Docker镜像和OCI镜像规范的容器镜像,最后将镜像分发至同节点的iSulad/docker、本地tar包或远端容器镜像仓库。", + ], + FRAMEWORK_TITLE: "isula-build的架构图如下:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-2.png", + }, + ISULAD_TRANSFORM: { + DESC_LIST: [ + "isula-transform 配合 iSulad 2.0 推出,支持将 Docker 容器引擎管理的容器转换、迁移给 iSulad 引擎进行管理。迁移完成后,就可以通过 iSulad 完成容器的生命周期管理功能。", + ], + FRAMEWORK_IMG: "/img/minisite/isula/isula-3.png", + }, + }, + ISULA_DOCUMENT: { + TITLE_OUTSIDE: "文档", + TITLE_INSIDE: "DOCUMENTATION", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/README.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + DESC: [ + { + TEXT: "架构说明", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/architecture_zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + DESC: [ + { + TEXT: "编译手册", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_zh.md", + }, + { + TEXT: "在risc-v上面", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_riscv.md", + }, + { + TEXT: "与k8s/CNI集成", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/integration.md", + }, + ], + }, + ], + ISULAD_BUILD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/README.zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/use.png", + DESC: [ + { + TEXT: "使用手册", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/doc/manual_zh.md", + }, + ], + }, + ], + ISULAD_TRANSFORM: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-transform/blob/master/README.md", + }, + ], + }, + ], + }, + + SVIRT_BANNER_TEXT: ["StratoVirt", "面向云数据中心的企业级虚拟化VMM"], + SVIRT_BANNER_IMG: "/img/minisite/svirt/mobile-banner.png", + SVIRT_DESC: [ + "StratoVirt是面向云数据中心的企业级虚拟化VMM (Virtual Machine Monitor),实现一套架构对虚拟机、容器、Serverless三种场景的统一支持。在轻量低噪、软硬协同、Rust语言级安全等方面具备关键技术竞争优势。", + "StratoVirt在架构设计上预留了组件化拼装的能力和接口,可以按需灵活组装高级特性直至演化到支持标准虚拟化,在特性需求、应用场景和轻快灵巧之间找到最佳的平衡点。", + ], + SVIRT_IMG: "/img/minisite/svirt/pc-svirt.png", + SVIRT_MB_IMG: "/img/minisite/svirt/mobile-svirt.png", + SVIRT_NAV_TEXT: [ + { + key: "#character", + name: "特征", + }, + { + key: "#framework", + name: "架构", + }, + { + key: "#document", + name: "文档", + }, + ], + + SVIRT_LINK: [ + { + IMG: "/img/minisite/svirt/zh-start.png", + LINK: "https://gitee.com/openeuler/stratovirt", + }, + { + IMG: "/img/minisite/svirt/zh-speak.png", + LINK: "https://gitee.com/openeuler/stratovirt/issues", + }, + { + IMG: "/img/minisite/svirt/zh-join.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/Virt", + }, + ], + SVIRT_CHARACTER: { + TITLE_OUTSIDE: "特征", + TITLE_INSIDE: "FEATURE", + CHARACTER_TEXT: + "StratoVirt是openEuler最稳定、最坚固的保护层。它重构了openEuler虚拟化底座,具有以下六大技术特点。", + CHARACTER_LIST: [ + { + IMG: "/img/minisite/svirt/safety.png", + TITLE: "强安全性", + DESC: "采用Rust语言,支持seccomp,实现多租户安全隔离", + }, + { + IMG: "/img/minisite/svirt/low-noise.png", + TITLE: "轻量低噪", + DESC: "采用极简设备模型时,启动时间<50ms,内存底噪<4M,支持Serverless负载", + }, + { + IMG: "/img/minisite/svirt/flex.png", + TITLE: "极速伸缩", + DESC: "毫秒级设备扩缩能力,为轻量化负载提供灵活的资源伸缩能力", + }, + { + IMG: "/img/minisite/svirt/with.png", + TITLE: "软硬协同", + DESC: "同时支持x86的VT和鲲鹏的Kunpeng-V,实现多体系硬件加速", + }, + { + IMG: "/img/minisite/svirt/extend.png", + TITLE: "高扩展性", + DESC: "设备模型可扩展,支持PCI等复杂设备规范,实现标准虚拟机", + }, + { + IMG: "/img/minisite/svirt/strengthen.png", + TITLE: "异构增强", + DESC: "除支持常用的硬件SR-IOV直通方案,结合昇腾软件定义能力,实现更灵活异构算力分配", + }, + ], + }, + SVIRT_FRAMEWORK: { + TITLE_OUTSIDE: "架构", + TITLE_INSIDE: "ARCHITECTURE", + LEFT_IMG: "/img/minisite/svirt/pc-fwork.png", + RIGHT_TEXT: [ + "StratoVirt核心架构自顶向下分为三层:", + "OCI兼容接口:兼容QMP(QEMU Machine Protocol)协议,具有完备的OCI兼容能力。", + "BootLoader:抛弃传统BIOS+GRUB的启动模式,实现了更轻更快的启动流程。", + "MicroVM:虚拟化层,充分利用软硬协同能力,精简化设备模型;低时延资源伸缩能力。", + ], + }, + SVIRT_DOCUMENT: { + TITLE_OUTSIDE: "文档", + TITLE_INSIDE: "DOCUMENTATION", + LIST: [ + { + ICON: "/img/minisite/svirt/doc-introduct.png", + TEXT: "StratoVirt介绍", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/StratoVirt%E4%BB%8B%E7%BB%8D.md", + }, + { + ICON: "/img/minisite/svirt/doc-install.png", + TEXT: "安装StratoVirt", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AE%89%E8%A3%85StratoVirt.md", + }, + { + ICON: "/img/minisite/svirt/doc-ready.png", + TEXT: "准备使用环境", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%87%86%E5%A4%87%E4%BD%BF%E7%94%A8%E7%8E%AF%E5%A2%83.md", + }, + { + ICON: "/img/minisite/svirt/doc-virtual.png", + TEXT: "虚拟机配置", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%85%8D%E7%BD%AE.md", + }, + { + ICON: "/img/minisite/svirt/doc-source.png", + TEXT: "虚拟机管理", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%AE%A1%E7%90%86.md", + }, + { + ICON: "/img/minisite/svirt/doc-box.png", + TEXT: "对接iSula安全容器", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AF%B9%E6%8E%A5iSula%E5%AE%89%E5%85%A8%E5%AE%B9%E5%99%A8.md", + }, + ], + }, + BISHENG_BANNER_TEXT: ["毕昇JDK", "ARM上最好用的JDK"], + BISHENG_DESC: [ + "毕昇JDK是华为内部基于OpenJDK定制的Huawei JDK的开源版本。Huawei JDK运行在华为内部500多个产品上,研发团队积累了丰富的开发经验,解决了业务实际运行中遇到的多个疑难问题。", + "毕昇JDK作为OpenJDK的下游,是一款高性能、可用于生产环境的OpenJDK发行版。毕昇JDK对华为内部应用场景中遇到的一些性能问题和稳定性问题进行了修复,并在ARM架构上进行了性能优化和稳定性增强,在ARM架构上更稳定,在大数据等场景下可以获得更好的性能。", + "毕昇JDK致力于为JAVA开发者提供一款稳定可靠、高性能、易调测的JDK,也为用户在ARM架构上提供一个更好的选择。", + ], + BISHENG_LINK: [ + { + IMG: "/img/minisite/bisheng/zh-speker.png", + TITLE:'开启毕昇JDK之旅', + LINK_LIST: [ + { + TEXT: "毕昇JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8", + }, + { + TEXT: "毕昇JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11", + }, + { + TEXT: "毕昇JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/zh-sponsor.png", + TITLE:'想对毕昇JDK说', + LINK_LIST: [ + { + TEXT: "毕昇JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/issues", + }, + { + TEXT: "毕昇JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/issues", + }, + { + TEXT: "毕昇JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/issues", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/meeting.png", + TITLE:'Compiler SIG例会信息', + LINK_LIST: [ + { + TEXT: '2021', + LINK: 'https://gitee.com/openeuler/bishengjdk-8/wikis/Compiler%20SIG%E4%BE%8B%E4%BC%9A?sort_id=4182234', + }, + { + TEXT: '2022', + LINK: 'https://etherpad.openeuler.org/p/Compiler-meetings', + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/roadmap.png", + TITLE:'Roadmap', + LINK_LIST: [ + "https://gitee.com/openeuler/bishengjdk-8/wikis/%E9%A1%B9%E7%9B%AE%E8%B7%AF%E6%A0%87?sort_id=4182245", + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/TCK-affidavit.png", + TITLE:'TCK Affidavit of BiSheng JDK 8', + LINK_LIST: [ + "/zh/other/projects/bishengjdk/tck-affidavit/", + ], + STATUS: false, + }, + ], + BISHENG_MORE: "更多信息:", + BISHENG_INFO: [ + { + THEME: "License: ", + BODY: "采用GPLv2 with Classpath Exception协议。", + }, + { + THEME: "支持Java版本: ", + BODY: "目前毕昇JDK支持8、11、17三个LTS版本。", + }, + { + THEME: "支持架构: ", + BODY: "支持Linux/AArch64、Linux/x86_64架构。", + }, + { + THEME: "支持操作系统: ", + BODY: "目前仅支持Linux版本,对操作系统的要求glibc版本不低于2.17,基本覆盖所有主流操作系统,发布前经过稳定性验证的操作系统有openEuler 全系列操作系统和CentOS 7.6", + }, + ], + BISHENG_FRAMEWORK: { + TITLE_OUTSIDE: "架构", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "JDK整体架构如下图所示,其中JRE指的是Java Runtime Environment,包括了Java运行时的虚拟机JVM(Java Virtual Machine)、Libraries等。而JDK是JRE的超集,包括了JRE的所有内容,并包含javac、jdb等开发者必须的编译器和调试器。JRE仅提供运行时库、Java虚拟机和其他一些运行Java应用程序所必须的组件。", + ], + FRAMEWORK_IMG: "/img/minisite/bisheng/framework.png", + }, + BISHENG_LEARN: { + TITLE_OUTSIDE: "学习", + TITLE_INSIDE: "LEARNING", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/compile.png", + THEME: "文档", + LINK: [ + { + TEXT: "毕昇JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/wikis/Home", + }, + { + TEXT: "毕昇JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/wikis/Home", + }, + { + TEXT: "毕昇JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/wikis/Home", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + THEME: "课程", + LINK: [ + { + TEXT: "毕昇JDK使用", + LINK: "https://education.huaweicloud.com/courses/course-v1:HuaweiX+CBUCNXK067+Self-paced/about", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + THEME: "下载", + LINK: [ + { + TEXT: "毕昇JDK历史版本", + LINK: "https://www.hikunpeng.com/zh/developer/devkit/compiler/jdk", + }, + ], + }, + ], + }, + BISHENG_REFERENCE: { + TITLE_OUTSIDE: "友情链接", + TITLE_INSIDE: "LINKS", + LINK_LIST: [ + { + TEXT: "毕昇JDK(鲲鹏社区) ", + LINK: "https://www.hikunpeng.com/developer/devkit/compiler/jdk", + }, + { + TEXT: "毕昇编译器(鲲鹏社区)", + LINK: "https://www.hikunpeng.com/developer/devkit/compiler/bisheng", + }, + { + TEXT: "GCC for openEuler(鲲鹏社区)", + LINK: "https://www.hikunpeng.com/developer/devkit/compiler/gcc", + }, + ], + }, + SECGEAR_BANNER_TEXT: [ + "secGear", + "secGear是一款供开发者开发安全应用的机密计算框架", + ], + SECGEAR_DESC: [ + "secGear是面向计算产业的机密计算安全应用开发套件,旨在方便开发者在不同的硬件设备上提供统一开发框架,让用户不感知底层各种机密计算架构和接口的差异,目前secGear支持Intel SGX硬件和ARM Trustzone(安全os支持iTrustee)。", + "secGear同时在中间件层和服务层提供丰富的扩展能力,让开发者能够方便得调用安全组件,乃至直接使用机密计算安全服务。", + ], + SECGEAR_FRAMEWORK: { + TITLE_OUTSIDE: "架构", + TITLE_INSIDE: "ARCHITECTURE ", + DESC_LIST: [ + "如图所示,secGear 主题包含三个层级(当前仅开源基础层 Base Layer,服务层和中间件层逐步开源):", + "服务层:提供完整的基于机密计算的安全服务,用户直接使用相关服务,享受机密计算带来的安全性。", + "中间件层:提供常见的安全协议组件以及各种安全函数库,用户可以直接在安全及非安全侧调用相关接口,不必从头造轮子,当前构建中的有pkcs11、pake等", + "基础层:提供丰富的 enclave 开发接口或工具,包含代码生成工具和enclave声明周期管理等接口,并且在安全侧支持POSIX APIs 和标准 OpenSSL 接口,用户基于这些接口可以自由开发安全应用程序 。", + ], + FRAMEWORK_IMG: "/img/minisite/secgear/framework.png", + }, + SECGEAR_DOCUMENT: { + TITLE_OUTSIDE: "文档", + TITLE_INSIDE: "DOCUMENTATION", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/readme.png", + LINK: [ + { + TEXT: "整体介绍", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E8%AE%A4%E8%AF%86secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + LINK: [ + { + TEXT: "安装", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%AE%89%E8%A3%85secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + LINK: [ + { + TEXT: "开发指南", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%BC%80%E5%8F%91secGear%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + LINK: [ + { + TEXT: "工具使用文档", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E4%BD%BF%E7%94%A8secGear%E5%B7%A5%E5%85%B7.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/use.png", + LINK: [ + { + TEXT: "API接口文档", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E6%8E%A5%E5%8F%A3%E5%8F%82%E8%80%83.md", + }, + ], + }, + ], + }, + }, + en: { + ATUNE_BANNER_TEXT: ["A-Tune", "AI-based Tuning Engine"], + ATUNE_BANNER_IMG: "/img/minisite/atune/mobile-banner.png", + ATUNE_DESC: [ + "A-Tune is an automatic and intelligent performance tuning engine developed based on openEuler. It adopts AI technologies to ensure the optimal service running. A-Tune builds precise models for services running on the operating system, understands service features dynamically to infer specific applications. And it adjusts the parameters based on service loads to provide the optimal parameter configurations.", + ], + ATUNE_MAIL: "mail to:a-tune@openeuler.org", + NAV_TEXT: [ + { + key: "#framework", + name: "Architecture", + }, + { + key: "#document", + name: "Documentation", + }, + ], + ATUNE_LINK: [ + { + IMG: "/img/minisite/atune/en-start.png", + LINK: "https://gitee.com/openeuler/A-Tune", + SHOW: false, + }, + { + IMG: "/img/minisite/atune/en-speak.png", + LINK: "mail", + SHOW: true, + }, + { + IMG: "/img/minisite/atune/zh-join.png", + LINK: "https://gitee.com/openeuler/A-Tune-UI", + SHOW: false, + }, + ], + ATUNE_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "A-Tune provides two core capabilities: online static tuning and offline dynamic tuning. The overall architecture consists of three layers: intelligent decision-making, system profiling, and interaction system.", + "The intelligent decision-making layer consists of the sensing and decision-making subsystems, which implement intelligent sensing of applications and decision-making of system tuning, respectively.", + "The system profiling layer includes the automatic feature engineering and the two-layer classification model. The automatic feature engineering is used for automatic selection of service features, and the two-layer classification model helps learn and classify service models.", + "The interaction system layer monitors and configures various system resources. The tuning policies are executed at this layer.", + "The tuning model library contains the tuning configurations for 20+ application scenarios of 10 categories.", + ], + FRAMEWORK_IMG: "/img/minisite/atune/framework_en.png", + }, + ATUNE_DOCUMENT: { + TITLE_OUTSIDE: "Documentation", + TITLE_INSIDE: "DOCUMENTATION", + DOCS_LIST: [ + { + IMG: "/img/minisite/atune/know.png", + TITLE: "About A-Tune", + DESC: "Learn about the architecture, supported features, and service models of A-Tune.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E8%AE%A4%E8%AF%86A-Tune.md", + }, + { + IMG: "/img/minisite/atune/install.png", + TITLE: "Installation and Deployment", + DESC: "Discover the hardware and software requirements as well as the environment preparations for installing A-Tune. Learn how to install, deploy, and start A-Tune.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%AE%89%E8%A3%85%E4%B8%8E%E9%83%A8%E7%BD%B2.md", + }, + { + IMG: "/img/minisite/atune/use.png", + TITLE: "How to Use", + DESC: "Find out the functions and usage of the A-Tune client. Learn to use A-Tune from the CLI.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95.md", + }, + { + IMG: "/img/minisite/atune/problem.png", + TITLE: "FAQs", + DESC: "View the A-Tune FAQs.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md", + }, + ], + }, + + ISULA_BANNER_TEXT: ["iSula", "Packs a huge punch in a small size"], + ISULA_BANNER_IMG: "/img/minisite/isula/mobile-banner.png", + ISULA_LOGO: "/img/minisite/isula/isula-logo.png", + ISULA_DESC_UP: [ + "iSula is the brand of Huawei container solution. It derives its name from a species of ant, one of the most powerful insects in the world despite its small size. This combination of ultimate power and minimal size is the perfect description of the iSula container technology solution.", + ], + ISULA_DESC_DOWN: [ + "Currently, the iSula family includes the following components:", + "iSulad: iSulad is the universal container engine that provides full lifecycle management. It is compatible with the Container Runtime Interface (CRI) of Kubernetes in the northbound direction as well as the OCI ecosystem in the southbound direction.", + "isula-build: isula-build is the container image building tool that helps you quickly build container images.", + "isula-transform: isula-transform is the container migration tool that enables the cold migration of Docker containers to iSulad.", + ], + ISULA_DESC_IMG: "/img/minisite/isula/en_desc.png", + ISULA_MAIL: "mail to:isulad@openeuler.org", + ISULA_LINK: [ + { + IMG: "/img/minisite/isula/en-start.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/iSulad", + SHOW: false, + }, + { + IMG: "/img/minisite/isula/en-speak.png", + LINK: "mail", + SHOW: true, + }, + ], + ISULA_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: { + DESC_LIST: [ + "iSulad provides a unified architecture for different CT and IT requirements. It features a lightweight, fast, and flexible design, unlocking great power like the small isula ant.", + "iSulad boasts the following features:", + "Multiple languages: supports C/C++and will support Rust in the future.", + "Northbound interface: provides the CRI that connects to Kubernets, as well as easy-to-use command lines.", + "Southbound interface: supports OCI runtime and image specifications for smooth replacement.", + "Container forms: supports multiple container forms, such as system and VM.", + "Scalability: provides a plug-in architecture that allows you to develop custom plug-ins.", + "iSulad is not restricted by hardware specifications and architectures. It features minimal background noise, making it a perfect option for many fields.", + ], + FRAMEWORK_TITLE: "The architecture of iSulad is as follows:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-1-en.png", + }, + ISULAD_BUILD: { + DESC_LIST: [ + "isula-build usually runs in the build environment and provides template container images for the runtime system.", + "During the build operation, isula-build reads Dockerfile as the input to quickly build container images that comply with the Docker and OCI image specifications. Then, isula-build distributes the images to the iSulad/Docker on the same node, local TAR packages, or remote container image repositories.", + ], + FRAMEWORK_TITLE: "The architecture of isula-build is as follows:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-2.png", + }, + ISULAD_TRANSFORM: { + DESC_LIST: [ + "isula-transform was released together with iSulad 2.0 to convert containers managed by the Docker container engine and migrate them to the iSulad engine. After the migration, iSulad allows you to effortlessly manage the lifecycle of containers.", + ], + FRAMEWORK_IMG: "/img/minisite/isula/isula-3.png", + }, + }, + ISULA_DOCUMENT: { + TITLE_OUTSIDE: "Documentation", + TITLE_INSIDE: "DOCUMENTATION", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/README.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + DESC: [ + { + TEXT: "Architecture", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/architecture_zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + DESC: [ + { + TEXT: "Build Guide", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_zh.md", + }, + { + TEXT: "for RISC-V", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_riscv.md", + }, + { + TEXT: "Integration", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/integration.md", + }, + ], + }, + ], + ISULAD_BUILD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/README.zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/use.png", + DESC: [ + { + TEXT: "Manual", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/doc/manual_zh.md", + }, + ], + }, + ], + ISULAD_TRANSFORM: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-transform/blob/master/README.md", + }, + ], + }, + ], + }, + + SVIRT_BANNER_TEXT: [ + "StratoVirt", + "Virtualization platform for cloud data centers", + ], + SVIRT_BANNER_IMG: "/img/minisite/svirt/mobile-banner.png", + SVIRT_DESC: [ + "StratoVirt is an enterprise-grade virtualization cloud platform that uses a single architecture to support VM, containers, and serverless data center scenarios. StratoVirt has competitive advantages in key technologies such as lightweight and low noise, software and hardware collaboration, as well as premium security using Rust language.", + "StratoVirt reserves component-based assembling capabilities and interfaces in the architecture design, that is, premium features can be flexibly assembled and evolve to support standard virtualization. In this way, StratoVirt strikes a perfect balance between feature requirements, application scenarios, and flexibility.", + ], + SVIRT_IMG: "/img/minisite/svirt/pc-svirt.png", + SVIRT_MB_IMG: "/img/minisite/svirt/mobile-svirt.png", + SVIRT_NAV_TEXT: [ + { + key: "#character", + name: "Feature", + }, + { + key: "#framework", + name: "Architecture", + }, + { + key: "#document", + name: "Documentation", + }, + ], + SVIRT_LINK: [ + { + IMG: "/img/minisite/svirt/en-start.png", + LINK: "https://gitee.com/openeuler/stratovirt", + }, + { + IMG: "/img/minisite/svirt/en-speak.png", + LINK: "https://gitee.com/openeuler/stratovirt/issues", + }, + { + IMG: "/img/minisite/svirt/en-join.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/Virt", + }, + ], + SVIRT_CHARACTER: { + TITLE_OUTSIDE: "Feature", + TITLE_INSIDE: "FEATURE", + CHARACTER_TEXT: + "StratoVirt is a stable protective layer of openEuler. It reconstructs the openEuler virtualization base and has the following technical features:", + CHARACTER_LIST: [ + { + IMG: "/img/minisite/svirt/safety.png", + TITLE: "Enhanced Security", + DESC: "StratoVirt uses the Rust language and supports seccomp to implement security isolation between multiple tenants.", + }, + { + IMG: "/img/minisite/svirt/low-noise.png", + TITLE: "Lightweight and Low Noise", + DESC: "The simplified device model offers a startup time of under 50 ms, and a memory noise floor less than 4 MB. Serverless load is supported.", + }, + { + IMG: "/img/minisite/svirt/flex.png", + TITLE: "Fast Scaling", + DESC: "StratoVirt supports device scaling within milliseconds, providing flexible resource scaling capabilities for lightweight loads.", + }, + { + IMG: "/img/minisite/svirt/with.png", + TITLE: "Software and Hardware Collaboration", + DESC: "StratoVirt supports x86 VT and Kunpeng-V to implement multi-system hardware acceleration.", + }, + { + IMG: "/img/minisite/svirt/extend.png", + TITLE: "High Scalability", + DESC: "The device model can be extended to support complex device specifications such as PCI and implement standard VMs.", + }, + { + IMG: "/img/minisite/svirt/strengthen.png", + TITLE: "Enhanced Heterogeneity", + DESC: "In addition to the common hardware SR-IOV passthrough solution, the Ascend software definition capability is used to implement more flexible allocation of heterogeneous computing power.", + }, + ], + }, + SVIRT_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE", + LEFT_IMG: "/img/minisite/svirt/pc-fwork.png", + RIGHT_TEXT: [ + "The StratoVirt core architecture comprises three layers from top to bottom:", + "OCI compatibility interface: StratoVirt is compatible with the QEMU Machine Protocol (QMP) and inherits OCI capabilities.", + "BootLoader: StratoVirt abandons the conventional BIOS + GRUB boot mode and implements a lighter and faster boot operation.", + "MicroVM: This is the virtualization layer that leverages software and hardware collaboration to simplify the device management and support low-latency resource scaling.", + ], + }, + SVIRT_DOCUMENT: { + TITLE_OUTSIDE: "Documentation", + TITLE_INSIDE: "DOCUMENTATION", + LIST: [ + { + ICON: "/img/minisite/svirt/doc-introduct.png", + TEXT: "Introduction to StratoVirt", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/StratoVirt%E4%BB%8B%E7%BB%8D.md", + }, + { + ICON: "/img/minisite/svirt/doc-install.png", + TEXT: "Installing StratoVirt", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AE%89%E8%A3%85StratoVirt.md", + }, + { + ICON: "/img/minisite/svirt/doc-ready.png", + TEXT: "Preparing the Environment", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%87%86%E5%A4%87%E4%BD%BF%E7%94%A8%E7%8E%AF%E5%A2%83.md", + }, + { + ICON: "/img/minisite/svirt/doc-virtual.png", + TEXT: "Configuring VMs", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%85%8D%E7%BD%AE.md", + }, + { + ICON: "/img/minisite/svirt/doc-source.png", + TEXT: "Managing VM Lifecycle", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%AE%A1%E7%90%86.md", + }, + { + ICON: "/img/minisite/svirt/doc-box.png", + TEXT: "Connecting to iSula Security Containers", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AF%B9%E6%8E%A5iSula%E5%AE%89%E5%85%A8%E5%AE%B9%E5%99%A8.md", + }, + ], + }, + BISHENG_BANNER_TEXT: ["BiSheng JDK", "Top-notch JDK on ARM"], + BISHENG_DESC: [ + "BiSheng JDK is an open source version of Huawei JDK customized based on OpenJDK. Huawei JDK runs on more than 500 Huawei products. The R&D team has accumulated rich development experience and resolved the problems that arose during service running.", + "As a downstream product of OpenJDK, BiSheng JDK is a high-performance OpenJDK distribution that can be used in production environments. BiSheng JDK fixes some performance and stability issues encountered in Huawei internal applications, optimizes performance and enhances stability on the ARM architecture, and delivers improved performance in big data scenarios.", + "BiSheng JDK is committed to providing Java developers with a stable, reliable, high-performance, and easy-to-debug JDK. It is also a better choice on the ARM architecture. ", + ], + BISHENG_LINK: [ + { + IMG: "/img/minisite/bisheng/zh-speker.png", + TITLE:'Start with BiSheng JDK', + LINK_LIST: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/zh-sponsor.png", + TITLE:'Word to BiSheng JDK', + LINK_LIST: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/issues", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/issues", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/issues", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/meeting.png", + TITLE:'Compiler SIG Meetings', + LINK_LIST: [ + { + TEXT: '2021', + LINK: 'https://gitee.com/openeuler/bishengjdk-8/wikis/Compiler%20SIG%E4%BE%8B%E4%BC%9A?sort_id=4182234', + }, + { + TEXT: '2022', + LINK: 'https://etherpad.openeuler.org/p/Compiler-meetings', + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/roadmap.png", + TITLE:'Roadmap', + LINK_LIST: [ + "https://gitee.com/openeuler/bishengjdk-8/wikis/%E9%A1%B9%E7%9B%AE%E8%B7%AF%E6%A0%87?sort_id=4182245", + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/TCK-affidavit.png", + TITLE:'TCK Affidavit of BiSheng JDK 8', + LINK_LIST: [ + "/en/other/projects/bishengjdk/tck-affidavit/", + ], + STATUS: false, + }, + ], + BISHENG_MORE: "More information:", + BISHENG_INFO: [ + { + THEME: "License: ", + BODY: "The GPLv2 with Classpath Exception protocol is used.", + }, + { + THEME: "Supported Java versions: ", + BODY: "Currently, BiSheng JDK supports Java 8 (LTS), 11 (LTS), and 17 (LTS).", + }, + { + THEME: "Supported architectures:", + BODY: "Linux/AArch64 and Linux/x86_64.", + }, + { + THEME: "Supported OSs: ", + BODY: " Almost all mainstream Linux OSs are supported. The glibc version must be 2.17 or later. BiSheng JDK has passed the stability verification on all openEuler OSs and CentOS 7.6 before the release.", + }, + ], + BISHENG_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "The following figure shows the overall architecture of the JDK. JRE is short for Java Runtime Environment, including the Java Virtual Machine (JVM) and libraries. JDK is a superset of JRE, and therefore includes all JRE content as well as the compilers and debuggers such as javac and JDB required by developers. JRE provides only runtime libraries, JVMs, and other components required to run Java applications.", + ], + FRAMEWORK_IMG: "/img/minisite/bisheng/jiagoutu.png", + }, + BISHENG_LEARN: { + TITLE_OUTSIDE: "Learning", + TITLE_INSIDE: "LEARNING", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/compile.png", + THEME: "Documentation", + LINK: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/wikis/Home", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/wikis/Home", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/wikis/Home", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + THEME: "Learn and Practice", + LINK: [ + { + TEXT: "Using BiSheng JDK", + LINK: "https://education.huaweicloud.com/courses/course-v1:HuaweiX+CBUCNXK067+Self-paced/about", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + THEME: "Download", + LINK: [ + { + TEXT: "Earlier Versions", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/jdk", + }, + ], + }, + ], + }, + BISHENG_REFERENCE: { + TITLE_OUTSIDE: "Links", + TITLE_INSIDE: "LINKS", + LINK_LIST: [ + { + TEXT: "BiSheng JDK (Kunpeng Community) ", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/jdk", + }, + { + TEXT: "BiSheng Compiler (Kunpeng Community)", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/bisheng", + }, + { + TEXT: "GCC for openEuler (Kunpeng Community)", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/gcc", + }, + ], + }, + SECGEAR_BANNER_TEXT: [ + "secGear", + "Confidential computing framework for developing secure applications", + ], + SECGEAR_DESC: [ + "secGear is a confidential computing development suite used to develop secure applications in the computing industry. It aims to provide a unified development framework for different hardware devices, shielding the differences between underlying confidential computing architectures and APIs. Currently, secGear supports Intel® SGX hardware and Arm TrustZone (iTrustee supported).", + "secGear provides rich extensibility capabilities at both the middleware layer and service layer, allowing developers to easily call security components and even directly use the confidential computing services.", + ], + SECGEAR_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE ", + DESC_LIST: [ + "As shown in the figure, secGear consists of three layers. Currently, only the base layer is open source. The service layer and middleware layer will be gradually brought to open source.", + "The service layer provides complete security services based on confidential computing. You can directly use related services to enjoy the security brought by confidential computing.", + "The middleware layer provides common security protocol components and various security function libraries. You can directly call related APIs on the secure and non-secure sides without creating them by yourself. Currently, PKCS11 and PAKE are being built.", + "The base layer provides rich enclave development APIs or tools, including code generation tools and enclave life cycle management APIs. POSIX APIs and standard OpenSSL APIs are supported on the secure side. You can develop secure applications based on these APIs.", + ], + FRAMEWORK_IMG: "/img/minisite/secgear/framework.png", + }, + SECGEAR_DOCUMENT: { + TITLE_OUTSIDE: "Documentation", + TITLE_INSIDE: "DOCUMENTATION", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/readme.png", + LINK: [ + { + TEXT: "Overview", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E8%AE%A4%E8%AF%86secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + LINK: [ + { + TEXT: "Installation", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%AE%89%E8%A3%85secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + LINK: [ + { + TEXT: "Developer Guide", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%BC%80%E5%8F%91secGear%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + LINK: [ + { + TEXT: "Tool Usage", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E4%BD%BF%E7%94%A8secGear%E5%B7%A5%E5%85%B7.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/use.png", + LINK: [ + { + TEXT: "API Reference", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E6%8E%A5%E5%8F%A3%E5%8F%82%E8%80%83.md", + }, + ], + }, + ], + }, + }, + ru: { + ATUNE_BANNER_TEXT: ["A-Tune", "инструмент настройки на базе ИИ"], + ATUNE_BANNER_IMG: "/img/minisite/atune/mobile-banner.png", + ATUNE_DESC: [ + "A-Tune — это автоматический интеллектуальный инструмент настройки рабочих параметров, разработанный сообществом openEuler. За счет использования технологий искусственного интеллекта инструмент обеспечивает оптимальную работу служб. A-Tune создает точные модели работающих в операционной системе служб, динамически отслеживает изменения их показателей и делает логические выводы о состоянии работы конкретных приложений. Настраивая параметры на основе данных о сервисной нагрузке, инструмент позволяет добиться их оптимальной конфигурации.", + ], + ATUNE_MAIL: "mail to:a-tune@openeuler.org", + NAV_TEXT: [ + { + key: "#framework", + name: "Архитектура", + }, + { + key: "#document", + name: "Документы", + }, + ], + ATUNE_LINK: [ + { + IMG: "/img/minisite/atune/ru-start.png", + LINK: "https://gitee.com/openeuler/A-Tune", + SHOW: false, + }, + { + IMG: "/img/minisite/atune/ru-speak.png", + LINK: "mail", + SHOW: true, + }, + { + IMG: "/img/minisite/atune/zh-join.png", + LINK: "https://gitee.com/openeuler/A-Tune-UI", + SHOW: false, + }, + ], + ATUNE_FRAMEWORK: { + TITLE_OUTSIDE: "Архитектура", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "A-Tune предоставляет два основных функционала: статическая онлайн-настройка и динамическая офлайн-настройка. Общая архитектура состоит из трех уровней: уровень интеллектуального принятия решений, уровень построения профиля системы и уровень системы взаимодействия.", + "Уровень интеллектуального принятия решений состоит из подсистемы измерений, выполняющей функции интеллектуального измерения рабочих показателей приложений, и подсистемы принятия решений, которая принимает решения по оптимизации работы системы.", + "Уровень построения профиля системы состоит из модуля автоматической компоновки функций и двухуровневой модели классификации. Модуль автоматической компоновки функций служит для автоматического выбора сервисных функций, а двухуровневая модель классификации используется для обучения и классификации сервисных моделей.", + "На уровне системы взаимодействия осуществляется контроль и настройка различных системных ресурсов. На этом уровне применяются политики настройки.", + "Библиотека моделей настройки содержит конфигурации для настройки приложений 10 категорий в более чем 20 сценариях.", + ], + FRAMEWORK_IMG: "/img/minisite/atune/framework_ru.png", + }, + ATUNE_DOCUMENT: { + TITLE_OUTSIDE: "Документы", + TITLE_INSIDE: "DOCUMENTATION", + DOCS_LIST: [ + { + IMG: "/img/minisite/atune/know.png", + TITLE: "Об инструменте A-Tune", + DESC: "Learn about the architecture, supported features, and service models of A-Tune.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E8%AE%A4%E8%AF%86A-Tune.md", + }, + { + IMG: "/img/minisite/atune/install.png", + TITLE: "Установка и развертывание", + DESC: "Discover the hardware and software requirements as well as the environment preparations for installing A-Tune. Learn how to install, deploy, and start A-Tune.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%AE%89%E8%A3%85%E4%B8%8E%E9%83%A8%E7%BD%B2.md", + }, + { + IMG: "/img/minisite/atune/use.png", + TITLE: "Использование инструмента", + DESC: "Find out the functions and usage of the A-Tune client. Learn to use A-Tune from the CLI.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95.md", + }, + { + IMG: "/img/minisite/atune/problem.png", + TITLE: "Вопросы и ответы", + DESC: "View the A-Tune FAQs.", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/A-Tune/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md", + }, + ], + }, + + ISULA_BANNER_TEXT: ["iSula", "Ударная сила в компактном размере"], + ISULA_BANNER_IMG: "/img/minisite/isula/mobile-banner.png", + ISULA_LOGO: "/img/minisite/isula/isula-logo.png", + ISULA_DESC_UP: [ + "iSula — это контейнерное решение компании Huawei. Название решения происходит от вида муравьев, обитающих в джунглях Перу, — легких, быстрых и живучих. Сочетание невероятной мощности и компактного размера — самое точная характеристика контейнерного решения iSula.", + ], + ISULA_DESC_DOWN: [ + "На сегодняшний день в семейство iSula входят следующие компоненты:", + "iSulad: Это универсальный контейнерный движок, который обеспечивает полное управление жизненным циклом. Он совместим с интерфейсом Container Runtime Interface (CRI) от Kubernetes на северной стороне и экосистемой OCI на южной стороне.", + "isula-build: Это инструмент, помогающий быстро создавать образы контейнера.", + "isula-transform: Инструмент, позволяющий осуществлять холодную миграцию контейнеров Docker в iSulad.", + ], + ISULA_DESC_IMG: "/img/minisite/isula/ru-desc.png", + ISULA_MAIL: "mail to:isulad@openeuler.org", + ISULA_LINK: [ + { + IMG: "/img/minisite/isula/ru-start.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/iSulad", + SHOW: false, + }, + { + IMG: "/img/minisite/isula/ru-speak.png", + LINK: "mail", + SHOW: true, + }, + ], + ISULA_FRAMEWORK: { + TITLE_OUTSIDE: "Архитектура", + TITLE_INSIDE: "ARCHITECTURE", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: { + DESC_LIST: [ + "iSulad предоставляет унифицированную архитектуру, адаптируемую под различные вычислительные и ИТ-ресурсы. Этот быстродействующий инструмент с легкой и гибкой структурой, который можно сравнить с крошечными, но сильными перуанскими муравьями семейства isula.", + "iSulad обладает следующими особенностями:", + "Поддерживает языки программирования C/C++ и в дальнейшем ожидается поддержка языка Rust.", + "Северный интерфейс CRI исполняемой среды контейнера для интеграции с Kubernetes, а также удобные в использовании командные строки.", + "Южный интерфейс OCI и спецификации образов для легкой замены.", + "Поддерживает несколько форматов контейнеров — система и виртуальная машина.", + "В плане масштабируемости инструмент предоставляет архитектуру подключаемых модулей, которая позволяет разрабатывать специализированные плагины.", + "Функциональность iSulad не ограничивается спецификациями оборудования и архитектурами. Решение отличается минимальным влиянием со стороны фоновых процессов, что делает его идеальным вариантом применения во многих областях.", + ], + FRAMEWORK_TITLE: "Архитектура iSulad:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-1-ru.png", + }, + ISULAD_BUILD: { + DESC_LIST: [ + "Isula-build обычно работает в среде сборки и предоставляет шаблонные образы контейнера для исполняющей среды.", + "Во время сборки isula-build считывает данные из файла Docker, используя их в качестве входных данных для быстрого создания образов контейнера, соответствующих спецификациям Docker и OCI. Далее isula-build передает образ в iSulad/Docker на том же узле, в локальные пакеты TAR или удаленные репозитории на хранение.", + ], + FRAMEWORK_TITLE: "Архитектура isula-build:", + FRAMEWORK_IMG: "/img/minisite/isula/isula-2-ru.png", + }, + ISULAD_TRANSFORM: { + DESC_LIST: [ + "isula-transform, выпущенный вместе с версией iSulad 2.0, служит для конвертации контейнеров, управляемых контейнерным движком Docker, и миграции их в движок iSulad. После миграции пользователи легко управляют жизненным циклом контейнеров, используя iSulad.", + ], + FRAMEWORK_IMG: "/img/minisite/isula/isula-3-ru.png", + }, + }, + ISULA_DOCUMENT: { + TITLE_OUTSIDE: "Документы", + TITLE_INSIDE: "DOCUMENTATION", + TAB: [ + { + KEY: "ISULAD", + VALUE: "iSulad", + }, + { + KEY: "ISULAD_BUILD", + VALUE: "isula-build", + }, + { + KEY: "ISULAD_TRANSFORM", + VALUE: "isula-transform", + }, + ], + ISULAD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/README.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + DESC: [ + { + TEXT: "Architecture ", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/architecture_zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + DESC: [ + { + TEXT: "Build Guide", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_zh.md", + }, + { + TEXT: "for RISC-V", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide_riscv.md", + }, + { + TEXT: "Integration", + LINK: "https://gitee.com/openeuler/iSulad/blob/master/docs/integration.md", + }, + ], + }, + ], + ISULAD_BUILD: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/README.zh.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/use.png", + DESC: [ + { + TEXT: "Manual", + LINK: "https://gitee.com/openeuler/isula-build/blob/master/doc/manual_zh.md", + }, + ], + }, + ], + ISULAD_TRANSFORM: [ + { + IMG: "/img/minisite/isula/readme.png", + DESC: [ + { + TEXT: "README", + LINK: "https://gitee.com/openeuler/isula-transform/blob/master/README.md", + }, + ], + }, + ], + }, + + SVIRT_BANNER_TEXT: [ + "StratoVirt", + "Платформа виртуализации для облачных центров обработки данных", + ], + SVIRT_BANNER_IMG: "/img/minisite/svirt/mobile-banner.png", + SVIRT_DESC: [ + "StratoVirt — это облачная платформа виртуализации корпоративного класса, на единой архитектуре которой поддерживаются виртуальные машины, контейнеры и центры обработки данных, работающие без сервера. StratoVirt обладает конкурентными преимуществами: облегченное решение с низким уровнем помех, взаимодействие программного и аппаратного обеспечения, а также безопасность премиум-уровня за счет использования языка программирования Rust.", + "StratoVirt предоставляет функционалы высокого класса для гибкой компонентной сборки и интерфейсы, необходимые в проектировании архитектуры и поддержки стандартной виртуализации. StratoVirt позволяет добиться идеального баланса между функциональными требованиями, сценариями применения и гибкостью.", + ], + SVIRT_IMG: "/img/minisite/svirt/pc-svirt.png", + SVIRT_MB_IMG: "/img/minisite/svirt/mobile-svirt.png", + SVIRT_NAV_TEXT: [ + { + key: "#character", + name: "Особенности", + }, + { + key: "#framework", + name: "Архитектура", + }, + { + key: "#document", + name: "Документы", + }, + ], + SVIRT_LINK: [ + { + IMG: "/img/minisite/svirt/ru-start.png", + LINK: "https://gitee.com/openeuler/stratovirt", + }, + { + IMG: "/img/minisite/svirt/ru-speak.png", + LINK: "https://gitee.com/openeuler/stratovirt/issues", + }, + { + IMG: "/img/minisite/svirt/ru-join.png", + LINK: "https://gitee.com/openeuler/community/tree/master/sig/Virt", + }, + ], + SVIRT_CHARACTER: { + TITLE_OUTSIDE: "Особенности", + TITLE_INSIDE: "FEATURE", + CHARACTER_TEXT: + "StratoVirt является стабильно функционирующим защищенным уровнем openEuler. Он воссоздает базу виртуализации openEuler и обладает следующими техническими особенностями:", + CHARACTER_LIST: [ + { + IMG: "/img/minisite/svirt/safety.png", + TITLE: "Улучшенная безопасность", + DESC: "В решении StratoVirt используется язык Rust и поддерживаются функции seccomp для изоляции клиентов-арендаторов.", + }, + { + IMG: "/img/minisite/svirt/low-noise.png", + TITLE: "Облегченное решение с низким уровнем помех", + DESC: "Запуск устройства упрощенной модели в течение 50 мс и показатель Noise Floor памяти менее 4 МБ. Поддерживается безсерверная нагрузка.", + }, + { + IMG: "/img/minisite/svirt/flex.png", + TITLE: "Быстрое масштабирование", + DESC: "StratoVirt поддерживает масштабирование устройства за считанные миллисекунды, гибкие возможности расширения ресурсов для легких нагрузок.", + }, + { + IMG: "/img/minisite/svirt/with.png", + TITLE: "Взаимодействие программного и аппаратного обеспечения", + DESC: "Аппаратное ускорение на базе мультисистемной платформы за счет поддержки x86 VT и Kunpeng-V.", + }, + { + IMG: "/img/minisite/svirt/extend.png", + TITLE: "Высокая степень масштабируемости", + DESC: "Модель устройства можно расширить для поддержки таких сложных спецификаций, как PCI, и реализации стандартных виртуальных машин.", + }, + { + IMG: "/img/minisite/svirt/strengthen.png", + TITLE: "Улучшенное распределение гетерогенных ресурсов", + DESC: "Помимо общего решения аппаратного сквозного доступа SR-IOV, используется функционал определения программного обеспечения Ascend, который позволяет гибче распределять гетерогенные вычислительные ресурсы.", + }, + ], + }, + SVIRT_FRAMEWORK: { + TITLE_OUTSIDE: "Архитектура", + TITLE_INSIDE: "ARCHITECTURE", + LEFT_IMG: "/img/minisite/svirt/pc-fwork-ru.png", + RIGHT_TEXT: [ + "Базовая архитектура StratoVirt делится на три уровня (сверху вниз):", + "Интерфейс OCI для обеспечения совместимости: StratoVirt полностью совместим с протоколом QEMU Machine Protocol и наследует функции OCI.", + "BootLoader: StratoVirt реализует упрощенную и ускоренную загрузку вместо традиционного способа загрузки BIOS+GRUB.", + "MicroVM: уровень виртуализации, который упрощает управление устройствами и поддерживает масштабирование ресурсов с низкой задержкой за счет взаимодействия программного и аппаратного обеспечения.", + ], + }, + SVIRT_DOCUMENT: { + TITLE_OUTSIDE: "Документы", + TITLE_INSIDE: "DOCUMENTATION", + LIST: [ + { + ICON: "/img/minisite/svirt/doc-introduct.png", + TEXT: "Основы StratoVirt", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/StratoVirt%E4%BB%8B%E7%BB%8D.md", + }, + { + ICON: "/img/minisite/svirt/doc-install.png", + TEXT: "Установка StratoVirt", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AE%89%E8%A3%85StratoVirt.md", + }, + { + ICON: "/img/minisite/svirt/doc-ready.png", + TEXT: "Подготовка среды", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%87%86%E5%A4%87%E4%BD%BF%E7%94%A8%E7%8E%AF%E5%A2%83.md", + }, + { + ICON: "/img/minisite/svirt/doc-virtual.png", + TEXT: "Конфигурирование виртуальных машин", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%85%8D%E7%BD%AE.md", + }, + { + ICON: "/img/minisite/svirt/doc-source.png", + TEXT: "Управление жизненным циклом виртуальной машины", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%AE%A1%E7%90%86.md", + }, + { + ICON: "/img/minisite/svirt/doc-box.png", + TEXT: "Подключение к контейнерам безопасности iSula", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/StratoVirt/%E5%AF%B9%E6%8E%A5iSula%E5%AE%89%E5%85%A8%E5%AE%B9%E5%99%A8.md", + }, + ], + }, + BISHENG_BANNER_TEXT: ["BiSheng JDK", "Top-notch JDK on ARM"], + BISHENG_DESC: [ + "BiSheng JDK is an open source version of Huawei JDK customized based on OpenJDK. Huawei JDK runs on more than 500 Huawei products. The R&D team has accumulated rich development experience and resolved the problems that arose during service running.", + "As a downstream product of OpenJDK, BiSheng JDK is a high-performance OpenJDK distribution that can be used in production environments. BiSheng JDK fixes some performance and stability issues encountered in Huawei internal applications, optimizes performance and enhances stability on the ARM architecture, and delivers improved performance in big data scenarios.", + "BiSheng JDK is committed to providing Java developers with a stable, reliable, high-performance, and easy-to-debug JDK. It is also a better choice on the ARM architecture. ", + ], + BISHENG_LINK: [ + { + IMG: "/img/minisite/bisheng/zh-speker.png", + TITLE:'Start with BiSheng JDK', + LINK_LIST: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/zh-sponsor.png", + TITLE:'Word to BiSheng JDK', + LINK_LIST: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/issues", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/issues", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/issues", + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/meeting.png", + TITLE:'Compiler SIG Meetings', + LINK_LIST: [ + { + TEXT: '2021', + LINK: 'https://gitee.com/openeuler/bishengjdk-8/wikis/Compiler%20SIG%E4%BE%8B%E4%BC%9A?sort_id=4182234', + }, + { + TEXT: '2022', + LINK: 'https://etherpad.openeuler.org/p/Compiler-meetings', + }, + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/roadmap.png", + TITLE:'Roadmap', + LINK_LIST: [ + "https://gitee.com/openeuler/bishengjdk-8/wikis/%E9%A1%B9%E7%9B%AE%E8%B7%AF%E6%A0%87?sort_id=4182245", + ], + STATUS: false, + }, + { + IMG: "/img/minisite/bisheng/TCK-affidavit.png", + TITLE:'TCK Affidavit of BiSheng JDK 8', + LINK_LIST: [ + "/ru/other/projects/bishengjdk/tck-affidavit/", + ], + STATUS: false, + }, + ], + BISHENG_MORE: "More information:", + BISHENG_INFO: [ + { + THEME: "License: ", + BODY: "The GPLv2 with Classpath Exception protocol is used.", + }, + { + THEME: "Supported Java versions: ", + BODY: "Currently, BiSheng JDK supports Java 8 (LTS), 11 (LTS), and 17 (LTS).", + }, + { + THEME: "Supported architectures:", + BODY: "Linux/AArch64 and Linux/x86_64.", + }, + { + THEME: "Supported OSs: ", + BODY: " Almost all mainstream Linux OSs are supported. The glibc version must be 2.17 or later. BiSheng JDK has passed the stability verification on all openEuler OSs and CentOS 7.6 before the release.", + }, + ], + BISHENG_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE", + DESC_LIST: [ + "The following figure shows the overall architecture of the JDK. JRE is short for Java Runtime Environment, including the Java Virtual Machine (JVM) and libraries. JDK is a superset of JRE, and therefore includes all JRE content as well as the compilers and debuggers such as javac and JDB required by developers. JRE provides only runtime libraries, JVMs, and other components required to run Java applications.", + ], + FRAMEWORK_IMG: "/img/minisite/bisheng/jiagoutu.png", + }, + BISHENG_LEARN: { + TITLE_OUTSIDE: "Learning", + TITLE_INSIDE: "LEARNING", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/compile.png", + THEME: "Documentation", + LINK: [ + { + TEXT: "BiSheng JDK 8", + LINK: "https://gitee.com/openeuler/bishengjdk-8/wikis/Home", + }, + { + TEXT: "BiSheng JDK 11", + LINK: "https://gitee.com/openeuler/bishengjdk-11/wikis/Home", + }, + { + TEXT: "BiSheng JDK 17", + LINK: "https://gitee.com/openeuler/bishengjdk-17/wikis/Home", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + THEME: "Learn and Practice", + LINK: [ + { + TEXT: "Using BiSheng JDK", + LINK: "https://education.huaweicloud.com/courses/course-v1:HuaweiX+CBUCNXK067+Self-paced/about", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + THEME: "Download", + LINK: [ + { + TEXT: "Earlier Versions", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/jdk", + }, + ], + }, + ], + }, + BISHENG_REFERENCE: { + TITLE_OUTSIDE: "Links", + TITLE_INSIDE: "LINKS", + LINK_LIST: [ + { + TEXT: "BiSheng JDK (Kunpeng Community) ", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/jdk", + }, + { + TEXT: "BiSheng Compiler (Kunpeng Community)", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/bisheng", + }, + { + TEXT: "GCC for openEuler (Kunpeng Community)", + LINK: "https://www.hikunpeng.com/en/developer/devkit/compiler/gcc", + }, + ], + }, + SECGEAR_BANNER_TEXT: [ + "secGear", + "Confidential computing framework for developing secure applications", + ], + SECGEAR_DESC: [ + "secGear is a confidential computing development suite used to develop secure applications in the computing industry. It aims to provide a unified development framework for different hardware devices, shielding the differences between underlying confidential computing architectures and APIs. Currently, secGear supports Intel® SGX hardware and Arm TrustZone (iTrustee supported).", + "secGear provides rich extensibility capabilities at both the middleware layer and service layer, allowing developers to easily call security components and even directly use the confidential computing services.", + ], + SECGEAR_FRAMEWORK: { + TITLE_OUTSIDE: "Architecture", + TITLE_INSIDE: "ARCHITECTURE ", + DESC_LIST: [ + "As shown in the figure, secGear consists of three layers. Currently, only the base layer is open source. The service layer and middleware layer will be gradually brought to open source.", + "The service layer provides complete security services based on confidential computing. You can directly use related services to enjoy the security brought by confidential computing.", + "The middleware layer provides common security protocol components and various security function libraries. You can directly call related APIs on the secure and non-secure sides without creating them by yourself. Currently, PKCS11 and PAKE are being built.", + "The base layer provides rich enclave development APIs or tools, including code generation tools and enclave life cycle management APIs. POSIX APIs and standard OpenSSL APIs are supported on the secure side. You can develop secure applications based on these APIs.", + ], + FRAMEWORK_IMG: "/img/minisite/secgear/framework.png", + }, + SECGEAR_DOCUMENT: { + TITLE_OUTSIDE: "Documentation", + TITLE_INSIDE: "DOCUMENTATION", + DATA_LIST: [ + { + IMG: "/img/minisite/isula/readme.png", + LINK: [ + { + TEXT: "Overview ", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E8%AE%A4%E8%AF%86secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/desc.png", + LINK: [ + { + TEXT: "Installation", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%AE%89%E8%A3%85secGear.md", + }, + ], + }, + { + IMG: "/img/minisite/isula/compile.png", + LINK: [ + { + TEXT: "Developer Guide", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E5%BC%80%E5%8F%91secGear%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/install.png", + LINK: [ + { + TEXT: "Tool Usage", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E4%BD%BF%E7%94%A8secGear%E5%B7%A5%E5%85%B7.md", + }, + ], + }, + { + IMG: "/img/minisite/atune/use.png", + LINK: [ + { + TEXT: "API Reference", + LINK: "https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/secGear/%E6%8E%A5%E5%8F%A3%E5%8F%82%E8%80%83.md", + }, + ], + }, + ], + }, + }, +}; diff --git a/web-ui/docs/.vuepress/lang/lang-modules/questionnaire.js b/web-ui/docs/.vuepress/lang/lang-modules/questionnaire.js new file mode 100644 index 0000000000000000000000000000000000000000..617a7426268e49c730e8e8042b4f4950eec2faa7 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/questionnaire.js @@ -0,0 +1,77 @@ +/** + * @file 问卷模块国际化配置入口 + * */ + module.exports = { + cn: { + PRIZE_LIST:[ + '/img/other/questionnaire/grand.png','/img/other/questionnaire/first.png','/img/other/questionnaire/second.png','/img/other/questionnaire/third.png','/img/other/questionnaire/excellent.png', + ], + PRIZE_LIST_MO:[ + '/img/other/questionnaire/grand_mo.png','/img/other/questionnaire/first_mo.png','/img/other/questionnaire/second_mo.png','/img/other/questionnaire/third_mo.png','/img/other/questionnaire/excellent_mo.png', + ], + RULE_TITLE:'活动规则', + FIRST:'1、活动时间:', + TIME:'2021年11月9日-2021年12月12日', + RULE_TEXT:[ + '2、我们将在活动结束后公布本期活动的所有获奖情况,并在活动结束后陆续联系获奖用户发放奖品。', + '3、获奖规则:', + '(1)本次活动一等奖、二等奖、三等奖、优秀奖将在填写问卷后直接随机抽取,请根据您真实的体验情况认真填写问卷,未参与体验的用户反馈的为无效问卷。', + '(2)本次活动特等奖将在调研活动结束后统一由专家进行评选,专家将根据您反馈的建议从用户体验等多个纬度进行评议,如符合条件建议的回复不足时,该奖项可空缺。', + '(3)每名用户仅有一次中奖资格,即每名用户仅能获得特等奖、一等奖、二等奖、三等奖、优秀奖其中一项奖项,奖项不可兼得,出现用户兼得奖项的情况时,只有最高奖项有效,其余获得奖项不生效。', + '4、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、网络攻击等,openEuler社区有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。', + '5、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。', + '6、openEuler社区可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。', + '7、所有参加本活动的用户,均视为同意openEuler社区的' + ], + LAW:'法律声明', + PRIVACY:'隐私政策' + }, + en: { + PRIZE_LIST:[ + '/img/other/questionnaire/grand.png','/img/other/questionnaire/first.png','/img/other/questionnaire/second.png','/img/other/questionnaire/third.png','/img/other/questionnaire/excellent.png', + ], + PRIZE_LIST_MO:[ + '/img/other/questionnaire/grand_mo.png','/img/other/questionnaire/first_mo.png','/img/other/questionnaire/second_mo.png','/img/other/questionnaire/third_mo.png','/img/other/questionnaire/excellent_mo.png', + ], + RULE_TITLE:'活动规则', + FIRST:'1、活动时间:', + TIME:'2021年11月9日-2021年12月12日', + RULE_TEXT:[ + '2、我们将在活动结束后公布本期活动的所有获奖情况,并在活动结束后陆续联系获奖用户发放奖品。', + '3、获奖规则:', + '(1)本次活动一等奖、二等奖、三等奖、优秀奖将在填写问卷后直接随机抽取,请根据您真实的体验情况认真填写问卷,未参与体验的用户反馈的为无效问卷。', + '(2)本次活动特等奖将在调研活动结束后统一由专家进行评选,专家将根据您反馈的建议从用户体验等多个纬度进行评议,如符合条件建议的回复不足时,该奖项可空缺。', + '(3)每名用户仅有一次中奖资格,即每名用户仅能获得特等奖、一等奖、二等奖、三等奖、优秀奖其中一项奖项,奖项不可兼得,出现用户兼得奖项的情况时,只有最高奖项有效,其余获得奖项不生效。', + '4、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、网络攻击等,openEuler社区有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。', + '5、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。', + '6、openEuler社区可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。', + '7、所有参加本活动的用户,均视为同意openEuler社区的' + ], + LAW:'法律声明', + PRIVACY:'隐私政策' + }, + ru: { + PRIZE_LIST:[ + '/img/other/questionnaire/grand.png','/img/other/questionnaire/first.png','/img/other/questionnaire/second.png','/img/other/questionnaire/third.png','/img/other/questionnaire/excellent.png', + ], + PRIZE_LIST_MO:[ + '/img/other/questionnaire/grand_mo.png','/img/other/questionnaire/first_mo.png','/img/other/questionnaire/second_mo.png','/img/other/questionnaire/third_mo.png','/img/other/questionnaire/excellent_mo.png', + ], + RULE_TITLE:'活动规则', + FIRST:'1、活动时间:', + TIME:'2021年11月9日-2021年12月12日', + RULE_TEXT:[ + '2、我们将在活动结束后公布本期活动的所有获奖情况,并在活动结束后陆续联系获奖用户发放奖品。', + '3、获奖规则:', + '(1)本次活动一等奖、二等奖、三等奖、优秀奖将在填写问卷后直接随机抽取,请根据您真实的体验情况认真填写问卷,未参与体验的用户反馈的为无效问卷。', + '(2)本次活动特等奖将在调研活动结束后统一由专家进行评选,专家将根据您反馈的建议从用户体验等多个纬度进行评议,如符合条件建议的回复不足时,该奖项可空缺。', + '(3)每名用户仅有一次中奖资格,即每名用户仅能获得特等奖、一等奖、二等奖、三等奖、优秀奖其中一项奖项,奖项不可兼得,出现用户兼得奖项的情况时,只有最高奖项有效,其余获得奖项不生效。', + '4、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、网络攻击等,openEuler社区有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。', + '5、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。', + '6、openEuler社区可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。', + '7、所有参加本活动的用户,均视为同意openEuler社区的' + ], + LAW:'法律声明', + PRIVACY:'隐私政策' + } +} diff --git a/web-ui/docs/.vuepress/lang/lang-modules/scheme.js b/web-ui/docs/.vuepress/lang/lang-modules/scheme.js new file mode 100644 index 0000000000000000000000000000000000000000..9f8a4398972cf4c46eb5e053394f735df60012a0 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/scheme.js @@ -0,0 +1,404 @@ +module.exports = { + + cn: { + + SCHEME:{ + + TITLE: 'openEuler迁移方案介绍', + + TITLE_ONE: '迁移面临的关键问题', + + ONE_P1: 'OS迁移面临的关键问题有三个:', + + ONE_QUESTION:[ + + '1、 已有的软件是否可以在新系统运行,包括安装,功能运行是否存在问题。', + + '2、 硬件与新OS是否兼容性。', + + '3、 已经做过的相关配置是否可以继承到新OS。' + + ], + + ONE_P2: '因此,迁移的首要问题是先进行兼容性评估,如果存在兼容性问题,需要进行兼容性适配,适配完成后开展搬迁;如果无兼容性问题,则开展搬迁实施;整体流程如下:', + + ONE_PROCESS_IMG: '/img/minisite/scheme/process.png', + + ONE_ANSWER: [ + + '(1)兼容性评估:在原有环境上进行硬件、软件、配置兼容性评估,确定是否存在兼容性风险;', + + '(2)移植适配:软件、硬件、OS厂家依据兼容性评估报告,进行相关移植适配;涉及到性能优化的场景,需开展调优工作;', + + '(3)迁移实施:基于全新建立环境(简称新增场景)、在已有集群环境扩容 (简称扩容场景)、将已有环境系统更换 (简称原地替换)场景,制定相关迁移实施方案,保障平滑迁移;需根据业务重要度、软件模型等特点,针对性制定搬迁方案。' + + ], + + ONE_P3:'注:其中(1),(2)主要面向开发人员移植适配,是新增、扩容、原地替换三种场景迁移的前提,(3)主要面向交付人员迁移实施,支持扩容、原地替换场景。', + + TITLE_TWO: 'openEuler DevKit 迁移综合方案概述', + + TWO_P1: 'openEuler DevKit 面向迁移全流程提供完整工具链及方案,支撑OS迁移平稳、简单、高效,从基础兼容性、兼容性评估、移植适配、搬迁实施四个方面开展;', + + TWO_SCHEME_IMG: '/img/minisite/scheme/scheme.png', + + TWO_SCHEME: [ + + '(1)OS基础兼容性是保障能够迁移的基础,因此OS要提供丰富的兼容性,避免在迁移的过程中,OS基础库不足阻碍迁移进度;', + + '(2)提供兼容性评估工具,从硬件、软件、配置识别兼容性风险;', + + '(3)如果存在不兼容的场景,提供对应的工具帮助开发者快速移植。', + + '(4)所有软件、硬件、配置都兼容的情况下,提供相关的搬迁方案,指导搬迁实施。' + + ], + + TITLE_THREE: 'OS基础兼容性', + + TITLE_THREE_ONE: 'OS基础兼容性介绍', + + THREE_ONE_P1: '关于操作系统兼容性,一般可以分为4个方面:1) 应用程序, 2)硬件兼容性,3) 虚拟化平台 4) 容器平台', + + THREE_ONE_LIST:[ + + {title:'(1)硬件兼容性;',content: + + ['芯片兼容性:包括 CPU 芯片架构 (X86_64/ARM64),基于芯片架构,衍生不同 CPU 厂家,部件芯片(网卡/raid/fc/ib/gpu/ssd/tpm)等。', + + '整机兼容性: FusionServer、浪潮、联想、新华三、曙光、宝德、神码、同方、长江计算、湘江鲲鹏、四川虹信等。' , + + '板卡兼容性:如 Intel、Mellanox、Avago、Emulex、Qlogic、Nvidia、AMD、网讯、华为等。'] }, + + {title: '(2)应用程序兼容性',content: ['开源软件、商业软件、自研软件。']}, + + {title: '(3)虚拟化平台',content: ['主要指虚拟化平台guest与host 之间兼容性。']}, + + {title: '(4)容器平台',content: ['主要指容器平台宿主与容器镜像之间兼容性。']}, + + ], + + THREE_ONE_P2: '为了解决以上兼容性适配问题,目前openEuler在社区成立兼容性sig组,主要工作职责为:', + + THREE_ONE_GROUP:[ + + '(1)建立社区统一的兼容性适配机制', + + '(2)梳理兼容性测试流程', + + '(3)孵化社区服务化测试平台', + + '(4)开发兼容性测试工具及套件', + + '(5)建立社区兼容性生态测试工程', + + ], + + THREE_ONE_P3: '支撑企业用户、开发者、合作伙伴基于社区服务按需适配软、硬件,共同打造openEuler系丰富的兼容性;', + + THREE_ONE_P4: '这里重点值得说明的是,一般而言硬件厂家会提供一个基础的驱动放置到内核,主要解决基本能用的问题,同时芯片厂家在官网同步发布支持各类操作系统的驱动,保障驱动的 issue 得到及时解决,保障生产系统能够用的好,当前 openEuler 社区得到芯片厂家的大力支持,Mellanox、Avago、Emulex、Qlogic 等厂家官网均发布了针对 openEuler 的驱动,双向发布兼容性,共同保障切换后生产环境的安全运行。', + + TITLE_THREE_TWO: '硬件兼容性适配套件', + + THREE_TWO_P1:'基于社区开源的测试套件 oec-hardware 整机、硬件、芯片厂家可以根据社区硬件', + + THREE_TWO_A1:'兼容性测试流程', + + THREE_TWO_P2:'开展测试,测试完成后,将测试结果提交到社区,社区sig组将测试通过的硬件加入到社区兼容性清单,社区兼容性工作得到硬件厂家的大力支持,且套件已经广泛使用,当前社区已经支持主流X86/ARM架构产品,FusionServer、浪潮、联想、新华三、曙光,宝德、神码、同方、长江计算、湘江鲲鹏、四川虹信等整机厂家; 主流部件芯片产品,如:Intel、Mellanox、Avago、Emulex、Qlogic、Nvidia、AMD、网讯、华为 等详见社区', + + THREE_TWO_A2:'硬件兼容性清单', + + + + TITLE_THREE_THREE: '软件兼容性适配服务', + + THREE_THREE_P1:'支撑企业用户、开发者、合作伙伴基于社区服务 Compass-CI 开展兼容性测试活动,适配流程参考:', + + THREE_THREE_A1:'软件兼容性适配流程', + + THREE_THREE_P2:';开发人员利用社区提供的基础服务开展适配,Compass-CI 自动将认证通过的软件发布至软件仓库及兼容性清单,便于最终用户快速按需获取。当前社区清单已经支持10000+软件包,覆盖数据库、中间件、Web 服务、⼤数据、虚拟化、云原生、AI、容器技术、开发环境语⾔、安全、系统工具、测试工具,部署工具等主流软件,详见', + + THREE_THREE_A2:'社区软件清单', + + + + TITLE_FOUR: '兼容性评估', + + TITLE_FOUR_ONE: '软件兼容性评估', + + FOUR_ONE_P1:'openEuler社区提供了', + + FOUR_ONE_A1:'x2openEuler 工具', + + FOUR_ONE_P2:',针对已经编译好的二进制程序,进行依赖软件包、接口评估,明确应用软件是否需要移植适配,是否有依赖的软件包待引入;同时评估软件调用的接口原型在两个系统中是否有差异,指导下一步适配方向。', + + FOUR_ONE_P3:'注:已经编译好的二进制程序,难以保障全部兼容新 OS,严重时会导致踩内存风险,往往这种问题很难通过验证的方式识别出来,迁移前针对软件兼容性评估尤为重要。', + + TITLE_FOUR_TWO: '硬件兼容性评估', + + FOUR_TWO_P2:',评估硬件兼容性。', + + TITLE_FOUR_THREE: '配置兼容性评估', + + FOUR_THREE_P1:'评估迁移前系统的配置与迁移后的系统兼容性。', + + TITLE_FIVE: '移植适配', + + FIVE_P1:'关于应用适配,一般包括四个部分:1)应用移植适配,2)OS引包,3)硬件适配,4)配置适配', + + TITLE_FIVE_ONE: '应用移植适配', + + FIVE_ONE_P1:'基于', + + FIVE_ONE_P2:'生成兼容性评估报告,提供应用调用的接口在两个操作系统是否存在原型差异,确定是否需要重新编译及修改适配。在需要适配的情况下提供接口的全量信息,便于开发人员一次性代码修改及精准化验证,加速移植后验证效率。', + + TITLE_FIVE_TWO: 'OS软件包适配', + + FIVE_TWO_P1:'基于评估报告,如果发现有缺失的包,参考软件兼容性适配服务章节。适配完成后,将软件包引入至软件仓库及根据需要刷新软件兼容性清单', + + TITLE_FIVE_THREE: '硬件适配', + + FIVE_THREE_P1:'基于评估报告,如果评估发现有硬件不兼容,参考', + + FIVE_THREE_A1:'硬件兼容性测试服务', + + FIVE_THREE_P2:',引导硬件厂家开展适配,适配完成后将适配驱动发布至软件所仓库及刷新兼容性清单。', + + TITLE_FIVE_FOUR: ' 配置适配', + + FIVE_FOUR_P1:'基于评估报告,', + + FIVE_FOUR_P2:'识别原有系统的客户做的配置,分析与迁移后与系统配置的兼容性差异,指导在替换OS系统上进行同步。', + + TITLE_SIX: '搬迁实施', + + SIX_P1:'对于原地替换场景,通常与软件部署的形态相关,搬迁的实施方案也会不同,这里主要介绍一般情况下的搬迁:单机、主备和分布式。搬迁实施前,需要提前熟悉软件部署架构及部署组网,针对性输出对应场景的搬迁方案,目前 openEuler 提供主流场景的搬迁方案,如大数据、分布式存储、虚拟化、容器、数据库软件,成功支撑多个行业用户完成搬迁工作。', + + SIX_LIST:[ + + {title:'单机软件', content:'该类软件搬迁时,涉及到操作系统切换,基本上会中断业务,需要充分考虑迁移造成的中断影响,选择合适的窗口进行搬迁'}, + + {title:'主备软件', content:'该类软件搬迁时,可以选择在业务量较少时,通过倒换搬迁。'}, + + {title:'分布式软件', content:'该类软件搬迁时,可以选择在业务量较少时,通过分布式软件的特征,进行滚动搬迁。'}, + + ], + + TITLE_SEVNE: '迁移调优', + + SEVEN_P1:'除了保障迁移后取得更好的性能,openEuler社区提供调优工具,A-Tune是一款基于AI开发的系统性能优化引擎,它利用人工智能技术,对业务场景建立精准的系统画像,感知并推理出业务特征,进而做出智能决策,匹配并推荐最佳的系统参数配置组合,使业务处于最佳运行状态。', + + SEVEN_TUNING_IMG: '/img/minisite/scheme/tuning.png', + + SEVEN_P2:'目前已经支持11大类15款应用负载类型自动优化,主要包括:存储、大数据、虚拟化、容器、数据库、中间件、web、HPC等领域模型优化。', + SEVEN_P2_URL: 'https://a-tune.openeuler.org' + } + + }, + + en: { + + SCHEME:{ + + TITLE: 'openEuler迁移方案介绍', + + TITLE_ONE: '迁移面临的关键问题', + + ONE_P1: '迁移面临的关键问题有三个:', + + ONE_QUESTION:[ + + '1、 已有的软件是否可以在新系统运行,包括安装,功能运行是否存在问题。', + + '2、 硬件与新OS是否兼容性。', + + '3、 已经做过的相关配置是否可以继承到新OS。' + + ], + + ONE_P2: '因此,迁移的首要问题是先进行兼容性评估,如果存在兼容性问题,需要进行兼容性适配,适配完成后开展搬迁;如果无兼容性问题,则开展搬迁实施;整体流程如下:', + + ONE_PROCESS_IMG: '/img/minisite/scheme/process.png', + + ONE_ANSWER: [ + + '(1)兼容性评估:协助操作在原有环境上进行硬件、软件、配置兼容性评估,确定是否存在兼容性风险;', + + '(2)移植适配:软件、硬件、OS厂家依据兼容性评估报告,进行相关移植适配;涉及到性能优化的场景,需开展调优工作;', + + '(3)迁移实施:基于实际的存量环境,制定相关迁移实施方案,保障平滑迁移,需根据业务重要度、软件模型等特点,针对性制定方案。' + + ], + + ONE_P3:'注:其中(1),(2)主要面向开发态移植适配,覆盖全新建立独立环境(简称新增场景),在已有集群环境扩容(简称扩容场景),将已有环境系统更换(简称原地替换)三种场景。(3)主要面向扩容,原地替换场景。', + + TITLE_TWO: 'openEuler迁移综合方案概述 ', + + TWO_P1: 'openEuler DevKit提供跨OS迁移整体解决方案,从基础兼容性、兼容性评估、移植适配、搬迁实施四个方面开展;', + + TWO_SCHEME_IMG: '/img/minisite/scheme/scheme.png', + + TWO_SCHEME: [ + + '(1):OS基础兼容性是保障能够迁移的基础,因此OS要提供丰富的兼容性,避免在迁移的过程中,OS基础库不足阻碍迁移进度;', + + '(2):提供兼容性评估工具,从硬件、软件、配置层帮助识别兼容性风险;', + + '(3):如果存在不兼容的场景,需要有对应的工具帮助开发者快速移植。', + + '(4):所有软件、硬件、配置都兼容的情况下,有相关的搬迁方案及计划,指导搬迁实施。' + + ], + + TITLE_THREE: 'OS基础兼容性', + + TITLE_THREE_ONE: 'OS基础兼容性介绍', + + THREE_ONE_P1: '关于操作系统兼容性,一般可以分为5个方面:1) 应用程序, 2)与硬件兼容性,3) 虚拟化平台 4) 容器平台 宿主与容器 5) OSV 兼容性。', + + THREE_ONE_LIST:[ + + {title:'(1)硬件兼容性;',content: + + ['芯片兼容性:包括CPU芯片架构(X86/ARM/alpha/龙芯),基于芯片架构,衍生不同CPU厂家,如:intel、海光、兆芯,AMD,鲲鹏、飞腾、申威、龙芯;部件芯片(网卡/raid/fc/ib/gpu/ssd/tpm)等。', + + '整机兼容性:FusionServer、浪潮、联想、新华三、曙光、宝德、神码、同方、长江计算、湘江鲲鹏、长虹 等。' , + + '板卡兼容性:intel、mellanox、avago、emulex、qlogic、nvidia、amd、网讯、华为 '] }, + + {title: '(2)应用程序兼容性',content: ['开源软件、商业软件、自研软件。']}, + + {title: '(3)虚拟化平台',content: ['主要指 虚拟化平台guest与host 之间兼容性,如:云宏、深信服、华为云、Easystack、青云、电信云。']}, + + {title: '(4)容器平台',content: ['主要指 容器平台宿主与容器镜像之间兼容性,如:云宏、深信服、华为云、Easystack、青云、电信云。']}, + + {title: '(5)OSV兼容性',content: ['openEuler产品与二次发行商生态复用检测能力,主要是任何一个OSV厂家与软件、硬件一次适配,可以在多个OS 间可以复用,可以有效避免每个OSV在相同软件上的重复投入。']}, + + ], + + THREE_ONE_P2: '为了解决以上兼容性适配问题,目前openEuler在社区成立兼容性sig组,主要工作职责为:', + + THREE_ONE_GROUP:[ + + '(1)建立社区统一的兼容性适配机制', + + '(2)制定兼容性测试标准化', + + '(3)梳理兼容性测试流程', + + '(4)孵化社区服务化测试平台', + + '(5)开发兼容性测试工具及套件', + + '(6)建立社区兼容性生态测试工程', + + ], + + THREE_ONE_P3: '支撑企业用户、开发者、合作伙伴基于社区服务按需适配软、硬件,共同共同打造openEuler系丰富的兼容性;', + + THREE_ONE_P4: '这里重点值得说明的是,一般而言硬件厂家会提供一个基础的驱动放置到内核,主要解决基本能用的问题,同时芯片厂家在官网同步发布支持各类操作系统的驱动,保障驱动的issue 得到及时解决,保障生产系统能够用的好,当前openEuler社区得到芯片厂家的大力支持,mellanox、avago、emulex、qlogic等厂家官网均发布了针对openEuler的驱动,双向发布兼容性,共同保障切换后生产环境的安全运行。', + + TITLE_THREE_TWO: '硬件兼容性适配套件', + + THREE_TWO_P1:'基于社区开源的测试套件oec-hardware 整机、硬件、芯片厂家可以根据社区硬件', + + THREE_TWO_A1:'兼容性测试流程', + + THREE_TWO_P2:'开展测试,测试完成后,将测试结果提交到社区,社区sig组将测试通过的硬件加入到社区兼容性清单,社区兼容性工作得到硬件厂家的大力支持,且套件已经广泛使用,当前社区intel、海光、兆芯,AMD,鲲鹏、飞腾CPU芯片,FusionServer、浪潮、联想、新华三、曙光,宝德、神码、同方、长江计算、湘江鲲鹏、长虹等整机厂家;intel、mellanox、avago、emulex、qlogic、nvidia、amd、网讯、华为等服务器领域主流的部件芯片及板卡,详见社区', + + THREE_TWO_A2:'硬件兼容性清单', + + + + TITLE_THREE_THREE: '软件兼容性适配服务', + + THREE_THREE_P1:'支撑企业用户、开发者、合作伙伴基于社区服务compass-ci开展兼容性测试活动,适配流程参考:', + + THREE_THREE_A1:'软件兼容性适配流程', + + THREE_THREE_P2:';开发人员利用社区提供的基础服务开展适配及测试通过,自动化将认证通过的软件发布至软件仓库及兼容性清单,便于最终用户快速按需获取。当前社区清单已经支持10000+软件包,覆盖数据库、中间件、Web服务、大数据、虚拟化、云原生、AI、容器技术、开发环境语言、安全、系统工具、测试工具,部署工具等主流软件,详见', + + THREE_THREE_A2:'社区软件清单', + + + + TITLE_THREE_FOUR: 'OSV 认证适配服务', + + THREE_FOUR_P1:'支持OSV企业基于社区套件在二次发行过程中,识别影响兼容性的部分,最大程度保障社区生态与商业生态融合,降低兼容性适配重复,社区孵化oecp项目,适配流程参考:', + + THREE_FOUR_A1: 'OSV认证适配指导', + + THREE_FOUR_P2: ',认证过后信息会发布大社区清单,目前工作正在试运行阶段,预计3月份对外开放。', + + TITLE_FOUR: '兼容性评估', + + TITLE_FOUR_ONE: '软件兼容性评估', + + FOUR_ONE_P1:'openEuler社区提供了', + + FOUR_ONE_A1:'x2openEuler 工具', + + FOUR_ONE_P2:',针对已经编译好的二进制程序,进行主要完成软件包、接口级评估,明确应用软件是否需要移植适配,是否有依赖的软件包待引入;同时评估软件调用的接口原型在两个系统中是否有差异。', + + FOUR_ONE_P3:'注:已经编译好的二进制程序,难以保障全部兼容新OS,严重时会引发才内存风险,往往这种问题很难通过验证的方式识别出来,迁移前针对软件兼容性评估尤为重要。', + + TITLE_FOUR_TWO: '硬件兼容性评估', + + FOUR_TWO_P2:',评估硬件兼容性。', + + TITLE_FOUR_THREE: '配置兼容性评估', + + FOUR_THREE_P1:'识别系统的配置与迁移后的系统兼容性。', + + TITLE_FIVE: '移植适配', + + FIVE_P1:'关于应用适配,一般包括四个部分:1)应用移植适配,2)OS引包,3)硬件适配;4)配置适配', + + TITLE_FIVE_ONE: '应用移植适配', + + FIVE_ONE_P1:'基于', + + FIVE_ONE_P2:'生成兼容性评估报告,提供应用调用的接口在两个操作系统是否存在原型差异,确定是否需要重新编译及修改适配,并给出有接口差异分类及有哪些接口涉及,便于开发人员一次性修订及精准化验证,加速移植后验证效率。', + + TITLE_FIVE_TWO: 'OS软件包适配', + + FIVE_TWO_P1:'基于评估报告,如果发现有缺失的包,参考3.2.2 软件兼容性适配服务,适配完成后,将软件包引入至软件仓库及根据需要刷新软件兼容性清单', + + TITLE_FIVE_THREE: '硬件适配', + FIVE_THREE_P1:'基于评估报告,如果评估发现有硬件不兼容,参考2.2.1', + FIVE_THREE_A1:'硬件兼容性测试服务', + FIVE_THREE_P2:'引导硬件厂家开展适配,适配完成后将适配驱动发布至软件所仓库及刷新兼容性清单。', + TITLE_FIVE_FOUR: ' 配置适配', + FIVE_FOUR_P1:'基于评估报告,', + FIVE_FOUR_P2:'识别原有系统的客户做的配置,分析与迁移后与系统配置的兼容性差异,指导在新替换OS系统上进行同步。', + TITLE_SIX: '搬迁实施', + SIX_P1:'对于存量原地替换,通常与软件部署的形态相关,搬迁的实施方案也会不同,这里主要介绍一般情况下的搬迁: 单机、主备和分布式。搬迁实施实施前,需要提前熟悉软件部署架构及部署组网,针对性输出对应场景的搬迁方案,目前主要针对多个领域:如大数据、分布式存储、虚拟化、容器、数据库软件的搬迁方案,支撑政企、运营商、金融企业开展搬迁工作开展,协助后续搬迁方案作为参考,实际以具体要求为准。', + SIX_LIST:[ + {title:'单机软件', content:'该类软件搬迁时,涉及到操作系统切换,基本上会中断业务,需要充分考虑迁移造成的中断影响,选择合适的窗口进行搬迁'}, + {title:'主备软件', content:'该类软件搬迁时,可以选择在业务量较少时,通过倒换搬迁。'}, + {title:'分布式软件', content:'该类软件搬迁时,可以选择在业务量较少时,通过分布式软件的特征,进行滚动搬迁。'}, + ], + TITLE_SEVNE: '迁移调优', + SEVEN_P1:'除了保障迁移后取得更好的性能,openEuler 社区提供调优工具,A-Tune 是一款基于 AI 开发的系统性能优化引擎,它利用人工智能技术,对业务场景建立精准的系统画像,感知并推理出业务特征,进而做出智能决策,匹配并推荐最佳的系统参数配置组合,使业务处于最佳运行状态。', + SEVEN_TUNING_IMG: '/img/minisite/scheme/tuning.png', + SEVEN_P2:'目前已经支持11大类15款应用负载类型自动优化,主要包括:存储、大数据、虚拟化、容器、数据库、中间件、WEB、HPC 等领域模型优化。', + SEVEN_P2_URL: 'https://a-tune.openeuler.org' + } + + }, + + ru: { + + + + } + + + + + + + + + +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/search.js b/web-ui/docs/.vuepress/lang/lang-modules/search.js new file mode 100644 index 0000000000000000000000000000000000000000..fdb35751bf34f4643f43088dc9975b35d5d7a246 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/search.js @@ -0,0 +1,39 @@ +/** + * @file 搜索模块国际化配置入口 + * */ + +module.exports = { + cn: { + TAG_NAME: { + ALL: '全部', + BLOG: '博客', + NEWS: '新闻', + DOCS: '文档', + FROM: '来源' + }, + REPO: '相关软件包', + SEARCH: '搜索' + }, + en: { + TAG_NAME: { + ALL: 'All', + BLOG: 'Blog', + NEWS: 'News', + DOCS: 'Docs', + FROM: 'from' + }, + REPO: 'Related software package', + SEARCH: 'Search' + }, + ru: { + TAG_NAME: { + ALL: 'Все', + BLOG: 'Блоги', + NEWS: 'Новости', + DOCS: 'Документы', + FROM: 'От кого' + }, + REPO: 'Сопутствующий пакет программного обеспечения', + SEARCH: 'Поиск' + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/security.js b/web-ui/docs/.vuepress/lang/lang-modules/security.js new file mode 100644 index 0000000000000000000000000000000000000000..d4a44ade8228a0ab8208feee3eb441ee9d019d4e --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/security.js @@ -0,0 +1,178 @@ +/** + * @file 安全模块国际化配置入口 + * */ + +module.exports = { + cn: { + OVERVIEW: '概述', + UPDATED_PACKAGES: '更新的软件包', + SECURITY_ADVISORIES: '安全公告', + SECURITY_ADVISORIES_NAME: '公告名', + SEARCH: '搜索', + SEVERITY_LIST : [ + { + NAME: '全部', + LABEL: '' + }, + { + NAME: '低', + LABEL: 'Low' + }, + { + NAME: '中', + LABEL: 'Medium' + }, + { + NAME: '高', + LABEL: 'High' + }, + { + NAME: '致命', + LABEL: 'Critical' + } + ], + YEAR: '年份', + PLACEHOLDER: '请选择', + ALL: '全部', + ADVISORY: '公告', + SYNOPSIS: '概要', + SEVERITY: '严重级别', + AFFECTED_PRODUCTS: '影响产品', + AFFECTED_COMPONENTS: '影响组件', + RELEASE_DATE: '发布时间', + CVSS_SCORE: 'CVSS评分', + MODIFIED_TIME: '修改时间', + OPERATION: '操作', + DETAIL: '详情', + REPORTING: '漏洞管理', + INPUT_CVE_ID: '请输入CVE ID', + INPUT_STATUS: '请输入状态', + BRIEF_INTRODUCTION: '简介', + THEME: '主题', + DESCRIPTION: '描述', + PACKAGE: '包', + REFERENCE_DOCUMENTS: '参考', + CVE_DETAIL: 'CVE详情', + METRICS_V3: 'CVSS v3 指标', + METRICS_V2: 'CVSS v2 指标', + SCORE: '评分', + PRODUCT: '产品', + STATUS: '状态', + PACKAGE_NAME:'包', + }, + en: { + OVERVIEW: 'Overview', + UPDATED_PACKAGES: 'Updated software packages', + SECURITY_ADVISORIES: 'Security Advisories', + SECURITY_ADVISORIES_NAME: 'Title', + SEARCH: 'Search', + SEVERITY_LIST : [ + { + NAME: 'All', + LABEL: '' + }, + { + NAME: 'Low', + LABEL: 'Low' + }, + { + NAME: 'Medium', + LABEL: 'Medium' + }, + { + NAME: 'High', + LABEL: 'High' + }, + { + NAME: 'Critical', + LABEL: 'Critical' + } + ], + YEAR: 'Year', + PLACEHOLDER: 'Select', + ALL: 'ALL', + ADVISORY: 'Advisory', + SYNOPSIS: 'Synopsis', + SEVERITY: 'Severity', + AFFECTED_PRODUCTS: 'Affected Product', + AFFECTED_COMPONENTS: 'Affected \n Component', + RELEASE_DATE: 'Release Date', + CVSS_SCORE: 'CVSS Score', + MODIFIED_TIME: 'Time of Modification', + OPERATION: 'Operation', + DETAIL: 'Details', + REPORTING: 'Vulnerability Report', + INPUT_CVE_ID: 'Please input CVE ID', + INPUT_STATUS: 'Please input Status', + BRIEF_INTRODUCTION: 'BriefIntroduction', + THEME: 'theme', + DESCRIPTION: 'description', + PACKAGE: 'packages', + REFERENCE_DOCUMENTS: 'referenceDocuments', + CVE_DETAIL: 'CVE Detail', + METRICS_V3: 'CVSS v3 Metrics', + METRICS_V2: 'CVSS v2 Metrics', + SCORE: 'Score', + PRODUCT: 'Product', + STATUS: 'Status', + PACKAGE_NAME:'packages', + }, + ru: { + OVERVIEW: 'Краткое описание', + UPDATED_PACKAGES: 'Обновленные пакеты ПО', + SECURITY_ADVISORIES: 'Консультанты по безопасности', + SECURITY_ADVISORIES_NAME: 'Title', + SEARCH: 'Поиск', + SEVERITY_LIST : [ + { + NAME: 'Все', + LABEL: '' + }, + { + NAME: 'Низкий', + LABEL: 'Low' + }, + { + NAME: 'Средний', + LABEL: 'Medium' + }, + { + NAME: 'Высокий', + LABEL: 'High' + }, + { + NAME: 'Критический', + LABEL: 'Critical' + } + ], + YEAR: 'Год', + PLACEHOLDER: 'Выбрать', + ALL: 'ВСЕ', + ADVISORY: 'Консультант', + SEVERITY_PLACEHOLDER: 'Степень серьезности', + SYNOPSIS: 'Синопсис', + SEVERITY: 'Степень серьезности', + AFFECTED_PRODUCTS: 'Затронутый продукт', + AFFECTED_COMPONENTS: 'Затронутый \n компонент', + RELEASE_DATE: 'Дата выпуска релиза', + CVSS_SCORE: 'Оценка по CVSS', + MODIFIED_TIME: 'Время изменения', + OPERATION: 'Действие', + DETAIL: 'Описание', + REPORTING: 'Сообщение об уязвимостях', + INPUT_CVE_ID: 'Введите идентификатор CVE', + INPUT_STATUS: 'Введите идентификатор Status', + BRIEF_INTRODUCTION: 'BriefIntroduction', + THEME: 'theme', + DESCRIPTION: 'description', + PACKAGE: 'packages', + REFERENCE_DOCUMENTS: 'referenceDocuments', + CVE_DETAIL: 'CVE Detail', + METRICS_V3: 'CVSS v3 Metrics', + METRICS_V2: 'CVSS v2 Metrics', + SCORE: 'Score', + PRODUCT: 'Product', + STATUS: 'Status', + PACKAGE_NAME:'packages', + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/sig.js b/web-ui/docs/.vuepress/lang/lang-modules/sig.js new file mode 100644 index 0000000000000000000000000000000000000000..ffc16f498ff0e96ec01d60a9b70d53ea50df434b --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/sig.js @@ -0,0 +1,370 @@ +/** + * @file sig模块国际化配置入口 + * */ + +module.exports = { + cn: { + GUIDANCE_LIST: { + GUIDE: { + MOBILE_TITLE: "SIG申请流程", + TITLE: "申请流程", + LINE_CONTENT: [{ + LEFT: { + LEFT_INFO: "个人或公司在openEuler社区中寻找2 - 3个具有共同目标的人讨论决定成立SIG组,维护openEuler社区中的某一个技术方向软件包或发起孵化项目。", + LEFT_CIRCLE: "寻人", + LEFT_IMG: "/img/sig/sig1.png" + }, + RIGHT: { + RIGHT_INFO: "按照成立 SIG 组的成立流程,在 Gitee 上创建申请文件,发起 Pull Request ;预约技术委员会会议的时间。", + RIGHT_CIRCLE: "申请", + LEFT_IMG: "/img/sig/sig2.png" + } + }, + { + LEFT: { + LEFT_INFO: "在技术委员会的例会上就技术范围、维护的目标等和与会成员沟通,在 SIG 目标范围及维护上达成一致。", + LEFT_CIRCLE: "沟通", + LEFT_IMG: "/img/sig/sig3.png" + }, + RIGHT: { + RIGHT_INFO: "技术委员会批准成立,对应的 Pull Request 合入代码仓库,基础设施会自动建立对应的仓库。", + RIGHT_CIRCLE: "获批", + LEFT_IMG: "/img/sig/sig4.png" + } + }, + { + LEFT: { + LEFT_INFO: "SIG 开始正式运作,通过邮件列表/例行会议等进行沟通运作。", + LEFT_CIRCLE: "运作", + LEFT_IMG: "/img/sig/sig5.png" + }, + RIGHT: { + RIGHT_INFO: "技术委员会周期 Review SIG 的运作情况,给出指导意见。", + RIGHT_CIRCLE: "改进", + LEFT_IMG: "/img/sig/sig6.png" + } + }, + ] + } + }, + SIG_LIST: { + HOME_PAGE: '前往gitee首页', + MAIL: '邮件', + IRC: 'IRC频道', + MANAGER: '管理员', + NAME: 'SIG名称', + GITEE_PAGE: 'Gitee主页' + }, + SIG_DESCRIPTION: { + P1: 'SIG 就是 Special Interest Group 的缩写,openEuler 社区按照不同的 SIG 来组织,以便于更好的管理和改善工作流程。', + P2: 'SIG 组均是开放的,欢迎任何人来参与。', + LI1: '每一个SIG在Gitee上都会拥有一个或多个项目,这些项目会拥有一个或多个Repository,SIG的交付成果会保存在这些Repository内。您可以在SIG对应的Repository内提交Issue、针对特定问题参与讨论,提交和解决问题,参与评审等。', + LI2: 'SIG都是针对特定的一个或多个技术主题而成立的。SIG的核心成员主导SIG的治理,SIG内的成员推动交付成果输出,并争取让交付成果成为openEuler社区发行的一部分。', + LI3: '在SIG团队项目的gitee首页README.md文件中,可以找到该项目所属的SIG信息、交流方式、成员和联系方式等,欢迎通过邮件列表、公开例会及对应的README.md 文件中提到的联系方式积极参与进SIG内的交流。' + }, + SIG_LANDSCAPE: { + BUILDING: '建设中,敬请期待' + }, + SIG_DETAIL: { + VIDEO: '视频', + NEWS: '新闻', + MORE: '更多 >', + BLOG: '博客', + LATEST_DYNAMIC: '最新动态', + SIG_EMPTY_TEXT1: '这里空空如也,快给你的SIG', + SIG_EMPTY_TEXT2: '添加简介', + SIG_EMPTY_TEXT3: '吧!', + INTRODUCTION: 'SIG简介', + NO_MEETINGS: '暂无会议', + ORGANIZING_MEETINGS: 'SIG会议', + MEMBERS: 'SIG成员', + CONTACT: '联系方式', + MAIL_LIST: '邮件列表', + EXPAND: "展开全部", + RETRACT: "收起全部", + BLOG_EMPTY1: "我看你骨骼惊奇,必是写文好手。这里有一本", + BLOG_EMPTY2: "发博客攻略", + BLOG_EMPTY3: ",赶紧拿回去看看吧。", + NEWS_EMPTY: '不想当裁缝的厨子不是好司机,不发新闻的博客不是好视频。', + NEWS_EMPTY2: '', + NEWS_EMPTY3: '点击', + NEWS_EMPTY4: '发送SIG的第一篇新闻。', + VIDEO_EMPTY: '我都把最好的位置留给你啦,你愿意投递一个视频吗?' + }, + ROLE_DESCRIPTION:{ + ROLE_DESCRIPTION:'角色说明', + TABLE_TITLE:'社区成员', + TABLE_DESCRIPTION:'本文简要描述了openEuler社区中贡献者角色的各种职责。大部分角色的职责限于这些SIG(Special Interest Group)内:', + TABLE_THEAD:["角色","职责范围(简要描述)","要求","定义的文件"], + TABLE_TBODY:[ + { + ROLE:'Contributor', + RESPONSIBILITIES:'项目的贡献者', + REQUIREMENT:'', + DEFINED_DOCUMENT:'Gitee注册成员' + }, + { + ROLE:'Committer', + RESPONSIBILITIES:'审核其他成员的贡献', + REQUIREMENT:'SIG的积极贡献者,经验丰富,愿意投入精力参与到审核工作', + DEFINED_DOCUMENT:'openEuler SIG拥有的存储库中OWNERS文件中的Committer条目。' + }, + { + ROLE:'Maintainer', + RESPONSIBILITIES:'项目Owner', + REQUIREMENT:'经验丰富,富有责任心、出色的技术能力和管理能力', + DEFINED_DOCUMENT:'openEuler SIG拥有的存储库中OWNERS文件中的Maintainer条目。' + } + ] + } + }, + en: { + GUIDANCE_LIST: { + GUIDE: { + MOBILE_TITLE: "SIG申请流程", + TITLE: "Application Process", + LINE_CONTENT: [{ + LEFT: { + LEFT_INFO: "Individuals or companies find two or three persons with common goals in the openEuler community to discuss and set up a SIG, which aims to maintain a specific type of software package in the openEuler community or to initiate an incubation project.", + LEFT_CIRCLE: "01", + MOBILE_CIRCLE: 'Find', + LEFT_IMG: "/img/sig/sig1.png", + LEFT_DESC: 'Find' + }, + RIGHT: { + RIGHT_INFO: "Create an application file on Gitee and initiate a pull request (PR) according to the procedure for setting up a SIG. Make an appointment for attending the Technical Committee meeting. ", + RIGHT_CIRCLE: "02", + MOBILE_CIRCLE: 'Apply', + LEFT_IMG: "/img/sig/sig2.png", + RIGHT_DESC: 'Apply' + } + }, + { + LEFT: { + LEFT_INFO: "At the regular Technical Committee (TC) meeting, discuss and reach an agreement on the technical scope and maintenance objectives of the SIG.", + LEFT_CIRCLE: "03", + MOBILE_CIRCLE: 'Discuss', + LEFT_IMG: "/img/sig/sig3.png", + LEFT_DESC: 'Discuss' + }, + RIGHT: { + RIGHT_INFO: "The TC approves the establishment of the SIG. The corresponding PR is integrated into the code repository, and the infrastructure automatically establishes the corresponding repository.", + RIGHT_CIRCLE: "04", + MOBILE_CIRCLE: 'Approve', + LEFT_IMG: "/img/sig/sig4.png", + RIGHT_DESC: 'Approve' + } + }, + { + LEFT: { + LEFT_INFO: "The SIG starts to operate. Members use the mailing list and regular meetings for discussion and operation.", + LEFT_CIRCLE: "05", + MOBILE_CIRCLE: 'Operate', + LEFT_IMG: "/img/sig/sig5.png", + LEFT_DESC: 'Operate' + }, + RIGHT: { + RIGHT_INFO: "The TC periodically reviews the SIG operation and provides guidance.", + RIGHT_CIRCLE: "06", + MOBILE_CIRCLE: 'Improve', + LEFT_IMG: "/img/sig/sig6.png", + RIGHT_DESC: 'Improve' + } + }, + ] + } + }, + SIG_LIST: { + HOME_PAGE: 'Go to Gitee home page', + MAIL: 'E-mail', + IRC: 'IRC Channel', + MANAGER: 'Administrators', + NAME: 'SIG', + GITEE_PAGE: 'Gitee' + }, + SIG_DESCRIPTION: { + P1: 'The openEuler community is organized based on Special Interest Groups (SIGs) to better manage and improve the work processes.', + P2: 'SIGs are open to everyone.', + LI1: 'Each SIG comprises one or more projects on Gitee, and each project has repositories that store SIG deliverables. Registering with an SIG enables you to submit, discuss, and resolve issues with other members, as well as participate in reviews in an SIG repository.', + LI2: 'An SIG is established for one or more specific technical topics. Core members of an SIG can manage each group, and members can contribute to the quality and the output of deliverables for the openEuler community.', + LI3: 'In the README.md file on the project Gitee page, you can find project SIG information, members, and contact information. You can join specific SIGs by mailing the listed email addresses. Also, you can attend public meetings, join discussions or forums, or participate in other activities listed in the corresponding README.md file.' + }, + SIG_LANDSCAPE: { + BUILDING: 'Coming soon' + }, + SIG_DETAIL: { + VIDEO: 'Video', + NEWS: 'News', + MORE: 'Read More', + BLOG: 'Blog', + LATEST_DYNAMIC: "What's New", + SIG_EMPTY_TEXT1: 'Nothing found. ', + SIG_EMPTY_TEXT2: 'Add a profile', + SIG_EMPTY_TEXT3: ' to your SIG.', + INTRODUCTION: 'SIG Introduction', + NO_MEETINGS: 'Not available now', + ORGANIZING_MEETINGS: 'SIG Schedule', + MEMBERS: 'SIG Members', + CONTACT: 'Contact', + MAIL_LIST: 'Mailing list', + EXPAND: "Expand All", + RETRACT: "Collapse All", + BLOG_EMPTY1: "Dive into the ", + BLOG_EMPTY2: "blogging guide", + BLOG_EMPTY3: " and post your first blog.", + NEWS_EMPTY: 'Broadcast the latest news of your SIG.', + NEWS_EMPTY2: 'Click ', + NEWS_EMPTY3: 'here ', + NEWS_EMPTY4: 'to publish your first SIG news.', + VIDEO_EMPTY: 'Share your first video now.' + }, + ROLE_DESCRIPTION:{ + ROLE_DESCRIPTION:'Role Description', + TABLE_TITLE:'Community Member', + TABLE_DESCRIPTION:'This article briefly describes the responsibilities and privilege of the contributor in the openEuler community. The responsibilities of most contributor are limited to SIG (Special Interest groups) :', + TABLE_THEAD:["Role","Responsibilities","Requirement","Defined Document"], + TABLE_TBODY:[ + { + ROLE:'Contributor', + RESPONSIBILITIES:'Contributors of the project', + REQUIREMENT:'', + DEFINED_DOCUMENT:'Registered members on Gitee' + }, + { + ROLE:'Committer', + RESPONSIBILITIES:'Review and approve the contributions submitted', + REQUIREMENT:'Frequently contributing to SIG, experienced,and willing to undertake review work', + DEFINED_DOCUMENT:'developer entry in the OWNERS file owned by openEuler SIG' + }, + { + ROLE:'Maintainer', + RESPONSIBILITIES:'Owner of the project', + REQUIREMENT:'Experienced, responsible, outstanding technologies and management skills', + DEFINED_DOCUMENT:'developer entry in the OWNERS file owned by openEuler SIG' + } + ] + } + }, + ru: { + GUIDANCE_LIST: { + GUIDE: { + MOBILE_TITLE: "SIG申请流程", + TITLE: "Процесс применения", + LINE_CONTENT: [{ + LEFT: { + LEFT_INFO: "Отдельные пользователи или организации могут найти в сообществе openEuler двух-трех участников с общими целями, с которыми можно обсудить вопрос создания специальной группы SIG, направленной на сопровождение пакета программного обеспечения определенного типа в сообществе openEuler или на инициирование проекта развития.", + LEFT_CIRCLE: "01", + MOBILE_CIRCLE: 'Найти', + LEFT_IMG: "/img/sig/sig1.png", + LEFT_DESC: 'Найти' + }, + RIGHT: { + RIGHT_INFO: "Создайте файл приложения на Gitee и инициируйте запрос на включение кода в соответствии с процедурой настройки SIG. Сделайте заявку на участие в собрании Технического комитета. ", + RIGHT_CIRCLE: "02", + MOBILE_CIRCLE: 'Применить', + LEFT_IMG: "/img/sig/sig2.png", + RIGHT_DESC: 'Применить' + } + }, + { + LEFT: { + LEFT_INFO: "На периодически проходящем собрании Технического комитета обсуждаются технические вопросы и цели группы SIG, вырабатывается определенное компромиссное решение.", + LEFT_CIRCLE: "03", + MOBILE_CIRCLE: 'Обсудить', + LEFT_IMG: "/img/sig/sig3.png", + LEFT_DESC: 'Обсудить' + }, + RIGHT: { + RIGHT_INFO: "Создание группы SIG утверждает Технический комитет. В репозиторий исходного кода вносится соответствующий запрос на включение кода, после чего в инфраструктуре автоматически создается соответствующий репозиторий.", + RIGHT_CIRCLE: "04", + MOBILE_CIRCLE: 'Утвердить', + LEFT_IMG: "/img/sig/sig4.png", + RIGHT_DESC: 'Утвердить' + } + }, + { + LEFT: { + LEFT_INFO: "Группа SIG приступает к работе. Для проведения обсуждений и работы группы организуются регулярные совещания, участники группы оповещаются через рассылку.", + LEFT_CIRCLE: "05", + MOBILE_CIRCLE: 'Работа группы', + LEFT_IMG: "/img/sig/sig5.png", + LEFT_DESC: 'Работа группы' + }, + RIGHT: { + RIGHT_INFO: "Технический комитет периодически проверяет деятельность группы SIG и дает соответствующие указания.", + RIGHT_CIRCLE: "06", + MOBILE_CIRCLE: 'Улучшить', + LEFT_IMG: "/img/sig/sig6.png", + RIGHT_DESC: 'Улучшить' + } + }, + ] + } + }, + SIG_LIST: { + HOME_PAGE: 'Перейти на главную страницу Gitee', + MAIL: 'Эл. почта', + IRC: 'Канал IRC', + MANAGER: 'Администраторы' + }, + SIG_DESCRIPTION: { + P1: 'The openEuler community is organized based on Special Interest Groups (SIGs) to better manage and improve the work processes.', + P2: 'SIGs are open to everyone.', + LI1: 'Each SIG comprises one or more projects on Gitee, and each project has repositories that store SIG deliverables. Registering with an SIG enables you to submit, discuss, and resolve issues with other members, as well as participate in reviews in an SIG repository.', + LI2: 'An SIG is established for one or more specific technical topics. Core members of an SIG can manage each group, and members can contribute to the quality and the output of deliverables for the openEuler community.', + LI3: 'In the README.md file on the project Gitee page, you can find project SIG information, members, and contact information. You can join specific SIGs by mailing the listed email addresses. Also, you can attend public meetings, join discussions or forums, or participate in other activities listed in the corresponding README.md file.' + }, + SIG_DETAIL: { + VIDEO: 'Video', + NEWS: 'News', + MORE: 'Read More', + BLOG: 'Blog', + LATEST_DYNAMIC: "What's New", + SIG_EMPTY_TEXT1: 'Nothing found. ', + SIG_EMPTY_TEXT2: 'Add a profile ', + SIG_EMPTY_TEXT3: 'to your SIG.', + INTRODUCTION: 'SIG Introduction', + NO_MEETINGS: 'Not available now', + ORGANIZING_MEETINGS: 'SIG Schedule', + MEMBERS: 'SIG Members', + CONTACT: 'Contact', + MAIL_LIST: 'Mailing list', + EXPAND: "Expand All", + RETRACT: "Collapse All", + BLOG_EMPTY1: "Dive into the ", + BLOG_EMPTY2: "blogging guide", + BLOG_EMPTY3: " and post your first blog.", + NEWS_EMPTY: 'Broadcast the latest news of your SIG.', + NEWS_EMPTY2: 'Click ', + NEWS_EMPTY3: 'here ', + NEWS_EMPTY4: 'to publish your first SIG news.', + VIDEO_EMPTY: 'Share your first video now.' + }, + ROLE_DESCRIPTION:{ + ROLE_DESCRIPTION:'Role Description', + TABLE_TITLE:'Community Member', + TABLE_DESCRIPTION:'This article briefly describes the responsibilities and privilege of the contributor in the openEuler community. The responsibilities of most contributor are limited to SIG (Special Interest groups) :', + TABLE_THEAD:["Role","Responsibilities","Requirement","Defined Document"], + TABLE_TBODY:[ + { + ROLE:'Contributor', + RESPONSIBILITIES:'Contributors of the project', + REQUIREMENT:'', + DEFINED_DOCUMENT:'Registered members on Gitee' + }, + { + ROLE:'Committer', + RESPONSIBILITIES:'Review and approve the contributions submitted', + REQUIREMENT:'Frequently contributing to SIG, experienced,and willing to undertake review work', + DEFINED_DOCUMENT:'developer entry in the OWNERS file owned by openEuler SIG' + }, + { + ROLE:'Maintainer', + RESPONSIBILITIES:'Owner of the project', + REQUIREMENT:'Experienced, responsible, outstanding technologies and management skills', + DEFINED_DOCUMENT:'developer entry in the OWNERS file owned by openEuler SIG' + } + ] + } + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/summit.js b/web-ui/docs/.vuepress/lang/lang-modules/summit.js new file mode 100644 index 0000000000000000000000000000000000000000..442a6c3d4ce5ba829b618159d48e80f4503262f4 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/summit.js @@ -0,0 +1,4133 @@ +/** + * @file 峰会国际化配置入口 + * */ +module.exports = { + cn: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/%E6%AC%A7%E6%8B%89-375x300-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E9%A6%96%E9%A1%B5.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/1920x380%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.png" + }, + SUMMIT_INTRODUCE: "openEuler Summit 是由欧拉开源社区举办的开发者峰会。openEuler从服务器操作系统,升级为数字基础设施的操作系统,支持IT、CT、OT等数字基础设施全场景,覆盖服务器、云、边、嵌入式等各种形态的需求。伴随21.09版本的发布 openEuler 已经包含了服务器、云原生、边缘计算和嵌入式的四大应用场景。openEuler 通过开源开放,不断探索科技创新的边界,驱动物理世界与数字世界的深度融合。开发者、用户、社区贡献者、软件爱好者在 openEuler Summit 汇聚,驱动无止境的创新与拓展,闪耀数字时代星辰大海。", + LIVETITLE: '操作系统产业峰会生态伙伴直播间', + TEN_TITLE:'openEuler Summit 2021 直播间', + PC_LIVEIMG: '/img/summit/home/zh-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/zh-mobile-liveroom.png', + SUMMITLIVE: { + NINE :[ + { + ID: 9862, + THEME: '操作系统产业峰会2021', + TIME: '09:30-11:30', + OPTION: '09:30-11:30 操作系统产业峰会2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9862?lang=zh&thirdId=' + }, + { + ID: 9863, + THEME: '麒麟软件', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9863?lang=zh&thirdId=' + }, + { + ID: 9900, + THEME: '麒麟信安', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟信安', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9900?lang=zh&thirdId=' + }, + { + ID: 9901, + THEME: '统信', + TIME: '14:00-17:00', + OPTION: '14:00-17:00 统信', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9901?lang=zh&thirdId=' + }, + { + ID: 9864, + THEME: '中科创达', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 中科创达', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9864?lang=zh&thirdId=' + }, + { + ID: 9865, + THEME: '普华基础软件', + TIME: '14:00-16:30 ', + OPTION: '14:00-16:30 普华基础软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9865?lang=zh&thirdId=' + }, + ], + TEN : [ + { + ID: 9866, + THEME: 'openEuler Summit 2021', + TIME: '9:30-11:55 ', + OPTION: '9:30-11:55 openEuler Summit 2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9866?lang=zh&thirdId=' + }, + { + ID: 9867, + THEME: '内核', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 内核分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9867?lang=zh&thirdId=' + }, + { + ID: 9868, + THEME: '云&虚拟化', + TIME: '13:00-18:00 ', + OPTION: '13:00-18:00 云&虚拟化分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9868?lang=zh&thirdId=' + }, + { + ID: 9869, + THEME: '兼容性', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 兼容性分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9869?lang=zh&thirdId=' + }, + { + ID: 9870, + THEME: '安全&可靠性&运维', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 安全&可靠性&运维分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9870?lang=zh&thirdId=' + }, + { + ID: 9871, + THEME: '分布式&多样性计算', + TIME: '13:00-18:00 ', + OPTION: '13:00-17:30 分布式&多样性计算分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9871?lang=zh&thirdId=' + }, + { + ID: 9872, + THEME: '边缘&嵌入式', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 边缘&嵌入式分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9872?lang=zh&thirdId=' + }, + ] + }, + AGENDA: { + WEB_TITLE: '/img/summit/summit2021/zh-pc-summit2021.png', + MOBILE_TITLE: '/img/summit/summit2021/zh-mobile-summit2021.png', + DATE: ['11月09日', '11月10日', '上午', '下午'], + SUB_FORUM: '操作系统产业峰会生态伙伴分论坛', + FORUM_HEAD: ['麒麟软件', '麒麟信安', 'SUSE', '统信软件', '中科创达', '普华基础软件'], + FORENOON_AGENDA_9: [ + { + TIME: '09:30 - 09:45', + THEME: '开场致辞', + SPEAKER: '神秘嘉宾', + }, + { + TIME: '09:45 - 10:00', + THEME: '欧拉开源操作系统重大发布', + }, + { + TIME: '10:00 - 10:10', + THEME: '操作系统发展展望', + SPEAKER: '中国工程院院士', + }, + { + TIME: '10:10 - 10:20', + THEME: '立根铸魂,共建操作系统新生态', + SPEAKER: '华为', + }, + { + TIME: '10:20 - 10:25', + THEME: '操作系统产业宣誓', + }, + { + TIME: '10:25 - 10:55', + THEME: '行业用户实践分享', + SPEAKER: '运营商、金融等行业重磅嘉宾' + }, + { + TIME: '10:55 - 11:05', + THEME: '携手欧拉开源创新,服务中国数字时代', + SPEAKER: '麒麟软件', + }, + { + TIME: '11:05 - 11:15', + THEME: '扎根开源生态,服务中国企业,帮助中国开源系统走向世界', + SPEAKER: 'SUSE', + }, + { + TIME: '11:15 - 11:20', + THEME: '欧拉生态创新中心发布', + }, + { + TIME: '11:20 - 11:30', + THEME: '智能基座 · 欧拉人才发展加速计划发布', + }, + ], + FORENOON_AGENDA_10: [ + { + TIME: '09:30 - 09:35', + THEME: '欢迎致辞', + SPEAKER: '杨涛', + POSITION: '开放原子开源基金会理事长' + }, + { + TIME: '09:35 - 09:45', + THEME: '凝聚创新力量 逐梦数字时代星辰大海', + SPEAKER: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + TIME: '09:45 - 09:50', + THEME: '欧拉开源社区理事会升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:50 - 09:55', + THEME: '欧拉开源社区技术委员会换届升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:55 - 10:10', + THEME: '全场景欧拉 - 唯有无边界开放才能无止境增长', + SPEAKER: '胡欣蔚', + POSITION: '欧拉开源社区技术委员会主席' + }, + { + TIME: '10:10 - 10:40', + THEME: 'openEuler&Friends 2.0-协作联创激发无限可能', + SPEAKER: '中国电信、中国移动、中国联通、中科创达、华为、品高软件' + }, + { + TIME: '10:40 - 10:55', + THEME: '中国银行操作系统创新实践', + SPEAKER: '中国银行和麒麟软件联合演讲', + }, + { + TIME: '10:55 - 11:10', + THEME: '中国移动云原生生态创新实践', + SPEAKER: '中国移动和SUSE联合演讲', + }, + { + TIME: '11:10 - 11:25', + THEME: '国家电网调度控制系统创新实践', + SPEAKER: '中国电科院和麒麟信安联合演讲' + }, + { + TIME: '11:25 - 11:40', + THEME: '中国邮政业务应用创新实践', + SPEAKER: '中国邮政和统信软件联合演讲', + }, + { + TIME: '11:40 - 11:50', + THEME: '仰望星空-操作系统演讲与前沿发展思考', + SPEAKER: '陈海波', + POSITION: '上海交通大学教授 、华为操作系统首席科学家' + }, + { + TIME: '11:50 - 11:55', + THEME: '欧拉开源社区超级用户大奖', + SPEAKER: '高巍', + POSITION: '欧拉开源社区用户委员会主席' + } + ], + AFTERNOON_AGENDA_9: [ + // 麒麟软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '领导致辞', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:25', + THEME: '合作共赢,生态共生', + SPEAKER: '孔金珠', + POSITION: '麒麟软件 高级副总经理' + }, + { + TIME: '14:25 - 14:40', + THEME: '开源新时代-麒麟软件积极拥抱开源社区', + SPEAKER: '侯健', + POSITION: '麒麟软件 服务器研发部技术总监' + }, + { + TIME: '14:40 - 14:55', + THEME: '中国联通自主操作系统实践经验分享', + SPEAKER: '肖微', + POSITION: '联通软研院' + }, + { + TIME: '14:55 - 15:00', + THEME: '麒麟鲲鹏联合创新实验室揭牌', + SPEAKER: '刘海涛、高巍', + }, + { + TIME: '15:00 - 15:10', + THEME: '北京鲲鹏联合创新中心领导致辞', + SPEAKER: '刘海涛', + POSITION: '北京鲲鹏联合创新中心 首席运营官' + }, + { + TIME: '15:10 - 15:15', + THEME: '麒麟创客北京·鲲鹏应用创新大赛2021颁奖仪式', + SPEAKER: '麒麟软件、华为领导' + }, + { + TIME: '15:15 - 15:25', + THEME: '幸运抽奖 &茶歇', + }, + { + TIME: '15:25 - 15:40', + THEME: '开放联合,共建软件生态', + SPEAKER: '刘勇鹏', + POSITION: '飞腾 副总裁、软件技术方案中心总经理' + }, + { + TIME: '15:40 - 15:55', + THEME: '护航国产操作系统 打造安全计算环境', + SPEAKER: '李栋', + POSITION: '奇安信 椒图事业部副总经理' + }, + { + TIME: '15:55 - 16:10', + THEME: '价值驱动国产基础软硬件协同发展 ', + SPEAKER: '王容多', + POSITION: '同方 战略生态中心总经理 / 行业销售中心总经理' + }, + { + TIME: '16:10 - 16:25', + THEME: '携手打造基础软件根技术,助力用户创造更大价值 ', + SPEAKER: '肖枫', + POSITION: '海量数据 总裁' + }, + { + TIME: '16:25 - 16:40', + THEME: '国产数据库与操作系统的合作', + SPEAKER: '宋瑞', + POSITION: '人大金仓 高级副总裁' + }, + { + TIME: '16:40 - 16:55', + THEME: '国产中间件创新与应用', + SPEAKER: '谢耘', + POSITION: '东方通 首席科学家' + }, + { + TIME: '16:55 - 17:10', + THEME: '基于麒麟V10的分布式中间件新核心', + SPEAKER: '成勇斌', + POSITION: '金蝶天燕 副总经理' + }, + { + TIME: '17:10 - 17:20', + THEME: '幸运抽奖', + }, + ], + // 麒麟信安 + [ + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '麒麟信安领导、华为领导', + }, + { + TIME: '14:10 - 14:25', + THEME: 'openEuler技术分享', + SPEAKER: '欧拉开源社区技术专家' + }, + { + TIME: '14:25 - 14:40', + THEME: '根植欧拉开源社区构建麒麟信安操作系统', + SPEAKER: '陈松政', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '14:40 - 14:50', + THEME: '欢乐抽奖', + }, + { + TIME: '14:50 - 15:05', + THEME: '麒麟信安操作系统的工控属性', + SPEAKER: '石勇', + POSITION: '麒麟信安操作系统产品总监' + }, + { + TIME: '15:05 - 15:20', + THEME: '麒麟信安操作系统的云原生属性', + SPEAKER: '孙利杰', + POSITION: '麒麟信安操作系统、云计算产品线研发总监' + }, + { + TIME: '15:20 - 15:30', + THEME: '联合实验室揭牌仪式', + }, + { + TIME: '15:30 - 15:40', + THEME: '欢乐抽奖', + }, + { + TIME: '15:40 - 15:55', + THEME: 'CentOS停服后国产操作系统的蓝海商机 ', + SPEAKER: '任启', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '15:55 - 16:10', + THEME: '麒麟信安操作系统在电力调度和航天测发控核心系统创新应用实践', + SPEAKER: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + TIME: '16:10 - 16:30', + THEME: '圆桌论坛 ', + SPEAKER: '合作伙伴' + }, + { + TIME: '16:30 - 16:40', + THEME: '欢乐抽奖、结束', + }, + ], + // SUSE + [ + { + TIME: '14:00 - 14:10', + THEME: '数硕Linux的定位与发展', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长' + }, + { + TIME: '14:10 - 14:20', + THEME: '欧拉开源社区支持服务发布仪式', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长', + SPEAKER2: '陈伟', + POSITION2: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:20 - 14:40', + THEME: '欧拉开源社区支持服务', + SPEAKER: '陈伟', + POSITION: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:40 - 15:10', + THEME: '数硕Linux技术展望', + SPEAKER: '刘恺', + POSITION: 'SUSE Euler PD Manager' + }, + { + TIME: '15:10 - 15:25', + THEME: '茶歇', + }, + { + TIME: '15:25 - 15:55', + THEME: 'Rancher + iSulad解决方案', + SPEAKER: '江鹏', + POSITION: 'SUSE 大中华区技术总监' + }, + { + TIME: '15:55 - 16:25', + THEME: '助力国产硬件,构建自主可控业务生态', + SPEAKER: '于明', + POSITION: '长城信息股份有限公司副总裁,人工智能所所长' + }, + { + TIME: '16:25 - 16:55', + THEME: '云原生安全架构的应用实践', + SPEAKER: '刘玮', + POSITION: '上海缔赛信息技术有限公司总经理' + }, + { + TIME: '16:55 - 17:10', + THEME: '观众互动', + SPEAKER: '现场主持', + }, + ], + // 统信软件 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '朱建忠', + POSITION: '统信软件 高级副总裁' + }, + { + TIME: '14:10 - 14:40', + THEME: '打造数字时代新底座——统信服务器操作系统', + SPEAKER: '孟杰', + POSITION: '统信软件 服务器OS产线副总经理' + }, + { + TIME: '14:40 - 15:10', + THEME: '打造统信UOS操作系统新生态', + SPEAKER: '张木梁', + POSITION: '统信软件 生态中心副总经理' + }, + { + TIME: '15:10 - 15:40', + THEME: 'openEuler 技术分享', + SPEAKER: 'openEuler 技术专家', + }, + { + TIME: '15:40 - 15:50', + THEME: '茶歇', + }, + { + TIME: '15:50 - 16:05', + THEME: '共建生态、合作共赢', + SPEAKER: '邓忠良', + POSITION: '同方计算机产业本部副总经理' + }, + { + TIME: '16:05 - 16:20', + THEME: '数据相联,探索价值', + SPEAKER: '莫良伟', + POSITION: '宝德 软件部总监' + }, + { + TIME: '16:20 - 16:35', + THEME: '万亿级湖仓一体架构下的统一数据服务平台应用实践', + SPEAKER: '陈元熹 ', + POSITION: '巨杉数据库', + POSITION2: '研发资深总监', + POSITION3: '首席架构师' + }, + { + TIME: '16:35 - 16:50', + THEME: '协同办公系统信创实践与探索', + SPEAKER: '杨竹君 ', + POSITION: '泛微 政务副总经理' + }, + { + TIME: '16:50 - 17:05', + THEME: '信创数据交换平台最佳实践 ', + SPEAKER: '臧一超 ', + POSITION: '普元信息 数智研究院 副总经理' + }, + { + TIME: '17:05 - 17:20', + THEME: '融合信创生态,打造安全高效的地理信息系统', + SPEAKER: '周丹', + POSITION: '中地数码 北京副总经理' + }, + { + TIME: '17:20 - 17:30', + THEME: '抽奖环节', + }, + ], + // 中科达创 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '主持人开场', + SPEAKER: '刘寿永', + POSITION: '中科创达首席架构师' + }, + { + TIME: '14:10 - 14:30', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: '王杰章', + POSITION: '华为云原生高级工程师' + }, + { + TIME: '14:30 - 14:50', + THEME: '浅析边缘计算中间件', + SPEAKER: '徐晓晶', + POSITION: '中科创达软件架构师' + }, + { + TIME: '14:50 - 15:10', + THEME: 'Intel 边缘软件中心介绍', + SPEAKER: '冯伟', + POSITION: 'Intel边缘计算架构师' + }, + { + TIME: '15:10 - 15:20', + THEME: '茶歇 & 交流', + }, + { + TIME: '15:20 - 15:40', + THEME: '端侧边缘计算赋能千行百业', + SPEAKER: '朱勇', + POSITION: '中科创达AI技术中心负责人' + }, + { + TIME: '15:40 - 16:00', + THEME: 'EdgeX加速边缘原生应用', + SPEAKER: '路广', + POSITION: 'VMWare 中国研发总监' + }, + { + TIME: '16:00 - 16:20', + THEME: '融合发展助力智能汽车产业腾飞', + SPEAKER: '王志杰', + POSITION: '中科创达智能汽车SOA产品经理' + }, + { + TIME: '16:20 - 16:40', + THEME: '双碳背景下的边缘计算和虚拟电厂', + SPEAKER: '樊小毅', + POSITION: '江行智能CTO' + }, + ], + // 普华基础软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '致词', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:30', + THEME: '开场发言', + SPEAKER: '沈翔', + POSITION: '普华基础软件事业部总经理' + }, + { + TIME: '14:30 - 15:00', + THEME: '基于欧拉开源操作系统软硬件新品发布', + SPEAKER: '董自强', + POSITION: '普华基础软件产品部总经理' + }, + { + TIME: '15:00 - 15:20', + THEME: '茶歇 & 抽奖环节', + }, + { + TIME: '15:20 - 15:50', + THEME: '圆桌论坛:多样性算力、业务模式创新模式影响下,操作系统产业未来发展', + }, + { + TIME: '15:50 - 16:10', + THEME: '深耕基础软件根技术,普华的铸魂之路', + SPEAKER: '王伶卓', + POSITION: '普华基础软件事业部技术副总' + }, + { + TIME: '16:10 - 16:30', + THEME: '聚焦行业,普华基础软件多场景应用分享', + SPEAKER: '王江涛', + POSITION: '普华基础软件高级安全专家' + }, + { + TIME: '16:30 - 16:50', + THEME: '欢乐抽奖、结束', + }, + ], + ], + AFTERNOON_AGENDA_10: { + TIME_LIST: ['13:00-13:30', '13:30-14:00', '14:00-14:30', '14:30-15:00', '15:00-15:30', '15:30-16:00', '16:00-16:30', '16:30-17:00', '17:00-17:30', '17:30-18:00'], + CARD_LIST: [ + { + TITLE: ['Session 1', '内核'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '网络新技术MPTCP原理,协议和应用', + SPEAKER: ['唐葛亮 SUSE Linux'], + DESC: ['介绍网络新技术MPTCP(Multipath TCP)原理和协议,以及当前MPTCP upstream社区的状态,最后和大家讨论MPTCP相关应该场景。'] + }, + { + TIME: '13:30-14:00', + THEME: '内核热升级技术的应用实践', + SPEAKER: ['尹秀江 麒麟软件有限公司', '何静娴 华为'], + DESC: ['内核热升级是openEuler社区原生孵化的一项技术,为解决内核CVE漏洞和减少系统宕机时间提供了有利保障,本次议题主要介绍内核热升级技术及分享在麒麟系统上的实践经验'] + }, + { + TIME: '14:00-14:30', + THEME: '内存分级扩展在天翼云上的实践', + SPEAKER: ['张俊平 天翼云科技公司'], + DESC: ['使用傲腾内存,虚拟机内存超配,提升内存性价比,提升虚拟机性能'] + }, + { + TIME: '14:30-15:00', + THEME: 'RISC-V Linux 异构多核架构实现与挑战', + SPEAKER: ['Tan Ley Foon 赛昉'], + DESC: ['一. 介绍异构多核架构', '二. 介绍Linux 内核对异构多核架构的支持: Energy Awareness Scheduling (EAS) and Capacity Awareness Scheduling (CAS)', '三. RISC-V架构对于异构多核架构的实现与挑战'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'Bond 3+高可靠冗余通信解决方案', + SPEAKER: ['秦云高 湖南麒麟信安科技股份有限公司'], + DESC: ['高可靠性网络通信在国家电网、金融、航天领域的应用中至关重要。', '本方案通过增强Linux内核bond 3广播模式,', '1. 实现UDP零重包,网络故障时自动链路切换的可靠冗余通信。', '2. 实现TCP网络故障时零延时最高可靠冗余通信。'] + }, + { + TIME: '16:00-16:30', + THEME: '虚拟化技术在SW64自主架构的探索与实践', + SPEAKER: ['张毅 中电科申泰信息科技有限公司'], + DESC: ['1. Cpu虚拟化在申威架构上的探索与实践:接轨主流,实现了申威架构下的kvm;优化了申威架构下的中断虚拟化(时钟中断、核间中断),明显提高了中断性能。', '2. 内存虚拟化在申威架构上的探索与实践:设计了一种有别于x86架构实现的影子页表机制,该机制充分利用了申威架构的特点。并把它实现,内存虚拟化(影子页表)的相对开销数据优于x86。', '3. IO虚拟化在申威架构上的探索与实践:设计并实现了申威架构下VFIO与IOMMU:以新的驱动方式代替设备原有驱动;实现了申威架构下二级页表映射,并且实现8k和8M的页面粒度支持;以一种新的地址方式来替代真实的物理地址以增强内存的连续性和安全性。目前支持千兆、万兆网卡的设备直通。'] + }, + { + TIME: '16:30-17:00', + THEME: '内核和进程热补丁技术的实现与应用', + SPEAKER: ['唐彬 中国移动云能力中心'], + DESC: ['在日常生产过程中,经常会遇到bug或者cve等问题需要升级内核,而当前升级内核需要重启系统,这会影响业务的连续性,为了最大限度避免重启服务器,采用热补丁的方式来修复内核bug或者cve漏洞,本主题主要介绍x86与arm64架构下的内核热补丁技术实现与应用'] + }, + { + TIME: '17:00-17:30', + THEME: '支持多任务的共享虚拟内存池技术', + SPEAKER: ['丁天虹 华为技术有限公司'], + DESC: ['Linux的多任务间的共享内存对SPA(Share Physiacl Address)支持比较完善,但是在支持SVA(Share Virtual Address)上使用并不方便,任务间如果要获取统一的虚拟地址,需要独立实现地址分配和管理的框架,我们在内核实现了一致性内存管理技术(Share Pool),主要解决CPU多任务之间共享虚拟地址的问题,可以较为方便的为多应用提供统一虚拟地址,该技术适合Linux在AI计算等应用场景的使用'] + }, + ] + }, + { + TITLE: ['Session 2', '云&虚拟化'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '不同Arm厂商的CPU互相模拟', + SPEAKER: ['仇大玉 华云数据控股集团有限公司'], + DESC: ['在公有云或者专属云内,很多时候CPU架构是相通的但是厂商却不一样,尤其在ARM服务器中,默认都是host虚拟化模式,无法屏蔽底层硬件差异,除全软件模拟的方式,但是性能损耗严重,本次topic就如何实现屏蔽底层差异的硬件虚拟化方式下,实现不同ARM Vendor 的CPU互相模拟'] + }, + { + TIME: '13:30-14:00', + THEME: 'Capsule:全场景统一的新一代 Hypervisor', + SPEAKER: ['吴斌 华为'], + DESC: ['Capsule是完全由openEuler社区控制的新型Hypervisor项目。类似KVM,Capsule充分使能不同CPU体系的硬件辅助虚拟化能力。不同的是,Capsule采用Rust语言编写以带来更大的安全性。另外,Capsule重塑了Hypervisor架构,使它既可以支持普通虚拟机(满足多种多样的企业应用),也可以支持安全容器(满足容器化负载应用),同时还可以支持逻辑分区(满足实时类应用),真正做到统一各类生态,支持IT/CT/OT全场景应用。'] + }, + { + TIME: '14:00-14:30', + THEME: '基于欧拉开源操作系统的云底座操作系统NestOS', + SPEAKER: ['杜奕威 麒麟软件有限公司'], + DESC: ['NestOS是在openEuler社区孵化的云底座操作系统,搭载isulad,podman,docker等主流容器基础平台,可以适应各种不同的基础设施环境,使系统具备十分便捷的集群组建能力,与OKD紧密集成。同时NestOS可以安全的进行系统升级与回滚,可用于大规模下安全的运行容器化工作负载。'] + }, + { + TIME: '14:30-15:00', + THEME: '摄像头虚拟化', + SPEAKER: ['夏华 湖南麒麟信安科技股份有限公司'], + DESC: ['桌面云行业,通常使用usbredir作为核心技术进行usb类设备的重定向。但实际场景中,诸如usbvideo类设备,由于其过于庞大的数据流交互,收带宽限制,在云桌面场景下,使用起来非常困难。为了应对该场景,我们采用了最新的XX方案进行摄像头重定向,其根本原理在于,把交互数据的图像数据部分进行压缩,在usbredir的客户端(设备使用端)和服务端(设备接入端)两段,分别布置插件。在服务端,针对性识别出图像数据流,并模拟uvc驱动的工作,把usb数据流(urb包)整理成完整的图片帧(frame),然后对图片帧进行x264的压缩,压缩之后的数据继续通过usbredir传送到客户端。客户端的插件识别到是图片帧数据后,对其进行解压,并把图片帧还原为urb包。以此达成网络间数据的压缩功能(图片压缩,减少包头冗余)。并且以usbredir插件的行事开发。使其具有良好的兼容性(usbredir本身对各平台的兼容性都很优秀)。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '亚信科技技术中台全面兼容欧拉生态解决方案', + SPEAKER: ['薛浩 亚信科技'], + DESC: ['亚信科技的技术中台,采用完整的云原生技术体系构建,历经运营商等行业的大型系统建设上云支撑的考验,已经形成了包括从多云基础设施管理、云原生IaaS的云OS产品、云原生PaaS、边缘云MEC PaaS、Devops等技术中台能力的产品体系,服务公司各个业务产品线。', '云OS,通过统一的云原生架构的平台产品上实现主流公有云、第三方私有云产品,自建云原生IaaS的统一构建和云服务管理。通过k8s云原生的技术构建云OS的统一管理控制面,扩展支持多个第三方云的服务接入,同时也可以基于该控制面基础上管理Openstack和kubernetes(通过扩展kube-virt,kube-ovn等云原生虚拟化组件)来构建IaaS服务。在整个平台的底层计算基础设施兼容性结合华为的鲲鹏+欧拉操作系统实现虚拟机、存储、网络等基础设施云原生虚拟机化能力的构建和开放。', '全域PaaS,包括数据中心级和边缘两套产品,通过一套云原生的架构基础设施层可以结合云OS产品,也可以直接兼容第三方云平台能力,通过PaaS中的弹性计算支持的多平面、mesos和k8s的多集群的纳管和开放服务的能力,在平面级和集群级可以兼容性结合华为的鲲鹏+欧拉操作系统实现PaaS层面向业务和应用的全栈技术服务,已完成落地并服务多运营商客户的CRM、BOSS等核心系统化的国产鲲鹏、欧拉+x86异构双平面的资源池的支撑体系中,目前还在推进结合欧拉打通和边缘MEC PaaS的协同的解决方案,同时推向垂直行业信息化领域。'] + }, + { + TIME: '16:00-16:30', + THEME: '基于云原生技术分布式构建 Linux 发行版的实践分享', + SPEAKER: ['王建民 中国科学院软件研究所'], + DESC: ['EulixOS 是最早一批基于 openEuler 操作系统研发的发行版之一。在发行版的研发过程中,时常面对编译构建周期长、依赖关系复杂、软件包迭代频繁的问题,进而时常导致研发中版本不稳定、软件包合入相互等待的问题,尤其是在编译资源有限的情况下。EulixOS在研发过程中,结合团队、资源都有限的情况下,结合云原生技术对编译构建的改造,实现了较为轻量级、易部署、多架构、分布式的编译构建系统,对于更多团队基于openEuler 操作系统进行二次的商业发行版定制有借鉴意义。'] + }, + { + TIME: '16:30-17:00', + THEME: '从云计算谈系统架构演化趋势', + SPEAKER: ['汪照辉 中国银河证券'], + DESC: ['对于企业IT系统构建,开源的基础操作是基本的底座,但企业IT系统融合建设的趋势已经非常明显,传统单体建设的思路已经不合时宜,所以对很多企业来说要逐步实现基础设施资源、基础平台、业务应用系统的融合,以适应业务和技术发展的需要。从虚拟化、资源池到超融合、多云管理等,其实目的都是为了实现基础设施资源的融合,能够为上层业务系统提供用之不竭的资源能力。其实从这张图我们可能很清晰的看到多云管理(混合云管理)的重要价值。对于大部分企业来说,多云管理平台不但要管理私有云、公有云,还可能需要管理企业自身的很多物理服务器,以及虚拟化平台所提供的虚拟机管理,这样才能更好的支持上层的容器的调度和管理,以满足不同业务应用容器化对不同基础设施资源的需求。所以企业系统建设中,就不能只考虑单一系统建设,必须要考虑系统与系统之间的关系,就像我们所说的,容器云平台和云管平台就是很紧密的支撑关系,而云管则可能管理着企业的物理服务器、虚拟化、超融合、网络资源、存储资源、私有云、行业云、公有云等基础设施资源,容器云平台又支撑着企业的业务应用,运行着微服务架构的中台服务、中间件、甚至轻量数据库等。所以这是一个整体的体系建设,这也是我们一直提倡“平台融合”的建设思路。当然这并不容易,一个“中台”就让无数企业铩羽而归、爱恨交加,但整个IT系统的建设趋势是逐步走向融合的,系统与系统之间需要标准化的API,就像我们一直说的积木,彼此间的切口要规则、能契合,才能比较快的搭成期待的作品。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于可进化架构的新一代云基础设施', + SPEAKER: ['高广生 易捷行云'], + DESC: ['面对客户业务快速变化,云平台本身应具备可进化能力,EasyStack的易捷行云新一代云基础设施ECF(EasyStack Cloud Foundation)以开源生态产品化为基础,进行自主创新设计和研发构建的基于数字原生架构的一体化、场景化、可进化的全新一代云平台。已有超过500个客户在使用该产品,云基础设施ECF一套软件栈可以同时支持x86,Arm多种指令集,同时提供包括容器,云主机,裸金属多种算力,支持一个Region同时支持多种CPU架构服务器即一云多芯,同时具备全栈全平⾯OTA(Over The Air)能力,可以平滑⽆感升级包含操作系统在内的所有云平台软件,将不再受限于软件版本的限制,从⽽在某种意义上实现云平台永续⽣命周期。'] + }, + { + TIME: '17:30-18:00', + THEME: '虚拟化硬件加速-vDPA框架以及新浪私有云实践', + SPEAKER: ['杨云鹏 新浪'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 3', '兼容性'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: 'HPC应用基于openEuler的迁移实践', + SPEAKER: ['李成鹏 软通动力信息技术股份有限公司'], + DESC: ['随着大数据、云计算等技术的发展与广泛应用,HPC在行业中的应用也越来越广泛。本次议题将对多款HPC软件到openEuler的跨平台迁移实践进行技术分享。'] + }, + { + TIME: '13:30-14:00', + THEME: '携手openeuler应对操作系统国产化转型', + SPEAKER: ['叶青龙 统信软件'], + DESC: ['探讨操作系统国产化转型中的兼容性挑战,并分享统信软件结合迁移工具协助客户解决业务软硬件兼容问题转型欧拉版操作系统。'] + }, + { + TIME: '14:00-14:30', + THEME: 'SW64自主架构遇上开源欧拉,产业生态兼容的新变革', + SPEAKER: ['周元超 普华基础软件'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区全球化能力建设与展望', + SPEAKER: ['刘鹏 华为'], + DESC: ['如何服务好世界各地的开发者,匹配当地的语言、文化、开发习惯和偏好,是openEuler社区深化开源的一大挑战。openEuler G11N SIG,初步探索出了一套全球化理论和方法,并进行了若干全球化实践,希望帮助加快openEuler的全球化的进程。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'oepkgs 开放软件包服务', + SPEAKER: ['纪涛 中国科学院软件研究所'], + DESC: ['oepkgs 全称开放软件包服务由中国科学院软件研究所、openEuler 社区共同发起并提供支持,旨在为个人开发者、开源社区、OSV、ISV提供免费的软件包、容器镜像的构建、分发和下载服务的第三方平台。', '从使用的角度为大家介绍平台的注册、构建、目标架构的支持、仓库服务、查看日志等流程。', '同时为大家介绍 oepkgs 平台后续会集成的一些功能,例如签名、测试、搜索、集成合规性检查与安全检查等。'] + }, + { + TIME: '16:00-16:30', + THEME: 'CentOS迁移与操作系统兼容性生态建设', + SPEAKER: ['高巍 麒麟软件有限公司'], + DESC: ['CentOS替代工作进展、方法及行业案例'] + }, + { + TIME: '16:30-17:00', + THEME: 'openEuler 兼容性列表建设与实践', + SPEAKER: ['李萍 华为'], + DESC: ['北向兼容性软件清单来源,覆盖场景'] + }, + { + TIME: '17:00-17:30', + THEME: 'OSV认证体系实践与探索', + SPEAKER: ['李君弋 华为'], + DESC: ['介绍osv认证方案和认证体系,如何让osv走openEuler的技术路线'] + }, + ] + }, + { + TITLE: ['Session 4', '安全&可靠性&运维'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '为数据安全而生,统信软件备份还原工具分享', + SPEAKER: ['高冲 统信软件'], + DESC: ['统信软件将探讨系统运维中备份与恢复的常用技术方案, 并介绍统信备份还原工具的原理、解决案例以及未来的技术规划。'] + }, + { + TIME: '13:30-14:00', + THEME: '服务器集中运维管理系统', + SPEAKER: ['唐杰 湖南麒麟信安股份有限公司'], + DESC: ['支持大批量资产的集中管理,性能监控和告警,日志的集中存储和查询,批量软件升级,批量账户管理,u盘设备管控和安全加固。操作简便,功能强大,提高运维效率。'] + }, + { + TIME: '14:00-14:30', + THEME: '欧拉开源社区原生运维平台 -- PilotGo', + SPEAKER: ['杨昭 麒麟软件有限公司'], + DESC: ['PilotGo是openEuler社区原生孵化的运维管理平台,提供大规模集群的主机监控告警、CVE管理、软件包安装升级管理及批量运维操作等功能,保障业务系统安全、稳定运行。同时提供插件机制,对接原有操作系统的多种运维工具,可提供无感知的运维平台切换。'] + }, + { + TIME: '14:30-15:00', + THEME: '从攻击者角度看Linux内核安全', + SPEAKER: ['姚俊/王晓东 360政企安全'], + DESC: ['Linux系统在服务器和个人桌面市场有着广泛的使用,作为底层系统,其安全性非常重要。一旦被攻破,商业和个人数据可能被篡改或泄露。本议题以内核中的某个漏洞为案例,除了分析漏洞根因,还会揭秘如何借助该漏洞完成漏洞利用。同时,议题将探讨如何构建更加安全的Linux系统。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '基于蓬莱TEE的RISC-V可信机器学习框架', + SPEAKER: ['冯二虎 蓬莱TEE'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'Sec-Anti-SCA基于编译器的CPU侧信道漏洞防护技术', + SPEAKER: ['胡科开/吴财军 华为技术有限公司'], + DESC: ['自2018年针对处理器cache架构的幽灵和熔断安全漏洞被Google Project Zero曝光以来,新型侧信道漏洞的防护与消减就成为业界热点与难题。业界主流公司如Intel、微软、谷歌等都推出了基于编译器的软硬结合的解决方案,覆盖GCC、LLVM、Visual、C++等主流编译器,典型代表技术有Retpoline、Randpoline等。Gcc-Anti-SCA项目基于GCC编译器提供一个独立安全编译插件,主要针对ARM架构,通过静态代码扫描和模式识别的方式,自动识别源代码中的高风险代码段,并插入ARM架构下相应的安全防护指令。支持ARMv8.5侧信道防护新指令,并向前兼容ARMv8.0及更早的架构。在尽可能多的识别风险点,保证安全性的同时,持续优化,减少误报,把代码性能损失控制在极小的范围内。'] + }, + { + TIME: '16:30-17:00', + THEME: '操作系统漏洞修复运维探讨', + SPEAKER: ['韩永忠 普华基础软件'], + DESC: ['对于操作系统安全漏洞已经可实现异常行业检测,漏洞的风险评估以及恶意的程序检测,发现安全隐患后需要等待上游产商给予支持。隐患无法第一时间进行修复。为了解决此问题,操作系统修复的最后一公里:在发现安全隐患后、实现自动获取补丁提交更新计划、提供回退手段形成自动化的运维手段,帮助非云端客户解决本地数据中心的操作系统安全隐患。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于认知技术的openEuler漏洞感知系统', + SPEAKER: ['杨牧天 中科微澜'], + DESC: ['openEuler开源操作系统作为重要的信息基础设施和生态底座,对自身安全性有很高的要求,为此,我们在openEuler中创新性的引入认知技术,构建openEuler智能化漏洞感知能力。'] + }, + ] + }, + { + TITLE: ['Session 5', '分布式&多样性计算'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '仿真软件弹性计算', + SPEAKER: ['王松松 哈尔滨工业大学'], + DESC: ['大型仿真软件运行时多需要长时间并发运行,遇到某个计算节点挂掉后容易前功尽弃,因此发展弹性计算十分重要'] + }, + { + TIME: '13:30-14:00', + THEME: 'Arm64上开源分布式存储系统的生态进展', + SPEAKER: ['赵帅、刘新良 Linaro'], + DESC: ['在Arm64企业市场中,由于其多核并行计算和高性能IO的优势,使得Arm64在分布式存储领域拥有了使用场景。然而软件生态方面,Arm64依然有很长的路要走,不仅仅在于软件使能,项目CI,同时还需要针对相关场景的性能优化。Linaro和会员共同努力,致力于推动分布式存储系统的软件开发和生态进步。目前,我们已经在分布式存储系统,加速库,HPC文件系统等领域取得了一些进展。我们的工作主要基于对项目的使能,CI支持以及针对成熟系统在Arm64上的性能优化,同时也涉及了一些在openEuler上针对HPC文件系统的使能和验证。在本次分享中,我们将详细介绍盖Ceph,Rook, Lustre等项目的Arm CI进展,HPC文件系统的Arm支持以及在OpenEuler中使能和验证,以及利用PMDK等加速库对分布式存储系统进行优化的工作。'] + }, + { + TIME: '14:00-14:30', + THEME: '华为元戎-分布式多样性算力的理念和探索', + SPEAKER: ['梁义 华为'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区GCC优化特性介绍及前瞻', + SPEAKER: ['马明泽 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '构建openEuler的分布式能力', + SPEAKER: ['孙宏伟 华为'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'CirroData分布式数据库发展方向和工程实践', + SPEAKER: ['董山 东方国信'], + DESC: ['(1)企业级分布式架构发展方向', '(2)创新技术及在华为平台的工程实践', '(3)技术展望'] + }, + { + TIME: '16:30-17:00', + THEME: '飞腾平台基础算法优化', + SPEAKER: ['阳柳 飞腾信息技术有限公司'], + DESC: ['芯片是骨,软件是魂。高水平应用软件是提升飞腾平台的重要手段之一,而高性能的基础算法库是编写高水平应用软件的基础。本议题围绕飞腾软件生态的发展规划,紧密结合用户需求,探讨基础算法优化过程中的经验和收获。'] + }, + { + TIME: '17:00-17:30', + THEME: 'openEuler 容器 OS升级介绍', + SPEAKER: ['李元戎 华为'], + DESC: [''] + }, + { + TIME: '17:30-18:00', + THEME: '霄瀚全场景操作系统实践和应用', + SPEAKER: ['解伟俊 拓维'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 6', '边缘&嵌入式'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '欧拉开源操作系统嵌入式方向的发展规划', + SPEAKER: ['林子畅 华为技术有限公司'], + DESC: ['介绍openEuler在嵌入式方向,与之前服务器领域的异同点,后续可能的特性、功能规划'] + }, + { + TIME: '13:30-14:00', + THEME: '面向嵌入式场景的构建系统Yocto应用与思考', + SPEAKER: ['任慰 华为技术有限公司'], + DESC: ['当前openEuler的构建系统OBS主要是面向服务器场景的,对于嵌入式场景支持并不好,例如不支持交叉编译,裁剪的力度有限等。为了使openeuler的相关成果能够延伸到嵌入式领域,我们引入了面向嵌入式场景的构建系统Yocto。本议题将分享Yocto的基本情况、如何基于Yocto构建openEuler embedded、存在的问题与挑战以及面向未来的一些思考和规划'] + }, + { + TIME: '14:00-14:30', + THEME: '推动RISC-V软件生态及openEuler在VisionFive开发板的适配', + SPEAKER: ['朱潇潇 赛昉科技'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: 'RV64 异构多核处理器下实现RT-Thread和openeuler同时运行', + SPEAKER: ['张海涛 RT-thread'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: ['王杰章 华为'], + DESC: ['现如今边缘计算的应用场景非常丰富,而且面临着诸多挑战,例如:边云通信网络质量低、边缘资源受限、边缘应用离线自治和本地故障恢复、边缘节点高度分散和资源异构。针对上述问题,我们提出了云原生边缘计算平台的架构与实践——KubeEdge,并配套边缘分布式网络组件EdgeMesh与边缘协调AI框架Sedna。'] + }, + { + TIME: '16:00-16:30', + THEME: '云边协同在太空卫星上的实践探索', + SPEAKER: ['林培峰 SUSE'], + DESC: ['本议题通过实际的案例分享,探索云边协同技术如何在太空卫星上落地,如何利用云原生、DevSecOpt和边缘技术更好的在太空卫星上使用更低成本硬件,构建更安全可靠软件,实现在太空卫星上更可靠更新软件,以及更好实现AI/ML计算。'] + }, + { + TIME: '16:30-17:00', + THEME: 'Linux实时性实践与探索', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['基于openeuler做的Linux实时性探索和研究,已发布Linux嵌入式操作系统demo,支持飞腾、鲲鹏、x86平台'] + }, + ] + } + ] + }, + }, + NAV_LIST: [ + { + key: '#live', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#exhibition', + name: '线上展厅' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#publisher', + name: '出品人' + }, + { + key: '#construction', + name: '共建单位' + } + ], + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + GUIDANCE: { + TEXT_TITLE: "指导单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + } + ] + }, + HOST: { + TEXT_TITLE: "主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + STRATEGIC: { + TEXT_TITLE: "战略合作单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + } + ] + }, + CO_SPONSORED: { + TEXT_TITLE: "联合主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + } + ] + + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/yidong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dianxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/liantong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shentai.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/easystack.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/360.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/yangtao.png', + NAME: '杨涛', + POSITION: '开放原子开源基金会 理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: '欧拉开源社区副理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/qiuchengfeng.png', + NAME: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + IMG: '/img/summit/summit2021/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: '欧拉开源社区 技术委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenhaibo.png', + NAME: '陈海波', + POSITION: '上海交通大学教授 华为操作系统首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/gaowei.png', + NAME: '高巍', + POSITION: '欧拉开源社区 用户委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/qinxiaokang.png', + NAME: '秦小康', + POSITION: 'SUSE大中华区总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/wangpan.png', + NAME: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/zhanglei.png', + NAME: '张磊', + POSITION: '统信软件CTO' + }, + ], + PUBLISHER_BANNER: { + web: '/img/summit/summit2021/lecturer/publishertitle.png', + mobile: '/img/summit/summit2021/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/summit2021/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/summit2021/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/summit2021/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + HIGHLIGHTS: "精彩回顾", + }, + en: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/%E6%AC%A7%E6%8B%89-375x300-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E9%A6%96%E9%A1%B5.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/1920x380%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.png" + }, + LIVETITLE: '操作系统产业峰会生态伙伴直播间', + TEN_TITLE:'openEuler Summit 2021 直播间', + PC_LIVEIMG: '/img/summit/home/zh-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/zh-mobile-liveroom.png', + SUMMITLIVE: { + NINE :[ + { + ID: 9862, + THEME: '操作系统产业峰会2021', + TIME: '09:30-11:30', + OPTION: '09:30-11:30 操作系统产业峰会2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9862?lang=zh&thirdId=' + }, + { + ID: 9863, + THEME: '麒麟软件', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9863?lang=zh&thirdId=' + }, + { + ID: 9900, + THEME: '麒麟信安', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟信安', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9900?lang=zh&thirdId=' + }, + { + ID: 9901, + THEME: '统信', + TIME: '14:00-17:00', + OPTION: '14:00-17:00 统信', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9901?lang=zh&thirdId=' + }, + { + ID: 9864, + THEME: '中科创达', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 中科创达', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9864?lang=zh&thirdId=' + }, + { + ID: 9865, + THEME: '普华基础软件', + TIME: '14:00-16:30 ', + OPTION: '14:00-16:30 普华基础软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9865?lang=zh&thirdId=' + }, + ], + TEN : [ + { + ID: 9866, + THEME: 'openEuler Summit 2021', + TIME: '9:30-11:55 ', + OPTION: '9:30-11:55 openEuler Summit 2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9866?lang=zh&thirdId=' + }, + { + ID: 9867, + THEME: '内核', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 内核分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9867?lang=zh&thirdId=' + }, + { + ID: 9868, + THEME: '云&虚拟化', + TIME: '13:00-18:00 ', + OPTION: '13:00-18:00 云&虚拟化分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9868?lang=zh&thirdId=' + }, + { + ID: 9869, + THEME: '兼容性', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 兼容性分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9869?lang=zh&thirdId=' + }, + { + ID: 9870, + THEME: '安全&可靠性&运维', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 安全&可靠性&运维分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9870?lang=zh&thirdId=' + }, + { + ID: 9871, + THEME: '分布式&多样性计算', + TIME: '13:00-18:00 ', + OPTION: '13:00-17:30 分布式&多样性计算分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9871?lang=zh&thirdId=' + }, + { + ID: 9872, + THEME: '边缘&嵌入式', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 边缘&嵌入式分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9872?lang=zh&thirdId=' + }, + ] + }, + AGENDA: { + WEB_TITLE: '/img/summit/summit2021/zh-pc-summit2021.png', + MOBILE_TITLE: '/img/summit/summit2021/zh-mobile-summit2021.png', + DATE: ['11月09日', '11月10日', '上午', '下午'], + SUB_FORUM: '操作系统产业峰会生态伙伴分论坛', + FORUM_HEAD: ['麒麟软件', '麒麟信安', 'SUSE', '统信软件', '中科创达', '普华基础软件'], + FORENOON_AGENDA_9: [ + { + TIME: '09:30 - 09:45', + THEME: '开场致辞', + SPEAKER: '神秘嘉宾', + }, + { + TIME: '09:45 - 10:00', + THEME: '欧拉开源操作系统重大发布', + }, + { + TIME: '10:00 - 10:10', + THEME: '操作系统发展展望', + SPEAKER: '中国工程院院士', + }, + { + TIME: '10:10 - 10:20', + THEME: '立根铸魂,共建操作系统新生态', + SPEAKER: '华为', + }, + { + TIME: '10:20 - 10:25', + THEME: '操作系统产业宣誓', + }, + { + TIME: '10:25 - 10:55', + THEME: '行业用户实践分享', + SPEAKER: '运营商、金融等行业重磅嘉宾' + }, + { + TIME: '10:55 - 11:05', + THEME: '携手欧拉开源创新,服务中国数字时代', + SPEAKER: '麒麟软件', + }, + { + TIME: '11:05 - 11:15', + THEME: '扎根开源生态,服务中国企业,帮助中国开源系统走向世界', + SPEAKER: 'SUSE', + }, + { + TIME: '11:15 - 11:20', + THEME: '欧拉生态创新中心发布', + }, + { + TIME: '11:20 - 11:30', + THEME: '智能基座 · 欧拉人才发展加速计划发布', + }, + ], + FORENOON_AGENDA_10: [ + { + TIME: '09:30 - 09:35', + THEME: '欢迎致辞', + SPEAKER: '杨涛', + POSITION: '开放原子开源基金会理事长' + }, + { + TIME: '09:35 - 09:45', + THEME: '凝聚创新力量 逐梦数字时代星辰大海', + SPEAKER: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + TIME: '09:45 - 09:50', + THEME: '欧拉开源社区理事会升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:50 - 09:55', + THEME: '欧拉开源社区技术委员会换届升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:55 - 10:10', + THEME: '全场景欧拉 - 唯有无边界开放才能无止境增长', + SPEAKER: '胡欣蔚', + POSITION: '欧拉开源社区技术委员会主席' + }, + { + TIME: '10:10 - 10:40', + THEME: 'openEuler&Friends 2.0-协作联创激发无限可能', + SPEAKER: '中国电信、中国移动、中国联通、中科创达、华为、品高软件' + }, + { + TIME: '10:40 - 10:55', + THEME: '中国银行操作系统创新实践', + SPEAKER: '中国银行和麒麟软件联合演讲', + }, + { + TIME: '10:55 - 11:10', + THEME: '中国移动云原生生态创新实践', + SPEAKER: '中国移动和SUSE联合演讲', + }, + { + TIME: '11:10 - 11:25', + THEME: '国家电网调度控制系统创新实践', + SPEAKER: '中国电科院和麒麟信安联合演讲' + }, + { + TIME: '11:25 - 11:40', + THEME: '中国邮政业务应用创新实践', + SPEAKER: '中国邮政和统信软件联合演讲', + }, + { + TIME: '11:40 - 11:50', + THEME: '仰望星空-操作系统演讲与前沿发展思考', + SPEAKER: '陈海波', + POSITION: '上海交通大学教授 、华为操作系统首席科学家' + }, + { + TIME: '11:50 - 11:55', + THEME: '欧拉开源社区超级用户大奖', + SPEAKER: '高巍', + POSITION: '欧拉开源社区用户委员会主席' + } + ], + AFTERNOON_AGENDA_9: [ + // 麒麟软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '领导致辞', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:25', + THEME: '合作共赢,生态共生', + SPEAKER: '孔金珠', + POSITION: '麒麟软件 高级副总经理' + }, + { + TIME: '14:25 - 14:40', + THEME: '开源新时代-麒麟软件积极拥抱开源社区', + SPEAKER: '侯健', + POSITION: '麒麟软件 服务器研发部技术总监' + }, + { + TIME: '14:40 - 14:55', + THEME: '中国联通自主操作系统实践经验分享', + SPEAKER: '肖微', + POSITION: '联通软研院' + }, + { + TIME: '14:55 - 15:00', + THEME: '麒麟鲲鹏联合创新实验室揭牌', + SPEAKER: '刘海涛、高巍', + }, + { + TIME: '15:00 - 15:10', + THEME: '北京鲲鹏联合创新中心领导致辞', + SPEAKER: '刘海涛', + POSITION: '北京鲲鹏联合创新中心 首席运营官' + }, + { + TIME: '15:10 - 15:15', + THEME: '麒麟创客北京·鲲鹏应用创新大赛2021颁奖仪式', + SPEAKER: '麒麟软件、华为领导' + }, + { + TIME: '15:15 - 15:25', + THEME: '幸运抽奖 &茶歇', + }, + { + TIME: '15:25 - 15:40', + THEME: '开放联合,共建软件生态', + SPEAKER: '刘勇鹏', + POSITION: '飞腾 副总裁、软件技术方案中心总经理' + }, + { + TIME: '15:40 - 15:55', + THEME: '护航国产操作系统 打造安全计算环境', + SPEAKER: '李栋', + POSITION: '奇安信 椒图事业部副总经理' + }, + { + TIME: '15:55 - 16:10', + THEME: '价值驱动国产基础软硬件协同发展 ', + SPEAKER: '王容多', + POSITION: '同方 战略生态中心总经理 / 行业销售中心总经理' + }, + { + TIME: '16:10 - 16:25', + THEME: '携手打造基础软件根技术,助力用户创造更大价值 ', + SPEAKER: '肖枫', + POSITION: '海量数据 总裁' + }, + { + TIME: '16:25 - 16:40', + THEME: '国产数据库与操作系统的合作', + SPEAKER: '宋瑞', + POSITION: '人大金仓 高级副总裁' + }, + { + TIME: '16:40 - 16:55', + THEME: '国产中间件创新与应用', + SPEAKER: '谢耘', + POSITION: '东方通 首席科学家' + }, + { + TIME: '16:55 - 17:10', + THEME: '基于麒麟V10的分布式中间件新核心', + SPEAKER: '成勇斌', + POSITION: '金蝶天燕 副总经理' + }, + { + TIME: '17:10 - 17:20', + THEME: '幸运抽奖', + }, + ], + // 麒麟信安 + [ + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '麒麟信安领导、华为领导', + }, + { + TIME: '14:10 - 14:25', + THEME: 'openEuler技术分享', + SPEAKER: '欧拉开源社区技术专家' + }, + { + TIME: '14:25 - 14:40', + THEME: '根植欧拉开源社区构建麒麟信安操作系统', + SPEAKER: '陈松政', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '14:40 - 14:50', + THEME: '欢乐抽奖', + }, + { + TIME: '14:50 - 15:05', + THEME: '麒麟信安操作系统的工控属性', + SPEAKER: '石勇', + POSITION: '麒麟信安操作系统产品总监' + }, + { + TIME: '15:05 - 15:20', + THEME: '麒麟信安操作系统的云原生属性', + SPEAKER: '孙利杰', + POSITION: '麒麟信安操作系统、云计算产品线研发总监' + }, + { + TIME: '15:20 - 15:30', + THEME: '联合实验室揭牌仪式', + }, + { + TIME: '15:30 - 15:40', + THEME: '欢乐抽奖', + }, + { + TIME: '15:40 - 15:55', + THEME: 'CentOS停服后国产操作系统的蓝海商机 ', + SPEAKER: '任启', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '15:55 - 16:10', + THEME: '麒麟信安操作系统在电力调度和航天测发控核心系统创新应用实践', + SPEAKER: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + TIME: '16:10 - 16:30', + THEME: '圆桌论坛 ', + SPEAKER: '合作伙伴' + }, + { + TIME: '16:30 - 16:40', + THEME: '欢乐抽奖、结束', + }, + ], + // SUSE + [ + { + TIME: '14:00 - 14:10', + THEME: '数硕Linux的定位与发展', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长' + }, + { + TIME: '14:10 - 14:20', + THEME: '欧拉开源社区支持服务发布仪式', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长', + SPEAKER2: '陈伟', + POSITION2: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:20 - 14:40', + THEME: '欧拉开源社区支持服务', + SPEAKER: '陈伟', + POSITION: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:40 - 15:10', + THEME: '数硕Linux技术展望', + SPEAKER: '刘恺', + POSITION: 'SUSE Euler PD Manager' + }, + { + TIME: '15:10 - 15:25', + THEME: '茶歇', + }, + { + TIME: '15:25 - 15:55', + THEME: 'Rancher + iSulad解决方案', + SPEAKER: '江鹏', + POSITION: 'SUSE 大中华区技术总监' + }, + { + TIME: '15:55 - 16:25', + THEME: '助力国产硬件,构建自主可控业务生态', + SPEAKER: '于明', + POSITION: '长城信息股份有限公司副总裁,人工智能所所长' + }, + { + TIME: '16:25 - 16:55', + THEME: '云原生安全架构的应用实践', + SPEAKER: '刘玮', + POSITION: '上海缔赛信息技术有限公司总经理' + }, + { + TIME: '16:55 - 17:10', + THEME: '观众互动', + SPEAKER: '现场主持', + }, + ], + // 统信软件 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '朱建忠', + POSITION: '统信软件 高级副总裁' + }, + { + TIME: '14:10 - 14:40', + THEME: '打造数字时代新底座——统信服务器操作系统', + SPEAKER: '孟杰', + POSITION: '统信软件 服务器OS产线副总经理' + }, + { + TIME: '14:40 - 15:10', + THEME: '打造统信UOS操作系统新生态', + SPEAKER: '张木梁', + POSITION: '统信软件 生态中心副总经理' + }, + { + TIME: '15:10 - 15:40', + THEME: 'openEuler 技术分享', + SPEAKER: 'openEuler 技术专家', + }, + { + TIME: '15:40 - 15:50', + THEME: '茶歇', + }, + { + TIME: '15:50 - 16:05', + THEME: '共建生态、合作共赢', + SPEAKER: '邓忠良', + POSITION: '同方计算机产业本部副总经理' + }, + { + TIME: '16:05 - 16:20', + THEME: '数据相联,探索价值', + SPEAKER: '莫良伟', + POSITION: '宝德 软件部总监' + }, + { + TIME: '16:20 - 16:35', + THEME: '万亿级湖仓一体架构下的统一数据服务平台应用实践', + SPEAKER: '陈元熹 ', + POSITION: '巨杉数据库', + POSITION2: '研发资深总监', + POSITION3: '首席架构师' + }, + { + TIME: '16:35 - 16:50', + THEME: '协同办公系统信创实践与探索', + SPEAKER: '杨竹君 ', + POSITION: '泛微 政务副总经理' + }, + { + TIME: '16:50 - 17:05', + THEME: '信创数据交换平台最佳实践 ', + SPEAKER: '臧一超 ', + POSITION: '普元信息 数智研究院 副总经理' + }, + { + TIME: '17:05 - 17:20', + THEME: '融合信创生态,打造安全高效的地理信息系统', + SPEAKER: '周丹', + POSITION: '中地数码 北京副总经理' + }, + { + TIME: '17:20 - 17:30', + THEME: '抽奖环节', + }, + ], + // 中科达创 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '主持人开场', + SPEAKER: '刘寿永', + POSITION: '中科创达首席架构师' + }, + { + TIME: '14:10 - 14:30', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: '王杰章', + POSITION: '华为云原生高级工程师' + }, + { + TIME: '14:30 - 14:50', + THEME: '浅析边缘计算中间件', + SPEAKER: '徐晓晶', + POSITION: '中科创达软件架构师' + }, + { + TIME: '14:50 - 15:10', + THEME: 'Intel 边缘软件中心介绍', + SPEAKER: '冯伟', + POSITION: 'Intel边缘计算架构师' + }, + { + TIME: '15:10 - 15:20', + THEME: '茶歇 & 交流', + }, + { + TIME: '15:20 - 15:40', + THEME: '端侧边缘计算赋能千行百业', + SPEAKER: '朱勇', + POSITION: '中科创达AI技术中心负责人' + }, + { + TIME: '15:40 - 16:00', + THEME: 'EdgeX加速边缘原生应用', + SPEAKER: '路广', + POSITION: 'VMWare 中国研发总监' + }, + { + TIME: '16:00 - 16:20', + THEME: '融合发展助力智能汽车产业腾飞', + SPEAKER: '王志杰', + POSITION: '中科创达智能汽车SOA产品经理' + }, + { + TIME: '16:20 - 16:40', + THEME: '双碳背景下的边缘计算和虚拟电厂', + SPEAKER: '樊小毅', + POSITION: '江行智能CTO' + }, + ], + // 普华基础软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '致词', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:30', + THEME: '开场发言', + SPEAKER: '沈翔', + POSITION: '普华基础软件事业部总经理' + }, + { + TIME: '14:30 - 15:00', + THEME: '基于欧拉开源操作系统软硬件新品发布', + SPEAKER: '董自强', + POSITION: '普华基础软件产品部总经理' + }, + { + TIME: '15:00 - 15:20', + THEME: '茶歇 & 抽奖环节', + }, + { + TIME: '15:20 - 15:50', + THEME: '圆桌论坛:多样性算力、业务模式创新模式影响下,操作系统产业未来发展', + }, + { + TIME: '15:50 - 16:10', + THEME: '深耕基础软件根技术,普华的铸魂之路', + SPEAKER: '王伶卓', + POSITION: '普华基础软件事业部技术副总' + }, + { + TIME: '16:10 - 16:30', + THEME: '聚焦行业,普华基础软件多场景应用分享', + SPEAKER: '王江涛', + POSITION: '普华基础软件高级安全专家' + }, + { + TIME: '16:30 - 16:50', + THEME: '欢乐抽奖、结束', + }, + ], + ], + AFTERNOON_AGENDA_10: { + TIME_LIST: ['13:00-13:30', '13:30-14:00', '14:00-14:30', '14:30-15:00', '15:00-15:30', '15:30-16:00', '16:00-16:30', '16:30-17:00', '17:00-17:30', '17:30-18:00'], + CARD_LIST: [ + { + TITLE: ['Session 1', '内核'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '网络新技术MPTCP原理,协议和应用', + SPEAKER: ['唐葛亮 SUSE Linux'], + DESC: ['介绍网络新技术MPTCP(Multipath TCP)原理和协议,以及当前MPTCP upstream社区的状态,最后和大家讨论MPTCP相关应该场景。'] + }, + { + TIME: '13:30-14:00', + THEME: '内核热升级技术的应用实践', + SPEAKER: ['尹秀江 麒麟软件有限公司', '何静娴 华为'], + DESC: ['内核热升级是openEuler社区原生孵化的一项技术,为解决内核CVE漏洞和减少系统宕机时间提供了有利保障,本次议题主要介绍内核热升级技术及分享在麒麟系统上的实践经验'] + }, + { + TIME: '14:00-14:30', + THEME: '内存分级扩展在天翼云上的实践', + SPEAKER: ['张俊平 天翼云科技公司'], + DESC: ['使用傲腾内存,虚拟机内存超配,提升内存性价比,提升虚拟机性能'] + }, + { + TIME: '14:30-15:00', + THEME: 'RISC-V Linux 异构多核架构实现与挑战', + SPEAKER: ['Tan Ley Foon 赛昉'], + DESC: ['一. 介绍异构多核架构', '二. 介绍Linux 内核对异构多核架构的支持: Energy Awareness Scheduling (EAS) and Capacity Awareness Scheduling (CAS)', '三. RISC-V架构对于异构多核架构的实现与挑战'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'Bond 3+高可靠冗余通信解决方案', + SPEAKER: ['秦云高 湖南麒麟信安科技股份有限公司'], + DESC: ['高可靠性网络通信在国家电网、金融、航天领域的应用中至关重要。', '本方案通过增强Linux内核bond 3广播模式,', '1. 实现UDP零重包,网络故障时自动链路切换的可靠冗余通信。', '2. 实现TCP网络故障时零延时最高可靠冗余通信。'] + }, + { + TIME: '16:00-16:30', + THEME: '虚拟化技术在SW64自主架构的探索与实践', + SPEAKER: ['张毅 中电科申泰信息科技有限公司'], + DESC: ['1. Cpu虚拟化在申威架构上的探索与实践:接轨主流,实现了申威架构下的kvm;优化了申威架构下的中断虚拟化(时钟中断、核间中断),明显提高了中断性能。', '2. 内存虚拟化在申威架构上的探索与实践:设计了一种有别于x86架构实现的影子页表机制,该机制充分利用了申威架构的特点。并把它实现,内存虚拟化(影子页表)的相对开销数据优于x86。', '3. IO虚拟化在申威架构上的探索与实践:设计并实现了申威架构下VFIO与IOMMU:以新的驱动方式代替设备原有驱动;实现了申威架构下二级页表映射,并且实现8k和8M的页面粒度支持;以一种新的地址方式来替代真实的物理地址以增强内存的连续性和安全性。目前支持千兆、万兆网卡的设备直通。'] + }, + { + TIME: '16:30-17:00', + THEME: '内核和进程热补丁技术的实现与应用', + SPEAKER: ['唐彬 中国移动云能力中心'], + DESC: ['在日常生产过程中,经常会遇到bug或者cve等问题需要升级内核,而当前升级内核需要重启系统,这会影响业务的连续性,为了最大限度避免重启服务器,采用热补丁的方式来修复内核bug或者cve漏洞,本主题主要介绍x86与arm64架构下的内核热补丁技术实现与应用'] + }, + { + TIME: '17:00-17:30', + THEME: '支持多任务的共享虚拟内存池技术', + SPEAKER: ['丁天虹 华为技术有限公司'], + DESC: ['Linux的多任务间的共享内存对SPA(Share Physiacl Address)支持比较完善,但是在支持SVA(Share Virtual Address)上使用并不方便,任务间如果要获取统一的虚拟地址,需要独立实现地址分配和管理的框架,我们在内核实现了一致性内存管理技术(Share Pool),主要解决CPU多任务之间共享虚拟地址的问题,可以较为方便的为多应用提供统一虚拟地址,该技术适合Linux在AI计算等应用场景的使用'] + }, + ] + }, + { + TITLE: ['Session 2', '云&虚拟化'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '不同Arm厂商的CPU互相模拟', + SPEAKER: ['仇大玉 华云数据控股集团有限公司'], + DESC: ['在公有云或者专属云内,很多时候CPU架构是相通的但是厂商却不一样,尤其在ARM服务器中,默认都是host虚拟化模式,无法屏蔽底层硬件差异,除全软件模拟的方式,但是性能损耗严重,本次topic就如何实现屏蔽底层差异的硬件虚拟化方式下,实现不同ARM Vendor 的CPU互相模拟'] + }, + { + TIME: '13:30-14:00', + THEME: 'Capsule:全场景统一的新一代 Hypervisor', + SPEAKER: ['吴斌 华为'], + DESC: ['Capsule是完全由openEuler社区控制的新型Hypervisor项目。类似KVM,Capsule充分使能不同CPU体系的硬件辅助虚拟化能力。不同的是,Capsule采用Rust语言编写以带来更大的安全性。另外,Capsule重塑了Hypervisor架构,使它既可以支持普通虚拟机(满足多种多样的企业应用),也可以支持安全容器(满足容器化负载应用),同时还可以支持逻辑分区(满足实时类应用),真正做到统一各类生态,支持IT/CT/OT全场景应用。'] + }, + { + TIME: '14:00-14:30', + THEME: '基于欧拉开源操作系统的云底座操作系统NestOS', + SPEAKER: ['杜奕威 麒麟软件有限公司'], + DESC: ['NestOS是在openEuler社区孵化的云底座操作系统,搭载isulad,podman,docker等主流容器基础平台,可以适应各种不同的基础设施环境,使系统具备十分便捷的集群组建能力,与OKD紧密集成。同时NestOS可以安全的进行系统升级与回滚,可用于大规模下安全的运行容器化工作负载。'] + }, + { + TIME: '14:30-15:00', + THEME: '摄像头虚拟化', + SPEAKER: ['夏华 湖南麒麟信安科技股份有限公司'], + DESC: ['桌面云行业,通常使用usbredir作为核心技术进行usb类设备的重定向。但实际场景中,诸如usbvideo类设备,由于其过于庞大的数据流交互,收带宽限制,在云桌面场景下,使用起来非常困难。为了应对该场景,我们采用了最新的XX方案进行摄像头重定向,其根本原理在于,把交互数据的图像数据部分进行压缩,在usbredir的客户端(设备使用端)和服务端(设备接入端)两段,分别布置插件。在服务端,针对性识别出图像数据流,并模拟uvc驱动的工作,把usb数据流(urb包)整理成完整的图片帧(frame),然后对图片帧进行x264的压缩,压缩之后的数据继续通过usbredir传送到客户端。客户端的插件识别到是图片帧数据后,对其进行解压,并把图片帧还原为urb包。以此达成网络间数据的压缩功能(图片压缩,减少包头冗余)。并且以usbredir插件的行事开发。使其具有良好的兼容性(usbredir本身对各平台的兼容性都很优秀)。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '亚信科技技术中台全面兼容欧拉生态解决方案', + SPEAKER: ['薛浩 亚信科技'], + DESC: ['亚信科技的技术中台,采用完整的云原生技术体系构建,历经运营商等行业的大型系统建设上云支撑的考验,已经形成了包括从多云基础设施管理、云原生IaaS的云OS产品、云原生PaaS、边缘云MEC PaaS、Devops等技术中台能力的产品体系,服务公司各个业务产品线。', '云OS,通过统一的云原生架构的平台产品上实现主流公有云、第三方私有云产品,自建云原生IaaS的统一构建和云服务管理。通过k8s云原生的技术构建云OS的统一管理控制面,扩展支持多个第三方云的服务接入,同时也可以基于该控制面基础上管理Openstack和kubernetes(通过扩展kube-virt,kube-ovn等云原生虚拟化组件)来构建IaaS服务。在整个平台的底层计算基础设施兼容性结合华为的鲲鹏+欧拉操作系统实现虚拟机、存储、网络等基础设施云原生虚拟机化能力的构建和开放。', '全域PaaS,包括数据中心级和边缘两套产品,通过一套云原生的架构基础设施层可以结合云OS产品,也可以直接兼容第三方云平台能力,通过PaaS中的弹性计算支持的多平面、mesos和k8s的多集群的纳管和开放服务的能力,在平面级和集群级可以兼容性结合华为的鲲鹏+欧拉操作系统实现PaaS层面向业务和应用的全栈技术服务,已完成落地并服务多运营商客户的CRM、BOSS等核心系统化的国产鲲鹏、欧拉+x86异构双平面的资源池的支撑体系中,目前还在推进结合欧拉打通和边缘MEC PaaS的协同的解决方案,同时推向垂直行业信息化领域。'] + }, + { + TIME: '16:00-16:30', + THEME: '基于云原生技术分布式构建 Linux 发行版的实践分享', + SPEAKER: ['王建民 中国科学院软件研究所'], + DESC: ['EulixOS 是最早一批基于 openEuler 操作系统研发的发行版之一。在发行版的研发过程中,时常面对编译构建周期长、依赖关系复杂、软件包迭代频繁的问题,进而时常导致研发中版本不稳定、软件包合入相互等待的问题,尤其是在编译资源有限的情况下。EulixOS在研发过程中,结合团队、资源都有限的情况下,结合云原生技术对编译构建的改造,实现了较为轻量级、易部署、多架构、分布式的编译构建系统,对于更多团队基于openEuler 操作系统进行二次的商业发行版定制有借鉴意义。'] + }, + { + TIME: '16:30-17:00', + THEME: '从云计算谈系统架构演化趋势', + SPEAKER: ['汪照辉 中国银河证券'], + DESC: ['对于企业IT系统构建,开源的基础操作是基本的底座,但企业IT系统融合建设的趋势已经非常明显,传统单体建设的思路已经不合时宜,所以对很多企业来说要逐步实现基础设施资源、基础平台、业务应用系统的融合,以适应业务和技术发展的需要。从虚拟化、资源池到超融合、多云管理等,其实目的都是为了实现基础设施资源的融合,能够为上层业务系统提供用之不竭的资源能力。其实从这张图我们可能很清晰的看到多云管理(混合云管理)的重要价值。对于大部分企业来说,多云管理平台不但要管理私有云、公有云,还可能需要管理企业自身的很多物理服务器,以及虚拟化平台所提供的虚拟机管理,这样才能更好的支持上层的容器的调度和管理,以满足不同业务应用容器化对不同基础设施资源的需求。所以企业系统建设中,就不能只考虑单一系统建设,必须要考虑系统与系统之间的关系,就像我们所说的,容器云平台和云管平台就是很紧密的支撑关系,而云管则可能管理着企业的物理服务器、虚拟化、超融合、网络资源、存储资源、私有云、行业云、公有云等基础设施资源,容器云平台又支撑着企业的业务应用,运行着微服务架构的中台服务、中间件、甚至轻量数据库等。所以这是一个整体的体系建设,这也是我们一直提倡“平台融合”的建设思路。当然这并不容易,一个“中台”就让无数企业铩羽而归、爱恨交加,但整个IT系统的建设趋势是逐步走向融合的,系统与系统之间需要标准化的API,就像我们一直说的积木,彼此间的切口要规则、能契合,才能比较快的搭成期待的作品。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于可进化架构的新一代云基础设施', + SPEAKER: ['高广生 易捷行云'], + DESC: ['面对客户业务快速变化,云平台本身应具备可进化能力,EasyStack的易捷行云新一代云基础设施ECF(EasyStack Cloud Foundation)以开源生态产品化为基础,进行自主创新设计和研发构建的基于数字原生架构的一体化、场景化、可进化的全新一代云平台。已有超过500个客户在使用该产品,云基础设施ECF一套软件栈可以同时支持x86,Arm多种指令集,同时提供包括容器,云主机,裸金属多种算力,支持一个Region同时支持多种CPU架构服务器即一云多芯,同时具备全栈全平⾯OTA(Over The Air)能力,可以平滑⽆感升级包含操作系统在内的所有云平台软件,将不再受限于软件版本的限制,从⽽在某种意义上实现云平台永续⽣命周期。'] + }, + { + TIME: '17:30-18:00', + THEME: '虚拟化硬件加速-vDPA框架以及新浪私有云实践', + SPEAKER: ['杨云鹏 新浪'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 3', '兼容性'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: 'HPC应用基于openEuler的迁移实践', + SPEAKER: ['李成鹏 软通动力信息技术股份有限公司'], + DESC: ['随着大数据、云计算等技术的发展与广泛应用,HPC在行业中的应用也越来越广泛。本次议题将对多款HPC软件到openEuler的跨平台迁移实践进行技术分享。'] + }, + { + TIME: '13:30-14:00', + THEME: '携手openeuler应对操作系统国产化转型', + SPEAKER: ['叶青龙 统信软件'], + DESC: ['探讨操作系统国产化转型中的兼容性挑战,并分享统信软件结合迁移工具协助客户解决业务软硬件兼容问题转型欧拉版操作系统。'] + }, + { + TIME: '14:00-14:30', + THEME: 'SW64自主架构遇上开源欧拉,产业生态兼容的新变革', + SPEAKER: ['周元超 普华基础软件'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区全球化能力建设与展望', + SPEAKER: ['刘鹏 华为'], + DESC: ['如何服务好世界各地的开发者,匹配当地的语言、文化、开发习惯和偏好,是openEuler社区深化开源的一大挑战。openEuler G11N SIG,初步探索出了一套全球化理论和方法,并进行了若干全球化实践,希望帮助加快openEuler的全球化的进程。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'oepkgs 开放软件包服务', + SPEAKER: ['纪涛 中国科学院软件研究所'], + DESC: ['oepkgs 全称开放软件包服务由中国科学院软件研究所、openEuler 社区共同发起并提供支持,旨在为个人开发者、开源社区、OSV、ISV提供免费的软件包、容器镜像的构建、分发和下载服务的第三方平台。', '从使用的角度为大家介绍平台的注册、构建、目标架构的支持、仓库服务、查看日志等流程。', '同时为大家介绍 oepkgs 平台后续会集成的一些功能,例如签名、测试、搜索、集成合规性检查与安全检查等。'] + }, + { + TIME: '16:00-16:30', + THEME: 'CentOS迁移与操作系统兼容性生态建设', + SPEAKER: ['高巍 麒麟软件有限公司'], + DESC: ['CentOS替代工作进展、方法及行业案例'] + }, + { + TIME: '16:30-17:00', + THEME: 'openEuler 兼容性列表建设与实践', + SPEAKER: ['李萍 华为'], + DESC: ['北向兼容性软件清单来源,覆盖场景'] + }, + { + TIME: '17:00-17:30', + THEME: 'OSV认证体系实践与探索', + SPEAKER: ['李君弋 华为'], + DESC: ['介绍osv认证方案和认证体系,如何让osv走openEuler的技术路线'] + }, + ] + }, + { + TITLE: ['Session 4', '安全&可靠性&运维'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '为数据安全而生,统信软件备份还原工具分享', + SPEAKER: ['高冲 统信软件'], + DESC: ['统信软件将探讨系统运维中备份与恢复的常用技术方案, 并介绍统信备份还原工具的原理、解决案例以及未来的技术规划。'] + }, + { + TIME: '13:30-14:00', + THEME: '服务器集中运维管理系统', + SPEAKER: ['唐杰 湖南麒麟信安股份有限公司'], + DESC: ['支持大批量资产的集中管理,性能监控和告警,日志的集中存储和查询,批量软件升级,批量账户管理,u盘设备管控和安全加固。操作简便,功能强大,提高运维效率。'] + }, + { + TIME: '14:00-14:30', + THEME: '欧拉开源社区原生运维平台 -- PilotGo', + SPEAKER: ['杨昭 麒麟软件有限公司'], + DESC: ['PilotGo是openEuler社区原生孵化的运维管理平台,提供大规模集群的主机监控告警、CVE管理、软件包安装升级管理及批量运维操作等功能,保障业务系统安全、稳定运行。同时提供插件机制,对接原有操作系统的多种运维工具,可提供无感知的运维平台切换。'] + }, + { + TIME: '14:30-15:00', + THEME: '从攻击者角度看Linux内核安全', + SPEAKER: ['姚俊/王晓东 360政企安全'], + DESC: ['Linux系统在服务器和个人桌面市场有着广泛的使用,作为底层系统,其安全性非常重要。一旦被攻破,商业和个人数据可能被篡改或泄露。本议题以内核中的某个漏洞为案例,除了分析漏洞根因,还会揭秘如何借助该漏洞完成漏洞利用。同时,议题将探讨如何构建更加安全的Linux系统。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '基于蓬莱TEE的RISC-V可信机器学习框架', + SPEAKER: ['冯二虎 蓬莱TEE'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'Sec-Anti-SCA基于编译器的CPU侧信道漏洞防护技术', + SPEAKER: ['胡科开/吴财军 华为技术有限公司'], + DESC: ['自2018年针对处理器cache架构的幽灵和熔断安全漏洞被Google Project Zero曝光以来,新型侧信道漏洞的防护与消减就成为业界热点与难题。业界主流公司如Intel、微软、谷歌等都推出了基于编译器的软硬结合的解决方案,覆盖GCC、LLVM、Visual、C++等主流编译器,典型代表技术有Retpoline、Randpoline等。Gcc-Anti-SCA项目基于GCC编译器提供一个独立安全编译插件,主要针对ARM架构,通过静态代码扫描和模式识别的方式,自动识别源代码中的高风险代码段,并插入ARM架构下相应的安全防护指令。支持ARMv8.5侧信道防护新指令,并向前兼容ARMv8.0及更早的架构。在尽可能多的识别风险点,保证安全性的同时,持续优化,减少误报,把代码性能损失控制在极小的范围内。'] + }, + { + TIME: '16:30-17:00', + THEME: '操作系统漏洞修复运维探讨', + SPEAKER: ['韩永忠 普华基础软件'], + DESC: ['对于操作系统安全漏洞已经可实现异常行业检测,漏洞的风险评估以及恶意的程序检测,发现安全隐患后需要等待上游产商给予支持。隐患无法第一时间进行修复。为了解决此问题,操作系统修复的最后一公里:在发现安全隐患后、实现自动获取补丁提交更新计划、提供回退手段形成自动化的运维手段,帮助非云端客户解决本地数据中心的操作系统安全隐患。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于认知技术的openEuler漏洞感知系统', + SPEAKER: ['杨牧天 中科微澜'], + DESC: ['openEuler开源操作系统作为重要的信息基础设施和生态底座,对自身安全性有很高的要求,为此,我们在openEuler中创新性的引入认知技术,构建openEuler智能化漏洞感知能力。'] + }, + ] + }, + { + TITLE: ['Session 5', '分布式&多样性计算'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '仿真软件弹性计算', + SPEAKER: ['王松松 哈尔滨工业大学'], + DESC: ['大型仿真软件运行时多需要长时间并发运行,遇到某个计算节点挂掉后容易前功尽弃,因此发展弹性计算十分重要'] + }, + { + TIME: '13:30-14:00', + THEME: 'Arm64上开源分布式存储系统的生态进展', + SPEAKER: ['赵帅、刘新良 Linaro'], + DESC: ['在Arm64企业市场中,由于其多核并行计算和高性能IO的优势,使得Arm64在分布式存储领域拥有了使用场景。然而软件生态方面,Arm64依然有很长的路要走,不仅仅在于软件使能,项目CI,同时还需要针对相关场景的性能优化。Linaro和会员共同努力,致力于推动分布式存储系统的软件开发和生态进步。目前,我们已经在分布式存储系统,加速库,HPC文件系统等领域取得了一些进展。我们的工作主要基于对项目的使能,CI支持以及针对成熟系统在Arm64上的性能优化,同时也涉及了一些在openEuler上针对HPC文件系统的使能和验证。在本次分享中,我们将详细介绍盖Ceph,Rook, Lustre等项目的Arm CI进展,HPC文件系统的Arm支持以及在OpenEuler中使能和验证,以及利用PMDK等加速库对分布式存储系统进行优化的工作。'] + }, + { + TIME: '14:00-14:30', + THEME: '华为元戎-分布式多样性算力的理念和探索', + SPEAKER: ['梁义 华为'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区GCC优化特性介绍及前瞻', + SPEAKER: ['马明泽 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '构建openEuler的分布式能力', + SPEAKER: ['孙宏伟 华为'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'CirroData分布式数据库发展方向和工程实践', + SPEAKER: ['董山 东方国信'], + DESC: ['(1)企业级分布式架构发展方向', '(2)创新技术及在华为平台的工程实践', '(3)技术展望'] + }, + { + TIME: '16:30-17:00', + THEME: '飞腾平台基础算法优化', + SPEAKER: ['阳柳 飞腾信息技术有限公司'], + DESC: ['芯片是骨,软件是魂。高水平应用软件是提升飞腾平台的重要手段之一,而高性能的基础算法库是编写高水平应用软件的基础。本议题围绕飞腾软件生态的发展规划,紧密结合用户需求,探讨基础算法优化过程中的经验和收获。'] + }, + { + TIME: '17:00-17:30', + THEME: 'openEuler 容器 OS升级介绍', + SPEAKER: ['李元戎 华为'], + DESC: [''] + }, + { + TIME: '17:30-18:00', + THEME: '霄瀚全场景操作系统实践和应用', + SPEAKER: ['解伟俊 拓维'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 6', '边缘&嵌入式'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '欧拉开源操作系统嵌入式方向的发展规划', + SPEAKER: ['林子畅 华为技术有限公司'], + DESC: ['介绍openEuler在嵌入式方向,与之前服务器领域的异同点,后续可能的特性、功能规划'] + }, + { + TIME: '13:30-14:00', + THEME: '面向嵌入式场景的构建系统Yocto应用与思考', + SPEAKER: ['任慰 华为技术有限公司'], + DESC: ['当前openEuler的构建系统OBS主要是面向服务器场景的,对于嵌入式场景支持并不好,例如不支持交叉编译,裁剪的力度有限等。为了使openeuler的相关成果能够延伸到嵌入式领域,我们引入了面向嵌入式场景的构建系统Yocto。本议题将分享Yocto的基本情况、如何基于Yocto构建openEuler embedded、存在的问题与挑战以及面向未来的一些思考和规划'] + }, + { + TIME: '14:00-14:30', + THEME: '推动RISC-V软件生态及openEuler在VisionFive开发板的适配', + SPEAKER: ['朱潇潇 赛昉科技'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: 'RV64 异构多核处理器下实现RT-Thread和openeuler同时运行', + SPEAKER: ['张海涛 RT-thread'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: ['王杰章 华为'], + DESC: ['现如今边缘计算的应用场景非常丰富,而且面临着诸多挑战,例如:边云通信网络质量低、边缘资源受限、边缘应用离线自治和本地故障恢复、边缘节点高度分散和资源异构。针对上述问题,我们提出了云原生边缘计算平台的架构与实践——KubeEdge,并配套边缘分布式网络组件EdgeMesh与边缘协调AI框架Sedna。'] + }, + { + TIME: '16:00-16:30', + THEME: '云边协同在太空卫星上的实践探索', + SPEAKER: ['林培峰 SUSE'], + DESC: ['本议题通过实际的案例分享,探索云边协同技术如何在太空卫星上落地,如何利用云原生、DevSecOpt和边缘技术更好的在太空卫星上使用更低成本硬件,构建更安全可靠软件,实现在太空卫星上更可靠更新软件,以及更好实现AI/ML计算。'] + }, + { + TIME: '16:30-17:00', + THEME: 'Linux实时性实践与探索', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['基于openeuler做的Linux实时性探索和研究,已发布Linux嵌入式操作系统demo,支持飞腾、鲲鹏、x86平台'] + }, + ] + } + ] + }, + }, + NAV_LIST: [ + { + key: '#live', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#exhibition', + name: '线上展厅' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#publisher', + name: '出品人' + }, + { + key: '#construction', + name: '共建单位' + } + ], + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + GUIDANCE: { + TEXT_TITLE: "指导单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + } + ] + }, + HOST: { + TEXT_TITLE: "主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + STRATEGIC: { + TEXT_TITLE: "战略合作单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + } + ] + }, + CO_SPONSORED: { + TEXT_TITLE: "联合主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + } + ] + + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/yidong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dianxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/liantong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shentai.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/easystack.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/360.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/yangtao.png', + NAME: '杨涛', + POSITION: '开放原子开源基金会 理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: '欧拉开源社区副理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/qiuchengfeng.png', + NAME: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + IMG: '/img/summit/summit2021/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: '欧拉开源社区 技术委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenhaibo.png', + NAME: '陈海波', + POSITION: '上海交通大学教授 华为操作系统首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/gaowei.png', + NAME: '高巍', + POSITION: '欧拉开源社区 用户委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/qinxiaokang.png', + NAME: '秦小康', + POSITION: 'SUSE大中华区总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/wangpan.png', + NAME: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/zhanglei.png', + NAME: '张磊', + POSITION: '统信软件CTO' + }, + ], + PUBLISHER_BANNER: { + web: '/img/summit/summit2021/lecturer/publishertitle.png', + mobile: '/img/summit/summit2021/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/summit2021/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/summit2021/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/summit2021/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + SUMMIT_INTRODUCE: "The openEuler Summit is an event for the global developer community and IT professionals who want to learn about openEuler open source products. openEuler has evolved from a server OS into a digital infrastructure (version: 21.09) that supports IT, CT, and OT services in server, cloud native, edge computing, and embedded scenarios. At the openEuler Summit 2021, we invite developers, users, and software enthusiasts to discuss new innovations and features of openEuler, and learn from others in the community.", + HIGHLIGHTS: "Highlights" + }, + ru: { + SUMMIT_BANNER: { + MOBILE_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/%E6%AC%A7%E6%8B%89-375x300-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E9%A6%96%E9%A1%B5.png", + PC_IMG: "https://openeuler-website-beijing.obs.cn-north-4.myhuaweicloud.com/openEuler-summit-2021/images/1920x380%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.png" + }, + LIVETITLE: '操作系统产业峰会生态伙伴直播间', + TEN_TITLE:'openEuler Summit 2021 直播间', + PC_LIVEIMG: '/img/summit/home/zh-pc-liveroom.png', + MOBILE_LIVEIMG: '/img/summit/home/zh-mobile-liveroom.png', + SUMMITLIVE: { + NINE :[ + { + ID: 9862, + THEME: '操作系统产业峰会2021', + TIME: '09:30-11:30', + OPTION: '09:30-11:30 操作系统产业峰会2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9862?lang=zh&thirdId=' + }, + { + ID: 9863, + THEME: '麒麟软件', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9863?lang=zh&thirdId=' + }, + { + ID: 9900, + THEME: '麒麟信安', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 麒麟信安', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9900?lang=zh&thirdId=' + }, + { + ID: 9901, + THEME: '统信', + TIME: '14:00-17:00', + OPTION: '14:00-17:00 统信', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9901?lang=zh&thirdId=' + }, + { + ID: 9864, + THEME: '中科创达', + TIME: '14:00-16:40', + OPTION: '14:00-16:40 中科创达', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9864?lang=zh&thirdId=' + }, + { + ID: 9865, + THEME: '普华基础软件', + TIME: '14:00-16:30 ', + OPTION: '14:00-16:30 普华基础软件', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9865?lang=zh&thirdId=' + }, + ], + TEN : [ + { + ID: 9866, + THEME: 'openEuler Summit 2021', + TIME: '9:30-11:55 ', + OPTION: '9:30-11:55 openEuler Summit 2021', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9866?lang=zh&thirdId=' + }, + { + ID: 9867, + THEME: '内核', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 内核分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9867?lang=zh&thirdId=' + }, + { + ID: 9868, + THEME: '云&虚拟化', + TIME: '13:00-18:00 ', + OPTION: '13:00-18:00 云&虚拟化分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9868?lang=zh&thirdId=' + }, + { + ID: 9869, + THEME: '兼容性', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 兼容性分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9869?lang=zh&thirdId=' + }, + { + ID: 9870, + THEME: '安全&可靠性&运维', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 安全&可靠性&运维分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9870?lang=zh&thirdId=' + }, + { + ID: 9871, + THEME: '分布式&多样性计算', + TIME: '13:00-18:00 ', + OPTION: '13:00-17:30 分布式&多样性计算分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9871?lang=zh&thirdId=' + }, + { + ID: 9872, + THEME: '边缘&嵌入式', + TIME: '13:00-17:30 ', + OPTION: '13:00-17:30 边缘&嵌入式分论坛', + LIVEURL: 'https://vhall.huawei.com/v2/watch/9872?lang=zh&thirdId=' + }, + ] + }, + AGENDA: { + WEB_TITLE: '/img/summit/summit2021/zh-pc-summit2021.png', + MOBILE_TITLE: '/img/summit/summit2021/zh-mobile-summit2021.png', + DATE: ['11月09日', '11月10日', '上午', '下午'], + SUB_FORUM: '操作系统产业峰会生态伙伴分论坛', + FORUM_HEAD: ['麒麟软件', '麒麟信安', 'SUSE', '统信软件', '中科创达', '普华基础软件'], + FORENOON_AGENDA_9: [ + { + TIME: '09:30 - 09:45', + THEME: '开场致辞', + SPEAKER: '神秘嘉宾', + }, + { + TIME: '09:45 - 10:00', + THEME: '欧拉开源操作系统重大发布', + }, + { + TIME: '10:00 - 10:10', + THEME: '操作系统发展展望', + SPEAKER: '中国工程院院士', + }, + { + TIME: '10:10 - 10:20', + THEME: '立根铸魂,共建操作系统新生态', + SPEAKER: '华为', + }, + { + TIME: '10:20 - 10:25', + THEME: '操作系统产业宣誓', + }, + { + TIME: '10:25 - 10:55', + THEME: '行业用户实践分享', + SPEAKER: '运营商、金融等行业重磅嘉宾' + }, + { + TIME: '10:55 - 11:05', + THEME: '携手欧拉开源创新,服务中国数字时代', + SPEAKER: '麒麟软件', + }, + { + TIME: '11:05 - 11:15', + THEME: '扎根开源生态,服务中国企业,帮助中国开源系统走向世界', + SPEAKER: 'SUSE', + }, + { + TIME: '11:15 - 11:20', + THEME: '欧拉生态创新中心发布', + }, + { + TIME: '11:20 - 11:30', + THEME: '智能基座 · 欧拉人才发展加速计划发布', + }, + ], + FORENOON_AGENDA_10: [ + { + TIME: '09:30 - 09:35', + THEME: '欢迎致辞', + SPEAKER: '杨涛', + POSITION: '开放原子开源基金会理事长' + }, + { + TIME: '09:35 - 09:45', + THEME: '凝聚创新力量 逐梦数字时代星辰大海', + SPEAKER: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + TIME: '09:45 - 09:50', + THEME: '欧拉开源社区理事会升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:50 - 09:55', + THEME: '欧拉开源社区技术委员会换届升级仪式', + SPEAKER: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + TIME: '09:55 - 10:10', + THEME: '全场景欧拉 - 唯有无边界开放才能无止境增长', + SPEAKER: '胡欣蔚', + POSITION: '欧拉开源社区技术委员会主席' + }, + { + TIME: '10:10 - 10:40', + THEME: 'openEuler&Friends 2.0-协作联创激发无限可能', + SPEAKER: '中国电信、中国移动、中国联通、中科创达、华为、品高软件' + }, + { + TIME: '10:40 - 10:55', + THEME: '中国银行操作系统创新实践', + SPEAKER: '中国银行和麒麟软件联合演讲', + }, + { + TIME: '10:55 - 11:10', + THEME: '中国移动云原生生态创新实践', + SPEAKER: '中国移动和SUSE联合演讲', + }, + { + TIME: '11:10 - 11:25', + THEME: '国家电网调度控制系统创新实践', + SPEAKER: '中国电科院和麒麟信安联合演讲' + }, + { + TIME: '11:25 - 11:40', + THEME: '中国邮政业务应用创新实践', + SPEAKER: '中国邮政和统信软件联合演讲', + }, + { + TIME: '11:40 - 11:50', + THEME: '仰望星空-操作系统演讲与前沿发展思考', + SPEAKER: '陈海波', + POSITION: '上海交通大学教授 、华为操作系统首席科学家' + }, + { + TIME: '11:50 - 11:55', + THEME: '欧拉开源社区超级用户大奖', + SPEAKER: '高巍', + POSITION: '欧拉开源社区用户委员会主席' + } + ], + AFTERNOON_AGENDA_9: [ + // 麒麟软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '领导致辞', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:25', + THEME: '合作共赢,生态共生', + SPEAKER: '孔金珠', + POSITION: '麒麟软件 高级副总经理' + }, + { + TIME: '14:25 - 14:40', + THEME: '开源新时代-麒麟软件积极拥抱开源社区', + SPEAKER: '侯健', + POSITION: '麒麟软件 服务器研发部技术总监' + }, + { + TIME: '14:40 - 14:55', + THEME: '中国联通自主操作系统实践经验分享', + SPEAKER: '肖微', + POSITION: '联通软研院' + }, + { + TIME: '14:55 - 15:00', + THEME: '麒麟鲲鹏联合创新实验室揭牌', + SPEAKER: '刘海涛、高巍', + }, + { + TIME: '15:00 - 15:10', + THEME: '北京鲲鹏联合创新中心领导致辞', + SPEAKER: '刘海涛', + POSITION: '北京鲲鹏联合创新中心 首席运营官' + }, + { + TIME: '15:10 - 15:15', + THEME: '麒麟创客北京·鲲鹏应用创新大赛2021颁奖仪式', + SPEAKER: '麒麟软件、华为领导' + }, + { + TIME: '15:15 - 15:25', + THEME: '幸运抽奖 &茶歇', + }, + { + TIME: '15:25 - 15:40', + THEME: '开放联合,共建软件生态', + SPEAKER: '刘勇鹏', + POSITION: '飞腾 副总裁、软件技术方案中心总经理' + }, + { + TIME: '15:40 - 15:55', + THEME: '护航国产操作系统 打造安全计算环境', + SPEAKER: '李栋', + POSITION: '奇安信 椒图事业部副总经理' + }, + { + TIME: '15:55 - 16:10', + THEME: '价值驱动国产基础软硬件协同发展 ', + SPEAKER: '王容多', + POSITION: '同方 战略生态中心总经理 / 行业销售中心总经理' + }, + { + TIME: '16:10 - 16:25', + THEME: '携手打造基础软件根技术,助力用户创造更大价值 ', + SPEAKER: '肖枫', + POSITION: '海量数据 总裁' + }, + { + TIME: '16:25 - 16:40', + THEME: '国产数据库与操作系统的合作', + SPEAKER: '宋瑞', + POSITION: '人大金仓 高级副总裁' + }, + { + TIME: '16:40 - 16:55', + THEME: '国产中间件创新与应用', + SPEAKER: '谢耘', + POSITION: '东方通 首席科学家' + }, + { + TIME: '16:55 - 17:10', + THEME: '基于麒麟V10的分布式中间件新核心', + SPEAKER: '成勇斌', + POSITION: '金蝶天燕 副总经理' + }, + { + TIME: '17:10 - 17:20', + THEME: '幸运抽奖', + }, + ], + // 麒麟信安 + [ + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '麒麟信安领导、华为领导', + }, + { + TIME: '14:10 - 14:25', + THEME: 'openEuler技术分享', + SPEAKER: '欧拉开源社区技术专家' + }, + { + TIME: '14:25 - 14:40', + THEME: '根植欧拉开源社区构建麒麟信安操作系统', + SPEAKER: '陈松政', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '14:40 - 14:50', + THEME: '欢乐抽奖', + }, + { + TIME: '14:50 - 15:05', + THEME: '麒麟信安操作系统的工控属性', + SPEAKER: '石勇', + POSITION: '麒麟信安操作系统产品总监' + }, + { + TIME: '15:05 - 15:20', + THEME: '麒麟信安操作系统的云原生属性', + SPEAKER: '孙利杰', + POSITION: '麒麟信安操作系统、云计算产品线研发总监' + }, + { + TIME: '15:20 - 15:30', + THEME: '联合实验室揭牌仪式', + }, + { + TIME: '15:30 - 15:40', + THEME: '欢乐抽奖', + }, + { + TIME: '15:40 - 15:55', + THEME: 'CentOS停服后国产操作系统的蓝海商机 ', + SPEAKER: '任启', + POSITION: '麒麟信安高级副总裁' + }, + { + TIME: '15:55 - 16:10', + THEME: '麒麟信安操作系统在电力调度和航天测发控核心系统创新应用实践', + SPEAKER: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + TIME: '16:10 - 16:30', + THEME: '圆桌论坛 ', + SPEAKER: '合作伙伴' + }, + { + TIME: '16:30 - 16:40', + THEME: '欢乐抽奖、结束', + }, + ], + // SUSE + [ + { + TIME: '14:00 - 14:10', + THEME: '数硕Linux的定位与发展', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长' + }, + { + TIME: '14:10 - 14:20', + THEME: '欧拉开源社区支持服务发布仪式', + SPEAKER: '江永清', + POSITION: 'SUSE 大中华区董事长', + SPEAKER2: '陈伟', + POSITION2: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:20 - 14:40', + THEME: '欧拉开源社区支持服务', + SPEAKER: '陈伟', + POSITION: 'SUSE 大中华区Service Director' + }, + { + TIME: '14:40 - 15:10', + THEME: '数硕Linux技术展望', + SPEAKER: '刘恺', + POSITION: 'SUSE Euler PD Manager' + }, + { + TIME: '15:10 - 15:25', + THEME: '茶歇', + }, + { + TIME: '15:25 - 15:55', + THEME: 'Rancher + iSulad解决方案', + SPEAKER: '江鹏', + POSITION: 'SUSE 大中华区技术总监' + }, + { + TIME: '15:55 - 16:25', + THEME: '助力国产硬件,构建自主可控业务生态', + SPEAKER: '于明', + POSITION: '长城信息股份有限公司副总裁,人工智能所所长' + }, + { + TIME: '16:25 - 16:55', + THEME: '云原生安全架构的应用实践', + SPEAKER: '刘玮', + POSITION: '上海缔赛信息技术有限公司总经理' + }, + { + TIME: '16:55 - 17:10', + THEME: '观众互动', + SPEAKER: '现场主持', + }, + ], + // 统信软件 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '欢迎致辞', + SPEAKER: '朱建忠', + POSITION: '统信软件 高级副总裁' + }, + { + TIME: '14:10 - 14:40', + THEME: '打造数字时代新底座——统信服务器操作系统', + SPEAKER: '孟杰', + POSITION: '统信软件 服务器OS产线副总经理' + }, + { + TIME: '14:40 - 15:10', + THEME: '打造统信UOS操作系统新生态', + SPEAKER: '张木梁', + POSITION: '统信软件 生态中心副总经理' + }, + { + TIME: '15:10 - 15:40', + THEME: 'openEuler 技术分享', + SPEAKER: 'openEuler 技术专家', + }, + { + TIME: '15:40 - 15:50', + THEME: '茶歇', + }, + { + TIME: '15:50 - 16:05', + THEME: '共建生态、合作共赢', + SPEAKER: '邓忠良', + POSITION: '同方计算机产业本部副总经理' + }, + { + TIME: '16:05 - 16:20', + THEME: '数据相联,探索价值', + SPEAKER: '莫良伟', + POSITION: '宝德 软件部总监' + }, + { + TIME: '16:20 - 16:35', + THEME: '万亿级湖仓一体架构下的统一数据服务平台应用实践', + SPEAKER: '陈元熹 ', + POSITION: '巨杉数据库', + POSITION2: '研发资深总监', + POSITION3: '首席架构师' + }, + { + TIME: '16:35 - 16:50', + THEME: '协同办公系统信创实践与探索', + SPEAKER: '杨竹君 ', + POSITION: '泛微 政务副总经理' + }, + { + TIME: '16:50 - 17:05', + THEME: '信创数据交换平台最佳实践 ', + SPEAKER: '臧一超 ', + POSITION: '普元信息 数智研究院 副总经理' + }, + { + TIME: '17:05 - 17:20', + THEME: '融合信创生态,打造安全高效的地理信息系统', + SPEAKER: '周丹', + POSITION: '中地数码 北京副总经理' + }, + { + TIME: '17:20 - 17:30', + THEME: '抽奖环节', + }, + ], + // 中科达创 + [ + { + TIME: '13:30 - 14:00', + THEME: '签到入场', + }, + { + TIME: '14:00 - 14:10', + THEME: '主持人开场', + SPEAKER: '刘寿永', + POSITION: '中科创达首席架构师' + }, + { + TIME: '14:10 - 14:30', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: '王杰章', + POSITION: '华为云原生高级工程师' + }, + { + TIME: '14:30 - 14:50', + THEME: '浅析边缘计算中间件', + SPEAKER: '徐晓晶', + POSITION: '中科创达软件架构师' + }, + { + TIME: '14:50 - 15:10', + THEME: 'Intel 边缘软件中心介绍', + SPEAKER: '冯伟', + POSITION: 'Intel边缘计算架构师' + }, + { + TIME: '15:10 - 15:20', + THEME: '茶歇 & 交流', + }, + { + TIME: '15:20 - 15:40', + THEME: '端侧边缘计算赋能千行百业', + SPEAKER: '朱勇', + POSITION: '中科创达AI技术中心负责人' + }, + { + TIME: '15:40 - 16:00', + THEME: 'EdgeX加速边缘原生应用', + SPEAKER: '路广', + POSITION: 'VMWare 中国研发总监' + }, + { + TIME: '16:00 - 16:20', + THEME: '融合发展助力智能汽车产业腾飞', + SPEAKER: '王志杰', + POSITION: '中科创达智能汽车SOA产品经理' + }, + { + TIME: '16:20 - 16:40', + THEME: '双碳背景下的边缘计算和虚拟电厂', + SPEAKER: '樊小毅', + POSITION: '江行智能CTO' + }, + ], + // 普华基础软件 + [ + { + TIME: '14:00 - 14:10', + THEME: '致词', + SPEAKER: '华为领导' + }, + { + TIME: '14:10 - 14:30', + THEME: '开场发言', + SPEAKER: '沈翔', + POSITION: '普华基础软件事业部总经理' + }, + { + TIME: '14:30 - 15:00', + THEME: '基于欧拉开源操作系统软硬件新品发布', + SPEAKER: '董自强', + POSITION: '普华基础软件产品部总经理' + }, + { + TIME: '15:00 - 15:20', + THEME: '茶歇 & 抽奖环节', + }, + { + TIME: '15:20 - 15:50', + THEME: '圆桌论坛:多样性算力、业务模式创新模式影响下,操作系统产业未来发展', + }, + { + TIME: '15:50 - 16:10', + THEME: '深耕基础软件根技术,普华的铸魂之路', + SPEAKER: '王伶卓', + POSITION: '普华基础软件事业部技术副总' + }, + { + TIME: '16:10 - 16:30', + THEME: '聚焦行业,普华基础软件多场景应用分享', + SPEAKER: '王江涛', + POSITION: '普华基础软件高级安全专家' + }, + { + TIME: '16:30 - 16:50', + THEME: '欢乐抽奖、结束', + }, + ], + ], + AFTERNOON_AGENDA_10: { + TIME_LIST: ['13:00-13:30', '13:30-14:00', '14:00-14:30', '14:30-15:00', '15:00-15:30', '15:30-16:00', '16:00-16:30', '16:30-17:00', '17:00-17:30', '17:30-18:00'], + CARD_LIST: [ + { + TITLE: ['Session 1', '内核'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '网络新技术MPTCP原理,协议和应用', + SPEAKER: ['唐葛亮 SUSE Linux'], + DESC: ['介绍网络新技术MPTCP(Multipath TCP)原理和协议,以及当前MPTCP upstream社区的状态,最后和大家讨论MPTCP相关应该场景。'] + }, + { + TIME: '13:30-14:00', + THEME: '内核热升级技术的应用实践', + SPEAKER: ['尹秀江 麒麟软件有限公司', '何静娴 华为'], + DESC: ['内核热升级是openEuler社区原生孵化的一项技术,为解决内核CVE漏洞和减少系统宕机时间提供了有利保障,本次议题主要介绍内核热升级技术及分享在麒麟系统上的实践经验'] + }, + { + TIME: '14:00-14:30', + THEME: '内存分级扩展在天翼云上的实践', + SPEAKER: ['张俊平 天翼云科技公司'], + DESC: ['使用傲腾内存,虚拟机内存超配,提升内存性价比,提升虚拟机性能'] + }, + { + TIME: '14:30-15:00', + THEME: 'RISC-V Linux 异构多核架构实现与挑战', + SPEAKER: ['Tan Ley Foon 赛昉'], + DESC: ['一. 介绍异构多核架构', '二. 介绍Linux 内核对异构多核架构的支持: Energy Awareness Scheduling (EAS) and Capacity Awareness Scheduling (CAS)', '三. RISC-V架构对于异构多核架构的实现与挑战'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'Bond 3+高可靠冗余通信解决方案', + SPEAKER: ['秦云高 湖南麒麟信安科技股份有限公司'], + DESC: ['高可靠性网络通信在国家电网、金融、航天领域的应用中至关重要。', '本方案通过增强Linux内核bond 3广播模式,', '1. 实现UDP零重包,网络故障时自动链路切换的可靠冗余通信。', '2. 实现TCP网络故障时零延时最高可靠冗余通信。'] + }, + { + TIME: '16:00-16:30', + THEME: '虚拟化技术在SW64自主架构的探索与实践', + SPEAKER: ['张毅 中电科申泰信息科技有限公司'], + DESC: ['1. Cpu虚拟化在申威架构上的探索与实践:接轨主流,实现了申威架构下的kvm;优化了申威架构下的中断虚拟化(时钟中断、核间中断),明显提高了中断性能。', '2. 内存虚拟化在申威架构上的探索与实践:设计了一种有别于x86架构实现的影子页表机制,该机制充分利用了申威架构的特点。并把它实现,内存虚拟化(影子页表)的相对开销数据优于x86。', '3. IO虚拟化在申威架构上的探索与实践:设计并实现了申威架构下VFIO与IOMMU:以新的驱动方式代替设备原有驱动;实现了申威架构下二级页表映射,并且实现8k和8M的页面粒度支持;以一种新的地址方式来替代真实的物理地址以增强内存的连续性和安全性。目前支持千兆、万兆网卡的设备直通。'] + }, + { + TIME: '16:30-17:00', + THEME: '内核和进程热补丁技术的实现与应用', + SPEAKER: ['唐彬 中国移动云能力中心'], + DESC: ['在日常生产过程中,经常会遇到bug或者cve等问题需要升级内核,而当前升级内核需要重启系统,这会影响业务的连续性,为了最大限度避免重启服务器,采用热补丁的方式来修复内核bug或者cve漏洞,本主题主要介绍x86与arm64架构下的内核热补丁技术实现与应用'] + }, + { + TIME: '17:00-17:30', + THEME: '支持多任务的共享虚拟内存池技术', + SPEAKER: ['丁天虹 华为技术有限公司'], + DESC: ['Linux的多任务间的共享内存对SPA(Share Physiacl Address)支持比较完善,但是在支持SVA(Share Virtual Address)上使用并不方便,任务间如果要获取统一的虚拟地址,需要独立实现地址分配和管理的框架,我们在内核实现了一致性内存管理技术(Share Pool),主要解决CPU多任务之间共享虚拟地址的问题,可以较为方便的为多应用提供统一虚拟地址,该技术适合Linux在AI计算等应用场景的使用'] + }, + ] + }, + { + TITLE: ['Session 2', '云&虚拟化'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '不同Arm厂商的CPU互相模拟', + SPEAKER: ['仇大玉 华云数据控股集团有限公司'], + DESC: ['在公有云或者专属云内,很多时候CPU架构是相通的但是厂商却不一样,尤其在ARM服务器中,默认都是host虚拟化模式,无法屏蔽底层硬件差异,除全软件模拟的方式,但是性能损耗严重,本次topic就如何实现屏蔽底层差异的硬件虚拟化方式下,实现不同ARM Vendor 的CPU互相模拟'] + }, + { + TIME: '13:30-14:00', + THEME: 'Capsule:全场景统一的新一代 Hypervisor', + SPEAKER: ['吴斌 华为'], + DESC: ['Capsule是完全由openEuler社区控制的新型Hypervisor项目。类似KVM,Capsule充分使能不同CPU体系的硬件辅助虚拟化能力。不同的是,Capsule采用Rust语言编写以带来更大的安全性。另外,Capsule重塑了Hypervisor架构,使它既可以支持普通虚拟机(满足多种多样的企业应用),也可以支持安全容器(满足容器化负载应用),同时还可以支持逻辑分区(满足实时类应用),真正做到统一各类生态,支持IT/CT/OT全场景应用。'] + }, + { + TIME: '14:00-14:30', + THEME: '基于欧拉开源操作系统的云底座操作系统NestOS', + SPEAKER: ['杜奕威 麒麟软件有限公司'], + DESC: ['NestOS是在openEuler社区孵化的云底座操作系统,搭载isulad,podman,docker等主流容器基础平台,可以适应各种不同的基础设施环境,使系统具备十分便捷的集群组建能力,与OKD紧密集成。同时NestOS可以安全的进行系统升级与回滚,可用于大规模下安全的运行容器化工作负载。'] + }, + { + TIME: '14:30-15:00', + THEME: '摄像头虚拟化', + SPEAKER: ['夏华 湖南麒麟信安科技股份有限公司'], + DESC: ['桌面云行业,通常使用usbredir作为核心技术进行usb类设备的重定向。但实际场景中,诸如usbvideo类设备,由于其过于庞大的数据流交互,收带宽限制,在云桌面场景下,使用起来非常困难。为了应对该场景,我们采用了最新的XX方案进行摄像头重定向,其根本原理在于,把交互数据的图像数据部分进行压缩,在usbredir的客户端(设备使用端)和服务端(设备接入端)两段,分别布置插件。在服务端,针对性识别出图像数据流,并模拟uvc驱动的工作,把usb数据流(urb包)整理成完整的图片帧(frame),然后对图片帧进行x264的压缩,压缩之后的数据继续通过usbredir传送到客户端。客户端的插件识别到是图片帧数据后,对其进行解压,并把图片帧还原为urb包。以此达成网络间数据的压缩功能(图片压缩,减少包头冗余)。并且以usbredir插件的行事开发。使其具有良好的兼容性(usbredir本身对各平台的兼容性都很优秀)。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '亚信科技技术中台全面兼容欧拉生态解决方案', + SPEAKER: ['薛浩 亚信科技'], + DESC: ['亚信科技的技术中台,采用完整的云原生技术体系构建,历经运营商等行业的大型系统建设上云支撑的考验,已经形成了包括从多云基础设施管理、云原生IaaS的云OS产品、云原生PaaS、边缘云MEC PaaS、Devops等技术中台能力的产品体系,服务公司各个业务产品线。', '云OS,通过统一的云原生架构的平台产品上实现主流公有云、第三方私有云产品,自建云原生IaaS的统一构建和云服务管理。通过k8s云原生的技术构建云OS的统一管理控制面,扩展支持多个第三方云的服务接入,同时也可以基于该控制面基础上管理Openstack和kubernetes(通过扩展kube-virt,kube-ovn等云原生虚拟化组件)来构建IaaS服务。在整个平台的底层计算基础设施兼容性结合华为的鲲鹏+欧拉操作系统实现虚拟机、存储、网络等基础设施云原生虚拟机化能力的构建和开放。', '全域PaaS,包括数据中心级和边缘两套产品,通过一套云原生的架构基础设施层可以结合云OS产品,也可以直接兼容第三方云平台能力,通过PaaS中的弹性计算支持的多平面、mesos和k8s的多集群的纳管和开放服务的能力,在平面级和集群级可以兼容性结合华为的鲲鹏+欧拉操作系统实现PaaS层面向业务和应用的全栈技术服务,已完成落地并服务多运营商客户的CRM、BOSS等核心系统化的国产鲲鹏、欧拉+x86异构双平面的资源池的支撑体系中,目前还在推进结合欧拉打通和边缘MEC PaaS的协同的解决方案,同时推向垂直行业信息化领域。'] + }, + { + TIME: '16:00-16:30', + THEME: '基于云原生技术分布式构建 Linux 发行版的实践分享', + SPEAKER: ['王建民 中国科学院软件研究所'], + DESC: ['EulixOS 是最早一批基于 openEuler 操作系统研发的发行版之一。在发行版的研发过程中,时常面对编译构建周期长、依赖关系复杂、软件包迭代频繁的问题,进而时常导致研发中版本不稳定、软件包合入相互等待的问题,尤其是在编译资源有限的情况下。EulixOS在研发过程中,结合团队、资源都有限的情况下,结合云原生技术对编译构建的改造,实现了较为轻量级、易部署、多架构、分布式的编译构建系统,对于更多团队基于openEuler 操作系统进行二次的商业发行版定制有借鉴意义。'] + }, + { + TIME: '16:30-17:00', + THEME: '从云计算谈系统架构演化趋势', + SPEAKER: ['汪照辉 中国银河证券'], + DESC: ['对于企业IT系统构建,开源的基础操作是基本的底座,但企业IT系统融合建设的趋势已经非常明显,传统单体建设的思路已经不合时宜,所以对很多企业来说要逐步实现基础设施资源、基础平台、业务应用系统的融合,以适应业务和技术发展的需要。从虚拟化、资源池到超融合、多云管理等,其实目的都是为了实现基础设施资源的融合,能够为上层业务系统提供用之不竭的资源能力。其实从这张图我们可能很清晰的看到多云管理(混合云管理)的重要价值。对于大部分企业来说,多云管理平台不但要管理私有云、公有云,还可能需要管理企业自身的很多物理服务器,以及虚拟化平台所提供的虚拟机管理,这样才能更好的支持上层的容器的调度和管理,以满足不同业务应用容器化对不同基础设施资源的需求。所以企业系统建设中,就不能只考虑单一系统建设,必须要考虑系统与系统之间的关系,就像我们所说的,容器云平台和云管平台就是很紧密的支撑关系,而云管则可能管理着企业的物理服务器、虚拟化、超融合、网络资源、存储资源、私有云、行业云、公有云等基础设施资源,容器云平台又支撑着企业的业务应用,运行着微服务架构的中台服务、中间件、甚至轻量数据库等。所以这是一个整体的体系建设,这也是我们一直提倡“平台融合”的建设思路。当然这并不容易,一个“中台”就让无数企业铩羽而归、爱恨交加,但整个IT系统的建设趋势是逐步走向融合的,系统与系统之间需要标准化的API,就像我们一直说的积木,彼此间的切口要规则、能契合,才能比较快的搭成期待的作品。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于可进化架构的新一代云基础设施', + SPEAKER: ['高广生 易捷行云'], + DESC: ['面对客户业务快速变化,云平台本身应具备可进化能力,EasyStack的易捷行云新一代云基础设施ECF(EasyStack Cloud Foundation)以开源生态产品化为基础,进行自主创新设计和研发构建的基于数字原生架构的一体化、场景化、可进化的全新一代云平台。已有超过500个客户在使用该产品,云基础设施ECF一套软件栈可以同时支持x86,Arm多种指令集,同时提供包括容器,云主机,裸金属多种算力,支持一个Region同时支持多种CPU架构服务器即一云多芯,同时具备全栈全平⾯OTA(Over The Air)能力,可以平滑⽆感升级包含操作系统在内的所有云平台软件,将不再受限于软件版本的限制,从⽽在某种意义上实现云平台永续⽣命周期。'] + }, + { + TIME: '17:30-18:00', + THEME: '虚拟化硬件加速-vDPA框架以及新浪私有云实践', + SPEAKER: ['杨云鹏 新浪'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 3', '兼容性'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: 'HPC应用基于openEuler的迁移实践', + SPEAKER: ['李成鹏 软通动力信息技术股份有限公司'], + DESC: ['随着大数据、云计算等技术的发展与广泛应用,HPC在行业中的应用也越来越广泛。本次议题将对多款HPC软件到openEuler的跨平台迁移实践进行技术分享。'] + }, + { + TIME: '13:30-14:00', + THEME: '携手openeuler应对操作系统国产化转型', + SPEAKER: ['叶青龙 统信软件'], + DESC: ['探讨操作系统国产化转型中的兼容性挑战,并分享统信软件结合迁移工具协助客户解决业务软硬件兼容问题转型欧拉版操作系统。'] + }, + { + TIME: '14:00-14:30', + THEME: 'SW64自主架构遇上开源欧拉,产业生态兼容的新变革', + SPEAKER: ['周元超 普华基础软件'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区全球化能力建设与展望', + SPEAKER: ['刘鹏 华为'], + DESC: ['如何服务好世界各地的开发者,匹配当地的语言、文化、开发习惯和偏好,是openEuler社区深化开源的一大挑战。openEuler G11N SIG,初步探索出了一套全球化理论和方法,并进行了若干全球化实践,希望帮助加快openEuler的全球化的进程。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: 'oepkgs 开放软件包服务', + SPEAKER: ['纪涛 中国科学院软件研究所'], + DESC: ['oepkgs 全称开放软件包服务由中国科学院软件研究所、openEuler 社区共同发起并提供支持,旨在为个人开发者、开源社区、OSV、ISV提供免费的软件包、容器镜像的构建、分发和下载服务的第三方平台。', '从使用的角度为大家介绍平台的注册、构建、目标架构的支持、仓库服务、查看日志等流程。', '同时为大家介绍 oepkgs 平台后续会集成的一些功能,例如签名、测试、搜索、集成合规性检查与安全检查等。'] + }, + { + TIME: '16:00-16:30', + THEME: 'CentOS迁移与操作系统兼容性生态建设', + SPEAKER: ['高巍 麒麟软件有限公司'], + DESC: ['CentOS替代工作进展、方法及行业案例'] + }, + { + TIME: '16:30-17:00', + THEME: 'openEuler 兼容性列表建设与实践', + SPEAKER: ['李萍 华为'], + DESC: ['北向兼容性软件清单来源,覆盖场景'] + }, + { + TIME: '17:00-17:30', + THEME: 'OSV认证体系实践与探索', + SPEAKER: ['李君弋 华为'], + DESC: ['介绍osv认证方案和认证体系,如何让osv走openEuler的技术路线'] + }, + ] + }, + { + TITLE: ['Session 4', '安全&可靠性&运维'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '为数据安全而生,统信软件备份还原工具分享', + SPEAKER: ['高冲 统信软件'], + DESC: ['统信软件将探讨系统运维中备份与恢复的常用技术方案, 并介绍统信备份还原工具的原理、解决案例以及未来的技术规划。'] + }, + { + TIME: '13:30-14:00', + THEME: '服务器集中运维管理系统', + SPEAKER: ['唐杰 湖南麒麟信安股份有限公司'], + DESC: ['支持大批量资产的集中管理,性能监控和告警,日志的集中存储和查询,批量软件升级,批量账户管理,u盘设备管控和安全加固。操作简便,功能强大,提高运维效率。'] + }, + { + TIME: '14:00-14:30', + THEME: '欧拉开源社区原生运维平台 -- PilotGo', + SPEAKER: ['杨昭 麒麟软件有限公司'], + DESC: ['PilotGo是openEuler社区原生孵化的运维管理平台,提供大规模集群的主机监控告警、CVE管理、软件包安装升级管理及批量运维操作等功能,保障业务系统安全、稳定运行。同时提供插件机制,对接原有操作系统的多种运维工具,可提供无感知的运维平台切换。'] + }, + { + TIME: '14:30-15:00', + THEME: '从攻击者角度看Linux内核安全', + SPEAKER: ['姚俊/王晓东 360政企安全'], + DESC: ['Linux系统在服务器和个人桌面市场有着广泛的使用,作为底层系统,其安全性非常重要。一旦被攻破,商业和个人数据可能被篡改或泄露。本议题以内核中的某个漏洞为案例,除了分析漏洞根因,还会揭秘如何借助该漏洞完成漏洞利用。同时,议题将探讨如何构建更加安全的Linux系统。'] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '基于蓬莱TEE的RISC-V可信机器学习框架', + SPEAKER: ['冯二虎 蓬莱TEE'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'Sec-Anti-SCA基于编译器的CPU侧信道漏洞防护技术', + SPEAKER: ['胡科开/吴财军 华为技术有限公司'], + DESC: ['自2018年针对处理器cache架构的幽灵和熔断安全漏洞被Google Project Zero曝光以来,新型侧信道漏洞的防护与消减就成为业界热点与难题。业界主流公司如Intel、微软、谷歌等都推出了基于编译器的软硬结合的解决方案,覆盖GCC、LLVM、Visual、C++等主流编译器,典型代表技术有Retpoline、Randpoline等。Gcc-Anti-SCA项目基于GCC编译器提供一个独立安全编译插件,主要针对ARM架构,通过静态代码扫描和模式识别的方式,自动识别源代码中的高风险代码段,并插入ARM架构下相应的安全防护指令。支持ARMv8.5侧信道防护新指令,并向前兼容ARMv8.0及更早的架构。在尽可能多的识别风险点,保证安全性的同时,持续优化,减少误报,把代码性能损失控制在极小的范围内。'] + }, + { + TIME: '16:30-17:00', + THEME: '操作系统漏洞修复运维探讨', + SPEAKER: ['韩永忠 普华基础软件'], + DESC: ['对于操作系统安全漏洞已经可实现异常行业检测,漏洞的风险评估以及恶意的程序检测,发现安全隐患后需要等待上游产商给予支持。隐患无法第一时间进行修复。为了解决此问题,操作系统修复的最后一公里:在发现安全隐患后、实现自动获取补丁提交更新计划、提供回退手段形成自动化的运维手段,帮助非云端客户解决本地数据中心的操作系统安全隐患。'] + }, + { + TIME: '17:00-17:30', + THEME: '基于认知技术的openEuler漏洞感知系统', + SPEAKER: ['杨牧天 中科微澜'], + DESC: ['openEuler开源操作系统作为重要的信息基础设施和生态底座,对自身安全性有很高的要求,为此,我们在openEuler中创新性的引入认知技术,构建openEuler智能化漏洞感知能力。'] + }, + ] + }, + { + TITLE: ['Session 5', '分布式&多样性计算'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '仿真软件弹性计算', + SPEAKER: ['王松松 哈尔滨工业大学'], + DESC: ['大型仿真软件运行时多需要长时间并发运行,遇到某个计算节点挂掉后容易前功尽弃,因此发展弹性计算十分重要'] + }, + { + TIME: '13:30-14:00', + THEME: 'Arm64上开源分布式存储系统的生态进展', + SPEAKER: ['赵帅、刘新良 Linaro'], + DESC: ['在Arm64企业市场中,由于其多核并行计算和高性能IO的优势,使得Arm64在分布式存储领域拥有了使用场景。然而软件生态方面,Arm64依然有很长的路要走,不仅仅在于软件使能,项目CI,同时还需要针对相关场景的性能优化。Linaro和会员共同努力,致力于推动分布式存储系统的软件开发和生态进步。目前,我们已经在分布式存储系统,加速库,HPC文件系统等领域取得了一些进展。我们的工作主要基于对项目的使能,CI支持以及针对成熟系统在Arm64上的性能优化,同时也涉及了一些在openEuler上针对HPC文件系统的使能和验证。在本次分享中,我们将详细介绍盖Ceph,Rook, Lustre等项目的Arm CI进展,HPC文件系统的Arm支持以及在OpenEuler中使能和验证,以及利用PMDK等加速库对分布式存储系统进行优化的工作。'] + }, + { + TIME: '14:00-14:30', + THEME: '华为元戎-分布式多样性算力的理念和探索', + SPEAKER: ['梁义 华为'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: '欧拉开源社区GCC优化特性介绍及前瞻', + SPEAKER: ['马明泽 华为'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '构建openEuler的分布式能力', + SPEAKER: ['孙宏伟 华为'], + DESC: [''] + }, + { + TIME: '16:00-16:30', + THEME: 'CirroData分布式数据库发展方向和工程实践', + SPEAKER: ['董山 东方国信'], + DESC: ['(1)企业级分布式架构发展方向', '(2)创新技术及在华为平台的工程实践', '(3)技术展望'] + }, + { + TIME: '16:30-17:00', + THEME: '飞腾平台基础算法优化', + SPEAKER: ['阳柳 飞腾信息技术有限公司'], + DESC: ['芯片是骨,软件是魂。高水平应用软件是提升飞腾平台的重要手段之一,而高性能的基础算法库是编写高水平应用软件的基础。本议题围绕飞腾软件生态的发展规划,紧密结合用户需求,探讨基础算法优化过程中的经验和收获。'] + }, + { + TIME: '17:00-17:30', + THEME: 'openEuler 容器 OS升级介绍', + SPEAKER: ['李元戎 华为'], + DESC: [''] + }, + { + TIME: '17:30-18:00', + THEME: '霄瀚全场景操作系统实践和应用', + SPEAKER: ['解伟俊 拓维'], + DESC: [''] + }, + ] + }, + { + TITLE: ['Session 6', '边缘&嵌入式'], + ITEM_LIST: [ + { + TIME: '13:00-13:30', + THEME: '欧拉开源操作系统嵌入式方向的发展规划', + SPEAKER: ['林子畅 华为技术有限公司'], + DESC: ['介绍openEuler在嵌入式方向,与之前服务器领域的异同点,后续可能的特性、功能规划'] + }, + { + TIME: '13:30-14:00', + THEME: '面向嵌入式场景的构建系统Yocto应用与思考', + SPEAKER: ['任慰 华为技术有限公司'], + DESC: ['当前openEuler的构建系统OBS主要是面向服务器场景的,对于嵌入式场景支持并不好,例如不支持交叉编译,裁剪的力度有限等。为了使openeuler的相关成果能够延伸到嵌入式领域,我们引入了面向嵌入式场景的构建系统Yocto。本议题将分享Yocto的基本情况、如何基于Yocto构建openEuler embedded、存在的问题与挑战以及面向未来的一些思考和规划'] + }, + { + TIME: '14:00-14:30', + THEME: '推动RISC-V软件生态及openEuler在VisionFive开发板的适配', + SPEAKER: ['朱潇潇 赛昉科技'], + DESC: [''] + }, + { + TIME: '14:30-15:00', + THEME: 'RV64 异构多核处理器下实现RT-Thread和openeuler同时运行', + SPEAKER: ['张海涛 RT-thread'], + DESC: [''] + }, + { + TIME: '15:00-15:30', + THEME: '茶歇', + }, + { + TIME: '15:30-16:00', + THEME: '云原生边缘计算平台架构与实践', + SPEAKER: ['王杰章 华为'], + DESC: ['现如今边缘计算的应用场景非常丰富,而且面临着诸多挑战,例如:边云通信网络质量低、边缘资源受限、边缘应用离线自治和本地故障恢复、边缘节点高度分散和资源异构。针对上述问题,我们提出了云原生边缘计算平台的架构与实践——KubeEdge,并配套边缘分布式网络组件EdgeMesh与边缘协调AI框架Sedna。'] + }, + { + TIME: '16:00-16:30', + THEME: '云边协同在太空卫星上的实践探索', + SPEAKER: ['林培峰 SUSE'], + DESC: ['本议题通过实际的案例分享,探索云边协同技术如何在太空卫星上落地,如何利用云原生、DevSecOpt和边缘技术更好的在太空卫星上使用更低成本硬件,构建更安全可靠软件,实现在太空卫星上更可靠更新软件,以及更好实现AI/ML计算。'] + }, + { + TIME: '16:30-17:00', + THEME: 'Linux实时性实践与探索', + SPEAKER: ['郭皓 麒麟软件'], + DESC: ['基于openeuler做的Linux实时性探索和研究,已发布Linux嵌入式操作系统demo,支持飞腾、鲲鹏、x86平台'] + }, + ] + } + ] + }, + }, + NAV_LIST: [ + { + key: '#live', + name: '精彩回顾' + }, + { + key: '#agenda', + name: '峰会日程' + }, + { + key: '#exhibition', + name: '线上展厅' + }, + { + key: '#lecturer', + name: '演讲嘉宾' + }, + { + key: '#publisher', + name: '出品人' + }, + { + key: '#construction', + name: '共建单位' + } + ], + CONSTRUCTION: { + WEB_TITLE: "/img/summit/summit2021/Co-construction/web-title.png", + MOBILE_TITLE: "/img/summit/summit2021/Co-construction/mobile-title.png", + GUIDANCE: { + TEXT_TITLE: "指导单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openaton.png", + LINK: "" + } + ] + }, + HOST: { + TEXT_TITLE: "主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/openEulerlogo.png", + LINK: "" + } + ] + }, + STRATEGIC: { + TEXT_TITLE: "战略合作单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/huawei.png", + LINK: "" + } + ] + }, + CO_SPONSORED: { + TEXT_TITLE: "联合主办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/qilinsoft.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qilinxinan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/suse.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tongxin.png", + LINK: "" + } + ] + + }, + CO_ORGANIZER: { + TEXT_TITLE: "协办单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/yidong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dianxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/liantong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/puhua.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/turbolinux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/phytium.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shentai.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/softstone.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/easystack.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/360.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/dongfangtong.png", + LINK: "" + }, + ] + }, + SUPPORT: { + TEXT_TITLE: "支持单位", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/jdcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinlang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kengpeng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/zhongkedachuang.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/tianyuan.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/bessystem.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/qingcloud.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/starfive.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/winhong.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/asiainfo.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/nuclei.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xsky.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/guoxing.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iiioka.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/isstech.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huayun.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/kaifazhineng.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/iscas.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/ruihe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/langcher.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/xinchen.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/youxi.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/beilian.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/talkweb.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/shenzhou.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/huanghe.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/baixing.png", + LINK: "" + }, + ] + }, + FOUNDATION: { + TEXT_TITLE: "友好基金会", + LIST: [ + { + IMG: "/img/summit/summit2021/Co-construction/linux.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/openinfra.png", + LINK: "" + }, + { + IMG: "/img/summit/summit2021/Co-construction/linaro.png", + LINK: "" + }, + ] + } + }, + LECTURER: { + LECTURER_BANNER: { + web: '/img/summit/summit2021/lecturer/sperkertitle.png', + mobile: '/img/summit/summit2021/lecturer/sperkertitle_mo.png' + }, + LECTURER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/yangtao.png', + NAME: '杨涛', + POSITION: '开放原子开源基金会 理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/jiangdayong.png', + NAME: '江大勇', + POSITION: '欧拉开源社区理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/wuyanjun.png', + NAME: '武延军', + POSITION: '欧拉开源社区副理事长' + }, + { + IMG: '/img/summit/summit2021/lecturer/qiuchengfeng.png', + NAME: '邱成锋', + POSITION: '欧拉开源社区秘书长' + }, + { + IMG: '/img/summit/summit2021/lecturer/huxinwei.png', + NAME: '胡欣蔚', + POSITION: '欧拉开源社区 技术委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenhaibo.png', + NAME: '陈海波', + POSITION: '上海交通大学教授 华为操作系统首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/gaowei.png', + NAME: '高巍', + POSITION: '欧拉开源社区 用户委员会主席' + }, + { + IMG: '/img/summit/summit2021/lecturer/qinxiaokang.png', + NAME: '秦小康', + POSITION: 'SUSE大中华区总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/wangpan.png', + NAME: '王攀', + POSITION: '麒麟信安副总裁' + }, + { + IMG: '/img/summit/summit2021/lecturer/zhanglei.png', + NAME: '张磊', + POSITION: '统信软件CTO' + }, + ], + PUBLISHER_BANNER: { + web: '/img/summit/summit2021/lecturer/publishertitle.png', + mobile: '/img/summit/summit2021/lecturer/publishertitle_mo.png' + }, + PUBLISHER_LIST: [ + { + IMG: '/img/summit/summit2021/lecturer/guohanjun.png', + NAME: '郭寒军', + POSITION: '欧拉开源社区内核 Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/liyong.png', + NAME: '李勇', + POSITION: 'SUSE软件工程顾问' + }, + { + IMG: '/img/summit/summit2021/lecturer/yixiujiang.png', + NAME: '尹秀江', + POSITION: '麒麟软件工程师' + }, + { + IMG: '/img/summit/summit2021/lecturer/yanshuanghai.png', + NAME: '严海双', + POSITION: '中移云能力中心 内核研发专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/shenxiang.png', + NAME: '沈翔', + POSITION: '普华基础软件总经理' + }, + { + IMG: '/img/summit/summit2021/lecturer/dukaitian.png', + NAME: '杜开田', + POSITION: '欧拉开源社区 兼容性SIG组Maintainer' + }, + { + IMG: '/img/summit/summit2021/lecturer/yeqinglong.png', + NAME: '叶青龙', + POSITION: '服务器操作系统项目总监 欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/liujingang.png', + NAME: '刘金刚', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/caihaomin.png', + NAME: '蔡灏旻', + POSITION: '华为容器团队架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/shiyong.png', + NAME: '石勇', + POSITION: '欧拉开源社区 技术委员会委员' + }, + { + IMG: '/img/summit/summit2021/lecturer/panjianfeng.png', + NAME: '潘剑锋', + POSITION: '360集团副总裁 首席科学家' + }, + { + IMG: '/img/summit/summit2021/lecturer/yangliu.png', + NAME: '阳柳', + POSITION: '飞腾资深软件架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/xiekunxun.png', + NAME: '谢焜勋', + POSITION: '华为嵌入式操作系统 技术专家' + }, + { + IMG: '/img/summit/summit2021/lecturer/lishouyong.png', + NAME: '刘寿永', + POSITION: ' 中科创达首席架构师' + }, + { + IMG: '/img/summit/summit2021/lecturer/chenjingwei.png', + NAME: '陈景伟', + POSITION: ' 赛昉生态市场高级总监' + }, + ] + }, + SUMMIT_INTRODUCE: "The openEuler Summit is an event for the global developer community and IT professionals who want to learn about openEuler open source products. openEuler has evolved from a server OS into a digital infrastructure (version: 21.09) that supports IT, CT, and OT services in server, cloud native, edge computing, and embedded scenarios. At the openEuler Summit 2021, we invite developers, users, and software enthusiasts to discuss new innovations and features of openEuler, and learn from others in the community.", + HIGHLIGHTS: "Highlights" + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/lang-modules/timer.js b/web-ui/docs/.vuepress/lang/lang-modules/timer.js new file mode 100644 index 0000000000000000000000000000000000000000..5644e5ae17f6e638e178c890abde533b01c93ac5 --- /dev/null +++ b/web-ui/docs/.vuepress/lang/lang-modules/timer.js @@ -0,0 +1,23 @@ +/** + * @file 倒计时国际化配置入口 + * */ +module.exports = { + cn: { + TIMETEXT: { + COUNT_DOWN: '距离活动开始还有', + NOTSTARTED: '活动未开始', + STARTED: '活动火热进行中', + FINISHED: '活动已结束' + }, + TIMEDESC: ['天','小时','分钟','秒'] + }, + en: { + TIMETEXT: { + COUNT_DOWN: '距离活动开始还有', + NOTSTARTED: '活动未开始', + STARTED: '活动火热进行中', + FINISHED: '活动已结束' + }, + TIMEDESC: ['DAYS','HOURS','MIN','SEC'] + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/ru.js b/web-ui/docs/.vuepress/lang/ru.js new file mode 100644 index 0000000000000000000000000000000000000000..1395cbf3f1e5040a9ad4923a62beff509f17ebaf --- /dev/null +++ b/web-ui/docs/.vuepress/lang/ru.js @@ -0,0 +1,24 @@ +/** + * @file 国际化俄文配置主入口 + * */ + +module.exports = { + common: require('./lang-modules/common').ru, + home: require('./lang-modules/home').ru, + download: require('./lang-modules/download').ru, + documentation: require('./lang-modules/documentation').ru, + community: require('./lang-modules/community').ru, + sig: require('./lang-modules/sig').ru, + authentication: require('./lang-modules/authentication').ru, + security: require('./lang-modules/security').ru, + interaction: require('./lang-modules/interaction').ru, + brand: require('./lang-modules/brand').ru, + search: require('./lang-modules/search').ru, + minisite: require('./lang-modules/minisite').ru, + scheme: require('./lang-modules/scheme').ru, + learn: require('./lang-modules/learn').ru, + compatibility: require('./lang-modules/compatibility').ru, + activities: require('./lang-modules/activities').cn, + summit: require('./lang-modules/summit').ru, + devday2022: require('./lang-modules/devday2022').ru, +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/lang/zh.js b/web-ui/docs/.vuepress/lang/zh.js new file mode 100644 index 0000000000000000000000000000000000000000..4b9e28af40695dd4cfe05a4a94f70d3df803cd2a --- /dev/null +++ b/web-ui/docs/.vuepress/lang/zh.js @@ -0,0 +1,26 @@ +/** + * @file 国际化中文配置主入口 + * */ + +module.exports = { + common: require('./lang-modules/common').cn, + home: require('./lang-modules/home').cn, + download: require('./lang-modules/download').cn, + documentation: require('./lang-modules/documentation').cn, + community: require('./lang-modules/community').cn, + sig: require('./lang-modules/sig').cn, + authentication: require('./lang-modules/authentication').cn, + security: require('./lang-modules/security').cn, + interaction: require('./lang-modules/interaction').cn, + brand: require('./lang-modules/brand').cn, + search: require('./lang-modules/search').cn, + minisite: require('./lang-modules/minisite').cn, + scheme: require('./lang-modules/scheme').cn, + learn: require('./lang-modules/learn').cn, + compatibility: require('./lang-modules/compatibility').cn, + activities: require('./lang-modules/activities').cn, + summit: require('./lang-modules/summit').cn, + questionnaire: require('./lang-modules/questionnaire').cn, + devday2022: require('./lang-modules/devday2022').cn, + approve: require('./lang-modules/approve').cn +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/libs/ajax-utils.js b/web-ui/docs/.vuepress/libs/ajax-utils.js new file mode 100644 index 0000000000000000000000000000000000000000..5667c0fc193d882233f1d8be72768a4ead447dfe --- /dev/null +++ b/web-ui/docs/.vuepress/libs/ajax-utils.js @@ -0,0 +1,60 @@ +/** + * @file axios工具类 + * */ + +import axios from 'axios'; +import Vue from 'vue'; +const serviceBaseUrl = '/api'; +let authConfig = 'Basic b3BlbmV1bGVyc2VydmVyOm9wZW5ldWxlcnNlcnZlckAxMjM0'; + +let addUrlParam = function (url, paramName, paramValue) { + if (!url) { + return url; + } + url += ((url.indexOf('?') > 0) ? '&' : '?'); + url += paramName + '=' + paramValue; + return url; +}; + +let postJson = params => { + let api = axios.create({ + baseURL: (serviceBaseUrl + (params.otherBaseUrl || '')) || '' + }); + api.defaults.headers.post['Content-Type'] = 'application/json'; + if(params.headLanguage){ + api.defaults.headers.common['Accept-Language'] = params.headLanguage; + } + // 添加随机数 + params['url'] = addUrlParam(params['url'], 'rnd', Math.random()); + + // 请求数据 + let dataStr = params['data'] && ((typeof (params['data']) === 'object') + ? JSON.stringify(params['data']) : params['data']); + + let ajaxParams = {}; + // success方法重载 + ajaxParams['success'] = function (d) { + const data = typeof d.data == "string" ? JSON.parse(d.data) : d.data; + if(data){ + params.success(data); + } else { + new Vue().$message.error('开小差~请稍后重试。'); + } + } + return api({ + headers: params.notAuthorization ? {}: { + 'Authorization': authConfig + }, + method: params['type'] || 'post', + url: params['url'], + data: dataStr, + params: params['params'], + responseType: 'json' + }).then(ajaxParams['success']).catch(params['error']); +}; + +let exportsMethods = { + postJson: params => postJson(params) +}; + +export default exportsMethods; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/libs/common-methods.js b/web-ui/docs/.vuepress/libs/common-methods.js new file mode 100644 index 0000000000000000000000000000000000000000..05956ece70b3ba1b53cfe0f9a312a01768381db4 --- /dev/null +++ b/web-ui/docs/.vuepress/libs/common-methods.js @@ -0,0 +1,188 @@ + +const calenderMethods = { + + formatTime (time) { + let arr = time.split('-'); + arr[0] = parseInt(arr[0].split(':')[0]); + arr[1] = parseInt(arr[1].split(':')[0]); + return arr; + } +} + +const privacyMethods = { + + calenderSortData (data) { + data.forEach(dateItem => { + let arr = []; + dateItem.timeData.forEach(timeItem => { + let timeStart = calenderMethods.formatTime(timeItem.duration_time)[0]; + let timeEnd = calenderMethods.formatTime(timeItem.duration_time)[1]; + let indexTemp = null; + if(!arr.length) { + arr.push({ + startTime: timeItem.startTime, + endTime: timeItem.endTime, + duration: timeItem.duration, + duration_time: timeItem.duration_time, + meetingData: [ + timeItem + ] + }) + } else { + + let findItem = arr.every(meetingItem => { + let meetingStart = calenderMethods.formatTime(meetingItem.duration_time)[0]; + let meetingEnd = calenderMethods.formatTime(meetingItem.duration_time)[1]; + return ( + (timeEnd <= meetingStart) || + (timeStart >= meetingEnd) + ); + }) + if(findItem){ + arr.push({ + startTime: timeItem.startTime, + endTime: timeItem.endTime, + duration: timeItem.duration, + duration_time: timeItem.duration_time, + meetingData: [ + timeItem + ] + }) + return; + } + let eachFlag = false; + arr.forEach((meetingItem, index) => { + if(eachFlag){ + return; + } + indexTemp = index; + let meetingStart = calenderMethods.formatTime(meetingItem.duration_time)[0]; + let meetingEnd = calenderMethods.formatTime(meetingItem.duration_time)[1]; + if( + (meetingStart + <= timeStart) && + (timeStart + <= meetingEnd) && + (meetingStart + <= timeEnd) && + (timeEnd + <= meetingEnd) + ){ + eachFlag = true; + meetingItem.meetingData.push(timeItem); + } + + + if( + (timeStart < meetingStart) && + ((meetingStart < timeEnd) && + (timeEnd <= meetingEnd)) + ){ + eachFlag = true; + meetingItem.startTime = timeItem.startTime; + meetingItem.duration = meetingEnd - timeStart; + meetingItem.duration_time = timeStart + ':00-' + meetingEnd + ':00'; + meetingItem.meetingData.push(timeItem); + } + + if( + (timeEnd > meetingEnd) && + ((meetingStart <= timeStart) && + (timeStart < meetingEnd)) + ){ + eachFlag = true; + meetingItem.endTime = timeItem.endTime; + meetingItem.duration = timeEnd - meetingStart; + meetingItem.duration_time = meetingStart + ':00-' + timeEnd + ':00'; + meetingItem.meetingData.push(timeItem); + } + + if( + (timeStart < meetingStart) && + (timeEnd > meetingEnd) + ){ + eachFlag = true; + meetingItem.startTime = timeItem.startTime; + meetingItem.endTime = timeItem.endTime; + meetingItem.duration = timeEnd - timeStart; + meetingItem.duration_time = timeStart + ':00-' + timeEnd + ':00'; + meetingItem.meetingData.push(timeItem); + } + + }) + } + let arrTemp = []; + let notCheckArr = []; + if(indexTemp !== null){ + let curItemStartTime = arr[indexTemp].startTime; + let curItemEndTime = arr[indexTemp].endTime; + let curItemStart = calenderMethods.formatTime(arr[indexTemp].duration_time)[0]; + let curItemEnd = calenderMethods.formatTime(arr[indexTemp].duration_time)[1]; + arr.forEach((item, index) => { + let itemStart = calenderMethods.formatTime(item.duration_time)[0]; + let itemEnd = calenderMethods.formatTime(item.duration_time)[1]; + if(index != indexTemp){ + if( + (itemStart < curItemStart) && + ((curItemStart < itemEnd) && + (itemEnd <= curItemEnd)) + ){ + curItemStart = itemStart; + curItemStartTime = item.startTime; + arrTemp.push(item); + return; + } + + if( + (itemEnd > curItemEnd) && + ((curItemStart <= itemStart) && + (itemStart < curItemEnd)) + ){ + curItemEnd = itemEnd; + curItemEndTime = item.endTime; + arrTemp.push(item); + return; + } + + if( + (itemStart < curItemStart) && + (itemEnd > curItemEnd) + ){ + curItemStart = itemStart; + curItemEnd = itemEnd; + curItemStartTime = item.startTime; + curItemEndTime = item.endTime; + arrTemp.push(item); + return; + } + notCheckArr.push(item); + } + }) + let selItem = []; + if(arrTemp.length){ + arr[indexTemp].startTime = curItemStartTime; + arr[indexTemp].duration = curItemEnd - curItemStart; + arr[indexTemp].endTime = curItemEndTime; + arr[indexTemp].duration_time = curItemStart + ':00-' + curItemEnd + ':00'; + selItem.push(arr[indexTemp]); + + arrTemp.forEach((item, index) => { + selItem[0].meetingData = selItem[0].meetingData.concat(item.meetingData); + }) + selItem = selItem.concat(notCheckArr); + arr = selItem; + } + } + }) + dateItem.timeDate = arr; + }) + return data; + } +} + + +const exportMethods = { + calenderSortData: privacyMethods.calenderSortData +}; + +export default exportMethods; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/libs/cookie-utils.js b/web-ui/docs/.vuepress/libs/cookie-utils.js new file mode 100644 index 0000000000000000000000000000000000000000..c9aa4950d0c2a2e79369ac0905b117230a47ace0 --- /dev/null +++ b/web-ui/docs/.vuepress/libs/cookie-utils.js @@ -0,0 +1,25 @@ +export default { + set: function (name, value, days) { + + var d = new Date; + + d.setTime(d.getTime() + 24*60*60*1000*days); + + window.document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString(); + + }, + + get: function (name) { + + var v = window.document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); + + return v ? v[2] : null; + + }, + + delete: function (name) { + + this.set(name, '', -1); + + } +}; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/libs/directive.js b/web-ui/docs/.vuepress/libs/directive.js new file mode 100644 index 0000000000000000000000000000000000000000..09c38215ed6be1a161a674c3c4695f58e9931a9d --- /dev/null +++ b/web-ui/docs/.vuepress/libs/directive.js @@ -0,0 +1,59 @@ +let fadeInElements = null; +let curElement = null; + +let visibleRect = null; +let visibleRectElemTop = null; +let visibleRectElemBottom = null; + +let unvisibleRect = null; +let unvisibleRectElemTop = null; +let unvisibleRectElemBottom = null; +let unvisibleRectElemTopAll = null; +let fadeinArr = []; + +const privacyMethods = { + + isElemVisible (el) { + visibleRect = el.getBoundingClientRect(); + visibleRectElemTop = visibleRect.top + 200; + visibleRectElemBottom = visibleRect.bottom - 200; + return visibleRectElemTop < window.innerHeight && visibleRectElemBottom >= 0; + }, + isElemUnvisible (el) { + unvisibleRect = el.getBoundingClientRect(); + unvisibleRectElemTopAll = unvisibleRect.top; + unvisibleRectElemBottom = unvisibleRect.bottom; + unvisibleRectElemTop = unvisibleRect.top + unvisibleRect.height; + return unvisibleRectElemTop < 0 || !(unvisibleRectElemTopAll < window.innerHeight && unvisibleRectElemBottom >= 0); + }, + handleScroll () { + for (let i = 0; i < fadeInElements.length; i++) { + curElement = fadeInElements[i]; + if (privacyMethods.isElemVisible(curElement)) { + curElement.style.opacity = '1'; + curElement.style.transform = 'translate3d(0, 0, 0) scale(1)'; + } + if(privacyMethods.isElemUnvisible(curElement)){ + curElement.style.opacity = '0'; + curElement.style.transform = 'scale(0.8)'; + } + } + } +} + +const exportMethods = { + fade : { + inserted(el){ + fadeInElements = fadeinArr.concat(Array.from(el.getElementsByClassName('fade-in'))); + fadeinArr = fadeInElements; + document.addEventListener('scroll', privacyMethods.handleScroll); + privacyMethods.handleScroll(); + }, + unbind() { + document.removeEventListener('scroll', privacyMethods.handleScroll); + fadeinArr = []; + } + } +}; + +export default exportMethods; \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/2021-annual-report-of-openeuler.pdf b/web-ui/docs/.vuepress/public/2021-annual-report-of-openeuler.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1b93601c458fe6ea3f6fc116eb0de31ada92fde6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/2021-annual-report-of-openeuler.pdf differ diff --git a/web-ui/docs/.vuepress/public/Raspberry_Pi_OS_openEuler.png b/web-ui/docs/.vuepress/public/Raspberry_Pi_OS_openEuler.png new file mode 100644 index 0000000000000000000000000000000000000000..52033bf5033c6755ec901fdb1202bfde535c59e3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/Raspberry_Pi_OS_openEuler.png differ diff --git a/web-ui/docs/.vuepress/public/atom-mo.png b/web-ui/docs/.vuepress/public/atom-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..9aa3dda40b4e97203e1e1d3f019f720dc6783651 Binary files /dev/null and b/web-ui/docs/.vuepress/public/atom-mo.png differ diff --git a/web-ui/docs/.vuepress/public/atom-pc.png b/web-ui/docs/.vuepress/public/atom-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..a5feafdd08c47ed32452b9ad23364bf28f1df44d Binary files /dev/null and b/web-ui/docs/.vuepress/public/atom-pc.png differ diff --git a/web-ui/docs/.vuepress/public/code-source.svg b/web-ui/docs/.vuepress/public/code-source.svg new file mode 100644 index 0000000000000000000000000000000000000000..c044996f0b09411c324a00549ef0b27cadea17e3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/code-source.svg @@ -0,0 +1,15 @@ + + + Outlined/UI/code source + + + + + + + + + + + + \ No newline at end of file diff --git "a/web-ui/docs/.vuepress/public/doc/\345\257\274\345\270\210\345\256\236\344\271\240\350\257\204\350\257\255.txt" "b/web-ui/docs/.vuepress/public/doc/\345\257\274\345\270\210\345\256\236\344\271\240\350\257\204\350\257\255.txt" new file mode 100644 index 0000000000000000000000000000000000000000..81e858cb27459bed1c15bda320aa4dd66154f55f --- /dev/null +++ "b/web-ui/docs/.vuepress/public/doc/\345\257\274\345\270\210\345\256\236\344\271\240\350\257\204\350\257\255.txt" @@ -0,0 +1 @@ +导师写实习评语:简单阐述学生的实习成果、成果对社区的贡献意义、学生综合能力、积极性表现评价,100字以上,发送给intern@openeuler.sh 邮箱,抄送给实习生。 \ No newline at end of file diff --git "a/web-ui/docs/.vuepress/public/doc/\345\274\200\346\272\220\345\256\236\344\271\240\346\212\245\345\221\212\346\250\241\346\235\277.docx" "b/web-ui/docs/.vuepress/public/doc/\345\274\200\346\272\220\345\256\236\344\271\240\346\212\245\345\221\212\346\250\241\346\235\277.docx" new file mode 100644 index 0000000000000000000000000000000000000000..87a1915a98a983b68e11039133efbd1e2e9819cc Binary files /dev/null and "b/web-ui/docs/.vuepress/public/doc/\345\274\200\346\272\220\345\256\236\344\271\240\346\212\245\345\221\212\346\250\241\346\235\277.docx" differ diff --git a/web-ui/docs/.vuepress/public/favicon.ico b/web-ui/docs/.vuepress/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ba6134a0ab94b8dd83d098e059d3c4dd93dd1041 Binary files /dev/null and b/web-ui/docs/.vuepress/public/favicon.ico differ diff --git a/web-ui/docs/.vuepress/public/fonts/icomoon.eot b/web-ui/docs/.vuepress/public/fonts/icomoon.eot new file mode 100644 index 0000000000000000000000000000000000000000..296ebc035c5b8d333fc5b33d192e9aab34674455 Binary files /dev/null and b/web-ui/docs/.vuepress/public/fonts/icomoon.eot differ diff --git a/web-ui/docs/.vuepress/public/fonts/icomoon.svg b/web-ui/docs/.vuepress/public/fonts/icomoon.svg new file mode 100644 index 0000000000000000000000000000000000000000..5993cbfc3e08ce844a2560a3c02a5b559c3db9a4 --- /dev/null +++ b/web-ui/docs/.vuepress/public/fonts/icomoon.svg @@ -0,0 +1,13 @@ + + + +Generated by IcoMoon + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/fonts/icomoon.ttf b/web-ui/docs/.vuepress/public/fonts/icomoon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4d22f59786856202df95442ab1af225a53a7a1e3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/fonts/icomoon.ttf differ diff --git a/web-ui/docs/.vuepress/public/fonts/icomoon.woff b/web-ui/docs/.vuepress/public/fonts/icomoon.woff new file mode 100644 index 0000000000000000000000000000000000000000..04a91af85e46766f2d489439cef5f58fa209467b Binary files /dev/null and b/web-ui/docs/.vuepress/public/fonts/icomoon.woff differ diff --git a/web-ui/docs/.vuepress/public/footer-logo.png b/web-ui/docs/.vuepress/public/footer-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e029c8d7daad57c231228b2140a505fcf93b8e79 Binary files /dev/null and b/web-ui/docs/.vuepress/public/footer-logo.png differ diff --git a/web-ui/docs/.vuepress/public/footer-logo.svg b/web-ui/docs/.vuepress/public/footer-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..f7c0b544604181a8af602653b8fd3d19ca2edc00 --- /dev/null +++ b/web-ui/docs/.vuepress/public/footer-logo.svg @@ -0,0 +1,29 @@ + + + openEuler + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/footer-logo2.svg b/web-ui/docs/.vuepress/public/footer-logo2.svg new file mode 100644 index 0000000000000000000000000000000000000000..dbffabf311cfa409f2017604c5161b7533ee9b90 --- /dev/null +++ b/web-ui/docs/.vuepress/public/footer-logo2.svg @@ -0,0 +1,33 @@ + + + 页尾logo(手机网页共用) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/404/404-banner.png b/web-ui/docs/.vuepress/public/img/404/404-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..cace3ad572029a32b4531fadf1048f3c6a3c85b0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/404/404-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/WechatIMG329.jpg b/web-ui/docs/.vuepress/public/img/activities/WechatIMG329.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f770edcb7a530374852110181a24cb0b223795b6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/WechatIMG329.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/activities/devday2022.png b/web-ui/docs/.vuepress/public/img/activities/devday2022.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ce9fa509bda918e89a7c7287a6591a2746c1e7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/devday2022.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/high.png b/web-ui/docs/.vuepress/public/img/activities/high.png new file mode 100644 index 0000000000000000000000000000000000000000..53c9609d2326b3e0f0da12ecaeb91824093d54e4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/high.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/internship.png b/web-ui/docs/.vuepress/public/img/activities/internship.png new file mode 100644 index 0000000000000000000000000000000000000000..bf93f145a1fec50a298138cc80954810ed52febb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/internship.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/line.png b/web-ui/docs/.vuepress/public/img/activities/line.png new file mode 100644 index 0000000000000000000000000000000000000000..c261f9bad02c9c0c7d57598565759397fb59eb09 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/line.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/low.png b/web-ui/docs/.vuepress/public/img/activities/low.png new file mode 100644 index 0000000000000000000000000000000000000000..c38c20d38c2881312f35abb3c6644272d1baa148 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/low.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/medium.png b/web-ui/docs/.vuepress/public/img/activities/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..14c45645f8ebbb2d6f0d47e2baf610dfd57bede6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/medium.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/banner.png b/web-ui/docs/.vuepress/public/img/activities/mobile/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..c7c1dbed52e77d58d55e7d4e427e1e28229a28f6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/step_1.png b/web-ui/docs/.vuepress/public/img/activities/mobile/step_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d406a1c9269de151abedbe133b1dcd911a4d363c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/step_1.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/step_2.png b/web-ui/docs/.vuepress/public/img/activities/mobile/step_2.png new file mode 100644 index 0000000000000000000000000000000000000000..4b7607dfa658da9ecdb5ade1295243cdafeb2026 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/step_2.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/step_3.png b/web-ui/docs/.vuepress/public/img/activities/mobile/step_3.png new file mode 100644 index 0000000000000000000000000000000000000000..0670a6066bc65cb9f7e9dbf52a809d4069e51006 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/step_3.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/step_4.png b/web-ui/docs/.vuepress/public/img/activities/mobile/step_4.png new file mode 100644 index 0000000000000000000000000000000000000000..a6f2af02ff2fa47a49534631a3921fff0fd2c238 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/step_4.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/step_5.png b/web-ui/docs/.vuepress/public/img/activities/mobile/step_5.png new file mode 100644 index 0000000000000000000000000000000000000000..78ea6627dbd10be6b641f9340910bf8c84a5037f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/step_5.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/mobile/title_bg.png b/web-ui/docs/.vuepress/public/img/activities/mobile/title_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..2491a1fd3d1402ec879e77a9a3ed8a7a03ed0a13 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/mobile/title_bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/banner.png b/web-ui/docs/.vuepress/public/img/activities/pc/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..4cb4cac7d383f5bb82759996cd92897b5aca2244 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/banner_all.png b/web-ui/docs/.vuepress/public/img/activities/pc/banner_all.png new file mode 100644 index 0000000000000000000000000000000000000000..89d468de0add4b450b7ce7a4171c197f75edb842 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/banner_all.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/banner_btn.png b/web-ui/docs/.vuepress/public/img/activities/pc/banner_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..89d28f57c1e91f7432548192036479f530534e96 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/banner_btn.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/bg.png b/web-ui/docs/.vuepress/public/img/activities/pc/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b7626445335bd35a7ffcf16db6426fbac238ac48 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/step_1.png b/web-ui/docs/.vuepress/public/img/activities/pc/step_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4017913899a7b5bc00cc3ea85449506f61c87245 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/step_1.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/step_2.png b/web-ui/docs/.vuepress/public/img/activities/pc/step_2.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8da1bc9c698ead348b0b05973e7832b1961ccb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/step_2.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/step_3.png b/web-ui/docs/.vuepress/public/img/activities/pc/step_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b30694eb9e0647aff3181fb5c7527b28fe9259ff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/step_3.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/step_4.png b/web-ui/docs/.vuepress/public/img/activities/pc/step_4.png new file mode 100644 index 0000000000000000000000000000000000000000..75f3893841ce5ba0d4bb13bc2c36498169e012cf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/step_4.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/step_5.png b/web-ui/docs/.vuepress/public/img/activities/pc/step_5.png new file mode 100644 index 0000000000000000000000000000000000000000..048fa3f1fd54adc9d2604aa4e97cd7e2a712cff6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/step_5.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/summit.png b/web-ui/docs/.vuepress/public/img/activities/pc/summit.png new file mode 100644 index 0000000000000000000000000000000000000000..0a08bd3b1c65f1408f09ba274c381d6d2b057ed5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/summit.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc/title.png b/web-ui/docs/.vuepress/public/img/activities/pc/title.png new file mode 100644 index 0000000000000000000000000000000000000000..12da3c3266e1ef3f23514b3d3c817eda02a120b8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc/title.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/pc_home_bottom_banner.png b/web-ui/docs/.vuepress/public/img/activities/pc_home_bottom_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..311702599f5e2acec6e14177d9ba456b7375b7d8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/pc_home_bottom_banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/video_btn.png b/web-ui/docs/.vuepress/public/img/activities/video_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..3511a159914ba8de726e0e4fa2746bd094839d4c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/video_btn.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/2022-logo.png b/web-ui/docs/.vuepress/public/img/activities/year2022/2022-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3960556cd5b1e1721bccfda48c87c2e91a6d6295 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/2022-logo.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title1.png b/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title1.png new file mode 100644 index 0000000000000000000000000000000000000000..d5bc9f0ef1844a54408a350d863c47492fe3f7c6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title1.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title2.png b/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title2.png new file mode 100644 index 0000000000000000000000000000000000000000..59d385809c4bed278978cce87b39f2f16ff8b405 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/activity-title2.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/activity1-bg.png b/web-ui/docs/.vuepress/public/img/activities/year2022/activity1-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..7279a5d3c2c6c9aeb909701285abef64c9a843da Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/activity1-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/activity2-bg.png b/web-ui/docs/.vuepress/public/img/activities/year2022/activity2-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc34e407127089c283a57065ec7398147398fec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/activity2-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/bag.png b/web-ui/docs/.vuepress/public/img/activities/year2022/bag.png new file mode 100644 index 0000000000000000000000000000000000000000..62f53a4bdd257d0631469aa0bb37c8edb60ac602 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/bag.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/bg-left.png b/web-ui/docs/.vuepress/public/img/activities/year2022/bg-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a32abb54e90c6084ee5abb61547a40eff7a3e361 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/bg-left.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/bg-right.png b/web-ui/docs/.vuepress/public/img/activities/year2022/bg-right.png new file mode 100644 index 0000000000000000000000000000000000000000..52b9d885f1428acb177a84979f39706fb65816d2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/bg-right.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/bookmark.png b/web-ui/docs/.vuepress/public/img/activities/year2022/bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..8f709bfa03976066f0f22f90a612dfed2ffa3b38 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/bookmark.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/card.png b/web-ui/docs/.vuepress/public/img/activities/year2022/card.png new file mode 100644 index 0000000000000000000000000000000000000000..a9da138a232f6d0e0f571ae1a2daf5726324e93e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/card.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/cheer-bg.png b/web-ui/docs/.vuepress/public/img/activities/year2022/cheer-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..52406e8f8622de1db65768980dc2dc7a97e65076 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/cheer-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/cheers.png b/web-ui/docs/.vuepress/public/img/activities/year2022/cheers.png new file mode 100644 index 0000000000000000000000000000000000000000..36a9842efdc736df16504ba6ca0acc668d4f9e27 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/cheers.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/clothes.png b/web-ui/docs/.vuepress/public/img/activities/year2022/clothes.png new file mode 100644 index 0000000000000000000000000000000000000000..b597192a4e3572df6c88fff4c797227062f1de01 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/clothes.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/company.png b/web-ui/docs/.vuepress/public/img/activities/year2022/company.png new file mode 100644 index 0000000000000000000000000000000000000000..272b0a9d7fc55ee03e318141fc8017bf6bad5d66 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/company.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/contribution.png b/web-ui/docs/.vuepress/public/img/activities/year2022/contribution.png new file mode 100644 index 0000000000000000000000000000000000000000..da57b6e624f7fd4f9830687cda632499b6705db2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/contribution.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/fu-gif.gif b/web-ui/docs/.vuepress/public/img/activities/year2022/fu-gif.gif new file mode 100644 index 0000000000000000000000000000000000000000..cee994784cc2f74dcd98ec3444b8e1ac2048899b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/fu-gif.gif differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon1.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon1.png new file mode 100644 index 0000000000000000000000000000000000000000..d491260de1ad048d87280deb91d09f76b47248a8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon1.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon10.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon10.png new file mode 100644 index 0000000000000000000000000000000000000000..4f1204a3bafc5930742fae77a744cd7bf517f06f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon10.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon2.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..3e767449109001f3bbb8ef73643cd035d5275770 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon2.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon3.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon3.png new file mode 100644 index 0000000000000000000000000000000000000000..8f462afdb5732a8f4860b08456c41e11cfcdb57b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon3.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon4.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon4.png new file mode 100644 index 0000000000000000000000000000000000000000..1200b8e86ca2a5ffc5592e4754b6c2df9e7e3ee4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon4.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon5.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon5.png new file mode 100644 index 0000000000000000000000000000000000000000..ec4d7154ffa35448bc2b0f86841092a55e7ff749 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon5.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon6.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon6.png new file mode 100644 index 0000000000000000000000000000000000000000..6af6749916d6f82d2a3d36600cf7fc52d0b38de9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon6.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon7.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon7.png new file mode 100644 index 0000000000000000000000000000000000000000..4f1204a3bafc5930742fae77a744cd7bf517f06f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon7.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon8.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon8.png new file mode 100644 index 0000000000000000000000000000000000000000..b12d4b6711cd2a6c54b979da808f868e87d0bafa Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon8.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/icon9.png b/web-ui/docs/.vuepress/public/img/activities/year2022/icon9.png new file mode 100644 index 0000000000000000000000000000000000000000..6af6749916d6f82d2a3d36600cf7fc52d0b38de9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/icon9.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-left.gif b/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d277fa5b95170f580bb81b35ee68cd653e41dca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-left.gif differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-right.gif b/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-right.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b3e0588adf807b9610fa6d61943e7b5b5d9efb7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/lantern-right.gif differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/light.png b/web-ui/docs/.vuepress/public/img/activities/year2022/light.png new file mode 100644 index 0000000000000000000000000000000000000000..d990ae2525704d2901ef9140706015d3f5845d2d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/light.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/mob-banner.png b/web-ui/docs/.vuepress/public/img/activities/year2022/mob-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8488e4f66ebe0db4cd3eda35a6506d66a4f30988 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/mob-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/osv.png b/web-ui/docs/.vuepress/public/img/activities/year2022/osv.png new file mode 100644 index 0000000000000000000000000000000000000000..1bfddd5d499f210a41f9cb2c48ca52c9b4613fa0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/osv.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/pc-banner.png b/web-ui/docs/.vuepress/public/img/activities/year2022/pc-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6616b0964a15223bfeecf36fc9dc806895a95e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/pc-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/qr-code.png b/web-ui/docs/.vuepress/public/img/activities/year2022/qr-code.png new file mode 100644 index 0000000000000000000000000000000000000000..85673a2f62a76b3fc156356b09a3c3ca1f907aec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/qr-code.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/sig.png b/web-ui/docs/.vuepress/public/img/activities/year2022/sig.png new file mode 100644 index 0000000000000000000000000000000000000000..93e71e04baf815e2d8435a70abae8b56ced06f7e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/software.png b/web-ui/docs/.vuepress/public/img/activities/year2022/software.png new file mode 100644 index 0000000000000000000000000000000000000000..4b50827e7b4db89c4999d89ed6def3843c4217ab Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/software.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/title-last.png b/web-ui/docs/.vuepress/public/img/activities/year2022/title-last.png new file mode 100644 index 0000000000000000000000000000000000000000..65561e56bca816a17b327e930a6a94175c300101 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/title-last.png differ diff --git a/web-ui/docs/.vuepress/public/img/activities/year2022/user.png b/web-ui/docs/.vuepress/public/img/activities/year2022/user.png new file mode 100644 index 0000000000000000000000000000000000000000..769049b0057d4c650217b02c83275f22325f9fac Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/activities/year2022/user.png differ diff --git a/web-ui/docs/.vuepress/public/img/approve/adopt.png b/web-ui/docs/.vuepress/public/img/approve/adopt.png new file mode 100644 index 0000000000000000000000000000000000000000..36448c539cf8ac396dc457b03a170089f862f320 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/approve/adopt.png differ diff --git a/web-ui/docs/.vuepress/public/img/approve/fail.png b/web-ui/docs/.vuepress/public/img/approve/fail.png new file mode 100644 index 0000000000000000000000000000000000000000..84ca4ae5104c2bf816c14a17db307738b49da2d1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/approve/fail.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/20211108.jpg b/web-ui/docs/.vuepress/public/img/banners/20211108.jpg new file mode 100644 index 0000000000000000000000000000000000000000..56d9663bd1f129f167cac7e2ce9a0f9d210f19a8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/20211108.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/banners/20211117ol.png b/web-ui/docs/.vuepress/public/img/banners/20211117ol.png new file mode 100644 index 0000000000000000000000000000000000000000..e992603617fcc251b295bedda15d56b3be9d7b5c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/20211117ol.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/QRcode.jpg b/web-ui/docs/.vuepress/public/img/banners/QRcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8857209dd607b76165fea9a23e20b6c594fa879 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/QRcode.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/banners/banner-20190918hc.png b/web-ui/docs/.vuepress/public/img/banners/banner-20190918hc.png new file mode 100644 index 0000000000000000000000000000000000000000..9842c367c8f365e883691ce07661f3aa4c04f316 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/banner-20190918hc.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/banner-20200101.png b/web-ui/docs/.vuepress/public/img/banners/banner-20200101.png new file mode 100644 index 0000000000000000000000000000000000000000..615ee5e04f7af31dc4236aa9703c6738da487469 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/banner-20200101.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/banner-20200707-openeluer-live.png b/web-ui/docs/.vuepress/public/img/banners/banner-20200707-openeluer-live.png new file mode 100644 index 0000000000000000000000000000000000000000..192603496f7973f586a673fa7f8ac518d6ea89d5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/banner-20200707-openeluer-live.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/banner-2020hdc.png b/web-ui/docs/.vuepress/public/img/banners/banner-2020hdc.png new file mode 100644 index 0000000000000000000000000000000000000000..044765e3c7015a322f68abcbaf6371e0e410f83a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/banner-2020hdc.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/banner-hc.jpg b/web-ui/docs/.vuepress/public/img/banners/banner-hc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d3df02ce400bcd84e0868619958011c452df734 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/banner-hc.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP1.png b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP1.png new file mode 100644 index 0000000000000000000000000000000000000000..230e140a5618f19813faf7f1de758e1be559d87d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP1.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP2.png b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP2.png new file mode 100644 index 0000000000000000000000000000000000000000..c83800064dcc60629f378709ed98407c1a3708a2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP2.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP3.png b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP3.png new file mode 100644 index 0000000000000000000000000000000000000000..fcba0bd290ef3abe07d1966005d17944f3844d41 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2003LTSSP3.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2009.jpg b/web-ui/docs/.vuepress/public/img/banners/openeuler2009.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f43419f9b5ebc9f096dfbc4794396dada6f4c48e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2009.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2103.png b/web-ui/docs/.vuepress/public/img/banners/openeuler2103.png new file mode 100644 index 0000000000000000000000000000000000000000..79ab63efff00bd8a098bbc44ed4a5807426ae3a9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2103.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/openeuler2203LTS.png b/web-ui/docs/.vuepress/public/img/banners/openeuler2203LTS.png new file mode 100644 index 0000000000000000000000000000000000000000..8f6dcf57d29fcbe90b7344d4f9dbc57bd7a51ad8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/openeuler2203LTS.png differ diff --git a/web-ui/docs/.vuepress/public/img/banners/summit-2021.jpg b/web-ui/docs/.vuepress/public/img/banners/summit-2021.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7706ffd5ca46e36138d3f3459227178188438cba Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/banners/summit-2021.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/blog/account.svg b/web-ui/docs/.vuepress/public/img/blog/account.svg new file mode 100644 index 0000000000000000000000000000000000000000..e24d9bc4628474ace9caecd53a76b3901507b209 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/blog/account.svg @@ -0,0 +1,27 @@ + + + Outlined/UI/account + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/blog/blog_banner.png b/web-ui/docs/.vuepress/public/img/blog/blog_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..70c64822847af147275bb4314ac45c613a6956d3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/blog/blog_banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/blog/blog_user.png b/web-ui/docs/.vuepress/public/img/blog/blog_user.png new file mode 100644 index 0000000000000000000000000000000000000000..0a768c4cff3ada0850ced58323a3dc1b9b2442d2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/blog/blog_user.png differ diff --git a/web-ui/docs/.vuepress/public/img/blog/date.svg b/web-ui/docs/.vuepress/public/img/blog/date.svg new file mode 100644 index 0000000000000000000000000000000000000000..b5ce4032dd0dfcb0460c4d10175eb4799d1a11c8 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/blog/date.svg @@ -0,0 +1,23 @@ + + + Outlined/UI/date + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/blog/edit.svg b/web-ui/docs/.vuepress/public/img/blog/edit.svg new file mode 100644 index 0000000000000000000000000000000000000000..e626713cd9b3c058feaeb16075b1294172226543 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/blog/edit.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/blog/tag.svg b/web-ui/docs/.vuepress/public/img/blog/tag.svg new file mode 100644 index 0000000000000000000000000000000000000000..d79afe105daa504a4e7106c82209ee5dbbecb4e6 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/blog/tag.svg @@ -0,0 +1,16 @@ + + + openEuler/icons/tag + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/blog/visibility.svg b/web-ui/docs/.vuepress/public/img/blog/visibility.svg new file mode 100644 index 0000000000000000000000000000000000000000..7e11947a4adb7edbe5ee3d5bd6c156dc7fef2e8a --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/blog/visibility.svg @@ -0,0 +1,27 @@ + + + Outlined/UI/visibility + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/building/building-banner.png b/web-ui/docs/.vuepress/public/img/building/building-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0bb6a3705a04fef89c94a077091401c5297d5f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/building/building-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/cla/contribute.svg b/web-ui/docs/.vuepress/public/img/cla/contribute.svg new file mode 100644 index 0000000000000000000000000000000000000000..7f09e44d1693c3f66fa8df53f2916b98ea800ae4 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/contribute.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/date.svg b/web-ui/docs/.vuepress/public/img/cla/date.svg new file mode 100644 index 0000000000000000000000000000000000000000..bfcab5082b003f3c7b469692a24f6ab4d4e1054b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/date.svg @@ -0,0 +1,9 @@ + + + 形状结合 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/delete.svg b/web-ui/docs/.vuepress/public/img/cla/delete.svg new file mode 100644 index 0000000000000000000000000000000000000000..142c34fd311e02ab36590d1ed646500d8c945024 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/delete.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/edit.svg b/web-ui/docs/.vuepress/public/img/cla/edit.svg new file mode 100644 index 0000000000000000000000000000000000000000..f84afded3d235223b9310edc13517e7a9c2ff492 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/edit.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/email.svg b/web-ui/docs/.vuepress/public/img/cla/email.svg new file mode 100644 index 0000000000000000000000000000000000000000..43b8b8c59998937c48afb31623f2cb806dd91bb3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/email.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/name.svg b/web-ui/docs/.vuepress/public/img/cla/name.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3a52713c8c93a38d5ea5cb71bd395f1e5e8f8c5 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/name.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/office.svg b/web-ui/docs/.vuepress/public/img/cla/office.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3be8b9af8f4fd5806c973a1a2106a570343028e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/office.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/phone.svg b/web-ui/docs/.vuepress/public/img/cla/phone.svg new file mode 100644 index 0000000000000000000000000000000000000000..3548e96605d595105a88181cdc4dee556e8ba0e7 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/phone.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/position.svg b/web-ui/docs/.vuepress/public/img/cla/position.svg new file mode 100644 index 0000000000000000000000000000000000000000..117797273e5158bf16e5699638a468572f59b7d6 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/position.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/cla/printer.svg b/web-ui/docs/.vuepress/public/img/cla/printer.svg new file mode 100644 index 0000000000000000000000000000000000000000..69b0f247b73f0a0d82a6f2d98105576dfcd6b8bd --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/cla/printer.svg @@ -0,0 +1,9 @@ + + + 形状结合 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/common/icon-close.png b/web-ui/docs/.vuepress/public/img/common/icon-close.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0d473f65e53ccfbd4a15b2898b047c22d82407 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/common/icon-close.png differ diff --git a/web-ui/docs/.vuepress/public/img/common/record.png b/web-ui/docs/.vuepress/public/img/common/record.png new file mode 100644 index 0000000000000000000000000000000000000000..0e1d0311d752b2acc509ec3550296b78bd7e1a0a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/common/record.png differ diff --git a/web-ui/docs/.vuepress/public/img/common/right.svg b/web-ui/docs/.vuepress/public/img/common/right.svg new file mode 100644 index 0000000000000000000000000000000000000000..8ac53c995be73ed89d93c7dc2357f0c2cd11adae --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/common/right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/conduct-banner.png b/web-ui/docs/.vuepress/public/img/community/conduct/conduct-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..f1ffc39b4c05f1871f7a1523c851b904a44f35ba Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/conduct-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/down-card-icon.png b/web-ui/docs/.vuepress/public/img/community/conduct/down-card-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c824bf672fb0305ccc6b8154689f6b6d9c51cf23 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/down-card-icon.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/hcia-icon.png b/web-ui/docs/.vuepress/public/img/community/conduct/hcia-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..02ccbc6eff22b26c611121bbbde0c4478c25c4d3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/hcia-icon.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/hcie-icon.png b/web-ui/docs/.vuepress/public/img/community/conduct/hcie-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c11ceef8ab95a506a63baefa5904a5e9dfe44977 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/hcie-icon.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/hcip-icon.png b/web-ui/docs/.vuepress/public/img/community/conduct/hcip-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..827c60ea3e8960f754d1259414877ea4596f1be4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/hcip-icon.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/service-banner.png b/web-ui/docs/.vuepress/public/img/community/conduct/service-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8867883a8030c333712b3095fbfe82d46fdec229 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/service-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/showtemplate.png b/web-ui/docs/.vuepress/public/img/community/conduct/showtemplate.png new file mode 100644 index 0000000000000000000000000000000000000000..6961b8b42f62f0d5e9e2d833a23d71b4582ddb18 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/showtemplate.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/conduct/zhengshu.png b/web-ui/docs/.vuepress/public/img/community/conduct/zhengshu.png new file mode 100644 index 0000000000000000000000000000000000000000..b7873da53580c11031203f2989d3b2a932023169 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/conduct/zhengshu.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-h5.png b/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-h5.png new file mode 100644 index 0000000000000000000000000000000000000000..15edfbdb632969b59ec93eda4c77a8c894e739e9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-h5.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-pc.png b/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..093e22422145693bea84524902645e49c4caa979 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/contribution/contribution-banner-pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/maillist/mail-banner.png b/web-ui/docs/.vuepress/public/img/community/maillist/mail-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..a14a2a59373557caf728c6bf5a55ae3e91ecebc0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/maillist/mail-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/maillist/mail1.png b/web-ui/docs/.vuepress/public/img/community/maillist/mail1.png new file mode 100644 index 0000000000000000000000000000000000000000..f486e3d5d8fd3bac93bdb0136f1ca38bfa7fcd9c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/maillist/mail1.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/maillist/mail2.png b/web-ui/docs/.vuepress/public/img/community/maillist/mail2.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a033f7099461b773cb8c4219fd513847916ee1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/maillist/mail2.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/maillist/mail3.png b/web-ui/docs/.vuepress/public/img/community/maillist/mail3.png new file mode 100644 index 0000000000000000000000000000000000000000..9795cd8e49755564370e9a8d3e89b3f50b02f2b3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/maillist/mail3.png differ diff --git a/web-ui/docs/.vuepress/public/img/community/maillist/mail4.png b/web-ui/docs/.vuepress/public/img/community/maillist/mail4.png new file mode 100644 index 0000000000000000000000000000000000000000..259f1a4f4e10997f218bdfb712ae2b358731a732 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/community/maillist/mail4.png differ diff --git a/web-ui/docs/.vuepress/public/img/compatibility/compatibility_banner.png b/web-ui/docs/.vuepress/public/img/compatibility/compatibility_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..71aeb5473dbadfce01cea09d07a877599a4f7ae2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/compatibility/compatibility_banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-administration.svg b/web-ui/docs/.vuepress/public/img/docs/docs-administration.svg new file mode 100644 index 0000000000000000000000000000000000000000..b3cc597426881b998faa3a97f9d39279070e593e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-administration.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-application.svg b/web-ui/docs/.vuepress/public/img/docs/docs-application.svg new file mode 100644 index 0000000000000000000000000000000000000000..420fd3367982d6a00b15227843c8523fdf4aa25f --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-application.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-banner.png b/web-ui/docs/.vuepress/public/img/docs/docs-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2d09c2b4cc505d4241005ff3fd08b1bd315787 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/docs/docs-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-exploit.svg b/web-ui/docs/.vuepress/public/img/docs/docs-exploit.svg new file mode 100644 index 0000000000000000000000000000000000000000..f1c31d57d6220a9f46b6aa72b6fbb06a4242395e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-exploit.svg @@ -0,0 +1,33 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-installation.svg b/web-ui/docs/.vuepress/public/img/docs/docs-installation.svg new file mode 100644 index 0000000000000000000000000000000000000000..74ae68531a12ab916409cfacc42e7fd3c159691c --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-installation.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-quickstart.svg b/web-ui/docs/.vuepress/public/img/docs/docs-quickstart.svg new file mode 100644 index 0000000000000000000000000000000000000000..44640ff4701f05fd1d4208ca208420a89b00b7c3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-quickstart.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-releasenotes.svg b/web-ui/docs/.vuepress/public/img/docs/docs-releasenotes.svg new file mode 100644 index 0000000000000000000000000000000000000000..85905737ad8776896fba55fb3e50c04d8141816b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-releasenotes.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/docs-user.svg b/web-ui/docs/.vuepress/public/img/docs/docs-user.svg new file mode 100644 index 0000000000000000000000000000000000000000..194a8c69372e61a26e0be5fe10d273e50a6d1423 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/docs-user.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/docs/icon-document.svg b/web-ui/docs/.vuepress/public/img/docs/icon-document.svg new file mode 100644 index 0000000000000000000000000000000000000000..6fffb75e09883cececcbe4408025e6d35b3005aa --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/docs/icon-document.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/download-banner.png b/web-ui/docs/.vuepress/public/img/download/download-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..60800d22b87c5ab328667979612ae2e0a3c27443 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/download/download-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/download/get-iso.svg b/web-ui/docs/.vuepress/public/img/download/get-iso.svg new file mode 100644 index 0000000000000000000000000000000000000000..d317954ab0d1e3be78d4f333aca774583f6cf9cf --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/download/get-iso.svg @@ -0,0 +1,30 @@ + + + Outlined/UI/globe + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/guidence.svg b/web-ui/docs/.vuepress/public/img/download/guidence.svg new file mode 100644 index 0000000000000000000000000000000000000000..4b09c7b98a9a397f2f4596e924fa146642a07b77 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/download/guidence.svg @@ -0,0 +1,30 @@ + + + Outlined/UI/account + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/help.svg b/web-ui/docs/.vuepress/public/img/download/help.svg new file mode 100644 index 0000000000000000000000000000000000000000..edfc8d70fb9997f0ed8371607c32513ae17ae3ae --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/download/help.svg @@ -0,0 +1,30 @@ + + + Outlined/UI/account备份 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/icon-copy.png b/web-ui/docs/.vuepress/public/img/download/icon-copy.png new file mode 100644 index 0000000000000000000000000000000000000000..dc11a3d45da3e01e5238dc22f7cdb0e4080376ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/download/icon-copy.png differ diff --git a/web-ui/docs/.vuepress/public/img/download/life-circle.svg b/web-ui/docs/.vuepress/public/img/download/life-circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..5b33427f78ea551ef098b8abb8499e24dab43baf --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/download/life-circle.svg @@ -0,0 +1,30 @@ + + + Outlined/UI/account备份 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/mirror-banner.png b/web-ui/docs/.vuepress/public/img/download/mirror-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..6e861add993b024419fd66f3f1747d1710505c19 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/download/mirror-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/download/position.png b/web-ui/docs/.vuepress/public/img/download/position.png new file mode 100644 index 0000000000000000000000000000000000000000..f3739e2616778a8d89c77d7b7183481746939251 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/download/position.png differ diff --git a/web-ui/docs/.vuepress/public/img/download/release.svg b/web-ui/docs/.vuepress/public/img/download/release.svg new file mode 100644 index 0000000000000000000000000000000000000000..9713f847c56da8f5eca807bbad78c64a24ab190f --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/download/release.svg @@ -0,0 +1,28 @@ + + + Outlined/UI/email + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/download/reset.png b/web-ui/docs/.vuepress/public/img/download/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..ca13f7e1fc0e7ea11cb9a802205f191895a07205 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/download/reset.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/20200707-openeluer-live-01.png b/web-ui/docs/.vuepress/public/img/events/20200707-openeluer-live-01.png new file mode 100644 index 0000000000000000000000000000000000000000..84bf298072966e0675935a57b729ec94e8016370 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/20200707-openeluer-live-01.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/20200723-openeluer-live-01.jpg b/web-ui/docs/.vuepress/public/img/events/20200723-openeluer-live-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2a9911353cf708a94609e83afd42fde3bce6b8c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/20200723-openeluer-live-01.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/2020hdc/1.png b/web-ui/docs/.vuepress/public/img/events/2020hdc/1.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3ddfc52ff02647abbfb7b00877afe978b39105 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/2020hdc/1.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/2020hdc/2.png b/web-ui/docs/.vuepress/public/img/events/2020hdc/2.png new file mode 100644 index 0000000000000000000000000000000000000000..5c9387f46288bd1ef66844c75b19be73b8f2d0a9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/2020hdc/2.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/2020hdc/3.png b/web-ui/docs/.vuepress/public/img/events/2020hdc/3.png new file mode 100644 index 0000000000000000000000000000000000000000..cbbc21c6d35c40cd8334b97db191b37f64d24042 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/2020hdc/3.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/banner-20200104.png b/web-ui/docs/.vuepress/public/img/events/banner-20200104.png new file mode 100644 index 0000000000000000000000000000000000000000..9dae89d02e012b691f8b2ea7330d0cf17ea484c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/banner-20200104.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/hdc202001.png b/web-ui/docs/.vuepress/public/img/events/hdc202001.png new file mode 100644 index 0000000000000000000000000000000000000000..dbf4e7498121eb1914c9e85cbba4b40324abd57e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/hdc202001.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-2.jpg b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..191d2a50c0ed038a71a2414993b136eb10f1eba7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-2.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-3.jpg b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01e616b6d9dda5624e0b069a66c80f701d60226e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat-3.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat.jpg b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..191d2a50c0ed038a71a2414993b136eb10f1eba7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer-2020-wechat.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer1.png b/web-ui/docs/.vuepress/public/img/events/summer1.png new file mode 100644 index 0000000000000000000000000000000000000000..80a9d4ae394ab06efe7070b101edd73c583697cf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer1.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer2.png b/web-ui/docs/.vuepress/public/img/events/summer2.png new file mode 100644 index 0000000000000000000000000000000000000000..4094c5bb74c3a49c6707983844592ae1de67ff68 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer2.png differ diff --git a/web-ui/docs/.vuepress/public/img/events/summer3.jpeg b/web-ui/docs/.vuepress/public/img/events/summer3.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b145aa87b605ee4e9117d67efc31a8e74592dfe0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summer3.jpeg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit01.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..406f3a93c5d86de17fb8e0b4211a51cd124be146 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit01.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit02.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ce6b1e96f80d5ac4dcd82c3492b843f93497258 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit02.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit03.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dac7d1a7fcd8f5cb4a58f2221a3dd25dc747d9c3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit03.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit04.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ad3213edd62860179278344f69ac2c63e9ecef1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit04.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit05.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8397e4a0ac3323ea31a01efc8e07e34923adcdc3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit05.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit06.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bace155e5c816ace89a75d350adcb6b3a866f77d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit06.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit07.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit07.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ba6aa3b2e53a970cf488e6f1297700a6e2e63fc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit07.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit08.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit08.jpg new file mode 100644 index 0000000000000000000000000000000000000000..338a4a2813c696c8439d16b1f5479bb828d9c2a3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit08.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit09.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit09.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c4c7ca42c635431d11719f76d930edf939e8dea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit09.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit10.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b5a2f51e719a6d83c3b3a6de263ab3c3a368d1b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit10.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit11.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf451cce475c82c14e83c6bbfc4617ffd01231dc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit11.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit12.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit12.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dff5e7392cbacfe50ce03df21251e65b2d7ed92c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit12.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit13.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit13.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dcee4b98913c734b604016fb83a735a10f94d2f2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit13.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit14.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit14.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8045ac4db54658c17175b88bce301167e6267639 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit14.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/events/summit2021/summit15.jpg b/web-ui/docs/.vuepress/public/img/events/summit2021/summit15.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21db38986d804249cd7fa4ecea68cd54ceab37fd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/events/summit2021/summit15.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/home/2.png b/web-ui/docs/.vuepress/public/img/home/2.png new file mode 100644 index 0000000000000000000000000000000000000000..caea8e2e8e49846568b5999937ca2586848bf30d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/2.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/Banner1.gif b/web-ui/docs/.vuepress/public/img/home/Banner1.gif new file mode 100644 index 0000000000000000000000000000000000000000..5ccb08c4c3da7513e35e15f52556541f132725e7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Banner1.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/Banner2.gif b/web-ui/docs/.vuepress/public/img/home/Banner2.gif new file mode 100644 index 0000000000000000000000000000000000000000..b892193cbb7b035309a79ae6735b9ca4c7336133 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Banner2.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/Card1.png b/web-ui/docs/.vuepress/public/img/home/Card1.png new file mode 100644 index 0000000000000000000000000000000000000000..2a39d97fab94afbd156f325c4a4d224606ccb361 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Card1.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/Card2.png b/web-ui/docs/.vuepress/public/img/home/Card2.png new file mode 100644 index 0000000000000000000000000000000000000000..52d1b9a53eb8e90d660dd7c15e3212cb36276b72 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Card2.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/Card3.png b/web-ui/docs/.vuepress/public/img/home/Card3.png new file mode 100644 index 0000000000000000000000000000000000000000..2a39d97fab94afbd156f325c4a4d224606ccb361 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Card3.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/Card4.png b/web-ui/docs/.vuepress/public/img/home/Card4.png new file mode 100644 index 0000000000000000000000000000000000000000..6cd484dcd0829a8e23b7ccb0da23928a3747804e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Card4.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/Gitee.png b/web-ui/docs/.vuepress/public/img/home/Gitee.png new file mode 100644 index 0000000000000000000000000000000000000000..6bcf1963425e55703f50aac62d345ae068d9365d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/Gitee.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/areaECS.svg b/web-ui/docs/.vuepress/public/img/home/areaECS.svg new file mode 100644 index 0000000000000000000000000000000000000000..ffc2c67263363a9cbb3a287e560f717638e58612 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/areaECS.svg @@ -0,0 +1,39 @@ + + + 编组 2备份 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/areaHardware.svg b/web-ui/docs/.vuepress/public/img/home/areaHardware.svg new file mode 100644 index 0000000000000000000000000000000000000000..cb5a1f92eb4a77970d8c586a2fe41870cd40dcd5 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/areaHardware.svg @@ -0,0 +1,66 @@ + + + 编组 2备份 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/areaPai.png b/web-ui/docs/.vuepress/public/img/home/areaPai.png new file mode 100644 index 0000000000000000000000000000000000000000..6f60bd7a9d6926a82119a34eb3f99c8d535ca07b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/areaPai.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/areaVirtual.svg b/web-ui/docs/.vuepress/public/img/home/areaVirtual.svg new file mode 100644 index 0000000000000000000000000000000000000000..78639b2633538d0d8b3534b725f1c5ce24737e6b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/areaVirtual.svg @@ -0,0 +1,53 @@ + + + 编组 2备份 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/arrow.svg b/web-ui/docs/.vuepress/public/img/home/arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..56c9a462d0d37aab24a7a268e1b5a27d60d10a57 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/arrow.svg @@ -0,0 +1,12 @@ + + + Outlined/UI/button_arrow_down + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/arrowUp.svg b/web-ui/docs/.vuepress/public/img/home/arrowUp.svg new file mode 100644 index 0000000000000000000000000000000000000000..bdddebb17ce0d59681adf1258d888f61059bff2a --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/arrowUp.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_mo.png b/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..5633a1b3c55be0fcc10214577c54f00e9ad10aec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_pc.png b/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_pc.png new file mode 100644 index 0000000000000000000000000000000000000000..f0300bcb414a3cbdeeec0725a4e1ecf9bf9e2280 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/21.09_white_paper_pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-en.png b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-en.png new file mode 100644 index 0000000000000000000000000000000000000000..20ef55aec0665519f9d1ca81314796f5f2969af7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-zh.png b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..f173ec15c8f383ea88366ddf94de1e0bf579145a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/h5-dev2021-zh.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-en.png b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-en.png new file mode 100644 index 0000000000000000000000000000000000000000..cd3929140556d6e06b28632bbae7cc93e8d58710 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-zh.png b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..153dccfbe63ad19672bf3b42f22063df03c58907 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/dev2021/pc-dev2021-zh.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/loop.png b/web-ui/docs/.vuepress/public/img/home/banner/loop.png new file mode 100644 index 0000000000000000000000000000000000000000..30ddce03981cf8da52a49933c6c12c3b41b70637 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/loop.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner-mob.png b/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner-mob.png new file mode 100644 index 0000000000000000000000000000000000000000..ef5c730778d2c92e4118a295c1dfff8a8123a232 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner-mob.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner.png b/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2623df48d0964832126a07c7a81a9f27b3239cbc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/newyear-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/openEuler.png b/web-ui/docs/.vuepress/public/img/home/banner/openEuler.png new file mode 100644 index 0000000000000000000000000000000000000000..43fe86331fe3efcf75e5c8271f8e1a35f6a4acbb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/openEuler.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/openEuler_extend.png b/web-ui/docs/.vuepress/public/img/home/banner/openEuler_extend.png new file mode 100644 index 0000000000000000000000000000000000000000..8572d83cbf4f91204771d383fb3d9af2ddfc6585 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/openEuler_extend.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/openEuler_mo.png b/web-ui/docs/.vuepress/public/img/home/banner/openEuler_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..c4bb8904f340cd425b56a9a8c001d911bbb106b5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/openEuler_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/open_video.png b/web-ui/docs/.vuepress/public/img/home/banner/open_video.png new file mode 100644 index 0000000000000000000000000000000000000000..01d15afc81fb7cc24fead7d7a99777c533222d6f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/open_video.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/video-banner.png b/web-ui/docs/.vuepress/public/img/home/banner/video-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..0bae53fc345e2b3393d11ce573e379e0fece98c2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/video-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/video_banner_mo.png b/web-ui/docs/.vuepress/public/img/home/banner/video_banner_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e429401bcb923e86cd70f154ad0988c82bba75 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/video_banner_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/banner/video_banner_pc.png b/web-ui/docs/.vuepress/public/img/home/banner/video_banner_pc.png new file mode 100644 index 0000000000000000000000000000000000000000..4b6593a74f4be157f793e5bf43d7c2851753b20b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/banner/video_banner_pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/bannerSummer.png b/web-ui/docs/.vuepress/public/img/home/bannerSummer.png new file mode 100644 index 0000000000000000000000000000000000000000..56f8a0bd122b66da7558b0cdf77cfe2c7ff2b966 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/bannerSummer.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/bgCode-mob.png b/web-ui/docs/.vuepress/public/img/home/bgCode-mob.png new file mode 100644 index 0000000000000000000000000000000000000000..91bac0befff924603938ce1de20611075c672b15 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/bgCode-mob.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/bgCode-pc.png b/web-ui/docs/.vuepress/public/img/home/bgCode-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..ecfe32160b6506af1335c1a02e60faa454b3d2cb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/bgCode-pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/blogImg.png b/web-ui/docs/.vuepress/public/img/home/blogImg.png new file mode 100644 index 0000000000000000000000000000000000000000..489f8ab6f8a9ad556a696b152d6d8a07858d7567 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/blogImg.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/closeVoice.svg b/web-ui/docs/.vuepress/public/img/home/closeVoice.svg new file mode 100644 index 0000000000000000000000000000000000000000..2c0cd6c32956651fac2cef7dda7d5db5bd8ef403 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/closeVoice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/detail-link.png b/web-ui/docs/.vuepress/public/img/home/detail-link.png new file mode 100644 index 0000000000000000000000000000000000000000..f80d3624e0ba3875aa15bf47a52c572912627e11 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/detail-link.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/caihaomin.png b/web-ui/docs/.vuepress/public/img/home/developer/caihaomin.png new file mode 100644 index 0000000000000000000000000000000000000000..f2610a9583dfbf297181273073874fdf394dd24f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/caihaomin.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/dongjian.png b/web-ui/docs/.vuepress/public/img/home/developer/dongjian.png new file mode 100644 index 0000000000000000000000000000000000000000..e7d9e52494fd7aac6ab7d5999602180cfc8cddf6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/dongjian.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/dukaitian.png b/web-ui/docs/.vuepress/public/img/home/developer/dukaitian.png new file mode 100644 index 0000000000000000000000000000000000000000..fa1b5fe37d8c3a01d6a433d6ab3df18ff0ba5782 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/dukaitian.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/fengtao.png b/web-ui/docs/.vuepress/public/img/home/developer/fengtao.png new file mode 100644 index 0000000000000000000000000000000000000000..6d10c9ec098c6c0d38e0f369f7b894fe7fea4d19 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/fengtao.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/guoge.png b/web-ui/docs/.vuepress/public/img/home/developer/guoge.png new file mode 100644 index 0000000000000000000000000000000000000000..845e41d3db309d365eeba45bc79e2239299b2a75 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/guoge.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/guohanjun.png b/web-ui/docs/.vuepress/public/img/home/developer/guohanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..6c086b1e6f044096edab3c127fb0f91e4d5a47ce Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/guohanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/hanxingke.png b/web-ui/docs/.vuepress/public/img/home/developer/hanxingke.png new file mode 100644 index 0000000000000000000000000000000000000000..e3914cacd02048fd1312aa3fa7ad8207ff020243 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/hanxingke.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/hexiaowen.png b/web-ui/docs/.vuepress/public/img/home/developer/hexiaowen.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe7ebf26ef83a9ac6e01ccb6de41923e3181b81 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/hexiaowen.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/hufen.png b/web-ui/docs/.vuepress/public/img/home/developer/hufen.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7b9b9e1bc18699414f069587dc8c390794a0d2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/hufen.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/licihua.png b/web-ui/docs/.vuepress/public/img/home/developer/licihua.png new file mode 100644 index 0000000000000000000000000000000000000000..42c75ce3314703110e12aed8770d39abd48e4f47 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/licihua.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/lifeng.png b/web-ui/docs/.vuepress/public/img/home/developer/lifeng.png new file mode 100644 index 0000000000000000000000000000000000000000..bb895bf17cae9d9c2827f4c39ce9d8f2f903b3b0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/lifeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/linfeilong.png b/web-ui/docs/.vuepress/public/img/home/developer/linfeilong.png new file mode 100644 index 0000000000000000000000000000000000000000..3486f3a971c838038bc04b3ddd6efe10fcdec7ec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/linfeilong.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/liqingqing.png b/web-ui/docs/.vuepress/public/img/home/developer/liqingqing.png new file mode 100644 index 0000000000000000000000000000000000000000..baa0f2ebfaa8fdc5c23657fb2ea526507fea33cc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/liqingqing.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/liuzhiqiang.png b/web-ui/docs/.vuepress/public/img/home/developer/liuzhiqiang.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e7a9c76320f2c4bc595cdc97fd7a51e3459331 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/liuzhiqiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/wangxiaopeng.png b/web-ui/docs/.vuepress/public/img/home/developer/wangxiaopeng.png new file mode 100644 index 0000000000000000000000000000000000000000..498e76ab6e166972a10234caa4852e8f36b2a256 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/wangxiaopeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/wangyiru.png b/web-ui/docs/.vuepress/public/img/home/developer/wangyiru.png new file mode 100644 index 0000000000000000000000000000000000000000..b2d181c5170729e3d64ea36eb7f426ffc731e135 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/wangyiru.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/wubodong.png b/web-ui/docs/.vuepress/public/img/home/developer/wubodong.png new file mode 100644 index 0000000000000000000000000000000000000000..759c0d9a2738afc04848d4a60c73d7d0d93300ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/wubodong.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/xiasenglin.png b/web-ui/docs/.vuepress/public/img/home/developer/xiasenglin.png new file mode 100644 index 0000000000000000000000000000000000000000..9beec5bb63f0338f34537fe6452429f50a413516 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/xiasenglin.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/xiexiuqi.png b/web-ui/docs/.vuepress/public/img/home/developer/xiexiuqi.png new file mode 100644 index 0000000000000000000000000000000000000000..ddb861e07f8ead9856e2c7d6b7d9dea7003a1b54 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/xiexiuqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/xiezhipeng.png b/web-ui/docs/.vuepress/public/img/home/developer/xiezhipeng.png new file mode 100644 index 0000000000000000000000000000000000000000..345d74af088868749204598e966d8308d7c34412 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/xiezhipeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/xiongwei.png b/web-ui/docs/.vuepress/public/img/home/developer/xiongwei.png new file mode 100644 index 0000000000000000000000000000000000000000..df0b390ed900102155ccc2bb31a2525d40573372 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/xiongwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/xuyandong.png b/web-ui/docs/.vuepress/public/img/home/developer/xuyandong.png new file mode 100644 index 0000000000000000000000000000000000000000..7aef87a1a6286bdb8a97f039479f946820a9713e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/xuyandong.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/yangli.png b/web-ui/docs/.vuepress/public/img/home/developer/yangli.png new file mode 100644 index 0000000000000000000000000000000000000000..66c261597486376f4a1efba64f9df0dbbcfbb743 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/yangli.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/yangyingliang.png b/web-ui/docs/.vuepress/public/img/home/developer/yangyingliang.png new file mode 100644 index 0000000000000000000000000000000000000000..d870915cf0e08b962f4ed74250c1bc8ee12c001c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/yangyingliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhanghailiang.png b/web-ui/docs/.vuepress/public/img/home/developer/zhanghailiang.png new file mode 100644 index 0000000000000000000000000000000000000000..cc9153f61ca01f296caf784ce14a5cd97aaed07e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhanghailiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhangrui.png b/web-ui/docs/.vuepress/public/img/home/developer/zhangrui.png new file mode 100644 index 0000000000000000000000000000000000000000..d51745fa79c338079413bf2277a7f0480bd96203 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhangrui.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhangxuzhou.png b/web-ui/docs/.vuepress/public/img/home/developer/zhangxuzhou.png new file mode 100644 index 0000000000000000000000000000000000000000..429bd6414ecb6450fee585ffb7bd7f6bf135baf0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhangxuzhou.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhengxian.png b/web-ui/docs/.vuepress/public/img/home/developer/zhengxian.png new file mode 100644 index 0000000000000000000000000000000000000000..41122093d6bcd4e184d902decf113a84eb7e751d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhengxian.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhuchunyi.png b/web-ui/docs/.vuepress/public/img/home/developer/zhuchunyi.png new file mode 100644 index 0000000000000000000000000000000000000000..be8db69600087470df45d0770ade1b6f268074f4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhuchunyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhujianwei.png b/web-ui/docs/.vuepress/public/img/home/developer/zhujianwei.png new file mode 100644 index 0000000000000000000000000000000000000000..76252096602db5144c1a2af6f24b8084938d82c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhujianwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/developer/zhuyanpeng.png b/web-ui/docs/.vuepress/public/img/home/developer/zhuyanpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..29e4f863548995bffef70e49ad00830194bc74a7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/developer/zhuyanpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/email.png b/web-ui/docs/.vuepress/public/img/home/email.png new file mode 100644 index 0000000000000000000000000000000000000000..952ad2383f1e8617c5069d290b18fbb90a915a2f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/email.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/eventDate.svg b/web-ui/docs/.vuepress/public/img/home/eventDate.svg new file mode 100644 index 0000000000000000000000000000000000000000..c4afbf3da17ce03a838066e03507963d1b209c74 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/eventDate.svg @@ -0,0 +1,9 @@ + + + 形状结合 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/eventImg.png b/web-ui/docs/.vuepress/public/img/home/eventImg.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d1a0819fa30db280226bc44fdbc0c96e24f2eb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/eventImg.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/firstCode-mob.png b/web-ui/docs/.vuepress/public/img/home/firstCode-mob.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf7e2bee7d4ffb58b87edb6ffe70373995f0a01 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/firstCode-mob.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/firstCode-pc.png b/web-ui/docs/.vuepress/public/img/home/firstCode-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..149a751bcf77f53c4b2da7cbd76507a2f0b484df Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/firstCode-pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/homeActive.gif b/web-ui/docs/.vuepress/public/img/home/homeActive.gif new file mode 100644 index 0000000000000000000000000000000000000000..43a6e7d7a6ba9338233129ef0a033f5d92efd900 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/homeActive.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/letsPlay.png b/web-ui/docs/.vuepress/public/img/home/letsPlay.png new file mode 100644 index 0000000000000000000000000000000000000000..cddd44678252ad5a97c5b6f8dd624da118239119 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/letsPlay.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/Authing_mo.png b/web-ui/docs/.vuepress/public/img/home/link/Authing_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..bbd0dc00d052fa85e2334380c15a995879b1cb92 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/Authing_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/Authing_pc.png b/web-ui/docs/.vuepress/public/img/home/link/Authing_pc.png new file mode 100644 index 0000000000000000000000000000000000000000..57677a7c9c4b59addc022788c0917460481b53ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/Authing_pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo-mobile.png b/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe616eb3e608a72d8034e277635bb9000279a0c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo.png b/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6c541b12fbe88673ddeec7995692749a42f2847e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/OpenAnolis-logo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/cetc.png b/web-ui/docs/.vuepress/public/img/home/link/cetc.png new file mode 100644 index 0000000000000000000000000000000000000000..7825c67ddbcead22b4ec813d1dc3444ac33452e4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/cetc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/hopeRun.png b/web-ui/docs/.vuepress/public/img/home/link/hopeRun.png new file mode 100644 index 0000000000000000000000000000000000000000..8bedfa4823fc0b8683a288204fced2baf6d422a0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/hopeRun.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/infoQ.png b/web-ui/docs/.vuepress/public/img/home/link/infoQ.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d07b53aebe9d09a6ed4b24a0f5aa491de6241c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/infoQ.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/iscas.png b/web-ui/docs/.vuepress/public/img/home/link/iscas.png new file mode 100644 index 0000000000000000000000000000000000000000..3b0a84259432fa373b88122ae4ecb1f888988ef2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/iscas.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo-mobile.png b/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fff0f6ae01fcfd20343fd306f18129b743bf8c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo.png b/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc47da18d4e5dd02aabb58deb8b16c2abcdef4a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/kaiyuanshe-logo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/kunpeng.png b/web-ui/docs/.vuepress/public/img/home/link/kunpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..d7672d12bec4db5b2c6143109b843eb74bfdbbb3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/kunpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-cetc.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-cetc.png new file mode 100644 index 0000000000000000000000000000000000000000..6b27c5977f3e8a7f76f0b7519d2d0fdbf7041c86 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-cetc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-hopeRun.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-hopeRun.png new file mode 100644 index 0000000000000000000000000000000000000000..bd665c586a72ee8e84b7ae79d404bbe18a316549 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-hopeRun.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-infoQ.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-infoQ.png new file mode 100644 index 0000000000000000000000000000000000000000..72e42d436876b468a08ed6c75f428a117d45cc67 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-infoQ.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-iscas.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-iscas.png new file mode 100644 index 0000000000000000000000000000000000000000..c18dde2495eae028dfe922156f5febc1d3f49ec1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-iscas.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-kunpeng.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-kunpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..4a0eacaa6e58181bcc8edfe2c2d4c525da7576d7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-kunpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-mulan.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-mulan.png new file mode 100644 index 0000000000000000000000000000000000000000..217086bee59d3f29c77deaac19a57b1a12d85c12 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-mulan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-pengcheng.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-pengcheng.png new file mode 100644 index 0000000000000000000000000000000000000000..d915946e957c162358cd3b0163ac4dd7c74acd9c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-pengcheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-qiling.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-qiling.png new file mode 100644 index 0000000000000000000000000000000000000000..5e38ae7ecced4a4d70b1e522ca4315a4dbaebe21 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-qiling.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-suse.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-suse.png new file mode 100644 index 0000000000000000000000000000000000000000..b13b73f0bab1669178129f07674809c199ac8708 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-suse.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-tongYuan.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-tongYuan.png new file mode 100644 index 0000000000000000000000000000000000000000..9e1b50ddbcbcfdb383e83cb2e656110a9bf6e06a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-tongYuan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-tongxin.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-tongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..27657f22c731073f664496071da33a4ac17e1fc3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-tongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-turbo.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-turbo.png new file mode 100644 index 0000000000000000000000000000000000000000..a3ee22ffcfc4b9171503e8a1c08e50995d0b5c97 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-turbo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-xiaozhi.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-xiaozhi.png new file mode 100644 index 0000000000000000000000000000000000000000..7d319feb42870563a5715e6ac7292610c65b4dd2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-xiaozhi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-xinan.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-xinan.png new file mode 100644 index 0000000000000000000000000000000000000000..990e9b7ee5b0bfbac4cfc22afa0478a564471df1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-xinan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkefangde.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkefangde.png new file mode 100644 index 0000000000000000000000000000000000000000..60fd3aed32eff29d654e2f3a9fdc091b1b6a75aa Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkefangde.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkehongqi.png b/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkehongqi.png new file mode 100644 index 0000000000000000000000000000000000000000..df88fc34458512bf83aab5e0dcf32b36472051d8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mobile-zhongkehongqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/mulan.png b/web-ui/docs/.vuepress/public/img/home/link/mulan.png new file mode 100644 index 0000000000000000000000000000000000000000..7cefee5ce27ec24bbf7b3b056f7e4cd353df28d8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/mulan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/pengcheng.png b/web-ui/docs/.vuepress/public/img/home/link/pengcheng.png new file mode 100644 index 0000000000000000000000000000000000000000..32a48876528760f599c87aed49cf21a9166ce821 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/pengcheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/qiling.png b/web-ui/docs/.vuepress/public/img/home/link/qiling.png new file mode 100644 index 0000000000000000000000000000000000000000..933a3ed7ce6f02d787c15ba91dc1197035ba92f1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/qiling.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/suse.png b/web-ui/docs/.vuepress/public/img/home/link/suse.png new file mode 100644 index 0000000000000000000000000000000000000000..09e7955ae6b973d3e06e439f155e13e34490d862 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/suse.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/tongYuan.png b/web-ui/docs/.vuepress/public/img/home/link/tongYuan.png new file mode 100644 index 0000000000000000000000000000000000000000..30c447c68dae6b4964fcd34c18a73154dbcdebc8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/tongYuan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/tongxin.png b/web-ui/docs/.vuepress/public/img/home/link/tongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..35584c90dd3c45e28853bf206e485d6154eff196 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/tongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/turbo.png b/web-ui/docs/.vuepress/public/img/home/link/turbo.png new file mode 100644 index 0000000000000000000000000000000000000000..4f344b335895617f7a97d6a325f76cc282581bbc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/turbo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/xfusion.png b/web-ui/docs/.vuepress/public/img/home/link/xfusion.png new file mode 100644 index 0000000000000000000000000000000000000000..f4e96e1f8d0977b4d75b2cfe944dd0f0decde653 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/xfusion.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/xfusion_mobile.png b/web-ui/docs/.vuepress/public/img/home/link/xfusion_mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba9f9d2064939b19ecd3041ec6505b7e2b403fb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/xfusion_mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/xiaozhi.png b/web-ui/docs/.vuepress/public/img/home/link/xiaozhi.png new file mode 100644 index 0000000000000000000000000000000000000000..c106f3547bc956c452ffccfb732afb84cabd12d4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/xiaozhi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/xinan.png b/web-ui/docs/.vuepress/public/img/home/link/xinan.png new file mode 100644 index 0000000000000000000000000000000000000000..757d716f38cf9fbf314924ea4d52981433e50233 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/xinan.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/zhongke_mo.png b/web-ui/docs/.vuepress/public/img/home/link/zhongke_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..d92cd71933e52fdf6b13f4258f3ede2d2826142d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/zhongke_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/zhongke_pc.png b/web-ui/docs/.vuepress/public/img/home/link/zhongke_pc.png new file mode 100644 index 0000000000000000000000000000000000000000..c8388609a93b1815ecafb512d01b1e7ab82341e3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/zhongke_pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/zhongkefangde.png b/web-ui/docs/.vuepress/public/img/home/link/zhongkefangde.png new file mode 100644 index 0000000000000000000000000000000000000000..e419017f83b4feaf13fbb06cbf35250fffc259fc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/zhongkefangde.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/link/zhongkehongqi.png b/web-ui/docs/.vuepress/public/img/home/link/zhongkehongqi.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3cde7d0dc6209f10cfe16872d2d10d0b9f56dc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/link/zhongkehongqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/medal.svg b/web-ui/docs/.vuepress/public/img/home/medal.svg new file mode 100644 index 0000000000000000000000000000000000000000..3ebd4bf64f104e2fa3296f486fa527bc5b087749 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/medal.svg @@ -0,0 +1,26 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/mobile-h1.png b/web-ui/docs/.vuepress/public/img/home/mobile-h1.png new file mode 100644 index 0000000000000000000000000000000000000000..3d9ab23d6683bd659f5c4aa71e57de7fffc6fec5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/mobile-h1.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/newsImg.png b/web-ui/docs/.vuepress/public/img/home/newsImg.png new file mode 100644 index 0000000000000000000000000000000000000000..17efec21a55605cdb1533c86f5f57ee7f33ada9d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/newsImg.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/openVoice.svg b/web-ui/docs/.vuepress/public/img/home/openVoice.svg new file mode 100644 index 0000000000000000000000000000000000000000..7ad930a7ab24997248e55248ba13d9a36cc38297 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/openVoice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/pc-h1.png b/web-ui/docs/.vuepress/public/img/home/pc-h1.png new file mode 100644 index 0000000000000000000000000000000000000000..c9e338629269ba81accef226d08a3895ba1a9951 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/pc-h1.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/planeLeft.svg b/web-ui/docs/.vuepress/public/img/home/planeLeft.svg new file mode 100644 index 0000000000000000000000000000000000000000..2608f34122cecbf7c2fbcb63ddab651bd038edf4 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/planeLeft.svg @@ -0,0 +1,37 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/planeMiddle.svg b/web-ui/docs/.vuepress/public/img/home/planeMiddle.svg new file mode 100644 index 0000000000000000000000000000000000000000..cf0f0560f7319387e505529c754974f601597b50 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/planeMiddle.svg @@ -0,0 +1,44 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/planeRight.svg b/web-ui/docs/.vuepress/public/img/home/planeRight.svg new file mode 100644 index 0000000000000000000000000000000000000000..3f75cc7649a4ff90a944055ed6ae079525c55e47 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/planeRight.svg @@ -0,0 +1,37 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/play-btn.gif b/web-ui/docs/.vuepress/public/img/home/play-btn.gif new file mode 100644 index 0000000000000000000000000000000000000000..55f7bb03b6286d9971b23f8623b0a243ce2f0c7f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/play-btn.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/prev-detail.svg b/web-ui/docs/.vuepress/public/img/home/prev-detail.svg new file mode 100644 index 0000000000000000000000000000000000000000..ec88be4c8e3c92f9de01f58a5437d3d35c0c3bc3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/prev-detail.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/prev.svg b/web-ui/docs/.vuepress/public/img/home/prev.svg new file mode 100644 index 0000000000000000000000000000000000000000..95ec059b11d49f761fcda142c4a1348fc17d3399 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/prev.svg @@ -0,0 +1,19 @@ + + + Shape + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/rodeLeft.svg b/web-ui/docs/.vuepress/public/img/home/rodeLeft.svg new file mode 100644 index 0000000000000000000000000000000000000000..21c189a14833bd15ab0a49519ae3fe3f8490faa3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/rodeLeft.svg @@ -0,0 +1,9 @@ + + + 路径 4 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/rodeMiddle.svg b/web-ui/docs/.vuepress/public/img/home/rodeMiddle.svg new file mode 100644 index 0000000000000000000000000000000000000000..303b612a102976dfca72e564a13f9e4305bdba16 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/rodeMiddle.svg @@ -0,0 +1,9 @@ + + + 路径 8 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/rodeRight.svg b/web-ui/docs/.vuepress/public/img/home/rodeRight.svg new file mode 100644 index 0000000000000000000000000000000000000000..4acb81fceda33b866b0465dc1a1d2e4be3b69534 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/rodeRight.svg @@ -0,0 +1,9 @@ + + + 路径 9 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/sourceApply.gif b/web-ui/docs/.vuepress/public/img/home/sourceApply.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad13f7d4c415f8300ea2b4176207db0533f73a9a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/sourceApply.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/sourceMail.gif b/web-ui/docs/.vuepress/public/img/home/sourceMail.gif new file mode 100644 index 0000000000000000000000000000000000000000..cf17e742422a3850e194e95a014fad91353f4dca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/sourceMail.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/step-move-1.gif b/web-ui/docs/.vuepress/public/img/home/step-move-1.gif new file mode 100644 index 0000000000000000000000000000000000000000..7b0db69d2920ca817ad2341ac0e707f378601179 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step-move-1.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/step-move-2.gif b/web-ui/docs/.vuepress/public/img/home/step-move-2.gif new file mode 100644 index 0000000000000000000000000000000000000000..ee4053fdcfc005e19274695c6cb1bbaba9797323 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step-move-2.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/step-move-3.gif b/web-ui/docs/.vuepress/public/img/home/step-move-3.gif new file mode 100644 index 0000000000000000000000000000000000000000..72152b7c319ecef3ffbd535237b1615e179cb777 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step-move-3.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/step-move-4.gif b/web-ui/docs/.vuepress/public/img/home/step-move-4.gif new file mode 100644 index 0000000000000000000000000000000000000000..9c19664fd0a9162c3f7d8c85e8f3931c374acc4d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step-move-4.gif differ diff --git a/web-ui/docs/.vuepress/public/img/home/step1.png b/web-ui/docs/.vuepress/public/img/home/step1.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3125589320394cca20bb7f5043e68512fcd50d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step1.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/step2.png b/web-ui/docs/.vuepress/public/img/home/step2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8de17c6077418708ab0e55710f2b3772927d31 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step2.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/step3.png b/web-ui/docs/.vuepress/public/img/home/step3.png new file mode 100644 index 0000000000000000000000000000000000000000..198f5fd976a815840428c54d2af633650d592ce8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step3.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/step4.png b/web-ui/docs/.vuepress/public/img/home/step4.png new file mode 100644 index 0000000000000000000000000000000000000000..367dc08ef8d477eab9b1a36222f49e3f1b71dcea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/step4.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/userEmail.svg b/web-ui/docs/.vuepress/public/img/home/userEmail.svg new file mode 100644 index 0000000000000000000000000000000000000000..43b8b8c59998937c48afb31623f2cb806dd91bb3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/userEmail.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/userName.svg b/web-ui/docs/.vuepress/public/img/home/userName.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3a52713c8c93a38d5ea5cb71bd395f1e5e8f8c5 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/home/userName.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/home/webBanner0.png b/web-ui/docs/.vuepress/public/img/home/webBanner0.png new file mode 100644 index 0000000000000000000000000000000000000000..017ae6775f9ff655bef9278916da3ec470d47edc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/webBanner0.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/webBanner1.png b/web-ui/docs/.vuepress/public/img/home/webBanner1.png new file mode 100644 index 0000000000000000000000000000000000000000..84428ad2ee8c2f903b7bfaf2c1b1cf2bc962ec3c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/webBanner1.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/webBanner2.png b/web-ui/docs/.vuepress/public/img/home/webBanner2.png new file mode 100644 index 0000000000000000000000000000000000000000..017ae6775f9ff655bef9278916da3ec470d47edc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/webBanner2.png differ diff --git a/web-ui/docs/.vuepress/public/img/home/webBannerVideo.png b/web-ui/docs/.vuepress/public/img/home/webBannerVideo.png new file mode 100644 index 0000000000000000000000000000000000000000..5383107b1b1851a8c5a0892cb46be25120beb39f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/home/webBannerVideo.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/1.png b/web-ui/docs/.vuepress/public/img/internship/1.png new file mode 100644 index 0000000000000000000000000000000000000000..12b8f8f5aafa3e842c979697d960301aea21cbdd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/1.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/2.png b/web-ui/docs/.vuepress/public/img/internship/2.png new file mode 100644 index 0000000000000000000000000000000000000000..da2fee66d6879d5b4a49e8bf0c05ddb8d2889da5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/2.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/3.png b/web-ui/docs/.vuepress/public/img/internship/3.png new file mode 100644 index 0000000000000000000000000000000000000000..e36b223ea1215a7498838f8bf4df981cab131bc4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/3.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/4.png b/web-ui/docs/.vuepress/public/img/internship/4.png new file mode 100644 index 0000000000000000000000000000000000000000..aa5df6276fbdc4aa382315d36a438628ba9ba1c2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/4.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/arrow.png b/web-ui/docs/.vuepress/public/img/internship/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..03ed17037edb46e38e8c53207fa64bac87d7909d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/arrow.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/close.png b/web-ui/docs/.vuepress/public/img/internship/close.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb322edcda73670dc19037ab491494315a5c629 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/close.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/gitee.png b/web-ui/docs/.vuepress/public/img/internship/gitee.png new file mode 100644 index 0000000000000000000000000000000000000000..5dd3d965386bef774b1b706d48808eb508e586b0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/gitee.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/go-task.png b/web-ui/docs/.vuepress/public/img/internship/go-task.png new file mode 100644 index 0000000000000000000000000000000000000000..8d0f1699f29789a23f49a9a6236f2ce4244f6551 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/go-task.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/help-title.png b/web-ui/docs/.vuepress/public/img/internship/help-title.png new file mode 100644 index 0000000000000000000000000000000000000000..d90c38b1e8901d16c2e728dad4b1ceaa971b00c8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/help-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/integral-background-mo.png b/web-ui/docs/.vuepress/public/img/internship/integral-background-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..32526f9a5b4e5edf404878ccddfa6ed8b23f0d02 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/integral-background-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/integral-background.png b/web-ui/docs/.vuepress/public/img/internship/integral-background.png new file mode 100644 index 0000000000000000000000000000000000000000..73db59365bfb4c5e75eedfa0da4427fe0f12276d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/integral-background.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/integral-title.png b/web-ui/docs/.vuepress/public/img/internship/integral-title.png new file mode 100644 index 0000000000000000000000000000000000000000..17862074a42b8b996117c64566bfebfc9deac899 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/integral-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/internship-banner-mo.png b/web-ui/docs/.vuepress/public/img/internship/internship-banner-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..6670ca1d35a940ee0a89e5742d640b2680f8a8ec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/internship-banner-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/internship-banner.png b/web-ui/docs/.vuepress/public/img/internship/internship-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..d87ae6ceefa76a54868b0a49619b8364bcfa51b9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/internship-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/iscas.png b/web-ui/docs/.vuepress/public/img/internship/iscas.png new file mode 100644 index 0000000000000000000000000000000000000000..f461b20a15f3dadbd64f79c49f49f9a920e197c8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/iscas.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/kylinsec.png b/web-ui/docs/.vuepress/public/img/internship/kylinsec.png new file mode 100644 index 0000000000000000000000000000000000000000..2e5b7356e9658a25dbe466ef1e71c53fd86391f1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/kylinsec.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/mindSpore.png b/web-ui/docs/.vuepress/public/img/internship/mindSpore.png new file mode 100644 index 0000000000000000000000000000000000000000..457a458a8582889c0bf2f20cefddf4923dfb1ab6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/mindSpore.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/openEuler.png b/web-ui/docs/.vuepress/public/img/internship/openEuler.png new file mode 100644 index 0000000000000000000000000000000000000000..66e91bb12a989bb3de9833ed35ae894f1e32299a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/openEuler.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/openGauss.png b/web-ui/docs/.vuepress/public/img/internship/openGauss.png new file mode 100644 index 0000000000000000000000000000000000000000..f7dd53f3e64005bbf631c4378ecf4212038925bf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/openGauss.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/openLooKeng.png b/web-ui/docs/.vuepress/public/img/internship/openLooKeng.png new file mode 100644 index 0000000000000000000000000000000000000000..eb682ceb4ca89a6a194edef344741befa386cfe3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/openLooKeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/other-community-bg.png b/web-ui/docs/.vuepress/public/img/internship/other-community-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..fc49766fb670d28c65b916757eedeaf111145f9f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/other-community-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/partner-title.png b/web-ui/docs/.vuepress/public/img/internship/partner-title.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dc08ca4f6ded1699e8dd1aebcb3ac0b8f09752 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/partner-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/qilinsoft.png b/web-ui/docs/.vuepress/public/img/internship/qilinsoft.png new file mode 100644 index 0000000000000000000000000000000000000000..9641134db2274e292fc778a78fa40ae98a5e7d6f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/qilinsoft.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/qq-code.png b/web-ui/docs/.vuepress/public/img/internship/qq-code.png new file mode 100644 index 0000000000000000000000000000000000000000..e00ca12cc6157810cad0bacfb21940ed5316641c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/qq-code.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/qrCode.png b/web-ui/docs/.vuepress/public/img/internship/qrCode.png new file mode 100644 index 0000000000000000000000000000000000000000..505275bdd34b5e35d980b5196d5fe6842745e5f3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/qrCode.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/rank-title-mo.png b/web-ui/docs/.vuepress/public/img/internship/rank-title-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..772236f0ddb2e1c5a1863050cede2e118ec96d53 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/rank-title-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/rank-title.png b/web-ui/docs/.vuepress/public/img/internship/rank-title.png new file mode 100644 index 0000000000000000000000000000000000000000..b8aec2b22c7b7b35de144a474cc8e67ac5d33ef5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/rank-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/right.svg b/web-ui/docs/.vuepress/public/img/internship/right.svg new file mode 100644 index 0000000000000000000000000000000000000000..8ac53c995be73ed89d93c7dc2357f0c2cd11adae --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/internship/right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/internship/rule-background.png b/web-ui/docs/.vuepress/public/img/internship/rule-background.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9e5fc56f00c3f24ab675765380b8794fe7c3a6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/rule-background.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/rule-title.png b/web-ui/docs/.vuepress/public/img/internship/rule-title.png new file mode 100644 index 0000000000000000000000000000000000000000..b6ab89bba91232044fb576f810741aed325998ca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/rule-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/star.png b/web-ui/docs/.vuepress/public/img/internship/star.png new file mode 100644 index 0000000000000000000000000000000000000000..34db3790834e000a3e9f73c86b1bdd3f0b37a518 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/star.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step-3-mo.png b/web-ui/docs/.vuepress/public/img/internship/step-3-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3096e639bdcadb183074e689210a12b893bed8b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step-3-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step-3.png b/web-ui/docs/.vuepress/public/img/internship/step-3.png new file mode 100644 index 0000000000000000000000000000000000000000..8486e93099b8a50434eac3e7bc9639469563c7ff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step-3.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step-background.png b/web-ui/docs/.vuepress/public/img/internship/step-background.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccbe13aa3f85cc5a63f652944a6defa37c9a22e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step-background.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step-title.png b/web-ui/docs/.vuepress/public/img/internship/step-title.png new file mode 100644 index 0000000000000000000000000000000000000000..1e99282bdb390f25745f55c7590ff6a6a502da0c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_1.png b/web-ui/docs/.vuepress/public/img/internship/step_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d014c5954a634038350db478af6ccd2c6f280f5a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_1.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_1active.png b/web-ui/docs/.vuepress/public/img/internship/step_1active.png new file mode 100644 index 0000000000000000000000000000000000000000..d895d21e7e6d0b654607c5357d3178186003f26e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_1active.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_2.png b/web-ui/docs/.vuepress/public/img/internship/step_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e7e3da38115e14b52adb2906ca9739069247fe Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_2.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_2active.png b/web-ui/docs/.vuepress/public/img/internship/step_2active.png new file mode 100644 index 0000000000000000000000000000000000000000..fd805b68ce9099157e95f4393b4bf8cd7d22d2e7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_2active.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_3.png b/web-ui/docs/.vuepress/public/img/internship/step_3.png new file mode 100644 index 0000000000000000000000000000000000000000..5f936386259d96d7825761aff1cf2e3ffd83759a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_3.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_3active.png b/web-ui/docs/.vuepress/public/img/internship/step_3active.png new file mode 100644 index 0000000000000000000000000000000000000000..010c91b9e65d9cd78305ea5bcbae9107aec9e8c1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_3active.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_4.png b/web-ui/docs/.vuepress/public/img/internship/step_4.png new file mode 100644 index 0000000000000000000000000000000000000000..66820952403e83a727d9f3bdacb0e16baadbf819 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_4.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/step_4active.png b/web-ui/docs/.vuepress/public/img/internship/step_4active.png new file mode 100644 index 0000000000000000000000000000000000000000..8c1f924b0cd2163d094d1048f5685b9d21cc899b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/step_4active.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/task-title.png b/web-ui/docs/.vuepress/public/img/internship/task-title.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ddab8dfaff96363956892e5e5977bc287ce113 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/task-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/internship/tongxin.png b/web-ui/docs/.vuepress/public/img/internship/tongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..82f01ecd7ae564c941b408bb4ecf1ebc0580501d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/internship/tongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/learn/hcia/hcia.png b/web-ui/docs/.vuepress/public/img/learn/hcia/hcia.png new file mode 100644 index 0000000000000000000000000000000000000000..59ae5ab311a56fc87fa57975962820f700e70b7c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/learn/hcia/hcia.png differ diff --git a/web-ui/docs/.vuepress/public/img/learn/hcia/yanglei.png b/web-ui/docs/.vuepress/public/img/learn/hcia/yanglei.png new file mode 100644 index 0000000000000000000000000000000000000000..dd982d7c88af5bdfd82e4f45ffab165188d61ab0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/learn/hcia/yanglei.png differ diff --git a/web-ui/docs/.vuepress/public/img/learn/hcia/zhongyunan.png b/web-ui/docs/.vuepress/public/img/learn/hcia/zhongyunan.png new file mode 100644 index 0000000000000000000000000000000000000000..360aa5d5639a1835edb46af3d54d3da592c003e0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/learn/hcia/zhongyunan.png differ diff --git a/web-ui/docs/.vuepress/public/img/learn/mooc-banner.png b/web-ui/docs/.vuepress/public/img/learn/mooc-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf03dacd4847c1faee574bd23765971d899809f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/learn/mooc-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/learn/play.png b/web-ui/docs/.vuepress/public/img/learn/play.png new file mode 100644 index 0000000000000000000000000000000000000000..563e6323f4c070f364ea24d8d02dfd276a71af8c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/learn/play.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/Fill.svg b/web-ui/docs/.vuepress/public/img/live/Fill.svg new file mode 100644 index 0000000000000000000000000000000000000000..350a4bac160380f2c76c9eb870b44bad57a566d9 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/live/Fill.svg @@ -0,0 +1,14 @@ + + + Fill 1 + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/live/Fill2.svg b/web-ui/docs/.vuepress/public/img/live/Fill2.svg new file mode 100644 index 0000000000000000000000000000000000000000..cdcdff2c9401c6bbaf39d81ee17f587ca299c61b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/live/Fill2.svg @@ -0,0 +1,14 @@ + + + Fill 1 + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/live/ball-background.png b/web-ui/docs/.vuepress/public/img/live/ball-background.png new file mode 100644 index 0000000000000000000000000000000000000000..6181dfd2776a419964a70d6c1fa38c2f7b93cf4b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/ball-background.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/boruifeng.png b/web-ui/docs/.vuepress/public/img/live/boruifeng.png new file mode 100644 index 0000000000000000000000000000000000000000..207312aa2b42af79722ae3908ed41ce3da3f63ed Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/boruifeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/chenzhendong.png b/web-ui/docs/.vuepress/public/img/live/chenzhendong.png new file mode 100644 index 0000000000000000000000000000000000000000..8adf885de55e903ca51d30d54e01fd7b2ccfab0d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/chenzhendong.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/fengtao.png b/web-ui/docs/.vuepress/public/img/live/fengtao.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4a81ceeb43bf0a0ca31e9e890f50c436e85db0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/fengtao.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/gaowei.png b/web-ui/docs/.vuepress/public/img/live/gaowei.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a0325d92e147981c39356333e6bebd68701d90 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/gaowei.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/guoxinle.png b/web-ui/docs/.vuepress/public/img/live/guoxinle.png new file mode 100644 index 0000000000000000000000000000000000000000..1bcfccde29db43c0b03488458ab8075be5468c14 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/guoxinle.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/hexiaowen.png b/web-ui/docs/.vuepress/public/img/live/hexiaowen.png new file mode 100644 index 0000000000000000000000000000000000000000..2f25bf659f3c0a2f5e7fa676f9de6b79c8e592a9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/hexiaowen.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/jiangpengfei.png b/web-ui/docs/.vuepress/public/img/live/jiangpengfei.png new file mode 100644 index 0000000000000000000000000000000000000000..1275128b7748d0211ba55ef8a6bf5cdaa7c7e547 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/jiangpengfei.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/kezhiming.png b/web-ui/docs/.vuepress/public/img/live/kezhiming.png new file mode 100644 index 0000000000000000000000000000000000000000..34681c621eff6856d59c3f0cd4b6ac3fa7af7935 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/kezhiming.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/lifeng.png b/web-ui/docs/.vuepress/public/img/live/lifeng.png new file mode 100644 index 0000000000000000000000000000000000000000..9817aa2308b71da2ab3993fde8884d7b8f4206ae Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/lifeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/liuhao.png b/web-ui/docs/.vuepress/public/img/live/liuhao.png new file mode 100644 index 0000000000000000000000000000000000000000..05885cf414c676143d5100c54fd177abcd7c33cd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/liuhao.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/liuzekun.png b/web-ui/docs/.vuepress/public/img/live/liuzekun.png new file mode 100644 index 0000000000000000000000000000000000000000..929dfd997f0788cf5150d861cdb3b1f0c4f700e6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/liuzekun.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/live-banner.png b/web-ui/docs/.vuepress/public/img/live/live-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..ba9569c8072fc0a23ed57b469e409f8e8b8c1c03 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/live-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/lixiang.png b/web-ui/docs/.vuepress/public/img/live/lixiang.png new file mode 100644 index 0000000000000000000000000000000000000000..6313c776f59e759e7bbe2d5e0ed54d93de141b4c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/lixiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/majun.png b/web-ui/docs/.vuepress/public/img/live/majun.png new file mode 100644 index 0000000000000000000000000000000000000000..04af44da09f79ada33be4ad26d45e1e309468bda Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/majun.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/shenyangyang.png b/web-ui/docs/.vuepress/public/img/live/shenyangyang.png new file mode 100644 index 0000000000000000000000000000000000000000..987fc6f7e0741fb0bc8764f04b0944c22b3d7cfe Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/shenyangyang.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/wangzhigang.png b/web-ui/docs/.vuepress/public/img/live/wangzhigang.png new file mode 100644 index 0000000000000000000000000000000000000000..44b05929e2f211be58d2bf27dc996af5955ec975 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/wangzhigang.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/wujing.png b/web-ui/docs/.vuepress/public/img/live/wujing.png new file mode 100644 index 0000000000000000000000000000000000000000..89cb643935574e5aa5328daf1a1b51d1ee752a2a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/wujing.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/xiadanni.png b/web-ui/docs/.vuepress/public/img/live/xiadanni.png new file mode 100644 index 0000000000000000000000000000000000000000..75b9f3f9ad5e1baf689ccb9e682623b9a24e436b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/xiadanni.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/xiexiuqi.png b/web-ui/docs/.vuepress/public/img/live/xiexiuqi.png new file mode 100644 index 0000000000000000000000000000000000000000..00d07b119e6182b06cac0e853b9c523abcb23579 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/xiexiuqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/yangxiaohe.png b/web-ui/docs/.vuepress/public/img/live/yangxiaohe.png new file mode 100644 index 0000000000000000000000000000000000000000..5916847dfe03925e09c4340a8e20a0682db2ed57 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/yangxiaohe.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhanghailiang.png b/web-ui/docs/.vuepress/public/img/live/zhanghailiang.png new file mode 100644 index 0000000000000000000000000000000000000000..a611c757742e6b65e80a4950d31d9bd69fb5aa7d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhanghailiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhangliang.png b/web-ui/docs/.vuepress/public/img/live/zhangliang.png new file mode 100644 index 0000000000000000000000000000000000000000..298274957d42575ba98e22f9043ade9e75c5f364 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhangliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhangsong.png b/web-ui/docs/.vuepress/public/img/live/zhangsong.png new file mode 100644 index 0000000000000000000000000000000000000000..a6b21b7e299564f30c077605b46f8620814a28b9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhangsong.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhangtianxing.png b/web-ui/docs/.vuepress/public/img/live/zhangtianxing.png new file mode 100644 index 0000000000000000000000000000000000000000..4cec431844e817c8a5fd5c6100d31b1d2e89d820 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhangtianxing.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhuchunyi.png b/web-ui/docs/.vuepress/public/img/live/zhuchunyi.png new file mode 100644 index 0000000000000000000000000000000000000000..3e18192673754393d44dc10535d7181f5a28208d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhuchunyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhuhuankai.png b/web-ui/docs/.vuepress/public/img/live/zhuhuankai.png new file mode 100644 index 0000000000000000000000000000000000000000..53ebd3100eb4359b24388e2aa580ecabdc616f20 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhuhuankai.png differ diff --git a/web-ui/docs/.vuepress/public/img/live/zhuyanpeng.png b/web-ui/docs/.vuepress/public/img/live/zhuyanpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..7666db817aa7daad815ae2b13e97d7a7a0e31449 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/live/zhuyanpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/1.png b/web-ui/docs/.vuepress/public/img/meetups/1.png new file mode 100644 index 0000000000000000000000000000000000000000..325a3eef0c4e7e952fabbe163a97e4a59ac763bb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/1.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/2.png b/web-ui/docs/.vuepress/public/img/meetups/2.png new file mode 100644 index 0000000000000000000000000000000000000000..e46dbe626499242d5cd22fb5548b4278be61f212 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/2.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/3.png b/web-ui/docs/.vuepress/public/img/meetups/3.png new file mode 100644 index 0000000000000000000000000000000000000000..3e5b51037e3754eae42e61493f94e7d1230b57f0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/3.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/4.png b/web-ui/docs/.vuepress/public/img/meetups/4.png new file mode 100644 index 0000000000000000000000000000000000000000..cd74993819da13682460c2cdce2d5ac8f9146003 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/4.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/5.png b/web-ui/docs/.vuepress/public/img/meetups/5.png new file mode 100644 index 0000000000000000000000000000000000000000..c766d27ec59b4e6da6476f8765edda714bbd9808 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/5.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/6.png b/web-ui/docs/.vuepress/public/img/meetups/6.png new file mode 100644 index 0000000000000000000000000000000000000000..2a6cfe3776deb30b2aa2c9876e9407a6886075cb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/6.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/7.png b/web-ui/docs/.vuepress/public/img/meetups/7.png new file mode 100644 index 0000000000000000000000000000000000000000..a289ab8842a69b6db68aea6640189618d4972830 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/7.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/8.png b/web-ui/docs/.vuepress/public/img/meetups/8.png new file mode 100644 index 0000000000000000000000000000000000000000..0061702c882a1f7de3bcd0ac48c1686587f13902 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/8.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/9.png b/web-ui/docs/.vuepress/public/img/meetups/9.png new file mode 100644 index 0000000000000000000000000000000000000000..01e23c722f867996ccf50641aad031fea7d87f15 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/9.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address1.png b/web-ui/docs/.vuepress/public/img/meetups/address1.png new file mode 100644 index 0000000000000000000000000000000000000000..5443484114ab095a98689004c9566d670b475f73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address1.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address2.png b/web-ui/docs/.vuepress/public/img/meetups/address2.png new file mode 100644 index 0000000000000000000000000000000000000000..97e6d111b62aa52114dd9e5cac17c63f3aefc38f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address2.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address3.png b/web-ui/docs/.vuepress/public/img/meetups/address3.png new file mode 100644 index 0000000000000000000000000000000000000000..a52f9851e687e830ff62abb964b9eb8dabe9d074 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address3.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address4.png b/web-ui/docs/.vuepress/public/img/meetups/address4.png new file mode 100644 index 0000000000000000000000000000000000000000..1e42ed5708e78052bb09f99c3224199b842bea73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address4.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address5.png b/web-ui/docs/.vuepress/public/img/meetups/address5.png new file mode 100644 index 0000000000000000000000000000000000000000..3a7c898b08920c75755e4d35341861d97dd2bc90 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address5.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/address6.png b/web-ui/docs/.vuepress/public/img/meetups/address6.png new file mode 100644 index 0000000000000000000000000000000000000000..6035d3ceab00a2770d07479d1ab3e3292fbb4be4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/address6.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/default-address.png b/web-ui/docs/.vuepress/public/img/meetups/default-address.png new file mode 100644 index 0000000000000000000000000000000000000000..0154fffa35a21154516f853fb6b2e9e3091f9c24 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/default-address.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/link.png b/web-ui/docs/.vuepress/public/img/meetups/link.png new file mode 100644 index 0000000000000000000000000000000000000000..49318a1d964b3cc84ede2a06f4c9a27462a408f3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/link.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/location.png b/web-ui/docs/.vuepress/public/img/meetups/location.png new file mode 100644 index 0000000000000000000000000000000000000000..80e3159662316d757b6176eef46d2b3c7e98588d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/location.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/map1.png b/web-ui/docs/.vuepress/public/img/meetups/map1.png new file mode 100644 index 0000000000000000000000000000000000000000..16e61a7b54b72b8c9899e1b78f43771a75bcf7df Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/map1.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/map2.png b/web-ui/docs/.vuepress/public/img/meetups/map2.png new file mode 100644 index 0000000000000000000000000000000000000000..e1ff66cbbd6dd60a446a494b7c32273a3543c27f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/map2.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/map3.png b/web-ui/docs/.vuepress/public/img/meetups/map3.png new file mode 100644 index 0000000000000000000000000000000000000000..187482a8ab555502fa5edc3676b1c5f478588b84 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/map3.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/map5.png b/web-ui/docs/.vuepress/public/img/meetups/map5.png new file mode 100644 index 0000000000000000000000000000000000000000..5c21ab608513011d7732fc8372a0588a6182e4bc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/map5.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/map6.png b/web-ui/docs/.vuepress/public/img/meetups/map6.png new file mode 100644 index 0000000000000000000000000000000000000000..fe4cd6f2a8f65c7916f1e08de122d65774c56b50 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/map6.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/meetup-banner.png b/web-ui/docs/.vuepress/public/img/meetups/meetup-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..0a874038591faa2c07d60f4a4c6a6269c501a68b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/meetup-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode1.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode1.png new file mode 100644 index 0000000000000000000000000000000000000000..fd6043fe366b876b7718c626b1ac34a5d570c1be Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode1.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode2.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode2.png new file mode 100644 index 0000000000000000000000000000000000000000..40d4f4997be56547392b479c3abd033547ca118f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode2.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode3.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode3.png new file mode 100644 index 0000000000000000000000000000000000000000..1813b1ff682ba14b3481eebd3a3ca11ea4b26b95 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode3.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode4.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode4.png new file mode 100644 index 0000000000000000000000000000000000000000..18b06cc134778f1ec6900bf64926ae06942c2fe8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode4.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode5.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode5.png new file mode 100644 index 0000000000000000000000000000000000000000..8341cec1378f241b954fce8f1816ca2fa9d74a79 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode5.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode6.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode6.png new file mode 100644 index 0000000000000000000000000000000000000000..fe413f984eb9af68670641936f481613d68e572f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode6.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode7.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode7.png new file mode 100644 index 0000000000000000000000000000000000000000..6b8af14f655393b8afdfea0f799c23434e58b144 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode7.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode8.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode8.png new file mode 100644 index 0000000000000000000000000000000000000000..c9f4ec8e691b44768874cb2ddd1977dc3e0721c3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode8.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/qrcode9.png b/web-ui/docs/.vuepress/public/img/meetups/qrcode9.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5c10f9d9d18be68f35391d689dc58e119c5867 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/qrcode9.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/review-bg.png b/web-ui/docs/.vuepress/public/img/meetups/review-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa64ef5ee4a98888cdf6c7a40ff4a087eca620c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/review-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/review1.png b/web-ui/docs/.vuepress/public/img/meetups/review1.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b59269e185e113e041f99329fafb365d4e35c5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/review1.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/review2.png b/web-ui/docs/.vuepress/public/img/meetups/review2.png new file mode 100644 index 0000000000000000000000000000000000000000..aea5ad9ac2c8c7457a1ec2fb37b87babf0625f7b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/review2.png differ diff --git a/web-ui/docs/.vuepress/public/img/meetups/review3.png b/web-ui/docs/.vuepress/public/img/meetups/review3.png new file mode 100644 index 0000000000000000000000000000000000000000..11a31953b1376aa8bf1d091c26881f708eea59df Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/meetups/review3.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/desc-bg.png b/web-ui/docs/.vuepress/public/img/minisite/atune/desc-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..27e5b6ad1a59def97739f3489e96a369d3a7cea7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/desc-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/desc-mobile.png b/web-ui/docs/.vuepress/public/img/minisite/atune/desc-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..a4facea8c152b35aaa4b9e990de31be89af8314d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/desc-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/en-speak.png b/web-ui/docs/.vuepress/public/img/minisite/atune/en-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..16ac0a0a6d3404297b97563bfce6f68b3a6646ac Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/en-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/en-start.png b/web-ui/docs/.vuepress/public/img/minisite/atune/en-start.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9c8ef1a00634f06700427bd77e8c6f04b8e8b1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/en-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/framework.png b/web-ui/docs/.vuepress/public/img/minisite/atune/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..0024cd66ea392de51c8920a7efe9aada15b18ca2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/framework.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/framework_en.png b/web-ui/docs/.vuepress/public/img/minisite/atune/framework_en.png new file mode 100644 index 0000000000000000000000000000000000000000..6b0e6b67e8059b22ccd681ea67c9e64719f74092 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/framework_en.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/framework_ru.png b/web-ui/docs/.vuepress/public/img/minisite/atune/framework_ru.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b5a651a694508f0a912786eb73e5daebad0920 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/framework_ru.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/install.png b/web-ui/docs/.vuepress/public/img/minisite/atune/install.png new file mode 100644 index 0000000000000000000000000000000000000000..594ce5897407a0499e2e7ec66514a2b1cb820fe1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/install.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/know.png b/web-ui/docs/.vuepress/public/img/minisite/atune/know.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8c1ada8c099c1da772670f1ac4fcdaf7c73522 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/know.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/mobile-banner.png b/web-ui/docs/.vuepress/public/img/minisite/atune/mobile-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..fc38b71d3f2ff3fe06525b1b2c15b8a1ae53205d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/mobile-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/problem.png b/web-ui/docs/.vuepress/public/img/minisite/atune/problem.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd6ccb07b27887c1b9283e794e240761ae8dec5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/problem.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/ru-speak.png b/web-ui/docs/.vuepress/public/img/minisite/atune/ru-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..fc29a488577aad129275b4e1ae69f19167740017 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/ru-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/ru-start.png b/web-ui/docs/.vuepress/public/img/minisite/atune/ru-start.png new file mode 100644 index 0000000000000000000000000000000000000000..0f81960e0d99a7ab1095b7d442de0f9467b78236 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/ru-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/use.png b/web-ui/docs/.vuepress/public/img/minisite/atune/use.png new file mode 100644 index 0000000000000000000000000000000000000000..50a70940dbb1ec8204f5aef8f54a5837e3fedc3a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/use.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/zh-join.png b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-join.png new file mode 100644 index 0000000000000000000000000000000000000000..b2f6c9a139187986295434dfe391b670549fcf00 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-join.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/zh-speak.png b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..82826f656a811b3d0fbc90fa5ce7131b81b0a782 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/atune/zh-start.png b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-start.png new file mode 100644 index 0000000000000000000000000000000000000000..175482e9d966ed8ed999b953777e4186d71f84be Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/atune/zh-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/TCK-affidavit.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/TCK-affidavit.png new file mode 100644 index 0000000000000000000000000000000000000000..eaa45f065feaa03572ba152133a4bff0d3016f73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/TCK-affidavit.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/banner.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..186f70d49b7a5bd864cbabe4bffe2f71d6e1d15f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/framework.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..1af9a1cc1a88ee21e537f354efa9f87559fc8ba4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/framework.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/jiagoutu.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/jiagoutu.png new file mode 100644 index 0000000000000000000000000000000000000000..14e9863c0b5ecf51289180e05f428c1a14b50202 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/jiagoutu.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/meeting.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/meeting.png new file mode 100644 index 0000000000000000000000000000000000000000..c94fe941a5f738b4a71db63f21e87669210c0c46 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/meeting.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/roadmap.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/roadmap.png new file mode 100644 index 0000000000000000000000000000000000000000..9f2f3e53268a16c0a8c1dd31f16868accf663a1c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/roadmap.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-speker.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-speker.png new file mode 100644 index 0000000000000000000000000000000000000000..8284eeb1d9aa3bc5d4023c336a4cd78bb3b60045 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-speker.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-sponsor.png b/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-sponsor.png new file mode 100644 index 0000000000000000000000000000000000000000..798228a4cf575ed2b9657fae21955a00d9ead175 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/bisheng/zh-sponsor.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/compile.png b/web-ui/docs/.vuepress/public/img/minisite/isula/compile.png new file mode 100644 index 0000000000000000000000000000000000000000..47a8a9bc3619eee58115b0fa9707b0e03adcc8e1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/compile.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/desc.png b/web-ui/docs/.vuepress/public/img/minisite/isula/desc.png new file mode 100644 index 0000000000000000000000000000000000000000..e1da77c8d37f3ba7c49ddb78d7bfbe243398d6a2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/desc.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/en-speak.png b/web-ui/docs/.vuepress/public/img/minisite/isula/en-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..16ac0a0a6d3404297b97563bfce6f68b3a6646ac Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/en-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/en-start.png b/web-ui/docs/.vuepress/public/img/minisite/isula/en-start.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9c8ef1a00634f06700427bd77e8c6f04b8e8b1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/en-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/en_desc.png b/web-ui/docs/.vuepress/public/img/minisite/isula/en_desc.png new file mode 100644 index 0000000000000000000000000000000000000000..1e7f722029fab7769c14501873b2e65a8f349aaa Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/en_desc.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-en.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-en.png new file mode 100644 index 0000000000000000000000000000000000000000..c2625f531a582e32ba724fbc34845a793ed6dcc3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-ru.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..daf0c5fbf31079437a721a10a4907e9cf1590e67 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1-ru.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1.png new file mode 100644 index 0000000000000000000000000000000000000000..fd557e14e974b43c281c282b5e7666da97d1c81c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-1.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2-ru.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..767dc46ade0b69aa91f2f76bac280cab06c3d366 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2-ru.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2.png new file mode 100644 index 0000000000000000000000000000000000000000..edc25149a8d9889602a20cd1b1c2f96c0251d77e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-2.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3-ru.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..174cccac3039c599ade486bf6649fc1f030356a4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3-ru.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3.png new file mode 100644 index 0000000000000000000000000000000000000000..b29394c6c3436f6ec42ae9abae7e39891f63d20b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-3.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/isula-logo.png b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f4883b2f1f69bb6ca4d52d035e3f431e584d2b62 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/isula-logo.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/mobile-banner.png b/web-ui/docs/.vuepress/public/img/minisite/isula/mobile-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..0389b6a3c5c36f7e65861becaab9caf319f53b58 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/mobile-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/pc-desc-bg.png b/web-ui/docs/.vuepress/public/img/minisite/isula/pc-desc-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..51beda5bfc551c14b0613de3b655feaf327df981 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/pc-desc-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/readme.png b/web-ui/docs/.vuepress/public/img/minisite/isula/readme.png new file mode 100644 index 0000000000000000000000000000000000000000..08777e7261ca867646e3f86e9468d6ea59e72d9c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/readme.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/ru-desc.png b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1cd1912b785e895eb103844a1d263f931d2e8f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-desc.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/ru-speak.png b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..fc29a488577aad129275b4e1ae69f19167740017 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/ru-start.png b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-start.png new file mode 100644 index 0000000000000000000000000000000000000000..0f81960e0d99a7ab1095b7d442de0f9467b78236 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/ru-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/use.png b/web-ui/docs/.vuepress/public/img/minisite/isula/use.png new file mode 100644 index 0000000000000000000000000000000000000000..d8320c5dae3e6b68d62f26139a5a274665b91834 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/use.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/zh-desc.png b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..3074cab45936c2b93014ed6f0253d5b86e8c9883 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-desc.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/zh-speak.png b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..cb37986f680ea8e4d6dd79f0aa66b2403f807ff1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/isula/zh-start.png b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-start.png new file mode 100644 index 0000000000000000000000000000000000000000..4a44dde7a9dcdeb6a73af947cb4c19e567234865 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/isula/zh-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/migration/frame.svg b/web-ui/docs/.vuepress/public/img/minisite/migration/frame.svg new file mode 100644 index 0000000000000000000000000000000000000000..f6062a1728270fd36db8c91531aa8f5e8ba1cac7 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/minisite/migration/frame.svg @@ -0,0 +1,221 @@ + + + openEuler架构-web + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/minisite/migration/framework.png b/web-ui/docs/.vuepress/public/img/minisite/migration/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..c5246d15a2abc7d165c015e0fed550b212150ffc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/migration/framework.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/migration/move.png b/web-ui/docs/.vuepress/public/img/minisite/migration/move.png new file mode 100644 index 0000000000000000000000000000000000000000..5230ec8e3daf29eda2d8e5c287e0988b89d92bff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/migration/move.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/migration/source-download.jpg b/web-ui/docs/.vuepress/public/img/minisite/migration/source-download.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e516bb81589df865c40497a551049d9a2a1bf2e0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/migration/source-download.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/scheme/process.png b/web-ui/docs/.vuepress/public/img/minisite/scheme/process.png new file mode 100644 index 0000000000000000000000000000000000000000..f609eda456766eeb572d1e66ffbb5dc8cd5065ed Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/scheme/process.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/scheme/scheme.png b/web-ui/docs/.vuepress/public/img/minisite/scheme/scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..055e1288d4cc528bb165a00b718f5ef8b77fab91 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/scheme/scheme.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/scheme/tuning.png b/web-ui/docs/.vuepress/public/img/minisite/scheme/tuning.png new file mode 100644 index 0000000000000000000000000000000000000000..28ae2639f0a3ebe6abd964a25d4550fa15528f62 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/scheme/tuning.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/secgear/banner.png b/web-ui/docs/.vuepress/public/img/minisite/secgear/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1a5a7454d54bc192cd68e3b01c3a1584a5b1f1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/secgear/banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/secgear/framework.png b/web-ui/docs/.vuepress/public/img/minisite/secgear/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..b608de4c47422e5d0153fb354d4f94902f4e91aa Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/secgear/framework.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-box.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-box.png new file mode 100644 index 0000000000000000000000000000000000000000..98a78d24428fe04b4103eafa42a1b9c592722266 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-box.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-install.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-install.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc358ac5e03874cb8fe3d03f77cf7135a20900 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-install.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-introduct.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-introduct.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fccf901dd9e8e248fbeaf9aab9df66058af009 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-introduct.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-ready.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-ready.png new file mode 100644 index 0000000000000000000000000000000000000000..05544be75d71cf6ff452a8ce5fb252fae9534c72 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-ready.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-source.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-source.png new file mode 100644 index 0000000000000000000000000000000000000000..6500ab304f64ed39b4e0949e2837cbbf734c0f9e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-source.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-virtual.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-virtual.png new file mode 100644 index 0000000000000000000000000000000000000000..1ca70d3809047cc73ff424102f53918721708e5d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/doc-virtual.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/en-join.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-join.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1d830151d39ffd2f13193fb96f60230c295b90 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-join.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/en-speak.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..16ac0a0a6d3404297b97563bfce6f68b3a6646ac Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/en-start.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-start.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9c8ef1a00634f06700427bd77e8c6f04b8e8b1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/en-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/extend.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/extend.png new file mode 100644 index 0000000000000000000000000000000000000000..59ba431096b2ba8433f8db40110011d91f59bbc6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/extend.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/flex.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/flex.png new file mode 100644 index 0000000000000000000000000000000000000000..e76e5930eb16eccc08296a5103b01c5f4d92fcab Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/flex.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/low-noise.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/low-noise.png new file mode 100644 index 0000000000000000000000000000000000000000..a52e3fe47a19f714dc4a6de6cb9bd1ac0cd100fb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/low-noise.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-banner.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8a494c1022b3a44b31d7aba77838bb3973956f93 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-svirt.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-svirt.png new file mode 100644 index 0000000000000000000000000000000000000000..3c11576742bbb17ea9b7ca99c88bebc807588d45 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/mobile-svirt.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork-ru.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..66dd9754a6104a0601292a3a9baf55d7db6f9e23 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork-ru.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork.png new file mode 100644 index 0000000000000000000000000000000000000000..0c8fc90cf98f10598f381e7d2c75f82d80001921 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-fwork.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-svirt.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-svirt.png new file mode 100644 index 0000000000000000000000000000000000000000..f7883f2b0eda92a1d5b421679496bd6bfa9e691f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/pc-svirt.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-join.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-join.png new file mode 100644 index 0000000000000000000000000000000000000000..b7143c856d20c5e425972e82e40cfd3f511009ef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-join.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-speak.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..fc29a488577aad129275b4e1ae69f19167740017 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-start.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-start.png new file mode 100644 index 0000000000000000000000000000000000000000..0f81960e0d99a7ab1095b7d442de0f9467b78236 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/ru-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/safety.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/safety.png new file mode 100644 index 0000000000000000000000000000000000000000..8dde82d323f7c549936f79033a4c78b6df1bebd4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/safety.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/strengthen.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/strengthen.png new file mode 100644 index 0000000000000000000000000000000000000000..aa75b442990d878976a8939a7e1aa048fb12866d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/strengthen.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/svirt-bg.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/svirt-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..0d57287514fbb2f2ac0394354d950b07469c5a7f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/svirt-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/with.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/with.png new file mode 100644 index 0000000000000000000000000000000000000000..a3cabfb0d4045cf0d414b4bc522800bfba23ecc7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/with.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-join.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-join.png new file mode 100644 index 0000000000000000000000000000000000000000..60a57121aae1f9732b732d5c9cc6a0619df36018 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-join.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-speak.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-speak.png new file mode 100644 index 0000000000000000000000000000000000000000..42193c0a1d9ad4cbb715ce00d3febdb64a07e2b7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-speak.png differ diff --git a/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-start.png b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-start.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb5adf0664996ff1bcda1352fb4915971a2767e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/minisite/svirt/zh-start.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_01.png b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_01.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc0abfa89c6f8fd6b0f77e20d994c01d06c308d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_01.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_02.png b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_02.png new file mode 100644 index 0000000000000000000000000000000000000000..ac988c047436f92e6427a1727c1486e2ceeb24ff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_02.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_03.png b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_03.png new file mode 100644 index 0000000000000000000000000000000000000000..e579b6f23bbf41efdf39a73a329625416cea1d98 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_03.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_04.png b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_04.png new file mode 100644 index 0000000000000000000000000000000000000000..e579b6f23bbf41efdf39a73a329625416cea1d98 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_04.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_05.png b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_05.png new file mode 100644 index 0000000000000000000000000000000000000000..d6b8b9701a816a7b12a72eeba3de2f482accdac3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20190829ai/20190829_ai_summit_05.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/20191001/history.jpeg b/web-ui/docs/.vuepress/public/img/news/20191001/history.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f169a72befdf8787b47c32e29f7b160628bed016 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20191001/history.jpeg differ diff --git a/web-ui/docs/.vuepress/public/img/news/20201225/poster.png b/web-ui/docs/.vuepress/public/img/news/20201225/poster.png new file mode 100644 index 0000000000000000000000000000000000000000..647a8eacfd4e56df12cd6fc6a2e605918b56ceae Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/20201225/poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/news-banner.png b/web-ui/docs/.vuepress/public/img/news/news-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..87f634eb7e6f80cbfdd119d980b78635909d65f0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/news-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing.png b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing.png new file mode 100644 index 0000000000000000000000000000000000000000..e5ed43ed41b5202166248293bcbeb5d4385061ee Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_01.png b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_01.png new file mode 100644 index 0000000000000000000000000000000000000000..b68a7bc19037c20abf1c2158e3c6a3d6598ef95c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_01.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_02.png b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_02.png new file mode 100644 index 0000000000000000000000000000000000000000..fd4a16b77b71703b90c68f956e7b6a3116b8a7a5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_02.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_03.png b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_03.png new file mode 100644 index 0000000000000000000000000000000000000000..65d0388fa421ebb7b42097510594407cf2655c98 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_03.png differ diff --git a/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_banner.png b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..50a16244555bbcdb2c277293dd273cf3e1981d21 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/news/summit20190723/summit_20190723_beijing_banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/Style.png b/web-ui/docs/.vuepress/public/img/other/brand/Style.png new file mode 100644 index 0000000000000000000000000000000000000000..d24c88882af2800b75e5b16f577238afce3c3c77 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/Style.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/black-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/black-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..0523e13fd34e3ed773ffe346cef85da14bfa5d55 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/black-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/block-hor-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/block-hor-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..893a2ac51b25a1047d63e4b2d3bebd35b7a32d5d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/block-hor-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/brand-banner.png b/web-ui/docs/.vuepress/public/img/other/brand/brand-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..aa1913645c5e4329cd9bf9be3ac70d4aca3ac97e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/brand-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/en-ppt1.png b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt1.png new file mode 100644 index 0000000000000000000000000000000000000000..1008d1af149ff5ac40e793707a4c784f5cf36e9e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt1.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/en-ppt2.png b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt2.png new file mode 100644 index 0000000000000000000000000000000000000000..42dbc026018bc72841919a85490245438449be0d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt2.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/en-ppt3.png b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt3.png new file mode 100644 index 0000000000000000000000000000000000000000..7a252ff5d6bd68d9cdabc32f6d4d64a897b051c4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt3.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/en-ppt4.png b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt4.png new file mode 100644 index 0000000000000000000000000000000000000000..ce8e9a8ec56eba35d6dee6ab89f1b890bb9b2b73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/en-ppt4.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/euler-ppt.png b/web-ui/docs/.vuepress/public/img/other/brand/euler-ppt.png new file mode 100644 index 0000000000000000000000000000000000000000..defc1a30263e03353f91235cfa3e97d5c5681cc1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/euler-ppt.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/euler-white-ppt.png b/web-ui/docs/.vuepress/public/img/other/brand/euler-white-ppt.png new file mode 100644 index 0000000000000000000000000000000000000000..8cc3f5e495606996fdf92e2343801df884d1372a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/euler-white-ppt.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.jpg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c638dc5fd62b9884fc4ebe0e534280e2624433a8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.png b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.png new file mode 100644 index 0000000000000000000000000000000000000000..a64f3630aa562d0ceef4748d0d90efed706fe9b2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.svg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.svg new file mode 100644 index 0000000000000000000000000000000000000000..995021ed54ccef75da50509d1a6d6c9e11cb13ec --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-center.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.jpg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d685a9897208f5d5194f50ebe2221c3a4c032d28 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.png b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.png new file mode 100644 index 0000000000000000000000000000000000000000..eb7b8af86025b8f27fa3b2539300b24a0487895f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.svg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..7aa9e64ed8948230f5ffa531ab6ca84422cf149d --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..19bada61f802d65702c4c1f40ed8b0cb903f216f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.jpg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..132470219423c56980a371201000b786afff1cac Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.png b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.png new file mode 100644 index 0000000000000000000000000000000000000000..77b0823de43f05a89b776d61ff42395ff30f7bb2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.svg b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..c0ad9e49e2330ef6bc12ac6e30f6cbe4c6084433 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/horizontal-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/mono-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/mono-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..dc20d7d2f8b0768db09e81ff49292bea472d26ef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/mono-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/standard-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/standard-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..213d648acd3d1b661d01fadd5e5130bbd37b3a95 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/standard-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.jpg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45dbe0f3348b6bfc80b097f74c3670aabe2ef090 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.png b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.png new file mode 100644 index 0000000000000000000000000000000000000000..4388da91d7a677d47db37aa4a036f33239403a36 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.svg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.svg new file mode 100644 index 0000000000000000000000000000000000000000..92f0b3e2772d92b3400ae02f39845559758ee6e0 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/vertical-center.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.jpg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7df796b140d50faa19f7bcfe1877e53c45c818a2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.png b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.png new file mode 100644 index 0000000000000000000000000000000000000000..6dbfd7c9e0d1ebe0b1eb6c811f978dcac1c593d6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.svg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..9719690c2d1ae278e6a6b8b7ddf70a3821713932 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/vertical-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.jpg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df8363b9dfcc81447fdab5f796430ee4f6680ce4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.png b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.png new file mode 100644 index 0000000000000000000000000000000000000000..7419e0d3ef448f05415cd664b3dea662208c7cdd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.svg b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..a4f626efd214ced3e0bfe3f899dddea10c641d86 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/brand/vertical-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/brand/white-poster.png b/web-ui/docs/.vuepress/public/img/other/brand/white-poster.png new file mode 100644 index 0000000000000000000000000000000000000000..26fec0340aa27494ff61b0b1aa0ec50be268aea8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/white-poster.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt1.png b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt1.png new file mode 100644 index 0000000000000000000000000000000000000000..abd661de5f2760f127b56e1705e6448c00be63b4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt1.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt2.png b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt2.png new file mode 100644 index 0000000000000000000000000000000000000000..f13eb41b35f45e4eb5f6f50ff546f62350840f72 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt2.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt3.png b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt3.png new file mode 100644 index 0000000000000000000000000000000000000000..1105f441318eb5991109819b2d1bc7e54670d1ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt3.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt4.png b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt4.png new file mode 100644 index 0000000000000000000000000000000000000000..ff022fb1a5e50a2dd9a591d67764ad1fe1de1250 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/brand/zh-ppt4.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/close.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/close.png new file mode 100644 index 0000000000000000000000000000000000000000..532f796a51b113865fd7b85c1ffdf012006c19cc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/close.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent.png new file mode 100644 index 0000000000000000000000000000000000000000..c07a84de459c5e3477fd1c40ee3b444f68504fd5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..3b26b59cacf32f7f913e04b27449f59e628cb865 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/excellent_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/first.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/first.png new file mode 100644 index 0000000000000000000000000000000000000000..9e3850b222b1d5de21e3a567212b853e4bc5625e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/first.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/first_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/first_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..191d4f810db0676d9ff5ee1351c1d7b36b3c042c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/first_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/grand.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/grand.png new file mode 100644 index 0000000000000000000000000000000000000000..d8643e40f82fde6b59db40be45c73e699563b9f8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/grand.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/grand_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/grand_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..17927844b89984c9d22ad2cbd168fdafde51f484 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/grand_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/qrcode.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..abbe310dde4f275d8ee012e8d6fa630ed2646e77 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/qrcode.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..30d3d17e62c8a8925e6306febd047842319c18b4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0287a2dd58f9fae6119e9d55f6572be7fef992 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire-banner_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire.png new file mode 100644 index 0000000000000000000000000000000000000000..a0210d2557df95137e482c42103e9c56726a5e1f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..d8d86a4173d70f10faa6847525c16ac2a512b32b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/questionnaire_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/second.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/second.png new file mode 100644 index 0000000000000000000000000000000000000000..8288c64160d5f677afb6e26bcd320faf0e54b220 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/second.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/second_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/second_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..03506274dcc329fc51217eb475aca4877ea4ed5b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/second_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/third.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/third.png new file mode 100644 index 0000000000000000000000000000000000000000..19255e804f3a74f6fa1c9e14f6d715a02899153f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/third.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/questionnaire/third_mo.png b/web-ui/docs/.vuepress/public/img/other/questionnaire/third_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..dc3cd80dff7e58b4619a314c20b494e86dbe3505 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/questionnaire/third_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/other/search/search-icon.svg b/web-ui/docs/.vuepress/public/img/other/search/search-icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..b762ccf871c7bd9057eda589bf4c037c43637503 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/other/search/search-icon.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/other/search/search.png b/web-ui/docs/.vuepress/public/img/other/search/search.png new file mode 100644 index 0000000000000000000000000000000000000000..7c75d566e52257f3e9ca9ddc252bc39e76dc449a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/other/search/search.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/contributer.png b/web-ui/docs/.vuepress/public/img/round/contributer.png new file mode 100644 index 0000000000000000000000000000000000000000..3abf6da4d7f20f53d793d02dc738c6555646a1b5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/contributer.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/man-time.png b/web-ui/docs/.vuepress/public/img/round/man-time.png new file mode 100644 index 0000000000000000000000000000000000000000..13e948c7ad40ecd097e8c2bd0437239a9bcbf0e0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/man-time.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/osv.png b/web-ui/docs/.vuepress/public/img/round/osv.png new file mode 100644 index 0000000000000000000000000000000000000000..34eee067fd3ba7c3dfebc11a9ca6af323a23b6ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/osv.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/sig.png b/web-ui/docs/.vuepress/public/img/round/sig.png new file mode 100644 index 0000000000000000000000000000000000000000..169f2636bda10b6543073f83880ce8e8e5801a2f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/software.png b/web-ui/docs/.vuepress/public/img/round/software.png new file mode 100644 index 0000000000000000000000000000000000000000..49450f41205235f519133c84339c942254581877 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/software.png differ diff --git a/web-ui/docs/.vuepress/public/img/round/user.png b/web-ui/docs/.vuepress/public/img/round/user.png new file mode 100644 index 0000000000000000000000000000000000000000..4e1276708b38008c6d82e7057acb694d67632e53 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/round/user.png differ diff --git a/web-ui/docs/.vuepress/public/img/security/cve-banner.png b/web-ui/docs/.vuepress/public/img/security/cve-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..88df3bb812d3decf9723fecfbdcf53dc54564b04 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/security/cve-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/security/legal-banner.png b/web-ui/docs/.vuepress/public/img/security/legal-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..273643b97e3c6b48d6877683ca4846899532ac8b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/security/legal-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/security/notice-banner.png b/web-ui/docs/.vuepress/public/img/security/notice-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..4e755ff3408c1d855663b38442f78e473d178557 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/security/notice-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/security/privacy-banner.png b/web-ui/docs/.vuepress/public/img/security/privacy-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8884f3a45223f04046babfa9bfd6b7d669cd83a5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/security/privacy-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/security/report-banner.png b/web-ui/docs/.vuepress/public/img/security/report-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..27f2b1180c86c93d9d36feaf66074b0479f77dbd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/security/report-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/chanel.svg b/web-ui/docs/.vuepress/public/img/sig/chanel.svg new file mode 100644 index 0000000000000000000000000000000000000000..6b4c306cebeb4a4d41b736d2ac1876ca5dfef0fa --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/sig/chanel.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/sig/home.svg b/web-ui/docs/.vuepress/public/img/sig/home.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3be8b9af8f4fd5806c973a1a2106a570343028e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/sig/home.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/sig/homePageLogo.png b/web-ui/docs/.vuepress/public/img/sig/homePageLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..bf6e8fd1a3b881ea37459714085f6e0ed6fa58b2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/homePageLogo.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/mail.svg b/web-ui/docs/.vuepress/public/img/sig/mail.svg new file mode 100644 index 0000000000000000000000000000000000000000..43b8b8c59998937c48afb31623f2cb806dd91bb3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/sig/mail.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/sig/meeting-guide-mo.png b/web-ui/docs/.vuepress/public/img/sig/meeting-guide-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..b04df051af6e822a9069e005ea06e82b522bae83 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/meeting-guide-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/meeting-guide-pc.png b/web-ui/docs/.vuepress/public/img/sig/meeting-guide-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..6d93b6d0bc828cc9c71fac62d772fac3cd4e76c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/meeting-guide-pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/members.svg b/web-ui/docs/.vuepress/public/img/sig/members.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3a52713c8c93a38d5ea5cb71bd395f1e5e8f8c5 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/sig/members.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/sig/role-desc.png b/web-ui/docs/.vuepress/public/img/sig/role-desc.png new file mode 100644 index 0000000000000000000000000000000000000000..f811de65dce320a72ec242a0c5f09aef40b07047 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/role-desc.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/roledescription-banner.png b/web-ui/docs/.vuepress/public/img/sig/roledescription-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..4510943f4cf2346a8bfdd1bc80885f88a79508e4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/roledescription-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig-banner.png b/web-ui/docs/.vuepress/public/img/sig/sig-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..f0910ef4689e73ff1689431af5857021c4e6dc02 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig-guide-banner.png b/web-ui/docs/.vuepress/public/img/sig/sig-guide-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..56791881f375ac12221c98ba405a5f2a43c7b30a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig-guide-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig1.png b/web-ui/docs/.vuepress/public/img/sig/sig1.png new file mode 100644 index 0000000000000000000000000000000000000000..4478789d12d9402e1dd381d21bda3e05c4ed3dff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig1.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig2.png b/web-ui/docs/.vuepress/public/img/sig/sig2.png new file mode 100644 index 0000000000000000000000000000000000000000..3d876cdccc1345b9042e09e42ffab0d4d47b0eb0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig2.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig3.png b/web-ui/docs/.vuepress/public/img/sig/sig3.png new file mode 100644 index 0000000000000000000000000000000000000000..030cbc75f1a4faebcc3cbaa5b36a12a590ad0676 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig3.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig4.png b/web-ui/docs/.vuepress/public/img/sig/sig4.png new file mode 100644 index 0000000000000000000000000000000000000000..76881039a7c5784b07332b9398d03bb9ab310554 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig4.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig5.png b/web-ui/docs/.vuepress/public/img/sig/sig5.png new file mode 100644 index 0000000000000000000000000000000000000000..f98dc6933d77f5a7fbd9168494a8ab431943c6c8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig5.png differ diff --git a/web-ui/docs/.vuepress/public/img/sig/sig6.png b/web-ui/docs/.vuepress/public/img/sig/sig6.png new file mode 100644 index 0000000000000000000000000000000000000000..6a8dc8201f2afe7f69b945c07f7e20d217830e91 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/sig/sig6.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/blue-player.svg b/web-ui/docs/.vuepress/public/img/summit/blue-player.svg new file mode 100644 index 0000000000000000000000000000000000000000..38883f34abe8c6becc9923b30b40989001ab509b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/blue-player.svg @@ -0,0 +1,9 @@ + + + 形状结合 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/camera.svg b/web-ui/docs/.vuepress/public/img/summit/camera.svg new file mode 100644 index 0000000000000000000000000000000000000000..40e624cb9402a56add2fec2103beaf87a0f861d7 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/camera.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-h5.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-h5.png new file mode 100644 index 0000000000000000000000000000000000000000..872ec9c72d174f986e9ca4bbd6cb8d4d17c66633 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-h5.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-web.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-web.png new file mode 100644 index 0000000000000000000000000000000000000000..7355fabcf812625f2732dc5c0c4ada78c32359ef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/agenda-web.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/h5_other_sig.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/h5_other_sig.png new file mode 100644 index 0000000000000000000000000000000000000000..898da09bee79414e0dcb1588753b0db8028f9a37 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/h5_other_sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/mo_agenda.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/mo_agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..c0b10736fc14783e3e92e78847e38b6c7b56bb86 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/mo_agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-h5.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-h5.png new file mode 100644 index 0000000000000000000000000000000000000000..d3411ac0621940ae8f7686cd491bb32260f1fc21 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-h5.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-web.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-web.png new file mode 100644 index 0000000000000000000000000000000000000000..b145352ef354d5b71b838310644a1e245ec92518 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/party-web.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_agenda.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..9fbad5172efbe8e4c4dd1326b2a05d00bb02329f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_other_sig.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_other_sig.png new file mode 100644 index 0000000000000000000000000000000000000000..6f93df39dbbec6eb667f5cadd6d12f7f06e7ac48 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/agenda/web_other_sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-en.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-en.png new file mode 100644 index 0000000000000000000000000000000000000000..7776091891dbbaa33c2d327c769414f34f66bd6d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-zh.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe1785969ffc7191ce650fe375cd46693f8d336 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/banner-h5-zh.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baode.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baode.png new file mode 100644 index 0000000000000000000000000000000000000000..5ac836f91fa3a0898f77cb4f873689922c690efd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baode.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baolande.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baolande.png new file mode 100644 index 0000000000000000000000000000000000000000..c276bc0be5196cfa5a6e0527a7ea121c52a98970 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/baolande.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/huasheng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/huasheng.png new file mode 100644 index 0000000000000000000000000000000000000000..4cc3b59528e2c88a4b6524facdd6e6bcb86e1504 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/huasheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/liantong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/liantong.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2f12efc560573461abfbe4f00b19dee076d3a9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/liantong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/lvmengkeji.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/lvmengkeji.png new file mode 100644 index 0000000000000000000000000000000000000000..b79aea5d5e959a6ac407623ffab058cb81b995f1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/lvmengkeji.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/pingao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/pingao.png new file mode 100644 index 0000000000000000000000000000000000000000..953a8fb8af1c32d223491566f435fa0245b1c09b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/pingao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qianxin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qianxin.png new file mode 100644 index 0000000000000000000000000000000000000000..929725e7a180b5ec72d59b5ec5937557fb1a6d8b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qianxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qihu360.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qihu360.png new file mode 100644 index 0000000000000000000000000000000000000000..de198c242138d23a415be9da3d4cb47681aef7bf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/qihu360.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/wuxi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/wuxi.png new file mode 100644 index 0000000000000000000000000000000000000000..39de615e570f83f45c20972ef941ee48e197f0a0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/wuxi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/xinlaikeji.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/xinlaikeji.png new file mode 100644 index 0000000000000000000000000000000000000000..37f61d0951c53d882480f5e86aa7cbba32c12cf2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/xinlaikeji.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/youxikeji.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/youxikeji.png new file mode 100644 index 0000000000000000000000000000000000000000..8d750b997d78e458d20252fa2e4ad6ab8ab20af1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/youxikeji.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/zhaoxin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/zhaoxin.png new file mode 100644 index 0000000000000000000000000000000000000000..551f23b749db98ed8c7dc0c1dbf1798b10bbaab9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/co-organizer/zhaoxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-mobile.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..681b09116edf6dc2fe5dc951096b61e5c24bfa4b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-web.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-web.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb01f9e1db0e72af3df69c04d8b17d369d5dde2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/community-web.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/dukaitian.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/dukaitian.png new file mode 100644 index 0000000000000000000000000000000000000000..fe05820f62f6dfa9ba16465aca30c1fc28c80d86 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/dukaitian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/gaowei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/gaowei.png new file mode 100644 index 0000000000000000000000000000000000000000..c979592b9365ff7f822e6794d991238bdd8915a5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/gaowei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/guohanjun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/guohanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..26ec58a8ce61ea4ea1ce0296ed8440bda27bfeba Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/guohanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/huxinwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/huxinwei.png new file mode 100644 index 0000000000000000000000000000000000000000..1713e222028306f05643195ba3bbc62a98e35511 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/huxinwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/jiangdayong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/jiangdayong.png new file mode 100644 index 0000000000000000000000000000000000000000..a3a4e24e4f01cc9080b329ebc8b874afe8b73ac2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/jiangdayong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liangbin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liangbin.png new file mode 100644 index 0000000000000000000000000000000000000000..5ee9a9a4aec3587144fbd5d7c8e65ca43e0821ef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liangbin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liujingang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liujingang.png new file mode 100644 index 0000000000000000000000000000000000000000..25ca82e2cb2a596c5da8d83a2d32a4c033ec0ad4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/liujingang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/maquanyi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/maquanyi.png new file mode 100644 index 0000000000000000000000000000000000000000..61c8f4430474e77874c15222cb410863976761a5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/maquanyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/qiuchengfeng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/qiuchengfeng.png new file mode 100644 index 0000000000000000000000000000000000000000..ea2ce69914205ab990f818db429cd869ffa1bee5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/qiuchengfeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/shiyong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/shiyong.png new file mode 100644 index 0000000000000000000000000000000000000000..87825d4181e339b4ecc43a61700ff8a69c1738e6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/shiyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/wufengguang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/wufengguang.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbbbce485ffd2f55b31198f5e59b8e9f58ba9b9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/wufengguang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiexiuqi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiexiuqi.png new file mode 100644 index 0000000000000000000000000000000000000000..683ffdfbffa8c770cc21716cc376d6993241908b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiexiuqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiongwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiongwei.png new file mode 100644 index 0000000000000000000000000000000000000000..f8cf07d3f7e9d15f326e39089a6dbb35ef2aa127 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/community/xiongwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-en.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-en.png new file mode 100644 index 0000000000000000000000000000000000000000..609c6a4cf715b7b242f13caccb1fda0da1d1e198 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-zh.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd5c077615604be567693059c58565097f1fe46 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/devday-2021-zh.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/h5-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/h5-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..a2628fb534f5d12a249c6f451de778bf96cf135c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/h5-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/baidu.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/baidu.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6a5d447f243c5092cc93ea56888cf117686025 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/baidu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-mobile.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..ff630432597ee2aacea69933742d90d58bca3b73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-web.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-web.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4da0fecf808559625b6bc3d622c7c923285441 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/host-unit-web.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/huawei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/huawei.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f05783f0340eca0360642e0db134dcd1738e38 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/host-unit/huawei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/infoq.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/infoq.png new file mode 100644 index 0000000000000000000000000000000000000000..7366fcf4463f02a4bbe219b2dd4b282c1506e529 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/infoq.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/caihaomin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/caihaomin.png new file mode 100644 index 0000000000000000000000000000000000000000..37769c4f9b29690b46a40388b4a12255337ad257 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/caihaomin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chehab.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chehab.png new file mode 100644 index 0000000000000000000000000000000000000000..0525860f373e8f3a90511426ac2930968522cf92 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chehab.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chentingyue.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chentingyue.png new file mode 100644 index 0000000000000000000000000000000000000000..34e73013af5e37d9a58ff4020c0221a5fbc8c7c7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/chentingyue.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/daihongjian.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/daihongjian.png new file mode 100644 index 0000000000000000000000000000000000000000..dc34dfec23ab5e4d69dc89449f3c576d8f1fe779 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/daihongjian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dijin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dijin.png new file mode 100644 index 0000000000000000000000000000000000000000..af3b682873a39343cdc239df7a33648de71ffad4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dijin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dongziqiang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dongziqiang.png new file mode 100644 index 0000000000000000000000000000000000000000..437fdd071074666f4aa139fb74367fa303d72510 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dongziqiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dudong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dudong.png new file mode 100644 index 0000000000000000000000000000000000000000..439a76bb0363398f24a61dca80572001a5e764ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/dudong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fangbingyi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fangbingyi.png new file mode 100644 index 0000000000000000000000000000000000000000..e7d64906a0d92aa102872668569418a2f16a90da Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fangbingyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fanghuaqi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fanghuaqi.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a60f8fa5a7d8afb69fddd99911321fe18da6e4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/fanghuaqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/feifei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/feifei.png new file mode 100644 index 0000000000000000000000000000000000000000..8206ac6ecccea8f329e39f502b6e74297009d0b4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/feifei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaochong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaochong.png new file mode 100644 index 0000000000000000000000000000000000000000..82677b78e2efec92d8ad4b06f3ef9c5bcd367f90 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaochong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaokun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaokun.png new file mode 100644 index 0000000000000000000000000000000000000000..93ed4b24fa8c210eb87ccffb0888ebc9ece17858 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/gaokun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huangyong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huangyong.png new file mode 100644 index 0000000000000000000000000000000000000000..948176a15e317a4de9f30f803c6f4b61f7ee09c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huangyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huotaiwen.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huotaiwen.png new file mode 100644 index 0000000000000000000000000000000000000000..70542c97b09d8c164e1ce4f726f8cb2239eba8ec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/huotaiwen.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/husong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/husong.png new file mode 100644 index 0000000000000000000000000000000000000000..1d50019c327a569d452cc1c8ea586ffb43e26027 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/husong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangguoqing.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangguoqing.png new file mode 100644 index 0000000000000000000000000000000000000000..b405717059bab9e1347b91afb0384343a7317512 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangguoqing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangqinghua.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangqinghua.png new file mode 100644 index 0000000000000000000000000000000000000000..7d47f215486011660da5603a73cbdc2545fa4c47 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/jiangqinghua.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lijiansheng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lijiansheng.png new file mode 100644 index 0000000000000000000000000000000000000000..a550b8ec12cb715ec92941f437cc613201068346 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lijiansheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/linjie.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/linjie.png new file mode 100644 index 0000000000000000000000000000000000000000..38ba66334e240736abef7b52d8aa3b5ce240d608 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/linjie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liujunwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liujunwei.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ac717ec2d6e19201d374eac63872bb9d620975 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liujunwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuwenzong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuwenzong.png new file mode 100644 index 0000000000000000000000000000000000000000..1f450b7679c5f847b83480f89a6416cf3ddd5b60 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuwenzong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuyongpeng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuyongpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..92acac8d60e1cd169c7d21cb50478eaacb5fb096 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liuyongpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liyong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liyong.png new file mode 100644 index 0000000000000000000000000000000000000000..b06a3d2db23fb10cba341610ccbc716b2374d139 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/liyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lizi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lizi.png new file mode 100644 index 0000000000000000000000000000000000000000..de380e6c551f817bdc73a5a997946e2c5f83eaee Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/lizi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/luoyun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/luoyun.png new file mode 100644 index 0000000000000000000000000000000000000000..827e97181f3325c36f7bddc8e248760393dee03c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/luoyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/mada.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/mada.png new file mode 100644 index 0000000000000000000000000000000000000000..8d6c7310a0f63af14a140c2bfdd01a18183c9719 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/mada.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/moliangwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/moliangwei.png new file mode 100644 index 0000000000000000000000000000000000000000..2cbc03609415f62eb92b2af778d8a2c822bd49c3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/moliangwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/niguangnan.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/niguangnan.png new file mode 100644 index 0000000000000000000000000000000000000000..32d5acb48f08a62ec665ecfd2bc077447b0e7974 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/niguangnan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/shenxiang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/shenxiang.png new file mode 100644 index 0000000000000000000000000000000000000000..63669fa549aa601aed7ae0692678c79c40983ad2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/shenxiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/tuguoyi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/tuguoyi.png new file mode 100644 index 0000000000000000000000000000000000000000..c83c351df0ba0027088a5fdbe5fd53ae16715f7b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/tuguoyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangluye.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangluye.png new file mode 100644 index 0000000000000000000000000000000000000000..d4e9b6670270094dbdfc78924557ddaff5012872 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangluye.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyanhao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyanhao.png new file mode 100644 index 0000000000000000000000000000000000000000..13de44b29c6e3d7d2dca59761b097732659dd523 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyanhao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyao.png new file mode 100644 index 0000000000000000000000000000000000000000..0d832414c5b16919fe757e764677a35016569039 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyunbo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyunbo.png new file mode 100644 index 0000000000000000000000000000000000000000..2189b14b3d847dcab685b6f6ddbddcabc8d6d0be Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wangyunbo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weixiaoqiang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weixiaoqiang.png new file mode 100644 index 0000000000000000000000000000000000000000..182d06c631a68874b47a0d4c881ba1a60acccd8b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weixiaoqiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weizhao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weizhao.png new file mode 100644 index 0000000000000000000000000000000000000000..357373d5cdc722f7bbd8aedbe95da29bb0cfcdc9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/weizhao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wujingzheng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wujingzheng.png new file mode 100644 index 0000000000000000000000000000000000000000..0c29d49d9e41483ebb0414498e5c1a7ee97b2065 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/wujingzheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yangcong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yangcong.png new file mode 100644 index 0000000000000000000000000000000000000000..a40c3bdbde4b31f38205cea26df9557d14142955 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yangcong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yaowei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yaowei.png new file mode 100644 index 0000000000000000000000000000000000000000..f23d4c7c22bc58b56d788a56284f21dd9f1d9d23 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yaowei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yeqinglong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yeqinglong.png new file mode 100644 index 0000000000000000000000000000000000000000..5e86bf85f8a3fe72ca595eaed9f92df3997b8e11 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/yeqinglong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhangxuzhou.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhangxuzhou.png new file mode 100644 index 0000000000000000000000000000000000000000..b2aa05d370b63d59bcb5b26e64f6dad7ff9df328 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhangxuzhou.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhengzhipeng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhengzhipeng.png new file mode 100644 index 0000000000000000000000000000000000000000..7fa5f0a2855be68cba4c6cf30f8bedc2447de7dd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhengzhipeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhongxin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..b8114393785f60cd012b41a153486e1c8083100e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhoujie.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhoujie.png new file mode 100644 index 0000000000000000000000000000000000000000..f99b8e423d494062166b4138fa3422481ff534f2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhoujie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouxiaohu.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouxiaohu.png new file mode 100644 index 0000000000000000000000000000000000000000..19b8fbbb5b8d6272c90bf9f939e3000536f39b54 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouxiaohu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouzhongyuan.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouzhongyuan.png new file mode 100644 index 0000000000000000000000000000000000000000..26b982c45f2080f7efb80075dfbaac1e29706f88 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhouzhongyuan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhulin.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhulin.png new file mode 100644 index 0000000000000000000000000000000000000000..27e4ff2364ae32bdf11ab7ef2634f88aad807217 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zhulin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zouqiubo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zouqiubo.png new file mode 100644 index 0000000000000000000000000000000000000000..4fd6aad860969bd6c32bf40dad068da8db5ee576 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/lecturer/zouqiubo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/pc-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/pc-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..8752c835dc2e809a97b3cc5795f28c166b92d51b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/pc-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2021/review.png b/web-ui/docs/.vuepress/public/img/summit/devday-2021/review.png new file mode 100644 index 0000000000000000000000000000000000000000..a9170587001c67819df84cf568cfb8b31fdbe8c2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2021/review.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORDEMO.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORDEMO.png new file mode 100644 index 0000000000000000000000000000000000000000..fb3ffebba284c63c23e73c429f5301e44b307abb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORDEMO.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSIG.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSIG.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3ceebac1edcb2451d5610ce63ab1a220203277 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSIG.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPEAKER.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPEAKER.png new file mode 100644 index 0000000000000000000000000000000000000000..bf756a5c0a15ba273c4099ac1985bb69c997af96 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPEAKER.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPENSOR.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPENSOR.png new file mode 100644 index 0000000000000000000000000000000000000000..50a957315bc51e84a60315279e584d1261ad6fa8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/CALLFORSPENSOR.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG1.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG1.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc9c2c2d378bb52718a9fd9adc8562e3a3c62ca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG1.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG2.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG2.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc00a2b78c9dae2aa5bcf8b7850d217cfb42b79 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/SIG2.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/afternoon_time.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/afternoon_time.png new file mode 100644 index 0000000000000000000000000000000000000000..df63b5ac6e39de0f2f50fc2406028682dbdaa29a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/afternoon_time.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue.png new file mode 100644 index 0000000000000000000000000000000000000000..50671afd39e14597b95382f18874ac50a3d4f54b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue_active.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue_active.png new file mode 100644 index 0000000000000000000000000000000000000000..337960353c7d033cd3bdc991f58741bf467c167a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/dialogue_active.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad.png new file mode 100644 index 0000000000000000000000000000000000000000..d76f6b2ae901fa243ffb6843f392c03e08da0a28 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad_active.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad_active.png new file mode 100644 index 0000000000000000000000000000000000000000..c5d500a0a059794e9e51ad477f22076284ce1401 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/etherpad_active.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time0.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time0.png new file mode 100644 index 0000000000000000000000000000000000000000..b4ef4d8102a173ba53a073d99ab2130da182c833 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time0.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time1.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time1.png new file mode 100644 index 0000000000000000000000000000000000000000..74fa4ab7634f8f34ca55bd8c0610cc2ea7263ed6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/first_time1.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/meteor.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/meteor.png new file mode 100644 index 0000000000000000000000000000000000000000..a47dd3062897653893aadb51a3a575e60cda35d4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/meteor.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/mo_sig.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/mo_sig.png new file mode 100644 index 0000000000000000000000000000000000000000..9dfed6f39a2bbf06c898690ebf0eabb5b10d8478 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/mo_sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/moring_time.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/moring_time.png new file mode 100644 index 0000000000000000000000000000000000000000..50e3b599281e257197b18e721c13fe361044c563 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/moring_time.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/night_time.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/night_time.png new file mode 100644 index 0000000000000000000000000000000000000000..c34af24f293e6be66d93a1a84ba6e93c94812860 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/night_time.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_sig.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_sig.png new file mode 100644 index 0000000000000000000000000000000000000000..499e8c05d37536e4226161857fbbce941316d5cd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_sig.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_title.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_title.png new file mode 100644 index 0000000000000000000000000000000000000000..a56a26dc02faea1842dd92dc925eee4b225b5d07 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/second_title.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-half.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-half.png new file mode 100644 index 0000000000000000000000000000000000000000..7de068d534e987642474c876f781c3547e08e2f3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-half.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-time.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-time.png new file mode 100644 index 0000000000000000000000000000000000000000..8230f8fa595f8c0b1a1b09c48d5b26fcd3957d81 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-time.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-title.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-title.png new file mode 100644 index 0000000000000000000000000000000000000000..2e224cc37cdd71452be2686d4d3fb0b2b46ccff3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/thild-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-0.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-0.png new file mode 100644 index 0000000000000000000000000000000000000000..26a616ad5ecfb5541c934cc9d241da8dea4af499 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-0.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-1.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-1.png new file mode 100644 index 0000000000000000000000000000000000000000..0fe75a30820dc201fe7573f5cfec73cf3b412418 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-1.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-10.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-10.png new file mode 100644 index 0000000000000000000000000000000000000000..2f6acd49a38b9d0f729945eb1be226abb6f8feca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-10.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-11.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-11.png new file mode 100644 index 0000000000000000000000000000000000000000..71241df5622f1c717f27e6c9e8ae601c5b90cfbe Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-11.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-12.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-12.png new file mode 100644 index 0000000000000000000000000000000000000000..b5144b700d105d4b4e707777bd35ca9b458dad65 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-12.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-2.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5729feb006ef2adbc6704f7ed82aa77dbeb2510c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-2.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-3.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-3.png new file mode 100644 index 0000000000000000000000000000000000000000..390e63edcf66556f4e92f6211b6b0e2f37c88b92 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-3.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-4.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-4.png new file mode 100644 index 0000000000000000000000000000000000000000..6e0ec3a75159628c9138701f1032f33805e0cb2b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-4.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-5.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-5.png new file mode 100644 index 0000000000000000000000000000000000000000..acc1d6fab64af85c14a0b6c961555386ffe3064c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-5.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-6.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-6.png new file mode 100644 index 0000000000000000000000000000000000000000..f18df7610055e7632c97110dd61ebba7c1386ab5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-6.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-7.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-7.png new file mode 100644 index 0000000000000000000000000000000000000000..eed61c04f84819ca5f01043c646209473bf78ae7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-7.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-8.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-8.png new file mode 100644 index 0000000000000000000000000000000000000000..92f8824aaf630bb11436200217bd396b55d08236 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-8.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-9.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-9.png new file mode 100644 index 0000000000000000000000000000000000000000..f9e9b859d7263daca9ce6abb628a28ceae25674d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/agenda/third-9.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/devday_banner_mo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/devday_banner_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..48d901ad56bb613597743fd397c310c2ccfe38e0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/devday_banner_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/h5-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/h5-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e4d824810c7297d8702621053a9eed515437e5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/h5-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/home_devday_mo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/home_devday_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..0c27241478c307623ce2c17ad7ec7e30ba3e1af0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/home_devday_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/caowenyuan.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/caowenyuan.png new file mode 100644 index 0000000000000000000000000000000000000000..79fbac2e0ba58e70ee756457c62516a1a4fd2ab0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/caowenyuan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenhui.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenhui.png new file mode 100644 index 0000000000000000000000000000000000000000..e58b9ab41d31f420d852c49714ee0fceb2d75fae Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenhui.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenqiang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenqiang.png new file mode 100644 index 0000000000000000000000000000000000000000..077138289275918e53daabf4f86b65ab67d787c9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chenqiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chixinze.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chixinze.png new file mode 100644 index 0000000000000000000000000000000000000000..8ee221833a840f340bf21207dcdfa58ab4ff6c99 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/chixinze.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/daizhiwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/daizhiwei.png new file mode 100644 index 0000000000000000000000000000000000000000..292f6ae5e7dd8f9a18ddcfbdd6eb08165858d1bf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/daizhiwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/dufan.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/dufan.png new file mode 100644 index 0000000000000000000000000000000000000000..6a05824f39b4c7a39c588e39e002b39516da1266 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/dufan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gaokun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gaokun.png new file mode 100644 index 0000000000000000000000000000000000000000..5e3e8dff73769f8b56baee026ac6161f40098d07 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gaokun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guangxiaoming.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guangxiaoming.png new file mode 100644 index 0000000000000000000000000000000000000000..56d1781bde6c4896e3ab9a8eb71c2f9999cdb1c5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guangxiaoming.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gujiahui.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gujiahui.png new file mode 100644 index 0000000000000000000000000000000000000000..b83f0c85cf1a88d0bed481484c99110a76ab6724 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/gujiahui.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guohao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guohao.png new file mode 100644 index 0000000000000000000000000000000000000000..64ce947976bd034a0532cbc222a61a298ba6bb07 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/guohao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hannaiping.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hannaiping.png new file mode 100644 index 0000000000000000000000000000000000000000..9adf0776ca187b09b77601c6714e6103bc7cc8b7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hannaiping.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hechaoyang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hechaoyang.png new file mode 100644 index 0000000000000000000000000000000000000000..cae8f33984e1c33b41914eef8136ff96c0655abb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/hechaoyang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/huxinwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/huxinwei.png new file mode 100644 index 0000000000000000000000000000000000000000..19cbda041c5144ae93ef35b0cd1339c906a783ae Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/huxinwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangdayong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangdayong.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e5ef62db92de4a05a21c70a1ccfe2d247bf9d2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangdayong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangguoqing.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangguoqing.png new file mode 100644 index 0000000000000000000000000000000000000000..706665938fa377a7932a032a5fbdc39546e6f92f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/jiangguoqing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lichengpeng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lichengpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..df56cc8b2af39050aecb150a67fec798cedc8037 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lichengpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liguangnan.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liguangnan.png new file mode 100644 index 0000000000000000000000000000000000000000..1e41df472faa7fa0fcb7ac7e8fd43dc528abaec0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liguangnan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/likang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/likang.png new file mode 100644 index 0000000000000000000000000000000000000000..2156f8baba204cda1eff521e8278024387def7bf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/likang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lisiming.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lisiming.png new file mode 100644 index 0000000000000000000000000000000000000000..d66480c83380dd55e16b54b2a781813c69d254b2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lisiming.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liubo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liubo.png new file mode 100644 index 0000000000000000000000000000000000000000..4483be01bcf16a2d7613d36a7d16924fecd289f8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liubo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liukai.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liukai.png new file mode 100644 index 0000000000000000000000000000000000000000..b5cc35c9037c83ac281b91014f143badc1c5a308 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liukai.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liulongfang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liulongfang.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d7908dccc19b9a74d637ceead3ef6e72e928c6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liulongfang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuxinliang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuxinliang.png new file mode 100644 index 0000000000000000000000000000000000000000..ef93eee4f838c02e31ac9fefcdd7ab55fc2ff866 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuxinliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuyun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuyun.png new file mode 100644 index 0000000000000000000000000000000000000000..a5741191ec687fe35085da395811e67412446ee0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuzuo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuzuo.png new file mode 100644 index 0000000000000000000000000000000000000000..982edd40dbaf8472f87ba54207d7dc4314d1ff08 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/liuzuo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lizi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lizi.png new file mode 100644 index 0000000000000000000000000000000000000000..4bba112e67b8d9f162a6837869f56ef1c14ebcef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/lizi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/luofei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/luofei.png new file mode 100644 index 0000000000000000000000000000000000000000..da106c08ae5f423f503412e6f71b1a355670321b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/luofei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/maquanyi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/maquanyi.png new file mode 100644 index 0000000000000000000000000000000000000000..54ed352ba0099c77c22e0e030e6c6ea0fe941cff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/maquanyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/qiuchenfen.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/qiuchenfen.png new file mode 100644 index 0000000000000000000000000000000000000000..b2be7e836d6e6a825d24c7da0d3a03b33f915a68 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/qiuchenfen.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/renwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/renwei.png new file mode 100644 index 0000000000000000000000000000000000000000..10e92193c545c6513a5d74bb49447a4e7fad5f6e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/renwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/sunwenlong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/sunwenlong.png new file mode 100644 index 0000000000000000000000000000000000000000..cb8f0744a28b5095ba39d031c75caee823af85a7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/sunwenlong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tangjie.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tangjie.png new file mode 100644 index 0000000000000000000000000000000000000000..f0161bbbcb3f0811a97e74478df990ae8b0335c9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tangjie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tianjun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tianjun.png new file mode 100644 index 0000000000000000000000000000000000000000..d35dedd5660c4210174b390462c3f16200b71a84 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tianjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tongjiawei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tongjiawei.png new file mode 100644 index 0000000000000000000000000000000000000000..3adf78ed077763fe8277bad84931d3c6e6593230 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/tongjiawei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wanghongbo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wanghongbo.png new file mode 100644 index 0000000000000000000000000000000000000000..95c93445ec07c1f9663d7601df8a8e331b3c356c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wanghongbo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangjiangtao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangjiangtao.png new file mode 100644 index 0000000000000000000000000000000000000000..faecbd574985c9c72603fb842ddd910930b18b53 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangjiangtao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangyueliang.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangyueliang.png new file mode 100644 index 0000000000000000000000000000000000000000..48637587b60a7e4f57f7f337c02cc29799de3828 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangyueliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangzhi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangzhi.png new file mode 100644 index 0000000000000000000000000000000000000000..c1605ab81837541465f1f257a953fcf943f6a8b1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wangzhi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuqiqing.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuqiqing.png new file mode 100644 index 0000000000000000000000000000000000000000..c2faeb051f4f596c93b903c0bc70891d197e0891 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuqiqing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuwei.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc483dfb5a9f177863956256ef5ab825e3d585c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuyanjun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuyanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..139d453a34809a4ecf2c718496eedadbf8dddccd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/wuyanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiekunxun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiekunxun.png new file mode 100644 index 0000000000000000000000000000000000000000..4aab6ab28a33ee8272cf945e6c69a9844d8b2f42 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiekunxun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiongwei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiongwei.png new file mode 100644 index 0000000000000000000000000000000000000000..a0128897bbb414fd6044fa762908a460c68aa617 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xiongwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuguodong.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuguodong.png new file mode 100644 index 0000000000000000000000000000000000000000..c5c83daee7e99352e0649e053003ecd47b05dee7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuguodong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuhaiyun.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuhaiyun.png new file mode 100644 index 0000000000000000000000000000000000000000..89742545be6937d9e5a82160395575fb564572d7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuhaiyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuzhixing.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuzhixing.png new file mode 100644 index 0000000000000000000000000000000000000000..d48863f106fa985c968c1ca6ffbaf0171188210a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/xuzhixing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yangzhao.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yangzhao.png new file mode 100644 index 0000000000000000000000000000000000000000..bcdcf42f5b09fe8b616adfa4247d435d15a1f43e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yangzhao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yaojiawei.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yaojiawei.png new file mode 100644 index 0000000000000000000000000000000000000000..5b51a57caf89934ecc83b0e15b9c7af92244001c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yaojiawei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yezhenyu.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yezhenyu.png new file mode 100644 index 0000000000000000000000000000000000000000..79948b03ab23a5dae6b68d95ba61863f4a738f23 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/yezhenyu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhangbo.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhangbo.png new file mode 100644 index 0000000000000000000000000000000000000000..e3958d3aa43476c02c9b3c36695d69b613d681dd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhangbo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhongxing.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhongxing.png new file mode 100644 index 0000000000000000000000000000000000000000..dd73768d3a1b41b9d16abb3b3584e40393bc45bc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhongxing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhouhaipeng.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhouhaipeng.png new file mode 100644 index 0000000000000000000000000000000000000000..fed80c9bd059f35fb2d44c0c82c993cda79cba56 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhouhaipeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhuanghaojian.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhuanghaojian.png new file mode 100644 index 0000000000000000000000000000000000000000..77ff517548231bdb0900b67fa48bbaa1f983533d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zhuanghaojian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuchunyi.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuchunyi.png new file mode 100644 index 0000000000000000000000000000000000000000..c9fb4d585397fbe997a219ce7be23439e8ab095f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuchunyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuzexu.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuzexu.png new file mode 100644 index 0000000000000000000000000000000000000000..ddaade9b2a663221b7f2f83e4dd50e976e92cf74 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/lecturer/zuzexu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg-long.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg-long.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2dcdf0eec1fa59d8b5095c45f5b684f56c6b0c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg-long.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..804e7e6494422fd02989fda96cc2984b1b60b046 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/live-bg.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/pc-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/pc-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..3bddd27f6fd3ea0d3a08aee7947feb8fb8679302 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/pc-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/star.svg b/web-ui/docs/.vuepress/public/img/summit/devday-2022/star.svg new file mode 100644 index 0000000000000000000000000000000000000000..c9876750d6c71e98924fc6f9feb0523e06c0cee1 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/devday-2022/star.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-mobile-devday2022.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-mobile-devday2022.png new file mode 100644 index 0000000000000000000000000000000000000000..2702e99ebecc95269dce086355f321233b5a416e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-mobile-devday2022.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-pc-devday2022.png b/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-pc-devday2022.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd42978d3330b683816e5eca65f135cf4a2dff5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/devday-2022/zh-pc-devday2022.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/dingwenlong.png b/web-ui/docs/.vuepress/public/img/summit/dingwenlong.png new file mode 100644 index 0000000000000000000000000000000000000000..48d495619f42c0d0cca487f14178efdf1eeca8a4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/dingwenlong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/gray-clock.svg b/web-ui/docs/.vuepress/public/img/summit/gray-clock.svg new file mode 100644 index 0000000000000000000000000000000000000000..00108c4c8aa93615d8a51dc3a9c7074530cb9413 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/gray-clock.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-mobile-agenda.png b/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-mobile-agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea444243080b980a835a9ea5e1a96ebffe6973c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-mobile-agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-pc-agenda.png b/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-pc-agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..42b386c6909be82313e41d91aa445567e4183350 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/agenda/en-pc-agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-mobile-agenda.png b/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-mobile-agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..3632da6af0f1d578794e1b991c4692c564cba6ab Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-mobile-agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-pc-agenda.png b/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-pc-agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..19f1bae9b08c71aa4b0390a22c09302289f648e1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/agenda/zh-pc-agenda.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/beiming.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/beiming.png new file mode 100644 index 0000000000000000000000000000000000000000..3707fb535fb58254cc48a8db01326dd3fe0e3691 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/beiming.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/cetc.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/cetc.png new file mode 100644 index 0000000000000000000000000000000000000000..6c3aa1f166accc8b046854cd72b9fc2d71164300 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/cetc.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-co-organizer.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-co-organizer.png new file mode 100644 index 0000000000000000000000000000000000000000..ee557b93a5aacc976686dcc223fdfcb66bd2b1bb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-co-organizer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-mobile-xieban.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-mobile-xieban.png new file mode 100644 index 0000000000000000000000000000000000000000..8ed7d06bca24d819db3236e21d75d3ede5bd08eb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/en-mobile-xieban.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/feiteng.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/feiteng.png new file mode 100644 index 0000000000000000000000000000000000000000..eeebb2124cd27edd3bbedebfdd66fc0ccb82fa4d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/feiteng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hailiang.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hailiang.png new file mode 100644 index 0000000000000000000000000000000000000000..30849931b093f513c4f9ba8118810e29b47cd837 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hailiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hangtian.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hangtian.png new file mode 100644 index 0000000000000000000000000000000000000000..40ef6b1516c911c9feaa0f231ed36ab33ee33417 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/hangtian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/huayun.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/huayun.png new file mode 100644 index 0000000000000000000000000000000000000000..a9b98d24e803e4f27a2c3ffaad0849e902ad5f7f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/huayun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/iscas.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/iscas.png new file mode 100644 index 0000000000000000000000000000000000000000..ef51ba05852111b9e293736d1329baffcb779b05 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/iscas.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/langche.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/langche.png new file mode 100644 index 0000000000000000000000000000000000000000..e94df19b1af381e2c6a77ee1e62bb1b46cba8c75 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/langche.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/liantong.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/liantong.png new file mode 100644 index 0000000000000000000000000000000000000000..d659545445d513114adc786de67a258768e246ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/liantong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/pengcheng.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/pengcheng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d046d6675763c2df058d2bdfb3a295b52506aa0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/pengcheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qilin.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qilin.png new file mode 100644 index 0000000000000000000000000000000000000000..5aff11ac3c5141ed698b5d6afb91f8e62d04af81 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qilin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qingyun.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qingyun.png new file mode 100644 index 0000000000000000000000000000000000000000..15cf10149376602f591e01fd9fe2087f724356ca Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/qingyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/runhe.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/runhe.png new file mode 100644 index 0000000000000000000000000000000000000000..f357642476818f748a0c9b465fe6c47fe97d4328 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/runhe.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/shenxinfu.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/shenxinfu.png new file mode 100644 index 0000000000000000000000000000000000000000..818a151ed71fde52df6c94d1b8f1ef2a8fadca3c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/shenxinfu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/tongxin.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/tongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..0d4d694bc5af5b63020d0d41175a45b77312a564 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/tongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/turbolinux.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/turbolinux.png new file mode 100644 index 0000000000000000000000000000000000000000..42d6d10767278275b266fb134eeed93f803da7ce Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/turbolinux.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xinan.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xinan.png new file mode 100644 index 0000000000000000000000000000000000000000..f75034f9d0af49c9521afcd01fb1307e7a89bd9e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xinan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xsky.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xsky.png new file mode 100644 index 0000000000000000000000000000000000000000..a7f962b2d29a8bc9b8b007e6ae1e14e34f3932af Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/xsky.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yidong.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yidong.png new file mode 100644 index 0000000000000000000000000000000000000000..e029c5b38433b7aa7644d274afef3a77be220773 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yidong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yinlian.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yinlian.png new file mode 100644 index 0000000000000000000000000000000000000000..9d58401a396d9d1f77c190c76261a6449bcc90fc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yinlian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhe.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhe.png new file mode 100644 index 0000000000000000000000000000000000000000..c770b13cea028c605c5ad37256e48aba9c80275d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhe.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhong.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhong.png new file mode 100644 index 0000000000000000000000000000000000000000..834cc7eb5cdeb603c2e8e4034d29bf95c521e3b8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/yunhong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-co-organizer.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-co-organizer.png new file mode 100644 index 0000000000000000000000000000000000000000..a518363c8f3a1e0c4d6353c5a81156e357f013e9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-co-organizer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-mobile-xieban.png b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-mobile-xieban.png new file mode 100644 index 0000000000000000000000000000000000000000..1bccb5f7163d024ed3ef77a69c3c9b687284b2a0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/co-organizer/zh-mobile-xieban.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/content.svg b/web-ui/docs/.vuepress/public/img/summit/home/content.svg new file mode 100644 index 0000000000000000000000000000000000000000..b15ab0738256ce213938c487d6e29b7dfde3615e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/home/content.svg @@ -0,0 +1,33 @@ + + + Style + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/home/desc.svg b/web-ui/docs/.vuepress/public/img/summit/home/desc.svg new file mode 100644 index 0000000000000000000000000000000000000000..391c63ee15702a8b4f376a5eb1b079b5de7ca427 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/home/desc.svg @@ -0,0 +1,26 @@ + + + Outlined/UI/time + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..25af95302ac28bc4ec5546774b837c0c90b3d96a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-summit.png b/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-summit.png new file mode 100644 index 0000000000000000000000000000000000000000..a19612beec5695dae10f503c24562f09e43fd046 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/en-mobile-summit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/en-pc-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/home/en-pc-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf4ccf03539ff5df4c615b3abe7a1d05c634e28 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/en-pc-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/en-pc-summit.png b/web-ui/docs/.vuepress/public/img/summit/home/en-pc-summit.png new file mode 100644 index 0000000000000000000000000000000000000000..fac43fef220cc69eedfc45e41207b939a0454f23 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/en-pc-summit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/cloudnative.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/cloudnative.png new file mode 100644 index 0000000000000000000000000000000000000000..7238602ee5daec7085b4be23df5bb619568ef480 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/cloudnative.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-mobile-foundation.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-mobile-foundation.png new file mode 100644 index 0000000000000000000000000000000000000000..f72a38567815289e52b6b4699c797a53e0f62d1a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-mobile-foundation.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-pc-foundation.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-pc-foundation.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2c2595c51622b299547ac85dec989e254f0086 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/en-pc-foundation.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/linaro.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/linaro.png new file mode 100644 index 0000000000000000000000000000000000000000..38ad4e9535f957cf145cb55b99d253a9fcc1cd99 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/linaro.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/linux.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/linux.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8503dce3e1c5dffab4e8289a22a683a1509a9e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/linux.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/open.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/open.png new file mode 100644 index 0000000000000000000000000000000000000000..e6c0a948185bf024328f273bd1b78f5fdff992ea Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/open.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/yuanzi.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/yuanzi.png new file mode 100644 index 0000000000000000000000000000000000000000..04c7b089ac2e4ef7876bc5ff0f6e94109db467c7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/yuanzi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-mobile-foundation.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-mobile-foundation.png new file mode 100644 index 0000000000000000000000000000000000000000..a551c8120eeedfccf75c0484391d3711789bdadb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-mobile-foundation.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-pc-foundation.png b/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-pc-foundation.png new file mode 100644 index 0000000000000000000000000000000000000000..3120d898d9fe349771aad39d6fc4a1e677febae7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/foundation/zh-pc-foundation.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-host-unit.png b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-host-unit.png new file mode 100644 index 0000000000000000000000000000000000000000..2fca9a526e198bdcae168956f1360d3c5f8e4b35 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-host-unit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-mobile-zhuban.png b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-mobile-zhuban.png new file mode 100644 index 0000000000000000000000000000000000000000..0e43794a17d5ea2ede8d0499bae6856c4b13f234 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/en-mobile-zhuban.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/host-unit/openeuler.png b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/openeuler.png new file mode 100644 index 0000000000000000000000000000000000000000..06e8b4f2916131cc5de5f72075635269123ff1c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/openeuler.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-host-unit.png b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-host-unit.png new file mode 100644 index 0000000000000000000000000000000000000000..a215e1b8177287f4ba91fb53a491b0ed53e0c125 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-host-unit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-mobile-zhuban.png b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-mobile-zhuban.png new file mode 100644 index 0000000000000000000000000000000000000000..2f30b074a8f1a61e0c9a7df74d69fbc1362caa14 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/host-unit/zh-mobile-zhuban.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/biannaimeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/biannaimeng.png new file mode 100644 index 0000000000000000000000000000000000000000..65f5c933700fb0cbdd498d7f07af69b71633d45a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/biannaimeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/caozhi.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/caozhi.png new file mode 100644 index 0000000000000000000000000000000000000000..d6f84be52cde89efd690b8861af56f45ba633ff5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/caozhi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chengong.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chengong.png new file mode 100644 index 0000000000000000000000000000000000000000..da62d9289c67897dd4f90b700835321b4d2666ab Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chengong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenhaibo.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenhaibo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b21550d0a44a009f78d2f1ef1256a24370126c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenhaibo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenqide.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenqide.png new file mode 100644 index 0000000000000000000000000000000000000000..ad831f65995bf09ee6b3b014dadaa1183108da61 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenqide.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenzeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenzeng.png new file mode 100644 index 0000000000000000000000000000000000000000..3b9c1f104f1ae96bce20b657bea707733196d801 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chenzeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chixinze.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chixinze.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2202953aa2b3bcb64ad0ade70202c4577a5e8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/chixinze.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dengtaihua.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dengtaihua.png new file mode 100644 index 0000000000000000000000000000000000000000..c72a7dbb5057a5c509f7fea85ffb1318efdd68c5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dengtaihua.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dujunping.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dujunping.png new file mode 100644 index 0000000000000000000000000000000000000000..7b74ca00517c1007bca98f1762947dd617587c16 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dujunping.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dukaitian.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dukaitian.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4a900730f369e63bf1a887e47ab0d6c7497e73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/dukaitian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-mobile-lecturer.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-mobile-lecturer.png new file mode 100644 index 0000000000000000000000000000000000000000..b802cc5bca89d76dc2a30033e1ca516f7d74495e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-mobile-lecturer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-pc-lecturer.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-pc-lecturer.png new file mode 100644 index 0000000000000000000000000000000000000000..4b01430d4d9b1d41fa5e3f383bc90048eb9bf785 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/en-pc-lecturer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fanbin.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fanbin.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec3929f9710597f90b5f0f306eec7f904480325 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fanbin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fangyafen.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fangyafen.png new file mode 100644 index 0000000000000000000000000000000000000000..a3ea35145915fee79fd6345e92f68f9fdd53dc72 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fangyafen.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fengben.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fengben.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7b4eeb06a8105dd03f70c85cdc4814522d5423 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/fengben.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaokun.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaokun.png new file mode 100644 index 0000000000000000000000000000000000000000..dd82a086d1c2ce70d265f8102f1ee00b59a80eb3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaokun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaozhangfei.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaozhangfei.png new file mode 100644 index 0000000000000000000000000000000000000000..ec54b88d74b50fa9de27c480365eff91459afedc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/gaozhangfei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangmaofeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangmaofeng.png new file mode 100644 index 0000000000000000000000000000000000000000..62652a1f948f0e129251e78ea163830864aeca09 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangmaofeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangxiaotao.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangxiaotao.png new file mode 100644 index 0000000000000000000000000000000000000000..1f2c88437a9c96a66b1813c5e35d2d363dbe1a22 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huangxiaotao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huxinwei.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huxinwei.png new file mode 100644 index 0000000000000000000000000000000000000000..5652e69c6421102a2b0ab4540877e32d4653c1cb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/huxinwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/jiangdayong.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/jiangdayong.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4d2718b0ca80307318a8e678f2c6515dd461a6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/jiangdayong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liangdong.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liangdong.png new file mode 100644 index 0000000000000000000000000000000000000000..37d80c8350bb747cb00777297363f6901f283ea2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liangdong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/libaolin.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/libaolin.png new file mode 100644 index 0000000000000000000000000000000000000000..eeb77dc02285e1b324954cec1ebf78e8dbb28b2c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/libaolin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/lijianfeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/lijianfeng.png new file mode 100644 index 0000000000000000000000000000000000000000..d3d1fde1e1d03bc54ea873033bbd7e43ee980bf2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/lijianfeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/likunshan.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/likunshan.png new file mode 100644 index 0000000000000000000000000000000000000000..069f5b2a8cbf7d1c5d9cf754891e142b9029793d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/likunshan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuwei.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuwei.png new file mode 100644 index 0000000000000000000000000000000000000000..1b46472b52ae198796f31ae4446684f6025e36b6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuxinliang.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuxinliang.png new file mode 100644 index 0000000000000000000000000000000000000000..a0318577707a76b260da53758211636498a60a88 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/liuxinliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoqiu.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoqiu.png new file mode 100644 index 0000000000000000000000000000000000000000..1c361fa8370950ce013ca8e81bbe56c622464874 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoqiu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoyun.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoyun.png new file mode 100644 index 0000000000000000000000000000000000000000..c0599b9b542b5f345c63b16b5b06e66774f11711 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/luoyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/maquanyi.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/maquanyi.png new file mode 100644 index 0000000000000000000000000000000000000000..10f5c9157bd151f468b2d5aa3d60d5e8ce94e25b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/maquanyi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiuchengfeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiuchengfeng.png new file mode 100644 index 0000000000000000000000000000000000000000..e91b0ac3029eee8e3ac48038aeba1abf3e1d3fd3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiuchengfeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiudayu.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiudayu.png new file mode 100644 index 0000000000000000000000000000000000000000..5f4033ca9697124cf4ce9655ce8bfbf838f70ed7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/qiudayu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/sunlijie.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/sunlijie.png new file mode 100644 index 0000000000000000000000000000000000000000..b857d6beba142daef5502a1826625b88edf4d35d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/sunlijie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjiangtao.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjiangtao.png new file mode 100644 index 0000000000000000000000000000000000000000..0bbde606a4904883cb97eb255e3353a4944859c6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjiangtao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjunjie.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjunjie.png new file mode 100644 index 0000000000000000000000000000000000000000..4c08ec44199bff799dca73614d5817a32c92c737 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangjunjie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangyaohua.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangyaohua.png new file mode 100644 index 0000000000000000000000000000000000000000..ff1c99de16761ea4cfcccb3110f1f7c497a4baef Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wangyaohua.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weibaohui.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weibaohui.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaafdce509ab081403ab197b57c3255c8a45bd2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weibaohui.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weigang.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weigang.png new file mode 100644 index 0000000000000000000000000000000000000000..58a64c1cff74e5a06bee92068927634cc3bb14fd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/weigang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wubin.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wubin.png new file mode 100644 index 0000000000000000000000000000000000000000..11e76a16a1421881317425797d880a5bdaf82c99 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/wubin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiaxiaoya.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiaxiaoya.png new file mode 100644 index 0000000000000000000000000000000000000000..e534b1d71c7a8770e37515abe085d5d1766ddd37 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiaxiaoya.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiongwei.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiongwei.png new file mode 100644 index 0000000000000000000000000000000000000000..8ba98299ac4b21d8da013169306ddce28ae369ab Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/xiongwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yinjiayi.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yinjiayi.png new file mode 100644 index 0000000000000000000000000000000000000000..71352a6fda8ac2169c94d003eff5522781841a4b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yinjiayi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuanzhichang.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuanzhichang.png new file mode 100644 index 0000000000000000000000000000000000000000..08ed5d694372883e90987c22e8ea4dedc6e06183 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuanzhichang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuzhihui.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuzhihui.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a2d9f15cebfce29b3c904a2a58f91166f6ff0b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/yuzhihui.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-mobile-lecturer.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-mobile-lecturer.png new file mode 100644 index 0000000000000000000000000000000000000000..2a9e7961ba16d6c97827fdb55b8b5db64488e4e7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-mobile-lecturer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-pc-lecturer.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-pc-lecturer.png new file mode 100644 index 0000000000000000000000000000000000000000..35736340a7577b1207ee640d4a69457ec5401db4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zh-pc-lecturer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangshuting.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangshuting.png new file mode 100644 index 0000000000000000000000000000000000000000..4574ed53914059bbea63e58aad11303dfa89bd09 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangshuting.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangxuzhou.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangxuzhou.png new file mode 100644 index 0000000000000000000000000000000000000000..37e93634b4f973f38427d7266193a16e266b400d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhangxuzhou.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhaoshuai.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhaoshuai.png new file mode 100644 index 0000000000000000000000000000000000000000..5ddcf99299b7ce44dae048498dc53ef9e22b9c69 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhaoshuai.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhongjun.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhongjun.png new file mode 100644 index 0000000000000000000000000000000000000000..a02189ac5aa245206cb349cafbea708c271cfab9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhongjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhoupeng.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhoupeng.png new file mode 100644 index 0000000000000000000000000000000000000000..a489f5de7cf568fc9e8b331dcc2c9c175f6b43a1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zhoupeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zulijun.png b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zulijun.png new file mode 100644 index 0000000000000000000000000000000000000000..e282e41a6017092fd8055a02153009e4b13064ae Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/lecturer/zulijun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/line.png b/web-ui/docs/.vuepress/public/img/summit/home/line.png new file mode 100644 index 0000000000000000000000000000000000000000..378a2af16a23e1b67abcf1cbdf219c899019652d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/line.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/51cto.png b/web-ui/docs/.vuepress/public/img/summit/home/media/51cto.png new file mode 100644 index 0000000000000000000000000000000000000000..b39905995d027170f383909e8cb3a8ab75133b09 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/51cto.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/csdn.png b/web-ui/docs/.vuepress/public/img/summit/home/media/csdn.png new file mode 100644 index 0000000000000000000000000000000000000000..2046dd8fe0cfd2da42bc890d275dacabc6ca195b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/csdn.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/en-mobile-media.png b/web-ui/docs/.vuepress/public/img/summit/home/media/en-mobile-media.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbb66cd9b9231ac3821ee52cdf137a14a6a6921 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/en-mobile-media.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/en-pc-media.png b/web-ui/docs/.vuepress/public/img/summit/home/media/en-pc-media.png new file mode 100644 index 0000000000000000000000000000000000000000..ab48c4ca81f2d00c3869954608f6526190a5b1ed Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/en-pc-media.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/media-linux.png b/web-ui/docs/.vuepress/public/img/summit/home/media/media-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..7cd117ab1ffce6bd6a377cef2f08c4762e51a97c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/media-linux.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/oschina.png b/web-ui/docs/.vuepress/public/img/summit/home/media/oschina.png new file mode 100644 index 0000000000000000000000000000000000000000..296d079bef63e0f913d4f9a9ffc5b2d7bbe363d2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/oschina.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/sifou.png b/web-ui/docs/.vuepress/public/img/summit/home/media/sifou.png new file mode 100644 index 0000000000000000000000000000000000000000..6c3ca9dbd81f3047c9ad85062e79d32a4cb67d10 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/sifou.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.jpg b/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a06248f010cf3e279768bc1f08c76f539d2d71cc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.png b/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.png new file mode 100644 index 0000000000000000000000000000000000000000..cfcd0ea4c839782bac516d78b3bee76bcb0abe8e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/xianglingshuo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/zh-mobile-media.png b/web-ui/docs/.vuepress/public/img/summit/home/media/zh-mobile-media.png new file mode 100644 index 0000000000000000000000000000000000000000..8865adfddcd67b68b7aaff115240d089687512e6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/zh-mobile-media.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/media/zh-pc-media.png b/web-ui/docs/.vuepress/public/img/summit/home/media/zh-pc-media.png new file mode 100644 index 0000000000000000000000000000000000000000..4766b1dbd83932fb39ffd5f59f46c37b207c5c50 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/media/zh-pc-media.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/nav.gif b/web-ui/docs/.vuepress/public/img/summit/home/nav.gif new file mode 100644 index 0000000000000000000000000000000000000000..d221c632595f422e57d5cc70899e7e789f83a311 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/nav.gif differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/en-mobile-review.png b/web-ui/docs/.vuepress/public/img/summit/home/review/en-mobile-review.png new file mode 100644 index 0000000000000000000000000000000000000000..07efb770be936b1f41f6eb3358f641407630a4b6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/en-mobile-review.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/en-pc-review.png b/web-ui/docs/.vuepress/public/img/summit/home/review/en-pc-review.png new file mode 100644 index 0000000000000000000000000000000000000000..b944a4e60900a3964501bb91f2469965d96275b0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/en-pc-review.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/h5-review-banner.png b/web-ui/docs/.vuepress/public/img/summit/home/review/h5-review-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..081f00705ba16da0e60ffca4e020cd71af8a7498 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/h5-review-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/web-review-banner.png b/web-ui/docs/.vuepress/public/img/summit/home/review/web-review-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..1bfa30d760a73e3bfd4d3b5d4fec250648f3641b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/web-review-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/zh-mobile-review.png b/web-ui/docs/.vuepress/public/img/summit/home/review/zh-mobile-review.png new file mode 100644 index 0000000000000000000000000000000000000000..d7aa3ba34f07fe1fd933aab94c64fd94f8a555f9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/zh-mobile-review.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/review/zh-pc-review.png b/web-ui/docs/.vuepress/public/img/summit/home/review/zh-pc-review.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb82e0cac304fb14724d22b932c37ea78b4ddd9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/review/zh-pc-review.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/speaker.svg b/web-ui/docs/.vuepress/public/img/summit/home/speaker.svg new file mode 100644 index 0000000000000000000000000000000000000000..643b8088e7bd8d2202d0e28db8debf1c8f6eacd9 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/home/speaker.svg @@ -0,0 +1,33 @@ + + + Style + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/home/time.svg b/web-ui/docs/.vuepress/public/img/summit/home/time.svg new file mode 100644 index 0000000000000000000000000000000000000000..c708cc9f645154a107fa05a666b415a304e34fed --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/home/time.svg @@ -0,0 +1,35 @@ + + + Outlined/UI/time + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-mobile-undertaker.png b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-mobile-undertaker.png new file mode 100644 index 0000000000000000000000000000000000000000..2b54922d56ae1efe53176482eec6c7e4adf9c4f9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-mobile-undertaker.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-pc-undertaker.png b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-pc-undertaker.png new file mode 100644 index 0000000000000000000000000000000000000000..5ab586d3f36fa808999d08d69e4c09a3d0581d9d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/en-pc-undertaker.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/undertaker/jikebang.png b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/jikebang.png new file mode 100644 index 0000000000000000000000000000000000000000..684f768e644556bce29796ced0d1e3eb5022a822 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/jikebang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-mobile-undertaker.png b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-mobile-undertaker.png new file mode 100644 index 0000000000000000000000000000000000000000..26775f191a374b591c61ae764010604cb40ab416 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-mobile-undertaker.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-pc-undertaker.png b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-pc-undertaker.png new file mode 100644 index 0000000000000000000000000000000000000000..b29327b4c64fe5c02a8294be2cb33e85a1c55cc5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/undertaker/zh-pc-undertaker.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..9d0ea824038ce041d4bdee519d7fb5c9cf617ca4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-summit.png b/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-summit.png new file mode 100644 index 0000000000000000000000000000000000000000..fa83774923ab8cf1f81777a0b2518cd9b2a343c7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/zh-mobile-summit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-liveroom.png b/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-liveroom.png new file mode 100644 index 0000000000000000000000000000000000000000..26f27a52cb2c2d89dc266c72fe8482e700bd3a43 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-liveroom.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-summit.png b/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-summit.png new file mode 100644 index 0000000000000000000000000000000000000000..268018c60c4158ddc8a7bad9828f04913cff324c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/home/zh-pc-summit.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/huxinwei.png b/web-ui/docs/.vuepress/public/img/summit/huxinwei.png new file mode 100644 index 0000000000000000000000000000000000000000..42674821c0fa9284d33a67309aca1ffb963d0144 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/huxinwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/jiangdayong.png b/web-ui/docs/.vuepress/public/img/summit/jiangdayong.png new file mode 100644 index 0000000000000000000000000000000000000000..b98ba3e511d64b1b779b666fbc1851fdd89f5e11 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/jiangdayong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/kunpeng.svg b/web-ui/docs/.vuepress/public/img/summit/kunpeng.svg new file mode 100644 index 0000000000000000000000000000000000000000..f739b90f4ee64273529dab91913039de691e6dc2 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/kunpeng.svg @@ -0,0 +1,26 @@ + + + 鲲鹏 + + + + + + + + + + + + + 鲲鹏社区 + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/lizhenning.jpg b/web-ui/docs/.vuepress/public/img/summit/lizhenning.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1eb1b2b5e7f0b0aeee22019ee887fbc422c9bc22 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/lizhenning.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/summit/majunjie.png b/web-ui/docs/.vuepress/public/img/summit/majunjie.png new file mode 100644 index 0000000000000000000000000000000000000000..0003ede511898ee016cf873d298b730baa641bc6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/majunjie.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/mulan.svg b/web-ui/docs/.vuepress/public/img/summit/mulan.svg new file mode 100644 index 0000000000000000000000000000000000000000..4ca5c682f9587699e456c6e89fcaacd71158b0c3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/mulan.svg @@ -0,0 +1,16 @@ + + + 木兰 + + + + + + + 木兰社区 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/pengcheng.png b/web-ui/docs/.vuepress/public/img/summit/pengcheng.png new file mode 100644 index 0000000000000000000000000000000000000000..0de4699913f4e20bb8d8c88d1fc04a4b1593fbec Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/pengcheng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit-banner.png b/web-ui/docs/.vuepress/public/img/summit/summit-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..b2150ca9f51a3ae468e166a9800e9f4ae4aa673d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit-banner.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit-banner.svg b/web-ui/docs/.vuepress/public/img/summit/summit-banner.svg new file mode 100644 index 0000000000000000000000000000000000000000..7f73949de68578c68e98f01e21672e9ec91d631e --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/summit-banner.svg @@ -0,0 +1,69 @@ + + + openEuler/illustrator/none备份 15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/360.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/360.png new file mode 100644 index 0000000000000000000000000000000000000000..89199e0c07dde8a4d83ae180b26da87d16ba0210 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/360.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/asiainfo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/asiainfo.png new file mode 100644 index 0000000000000000000000000000000000000000..8318136e281e42f52bc9f8375276d20b591f54e9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/asiainfo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/baixing.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/baixing.png new file mode 100644 index 0000000000000000000000000000000000000000..316ec0dd644f7f9d0336f962369b71f354b31295 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/baixing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/beilian.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/beilian.png new file mode 100644 index 0000000000000000000000000000000000000000..1201e811a064b67f0cb317aeb425f7078616e882 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/beilian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/bessystem.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/bessystem.png new file mode 100644 index 0000000000000000000000000000000000000000..85b52d8a0595ea55f97dcde070ed69416fd22027 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/bessystem.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dianxing.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dianxing.png new file mode 100644 index 0000000000000000000000000000000000000000..6b29bb25e54f63334fabaf1a454dba0adb451a7a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dianxing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dongfangtong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dongfangtong.png new file mode 100644 index 0000000000000000000000000000000000000000..049f0006db9bffcae7a174cbdf3a1c77d33f3f92 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/dongfangtong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/easystack.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/easystack.png new file mode 100644 index 0000000000000000000000000000000000000000..0402841567cfdde9dad593b6407a28d3b3d3614d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/easystack.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/fusion.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/fusion.png new file mode 100644 index 0000000000000000000000000000000000000000..1e042dbb3ab1413e38de0af06c0c7a178825ae65 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/fusion.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/guoxing.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/guoxing.png new file mode 100644 index 0000000000000000000000000000000000000000..34f96f05c17bbfa0c9c28215d8864845d6fe4c22 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/guoxing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huanghe.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huanghe.png new file mode 100644 index 0000000000000000000000000000000000000000..5642feadfb28ec343bcaca2fd2469ec62c1178fd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huanghe.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huawei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huawei.png new file mode 100644 index 0000000000000000000000000000000000000000..301e5170b4d1dbeeed4d73b891551d46b5a47468 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huawei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huayun.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huayun.png new file mode 100644 index 0000000000000000000000000000000000000000..92b8dc559219f289a14d39b4561e641679ba85ed Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/huayun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iiioka.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iiioka.png new file mode 100644 index 0000000000000000000000000000000000000000..d7fdcd9acd11d5d009b236233dacfb5752a4c579 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iiioka.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/intel.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/intel.png new file mode 100644 index 0000000000000000000000000000000000000000..4b8b46d92843db70fe2d9aec13bb122b2189baa8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/intel.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iscas.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iscas.png new file mode 100644 index 0000000000000000000000000000000000000000..dfcdd0cc1a0b1f6e81d6b50974dcd82f9c0b7f1e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/iscas.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/isstech.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/isstech.png new file mode 100644 index 0000000000000000000000000000000000000000..4c1f2313081411b32a2d0c3572d655fde1dcadcd Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/isstech.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/jdcloud.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/jdcloud.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7276528d6a9f81f47abff9161c5e03a895366c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/jdcloud.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kaifazhineng.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kaifazhineng.png new file mode 100644 index 0000000000000000000000000000000000000000..605b73401c3d5964abb614b21e3f7f4d819e6eaf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kaifazhineng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kengpeng.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kengpeng.png new file mode 100644 index 0000000000000000000000000000000000000000..bf38339ecce38df18a850d625cb3d55d761f3c84 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/kengpeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/langcher.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/langcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1ec4acf3954d448edae8ad037cadb99744905b4e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/langcher.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/liantong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/liantong.png new file mode 100644 index 0000000000000000000000000000000000000000..76c446bf01f90ccf5dd99aa5e576694ca8a25ac6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/liantong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linaro.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linaro.png new file mode 100644 index 0000000000000000000000000000000000000000..82eab3e3320895f8e980d8970d1759b736315a0c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linaro.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linux.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linux.png new file mode 100644 index 0000000000000000000000000000000000000000..27d8972e3915503bbd83ccff409c3ad81f90c8ff Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/linux.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/mobile-title.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/mobile-title.png new file mode 100644 index 0000000000000000000000000000000000000000..3af39a1b1ba3827eb0b3898db3d6f0dc5abe74b1 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/mobile-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/nuclei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/nuclei.png new file mode 100644 index 0000000000000000000000000000000000000000..d3cd84823e17696072a04effd9983f787457c433 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/nuclei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openEulerlogo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openEulerlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..111c7fb4e9ccb8cd7336bea268d8e17dc10f94e6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openEulerlogo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openaton.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openaton.png new file mode 100644 index 0000000000000000000000000000000000000000..fdbc589f649176e2c61da1e208ab8f7ff2d92a65 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openaton.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openinfra.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openinfra.png new file mode 100644 index 0000000000000000000000000000000000000000..d7723510c76df530ffd1fba86bcfd02b5777a8db Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/openinfra.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/phytium.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/phytium.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1e1e83cc7377258891510dceea8e9b89b3f67d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/phytium.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/puhua.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/puhua.png new file mode 100644 index 0000000000000000000000000000000000000000..aa448561a0a37c32a158351f27f9506b2893f258 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/puhua.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinsoft.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinsoft.png new file mode 100644 index 0000000000000000000000000000000000000000..81a1153a3e4748af16a96a9ccf6fedf8c62eac84 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinsoft.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinxinan.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinxinan.png new file mode 100644 index 0000000000000000000000000000000000000000..4a89452417561b628b38d040dffaad637b78803d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qilinxinan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qingcloud.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qingcloud.png new file mode 100644 index 0000000000000000000000000000000000000000..5d931234691dd9328b01bdf8ae7518242b416571 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/qingcloud.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/ruihe.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/ruihe.png new file mode 100644 index 0000000000000000000000000000000000000000..83cac675e385aaaef228fe0d02a9cc7cc82a92f7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/ruihe.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shentai.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shentai.png new file mode 100644 index 0000000000000000000000000000000000000000..24cd4addd03845e045faafae35343452f9bd0cb4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shentai.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shenzhou.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shenzhou.png new file mode 100644 index 0000000000000000000000000000000000000000..212e3bc76064e513c3ce62a91c17ca66cd8e101a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/shenzhou.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/softstone.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/softstone.png new file mode 100644 index 0000000000000000000000000000000000000000..a0cc1890fb6c97bde7f7ec6e0f11b1233618327c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/softstone.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/starfive.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/starfive.png new file mode 100644 index 0000000000000000000000000000000000000000..1c09adcaa5812ed416421f684a13ecd04379237a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/starfive.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/suse.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/suse.png new file mode 100644 index 0000000000000000000000000000000000000000..55b1f0875da79c93280d5f13ade035dcae6faaeb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/suse.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/talkweb.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/talkweb.png new file mode 100644 index 0000000000000000000000000000000000000000..3c36f2f95a637b9f1fbd3bbb0e32a31235f9f6cb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/talkweb.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tianyuan.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tianyuan.png new file mode 100644 index 0000000000000000000000000000000000000000..680e96120bf445c7ef41cc52cb956b1ca48a440b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tianyuan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tongxin.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tongxin.png new file mode 100644 index 0000000000000000000000000000000000000000..8b9112a7068a4f3b136513e3e898d4979109ca27 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/tongxin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/turbolinux.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/turbolinux.png new file mode 100644 index 0000000000000000000000000000000000000000..73fc7b145db12c5d7996150c55a7f7b0490a3535 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/turbolinux.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/web-title.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/web-title.png new file mode 100644 index 0000000000000000000000000000000000000000..546c2312ecbe5f3ccdf621130a9d5a685ec7fe44 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/web-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/winhong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/winhong.png new file mode 100644 index 0000000000000000000000000000000000000000..5866876e89dec8fde0954ed8ed325d86420e3574 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/winhong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinchen.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinchen.png new file mode 100644 index 0000000000000000000000000000000000000000..cda21add06c3c84b72de967c8139c946e3a4a8e2 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinchen.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinlang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinlang.png new file mode 100644 index 0000000000000000000000000000000000000000..9cdde2a38e1509b844fcedc1c1e16f149b86cea9 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xinlang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xsky.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xsky.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6c91bc957a148c93cb2a52bc42fccc72069724 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/xsky.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidong.png new file mode 100644 index 0000000000000000000000000000000000000000..5500986b56629959a155b5a194594df1015449f4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidongyun.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidongyun.png new file mode 100644 index 0000000000000000000000000000000000000000..6704ba6abe9fd97fbfe658a510def14a1df9d47a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yidongyun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/youxi.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/youxi.png new file mode 100644 index 0000000000000000000000000000000000000000..e764a0f316ec4ea90acb361030aed36748177369 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/youxi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yunhe.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yunhe.png new file mode 100644 index 0000000000000000000000000000000000000000..81d59bfbf15963436d2f70d3c079a0285630e411 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/yunhe.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/zhongkedachuang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/zhongkedachuang.png new file mode 100644 index 0000000000000000000000000000000000000000..5718fe4b65a94f1042499db493d2f131425f16d5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/Co-construction/zhongkedachuang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/exhibition-map.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhibition-map.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd217b28521541fa9bd61d603c6df6acda80b1f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhibition-map.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title-mo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3dc91f4130864dad1cffc796a243304f5008311 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title.png new file mode 100644 index 0000000000000000000000000000000000000000..8f49c064e2c5d8c846a8409c6e49b4dc9a750d33 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/exhirition-title.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/caihaomin.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/caihaomin.png new file mode 100644 index 0000000000000000000000000000000000000000..0335674d1fd419eb4824f72bb132792c3154de0c Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/caihaomin.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenhaibo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenhaibo.png new file mode 100644 index 0000000000000000000000000000000000000000..c0472bbe143ac6fd0238c8f677a4d4697d654e8f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenhaibo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenjingwei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenjingwei.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c758f3486675c1b9c7ada9833fd38a68b56322 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/chenjingwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/dukaitian.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/dukaitian.png new file mode 100644 index 0000000000000000000000000000000000000000..b9af62ef9e28bf0fb11ba5363db572952ba314bf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/dukaitian.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/gaowei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/gaowei.png new file mode 100644 index 0000000000000000000000000000000000000000..0e127da9e19eaa3eeee08e64c3a75359286e831a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/gaowei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/guohanjun.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/guohanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..8923169799b9fbbe6d0eec88ef34db87bf2a2c2b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/guohanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/huxinwei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/huxinwei.png new file mode 100644 index 0000000000000000000000000000000000000000..a1da4437a6013c21880cf16a9eb80533735a39cf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/huxinwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangdayong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangdayong.png new file mode 100644 index 0000000000000000000000000000000000000000..f242b8ce4793961e6b7af99590f837c25d01702b Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangdayong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangyongqing.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangyongqing.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9bf97b16c68bec09f4b953871715f276664c17 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/jiangyongqing.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/kongjinzu.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/kongjinzu.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd4d7699abda20ac99523626592248bc3581939 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/kongjinzu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/lishouyong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/lishouyong.png new file mode 100644 index 0000000000000000000000000000000000000000..9c5330553d8ff2f6b4e32baadcb45feafcd33fb5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/lishouyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liujingang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liujingang.png new file mode 100644 index 0000000000000000000000000000000000000000..6e9df351619e3e631ea2fe6c9b30f7a0012ee44a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liujingang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liyong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liyong.png new file mode 100644 index 0000000000000000000000000000000000000000..bd00c1e3b6165243c80e45746ef5543983bc4815 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/liyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/panjianfeng.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/panjianfeng.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4c58e5afbccc645c0e1e5ae1a023987808ebc8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/panjianfeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle.png new file mode 100644 index 0000000000000000000000000000000000000000..15f5460824a6650a20b94e1c0b369c98fb7cbf3e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle_mo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..44b5d738288ccf68eeedb440431bfb112004c1cf Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/publishertitle_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qinxiaokang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qinxiaokang.png new file mode 100644 index 0000000000000000000000000000000000000000..36cd160ec597589873074a67cf5541d066f17cde Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qinxiaokang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qiuchengfeng.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qiuchengfeng.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc654e19943e400024ed35a3e6d5302a2e13de6 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/qiuchengfeng.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/renqi.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/renqi.png new file mode 100644 index 0000000000000000000000000000000000000000..6aaf9191409e4bc209ff734935b9705a0453843e Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/renqi.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shenxiang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shenxiang.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca2ecc15a2bfb96362bfadff2fbbd53589323dc Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shenxiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shiyong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shiyong.png new file mode 100644 index 0000000000000000000000000000000000000000..5e665115eb888c790ee4620b50158c2535f79258 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/shiyong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle.png new file mode 100644 index 0000000000000000000000000000000000000000..e77783b159e99144cd8ea7b4d06607a86b4e6350 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle_mo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle_mo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad9d9384452a834fd004dc98b854d98dc422b3d3 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/sperkertitle_mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wangpan.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wangpan.png new file mode 100644 index 0000000000000000000000000000000000000000..fe60f532ad0b376a05961aa09c4db40597fd74d0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wangpan.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wuyanjun.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wuyanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7667dead8ad574ef893cd70a0c8f6094588321 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/wuyanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/xiekunxun.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/xiekunxun.png new file mode 100644 index 0000000000000000000000000000000000000000..f3658c08abeffd650ce83c2e02b30862d6523cf7 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/xiekunxun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangliu.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangliu.png new file mode 100644 index 0000000000000000000000000000000000000000..f2179355137a11d3f34c5d7792d52fe6b6855621 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangliu.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangtao.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangtao.png new file mode 100644 index 0000000000000000000000000000000000000000..86f480e317a8d1da7d851213800a97a63917bb73 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yangtao.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yanshuanghai.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yanshuanghai.png new file mode 100644 index 0000000000000000000000000000000000000000..73a335e86028f1f1677c2f904ba7f91615f7ca22 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yanshuanghai.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yeqinglong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yeqinglong.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a7dda70e7c6181dfd891d28b879367d6d80e12 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yeqinglong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yixiujiang.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yixiujiang.png new file mode 100644 index 0000000000000000000000000000000000000000..66d4ae8544b000758d92de8861539913c6dd3ecb Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/yixiujiang.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zhanglei.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zhanglei.png new file mode 100644 index 0000000000000000000000000000000000000000..8e616d096209b62d768f0a207e147f585670800a Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zhanglei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zujianzhong.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zujianzhong.png new file mode 100644 index 0000000000000000000000000000000000000000..717a98c7a2183428b462c297c2a9529c0a1ebf25 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/lecturer/zujianzhong.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/left-longer.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/left-longer.png new file mode 100644 index 0000000000000000000000000000000000000000..94ae6170a37356bbb375b9f3f810de830d5e2a22 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/left-longer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/right-longer.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/right-longer.png new file mode 100644 index 0000000000000000000000000000000000000000..9f1b422bd6b9124ee540543be9bb6394445e9e40 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/right-longer.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo-en.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo-en.png new file mode 100644 index 0000000000000000000000000000000000000000..866801ab34aa33053285cd06b51dc6169f0f0b5d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo.png new file mode 100644 index 0000000000000000000000000000000000000000..36569ea71618e40c8d2aa9312dede1e20be71d68 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-mo.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc-en.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc-en.png new file mode 100644 index 0000000000000000000000000000000000000000..6ea17da9db86880dbf1c3867168acc34c7dd110d Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc-en.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc.png new file mode 100644 index 0000000000000000000000000000000000000000..c59ff40afbd3c2977bca5cf79523e7bce6771d78 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/summit2021-pc.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-mobile-summit2021.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-mobile-summit2021.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d04c9e20547f9627bb785ac127d6f26cdc91d8 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-mobile-summit2021.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-pc-summit2021.png b/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-pc-summit2021.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd42978d3330b683816e5eca65f135cf4a2dff5 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/summit2021/zh-pc-summit2021.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/wangzhun.jpg b/web-ui/docs/.vuepress/public/img/summit/wangzhun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d362750f27ff62f1371c06d45c1004ac7fb80175 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/wangzhun.jpg differ diff --git a/web-ui/docs/.vuepress/public/img/summit/white-clock.svg b/web-ui/docs/.vuepress/public/img/summit/white-clock.svg new file mode 100644 index 0000000000000000000000000000000000000000..6082121aaf4edde418105326bb518698ad8abf1b --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/white-clock.svg @@ -0,0 +1,9 @@ + + + Style + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/white-player.svg b/web-ui/docs/.vuepress/public/img/summit/white-player.svg new file mode 100644 index 0000000000000000000000000000000000000000..b60a9873375c3137b4261596a43912c713764c72 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/summit/white-player.svg @@ -0,0 +1,9 @@ + + + 形状结合 + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/summit/wuyanjun.png b/web-ui/docs/.vuepress/public/img/summit/wuyanjun.png new file mode 100644 index 0000000000000000000000000000000000000000..9b34cc235331c6031fc0fa75f81b490596d019c4 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/wuyanjun.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/xiongwei.png b/web-ui/docs/.vuepress/public/img/summit/xiongwei.png new file mode 100644 index 0000000000000000000000000000000000000000..686d8e3742e96cd109fbd2f2fada2b5723922d0f Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/xiongwei.png differ diff --git a/web-ui/docs/.vuepress/public/img/summit/yuliang.png b/web-ui/docs/.vuepress/public/img/summit/yuliang.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe8e077f9718f23ec31c7dd59f877fb45c73f70 Binary files /dev/null and b/web-ui/docs/.vuepress/public/img/summit/yuliang.png differ diff --git a/web-ui/docs/.vuepress/public/img/video/full-screen.svg b/web-ui/docs/.vuepress/public/img/video/full-screen.svg new file mode 100644 index 0000000000000000000000000000000000000000..d9fe80d754332216ab3797e09897019c7ac82411 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/video/full-screen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/video/icon-mute.svg b/web-ui/docs/.vuepress/public/img/video/icon-mute.svg new file mode 100644 index 0000000000000000000000000000000000000000..28fef0592e9baedaf338a223d189e7d960c7b45d --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/video/icon-mute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/video/icon-pause.svg b/web-ui/docs/.vuepress/public/img/video/icon-pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..a808afed2c61ff850f224e2641992f871b48a882 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/video/icon-pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/video/icon-play.svg b/web-ui/docs/.vuepress/public/img/video/icon-play.svg new file mode 100644 index 0000000000000000000000000000000000000000..281e51314d8aec2c9388e0d4ac152495abdb997c --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/video/icon-play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/img/video/icon-voice.svg b/web-ui/docs/.vuepress/public/img/video/icon-voice.svg new file mode 100644 index 0000000000000000000000000000000000000000..e3054ed03767eeadc92c1be08b3ff0b7bb0df9c3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/img/video/icon-voice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/js/analytics-ru.js b/web-ui/docs/.vuepress/public/js/analytics-ru.js new file mode 100644 index 0000000000000000000000000000000000000000..df5262f170b5e2e1cfe82ee0c4d5db12108ad5a1 --- /dev/null +++ b/web-ui/docs/.vuepress/public/js/analytics-ru.js @@ -0,0 +1,13 @@ +var _hmt = _hmt || []; +(function() { +// 谷歌统计 +var hm1 = document.createElement("script"); +hm1.src = "https://www.googletagmanager.com/gtag/js?id=UA-181761489-1"; +var s1 = document.getElementsByTagName("script")[0]; +s1.parentNode.insertBefore(hm1, s1); +})(); + +window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'UA-181761489-1'); \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/js/analytics.js b/web-ui/docs/.vuepress/public/js/analytics.js new file mode 100644 index 0000000000000000000000000000000000000000..353e178066c2630ce188ca2d439f8f01c129e4d8 --- /dev/null +++ b/web-ui/docs/.vuepress/public/js/analytics.js @@ -0,0 +1,20 @@ +var _hmt = _hmt || []; +(function() { + +// 百度统计 +var hm = document.createElement("script"); +hm.src = "https://hm.baidu.com/hm.js?ab8d86daab9a8e98cf8faa239aefcd3c"; +var s = document.getElementsByTagName("script")[0]; +s.parentNode.insertBefore(hm, s); + +// 谷歌统计 +var hm1 = document.createElement("script"); +hm1.src = "https://www.googletagmanager.com/gtag/js?id=UA-181761489-1"; +var s1 = document.getElementsByTagName("script")[0]; +s1.parentNode.insertBefore(hm1, s1); +})(); + +window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'UA-181761489-1'); \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/lang.png b/web-ui/docs/.vuepress/public/lang.png new file mode 100644 index 0000000000000000000000000000000000000000..1b5204d3e6f2f3b2c70399d89ed4ae41af19ee0a Binary files /dev/null and b/web-ui/docs/.vuepress/public/lang.png differ diff --git a/web-ui/docs/.vuepress/public/menu-mobile.png b/web-ui/docs/.vuepress/public/menu-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa0e59a59327cde15d49037b5a01f1bee3c1f3b Binary files /dev/null and b/web-ui/docs/.vuepress/public/menu-mobile.png differ diff --git a/web-ui/docs/.vuepress/public/openEuler-compatibility.pdf b/web-ui/docs/.vuepress/public/openEuler-compatibility.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b699e63c8de9e0e0d2c9fa14080b6603d6e08fa0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/openEuler-compatibility.pdf differ diff --git a/web-ui/docs/.vuepress/public/openEuler-whitepaper.pdf b/web-ui/docs/.vuepress/public/openEuler-whitepaper.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3798e6b1323d69a2509f0e16ca0b15df760216ba --- /dev/null +++ b/web-ui/docs/.vuepress/public/openEuler-whitepaper.pdf @@ -0,0 +1,9246 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[19 0 R 20 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + 白皮书9-23-B + + + 2020-09-23T09:50:01+08:00 + 2020-09-23T09:50:01+08:00 + 2020-09-23T09:50:01+09:00 + Adobe Illustrator CC 23.0 (Windows) + + + + 220 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADcAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9Cf4J8jSzT2z+WLCNUC8 ZjaWyrJyBJ9NlHP4ab7DFiJkkijt9rd/5S/LuwtJbu80LSoLSBGlnuJLO3EcaRqXZ3YpRVUL1OID K2KTa3+QEyOLSfy0bpUZoCY7Zo+RVqF1QLzApUiuSERe/wB4Uksr8ladpUVpNeWllpdvLJLJCZtK t/QQrE3Ao5KqzMkisrdqjxyNUtskxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KqP1dvrbTtKzIUVEgPHgpUsWcUHKrcgDU0+EUA3qb2QqShWUxsOSuCGXxXocCWN3f5 feSri9t9Zv8ATYJNQs41C30nIMqxnmNy2wRviG/w4Yk0L3PuU18GQWaW6wBreQyQy0kjfmZAQwFC rEtseuMr6oCtgS7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUEk2s fX2SW1tl04cuNytw7TGgHGsJgVBXev73b3wlUQtuRPJIZGdJAtIWoUUrsSu1fi775Gt2RlYArkqO iOjI6hkYEMpFQQdiCDhYqFnCbdTbRwxwWduEjs0j6CNUApxoAvHoAO2Skb36oCIyKXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqx7zZ5v8u6LC1pql39WuLuJxbIY5GD lvgADIrLXkwFK9xl+HBOe8Rya5zA5ovSNb0vzDYLqekXxuNOPNBJGpRXZaVIaRVPw9NtsqyYZwmO Lby2ZxyRMdvmgV1kyykRTcIyOcXNoGJBAB+IXC1ofAbVGXyxcPP9P6mnHlExY6+79aaaPNLNHI7S iRVbhtxrUAHqkko7/PKpim2KYZWydirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirHPPXl19Y8uXNvaXkmmXkdJoL63PGRCkizMAR/MYx9ND2zI0+XhmCRY7mvJCxtsmljp Vtpmn29rZ8lisoTHEhcgNUA8n61YkV5HxOVSkZSs9U8NcuiS2uo3IuPTW7t2JVWMourfkQw+JqCC tBxUdN6+2ZGSA7j8j+tpwSJiNwfiP1BPdLleSKVnmSciQgOjpIAOK7EokW/tTMeYcgIzIJdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqAN1bTWs1zexyWdrAsnrG5ZYk 9MD4najEBeK1q3QYYgkiua3QRysrKGUhlYVVhuCD3GBVjiKINMI6sF34LViBvQU64bWlDTnBRx+/ LGR3JuFKtR2LBRsBxUHiveg38cSbUBF4FdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdiqQa95jfTpvT+rJcW/H98rSKr/ESuyHkSP9jksEoTyeHdT5jz+22rPKcI8YFx6r tP10XNqDp9jLGsETCK1aLhExUDiiSqGVQAKdMsy6eUZAmQrr3scOojMbRN/Y3D5oZokaXS72OUqD IgjVgrEbgNyFaHvTE4fMNnH5JjpeojUbQXS281sjEhEuFCOQP2uILbHtXK5x4TTIG0XkUuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVDHT7SSb15oYpZ1blHMUXmvE1U cuu2MwJVfT70AVurRRGOPhzZ92PJjU/ESafRWgwAMpGypfVZ/wDlsm+6H/qnk7HcxpUt04pX1mm5 HkHbj0IHTiFFMBUKmBLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV Q9lFeRowupUlYsxUxp6YAJJ6VbFV13LNDBJNHH6xRCRCCFZj7MxCj6cVA3SB/OcEkCcInt5W2fk9 s9DuKCk4B+LCBbGchHckBNNDkSWzEkUiPASQoSNY6EbU+BmXtgEuLe7SK6Jjil2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kse8yaZ5i1CORNPmjtH4lIbhZSsg5Hckei xH+xcH38QYRJBrcOHqo55xMYHhB8/wDjv6Us8t6N5l8uaHerdXcepwem81vEnqF1c7kKzdVbr88Q bGzV2dpcuAGOSXFH7mHfUjDCLuJru3a8lEc0STMzF/SpyHF1biQo7gDbqcAFF20skjEAVty2+O/f 8XpXk9SuiR1LMS7EtJXkSdzXr39z88IAHJqpO8KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxVpVUFiF4ljVvcgUr9wxQAtiWYc/VdXqxKcVK0XsDUtU+/wCGAM5EdFO4 tElikQgHmpRlKqQy70VqjoKnCGBVl7/Dx+7vv2xS3irsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVQUMenadIttbQCIzszssSfCOrFnpso67nFiZUQO9bcXNpd2l39WuR zijZGmjanAkV+30rtlWLUQyWIkGudNs8Uo0ZCrYBB5x8y/UKXsXrQBKO6J67Sb8fsrHvv3JzI8M/ i2nxB+K/Wzfysto2kxXEEXptPV3JXiSWNehAIHgKbYJCiyibTSeCG4heGdFlhkHF43AKkHsQcilQ E2n2UTRckgigHJgfhVQxJ6nbc1ymeeEL4jVc2yOKUqoXaWeZ72ZfLdzf6ZKTKUVoZEYgUB+4dd/x yWOcZjiibBRKJieE9GL22ua1qJjjvolMqKQDIIvTPQk0NFqeO22WWxpm+iKyaeiSQpbzKSJokCgB q7EhdqstG+nFCOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVKL/AMuWt9IJJ5Z/ UYj1fTnlRCoG6iPky8WPVf6ZDNATiYyFwlzH9lMsczEgj6gqPp9rpulXMWnxrEXV2VWLOGfj3qwJ 2HjlOn02LBHhgOEE/b8WzLmnkNyNvOdDg0u5FwLmsbN6D3ETy8o2dUAjZYzG/wBoLyrXMsRLQZAf 2PTdKt4LW1W2hJZIgAGK8RToAKADYDAQoKMwJSW+8rw30/qXN5PIhrWIiEDtShWNWBFOtcwdV2fD OKyEn5fqb8GoliNxS7zLpUWl+S9ZhtpGMJtpWpM3IK3H9kce/fJ6PRQ08TGJNea59RLLIEgMB8p6 zwto0u7uxjiXdYrhYgePXjyj33J75lNRexWDBrG3YcQGiQgJXjuo+zXemFir4q7FXYq7FXYq1JJH GheRgiLuzMaAfMnFW8VdirsVdirsVdirsVdirsVdirsVdirXqJTlyHGvGtdq140+ddsVQ1nO1zWV oZoChZAs3FeQLfa4qzfy7V3xTe1LluLGW3+uLNHJbcSfWDhouK1q1a8NvHCY70QxHegxpugTQfWo rWG4jK/C8Sq/IIOIC8etKUxIpNomxvLedpY4w6PGRzidSpWoBFfnjSql9N6FnNL6Us/BCfRg/vW9 k3Xf6RgUi0DZeZNIuIogbhI5nLIYZJIzIrR1B5hGcD7Pj+OFHJGXF1pj2csk80Js6FZndl9Oh6hi TTvgSl09/wCWojGFjhn9VWZWhjWRaIVBq6jiDVhQE1O9Ohoa2tUzsbmK5t1li5emSQvJePQ4FV8V dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqz0IOHD014cvU48RTny58qePP4q+O+KpBq HnC0s9Way+FysYd42kRZN2Kfu4t5Duu/IAdKGmWYMfGSL3+xjqCcURIjY/j3JtFJb6jayJ6bC2lU qyurxseVeXUCvXqME4cOxRCfFuELH5c0eLjF6b8QoVOUr70B/wAqtadcrpstMbW0t7WL0oF4JUml STU+JNThQqmtDTr2rirz3RdHt9J1G6kupmNzc3TtGLeMMkYlkKmvqL15VBK1qMsjhkRbXLNEGmQ+ ZJYZ/JupSWVHSSCShIKHYUJoy9RTuMiRwncM4yEhs810P9KI9ssOrRvckCMKTKXY9CQPTYAtkCze v6PFPFpkCXDs83Elmc1b4iWFSFToD/KMLFGYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYqovZWj3C3RhjN1GCI7goC61BBo3Xv44qCRddUJr0d1Lol9DEvOZrdghFRycg7ACpGJUPJdL 8u+Z4iqDT3Mn7JMEBINN/jkQ5Fk9N8mx6vFpskWp2/oSJJSOvpgleCj7MQVR0whBpOrhylvK68iV RiAg5NUCvwjepwsZGhbCNN0jzbd3Mi6gzWzI/wANwUhkVyjF1f4QtKtU9MmMshtbE4oHek31DSLp fK+oaW0v167mikeGJAsbFaAcaVAPxePjkZSJO/NnGFDYbMf8s/l8j26XV5FLpuoRk7KkFKGtCpAY 9DQ5GkkvQow6oA7c2G3KlK/PEX1UrsKHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F UntpvM0XqLLa29wvNjHIsph+HkaVQo/68ANppXjuNZUXE1zbwiJYw0MMbkuGWvLlIRQgihHwinvk tkJbY+ctO1O2cWpkin47tRCEb2LlA2RBZEUmulpqCrIbuT1AxqjMipJ0oeQQlabbd8kxRN0ZxbSm 3IE4UmMspccgNqqCpP34FYVpv5lWsgWOZYoRExSVpGkVtq/CEWKgKmgONrTIJ/NenHRrvVbAm9hs xWVVDJ0FTuy9hvsMU0lsvnC5mMfo2s8ER3dzBI7bkUoCq9q7Y2tMi0uYz2UcxcvzqQWjMLddwyHv XFCKxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVJ5fK9rJK8n13UE5sWKpe3CqKm tAA+wxW0RZaTa6exn+sXEnFGUvdXEkoCkhif3jED7PXFXzmnlnWjC3+464aUspSQU4BQG5ArTck0 oeW1Dsa7dJ+ax/zg6P8ALz/ml7J+UGlalpnlq5g1C2ktZmvXkWOVSjFTFEA1D2qpzU9oTjKYIN7f rdjo4GMCCOrNZyggkL14BTypuaU3zBct4JYWEP1ueeK5EcEkrtFKYYGcryNCVcoR9kYk2yAp6XDZ WNl5C1NbS5W9RklkkkgCp8fAAqAOmyjrgQxS1066uhBPBbzsYY1QkOC2zEgsDEaMOn0Ypeq6a7PY QFwwcIFfnUtyXY1JC13HWmINoKJwodirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVYZ d+RtTlvbq5i1Hgk8hkWIhxT/AIBx1xpNp1pGgSWkZ+sz+uZUKXMPH90wJ2oCT0GKEVFoGiwrxiso UUmtAg64raJt7aKAuIl4IafAKBa0+0Kb7+/hjSbXzxtJBJGrBWdSoYioBIpWlRX78UFiVr5BMNuk QuVIUftRivjvQ0wUm00ufLKHRrjSraT047sUmkf4qgmjUTYAle+KpbF5CSJw8U6Iw6MqEHw8caW2 S6bafVLKK35FzHWrHuSST+vbChE4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8o svMeu6fqepw6eiPardSAxoIhwp2FESm++4xtkQGU6VrGt3cN604aF2tC8UnKI8HXpxUMRX4+pXsM bRTF7Pzf53ubNYvSiuogoimdo2kJIA5c+MfHl3IwEppn3lmMCxLlU5uamRIPq/8AsSh+LanXEE2g hM7uCG4tZYZ1DwyIVdSAagjwNRhQ8t0Xzbq1sXs/U5w28zpA8ghVySxFd2CqKHBaSGX3Grai3lbV L1ZpBNFEzQShYRQhagrwZwfpOKpHpxvNV021uLzzRCsvp/FBPDa1QsASCHG52G+G1pnOkwxRafCs TxSLSplgCqjn+YBdt/bFCLxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV5L54tdM tdTvpzMZr17lOVtHNGHETxKS3prGX5B9uNPs/Fy/ZwKJb0yXyhMb/Rr2zuLWUQ+iB+9TiX5Ka/HR eXLbf2xSxfQpYrW2EM+kEoTyVh6PICncMprv75GN9Wcq6PRfK81tJYOtugjVJCDGOIpUA1ooXrk2 tNpVZonVacipC8txUjv7Yq8S0mOG2uZnkuFjuI3dWjFvG6K9WU8fUkoRX2yLJmcUxn8ha2zziUen KAFhjioOA34Rlwa+PthQxfyn5e0q+Ma3FtPIVAImigj4FgwHEsR79a4pL1rTIEgso4EiMKR1VEYI ppWvRPhGIKCisKHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUki8xaJO80c5aCaJ6 OkgAfY1U/uy2xA79uuIkOimKNi1nSZgyRzKwVSWXi32Rt0p74qhWj8s/VTIiW5ThVQnDlSm1Ae+B TaI0e602aKVbFeCI9JF48QG4qe21aEYVRd5IkdrK7xtKioS0SgFmFNwASB+OKCLSK38x+UFQfvYY mkZjIrKteXdm4cl3p2xSmMFzoepWk3oyQz2fExXCbenRhUhgcUoOWfyrZslsiQs5UssMIViFWgqQ Dt9oY0hNNOltpbRWtlKw1bipXjTc4qicVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVeSNq9gnmHVVuYp2eW54RBW+KqkrQ81oB0pTEiI5MrPVkei3UQjv5bW3kWdLWQrHcOnFqFdvhHf 54EMb8uaVfavCvpaYkZWMOZJCUQ12orcWrgAZEvTdFt5rexWKW2itXWgKQtyVqKBy2VKVp0yTBHO pZGUGhIIr164q8l8vWWvQpeHT7F7hTcSJJMkq0JQ7CjbgAHp74GTMzYX175WltriycXRdf3MrCpI 4nlyiZDxqT1NcUJNbeSdRZ/VNlZooUIIpPUrtvy5By2/zxpbZnolk9jpcNrIkcbx8qpDy4Dk5bbk Se+FCOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV5/N5c1M67qksdhHcWU8qyQS yCJ9wKMFrv8AargISCm1vaavBZag7WqRztA0duFWFSzvsF3BBqfHbCgljOkaRqlpbxRy+XnZolA5 NEj8iR8RYLcRJ9y4lLOvLbXhsnW4sxZBWpHGEEZpQDdA8v38vowKaTVyFRiQWABJUCpPsBhYkqNt YWVuxe3hSMt1KACtfl8sUq3JeXGvxEVp7DFNN4oaVUUUQACpNBsKk1P44AAOSSbbwodirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVeeWnny7hv760mvbcpbTsim5jYOV5H/fAC127jBaaZ FpHmR9TMywS28rpE0kaIkwBIIFS7hRQeHX7sd7VVvNYntgYb29tbCUxSTGSQOqJHGY1Z/UkpHQGd Bv3PscMtomR2iK+3ksQZS4QLP6kfpsGoxGX65dC4qRwARUptuSVArhQiLwSG1mEcjRScDwkUKSpp 1AYMv3jArBtK/M5HtEWaxmeVCEeSqqpqeooqj6KYrTK9C1tdXilmSIxJGwQK1Ca0qTUfPwwb2lGX MFxKV9K4aBQDy4KjEk0pu4Ybb9sKF1rGyRcWlaY8mq7BVNa77Kqjr7YrVKuKuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KsKvtAtFvhfX0lrbC9uxHC0zrHI8kqlI4lLqrF2O/HkT4DJC JPIXTG/NMdI07jYi5SSGS0ubRWiYRemzIY61YkIw5EhtxtlYmJRBHItpgYyMZcwwrQdQuwg9S7eT gSfQS4kI+mjVpvkYGwyyRovRvLczy6VGzKy0ZgrMxcsK9eTEt7b+GWNRTPriqXf4c8v/APVttv8A kUn9MVRNrZWdn+7tLZIEerN6Sqq1FBvSmKojFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FUqisNG1CR7mKb6x+8LN6U7OgahQiitQfLxw2ikXb6dBaqBCC3wJGRI7N8K7E713p9 +C19yiuh6HCpIs4I1G5PFQMAADIklGQujcjGytGNlCUIHc9PnkmKpgS0pk5fEAFoKEGprvXt06Yo 3bxS7FXCvfFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8rPmTzHZa7qltZTTP arM5SOT0iQx6kF/Uag7b0wWypkFhrmpahpl+kjXK3yW7yxLSIKpWgBR4wGr8XQjDaCGFaZceZLmF Hk1LVPqsm7rHCZA1DRlqGp2ORAZEvR/JNkINPmlZrh5JZPtXSem/EKpAC1bbfJMCyLFXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8Sv9TtbfzNqcjMY3kmeMhbcONjQ FRKGWM17qAa98izplvk6a31HVLhHufXlNpKlAgiSjtEGJjjEaN9haVG29KcmqWJUoPIGp2Fu8kWp KFiUlzFbtI9AOZAVSzsf8kCp7Yxh0TKbLfK0Ih03h60sxdjJymhkt3ofhAKSKjD7B7ZKUaNMeYtO MCuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViSaz5fhv5oL6wjiv 45C3FeErEk8gxNE3oa0wXunh2Tkanp6xTTCBkigT1JZY/T2CkGn7ty3atO4GN7oI2QI856FLGZLd GmdVqqgIDvvTrtWmG00mulXzXkTubdoAGoAXjcdB0MbNihG4q7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXhmterdeZNTu2tfWLXBUq8YYjgAKHiNjT3wFkOTKPJMFwL m+ieyit4jZSgEDYnkmx36YqWPaFq+nwkfW4pJQlKAXBRDQUoeKHACkh6x5fu1vbQ3RtVtpCRFUOJ GZIxVeT0U9WbY/PvkrYUmmKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV 2KuxVgq6N5ut72/eCx0+9gubh5YnuHoyg0XiPTjT+X9qp98T7lCbadp+v+nOLm2s7GSaJo0kswWd Wam55mhUb1wKSk9l+WEkSqtxqsr9eZjULXwpWuIjTIytlei6UdMhltxObiMvzDOAGDEAEHjQUoBT bDSLCY4odirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir//2Q== + + + + uuid:f544664d-7d96-4379-affb-eb90d5ca524e + xmp.did:673c0d8e-2689-8743-ba13-31c8a886331e + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:a4a338e4-0537-5149-805a-c39b0de2eaa0 + xmp.did:a4a338e4-0537-5149-805a-c39b0de2eaa0 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:62d1feef-b515-4552-a7ca-5e46bdebd44c + 2020-09-07T10:17:26+08:00 + Adobe Illustrator CC 22.1 (Macintosh) + / + + + saved + xmp.iid:673c0d8e-2689-8743-ba13-31c8a886331e + 2020-09-23T09:49:58+08:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\112.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image003.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-9.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image015.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-8.png + xmp.did:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + xmp.iid:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-7.png + xmp.did:073824fc-ba0b-484f-ba1d-4c100325c479 + xmp.iid:073824fc-ba0b-484f-ba1d-4c100325c479 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image007.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image006.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image005.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image004.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image002.png + 0 + 0 + + + + + + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\112.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image003.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-9.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image015.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-8.png + xmp.did:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + xmp.iid:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-7.png + xmp.did:073824fc-ba0b-484f-ba1d-4c100325c479 + xmp.iid:073824fc-ba0b-484f-ba1d-4c100325c479 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image007.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image006.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image005.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image004.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image002.png + 0 + 0 + + + + Print + False + True + 1 + + 420.000000 + 297.000000 + Millimeters + + + + + AlibabaPuHuiTiR + 阿里巴巴普惠体 + Regular + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiM + 阿里巴巴普惠体 + Medium + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiL + 阿里巴巴普惠体 + Light + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiB + 阿里巴巴普惠体 + Bold + Open Type + Version 1.00 + False + + + + + + + Cyan + Magenta + Yellow + Black + + + + + + 默认色板组 + 0 + + + + 白色 + RGB + PROCESS + 255 + 255 + 255 + + + 黑色 + RGB + PROCESS + 35 + 24 + 21 + + + CMYK 红 + RGB + PROCESS + 229 + 0 + 18 + + + CMYK 黄 + RGB + PROCESS + 255 + 240 + 0 + + + CMYK 绿 + RGB + PROCESS + 0 + 152 + 68 + + + CMYK 青 + RGB + PROCESS + 0 + 159 + 232 + + + CMYK 蓝 + RGB + PROCESS + 29 + 32 + 135 + + + CMYK 洋红 + RGB + PROCESS + 227 + 0 + 127 + + + C=15 M=100 Y=90 K=10 + RGB + PROCESS + 195 + 13 + 35 + + + C=0 M=90 Y=85 K=0 + RGB + PROCESS + 231 + 56 + 40 + + + C=0 M=80 Y=95 K=0 + RGB + PROCESS + 233 + 85 + 19 + + + C=0 M=50 Y=100 K=0 + RGB + PROCESS + 242 + 150 + 0 + + + C=0 M=35 Y=85 K=0 + RGB + PROCESS + 247 + 181 + 44 + + + C=5 M=0 Y=90 K=0 + RGB + PROCESS + 250 + 237 + 0 + + + C=20 M=0 Y=100 K=0 + RGB + PROCESS + 218 + 223 + 0 + + + C=50 M=0 Y=100 K=0 + RGB + PROCESS + 141 + 194 + 31 + + + C=75 M=0 Y=100 K=0 + RGB + PROCESS + 30 + 170 + 57 + + + C=85 M=10 Y=100 K=10 + RGB + PROCESS + 0 + 145 + 58 + + + C=90 M=30 Y=95 K=30 + RGB + PROCESS + 0 + 105 + 52 + + + C=75 M=0 Y=75 K=0 + RGB + PROCESS + 13 + 172 + 103 + + + C=80 M=10 Y=45 K=0 + RGB + PROCESS + 0 + 161 + 153 + + + C=70 M=15 Y=0 K=0 + RGB + PROCESS + 44 + 166 + 224 + + + C=85 M=50 Y=0 K=0 + RGB + PROCESS + 3 + 110 + 183 + + + C=100 M=95 Y=5 K=0 + RGB + PROCESS + 24 + 41 + 135 + + + C=100 M=100 Y=25 K=25 + RGB + PROCESS + 23 + 28 + 97 + + + C=75 M=100 Y=0 K=0 + RGB + PROCESS + 95 + 25 + 133 + + + C=50 M=100 Y=0 K=0 + RGB + PROCESS + 145 + 7 + 130 + + + C=35 M=100 Y=35 K=10 + RGB + PROCESS + 164 + 11 + 94 + + + C=10 M=100 Y=50 K=0 + RGB + PROCESS + 214 + 0 + 80 + + + C=0 M=95 Y=20 K=0 + RGB + PROCESS + 229 + 19 + 115 + + + C=25 M=25 Y=40 K=0 + RGB + PROCESS + 200 + 187 + 155 + + + C=40 M=45 Y=50 K=5 + RGB + PROCESS + 163 + 138 + 119 + + + C=50 M=50 Y=60 K=25 + RGB + PROCESS + 121 + 106 + 86 + + + C=55 M=60 Y=65 K=40 + RGB + PROCESS + 96 + 76 + 63 + + + C=25 M=40 Y=65 K=0 + RGB + PROCESS + 199 + 159 + 98 + + + C=30 M=50 Y=75 K=10 + RGB + PROCESS + 178 + 129 + 70 + + + C=35 M=60 Y=80 K=25 + RGB + PROCESS + 148 + 97 + 52 + + + C=40 M=65 Y=90 K=35 + RGB + PROCESS + 128 + 79 + 33 + + + C=40 M=70 Y=100 K=50 + RGB + PROCESS + 106 + 57 + 6 + + + C=50 M=70 Y=80 K=70 + RGB + PROCESS + 64 + 33 + 15 + + + C=100 M=90 Y=0 K=0 1 + RGB + PROCESS + 11 + 48 + 142 + + + C=0 M=39 Y=83 K=0 1 + RGB + PROCESS + 246 + 173 + 50 + + + C=0 M=70 Y=50 K=0 1 + RGB + PROCESS + 235 + 109 + 101 + + + C=73 M=0 Y=61 K=0 1 + RGB + PROCESS + 36 + 176 + 128 + + + C=50 M=11 Y=0 K=0 1 + RGB + PROCESS + 131 + 190 + 232 + + + + + + 灰色 + 1 + + + + C=0 M=0 Y=0 K=100 + RGB + PROCESS + 35 + 24 + 21 + + + C=0 M=0 Y=0 K=90 + RGB + PROCESS + 62 + 58 + 57 + + + C=0 M=0 Y=0 K=80 + RGB + PROCESS + 89 + 87 + 87 + + + C=0 M=0 Y=0 K=70 + RGB + PROCESS + 113 + 112 + 113 + + + C=0 M=0 Y=0 K=60 + RGB + PROCESS + 136 + 136 + 136 + + + C=0 M=0 Y=0 K=50 + RGB + PROCESS + 158 + 158 + 159 + + + C=0 M=0 Y=0 K=40 + RGB + PROCESS + 180 + 180 + 181 + + + C=0 M=0 Y=0 K=30 + RGB + PROCESS + 200 + 201 + 202 + + + C=0 M=0 Y=0 K=20 + RGB + PROCESS + 219 + 220 + 220 + + + C=0 M=0 Y=0 K=10 + RGB + PROCESS + 238 + 238 + 239 + + + C=0 M=0 Y=0 K=5 + RGB + PROCESS + 247 + 247 + 247 + + + + + + 明亮 + 1 + + + + C=0 M=100 Y=100 K=0 + RGB + PROCESS + 229 + 0 + 18 + + + C=0 M=75 Y=100 K=0 + RGB + PROCESS + 234 + 96 + 0 + + + C=0 M=10 Y=95 K=0 + RGB + PROCESS + 255 + 225 + 0 + + + C=85 M=10 Y=100 K=0 + RGB + PROCESS + 0 + 153 + 62 + + + C=100 M=90 Y=0 K=0 + RGB + PROCESS + 11 + 48 + 142 + + + C=60 M=90 Y=0 K=0 + RGB + PROCESS + 126 + 48 + 141 + + + + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 27 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 42 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 28 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 45 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 29 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 50 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 30 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 53 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 31 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 56 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 32 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 59 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 33 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 62 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 34 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 65 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 63 0 obj <>stream +HWI$EȳPؠ)u@\H;3*3{ՙUPTfdċW_m߯~ﻫ޼~]zu}(q +}Vrowݸ75P_ h ]3J{w1s| +oWrw±_h J.u>$/jO2q6G:PůD ^(uL(~"^'7sPeߺݡh #F)}`1cUxI"#NYx4M;D}X̱G?`F!D!s~*9 3_|~"NbexjUE_D=UijX,`$ 1jBoenHJQއ?޺[g{۟^>RX1zi XLg);C_Nbgp*)FRBkêM! %1_\4=-W*.ۢ88pҳvgx[pF:M|A'j>yc@1%21$Oܫ 'Bo#o#ޙFpŹn{Mن0 +U)+؈M7IF 6yAIGrЌTVlTOQڑ3cy$f'^#((2ޕ(꽗3JKHóJ˹ +&Xi9'CA)IJ+̨1XDTcڬ +CRh&ەVz܈}Z <)kMHP\BO+r;ԥ?WKßO9Z^cĬ앖+>=~ʧZڏWd< 1sy[']wa6Tffޮxe]-zx&،yLAvv%a*6^SK,= eDc@Ҿ 1 _RܲK Zb}R׎FR}o +E겤|\GF;C.ss[ׄJd`q \)pKS;v`chfJ mz38Ti򓑌KH NN; ZPĪ%fZ_@hN3 1vH #Kd&p H2LI0靲A(f ^6PH{4B`”B r!'*"8'ef +3N@@T}9@RO2VcGˑ@u5Ge +UdA0ziV? j+q*>#7 ިjL1~ kǚ> endobj 65 0 obj <>stream +8;Z]!0lFl_$q37tH]F2IaPJMXi92U+dATDh937_%MmHsFF\40%6l0_-aHR;?I"EK_ +1&+=#qG7Ge5(KVtM(7QFLl+a0(D.tfL&&C*$8nISOY8BF&TPrHqWF"$<&I +SdF&cgX%%5LF2't[ae!1:GN(ta.6*uR'-8ZeMR@O3HPBkk/bDm/7,%ta'k;+oeh`K +7,RDHa7op-E\,`9:>k-O?#u&ODk@uWo"*sB1hukAcFnELVt4c:n12&^RSM\ZD9i,' +>$g3 +endstream endobj 66 0 obj [/Indexed/DeviceRGB 255 67 0 R] endobj 67 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 70 0 obj [/View/Design] endobj 71 0 obj <>>> endobj 68 0 obj [/View/Design] endobj 69 0 obj <>>> endobj 15 0 obj <> endobj 17 0 obj <> endobj 76 0 obj [78 0 R] endobj 77 0 obj <>stream +H|nFzY MVI0dw^qteC, 0Z8 Y?l~Uuǻӗ_=\>}yz|ݚ._^^I~~w?ӧowo\6<=~x/Ϗ/O/cruz}z,o/OП>|˽qy<zI`=^|p}zfo/o?p㧇~x{G%QYE)-$_! +"Dj/A"j!Jy7)6eb7ѱiؼfNDfdNd7%- 7Ǎ +i`F@( +M*7(@!rvVvV fD>s/M\Ivl7e ":EEmMN],,q̼,A'tfCʎʎ9#۝loYԒhF}^y/9z %QXUѴybIAd'_ԗf- ;ޙ(QEQD-DST+:ᄁV4 f ++zEQn.*ȳh~ ++V + +4_:DEVD%\`xxpr(gEe2JDDe +"*؜x(xX]X)X9]2$Q]o4+k脲Sg:.M*h*)_6eT+ +-d{Q!# >37ԗQ3g&mP]CdITVQYCzƦtԗOQ96tѩ;7v D&^%5kY.5vfv. hzxohޠ:j +SmAr񌜴/~$]yӯ WL@.Q J+^w~bi`E`ͷzpc.u!Tb$Ƞ,r*kj }*AȚ".u jtlcwn=dt.Ebѷhc +hwѾ zZ~GZe`m~5j&mQ;])q:h@ 4:v4ȏ.w#7Q͝.t;ġl(݆[dN'**(2&]ұK+";wӥCD4bfQi: ^ӉBAԨQcG^.*1Gcn PhX-Afwz{Ev+8W+R\EQU\6VSGuѼ%i|jPY_w m:,76otFG%{rhjQ@KÊViǾNtes.*EÉ f*Ed!*.w{pw uQ΢H&LHA(x%Ge:HMe2& b"GFԏ6.'+Fޮ))*E-[w +Q-**w@u8"/"7Q!OR +j?hVKKFՉMZEq7tb|g|CMT!' +MVx̹/xA9D%^f(jY І=1aekE/H=IUr%x7zO{DvE7Ěw7CdMСBԢ%|./(7*QEascxAނy=qy5Lާsˉ譍Yzd阏&5Ub:ky`gfȮ胦Ȓ(-pvjS{שKGPQ-j&.$ ++ WV6 ꃻh4hCKd|7dPtEZQY11PZgȺuG7~Lj|EmRofRoD}EǬ4]Q:)'9dЀz}zYOldeaas]t-X0N@Ξas?t-N(b1b@&Y4ȠvRE-nD7)%b'O4D3AV&V߇?i$UBު[#1&;wټS:p +-CsS]\yT +mh'䔢[R-ЄTCM. H%1A[qLʗة*6)UdЀߵ/sBW;3;5ޯ7' +DyE'U6(Nt"w>Qىsg'NMXcM&UL` 30o&V%Nv/O}܃^,CkA͖""j9kqvi3e- +o"T!v;Ja%k7Q2W2 +jJ/ZXLTMyEieMU~lE&02Ȅ#jSUYLbY* eBDV;魈Y Md|WNgHxPY͞BZ=Q8;:uwQϋUdI{û̡ԗL[΃?ßD23(2ZxD] cdiD \OĚ=3:]22}R}}%q>iŸ% jeXX>D٧k ^TK-j҈NkLtNdUԛhV+jYZE,X[to䦦խ$$r(v:V"twQ?NTFeAtSD +(h2s6XKeoFeϋ̾VF78kԆM%,((rXD@:҈;E:TߚɯzW{E! rEҳnz֪A ڛV37B=dтTrQ 3zkƊ>QDv^p V*զRؤtsYEE"j2vs1U:CmhC4vzAOT(,؜uq**:~جdЄDA|g|]x۬~eBDu@Gd&u'תpIԓ(ɋ"wvCpM4ԡ^Dh'E5]*dЂ(rLkP'+(Q\CqnbAKAsZ.6b{ +ߠ3)iv Hb8K馋y)R$W[#Q=":܏YwvODH"ޙwhH==Ÿq(" +zPAͱgEӪnLS(2 +}ȦֺRTAM䱠E|1T(C"KDu1V+> (>^b4mLTU+/0Db M9Dd4tK./1{A֚EՍs0wBH6$CKA˪ōXTH$PlE7ºu@E;Tv◁ R)(hDd]chv% ~w}x4fQZngQԮ`|:`tj/4E r(IEj\DKݍT/9E!$IwtV$\9Aԡ. +kJ4ń$3df,Hs2%:UzREUTVyr*'&yB'ѻlI-tI**.ܩ~ӿrrHzԮ̢q4FhREO`±~}#TQb +]WpBpBSgQPz_;gjP:Eκƺ5I1*TB1V(AIlwtt:C*&jMxp./iu>\O|8|zzy~ޯot{b_QOc +endstream endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <>stream +HV͊Gnkc6&A6 !_jדK -$>GA0~| TuϴfFgf1&-̎=/vy.qK.sx ԯV-[6HeG`[ޭ# gcxVhuIJkqn?bhSxn(>ag &+=ovֵq. D j6cP{R0Wc>G>&dhïS2c~j(ƐF%nI.DPdO3A4A3Kccͮ _AƉ6bﮰȧJ)d^9!8pd{aw/(Ƣ"QY% d';[[OmK:9̦{L7zIâA#~yI`Xu"CctkLo!!tuÉD˃#֤Ȼ,KLGz@&}CTV;"Q m4 L7G2 =IXu[62ZiA̩nN.PWM'2>̯K0rVKV5#z-\Nޮ5K7tȑ'!ͪ(:Y .c/SuHmIRЕw6TRSxW$RL 2D<ذJT}_|Nx +3Զ Ek|R2#p7N'3>9ϛDՆ*1w"ݯ?ºc5,4wwk'۟{zrnBǢ◙#ӓh v{nC_37~7fqҡ 2UXΟX ,jN^zlsp.&|vLNœCA -J5ɝȫyRpMd[>~YK@=ԡb r +endstream endobj 82 0 obj <>stream +H\kTg*ڈVa2f&$3 I`B\$  +r/Z+VYkJ*^녮Ej`G*(E]/[kGKݳ$J06{VKale{>yh#׌ fl<4J 0X"O)W̩)UTV(AP-ύ +Ҳ9UI]S~%sK3+gSTL3 F7(0D1 +D`A, (APLj@h0@XI  Lvi 8 A<,>  @>@@%`n=$#$3r:LhW[C &d iFv"{}H r 9A!H҉D;= y!/?0 br Pu dp, +.o:k`#<Cx ^`‡| +/P):%^l@'4C.BW! +zE2TvMvCvS-# `l6Il$6C +1-X&Vb:[mƶ`bCgav;.bX6gq'V<N< ߄vo]_C )1GdSiD1QBL'fD%QE,&ˈD=XE!'[D3M!>'6,qxB%rqƉ'u?WSRިުޡ>>F}I}RéX*"b$CQ]ߩT;zDHzC#DF;hҕ;t}ЄkFh0ULkVkviZ5kwkhkjkvii{O0aPf͌e18f0)LSbʙL6ib0ۘ=~scW!:N:nΪJueuO z>U?]?CVQYߡտ2 5 7!ՐfH7x 9Pj5v:!l8;l7vmf?c[Si=˶]u}p1\hN\7p[w%2wusW'HI!WB@(aP+ KwzAx_X'4 +—ˀTS,Np¹vB{% ht8K.9xW @Km3;y!c*x-^9x= ,K0]u*N{Gz7?z̢Mz.S6N5z}lsw9LAw'T00A!x7%l$|Q Q05K""C1DU@{.!31cX~`d"#gT0z_E%e!ce +c-[@lbo3nqĝa|6F3*}XL|2)L~L!LmD3<4hvLEn=$4g$gk0#ͤoάפZKofv:K +Hw' ;2ƓqL/2'9YBY*#ۚl1wsϼwc~ BYL nESY X|%sX|cY55,ob VfʇƚM emk)ۓ䙓G^-릑ߝZ +YG6ܧЀ)ʢ#ټ-5l:8wi|wSb,?c{d_'g o-J8xb?9á[΢ė&'=JR:2s&Svh p\491;RZNy89}_J8O)Tpvg&Eqn-9| 7*Wsїw4#~\z8/q#hngsǙ;7{?QgD5꫹i<|#4T8'htq5OSyP?E!+yU\$ԙG+}&4C%H>F)O-i|, DΈA#1n~1,b&fDQ.[B'b5QDSl2;.>b_)mR^^Vi;HyIt0T\H4X/[S}%A{o~W$8^/I Xlv2TIJJh͓2J{KyR(CHD .ǴwoW# ܊ WLcv(@| !I5Fh fd#,٘93q*1;sL0w<+*DO|X  ! HF#Z`3F!|RTbcR^j,TP]@$_²X۰2X#C djV5"3 s公td! ב㋜)Zc=DD~ufX+֋0cc!6`llfز [S- }P]G +??Wb +{ƞ(j޳=ӱo =~ y\CA8<G\Pb(}c{QD4Nƣ| *2q1Nǟp2f* TǠp.n.e +7}Q_hCc>uzF84ա7Th6︝;f{z9x$t: 硫Gm||Rc9N ^[DX{HCB I6R8C_Hk0iQߙ=HE,~F/e4= rA $s"YDN'^o+hK^4DL}Hޟ*2!w4&$=dRF/a"v'2 s{Q4:hј#d9,*'M?9DG]X[&ZKAIw/rF+\Fiu\NMES,hcr$@Sijyy; Ӈ|no5%Z +(a8/PH +zGI )$e0))8Bt(n6)ffRD%Yin9 47Ѽ"%dSt!AbQ\,ŻQ'%iBOJERJؕBi`Z6ʘT>J'&RU5;Xu.i+b)#7Y*a;%. L-3Qsi.SxxZ#ocCk\ _-0MmYMo'<݃ g7F(jY;5LԢ2s}+Ѵu:jKM7x f"rByҠ*, \l) +(1*>b\@-111# \#ƈl*'B"cT +:! 29OS5LRV*?n{Oss*; +08jO:=O?-3]WTWga☀iqAO]ͫW§ׇpUV rax!8{*Nw„;ǏL'oqCo$cπ}0zOEZ0 ̫y*O߲^ p@ xRq"|ACLjypr[ڶ@SCgYg ‰.MgevFr"9/~GW}4XwD +"ge0=@Kx ?-d#A Bi'wrMGU3sYMQ< nVspǒv FB w lļn |ƒo`O?"\x7V0.wa06{Ud1~-^:-bq]j<vdau]pqn<#㝱k`/I60)mP8*= +J80XGM[D ]3[⠮] Aо nBq;j]zz/;`< ' 'k l0]ȏwShjjB~'bw:hwlj8S +.@NN¼uA^Iڹ#{A, hnBzѶ:ҰxO*N:ΩAB)}_e%Et%_y4 .-ԟC;~&W<ߥZ{B?Bd'H9zD?dȳ0$=}̎0fAW]+NGYED JpoUhQ~Q[cM`KX&ꃴWPmQV0jG (iYy.M=Q`6ƙo*euƦ-*#!;v!_,8!Y[eZ[wd4N.>u&n:/-2/r<)Rv QÉW5C0gRRQHKQllNpsڤJI]< +̊:Gw%WNoXRGGٵR5SKQڿw}$޴ '2@/</ÒjWp ٦$Kz cA:wlqś_d6!92hgV'UuF֟QkRp𣠃d8NXJ iCO[˸؀^hECuCvxL\*s98hq=͇V?F8W JmBb"r'F\{ 5+2Z)BfoX,rX:5~RQ\rWؘ(w.#|{h)e5Jm_ s8\F_㱃 |_՝l,$2G}<v_La-ȯ+`Fץ{1!x Tx9"dAҢXXLt;pg&:B[݌l +yRqt!gIbL ˿'6sQ^(x~>#=I#)E8$B&7e[K6bq`:Ate~zf'lܻU^c̺B,\nULVU` Ƒ+B]e݊M~䞋Ri#_ޖێ1Sh-rQ(ߑ*kQ￸(H_]2fwb -~欜ֱݹUlwA3]7* *b98޶n qeYQQATP@ ˠhIE% BpDâ  4J*N2:rns^OIR55չ{{LCSJXLn !Wj;ņ'$;뙸,6+ZNxYrU6bP_x;{؉bu!9>?qOIN|c[64XCjX,ҌI_Q j'cm1o9IxC.}26%.ήDws 1FM% 3e otXE \<!w 0-=V^|j|2ڟkg;=BOeY@T +@(Ga6GĤl 1yBcE: [YG]s;"L4=lS“Ó׉xRm·Ft2"r.A=w+|适Eq{.9R+ϫ̽ J1f +s9S6Z3weaV!ݙX D|O h0J%wɣH s5קE}9*Dipћ@G"ƚ,C߰NŻsJ]\ҴPqziZnY"CESI}oygC7(?˨:x@s}߽7r0'|u=Pc :0'>5*50B- t^4Ǧ<۸%8ģc;00KA. dÒŖ]r Ȯ뺙&;37GH +fq6Lq7 x_x#CC?aEzQ-n}[8vbQ9t(V{ ہc\§qN7|_´o WZ>uq +f[%yI{en0ȥs_9?lr)G%eU-n!*jչ? XUTh)މ Rן\䕤\薻\@h4xY[A[QA>]ݷ_pm#JPxsI@h}Ü"$ͷ-A hVuF2 +}21hm{X;# P* Ld!^ QDBfPAphQQAEAasQ@E1.!D.#"1^dzW~u/ް8w]Pq~gR8-zAw[L Jy_r'#q_~A,v sĚY +q#PE]?#Ibk,-Gd$׼ɡa| NAj:‘rZov舌ϩR +A #a#Y2q4ٝX諳e cJ +=h+I|Omo. 7Y + ųuE@ØnI.*rh`L%#;y璥ht{htv,m&QFP_Dvv,X62I"$Ee߲LF +q@2^MfR.]x !*XM]Y%[u87pR~q֝mI0Ʀ?3ThqbZ n?7`pP[ +X[+&W-rrV__ ')k[}JYU.h戞J'g8NFlZ$&ٓ/ll(-/,,(,(}(f%D LMy((#խ}W|N+ j=<ڇc.L`Mt};1} +~'rmX<?%W>0)L/T-݇QoGcnۼ:=w'K|dsnB=)Mjhe6gx 3рn`0%fxfR-:Ӝcew- ?bLrh`'8O`x NPs4d7ʸEF>-8#i,a1'dh7-C& +b'jo餟k+]^_Y7s&(q+8aa+(pİ +.h٬z[l-ƫ@/ ϯjR69|w?ހdpcqxJ\AW-%7vc(a+wh5p5C x,*-7 uu)'J +E%g´SX÷9=eO+ tߧ7e+)8Qp"tiJ>uKjf&ZogzD&]Vl˧`-om;_t{y*V,pOAE9^TUIu5$^50/q+:Y}?ma̦<_`ӳ`q1tݜ]f.9{ֲ`HegYSvm>v>yNS"#ސ[ 5n fɿ$Lcʆ.<g`uP{b"oFΑ\z+6.-4̈́G`Ic?jN=tPZ|]E|aeE! 6ٺ(uWx˳%0| z[z6NWG ~9u#+1 )^bwqZ;8tJ^&}bFp/c| +eKq=oD_PK yJ}m;Q"\uetZ>V}1%R2WtiJ<Ž%xtJKIcFJ' Sqٶ7ωf֒e ^h}KL^8܃3T} 6 g\_{ͩj̼O|>h+qF|4b;uP˨֬nb_>ꖸ`\_qMAܨ}MӇpz6ޔ<(k .qJ7aT #H QqaW&" %:̰/ +PDIc=_;=uw=},¤B9PK,^@#钛*#!@ jqoRyB~S6P|G:4ZxU~zaz)0g%ƢJp.@sz'oow/B$\&iҳ/dYN_O Ƣ6j +\)LW=6amcWL赼1h7m@hw4L鋲kİ*}~ +XMF'&¨Rp}wa$u$y/VN #yP.[DR_<|θRť{3rZ)C[\VL^f߼2*:nӜHٜ1 3,s@+F}wyO < XSb?h,?8nh.oa?RzQʷE;DS+v`ǻltオb[s)>CO;o +^k4O m +1׸}EP 0+&7(|w?x,ЙfUdef;fa 19uԪYx8$.UpIA ,]Vrn_Xts;IޘbqJrsO ۯrC Y܁(H[{ZAFjYfS@ʬ>mSSAΔR`~[mp:}MsUKE?C0rq'u\qSo{.]πXDP+ `5X@ F)QgA 1C5#N$ͷmBO}KUn?3Ș%WY׋;浆zW<@B~3O#JZY;\gs|8jFVT,kVx)RG A bC8KۂhGh8ETTyS\lWTQŊ:z~@  Qݮ0@!1reaL$z'V8 KUC0;\8s9fc+1}ǫ,IP|<㌐P8ѠƜNy((+[~"758ih*mZ)45UD{hL#(11' 13i41 OL8 >fakJ.GS^;3mߚ9o"q\|6>Y1YnTҲ sa 5hNKK24T.!J^P64m)|r+ӦVɁ;X-eYGCb'0NwIݒ%G>d5= , +"{{hu+ħ wET-N_\O+LUs2*.b-?eŕ JUqTb"3Dq ֍hdXDD= 1AL,4B,ʾtC71F̢''řy^SU{WP'Ѳ` vIDi~'`8h&gsF ˨"`= Mh rth), tJ`xJP`BCЮ^nᏉ_?C v$>2FBp<lΪ[ZFz+I5zs RؓQHyC!EJ6|J$[ iԖ 3hI8,iIe>2 pŠk+~NSYUXm53/Jq }$;>*NdgɇZcb@<'lj5-#./ ߂(pY 2WO jZGZgW="[t( Onp]Tʚn4rbF+J94H Qa]ә »Ĝ=P_vDC.- + .!.}H=c-Ac'B(:i +6sQ]=-ܼa%YB+~gNЕV>tTt4|56fP>]lQqaISĺ ;4.h۪:4]D,d@Q?TMũ2ƝFS|+39L}^51\fiVOfWqղ ·}o Ls;b c\p_VseϪ_wsu辷=:OHA,}=I 0ҿP{q2r/᪵K:=Yʖ?Tt#?a)q-MpV&0Ǚs|kld%ZpJgB Ìh*}1lH1f]7Ta}6Jbs] %9DM +goKy^_(Y +q]c!}[t¦f]#lJ3k2k"!XǴ?E\,^|gALZJkUT4_:|PŨfrъ.}{` +В˧llm,Gza%#ȕ*{ݕq5%׷ EeBUJMa[~0lwe(`nY?y}ڇ۝ vz/}c"y!8]nVaM3:eXR,KrKr/0Pr|aتc&} *`l l#9v(A؈v~`BocB3fV÷] +8,?m9(. =&#}U / & ++.(32|еѦ ~C`KS1O 啮1!!]BKOmuhOGaZʇe|P( Rg,Pi|J.3 6>hQV.DܳADL p4x 3xWG[́LSF@7\q;PWSL]:Ŀ٣7nնWwT1FT?Gw8Xߵ4'a#u+q|"7XY )h:vPHLH-}Oo5KKr/ @6`GD-Gs7S+ ߍqqgni*lM?JmKjTunq[IG*6}(|& I9\ҷ憶G"5|հzlyNp;s0j55 ;ȟ=x&2)@qUkilZ`1iWJ,xzt,˿;Tq),8VrQ%]M:Lo>snR gVojٵY=Y$6#\4}}11#/s dfTvfdug˵7҆j*hs3,4tl2WLi''* "K‚R舻DV(1 +݀" "rhppM7Ђr͈2rvs(Ƞ\"xYe>7Gf;prO( M1fEH{G2G_b +Ϩ.t"pהUmTi]YWM5ə;Ҏ(R y)I}iSgK 1%l 3~ V\$?~#-K:lH`ݠ#ٺ#p?*QEZնTyTqXync) e9DJՕU4^g +S=Og~}}QKQKa{EwQ&Ύٟ!NS祑C;}U +h&GplhC_LWRRƠN3/^Ġ\XU2C%@? ®BHuRU\,XE߾#^VsũSȗFΎˎM +MQ䥨E[ N]C#~.-!@&gv?/\u)ȻRA?wx1Hiտ6Uuuwtl;o>'pϺ4 pB"2{쀊ɶN"TQ&)deʐlݗ Q ! +wП`8MU-;sb"۶uՕ+Ex"R\=Y} z/`()ڴ٦}y +4ÚuHx_`ZQ- Mm"|FHp `UUx#_IѬΰ9&Euokk #F1mzP K"sC)<zr\zk5i1tkR[J!+ZȃZ]+[*D-Y +h/P3F=ԁ% 2w湊^ +7z3ug}oG\FWk]!Ðx`2C|N`/["0f +СМ^L]@4_VIMϊ86N6AYXW\W[7Ά0_1ix$=E32`2aLEUև18~ f(܊Fqpz9@@\dȤ?ja!xӎ_374kA@!y/_0>] )C 3H1`g.vLvP : (5= Znc:_O]lH4 raу sVX`N7"ⷷa=\ ,9!7t:, hyFhݎeIqX]{okrú=S$bC q5Lk~/G`>=zݾ#duw@ uQ;lB; +dxg0eGڕD4sgxwfV h87V0I"i'1/`/T?z1zd~Џf xa\81x9fIF%)><>0sr 8/lj ZuiCɰ} 1>,/cTU/ڲs~ZP"$PUi5QWVqQiձ f V:_I0(oN(|QNߜ~B 0aȡ=Om,.^3Aӿ +HS4dTB"LM0&h܅I)iB +Q3K/gւ>ۭ^`zqQ]v(1V-n-hS]APLmʔdʲk/k `Qyub3m4Q 2>jyá/xr 裉'`jKVg馜.=kJa~FE&$M2 +8)Й( 53#lcrFEqeac +q|Iu4h2jak@@dD1 +BDWffT";(&(ND%qLsÓ_:w{w1?'B%1?Nhdf/b'IN +QDMkaA#P#(Xa#QTvUm4*TD*(Y+=)X'm9ڒqH9rejqzhoN`bH$f EC'{;mLVY;QguT2͌M:ReW?́)r4j9A7=g㣜Rt%v݇.H`5B iv@]| |tB1@3X`3 /b3cTȹ +ܼi|}m3Os3a cI;ہ;[%*MZ%({`7ә޼_ ^u #]Οq|50Vv 6W+÷)dk^uut8Rn +e쿳f^s ]om8*"UPjxRZ`z:IJ;M,? ib M,j ~IѓiԱfJߕ%f&uĘ%JKnLl >vV5q?'z pЉ=Y^)\ֲtna2F2okdk%"K!ע E+C+OSϐ =*nǗkt4XiFccb3jθMBaZ +^˗qS1ü^$4/2Kz?׋Z J@K^̘$@qpF]JJz Y'U\=pxf:^Rv K-x0@|\.<0@'<ؕO`em'AcЎZO,{oak*WD}O 0zGacK ROh) x r\{|`)Nă4@Ml@a4 +lcd0fewMޯ?{ִ/MU7~t!u_y3X6m~yʨMZ:J?0Ft#˖]}|h8I g|o + iϿ9I!\ #8Jr+;q)>i|DӠk˖?).п}XG8j2!J(9xʂmYZEK1ױul IG62C7R}a8_ZZsPafo3]2C.ktG &fz2j?蘱1`UU*r#o_J;r%5|i42[ʲlR_F9\ZJ_Ӈr=? pgtyƹ5g嶻Uawb2fFRߺ,:L|z7)ܜn'?J.1&>Sߞ#ڶ +0I.qxV̨g֊YpStaLA&PُBA?H6V<K CcS``De6Sb +qt紖nSΦ4lX..d©v~3(Rycf;pc3t#)<8erDڢy!_r_XLqHMoU >qmH3bPo(e]VJ(u')D+kԁVAD pLl'KGϕM9xy0!TEnNR-OcQZ@f=]< rxdGJ3&.'F,7Pt{TG^WĠskF鵛OXы+`"i4:r m)焄V(Iʶ9t5ߋ83oxN0=O]*\6pzQ4RXWֹ~M18@u'_>˂Kd_zC<.Tڸ4=DC$Eo[m\%&O44tU_g;mTsꤞPTA,|mXzQΠOߝl,/Xr8"w岵H[ *>-쭆Z$ctQӥr>I13/ ]~-in!avFf>\hIϥվ5Bx<ĝ*WDO/-U~hnéΘhR4U{e%el==A"hgp:Ofe`a+y֒ +ZZB{397~,X.j(s; V0[ّ +WHR;fE{!CW !ߓȝErXbQX}y5gs⡓kp"x 'ڛȣ.$*EW;6,:F~)F}#J30^6g1AK./W*$ϕ$U#bʷncB;8,6kV )(.}$@ӈ6;ߠ\`ae.mʓVZqKEu$dYJHi]`rMF娻Hp&EE\┙Zu, Z{9ݠ5j e +-@fA쪤Mdi~|ٓj*}}e"uں$$.:ztǹbQd~A<fJn\,-@JzSp؋?RryTSgmnctęX;2TŎKk$,AdGZ $PTPQ+ REl==Z;}yÜ<{]y^rIﲿd 7J_YFLVK<*^ZP >j4\dNʪR3=㚉8رM ; + ܵy @0 8x42U,8L%?1XC:$iXKC*\NGf׼/gw˭Gk~vFcReNC2G%/$uy Od.,lp4txC+ъ ۸J9pklug%.=.tAn&@-У BaxᶫЯuolB7O?3 Ȅ +(Џ&d9AY +^QnQ^aH KƦ@ ,1=Q]@~Dۦi2*,qzne(1Z#O{ F')SP%((ƬI> `ık;zO(AR></2`jyF"k%a֚O{pz\\ǤlkkKXWiPSYFڼlg~3/QBc#jBvPV%QBF E([,"6 츦mqԩ97ޗyοS{ν_TMUg;UW( t4jxj oΜ+{w>>[P'[ǚP(KF >U@*K !a<}xo166Y9RȜZcI0v_o"rloj+ug +{9,M~P.N<"HEy 8eF!sa[ccm6>i(0.$J20.*oիJ +爸% ef>@gir؆7T [X٤Gt|v؜0!Mj;f%=6UyLXCH~hEbzȞ5h ˳ HiwPnԷMyo~2s9b]g<6>~߻7<6k$No73t/)pꂱV!dDYmIMqwݵ~oSߨmJB.ORٸc\W` g,ymq$f.3]xŴeF$ >nBi^m}ˮtA+'(&i 3#ͩY_qhf+\ >/pbuqȃƇb+E8ANj*S3x̭!P1%8 l?*|`^)h`?B iv B [@T8|l6ǿcܾ ޸(Bم:-m"Z:x7qōY{{]`(G{vޝLK/nsuȦڣ;asÿ]@ꡱv +- ;Wz/cn^S['5n<rb*[؛ӗ׫^P_.n+herrbd}qXA*KzS$,o~Drm{`}'n42 '-xff"dr-s-{?HM`T +Wp:owE6lD**_bvƀ_%*[27+Gdydd15. +Z5qu*?.z4;IZ$&h,1H{G';a%`',A'D]Ůz&92OB=D}urK@BG>e{M2%è4z,(8!`q+Eؘ˧|=gٵ`I~BF\͞z0SxvP6lԡ*"O~ I`$Y)[O"OK>FN q4xaW8_OXGUSL% +/zWk+Tbܩ?9]LPt<6 +M}ZClMOJ=ƔgͺIq+q 4kvWCqv#j2:u0H +]*ZPe^;Y(g{'!2  hep5~D1] +ϚR q6+jv +=1)L6w=}6ՏduSE{I5_d ߒi>)a r1` g +CJjl3(qWj0|30<)YCgO\0B8 nMmih}>̿{7.U ׈wkl9Ť'S.D`JPeZ V׃yyM&>U –ѮQ| KT3Lÿ;l$2Gנ[j;bCz>݀ Re㾊YojS)4ZM(^*FQ/&=~G] )A^l Z2 +-Cq6rkhw!L,Qh蘶Ug㖍̒[#5ɢh]~csFX ȅPdpoǠG'I ʸ?XҊd@!;NhD+ k}/.PL M=h?/in')-$eU\x?RaTUBޜ9MO>R}y2:_ ý~"5W}Uzd;D^Upnyx@Y.uD]T00BRVn[BEW6ah;aQ 'r4h`NYwwS,W䐔sp̿ % +%BBG0, +jB D"-DpN`.m׃"_:FOf^oClġYԫxwANEKBs? h++luI2".2ő\Os"RSB~NKO3 +;F1duXbmQ0FR;=lrsv8Vܺͮ<Ds((>XGr$_JsGC:|@=cM֫pWn,'^a.XM\{ot$Iicp=612}\_gKF釓i:by vAsrG64,,@ LKnP@|"GZAUjw"\3of\Rߧ95/"=^/uJUqgR*9muT14{46? S~ffIfG6gsKQ碛ԌVMA&zUqk3 ͖P>B6 泸ETUGcOB?L`?笷* kJÂͽWSoRQFk$!dQ qAp)nP[ R8ZA"( +Vd 8utQw2Igc~뭝OZHuHrr%ǮD7};/0pMml+c bC=i4x2Wi`K4Hmf;/ά9&'; <'x |$78F\!{s:\y? 4QIb녣 +3mXA=.ܓl(ZGt"'4P7'ENWgMZۺv%.8TswPX&ן:w!q8O\3+aDHx2/qb_\%A%999{vHS!lwH߳!M +bZ@s;"k9fS]^2~ <j <%w i +uSHݢ0@O&ʖ@`}]Am=79% PlTbωg*fl]dA s \L ի0XtW*ks~s/r]i)sy]B{#O>/Q{]و&om)2 Y" +)2EɁC;kcq6ː0KĬTA/3Y!0nrcX@FA1 4Q +d.=]N&XisJ G2LRPS؜w-O4o#s{m>fBTpܫyӱ;*g"!ETRF/Lh +JP4B`́ ~-a-ћIة:Vɍ%KNX!qdKSӕ.B@K]$Fqv EܳywdWHƗ=4Bf^>\A{}Nb8ݥrCKr$;L\G5-̨s Ji Z'=dB**TND :."*?XaY5wJrj sM&.ꡒM!:O,<~Zw40쇹-mE0.dfc: 'aHw =Tʫ>¨Jmt Ā+zڂqh=ev4@Ӽo[P)M0Ú*uavƈ̊#FV凨ջV:[4nWz.ޮw_qUQ-AV0QcPwɜeGVk5 Mf| batWMw +im0ǹC.ھy.Y?># h5}ګ+P1"q8?026`0+3-] @ߍzP lD7B#/Fo~tޓ]'$^KM2~["?`md +~v4c9{0>0fV86N%9X xR;~6@cI]t 1)v GΚxnu˃B^g}qVo2{ehO=ɐ5!OY形ǹOk[osZ촨Y%lc AfClv\zi%'O@a_4$RO_bP?lJ?s&wrFu+{w-g0AhxQ#G+SIbbٵ'iVn~V2+Rg^UX:1,v € is}mMm_KqEsAQ~A>G+&Bka*>)]-> 1.\WaV2,?v`8)=^V_(n 6 T+iZ]/+Rhx_8)#|`* ((b{8T,To(JQ"#;AEfz)u1D,a3'`dlI..wqnUFFo.ւ$a/Ɛ[Jiэdgʾ=&&De_{DXYi>$`VpYy.a1=ͧ +oCKݓWIJea7^aďyKQuO`I?Ưi9,IOp`ZLw?mpOIJMNٍu.ahOϵKuqHʩOˁv[KpgHT/3s["$)8R0KSVO\mKKndje oi9O$>A͊,T3yFIuR&[shz\ +3P : GM!Fۤ= +M+歷{WK2qE֟LߔPuseΥ+-:nyN|W0h h a t/ԣ6*o&[U+tGA߅z.i]JOhye/٪嫵 7\ V>6J+ZCϡxX:Z[ +3.+]g; kʫ+*NGa5)R'{|T 3 + He+O4 p;KXֳƇuGi8ZlteaU󐣝\<)[)CgQI^Cs +68@qqSpWlilllh tJ7eOqBG<_pSHBXBD7iqSm( o(YgR hl&MbCcOYojss;i`u8|Ã5B-pZmLLRe fTg7f7eJYiw`ܚ8ә/890~~_8P;Ԉ#1IJ}CpZ%PsnQx]a BrZpmXSܨ Es\AQ\yWnJekgLj*Rh<dF9AV! +#rAFnE@":D5;$h hkl7Uu}~QZa)밁{w4uhGwo8An Le&_nߓ܅ƊosW'o@2b4`aΣtxNS%3voґb%?Vrl2S`pC/gmUcQzt^ԭmۣtq gyvaVG/<;x;n?p&n'ym51.ǜ=9 >ld0%~p=+e\,>gwIbj`>ɸ~L|(Ie~BWrĖ/vo_͕D-[rۥJn(VEj5ܪW䆤H۳Uqim 4W}# N:ǖc<Z שkm`16!-6|o.olGC7/ f32%=j ]x60_ڄJ(u9rRn4(\u#*v/_O7g`m2\sr^ +'eΡJrlBmX?1Lߛnq S&Mm#?k@n#4 lp>sy'X8Hb$aV  HXX]e`vމƝj&^,'~ݑB࡚|CC2Ii'O-NP4FKm{sAp8+lAEҫdd<<#w̓ɵnun<ڔ +-ptbo~^_S[xsknviѭsub"4a)vx5hiwMYٟ~I^ZN+&c(Sc"tUP4=2(AG ) e/Z1T1 q'RYG+7Ҧ]2Dﯴט^?ǣiǖ;NO888JsD,eJ0W!Of~V6vZ8,'/ Ci.t|}'4QޏZAK Lcfk?ThUgޠ^?ĩffY)Z4` =``w&he +!?VuEX?X}^ +f\F!wc:iLpHN^P2HAh>V$CPl'ER9謁%h"`Sw.c2ӛ(ȬȌ(hMڗY9 gs9U^JM904K6#'=Kf>saGDw|ϗ,\¸fZeם{_vza9]^3q7Y457bakcAhP=}4$t:^#G è%f-WNSӯ(RImHڈ~4t7o(ou&M6qWψNZ9BDAA0͜q UU-%`oÕ5lmu_['ˡWbگG_٢m\Fg<3 ^tĎε_QRPQ1a A@Q64*Zk=Vqa YXI,1싈 vc3s{{~ϖ??([w~ba:x珜~|fX2ISլ`݇&h^eu P(JBǀE)Y3q=VQzä37?Y'n0MJW~&[.B'#t5ٚ--m 3$ tI]:x `gF`^].ْGΙ'x%K16M:1.xډs ɓ4b$Q|6N?/i6cqv9A׺Cv?JUU&ZԪjyT\SUV"|]6bl|Y/`|}$$k%&ɞܝ1$_*Gl\W'lXp3Ra^sfan?jC)yPiYMo)< ?[Rw\(6MjȲ/ސ2NAmV dT,wp ƭ!DdČ!Za[)eg6n.6q'>QXP=b0L5fuZNSWG`n׫cOZN5~%it-5Mi[z\mHVU* LS;{e֚i[>͡dg4[nt&)AT+ LR8On~)B^6!y1/VYWUT=í2CxV K$[b8{tT+WHֲMU@TJ/;߯JN$Z?{ɛ2_[c:mMHZZj#y+Y5ʪ +%aT(xӷX}5p/.{ _P)UʺoXI*ѴW]ZvR9;@|[!E !ėTjqsa(^aSTH9s.0]ǐ<f܈ې'X +m\Y¶mxQt_GygȄәbx,_Q@*Flp9Df +j:'(`0Av]w& +E|ۧ|y +Oxg4.J in<{ xʧ]TWhWYi;: "Ϯ8v3zj0yqBO5,0N6yAT~ 'Җy$`U1@ oǰP{v% Hɀ?Bq-΂^tؑ#>. j7; a1l|]v:'`9CbN>z{FSv ArO8{QU +o9r0=7`PRt4Z{$z:)-1sރǎdIc~*{UTV $ 韞)H +bH5_cj6LM N`Ǵ~M6])/kr.>eAAq ɗr"AǍî_,Yiζ'nExJ"z,Cm tAzYƸV䲘wvaFyFxNo.ĕY x:]xwJ?.&ȥ Xs?*~:n9צ3kW O,N_<{E/=);ʠ萳h\{JgB|4je-odK7-/a +™1XN{ LQ% ghDAfTR N P'5#ِZ'©xcDe<ͯHHZΐ".Ih;z\~MOZ%SG[N[Ӭ&іĆ.OM;H+(T~OM%dP A{,p}4LL⯯I^gUSm,`w4i`rarc :9Ƴ5'5+%#Y>%IeWIZvmma٥(_Ŵ>b]:lLww Fi߷ +CAg}ju&#o"*0>ZVWꗭmm7o&pbH$9EEcX= udksXJ ,AvpD[ y~).T2o%kH̔;@T"!pKZ nD[M_h͑k]W +Ki+il\Y_1p̕ɜ4CApeaz[(Iש5|! +┱:d8'JБ5x| !2>(qR0}6y6F! 0̎?W/s]\!1)ixA+#1mv6P$bu`h[-QVkkL2)qҨxsK%Ú I7Y⢵'vypi,V I8xG <:NDRyg~V|Nļ1K;ʵlo0i;V +LFm6%ah:Ҩ0VΓ)ޢ_Bԅ3ƒ4Q+qHVX(S6Қw e%FV1'Mςٚu =08x )1HGQ;!J=r4ƕޜ1NU4QhD}+]k+cʞ-/-u9.yq36`]ΦJ +rȠ>Y!tnG +p?[舘Kox&5g BO,%!DCK;L-q9Q5D ʈ_5/;n1/klF6* Xʩ"eB|LPk2Vr[[2 n 0F[C)ca!5T3>F?3ʻRKrRP3_M/?f93Y\糡RGIQXJVW>r70 ޢee% (Ηᾗu)Jf%ftCL`.cr2;I?g D2%-N+R iwjB֖ͪ 'a91 \j*BNk(U~Fi/!~(i'҈y ߕy3QZ|NB[b 8 $H@"~Qpʱ/ a1DbgYdqy ^BX|)\؛FV:V^35el*,5o^pp,.̑s +Yuxpw wJi̹qsL(5"MTɮҨ(,~U:3 %.`rsDMEdYMAQTTP* ݀-J  +i6% QDg5[5ș_zo +} +:!J!훟/lR^VCQQc%s.j\%2q: \UU\%?Iݵ($;Bm6wM[12!u;j:\8(D[tokXWN%SdGׄHVTzUf$1GSjH&D&F3\OAN>-wgNRN:;2/5?HjM+R9~ pVe_ + l,*()Ur !K?0g;Wo*l]`U + ms*űx}/[ad'XƧoC\KDWKN998FYi*1;>& mBcqx^DiCMlm>T^HyxhS1Km)hvx)fi4P#]Ѯ\8}Kb1ӯ}p*^샮>s);9kř.X61=zX;fӛ\銴<@)8^`,;M~R~l~;mF<)0:;;poNTp89@ä(^~H`G5V;*.]R2Lz>VSMOSk6*[%[ӻZ)8 [*?T7sOkKk6jk|*=sܛ ?]^~*CXx !*Xu嘼xOrrw|J6~QП4e2J3{Fw5$3f8/ V@w89aZ!7^O?G{df[o V χdR_[QVUVUR^R"Sݝ7zѾK*}OAx>gstڢ S"Jq[z_n6_Vvg_PZڽ_(,CROP +!Oc2dKsͮeGR.`8̦ +>F%Vq4 |r?;|S8Y$0;[#X1+~r\ Б^랧8`ι3#ۤ9j9j +k:yQr+_<3X,UܼsYXN +pT&6+vl~f.crp4Ia:QvJ!4*l:r/Nj?;G&5 泯lД#$<{kCVŃM*x+n>̥**V=};vcCh6W^Y]z,w$w"G&CT+LgD_a7=y 0 +%k*F6c {/eJ70fj*'! +6&4t]zNouwh['+CXÉU=oJ5B0 V@bA.8״Iڰ=|p ݜ:lIh5E7KnjcT;p +ٝ{΃i/8ڢ/GL)]7(ڷ;$N|c v]*!ۗU}"lŅRBZ_xT/-t^Tx~\58Qq#yv&IE6"1iȣ:g E8EЛdaJbѳRJi.%GvOI{<Λ*GMUY+oj73?(Qw1d4FM`Lg"xT$-xq?8O nXYAxXu ql0=8Œo!Zp.pmfp8 2 YBAn܊aСWQʱԝ_~njC=i& ҸJb=-Mpl,Yڀb)Ew|4ºFBuzni7Cd> ?|=m۩'`黧 Q{|sEAFCś HAcс⍠;%NhetCrCz}v Hͽu^ѐ$yTSw{Т]}0Q+ТSq9DqcJU-n,"Q0$aKɞ" + +aPqEu=m9ιw}; }d}1ar 8}(?DoWaJ6vAz7/ W?7CU;Qh wZةՇU$uNq'd0<@op׸ɕZa(vp9"`!hK;x`V"2pz 6X?6@xO/-~pP{Ix"}[y_0T(Wb ]DN'`"G6(;j9eSKD2g4(ҷgg3O`8*L-[b@ +"xVaW_X +<"{*-J,3fxǾQq_AdɃ򝥻)g^Q\UyKC,f)S{Cm"`ujT92AWSqMٗ|ʱh)C,:<緼ܺICa-g#Om](9|_;$Xd6n>wm7jIqyQEQEP%;⎵jכ7)>ndN/ZK=Q֐\h\{9Ḿ?q0q7,"xaqzܩdW6jYfzk+WjDYp@fY+X\d˷,<*mfF l^+JFp2=_X\.XsM&i?xN"cl)h^EbÚX~9̓!aXpwDNi +Y~ω(LFuedwHZAfH_*ga |M$*#U2X}Ek\ |<#bI0-p@d|O<9`6.2`\tKd%M77wYdŦ (^]6yO|$$v-G 3:;]Jɚdu2MPFgl޻%=PM/C;;{lf +>O5MUH9}&WǶ$Y2pSk.Co j [q$Yjι8xKI]7 ٥]٩I?G/Bƻ P2G}H<%l%YK<8?ǟiU\`3; }GS6Xnfxn!&w#*HrZٿJ!5Xdx 7 _vCHˏl-k1q#RBz!~N8:rN>&NʛA"|d]N2l笞zStu>BsOpp'Ɲ~d])W`_?a ͋a; +AϋW`,'Y*#4 UW"~bDiyO\ Xpni+>#aĆeᙇ,] %1 +F$-ʲ+8IWqR8,xUHKkKjMuܞ-i[RAkY*ox\)Aݷr5um;VuM\SPƵ~Q!0P!h@ "򨂀! F-8quֶv\WٹsΜ=~Q)z\pH 8|3n-mvc'A  HșDxF߀l 8ހ =5"`Gsm#K`5C1L9- y^*Kpr?OC?iH;쯈.a‚u,TLL'x!a.t1cz9߾,0 *Xq0z{ZIDzѳscC3QPK1ض&dI۬||(N5}?\1E--WBx1)'MRnDQ`Gg14U3Xup=ج,@^w[!*`5/.38.$A'TED3w(eF# k)5HL:vKx/f 5om咢#v1K(*\Fa'\ Hl7/6E1su(C|*b(h\g4ZAIl?)8>}\꟭.QQ[N7hB"kdUfևZ%tؒ\yQN=Α=US >]_~Sbۇbve;q6\#mvI{#y SP6 +fNÈ3fӷx zXAFԏ`'89&YAd;+&[M¬bxYPOgPCtbuL 3ͮvd ~ Y<`@nxki-rg0lU I=(,v:#}pM?U'g % cO֞(t/ly#%V0ǗXDajB\%ƈ Pwc3~;{|K[OΜN-W2SRZ:#z + /9~Ƌ_ٜ a@+m`h +:UîbtN*H{\#un^T"xC'mOQ~}? ɟ ŧL3eJ"xŸD:+z/@Gy_\(e6i1NFdNccs>*g zf=iD7|JxC<|{8lbyQZSʨ0لrٷNot(V/Zk1~&g4.3J0l̳BfˉD 2FpG)mKx_R[]nf=?LSF[Vtŕc8@a\B\$-z [\ dntp=/+A$j33'WRux1̧r{r֒!K6!&XV!iwSeEQC.%3qKok`2Vf r{3hg=[=2RSꫪrSCKz`8߯`{a8cgaI{kREj.)ܥvX 1簼fBVz\Jʋ{".QkKWc4)|=d~!Z|8$\ynө|C|܀<5nRP舲\`|S~? +s\ kf42z8Wڞ~=ᩦӖӖ"KAۆFǸcqD?cyNPGZӯ(w#Iaa⪥(GbDx7(X5ij\iK|2@ƮÏiVв8Sn{#\WH؍`KPo.s==58#16R|tu| I䡱<8%3+N+S“)kVLzg !Gbkl[]͆k2/$yXWԮ*!.(uQ@PifUPAElD4[7,.=*6 Q. HH"AF=ޟnsHw47ZϿMIT"?LB6JURP\m& 6quZav·ޚ~o;˽o +C#XK_rxkzX C4- xy%ŸvɄ%FC~$i=~ G +^/bE6w(n''{JF_K:{^ A7D`;;E~>:Aw@OڢN$ݹqSĆ@vk߻ ܗ\ +fh(ǹ8#_M>I. T¢ojna͏ G&Oocx0һ&U(syvI3@3=hM{a.w +x3>L'zh9x#?8> %vt7w]IY@,OC,;a`M)0E2`"( 8 E S-ǵ[ͺ)eL\ ThFx3Qھ!r5F m*fm뜊rrgWT xIǽqY*g|&\uQ/tsq?4L30 m&A/Zdp@2k"qQƋUGrQ=@NLW&'51Qf"}-C(MC=\_GqLg٫AD$_F][K•O[*_Uhr/0ZZFB)) USC\(0,SL('gD4 uL&E̦\LPYУ=Gp< +QCzP.;AĵƳEIb<A>n{!^` +܌eifi3Ng`nqilIlaX]. $BqYB|**3! '졔(ٯo.|;Dj[C I>O ʾ;lq@FV^ 1E#g^}8 cXqI҈XȱCiGO 4LjuBLg@iwB=i8׻=:7mD^^8df/5ؒK-M߲[<|w59v`Hy}foynO!U⻹"ZXU6#{18\cnifp|쨷^5oħ1p?zފhV{6g?ɫ; zO-N[n)e:dq͠v8cȹK+qmg\e`iwp)![BYy/LF_ra+qB O m%Pt\՛0>]pQnS:r} \g:d;:swVDF8h łD6VUWT3L]SK.JCJ!r@:9՝R2}!$lN됲 62ڹ8Ұ($řDIY%f]Te@D0éD +@(3Drp 4 Dw!og~TZ7L4j h$()r:_2Huq ;h(ĉONbyS ,Ft]9A!u> t&rFn{Z54jҐVlǁ焝7i ZB#ƹ{9 +!nƞ6|fVUg1&"uUې;Ј"^? (ä!8I{{74ߊv {i}VnV06MG![nNv!Ȑwbc#\]_zshD~ڈ՟}Çd }lHÞAf?-#Qpnkw?wW(=2wZ|DTz*f7.'?<~mF^svaXt!g@ֲ"uF+Ճl,mWw2H?%! 7H?Yх{sߺ0s0 +ivQ Fh q^Z3!|őrjjj5|$jl°o>OfBvifޔO$n8t +fn>̟ \ +;> "m=5;~m` JuڣPkdtsQX{uRJCuTO U&2%4%8u??0 JT{4Ea~Ck.OK+uQ +˔bv +q^S`hf.WnCn45};lÞưTB:'gb1̃ Itz?fH(؜@)S` [%}!js.)z0T0^4'ԓ37πXkIF֩f_5!խʶv=B +XŽ{jwTaӆpοOyHtȃ7bibsMxWpd⯨ 6+_QqC`&7s)KK +˭Aѱ;C .]C}őtL#iܯP^)|o/+eЄww0ƴyd=p&*E V +|.d&JଌKƢ]D{bf-5wl| q@g=ŗ('H3X{1@,|$Tf+ KtԀvӷʰщ*yGPJ]{aS;j>^ZzIq4+sX'Lbj 2j:pq13m_[ MilL@5SSuaY1U$X +kE|,  hvLhj4nν3q!B_ %Bv$\]/ \.'_b3n;#8_:BԮM-“RٟMnG{.8e?IOa]۲o8_+YvWbgk{+3 (AA“ܺ +}I7?R(|u^w¶3i[ېI`,w }ྵm_Dv?s0f {&~"_ٝRpe@vʿLXXpܗ<]v,R1&6pVfF\]b8 lvU4PKDК:t4-_}.$~Aˋc˸#E7b1w/q[Lb:[eU ]u= i5{Xmy|UVu\Qx 2x)3r2UH >d6Os8D*u=+u Ui=k`IYd1Q, :iz w;!4x2x1.j>SBak(ڍh.@q&! 0'W)e]bU''De)WO1}6H% Ѕq{,\F,/b +8Iա#=j?.cұ +YtwBQTUQb6Su3C*x;|S!{4q7Rtdn3e~)B6 ]AMyov;lv:Zm=V9,\Qp; #L p%` GAnT ]mL۝Nfՙ 9g%'Ay爧}'4Kf4?‚-T(ױۓy{Hef<G-8Ed8/,@)X̲;AlC):/@Yt+)%1Z~/~Vc5㎆\'խM^$W { :DhYQpt>DYt!^_׋P,Btyt] +C7~F<`A +E>E6ؽ ",#c[h*81I<ՕPǢ7bΎbjdK_W3V^@y6YiLVT_P_$M4^E=e>V1KKOjjmU--,#.ֈBYpTXv+%yti[,6צVG_^Xbd^ 4Au;.~+* LBBTN`) +Tg/ҵљ}b*9g nd&ٸd1vu*S ; +?I .E%$; +#!6_SX|\7&+-,80e^aioHGoJ՚ۧܤ5k{:qP#(C@JM3iիN4$l%k`'6 f+Gv3)߁F 6lEZn6/) +1a(c#\&Q͈TVW׼L[?HzCzP-9 _ĞIE7s㣁vA< zz~WS>i#.R|,&ΙJL9Lĺۃk;DQen2VVD5U׸h#է*ƘfŘVCêVy="Qg;7^P&)hH@53 EVYWc&Oqv_Pp{8D_~e$:/NS x){)HEg,g+lD|lh$"*5 e$B|oQOzPi~ ͐?DD-b" +;ys|d^/KLJytU?lv S$&cD-7^1[PsZ7tU=T *EL Q˸W.<(Hq|znFB]E^[z׀s*g~S_-m@u0kp5hqURq,\N/NíMƜx'{Ci&읃- }oÍ`'^Xq9͸\HHB꣹80ٝ? L:Nǹ2IxIYR&K]*ivv_ox +ܕ}p?# ;>a&?2,r&-+%>Sj*/?yދb~!]=TFF8b*7[Q WUUYZI]ۛ}PNѐ{Ud67Nlf^s4FͿ1pa^)bpx>FpѹLɵn")ƙk%%E}42&rxYL@0nj3utv |qkz[΅~.Ć!iV"ۗ=dL#6uk59bDς( >p+5M,Q5>u #(k~!D;ϱK¶\QQW\OĐ7yԣh=F.XQqa 3,0 00,3*("&nY56j''>~s{߽{wHwd-uYlFS`r\C5Ia~w(67r5,A^luZkju+wl՟;Q@sfw@[S^8/9m~l7f5UE3ԀE_~LOOR +$Ot?Hhd~b^o7?:$0AМ +g~, E`KsWPj>p#+:nL%OYkiŏ]yI`% B/b>m^z|%Գ.xc*V^0 I&k  fzJ@]VAh ?Y*zi=eA ++FaS[\JQK( @<̃0B"eUw,"X\~ ޒ +)Oޕ= 1(hM>"k֦Ghd\wk5 Ɠ-)_w"X +r9bBAºtJи5j06]G,okz"u,UZDsa.ՔR7EiJvyA4`CQ_VoR#]UmUM hN栆a0cuqɦd3HcB gtxur' &T詮 -( zg 9Dh% ZwE5A@酢!E gSak_nv6Qg]y +NXirJ~4X( u|i JVrRض2bkC*`_EѶuҶv>Iϸ6-8ʊ̒@(k7IA8o=Ãd@6\=JM& +GR$t {C wP=)QJz%q`A8cH N}@!`BrtnKm=-Fy7>Hϯ+G,W5Ϥ@ve2 >}}?bURE]_ެN8\46q?c@ʸC(a8?AIk}zfNSq,N/Tza-bq<ۓt)Ϊtu[@ ((w+ $܊!` +("("(kewֺn}|q|8{╟&t +K#NA2 JMf}ɼ81ojS>A?p}f`1~Kٻl;h99H"8| $QpvPN(bꑺC((N7-1hgyІz;rZa͔,H$s K + W=R,Q(4'47^n1\.*PLlNl΋G6?vDKתl8nu +;(v`m_=o.phd8+li[#O"%[3̱C#?6*;H+} d^OJJP+/ =NdXfX7l`0^&wZB {mdM0J\t(Qag!oFP8Qdh{? lg-cy4Qx\h4qzEfD' \G%\~oݎ]E$bayQR/ӣ:2)VV`ͤ&at5ʋ+mUp0AgK;ڼglmiĖ-jWO<K,t3tvg2_;Csd"꡺+s>e|šs]w롣0Bگ{ߏcw{ڻ)G3]ЦQ׃M(lCvvB,i3!b,aM;%ɵJẑKETjo -zr 8BgKܝtF5R0nҒ/~ qa +p/WO1KR@'~`N>Hf0z[&W4}*Gtܶp i'-Y)jzf{2ő(2g_DnfZV]@*LJ9us-R'-\Oo?6y5pZNd[Sǝj:EmLF 3VǩedBY "BHX!ưl +SA +;GOm:yci?pys|rbyРWBI4 v.CV4V0~hDj |X Krz5XXb?gWҲY)$9ft(![s-=!8֞1!R~B[`?Y»j(\"ueux^&#D]AC}~ߘ0۶gQH8ѲUOE_żMHDhs<}j 霞8Y$ 7W):~$١*B]uxUsPEVTpv6f-m\w ,kQL2V0wUڌBPMWa.1M$`0haO_p}IL\T+FC8ցb֞iSc!Tu\j֕ +a' + b +E]Ľjy:'Z.Ime;K"7[&uLz=FMDf$zjAwG^q_6s,=E2ك:DzaePo"X:\\|JޟԺ2\fil*u1Y&HfymsS`$e7텓̖hM ZH\]V>C8W0`^9єQj 5>zvF~F_]Y"5-y0},YpEф;mXl-a+@3/ SYɲDl~5MoV9*Nz$'3tvL{`~yxAʼy-'N%-UX]Z*t嵥Efj`e$Ai^^p_I x`DaWmaˁ̓gG> 4L3]{[C!MaZmku2{]'\,;ȗdR!E=|h%'[G1g\s1\iU c8Wr6@[XwC~2~yt H s8r0wA6VBdLWN3L"A:5`q| > "^H3=Wtng!gy2dkzA1rv߻e4}} +\1B~ꪴ1Q'TE tΥY|1$۴k|v)jh >+J }_8Gdփ_: 1}WZOsPO^b ^9Ȍx KoL.&')Jgz +)8_N넦Pު*n㤱;h a]1]f Qm1=! hb^8Nqtiqb fT-g)#*]Η}CxP?i h gn"L'd-nŴ4P.L۸9\uWc끰%! ZkF:3 O_z$.1 LGisZȴ4 M f`E vJqs @lGP0qՠ܌khLf}z})&!֌: ޜ-4?9~n'JXVET6iU 6%L։TX +4~!ce( =-Nn/gjթk <*QrzXkpI,À( +((`ĥDdFAdS d*ui܎U{g6;̙;߻|4O_z+|2Ke5-ޅi2iLòNM |ə|Vش:jбH;ڷ+E^%QL`iVR# 5 M4̸yߴwm.DMVVN BXA!Nԗ4YC.&_8٤bd߁#Snq&'yZs^/2<ŽI` q`:?'a\AP흫`A ,x<XG11210mnv-/UkrehxP+;iiTH'T<Bz}zZKbŏsI<`v'nMy;CQ iQFGs5,)/A` -or(ztqeu0y@_{\GpMg|O{qH[#9yf9mx}]xYN` ̿cJ΢VUv9mkpRּhw{= + qI'B{!$]F†eͼn8Z 'Vtz%[wȇ5k%V77|[a/%BcO9 )+vp.P/N`DʑTU*ȴ1[x\pu:mϭ^1v-/m|0P䣰6yԻ)jΞjM,*¹MV6g0@irl7휦N}Ms06?84_%aX .vi%y10@ "V +"OKHC6F6I6 6ۀ80g5" ++7gm' b)8fp."nFˇnyX$ZX+FC0E {/Ƃxu#]xuC!ϥuo(;'8tʈE; dQ8)yBezML|b {t)L +b +:#Z)lzUrDm/Ѷ&qrUE E[`<9oA`z0YJF]]rᮁ/w׺rz.(bBd5RW% LI`<Vh2bl$}!Ric:D/y +_`+/c&PA!H$L̍Qhw`o1T ƤEq,eCM2%Y>Z mKIk3Sb&;j*[/*WBV.?Ƚe 4R8e:6QTUt MGs_%\3LOUX{?2bO%Idy*\YRxj)o4632MU=A' #+.Gr&RkJNgPw7pn'=‹ngyiy)f 7!'PZ-˚` Zzuq1bؾ n38P+VOWKg4\xu`DZ3;cFNi-ŝKohD[z~oqfVmgˠY~ ݒӚӖ\%E"uE? `U?b0 ?}dHtf?E +>&mrtU.՛hI̴.V4ݭTi qu߂"U0E _.C{E`(ػ +,vJ#"ݻ8ab7{Ck[Z1p|?x}!uvpv~TNݩQq{n=LkuZmd'hb@멮 ~D~ԉoq[tq6O1\>C3n Q$ m<>jigܶLy%wae;?xkhfRVyYNjٕ+(% LNI.^wKa}XM=^}Yt0[sc<3;sdvۏW;d.Uٮ- ibGRRTjj]O㣥6p}x8%(rnqC"cq,솿,NRXjڷ*;ukvKsG_=_,` +I"X7=)Em`"NGa~40JR]FRqlD],QUNQGXB^_2|MgpqY]T12.ƗDQO"if#Nk-F@D06Sy?6WU"S٦ԖvӛɆ0pPJԪjEK$R_M0yMMiZz^?C =RL1;ήvR^TZ /r:dTؔ NqOSfM\Xc(t^d@ܥя[ղ|ڜbsPͭnJ.]'ۖǧ-ʳcIʳ<$2a`s(y7S-|=3e%GJnpd1 k`=XiJb~73TWnXp-VIg?]G\cXUN6=yNõdY5{Dck`1rٌxevߓkENR);_+ a9TfGnP=ndtg+SMoS3ҙ܈D'LnyJM?h&_بؚ0r>qO`4KP[]pYbں&lj%@F#͗ڠk $eahihn8wwi/':G!%E"6{ox}tvE{CݟޢC,llh[7 X?rItdFE]Yy7_w.߾aEcqE"u!MZ%MZlhat WȲ¡sE +|ZWsS֣9RBGT#LU#FU"?#Yu)T6,lqsq(mih@7!ޑ]!se}#'._QP`َNs?UՕ = j&B@@$"74-(.,B+ Р +7"& l31q,ǚ8&Nsjǭ:}_W0(@_6++8 +M\o~[ٲ;e+.\˓-},{0 Jٱ (rT3TIF =ƹum8 (@*+F5Q+*+fq-n aXNokMIe]J<4Z9L~ XBZ K̄B&&[KDʻ`@/a]ߢ!4|- Џ +<{'S'ڹ#GӕrW4Ԋ= Zڋ`DA֔33=.)쵓.@s0_2\Zo<ԥۃ]PN*Bc]˃ĊP w)rb +D8K;,D ocԑ5I#n"VeyMNuU&{`+]3)w<;n8KM} _0#H[wP@ .(NhסVEEDtvfF0++"V珟O=Ơ߬IQ'$^v1FMgn?mh?~E \IqMIMuQ B2jTTʪd5M~!]-nֱ־Ó!š[.wT>cc)UR_PXm=`h04yZT}}jOv0 4W{wlcxVsh{c1IyEw'^z +j@I×X@D^/+bN =,M}Ov|ȭָmB!0nVM[4K )IlQTWDu +ob\;Ypfеk!-4ĥo޲ eA`h$!$ +ԃ]@Ʋ˶PxKųPMkbXFhohmޢҡugs3'Ӱ@7٘6a\ɨ߁%.~,z[3_'QfQqI +}4_7MD +۲PM֌: (s>Ga@^#ngMbsOVw.0-IrgB/ [s}s +#VjRlڼy23jֻi%=ԯI_jgqU R|vc4l1/. e:F:Ckߡͯ4-c\^IΫE,`l_͘\o_lh2OYpLЂ.)dTJN<>^N)?ʠ*r`pP N iT/^ռQj^5?7Ixc4>ߞfzV鼆T:" )vScLet>`qCwɢ{Lss1~ԫhufX0plu&H*]8n(3pN7 ~X, Y̡D|cʽy{4tp~RU-4PQC-=VyFړe?jiK0ɘɡ{7h{!ٝ2>(3V.[>du"~GPEC]_sQkņld&g6%`7$'qS\Ȯ{UeI ۱i44X%MZf +c"89Qk>嬧 -{~i{NߨLfqj,řU^lnx|ȥ8む,QЁi! vKNeR6JT<f{Wp) Ko̮wY)1TdkF\ +n>A<f'1(C;Q0= x8sLȲW(Swu6TW<i Y̘tO9:^J,M5&ÿ Z>>2\#TF!W+fGpi/ Mr,6RkozͥM@-vs5^o>Y,|a>}%4Yі~5?dM\q3Rx!!ӌb%"$ NNO=ޚ N(_D`άSf;B-8 AP>ITdsy]`+9>FPnX{93Q/,=(12L<b-|[h݈i_u ;̊ Lwdsӕעd'f'(L2kz}<%1!U}*VDQ-QTnHgut4?o731 +%`pB3*<uopR!7#iN?.w3AÉ0wl{ſZΝv+ΦU@].2BuQBݦWחIjC;}SՆIUiJMt"Nq7_Р##'c2 I-3ͅl/ W/af?BV +ǤO׭kתjYUT%-S554 `,)חxUƥqvrp0psn~!m'3yRHi\JΫė\-x"[ PI9:<5@дHA"r"¸m Z7ꀈu%b*yCpp@DeD A]1cfAd@ (y |뮚74u\WU_߾;>sZtT v#S.nHt C cx S;}~&A]X Ac%U +GXa#:p/Tj/^ó`Z"j!.NJ >C.YҎ p8i`D~`+=ٺM|}л3z~S N[-:-oUސu3&`$g:w0026nƕ h,lxߍ2‰VN0ԟtfJRĭ}t5bvB}idz ~Ke9rr_W%i242!R#( 3bB-Iؼg[莰q~ՍվQb=]" Ww׵4݋z}W᥈5Lo+:ƨaJHcCȤ,,lz:ZZxi#.*7t +-woxL"篟1^ D%')D=viOi@Ke`U֤͌eI.zו]8P-#p|p9'xs4rB\  +,TRmispx\<} ^O-6JZijzU:yZ2\P^b*! oƧKϾTL.hk4<;N>*(Mȧv2zsg'+Akp[* 2^ftЙHo[(Y7`Djn+kY}-V#zvwm5+==XP»w`G>s3=殇wl=pY0?O`./a\4!/p.|<5"34U`K7|>`#JFyb0L_pV0=-?48<1]AiDΕ"ўi3߄9`͏ƅM+-Zj6v6!,ŢQmPf8+ +gSEI$se1bv֚DWq፜E <JU+]ӻ}axÂ%-Կ(2b5 I|bXxVkk~eaqqݶo5B#o2R +x؎vΒ4Efvޓ%EFzld: |(q\AQYO=6Qnd5+( + )(@f7qbFc(₰rh쮥]]]~/iC־Kʮ K}Ih,l+C7}OX?u<^Z*Zk)jvII ҶJ&8m|e wzo>g$ U W )kmRF&)pNU0qL{ ^6/0dz=EkWSZSۦ"l|[]MW"`OV4/QTjhl6vWUׅ57qه/δ2O gBa;'xÄh{F̒OOzdBQvln˹B,}^) Mܙаx6yFu3'F2J ҇s7e Ƅ -9 6>cx+1Rj=\uQ0q ۞V!bˡC]oi!,>)|Y>cgG?IɔUVo) )4eZRGPxeڵ|qcYO Oh y+|/brXI% '0S;y)h&_vz ɧe`ޕF8 FJQf)(fEwe#cEy"Q鉳h)%0 vkpvTz`W Pպ1GعTd@tRŸb@[/gnRx7JmJ$r0"}9ŢlJhaH@c +ahMp ;4J,&Gs1s-xܑC+ˤx{[ɂ>;*ьY  `#;|? jx '7`!7# } 5ISaԀS3: Ȩ]H1rAgpHUHS8{#A"Bm~070>1Nܴ/]\Yx2PY50$и5W-RgNOOP.s aezI8B 7H*dFf49^{ `,O=LjibVH%~C8b΁~XvÑh%KB00B^iҍ'ϝNe(<(氟2OB80%*p#Go0wfkAX[Uav>^r$eZ~s=_t;_Y[2p4A@{ 4D=ňrO%+ʢ!i=7CIec1QyIMP[=d3X?ÿ7}}ՔM.)3/=؈$R;i=l-=p,ޙщiw0k$ }_haflHFfPNJuѹ;sUTo1*#4Zr-GHs?܊v_MEF?*[^MƐNa寣[EZ]G9j](#ƄDZ)!u"N̺9c% vT4%91'3]J=~;i98 + l!tj>R5Osw B]#Ta:䷥#J>a(Y  +j͈9zB~2FИߩk:RJqFZ+`Yߋ{Súz7sG>;!*TH-yD&Ays˲V-5q\-;CCcFL 2>݄ٶ[ud'盔Moa Y'N9^TZX_t*WNqɧ> +}?' q[K?N@:YL @;.vjŬ蛟0: + +*.߰-vĵVUVUkTa5u2PH\]M&T&Lns+gd Պo~2|q.̵=ROTLԤeIgl~a dR.!QڸVf } m:+ରI1={IH#{#a![9.YɀhnbFEu *|1p+ŸM,p)7xf8Aed9]:^u9qU=Y'?'pWcWre+wTt*k5}9ꇲ +۔p'i K!R銯avԡ(rAWaR<âk .j1@rP4}0xCow5 BZy`Yq!~u'oдۙAqa +;FAXG]|Ը$tC "+Hhg!s/.`a%B&y"w6; X'v'G RAFXXS8U >:*GHpPr\UXb`,;ӄZf3cj!|o+H<UQߗZgf/ IE/\fG2N,R.h^bMT="=,IUQWSIPN.e;^xM=nxIKe +*>wܽ<\|־4saƀ6ԝ]t-PTed/UT97y5⹰ɱgz ~nেpEaA|3_$n5Vy]t3Q}1~0ס9z߄n.`M>SR\AMei{H+O_LGEhEQY"҂t* ,ؖZ ZS~OP5zUԫ=b';{ |B>U\OQ?2>:_(բzvQG 7G6l3d_qm7kػy *xc4XcbΪy~Z8J;5k `+{j'+^~#EXVu*)+ R egԥ8d |d` a\Tzڐ^ +s6gjǬK% lH펱CmXlGiσe[x|ye5hnQaQWbH~3Uc}׈b|b KǯkH_.e4d6]fC@4p&B+|ȷVC܅+m3پZ6?gIb<ӯ] QkN;)ٹ BvSl'8wčJ2ӚH{DـyD1ELInUǗnvm4LAܐ=IQ)n@5'[RQXYPUu`APc^-4(r <)2D#qM+a` V4\4DB'ª*Ej2$/!1]^0ɀLq56<q8 ^VVeFYijrGin<1.bK׶7=30~f~.ulxMAS^fCFGqz[;؜,DQ˞",?$$ %=K,XK70@N4t"*o?ᓳ} |ɲKZON>ˢi|Hb[*OLqC^d\iϠˠTE@@H9GwɅEE"UH"Tq5z#jSIekcj*;#Z3{­\;d# +EE3 /sVI1BX.rƞ /RKs/>'7\|gQ_oz.#hL9ŶʅdBUT2չDcHm ; }EǃďxS\VWyM{.N|:e,k\ݽwnV={G%/Y?b>/2x2J¤=.DL# + "[hY\h& "Ne2 +c&I|ss> __C}dd:[{]ڇG).34H^[7KD k(^^ci@$cLNUB@*[Y1MIۓf%oDa9IsS5^bTVNqD)6 syb(԰"sܽ/q@<*XmW} vgx _Lj{Kā M&oKt7uT5b̬Ve5P>XCd?VMZb}t7wD ͕>j&H؞H V"'/W1ftLw4D;F(*O$_a_lKTq $TLǃ??qn=qZ؉8閜*,aNI~%G/US=hg7o(P`d'>ERXg{ l nw\{{`_ST#K݇dMnhUpud5_<a-️ُxm@*4څw(8BzuHJ-%Kr*_ xa$ ۽`j64t3:]n)5ٗ@՚k=7)HNIXǟ4M5IYe/7_Se &:"& jtw3A%x4>TӦݓa2HF(,} i믿bvV ~L yJ|]S}!>o)͓#sNP\C&l( ^:8jm2 f]:ßm3 6r 4Ta.^23)|0$3qZB#ƣՌSOk6OF#Mm:^?Iq~&%olqϸ c)֗Ɓ_t18?DhOǐ,E&[c&Bg+yyR8ZRwƅH^x5:>z=]*Vf6)dݬpu.:d oqwFī=be2lĻy d`=+_ Mb#Y N? RZlە=lA0H-DV oy<|TRh]f +[2^b[x /yP2`LZD+u鵙uI:\ηd>Hڼ4Fq* +.܈C։ Wg٬˙AI6( +bTbKG"M:;Q9PT-,(pr/U 4(J,59&y;x3Ϗ$>.m<|gfcKTllZG +(b +& q \((3˫9=ݜi o:,9tx_ucp n5 `:bG=\iNk ^^]xXXBX2,ꂯ\k)n:~Ht0-Ԑ#܏HX`贚=LsaU^Cދ_p&ddYMF>6xhL}ҥqs&\+:giY"i5\6j_IoLZ&m̈́w# 4HK45˴Mg!B^11ĕ1cGsOCŕX3 + *Գxpފ憖oװD i-Tա#uLI + ?XpD7nܣe4T7kO(YU\XY]w9sfVc6dm1dըۗ?yge.=xO ~eNF]Z"I1pj{bՉfpc00UsEN{ qzf-&,؁zVjK+[dA"XinV9=g7r"AQem~|/*-/TA)ƬIȔgF4c48B(5:96)*G9ZluOC몋1]s=7g!MB"bb¢eqeNdr׶_5O Gl}۬Zo-2W7CI]24*(`56<޾^È;pp{suDQwkٹL2ߛ+By%g;d՚^៯xoNN`fgDK6=ȔF +"P wZ{ ڡ>Q)0?,.oإp$1M#> +VoN_vW-v6iLY_I܃>܊`MXb%|+ހn({j+dK\?DXG;XǴM ' ׄ<-hSSr1+mN~Wp2}c |)c*-qe&;Zhx>"=5a(RHW)r9mTz]p"r4e&&}Q6K3B%4ǒ<, +%WXN՟4-HȌsrRLΥ2 N띀Qkb}YM95'r 6y4%Znh$tD{ɖh~8y%ӡ9ڦ'_u\ +e+hb8u,9KF"hQ*Mh\.S\)؉@C\?+cI.qe8^a + +]WGK"9x`vIذp<. +O6DQe +Cgs]dtZp:OVSE9 MS?q1{tG=SirGpфwY>)}|՝a +rs `uuL\O +$:F>V 5RHxw;ſ|C7;8ɃL`Z\nCΏƚ8 ϿbkP 5FX$UH܈ +AGX+XL5!=1|ZFj {+n̝;W݂/D-)0 C ܁E'+ْ5A`廅(A\Lq6 R 5J_ ^Հ-EQإn%msjtvZNi HLjLMvE=6-TEp V:{V=yCqOuEqa$NwNJƍ{LTd2k 8Ue`Dddga5TFEEE06 ] c[V*7llOqN}]~D+pf?:^ˢi'T}KsG,f?.T=m6(Z.$T[_[P1Ah>bVTeծ< ۳i`p`rg?NWxÇĺ$>Hje (y/?V#+|{Hf5>Y,$ƞت%=!\Q*=\Vmc1rC3ꉱ/ʣUU&);h~ts';7cwe#M0$f۱֎"bx4jTT +Y5FdOLr@^׾;!#k̹E IF962ɊoI*ٿ{QJ_$/ R0E׸ L7n~$+NQSbujV!hp; nnRۛz6 E@hGipy >c4(kǟX'G6o/=b!LdRqF(p{Ze~A_?V|{]""CRte+.yGG3UeRo9+ 8D z3LRdr +7mUy1q@ 29ن,[6 OWTK*b{X4YK V, +@MfY8NSy[i "=V K9K&'/pqgx&vhg/6I?9 +2ZoDk + !TI룖7vsW7}M0||hvԯ6p/!3"(1 +4u8}ΐg55t"bŅ>22$:͎ ӻ+rzp qXfj`*|\ʿ^ep'V޻NRaCN;h#9ĭph py7ĹJ/'{N]vޤFT皇!M\X@w[^A*&xǧ(z]bJ>b:M#GaN-nN.n*&Ьޅї8ArC 4,>9!87c} H_5^5kL?CN$ro;:\9e:c$>jJr n+evVǷnƦT+HzL^rѝUjkΈ6]91,x>X a.6T~h&.Xݦa>$)~kڬ/|ay +Grz6̤ V*?=R%nZ6Zˍ¢u盈iT{!>0jA0j.zg9{F +UJ,-VUc JomÞoknoc`gPFa,,{<]d NJŷ\YF:S<> HTkfs sv=_S{z!`NJTe>ulvOʳ݂,p]qY'|;v@bqCǧ0SDx8QDԔhJt(ug]`Z, dgʊvi_TmRj Q:Vu6_eS%M v;F:\ł/| f蒶Ș$gS3Lq1gV+*21knr:7Όޘ 1ze#r_"!ܧ xD@E+&r" 3 &XǪV~}_UwQxs:SL>+דCx^k/p9_ h + +r`s}[N?O}\,!ov_Q1wGq=BdyTϔ 9UtSĦj&ieJ%tU`⽚z@^J_nTTXDN,vaLտ +gT`J}7\G@{(#+/ + s7Ţd';TQ6f`aྴ* L[P7dkySyM ŭ{Ip&ЁNuj^EY~"1,%$L6̘cֿF,Yo(6gp3|M_Jo +\u_7y7\NZ,F$›XQV-YS4{|9iDn+DvndDh]%Lyle* H#QОݦmz!>z&DM @JnwQ~.{QqnsP=`:;?ư8kZ]Snqzgz)Mw:̴ 8- ?#v&'IoWD`U*!$` ނ&';! zwYqJF![۩v$ +uOQ`t=Kp.e,2+`8Ä希3^آH/T4)Sz]3"yXs6I"2d}s#r]-AW Xk*WS*-[od`ͺͶkaص̞  rhD_,Ws!ZtI9Ip,}M4n;ZBނ;ׄvl;A +ߖ:3Juʶ5|q${0qxͦ}[q` ,?FI*(34$3+S2I:QP6Sה^Zc24#imWgK\UYZQTQ,)j?;"劰&7Wr_T)W^f:Y^lVܖߡ hYG F(+NݔpMP+޿*7js2A{b-/(F02mD]`=dQ-l!"EUg&H]ԝ>_lDP2@O/RsRoNSpemic{tnJ>-q\2놚n_ }q@ +*N|1OD\bL4 a %SP J4cgp2ݛUcw:†'& V4'(d5fK RP2b7ȭ8c1X8֔Z +Y{5N+ +c ͥ 8vba̘p 4j GU@7 ~0ÊBBZy iHR̥ƒR`DTCNŤeUr 碉;ud8oG< =_Nax'tX5;yz'7`,l`c)O +bjVHa՗p'8 /Ĕ??ѥfNή?ke{ `ˣg``JfZ$:!@' ;0t' +ZTb`zL@ BKZ⤂f>ydCcg*#?x8v u1^)f +ej|sŒR0B9l޾ۓueiA}A}ժD_j.LW;,+;BXjdK71LVaVZE0 $0b֐93: N +fnqA%[VS=uɨhw5uڋ /6m kÿr}w}6It oUkUt&0IxۡȠpxRVeLރ^>8oXhX/ 86s 4ZaJN#2NՖӌ++RiN\#YLHUDn +i19>71o?ՙ$ʽ7cv]?.1]lpD) +)aiġ *Md2 4EJ($v7eɺ&g{{ǾUv_MH'HdZtZL:f`=ְ.%m}鍡=[Zx91+![?*Yq5|*mm +W]@ƒuqn ⻌sEPgԓ̦Ԟ#tس8ໆoj:>~kBzRoF8虜 '7{)vTI2 + +8:ڴj>x&,MG5|@^SrA罷$2+i$oڇKF8P'.]Էg&؅"4[;WYPˀ=R春Ofgokm4O +kkz|GHL&"Td %tm]E p}a^Gj~-$(G _$%('(Z,$Y~5w)'H8qf,Kad`͚Vdjy|Rs9tA7F[m`{mA>/'7;'0dl%OW6w s+1Nz\Q0>= }K|NtvGe h<0p Twf$9 LJpD1YH³wP.=`6mF[x%~KێX _痎*\$Vp^La":~łNё~FXC`-,`ZP8Y*X{=GOjqb>^){Bܲ=t ~ϘIj!ɨ=9̐2thIqH.44H$.HEhr1~ַۜ~߻tsɨHU!b25omQL#XrΔB}QlCG 150/8E84IaO1ReY[g'KteNnEE_DuD󙊫yIܞf'=΢}k6MmVmO77vSG̟\S6la:` ;w +Ď H໱ a$S C<:19*'D\!a 1oΝӻ>Ox~)1-)-IA"G`' rz?쉦z 5pmTwWVCC0Zh[(ZƵኖ8X4sa}k8!aF;mڬJ\9a|8Z/t1V.h.PQ^#)ꄣpLGNj_-lמ8/=ݰאaU)|neSrz ;a`F0VÉJ6Op*)]^qxKɎٞmeۑlKfɺȱЯ2wCQ$ys\hQuA&a&ї {ܔ`5|E 3Ͽ ~İې0dp˵*^ + ~0n^!θ^Ϋ9TNhb6܁ F(Dz{Y__W!=HPC/_:|EO.#3ا앀O"&gbWv  ~V)[u7R}WaI}"eqW~OuةKGopp9ߐg5HKFgpV⨄/1d`5$ۃ Pc`Cu?.W^JoaKK0-#9';;';Gy7N컖Zb̹ a O%["#.S߱%T9td%-_nB݋}ZdeB\Pq9MLoKW-5)*.<&]:&HGՀ88U!N>YPe`m ƴ)x{%e` VIG g#B>-*z}[A'U)s919Ï?3*dB~'KT7wW-THMŞYeGv>WhZ.;T3ebj-LIJJ/8UeOP,mܾ2˷B,(SƪZ#w򻨶40 f!: fB=ר kWTK}n4|oߦb=s$t-]ǡ%jO*)|mZ\Xw 1ƴbpM8in \3:'f`+'1'Wt{c&),ji@Mh˺̏џ҅?7V[wS\pRlJ+[3'Գ{t겮Z}EjJՆm166uqG5uaM9Wo!nE¾)`AqcHRZ6  a1B6рťq89{/ΙKy=o}YlE2\<@_3 O&1;jM˯RrFCWޥ1f8m7Jg;X`kaRPgvGĮgф>ֱ[N4q8G0dQDI9+4s;HF&’wYPr}5V;FBxTL\^fäH} ֶ.tEo]j($)ѲHFܜP9i/":wE1d1I.&]yyZhD3~D*3Y҂l $tBp_/>z6k֗7|j,9U"O?d"RST M[PzzQXIS2fPlce 3SRsPLxTٺ]\6| 'AC6n>YgAca"E>E'STFh(D.Kd6nf}"D6=MQ  WsC#4sG 3=qc0 Ym}ޟJִt  xac{ \?aC:~ESY8Aspi{~e(0YGf?BADb=9NNLk浽}ar3Ic'I墓yS^SFΧL`{N}m 3 Cү0NBXƌ(oڕ% f|E,7Wk4!Ybd&wR=k/g3SYޅWqa-еA4OlD/-'jr- C=3?w`' akV.;z>6\;|量4%\ЕU_uJ|:}KbmWA>o@Ȥ0%Lc6&Ci?}W&ڏ2OM>$#хqs/)( b2bU{׋4TCFaR effľE츫/tz`99&řY rᇵ\5?IEyř$]17)_e.LҬ*W):f*kfy/En!Mhf~qd1l}ܭӑaHa4 禎_˿d{ʓC1Àѿ K8c$ʅx;#H%LpbfeJd^l?i5{SB21{BM8b5Mh=72%Qm0a @Ж~?gIOizx/0pR!pnNoU7J-4[0(̍`)w.a((;W +fYq,azϛZE=❋nYgo{M$+ g#H#3:oaZ$4Г]UhGI6=0(sVK{PZm;ػ ^q: /DV%uBz#띗Zƨ~>k/_jن~>ДUW]UUfp%~7`|DK8G볎 }+.Ǒ.MC֕xP?@d-i Ś c!O{t@ԭm'p-,7elх33nt8Cq&?=:2:DꀋChHYADL&c/Y[(ɍi4r +ҶI +i{Uq5WK) /t_qr` JQ89Lx 'x1f$i SGYkaȗB;C1S}/Ӈ92رLy~T>l{%9sLRR3urGHͿwttt^٪qPa0G69eY%9TK+Xc' U&.A@Rɧ;x6>q2>M7Ig P $Sңr"!K j'>%*ʿVI5)Tb|?lNl}`垽}6bfo񂫑9HCw +uu]g8Kz7EADySAAT&8Xaz?Lrbolb 5,,"EO?Xgd@`1$DjX䱰⼗~zCg>do]mrJv!^`G=Ér|9FZⅪch[qB$A,NKTv"ɑ"-'Zƞ?U[Uy.9T!9'7rFX3/7w+ +e+u--_Ԡ|P/< n]q2RpB)=_*`ӂW+ +8p!B* 5Y7Tp#~>We6VG36bEE)FNSӶ\*TX%ߩH*n +v0?l-5bȼNԞw&٘ 7m4{:nIGI'*ʐe uX 䣤%.K#/8~}YSL&A%Rj;t YC_fY@侐Q .lRl̨V+*,uKsfPS.RuxڀmG{i<7 vZ,6o<ю1.l`np >W9hnfgY?mmЊb +^%.%ʻڧd:p${5ɾ1647K)lFU=g戀t|jibִX3$d$uʄ˵r +4:Jlo6 CfwV֫uad QI?VCȾxNUOb i#͢gJ&( +* .WF+Ȳ֪{M; W,!V#4 ?«3ˋ-rNV"z|S\VDO  )bwPnW XQ:َs)rp2mVZ_o; B~b +Vjok5;ÎLDF}i~3w@}%3 6C[G𝦤D͡kW3X9KlPYE!0!Av+ӧ4CE^+= 2/ϻsҠfɚ-dƻDtAMS˷O +x7 ݫF:btwu]4NP֛%ԫ,+-J*&P tNq+ʩI>Ga2KVU[fpo^aGm#,q.`.ރkAUw=:6:dg76M"2Cw~JHU6D} ud{%RsLBVF*gTǺgG_׌“&9TuX|#{ ]╸rOJa9 )߇A 1=p9~_ s{ +EyHru,v69%{& K{kWS7BCΤmb_MȃS;^pKn9 S~"e5Yl&F|c| 8CzPEG"zmٷ5XJn*.y=]wv]QP> +PSkNg +eIjXij RP~evz<(we`7i. xym̯bI@SWǝ<.4rR]S: # 3-v:K:5]}jWG:Z-#wrrq9z`2ޢm *32-,oLR~wiZx8K|zQ@2˒_);:oe5Wal +K ;2e69ش[7,8sRHr-eO+^hXf#m@SUz%OAZcUmU=; MqtVX: 5[lT ޓ*+#1l6[:{1p,JpɒE=!raǹWwY|,"?Id8";'~^J +7z@P2QP܄ \y}xO(zGНf)9v:ҕ+ܭ|/bYي"Z5?0!`.1py5b4N1sHD~* ̻; I +v,ofQhVtMh@tNF' Qei2QSOSWY_Y΁dMTy"N {aZv}b0<`ڃ0! _`1s2W $g0}S^ZhPI m i;qdS=X5_ ~ +D?ǐesX/eV:\`؃`J+NՌu0Ѻat8*#y-BLg0.# K}ZӣN1$).,y:y~TT;{p"@Xd @@  % "*K%aXDDuJ]F;cAy{??8j~SOS4pNbcf%ސ_qz`!)b|rG_O\A>}~T$V #7T_9zReߵ 4b:9Ka< Kdhع&iHz?e6e:G3/@^3/}n(W oTAM8 +a8[ fP +^-(3?AT[ +Pѿgڶ]!Ex_vc .|Ԣbg8oca/>ȉ:..Hi*ee/ +I 8y@i!xVqdC;O 'Hbnܺ醳tUbyRi +m +}QmrV4lR`D +{Q +{-7v[u*oJL28(0Ǿ-eG=xf檝Tǔw0Z~_L͍͕*4V.P'QXB@oT7PƉJr|u#l:r!yӹw]jKMBS_+it.ABh`]xgԉbx=0{ҳx֪J(x3#ˊˊ=4(#zR&ل>$1Ƀ&+F(QkUQPna/{.=1Rz"]A+Sϱz.!-|,׽"_{i!2|NE}ƗCҴksά=9Dmr)s .6]ou$u%xɊv|w6/4U '4!vxLUO"g=r̾2Mk1Uk[0E'ء +Um ur:5B>p ƗLw ,kFl X ױ,ζwI(幪7CEU,Yr(O\XPTAuR[%)I{'|*:Iq3 Bߐd>/KAM(-;&K +E|i֟ՌGv_DJB]QᬆYT3m<_dH FXK6/$fP +3Dԡ.UYB]:r+R<& 7aWHٽ"^)$KTcju j;) )9KFyF8 -* u /#h(\!x4.eAc1E\%G~/ѭxqv@.UɗeeL^B~D_gc.9+z3>U%S#&oDGQ`0!(4u >X@%hG&n;Ps||[p/-gnbW'xYn VTMUad@'wKZty~~7K_OtZJx辔Ե7$tmv]Gp`>i ])͍S Ӎgmeg0v [isvŷ9wv갘u爲ސSQ +~3\Vi;<[,AALŚI}M׭B3xBL!&M2ޚm%Rsy<2CLO7U(C,<> s܂RyǸ\Ny&8w`Nq8t*eݗMOбV{c +tiX%q$K#kL7Yzj׺g&ͶodUl<ۦVc")V*IK*ڠ1TSCI K +M:p"7_#tZ՛?`Ym1NǛz/l,<02cobv=lL06xa (LlLpX t{x^mI.*F a3 +0 :FJeG$&Od.6몵zVgѪ˱cN($L;z -2EH!{Ǿ*hB0E J/o(k04ס$;3]M=c;A-kG@?qklyTg] ߧUF (SjQE* +.([!V -BXH*a$-lX((Uޣ3:7̛>Ͻ+|'Pt0;#-[|:̞ +e^2$Iz)O>j;ցhxգ nxeLhrDdncJ!q ƹ9Bgw ~ +X=VMyᯮVIre6%&~(/kUe^iZM#|ۏ\ 9[Yj ++ i X+EiyxMJ6,`G3!\\0UBHC/ 8LK.wFՊ( cGطx`8P1HO$Y-N0;9gu]85)T_bc3U!E,PWTP G"TKVɥ?#~.Ax`AijqhW^T{h3Z S<bJY$/%f^M,/p9- 1ǫ`)+ejX({qn%аl/f);e}!n2Տi7L] wv]v4O3:)"ӹ6oݑ.u| T V7 )eC[O9)R.qs\>Vp=B|"2դ{UB8p\2}|=Xr s&\=2۠͂?Bdv%1*iUn32;L\h{HO:JU_)VۨPvƺRkuچ@mh[KUf7^ux&_1ifkdFH!.ȴD"RVREeA}!|_Scn^A,aXE|N_Z%Qd;_voDL0'0U1YA|úif'(<2X o(b3EZ-GU" +5f$hQ(-q8;i/yjV` Z6h[XI55ɥ`ᆍ,o%$?(ꋛVz~>-* HMŋmP9ZT[bǯaO> (%<@,u EHJI9ϔZA ?202YM4]]\av7bs >=*}_j$-Dy`30i|vXNLFNDP*E)YF^i/I4xEo(55ncpiGYZp +K؞8h.-q8ݷf Slfd*Y'Jb僿{')oZV_wIJ:k^!̯(k.t\hWt;IxJE9 3R,+(tdB 2 M$n ޅ/n-.BA8Mr@%r!8j#cLjRo1P筺@fC;C8#e+7ތS} @ >wXzK e;\C|P LJ,]WVJ'Qxܮ;/a(-Вp/IYc$75 ^&s]TE3E jKq$!oN#>g9דCG>;vӸxe:IX7VY `mO1tMt㰎)#`a|8=Eo8(GGF!';DzY.&4IN3~C:Sl,|I$d!'$a$$$@a Ug3#N33873_{_y[T&c]sV Sz&5ʫ {eT'yF^ +G"-ow!M$R(n uR veNscp6._| SW%<6=)۽չD8$C\gΉ&fxvDnHģ؊+%>5 Cy(r^E-5+f#,-**ZȨЫtJ~b2@y5%76nL>-$˕̭#H2ad+uU_3+M2jOFMh J4BƖ|T.r"fhJ*Xҋ 6Z(Zi+%iFlx؉9idjjT5`vHVjEQ$,?mVTI~D9 M}$4"L$u>Yݤ$EmwℕݓA$sNZMOd^f Ł#cm(x]3- 0Q@f`U=9H.H$.Ñ X03mtd$Laܥ&^ Ru<}$rφ;l i/8ja ͙܊9|(!ycX/%T +s9SE.f3-hW]A0Z\H3aPZ= f =DG'F;3ӣsF>MgN~ZpxWOtNG brQ$ kkjzj!^!RGȕNm|?!C! |:W#'g~1֡PD^T*5ŵ:} 3}W XkW8Kխ2c+P7ÚAq*7 72ZZh/մTЁX2Zj  9M(KUG6|Tд>&dpr9`}g Oa/Va_Veܲ zjmkd\5%հH\ˬ(*[ρVNV3Z9 =S.Yܾ i$iB Qj- |OeEkRIr ^?r'uC-N]tȺΏ(g2 +Yn=uRkU$K?/H5ƫK]@'Ӫ#e7CG2ҞI-jn#GQ>a5w0gA'.]_П;ԡ1h5D4T5JJperw).j8LO| +OxoA-RT|;(W$Qf[S(ݒ!6FLuuCmc=ʄ{0d-8;z9;3`uݩX~k^`=@iC ѝCc"S5kamp,\ک3G a[-Rӄ:I+;Ozd|s}cغs*=Ӈߠd@Cs':#^$u/0 $ y< ̨tbk,|vdL߬GIyC?PA1R`l&' '9Ofd[\n_R_a͛HmOt e5>Ir-HRgn%STa,<^Qv[uHY=^dP6ⅸIv`IqҩC4 MT¢*R+Қv*{g>j_!5Y'0E7Xh)1H(;(s3oxl^6C;-TEJ+CP% p*U{'*h> -lf~' EE- .q_=X#HmQ\W9sSŸI@Mzފs4 C+^M`iN:#B!Dl +Vr +V/zv'9r u{]b}l81_ cs ad9$#w9 MDKtӭl۱糜#070oovpJ5OՖ$..ʢrw*1~ t1}y sTF&uZ2_$a0Ǧ?ȕC.SoNL-o;{vz9I}n#oFߺpZKf8 KPMp{- _OݸtozMS . X/BsCUM]Ţ5/͹{K;rD[1])tHv\eᣪq^,ωis.9qwwz7r-}Cܾ0s_O:-,]V["{Z;aΕrXpdH|дʋ1IPe_`=֯a(ΛhO"qiPTWǭݧ)k⍯[Z%D1"n4 + jD% 4"4 ++ 4;*EDQ6D8j,f4F99rpΩszuDG%,#GV_Eٵv8WG*i9ڧ +:= +mbAixcBv=bI.&Z1V + $TF1.Q +EWqXɵWm,.%Y _Iq9 S#nB8ol>ozn]uYPmnrdtPyȄzWWn+6n+?)H+{8X +Ҏg`ST7 #ѩA,=m~ųS_FՖfH'd|km|-'[2mWOe l&zr}+$"X`=S#Zn"|4Fϡ80.$$F)(Ą +C%7fG I=^v?m^O6+CߴVv맘{.x_~vj1A3`#4 V\tԾkTXn/Ƅ,^ap&{\tŗُǟqiOmT0)z*c:TBǓof)1i5$fm亭0"FZ"o(.¹`1 E$@;,_Av @R$;4DJLŦZ?a˝[^ͩ}/]v~w@3  +zl]UoP@ۣ$͘"+Nvf>=@p}ћA<2mZ/CzKΩ!{bB"bs䏂㎡3ND˼|3W ?YPOphկnpa਻ +WN]=#,~HZ d۠,g^v@D#Ș;NUo!=8 n:/x?Nmyhn71F]t:kȦn*<"5b8tF'+jdTxmR[L{L(aa z_YS1+}c;S&jSRxgђ'{QwB(Mq#4R"i4jY%[wy'>ͽ?"C zLv쨾fKׂ2[YN Z&b_V)j)8S1yHVUjV3ErIGkqEhS誣#ю`7t-U^;#W 3= ӕMB.5L/?=*g2Nc$MliɎ4~hnG Jphb6qKxWt/ew^Zjm szs ;7E+N;Sݮ𥭱_N(g[i6F婳κ={t[!MfF+WruN3l3_{]>\b +^}ov宵vܞ^"NhuP l9i(%Okav͎anO(%JQGֺ>BE< [}clU%r~~G`c2 DiR3j#ّ6К)E3|!.w] !q?;S{{,c* +Z ZT} .Ďυ2z:ʣ j೪"\]_1*_L]qַ$~ +IrPf^{<ƒ;[d.5Uafq%/oNR'{p5Œpb(Ɖ|X"'3G "Hƽ,=[1&H_?Fߛ4H1]W+\Jk25۟⺕%?a"7ִl'u8TXDr4{PSwŒ{okeް.:>P^ IG!! «1 +P yU]wjvf_;s|ΐ`;z4|_Ѷxj V:7 k(laV(kLk?T=,K smw&KNN%pa{JaÑ!k/UIߋJ`+,^,BE)i83:C TaM \9'? w)Z-r~^"*#]筤 5֝j`GYX7px4f$@"Wdx>,Vl C$dhn#^bĖD6!ARviI3{g՗Owl,c# Pw&]s\mDD@xٲGfKcGKHiFzNZDj+k$51jR-qG42}n =75GЫg. +`I3FL&Bc!VA&q) . 5'ϠKX`E}t%R]im!R|zac~<94CW2VG/#`lDa%B[mtՋ!ǝMz)W)[{<6" | 9'e9J^WUxB+o؂r"z7tK4\vJACֆ<{t|&„* 熆#uu*˻=e**։!j446^E"?9 + Y ϓ>W/+^Ze*9kcyѯ13ˢ곆ּBJOU9v؁*Q=+9s70$ ŸĐ =sQSڹf(67=#n3\oS|w1I# =!ۏz7?Z?:RM͢zkdh$8 Oy}|ѯڦ'E CA ZO-D#kX#G7|6 GopD3 $"q0$br +:Zz.5 BO2V/ì[̻qE(w|[sHq{L +ZVJ=U(-i1ța~b%Ya# ``k=BR4PP@++6 K޺b=ZtLHd<Œhe~:O=#QᨤZ\Ͱ6 R +L6XYaM,ʂ%;?#,>FٽkhwHyߌĐY9{a0u完ҫ630|c䡒7Wk5VW6.P ա +Jx9{\QM2Z:p%B܏3b^coS'Y:&:^IgĞ'Є0&5su]h xWO{o3WKq c9$Ay )_a{$yjq~@s &*㋱z,`|ɼ88hZJbACjWܴOS:)ԒjG;4p `h(y=P=P?֨%އ2h7?<(32_kv5 +kn4 QQr} +*ȩrP 3  @PA@1fM[[f_S=Vy|tqofSRh%}]'¸qt%nI' k71̺g,'.yi >k~.Ekvk6?`jȫa%lvg2&[iq VDr+蠓}#adW#X%%-=Jc4c]1& \ z:ߒwqV6_yCLY3!stL 2G_čhZI +Sb2\Wsb,ha`K:ӐΎBR ٝ/w)Dx)V1/*})6h㖑unnFE': zqB;I$Жݽޝя\[CJTPH\؄ dRX[qV + ++8[)r3'qNC~8ssFe߁AD8$6W(F2 +j +j.qfq>T7+k%9 ,`,w5iMlp9 ǥCi|V|̓>Gkΐ3iY&aY.7;TU5|Þޮ^ͫ!nwGw{Fij>~Auŵb /+,A)\**˶V6;E8ÏuhFw۞K֜i~| g! g[0ϴ…A"~axq3 fi=[H6YҘXiNѬS4ܻ#nƳ9o nwcmh l1p }:V8M"Wǝ=ЌfO2_ ޸.n6( 'S| >$qm81S77WpӇ P|k0ʪp̗|I6epRS9s6l鸉tNS[p; .gXf =} ~lb=g U^tJ]PqATUWqىɊSJG ?{ᦼ@zdz'OfK)= e^s|La?|ogRTt?լ3ь9a*6TuQ.N(ĶT۪ɿ]\XS588e2>#pzE6#tË,폮?\4nAdN*~i8SF6$Ax~?`&7X9򧳊Yp,($WZΝ&eZFTFZPro[>Q,/&QT0=A<7cmSyh l^ +\0jw'$ر-E4"":*\ (@3M`Q" k0JXqk:[쏭sS{ԑ؀ r>H{j½B؛a7'+[Y7;"{BemoDSpk~+-}{ʔ9zoM,AP C +Q!݌D,\sBaWq edI4Cs"34BI;3A,ޡD_o9IX8sp9ؐ.p V=x.B^f*l*~,*(dc5\D):$*IXJ$QHI=㿛:&6>tkpBQU)4VAqq NJO] Z<Г?@Vi;˚}P +?;3;!kg2h^_yջN{{ofѼO}d~v].LCO_<ĤVQv 8Mڡs;jX v&\%q6bf~VܦYiӘŞBB:C" +pWGzN> (xSJ߮l5P\%-@03INONzf{/eI@E?GY[ȱю1ƦeϐzʨW 1G'G Q!~ {hpW +]az=a#XrFGQ^e1$ȿ>b~ZjKq.$ HmLBD[Td\-WG:i})% ]`Otӆ^Lkg^-@ub +BQ,x">_֘ m]tW+QJ#0٥f46Id.!aڊFvX~ K֐_vWpQqsP6n?F`A;a&@2CZ0;#lz JɕLJd4AJaqXI\D-nKh@ +ԯ @  {^^Qf{!,+*j(c2n4?4o|BpcQLqBٰo(K̄$;[5My쪙mBi6.9/3?R'92;o +ɿhc~=n`wЧXl=,( )d$譁OtFEqeqtUh4SV`*F-"Ѐ M)iY\5qaqcLOz}d7hˌcnÉxx2 9\.?\cUےۚ{r0r9_g`bmGU7׿M)WT3Wdhm7՟oj8{,'N-8g6 BSL:UFැmi%2-5Xٝ*j FZ+ ,ibTrѬO7.bVek2kjrufms޹gkn%bC1Z~28y~̠ӗqŢSLXO]/{,L\!ك٘~']NU~D򾰸LбbXڶ3$tݩS3FJ%WК`2'3l%9 PF@2^i'bEU՞V+V6(W‘kI5O*yD䶶L{U&\VOpKZ6gCBPiUt$hYHzLJnWl~U~J-rfו8*OPp`%cɇ$[e0{j#5ۓҪyzy)cŭBq_?d7ztwG4E#2BTђ.puk-qiKIY˗חޢR8t'v9Mlgǁ=5ڠz惟тУaG8p3g KcTAHgA԰5hj怆c2a!B7&]e8&m]/]m'I=~)Qʉ<~c0h3ey,c3y-XF-%}W_?H!_:;O6&ӐLxY,1 &;6F[޶L_^R(=ϫʣqs\biH rVB" + GOyp\saT8O 04ڭ`j.S(B!ߵ\0D <||+ _(efbm%bNU?Ⱦr$ a.oB-<ɃB( +Y7Q[`1sVe=;NJI`K cܢww;U7 ѽ f "J=:jxbEpK~LceVqx,߰9h +Q~5쥔EocM}{gS=17d-; S-:_0IUy$-P2RXq.XUsCPKw2#\WT=B9HK*f}vny,y,9PCerjSC _+Cp` {i^2ZtjzBg'ň;}uJc,~y X̀Ed6D+ΙIf8&(ӷӃ<`L-LU-NQ/$- O4 !TrGs.G7uqFDli3->_[b\jmS|Ss&t'\McdmB/J5 I +3<"h.'nJMɫ LDnxo/K84P{2>;|Җ+rI0rBݽȿPMOUbMKM d\[d:=1OUŷq,]$e -lUqyIy !-Ԏ=`n>XA!H\ǂZ|#͆O΍#Z/=SB'O$k zn?J@H՗hbZ":&702m.WKj'zJU,yV#k,T:J=zro*eh~{6?&$:lGƲ\AQi7+ݫ]=N\]㊮Y)$ !* +"0a徔3 = \ EP5bŃXYVŷڏT}=dz;=l`b9ܸ}p0M`im }la3Rejrfi5{ 1أyAK.7^ߙ{\_3)(b/gC14tU- |R@^~R.~ u2ú2Pk WaӝC-<x ?$I!lKLTa+"#*ـG]Y^VYAmcdPS~|DLIߗ9mvShE +SZL$`Dr&M$Ģ^zWH61ӣ"e׼55唓]Cb>z%`!Camq6S!X->A㛚8-$Kc$,IFӌ9ⓒ&c iSJVTP35Us@]l`rΞ/2-d W] 9.8a+0<cg4 n +Q_J'[e"`3 CJ..nA!]#'S4 GhA{܋Kdd98(x񊍢%])*VK9 1A! X<-= nxQ>YI q |~r4G0粱 PUUQ[W{|\BфDM>| +O"`e,L._z~*9q'Yt1 OYS` iSC_T;Ş0m񆠻u7| Xe W#$`-QX; HN+e{nH^o<7aE|J , gwI6|obƐC^6p W\+) :NB́Bm 3_V\~n[[6Ú!#Ճ8Q܇wNi:HmpN k5ҙ#7\~wvqDu]1d? ŶKN4TH/a;l9,ndTezm\gȰ]QҸ_'v=wok/8JsQ :ttTxP>2F!OKq+n"FtUFg%ʌjJMJU1}*!v}Wf&eݐNz{tzms6]ypCʊjWoMn|mYmÍzZ:>tU'W$%C=ʷAW=`HIbQRa"lïpo]>9S))V:#V: 'mmE(y[HFh0sw=B6Ҡo鸕YԱ䐤1JJ I͉弇3=(qQ% Ⱦ+.(݂("( c]]vEDq}f2G'dԌm<ԏu.fAX$xbO:B*"ҳg#NEf(R2SH=8ZSނ̙C'4~x!V$˓)Iͱ at Y`_*'L۫:Emf]`ʂ΂?ȧUAn_bR/ķV( K +o [O\l-m.VbqY\3 +\zޮ;ALa'}ךc'\K*ܘW** ʄ]A6*Wf~ݾx;CM~5O?6BgdD9I<ӫzh57D6ľv] ED;8h_4OtK=H ׃T,G)FY;KD!/w +F3\xS Nht3^OrTqEqeQ] u6eJ*&yB㤸J[ {pm6HZDߏs`^0RA`_'ƣh>j~wz3#u4LQ SQNv"J,=EƘbG=%aVXZV4ε2L Vo1GY\J|A7 eu!{g嚯  ULJ +X+E$;?,U >c\uIt&=0y̰I`)'{:bGNYj8/3ɱI󪂲d4!yQHËY1`Pgw20 ~!w<]M6f= |9{05s@x&m +MWFI`=?YЀWށkC rb~-\^ .IS c.( +ESKTT;QzAYs FӐk8 $(S#$ T;1a4&G<_JV=fҋw74w)>a=ÖYò|5MK:Y͝х]EV\&'~ 8x S후oH+*5aESXr?0,*5tvZzfڊēɇzE”UJ+JE"tv?f d N0vgm38GYT&dbZ|hPmM,{g!ALͶt\ajMx3f9'gKGr'sKg"TM\P:'>w =ls5}c(") +ŕ4/cFbt=J㊻ȹi34/ǵ✪Z1HR[a{B冇^_좜Jr(>fje{ͯ&Qrr*T0ZvϮ04?=|w9Irz|ŕeTA&ծ.EפyJY3*t*:o\M{jw0*\H>ifѨ囇.MgDO (/қCsZ`ZK` rV~_fnPGj n +r/: "F7q{OKOC 08!Va(8 /&*%-n"HQl+uD Ke[oG4WA 5=G|4 &@ + 4%6>?]κa1%Ɖav2LSai0`MA Ni:+6?44N)Z[ЍK5[VEqAYE\XB1(f"l6tk\Ftڞk憚p~M{sY, +ʩ*'C1I=\S]T{+W9'HIiA(;!ٛgP Cw^YᜨRX5C/G{%bkƜVUw.mr,g-+1Փ(pv )\4m: 3 w<$8WR/HVu'カ$'\,`Onz#ełLaAPHYjEOuڤaN&d2.@bUw_v@oggs'ʲ[USTgTU~_X`3k8H-ȜHfRrQW:=|m +2^H~aʞ^;Oj_NpA[RҴ$y_ EDT,,_L/e2-!7<ɩ NݻCE1*Ο<؟8 $^3Fy$>Mπ;QCaQ 8єLDaO HS7[۫ۙ3x>~󯍣<{vݾN<[oKbL[4$/h܀9fPㆆo"neE1U"$a|&[[&u8fJR҈L97L@"H{0Zswɯ"e@/IWbcH*#]WLe"޳ˈJNa~>.rmƛuI(KlKܛ{:{M6Nz\!a탵j QݰȲEDҁg/Qҁsde&(84O`ў2J`ko]fLTYHm$x)Ns`R\ R^DSrk@ yFzJHR7:udW_+*bm2K3ȇԄlM"7Q +/W@L,@%&i+ee5Vh +"bNO/ _@ǼE_' [҈a~7,~G̣gGQ,A<|f2ʆǦHpH$:ξ~8D67AìS\.vLP&:D2XIpJEu-os5 Sx~遗b(B[S`7iΟM109rMR ѹL)rs # !?DI"$7P(Qtv tE %$xhOGlCqf1`0;ĴE#{P =W{y+DmD\z{%s<'[CTV_ϫa$@K*6t@v${}j2HnHǦvIz&DB`e4|C8/LԤ7 +W :a+".I,l6Q|GuxEqfQ fKiA +l, +5*1diAAA9}e_DqZA4q͘3󵘜3{}>_09[C!ϭcے$3vU颱"`VXh`}Qތ-,F_Yה&>2tM2;" &MvIj^ctq)ʩ̮d>b Gs qo4c9; >=4gѩ"]fI$Nw9C$c4wR`яg156Xrr6(O7 u{lbc}IĴf3ϷK>|6ûM鰂n (nU@EbA`"xyG81di.R7]h\ 6LB퇐lE"XKicN|~5]8X fJ q[bN_ָ>sClLi5(2GSƬ-l5δir+j˾?ϸC]]/LՃdM&*Ki'#z@ B;ړC.){y?tA/h0 O75ui<=G$ҹ^*aʿ-qrVɡR`t$6)Z;1;:)%O`F XL]nSV+c(\i,W9ri+Y ꣽ-أ1P c,QQ+ڋ1]9:X1V V.>+\A=w NrFZ{*tD *KnotcaKIi!~}#j~fǛ T*<=۔UJi\ +gHU-2O+߇?iu3W;-L;g/gC`?B2lCꐪ>.²=хW}浼PB 7-7KY֧XY] ZMgJ~3*۞.)@BEcT%~3>vwЪM\uڼ\zm3M0G 絹m3qfq<%OIE'$0v^4:ZRvY8sՕ>uJQ@MTQ*C~R$w8LŠ!F~9nu/Fol#IZCik3oɎPVA[4vv+jP{\aɰ(a܂DdӐSvW뚧j\]Ȩi' +J*qhooq8k/|{#GO`-Й8Aq|;ہ6[]R%d`Fi̞FD1\L^nm8[ +zVhS60E ]`Y=rԋ˼po/ww\{pX-gQO!-p`1Y\T[A^_Wت6H F2\tH=fmY:;'KF-1 oIE9;7~G~+ 뷵&DKյApx*QgXƔ ޜ)K2Es.a3*. _tH\D溙HAZ\nǦ%6H<ıegEni+!ۦG<%B蔓빁\uLO;9\ Њlɝ*:JΔ0ZHo1`" d$W29&$N^vg`67B yLJ)=q2 K~sRPG^_ld˺ZOn}Ya?{t(ޗZ\rE _:룄 N~4 X?]¥WiPD۔ZM7E5`c$P<@SEDaEh6bR&뮯׵=`i*li{=vhb'WYa i=ca >n2uv~ަhUD\[RCLntj39Ŏ~7ALg-Q{'58՛m#ZǷ5x05!K<^~~E◨dł+@:U 9!l^om>iJ<;!]oJQ ô>.thYjЈQNp-6[t7kt-7Flݗ060A4K$XL'=B>g[*/Pe7RMK괒E'F3+N;1R&eǶ$ҩ/M7{e#d%\i=قc2i/Q;+eW)YEY’B~/nb׳ NPRsh>8A I+`3_\^Z%Ĉo xء@ L(DA:WcWo#vP"8 qAb[KGw>k +a K)7yMEjnYC8`0ˆ[HLU*|=*E2;L Dc8q;^Mq|:Eg*smH˜ED́ņ!H;ab,p +]y\,g◄/ ˜֫(ak,,G@)$λD#Xm+u.10S&Y0 _57Nӹ*e{QhAk6r(|jV1HC^ۜ,%וV|wF; + x xA{zr[$ӀJTԀwĀT3(SioY%%e3T?QhB=6@RRIj= z < +.#b .AX_( yw6?p|3TDl7Ygy7}K1L+8\LOҚy}CUidۺ71^.Z*uy | Kf +gfb^ߤ:spBE!e._O̊͊]1\7 +q-ޛ&XԪ|^@M^߷bȰ |R蛟R`c])}1shGgg7F7ǔ;D8 V"q]dD%p!Ht~aXI +[IŸQ阹G#OrɇѵhʛZCt)/, KvlEC@  -3 P,, D +A(Fe(dEclb#j6IӉVva1~]ٻ?ciN:[=uo+R9рQC+!s|tf+/ M!ނ]WruA#I\K^zBcbH/3pqcmU !QI_`FxLDo,~KbM b<_wtw_imĜV('1NIdn<+.uan^͘8šӥQ48!+9r'M%/w1VPYPR`Pa`\A,Pg-.e ~d t,o U-5Ҿ}wxv ;+kF FePi2 N f^.Mu*>G8ḥX؏LmS}[IS@7 u!ckJJIJHT'v۽Z֕{Pcg^]\i\7K'Ap•w@K6NQgOE qK?9c0nA3]C~;U^M{*82iiJ+'4 +*suZCx:e5\+ R,õ˴=ŠUFFw R Ht󐫞Af޵bz͋}?UkƛƳ G#S"eXC0jDPQ Z52 Ђ7ja LU[q ymg¶z#k=-Rb@(XE~P=VOiI` 5?|*?ye+?=$]"OvOgIsyI=B<7C0C5{*jKoj;"w'ZTӼ9} -$]Sq,dc[1-1+o#lCSֳZvCt> O,le*gs簚iIF/)N@v9.&<ּj]|ڴ)V]ƫj@8ʡ*!^x,"w (rAj,"芐.VǪGiw}cBDCe1n@#1aػO|g;,"ް b߸:OD4cbEqy|]$rXOxκ9#qō>oV[ S0>qsmkn׮v ?Զ7NIǵN]-I=i1ξ+F:rL͇zu=7,rİj@xY↔&et?~]~%ac`g|}I!/nF&a=8a/ZoIX wK|cWb +Ju-n|_3E0Ru\` @/:p +ރ~WnOx.߾ofLyTy6T)ЌÄp;m?sDzXȐJ`^ɓc498w?-yE~1Ip H#aIa|?ߛºaV0b$I{$h *;G̶92[DWY\<皵4}'w&Ao?gg!D?N ѷ ޭA0(AA?PLZC &^DF(uHe'>&oжh(A+/5_7p 6}ca1,DV(‡4 +w#Җ|\˾F~v$bIo1ţNO9\ۂ)en/=.#c|m#44_ƙX' ',e;F k0\ .1l0kgGRJm&OgRaOhd;ucTwi .i (X7+ +RDi3)|F]Mr~nJCV]UД/atMY4Γr6l1i~-)޷B:MďVFePtWtTaFF<ɷnl{c`+I_c"8FaUZ[YǏ#F0 ڙg4OHp!Γ< cSr%^GF&>*/>)""XDsL`1lfڎN +-([*ZdU|< BJ*$ڡ7n6=7+O,UiA4WrS6_Y< ?1`VǨANLhUyb[$Ap3Bٳ)l-YJZJ ˌAxj -@_kC 5WjV]qWq+qX^ߪ]`9'=x=#㯧N.]iw_[ ]C}op6Mޗd{"\e]Q^G +Ndk[\VQ q>q\d|;dSOfIJuBUh^e36CWNrJC(jX]{mr区C)UBpu2eLe (64IK`JQ*`rImD E8K;f.ZX|iɛŜbrfèVRRf4Ne?sz8Ax@7Q=:d w^VZ3fIeYֺU?ltiב0Ο2 (zrKrT~ϕ*cErwG`'d0q>gIag +r3%JUEeFj\`4,/N yK\lTHtxm{o6)xU*Vy}ΉZF5yR:5-NF9|FdT*zV{z#XkmնrDhZ-&|7.e -s3y^]Y,)5UU5* ʢU&Jtj?K'9M"Ҁ4KGP@[FA #*4 44Z@YD\@!lQc NTVvO˿~ԫ{s>A^BoM[/;r:p&u{mnܺu NptFSaR=y304|spԳNt"X$ݗ5˽8q Uc`mG}uӊ#B? +OQ8 $';mQ.rU(Ԓԑ"Y-]}^8{z-w/3El,@UcNUZQMTNwOzKXGZ"">SftoM/&: &HU +ծg~QGypAm>Md15zAHtn=`FmGa%0W>c$05LܚzVz`N2"-QRD1g di˾}g\7M=C=N J c:ElzU׹حSKoT^~Z3y:%]Y"k/"˘qO}3 a9k)?oŹs{{𸘨#Bݦ(n<2; <Ӈ k0E'0PBgN +/y{&;Hh4MXl⮤'Nq1eB![~eSe V{ooudܩii2$DɪS}E5/nN-p-\#+s4%! c&1ha -9z0F(>Ӟ +@9ԐDSv @zlɍ!)F}^ZJ'$A8o*?vV#?7W-mCWD5ڋr16aFXXb,K2ȃ2cKz*Hk wkQj/VOpň6OS%4*)|+iC^r Ǻ%kMI:{_t?qeWʴ ŒI_I!"3+ŸA-h:[^!ǟ ,}yrR>fp Uj h?!d\`Z^lHxA_p ,@'w2/_F, k+O:X7΃p1uD0N7 ]{ƱY0gڄɃ\߆26Xv;4eH^WMf-@"ԑL:fO\y+TNFŊ8$!pRzrKaXhIBpйaZ9 affݱ*%sw|uFU/Ռ@IRϝ,) Dzh2̱qJa9;9<_&bSj+aQ! C !p}uV0=bi6LOR 9l`SZYj驻W8t2Kp"T>M_mπ^G5>r]>[ݡLYRoOɯK~Ȭ&F#WaLE]]\ +(R4v iۂ)\%!4Wʪ-[mtm2á*J5dHh?Uŕ'bW= TqQGY"Fqi9bDn -.[bq9[=y1ޏ:w[H_l&Ӿu2VDXqIJD"A ϐ@*S;s9|ss3q.]FܕO,]Ҝ#{WX.'mMԼ2պO]SCʼnb0SG_gmRς-8xNw4%ErKӀً-՗'(\M`Շ T/H$k;|W[X!f㩶7옟撰t(vg-rdOaB* +e}v[ľEm'ere芄VAt#74'?Cr|O0-? 'x-moT7ʽzFzB/FLeao᨜;{AFASVW5궴luM2>@cB,W>g]1bKЌQbء +2cAAIG^KM;%"xW \L萺W ̳Lð!n "8_{ ,[8;;;U ?:$eUxN}@7+6⍶kBH芈䔋;v$Erx[ӹmUŹŹrf~#3fx~_ >CEEہ{$#L C0~_woj6_@aĝ ܶB}e]u(q| +EpH:]{nI5L|9%э|TPݱ+_ڔ#3hˁ(ѨEB>]뎗֐a䚔7ڄ^' a׉=(}'=E0I[&J8z YU>ӇX5]b&Qٌ*[2cfB +f?/9G#5avgw/Q8BpZq. 2y'LyO,5T4mSn}7P,:r +\RH|ؖ[Ζ>KMvaꓭaBۍ־ zbYoMcǻN2`,12[)ƃz{qq{5(. d/a*Li0\`j/LvJ +C,nx?(3I\@Ì2'e L 0/ҜQ cWPɭYV"D7 Kpwt^PUjn4UK +Nj4h0!|Z6;pG|ֹIHÚU5cٕ3-+oPU0Pg N\6:>&r}hHPZGumG裓!aZ挬fKs(*C%tglAi}gQ.m6* b:)ۇB{äIOoًc(J_C r!pϭ_$i46r?,V|B4rfc%vd)vm+:7>\г<90p.iMQ,ٛX5)ަ|y8jJܩS<3Hz}DV/=~cno_暲tz\ǜub\V鲺SgY&o=xgſE8 +\T Yu r, A*vpr)tF2 7p p63|1 5RpFrP\Sj/8U($+\Jkii`|yCtj/5-f 7J`te?Iн‹\AU]WM贺4[3E7Bysp@@AE5>Q V"!\  +(EPK|Mjt:n:|3kꊚUurҰ?t\V hϓ'8nƣ9S=SDžh};kxٸ kzՅwŔ7JʹI9۳wH],_W!qz +nk/U_Vyz$mS/ <`a +مոM%fҭ)/b[ GJoy 4z0Q.>_ /bݝ Qej 00uRT>!]5M?QiC)aېckїw6ʈYLɭrb{M:Ypg'w&~8r5ՂEdd#@MΕwZ00>& 6᧣0_J6223l'] [wUQ%*n2dwP[auO|$@L]~gzզK M,&(f $\k#+n<-),9ʗ`Kq¹`݁ωW`!`폖`遾Vm(c/l?rd㷜K?-dZwD/:R@~ط|:άѬMD}LP|36SH)*b;jLwt[yo|f +欁Lׁ}DLļœB rRDgTT[!~A&`-)..)+.] +ÕvDhEw?BAzL@!wCmjp TK[O6KL>=MªECsLrZ 1Ubղ()*gXMPS1=(sKy~T:ZtDsN̋ D|/d?Q B%HZf M|MdDŽHX']$+&+οxLY$#H~cA[n#w\!_k/-Kyih^׹Luܗn\.?^҉nO7s=9xz@x4&YUBa>}戱$.LYD!YLIkLC%+pGρcX0@]O@^xv&/J'p؇δ3õW *\3}8p7ė,a}vj\0ox+s }N 7S4W"%W>gZt"չgj$ңlh\rT +w}5@1:y7b(NW pP"ah@ZS3}Ӡ2)4䪯Ŏ.&f*؉ZN (Џ̉7Kk6ĀR$-&9ǻÞףdx)+|s>7"!PA$ "2A4lg_;ljAlUv1 FKF# v͈T!cCb'ѴU8ce;|e~߱Ï%%%J&֚6:f뉧?yLnrc5/9Or +OΔ5oD_vމz܈ﳨ`=+G-D$f|"ETPw&J?Of{L5Yele\|_#7~J7FNe'"m78I |c&)+. d6ueHfKljVf +֐V2^څU+ +?B9X% yF}D3Ӝ/ZM'm +<7~l#B̈́-\/j ?dv˜9w54wQp= gOo`ୈ' v]֭E<mi'Z} +",`'G#xuN >$ԺG"y/GuxlENMT&1PXWoqĤ ɎSL@ufp׆ +lbke,vr_;ŔѨ[#@^VGE.D0מ'M()iِSrgG9W'(j()$Û;:{dk8^sѭmiZIJK+{\6'4ǻ 4 nte^tw#CMa7eT) SABd\Tdt@U`ExuGN?\vNNF>tOkza'R}Al}|,3:_4DETZ}Jx~SFVy}4}c̈́̿;S`vX/4=j+?mK)8\b^&jcMSe[TĕzF 烠C2kT懆1ss??׻]4Ϝwy^ɞ'k##$*Pw{TL4pw3m u3U/AP:<35Գꎤ-5MC_|ĵr {G3c/ܼXKg%|#E_ scbi0mUya#Mq"U{*fAm! P֘qXJpƊy 7$[(Xv-q Kt%ujE`!]"~RGknkSF+鏚 Mjwl))oioZDh!*o/Lqg4' :RYiEjUdY YpgPi8ح@?b + [i/qzvRŷt"'lq7Cڻwi\6S +-!SxwE%z{8ψIŦ&IH4EL5P 9ySO=Y-iO]Lf=), +fO+1C^ɭj H&»֝f&*U-^TP5 :Jkm_ۨPI7zeUzbHm͂@yMsy'si+?"^\^'g'3r.[RNÌ{ +`pq6ĹW{tR$PGpM4p^ݦMpu12:=" ^م8Lkb%6G)dU>zPØ,9 Ƚk71Ttnk<IސuaaEó{NhZ&iЛP+H|KE(EJ(R䮙r _KV@S6g R/j+r9 mijvR"_v~i K"\9I<@~XG RtlsHQ§e\e2$m",23d~gE"BEڰa3Q<3$Sʕ; @E +< ^W<*bL*˓q!WtmK\5%_w4io0[#C%H1kiLJ`\E"Iѥqօ")]qs_ӯ|TlAV$pNT*leբ':uWZ Hb^A *p{/"Gx7wh`fS>Y6P3IAVV,zX:W> rz|+?uvc $-;>6U7gGҹLj(-?ws4ږ]Sl4MU\{ZFHD>4%MsMav٘W꟣ +ʕifJOT`b99@?LP&b2)w0 ylP6V4;(4vڰ򼲪Y`i0[RB"[QF1nUT <=6z|Q W=s5ĭlB)"N'E(23de +K='ZGب(QW<4o31}Rn^9Swv/5ʇ|c0)q>&9~¼٥|iU =7Q]sPRr6ê[6/x +֚d`\Vr-}ce!%7 ) +q^n,X8-SU +J34M:KԎ4D8f +$)nǛ>e#AjDyKCW ]w>UbOw̔jnRYrv+ktf}z`o6O\* 5hQpC8.!wZzk9Q{g|8 ֑ݵ&:<KTڽJfDOlJ'\hR5{W2ŇE.pcw J +DWKA&._if +`=LaHG^m­ף[l=">wMe;Шk^~6tyŗ1$+ >(xB ' ̓lQY,L<\uѱ +ܚ9Y^)qJ;Xw.VQtW:/*?uOldn)wO͐"y~/1#Nd ~LhM̕}5D!CuD9Y^U0V*iciBwdxGQ*9=pG /?X 5m3&G´צw1w ~?}]{nSrIܲH(ugU̇?2 _-g+vv̖WQ[-%/EϚ}Gָ- +>g20AeS]w3~חdS-[oU?>wUJ}7];o~IN[X淌%ݧ~g}(e搬jBtɇUNj ӼK PAXh0H ^k搤27{h;.>M΍3J}u[-1[Κ}wJ_YnXW-X)w/ؖSbcBc`dd6WiJnVn%\g +`He +endstream endobj 74 0 obj [83 0 R] endobj 75 0 obj <>stream +H\j+9~^޻X-JCBd1LlqyQcTuJƧl_޼/u~ǥyYΗMxͶ~/Ofkŏ|NחfzZ>n,޸foNk }i8T;-sḬ۲ٹ7rz)|Y~~n[SO_-P; +endstream endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <>stream +H= ]#(>k^IzU$ & o2g/b>sp5wh4F + ) yҩ^UUSy v$ e$[ëo;:n ULkuS7H:ȷ cOz5;uSv*Nv{ eGS;֕DE&x0./? +endstream endobj 87 0 obj <>stream +H\SiTW~MwU`B5KaW l *4.(" DqA(8 Qdd8A$e49jbge$x o3̏y?}~Ɉ„d2블g-rY>f}~j~XI'.S8E&Z)D)g={Űb=`L"'XXi&[>{3Nh61cLCQNn!$}=p4!"IPc頿 v .n {XCEèfMU?AII_KwQߖ,_Z)R;INdcAʈX;!2^-+%{agnlͤgVZ ;EJĘ +He(`'Q5npUhj42"O.}-& _ml W%@XMf}*m(^j{ 3 ۀ KTeQC` V'0 ËJ`4,X+i[n0[$F씘ǩ'8;я*K5h +D ̯r7h6HS{V\M =v}\}AX0ϭ 13Ѽ;\G.TאB[fk?jԈ3֡-W] +z#I)aDSڅHIa#Z$C}JGαqyl!b34 .9C91vut]1-E T\OIOOw~*@)N;T.;(e,JC-Ld6]rZ,ڞtVoieLI1%U +l 79^bLWLY^XY,ᄡuhS{w7^SOLJ' q8ݬci!Dx5c6J[vmWn ?fffX .$4P-^4(Y\( x4̥|߱HI7̕C-ݼeOTzZb M(^P(x~#"ĥN`P +<A`ۻ( Ot=9fMn-$mF޲12I8Xw+:, b87烯^Gxn9K8QK(]%/eE%jt@cVTZ]PcQ<8nlTjAAvDQBufw_4b7?2^3cOY@9.Ya h}q^cOt\5%.w8C9ݎ߱8k酪 wN +M + [L=FGKÉh|'й!%GEە?=a*-GHlYO?3l#.st~>F9 щC:}uaA q8ps53` j@3mmfSk=*6mau _v`m_j l;S )̖-E80fP"e U˲n=[w\0 F vk`$/Jt쟂zV<\\{x[һ~MU^|>KgG{]79W|rg\XVkjrSVghJ+6z܌0(=5oڦdVm\״"O2XM ك y&d<5}^hȩ=^Dt}.Zuz-qgQJv·S購XP\a" A(:ER u|:iYvlpbp[?ЇNzrZ@0_c5 2_P}8(Tn!(HL5+mAK,G~r~#y +(緆"L9DR b*`[L#έa `ˣR XS[ܛc4 mVsW'dt{MEwǤ_Jl.Ѧ0Ahs49q\1E+._]Ӑ03jr Zp]o-W w&&#s"[Nj[X +CX ]L A6Ah 雐 1u"OGpȂ-:-[9.k6,XJ#gJg.opܑyCo8ُ 9 *ԽGZ+(NDξ0α8}5!B_zVu l9u<*[Ѕz U yF[8߸P4z( Ux#{ek%Y>.H064KcOo?Z`b)~ +_mAi;Ž; -TA f>f~I򨦮4*y9V\K_*nU+.UQE#P@ $DDF#E6AtPG :\;?޹~o3IV 3`=Q;H_{ poɯX4& $ ڽqT{Z힆Ob2 q"B6='6V8{IF 8.a9G)gxR{cD60Giq\_` +q!|w9F\ ]<&1/|r ͯ1dͱY.;sƅ]kl. _j! #5$l_jA\_n$lg2zf^ӗ]0zcU=WhfkJ喰"*Q:Ɂ%ÚT\dl֐8u bQ ?,$iq9l36U#wLض5(7W%;OI_4%A?<ɉ ž iv*E%756艫ؖŨQbSoWq +- -aO*c<49x{(=&33xT;s:lNN9"*Џ +6FQTp"KWm_um+_]Q#_ +ž4K_i5(v*C\GЙi|b.xj63BvJV^pE>U7nV=-ж$Zm̘.->TW'ô)c9 [} 5|i2&nPĄIVW]8fm%˛s=;QPf*;h=P:BNN3emf qmF>Ƙ[%{E=$U^PmJ@%g4zyd)\etYbm)52HIY#-rtS;ľlK)B-m5vܕA2ԌT m2vc/B9Ş*`Lt7BIEpL}=IhWtE8V(˫?[|ciDZL8AH^O߭i EoqSk!6B^&$֪dc>xښ7v9ׁ9{:M#%EGK+y_,qymgFN.&i3p3O6ܜ5b*Tч|E GvI)?w$ւR& oF +~[?+@|eWyƶGxؙ&C$:yR^>Bk7W}Ⱥl1ů Ë{ gf''ke:-Fb=r 1IыâwT8.N$[Vn$W3o4IYʠԕ,Vʤ[N9P;R.087v?f).[$P(C"΂Ut뎦^\VWo#pۭVs\e#>g85p@<({S)<S^ sb&p-'g%|&n6_`(N'q \Z(^ 93rw.[q(\AmGm(h -faWx0-qF01np!dQpeZrvx@l}xd"2`K0 7p|`*> zQ''Dx !9NϠ}kpxge~eil`;<dtPe%'=`9PV!%(!OA`9p2l6g)M %ntH3K= ̤5Yn.<Z.ׄ me(kF-aq^/Zڞ+Ya:X*Ώpg*VRtc^ʢ(& q?|)||Ȼb>7&ʆ'"lx>xқT 2ɹ};|Ԡg䲏1]xjyT*{Z;R'KD^i +Ԣf4#L͔1NA3ՐS[It%"tgk:ל9O\}_w3"E"TJPUL[d=-ް[+`3h ނS|<'9\}E{1q1])j$׻H.H\?&"\V2Hi^KQ +59eG5eEzUU- ;'6-œw`2yhA 4Zы䜡S q)]>-a!v/ uIƅQZq_U[{ף#^ :v>y\/)l[PwZ|=yƺo]9, "d+2(d:;-A7٘":ݚxY[J.bg4E`R|X䖩EO]!,Z ruU#:!5LXewX?4 Skݙ0GU })dt qVq: nB!o` &VwM/#=9-Cts E=r"mkE&dtE EXo԰8ɸٜLe\ޡPP +7dգMW>@}tHEl݊\R-Xtco˘쮹k.xH`7|f&FKw$*#E9gK.\ʀhF#s iD;R(RCg nφ0pkٞ_j`9. ;h3ȝ|ZxJtݕDcNM6V,iI8> gߟAFt]ˬq6L/Ked.XֿpZ>cB<ڷo.6nd?@ ]\\t̍?m <#AkO'`WXs4[ e Er*]~L3 ]y| 1\yHu[,|-M28(E +BQ%w|E'{%E:ZIɽji@ WmLA+SSO'Hɻv +wJ%huމfqB/Hyi*`_arr(:Qy )U‚3+K5g.g +w$D,\}gA8qJԦuG4^FU;-4V#jخv_GTUml֘j +Ԫ:)BMQE{<{.jY$h|)[ۏE;?{ KoK?-KQOO򟟬r_f=k2ճ iTB͉mI\7'RO%Q, f +.J,Gz9q֣%)R,A)Uzww&ifEvZazg&z B +]}A[ aϙؾ +\\beeeM|>>/(w* x{/v:R^y)=ڒ- T;$g1  df'=g|琊 1L~nnRƅt4`=9iGSiTyPs<9ɯ;rն;Y+9%^yy%y:(ba*U-sw A''!td99SJơvVI;LX{m{ZZ X~ eڽ`OX&q'D!DBp(x~"i"Y>h)^`hoj.O7-Mmưw»GJCFf{V֚|+$e)A &s\aMi\]33^c'zuQ<j\X@pEdž@1QcÍh- BūxU\Vœo}tye% Zc"FyGe^Z k)dp\ +,pf!tE&UMS#qfEd͆wDMC&Ёk up~}$Hy|'θaAAC&XW> L`Pvv3rOrKݓ_s& ;n,,*7nkNBVö"Mi2i**Wߣ]]-nE%!Z+ЎˍL]G}qu)-8M)[ͦا1Okp1?y8g7X5B@!?e(AHBpo%DQ[A^ 0 [&SZcMy HjdکY凍+NY^[W_Y^lk\vJnBp 'Xޭl?~Do`-'E'wi|uM V[yvLp!A;t_A)iG@qPuf 5Ӗo˄@BzMݓAC`V_DG%" EXT{TؖbXobfY!{s}*t!9D{ ]kƫh +I. *:$#]y |e 荮d1{ +å5eO^pAWw-cRKYFn/[2!Y9 wQ I͑ҕa*31_3߰o; :xaef8N$1Ь3n}֯=i{׳NF')s#4S'J) 1ڒڎ='ȭQuZT6Wg\\<~P|fv8ىҝ"R5'~)rr2HR)-hMKu}0,YvV+ׂB=P?(R^ v\/o]MsX O +E0-vq@+(DFm2PX D [—u Q,LIȭ"]Ф[0$wu!P4fwʓR"DRtL[tyR\\1d*ZW $efX +m-úY-DPѶJvJ4}Ftou"XqKXm0rOybo./n3[79?IP54Jw4Х%:aQjH+={`ThR_(+K.OH%g> ѓA} +Ժْx.Q6U'Zj&Q*rU + "2GL#/ !c椧sTHsF@|s @.UM}ADEnꝞDGr|:Q(USgfu'>JkA)OGJx|^~Ag2Nxߔ`j7kE]4e-JkC E}B1@c\+=4 #W-i\EfcH@\88QHǠcLLjȠ: XLɲӲSs\AM][؀9U]O VQZDjIEDB1 +<!@ 5R$@@yh"bQ+wjV{պ]an5˟XLm8u7٪ʏT;/V1L+.4Ax,.va}yzpv'*V~`u/7֟3qYCYQ~|j*.Ү?Qg0ä7ыԕ!b۸P, X#;^m0_l"Mn.GK %%{ƣyT3Ύ`"k:򘖢ɋApZgaC7*I29(S$ȓ8f:Җ֜/ C&@؏9]IX[܌=9&&=)=y{*y;]ǩAp=85 DOO[eXfh3Z8jxIy *\sCBy"sLN`Cijviզ#r`&n/L.ثT)K7:BL&ƶm8WnUqK98Z'qe"$&dpn|t}xKvn450m {jfDyZvSⶖ?ݿ|Hvd+p<؄i۝GAy\?,ܧ}0faO=wqi} ,fb/Yڳf?W&(g&ɭJ[Zx!^<Jy#(ױa3}xN2:rKxoiw.xHk^fz^SKyKdWi&ly1AA7V\s᯴wur87+i ʆ ]~Pzo~!1ڻ9oe5I oͱ?9Ab<sorGo(ni05p1 +0C;TH>+ +A/ڍwueIg)345wm+z*.s% @oޘ¦+uF6> endobj 37 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 17.0 +%%AI8_CreatorVersion: 23.0.6 +%%For: (\723\732\710\774) () +%%Title: (白皮书9-23-B.ai) +%%CreationDate: 9/23/2020 9:49 AM +%%Canvassize: 16383 +%%BoundingBox: -3039 -10639 6131 147 +%%HiResBoundingBox: -3038.77659574466 -10638.4999950105 6130.22859775509 146.057975960672 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%%DocumentFiles:D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\112.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image003.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-9.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image015.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-8.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-7.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image007.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image006.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image005.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image004.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image002.png +%AI5_FileFormat 13.0 +%AI12_BuildNumber: 637 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([套版色]) +%AI3_Cropmarks: -3038.27659574468 -3493.59909532577 -1847.72541464228 -2651.70933154627 +%AI3_TemplateBox: 3090.5 -6532.73789579497 3090.5 -6532.73789579497 +%AI3_TileBox: -2846.00100519348 -3352.15421343602 -2063.00100519348 -2793.15421343602 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 1 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 3 +%AI9_OpenToView: -2424.88334434483 -2961.01477658441 2.73144400945827 1789 1036 18 1 0 82 125 0 0 0 1 1 0 1 1 0 0 +%AI5_OpenViewLayers: 777 +%%PageOrigin:2784 -6928.23789579497 +%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 90 0 obj <>stream +%%BoundingBox: -3039 -10639 6131 147 +%%HiResBoundingBox: -3038.77659574466 -10638.4999950105 6130.22859775509 146.057975960672 +%AI7_Thumbnail: 112 128 8 +%%BeginData: 6122 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45A87DA87DA87DA87DA87D7D7DA87DCAFD6DFFA8FD64FF84FD0AFFA8 +%A8FD63FFAEA8FFFFFFAFA852524C7D7DA9FD69FFA8A87D527DA9A9FD63FF +%A9A8FD05FFCAFDDFFFA8FFFFFF84FD68FFCAFD05FFA9A9FD63FFA9FFA8FF +%FFCACAFD6AFF7DA8FD0AFFA8FDD5FFAFFD72FFC9FFFFAFA8FFA8A9A8FD64 +%FFA8FD04FFAFA8FFA9FFA9FD63FFA9535A2FA9FFFF84A9A8AFA8AFFD64FF +%A9537EFD04FFA9FD68FFA92FA8FFAEFF84AFA8A9A8FD66FFA9FD04FFAFA8 +%AFA9FFA9FD66FFA9FFFFFF85A9A8FFA8FD66FFAFFD05FFA9FFFFFFA9FD64 +%FFCAFD09FFA9FD64FFA8FD6EFFA8FFFFA9A8FD07FFA8FFA8FD64FFA9FD6E +%FFA9FFFFFFC9FD6AFFA88585A984FFA884A8AFA8A9A8FD63FFC9A0856085 +%A8FFA8A984A97EAFFD63FFA9CFCFFD6CFFA9FFFFFFCAFFFFFFA8FFA8FFA8 +%FDD3FFAFFD0BFFA8FDD3FFA8FD05FFAFFD05FFA8FD6AFFA8A8A8FFA8FD66 +%FFCAFD05FF7DA87D8583AEFD63FFCFCF845F84FFFFA876A87DA7A8FD63FF +%AF843B123BA8FFA1A17D847DCBFD63FFA8AF84AE84FFA87DA8A87DA8A8FD +%66FFCAFFFFA97DA8A87D7DFD6EFFA8FD68FFCAFDDBFFA8FD05FFA9FD05FF +%A8FFA8FD05FFA8FD0BFFA8FD4FFFA8A8FD0AFFA8A8FD06FFA8FD0AFFA8FF +%A8FD56FF7DA8A1A8A8FD0EFFA87DFD04A8FD52FFAFFD04FF7E7D7E7DA8FD +%0EFFA87D7DFD04A8FD50FF84FFC9C9FFFF7DA8847D59FD08FFCFCACA9FFF +%FFA87DA87DA8A8FD50FFA8A9A0C7C8FFFFA87DA87DA8FD08FFA8C9C1C1C7 +%FFA87DA8FFA8FD50FFA8FFA8A8CFFFFFA87DFD04A8FD07FFA8CAA7CAC9CE +%CAA9527D7DA8A8FD56FFA87D7DFFA9FD0FFFA87D7DA8A8A8FD55FFCACF7D +%7D7DA8A8FFA9FD0DFF527D7DA17DFD1BFFA8FD31FFA8FD0AFFA8CAA8FD11 +%FFA8FFA8FD52FFCAFD6EFFA8FD11FFA8A8FD0AFFA8FD50FFA8FFFFFFA8FF +%FFFFA8FFFFFFA8A8A8FD05FF7DFD04A8FFFFFFA7FFA8A8A8CAFD55FFFD05 +%A8FFA8FD07FF76A8A8FFFFFFA87D7DA8A8FFCFFD50FFA9FD05FFA8FFCFFF +%A8FD07FFA87DA8FFA8FFFFFF52FD047DFD50FFA8A985FFAFFD0FFFA8FFA9 +%FFFFFFA87D7DA8A7A8A8FD4EFFCAA17D8584AFFD04FFA8FD09FFAFA98485 +%84AFFFFF7D7D7DA8A8FD50FFA8CAFD04FFA87D7DFD04A8FD07FFA9AFA9AF +%A9FFA8FD047DFD54FFAFFFFFA8527D7DA17DA8FD06FF7D7D7DA87DA8FFFF +%7DFD04A8FD56FFA8FD057DA1FD06FFA87DA8A8FFFFFFA87D7DFD52FFAFFD +%07FFA8A8A8FFA8FD07FFA8FFA8FFFFFFCAFFA8FFCFFDC1FFA8A8FFFFA8A9 +%A9FD05FFA8A8FD06FFA8FFAFFD07FFA8A8A8FD4FFFCAA7FD04A8FFA8A8A8 +%FFFFFFA8FD06FFA87DA8A8FFFFFFFD05A8CACFFD4EFFCFFD07FF7D7D7DA8 +%A8FD07FF7D7D7DA17D7DA8FF7DA87DA87DCAFD4FFFFD05A8FFFF5A2F5A5A +%5A7EFD06FFA8527D7DA87DFFFFA1A8A87DA8FD4FFFA8A8A8CAA8A8A8FF5A +%365A5A2F7EFD06FFA87D767D7DA8FFFF7DA87DA8A1FD57FF5A305A2F365A +%FD06FFCF7DA77DFFFFFFA8A17DA87DA8CFFD4EFFA8FD07FF7DFD047EA9FD +%06FFFD057DA8FFFF76FD04A8FD50FF7DA8A8CAA8FFCAA8A8FFA8FFCFFD06 +%FFA87DA8A1A8A7FFA8A77DA8A8CAA8FD4EFFA8FD047DA8A8FD07FFCFFD05 +%FF7DFD04A8FFFFA87DA8A8A87DFD50FFA8FFA8FD6CFFA8FD0BFFA8FFA8FD +%61FFA8A8FFFFFFAFFD07FFA8FD06FFA8A8FD09FFA8A8A8FD4EFFA27D7DFD +%04A8FF7DA87DA8A1A8FD06FF7D7D7DA8A8A8FFFF767D7DA17DFD4FFFA87D +%7D7DA87DCFA8FD047DA8CAFD07FF7CA17DA8A8FFA87DA8FD52FF7D7D7DA8 +%7DA8A8FF7D7D7DA87DFD07FFFD057DA8FFFF52FD04A8FD50FF7D7D7DA8A8 +%FFA87DA1CAA8A8A8FD06FFA87DA1A8FFA8FFA87D7D7D76A8A8FD4EFFA8A8 +%7D7D7DA8FFFF7DA8A8FFA8FD07FF7D7D7DA87DA8FFFF527DA8A8A8FD50FF +%A8A87D7D7DFFFFA17DFD04A8FD06FFA87DFD04A8FFCA7D7DA8A8FFCAFD4F +%FF847D7D7DA8A8FF7DA87DA87DA8AFFD05FFA87D7DA17DA8AFFF527D7DA8 +%A8FD50FFA8FFAFFD05FFA8FFA8AFA8FD07FFA8FD06FFA8A8FFCFFD6AFFCA +%FD56FFA8FD11FFA8FD0BFFA8FD50FFA7FD06A8AFA7FFA8A87DA8FD06FF7D +%A87DA87DA8A8FFA8FF7DA87DA8FD4EFFCF7DFD04A8FFFFA87DA87DA8CBFD +%06FFA876A8A8CAA8FFA8A87DA87DA8A8FD4EFFA87EA8A8A8CAA8FF7DA8A1 +%A8A8FD07FF7D7DA8A87DFFFFA87DA87DA87DFD4FFFA87DFD04A8FFA87D7D +%FD04A8FD06FFA87DA87D7DA8FFA8A87DCAA8A8A8FD4EFF7D7D527D7DA7A8 +%FF7D7DA8FD09FFA87DA8FFA8FFFFFFA8FD53FFA87DA8A8FFA8FFFF7DA8A8 +%A8FD09FFA8FD0BFFCFFD4EFFA87DFD05A8FF7DA8A8FFA8FD64FF7DFD04A8 +%FFA87D7DA87DA8A7FD62FFA8FFA8FFA8FFFFFFA8FFA8A8A8FD07FFA8FD05 +%FFCAFDC5FF7DFD04A8FFA8FFA8FFA8A87DA8A8FD05FF7DFD05FFCFFFFFFF +%A8A8A8FD4FFFA87DFD04A8FFFFA8A8FFFFFFA8FD06FFA87DA8A7A8A8FD56 +%FF7D7D7DA77DA1A8FFFFFF84CACAFD07FF7D76FD047DA8FD56FF7DA87DA8 +%A8FFFFA8A8A9A8A8FD08FFA8FFA8A8A8FD56FFA8A884FD04A8FF7D7D7DA8 +%A8FD64FFA8FFCFFFCFFFFFA7A1FD04A8FD62FFA8FFA8A8A7FFFFFF7CA17D +%A87DFD0DFFAFFD56FFA8A884FFA9FFFFCAA8FFA8FD64FFA9FFA8FFA8FDDB +%FFA8FD0BFFA8FFCFFD61FFA8A8FD05FFA9A8A8FFA8A87DFD62FFA87D7DFD +%05A8527D527D7DA8FD63FF7D7D7DA7A8FFA87D7DA8A7A8A8FD62FF7D7D7D +%A87DA8A8FF76A77DA87DCFFD63FF7DA8A8FFA8A8FFA1A1FD04A8FD62FFA8 +%7D7DA87DA8A8FFFD057DA8FD62FFA87CA87DA8A1FFFFFFA8FFA8AFCAFD62 +%FF7D7C52FD047DFD05FF7ECBCAFD62FFA8FFA8FFA8FD6AFFAFFD6FFFA8A8 +%FFA8FFCAFFAFFFFFFFA8A8A8FD62FFA8A17DFD05A87DA87DA8A8A8FD63FF +%7D7D7DA87DFFCFA87DA87DFD64FFA8FD047DA8A8FF7DA8A8FFA8FD63FFA8 +%7C7D7D7D7CA8FF7D7DFD04A8FD62FFFD057DA7A8FFFD057DCAFD62FFA87E +%FFCFFFA8FFFFA17DA87DA8A8FD62FF7E7DFD05A8FF527D7DA8A8A8CAFD62 +%FF7DA17DA8A8FFAFFD68FFA9FD6EFFFF +%%EndData + +endstream endobj 91 0 obj <>stream +CB٠ZJ%!v쁟S e*|CTS $wC +ѽ LEx D +ErC FނfIvC0 W v+b~Pܗj^C8S:(JR\6[P~,Tf \I0GYgj ;68T2mMAsRǃqN#7ao&OS:j z)0:IBفg1ZkSy{/!I]fʥɋ*ЌR>ԮDGe_]wBll?JFz,s' rqd?JBE6ȯ]ݒ%(UZv6SУř,8hNX< +򓵔2Fʒ#&]g-$:R^OU]9#+q`w=z@uy>@6|cNZ +w▃,lr_/:Bks3$=+w&twʂHka;Y@Wɂ3ljt՛b`qh6UiR/m%CmGȬ/LBʝ@e')rP𐹤:PkgBaړP1:쌱ˎ#B92XPWoqXf$T.‘ʭ.Y$Ī3EHDXl֌)Mzr+6XU&c(]WL 1W#b+WfTzS0}sћWBnSo짔4bKT=&erx=Eh=XzkacʋQBDS)21>] qb7䝀H 9I(le*3-?s%2!Zz&xHXqUׅ/3>\ i?ZC|I=fol&q 5϶\[>;_ [h!j>=.rV%@UB\,PuP@ʪkP!؍|=ȕSYo^N!,F"30a+9Sɜ`k*k1=-@Vl7| & +\S>y͸32Ikqǣ:ECb~B=( Q=mkQOT}v2oB\) $.' c h!.fqW ϡ0z/=D3g8m܌@nU>aʠGW=8aXo!̤\K׮)0ێI%/wv|W Dj@d/w'2vʀA@BlQ#6Wp'N@kͶV;>n;G~<3ԇJeXΑ4"i7B;ߘAPFL %xpP(i#@QOe\{*ԍgD1@D-MǠr^n([RQ')j\)NJ@BכJ롛#&DTT(SP m 4ft]\l&Z܇8`*S8*I}Z'ITmDVRm=RBدp%D"3Os{MŎvۅ%GLȤA˪ +@ĭcw݀Fʼ!v\$~-ql k#rPθ$J1aqf\ KU >s.K{ uۃYpVcQmqg׽Ήm:vp&-HlDhG;'^ ?ӆl뵳絃ov…m'L'f;ɂ%9eR yij0@>w:UBX +<)љX8@v2Gky2Sv@0\ +vCzqO"I].{$/ Hj?jW"D!x#0~%2rխqy`g:O2ŷV1)Fzv^vc\tPk>='^ (_@P?hg݋_8B3.VR-N LO-!_c@š3#4T\s5 rᛑ'int?b|&OSlƙ4ل6TkVA* A?^A]I.@{dmڔ)0lBTHMd;9x@" +@nVMt2%uBdк6 SXzs(Xn y07z"-̀yk`֡PrA;`6b-ȍAz-@jĄ:S8 L$!T4 <'dpŭd:v3? 1緃F&r-8^CfWnlŃCrtUȞq@ (cMi8H<Q7US`N1I %u.{tξjNX!u$f,w÷\T5"toުC7*oD\©8\9nzf܈@q̄'!)(c'$6HWf= 1eKQ QyZiעM7 ia&Mȭfr-$ݤv&$AAK^vyQ 2˒[h.#kޤB`O.#.;us EAq@;HvH^Of[?GaRkQ%[sQM<| 466m/HYg!ơi'$2A 0"Iŗ7jퟤ+RiJ f-G05xr@X ae=$P; py4]>ǭ)l ՍfQq }Bڇ Q|XUQC/N 9܊ŭe¼wI.Ʋ3aAm&՘PF#0 Inͨ2 +Uĺ )GE"k D^#NyiCxaGJBh ˻|텸AJl2?Y(XeUKtqT~}6Į0WDsN,j0S]27݋Xf^JN9+~鮇[f7| HڍZPJ-Q쭈TfT\E儱}lB=p&2Jk!Ù*]e'afD魇Ճ9R(xb,!! <0WzB|Σ*谾\DrmrL7.&j Px]&rÉlp|`-^G-?Wǭ]<ú[d|DG7&[<Ѝ,jOx S^L#`!ݥORB\# אkO'|y%"ElT"UJ1@Սr0̔W\Qǟ͠5ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk{dɕGp `r_34f#\ 1p( +%(*¦CЅAZehä"WKp.| [kg<>S4%Lժܙ}XmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwwVwk_|ɫ_ko}+} wOߜ]wo]߼s~zs~uyrWk}\u}x%O{};=8ϫ4+j+GI8˱=|^=S9gtyژs?v15}Cn{ʯ嫯7ү^}ӟe';O١q?/o/?::2gw_d?\|OgwY}\G#OnȯOϜ~|~Oߺ|o}냷.>?ߋxxw 7No޾zr@3f]!9<{xNf m 9nƻo\'g[lخo'{zsP +o\"?Bw'Bg/QoS;Y{77_lA}z֫`5=Zg'Փӳo^|Jgv~;|<%]}rv}rsu{0/!AwN`}rf+&CUiy՛{cƃqz0N8=_qom%6ߋ\?>XpЃuzNKif-uwՐ]QX?'ß忺KQ⃹W[5L;܊M7k6lwgЉb;OՐ6?޲NNNO;|[z;Oj?8OO.N-W8 \ly=ym0u5{7+J+[Vs}xKq}Y7U.ҕ.vl>\?FBD/;g`Z8QBDu0Lx/^<Kwњ͓'\5n Uqzûw<}9q\l#g³;S7_T[;$-Ɋ^QbEa߾l!W8okhޜycm9x.gakoA]'s &rߍ5{!!.=ˇZLy@ +Bys;ķ ! W%7g!Ob-7f!Q..>x(N. !L!\9{W_n[oZnAHDY"x6Z<ŃkZms]ο团) 7?=8yW' +1|(o?߶8VCvFY+/TJKͩw}[h `2NVd\=|\>3i|6o>ߪKZlwx뻶/xCyVfx~{-nEYWbUYB>dq\[w)y۳XFF;߽kS"ٿ'ːjtێE!3ޥLM[osnᐟsٱyq}`;>,KG `ܶzaȽ;yƭ7/]8{VhKۓmuy*^>8o.;8oGCf7yG2nq7r?rݤfq溹{=bYusG]7/S_`7q{v]H҉}sOp=z`>897W +_iѵv?m=oE<=kw/UؗٗH7yɃeFy'umk$9BZv&z-*G}'vmo7_m&"uO߲nb4v;CBcɃy; oph}Pv_~c'w T׋yO:o/䗤Qˇ{$rd>=/A.[ HG7 ^)`9^[~ [r[fۇ'Ͼq}]nQS93wsɣޜ|zEz̮'>mñoOd/suGoc;Y{77rO*/ɠ Mv j4@6>Vʼn싌~=檏NuyN~[#,vsT_w{ksٷ/s^m'ޱ}; au^r'FU{{?b y] :/Ļ}9=}ɳ36&X"O.>;|psr(Zwf\~jjĮx}F}s\}m0u5qH]-oo~nϟU!6رtryh_DNtMӻ̟Kۜ͞PRsdB5w(wi 43w7r6W+wmHiorNnK;.rK_y{rA"K{hlqj{fr(wi4~xwsXڞ1 X~x< ?OޝW:[0ڼ߿$s]nߺ}k޺ł[׬.n}>6ek ztg$|$^(𥸕\D۸s\sM6 }Maq`lۦGc4|qz0N8=8ٟE}T'$ٳ gWXNZ뾟W|\ַN+?=]q߹⋽_ +xP--*[??sw^Oj_DCC!6 +m$>]37_>8{x~̅mnJ ndY*nd9x'od>{tc8eH6V pe]st\]8_-;acyzr̞%Ҟ6wuJ|'v;(~`8@|{yё _^};{}xu!Sٟۿ\_{Y+߷^} 'Y?oG~M}o~7|ZGrG{?Q^-qc>. 9n..}rdw>tRki5po{vrJ؍ >߻8?={B6~Ld} {ߕx|sMj~A>O}uu1y'^}#>~ǟ\]T}+ ,TpmbcL!us i %/ssץ^2X .>žq}nFƻ6ǶI] |Hͱ|fGqQp]& Z<&;U: |c'\um<ᲠstSAOyA\:vM+[Q@{, DJŨ K LPvc%9bbXmh|-. *Hܮd.K9 +bcL^HoonⱬЯzb/;( +C׶@_aYʮޯ9nŽ#AG(Ok,w /M.tqcy]ӭd9~y,{3Gɲy.w!z>]cUa)7)\Y>+7 >h{YP NC9Чc mܔiă>f, A_ρ'P +;" +N/p7g(?w!Z*߂ݫQ@˓oW'go_]>)Soݿ9ᖧW3C/EE/xnU>)E wKɊ©h%/AaT/ jwB $p%Vru$'.4mk+uc+9wa@٨+tB6QHɜ}/E'SYhi6.}Ђh{w)[ᢜD=)E5)NhˮY)nQ|ܕD-ѯ 2;|9ʭlLA;2X +^AHͽ3whBPbD\H||_EK!7`MmJp{ g()|X۞J  +=ɹ:~yrUCen)d$6@E3e[c2 +:rDQS/od3L`" |ɧPh]`@I4*kVV$AY(KvK"28JX"wT*H4r(dPJTTj%sZe5ֵ!e4or2g,A.s u !9tǬgNB R'*v]Ase)d3GQ[MtD@.)K"ޔ_ H^)aD)Vp% *j +n,fG%Au"9v> 8P:%E;(^T#Gшp\U>QrN-"6ڱFrݸ6u :[Df$ZQ$d.La4 9ah WTWP]G691ӓe.c:|倰m_˾ľi:<-eLӡ `*.K9ʞ2 v!rvXTϊB AeUu|K4ΞzFׁ{xRV'0D-:T,z@"OKNQ^U>TV6BF dZ (*bBxXX1h|-d!;f-ID𦞢#>G Ur=At1m-t#<Y/3|FĢv%ZQ)rs6E~5vb۫]E *&UhHC9# +B@B)_LF:"Z_-5nܪЫQqPu|L6Pt,:{| HQ!E)P1()g)iٺ@AZxsPaG(.h)|[)P 3a &e^UvC)9=$\)\eSdoSsYOEZ ,fS+_Q%˝XT(^`}ZQƚAaSݷW^v{# F ֩&8 ēX`p9LZPPecڞҵBT@1y`x4 +aXy껁8*tдi;pLy#@T)F'au0P(ha+v:9G~gQ8<Ԫb(" 41rkڸXAdQ4z4 2Ϸ(bfp!|-![X +B>Sj:_ӵ4E% Uy+O }$^$^R+HPEXZjLّ͔&w1YvLA}U ))T(lQ+[A0DcGJ~LCј + ~2.#O|YP$ ξSU ?e`P +/)9:مSr7tDp+ ZtS4Ij 2xfZfȬ E~{+NRMa!D$ ]&'>”d$%\:K[qFxr`o͑1:kQ LZ!ک9ܫn 7N`D_PK=P5R*e$MYAzoO"z~{dgJ80V-[ Ruz[GL:ND䇎yZKO! ge :8ip Uj=*[5>yTLO\8J#9J 'sT&h) qɆiR%k1Tҩ\t~G#Qai°ȧCxB~+EEybߧ6fT=>}+h, +;&f7,`{kNq1 +j/ .Q'P=4=2,XlZj eWo幃wkhjwam??Gk'P*`їlo]^]N Ezwg~/Y!O 0gfK'Q8pB,-PBO)8x=M~[EDvSdLi~G,J;V;+ mRTf+/}'""m y;d[DaCyBj: >{a5^v"?ホLY+ܸu}o1l8Z|3g#Nu=R:AkÆ؄u+g+|T VxofE;nW~)&2`^9wAn};Q;1n_??4w_|Y#)kgӶY b"{Z[3c8-Lgf%g +yjVtdοw|rItEw- +㎙Ä&.Ak9!d$#W!o\]`jv:X+^k}/~dYxrs\{f=ŘPi/¢3#)ֲJAc2gNI,f&#Z6efjMV(!zJJo:A2ܳVY +`x1Ȥ~<e%LV 42?Cg΢bcz +M52$u\“Pf: T`+hCFXuR@D=$!h ZrA MhBuۨ}Odai,Bc%.&g~U %ԋDؒ:9o1[[0uD^+R仭m\" Xhh$(ދF ;yv>=9`\:jYlY8>Qb (l1(ʅRțMP#CGo&uN PR9?Z2-5Zbd&eH %!f%GErQC&1,`.DHNyvI:D:@:(8i ކjQ#At abke3D/ٜKZABxPdUDv Sc6(@1Ad2Vft=NBFLpTz +,N9GV$keXز^B`+iHju=aAUAB-#Rl6z^6i {(:Djd[,MЍm +"?QߊhjI=m袅_oЅ‰/$9OclcdAk.:%By*Tn̷ YJݯ) D +#INYϺteF`q'1 MYhc`V z#j}0LƂMK -Y7SK7a6N]pE%pze´th8a?в.(X}ޫ!rkfCt*=Pґ=Q8L?d}E:M.$bLGPozB$X. \Z +6_4[zcH!4#PvӾ +":UϴA=ѲS`;Cv"A)h'`Jl,7k.tJ3Oljj[ @8PNaUv}8-I Eg 5蔻®,F@Vi RS@ڣ&^3Jo2&DUлI΄PYa]ѴAlj#O0-:r%tQڠřkM( %L|m6u21u:z1C&E .n8zۈ-Ъ*0nh{UTakR;!E6wt#v-& M!̨WCR Y _U-u݆҂SM07=4YզbNI%VaƙTEw@ܨ(zn `4fTﺒ~p3*6;ɔZ 8,2F*UXaoD=RܸN{bBWrʩ6.=Mӄ(޴0_2A*mMm غCEt#ib8\~-.6nKnVh(O t֣' v VٶoFՓΈXQ{ uԴN– E[Tf7~(<;5]qI]Ψn-\}f*ôF5( G/1$',{~Ξ83!( @H2oJY{k%jE!=xLԈxѼ/Dch +U쮡d BU\ţС>MM~ @ؖ_ RX7b^Ν[VqpdB(y<(Fu5M= + 7yćKmrDP~wxWʠ&3>$LDAؾ}Eق)nQo]s9+/ 1 ZAz mPwQ-"uhK4-g +LanÍmr=XcQCoPۘ^lܴBmS7eOxBP`8)Ki^)Ă%6`kDԑTSqaN8SY~j ^|(q.TA=댵k%5 Ǿ]v Mm20eĨR,+ߢ9jXC8[׍CP5ah#ѫ&ëGZTⱲxTqDoPO:"WtP +XroAxrpagbuz["+qp+3^Z ÏP(*/=`>p*`ߖ[q@5!=3}$!B^kAQ3lṴ;0w[6 c{oQxVi4_ā.]6*)$|W vCp PՇ 3t>sfot!!`ѡyrfV뵡a{jVìAnj +2S- C}179?ͬ dhWEb4< $Odp/mdmMFwjKN#+S%ǻ䈱 +$@B) 5xՓR߭p^_04z)˔e:Z x p) Nfɍ=maBDL" +O^y`L"%*E1)4@{{ 1 v= lu L59ds-pHE覶Ɉ!;.Y;A;hB]vLk*NHOZV)NuuaU .F ?'?,Q=D=<`L9rx)Z,0H0&6HHUBR:yueY'rlZbEit`}0c%hϤy-eG);td A Ag^쳵MU=ߑa) +hʫjJG@8|# ++8G0t3bA:.&0( 'z'*ibEp+ρܔ!SH0$XZϾ ig@ h"9ԫ.λ[:=8b<.T *uҢP7V3$Г'gGZCCg0.C+F$[6 M~ܠHte ;ޙ=%_ĉzvf̧ +]]\9& <AZDGCTm*tN`t%ZISK9 6D ZrA5qe="w!)hDm1\dJzIT/c/~oo k$ A%tjЉyGf  +%zA]<pwfH)ש1" b4E*)gq:G4$MD([1Sz@ Rk 089{ +l03d"z}..di |mX~:,!w78RCAW;:VM7՟,| yNy5Ƚre?3y7\F{LCd  MiUCդb"f WvtNuΪ@J)r8L0)FRyGxU0W.AKn,6Խ%OY'Vѐv|vg77 5\ +lD텫0Z4bd(=QUO'~W?U?/4ͪg +Yz}?W]87Q"棘{T\Qq8RPekQs/zStO?G?&ߦ?G{3$?_og-L}yOR$ES̵~4QbNNx|[LؕIa,O?W6P[ab6AQp  +) { +ȉȾ7bN~L 62Ls=ЉEcmZ(Pϑ=.`֡kxMRXlbCc(sdX?(0JlsP^ z"!#SV,h܆u'Zjdccp +ns5Gn&pӂqL>dDEDXR$TTR9AI{$@JƖV >M!ty It9(ye r.BBpvyGL16fT@j2>Fު(k=R[BSR&wqwF<'djя-_ޝ3ܫ)m6~7nM5 O磒9i td]<Ԩ݃+˪%ޫc4W(? [(?3eRߒW~UYápb6ě;lb@Qku: 6Ze,`e7@xA}a ֗en2a(cWSWֿǮG`ICY fAj˷ұ5ޚjoFpQ7lx0WѾܯV,+Xdh8դG4RT` sqb@B/qHat3";˩'hh{a,Z×.4Bk #DGFM>x-~yUj +@10ݨ]*7#rc ͩ|Iy٥=p7pMP}ӉPW^m\`)XBG3K@Vr&m"ZBpކ42 I&x@vِB qv-6ahqF2~ s:j =#VK/X:4SwξMV|W&u%U 7X70:9 +\4ToLuv-&}xϨ/5[6pYBq^ҥ8{05Rr/7f3\k\QVW ^V41bo mqƱ7W"cYQ*~+ + +q\PG0ACVS3SwԖׅXDȞ8EDB# EB%JP[[ ȖZIk,%(:ͤh 6Rԣo;գQTEMУ }Q^tǝ>2kj K`#(2>C3!QjS(\Ȅ,r +jLjDx=yл˼.Ïjft.]C50!~X:'cL}=JK(HZuU譩48R!劣||hB\d6TȏR8%Sff !VEQkŔ'Oeiv) l\Y!/&/rWQ&hmB_;j`Av$_an꜉=~I5h]5d\RZFIhYh j{ WB#DDd)ktD5k$LJ۴Z8^EZz4Jծu#55܎:a\F=Y١|ݱ',Y +؛'V2(5sh2iM(/ ^9@+ry™|谲i0XղzYi˕#HIDm{R:ZU\e|v|R$h #h D'79J&Wgf!nrlŇ;fĊfgjZ 0GRakf[7ٙ41hؾJOXLPhjq qWq Lq pNb}Y=Į΀GB +jP3#tqNd^98G)nU0b.8Њ$P7b-󢜰- +U xp+=^5H+Q4~RqRFE9]87;E_;{U:9LwXgJh@KiK)ш,AF v`SW0( \T+!ډAcȳ4 u5+Ƃ6g ]jqOkhvڧjqҿAa1Y4Pgo™%V@l[\ž|XDVžJަ\=7U?Rž~ž0ž +K3>,ұI I?AIM gbcUEGΝD>PWG>+h|uX +_ +|bzl< O >d̤.4sQ #Z :,rTdcW=nu4H^Q4RBžpy]fA#nx]?Xn {r,m& + %C솰g1]ͤz{):v4=uE)Ҡk>@C,j&sÞ}˦C6PX Ƀڲ3Z@tIklt;C.g/qdQ^=$~z H>YY?b22p-2n |FKĐYеjP_tDDetes4V\2Ѭ)E3'Tgvc m$!&Mݯ9?D+ImPS*K緙&M*C471}uc- Z3)@]D ӵ1 y(w tEA4᧖Cp㚊iުQ GU ۡϕ +-LhPQtOEsNhN6QTwy:M^]ߞ]'0zmwF;gyf>N}Lɲ4qe~.Yhh+.m iVt򶴄Yz^ qh4B 6ǜ I#CJ (mtڅt"W|՜`,CcՕ3~|J; +4p3M(Ѣ#p!S\PR+@= ב\!Jx )Тe.+^s_` j0H@=ϕ6w43:f_8ӏhgSGtȰy8h2@K\ͮ!%.I*0!79"a N ʺ9?Y'v|3)ln,QMULz=8hk*cPz|xε6[\&Tm *O-E>&kʰ2:-ə[;ʙB4cgkZp3.JC j'kXj]4d҈~h) ٕ?^MͶvȺ;9KI"䚜 c۫ "h)F@铨D@^H+D$&k<ҩb+דTR1Y3LzMI-gSiD'+ ׈K1$71S-e|U:H=߄si?3.>5O* z\F\Α!k+P_8!h Q6YiYN2?U{\<h7Ճ%R:wֈ!L?2d6C㴃gV@Zrч E~M۵|:RE696:?'uLi}AZ31v0hY ҷRisd1:=8> +D̩ڕiOLb3O@xDکI W%5PƥwmSs`r}v멹B0+.0#hܚ:V;]G[]qUU'F=L%w N Ό"u&POd>bɈq>v5#:]8.j1CV1ci^JbˠP]މ ++՘ ،lmR4Tvՠqgj>W_Σ^984fe\L#Е`:t1X{:tX(sL7.[4DFEimݿB{D_[yBհ T \դ9촽Vd&ȧEƑO#e48iqӺM4ȧuG>-2|Zd.ȧyƑO#}G~P|Zd.ȧEƑO#u3|Zd8i]l[<8bKg8iqӺ#G>-2|Zq"ȧEƑO2&jƑO#e8iq㺌#G>3|\q"EQM2JƑ#?i`G>.2|\d.h)J"5G>.2|\d4hf ~a㚌#G>3|\q"EƑuЌ#GЯۡ)E>8qq"uG>.2|Xd.hƞ}\dM[2|\d8q]ƑO#G>8iq"ȧuG>-2|Zd.ȧEƑO#l ]8 +h4ISĔ7jqp@ҋcu@g: +tꀘ W#vSP\瀨] +*ĸ[fDuF19Iu@Q3 qi(.bm9 |Z8 _nt怀9 [8 9 HS@K7u@lk8 PSiNqZxꀘnM 9 .DuvQpq@P퀘9 Ж3.mξn:LZ8 拡bh+Lf-G2u@fꀘ򰊹b^ꀘbRrqps FB]5h逨p|1=jzsDu~ksPWCэХ''âȉľDmlDcI4Y!mѥq"g#SabT vNdD$p'tnjF@uCuǙ*90 o4AS! ΉtR|P::&qro"#+H2rmmSLdGSo"ɀ;uAo4 67a2}ź|ܟ}"hH֬Ʌ7Qbx|::.243p^H0u @uhqM >0&2NH΋hօ5! BHV (?F˾C.UvM QAmď*13 Uޟgb3QAg"E5Vg""Dn3Czv_?JN_yWT\4z&]M h,93 vZ5BB\~pM$ZH~jdpBb]t#hM,rM ݖm!]V\dp!, k^f{lTnSK]Gxm>FSn 0cMȄw5՝8mMɺ878ri_jD.4]?cV)^lNZ3ۛp>{pmHP +hI6%iEF5TnBq^Ċ[$⍾2 tl$hR#ȋ fWU)Kdi>WY3^[G^ȓD?rkZmZ46nh>:BKZWZ4}v<6#&L{t~i xyNG瞛u,b&{C4-bM0lllyu8`k:NY?A'QHW7,ӆ]&{zܼi\k2iu?A şQsW͙j#&BE8L;fDS2šQLёxQ'3OWbTh;:BfXkgʬk}?2NÔʒ=0Yve$OtShkpu*FIQL~"zU$N!{ԥf**3ch(lʔfMnXob:KaYD QT՟$Qc7xUf3' fzBRn6nVђj~%-VoM^jJ尶蛨Ƒ:v(ۡk+V#es~؛'/)ԛgtkӊ1b{N8@c? ů%=#t .?ػk{=[̹:aWc 9zѫhdښ;u^3ɋZR,lX%1ٙToX6Rtui8o1A۾M~%"iM:X;۸7pT,^^V owy8 +z 6*:JifX5 +T H:tv" #<ۑ6(khNpa. *Um9e´EeFa̎MZշyձ W ߏvڵL7ąǑh^B7 +c;xm[ɽs ;m*ȱMCo~/@)hށ2*it9bUh K7T*ؠS7*VoBH+[H*(%Gɽ%9kukfhmujK)tyٹj3qm5.^Lް2t]:SI"6LU* }.3d#ѕ4,GGF?tlS +f#>85` +t ."d鱔a gծj%}z+lٽ4ك:)Q';I`rBg{z;hp9C!Lm$Pf%ϡ}y2/r7}:k,vT% e]ԩ{8ՠP{A_T=>vG춻) +BIӮG[ȈơD'A7+}zTgT;0GFܞS09z 1lcԒ)zҷ{^Z +6M07=ܳnID.qȋWI Ŕq5']1&2f3 +5Cƶ9T2bc\w+9z ;7`tUʜs +E`iUK`e3Y  Y4d CqimbNhUf5qM򠹻 4zDMǵ !n6z{#5pb9* (RKK2TXnhVܢ1FT[^S6 {|ޅӌ5skHW{^NVۯڅ)͗xSz|z{u{>1`WU6b}2 SOg6dsyT`&Fu;l'^/ws \'{?Rtp"{^5tPjZ|IGH+9{/" }U7J.P4|7 +T_˪Sy?o qҰCk^ ؗ9^7`8:=Ipz$Mu$1B}24.6z P=*Op5N(kZ3Z_c vWn9Czn%ƾ[TV5أ,#d΀s-߯g pvv@>ëy 5 ͙!X6r 6షG~I?6NrQ:|F: 76&2N1nGmI%oB.ȅd⟱Vr0 vV* [2;3N1G]{Z6ĐNy6i~Ntucڏ٧(:}t>?>{4J]WBњSS}-Ǎd-}VT4_e1rYMN~0QYG_@OËT84\kFi +^|cO#5뚏\NL~J{ށ\~NtZ#s@W^o9?9<|+57޾Xַ\.wv}xu˓/~~E|,il '[ߴB7x'7?P~"|ӓˏy}WOߺ@Рo"zcc5斂|cIFEwWע?vȆVYkf[Kp}c 5˹Jrv {FA?P y~(wrhAzbOV5ZJ9.I3[6h(FϽ+\i\&YKAjO$'<v+юh=Tؾ!% +%ǽ LPy{vHHaGLӢiKdUGP֮i3`(8ᱨWI<,KI}p6am[ +Ue(SH:´*sj.Ak@({7:%FZJp2N2CQA6dF( `a2 S< +B-X +@\Ï}TIї2绷#3;8)ըְB!궨L$j\PFSޝOǶ 1#:#瓬Yuؕ~Cs#^:d/"(3+bc(8Q-Z +)$ڊ +:q3iEsrFiRtGՠPt*vQ NVqҐݴT`5abbU'b3ANV+Ks ,2m 5m۾ +6@9Ġ;ҳ?UnxN ,Hϖ}:泣EǏFg. ڕmUvȽ's7=[lfDt6(zV8C.OtgsP^] +?k.(q=5v3DN ș.qs7ޡjUB} `eGA@(?P *Bzh2:\s-W~vpqAB*b4A:UAubl?~+4V3ttPpGSdb{ٞ)+\lbfyDF<)~A%H)dv7z $!OA $k' P!'L7t`8 ]lԭf3v]^-0Aj3 0eWh"1a2+Smoȟ[x }7s&(;/['U0i)%*דEáG]6YP$OGj=?"$ϭ n#)Z +ӕ_z`4|Ha,Z@b,6EOSQTǹxs{фh 5Y8Ao3<C"$FXfŒO}Yb{.)NiQW,p{ʭx3f^>%.EkMHLMRoZ +$ƲP@KɸF09㼋>!*uOo`Qvk;= xFp=ݥ1-Ʈ @+S d?C"69`*ߠEsxa)SWN kD|(*ER^›;eũHN3:F)سE`4)%; zٯ?lNMDV*}ŧ?Eǐcާhhn/vfW*;u)GLk> lcehʀܧKG t`MC5hUJרƇT] 4|AhWEl!;eغON;k@i3' Uai<^ K M. g"y<`tpoߑ]ƉKNSup(%=W^ፊ(Q*AՎx'znfl'I31EX'v:F%k3fq,r=>:)7"CMy?}{r ,n Y  PXaYW}m=Y%W;W}Ǐ-Kc9'"2HUfq"Nx'"ESҼ1Òyʙ:\BM!,EMOYA^&zxCio&~Eb< %K2U9{B1Hļ&CP fBa@1gtޗVL]p870ծЧ}SxKH4Nv<d4'y %`\H:fk٩ 1 6Ѥt97c[yS@̣8γ +U2IJtiaN'z\YG$Onrݴ9J7jZg`W2'g2 Ҝ  b(cP.AZ.,D&]Wf;K:<7 < W7'7uJ禐@OD鉟?ݓxY=aUi8YhW[F`ܸBYb2eU+ѣfBLpdF]=z 1d -0zFt4^K':QZJ`bzLm|B0EMz[Z>d.Gہdm@x&mwf;{ϓU+˛J㘄!BreД ^J<u==Xd*#e4˦&pUv,tKfPrc1op.Zh.>BLK)YbP|p]78(dT'x}-0A$|@VH&S0-kk\-HbUK4\4 ~?]5n'c}\ze]7AaDV#tg[KK +S-⤜cniAap&LʘvP5b6,BSs XQŋ+shJl#0d7nP\1QVk IW W"'UЕOc +Ͼ)[mvsDgm&:6zݍ ]n 4Ye<[HXTftQ\a'5 +lAа5VƬ[JޛIseͽ`V=Γx6cJֹ#XG©3m͙M@nƐ4hӵb +dh6Um +H4樰P 4MESDP3%nq'l1 @( &MV+/`+j+eL拊hSAS4fJviSsz9F1G,gr;ӛ 7g{qm%(&YW{ ɲ2nM2x%!`w.w2БwhN>M$vZ)t +[tRxҫY֣3۝JfB]qO(ܡ"Tl+vw +ƘyD3k;-d '\oELy05Wbou❛9Y"߇@OףRT1+Qg*3ە }KPl-͠bIg(tD\B뗨NfdyRr@EeVʕE+˝&ShXaօ$腋K9Eoj{7/>GՕ=`pҠ=ҞlͶe}Gexڦ+~IM$=s4ϙ9TЏTh⭸*#c9s=ɐ)~KW[>8o;ŎF#|?81Δ);ʛz*Sǖ.|+4#]a޸;ǛiZ4,|am<3o7IĵS;\~YJ,k.~:H@9rq>jx +FzwgiҳYt.fqr"f0Y߸v+?!tF (Ǵ%7BR3;bjnQβo\\w?d1D!06 _C`V;b_D0+D=MО }ָ":MA*>#T`3@Є;t){66;Yv;cԨrk.w,R%dT|m؆-3$;&;*}7]em:vv/jeZdY$TMMٜNc*gEKB*`DTQs̠Ԡ+,$s m<чgFfvfX-?fb/u ݣdTmBm=0;MY04FBt +$b3?ͽg_*t^+HUӄ]q9Ohftq  @IiR3MƉ}6OcfP&Kvִ %g:-g*( +Tucn]24CG Isv#RTW17Pslt.F DGTRAwar*d>T<̮L&LX\u659.3E]1jv 3wiP<<ZDIgl;yDz8{c_Uk9Fs$?4`$lK [&l5}mPDFSZ" 5JXȬz)1Uy4,uU=I3fE^xX +jd)Ly4ll L2kWZ1OCG\6s'ʶbtyspOcޘyi[9`Pg4f,fH![.=f2m+g D=i[[M*i& ѣ v1MhD!,;m+nNSbHt> Ĵ>7 Zt~.DĥkGǦZU +ŔҊC7E"AKβMLܴQ*D؞)&*ZZ,"i?ʖij]NnfQӧFXn˗0N/l+Omsk|hr^jUh-[^jZPegKe-[*xLR )##QDʑ(~_YV3Ό8+#o\V(*ScLQ޸bO:5s&3QǪU4sW>mAe劽buYS$'M:E7EfIנ4w>O*.+9Q89E&Rj [n]!cU ="5{,b8h(§LGz 87!Dhܳ$ mK5]>ՊF@?OoNPR9ݪ4ˬTn{7؝׿OC Mvm!ϋ!22^N npd&$z:d^Qe+ét~կ l m&i&4 .~>_1Q$cE%glEeLF&z{oѿQ+zrw} ɿ/-.D5'-oJyKW#9vu)1@14B(?td`vRW&W˕/wG +hɧ0f(X/ +x +)*'lbEQv"/3,z*d_'\^* ! +yV[^}xC=Kx-)ed w$Ig؁x[-'iE!*B.Kˢ, + + K *xZԡ])8Sם9lW `@註Z==sz$ +88DVTY%QJM$x ui$>lő8w}F +Bwf}< +4[M&?1;x2&u`ޮa/{ޏ겮ixݹjx,YDDe0w!}< >t!SMhnj:j?3A CxTEbbJupkdEaw Q$z Egx~8y]p~{NF;qL +t ? +Ax;ޟ_kEׄNR7vET Y!2 +!A9^H"tRZڮīyٞ15I4]zMh@uSɏzLmf& e&HQd&{(ׁyׁy]|*Wu,X$a=D& +4Q1,-DP !`DUȈk`3ю0Ԍִa ĝ='郔ƽ/s-tCEA5DTd*BvBG\ZIyTw@d i}p7;]wP0h_o6vP_W%Q1\T%I& +"ACbJitTkwdE b,1oީ^WY+D̅Uy2FC4a*'\eoE6`SxB@+$ N kMkM_wGr1mؖmؖm%jL+_s ɍˀ%6H rU4PŁ*TqU`~5X k=E?&J&i!jЛ IaMT I]e\D'&+ቬأoD4q"vdK"Zz)s \B:s& iLDCE膬.BDu +Ua@́V'ȸ$[mu,1Pu.358l)G0]?..-5D;`M0AVeAh麢".ӥAQQ]uYP5^D {3'Ԟ +@@&H@&pY r`^MG v͂fn`Ywߐ ?+Zt ?Jl p?H! wp_3M=A^3y!Ul(mO[F,JzmTj'@wrԼ,Ⴢ9sF$z$bnk9!2cQT "I*d/ +F;G4]5YI :Q5 210uh-TNU Oc4R[1wvı\ϕj"H @]yiPgj!felv7s*o|n3E0I5 z#V +!y=X{B܍&;LjnUUAEM6$[Xo(^-RGDU<5HC>V ;0⃉>>B==#/ׯ_^^?=/p&X13ŘL-[_Tje`$[ʢJ$4&῝keF QkR!7r^idDV(ԝn+/ +{˖ +KZg캿qԗ^q,!Jj'-+ů|;F ۙ%3VMtX&Y416`w?wVɽj䳺}uѳS~/~w@Tݽ8NHoesr@>t5C +EE]R"xW*:"QS4Njc/g`j~ֲn#I{< H,ݺ'Df^hRHx$ `""7zHT=&Ȣ`ug8JhYuc(ԁE%:|b] ]!ȚȤ48!XXy'×/{//tPDsv/Vlo?ďw\:s ɆH ݠAȪ .";'+";E~:ً[Iqthw}~W?^qLe4GވQ8Y6n72 a&%3 4 @\o_8;wbJ%LF1G0WRtF5jj .mpcb}ȄlY Gs@Ә@#bRG^Q찎$M(I譇R[ !d,ogy0l&hAkG +>:}Z)o@˗0+xe#1b];teA0( #:ۢ$*Ff.\&t響w>:|yU<&ld_ +/~BTA\ CWM*<_XƠ91hEA$M34]S낤*htdTG@AE-_]E"}F^D$Jc,jDK1nAQCLh0II7\IP@a0P@T@'"0,{HLykKvihuj0cmfH]Tl:J8L1@vlI (0ГXZ0*0yL/QBB $4*=ho:B_m mu&yB4ma"b[dH +!GA 3&kC#wO I4Ha(X~`=vu L3.xj\BmIhTUFKP0ܩW( +N:AUFkT +SZRx8`ZW.aazB~#D_dcἒM_<-TV(U浌T6k:@VcZmA@o0# ,b mV-1 f<}j^uxhT;A5 dnT&_:@JjQ hlPt3έj5K Z@NE8L$mq5U&GcmM碪dk 斡 +j)aLq$0N5ejVZ7t( (C `a40A\ ؼ{@ <6=qʘ5l?'B<(g?pT}\8*'o_7Uki&;u_'#soB,M6%z> U"0E7 CT}"A4↲eH+J`L &+@?)K O-mf1G3`= a0fap^h`-S11G]:1mû4K}XB˾ }]>c3A8-?ij3@~U쬤h$b@jlJ@cN'~!*J("ЉW4AO1+T(Ry‚!v8= iN5.c0 )tI|LF %#QUtMDopDN#%nM0CNK i)Ԫ{AV; wUgXNu>#N^t;C!\{P}]=6Eec04sߠFt T|nis5EmFmb唴L (}igwfJXo|dB#4쏜7|#Y>u?Sw k3"{yUo|󗿣{7ŷT/W۟CG#/~ݐFg_=ۏ?ϿfCf%>Jy[(7 O[}l-/y=TlQ+7xk\ڔ-+БZq^ZUIi +boŽekV<ε[]sBP{Qe +4B|=/ SrWm +u<[~o;ƝbT(wmʬ ^TBgezwj{H.͒=x$ +K +1DT";ӓ(Tl5KC!QWKƠ60S.!L԰oDJ^ee`.FD֠B)Sbmaۨԋ&Xv.k\Lk"`Z畊.]) u3ʗˏKXW"KFdId0"ݱ=Dr#ua`H"`]$܌+F&wYR4/9c. *2$(2&vc`"atZ)`u`͗ՏgS""AN+ÃIS3gD"*fe P7TS*@w"ts,`߽#$4AP""aJ_Ro_?CeH^J +`DܧR|0nŠ7_T~H ԑ"hK]aH ­\#)rwHtFH0l<5D +ګt~wᮦne$C;D̪: Հ1R $t&“/3zp*""(*h tE/i"X=KN7C-rwL9s $G0NDVzD0upS %"JC4] DdQ`vEc:;2>8" :((CM'$p"DO4< :B)yG wz[qqz;R]#~wކ_O#;R= yF8Hzx4;R]|F=%HOIS0@_SS\;R=g2]f5pٯ;?~O}_ +Cg 5hYX+V_Yt?UWJM[$8>Yo6}9י3}r S쯭LR<[*Tzj:th"ݎ//J%XX9C;;ˉjSOvZC{WF!P&.hRʄЅ5"fT,Buzj+˃xFVb?ݑ67 +4Z 1s]jT5(nhKIh dT֫\+#AhS)mu;`+*Q2mʊmeZFVe!@ x׽Z,m[,| -̆JȐT6W/-im%|#6l6J^J(&-Z ȍjlQ AY+9ϓ;mB+ Du;+ M,ԖLwGҶ)w kY>)BO$5<ݼ5;&fi{5/JJ*)KҊt#BDeDSRTcPHw:ιCֈK/U@UKTxB.(Py{Z. }[h}>M_4p0vH:Zjx@l=!T:A; +p*5?f $5~qGtpN60CÇ6% y"NǬjKj }X(UMB0 "jn̪g,Ї팤X1.O:\X *QPp a~.Ԩ~QtB`g/=#yhM@t>NJxZUxGo5^M&?Vj Ԩ:(z LpfW]; zp/6om.ıM5zw;56CeQm9JKB2:1Qf:V**6)OtW띦&lEb%>%~31gmrz!j,mr/"rN6.ʝdkGuL&76 US#[ꪵHtJf3G+*4r65 g=*%΁ N!Po"yOJȚqVd|Ȕ;oW5xXڪXvسK6)*ذ`]. UC/?}z?{?z_~o߽X4;Z_&|u[yoezu}KRa,?\ +W3^jV+qt#{V|ۊ+b٥l44ѷx-0*`b*_>rU}1/#lv^E'd_ӅzZʹ#"Bbnjʕw%l Y)[]Jt*wՙѪfL'6"]R5+5"C5ՂbY|-/mϳX[YM uPvH;Q>˃ +Aqg/=(7"RvQimڕ7;& vH^[5sZ*)DN\N 'j}*Nt_,҈].mfv8;KD"×Z>)`>m%].o7f*!ŮK{@&q!6Q4춧j/7u0s:^GnbP~Nכ=-VZ(=]5Wqpl(# 3{"ht=~ryR߆'}~=Y#eM c\9es$~%NDӉN*^h_Mr8H_1DjTd%+ kGhz{9v`tazJ2B]nf6Y2"VJ}8 =IOYd6;(J-~zp!<ӿ0:|inpJ =nV5Bjd:RXPMi%#;ҋBen&|)I,_kYlT緫Z*~ dH2zJEfu: #Rm wxNE=T}J]fUKG՘: R2zN_MCI-!8/u.mL%MaUs>"\wo]*xQJ|9Qz2lg'=O>[2'bc`Y],|H-vMYATCs$#7Fxb9u8[*}fR8R;Z8Vl~x@K^ Y%H +5LWi>ܲX*Zla!9>^tVz;Yh4ήf'&Sd,N` &2P\s eU'3aOhHI%&)=Mo4*l/?iB}/?Jvml~3)B]O6GgyGS4=H M>b%}xF:ĨI7'//&1XT;0L3#  E61OZֶ dH,sS|Z`%8yfU3pu#>\]Umf#SwpzQ2R/Ʋɳe j$y@/OPPӕ <.im7 @hyVO\\l>,f}.-SdZBei+%0ovof i=y;?hiO3'0 + ZC[^ɩћC"8ٹ[M&D5cutu/%"]S:+["ꂢ̠KmLݘ^]}VlE061fe\Auϫ9V@fq09&ن`vUgxQcz*N熶gk33Q5rq4{$n7Gэù#Ĵfm8uSHrs$VXGK uREAS^=9:A+[ӈ7h14ffo20 uuq<  %C}fgFt}g)ݪ̞FswRŸqlft`0F0Kx2VmҴTGGORiCM4kڐReMw|&pTZI\D`^\zU18.Yn˧mjD+L*Wd:Ag @wijLb8#F*^؈ނ pAM<;(% +3'OcWh;<>0jU9p9[fW;@+5irS/kRTagMadJI΄ Tyz[k]Vbp-6loh<ň@be}h_IW0,4[KO6][>3'`"Ska4ܴ#rMir2v6>0fx= G8ild6*ZLOH386Xq4auq0J W314dfɰUX:Wqʎy2[@(,,#G(ic:``8k;6g2@E5U=JLUFbed$EBr\=<87 myBݨu8y穑쳅'ocXn@S +tͩZYFM\*ꓙQQ{>t#b~!AIZ^]]9kbu$܊&N̔ۈ$Y9qوBӓfyk4jloVU}O0sSԈ<$ vF˖DM/%Jr؋fvL}u:pg{`1VzTyZt)b3Xq26*V9TVZӨHX.Eh9!:ڴ{dz04*ɳpwXLY?f"N<5ژ$sꨂ6:Z˛7Ca~M'1jvfUa qS*>ur[En) S]YZȃJ,Hkh0ЀADG_`p2|RlMK{)O]eX |"NJ߅`kdzy}iKzs)@-@NJpV(P8 +S?(C1NǓk̾ Kz276`<`$˽mIFge@+3I G{'0mpTjҬJ-6ڿwk? @m$RE%6bx[ TVٝ%]Yr 4Al6aR*Zۑ̦UʕUr[HT>.{$=XWx~W~ů~~//×_gM(B0|o? 6?^׾/wQW?O_'w~׾ŏ/ T?W~_-P,^⻯^;/}m>|ӿd ?~J~CQV!sD Zzs2-uв>eadqVᲃȴo|cݵcjp*v#[gkTJ+y2+N8FicySeۼhh%_s||Gc{Vg *^)lDMB~B :$h~8Lu7v/3pϱNn TVv2ٮDq>xjl#Ps?tZ + x6}Z-Z}oiu2n@Wb-iԭ-PwqF1|}m,dmmZFSK~‡l`:ߋ$2[c0-9m$:7׷ I7aPGu{?@A]ٳ#mSnʝf|<. p^j/c߁ڡ Ŷ&~ڡr9NZm9wVXH}=ZwTrsiU㥢}{%QKUw˖|/ޯU^zls-tվP؇MmvmOϕd*Z*ND̠q;M֙ZF>%4̗}N9L=&W )ziF_LKF,qa,`P6q!Yo-o37!07>w3?F+?vFk5oT=&1h-'i#:FhZb/~I$kai jb=7,7|}z07r8&cc菉֛se 8[EZr]褛l{P7q]O;A74ozo<2})J}D} .@AL`iim,'} hQܐ@_,1/RS̊}$ےbZm'>V>*dl1]Ԏ&q|Ggsi!^S]r3$H6XoXpV- AKk d]_ıџO_Ó|pR=mS]N哈/ՓU$$WdOuOĩ1?@><n]j$;*ψ}}:w4%FXHVPUʵ6TOm?؛'}3Cd4]aqI̴Z`.sFr(^9FTC;/(P+J 1NucxEUQnO~T)tNOkW %쥺Uz2ՎҀ42}DOwgW-ѹi?ӥ9?@ +º?}!eO}>I]j[U!u|T)ظޔfʼn]Bt0"Fļ ʳ$ytrP=Z0㦺T[0ZA U_ɧNQMkcdž*aO-\מnRݞR]-lKBaat U~]]*<=<;\lKujE𢰻Z񧚖wR 3T+OR=]|`vowׅՄ?յ/eUFW6Tt^ +S}z]]7tɗrmwk}m/UiIq8 TSܲq^T㮾eG>YvD3ׇT#GІB-\\z2d5ҲU)N壱oѵB۷+rӢ}Tϕ%!9;fzjdvKM$c1[1kOٍ0Gwv\4L|:G͌5<,L>k>3(Փdy ;Nɠ+d_;U]CA[SNP[sTUtm[wCC-7J.o`u:ߢgŶToІ*QS?n]`r]nO}T7iEnK~TMLCC#ڂaҧo;)wҼ-;PMQIU*W\8nĠGQEk [dЖ-3j8 m/djc:psљ#XuK״sa@,DҒ\rXp +:6)cX)W +006yUH Z?ִ3Hf᳕yt'<B(h Ї!'VAr&ğ5Xn,l0Hڄ87B{}U5si@'kk7L;1O@f;wgǓ,DCEkɡJPOx gDDe72~tu"8br뺑Mu!m7CN44Q=lX$rk4VzqBI!lS=w[yB}PpS}_ncOM#;c Nvݜ3w:mn߰neQ\C8)Zͣ@ Y{sr#&G$hɫm$xzUUw9)aۉߝGXrܥ(nc ++6ݜ)aq{JF^]RaTWʭFiM 6 wqױhd +gޝ_z'niV[10QPH`}b!=5oˌLy(`Y8 1rb1gآZ4ڒ>یoG."D#v@&l2Zt>za$ eG@ƞȂؼ3jcf3~=$\?['5o3l)>7ڋc?syO)Bg +!-M0Dyw"hn61@Pg +Z=7ߣkJE+Tε|f3|ε|>Vr>Z>r>Z>tqr>Z>r>Z>nnϹH9TC-otqr>Z>ߢ +or>Z>xrj]LT\gC;&@;[ΖR}1m7Mܦ{xDVeNn]EMlDtOF `cʭ1 deT"5U~H(QT-os c{d=]čBJ"^t| U{>,Dm~)Q٭kepwps9 p-Qn/i9s'bۖ[42"I-)Rzm_2s5|/xҜ)6k_ޛɣBk.8A:VfPnY=:&\S5CMsspth9":y}kV5wy/쑝^O;9}Q; vXU)e7/4ՑZ*~Ln ^f*ߩnjڝ&}/mI|{{6xlzb78'{ǎ=h9r=,ZsZŽfX?ۉz#lmOǹy|qgHnYfG5R Au 觮7_c}؂ٗe} +xzZ۷Ӟ|AKI+ꗰK轱&Y'&Wm+PMF[UFM|~0_zLޛHKxpݦ@(l{Hrmr>`w[{JD=fj%T+Z{w<9UZl Z,EEFEoV-sEi2D歿Ȣh,C·Onyy?޶塌͡OWVF۳QJ<.Ҷe1<CI߱36it,~YY7MW6[ŵM[2Ov/[æ2{Jyl Wm2?ZMTtuҺ< He1m2g`Õy:wSJjyK֚]\5ukukR/mIIT_kR΅?ֈMyd*4Q3v',P^52qv΃^"1 ؝d^z"34˜ջTa_|^ +vlhWuskOmիqP&q%{޼h#RؼP?Nרz fi5"̡G }QPOdƲi._mRgNewӄ-dX}{֮j;A5Ww?Pim<5m4} 9Iq[S,e3~ؕMٽB5eNљqpҶ U +vPL~jjO X]@hT&L u[0k4q|Fv"Ĵw^)qIS 3`+I1vZa7.(znI5k[U/;(>YOmd=P`0f 0TO~~\oZzg ^ϓf>^ϪLHDaYٹڻdaՑ| +1E +!>0W}C}L*&W.쳪tw{) lϪ9kh>+:kh>>sU +T͆ $o6QgUշ@_g*쳺Åf>u6}V[ͦ +\>51 m>(oiгVg@0둶>`a}F lMY7Zg+o6[glaMA٦ Uraf6.v; V-XgoCջ۳_1rLӾ0g?+*]WmQ\UƄKjt`3g(v,~dwmz&}rkf6N43{il*Rd2)ܛKn+6j%27㢯7lly;?]ʈxMP΅K>U 6qvNH?|b?]:xڱl=Xrzo,onl[s9\)jal Gk*EAAm-=! 癍>zIj@@̌7ֹ +K +V@ ڇ/kח\rЅSh+4T+M$܍nsFYU7r(]߶FgZ9O}COW,{>Wݢ_,6mf3X06$r036}6sq#˖?R vퟟϛ)1wv^Im5'u? +u{ȍbcv%o6om FN,әQBU"^B!,ZO%N{6oe̔5ޣc#f;fWgV՗FXizy(iͳ[\x"bmsƭ:e幸@W5[};J֯nD}i7/'h[վ@xzA;iDztbmvҾ\7ϵ-ZK[*BxPt=C.!XHu=O +g1=C-pm&rRCSd$Y^h{XHeac-la[-4hOmSL7&>Wion=%}8 s9]wT^wK$HzEAL'D]t|DﴹY~\zE~hRó,krŐyu>g HPur~hrFsʼ}=ǿdHjɈ]!bf+/8U!)&J3".ƶPݻhUѐ|j>ٝńETtU&1|zm, /DLC԰yc[ǝ_;"{ {Vcӄ=TU(AW/RJFRH&/u!8)::)O;k8禕k:l '5^SݚUN1gcLE޶VlZo[Kf:j/2\L1/>> iFL})#ycr%M:1z+h[r+i[Jl'yj`M\LN>gWUM3=k]sSm)%MC|5v<6Hȼ>qli7YiDǴ4בBސ6HmVmdZkՒDzDDw5.%SI#XW+IGo{DzDBP="RIh=O#>"%P(I4|}=b7+ZZM+ ̰BFwJG4p~mzX-OB)8p +uYCB{]`aoZ2`_Vl^vhUU <YBa}Zz^)v׊Z2{wq2= ]ϔ:G45w)޳CoCg'î;9V泪^]eҽ: 8 Su+izJ[kCg罇6Am`36faݛCϾN#)2 + śuxҗϳF^Su9] 2; 7\1]DV÷ɏil\_TE ARMlNsiӝ߀8) aT/x<Ә;vtNg+?gP/ ʎHL +endstream endobj 92 0 obj <>stream +H}0Ưwb0~J耮K{U4s-̝Ef09uJ[*7\>?lzAJ 77egx}TjO~ǧt+tP8!:Ju(l& -h9=tQSk16} BFKEAG] ?-#C^Zw[@qό0bYa iN?MNw5XpV94N6#ૈH%2a'iף L[Ye{kC${R'I%VuD%iX3XU+X$ҁ+K,ټ h#3Şg#DF[V^Sx0̔p24GTD /6#FQ#nAE{`z;ƒĉ-[Q8rϕ$WBUyQjͳV'ׅ͆lcҖ#ҶVQ +VۍHQdLDdk%7c/MRi+0P)D]T+i"i79ZԪ Ԥh,)nc%[Nt!=qH7 N3-˪nV}Dfѷ"U+Zľ/l vIOLj_HqUl;!.4zoI"軷C9KEH--x,'߾qo<A}; ٷCU)3]+}G;S3YCY t:i.C@Ag,&xے:P =~2 PRE"bT˒2VꖅӢR8"[K{ۇ|szyB3jnJʎzzL@E C +'ђ AFXuL$ZA5^kyD u +1Av-Ku>wd%5h3A +9#f QkK +a8N=mYl:7} +j;JX! `x4 $vol vlhC3L}jRO*2&fF=v(0d)KcMi/1l Qi)EoM6*Z/ջ?I$t=IqAWISJO˸v͘)1$ӃR˘_j7iniU/+.c6)-dnNjZh'5~,.UǦ -Hz%3U5:<*Ƽ*e#y)Ҝ ]"-6 +[/MUI5y*2Dܼ$skp[2ԑJ?\:x"+ +;gJaN <-/j^}d׈%e RZ.i.L_:b 3Bݗ3ug~%گ[o8*+Rt=6(H7\dQTj?^!Wqj3'sӣ=ͩX> K:$Zj"`T(z K*8:PO2!8&;BM3?!7 +ok. ؒV+܋||e1iZi:+&/1wALW-\Y=yD؊4)*P 2i A +%ϞzO9bǔ5=yt|~s:aWŏM%k:!`'(USQZܯ<]*wner3]O6FP@Ц eGf#9%kҏ(I @Dx{Ёᱏ|g +ZZ+-wiw?dݸz/V{#j!#>A@ANRf;&24$@7/IYR]ρƥ,Orf)gEp-,l>aA9 ̂8d Z")$NPU2 vrxW|-c8ҜXL[#+l0Z8Um"f#e!%-T5R Xt(y]W ;xzP %'NљQ8?b|_ܺoqd݆vC˼R;EUN3ӻI{<)[.<>C5Gg[fW% {ح•z.<=#RI!Ԋ2סj 턎əVδ[i4zEciiQqySWqcXiMyO28b=Os73-s4^!`koqe%ZxP^,XYp7;J:2 BChPƼ,nyϹ*TaЏSإ*^JA 骊y*F-2Tge)+=`iDϼT9X +DW9f`fZxu +|,i\/YBK2e +Fko^2Bmcve,BE"P Y㸲jF@ǤC,>|'n'IY"ls!zg$:[ +{Bs$(}4n"Z "o(tz{Nbqj? ~Ğ%)μ~(#U c Ф \fS l4\LJv+\ >NmltM/wtR:Օگr+~^KF:~>D<Z'[,f +nWza31na?*Gj"k]4A 2z Ykna٧3\ ]uݗ+HU=đOw[KujK{6آ5P~Q=gS兴>5r#q2 IL]dI6P|hz"1td(.r %s6P%~ߍ? S}?&o~ST `!~$h۟Å.\ 9[+yJC"~gn2yӌle! v3UbB2,E|lLӡWX[<fo*PH+噯s;ooy.LܛǠvm HAUM2B-'gy3_A5,O0.P"f]d|d RU3 Ç ˶,*3H'CzL=Kx‹mN Hq@P{|$kE d ZuoJ+WW+>>$*!B;r4$a+JGv%%Dmabn| +TY+Mo83mCm{ ʥ$^5Sh& jud$0##6SӂNʊݖWur *HxՒΠZ2eKK fn`/CeސQ\΂0̣h@T#MP'*{s<trd]+8+_|NXbCxԢ=؞mՓOmDM"n3m=ωg48j{Sq-DıN #!`T]V=U3C<ʖE;`v +~ OW-o!ODY|T p|֙ؿ UP&{? 4)^I+2,S;}8oY]:=t"vEׂ?^xE}c8BtI2/ت6Jtr"{["NcUߐ@ESnwZ#!rg!IA^N/|p6F&Ti1ǐ+7/22dTNoby墊GjK^yeWcHB>#suEyCZ_M4sl#T]+,_|Υ\ VP%C 4`q3$ 02,.DT>zI;AZHZ8 +РȒTCLV3Md ry҉HSY$5xm +uY] = ' *S ⢚\ C +ށϵńI~גҕplZZ7O'1(W>ɇЕh?m [z|)<벻>=E*~㭿2U"NyBw X|B] ^=غ!nf5i"1% WpP!s:B"+߮'#a*ݽM+7Y8%t7ɆRNjޏXCLڬY_O"l‹"Aٕ&d{cpƢQ&tw(fesg\jy9Jxj^2mhZ#fn a=OVN<,hTB=S7aYLw›Nci +9-鈓@.v@hii< n(Tp4.3GWg vy+ U$թ_b(B$P;M蘍*OE/0rf(~RX7&U]B(I i\/,t܈U?n)?M 2CX@vEb/ VbRu@1cʟ,w]?[{Dn#DӬ|ɤA%!q%Ly1S`PcqФuzp@O9Fp]7~c|i|B2ֿb9-emJòq~zQn(:"tYrR6D@.k">_ zi H RaM_.Wp.m9 y`>`uwIjT'u}[j(_#7Y~dU9Tt& s$_~ +F1Tt8X:GƧ1aAeT#AԜF& kPPu+/6Ny8"j]DgkP*nLhA@>}4J:<dLlIP:vO='KbH[`%R>4p=go=GÎ6mjAE*7DfzqX̙R1n*-ʚbXN#J;.c֚;_Dd +e;ɐL˘r+҄ 1Kx}Ηa v42ڧP14Ni+%Y3:4 e;(RFMU,+D̻tXiIg\W:_ 1YQ u 'Yhk;jjofZFZeWGL3=~Bld熌J3CĜ)r:[qTO}O ];MϜ&J}@OCKMQjâEݘe 4UYK<ێ%.=]U)wFyST-9PK+`NL&oԴH/E7,QANPm8ԢURA5"U+LvK|Ɇ*C$SeYA{d[M4JwWT"+Qf[ ?6uAG{E(JQ/[EļiMQBs t*ƑNœ>KOIPՖR= } 5v=}r86mU{=LdPOruàt૘6ѭd2:6dfms[רa5hbI<İU'KgYCV}^%<7Q2ؿLa(TENz} [C`FP{\U߭b\Yl,Q.>z7s3._U;Ұ As13cMĵN-K&ieAmэcF_p{Ɠwyhr$ +й9-[3 +$j/;&t1|%L =DŅ?t褁$i^FXP? DV +TȐϬa˰ʲM_)̓K ,lWy;&Ǧ֗ċkd$3iC ˯]3!1VKZm|Z!9 l/BvH`(}GT1ܟJ:aWҸoRhbϴt<P*=d*ݼqe^wP3JO8 ح=P3Z͡JL`[4Fdč2iefl:,V͸CcQnvcmb0b0:C~, ++饥K2ϟ:N#~yҨ> +{Ef%Р-}TyJY&`XiLP=S2wDUAKM&,c[a'Qa%zsrhu,+0ڮTt#p~q0>A.'o!G +3|6 .u' ]d[2]A>s;jL-` |HOʦS3XeqD퀷X 9`?wG9*p5c=vtв11_豘h$2vubb7UY +Ra~0Ix")iҵna8ڵ܍Ƚ KF? s/h $\)VH;e +9Cw%Xx 6Ã'$t!ѵjhl[m7J_L>&@-qExKlg EW}'RqӤ';U':3 +ͬm^XyG\3NWzZƓJy+'C*x۾%Ei^7F.c +J"~7-&h: Z@k1ޏj4%j-6gɟ_XzPCUuK~%8k`bFp JO˸QDo3iX))3@e^3ÍaeڀwcR2Vhܑ +_'6HloVMja6ɂ7NnC+z\TG!U(~o`VɜOV!@s7i(.O!RWAK9%Py~o}J׎"4]L\Ji +I 2~ү~K=6Kz0: +V`1g]֜b|C_Vc)F&Ze5b&=n[} s#eLBQ^рhG x2-gJ漣Av6P #r++4Amp]@.zd`lȸ/cҬ{Jt#hJjPe=-c}^kF{e^W$XK$ ަ^=¥| O?~N`N~X+% =Nl05Q`XeA YGTվXDUE'tAA +i j Z̒#b6ߙ׳HST嵊F* >51wBnhM'<HkQ +D]oFC-l4X$'7 ,\ Q@EE /[(6 U|G 6ːY1~>KL!(PnΔ:O7h3u"00!S %tJ  WX/IuQ:q܂zW>~a5e>9#1O0O)OkP+t1cͯ/K:ԳY0J:k9yG̗6d<(Xh 聾{/-KjV6G<=Q'jf]f}Wukc=S4ǔ͋X4̮)Qidv:Fif)H$Q8(tﱽ61_|gϪ{}mxi5k3 B.i #͗TzEe3g4c ϳ%g[LD_"A +zIh}3g*-E5lœ с/3=m/8oՒ|:Qj]I OXi8q؝o ڛ':m> ~H2yE}iHՊ7XMHC sŷ+,}D̲ɔ9QY }76V5%)dǟH}?<&w3[?I>=8sqh;=qjHHG&`jE}&ɿoί9&% +V"]g@d_'oI`wY߅o 76τ5Q1L-hֶZi4;JU;W6g]M\J#n +s܈/cbMpeħUӛ1MH'U\Wcf`JXg\Ѯ֑ +YNҨQ*|̷e_cK9A,n`2:V= рӯUfbˤEi!<ʓҟ%kK]wf[J:l~k#=\fOZ<m#_d֚8oJ1k[C(<n, +)tF PDRM$'k@Urs]Њ 6-S1( k@. ^0MG{u¦Ov +EaX-yUDkAU^x1V!E㩂Q|r(T~@5jэle3Tͪ ++t%F(x',-VѷT'Mٮ<1ZA@fI>F \U_@!6T WLķ6q 7 +.޳'hZ3kVMW 1io]o"Mʨ#agnpʇd䠓y6P %?bTE Li)e+d5/fc=n(Wiuq_+a$:7\«͹a3:A֒Jhg}ޥj쫏~&qi92Y-Y +wǩL,Hc#T=54PDq4|d9c۹#VJxVAFЏ-"G< +R(kU$E _wq7Tfx%GsGl#0+%rWěK-xs|-E'&[c+KQKP9͗[*7lFjfdaG Ϡ6m&${wO{>2-F-TVpְɪÙXc:Aeuzcvl43I"/Ȭog1Eq^ö<jyBv= $5 !iN5B,c:ŨlqK" {0 >#J|TULOcɺ-H3-*+ ˶%"pE!NZ&?P? ==oq70xGL+'bEۃa(lϏoܶXP::}Quf Hxqt irـ})>SwCI%U|NZzssN?𐁋jBv~Q|FabHQ>bGiY[`䄍eK^xlKƙ؀ĂJH϶0(d?(=3{ ?FYROnpG}¼4Gl +P{8 +MWno{I5tD-ٴo6W0^ + 㯏H +WQs/}e7lih[ I 5,tG j^ s/R=qځh!CkfM0Lz.5،P6AE7v j B>*$o4V&Fq3@5c Y#y *!YðXC}CdVX$X2 ecyw[SK$pXE- Q{Ѧ%OE+ݡ%ofbo4n0Ҩ*2J}B˨> E1[cE+RTt65f*\%SS2:\@j@͛blA>L҉CqnhFeX\^rWZɗͻѽޚb +wt+5g7ez0j+헙Cx2Aa'8zHvpt5ЎrߒҾd]R "+wԒn$t"}>p#XFRX[*uDY +xxQ֕)=u$52 +A0-kj3/xB V-; }EТ:&@ZCeMMf$6*%HwMAS94T8uҠFI3T#PQWYmJ2kHXa5|@՚=CX2Jhg&@EYV`*sne÷2~+!#?V1-p~-<?)]!2&C:2Z>Y: ]<oN^!K"ܡ!TfS@x]F*&bBDmY2BY6RVRKP"@aqWl?Emg{ԙTIK5{3ͪ_^zwS64[fPMH6BM1U,LA#V`XJ)aPѤ֮7 +0+:>6oG-+uCV "f1e#Uhe +gdШHv#4cNYlʕ[lh|Gh~ " ZLαzlG#\d:M+=-c$`z[i3ar>QzÍ2~JRui~a_s'AFyC8ʔw,)wyʮʳD?܂=$Wlr,?OϾP,],_>֦|â?{:3t.%9-c$`蟍٭3tX3vX+aī~` 9 hrGVw }M-Dx +*H ,Vf9PdDƓJGS5/[jm_mUPYBϣ!F7Ta0Zk%#ba,iX`gd4O{<7Y ʰOm4;o ex\ +qdiY$ h(e\_iMΰ_J2nVY|`a" 7.LF=N}6|,i>%+Iu㩷W&Eb'eikc/7+O )$J2^JeJ%rՉ 0xǍW +#ategyT+>KNZvXSYNފ*ߜޟX.xͷHε+>#hndZ^5`EBdV6+ZrmU`&̍K3=xiC>>ͧCRگ7~(sI܇#[u&5aL: +e,%1LUVާޟ}f33jo-ۍGD^бh2vþH';fDh@x{NbM)f΍+U~`Į (~~|@lyw7]4eh- ͈\5,Lv.X_8͜8pœxZb@íFQ21VዚvLqMJm9v星 8ϢFLl<{< +\ez W#ey8O"OUXcP!j*6Ӧn+-{{8xZ9_2~ }1 z]LW}*J H^a { L-ENT#T$0ee.0@à/Qsw>.d2+ZG Լ<''FiI[$foafCLuܣGtL$?>Z z37e8<6Tٻivc-Y w6d`\c 2: t0~Ld }8mj񪈠}*[#Xƈ⭖0zz6kEvj%{U/C5cu8@j0\2C]`x~6 @\I͐7nΞ;J jL`O(np$&e.Lz$NrPC҅?gV$3f44sP[ s(D,,A= )Ii OXċ"<5e22B5=T#93!yPs&$;B5`uafAx rs-c&+r[8oRJf" +*OF|Rpt 5e^^rB[JC-Y@Wߎ |SkEI]_H C8 +QVE2ӭ~G9 +OdY uJC(%`rwB;"+Y:dN2H~ZU3jY.Xgg%`b. pH::1+ 5i=f<&QbmzPת}/*,3-z",v}o:SxCE4q1`#U;FG% + C?y j`^W -sJPsJZ5C wf_J/Vf<:Pva۞9` Z= ؟V}03d.Eg0rcCƕ޿(˿~mx;ݷF}O=~oմHtGΕb\i'׈6>Zۋ ? amcE#% ;[.>/P'6Q½`#\.?"ZGwJxJ;;nQ~<"> +_Fr?1͏+R=Y|S?ݔxz/p2OMߤ??=>';Dg-sF|!3d{v[58|ΟڻH@Mx83aWɇr7C^!q1!>GC'h[Y!t!pDfAPL ûD)FGnøGAfip=$iuAk6kѨ،m6R= +=n+=$pfTilF> ß&" U +ߵ^d6@i PZb=H(- L%s֩|uM(m="8a| i+H/>-cI,8)A߈Gp.`yMN(BB*7vbC^A$uGGX>T4QdB:ecuNrIN~0%F)#02&mR+04hlЦkL>&mq%{/KhRhzT?t)2nF[Ǖqu2N'dZ_+߷ V6{";LÏWy~hʴtDJNz>hw Q]X3JrۿLEG!帓_Hcr|],9t`捠H!{7sxή vnn!6/(/я$ݽM +K2 CU}t249b  C aT$z"ED>w^wlpynZGr3xn|ͣ&';یnk:3NHey@{|.ʸ:G1F@ !#*E M PQ'gxesg^ʎ?PP*'>qqQyLM!AxYx' H]o VZ +1W'Nx: H"3ɋm #8,\-5\l^J}G I6=g箴1 /V#A(#=Qš?<Ј]F3&rG=͛R:s˙LllRw`[dƥ|6)'F%L8MwsgK%oN?ppLnVr%Ixj2qw$HeLb5K4Tƃ8k~zQ9dc.%nqmRRV + 4Ыf޾%=#v3X.(MC~7@mbNHo?W + .w,t-Μ)OMXpc"W/[J!gZ^j3l+b.|ٷR9{HHԠѧ\!T,"@NE.rREZkWQUP w~9Zi\s"7k&N"sEmb!$C2 aEFՊp8JIⴃK%|YpJ N Xϐ  r9RZ,cqxGVhoVsxSzSJޖu [S̎9X;tCCr(T) +qPʲk޵dhS\8~ґӇ+Ye棋:O\j.F +g U_þ y׬3+rH=DT.~> JԞ_#|! T:4n 7K(-!v0RE?K\|[-5l jH@ r[ţ[Qy"B",!gbxgkjˇ?1b9 x$ =FHZE9KƂr+S/YG4 p1ښx;WeWRx.5+6bt+s ^?"r +bMySU;9 `V~V< +,6V)uX jK)FHP!lYs <Rq$)jUQ<;heEGլ%"I_b$SןS SC lX1U^s/[TYb I!4L@s^™ HWpމx!0b8P'!EvP2z%7Aa +NEhH`(De_&50L> 땙vJtDvF8Ni wNO󰴲w,eT6JvrWޟ$X^Հg+?!]#Nʞf˼B]PB)CdY|E~L}j$ 'GO9TKY:QX5H& ƁtK1.m4Fiu.Jhg΍|F'mZuE"[fͭ&v}C;Z:}4k%%f2(9 +|4zh]]Ƣ PTmBw5TbRbH`~o=UFfo&oVؑ*P1>|-ֲӢJGFz/Цn\3\;b>l73yZtGRFa.OeL›$ yq?혅¢y$7Y؜<ʗkjoBZ_b9~%ӵqX(Cݨ跓BP +QK4[CO M'Qߌ^E+mPYv<)oCx4 l#KD&ewzo&4+ Ь'?YfXl*P }#6C6úЬOlƢvBXzlFzBb +,0]5obDsldcD߬ +XQO)7\d]#9(gVhxpdo@S/p~ɦ-pɈDEdfN?+!3ڛj/v[{+ BE($R)djc%ׅ_4  زp4 $)@F#m>ȘĪ˒rdgIY n%Q6qIJ E<%yvz;,UM䌮<ԲEzlOh;C|L +m5/g}ՉP\W-{E +exBz%~iGfrײT`C(>GfK9(J^f-! p^ȋbPeHrYkJD{ k\MC?}[c$IU&g&S^^‘uǷ~RfԥSiTd4L8R"a(`s:Vo 3Vʋ^ +V.&t΍]f#5k~T$|mSQ)oS@CR%60uŧvvC'<{ 7_vCQ|ߊuNc]b1R8t-e/ įQwc|l4t1jXH*)Z>Xu?>^7ES?ZQ\]cEk :sÿΚG]xxCb{9q*vXP#M߂T;I]}`i(eC ++rAD@ K3O2/8?oC;o*j?`x)$SPv!O_/PG WBUFOgV{&h_,P9[w{#h6<DB q\h*xha)-OR1PjV,y__@&P>QP"f|LkؤtY(D &{'^XXUtI+Vxea,_uτEXkpa qT=F~u^P'`YU S`n<2#Q̣ _gj6_$Pk\^Z*lD0*H-[x+e{A,[-O5T7Xk*$MeC#+?H-c}-Vd|&U~ay'w%jpx .~wU +IIp)V-R.dYj(6['R9bW +bkK״xmZ\<a|UVkV f36ϸa-QQѲKrf՟hݒݳL Ffv)wW*q.fXù\?hm<'°=PCOD] 2t,ȗ"b#(ݍ6Y`"/ƞi9)B,DQ)(7JI+PV@+T.4T ΎְQVdT*Ro6\CJ7 P+b:OrTs]I~βFE-_JF=7lQP [0{ +D`{}LJ2zp jw`{1{ ۃMMz#l6ýkÏ- 'Q%8#S-6B( ηӮb{ξ Wb{Iҁn/`B;iwMץ4j4H8%C4OUv5j|$IԝPg J!QkgNwEaTILOpN a[CfdLl# oR/2:ޤ+kldzZYsP2n[f32n-3Xz!\4Y[ds/n-3e-3: +o̠[lm~e"(-Jg΂8hboIA% HŢ(?peA?$c"h;LRZ Ͳ@VJ?yg9XlE.o+DxJ7*J#q- !6YKF_!2Ұ 5rɏ<_8Mqk0s1eGe^wWwiqKD}iSD!8,O\P!yzG c$2Cx[!ݪaouK8DEb_*89俁yΎP8ZȫU2 WfSNQu_4;VW/RU]dlM|xEDJ\nx@g,:6MuѳUZ={rD 1 l$n39*&9 ; ї $JEvhj0Y tx%C偌-_~W(%㗑Kd7M9ڀ=a_BzCsһujv X9 +UuUm;_Jpd4 /.08Lg*d"a3X(عF@ye=MbBQlm=a&^yMW,^œիP/_VQ$beJLFs[ @pa4:OkWR6Ea Xa]ع!̛  +W7Ł4{J$DaY)g’nB9m.=Za,TZXBFItX+?W8k~ ogOv:+٩:X?=d%{KB#H0HÎSw[i뚃r$5M(XVX$k*ή нܭ=iyO(=GZݦڦIC7ԛ>Fv6KXD:}22`;8ſrO˂ +ZaXYndQ %\.WT + ΥDL .3=g4ʡs,߬ns`ώ/iz7ޙOxgE>y!ΣV;M / +qqTIf;Fc8&,v.r,"uGy]N}0p1:,e[צk_7%PȔTkԮw5n^֒ÿgD0l99Y,dO/˓eE~ϥ+J,o=(q1?[́댅Xٟ֥pFWi(pڴRmˎiE~*7r+4?.eOL0ʿfߥgudw'\`(dem:s)$=_EY{i|,7Ra)?S;WS[?N˚4aU}5 n$ +B'ZLs_}8x _t9t:Hʥ#泴Qn +8_E|ER9}|&z1G6V0} O77l7xGT^??hYo]{K%kʎ1J>h8r|ŝu̩%ˋ; p^]{ቲÕBǂc~jK"9^u1u]VF[>ԑ񖿖.A}T3L#0: J(9 /Aߋn|jzB|Խ#R-J?VNNTz8'/!v'pվUf%ISs|~Z>. ,qugCH?_Jӧ~=ieVlM?]"w +YCk_?RᣚnLGuyp(eyF7o˖=¾m *pK!<;X[}Cbs߽a(; +[oGhoZ΋Z M(?hT9:Gczg);& 'Q,ͤp=}~'SCS_p6܅ԡHl(!7LU-kc>Ps/co/ ~ efߏ%Tަ~A,=lJ_/ !ZZ%"'0ZPY@}ª۔A*6B43;mZR[Go=ҕUU{|ڱSboV(d n-6v +7t?Y}\5]_}Zzɕέmi]9Qߤe`Xk*ZN_x݃L4vW5QMpc+mxúǨJ6ةՍ^B̈́_ηX`4`z2 DtކZMjXY ͟,JXv,b1z>^[f[6j~" ɽzf7eC|/[;*A&Th^ mLS#1c\C!Rsl=YKӨ nD5ޘ*]@\l{QvǭXUG04򡈓Hu \eQ(҂R>$P2*!}_Gv%qKv}pFGiII5|-Ř]Y$- >-uߌS"D TDxuuT/Yƾc{(L?gŖgyɻ/_~ f'_E'S/Hv&𞺵L7\‑9QUŝFڔ\QHv(-bnI2 t!}GmjbăA<Q|pw67%1:q8RFzSaP^0 Y䉂૆%%ōs`-34[6 K6E5o +p)B=,xO]8!m!1Z 7ƿB;(W.,J-y) ̆)xycI1akAʪnJРn\Jt7tLD+uO: ˩z?:09\ $NvqpSA5z|hQ79=7("b'k64~6+nd@?lԇA85R#9A4/\:mq#p0'$L9~Iptqຽz ,+``59!hP.ЇmS4惿#:)p=f)>^MľF!HHx"sKEaIs/bz-D0G->pCޣC΢#K[͋4Zy~8/9ߧ'TI} EP2ZNlcbHF ?hר~gqģ2ָ z + Dޡ[wh>#\~;Cʊޤ'l(NKȟI8u,z|Z<4DNP)! +G DdFCX , +k/8PqcⓌK H`[|bQkڋȯ~X ,ߚH|[9KEVeV([| Px'fa4Y@k}&-jp+8C W.;d_QH9MмSx\>چ7,JHQOIn]`%YYu#gl/e1: 6 +XہPrvCˤ#aIkI~9 1"zl#sAO}*tX?%oQ@W$V.2+'A|9"0: ҙ%';c*,>tK q AJg<  O3ПV_IGS2cw8ėl D񰒂!"N9qǤ!ƌM2O lCǭűCCbv2m ! _aYŲYQRiF5,dSJ$Q\cX`m/x< RC{7#h/ H+V5 mM9 8s M@qSypg6VQ7 LJYX~oe3T` Yq +9RX»2&[WbDuh z + ˹v6 ?B4A)D0u읣!*õ1[b9po=S6:k e =H1X)tìyJ *O~D{S( +uWbdzς3 n؅fps?)>V{%h5=[<7"T/#!i~rU/꯸P,NtR`LťGfl?AO kG^]",˃wH!%euTm)T݁CCbm1kN#+R3I ^ڸ#jA`\[qMVS/^&Y7KDr7l%3휕W +JE '(@M5zb C waYL;~}k l2b;X SZtܹJRR~n*g8ϡu'S$tcMN(3W[[(Ut,D@jУtAX+8;.BpyK`iTBΑB5? MO~+^x1_gznUbp!#|_:AshE =9C:a#N7zJhvShD%viC{4Dv61s η 9e7!m,lW֚'ϥ dkڮ[gՆaΈ|#teaG.U[Iw$N'tqc|B!qa*f1djgQ$Q>HM*.wzM!I׮ôuZ 0:ICx9R}zܸf-LЅO$t,7{SxX(EQ9[6E}8u?T 5ja B=D+mi*,B>2~B_6K[[mnIM`(5a@W/@,J@j9gp/|.ҍv#cmaTy"P!c: i!K=i7k̏ҮgĻ_PL/X$XiKwtؿHBiN-WҌB]I(AF1u!6dk^ǔM#akݪÞEaN¦b =K<ڝ&Sh  N еm)#R_`{K܍E7ě0U1vĐm_!]%xL߲Xa#x@ ;oPr\'OH +=@ba|]pjrT[זbeԍRjm}#!o iFk[O@ +R⬉o"lY`SSD{mPK 4 +0adq]um܌eܔ1:ְRQvnUUZ 6hkP!CFzV JMC{7UzhFvB?LR?I{6A/Ͻt2CjĘZaE,[̌*1YaYS[KLSP߰v! +#gb}?;nbE +yd hX aZ%S/s.zY+ }PH8kF\S(Fwf1rX-A03 $P~^BIi~eoc<d`ݕWOFe2~@xzk8˯\!k x__F%N:^蒓((k3[lE3?MS8 ̷gWF ODpcW+"xd6VQj1 eQ#Pnr4 +U0R-\t!H$OUT?3^ƢT٦ڢ tJpeʨJwGrlS`zc%#: s=*tj`((ʠV +.<×L:.Tfz,R0:TB%wv#' Q +z쮝]Nߺ}h#i/[xBo8 ə"%凉!dA +NB]3\5B 1 2]"+Fd駈Yз:V"]+f1YU\dpcPU"-L@pO\>ڻb5&p]}hħ;dCu>*F3`l`k{ MFtx`lǵn K<8x_gxV9yM"> 8`*{~RlDA|AmiͷDzpۅuO.xڔR,E8 +O^?_ zʯm7m㧺Q;=[7 j MMb\m|pƙkO[J3O3&,'hs֬?s?1N^GEO>?rbI51=@"3TXo%oޔCEvjR,\{d:?R X{A깭eAh74]c3i:zbw̸2Ov^QuE&@̙1[>e|Oȝ +"WxsoƎƴ~'x5'E}F?26!o2 AO>\5K6aZ]zeqya"tyo6r%e忰M?D?4w᧸3tݱCD%$lOhev{au_,-Ku/W#U8xN8.1^}zw=iũ.4K`=T|.Vzxs>ls\H%qo6p;ݹDr=2i|pQ*\q]#Q;O;4`)5ǽwmI\6]nvfU޸*oT93wc\ ?` ^Owm֢3 qφGqf[<4Y:H4lӗR 3l2sn㟍;hVHgp'+FB5biӹ}ٍχ +z}%w?sWrjm]MZK+3)pK^Bgue^u3Mg7CWHو-!%NWR芇z?ŲP ߨڦ,uss1{%_Q mbX{ިrhƂw}&_lvƂoAr6?dKU/vA!wX'\4,;FVt}ҏ9 ?yv)jޘrzL"7O]Sb&f{i8JC`MJGbqꎊIFzyj \q.O/1)>r0V8R}ڨ$,U~'g?{b?݉;|zF[F<gF7Hd;wRR}ЭHbV)%fBHf=]R{цqܱ^s Eԙzmb\o{saW7eHaH u W΋n≝}i- ?ڠx9kQ~tƧV FIiopGql=C+*5&EvӹM>C5o \SHdiSrI pL=|r{y`|Lko\H`lW:g}'Hyc@{̡2GtsLڰyG `Y=O[=|v3#޷fvV+wɃwqN+bXB,⣫@XG>;=h6hy6wΧ);>kGE|U\z{xno{S+$)&z>vnFM-xN_܄Q1Y% BYn^=,x^/Tw4S/\]g5_範|5&\S >?R^M =Z3i\LpKVPlX=v>xi%rq"aWm[ц/) sTN$/.Y~M)/]1*d~~ێ|%ˋk,ÍW~w@8"'49iw>U^޳Z: /mr*>&i煵1 \ + #O;;Cdb }T0S6)gSf#JS{3XH_WS'Q a {j/EweSVnhr***ˤw_0Ʊ%p\%Bqҩ=ek7B-ٽvJn+߯sGjȰ)o +?31NUxȗ#m>7/o!;[,,Vbt~ʼnf ? 3vaxlq{[#iYa#3mv R7H#0.Km_OrBϩ߷UVa=xUX¯ʗǏo )f},SbmvZ f C2U9ڎ Qfto7tpFXګe-|j&ǮxYc}_q7Dqf]tˊ ܮ.,-s(H4t<~WR\M{f?%Jck޻ 2rϼpyZib ]`q1t7pHw~vɏW,﬜ў+mm Dw)rj=mcʱrU ěVΐx$ahu0ai rvq}IYE$4EAu4PEM}J(__bZ0SI$[ VOm_h\)#N3QcaQN + & ɿo4&۫Ӎa.zlϱh#{WLrŚnRk6?P%iѫnV1E:d[i{#;n(v -_mǾ:{ +s򲟯07TQ쳘)ɮ)XX|?+,Q wc_axh,obր~P!%_E+vFW`i6q7N[}١tag,eǭ:0 5N^=cNj!|f96†d#, +Orl&^=ۏ~#~Cr__ՐLΑ~ސ)Gt_=iHz^QEHPw`~I#Xux(n'iB3Ck[ ʌ ƽ!ScuMx[صySkNb 2A +MHU몺,ck]w" m] f|.,:h8Y>]@C:&m1ޔ JUγfHW5Pnta6[1 ']c \rz 6+`W* H{K*2vf:R%|qI 65ocE񀳸BMp[E8ٟΨ+%O4B25~T9.UE1=vɯUw<V LC +oMī99ц21DRɲDX"m ܡ +M NnF~T~Dտw+I߬Ï2K)!vx8'X T]1?;Ȯ5Ifk.HlVZowy!mTxVjBU洓kA8|3ټHA :CĞ,{跈MůF4TP/Hs 5m}:$^p_ ˣtf6 `B'TxqY BU4bI!DfqNz2H*xS#&G0Zv+W&*GLo~"X r֑o?PDT>xn㑄MK+cԨIM!{/-xӻDXCo?;@P6*oP_!&JJY'H닩żLra":DURۆpg464D?FTD>H8H"i( +\EQe# *hC/p9peꘇ5 +I3!w r\3ѠV*,TfE=y~Dn\9Dhaj>jP0B!-׷Q; ƙL,&Y<CfqV( R3;5yUklC({/`<'fz0Nh$m9#\cIȉG )@W3RXbտ}h;Vro)>P&c{;+>:iON0l" ,A֔eFVBS ޣPiƑ9Od>~((l7ZT/%""dw/Aّ(@"F˻"{ IdsUG U +,TP8cj#COC*G#”<*FP jZ}/zDU{4e"FK*@@J9p<n85F RM^cc >ꄳ^aJi(%޴Q0PǺlM-l.׶VFk3_XhKUZtshB[`dkhuYPt)1B0I#7IL tah3qR7Q):MSeC$b?US/W%X +V (LzTg"ŏy79-lྲྀyu+,ZM!G +OH>Fa7Ir7S4nb-۬OQ +]V^^f}ֿ[vR:.N| +nh[y4RCp9b}ef3r-L2VSUBqSқpc.7bK\ܞTB:vpf +E5G,X^ e"F >&$jyp1Q q;m +"+>ܐIؑ1IKJ(7Oc>@m3ɴ ͞c3 +(ԛk1v+mG,w0<-Ƴ="[bUe* HK JCb#gJ9 TVCJ3+bkiR[C=ţ[kiEOAj1-%B '-SM77(c) hX$ +,TYX`E ɍ4r* KqW2ɠwS{b_Mn3c{K&vE_Q׌FQd16䤟0 +XE_-*.| [B[h?{ 9ޟ` +LEx-,ck &#ZarrmWtӻQӉzn ڙ\pxr%s<HJ A`VW]juI)U@aIJX"?2-S/'$}6ſYkey T24)[Y:_ W"LiޥO%2ŵLp#ӳS~U7~j4WdfXMQPdWK^{s }d㲓aݎN|f}'rAlJ.q霄x^` +$:&857CYV|0iǍv凇Z FjuX8j*.Pv㱠V*/ɁV WdX9d"xψv%Ayjqߙl[hey2ӱG +e9V򻴀w +F1z+Eu7'ڥV^ii{H}*Du'D9aސq<]x1&x%%(v+̀-hI!n@4d q.w:iM[gw?trS1O#+Y 9y~r X#&$;PN&KF~TJՍ)X.V1z\Hk(lùQkm?(v(G3|XhSګ +m*(BdFTT%(ˤjP1ma5dDyD*چ:З^vEU4 !gq>x/y:PoMFA*1`!"xcb1t+-{BD*A:|jtz~<*a.٨0ݳ,㇁҄kQL$V >~ΐ%dDVU%ܠ!t1=ASzg`I3l `!Ӷ aWe _zUy}D`Ӑ^gT׊2JuC[4{q/%syL;?s,Y}ܼw#<*K) lnX *v )gqnu F]83EAc7<=<еڅ4ѴT_!%gZ쌷Lr\xV+( yL0C=sSpAcѰd2 QB 4@(7! 9YA=FOȷ|46R/;"+ Sf'ʱG<"V>DNsmD0 Ѱ +y R IJuVaOP3 s^cR'lb h`=_I n3qJBM& Z +-gD)!Kƿ_Vص@k3}TAhy3v_g͠Bȋx- &TRv +hRovոʧ1y 9̀f4C HB" j-՚@v]LҜ\MXHLP؀ 9B ‘F&Oȑ +H$l E yn: +,ap_H"$CMW MT"Ɗ!hQ"IN+be`j@UH;!-<:ϳaւەk41bZuB$؀5(vÿkmgc9~ B['pz4xtd]"%'/k$`-zx\'o-Cpk莿J<0pS{mZYzS=\gl`X3 |_fB?7 6m|}%=;jj]{fg+gxD(B3R +Xttæn 2B@F& p:BT>bnqλ"RJSfz8F6 T.9)`ܑg-5 #jLXmD@ +f.|bfTiJ +9XDpurq[.ZxF^+M86~\j1}1}usg9Բ#g3LŸ*kjWX9 +~[ôzspT]*;c +Y!Bμ@( +Eڀ^1Fͭ4C]hiG;daiqXXį rȦN{d +䃅ߠ5Ɨ/~LDU^4 5AР:o)zIUO_QT!lҴ(|6:(. YFԢ1է9!zV^`3왜 n/1t R)z nP5E9Q1㉣uE!?6{pd}=b," ڬH$Q9s٢ ];Dlf /"  + mok،M/C-tWg;9W%v KC8lRC^HrFԢMcB.D9O!ywYy|"T-rRUHfڿ$>B2:*$>zнEH,QȥU E1ֿime$,*`c1u/0AaWb-DQo(VJ__'!Cf7u"-fu/`Խ=ӯ/ESC|?c]"7lgQ]/y+~ѺVu1YUJ:iisD\`t t"KiXK/v)U{ٰA^re +O.݁|o[[p@}]UW1ei_%T+8QT<\H/Q=f2L܊x.q&mYI;#Y"I)vrT*#oU$Gsr$gi Gfo[7/e _y 7$?3s1;S]G28} r$:on?=ԗ{|p{ަC aѱ,z2{W\/<7W_ZUN6h)a3]S9sۍ%i l[` C%%Nu+f(dm>ұx?G?Rsd4H]9r'AH3qWRfgVva ⻍_\V x)6\0ctO1d>!C4 +Aw xX,B=ʥ8h"Pc;g1a*z2,fm5wn#3HH8pZE^7kY0tFE#6H kGsztP%ad8ztrY| 0{o\"3D0?sv~[*sDlS߰7w^]J"eִ䪩1}gӵ祋1ݻPT\Ebo"k/XGUg nxtMVBL".˔aȒ֎d-];R8Po%6dS d"v%Y?յ{%,m):m06 Z|6ʻ4[B V27إepFEo*U po+H6-;>Q ƁQwJJD'zݥ.sf'% +!|`>VK,qޙlͩn1_Z,j S]l$^w +~>/v]ms4I +Ky[{X4|텕Y?l d(]nKVR.W1pD,GXȸ%"_n,(UN 0 6 ly>6E4 L&@nj`&<&IP鼂SbU,ԲZ'F>/0BaY vVFxj8z˚XV)d~T_O@qQEIfI:Ҝ'c?৷bn__*oP~ V 0a3v^|n {ٔ +R-/[ +X'.i¢Q Tڨ!A\n_˰r尽InI$2uTc/bEџLa~ ;ylX"좩( 4g av1T'^ItinT/Te_Ÿ<~uuħD +O;NDfh*z 2Q̓K7VsfʼnI/@=GQea*V)'b%wc)~5l YXiWƘk'ׇ/CY-9TW(( Vʚ4G@Xv#䰅hd?l{aXO65hqpiPRx6sIj7_8 c EGB6Isb'ǼO8&RK-|M܂l5Gx{,(Ø㖽NAP#n(: OiN2)H%bBXC_D/vb4 +t|MZj& +ǡn%E9٥7= Dmo5}}5Kc#bIh|ptz(XjU^L~ A\)79)=g6>+O^l(=(,?1r^vm_{rdy2Ҕr9:0=L MU=bvz/ڸiQ baV/%)Dz %a/6vpY_[uλTjRm9&t"PZ)sS'#LC'=u ==d +M'(o+%wT;(N1ta{vb`n`檙eh<*u ` 5uU #hj(k9[ 3w\È+kUsT9'eM} V +; #SM|<7N+Im.suy+{u@?a[H(Wҕ0^8w05UYLP7Lxヵ)z^d~vԋ{e"^|z]׏GtM)p jLje5LKweo>7q62K%@<,f/()].G|{TeEc0K.Q :Öguۋ/$$ E$" paPv2Bsp>D6]CwHa2DU{CS[X1|O,<)!^:<(<3u&? r0>ЦԮ])n7z}ܴ~KU+pd 7U+kMOܮCM?,A˙Oq)hDl ,AդAd1#چ^1nJœ_oL +;Ik;x^]d.!CL{U%ؕ=[͂/^U4æS('hm1a7Ɗ3N#1VwK#~ IVq^DhKZ8CL5*sy=w/C*1`UcD)ï<(PBus`  y h?p/ T$\0I0A^lć."]pMwU!}`\C I=p RCOXazXD>2odġ}az}RO;G݈boKZ* e`=[͘jTKV4q.-&e@5c0T)Io-Odvj Ky&LƎlRH(lZgH=pu!|ء@q;'kFu6(.jp80,Q@e~x,z{ +Ȃ-cF)#%~ jo7[Z ݥ*uNFjJ.F%\ bP˜. `b35tq*V6m="B ;HgDI`!|IC<-69ܑ3Uehlփbϋ6,sRh?'|me~ e&y9GY~n_nj` DŵEo.XrW%ac'/n2f_|7Z\`;!eQH2 $5 "HPRZr>Qķ6ʣ? +X{kt9/QOc}m4;Py.`EK T8YD +-ytfi*TI +jD'HAl+pM\J|h*!ZlTcG.HwG+ĕbT~ܭw2j-}B)y)Cِ:O|R,O7Fqr(-o,EX2pnCВ-okR!3i% ύǒT仌ϑ,LpqBSۈs/Hƒibs-6Mdk۩6$e"Xyt 9Mѽ|t0ssGWݱsb +D6L!uJpFe%~.HT`Fu(A!J6 +BšNKce4qO>,XAkQmkU ڍlJ(@Tā;`ݼ 67gƔ15fXF(Ǻ!&sz/v,-$y m(`ʤeJRSKNmÐ ubMJ/GvE@Pb?^6ߍݿd\~JB٪;W&[+#WJ`BLj1O_ByӮb /3xR5OcI߅& w$ QcdU$더Nμ(˲n( ғtdIZi>REZa̢8/z>[UEPM˾kEZ"\'9z&~{W;փȽ%EsѯFqoW(4׳i U$b̕a[2+:0JȵOj(-{rvzƾռɷc;)ZLw=HO+yl9;X_dffj2~vx0o2>4wXWK ĘlJ5y@%9`򱁼 ߛOAC' cdCaZȵ\u|hLT5RDO![ulP)s0UЫZIRbRlq uUV6\5 +N99X)rB1}7P&+=Os|`^ڽ P!'$KZҶ@ +2C?xH-JuPF@ibknlՇ-`:*  =ILg%r"D-7:}tˋ5@;xjo!x8{}J}sUcg\Ӷ\o\/qlw'Kg;;G|az勫{-ڕO'o=[d<=Kwm&2Og^^ogzc֍ΆݠICydCu/$s +}|g>L7:v'־Ѩ s#tT,5&٤7+t&o-qןi]mڑk0 dkY.gu(<Ajrwb[{Kܵts~{],ޅrԏrBkw8Gdţ^f6]۞7mx+R~=%^?eW*\~m$L)ŞOyqRvOV.S8Is& +$' ˴;(Csm»ý&.!_]hz/?_/gRk_ۻ!@5'x?뾝Vxn/h{S(zJ>=NwtP5Oٱ[:V?҉մ|'yep8G{mT~;灃VkS 4jr}TPeL9P)?" u ǨqwݦXEtJ,$QÇZ"\a^LDo>SSTQq&JQ;ꗚB"3TF<JtC/}>˨ chs6ItgJ#6w$Tw7@2xRm kҘx .D]";]$XrD(ʊޣ.j ǑG>³S9Lx7jܸHxY"qZls;@{;تZ(Ӭu5aBکSjsj큩2a޻|qT*`~߰xN+nюRܮB(~/r|}2,yLjhk~ P]R},- OM /22´?% 7L7GDS a}``q#|\'|5ck/a"ʍvxM@q` gq` \frB r{sSGio<F's`2AtWBBC4ll\0)PG칀}n2QV,(Bp(.H$H.c>]qܖPo@ph1a[Q~g(]kpr(H rh`WIE7q>&6,.ͪVnng)3ĭys zBMlt+Na윚>]BΰoNڈN`-j`6%=@@3.c.Aϰܦ ۓF٘ى&dgSPGț*G}nDV7O4Y(A*f P2@!4_se/.#cro!.Y9 geu8xFxJp#nzRN&(5priw/pNwY& ۚţh-v))s$bh{CDZ"{&S =`bĄxJ_RlҖ `Ss^^"`Y {;I677Y]^n( Ŭe2gp4{p%%)I ]=x 6QV(Dwe=]VzQZrڽ;|Ǝ_wU a!>94Oj̶GLdIMk ^.;/Oe̖cFqgU~+)4@g"Uߑf%}Sh͉ NAYelM#Ry9MZi6/B~DeuOEpRGi7EX +=;!e au:;E5 #]/zB㴵GdsV*4z]CuyZ]m,a;gckϭCPxVѻmlr7Z3CJMc:0j r7+GqOU8PzZȷv{~#W.8G =?G~nEy34%W$|bHKg‰4u2(}kK-Idl M=ָjO}nX q  +zfeۡ#%=R$-G[f(:4iN;!¬u;GAC@W\[Hi}sn>v\B,l5666t{>oޚQzm*o~7_譁Wrop~?-l}z#e2@k#;x" ҥ6ŧ8I.CFDfd2AQrmFTr42V1Vi(Ql|QA= +#f'èj%5ަN DNZ6ӝi 6P|8Ҧ4iOݢ:H߻b6i<̃sGY495u0ƈVmi^~;:|qع8&f6`Q6+c%gGEk6?؛kgX&|ҟd˷sࠖ$w!ץ(| +_|UAzho}r;S{0f l^&luf\RMp<8؞Kh!4]L^m,4q*JH¥ ۱m&_)-\R"92B4~\ +q4 :^1fqAz%lTD{K 1 y6Qxެć})mI1䪑%߯]B9|WMC# +{Si]:ӵ'iڦv+䞠e$;~! 1 U$8tW3tt6 Bd \Ӌ ȑی8f8u 8(p.MAc3.Ac3t<)plF~C-:*plF~l"ozFJt'@7q}[/njYe*X%x~v.[D9GFL6fnW.ڣVn|o>+V$)"d*3pm|TUe%!h.6MGb =%bsuRmoBR< +c6nFb ִ.OԓVWچ"H"y  +S>,8:l^.㨃i a kk;E=F)qE=\ ]Bcc]()В!Q@9DAʟoO@x=J:`K |LsQL}H懡xpi}إ/a9,t2@]CmjPü(ԇnDOiU YAI i2&:M +LZ>.&1Mzd Dx%U=SH"ܘaf;2_W-@uUZkj>>,M3+yX SF0u,2H1?Z{H,#Kk"PC0m /b'3[hYb:^RXƑb)~R,є?괟84r;$xkL_ލs qsrIiq-&^1'\}U&IƉ` +s( +a\c&55yb +Ψ^!  Ep"OSرJPxrF>? +y_֩BHٯm^tIooS JQ +Hv \ʼn`Ϊ ̙aK9]ȥZ! + @)buXjdOFoC'`Kd8a=a qjd zy+'V3CL.m=%7WgY{jfyQib W@]9FYkk^gV\7@',N[w X9w7!GȊO[ +$$W"&PZ[ij=z@l$dࢆ_г]MUU47b|G+G *ٯ6> .[ats{&1qSAy +{ʤdUõ diO{ H+a9| H}w 1k^>>PE ŪKUix͋,U4%U)E)Cx=U)uy?[U8wM[2cejqLo,8g slq`;\⠅6꿲86ԪGX0ht1a_i&ƅMmFJushlYp.iBYkK]kށ.3my,}죴QRxe6}+rDlFDӰMR{ɒ8U4Txhcr- 'dwRն|bn uSp6Ɇ RLTk$U%Ӡsk?rW:*~i 0$ .c yO4mZP4LV(V`4z7^X;ލG-9t5+R &lt3PChXHh<&lD:On5$oÍFXSJ5>4Jy,ό 1GAӅ?Z-lY$f4[h[?T@N̰;1Jgg ߜ&NưN?F)ULɔ͢Rź/1t9l4UDo٥Us,SR8iFo٥ɇ,z.U:VRIEY]]EoSş;)WXYeҙTadktjN8?ILr6kJ2Rs rU*P-Ҧ ^1pLaR+SXH QzH$~{.@# K}f4FT&=Br$\&YpxhPTXb˱OYiQQOn:~|1"XO|>؊lҸ6n+M1vg1^s5kT \.UyY +ٽȚApzJK?8_6{;q36^ܰKI2S$p^vpRk?7hbq0 YekD_̀kf?,VZx~W'ƭB~XQ{ଌj$Ʌ̊WfJQژzl2!0K8z ,ECVdʧW$)l!"r%{.P],g2wp]7Eb# 9{),'̭ +߉4 Qhqpgq9|C$9iUi^aL2ByQꈐ:q zlho;34Rvg,I*QIf1#IZS&榅djeJtCXi$:> fR' +li[tx1}G1ZmvFd]-l65!Lmq bv\(6OFVT ! +6wXZ6Qmg `aL/aDkgh n2f&Zގ4_.CUt'LR\\/<\6q +:?rD`UslL^KcBjt*lN ;be4 m4@f_~LmĨ*E +;Q~˵nYU3+yM_T&?,V3(* +_.>b7'$ dd[k[$J]Nstg!.܆CQťβ66Pl+.qu~-Za~EvO>a7*nB"Dg!z1)d +]bku~-)y6ӣRTRdA]YAS4]HOYCy 57ʑs¯X@f6Z+Gͮ=]qfHB AK,gcqoMjw ɱW.]IF1є0eW,y27N!ꇊ?aQmE}k+8;ۉ D iBUqfdҘv# n3*<+]OmR8 .H8v?&! JUJGɀ z?U_Uەa9u_sǵƫT>|KgIt#@9f0)ߎV}Jirma>w)/o౲$!?˝(_&wCN>F'e$w!2^DU=I4~(նaZzC'xoe~"gm29u8S瞝O+}5@>g3I׷$ Jx"lJ , ~?Ǐ}<*]jU ֡S5m4ӓcIIN*Yu1=KO"VॣݞIA +IK&m]xb1O*3_F換A䆴[GPJB0wUelgS-H핍W̲I{MbЍ;3<3nڷ sCTWmm i&SwH@Ey.NAf۷"|x*ƂLO5ɫ_KL̢y:qia}WcX@94{)C_ŞG1!pzPnN楁avx o8 b$b{ `1C*&W*Mq]jV[)C)WnY+ +G=IKʼnzZHn×Jc$hѾEAD LFԴU56A; 66;ÝÝ aO<%VdbDW$>\G|${0D ?uVy|b)õ6އ].5ɣNa;Kז! +[?Cw;07Yy%s=(^›BBQ Ɉ.[gȍ)piiC=%BfR}[l@x&ת:D?chQ B;S&Da4i!drTæ%$Rp6v+I$H`)-Gtp7F6C5$-hӲmLYD/䱪.͖f1xl"y>.vM?Ǝ}ݽWt>e΅="yaҺQP|gucw(`?Uqǁk?2eBZܠ۫IM?jM=\ wcDW KR&TpvXVno+=T-9WO_QTp{X}0K}]*-w!P-|OZ/4 wUg +ޝHp*?sˍ!xhDᩯ ]2TÑ7)]+mܒ@4'"rGU:\Q]Ó`e=H`SI *i {4EA${,#{`xdBb7} }M bFt3,NF-8jLc9ɜLX7 GQX!026fZ ׊\E*wQa2Xp{:NGd9$k8j{H("nwa>4.H$8"W{  ]h/ML*elDQ~/a@(^ŕSQuTGpۋG? 4w]" x;V.2NcSD)[B V% 4'OĄG@#X"(f:`9,} +'eGϦCHQӔ~_f:;B-)E7WBo呏P̳la6 T['崶]x Fߍ~Yr0nK-hm6I#>u~26WN~u>?GmyX8ǹЖ,SN^.['קu0 7S~C}|ɣbsNܑtxbvDtxt?O?2f;֓^'Mŧa8^`cd5[')e۴mR?.m׹zbًRQ6d/`1fݔ:&'\z~ 0; =wJ\H ,o!rm% -DGO?yQã{4m ?Ѧ~݋K*嫠dR`^+G]Pu {|v_W:NÝEw!Bn/kTbGmB(g'4(j֛([M`Og-O }a.!!/zIJ1:pޣ+$&)Iݞ"d!]9 SJ\B^JŸ=% +}%"+LNT;[S=3%E#0w~3ea !+Îۭͫ:w,ډM,=7T<ֱ) 0F n߳gJkDPd2LXu5ij/T]ad1S+s>;x bNٹ=gMi;bH4C_RǞ,K{46/P&mS._5S`mz Y/܎8iӨw'scǥڤݑ3UzyupAwJ7 +!~lp +gud&|zt^ no[ p)Ar/ v1f{`._J,ᨡ]`JSәQtwXK%z.Z*!{DXF}0_y#2r┘g3 +endstream endobj 93 0 obj <>stream + xۄђ>*j|d'g`T{ +.!(x#漘MO3~ ?Pѹi&@U'K^#V>o잍T . !NBcTpb G:DWZ&[R[Tc;0EaW߳:OK?ɼ&eJxљvE%̴TҙM^?J~y~j3\Jqp +-GRh 4,y:͒zJh=g!cݎ[5 E!ce5;^وۋ2 |5t>Sˠ`,8K-̉՝P]EC7 +%,}娛 jD]qr{r)|ؙIa+ٍw/cwnet֟?f_;N8q>2Ktx{;S_guZjt]~wUu"w cFخYzZȠAI?C X<兗@,]߁ /(.Q,cyB ";>6Ρ(z_ 2|QdbnNy"8"'v.C=&2|N>E` k섑5c;5 !OؔKU)S>ϥ,#E*G,#{ 8{zzSO؆0h\"LaR,N3+~_3Ϳ!vV4aNZd%㯙$:7B43Iy?O|9&Qe, ( 3͈I R]]tdYʒ\ː_i.Da]8`i+OsWkB|4iWa{7{.5Ίx=&B4t{k80̗_Z>R4if.hS3lYp] $LAVCS$ gLלjt騁a7.Mk7YutQC_w0ߖOoo +,Dyy0.jFzʖ1x)%0,7IlIaM!zD R46/lba;raTFHwGY*2rzD;͸",X wfQX 移+ujrZT~FJDoɳrՒ1:7dh\f4T=ehpDJ5Ƞ6pȃO3Wڢw٤6a4zP5ũS;v'{iQ!xLt9^ͺEK)ŝHJV}13aTąãFuzJzdzN܀آTW,(ؗy5l)!y9S{i0UL jz㸂GMYFYڼ.ܮ̲.o;éCC8 =.8Iv\ky+ӵr܆!a9,B? ra'qa#؀ʅy\ +;{ºybZ?רv=[#A9@Ċ^n+쪅R$,g~LXl$X*8<%K*0U;Yj~W=>;sAs =([-ݙ6AVW͙.)2C7LHC\s'`XF,!zgWXO0Dq&v6\د_z?$|%}e[I}%v,Vp}٩rb[T*! .H7R^lJo gfFccW/_Yz+1x +d3)@:t= 1o}kFycN7,/H3hOFF"IN@kjH#8e6ߌ ;G@+f\!-=J𥻹Zr?I SV=Z>ⱌ1[Sg1j9gP2)|;>Sp~3Cp\m p7ǰx_3?!-s)r `>D m_m5?=}@LeF,|O?[5L,"'~vvI?I +EYpvvpQgQ>u{)rh}T9 nOR_o_dv MMfoy<3}$϶m.'/']|D2Y(y?OLr5>~jW^hM.' MSR'3]1َ~߄~g_9GQ:2sH{_n᪕֏Ǟń zgGއSdmN4" }@ry\E1LP|=ǃ#[91ߦ8)a:7XėXlx:H5ˡ<Q!hbeNq;M^匎_D{dj\|E Dτzk, 1END҂Y]_*DJvV yIl`Xk1e"0G]兩 QX}g +ziv1j0q7-v&-"fX9"JJ%-{0ja6~X3l©B}b)[G(+09X|![@! 'j>D r^`pW)OIS>n$UX|J7ACۭ.om-GGn?]gW~GtRhЛ d{wPϹ;^<9irKˌJ6͈UPB`҆u(LZCs"B&Ĉ|02P]P +cz0bF.5y>)Hќ@$ \"I6pDgCA9`#g,f^5!#x\Q\k#zr)g,%fPݺ'mq0]Ǝ 9w. 7~E1 &H ?& s.kI,‰s,N@_E~ ˰ǮoӷT^^ .QeX–pH ?UU!p~nF)V뛪a$W+X {!*wK<9!%ab g a=x> u$ F0p׾f6T9y[R\ +hOD1,SM^\8hbhJD +؅(imڢ@JД=@Y޶U'4"Ѻ;2}R,>.d\= O_ ܡ/_YsTA.& ;6ެ +o%1# 4 -0a5zibͽW2kLPÌn*28S\2`%e@yB ŸRd8)%n?5M>>\m2*Ǩ1bfVi>Fd>qUYn 0.hty!l(|nb;>pG"+pYR l>#jՌ7Q3y\Q5vQ ,U пt:nCf^8!*:s7:H/c*Y_tҳo $wͬ c-ʷf q{4(%Gn],`u]Y\gB-,fg8eøfW&KAe]7e_H-:,pU]S'G:Nʶg6ҐHU`d4+i + +( % bB@k&Dlcm͡|iND\( $sm2,޼ nsTD>dhOiBѲ5D%I:kMdDONT}ݰyt-" B@<𹀓UC$6Jފk8 6 B&茙C X_}/mS"ig6`@M.bx,VSp}T(!ԢK[? ׽Llv^Xm׀'^hV'mf" IkdmEF{Vw+ cJ3oox/{ &N 0dlj`;^@v;@\mȁe4ȤO%T^$>)Xs[C`dn&]jgi`9T3Ϗ3oo +/U"r5XqwkBDp*Kʲ`Z ;JQY8zÖ0dՌr˭s 牡?>[hXmtD@,pk ׂU /tEwvap*U%v@2(ZkxMQùU/|QMܐTeU+Y@ʡQQ܅I*&[YXo흚 ݳW !uƮJ\R]o%d#D[%Cx] H84#I[m78, ޹()k 8&P?'YkO}ۯ|9R']MZE#iҟ8mtj ѲGUPgl=W ޼עNvp20τW([$@>"Qe9@!tIwŷtς}stVC +vK?GZ-+Z)IOו>.Wߎ8MJw}xS{WdN]xogW`:~}eE3dZ*0{J)cq*Dž6~z}Nsﺻ;{O}݄j^[s{WNڇ7<}.B3&?:r݁ÇI'+x~2W;bOw!qO6C Jp:m;N (f3%|jv@޻G?Cl&!Zy?q΂Ҭ:+`yWk||m^ +/ш$Ο>;>ܩpd*N2q{O.'Zpz&S_T1NއvgN&k}=nOŦ7q´MF'En Wt,YEBx +([}yLEwhw'{ea%sQםgL`pz_j&ӏT/םTiwRS/Zrw1w'~>^\TuV܃7 P~QҤJg\aY6_O[ߩ"MH?s.tT=xG4z5 <>v:q\?;g=gpTB\"f.wz\4fÐpo__ᏑZ9{؍է&`ueO߾%H3oK:(f>!ΕŊ{{b/NHrGؔ\f $;(9&{sZRkDžZe__9&ǽRsp*'ȕ+]xwݤFС,{w(N1P&CAgzG_q㝗e0$2g>`^N{o'7vK|<8Cp[} j#0)kxI ˹1%h9 LKKKn8:ޱ Jjm![N+ +`ǺI(T=plAA$6ճ^EAF`뺛Rzq%r(zNHrk.](~'%dF^jFGFڗ0@X1eZZW"` 7zPsO ll<=JkEIo~+oZ3BL,jSAp6~6jQozOfmH؍Fxطf+`SXGF*,X ^e) +W[r`Vkaðv2P]7@JBYa)mF8uUicXX?2ؓzycuƮ78-*PA2~oR56I"Yj  d~GpZoGPAZUzĭjY݇ߺLHAPu#MeYDF{-&Rv8m4PZı69L}Oxnh-JѪo} `$|Whjȋ{V|4ÙvM4˲gs(2f:uص + ZW.X+ݰ*lDqaah]C5@vݏ(ٙFzVk/;R5;R]FΞY>ֆ+oLXm~h ha'Nr\!FUNrhYrK=/uRi7m\!6Nr1<5#~8W/ưP;j~*?j8آ l&recj?#iHC$[F*rx5l"}aF)P64^ڻ +u1*qUm/C]r}Q5.Bo˜-.%ӎ"0P6  zIR[ҥōz#}en# i2LщG,JSc̠럵27$I¶צߏyVh I"_ .\WF6K +EwcfG؊~51z?u^_5Z/!~ׁcL6m \"L#5_LreБƓNnamdlLk+N;DF{ +,З/\> +DI=go q,`f US(ΓPT9 1Fo0bjYYY.3u"jǙ\w؟ +$AVv9'rk yv P2C QFIiд\UP{6ǡ .Ʃf!8[! | +uc;; =aW`X0X-J?Lk Ffu`ʷ5驔62/QUvR3N{yO1h@6!l;ύ)qbFkY[sHŐO;BK"hI^Epl`"D뒶S6a]eP:+MfF<>Y=ԃ{x_\pzG9q/Oýse1>4B)H@Ӈˤ BTкrBx +qUEM$^4bݩ޲?%Jo{E-1rDu EG Afl54;?=ߣXDb 3Z=*sCqq"z`C]HGD]jtjC-ܾf£! jUș!rKʏG)=4yY 蟍V`?{dF{%t݋ؤ +$yV:x4ש8C[:ht߉ L-:+2,tlꔊm9(ʨGƅo'F4̞K9RL)` ,BV i&x˽ I#6{ 3d9Ś憣p,tLe*R⒩`ʫï#Mn3ˈVBEqeitrH`t&&LӒMP ՗9D^ 6|AиC.:Сx,$.:q#ħa\4𚲏Aq$y \BhoRnp*Ï%΂ެe"u8n ŋ]~Ö7 kxxn ?,!]_!2 /Bz(%B/5lNC}&`&' *#Ub]{y/IM +hZE0԰*$~K εRwGA R`7ɟmT~/8kAPM, . )S'^ aaN(ŅS & +h'e!u䊊hXLLoT$Q&8& Eղ +ФIhaT?imuQEuljȠQ\Y  De5:ϓ&s_!E\7!|A!YA,ޏ eCwSA,r;klI2 UĎskmN:V Úd~ެSL'giX{??F[U y䩱2VÆ(j)[HD'2V@8E4b >p.."_s@IҐIXA ։aH]Ic"%D^|ZE;,;D`sYsIHQӷ}Dd:qؚg{Męb]"_1C P{\ҘӚ<',8N7BXE$B*>'c mJҰXt?jb1j HoSJ6V:B,[18/H.U/ }PAT+ |2] 7F)4iSN|¤|Sp" C ºJ^wbr{i&E aT}P%|?9L&,!:Q;މ㦨s?t{9VlV*ӛ]sF9BSR85T48D/pu# +'0 ! Dj~J8 +QMa$䀵i:D\.0ςb:s/=pc(o1Tjs-[;֙)8s^W9!XjQt詯XY<%V֐|($6DC}dʧ27$x]D@Ɯ?I(>9޵WY&O}'ӕaiR+Pu11<aHu^)B.rucV#G#Y +&iz|1oIoqUsKi6)tp8h9|0G;X7kN)sήc椁H +#Pm_B ]/iTt"Nq] %Cܗp܆Ilҩ#ka~Kh͛l!QGGQe)(VG<Ҡ0?9A|q=]~eqaؐZ&i=q0)q5 e/ a8Ǖ/#V"c0cqOC ƝjXY[WоbH6-O6cM"8f9 ŷyXZbܤS,,[^JcyYﲝhY$~:1'XM A +ɜ޵B$J博_!"=W*dn:R VVyssTdA38w]h Q75r2BNS^oګ>EM.Qm:ГWrB6 +B1,0vHȚ@/&`!cuQ0 - "N 7"^e2`H0kPTU_q UiewD`P53藹-Uǩq*8,JqְQ +ia+)<,QQ˚^ƫX3"Qqu׀Ѧ5A5iW8 ΣE"xjVaW>K=^UV3j:A sL~+IC-*e\ܼɛ[ED|ֳbgo|Xq9&d斲"%}0Ic8!p3Uc JN~QZ'm q 2o.Дq׭y)˰luŅ\Nڏ[RP5*`3a͕,P;xU;@ +P÷"DpE_BJ~|(gV;m_؞PMR{[mZ&{}#0Y'ӘO T8GAMj̛(>q(9WJ 2:Cu+"4|QKOδMZ4*,5_ +ʪ 'W +-8'>K6|Wp('A dN:RFoOAg"!vi%g i8O&'xO>DԾRL@~lmۣqE_7Bc[~DjfOcU5&&mҮO\bwl0z) 9("X(@XhUQWn=o4 +RItwe~=4lS@cr]ե$dut=UU/You(l& V`yfi* +RA&4|Cބϙk㶚d!oZΜNq[tءG_ׁXcfA2UµB0IUF}nj\:_2lIMuÍۮ- ̟N7@zۯJC'ts=,bRAtV,gb0jޗ2:]rWUu_g)fpwRĤ^:DV+<Tyپ۹^vw=9~4l&fMZNs.'fd|D՝r~cfʇC8]^'5|jr^sȞs_~|]Nyvgd1~_=4#4yr2Oǟ罤w+7<ȧOf٣_rt $/ >KOWߣquu|?Se)qy/n=W%gM+\SYLzʁXl7]8Uڑ"3ApOɘL&+ 3pf;8/wb: >qfPDh౲7*}R'ǯa]Ax|P/YmNwG㩳{Am"g?:ݧ2%}iʼ,4й6>{>> w*OYϟC.((ˎ=xu~F@)"{׉ rE\I+gn?p#s|m=c&0{A/}?_Hݿ(x=;T@|?㘢N(#j/g3+ܡ8jun޸?>on=*{uݝ.y}Q>ۜëQbT>) Jܡ4s =x+I':UAF˹'/+elH:#d2:J.{#|Nqr]/7˞u->{lmZ|Z2R2y=:9^Nvv +d Q)=s+e6?>eItV`& ]#߂i?Yqҵ!I-[%< vRZ~>5 +YpyyIOcMC ѻ5EP/WUǥDJyOf/uu~upߥ֙7 +ojԾ<>,yJN"\ojZ3} )Aoa]t:\O^}~ƼV$O]&Dއk-~sRzxFi_A,3i9OWKCy%L{xƮD.Mbw7.tRiܖkwWPBzi??qsjZ 'Re;kDHfګUoj-dS llpAڂ7qSL/:Izpa~${ϭA;+OIXRײ& l7V}V]4-Q㱚uz!XIqq̱4olȦbDMH| YY &\):@4=9G"Dd"3YX$m~0Lg 3~0)-[W +􋬶LNצ\=GRXDҖB ٖ<ҖP%͓6ZN[ITΒ/Yr/7K=!T,}I^g |FМї9__7gWi_Q~f΄uIlw挾$g 컒ۄBޜ]Ulm}m8Fٗ*iƏHqCI;d26k ~ȭRYXؖ[w b]Hs[n5u:&#-' 5H˅o񭉞q[iQm/bmc]÷U}(#OѢp/\߿emu\]GbKI[Xzfa#36+E*fa>rWGDz}ǍrhnHgVEF?_edgIBe0k~[~gD կĿRȑ=R1-4<۞Oѣ꾼DW ]6Sl"bJxԮ5΍LV["^-daos3PKI`[645d5wkzc3]u»U xUTvq(x &i4eI.Lu`yGI4^ Þresш x* 픺D;` dUB?*gxp sz*p!i:F$'"(Uh[ rg*"hx0/DgΉiF8i"hgzsTqwt~u彄 $,<#FZ0pO .YY|EYBTv߹r\,a٬ZF-,#+;4s{y̶p3ea5T=Bԭv5{g TQYU}G!),eS: j35FnSq 0v*$΃bdGPh".Q,0_A0 < \=I #jZ* g{Yv8$N:mBsӠDH~\Eg$zrG*gmWD7$XH$ T!\S"Dn|_Rs|YC,R VGq WKCo_*Ӏ+@ + Rm= _PU㎊By-ҏ"sx %#pܔ\PҐУۘ!|Y2 o@rEpK[bO(4 ;uC?.KZe&&y_@BVLI8ۼ6k +߃G$c&~6KX&m" /#mN1{Boͨ]dnH0hʏ]t;WQ'Gi\Ø%y5A9XitYbh@#Jӏ!CGR xS~P +9no&S[M2CF7 F6‹zqϝk#"q"&ct!vYӃWa1|+t<` CsD%Sk  ^6ڤhl$n@s,9Kp허CUjOERA0 +>{q89 48&T4JxHU4(H$;БhCE|l(ۘhSUyGEhx\"yT; 2KYhA—V)|cz*ϧ:X)Xډ#ttDB\X !*6=(55g\#攀3ܴF<n8_/ TOO( 1aXhiVI%$\')3hv,THr-U[S*( ,H:!vkQAA: pIM ?CMrҟb×U_pp \Y<<rB9@ۓĄye;N,$PҬDV$- Fq5ٝO@<{I`O, ?D<'CaeI Bi&iiS{Fb0DƢ$JBZxH +$#9ĺ^*a@~ bQrjs߾i?KE,ecYVǜyM!ǯǿtk߄-ZwZ4cKa+"F B0OukG# J.'*/1 9K +\+DžM> *|1|,%?*N1XDg*Mok `3"\JT]Y]J*ӐŦ*Ȭk$"r6'֐o$ҚF I+dk#98xi,jx5pjʁk* C+Hh~%jiBqsYcO9oc@ <dE*܆P9e 5W^ʚm ꛳I\*#룋T RӁh+ﱨ%RT,D25DK0䙏' G)0%ag9xs(u8 H#lw3&+гaw%Al:ԃ^xy98˭{C Yḳ'@*67@%hn5Ͷy)lrXI.%QCz}YߥJceLrkHQ;0xpĭ(i:R+jP%/%FELӅ (be|a5~n5K Ol+BHBX7>7V6oH#RC ߿Fj)N?[42*(/6{DՉfߪ!:nU/$n(ߕ }]U6}k]Q2}Y.,FkohE?^w J0j9On,b؍aќc_݊QtcFgF aڍolފq `1Y _bYd79}%i0XrLŢGJeM~`w} VYȱ h}Tpj%'È p:< ,^.B).yUGE*0@SǤS̹. 9^2mJ7+\TgB9ڊ{Y/pRN%LZ¤7ܶK>ɭPkkbioy`lW& V#[JY;u94X^K]RQBrޅMҀ~&Ju)^wg,潮a;e{Y..cpsu r▃$Y6$Y(;k Ah?^S +H(\oj'hmYcʂhGjHؤUiB0裆N*N%[cS$|@ Ah°VSK4Dun"J͵qRi8`Fݢ釫R^zwl:y h$~Ds?dlV'Ok^Ru~<3x9v-L9*@hw:)^sYaD+kU}dS,o-.AknF6 j8q5"iVM-ydҒf #i ,Llj`y8sRD,t*HoD/Xj;#L8[Oe6*[*[z*by7V_{4/ n  xzۮ$n6r_rk18'8WZ tlzr09 +X= +L/B{y MP}]7я29Ulu.>y~*r^}vNh!$528n}mNJ#52^ztQPlJlLߛשjVPo89&Xfnc=SڊP4ߏ2AEo*6c>gS-V XkѺ&3<2瞠p x}p`]Xc!N3W{<ʰ +uV(Zр)Wzq4"UYh LӴ~uYbߏ/kGyÄ2~o*/FЁܺ͢C[w}2"H +9 + % )8U@fo.AL cBE.hni#1+Ú9%PD,=in yNixH>y *jX؍Rϯ3=fKKjXcӔVLo|/RW,ܾ zjbv}Dc;!8m@B5a.HExT6D%Q\ LDbM蹔)0rH)HBb? |Yf ;֦~sSVGtPC@4b عd(N eFHЙqtTPeu,z4i @VI> ̀ƒ(5z* <"A1?k>\$B" Ě^8\="\pQӁ[벳K|bI\gȰ*ЏpxXuˊ7XHWY5I zآ_QnS`(ӏË շ^Gf(aԹ$zwݒl\k.QC~j &JP jhw߇Y@jJCoAt(Ul!8aQ *L@ K隻1&}B@̜s}0#JgC\Dia["*POL(o c Ah c{y>$ +,CMm0OS(ni߃T1t!- 1t#.HrC1Đo%!; +Eס~!(f5nf=ٞ 'DufM0Q,q}z +/HƎ.Ʌǒ7il \yt?(#fnBc|_/+~?B؞xjMFlr޼K">" Mcr.…6 d +o#F l.`u􄃷8`onXNQyC%:XA-`4 $ Inrz"/ LDYDAJG\U&azװ.1b,;Zhokwc[\ MNҶDCWhgVL÷DGuhxmA3LM!|X/. 枼SHbޛbCX)a$_&%]ڴK'˸!~Ҙ7Fg@rA7l:K"5?ݕDhB^>m^"g.l\yAÚErr.K]AbUNݒS 18H(q + kѢ^̀ZC@(ŌO⛄ +FW>Pek@CL4m@P:~8g)vf6Y"L_9,a?.3.=πYhF1 ʆpDb4Z wv岜p$I5NEDDnV痃V3F;Yģ*#ص>Ӎ%q4F Ka(bidrjCFYԯi1Q]{%0.<4fӻgÊ/fy':eKRY3;bB#2lLlڤ| '8MJa5PϲR\qT!xNN`YE'Iu f DFKn!b5Oh+`w"@Œ#QV< +#f3iONa׷M8|5ă{6%@|Wh־Mr[B25 W$E;ԼL,l(/-qXY忙]:zO^ںsGLo 4~8٤-wEiӍ-,$lwٔH!ox^Zh6_UJ̬%J#)o-j-+0.T{FAd8HY.!ꨮ7\n7_¤. >)=C- *}o㯁C^S#jmVE1ܨIb%Ӆu +> B$QҐOQ&MU[ ғh稾yɰ`+DW$CU%%S~l}Gw+jI䠽[X #oA){/S{J{JE%[gf䌏D+C³qpU3vtBy͆rcvP(Av6~ձ:j42iM7WuCe‘;Oq.: msKEU< 2P6,]ynj,'kB<+4v`N,D3:j"@kO5!F@0k)LEPN() +Q"\3Uk2~^0Fv5Ȑí ~_s]Ub ܉ӱ {ϵD&\<ɩMhrΊ( F=]U#4y?s͌HU~(P>[v >Jqo&X FYσ@lǗ[`3U|NMlx{ wIipн|o%#eTK}}%fE0 ɵΡ Qp yѢXyP^@pT('230O ddqSK̋y|?\%&;#*P;2 ?JwL_5B]]Ye%lp5Dpg2UQܘy#dp{D!Fb_lӹŚ|ZlbwVL?_X4p-.lbA\sN5,e|A>}Y?d$0#_4ػ)򅛎<7Jc;JT -?ӧ:ȷM'sGSlj!UtP+*$&3 &=*ɞjs:sH# w.,&j8dm %ѥg|Eyˆ pi`5n] Yg *_T8υ*fa} +NU#"z~9NސDI38IJzthAWczv@άfͭ *ձ$NhDZ;SX'\f_;MlNiVnQߚ?y+xGl`ݕ،t5;,rj52`XiG*^znYZ pyWq= `B EHq~% ԗf(($Ww23-s3(2)͠ zL}F17b֍njNxiQ0x I> =t|m0h6G=H,ԭQUpic}7hԄ3p\GS̸ܽYV@;<0mUsilMqSJzmδ]fRSG;Ns+/7$;MR喺BW ĴQzz@bV0+gPO+fIaEìAh3XiO+Rar%984UF隸xճZ_FBR|iDo%}Xs,`0*\:>i^{Y:B#8v'|kI^g!zL7{W[lz cǯg% 793*?dtNP%p5P^Ā<ޱ2 kz1`NB2^pÉ6;B~IZ+JMz?{GP_vYǷqr35JcT:j9fIH ݈|.Fr[2=,Gϋ Kw#}1\le_'7_k]eJ xԀRu  ]@ܯb +jDDZV <9k&/'M=HtdΏD0QiAq/V#sk&}]r+K޵D!I +wWJ 껢1m+̣Ii{_ԭvR_ |26ۛ/m7 W. -[\=q0@ ! i+D IgwVw cӡq@u7.GDDHg_#YF3`u{e.OcnpLUߨNy>> +a[=cx7׸5Cܯ(:y aHHg&rt| +*4Ѓ  ;8]N)uHPBhXW&iR!2Gfq/xmf:B >ZDm|~΂>Z ly@uГ87*k~2Lp,޿O0m/kݾҬ7H<va +Y͝K Lfz.o4#:4v(|YrY@q-̇6B # moJhSH? AY'xGKc*#1ف Y>Z d?qr-G.S_e%qWXIk[Ը2=f9,Oكzރk V>vQ;]agu$haʅ3XTj[btA{<d{C^* jXWhuGU7mNlpE~I{ua_ϩ!9]V1uOqÔ-ƙrTfSth0@ca ƀuNFBOO0MՄzBiqBOuY3 (`/IHQY&Sv'b%\p4%rtu!/QX/T1 Qh&J CL +HiʾKӽ.ƳR&_p6{kKG4#,U,pb^5 Z5G mΣYE*,}}idoI+[,bʶq0XyIo1\`S n,{e`Oe ^j`V3,/SlO%7aqaS>zI[cLjaZQLXmړK46mMݡzZ!Hً[h~\i o ,Ybդۑ~67а026 V3`ZB!]]a^6ik5~^E2&S!ߛ_ ؁ ni'8qU1^ûlʧ*EOo]av"<^f&aU{( \ȩ vj[_xHW1qB{75$:L,.]XBR>g= aRFŵȔHn'e:h_EEn뎐T#-[YWCb}yStzs;<,]reh'=1_wp3gŚ,ŋ}eog;Weom,9&N.1J8Gl}2tefy=4l䓿llu +._[oX81NJ䂴~wܤ3PH\+|y?݅ 3z<]KlY oADcBc_ůRx^ﵖߑ K'}Wlg[UO/nqZzr݉!#$gKUjǒ<oB̠WDX3ek~9mZJi{qوielj`4zaƻ.5wVB1r+oQT2dk⍭-6w΅ -(WuuYJ/g?E^ҷ=oK W\M,R*8\qJLYsx +T&b(ù֗IweKTE\Ens8RxwϿj7}i̱:b󍣢{Cm|yw\jvQr +t\oizvV_ +m}6KG2UxtPRC>R#1gG4z=Ɏ3l":פŷ+GpK?:ζ*Yzu(m۝^f{G{FSE#k%[>},/;`z<ݸs9{%LzS:P jrZ^[7B3޺21zKM:gё7$-Pi4;~zWQS/:Nb(ޮLD +4ǃݺĐlFܷ5TfY X([:{ kg/7q۱\^_f'`̓49/Yryϳ7`^Bl|h:Yy܀@F+rݒ-ĿƹxgIgwƓlË[+}ߋfff;7Zӕj$ppgCZ۹oЛk$SǍ?xj "仕pTzudW=HTY[%[絛ر7#-O/׾#G (5|#r~.se?m2 ?X\kEQp6,tFܮexG杷z=+G5zU%8:?<:<٥/lp_Qy" BgH+%ścWen ő LzJܶd3Tq)tvrh<)g^٧(yB^GF9;-xbΑZ9zuܻE#PTgP/앴;:#6X<8t\ig_|L{v_H1\l̸\§"o+n<ek:ڐ+2L F @p>̈́q<͟*ʆφ`~(ruS@p4VB21#G=_sSKg X`0 +7G*UvH*A۾wH~0GXҮqTo@+ b ?v>xFAC + }w_!T؜9eyu/b&D1S_;al튱9l6)陳(c0T+<&Cc$_ FxXl[z`XU/4cw:̚{Aڋ>AFG:@{2T p%fDw@uPyCo6\jTsvYCs}yg:ݹVCåS^a\/ȃP+_'-<@ݍrW޹n5&K(_L{)<ْ>W4,{DK|ӹx/);/TVaF>^$a7ptX87't/C\0,r\1{/q{ PU#v/j:CdHQV^- v}o!68ko;j/U<1Q[er25΁ bAū-ٷS`y 2|!1_pC_p/{TAJ^1Y9uZ3ʕ=L1qOu$2h \0f7Fkcwj OB԰z%G): RB1@٪SݳtL[F&^0ȥ +iW} *}fPn>t5u|=,Imvⲗ-+Fw ZPnKWx(?}m^^q?+`/-ux \ҐtÛHSknbaި| +1t7[\ muSo"^ xˇ4%JpAO~tL/CS02,)tpymZ`; D6ZRSμ߈>up%nbI#[!B)@*枈@/(!^QՖk/X \W4IlֈӿWs2qo3ֽH^X Paܯxyv)nm'ÌK{XK;}77,Iޟb{ķd""u}plmRc|#A +0 +!7."GPGlh%:ۘ@6gf5Y}**.᳧s ήCN!(/ :-!Y̪ *p%;ͭܨvmT♐-,xF,8QC+{ި&c?'885NxtJGuu740ߨD M0Ty(I悸Kٟ 2;R̭EA(^R\())Kh0dPI;ۨ~wbdŻ5@ +eraHy UeAgW>D8 ,$a0Yt:Zt߽2`Q˭8x/)gHPrNnZT)OxO\9'C3&E"vYVX:#0Ol07 vʹ4,brQ<%G, lFx>Ak7 0wB66F\)Ά!7z1^G!, m$\ Kh +m=DOEW҉zQMHձ\[x bg6N=?t(/=BnT2v\@-n{AJ13H[qM q@\DZA5(栞q^B~JOzaS R첛XX4VPRL%O4a¾Su~M]=48}A-BPy0Yx)ŔHL`G GK˛MR.sc)M4Pm]u&zf\AV1Ai8P{-5QpR7K+T[zjm/oM يtE5 5#O;o8~8q J?K"nqW_wL{N0og#Z,>h/,:?MO`|j&rȅT%oB#+/dm] ?;s +Gr,{ւQ N|'X9mG4G϶.ϳ%2|QJD2[٭'yPQ'S`LV v[*?_ӿPzz ƺCc ~~H WwT!9RVs@.!AGj{9-9aWPXہgPq @+_ 2.( +QU +rĚ\ta1Fa\BrJNGJWnW^KG8eXb9SwC\h{ MM_A6!raxaZ6RlOutTp%|*r$鐊Lj?vy Ҥ:ed~K +^B%ݏeo +9tI7 2DŴǶ-CRȇJ #gu)9L{y.f?Mik\^Q;r4߾}G,3+w^ b;e(bƏJrע=]&Ѩ AFR\KR̂߀/GوCѕ^KO6,2'j@} .t-ӛ9WCӜCC#@)ZjXOMkzw2K+ᐥ j{@5Bʏ28N, yx@؊ +JZ v)m`bW(XDHdIPR0>8@e^f /1W`c-rN+x8#>aB$ز؅tǽ9 ˁOkSԐ.s%:6~֝zĆh +-C +~iƨ$/bb0_‹yM8@?uW{4!,0V^swǵQE47>582iMŤTN 'uZ&9mm N *yosླྀu7UQvٜpfՃ~_` HZUJT폳EC)PCpS6chyAg]h5J!{ŸJ jQ*n.l`);qVۡK`aDJAS{GIZu 1Y+(Q= WTLЅ߭lkM+N*v&vE0q0.]*C[ѫjªߊ\=wP;-) +jg^`ڙns z@,)4ɡܿ1Fb*xL}wh#`[$8^>>btmBٴTR70ŬF>?7tE`IWIӮ$P}O\{l0]ѺAb +$ Dɧ2E C̬ZQg _76$K@ci'Z2N!SI"?RVU _KPi8`TޓD/k5ȢaReG?YMy2LЬmڳ WױTQ%E|AHD la8^Cx]o3D 5qU3x!G/Ϯޏz^"Y4Al7oxOcod9d5I0y r],3\-yq"Q ҏgEE%sct"< r-l(I貚Rnر̢Ȼz*Kn-0> 7N&XGX`9dXc0"j PmB_d"1}on0r}sĸQ ;(nv]$a`:8=]x7La@ +emGC[p:wA@MK%)# 4/MOqu¥;0vP BԬz&ts8➨<׽8Q~Q?A+1nc5YW: aq:B>\ͦ͜ T@KpR+otd'v0v#9p 3ApFdȷG#k#UlVˡ֮aNUezLY6ƀR!\v!&)VDw +]d# xuCߨgnм&K2*eT 83>X⑉wN+"K<.tk1r18 5Ү:6rO< +I=m-xh%xA~,#CW?_U0%\7 3u%E=>##7X|LܘtMk40=[6z3[uzxpIG*k[!~ܠlh2oe~|B1]/[~ 啗Guvu.k/RR[k u"/b1,T v +ZeM|XB0Ӆ.ɹ9!ేv$q"ş pU71+>9lV'ծ#s/y2/q]8,@Ԣti =/LA,̄%KTqre,9cɔOʻܬde"} r(A8R XIn-Qd,РqLTDWC,'.)#q`J D@‚6,. ]9YxLt`ȦTvNDglEg.j.?گ 4?" +V`"͉d{sPnk5,agF'5d+S* s-lPvaxF~CŔLqت b7( {Ǿ:(9xIWݽNܚ<vßJDc%SH`&ij-YlAўu= N]'Ɋ<91O +|°!B3Z:ʩFz .x%֦C +|;J9-8'&CD&vT]QC1nxoçFX#URYb0, +%( H=aGFlan7)ow2_kyk0h.ppT *kF!?$PWiuB<:[!62W +ޠk'%3Cx!!а.J3$]- &Z\XIKڛctukpv7C\#{PPrk^ a9GUqUN_G-2GCZmGl\0ӴŴG1~7 zCQC@ +3]9+) ` MZ45eHʡ*exS!IbD/q|/g`ɋFneHtk3a#tZl|4@OpcRn(]z7‘IҴK`%_2Bt|gG_ɏ\)|mVhRć ֳ C-f7!<$N)A||W!R1V_M8wKV%¦sVژ]z٩Ŗn(MA4YV̂RoH}e]GlFʃXO31iI^^L8`ڙ+g?|ÒMzb衉@W\/Kc9Z~|7'LWViw6 U*hR J-FdB[!L^ GjdtU7xWd0=-| rށ+[]EށQdbGigP)xAZOle~Yţ~lfGQudnɉ04lQ𿃸j,6dƜ \JD`JAd$aB@̍'3| +"UyW\V3p:V`Ye!$ srR= ޾ښh(] G4S5֋h03}cߨy(Mf0WZ`e"E}GM@uPդߋnux0j|«P#G/!8ˌsqIzQʼn;!LEvȦmY88`SfZ{[E~U@[`9I_D1ud6.-WX!:%2:ѧqY-J.Zq?ܚѷظ[:=ƖL/$Sw_ӏ\4z@䟧Zbko)y*\fMw,IV#Uv֓uWKy,|jY;/4{b4~tFg.dQ;f/g%uHf3 O'ab׵~śN~x_\Z+x[$ugvD}pxwi!RrLM~ꛯjgqZ=˕ر>gw-okOycv?7;ӌ|XwǒKZ+?sϺIYܱd鼏Pl[@2t^)$?Ewӈx#Bl^y,ތжx<#Z:Nort1aeaISJǵaʴg|b9^uedJiOp!It ~ oɥR::vύX7z칫=E:6KaÅ$ۿm%?wY%M|g~8OW4N`܅7hv + \Fd]W-I#~ {9 +0P/dwΛ -CfU  )= u?ucȶS|S ьyXVd4x\o}Vza#E_tәƛ}sQ@>Z^piM/YǾrYiێKWVR(TMQu!x]E`DҌ҄b:]M̊oB'j%Npu0͆ ve=qR#A终b<#R!drj =( rfXxXLgp lh~~W͑zx`1wO]"<-OVX'4 ySMm#H~Bl]0\p"ي!XBcZ'M˛K/AqptZ fhЂq ..Y#&PsEhp +(_'4&#X +G8j]qtّ2QyFCϠ{N$$0plAL""IcaI~}MIlW{#SQVz {ZrX\F~5~S[1t1Gw_8bBRX +7YW* *>V2M a~x>i>V5/8#n>qn* 7CQ}p#[!(QF VieJ\؆ofČ*#%zCBx^։q~huEjׂN=D#7KSOe/C.jjN6I`su + ass­T0ΎѾoB܏؎w<5®u\;߅I#ʖ +xSJVxQ#^ٸ=HdSgUZW(`&IόqQI .vOm\nlG_"˱e_u# +r98F)"ÊT40*L"V#cTk~X8 KMy|a괛&LZ+ 7ʎ0Qm~j7po6,rpע  !UznI~i:@+?$B~'WƪEyA2zHS(E2$3W= d(Iq$0᰼ +\rIN])e&Te+v$DeE4eEP,eD%ft^܄ciZ{8Jc vB /dpAK] +lcHWգ %cܩ8ַqC'~L^^KS?ٸ¹\LBl*F(PJ!O-3H) kr$WQ<`lcn^ޟ&W*F䀲2?"-x@nF *EDN/`^$]D, '&I/Jn^&p#23}GK\UB ;U +;FX%ne\71̲ SO.漒4!KܬíOe,ǹ@.jKq>%\lIJT717[7[x8 àLkjB(>Qd+Ӧ'0XJ,F]!wMI!*IpONKjtöBQfkD[8iKȴ |.XIApdTp@4Q{,'3rK| 1ƨoV6J)~$<ҭ~ Y͉h%7{t"CHGD|XƗf2" #"j۩Q^cG4;Nf,L1шh[IZ#NS#3ʣ*W[KCNI:+,*~A_-H&Oy0"y8Dyu۸*Ҷ ҞhIslrS1 )'[YL}pxӒ\H[^ފؤ ʋ %%ݓD{AOyčqpJ\s>"M+^w>7so]Cܣqiy&i IUT繳:ŏ]2 hQE0#3|g GLg`.!Y )ldł@DmRcY*|~@\ϓV(=YJ!&^`%8"4$S+7rZA<,eB˪f{Ǽfp?Ҏ=ߖh|#"fꪷC{zg}rFy\ ?Ip!#].sn_L 8" Kڴ>Br^.]HlZĴ/1[a${y6Ms}h1,7[r't_,,6k` %g ʅVȱ#|16HC׿b{HȖX.d%+0JmFF|h`̿j9a?X4fKZ +e5NyLeQ!~|HhwV%G_s Q0#ܳw[~,E? <}%b(eT% HfeMV= t#IC fQ k(GoC Qm>H&Ы-O[VPX9n\m\˒/A_ު>2&/~Oup]= Yݝ@͉>2|=k*\[/g68\gGc7!5e \on7hrnox3y\N͍D]+.] +kIKٗ{.w%-5b[6}C$M9l^>^O?EL%~Pjfc٪JA 2s>VҧTO%P%T>ʿ^8#mvU eMI܄ +bD}t00YRޟ#v!#*= " wziiq5ܯ&Bts(m6DpOpf@3a-ETϮΣ@ini,~@t%v{m + 1"a!{k,ORg%]d (+I_ uZ\Vv)>^pDTΐSCxJiȄ3zZ=!Pa-{Py 0usF 'm"B)#?D"޻Y-!EpKE0Z UaӋR?.-)Qy ' 78G!V{p3EaĤ ܰ€?,y!VQ{&dZR:\;2&EVDQۅ"XT_ϖ(Rs]&'w=>r0JѲ@ϡ4x q>Xhhࡑmd1A `09ǰ1Gl;AnHZ M|r4#(EƠ˃vwY88 FPcM ,ʹQ ddNmc%Ծh ;Vۂ.YqbE˃A? ;CsH?o maU%# ?dh) > +%ƑrfaAsH(_TUR+. V`j%{uERLO6(IHOE3wLy<;6wfp^LI}z|h:~yأkű~V< |pF4/p05zW! {eLsz G-p>FsEV3&2[MіO@$.Io㳬AʂZ ~9I"^ K&0am<27|v YZH]xҧHK*8e#é8)@S&906W_|V ?"4;e!>H|ݒT +4J`#f|,pQs WJ8 +?IJE #Uݖ/^ 磶Ol6ٔWlZMz9txFP#ح3J~C0<Q 3Q8/nݕC.NGY>BԿ [+Xh]ȕc,ޣlݤ{&0Ơc2;od)n6F}TA9-wMS509wnłKy7PCQńOIJ&HFyeau(sVP+a.-$F2j&z8UY +s9<;q0ʠY.ʩT +nYM3H b"QP4ߣ/ B#,A"1B0ĀF@.a~)J (eZP' +'-.b <k*Tݐ*ƝR=z_*g`zH(C0rCT%1|OæiƧ1wԫ<%?vE]q&8)oiJ囘-JU#ZU%O*)?T)^|]¶ [M8ѓɹɍd ݤb$q(I(&KJ@ trBM9ݸ1jJs+_QjƲ/NuW(o$'Vcca!T+.[;׬6;~1zb곷p6 +t;( u]LEw1cV QoȖ5^Rmid8膷I60ӗ.G7gY ){>OB"! ckwSPܓզG6G[^dHfʐ+ܳ=5bu q[b8W;N ,Qx6 +y`z @* CJGa]xrgMaj=qѿqaںϹÍm3okMd> _.PYkӡ :? +J(RqJyqIca6!(gP((@>{j*.c\30+BGV3懒_ݵc x1.#~Lv?lNw;'عW&ebyOxmv^%m|rx/[xpQ 5Pר|%ՅܞY4|l'2g)v}dY4rZg?\Ǔ~ lBϫn$cqBZpڝ#P?-afM:Hs38UFW"]qn-! 2ԦA:O7+ f2쬺ߜ¹%"=&JY# +f$>F?X韕LQ҂ }_~ :x4#QsWg5#!9'3!Rq#@RV2IJ.#ٙNJg${<#Qa zRBGތ(Ԇ;HlVg~(1qdo؝d;="zCH^אAv+Xܧ M@x^ YK%W|Sost%6Q+P5v+AQHVa?k=۵LXp9i42SaXgT&`|.} 7EA]Ză>z%!KW)W2 HŷY2bFdcC^sS$~0u4\jGu9?)z_h0rgMcbJnGO|X* ic(_s<`7֤#0M:ׂpJ^5 9Yl7 6AvslrvkmRWUUG4^!ѝ?uŃܵͲ@z@6! }ϭtڙrwbdaa'ݛϡHI^d`TxfJx \qg.@M_W.B8-&$,j/tI7F)5<`E@sY*nj"2pAX .@$F9o9儓<o#6p|<ΪG@%RI4)ڌ+sy*礌F>TYƈ~@w鶆/Oo2)OL닁ʹ)cS4iJ M=CWxJ/Wf(̤o4Z?UZ,qbgcrx2a.cl&!ʑE%ڢQ€dDg!>;/Ywlh[U@[$)YE6%nFq +dPWl (\wNE3u:OrThL+Gy1dG.hĦ;;9{C I&;ܗ Ńg3-%ڡg|]eJ +_G9",`c77M GQ>hwmJLrJ"A|$O} ?ff5TUv]'EA I +g3cj"vl"m92=ߤ"kK+W2V(\?L|e  k9+|)2^^Cvrpm͋I] Ȅ[L m`6d~C#- 3ʝjmZ9$$Xߧ'dr 'Mc*&f u< ",qf'^%Ϳ +Y4P% zdx5Q +,J`n䷹ QBgzrj3#}4BxJd'M~:l5ir vrbGVy8h}%>P%0ѝd +h"ya`()N+vI&sPQ^Sz0Ґs%^ܺl#Z=Ų\>-sJFB)z¶J@)!JӔ] RVϕQK!IǽkKhZ$Sil 3jv^Ofs&$([z7p9 83R: p{ l6ӿmqj ~(9LmHIMxr;{@9\Cr,x%VvwOf%ٲ./wSBq,n)C1PG0 +%\ozg𞝭FY`Ϋ=[S~ea9dU5;&~k +qG)ѽkB?ZʀNt-ҫeiwHbEFҲӭ^aY)Q>-Te'_2+]3gl,;L)?f-f~5?{6˦[ $lڐ<5#s]>>j<̆yv bC6w -l,(b\x{읶S4SGDMa2[!] `E sݗDL&0:_t ௾7"pUŝ Z38 +tmyOt/do mc\kЗBB017{2XSz"4&6? .hqRklC,- (3GHSѕfV+c0H_.nΤ +T4n@D +E?9 %YfCEvɋ[\0 +`S2MyX`.S(=R.1~KgN0W\9X٣8GGG8o L83Sv ` u הeEGѬ4K!p*2'Z=r1l{h$vMڶ䶄tSݳp+ JhB#'pb +7$Pj[~0Twq礶bEL @Q'yL-IfkyAbph VPÃتЫP55z`✴`ӢZ苜Mz +t+ MT,\v~_ob4(j(A 3D +h;3-歹 Lrc6 [Ȣ52ܢ]@@ܰA'nsq$v' 3N96ɖqޡX{Y:@?rn]Rgk4ͣH%$;$- >b *pRB(GV67oALlo@OD{,Gqt@փ= m͍ j 2@g@JaNds#Ax&ݍih1dX,=M gZu1n{KNuÅR+ +Nd)ʕ~kS-_a\-ԅܓ)e/Oc>7 +Ϯh1b|/ +VXHR/f_ +gl+f +1*?Iu;qJN]L}K_fzsӟ57ȇ g'Ië*(v.g)҉+ 6/!A߹lA-BSpU_vMw嵓wG"1*?Z~f7|7ܰZ?,o8<۠GZI]]wYȠsn'3+ff=I.Gޓ"}1m*X$]ͷpI^e+b^ʫ M z8_sf\45!rIcvY , k`X8οз }:YUN x GMɬ&ѽtkђomSO,iɄ~k>${7zk2K 3_jz.UN:l|ʎUlX!?f:qm;%}?zkaЙXbH(lib@)*Y td1vVb+)43l1q߻=BAfCZ +L-9~1R",=N@ᜆ朎k&\V ݄&تcg% .NAbb=z-0Y7>?eOqhi~>s%Umo t:hQq -q0ЀT1D87n{O qd6mT\?^x&|s}D{ٚb_`7 +,@e^/ e3?\H Qi%F u [薖%(0i  +bhbn7n^`{e,I% sP &Ac<+Cg /:-Q{ LIM'c@PA`f,H}y`|JɃ˸=2瘯˛L ;qषn+9~h(. G2>{a۬cϗіiy$J pJb ȭ6J"1NH~@^#Ct!Ӳ}];bT$?4=Ebl + `:9bxPsp + +։3( +fg>`(گ5D -UIg}BWJs} +%rhW[MLbp؅7C%Uqwmȹ3G:[;x_KYBia ,)qwΝAu3nPZ 6U7txnM oPrжЭW}\adncG&mPk!^+ϝsy82$8eLidSqnIȊ[$) `ز2 Q`Rr e,AALD**( k.Kl3ٹ "%㵸NjR[08Gt^iz- 4N/nn(ua85m*!UACC#ĜaVezIǾ"3Cw#>"WAشxaELUYRѬOf#[GSܠ 7Q^2h".ApMX G +GEM{~k9 D5bsB|R)7֓})h,!CqQnDgZApVE:N?̤Ơ1ѷ{, )2"%pn FA`I$͓|/לD +]:k#qvxVLO,X&LaY0 !:-PWV%;D`bad/2F', 8xdPJB9j;E=/qHgYLh'm-bS4_?x9d]C$$/Ex[ gUs_U g0Q0'_}$1(Źg +endstream endobj 94 0 obj <>stream +LE&D1#KMFK`IjD`\SteE=) OVu&BCsJFHzwGeY-CHt*9a9`ӭӈ6Q.LbH*[)+p Lj* F1;G L +pJTH +$7*gi') uw#ѕwoSmaOb-}j+)HELIZ}|Iy]|L1zk9=h?8k9f%[`Q[8z~B>`ÿBhժJ@'Cx[MH˘HİoUSm*bD(UH}Z9C(ޟZ2Vڳx}nZX8(MCqSձbDy agMvzuB<]-WQ(?i]-aRw~"ZS>9{SKڋl5N$Vo*Z8<8?{E{e +L?kɢ>0C:6`jQ=GnJ@IUf;Ota1b@𸰘mD[oŎ$Ґaqa1 8-7b6E.䠶OG^v6f3d=KK1T$ LMg:,I~sΐj;;vJ1 vFe0!ۊQG `_;:#MaT޻tœșf0/aG̋Ru;xP1s*xJr +hvjwkL(hj?yvg.m +[C=q"pǨ @o㭰hԞA9$d12U?VH6Yd{&3"qwX`σ~,3Iq}R1mo< ;w*nhz_uWu1WAqpդd_Kuu&VoJ w (#ۡwte&B0Kz{*8"RV27Imae*}J W~>ݔ̠9qտJy̭7'qWͷپKwnvGU?qxS} s-)oc7`—fR_ʤnu!BQ> +s b_r\Tx`jxpx^G=@zYF~Yu˭r€5 +wo@ E~$8|,L~U'pU|l*CwgJ#sT{xPY)>fDp1yc(Z[3 x2](KmYc{HEE>s{nUlj|Sn{p_,{,/&k2B _XL@-%cqo m fTA h4_7!(_Lbmv S}n,0e|;^.P1wѫߤY,ٰ75wݢNz>Fxy1ϗvvΈYC5(Upe.a+Fe)xt$IW"s s:˸CP[*;g.O3)AP"49pFќx fJ;6b sԔ{}}r. .t}Uv +ICHJtЉ(upx#` Gh9Wp=ĠVf0:Y&.Q7,{$*pAd+!_aD%UQ#Q!0}dz<&<7qy o<-ulHÍo(gШJ}/fI ʫ߃A×N!qʺK@:q j{}"Qc˴V߀#-<5J2ks]&am~fF[NЕ@p[-X%m2P$R%b(*$# ~Wg0BSd#=C\/ya[:gw}yrc*[^UFJMoQH] swAҐʖJeKZ*[;lCf&4#zDx&p'aO䛀Տ1 R72Df"Jv}7`(F()AR -e (DG Т@&jgأS A;^閇 `? OF.Q˝E Tw*%Hdb}D˯}x).+?'wȒ1A-MfIPiWR#MI7]DڎӬ))DҝesH +GrʻFI {c}i"ȑ>4Hi ܛ&m!HD6$^^)5xsj^~\ptiƊnÏ G,}P'b3胋_񭧕7?2vKJ[7pW%=BIuV@wV:[gW}6Xp?W2ym=ӝ5kwvq۽է>.?L"U_7"*(U|g޹j/7v=,~0g}-|RœR&}M,߫t^e*^:cMMDZhڦXc Yc"ڿ5l~EY5.?}pέm.٭ă>m_kGmS G +$3SM[ P@űvc&Ž]_}1XU 8{E2BiJX8@3#"Ee#4Z?&Rb薩YgT#jNvmpg@PGzU1o7t1e7&G;sFC5'9ڹ܅ mpCa=hN7O;nyҺQX͓Mևv [mBnl*͹gktOP'OPMC皳C)LO15  3w.ݫ\5v"6EkYɢXYXY@xFĖb"Ve6mƏIAwˀ=4>_x@ pc ,I 68?S*Ͻ3&x$qQR\: ~h6)&}bN?Qq< +@-LݚӚ9Se6&*ǩj9Ye#mv?iQӇ1$X Ӱ=`0.0Ƒ& #ӶiwTShSy$[!hoz{s)\{@a6+D3]n+`RZJڹ?ao]&NN @=E ٷh݇KQA>+`}opwsI[$>#\zk,&7mo!qRq|'Se9 <"07UkۥJm3xJk>a^Q0#Xo#΢WL,# 0c\d{{0,ޒON+xUjA?ڀg_uМ V ErwÕphܪb-mLU GMN"L^6NjJlg5“pn X#7|k%^U['Jxi Cw͜f/kv~uwڮkv;u}T5G"bo-C5~]61aovwLꘆKFm+A`( .F@˵H] ΀˴"0,$f;~5Ii MCw,F g>9 jD(^L +0mK FĦLLn$3Y7d~zV-pO7&c4;?cMq".W&@,i4*F +;ȏgZQ'KWv( pm4|(Ę Dg9_5[ȭ`XSm;?yZb,]I6A)Ai(0g ÉPƒ95*K&X!LKF RQ3E[ +oxK9 +]}! 6@ہ2]:u"kjUB~XWbyS΃k5g:}'x\`^\?wp 4 edP914`˃vnܩ\]B$?X`.]wmN<0&W)9Vf/w(J[*mDfW- ct`0' *l_X*ӦpF)0Z\R_"'Ub}7NL Z/qE+@wgh5Gk~ dϥ4mq mtemҏp8Mǝ_mcg{6U~oƾnBg1Wq5O4N+_IR(qn1~q5^-taF,;sUdsbǬcCQ'XM9X٣8God +Ԏ!B1\߆U&2k9E(GQ< C`3ƞv8tV+O +P[$J_C ʤPKoA -覊OYC&vg7A$č̉7I7Gq"%1j ʁ=VߧIvjw'1;O/%z:Pqi(d;ԅ+4H!M:~s +(>/nB2a;gbғ^.C5z`J!UyA: jUo8PΥmdZa\І<*=xts_ 3|r +US8y%PUr9Ec};וp)Ѹ )I_n Ts=vSвHaJs P<( TFu ,a.900k +OC_ʯ-,=3R>s0:xvt[WVZ|0(<ƚg)ͻimr,"M7+[%T Jfۥh ^t쿂prjϹ~u drnl( wm$򔸱y+ږ>)(Cw1Wհ[GӾP@@.~*|Aq}7Mͧ}s~^9~9D3c-XKo!v%76IKo!6ӡ%CKo![;Ov{.@F|׳OfEg2_ClDi8!xmDbSyDbSDCjHKo!JpKw|&sC޵~:8 +(ɸZ):UŒnb~ɱ1%?1y +Ki2jɷ1E86~lmVf%ՏvЙ%Cfhw: `z$kT7pMmuܲ:e| NJ pYieDj#CQ @b0iE&+QbJԩI%E<̓qF7F?D߂i4`ջ46ʽFaТ^Q7i?\4;ou'&IiUq4.ڟS}MšeL<4ߦ_Ҧ\`/5K* XWLTϝJT~ʷǦr^CX| e.PYp]`XwqnSz>]~'X+0|_bus$4P_}kD^\ K#{&xP{-Z.faܻ7I+6h>׍z3O.?JU(,γ8kWU&t$ +Ĕ+){"Xu7-yY~.5bc(w?O\ V8Ds-i+SE\I +ZGl}քBWJtd,PMgsȗ20S5mw=mғ:NHٯj֛r1;ּr\;ou+~ثt.U{Xn@>O8׊A&J˥U+zS#VYv[uw~I}MFtqըZyo&՚/9GGkRSB()IS??ŗ[{4l8\ս%Onv9bBjt[U]otI9l \B+!dVi"" _3Ǘdor'5+c|{_=\)F |etuxle;i0Nѿ:r"AD}ahn ^ٿ\~}}-W;70*2r2=7+-[MbOXYqm{jq.e|=Щ/ޥe~Zm -m຺`й\a+YGW $+M(^ԳsJHgsw)"FgB66|cŏlƍR"dy1iwu((S`A_(ZPޡzȃR޷` M }Yi1xOLF׮ȋ*a#kԈn证Mu~ӂNʿϟSOON ?ڕ*]f(8s"rW FPd)z.r.ga/l }aMڬ7 LQz H^?xq-~x +~kvaFc vAewrV~Rղe\f2rAeK[A9׷8m<fI *kF>~t?%RjCInZLGzp̨{MnR[IxTfAe>:mvJC]i(- Vs(@!dF-?9O@W]Ռ3;׷XK_!2i|,Xv39i{]nڞ2iq쿫W_aQ:xNRBbJJ{-`Ko݌Uclʭ'Lf&,#K-j6Eth,.C)3<;v1x|푝f62(0՟Qg; +B&mVypsߐ/zO2 s`1چ1Vh{#5{UŹM^pEPil\6 0M3 t9ub~fS=#|~{djЂ[4fu~0א"f ;*7 dU#}c5N{]}@-1jv2{TUFNS8̾4="on=#Qck w54`5CU=&F,m߈܄b8ļ׊MbF `(+COYk#bsPwZP}U7*șP~<ˣ*аzJ-xt|>kNynΠZl8g<<;/6`N% +s/81y$)tU I,+,@FBԇq@O}Å4Әg@ fނ@2Cw$!a5(]"hH*vA..$`S +qD=jFuű8.2 b|$ _(z5`1@$!3הag0TM̞^+Z;ߓ<b*>P07@E̬Sm}1a +*puL/D7 HW6j1 [6g.l3f ,Eb'l@5#JRL˅|kU OD7MӾ*GA9*?,th;q-a[/{#n1Ұ8 .I:+hBR2' _i.A>3-i7ޤV:%`X41b"O'iOU`$ݫ0ϫُ +"Ty$%k.1s<p_`E1YPaPHNS 퀨DN4bX$@BW}\t;@A%gIntu* KP2N?2zCu#CNZds 'w*璅>^wA'vY?cfo%aًψrZax^i9U킒zs >0n^x`rR;4xve捥^"; &!,͘-5UXT/<@%cFyW-qncixvu# 捿kL'k2kLX=1M|GJMa7W9iJR9iSA3ٞwp,͈9IeKkHRD/Ѱ0$J\flx,'@)~"CeU|N}S|-dzAd3N]:CŽeYoӣ\/M}m7(gfÈ'\aCod󒹚~Ȁ/>,E,M/ AU5a5CY&K3xn5pz|%G0rfF˃r0'j U@0 [ABg,z!pl|n&AA$&pU Ef!HMDpZ锰W[Gnƒl(`{\ DQ)+nӃjHBlϴ]Ë{ߤ +,o/ +:Pw)`/,;3xt-oNiCX(#fK 'g?M =Yxq +1/0s%>D-#.@H'g6.QWI=FQ)t7a+o0VKlm2 s!HCh0'^MJޣ{B "4"  +Y+>.ة)8 +vS|nV A~au'vn`.@^} Bkn97Me. &RA"؎{Z7 cb,- ,X9dp:þh?R(w@#sod+п +4 Jxx5QPe>xw0  ]c`.ËDN%(p=,ʅZ;>/`Üs GyM{*TfaxWvKSJvEqݴ\=,枹И!@wb8؉!#"i';Ogԧ'TfiJ719umfx(YN ʤp.1:u7u^_?4)wdg94!MgCi6圔 + >[1+JnwX~'ÐWM9dQdzɜܣg;u*?սsd_? oi4k!"YTĕUup{ =y5 33w~p%j">ͤOZ砚.R(SX#!R__,˰?S3OԶD887O(†  5 P*~7p`!&'XP# H~LNo/Ū۠`6Zn0k#K7` ?!<#ϖ(ش~Y˝@uH\>uiQ^˼Rb[]xp0Ȳ J}xHP6\:J?3׮֔YG> *>#8TY5-vC{Ez6|\S-IԸD%&\aaY @Z\EPA [OΫW-S yyL)%=ڥJ^Grk`[h}!HȺw(I w*;5\dfI-M\5"(TŌ r),6|:0ۥexz8r?IYnd([ +yn,f^4(d$Z#\|%aYA]O,IE@g5Ɩ|t_%68 ա5$"LXG1 uw]Pс[MYeԢ,%V[G ㍹}[Un÷ +¸eK6M\1O㚜,)ɊY[l7Php Ȩ6 9asd,zX{~GNL]tE?ji yMQIF@-X(_v=a-ofW,4atBu{چB> +#hUjEX/"Q:@:&&Ux0<9PaiECQ*cٯ>u(Wn^#6z^:y'I!Xa=7g? o*1{{o}{U7,4B;{d%]C7>-\4h1Q,kvn]b1/rrJ$t4Jy~D`.{'IqS]&ˢ xL?, L@TޞVMG6) :߽ Q'kR:.fpRI -hv7a? cr+DS +@n">g4" Qэ +>+7eaOv/oы,<)-nOΜ"PC > Pf>X44Y. /r{^f4Nq6l`{k E\_lک[K69ҳs7 7INX>JcDٻt.zقS~,C9Rf1' ',r$4 <ꉟF}agY JC$Pp9՟uN,iBoPPɿgڍoXɟ_x#،#Fq +z"[$w6!ӼLyW[cZSMG٫WI|Kh8;9Bi8 ի,a+j/2ʯZ!X<űɡc'vԊXyD\Y`$~mdžIG͋[׃ <#pKҶH/%B֋M>!oءxGӇ7ADsux};@ڦkoB,[J0O[;5|^PX*L&Ў:>Qk\,{=LVe+#eGyt?zp16aB.MȖ78`3f1M uH؆!7s}ȱe;D7j_-lSʃ +ǫ!=󉁔?lWޗRxm>` 9=1b+ؽ~R=p~]k{cl㾋8&3oc|taX =MaػԚ eF +3UQ q+`4>M& LDQ'˂L%$4}c1MV|468 b)*3d{ik]euVr$G?PVhH,T>Χaׁj-vy'y~c M'O&+Y"/z!^ZWb1:nx&S4%͐^٣gJDY76{\(~6vԚip^)ˆcb[oJMnGQoq^}9Oc;``W*m $S_8zTV(Rm,xNW=ډ<+P"Oc6q@c&ç1CYh/CI<;=C:bEԳOшg&r΋4΅1$L8v[و,fR8Nj$C[sLyaK4$oHT}j@˾C|OPQ tP𹵉ב|=Z[$KKngkB=L`[ohy%ujEZzWz̑P&TN_lqv,"nO}%Py7#mH|ߪ7tu=d@)8ek^=CqOsDM+،upZ(+yς7mA\!^y1fyhQihM&pzђA/`c}kOZ g)6=3~lyC2";~U*U\v?;ZW+24jd1 c;_J~VZ?f? {"sOE- JKFwBnK\]T;B>WdgUyبU^-&Aszk +bGY}ݔ@C8`y )حhs&U$qx`O{ &XBj"ۮRlfH SJ!ϻ+[%.6Bڸb1(K3({٪vYiml|@7_~)h߫Cf:VN*KϽ:h]F2iݚEm +,%l8.yŹb`=P9e*.3)Tj>{ŚXYTfHLm&H*b͜viR}GcKv;Zh%h US܃ IB>bVAbs'ixjEˡ4K{m86Y VqyΨ$/W1z +*QBf +z> 2qZ ۚ14ƃL:̉R,gN_#3+ G/k#bX0 QarwbZ Y))($ 25Y.Ȳ4A|o}NiYnڝ@5{6bv :eA*~=sTMHPf Be(T OMw)yjsvC.|;vkmȿ;>ߌQQ/'kB3CsQ}`5D\Aʑitd7-Oy{n)p +l+'Alū oftpfC&SӗVCR&?sE.XztޏO`>$c G66ZٞzKcod\ptSa7W_i~!65n%v]yj[;2h g%{Qy4}&1([L&P,>? *k΃4kYzy O:&#O"DE"OI˂w;yw9ehǶtRjL[>-X=[O0{ 5_njS聯ۗpV/YSX#nL(b(B!*()X l +9N:0CIG@6#*7uG)LsjNbtsBag@y$ɼ}]yh[]#{G pm PsB lә*4θI7bvi j4J.+7,bhI\/Y&jWu>9 +(_(;/9g1Pը(\=:;P %vȜIi+U@f(qWk.qpW4pdQiY7i;;_t-"mO;P6 M5Ā9'`g~+Bjcp~8H`#W1]p%1&ho9r Y`<!jꊙcLZF in@l (Np6lxx)92G "XܯDH"Z} v g11kk4WV|ᩐxj0ZW%Bք![{?Eo`2љg]OotY c7ãi.}Ng/iӖWJsۣjќ7ǝ3S~15 :Q-=)(~s;=Ziҥ<:#JXlZCjuhk#]KX#"#em E m{7g4"Qpy~}8shȁmgw&4g&8e 7mҨb߄X`ch8k|l1tPKW =`/#>IǷOb)X+z(L XTXKmr-iiNM e*|m4aY$;C@{-ajQoM[Α81*"^&DOhoƉuZ} ¢G~%f= ]3(xB;q +;!p1_|Ok͗<5TI0eBl 7ϖ{fF7_g $Aۂ;/̮WW[r|B*9p']ա>ŌdnMVq^r9D4}5H]9$%#%(IBG,A N +zuTr'(x _~"C,mnߝ0I?skN!oLIsCFXwqYΛq-N}k<*c8Gڻ*=7Qu ZFH gRf#Kp/o02TPџ,,񙀎qtho mPSfq]bPj\rۥmbȘi[`qQˑ=ՠ&Y;m(lJ.H3]SSߋE,:gL2NpՊ\ղ7cfŌ,U2^XS1pW.kzbM^ǩd]΅/"9{js4});;wX"'7@#_91vb*2>:uosg Τt'H+>730Nw,Z=;,Qل=}aO2ljv7쮞~[_c^~-a +p/?z9 +YvUscy`6&pTl.SLx؊+#_^7(^{IO9%W.zoT o+:gTӦ!^wNG}tSC7bDJƱU OnryHnꗫuymenFrxR/7L'8߄=9~ewma}{732񇣾f.5fj]Aؖj޾/Ͼv6Sٲ9v_A:/|W_]l>gs~q[ {Zs@1uH@ /*Na/| 3 Zӽzw-kz#<'gO\c1O^W2N]p'JxmPqeJ5:NH]EÇjA31)U'C]YEk|gVOzt>ͮ!s8͖r V]tə&xo*S~1(t˦ٽ*i橵oMz.?.7ХyŲϘyB&`ۚ|A[yn[=yh,3yܘEgSQLy<ʾ9F/>ƾ}V?2Wܜ6 MG:t7Lsߛ"OߦzXXS Zeu.];g͌%lRm Y9*O|Vb[Bɼ)1xS̈l]Coà{ݚVkC-8j(Ɏ:>2=5sOpfk#ak5{$]xTWlgG# tŧS5:/ 84 ~$l+% ;;Cl8 K|qtq(p_g#>ZVG1GÀ]ISavgҍB8IR&xMҝ>r; Gar9eC#}={PYt^ +c^,s3Fg}t*/R),ZNaWkXA5P?rrFɯ=#Ojkͥjy%,98d2y0_bMci۵r0w,`Kf.5;55Pл=XJyȖD OS!_y7r)]l?'`\SJSd]9asu`f8'K=:s!ǫaϿC(kaY~b(_@' z^>"оSn*\g?,b.B&⍭R].V!Im/ +T!Qw]~yw*TWfyDl SL/OMۇ-㖬KAt^~ + 1 Dn_\oc›Ǜ"v~^ipӥ{:NW5|y˽Ö*2e߼!N@߬fye X_1`B /cM^F)lNts3캳%25WBoBxF|b꼭^80ZT|?ig#d$žs.hWÙHSXǕѐ΍?|pR2_4P)wSNz,7^eä֭|U2Vlw_ƛPQ|l SsgK!O`Xz!`Q6 +ˌ֙vTtVQ# +_cE@wv${tj68uӢqJx=@G8aiCvko-Ƕk+(K{ZO݋Wz(&lK~jjjBQ?=UOi=CǷrGp?X|FE!^^S궥x+N#Gk,PoQǸۢksϐP /p:M?&Ph b~ !;uرI`9aN|#ۢ}-  ?a^j `_m)HlgAN49)2'u„Ju UqWh<ⅉ/P!3m'5)/(6~ AGVl٥2'Zg^HZ9o)T켘X)iZ\&5rai{9mOAIF}Ư(etOLxeơ^>%8lob+jߚR7 +>!|24@Ys/t :Nh0̒bf)DڰiMLC&1+ z<:#ǜae7Hux7_]JB8nZU+sK6D+8Is!:8i|F(9XVAWMc$(\TH!NfC,ٜe 烰=FqA- OI$ثKzH!("J<E0{]hʇL^yhV X~ >:OJUٛ3* IS +1b@4m)Kz.8#wEHm +{|Jw[҇Ã`~Hd!H|̗.E)';<`"BqQ ONCUu{,ۡ$DpaLp(u]+ݍkU >Tů7ri޵x\N?CKTR1Z)gRb3$eNǢR~]r۝g$l}+俑 -c ۩,haG)>u%rՠaJ9{:k 1P!E +:0$ا^"]E'B3RA'"uxj B/JRM<;kժzS:4(*Nr5oD pcNuP~淚`~?Ɵ:= bbR]3‚]c >.XLX(u,0W#XY Q)dipu!萅my1 zvj"S17T 2są7iCB ->b?Xn&=~CVyu?#2T]S`A\Q[(bx@BYc:}6P,}@>gƧK=Am? +/8KQE)3j&Ai|OiQ f3m}T*YƆ3m+R?D%GKd~clG%UToP >4*qlTiu1SqQTK\lxVrq:CVZ9/  h)i;`>.hlư)݋tcNx"kغX')t mY@*:!.,T+tPԣ] $tŽ.qr2(j /b.AϩޒAM-)DV:-ha5G Ö_J.nNH~Q ׀ߑ!#{dw a?jL/ƴù,{^5y,4l^}1*G/EpT!}lǪ5%CL?~r Й),FDoRays9٩ݰhR*K^&gk5ꅗ^ˁ0Bs~,:p2;Z 쐋 *>eG&:J iuPej6.j1w E3R2ʰ|![KtQyYE%Q(I}8{_;]Q?u1-V3}3 zoa=;RUHA_OO3ꄩvGe35U+8* +/^l+|kCpgg\)/E",ȽKliQsg{4/#J *XM SvqA$#/&nG>ZRŕ.GRk߾iތE*-jB g}ܫJrI.J~FNZG?W%8m޹Yjù.uWv[&8(נu39[+.˱+`\)_Ǿ m۾~㇂G0 Y!6CK̖YVW|*;V+MM8~d!dƹQwﺄ-?4a3RP 7WoJrꚰݻ!]{Kgs/XqGY|"jDW[6δYZPL0q8 ;$6ׁcu]oUCr벬l 7q!*W{t-DiwPmT'UB3MtGz46WcwY$$z()#_plD$h̕$ɕ7d2!dI|mPc%rr_,@?t B!Y> @Y>)'=y :ԝdKwzwLD!Y$z~ p-OŲcՕ\vA-^f!=~öpy^NQuչSf}%`fy[=W]vI-Q:$w&WU#柖+;Ϳ/ IfWR) %%[F%(6sݦ$ZB94쐭&VGKA*$,\o5O}\*ݎr;H]1;+"3#]A;F#ҝ~Yݞͺ@<"_7y?z] XO?nȈ+p30JoG @yfdyyͬ &b(WtRzʠۗUTU';oSť""nz+Hc X&*%~b~~>˝痋_z0FN21ajc=tջ( |Ghm8v_c{‰I;DZ}09M˜XUbQ*[!e >*!XG9tzc2B7=48l'+,OBzח cвN7[q' cG4ˠ~OBzJ.IiI]6IӚ €󎜍l h(kt׭@J!^hM8vPe6!zGD3M`?8VӛI-r +Z^^&lL[ #&N-Rbb#1o1Q epjlck( 6;}놃 02DVALt|kv,YPAs9jGim{M^ REIjcuxZ iy9zyՙU4 +KK'LKRƾ.%$. 3Uuqeofls,TgEag)#ݢ-g4꧋ѱcb賄J4-M 45 -8LgoA΃"+E5/Eq h5`.,h6&mPv13 [W Ȱ$o=yBl r׋>KICے6*>D 5pz7B?인EkVFf8%UlZ&"կw"3""Hrs CE @x8;ʁG]7E)D^Aъ^#+PpHr")XBuWS`bv C!3;v4C8̍g*-H /jkc0i҂2xZ$1&3wWc^_596Xv ,QDmKt%:-/_cy;"(`+?|H7j[0`tXS]+ȭ +]{Iץ]w]{V`~99XD]uj+wIpg/jx#?lXp׷ ?Oe)tGdZv9*[FIN,O7Ƙj:E¶eTi9s #e~nz5f˕D}i/vX+pzHv#iYːsZKY6?}/18e1qŰޞXYA1_!D ])D?5 x ( ϥȳC(ȣCs8D1Sぴ3u;lM.3[Z0<@Q.*PA):l] #,1JPHz\.]yQk7Ib1*QU;p +^F=|{=-uq7<^I4 @i{*:bSA(egi5ָ*˕3M&ü3(5ў E4"5Z8V[CfSiqo`:͞C jMh{\4U2~sO \^YEJЌK8X9:QȀٽ{}|#5#+8Zj`Dy%Y@ۦB(wX<9 +GClYeN] (.Pizԭrs36֙MÍ|o42sD6m4f<ȥE3Jn ыHǕ 9Q'f{3ھ]3o6O'ǞMO>Y'̕F=y欕hOcbXR:74jk$;w2wS5KN#C-v7uv8srig˖l/^^b15ȓE-] 9i疝KJIK5: a,Sp:o9u,RM7:l`26znkO\UQ9c7gyylkh*-橜->ل? D25}iُ _J.Q^2a_.fUR.i\NzȱI^rWQ=m`E&^)sk +YEF 8C3wKXJKX mZ#W%9k8dO)\~ͮPtY'iQ^b*]Gnԝ3$}sX# Xj/آ^~ Ŕ-[}MvxZ39T=>ch_W7c编|jgg {XM6 _OZCz,96Xoy"ɮq5ybsl~1FiA͎Tr/NjNyܲ#|396OVލh=*O@.Y*%:)>] "nPb+?d<^|&}x)獁!T~09|۳8d˘wϼ +-wVzo)v*ۍ;*4%{V'dF_ssqVu΄s*7;v}&_,J9ˑYFͱl~NTCqwZgk]ؽ۸Y?HS{n$+;ʟ_\m6Ş+Y<~~&l|-? VoE61R#; Mqh.5>{!k˳, + 6^#yW.Ֆ_[/cqbOyiv?-Em,_=_߭2n:Uc/P~M9O>4^#G4xh=y{6%]^>;}C_]~5)%Ϣmvb W5q9cqvn#ےT*ƫXw/ߔfx*[$25-LN&rcH +ɓ8")6بt_v5%ْ>1$br<3zG7}H̢cY>o/B5~zdB"Q9 \My%{;wu=[ ֦9q}5bSјMyԉ l9YY0x۞rp-7@<3LO5u7O̡ѵީ*YR:<.1U$$ϓ;H{2l9,k1.\ [*HN<7MT}v\wjKܥn$t3n&.,CU=Ό?s==UNm"/~zbF6ODm;+joOe%\BMh civk-$:Gi89wwey}>Eg^-y {^~ fb +wT-=0߽M_; +~/Ȥ?9k!^^/峓}|5ޏr; +\ϰr>o U=W>dfxs&n:9p6OOKx|*\7Z\3ښOjҍe|^`ELJ)z]cn}wX祇>94 yH +naWh0#53'L0"pPr5-n{Ʒ o*lu~9}@8h̳ g=C\οXV|z)~i4M׵7K5~-r¶OYDxȿW݉+9,4BWxם԰8DBgyyI2`͵30 ?q=FI{MRSr|$\ĀųX秡 Э^8kT%^>ㄏH]}%ڷϫD:wvluns]fuWXO^BNn9)lTSIs"c}klmv83fS*:yJy +P= +_;9glezOJRDPz~8Z\2UtzoNy5~~;0Usϲ\ /w7Mf!>Q6X|!ֺIeGױ9xX'8]9 qB9\ A 'jt +I +D1T]qz}$W#W(]D{1vI]-b7zL0qe.V M<tZDjqJը X3oYY/ztWĬTZ^oBvmq=U`ApӍ$VI?n _gASI1 DW3}+b I(m4 %qa+M4X r&TX*ۺ\'}r s9]A_?}u94zXuo,6kwߏ`kC&OS_yA3g9E/O銋>ɷ*" aYrd,B n$n"[-2pg.fD63ajZ?բiTEVUjMKuyX"|tZK ߴ7J]iM?P9}y=<=1_]N]76y_9f'#,WCr:r u֫Lmޯ]ع_"bybO\_Z)=6ֹMKxp Q*“#vv%U{kfdNJ!_"P7DDwmCG,cx_?4l>Itp@\i|=^ݤLvk{E֬#l3߸ܖϑp]{pSDҩ{ l_ޚDPCϭ˖tR6P@Vkl@8KơC,dA$a%Ač"vY8{4R1<3SDp藦|h+_;>gMrǟ'q<0lݤ⑌_YxS6zk݋3e}$[K&ܬU[3i㹺~H3e։KǾG38k? ѬQ7٦opqo>f69 sPDqջulɱk$603UasWs %9C=7cՏy>XnivBW^+M%7W}u'Ǟ8 5ZڷIa8ZwHxޞ/Boa'"h5k쭃!ř1 8Zg^Iq ^4UWYlY0Z K,rq,f_2Ǯ(H4HHQ>0lZC6{1 BT;+e8֤; G5܉KL'7 &#Q~O&&,Ϯ g#ܕk޴%*0C|q59* +7Ja(AG/ʹI=;4ٴ@b_OMb!{prj#Dk^ k*xrэk&~xr&!cg'k&$݋Pʤ.>09m~h 2Z8x5xnS˂?Ms &YQDZ/Ǭv%ןtG;t}A9AȖN V<)%)BݘgkZR9[4dI0\t#K g F^_dw崔UQ;CEU*Ƌ]5y|t^(8nC%\߭wAxaHg$Л+ZT.!oDwkF~b) tn0pbI +ަ]#;wQ ;'sl{( CvU.bb/id U'wP&mk༐w#v +G ѿE]2-eN^|;vY(A$ɻJϣϽvQu??xU-pEhhqQ OHx)ٹq L)8qmHpxH~r~zˮگLoŅ)rBH);?۲>Sڽ1"#Bn(m9,Ii.%8|bxuaO~iu#x0m 5TG!y7!A=od/D 28J"Zop)E={GXOH{qqw9}~+[jWO6ڵO?vK|+Aj&Kv J7V,\ލ&Z[=+W #:WInSSO|mZYET8b=3Znྍ bw{>*x:f- O2̋N -g\Amd$M6\u \!e Uaww)\z35/UX._pQ/B 9PF[]z~!m$$\k) #k+yu|>$}Er(Ʀ??U2!~ + z,S,ĺFAi5VFojNG尲l{}F _QJ[?#16rbaR41X|MmY1-d.+=ZmhևqlRu)=0g +fFfxެDiH[oˌHp\'PᅫecPS -80Edo:-iM#~=\,@ +{g,֕u,IzzՆc;ue{|Z4g12&.1"'iY7"I&FխhZ Uϝx)| Cb\NI=W:C:(SptsmeAd :W^17*2^7W5`uܜ_HĐSjWd:BFShvDuI; A xTkŅgCս#[[#ڷ XN'] }hoq5Jئp|Xھ%O4-TI4 ++5<nBo(np*m GS`shYk/O\駸m@ZcF~FB`$%\qcK޼& *|VLnϋnp/Mjr/Sq\kVf[ >h*ٽW'e]ȧ=AlYpLu:Ah tHZ6lvmbj8LMF36IF4wpOɩyVJg+O" ͷĹsη] v1`լ! F+qP rՄM3.`b .J̌PLz9(Q>1YBi_q-j7$vR&+L:LtB4^Te[d>,PT񗴽i(=QABYa {\c]'A/.aԼo؎XgJq[-~44,|sjaf dyI=1IgQ_I`*qB")&C + WKt]=}MLG.@!|AQhEGH)ӸD7؈ MVуE_ؙɐdÃOa^x2Ͱ}j X}]-@,C[44&/fy /2z&JVihIk&Քwr/nK4oBtɌynd2J.VqޘmIfh2\#,p`*3Ũ&b9ޣJ!nM˱̙ #((7i$G1ӚMh#'xqu*,] a#R >K)Rw\*hcUgU(|optl\taxqQ1Y،k9Gu+4aK+}@+7Y) 0É˲k!\X +~*x(W7Ia, A]b%MDv=r6Cw+l9A٤ ++Ad@⛵z,KOIm ?'3DZym5\"%9C\/={# +ߨ8US2:!'A/ + 9f%6*_kC@h& 2R + w +L' />*SsWy_&yOĊST@^*իfWNlr2pr + (0"s{ij Fe4 s{maR6P$Jf5˾qu@Ս}ѝ(/rm'HHzvɃP$ fakXH^|ox[RE^l|9UNmNN lSbҠ +GÄ 84ᷰ-\ +asspWir]tyjJwy9zɑeQbGxAeB `僸㼋j:љRVeM#&wtzwb*H^5ֱ9~l rc Kd~;uu;vYW7lTc"@R !#R($5`#4򽃥.f'#sGo;X7%}ۮ|B1Έz˫',9XaY53)D?/Qo6NwIlG/āacЇ-e>xVak`K*z#Rp~C (jiVW]OI=D.dPR!r9-E1qF +߆xS~nQ[z6wH WGU!=tc)$"v\aM%P7 +SAR]ZU^h 'i&$]#|D6ZnrkIs b"YQ~~~%R?~T̂BKSSN< '8Bf4A*j}ZV@<6J []`Gjr9AԨ̐})$)e5RRJPAa?Au}2SEqۈ뫽|6Yanp3D8# +21@^e<-\%@G.` F`S,j~(Ag .)ICoσ- +%BiRz(hGEU;Y0@r +,xEˠ(BTKXDY-L"PTke2T#(J.L.WpRO5p&-RٕɃ<Yl +-D ,+n*7El0Io0&OiK ))טa7ds`5NS4JMT$.nU44soO"k7k{Qrz-R1z_̌pmƧ@`5bxtivloW`xݜP ) +iheo) !nm^Q׳U|Ʊ_w>[N.]^`\(ڷ4,MQbq[1NӨQЗ +o)KjB X}AeL3U"{[թL%LO< r2\f4 ;DjH΢ҴQhtDbB!o{ٵC00ޔCA{[vh~LaX,Y*qW'ԾgOoc PA~= Fi;)gxAE"<)7OXĦ{hĞL]᫖p^%O&SK7D? %74{r2RC }ыs^3E2N[I*yؙփ5[(i~q*yJeFNLݮN9d;=㡌ܺx,Y +\F_~8+-iѰ0[eJ\H/=+>>P$0e#=#q-L' LLi5X^_3Qqxa\/7%jC$E$Kg 2}PLUMe}e/=BV@9 6؈% &# N;T%k142Ӫ@,ûM6%.tm~+&6Y $Չo NX"!n]_@Q2MJ@s RJU*K cbm ImYE,NNWO=ķnl-ד Zɋ4wQ_drEBzY^H&z|_&Rʥxmxٷ=A< q Й-/8嶦9I1Xz/jkTvl FR{y04EP`#p"LboB(\N fl~ݠ*K>A#~WPdUMòݑ/K 9$*ȪHx=Ptfi(ybe4ԏ(.HY.0 +48l\% *nmmS#ؠhmcLr2B!%V)Vz"9U7&E .N-.-mIf̩^`-RԹX;0IpڤK.j؎3&rV}OplS +Dd&19~:5}a+![Cj9$_}PK6%Dʪ_K{ߏ)å1j C3sTf<4 a "4xū% bi֒%2qlNP裤/R# (! ̑)5,>6CcWd /;'0lj9HZ#$m>|Ԍ#p#jQ3rb?)ޕ xFȌWKx-QEEW-۶< (1)d&j3=>iV%/qd&-l6,TY|41,JHEB848wbA_ތ3z[rIE^ҙ5R"(V)*RFDV(أ;+F J0*s~f$> b^|/!gă"+Jl/e6fvޢN(` RaVطaAl~ςsfMf}Y?utv)=giƙcsjKQLT_v9u˓džڈv>Vӛi=Jd\N1I~ uMC:;bUο eCtRYVP_0[PP~|wR<#Jj-s#[Ye/UHɺ0ebCH uC!彜Q\XhÈMAeŒݎhI4K|,U.%o@ۧ_uwߵQ+2`M\l4`]|UX/%;ƍiOManZ_k'H*8/H bUQ!_xNI:ItaZ;FZR%Oep"T8S3 P4C(F]D6m#}Hrܕ\L(W'L% %VG3D_r QVJq]4LTjBÉ`o!v[MI}jԔ&0Ltԇn=Oh1`+Z۴V;9UIAg_o/3#4w8G*rڂ:1<Ě +H($b9 +bp&I`GCG%q x1R {}X{V/ ,nkt%5A:hK*j"5V*o<%f!3] %,2dU:"ͿB6{!W 힒#dZmd<`Nc Flg0rn Jtu@ #VSM&F 0%}1wTRI!}J DqP//X${cOLrWgrs ²ǂ4W~UI[,!0Kl|]bJ-vvH-*|fkuȵHRy<=);9߳?-#Jj~Lض~g/h<]'+Q6gA4"(dX'K{B% X6H +g4Nhh^Qd`'ϙe >\j+_n\Y-v +y!a{[_ Dٯ !po +fRAQ~ddEM$KeʫP0G +sJreTĦL pCNQIـ}8d#RFDY+# 1Fu,"P\Zѷ3I'(: p> حw"6Co;3"QEy^Y8K-.phS's+kDpZ 4g0up,Pkae+˄ ކˠq]jOׅdFK3u]Ӫdl<"wgU ]l KU/V+"߈sUcT%YBXB))f_j j0BrC/6(ְ-BmBꑨE:C,LQ44vz2^2!ע[I<zᴻJ/b[#ɋ)kCJ TEC#;b$+R``= R'UCcfICkND/Ua<rk9Oic%y'Efy+6˶}ī,li$JN + HBAguIcIf,9+>|8U8M#u*yj1 Vx@Ae+~&ґ 9ŌC,j̓}`CK_D}(`b]rU[x9N;^||{1\ +N`"xK`ǧݿ7ڥpu&y= oD@ڳaO_q~ORqJ)fMˁ؁x *jF̖W|e0?咔l'TzbYiWnjXr_c-*h}L_#H%l古b9d113jEU3Z66E;wшv rBkKD[C)u /VƅT ҮSOj?g3'@0c*d1h<1[A*iY-阗3P3Pײ!䱀 ϰ%/UJN3 +q0U.+ګF̈́d}ͷRFAdEM6M̦ BS 0#x{^eY7l +Ove7Ȉn o`R.,@L/vP | 0ˡ_0cb`MuKjk.J%_AET)FÇ t؜E )k H! F4hS݁2D[@쬉؃nXdU7X .y:9sΕ|IےޜAyG"srk^Lx(6zì2HXu:9h,UTc)OaY81{xl`Rfj\-wW w%;9!#.:OVªRQS +6 ɴ|.+=qMp"5c'f5RV)LL~Yl|-l5I$GAJ ]вUa]%Ps*(\ϔEpR7SC J? +0OϿOBBLfњXE WE6IJD}P 8~7+<|[ .1sn d*|I2&dC9,!Z5,oJrnllv!(aOw/2YP{"< CVF/SC\ЧF5EH柤J7o?"~[߾,/m6g1IbLN4jWyː:qү.Dy\5O.Otb䇠!jkcb̸P+E`ʶ--Ms)GNzm3 4ͪlgA 1$t`D=uf׊5".-㖷L]"UlC_]r*/R\TvtચGG%@t:,MU"R{A6noGǶJ{5K9$%2fp"C5.ib.2 =JaUfé~of/xOpNbi=n5'{d4|}1eL\` lcx "l ,;S-OLa96H=U+b#(RM4~ +[7TQ8>p?r8rQ; GIdU~ b$P[ՐKKl23)JDj^FEq`MAfKfx + Mޤ`.L)%Y$h ,xfUbw*8 qm -j,sL{EoR{X~-oRHͨS'A +T6@ozϔ!CF}I1tYrAhaޖB8d%t'5-L=,]IHNmrIb.mPe]}ja +3*`:/H=6QGD~@$^'ezxq +lMCsy/*xT [pȮ۸f|ja=?(`{r'T(=nڻ1lqpD{Iw1QюO6O) wjALZ3$x|Dj^"fb_T= Ev18q3AE8+rYġ ;$|-pV/S}>u= +a)/<"hVٰJtp:zق7)LRݘ*ۡd/q"8_*IWkZF33fdG{h0,A7Ö + Lꮈi|,p">jCdlZUega~g(C֣ +Ppˈc +APq&ep%"%vt9_-%1yix>эz)ʍn@&_l_E&jT7pH=BnzAΪnLzd/.ۉH }+&WŶI֬XmF6g R8 Ck !. +6$Cx/V}J%OmĆ) )me% CMEKCiCa +4f>Ur)ZǽUO/_+Gm7 #oaNttϏݯ+\jќp.31`WqNn$:DJOIO0@$"DdlltgF3m|ɥowtQTxDDMp\!QcnJ4Qc6S,C*lOS"ȁt5o ~HޕF:u&# IutQAlT%GB6 +O(6Mo:_N]_1Eo4 yIy= =?1<Q<W8 lկ X9d ǂ?BP4Ysh#t0.Ff +9RKѭݔvQ; ~H.e!`0;, ²YQ9m嚥.Ÿnft[0e1u7I7yHhu-VG*}&_Ro$zv׶0TB9$4<7Qj:i(\CL Z(20NRĤU`%9 ]p&弴Ž%ё `, +$1C^(* & G#JfzfFHGh&:-$'1 +ZwղHn)"l"piNa2:B'RڀݯP|6J.wNX\WX갍Zi@5JSFCW"8ĒdGS +2yI"k;RCJ<~d_d:l]JmN%dsRx^:;devG,kb?XB̗uN|=XZIP9Ya5a{VuXd|8LJ^ +RLއZh9E}m}aMaT~*˖W^"M:Ɲ[\U?o?ꓰ] Ц;?XW~t +*zq0%TFVlJGGYao_j>y?׫=;k=X,9#$FySˀQ1O8R\Iϥ?0#JtȘ~U}fISxquZbY& ."-ͥ_WN/{/06J1*I|0qfx ++of`jx5t+U̘I" /2g˧9wޜYE(ě_t3̠~sv8cd>.q: gRR[`c+lN*wEZrĚPcp`aTJkAN +Ok2O»g"B.hM!]OFV#!?CtaN0 |M2FZTsr6`j% v3򒎍Ev-,'sumNo }ޚ|ip?t +$.klX.YjEGjtK?XE}aq$"22;&0;8~5ͩĨ$,uLPurWL2ez>nzsqMD՗4Kao;o^Nϥ'C>Px|c%fDN۽e4S槓Ikq[[ Z\glwNTtRfwmT.lj@L5Sodɗ 4ҍ~Xm(oy_DSN%>Z֑Tjh*zk6Pj>sKW ͣU =I]yw>jkl-HM̛pY)fwyfŧ%,SI6"8uuuos;YW +f6LXE.si>ʼ'/d;9d'J| ooL-8?mZΏY6ћc\{jfWӉB4ON/fKߏNaV)uK'р|=Rk.ҽTR.=|S%JcN'q/;}jݚ0: F9_r sx4Zbks-s}X>ayL26olpA%lGrz| b7? _FOQ@".ǂנZEW'{皽Fn=4=KqEPyn.hq/zҞZa {xKWx!*-ssti6ډgCR]=I- AѨJ7Vw^<<.Yv|vTWW~{'(?jcCrz_4/rKesoѭͩ(p|Q.{֏{_U_g7}Wr[M^ZnYG֣a$ӨŒϼ-WT(TY'nܒ ڰTdҍ gý~"`HJ~‘a] |˻`ݣH-R;Zl\{m?罏ykB%|Rѫ8+=\8:ϔgUC'wS=.gEhtw0Pxtg{q'i,6*kg9ɸ2s;nW`vXC%>5X+OϹY|ˈϒ"ies:N8>V7 1OCw}nPOWI=L~o&t_\]=Xvf{IeVos~rWf]3> htvf6ۑk{z on<g7oM{Lσg1Rx U|V*ܘʻQ1+y=r||讎j<6FV<LJvZwԠ\-y%OgVǒp_xn\D6M0wG9A;n~sJ>j.%𸁠eJ 4(ަYbC/[K%a5;_SD4MW)Sz._u, Uv 7'#ܬ>{>=Zv>F_rE@xX5n +x/1y^zy*n7lW5o}W~[OmLݚTѯM,i37^TtjCS$M#NxIaO-[; +C6`[;=BSs]?7*(ESKet_urkk-aK1Y%d4I _@#D]Rtb739z[{f1- ۣvNZkwywwCMQE-h/==>)U\V"6uFWlμӓ;ݴ;[Ͳl2YDv,畹EHG<{FI0q/a|<M9t61OU*~cSjLtI' +>v3NBTb 0:Jܮ%5%N9l|"C|,t&&e7"|%Wi:CX>)Gc^7]83NpVop\U s3^d?=wl8jv&/ajJ{my̆Λ埫Λ̯nE]et,{[j~!y~{y86v oYҐ0ipb tң:)caj]Z r^Y7M,rh3<_0Inńm R3+&~L L$FRwߙmyf"O csEԥ +(sGvYw ;a7H5 O؉L/,*}*ÜT߈QOda`f. 9jZmѥ3t=ʡvj|̓ݙ3 U-£)"p4?M[9DäDFkGCmGDNc5)`nƐ"4eڞ^eҽĈQliMki5hYbԓHL=I-#_ D<EõAPA{N|ea X' +/b! +x,ørl"FĨSᧃT12"Yh";qof@'hȫyb*bY\-Aobٗ3| ( 2` +B92оYbIN^EAV  t B7rIaܰ5H?2#[W,;Mvߞ3tT?j#!e}_Kxb:ژ/Sf< Μѕ ^R ~+W*Y{(ٚI]}"0#BlO"I&V OAD":NlO>mr<plRu#D9h#@:G)ΟR!jx#q8q:Ż`|RM)L~* Cl+&[HI,fQ=H5Ar@ z E7{hֈb1rislHإm>p?킑1Yx%/rU腅xVAb6R*H0 +v=i\'AFI6Mg҂H"m r:Ր4[WjXqJcbKoU$SB1ϖ5[8DN>Q|D.j˗<'Fn7Zh0: %ztDl;N/M\"?MSw~n.ƃVq:XDb:^)Mj aH RhK J7Pޕ2P"[({Kb y qO+.{kO->~({^-+Z5xq]h:*u|sțDq\,[PTGDA%r rIUygN}3.6/aY=5!DC5u|Tq1g3ΧioK}t !yȘp4qcVJߞK0k :dT7C +3y&ַ8df/|o XgGt pLn ֛r}K_v$&ku?)![X!1{8qܢ۷Δ޷q$p,&#}fnƱ@-lȱTvM"з9jw(ři6f1M7AD ɡj,< @pKY#um׃bBi?* m0a !ԉ9mW}vk]eT}X*" ^fR^W^zT֟TV.ӜEREs2I2Iw H +ngMER=Eӈk(xtLmpR/4"PR +읮=FةFOnHZBM\}"{ +Ձ.n9pH7WILbLܖ3(8bFiqn2I`HBflS `p9k)g0OE_}dU1omd8$UژVclŴFvYt_H"vVj.ʧnHQ7$LM #yφi+9lYC7.QVm) +@hfB9 u&u1[3/B)r# #KoZ֎C'}8ѯaI#׈dXW::#6Ǹwi}s3C.r{-rG` q/eכ8MAXb,=qg(s CYǝ~M>CΖpWvxnf'ΖvLl_lavovۗl=DB +[ɢDswG,w +l5,:MbqsQx 1ٕ6H;_F@t7{v45 +Nojr]{JbA­5Np +BU,i F=Jɓ"?^ mf̂ٹ4w%gvAG73L{s<"A1fƷ73)a{'ŭ7ޙ`)-9~`3wy#ߤmvf f6S&TDF10PBx '[IJhZv]5 i(hͷE?@Ry_2vϿ)dD?86Toe%ȈH#=*ɛ(@#S [FYPh(@WeV{!= A8G0ѐQ帋 ]x_>J7XgmطK4JJھyL![ҮaAR/ξs?آDUQBbi +z1C0IMZ<u,*HzZ˷.-O{ H^Anx\F&lk֝_[܎5]qkP0-YJ-ra"Ncle%? :1H3# RCnh]&+4Ԋ+MVECa8/  w}8HѺپ VKS(gj4k?wa*P/}0yA6(_hE  *A)LmkՖl_ Rk[QHvUENmٕЖh6%t%ƤS\zs?rv'z$!L˖5!CgKX I[7%OZgW>.Kuo6_s`6?l\Nmo jlo[|x@ ϸT~.z %0s+y咋EZUtqՙaۣ9kpTm[q`:Pv[,}J~F?yDJ^)ōN s(rKr>fi1K! H(dT4(\@=-b6mJqoc Ըr6@u6W|iآ@OvlK:daK0zlз):_% M\*$S=NMx`n\܂4fgw==fH.!ϲU-Q1IϤ"Tpg8>kQ Ae=P8G~ 쭡w + soSCaSƛ߅(IZ5i(XI“+2NQ }՜:Qy^;sh3퓷 +]٥*ddj"@l)q4BڊlQ@ło&%:YX}}0U=U(D-?S1Gb,nǁ^ TBQ/zC'y7C)3 2B\SUmu~OE_$>=Qc)sb[m[(ɉ$=ifo;LB9!8P2x͕5Z~o^Z5rLe|}hHb"}J׎ +r.Ƨ?9rM-af^I'Yui\1v`XɅ'ɫJ>ƀgNFYyihm-yp# +4vh'0o iW8iJбˡSR}'G#Nͫ8P//;+4| b*FyqWs{4O"[bOWpE1uRw1`حyXɬþݴoV)yDi߀\l<[FK:tE-ԜXM}&="*ȎY]8Oa+jq>Mzu,OIy)-ٰjiVܧ nFtk *fNQяKNh&ž˛Q8#fZpی# +M,&̞Y2}_X Cat1l"͝7,дxVvXm;n)] +w +M/yD6 !*)%0-} =3-(CJ-@.ۋ#m"ycgŃCL+&%0jM,RYX+1WPoj.;x#Nm-ø0z []`dQ :J +ߝ FJ?T;CÄDXW'я`CƳ,u0]צ%u&ƑAT 1pRB |2=eheSe 묌;AŽqp' ݵs h󀃽^Հc(n Ӱ9v,DM+,3Ρ{ɂ0 lqk<pSTiQ_)DUÉ t_׌$'Ka9g3ՌJ|N֮̂Rv0;W,-kkP]hC@t!9N0,atY~ `nI͈FBuE(b*˹n*D77qL50Cَ}GżJ=IZ擪kQ҄LyO\j*VvKgCFأ,F/|S֌DI4|g1Ca3l +l<̧2PT@BDiQA9WQ4%2[CvK,RKU`B ;X58M:P(4]ڢr1G>2>8ܷDEņ_1e#)Q! i׻ުB_V ]42ӄ\\PJbٽҜ ~- u4ZЇh(f1.O,97@a~e0kz; XbN# ԥ(L'G]*ݩu*ʧQSݩadɠ@J4L4TFbeF/%()9R{`X=t*~높'-UEj\mQK5`41c+2z~QZg$ޒI)zI +'MH *Er~KßxěYoO0%4Lr94#z. @4 P96eDz) /<_JS.rOƠd7̪^xsw fLB}.]}2ʈ5Q.w)JEF=N%J(|]/ȥ2>WլVu^5z|lE:/yܾ +靈̅]K(so;?gaBUmo_JxlǸl!> +HCNix}v"{K +ak}\Jlzͱ^a ,lGx]tbi{'FL-{ja$j-1 ? ~CӸcx=@Nܨ&Kjb=M\pJKjKPaAZKiV. g'' K_RM`WXA辊OY'. +endstream endobj 95 0 obj <>stream +JiN'{H8_y* z1!;IJܤR4^Lwn MLqETdϜ6jiPb4(^n. VlAu3F^)GLX6O{0X\i`GRV{0yz~ac(#;#f b*皫"01 d̓7Y]m剔 Q'1 d_$i@S|xZִ`1Yha_ +ǰwoԧ~<{ߺM}xhm]TYP[6nX)1] ' emnX2%fQWh:1KMfmI>E̗utXc#; 4|9hVTD~GhVt + isp%,]?o^g;ǝqMBW+/?yb9_Q9΅#CcD)¶hؖXdKѝbI.s ^-biw}w<'W2i LPc-8<|TGAdK&6Mٔ6O^f@8 )j_-c2߻xu%wܹ<&>xH^k d?+~&ZtwT DփFtaۇc U.it.W#6߽ybTqk t KoajȺdN%P&hA(ڠ7vjR3́ iF00 y ,U.xM4vA *$5UZMZqMsԗ7z_r154;$󳲄)vApME0 B!k`l>(k֚ɠ4"V#u`I"-Eu:CSi|=!}CTjG\(%qrAaۧp6qiF(! X;|N_O$S3 jXsǪe4-d*85ԁœkd!e{"( +[Pf4jBa+ RaP|ia]u)n7dhMHͤ\n(-ÕZRr;+c`K(F>z_իɓں{f7s{puU9YVq)NKHšwD!0)RZxzȥks8VƠ3;U3Gx{N~Phfs>c_Lǘ- &b՟)ϴ8@qL)X[=Y#Fa%:8q-NZ<bv?%4yE i^1Rc?!BZ&/*5A`+dE3/: N "/s#H؛@T_a@o/Uh”)}gV]@!gg8̐ r#A/#no'^[tn[͒tpu/&[iyr]R꒺<9y#6 AN7@בj\ ]!scJIµp_zR#ٰxˇ-O־IuXWKzL ܲå6݊_OYZ2-39ȝ{g)PLbŃѣgޢyz?4 "Z75J\b$D\Uȋ){\OfPb:{)kW^1Sei`&[y6󪇎(-y^| T ҋ/(#/yb6nU$sVn]lܻC]7{Ь[n`|q䍠^;f+pD0un;08S UZĉ`~ƙ J杻eL$p>jL`2ꦀ[}V9̒hrPuvۤ4؋Mn)~b +/N"!ėkvD;ToF;mvYvxWGצwXb9lYu, ,>̌%e5nPNOԞ5fZ{w @j[2=HrT\,#)NZJ@Ax\B{s ;?i;t&a;aliهz@d!Qm"Ea ~W+!}Tu2*:gaρ9,(bmߡo/D4>;y|oW0McAP4?>-tXQ X*kpiVW g4N_fd{'scyP))Dqu?țIӡYݛ8xR:Ζ7_f<0g?>vHIvZwK0bRT衳:[-Ŷ8Wqv7jf[Q;6V9^ +T M48&LJaw,)넸7]e܍PQ=)F:JOC碫+;.,{ȵ+; b_:٫6Z΂.hvHFDo*拠2hvĨmxf"F|4F7U)b$C"V$,ξH6yMlYh˼LOr,b/#d'?Ay1B8uQb֜A>iƁbϼDpȹ$NDoP&m} +2m. M. ȳ1GbrrF\.ge?JxaKjt^t4=wr͂N3h'( VrzY[wYJE~:  +22,y}Aj.$"M_ap-*U{\c9q[oa 5N"G Xc Ao+)C _)6i\9%$N"Q"P.Pv'V@^?c RId>f_tysHR0z}LuZ׹TVrDη +9mCQjPX,hb3KSC{ \-vrP <4(5bŦ,+uL8hd)Lpj" Z(BY<1A噠 ۗ]c+=vbyTm͉ 5W\8`vCk}':.FfxgHq<(%Sgg>qM Y@{Ym :IXaiɹҒrRZq46~W=R t>G/ia0:FW+~iH%263lfRy4bk&_ȹ3?% , TG[sf'$3n1@y,&zcIpC|X X'oPRjT[V=Ǻ&F5<$b\FtrJC0,H:kK3^{5B.Շ{OyI(V/22~G7qpOlCs-6Cr~ZV77Y>yY ?,,ɣ|ST x$jXS7uG%9A7_#pyO?=iyO[Nq +5TR-Bs,"/WmI~!Òlƒo{jpm_mJ2ƶ}Fź9HIhJ&!}A5נ)⨪M5;'nA %HfO@AuT~ƔRkKe6ݔxG_{I3AIF|Q!z:uxZ7bd[E̋wԐ\OJ4:23aЉbth|,/3(\VFI ل=7 ;t9PZ(΄rukA<lU|iȓnyY1ͽ+ϖ0י.W^fY#EF>c%̘3PF-&?kQn˖Ѭj(jVDחĈ ?kh?}Cm#zs5~ dd(=MápҐ-ᙦUx+>\_!]`FH,K;v]D"tykB*_*8 ,fb0,Sn}B:e(~,L3GxC@eҖf3G,z4e"i2ͳZreأzAZ$ ] ?1ẘZQhTtiR@}i,TQMe<ڒ'LA%Huj}[]Ɖ5lZRmgJbweuvYz"LK +MCaTkC{jg)[؁,;Iϝ+N\+8TDRew +}E1FLKؤ/<Ӽ:E$\{e0 +X;X2%c-YS?+bA80Yz6y&x~m˂4/FJ gxa̾â_"kݗ2m"VScT6,ż 9?E~Hjvp%ɓS}Ȯ cH$P+#BSQ1UV+P!zDᵂۋ ++P[U8uv +n7@媜[烫t9j4Fs͕pg966FXD7 {.쌮ϱ8Bhϱ8isl.>ǯ0fuٯ9s>Ǻj>Ǧ9+v7B!-kRs^ߐ%,jjGt '@ȐjD}ƞ4y-.QfB#"[Dh&OKC,U"ב܁:-5s'Oas8VXWLHA*GUogT'I>M50זjhT3ߨP>#wKȅ"ß]Ec^ye8nЀN^HC\D*yBcw{ExD%ˤGOU^cPX,4mM#lxU1rv֋ ` cő.o>{ K} (QP[cR3e-מL"H +MZ|$U "rOڴ^P'ToK!_z!Nh_?&|$WMGu$UI#2I31vv8)]߾teq_h3LEc0K#g[ur4+4Y.{rqI.,x]H<U0DQ|:j`J^E20&?,V7*sDW#E-5*Z*dR + Wh9pu~@iu:Dz &#2 !nyC߬;5b[ lU1-NM90P1)pQ[z@AP"F@QBPWBE.J!EJco$`KSɀ;<k7V 0.⟑T >TOG69Owt< +7=B 4,u?龛zTϚkOyzωU +@T1Mvy$' {@0K}0>5E˹dteҒmҰ=,:u wSBH.߲-a2}/F/J4hÏfkb1?S[څl'8߳5[ apJ nԏAJl~`?־ Ah!gy5NA<"b!v:< o AP~pi a#QC,AM2īÏ֊Tw2=h %;*D6+L!ѓLT8qS©|Ei^k,O;MGepZ) An-so&0B͵VZu"|/>yjnkjArVkAj`JrP]U2@?벪{k@P~kAa?l\ag̡Md+/NNlWΊ5t6X)kΉ[ysR}Y馊\Mg +U䢒 xRgiyt[ɨ?7Җ(MRos</}+pV;]gq|Oxo.G䲿IގIݘ+LNs[߫Uœt)l%OUY=>m=gc\{,K mʳk^w5^4|^O .gBȑ)jhN雟zg>$M?uhSà׼/O}ȿ&gO_;k|Ԇ*ۯ{KKSO`Cs寔+^ bQS:͗2Xģ&p68)ZV!pPb= (R .m*KKG?iRXh)bq#{x#H@+:r;\u'rV}oS n73Hcw;1|ܐA-&V{=Y5[YVU r3(kE_pۭr;&kkŚv5W\=67/;jsv5(8]lɛM>&uD@  KKDl_a5![i<;ts0W%i%1 پ.0~wפhE܌3S}N{ӎ8f@Rܥ}xLYkl4ƪE1b`-R)04ˋA +܊FFW}%:`x;W?xX2%oCRt7:S}jNĶ/%PKp=8QUBS7S8۔HEdiz-03CPNg qhJ&$4U؅=qȢv 3ZQ"SEiV Z %bQG Nd\w6CV>ьF?e aG"GHrG7%2c+)sMzf6汀CizuG]v6O؍L~=3a" gDu(G,vz@c^$Otiv'GL R Sxöw}U#v;,9䯃A'RQ,$o<ңȏ2{=AB:1mW\򥨯8:~^t۴Z\m=z {R]G|!/(j <4[? +-7*Bem.W+nǺ w݊[s{S͊;~تrSMV܃ T,1Ij? :ᛴ 0A:¸ͺu{7X5⬂*TwR& aqҚ hf\O5hCjiA ,Ӄ%mmq- + +z*;)օmB؋2IHQۤQw'fBDin+"c]3'Lgꨫ&s-3ښ_QE}?R#J]oW0D07cu`ݣgگGzwϹavE^'kWB%j7!F沯X_%HJuCHyYE<."A̎䋐d,Tho*dޖ<˯^Iȩ+w)3Lc5ݑmAg5K^YX "o5ގy#x^dOʫ ψ v*;g}}pAAazg@{! sNPHH% HCr6̂ťi20e[<"[ѪiݪZ&q+3NBi'}hGi=nĄXj!#PHt+EQj;t{r_| (i9u ^DDh3id%z'>[ys!760zw^b #z7CF_N+Tߒ(11i[AX ˦P-%lf-]s5tQp0qs~UЈ7A/srs/5z˔W 䩽)kmZ4!`/& fm7 U%VmoGZ̤n&Tka^)y(&<$jGS$<((E0KݵҜ_,䳳SГ vkqii7AN,I% N:<'ݾvxvpoR3HE +t"[ =Dߪn,x`JR"c̕.MEE= +C+NX}$y3pL_+dU;;N.uцc)Ϻ>ilg床X ٯ6q0#=E(׫UI&8ƎD[ՏMV3|2X=*y_db]iF2kAPGq7p qf sdOV'`nb?,cבӃ.Xp@1hkX h!!lx4_}:Ff7 )Y"dMm~_h5KnTUf) {|aXiN- |xĺ(: E\ytmaڝuKxߟAZOãL0{J߶*;eZ*|y$âx DhH7 eq2@ ĮսzYht/CҸӯ`%!BDnx#aGS(򣕗?γt9 Gܩ3'tf ?*L}v֩&O05*hl(n^ n5fl ޽.h$ n:xlߍ$IHG>*ݜLɓ?^Hw YnO_:sӏmbBVd"EA  P%}B }eҙyצ鞢|MDs=wG%0"W!PL{pY +4AGX +XX\K.DPe)"B^'ej!X\;uYkn?cgeA/߼$ {jiZ3b:{" +LaN6K o' XlY^EfϪ=T擏[iGqm=-%}|0YfQRuU|Iyxy5w얟M\Z+wib&?6 *q=45$4s#ϧ#r:'#<p9bS{~T$Q)<u_[vqO]lVFd*\n{8?$S^\~FDa^nڮ밸_xNc9Ng>d~kرA-mv>a؈ܿ!-Bү_qHr^/U:se^P8un wۃ#r=3 +q9S7ܹ!_m>x23I&Ou+BL6ShJ>O (;n4Gt#U2_8~"8N>g6R&;A#Kb d7gvTC^,y:"!JK muc1I-&c\2%SCR7uӉ\GרYujCF-2u?^R]J,BK5.Kq l6zP@*ZբA} D%I"IJ!i}U\0":ǩ$Q]]TxӔ?>~%z4;kY]d=LR-uDKx[1‰]y"^P."gNb}%p]('<r=J`b yR楨B0=dG!G.ZVF:_;~C#w1 'P+N<xz~ӝ3qAZ^)l + Uv-ۚVOTձ_h2TUQ=m.*$DYE%/Oifa@cYE=/mj~_diYܺu”ϧ6 ӌ6jլFm0h}ɹ?tc~V# '4Vr-I(* M#XfBY W6tXQA3#`?@M+k6lBs/waaنv,.nffdTwn3%mhŒDG]H|NGfrLe:=?n + a ^8 ypYE<5T]㗘=}I#0^O`iYWq$9<f].L88XKyYzcRk&_ƹЗQ˄ nYGVʒZR32SEw= +n.*?d.c;-6d`҂%:o1YT {R.xjGګ{ͪt"#qME}aGF[z9n7=tҽ&òVosCUbi6qXx6vW8q,h*#i0Ub`Qz1֜`Dq0u<0Z(uf=P&!лD& L^6T4́x>ݼ 1c]*h՘v5vd1YLɠ yP5Qg^7&N^ vyC⇊^^ M3#umy o%y<C&=%f!JZ 3 $Ɇtb/,eE70T1G[֍Na~b E{l/\uj̓qA^+l^YO|x8P[G,`Nb|[Ԟw& Q-8Y|b7N%*@5"NLq$ڢ87J``H1?XyV:QvnR4"<0IfUUٙԎ.D8iVcGPLOX%{Vu'-z+^%fSr"dS|\)3D4+fI +5MlR̅CsR*C(|vǼ[LC Np]A cœc*/]}:ɖa(Jbc1J-G@BytfՖoBYmhX,%v(=-yqsxTf'%1lP6ɠM c:base*[ag}^ݵD~r76îEE/5>IVWbFVP`0==`$qfABԍ.cumb怛EP +rQyy,T}[CV3hu8?t&o':̇9٬Z6G0E`]ѱR7b.# LZMiKqB\6o\mZkNx`]J(~T7 +g茤Z`@ s~"q#qP J}G՜s0MKPIkeC.uǧ;*sY%ϡ#϶Nݩ,`$ JbGqNLpj sP_<㘾 E"*DdW C%O!UX8qgJusJ47ݘ?wx* _8' s>:Zza=m; v\=>LZ-pPN]>>i}.pNS>_DSEINFW3e^{_w͓Uq@OzNw.T]Ꞽ4tb4C~!JɄrW\?o.=Ru.q NXg,8C۟U{?W J9gO}r=?=I9X2ˣTj\#5{TҸ=(1pn~x:q_qׇ=*!_k\MNcs$(U){5:HF5!W+tq>ߒРUzµT%([{./ R`]=ZKw,xenQ n)هGjd2u^8~O۷Tqܾ B_I83WGUPq'tXI8*W\sN2z.`D]q8ç⟾qh n֞w0[φOjxKRבz-|t?'$݂IW Oz)$=%Xtx]ܯ#1n9]И&t>L?1bLi:e砐lTY4;^r@9fa }3 ߻7qnԩٻ^8m{za-^$FgZ~tLqq%5$yJ +v/_oQn!tڦߵ1M3-#/Uc>8GBdx*\B8 9ydž%ӯu~?q@oN4 +r\h;qܟko9 {QTJU}\q=Fy^KIWh3VZLY>H +[)"Tk݄oG#٪OXמS4+Fdz!t.6|`4כDZ٤ߺ䍥2v7Bo߿s[aiӋQiKSe#dS}wc3Au-,zP9Z +l[uuls(^vBdnSfY)8p\ZYvo,6Oi":Ň\#-K{ɷQA9TAK};}_,w>ͳf`v"'z4bڍ. *X.[9/tO¼|+K,0\bkDרDג[>=^`5(6]u/b<9oa1\7K>šDS-f ^Y`Fgr̐`c ^Y^MDP}Lc;F3PUb1 +0Yz@$p>4% H+A;9F`JW4Щ5,*y {Ut`Mb rɌJmi]QD֏Y<.nޛ-sR6ͦ]L,H9f$bTë@ c: +TZe@A]LlG8mڌIuJ&jXubxW{C[LA1n$ì dE͌|t46 rmcqS@10^-}%<;omb~J|~ƄՎ Den`02^YZyo^Xj8֯bnnⴰgp*٢THc7~9ɠ`e6fur#c)ag@fVPr4%xnP|20lIƘ}\Q*00r9q,RM`%˩=23/v,HTf짅uןjvאAQv|ę  R`{r>*Vf+-U3DBKTNܽ8# &qڌWbq*"B2oxC7~_[O~*y8ZWUW9n۩+MDq +]c@8-ELBtTi +I faZN@ ް` y\aXC XߗY+&a"|*:!oW^>.ɻed"I`D"Koue{I0BSkm+ߛҤBo +^dl?~ 79zȝF!R~2Htbf G1s&u[\zȮnLg M[`# ޟ]_: iL=.DPOr6ETOsPA/ʏW zݱEyзThJȽwѵE}[w:ЄC9eэp5IQ;4q(,=F1lto$-'2f`))@E6G]sf|k[рCi .jLQӭɴW(0Ix!ҷtcম*V. +{ZAmH%}2(``Tb&s!9jFpFX2%\uu9hnmE$nRf +wךIźYs~B[ KkA]MI<#Pq 0cqb#XKԀR{}f($98#B=2,JtUC&*%aT,3M=ON! -f:ۈAĕaBҼB(\_@)\?:Z`Tv&v{% +]r yt@"f DOgzAI=0Lk|5Ɗs_0gטUL H{7 +svzU +s̝U*}.Q&? $!,NGz<3 RR31i@5AIw*6t%&HB=q +$ˍ< +Z]rm?8$ +2̠#7< + H^~kro _G +3FiR+D^d?uhs8OJqݔYtֲe6Ѣ-ˮ q趬GA2kWn^B$fj1cCP,,n4f@Qh ɚ?b[*,ACE%gxY6ңJhU$`'IV/|eIVx)qC`75 K߀W Qu /,tcly]`6l^+LiLҸ7beY f#䅥/UM=obHKb#$,,oYz`K:lͬzZ"CD[Rd"h/M~c*֡7f4kzqp_7E[RSZ[k)2[EPY`_p^UB^6e +rdh4^}ckoP(JUr5l "_nŲ5l^7FeG4~d:jH5{D3T+4UeZ?N_k<7:qxC?oDW? #0^8赼2"9XsVf3>,=*q!J|XT4ݥJuQAH,z$#4;‹voyxC^hLۄMYa,If7!牱5!Ʋ,*{"(DU k +p_qVP*k LIgo6|bVki +)cyUF_M^cWy`(S0*مJx1'SÑ<_~Wgee][12tN{]{|x,NQŽ7"QAl>m jfzxWv^I @>"t4o8YV+ w 67ݚ-/ID'JYTqyZBb̓*,#tRc4Y<=`q@etjW +>P v¨ǟC{|] E+=Cz3c]+ҸQK*_RTOBF%]Kr6zGȍ?7Ks<eUg! tv6oμs+ȗZ +a'vu\ +5IqX$3˿)tesIޥ,Ki]3S/p;ei43 :1f :ptSs&{1,(Jnb "K74@@2?*1~yd$~ĨXCPsD ٲEc:R}MT!(ќ/:raUKE.2c:,Wn7p p-nE-1yMK]`);iC'ZXVP-,+vt6oG7&#)+I_aY}Z3x]o4R + y|Nrv`l*4-ͼTYqJ:9_`w/,Ev|,ӑWCT,APSe4iA*Nu@9#! +Hw(` +E^cΫ6TeĚ4͖`AZ s16 +I5ʰvrxHۥh|m<l]|P}2)6b.I_kK1{L/\:ԗ4mt&1y)<{ă?(>^Do=O)7'b"1<|ɞHџ7LE4I˟g2Ϟ=Ξ ;{:mygbۙ2ԡ{~=NOWG'vy׭+\q|Js^{|yYP"?`gm[Ysӽl;y`6q,r*tWT1 =z(_]wO_'N.{UEQ5w%zOtq7x?Sу^6sj\&QwiOp/_' e^ʿmT/U%Cz*tfZNB fzX46(-ܳ`G +,7Cܭېڐaٲx_Z[F9 B"'ߧkSnǰɋ)$ȰfkX ]!*(p8F'Bs&oM|ףj VcU*X%/;hc4XB[ÎVQ7(^m䮌X\JPgv%+Bd/Kdo^mx 6p|{XNJ}doslPR.? u:`^YA2A#vURf ':;hG-unͦ@4@ 1@1(YBh=7l@?٬?7ӱY}w)B +Jh|VxT \'[پ;\{l1aPyp˔}tS1A@Yn<5e<|cQ`2ƮhPr|1Iu7{]Y[cP@xi(|݂sQ]A s "'[*\a%")?Z`q\RY##!p52[J0+t8yeWT]; 5hv@Osu>;xh$^qeCfE?/=\zmtmOi1Yt{f(m'ioR:9: sJJbXh!Ry3U}\@ C|< Sڼ(qzz,!N&,9b^4}8&VK?j#PvO(TtC̸Ca6ALq, Yﶜ)A{1g[50=y'X4g-!&gA)s]qH݈|b g/} Gb(ʥS1:3k q$O@˸궆0ɽMva֚t-1˽ۆ96*I +t!D]_4PH/RShXpALj;Hfn܋E5Y(c!ibV"Wej#TΩS7VdA~a1+~\c>M歝`i`juwZ=l_{Ff{Z.>7L M=a D⡸'g~agkDJY)TiH9XbwW6,9AA (Ѧ|GY2_8liYw,']kvP3Ȗ!uLkC1˭ +K<{'yR.Gc;h)|"J9rȯ6h, +6HqHq8C] cY,f z|D@6k mRn' l<-}&Rm|RE +[~+ɡW7P尗 %r0+}Z cR6պ,b& oxk Bi܅b],vq5O.aQc 8Q+ jH I1|lq{G(s{(9Ԗ1;eue@axXńhKl \ d\KqD}6 fufae{E[88OÁwNRFޟ&߽B:ɜePG9h *{&.qpkv ,ƙclHPy+F#lD!uKr f 3Gy_g2@&>/Ӄ?JΧJ,}9:?.iq*=Iǒ + 7}H +,^08 +fUDF-8ń kVw!fiCaA:~>G vkyTD?׊e줒a.ī(KF31"Ea\i)c&i\y.+n~H+d +2ck?ZK9VtYⳛY'`zX} Wh5ȡ| ?vLR|j*+5!)qj;x]SRHttNO}蠱Phkc[Z?[#쓼wMݰF4䦙pF)( 1pLe4{K'3d 4$0a(4"ɌAjx2 QI>`r[}B&̂mڰ\wFm +C(cɬL"-,į(_^7z֯6Mk[8Yݚvp_ \YsJl½[ 3e)-)bM\ޟΫRMarƱl[JhpM +Vw}2hXU%lJ_d[/|ioQ J:ORm̉Jw5a!#~y!q#hFGhs={UQBj-U,|1iLT?K<%kW@Zh +Is8 9iztŬ5l[nJHbBc*iIߧ4[eU +u=wuu[TK+4n4Sjӽ9XEY +f9"p{y*T0b}l1shO k9T3do:zo~X=VWa3h0L5'cÙt^֜3H_<ƺLfX9IIFxk!>ڂ3V‚!%fvH? 8Ï\{<vAmŊ_ <zIH7]IiNez?l[*p'ٗgE NFܮ4%0Wklp?zWȣ_XM0Sh-MG'OQS!PwrF~P硵yugI?پ:RCtȥ*$;롁\ +5gO+D҂*t0**q"H4"?jܡwͧGauXD+֨oGJ~Iwtw_$w2_ZygNOp~__Ookϗaϕ@ތ8f yDTx݉( m6R]A ۾ ^e +W3:}i 'gqY1:i^I^*Gv~)=sՋTbx4&>T~Ry7;cӆ>b* vJicߞ +D4#zQRl.ϬUcSl?>[ +>VH ϓ|SЮ;zsL 'dMrTVrT: "-N +$)&vi)յsTZ7_bɔhsGT )^DcNtt(SOtzTvY fIw?QضAIXm_jܦCf+<)S蒯ƽ7U#_+Gދ+%1!wO?ljZN9IH8"x +Y˔2̙w׺.L-0zBD㳌ruZ+f:oXZJomIb]_Z./TVrN[~Qlu~\13b4ˋX$`H +aE 9,̕` + +\E,~NOUf;a!q)Tb'^s%#>lRT4ë|qij,w/ZiNul۾n*١` w9}m*Yy(ϕ"lIɫ)hmOl'4|%߳H0fXݮ6.mƥϺ;Ua +͗e05ojcҚIq5U[hs=[ ZN~` +hA`\6ʥC>hB?-êMOeF>[ ++4A_\|gփIAbK>gCYl-?d2T꽵_U[ 6 @WB{: IXj "LfԀI  4OғJS@v6c&6 +$ 4N٨"yTsXJd $[QXϹxi$m-«jD?pFx1[n!gG`qUYRX +o~(Uru^ȮГIJ&%\|dQ\IL9.{e}ayb}Ѕ牿3|cJ=vŅ̃W^q'xqh7 9פlx&VW.Rin+4% {t3UD$}RO\ڬv5bq#jں}ț +FY6y-L +3#{Eb \.(I/k3&哲BUI7VH"iR%JvHMJBx[,cY$q"( 13#{Ո4R4Noh$s# +LT)Ӏ}NaIoIdVj&{% \[Esop[);f䑸7zVLU"eHCǚ-o7GMH;+ȔiIjeR~S+^wa ʧ$`^LzѺ>W2W5_,$L@A뻁Ѵ4;l+!ID&M4M$Op[>,aX%(;gЖ@ uf`=Dt>W:uw@\m}z[ C ʹu#*Kwvڝ~8}3_]P  +ygцp6ν3r٬CyR鶮_ZrnRν'tvsdg[Oszb/k78=/M!#νjk+rǙ-I[K./5O!ͪ },}H6~dCu햿5o]]Zfv߀C6HյD=Q;V:LM;"ŶSVr萷B^ ,I*g8 ߷)>a_0vZLzu@Aq~R0]:}0jx+$;'yAT(CNT/`u]܉qӗ:gy>ts 9_?J?^?T:Og<53yʡ|3su4<: 6s +fWoh% P \,_~rL>mx\*C|e xv1 hZ`y 418ԙi_Co ,f$;Vr%p\d1;ί<,ꉾsRB[#R4ȴ.KP !H|G"CVk&a.M2l2 X$> tP=QQ5>l 2=$E>_ԯ})3ҽ`}"l@w>b +tDsE5 0MP_H[ZmS[wΗ<3;HlI؁s^i癯b#vb_\oXze?;+y^ۺf}zTٽ<.`~X:Nӫބ tV5Ԣg˸|R`ؿ8~sgL7݃RZwo{*eaKC.zF/r%clFY?| <y^Ϳщs,;ɓ> zpӵ}ͬ g|uO h~uw'ez*8G >G:G.˧C\=꟝;ug_bq,a D>\gO/} {})rgaJE%T괸+JP ADa+~.s{ԏ=Tr.^~}8$sܘ?Fmw>|ƹzTwJi" *:7c2-#?c%'W +!Ū;nG=r9W]L_^.:U8b~пM3b1 ;=ܦd+/dի*e?RuadwvHBWXd>pP=WvU2[rr̽w?J{ݮ|/6s9ϾTAuX]Nҥz +Jn7گ_ +/Mb:,uq[v= +']d:{ShNi|p\*6p}[mKNjɝ? 7:}۸pz˹v__=-> MqRjI;}r$CٷJswfzk !>0%Ǟ{v ן#>*^ؕK{Wvޚ27>_rr&t>''/ّ({qIf(3v:t9m\xK{OO?pF_[]Fm<̏_ + A+syWV4ľel]SԵ >ri R<Ъ?<\AE=&4{xx>ag׏IA>`=mlћݫܴa**=,#؟u{`#95Y3#XZZZQX,./0k䧹v2C# hյ9EcΗt''vIu-u1:<׳e-]gCvlNX J(&`] /g7X .ч -+ ϳ O礱3/}a# VjG~a{䫴bXV?Z >mA$b(`{b=};S/l\&R.e%/b7coidi9~!&/nϵò[~ {c0*;P([͓N^q t3g[xE6sl-)~[Z^"){0_Q'cl3c#]q5`9Zo X>??W>&m-wWc,Uwt@aWtNISls.iه {>S4r 5h7-h&D„&Of G5 +}J:) rR'p51QZlăa \q}瓼uY[;##x4q4kA&;ҿ IcDJ1͗nFNA 8k0dRf-h*Z}5$5Q`Y()<7fPB er}@9/i#}*ź םqwI>/S8C-g6BPjX.fv-P[P +ʭU#5*?%DmSQe>݋ +wBefDMJCI3*pjW]"C?E'`iy }RDoHW{.IqÛi-.!v? +aM(.ās/f2QH'41'|.zqb-V9Ȣ:IrX6e<' ؗ!S_؅"%%4 0>4!ʲ3/}]vGy*N9+c ~ƾdDӓF~})%&cg +Wce7V{U HUb~ma:!Xi $PkU )>&p^Z؆ )oҫO η:[p@b"Ѓ/I[5mLtK-]Cy;lrzn^tRsz|jgaç;[Z>ILU Q04^RBe$܉4R:RO>Y Gjc#ePj.٫6rA`K嬒WqpVgUe/Y֍V%Pb4!3YwPB)|Rnh]72 C?7DΆ91 +4hgPd07ϩ1WuNaMYЎ{%-&tf'a8XmgKw3g߱rp%\&Y5^u}# |`||o3pY;DE4IyU=XĆ */\ӋB4>2'q۱HS$ip&B8Z4=JQxСgbTӣ$+ 8uƔφ?l' ȝ";B0+R)%)?i̝LMX@g)c,㔭irHKp;˓CDd[bom=׷YԱҺʫMQqsQ,o +%1)m'eSf  sCjf?ʣ3(.Q\o,QN-U2YU Y՘q7d֑}x(N4,o~kEnj %3TvXLɧL&jM_c*M_g6[~^U=46<-*( ~fR([Ķ> 78 Yb2|r l0}?у'wcINWaa6/ 5LT4(tJfLȥ"9M* +>>ݘOSVM6"Uf9ߐap׏鍒C'3ٰhlcKCai۱fa>N/Xز\}Bⶌ"6,SbUOTf.2'*u|Ṳ`dT~8ُ#ei\$Q=N3[NO)nYQM\!f%?wK:'}{ As;*` %A0B, ͔4^}tH޽ 0 |,% wq/-.-; ߗe,vL^$jHhaYe-ZG<]?eOkl^ wh K).RɥxK~MX iט +SiYJ-k^YjӀ,'DJqQXR-?y.M^ ߩ-z>m-:eJ٭а +1 CZmΜn?g%gO{1 |-dd~>C6E叚 +AS3MkAj1,t.ꍣ_iI׈*syM]#ߡC +:`#;¡ op+2S5/` + XcNj%2h $l;!?f᪭>4b]8GՅT@@M4Sy &-# s(t(,#J y,R&-JK # *<@jzeMkwӨEёg3(j.yQ Ł(=7u'Jy)g{t3sK X|8@0#^8c2FKf (lF7Fc׳$U5M,!SQ3`-B*.IcYRkg]kL5F#6(C]BMA^S}4,.M|ycn͛PL*{ 櫓HvFEvFLiUV&LzKZЫur}zfH]娗kEau$P(jCgwQc]R-lu Xղd(M1gYOh ?vX|p|怙4ԝ'COtKqtb#87Kh{n["! n%T1D%? IP@R>daZ_PS9޼vLŖ)k5T~Ojgol)a +. 1*wk$ ږ$olA)^Ö۽"`Lm`9fH;#n(5.w:I͚s_(@xTtS"]ߦv͌rܽ`Uf\TTz[33Nj}+2mw͟SP)&-%=50nE2!!ӆDbѰz+ᄂw4@ɞZCųrH&Þ!񸿑71zYRO p~-7rLYwDw1UB&7-RFMopLR K$a =ؒkJf# +F$q/)2K#*09=2Ό(X +M9=Y{A׊G5Aihc,v-]5VS^@ gau(\j߀gn D`VPa5OޞqPV).c譁?r:7 (XC +cHedJCisOGY4sif Nd~_`칹+go$7wjO{ +N^n^~ק)ROyq881eR7 y+nx@TV0[$*O\?*{WkpfE=LF"_)]i + t$.` uEtbA+BUq֛)b^P0e!3= ֙ˌQ 誏 +ĽYL:M# نMҼ?(|Ti wCg~xk1ubr)]8ů&qqځ5 =Cx{'jô(n $:oG5s&i<ΘX**UOH^F˫A,i^our|S{ c\z}ʳ\39Gq> 6_(tga`"+*-n\`-gc 9A#>婭~kc9.so]]eFϨAHE6ܱ,T教x,Q֝ҖH[ +\mʿY,U6!ApX9z5$CnDuc"ʳ-,RTDʧD5䐼ZWPŜl}TqY;7".k,QJV+Y⃂Snf[9EnfҒƨ*r/mBϓROKr(Fj fSDWB{N%!A m=B}ƨƆ!A\JGާ +4catV7N?ݴ=2YfPpl,}۝ 'b3%$>UJΊ(¤a'5o U;A77N,EݧM:]ċ>RǑ{.]HPi*ԙE+j9=fw3Jd x*& +^}5Uau۱(F4vEq<a?(٢P/ADU8ã^!Ó y ai,kiDh+^}'Qk,)lZ.Wy.x)| 1vm@{:ЈjPK/2r.g8 + zf0Kqqͳo2TJ:`}]gxCP`a|:I8ݴ{">eWYIr2# |J] h˂ +yG.5$ kyY1( K')L rP!Yҟʣ)|j]:qY}ҢqqSZKnJ9] j96S֝WA Bd (;ËJͤ21e>c/-j3ݨOZ'.6|~i:sWR3S+!<9ƌ!bqDˤcmd)|mhmROS!њS3@q&ؕūƔ<烳l\1OjkBb 悏ƻ|de@vk^LQ 2ep] TjjT™p) 2oy*ErwdY}#4+h8 ѯZK`@KPe|5NHM<֋آ1#~F }ك<sxS9яHiѽfcΊ" +;s$rO+9"G?$d0?CVXU5X X!Z,l{%o+O&b<#@Yn*yB:#36}JYey٢]!Ћ6⬬hҀ|hNÝXYwl*6.fS]5DSN0s\ +í`'ϠBT%v\Cm=yw7T`i,DQ; |B9:o'jWխu|n>GL`<g6(4;`ֻnP~;fc@9S z˷WI(g@U +%aLMEz:E|i㓰wt@tIhHI7` ˗ZUxL[U@8ߔ B.N.BGegkxo= |hW՘&1|\zfrhL}lyz*Ě#v +X>>0># +eBU B ;#(k@fuB;FğڢɤZN4UUBΦT)83` +<` П )$ø801$q;Ou*<ŜPƜC]zOAp'V[Ui6m\6k.7.GN=,H8>) #~H-և9#Ujaڹh]^fGsufV jQ{3k:4 z +xw mA +~Tՙ.IM4 T/+nPODu|VbYM@ǝ}WG6*;Q« w[>SWݿ)M&| {t?ҭxE>DLO<\WqYש +SRLu|p@$jN6,!v]r:|@7whҎr,BYdUGgܩt)W=N+Q$Cʿ׳,\4L}[ +PEVYS f Ϊh~|~7Kr)̃dP$U t$;- +[hkxTP%t4dF6 ,u8XhH2nj8v5@ s1,ڰ2vMSs/b+aד`Eα2E0Ϟ jRE|4L4vgû̘ Sr۪]( G(#xȆ<ϪGZ+|U 2䊙K +}̵Of}Q%&N'w;O𖇙yi:H!TbN9-H3#BhQ3i2;9 +t _轸 P _=io\?۬Uu)p(u斪H 6dn꺌 +ɯQշZ?%4OsfPgc-B(GgĞBI$P5T@?bdL nv>1%f3!!pA.)A"8hG"19*G߳ gAݸà`Y,M9@\J;9cCT3 䝵;5#u#sx7B-+aȹ's={wom+]2J yK?V@7mFne[ٽ;@ٮ̷k[9#N`5c.Pstsr^]fÍ +Ipq&zWpt(ɓjV{zڻȅs893 GKWv\l9*3 &r[əs}gWPg-~DzCo4 v?{&so:G!;ɞ=}+׃la4U۽<^= Y tdAokO Uow?@L~Zrh,9K`?* +HL Myx:By+v#㷛ޙӇ{`Z8!` WOlՈ_[X٪0Iڪ2nm?5iśF.0sAjd%ݧFSUvkǛPPҎ nnGKԦ[{wSkwP3&4RPȁ@dRٚ'!ta\^ X<#&<-9(/ꝒOdGyT:]Qb: +L+n=6-yZ };ă@$/!mU^0}j%DqeA ]iYO^kpٍu<1rCH5ୈ\Ar)dzoLxxAZ;q=ty`p E.OT}{& nȓS [i~\SY5 J (2ٺR%1FdEafYWiȃ1Wa47ˁbJB& -8;,MnCfLV0j 1e%p„`xwŷt$z e q/$v !H@ǮyiU:̯ѴZi!!32R]?Uߎb_=yLEpBQha0Ĩ`'/`w񬵜 RQ(}fQj`X^D58vzj)ƹkDRf T +rYU~qt}ݞ_wNqDdiwf\+ťEa\ic\3aف_2D=(AmHKV(s.i\LF*G/k}L`t[L\_LbR+sK*°{T&YAe^SL7I[F8E00sE|7UɞN3wybJk\NX],/y"mxsGn3\&l̓L5L%ڢ7ObE/Mн{t6*q57dыzU!z&{X 2[b+qp6l ๐=O5g9 +wZI]Se/PrE]K}ʊݻgآg`L}B q1Z9ʖ/MU]0s"NT8:Љ*On‰×dy`&\W 8u9:Hb6ΣεRI068'wرp! ei=W7tHC qI*'8ϭkhid 1PJA1}0MjGU/btpO&iIACfimCQ"vrwJ^I/m #ai?@F QצɴzgGTϝտfxQfA6}AƼe\gAr^25L VN1L&[Oom;jNdWA#]&EYnv:;q#ZD)<H"!` +A>.ݳpD(KJ3 xa\Ã;6*JO7ȢKE,d@b`#svh,L4 +5n!n)֧a}EFW>JUIxK@չn33i'2>V}B4iB<aۅfI $y"}QQ?/ҁ Q̆}WRM}{A@ER-5?(OбA F |zQ@c (OXE:KvonIGφ4ʧv;~IC`¹ 1,nޱ#Ш,$,!5/▟a8C;}9_,8 vׅdv7xj@3lATF`t(r֐F'5_O 7EܞvS:!i1#j}? `9 d 93tb͇ $oKФn(U"L@~7 -L%F "jтhqqbjyhnux#STL2=g2=V-Njmv_! -|OVt@q_{R|Bd8iDa_9{cr?]y#R8+>vLNo4Ą?7;r1)Mq4c c->v4Еdv"LFgF:H$SUz2zriI߸wά]3 |B.ɞhR \;Z0ҞF=04U|hU|92>r>M ]i3JR #2lM!mD=Y"dK7!# 1%k؃XU8hQj ܫ @gT+i d%l$.Xק )UnZ><ЈE-x[ + w&"4kGsҫ, 1`3g9 +i:2z$SwM}5n/yY~\*^'u:`Tϴ\w?_%/U7b9{c |,;bB.xwfQp_mkeɪ7%UQ`|`(!^(}_*5sOUQe @ y}00wcW*$dimJsK_M}7mˏݵD?ԆŖmq yYfXodT ;㻮s8 N/F7Rn]ͺ˙yvizaSFKMKz㾜IQ2< ULUM3WoK"VBe!.R_1mJP'r|3!pbM.2wm%np6n\A}b寁:)u=Snjdi*FE &V{Af̵~'t&rTO.sVᡝ?[4Lrٗ{./ f.nn(z,8y^nore㶩Io/ wMp^|˘2:w['}H+J ]\Tq> +-[KI^Fk&b}p~i^~Mj_ODz՗])Q5;*Sn U&qtr-hUس@'^k8nJwӋ +կV䜓!]Xf_{)t ikX9g#Oc2q]LWz'OyոK)2~&ne`FdBU_a [˨r`rZ|lYQqq8LpJ·T>>`2,c͛k?(|5jV4ߊ[O2pѱkf!.9DWgo-L;܁ER1¬ሥ+Ar NPe',zL3s Fleѫcr86w#~/Dieԙ6G ~2>NVz*zG+l5 i+lxYH!k z|~\x+!QL%ݍR:yyqe<~|МK=& Pa{! s2 +Q-G u 9 SG7)=s8VV,$.-tIAYO 7.@owZdK%gδ! b + O`lm~l1"PW FIKC$}|Oesv:ݑGNq&`%1'/ͨ&\zڋ4Jፕ$,8_7KI˜4~Ke~Ώ.Q + + g/m ;k28I{ KL9#Ke\Pߍ.5]ܼM?SgZM Bfh0zGUչ+d,1!#kE;6nRp9~ f"*F%lD`ZI "  8c)xt4͡groۍߡ3Qf_6'l=ߥw)fM7Ur|%=48n<Zۙڛ J;؝,n{sjhaXܰ<Z7*d{32;<-t[4A-/Ͼze/eUgŗOp&_Yָl[ԚZ%A+i)PSWaQ3V? fҡmi;Y柈fvzQ%Q>4mFkzN -@{OiYsu16ʹNsk}ytӇZ|fQY^C1-fyJGҴ#zILS:3ޏiOhSs  ^BNx6[ϰrlN\_RAop90FmHuќ#()W@ ϥ0i+$W4>NqH7[ց<] \m+ @"phǸd!Gp >Aα&%`a] 2xxP:s'>ilU]IrqZWg3[Mh<0ӓ-tzS`].  <],e"@-C~ + 4KvOAYꇇ˒}H`gh!7N@/ ZGOdf)ɬs˰9/pF2Ǻn9][ TCy{FkOʃd8OcK(16:!.-|@z9-kt<C$Y+`ލLj&FOtA}B62RPa"@uBQs0򙝣%Pʣ0=(d7f}?C$y# (A0z oӐRkm~ifȉρQzȝsp2B!l( +Nxdқ UuB|}y0!֣%Ej%ojk1HDOG帚,!긯:@U2Ti7x +5*7FrT4NŝAh#Cs} +T4`9d`?KCbJX68] qfQ DQc]C@xE3D?Er$0P#w];|Ҡݾh' +93ctB4j}Hj;T.M.(#)ᓸ?y +tċޒQ'ۗѓ/4$g]ݺ~Kb;z͓r0c.f9e(t=F^@k^d +W&b*ᆢ6n-5ѥ(8̈́a7nzVn4_N<**$/%f|+˺# +0 `>vi-N$|\KQ& +vWY+\~M+ -/ O)5m +͙:Q^u%EuZb-y7$rs5"EyW[z_wO98q;LRC܍y>/73 8~New'dI4/R@%iji`o- {zL9|9S,jqkՎa3쏙S&Qf68C%1 oIdrݜm*n]R0*-7pWl0kGņM(A,_+MVlvss34v@~*hQ} Jm`J,ժS|d/k;Fd3^ד#qP7B8Ů@.D}YrUenax%C/;8Iq SJ^ ށ-SY@*s HH.30 p=*"$;jRAׁ٘Ct XLg@U297"< l҉w +qG4&'(ǜZ~+:,Nb8p"VATQNb`Xc| +OnĜ@)2'rx + zN! ӽDs3m3y9汕 EvRid:6s K*K0ܸ!0nt,Rz?ĵ<%f%eVBL_Lk3e x s'K3IWM۲4(KչR#g@3B;`Ƃ& 9#^u~,& +&#Mt5FPD(\Y6p0ơ$PF@Ћtm<y*~moaENy6c% 3xPnqi P8{"г9O\>؛*~C.%ŒO7,vd04bM1@[;Z7[L0@JAe_y)c8O\!R&3:Aұ]"ձ~Il'@T ؗ\7 FWAޠHS/+X~PӋA6 IUgR5hԔrvp +CEfbȜ;m*'ȦYJgg0cFWP`y@c(!RcyPu}6\|'^Xf)8JHI u? +Q1@* :=2|aҍo dC"jT1n0JnNˆ< A ;c4hH wANLRHN qHŅ6xvc6Qw%b$)!5< ᡓAeniuX9Q̓qXh.ߧ7Mdl; Ua5sqj$kbzj>Q} }B/ɅG0/Hj+qy;r,ɜA YhK D%׹*Ohí=fUN7TZɱ'q3'{&ܒ}wC {nE7Ce8 zQkσ*'8G6K"b"ж|:5(XQ/LgI8rnB/[TK\U>?wiЮDuI@m'4,Yj{R,.csC + 󖓨ݛ$&Ŀ-H>H(̵W'-תW"$`ӛ(%˱9SJJ(C*(hbxfΣ7vݞ{'ǞĽhS9IyĿ~m&{Il6|̶SSL<(L>r + R8J\u0A|F=)@Sh{."~ɓirDf#9BDHPΙ~Eh݆`KD -?9%0o!.\VF˜8v P=kl+DTy.' b CpI/$m~;Op J >cl %z?jFP:?:XwՙLJ[d~H +YQܙr5j]*b?v 8nV.bho5h-fA_BKn"ea>SZȹPfe,7l /5YGUM< Y%? _lL. +Ֆ>1gsJ@1gsN?"c̟38"}fΆV2Y TU׉5*bGuvbg +@kA*n2T;#[ejg$딲騶rU-I)eӏ:j̛iôy+wfM_'YM = m@ܶi =Q1Qwq +W,@"CJX.]RwCoF|M +[pFR P " kmvE 1kb5АFi|"L:>ܠ74\-–qGv1p'/S#GBX W%j/2]} +M跜3-e_NȗJEgϧQԁ! +][\D|_iy/4M +*œ~sЄe"R) x)TtMgLGӿ*Z`g;MQyL&f[$*d8+d*^IMsk4DA إ9:#7YK?U#д&C7ut696wv uOaGIuM'#'|z||Ms7||Ms6h'cH(;:lr*m`VǠI3E-i+?myuq%rUl(Bj߹-GwknWP5 VBVX9`h8hZ5,0WsԒf;7ΐ׹亵ay~k0!wl-?*F*g^SgBTkF8ލgs#Up_%C@?}~t@'c뱓9 OMPGY U76o_7VwC]@flS'!2a&U 8;gҦXQp~hz*.tGIZ{}W* `)% ^ t<2Kυ`:c#8Sc`(twl$l%lcǥLe $4RC +BQ @+. R.H43j}r\t.y-aAd:WMTRt Y/A<v$^t0n&âM(!!V's4{lFM̻r\ڎB:)Dڂ1ƳWƝVInXo@GB\:H%AV&MsC&as! HVp lc/?.PٳZ-A UC]bi5}?iTvֈW@Dֺ"qS]vn 6:^Ⱦ7>G ={h¨v33-j7n2 KQErq6%򳀽dkgi6S]Rj,]pi@b͡G~F|-T[TSWoZK#^[Zs) Oi|(2ܠG'pYB}l*9fFCS* + /Sd<*./:h[(s򗽃?*Í$;a: +ucM5`mLzV5CEAF/=pQB;y8 X5\`مlB % rC(? szן@U9%Ue샒vV礲sN礲~?}IexiU~NRjK'_yjCuXX({sOy)T y%&aM'ˬ$,Vڧ4+ D|<83"_&n7|%&J\'Vzs-WB3OlniaFq~Dzu$S'n}䕛豞=潶1!/nЪ8wZ}+ %9<ړk͇o a= qUGaϜ]r~ӔJ:Up +]+˵ꮽm~zitg`8?FE8kR6r{gw_"6$ȗtRil rWjv/bjdj~Gi~& Ėu4e5#j/_ĉS90I>%_Lid}09یC9-NDP&,c1Y#^␯ 섞geOaDM{_VTY4ش5s**.>&SvtF= r`=K<0bobRZ/ߊ|k'7go2cd/py9nZiw"Sx{y)6")(@= fRÝ)7$ǚQtkOz bDP&vw@T}[jjd.ߠeND 0dc an0Mqúnff.ñ `G80(#%IbH+#jR1)%R\v +{:ddvs AO URzQ{r=^%G=q6eZǩ(e tC-HZ?6 +SqD9O0 =}D֋o*Ͱ`І.'~%H@V5Xa{\@VlNEUGg%$&9QJՌ#C$#[+!f yDS,m%p]sl 7"Rߴ9ޱN/Γ{hW{8[c>ߟ=%th/S3.;RI{,s~BŞ!zfSdWi}Rmݳ^:x0mj2\C+@3pMxUN#55Q}"<|uX_v\l-V"ޏ-vxJ tt &zmF652T!9`k $RS&$?X3~ ׇsk&{<Ȗ*"˜j`G}hTEr>?KrxD4(9o;uV*5oVaJ''طJ|F֪;e:c֮{eLb'0i Fte[dFVGeR1"BnWBBL0Ȕdp(8Sܰ5mLyTwJ_P=_]@i/eXjj>vj&vbj^9~'_DV˵u8v4Ѩ3Z]PU +0~UK*!߷U66b֣N2G/eKZDCFG5>r0YS.UGvѾH<- +p@\-60"Po`hb\%Yʃځ]l[IZ +I .蜼+,g)U(7P'^nU>˘]n0i!E|)St^V0.Öw3ᯱ$ pgVl+DžbMl?.Ù*۝B8r݅=zjM%Zy-'I#3x4½`b]5φBM=Pnֆ>xnQL*=Q9X놝oJ7@eZp9$vz ++ҤM{re^^1QgY3{rD?|!swc"ܕ11ګ ƝD_9C֔~y +;wfW:?8gnޘZ(eCҘ,)Y2 ۠Fn͆._jdA;9Xnreyz/Aِw-vfaR銰X{25y/cs~ty5v,^tsB於 2gZ)o?яa>NWpfң Ծ5[ykLR>!Y [U)] uf PH_?{(ن\L>(Sqۮ2("S7q-\RBGyRs)_p{x~SH QW>[((ƒmPPق%t +JAk^dž[A[uYUQQAK{&L}a1wRnl]}:vCme̫Fէ个9 DDzK*g:kn?J *r3|y/ɺ"9T*<ۮ,y) CHZ=&{-O+:;ȐxHtQc ,4%E1 ʜE5q~O%ʆ:}kvH|1^Y[:PunˏR$YT&p꯶ѳOa23 uWB%9=O_Q^˄Ce7%l<4@MaCY Ea1 NFM* ]*Vzg59Y ++r_ UhnMOXXRet^b[\1AJ]ډE?uixIY!6/ H" KOb 5߷zzpªJ@q(D)}DuݦT̙'Twzz/$i[DT2lDq!-TKDL{[1/Cq*ևc|ӁIY=a 2"S  'SӚn +\(}A:2ġ21mFLspil=6R~⺝@ѓƶMZZxɒڽ + 6Ȥ@>A/͸Yh㲰QT6;;aR/t3vvq3d淳flN6k!m:'+?VQXNN-'&mmO-'k_@ώG$m4m=Q-|i1%v[F(~-'2r[qrOV?Ӛm :Zw۲ja,:m[pOL[Гb[-'&dۢ(:'nի\_Xc'j` H97To U[{vn'm 7 |}1sw`&g;!H`n9{/'x|$q?a*l f ]-PPzd_'NU;'7G6c_ D@34&uC_řb&-a4R\Fx󲓀x'ܰ +; ~gI+;g]I蘶w*{ +endstream endobj 96 0 obj <>stream +VAWҷ&J:%%qML͡ L#4Р\fFR*NL-ϊx*G $Gny 9Wvn9)~57rz&|M[Xޛ׈ДSSzqZ2᪜vNF#__zSzEk(w=Ŷ],z:2Y]꼘rnhCs(c.n +WOl>QJU (4m)f$7ܳr2 +EEձf޹5ޡS1M7xsŭ}_pwux`H9Tj9|(D6Gֶ#.h]HjFl&iHr8$=Q5YܕYZ}Ћ@d<$rjzyAatbښ0n㆑n8{JJfqc중ckp'Cΰ!H?dTX3 LoZAn};[F < 9N +[@LXڠ8g7*tźq`"(U&v#J;Dq\J62ln jᆭ 0o$٘Ž$߬~H޼̬[uU#Dug ډg'WC6`R*% Ne|X. +8 b]{{rP㑂zO|A򂎤嗦{^<#_e8<0*r){ rc*j+xuBOoPymj ȮKJgiv 2@,U7T2oc]\I8zDBBtaA#L<P@ Q!Qtɬ,Z <Yt:IP{G׋_Pu*hA[ݹϝnLUrTGJ4@E"`(fۀ߅G kL3Rd4q tȋ ZӚpqXㄡU +o;'ơ/c֢>@k';x<rǃ&ZpۺAIBJ0~%v(ߖC(=rͽGI-}];Q{+pG,H|Sx*N?`wH6CbB? c|u^փm_y1q)pn{[I4k|U8Pupwax}l (4y#Cɒ;.f}P1?Bv;/TBxη8G\)UasZĕ! YT]veq[ci]e~@wCQ:XnAn-hW7?K(ہy έT 1MXe/f'6[7޽@.@% *<,cS&Sրߐhb"/mTƹwoe/Z#0r$Æ;|1R 2et醴ƥiˆx'um [x@i m `M0.qny6gbX6Y{yY0p}!8(I3t5⭜)Qm#VG+] N Ϥ5 +U܏s9-@5!:ϭp\f:D)J"YVǎض1r+;xAW,y- 9ˍ4h79p;&;le pٯ+Rmd؊$EeYֺ5sI1$2$4Ѐ]yF3QA\): g?f7zN"ߙF\k^_lo!XXwrۻxbGdI]62ƉCH5=ؖ=4-_꾳+m3?Er@lrhrE1bZi}}qiժU5k, +k#IL-O=B *(ir9#JK蠏diQ,ŧ1䓊@h1'yzNPFw,>mu%5(bW!5UI9ȯ=3AR({4oiFwְ~_twx}Ŏ }颣n~|T(|<+$ 'wK|CaBƳnw6/!C];EXG Ts8Az/l%Vzbs}~+j ?sӌkQMwlL%aKzD  +XcU88"$!? EI8r&\,Q$UcO(J2F?i/{(Gzu!}}d#B`7,Rav"(`Y4f@Ú#{i̔:Vf# _"<\U;VH\9~CƢ׮)\UC#zfCZ;1wxq L +'7-:N;솢j1 6&0+'Zt 4a{'ba0 [MZ2` +Zj~V{ vW }8Q5GX"lH\iG8O!MAB /$u9X%w/~bqڞ%q"0gO\:$>SYCWBLM巺d]_uY~~.T:e'S۠PBٔ|wpq C\G(cW`k] o=GszIxUr'fIpLDHP2hifv`l lo;;أoʸvP')J#)_,NȋP:fG3ʂe$C0r1H߉ J,*neQkS8fFV3Ҩ"$#|vrĒ: +h?Ƃ$Ikmx༜3<;ŒtB q*t~4NS@fPc \ی\%I~CnfA20(pf0߬tD?LQ(CR|u Erh,/auMaIuQgܧa)-6'/!G`5alA\[+iG/xl >]y`Y8~9R#f1^ӏrub X[w ݭ)*ׅ//?.+;ZЅw٬(.cR &gW9tW)$}w=75woJ3~iG*< UQ=|W\.v1x7kꮂ"=VH8&;U1!~Qh(}b K9x S3SAA +?>ȩ SmDNJX[+ OnPgSR=TL hk T)Rs&0X,^x|?KQ~w\#qeZIkb=%w|j Kb:/`4*o3 +hLƢS?ƌE :hYtAK~v7,F,""7]O3 Kl, @9xCjh7ye+LVE4_F9(-釽$W̃ |U@^C0er_4  +x=eQ^#,ɛZ؀Ls><СA4=e"; +\ 5ØcAÂdeX J{ +(katevhak]E.Dit9DWMJGN3.%W"קbICʫ\[f|[$=b |[8 +Zno_u7L} 贘2?Fw`C85s 1`0\߂+еW9C5?oRol৕,ݙmEfc%}K}nm匯b[Knϫ.wšPQ΀&#&O+;cg[7֝4˒'GQ@-4iY S>Đ4j |lbq uD)콣uJ0s,M<82` ˟EJ&'s vC!de^>M7YՠƐyU\h DBr]sOAZ-(ԓp]6N`S@܋1՗1G%i[R[ .8ٺJT"EVgHbG֒H9|p`<݃\ztGՈݫPgH53P7VC59T cW('d- Ri)ֽ>25>– ANE >vEEBk0N;P$f?;"ao?F$ Bo9× lR5 cEĽ:~*Ҷ #2 +xEl RypoM.'ppq]2qp7;Wlr)~34/BHD;ݹ0y'5;=AXz'F 'bB"O!}*9G&auMbdFTⲖZrF$tEL&h{t44@[MHlQ$UFT-ҺVVnip>]Ӯq߲3.]ۭ%#@9[Z +hxÒr RLiAlc5ڛOOqD6YQx NV`\\吳e" d1o$ɸOO"`.\7aKW&BMy!Ǎaa~v6jVINi#3ؚ?-BmM 9V-͌N@+P`mZ0~ai'Ȉ`jG)3ysE_%Jy}5t >P^`  ٯ O08;;;JIh$}<7G8=XsKrc2r-*F/* n{gɧϕ'J%Wf&NYd?ȹU7a|]2|~9¾n/cu6c{ؤL-$lZ>lh2M ԘINc[kƥ6o@R 炞&֔)Źp@oEaYPϯOQG<홁͟VG1Decޠ?mN.!9c{j2li rxxLv0]ɔ'쀻ὠlW2rh%C a-K[MLV⳷Ҙj+K}I+8&Z)x1N#&I` L/yP{D=91QPO-\ lܷ+EIIJ* C?J?qcÛ"'̶OQ=OQ'bF5ՂF7l P#SPӂ1ErO!K# j1X`@ +E#GRtgĶiR*waVϑC=-},}wptkludBB +2nODv."$4#kXw^.O~O4evuOh G'هlCKcG͸CI#P +*F $= gj5-wh֪DI +SE̞Ao`e qII(IE?[P`Oj*Po%Rw~wPۋ.`lfڷkծ͋tXYxyVQ2uO9c=|;rF#?14=y,,sa ,(y źͮ'#2衵?cGXb#&gNvDq3x.'yleV/ephhtuNi.| ɦb#h dHu) !07bl@%:OrYx|7e鬄lLZ|<9$'vc|k  `Z/ +Uw陟 +Tg#))m(GQzOhxr"?C'.#A k5E_/߱Dbbq:)lȉ)DQpxZ)Oi3* T`/u.1_ \tK7[.O坍*=cm!}z1M^e MxqNh^H{Bb/4?T#K&nwθmwqlf̤p:XKfs"3c/d}&Y>?B[cҫC:YX󒻞?,3^&A^\Krjg_WcZ)x9O=/o^ĿM3^Vɀ湊_ղz5o{ݺtz}\]Z Wۦ{Yy='9; V_FUW#߽pgF=A{Qokj2tFxo8 +2Cu}^?j]i] Af0oeq k'_f/˷m=N]j<Չ|OzjKΛhuvO!hr5ݘ'bmuyܺˉ&W?<SE}Wv&_0nC,ǻQH|Mg?Elqq.Nvkkx +uk^XFl{$}܏ Pn6b+ZjKYuv37r 'B44l~ݨ2ia:-+oUCHڍ?WrN.Br6$_ +/}H|v +Nk&_dr~`FpI|σW VeVK*܉.n 6 .;9Y\GW|dŌ|4ig_0 +:dE}7pnf:sI!o䜽${>.~4~S,ً|wU-{]u'E[5jֽg6A>篍\3L?W贅H:,|J>k\i!lX81vPux}:?1yqACN'|J2oI)"aL &#ʤ"_jhQ +FT%;#v}1ޞ+Bz/`Tz29Gcb>K Pv>t_Z}Y~bK:_VŸcr##Iv6mqBǛN=욲; IgoTXj;"qtU꼐kRiL羄ưN3|+~ǝ5lp؂xϿ}9%6' +w}r"7{{5} +njX&z̶m4'AJNG[XExCZ=GVGFxC 4/LA 8-m6e{wU%} 8x#?ڮN{<w1v>N4?^!,tH9B1v<v+F?ؙa%·LМ~Ge@ D":ߜK"w'|p7 T?>3 .C  + H5l/[[=d./G"3?˷omы3~?"γ鸡~"!ĻN +&k:~69.[~M~ZV5zջTV~;>Y/S˯A{sv>VFvWm?!_)wn }sEq!~)ڽ-~XFR̬ -_[y=?18g.l{9)o.!AԄB_(#WV0[ Pt#O +l_R9:IzĂO >q: + BNƄ2՗n7o ʇ$1t +CV> T˰(fȇY`<YI ~*jDɏG +Ģbj9dyJ%WH;Wd `2](@6YX Ƹ=ƃ'I%ԡhS:l)^_Ppm.oPsϭP*M}W:WWv_>K/2|9]`q=jVVӖ"xC;䱾} ^1U(:Jt0`x 9~,N]=+5"6p +_ o~1!qX};)=VV2au+$Xf*e !mMm*0s,j`WfI?Z[?TE8\4 o=C,ÃHtmExͳ"Mȱqy8БDCF㊐bv]D]MExmEDf}usw=[qܓĹVPƘ`pEt ^B"{~1 +4LðH/X 5N7nɍ)=yƣAԑ3'[[|JF:oJeD -/;l|+E~MȥxWܭ5m>* o*$ǕPԫe[8 .>$ @*`;A>/=aH]N+)ɦӱL4YIM|:5ǁt Ð +9{`Tu5kk'hj5O1h -*!Nt߀‹x 0iTdiby^)V!JНU|NjFe5F~Fy`W(H+B;pll6k}*~4)ʍ&%ewg 3Qkr&asY&z+}xo͆*h\C! +s q3i Xa/igRedi͡P,gwǨaGN(}ڂ ^ -0^o[NPmIP§!~tp.nvG7RF ԬJRAش#/hg5 6LFq'2SGZ܉(i[W$lB0/ +UȰ{N&! eI< $h'AfeMJ0 * )8eE%mw(!Yx^)J_: +jb%8!%#[np#^ATVS:7Dj GjhpFQ|v7pqdi ۓz.A=W /"70l7NC5I\'F|R.ot4B?:[\>M9G~Hچ6J¶W$A6~ ^C6`$H_0UDq[Y3);òj/ȈP 6*hƨ'ƗYՔ4e! 2S>,iOiǁ \z +g&9VtPjARܥK{ҋ4ӕzySyK?HGm`bRɓ#]FĴʑ$RȐw%)>17C=m$7At DLincWwL!eܚCE=˦:ĺQ(n&< NyK(7׉C( $Ы v3`U_ +UIJJan{Klo.NoY$/+c0}b< Ϡ:ZP5`BFN'ڔۃ|.ퟍ@btTzBt> ~4 {K26u h27^2Ve< _t9L#l,93#?b#_(ĚnQT:CMSBd)T^Wl E/p ]u_e5 +gPo{Zh)΃n[k`%Q^!Ճɓwah\Y:zZԽDҘb{%S +m͒Zچe$7T<,n/}N[gQ[4"G®yp,jA|IZ&8N -N $es.gPܧхAnA9Ί8EܽSUF< @`h1q &{>3d4cN}WOYOG &g >@;8,C(͡ar2B"RXۇ }hr G\pSEB"pWȡSO!@򕞠 fhNOq4ΜT e.`)4MQ4`0(cmnZlX3 (ǝ(#ʸgNKS*WT5BMTk]Ź澢Na(G+ %+oc|0hHBQa+$BP<9!(?84'k &uaXXZ3!өBb-R0V u` +4@M+&o!}]9JVgd[Y&y(x)/c9R MBχ5% SRPl[i4 Xͪ۝aqBlZ9򀝨v155EVnE4|h(t DM(of{ztp @U=YƢ z>30Jy:aa=(axeQ咤eXg^$zh:|gKyya ,`A;@9,iJi.%k%*MpRLā +٨I nFii t{DfIG_DF,ĉDfuL'iL 5v:utWủlۑ5Z!u>FW*o7,HNK'v'o*ut^p ]tjDGu ]-[Uw=WQ/ H.]yU–31/Ʈxz]%k "MN` VIVHY蕁:?7+n)qLGBj2e,M2fʸ[7mJƽLS+9 Ǒ(2->m1}xHA( W 4S 4C`S;{rwA[XI<> U6jW6 B-:Q_QX%Df6ԥWơ[sGT\`/AU ȣ`Fg6-5Aʱ^{8\mReN_ab>ҏ4ֈ-OH;[3G"C5x`pH_r̿%{910?B c{xytg&5+ _uYGDfm L g'5v.1ˆj;Wђ +k@` sβJ,3j+5&ˠM"JLj؆MŠ2rH79WY WLo0(jj҉\akUwi` E}Z&V(+X_ۘHb C( ZxZHz  A /:dp1JmǰlқllTGp>DJ_VsN&= <.@eXꗡ~t4E_v[Sdqqiʯ/)ن9b$88MjiZB>kşvn'y;+63Ryb&땋I׏C|ğQ.]w hٻ@nX2Mz*}Z&!|ZVYӢB|g|5$T&M)lRJ1/.Wrl:}Yq~Wu2KN;~"y <9L.tk[yÀؘC5!C!Fi0q%Y|ZZFrgZMrzHg;Vנ+w*jc% `) m8U* coWj}r7>%_B;6MŁBPq^i&KjB }նV|лPo>J> + w9} Рݱc0%ÚJ-*f^ +KV꒤YZ_m׋Xh|fplIi,G<8Z=Q@֊$Y2 Q"w,/TxX@yX>}(фdn +C)񥭚1]^?/OܾFPֿ6'> D'"&4yP\기x/IlίF$rl$Sqr˓ Q8ux$X$Fo֞Glh|'qJu0 ’;B^O)L5}8BLMRRvD5Jd8u;YPA?Ҫq02gu RTO4Nkn&PEsBESYЌT$Īzۘp!rx +I iA;{(B?7'l W.1b+tš{i$O5T]֬Ц;V?k,IW?hy[A%F S$aǯ~7]"? c^Ȣ*޺6AYbx4Kp|2_U>ELCJY;<~'Vc6m׫|2[ܝ~cgq{Lq:Q=ϓ{n.yo@Xoe]qUfHcyYe.uaHRtAjΓHpG +a F_|qE,WgBD1/Gu咞-QL|x 6Tl~J-,?@Aa.)4g ">_0+|c p$W߀5NVCPGŐH*vox S!c$HVCc( W A +XGOEwZ@5VڲO$/aCWNl?upmSbaq.ٞ[Cz⿐a,^Rx-9X2*`_q#gբ?^`HzC8WɎ)bpTvGLl5B1x +DQM5L{y"gr/% A VNH.m>lR8[PFv_ڻ\ vIVH]v5-%4Xfɇ %ivO@gQ4*I4Js8`rـzɠ "iO ːޘI(GȋrN݈ZXǓ|^WleQ?V_^۝Zjq%&qq ٢Z eKs 4e6l^'*{zM/̲?9EBǺ)ӖP:9&@yuv6562i)Z/odGMDɫ'M(8@YI"9l"QD0l%$)MDuL"W->?<]1/W⍰|vI+ ^%vMqw21& f@N3GF&̳&ɥZy n>$Մp$MEHsyV\D1 "SI`u04(.u .s1. xM:|4\Tl$(E"Fv"Sl9 PW/ȹfw7ο$e#A\m%M>>E{WV*9!B#5Lh 6IB8X3U.*0^&7i:h:[+;SL- uΑb 8ҭqĝi ҧfm슐y Q*yasG, g`6;: 3l@@a`O3vi3&)S}ϑ|Ho3|/=ɽO,$ՓOO0 z] ⑆6;܈fciч@2*TF@{ӓP"+=nD ]wŷHDW#)V_gN^;+E@KwۗN8hMDNX3wۗHը߻% 0d=[s G6X:(`Iϓv.BݏlUdcSr%Q&+)(XSiXAXC_NYם'Emg2y$/bG,bi xIQ>؎F6EU#YTOyonG. x; d!@>o*_:%s#>e( 'Ixm,ɿH/84le7EҤ%$ݛհP-D\_`F ?gu±HMWq#$?1@Lߠt4[DIGH qQA> +IRckШ.dߴ(ݫ8Zˠ,ŕEἘR8@;! [VƳs +O9v )3\SS> +8$[I4ꡙ\nu-E+m2 + 2]f2W0[d tEG-d} @4 ĵIsElt(Wk8ɶLM`v!A;e?^CwFMKLDŴH\#-4M8,^,R{6+PZ}o.028= 3b:u,v,+>|1 fc؝[grv ׈i`ǐcx7$ɘglBh`ODB!}y0=n):lq5=RWnTV:EWm^?e~eY=*Fg\p{dS~5Mf}0IFl)_rn+Bl>TK@BvC0Bb9= rl۟ZPt}J8t,!2m:L4Q(0L2pan;zPJ0B Xi?zEC 쬂#SPf8 u5K2v>',~-)Yف YYAl(W;U ȍ1ۃ%?u+6om衱ƺ'r. 4?~fhazhuV<EGOcXHؘ:Z>#;%UTr[c"q{*Z%!=}[2䩑-!_.s]o-隟 .mi y&'_J1Qʛ0agGq: II{dܣCkB:_W<]kA@j#G:Vocطf|2>M:B'WT3LV}y4q["~s̤j=|߃gV[!xc[ûDtvL\:ZL=ꎺ7LNHNIe]0 jת52|MeW^ +4 dmL$$s_._Vgz jerk$uDk&Y SI+\|? AIatnܜK[#x-9>ɒbirgG{*7{V}v^g»L b u5= 5ګs1Q |8qƥD#[uZeOӑ{[sh/ȿn;BUlJ!M__ʾ_>3qrKwk>ɍb/iƽE + Zl'%dg11WǏ&I))}cs?&]vm==TN'D78:q=|\g:ݫV`p'k2Olqp9 N'Mu5Ǟv1W7\nr'gag8y[5#X`zm4zֹմ2X):H(lwi9.tpU8'?m({vD&QMܤ޸p-''o-i,}9,ϫ`{+0-Ӥ|%?Y o\彂6 ρ'b7gaE>},ՂW+tH?=,1d|9O,l=/MO?w1d_0mdxq{Ȇbb-5f[辙÷YJuRES'wB*<U:0~VYZE5q3J;!Z;4UY)wj̜o?Ov;O]$|^=m=H/LcX Ni W~Azү'Nj2XZO8LzT)=/N:'VOqI䏎^)Tu%҉z;,svǾdZ_kv~&$Ξe FdzIuODO#4ˌ7X^[ +#ozy+ysso^^ڭ\ƈgsM$\nNjh{nNfwʿ8_oy=C>?_ݻG_ ͅ567.\/ׯvn>O#;~Y]:a4pumVϫo!1řLsk_vIaYZ|ZKk[r4c}>v\l3!VZj~8'3s3R'fVijguz9ep?=ϺZ=LZP,5Ds~#Sdz&i0\4Z.;)m|dRdPҽlc~߃+!͟/a%C^iubV¢̍0>jX@-aX jQWg@֬{#m$ H¨S׊p%Q\ +|3ej54q*Z&ff=T-:荹r;ݶ7n1#!f'S +(n0$%G/"Gj d1 E߈gaX r_-a%-a%ݩ2Sv5-۸s[ ʰ^t=*t+/uډ(6ހ7clr_OJYev8v`5WgchaȈN׏Gk[{LOM :k~q&>[ӛwb9[]>e1]K$PQiPP^ +lɧrd F6r +s{wyR\yУcۡvMbډ5Sm];6[S>yv*+LKM2LG)Zd #K4h, |M8یvpAyuV 7c%=j*M"-".l`A*E׺Fm Vκ{@!/z;81hf US>Sfe +Lh iAF-tf.[c!`Р%ڈnO,͌rL!`Mrt{F\߽/.c#4wݫ럨zEVEa(ؐa&E$HQ r]9>6 b"haCJQA'֘|QP:t1Y狐5v5uNTmxWk>[׋y7bsGͱR^c # ̑3 q] ώh́ΰac5X +b#Q5rE(W3Aﰝ,s}䑿ً\{:Qlb) Asa?M+r=ÈYZ//0Vyik#T^9 Z q;u1Er=M.iڀ69p^~BؒOiVL +x2zwa dq.YefSںYI^sM 푄qN^Ze +!"YgBw È9 )L,36c,{8VĆZŬaqȦjಌ`U? +B*`:b6j͌9LuM~]֌0QCRs(p=aMqт;BsI<\  +:s>9(*vunPb9 Dɾ7{tlq15vZRj~^/&Y>*KG~p」l?$zAT:>y;c~Pq%ȟ(Fj%b k?_&J;L$ugGU?ƵN;H. '.`^7P-KVI{}I{^(2{/ʿFԁzpϜyEڠ?VXE΁*3:̔([EۆIt$ 0O\iqGYũTU8яimqb "LofJ?1=BkB8)=ey8%qH h +rC GȠ/D޻@Žr]AϜ-X1-_bE_q46XN_I !+m +/c I4%uͿ +cX-\a-˶ͻWW+(]ߞ$eS{ߊrDpp){Ʊ3 I, ~JzQ" }IcPݣ4VB;NO~jeU˂32^C'=Ony.}U^ f\d9+Kr:*n4IJBzEbZu˭IQ`;LZkdM:gf9 +o"LnĦ6W@lɇBwEXa +X-+|Mϋ xɇoÏB]hAoe$rp:wy U\T=Rђ})i߀lCZ X>.'%$LLZB}J^$ভ!!H@^9:qԚŠǡ[TkQ-.oӤm%e$([9ҥCEFS|.N~+I4v[_w9cѦA>+.9˹bmMAb;2_zcN]l٬Ȯ=6%8w:P_xg'=o,;OO9c Y%%n6_=O#,N~юKl~/xOs+_Ր D;|ݨf5#serp:B@ߥߠB zV^堠wќS!TVҰ,*\~"Ύ\ m+v fȱqjDJ ߉ibv1J;ā1[ w;i [BЇY1\;.(r+/ݝ~T~Vb&G #3m)({$s)\-"jaB*ɾ_>p~Wsе7nWZ8eE>i3} 7hU),BLy'smiibd ܼ˯2[!`v}\X Ո|1#0Gt]C +JCiVXqT:O }J^IA ?# k? rSU`':IA ,1J)_?$h!(fl 4{O.9ή؞_T\7S;惠V{Vn%Αz7͞).h`%ks ́!}WZ_JZL)f{ji1ppqv}PcczS 88 M, ?׬e3 +pNW;=M;HЛSfD7c=lFP9$5A.^/2鄕5WD}8wL(H8=NzCzhxU[XVi|YyYLzHN1'ff{[ x'T2F-iCсJh2y@eo +tN[]{UPqp +wEqzݕ)okԽȽ[[+B:>GK聾%YQӫ7jcPdg&T(:dS^Xϰ5dǭeȢ? AYX% {0; s]ڕSC˥YRP8cmu' irx" +I@=CMr쉙K[.B>` {s5tAa*׌KVp\<}F rzW/A;n =~\ +}T^Vل2z"hX2xןĠH#}SPx8o"8`1% z/ADI{ 0T_Z˪]'AWJkG8NQ N.5 .]fLf|+Ku1hߤτX/*RU _D4ڠ kt艾ZU&˒Q:[ų .M#P_^&j4`}ySG鷒]2ʥk:lDWmgFULQ Pv9H4y gz.#q6$p䮆y8TmίRhUʧụ} af9)Rۓg 6/B"E7[/ȾE) V@.u +ou:_Qqpƽ>1X]TkFZ +a6(/_OC]g̴c">Jk,DkrKFq)ReMV+G,1znIkE`aB!ݥؚKd H8,,R3iÖE%f"*% S%D`~3RE+8tRkG B`50 V>p ɵɁV +FkTT9lO6wG ~9,1(,nҢRw @6/G/~5RnQ}݆ j(WhmiE68<$0=aw4nmܩ㗻ʼ@(Jm8[iX0(ߦ[l}1;ɂց ' + +vt{þV@\ &v_'rBTdžaBɽay\PG'c pOQ T ZA#\3ACNjZGW7(,h nϧ"ZQnm+P]%疨ni H%QJ16|}),^>f)JwR_8n]غVVW4'X^wzOY̱Zk];1znϫ(<'=Ys\a|EI F<`rA.QigGAvՆi{:`ҩ wSSZ/7Yh`g4ie%:!S@t(J(nqH]M;ӷ\҅«wgˉo3y/ƕQt\jh9!VKE[v9vi bR:MtW#gnGGGF `gঌU'<(h鷐+6Z\D2U(̦!Ы&D>K +Id(CUC@PpEy!;Jidس1wܑaM|~R}i9f]GդɓW%UMi>Q4x}9/ZDmJ2V?Q?c33 +'*/荠Z'΁ZRDUj瑗Hl6%n$Ag + С`ʆYYxn2c:ju#ҤTrA\+YIO&|?|n*|}iUR>GJ%d\f^͔pw{aݻowfW)U6g51EhˆlnYx +(еy?NzB4QKmf0z˭F4^Yu\κH1b+ѿYӊDZPtJiPtnLjXKVaߦT?`y*_:LN:GMS3߷^搯O{.#\u".RUaV$` "aL$Jyx)wHy{ :`˨'$2>1ys-3]'Hb4NQ6(^GbTNK(ElmT+&TtٔwOZ`sM˜j|4*kys92,Bz(ry(~\sJw +oB}X l$U[Ljn=wR~jctf5Arw~ ACCQ +"?abpa&,j>N\z'L|֌a;Ӳhұg-͎ͦKj7a"I䖣aϢnx֌^BHbQL/7~ +=!/+Ӛ]3ӋZf[nؿ44A Np~Գ,̇eџ&[-8,Bj +nqa@;" f⼜9We74H@7zclf0wq|hצvmc0Z2 fyy(UX24qҋ·U."_Mp@\8};$.{p@E^at_Ԋ4sp.83?Ju双;s~w>k|w{U?7ەƏf(?7̆3o!<(5(Y%.YR%twWGtِx/I#$m$4c|{4'hD"+ͯ1~b7iK2j0idYl 4G0|͖O{GCWo >bA|D[ͯ Gj*LaC +V_Kі,vt&0P12 f'$v!P<IǢ62 W>zN +hDc%t0Xʾig6C= 묆Y78{rSw9gO2B8rpo3)fYtS*N|yzz{ݛ"//xQ,ȗ?i_(ǝdt%U:ZR߭/ًnW\S'G mt<֣M[nt<_Lh&~8_ ]QgQMfgG|wt>=+T e?vu;({+óJ]>G}*/GH{엃ϣWVV I]ں}+-y8.&G({=")٤#zxiˣox[Ko]ܿd}Vدp#!|;'oQx笚(7kZk\q-FIVv8,vAuށ\C3N9s~vtKKmV7 R=.`KK=[ lZ9ei+ՑDi쐲EOPy^>HVW v ھ2gu!&lI8Z*X"=mQdRAENCx +Ob az=Odڲ8kB͌#F'l$C%ή@+X>4亲G̊θıAShiH͒9-,Bq/:'ǽxAw,S%2[jFG$6I-F~Oʖ;*[oo: ^>'d:%!JD H!;~ wue((>ڭݳ +bйgB&GgbPyJ}Ka{~{{o8?&n@r{'2ԩy PacJD >SJlk%-ċO_?mYQ9 e%1Q?:@KC}z;=&oßa=VoyZk/r]pM,c.PXKg{N :J'eȣ,O|jZO{Pz&~.5{.MSO l4]"Aؼ#N#nHgӤB 0:?$\ww[@u)9)N7eu)egpJ3GS7f1]LaXMZ9l +v hjvs<~A1Kog +6=QfRBJςt 5M?\S3҂BV)<8[l9h)0^GEV\Gm>x3W5iqtvm:kZxH^1*=Bov\gUP.Ƥ鼱y @̈́zqu'";}߬":|v5X[l"t]yA D]|w{.<|IzceNrA3;b|C<#0D#L==4ss0*LvJ2ÐVp>]yJ`1i:ʖKkIܦ^<Ґogv<ڃ{Q);ވ=ŶF0u{ +JJiqzfWbZVZjvIOɘYe(xPNHm7dSA_dsoR 7q;0*N,W`7~xQUS:>q)te|X{؊(˦!mhk܅Уlns'hoq?aJjE+AX;) 1cMwo+|HM,j8Wӫz8qjpDTP"߄>r+riҘڅnS gn~oYÙ DV8-j]ߊ(Vף.XIVI5)fQ@4K˛dk>!T P-a}b8hQ <B U+VtBۣt@vfAGj( Fq+J^h KhX?w1ڡÈZ54f~5]俽)` &ە@rCpfؼWv̓>3|AIg+R@'*M]Ʃ}`sa|>6'-W=G@a89g-L\^}+Ѝf9 +atcʏUΥWHh +:yנ8u_j+@oR\"%c V^6[ %!&$1mp):aNG;:+ HRiY5 9cZ%ЃT3pAC&,!P6Q樨xU6iN||Q(1UK@K5f:U>V75{[ܦ zV]8[ q3n[Q)|/'Z> #;j5 ̝~R)1-brkMEU + r.gctQӫ}QBջwIq%EcOmf Tb4Co1BG nqyn>jK;$%2V9R8gm'zc l! U +7`(t=&9 +=&{*4$氆S ZJX3hlŘQf-t"=Uw.{P}1xu0LQIm(];ޕ fmLTӔr[㬺Z>LjnG%2o>~l驠]/uC_Ѡ Q<,D9*]a]cȳ౏{GE +zJ/6X rcQx +QЗ|SފnB ݲyIa=cirD 9|-ڱ%<q3,@#A>o6ا}bd9*zHhBg_8 +aAQER}r-,$5gO}#f,sεtm [tpMS#&6 =b'RS!*9]{.r%B7'Fõ!׊w)L:byļ^uM!U MZhXDϋHяf#H'N_l9Xgkx>}'GsOz ňeNFֈ+9?J)[˙ϛȷ\$NJ?rl1=r O(O Kw"jKY!_kӂcόbf5뒸XjF|6IWm^=s/Cj'4Rp2O%/53)Ƌ39=m(DAnIg-eg,b$v0bV$d(; 6?W$|ެшqq w[~cu9tOo_J3qC: +7T$~#2Ta]tޟKwU{*~6H"HRzeޟ4\S +$#ʛzWc V21I:}c :j;SwK+AQtg^T~ +*No6A밚eyFq+HjISF:`o򭷷B~\+׊tuJ:qiV0LmHڐX +T6`!औk#Qm IȾ#IQJSOGAѩ2QTϬџ?.{ErY:h_7+̗f8g0LhBkDe'IRjaE +﫜tGtHr]lB/5ri@yuWڔV\Ya@3jijE8.ʭh@1M<ߺ?8xfqgYSc~vZ-@ 4u2F9ȋ-f+;QlZk 14]Qj^OF47镬(jY4eS&W^CއM3=.yß O!>0a#aZw:{8B$vaŁuC4O P'Gf%G9O` Ov!E*GwȳT*/*Yv6g[Zkҹ;cx ; +>ѿQ0tY.Ejn +װCJ[GH~Qy*"[`ҸFY^J{s{nOOcn)LYR??̝q`A~<xQm xՈMkfFL_.icђ6ZvQgmsQd_{YqT8m-e6;ۍ/HP"#`l)A'/ 8&TrEp)+wqXZa)IX] !!$E, +& 5S|PE9qziyj 6L~*4/b,LGCS 8˝KNS$AU(s$r-R =k~a +赉o#׊7e({ f0ZUrv&Tbc2{Mnd*[ B#́FPKD&\'>I\^Fj_}YŽUV\-|m^O xhqg&4 +ZA2wUɕ=_ynq-Nu:EY؇k8h+=jvZeb9c}G:v +A/nLCumqU;lflzU E+@&BXײX`Q}|_Ct5~\PH\p4-t&b}ɰܶa;Ϭ_;Ru0DF:˜m8+A졸_̑qZ>72>2zgLV63r>p,V<~39h%?}n&9=V}B#8o;ڧNok-"mA`4/Th& oĤn r-(%LYP۞\ )"{ +Wv rN)I۴l ~$!]z)_RnL;Dy"F0) V(',7;qoXp\M$~X3LH'{-> ]fCDEsD]utFa3DMӐ0DmŔM*"jIulHscD7^K$[P7^K$%dA7^K$L';Hڐ@'KJa0[LRjnwM"z!7wUmhb,\ +O@d%xw2,YQh]+ӆM7-&| IwjѲ)F>tg͢6鉞;a5Q3 |{BK3m{×у&q% ü~?z[3(9dEIAs0 M~l5 +oЦgNK^,u2)P("L%Ʊ TTJ)k7$SHMGbϡ+8P{s58 KDuMyNtۜ~ffNJFhX趾#V5Km'tӊͼ[P bTmLhRVFa/Mzb]#0VZhziC(~,K-R$d((5{u!s5dta[QfJ=#}|A^ǿ77Ҵ1 o.suې GU@n|M8[f8#0Ai fXT4;2}UK~pJg>KXZF95Oq-wxJKӼ' )V{(U/T +f:,f1.!x6/8p&܀Qn.hr0mZYtZ(ʐ+N6t՛qHp~Vv*0mtV(7Jbjl+׭iAq|1lc1‘2x 4{g\6z{aFOs?PѮLihR͉3kVjZ҉gI-_.5(+ +XX=*XHY}W~Ya}pU,j6HH@ =7v@D\& S3?:KqA',,L,`};(e+'VOlʿ} S|GNe&Iafn+߳7e*gϯ{?z;wI|˾=]y.>OOtQm0{&)ΪGT&8vOXkg)v=ݭDgHuD'/¡nO&AApFO7{Csv@TZ + Kۿj7t*(taZ?xxՃGvԊg75e0} +W|JyAЗ )q{%bq)Q Qqÿe[v˕:z Q$|пɝT +,m!c|&*=|Z%dkm4aIՙ,?eB?o w;I)<8ύw Ce~^s&;xnڍb}@`.C@ 0#ujv1͛gѼ_Z./]a~] F)ᇫ#OSlT~%>d!ʲ+dͤ>?6ԡו2 Ra컢3!Rwr7d|QRl`3.q6Bj3h&Ncfն贉P1t"@pu,Ȃ:ؙ? P:++yIeU3=:${EG>xƑhd@iMW Nqfؾ !1w0 +)eo;Jy*mLnJ%w<n&Ⲡ,ӹϠt8dLz7ʖ+y807Ӄ[[-K؁WCbkBR%6Q86j +("( @]-yu!M$zXM`3C7{vki„KHF2f~Z29 On !stɠkhzSbc:߲\! Wm*x@0 lo86$eDflqp٘"g$WmPF nj^D)jSyh,ų?o5n\T9fTǏvf3j|uK֒1gqtٸ])\I:0(G]tҏDQn?=W`.7tC(tmgݍ)I k}{R7 Q.X=B!$/Ѻfz{] +thhJR2w.0,;Ď?G'~)c p˪Qg4cJ;k-:+nO,jr`䐅R^<*4-(Կ+}͔i' oLIb.Z4l %j*OR*p`j^tm,jH=sax8gnH.PG\YV֜}_әOeoSmuc-aYil101*ZG}mmw +s9l ?&o͹g.Bu񁸪q4+Ĩ\ q&ϖba3~؟ae,p= &D^kӏ1\,cPo+*jRn/<.Ӝ\ks _7(,aC&rG:4iXG r0Hޛc\g<>N]+#ëv< U>J[qYB6mYCzc*ƣ|歊8B[87mz#-'YGTGWfWObm_D:&$LQڳ&oT+Cjׂ$5geMz9Q٪GV0}+Q̼>(OӣC: /M|X&Af(u~_҉)&[?ǓnGiv_ӹJ!pQ ^e>}u{ơ62ܨ A _l1\[BxvUm:-/n'cܠ]pi 5R\R.f͠0tn:Cho[*b^XBw>wBĢe% Lʰ_ t&j\0}ʃW0 +nZ.M]+cWh\9Wzs4U6G?% +AY +Jҳd_f2mL3j1 $zs˳쇹 qQũ J E4{EQuHܴ)??.x0P};okLaC_?;BWM>B1VX"C;X0H9IHAQV@_H:-$[5yOФ nXEpֺт>&ne C [kH]]-vkGQj6I^'Êӫ*l+T_9. e~=!P ޻H;<ޔ6l>˹~K9]{dvM]jm}&&n UKRIE52O2 QbJnem| +PplFv'UN]@MPN[tg~,Cd[Q) T?Mfɠ{m4^j=ۉ~f6jeid^1skd|TEXϏ +R+h}P֫ϛuuz{eJ)C~D_߮GZ,\ޮm5@Oܟ50@*`G5M%UVDZ?6T?Nt" J^z5`' 0~8A};B,QqZ%c@/ݔk +ϑ61 `* +{5ϺuK5Vctih!VZp3K{SpmPX {%9e+˷ eNޞUJP +.&3Db`=|ҨKmFtqn^.B!ap8V4@^߳iCٙn °vm`[mƔg]"R]&X>{TUL8 FUJ9mfLyBh7} ^(*Uic~.>T B\T8Vᷮxߓk$5On&*=>]r[֘6^ʑi5y]n%Ft<5eiZL[n z.1BxYyN~Zy-8iurv6E?Zh|fi2yAL r_(%YjeJOH<-_Olt̉/Q#9ygL`G)ȗƯ_-&*be`aL3"&Prc$Kkr^}rɾNppNMmP*p?Eܡ5BÏg{w{ (nhcLo{~)ಗB;7WHxmoFi/[{m si1 NǽL%6*?yk"!gLW=u:o^fS'J69ciI R;q-{RU|qNr}|ۂR*ӜR'乽P5ouW0E7%w2K^=p0#l֟׏8w7cN:[JyǠslfq[h#a 74[,Uϛ9Лe΍6SpIї$KA)]EY!xPcT)'фve-Lp(XTCO]]NP \[)֝6g2(?=QD@}Kt.ETˤQbƴ4PoJKp1ePiP#\<%i#7+?Bd'FP^ƧT3mΝy[ kƁdP*y=g~,H4 +5Ӱ'؇¥yc|=41"^tL͓6:쎪F;Л +gbnٚV+NAL +^S{ힻ_q?a uR~ږ!tsm׭;:yG\U + u=N6=/?Uͅ\tn~%mZ_֨~Z*Ji@[~{v]][(1pBfCj,l 蛘)+jr_mZ-RhH!;dWSF1K8Vfo J# yKW0x4f^r4mp loM/{ ɾv=f۬Պ;%BV(x])%S(x:@^~_~Jd#!1ϵ`KW?G#罐A`J1Xr?>`?G]]?XZtȜvӼ[ g^e~X=]SML7t!ݪȘ*.\IIGHj:ʅt[5a]iC}G!J2"QoCc͍I1UL1t+j)Zk,q6l&F1OǍm*Q +^c֎5:dk& KR:iG | +GFߵ(c/ԲB<T/G&GEܢ#l 5Ec&;E #5^!P"tԍ jpuVuXzRԂX/@g]?\&W,kCK6qEPPyI{߼U ]fч9ƥ+h>dc| )pirRzۼt/7Yhf;Ih 5!5:|z ou_o)]Jnrvk*a*?0l<_)]~W^5!?DlJy+H9-KFQDIb#~=]X_[O=oQagz:Owr .u@mܶaueF +fP+kTj&M#q9K1c#lͦLFlX)2nǖ +{=-/gfdl蠪C6gj!{kJqp^;9I:e9UT PeVC__O;&PpwTlZ9CUj4t4JxWPϣC#vWL3~q; 1ԐޛJU{$N¶w*[_LFlgX8kF$[2dO;/]CE  xuqԩ{VJD5h,X]6Ƨ#5{0p pl6QcX3x(P\|-|&P^m . r1gsU}nA-0n ]F$z)&۽WP]&{,zoreɷ)ԷӫF]\n8k )Ǭ*AMv,6JH.wjulm2ԩ17\@5*oj;@M/uPϾOJRegOӧݻ4*+:H;wT˶B|â PِF.:g^YBњ-\|c܅9;M+i1 +M9 /tE@ϴNfpo/o#FV9'M7&0/? a8~4ܻiUTb-/ixU,dCFRͳY=b66٧"~v>i_kci5]f.Sa7+*uIOgSAf[MD,}zڢf[i;_oO>O찛>ͱ(|ђ xaMO6͑65\5touΎdj}k4~u8ݵ|g\~Ijoʧ'6TTĜݹC#ޙq=lo9t.vWhnT b{ϻ6I7LW妣ޤ}j?_-t1kcGrrp]nv]k:T)78bSIa7;$o!4Z_M4,F'k^&jN߷Э:Ԫ!wN +Ƽ ZNo,^c9U[R* pMtp)`OܝMٜҴ-T}`l/]\-CS +xD}T$7O ׭ nwAcdz{|*YA#P&)ȽIMD]NNGc{.G%tyGjl'q , FRMwA$>ė +it;Vyp&N36Lڣ`~icC6 fC:Jʢd_޶њTfqhY:^S#߾3\cԊ5l g3TvwuJ'F{g t<[׳mbiܟ"S MV2[3%FsԖ?̭d_'s[7r|ܭr$|?Ο<\g|njW+e;s8cwjkܚ6C R_uJ{OzJEGh=IآCs'M133;{R7{=fUZ,L~a]L10M栖ުł`UdUx_Y6qUVq; )z\,U@ЉU#頴ٜ;e1^eUDod}s(myzd۷?zypuޮUԎ wk`kk RPk7@74_KOA79fc 7{73Gjk-DLdtP1UN᢮5w!X2zCZm )"qa1SKny|psY*J͹-P)>B܇uf~-1%brKY7,8)e Ap.DөRƓ>ƴwiĀO[2D8;e?k8ҊKoN6B:D'L}ND*Bg XfiP[TB`N6MCb0. #6KML9sAkg#{,H?BK|꼵 IןVl;5ރǛ&V'fIpu4XR\Zқz7 r},Nub!Y=r<(ݰ%f@Ci A+>GhMZ5~/~gkcO/o⏗ifYq(E](G턯⒉v'xmwb6 2t7JiR&`; KcͻFD69~8so!G=;k"6hkoӄ˃2rЉ~s:Wp)6Jh\gqM +ā%4=?8Z& 6 4\!X>f%WHM 6球i9ZZoDEMO9{^kb܄v@L’Ÿ} q 4R6rA`Lt_saHhWx\BYZ݌[6}6LdXSI2]Yg35&úo&c9U1=4'9We1^bן+5pOخ룰>og5R[_29#H#QAVUMiTוkK\S{ݤ}G%n7ʖ ԈMS%C%R@.+cP%iBWJ7UCWbܛb +.m頞ȯP${r7Y[i5ʖ+%vgAv xzL2wH þ}{:tpȣ~Ӧ{f{mۣN +IWOr?S.GUsTnPE`ŗsD-\ +qt=9.p\z1qjqu{۳9tJsn^w|ݞUҽd04]{RT窏>41&g&^m]ϦDfBɎr)w\+gԁ5>[QҮOg8cɏTsƃ-;ӷ^)ټE|7G+嫫38dB.t>v*߁5AB.ߌ孇"krŖ5'^8gAǐq~d;F\RżXڕ6V[}]*{ߕGAFc.G7m~jgw+5(soGw-PWahx^Wt'd$ȱLȵ]=;sN&Rr>FfA9`Tsp^jRΫO Z*?#vBPjI+5qrHu\תÔԲ5+4tX~5ڣ ++S Rµ6!> YLb[.:wFb)"G,~Vc|_6~E:y۫0/r=H6O4!qL\B0K7(+Yt;(:}ZK ӾWīԀjd,ݲ5.;1 @bs@'g^IJ#eɟa/d:*[R-Wڜ"5i2=>)@Af`l˻#&4 ~ NZ$s ^W,jr``Σj9U)sB *]qWl'x# <ѭn +ʶ1qsIX`""8|t0'q|tTYP+QF4("'vFVp,=9Nrzb _ 5ɻLp/_ YUP7>!M# +`=7шi5iht\] ̜pk'/2]ey? gs?dWP)png4lsG*:t5C$e=`nZkW\CNȋ[[dTM񥙟j(F4_},7}٧kFgI,dIh&`RB%6K +Ilyb$',[i2LO>t#whȣQԢVG-^GMC%3+05زBÐilryn)^h)ɩ 'љ*֠ A%FKU(߁+h6zA[{K-*ukB9$6+ +OL%jFe&;>ȗP-az$>ubu@ʡiRG2 *# +8ix)V:|w=%$w ;7XWx]lh/v2Jȸ|U(Tϫe!?% ?'u3UrٖiAJH/:(@/]YDb s hYͽј䈪b(˻#3.&)1;슜= +^U *=\t;P,Ю!(\Z(8.=Pc Dvہz02_rzbTzK)T0t9nIP+(@r3aj4kT!"Y*8uA LPs^% Q`wf~hԍH@d0`cW+vP e}~ bN$':YBt7QDQCcI!/䉜}PoC ^_b">3;`9NU9=kC_iRa UO +(X5ʰ-p79%-%tl}n3eβ`8/.°:LdpKYF*N}Zĸu"lM@{C۵Gjͱ~(g0|D- ]'`%<)ad3 񴟌 zrX7àsh))icÁ^T(J\o;I]u /3sNO# p 緯<R g + vۉt=AQGM}n:`s(x܇y6;ɱOAs\!t>Uf҂ +ܳl(b:aĸݎt~v [yxx<q(j2$N)39f0-j2Zu&mVAA[MIz xA߯*htS`C.5Pfn$'}s-0wkǎ "h/YP7a蘑Zhi6Ǐ 7[x uHxλuKB^A ] [$9(^|¦(xS/A/}+ۙWZ=dj#~BCwrwYb̦*8n/W?*xޝ/v8u{ Xs1@gK}J4WHU9&̒xf)TR9Pn m2"*hseڴ[$wE`9_^$ʙ,ox{UB*iT{sI4Hv˓+U" a?TaeD >*ln89X5HUvieC;P_znld32zk,[Ok`_9R_JI0:^, `,8# +98a!U6>j@n- k0Z),X7'x\~d$<&ThOMŇ%N[OP෯0haH +1y"5лd<.W_|#?i?dO4f2<8W_wg'Nv:p;g:Eipv#e<0RՙQY/Ca=@g%M +vZ[\# aģo1Ou@TuH>:͹nyw_ eS g )>q+Xl(~EHy!23^2jZL(*A 3?x_*1F8'.3^Vi:O2mt`D 'r =Pj{U~ݱKj",ls{̐v`n95?\fV\B!M`ED4sD r8aŪ }%aF<ydom?+ӄ)^\ԭ'n !rGQ + +=G| +Q) +c-11\T?o.M៨4x\ˆ4Ɠ \%jL80,^²ia)f@̃Y+ 79!͇BאTUe$=`g)`&ڿucE`[_biȍ` +YAA:`4l /nd;z!Ǣ.f(-ʞ1+I~Z Ӿ"{OoůX yq( Af$Oq.R88$J#5e |{ ?ߎ|&_ķ c?]si+, -;w>6M=U2aQ09 !U":Dr9Ϋ1+cZFH \ c + 2f1/3?GtP'$K 5N0Llh{j0J0LΆ Y-",VK! hy!ޅ:RmN*oZ59 i H^=W,aPs2̒$W9|*aV99*mwPt4Lu +endstream endobj 97 0 obj <>stream +cX$ͣ&(_ǂͫuMШ AH{c!4%mDRF}_2 Flhb.E1&Y4eimԺ1 1[M%ȍ#qaJ5ՑS4'P :󘀳A.,AfgUr\o%ҕ¥dG('F (:Yg~̅]$?L<1i%0 _hmNKývbgTEHϡEQta)o >Eѫ+j#Eyp#]P1%t3DȀXސ:ɧX~^ B 0LH UZGD'f$%J}a1)7.yM>yo>bb{C!76ox^Rx-o +m@#aV/P;"bdJ'%*+):XS *)y)H q(U@P68HA%HV0bXFk:П㨏xix"p|+l~˘V֡ qӒdv}`S*i!w-!U*4D\VʀPukF)dD:ws{͔x122 4qr2!# +5eLFn0|B MAULTff{W:J;{́Wt>d)BĿ +4玼6aCR? R_Y1M:[o @%NDҝZ@P]6M9n,xÆq-jtpUǍz,E)^ߠ9}@WŊ"FB-<;ܣ%sb4d" .QM|o :w +P[@+VAܮVVCUV+`3AlFSmWG#OdWN˰ Kд&x54 ɍL4Asp,c;YP[tt %/ƐdFe !=tf +6TD"q'*ȪTzOml̃wE{$t1CmzWD|.%K _L=4A~VsHi)B)=/Lùz$: 0hZwǪ5TYٸ]ySU +`ʏpn4'_ܽ:\rQ"r.b)޸O/yI.x[LrsltX'@mwK4\bEXxIW8t~yAxHG *gGnMQ^lBxb\!+S Ń͡e o>ϓJ 904\|Qvrpy $n]%OGGhcT=e-ta S~f~y` CPJi x /g <~A3aK-9ԲWV0+0`T{(b{,}@hV܈sj6jĢQY> %DJ @ kی^PGLkP; R7l=%B +nB^bHcUL/ ||R>1ՏE9|PkI!zS;B0Y`Y AeH @z,FktV<Qj$we0f!`>Y'o1J{3 PXԝlq(#:7}~fB=t,E#.0<* @dED!M#m{aLj 'u| ߂5H[-D,+؃䵍yMJձEJ/p8~Ӽ=y"r"`53:],+Bw"ޅ%@SfWFHNiHp/T ɍUH>~HۤVBfQ +@Pwo2OXsPgX\.72o +WpPjPtKZ RK2sT|/#:_uB)Y`cbt'8nʊ¿bM'095sT"WB0|f|-%㇟*^)[턴i˰3,Ň8˺[:{񜥘1Pĩ?kj $ hkN4g#?6AR&sgSp!NߺoT{]r@MEm8}#69z*C}h7`tM, Nx;nk@.l(j$[$*HxXgay$. 4 +H &<61A"aY[}oxQV= ]ny&BiV/~C2]E'fXKzV'r~@(:UsH|dVyRNӍx9ůOEPl" cy?W`+{-Uϖ+=Ii~Oi_.=]=?ĻL +!}yMsJ{݉G*fsLDx\D/+]mf?ML/7d.BomCʯ9˥zөJP+}Ș>~fDtN_~IZկE۫_jG>fԿ>N5:l:xp_xokuáẎۦէYGP3vOJGHg pq 8ar0K'z,0ӽM.bB:\϶`o%"m{q6cXh +`CqKZxú ;?n%ׄϯ4IN]ebNK/5qM=?4 +Wߌk gt.Uo<•`x_(?o] +c*UKQm~ZI-bnpeq^u7밭3[-quozWZscw)]ޖ׾}upBt I-{3e OAI8ǔnCȾ M>D9{F-w+=K᳞# |j\^9S +T +G[XH|vu]OowAoyߗK,=cRػu-1BIÅX%u(m{K֓O鸳Zl~h?&Q||'luTۻr +JҶR`Ng ^NdzqTAx ,55y5oyg<,[c-]?mw79{_Ewsmt:/۟PI53eK~\<1{J{F7lӻm{ +}sg+ݗ-1M=\gŧ7o~9d/7pvZ;?lˋQ >x|/T>{ dz}÷f|o;l뻸uS*䎭ؗ־ʳTyR}x ;=Uͳlȭp>vLK2+Cs:疹|Ϳ3u5NNۄʞ|' cXAQbry:Q IDyYV)#c_Zr/ݵߴTH&Svى}˴2dlճF#xP=>ؽ=W62_њKi!}xlކY"9K<0ept8fq;i$3E$y޺SgThGOq j̤*Wz,8=K(c\{뭏5g;W(v%ݕN2130cXOƣ?~<\2 jsvD.p(]ݗ/=G B)Ǎg[+>ҮQAFϟJ;[ޅ/?G엟{w^ annnϩ*&Wo\qo5 +_e iavv3H+~w?ջ/ Q%S}ݽ 7y-e?^VCCE\õ{Q\F+j^?We>5kզ; +׶iν` qmO_7Tҗ9kyHOtfemYTq9 mu{Ql]l=\کg[ܹc~"?IA72ICcEKum4Xȭn9%4䐓G\/4ϓ6 r"qS^++3wxsrt;$s@fYɝl*$v{Nd:vEGmEMⰛh27Btj7g\WrF731C#PkV4FdZ@FB+TSHI}矍9CGBleZh!ZFK Gbǡ) 1[|/֋+,/HIu:rk=I39?;iot̚_1cߝ~s ?4tӉbHH) +Lg升5+VMg~ҵ O.dxXIFp&ʳՐ4XX Xh%0, fITakݥq2ˆ_I"uxzDu;e\佦KX%~WqvG[I{a7ttNzdz!)-HЅ>Wݶ +䁬@4M|nwGy{*TdJ?]BB"t*mV=yB&g> ^FwE"&X=Gz\]^ +LR7Q TX K IfsS*߯59/6V?Y si {%t^}bmG.Y +E/E[lظԼLdt*k/[Y2vs^',,$5)j;' rKҨH/$qYefal-7.40\گS].Iy1٧ƪ,C{A<1+ ]B>ى`7yކOZƁX~t 6=*Ζӎ&g1u}|{6i4xuck||sᙟ$~4 V79#IZ#Y§2[3W$ػTPSc'q"!mBir>+ @{lFat.㖗zvDwEUEk }IeS-O +Aw,\&3uO8Q93_9Ƨ"OZO}g#}WD$wa: +=wڎO^0lՁU.{.ooy#  nC$ V` Wgyu5/\l `@^<ŢJ,|U(Dd[]Y5b O.FU"}#2mDΩn/p7Q z"S9Gnq5j3dIsZ4/a`#IbD!W0Q,MzcA=0>yϡ) je ʉ"1c"X6gjC6 +o +0hCyƋNh=ꤧ/?.aGe:Z(5)/ !fPq.i_V5ipJT M(5vmԣ6n)JB> #& dPi4HD-`5MmqgX1:IKV:Cr#~]$&G=g!W rysV2:  Ĕ:uP͙kT!q*)|CM@GHsMrQȤDtr=4Fldؤ@0VG +r?#>3Z;QBqGԢ +-vSACQ5}/]v2`W2Mͺ>;‡;_I<%Ҿ!^ؙ'Q?9 ,!r6Dsn|TYyw.9Z[O "YAGhﱅSu)bf f)MiGQHp ͤb{A]:8ѤmpRq Hq`|Y޾Y'p9BiFt9G}^dJt/, 1YNjFfj&Op^^kW _,RN(S*Q G/hfF(W*Tu1@L3LT=VnEqƐ1!?^rA"$sd8(,%Dc!nW^ž) Z'ҭI@@p>XYˮw+BTE% Y=,\H#19[Fr@F&_gJnb裁xӔ}lJ}Ad,|vA&$/n[ W  NJMo +6GĈ~UBH{kW=V{ˌ&WeU'%_9oW#o:ˠ2v3b(&;e}4}{~9%%8RYdn(L,68nQhCQ/HnܿS3@ ژDt9(B=!Ͻ"_@Ĝu{9Mm%YM~۬ +6n$nk\a8JBA|m:G^"l/eZVl ++I[MFGel +?*^`.^ JFA}@8K S:*nB4{w=Cj@ËI}eҨ8e|s6V.~酄{Ϯdm?SCC/4E좈${(yz˹N읝I$Cqx0Ic~f%o ܵhthp-]ơٰF:,ҋ`q0o| 'ʰ?T0Ý4dP ;HBb`!ZJLلdGA-1}d-Ur8D0c ʿjܩ۷CD +4<&早̝yLOu1wıbɿv"UA!e"Tb <YGʞ]]XT pG3xY`t_  ]V{>Gz#zŵWP%R9u ذ:8(j#nu }@ 6[%'CE/`/)D6h=>n(5",r%"^ +:6ݬnt@h) C!1ՙ0$,;V:/(O>ލڍ7 +0yYYjܨEW~,i)Nٽ48],~Tc "!:€c"bRcj(FR:D\5-RTNMHR|DԢ sv.j7& +Sb^( CRp<@\H%K"NϲgJnRd!ܽ_~ ǻdLyY*Pf=kRY'JzU˽ gۮmDNk)w O0xs>:f* \`XڝRFT ";#;8vA xw>iSbL)qE沚Av`a72ڎ!eQT% JNNڛяD,ՙCBqSKEA;|2?B9nòQl1BIg6CK0GMI!ֽJKE]$KҲ͋y.(\ᰫSqd3t.?SKV݀⋿c3,rKIfIKzQ=qel7@2+ƋqʟPh 4޼xy)D(S@cA:šL}?Nϭc~0[D"G+ KIŬKto^3ڊ.||,hT<UM${W%[isz@ENp5uLq̀=:=("DuNe&h"L߬٤wElUODౢ\q]| H}L{0| g&RSڍkk5Wy)M;et|_'0؄*!ɪ{98F28t&1V̡P-ap TRA`Gt T-pq wn1W܂DA.\VxKt,"Jk.2Q6R`k#@A@cA1xg +grf6 aZ(ƱG$(^9Ś

<49=.d= yuN_;U?sEDz>Bϰ2BQ*w0olDvmKl5%B͚q[Iq]a2 ^)}XffkLvHG(eVaBm%/=ij3+R`GC8 C;&pKA-|π㿎zTcBvn.Df)uOZzb*59Z W*GN_Gȿ1oKxCX 5o}O([z|p$+G6VʼOp!S~`I1Gn3 1!d%1Y2P1B0U &*Ҍ"J3r 5m3EaV_Qx@c|T*EE ֺ4(Nm7` ưΠG &sD~p(s(>152}GaSk}g:nQ&@ۑfZ K-3۸cC6I .g"#m Ha½9;07R|+%o\Z-BOz6܃@9 FL4oC(s"XY.n8i]^fn VLL@@ޤ\}$#!'ޡs5%aXH٬fR?#N}*Hڇ8tb\e#ENe0e'+Px<8=gfrgv>yŚ<ÃEH;u:(ōBG$ւl[Lge'1hSr9*Ǡߴ(!%L*#*vRDB ւ +H*!ig~HIO#@D|= +wpEH=%@_VԡQzؿ$]T|Sz&߬[+{@# fUC !&:qiHig`FUdC-Eb"4 q)$ tn5 b +4%M{,r7rQ/٣,῝O>z$HRm+`)Y174 :[MjtGċ^H"RD'3!rŎelX\Fw껢D 8z^go%WLbpꏴg5 +u}H@KEjq ך2;Ea )@1/ALlI {{m'fO3<q7u[~ԀV 7\~ Iʮ 6,0*"9aqYfޖ:qo<ÂO:{1lgN݂dzӛ|?C!l +XRhp`, B+2`wFFn\cJ7*,4.E7~ɩ}} A Bj'>YLv_Mr=xgӟ 0{˒^ T˘O#fVykIg9TI;h8> ܳ1K [o_ [IwrT΄1b m66P5ΌѶJ=`ַY;a0:Ŋ:9<(xb?WLdG!Vh&1J ({3/ʫ۬[HbB6X>@)FGȋuUxm1zB䩙q>I=)>n"3HV +daV)"$<]R]>C߀?HX$[X |/sQ~\y*Obwfvedq&$:ng'Iݶ ʩx4ʹ#~o6|x t-"YȤ ݅܋볛N{' +J•Ո^'/ҙZr,qJJmԓܑ{؊xaNnrhpNgɢ-RqL7xXHz25ݳworԾb}ZaX}9,*[ϼpg+:#T,ս<:{sv,ď_Fc[|^ׅ;-{g/[nȯcogF))9żw RrROwcUX+هr?{I5m9܅oڷg޺ZoZ)%rpaPGzvݪ@?8XsuL33K̟K7 +5klQ{ +,kE'[mPs}Ō+_K1$W ~mof?S7d^o4>/^㧇T-IgQHϼ4q}mfqO$ܠ;;U^%<ɧ/8XSOp,& +/ sY>}Zܷ;W5Zq''t蛵 +p(nRVNFb5*A!LJ'RZ.7ٛ pzB,`ɇWKQ4;vOH۳8ʝ*1_̽VJWW\dz=lv;~}t3UrxGdwkܞ~ܟUFsB0J۲=Fwn4no|g0(6㹩[z<\˧שs`8:.]Y/ݕ.Hމ"žN/A2ADj<.vTV·׊UtcAOag&w WOi(guضʧ&NU1skHu.l9-yH^$H*, a8^ͫU A%v,tYQ/J_uǣkSu6-'@/ +|>^cG ?UX3CWpT6s ͏d&9X$r /N6&2mU뿦o{pNO+#{bA H< kɓ(>Cjyty;|gK +u~倔iRPۖxi>QiOm}d}N]_^]t5]_9YJe]w;qvu,׳EUCz8>K9K6</k7(MøW/`=%U%NL#Ԝ^=f5^VDzES P̄3KV9?_R+rDj^AnDyعYl\[۳I%Diyb%avEU;Z*ke]2v^LnX4+f,_U?kե<|޷U_Jl=ཅDҀjєZ5jWKd,ia '˽LZB~ǃudiF&{qZ>憅sppoSeDRwFZC,^x`1-{0l `lh1kfBVWz=O' +EnӋPTQF< F` ghO׵״sbi~yll;mmj6,kX r݉Aоy3 :+ͳ+=RbOh8t~#eý |^ku@Â˞d+\~vm/02)oq.'Dgݎ|tU]MYI|>_|=T ~cZ`4Jl^gxH꺈}.08Vc +]S /f*S#Jݖ?ﯟH٢GW'Z !cCEwDtq*08#5tUKs_ 7H,?fHM1A:4r)^Y#S3ѱ6WCˢ< X@Ka$,4dxN'ϗ'Ჸ'Q]_JOQz}AͲ8*ᬱ֩G?8(?8(O’^Yfl(Qy43HǨcݫ ڷ&pNkcЋAآrIV9łTJ|ݣm)֍V<,[9'a'TݔwREjՏ>zW "{sxkZ^Zr#nSſVEGjh6?t^uZtҳT%7a^zN[טy>=8ϭ_`OF+AL"ֽZ:Ȝoz9\4^YidKYIMp榇M{ +Fڛ<]W8JOKRdLͪ-De1u޹s;2mo޿9Uٸ:;S3K/_H9cw}c'nJO$/wDU?)5&[[5`ǓU8TF6(ҕ[+w&SQ?s*LE$8(Sqk.)=QI$=ѹ?#0Jp򟩚ښSGq#a!]N{qZ F+J^azw=CI}fWwlØT>Bn-]~쀝S7;b1rkȁ˗[NzE/vI-c޼tjڡ/|jaϟ"s/:Ykvr BW06O&#YOŋ5 I`W~T%%E 4iE99~VC{`eݮwPXlz Q9#JRy wv@DcrkcAd"Q#ޓB$S{~lFL<Пrn|m?,1Wߑ!sGԠ7g-h5kBuLdḓկ.2vF(vU'.,NaNmTbq'kYلtꊕ--䵨s!kJ(AXʁywejׄuc8u0`Ix*ʯ8^DP([y(쀐CRNw3]緦nCS1}2och& 49GJq`s`_KX\nsLO 죂J8е[GtqO:}װ_Qڐ@:lYuR/txs\ 1Ŀջ!D~O{-?[ٻ{uȏkְwrXkr‰-cW}pŇ$}+Rκpr`#0lXx`17LSu1F,N+W5`#jA+t5hYoRF`ۇ &@]}&7O"vas4EXl +J|PNDH(橻mq$O[sbmA++!# lw=ſ4ua*γ^o #] ftR2E~ڷ%>t9J vjkBÛ / ÓlIӈ'-F#p"5qquU6RTg{ݬm.B Uܜ"cGlBYP™>4e g 9Vk:l$㥣&1qXR58Np`Y_Ls!+_ / /t{bkw1ƁNσ ?vGltPLۄe\ێᔍBB ;hbX;vۚ #>oڨVXhkكd<ҋ8ܻ/zQX }ǤQ>cɒqq(aF'`[*upFd99-z-W+9K@t4; eEX-΋|/ +(@A GXMB܌P_?L[lv=V؞  ` +8@R2mn +T4`\ +LR'u):XeKwx#vz]:5X=gnjaos\3DkR0钢r^b&۾ڒ8\pṅj +[b38\(`/SbF[,_ѠCo+@' K1h@fy}ԝ`?`=d +;>j +%j+Fy@a7uFCwA=sz{bǷ>= EmVS|ȘN7ulHUs _`Lt{(&hF^CY)Z6Q7/}fy@3?[R'C1iE.m6Xƈ谔 ;4,@6մcx9/1~Srq# q"Yc*M7Qu qC?6` #(cvi("ƹ`H;3z H>Z,1e2h̼vj.>b1՗a|K sI߀Y@P_w +jzF_c#B DQYj"G]@⋆3`1"dQ0YSB!8 4^= 8/<;px=.%lՔE\D4%:ٺC7o-O!7|a]}GhjR]Hƙb:9!*vS;ӕ (50p 硝Ǽz= (ix0l:]|6fsy{ +y-y!2tZM^"t1 5W"z(PErguOKtY"%y :1ǘ5bx-BayԱY\Jcxn1 r.94}0]r$ _L:!#W|9j#Gr.89i5C +Ikb{b5&;O-Dq<ٮ {WXwJ[x"kVc0\qtEч:aGJktoHhC(RlI?a L( ߡHQ$@k ]e}QT:8 nm@lDd#E\ sƑ]d< 7QMR1ƄfjnADx3E,X^jԯ¦>HwvisZD +f傧{ 8ZSpdP!Q5, @|n!=R:iTym)iVFc(')Ȟ: C/8S_;Y@/x~o:ǫ;Il5Ivڑf3&" )!bU&Fna +4NMHXEjm`C8a<:=\%Wft5zk;/$R$ؒk`UzՅϙߋK|#9bXN3kI>|M]$mr5MPmbNYrpӴK SHo&nc5Fm|XFa`. t@F3Gr{v|l.6Ǐ9^U;T{xRn=baA0de33fXsK]Y+X29'FҮ9P؏Zu]o_X߁̱w ++ c HW5Ć'<I$l5lfdG1ERӈFR< 5DbF)u +pTY[5_ŤեҋJ4BQOF|!0ZW3 e !pEaLY}bQ|bȁOJU +n`^FkֈBlr'tNw[J՘ORĚaz :M6o;eWZ^>)2_I}(E@v#{EhW]D'b^'"E"pHh:D{E`/E͒E@Ѩ8a;褶I o].]8 mA.@"W  d‰@'Œw5|iV!Jx]B?bw$BȽ,tfon>Xa Ro#U#by}51!sᯔ8ꖺj+p4犓{@}) +T]mtz2qSKawI({7PDV u./h3/h!jFo1f|-oLzDA V[wF0zQ< $cz\$,:ꢔ>"VJe@͆T},)\y\&KQf))gpm8e7X*?pQy 7<4DN3FVEa>"JFȚo{ aO +-nkx‘$Te_ JcR1;Hڔcak0KŲKhNb~5fX~Ca#6Y2=4&뒋l^׎ʆb>l'@,F> +* +P0~T&Nڐ]fbcdںXDCb'T -(`Ib,%"&,+\%)Cʌ Q3ZO$ Vu=:QM0Xs+sELGQ4Jњ:#lT$B 9qye50y6@ZyOw-/ޱEOuFnCVpJ *.bÑY&J;A2Y14B4)\lVK:7kHR[2bn R# sTDW7\8uR +lKBiw_:9o&u7I͵ +8TZCيg*:ȲG4_ٛ>Gĩ@y,<:zN9vE Y7uꇟhQ#(e%ZX ekU:aC”JudjAO[QM[jk LcV.BldpY6'ntk¢Ji| c|yjVp^ ߈,TT#+6Dzb$Gm[xff@%*.aձg7s<}x߼+m-UbozooC$k@O +-&>j5dR!n~,}W^=^`imz#a#}#v6ϕN1C?siP{⻦H:YHNLNNW)Onu:cֶԧ3wlM‰J(0"#;60cFJҢE/52 zln6Iu0Y"aҭ&ujOsIY'ṫe'(ﱉIT6QD@4`~>:i`jz!{nڂK[!a +lq!3O#!o-3C<ɒrqU 4'ڛ1h J$_rgK[6tyKx,qFWۅ$<,9Fj7X'i$V1j V59sE*IC@ ˚dfݰ" 896-P){H^e2 J(W !#D> *#, !=2LrfSJ`i,R!&k<+:[X&/*xԃظii_]ɨK Қ[է66S&T|G8 w[ܟr /߸B\Ysb-Ϋܛ2|aG;}J%p**QxѳzC~jNn-iT;)kCl:{J03gbc!Xq^_fׁ;s )M~VEXy9&o䦐i,I XYO#Qj|9٭O>2Ffzh/^Ms~i_R6JwM#)G? +/gHGdT@! w +$)I)9`RB=5{]No1-")3+\ בi7 +#h)n;ƅw-ujz@~I4_9xd`فM3 +w,I]N<;O~mBă5N<}|7vɇkL .^(kԫu͖|EMDl&ynZͪOI2c^~DJfz@Uqc J]sRV4WߚAԉbC Qi:JpT>#{2Qs֒ph6/Pq&G)ԡ/@k1f8f;%Vb8WH0ǐӝc]fʍxȕ"#΋%FGA=xU @ydnj  _W +Vs|f-x%w`s]`E5"S_KS>U񘮜![֛pz][qR@|5, 7#fGT)Y}y"/@?,b\$Aa+G"Dv)4փ'Nrljx$d\:li KIuB?GM_ȃFI+V/ *`)ʰgB QRJYHL]GBo5bڼƗ_{ҜIIΑ]9}'}T0yIҞ}T&85dU)~<薐 x  #GZV+ÕBDe{56Bq6wUٰcL5Zwɗ~bo^cG+jyucMlmB!0< ůsEGƲ邤~d8\|OZ۬y n#K|^[qVlt O{.ϟ{ayЗ.]YPӜ‰+ o3/ Vs^!ho3۬g:m[#غ&,_Nwj#5 1X!*Kd`tppPGlfLPU^ C2vAߊnz;f h+{FȁfD#2+!*'{;R=L^8P_YAY܁+K*f% w%osW&TɂMPl.]=ǣe|';J_^FiNvyv%;d%`{y?m ݓ܄ yX<(b0d +VELe'#h +|O]]A؋Ps CF R"D箖hvݘ,Y"]0GZw\w;^B,eJi)u + 1_8P^ׇGȿWO6lbX̛PLSI b{IE&`S ZoIn" D=uL:IdTג=8V mĉ/i*=Z I66C +S;fZcKBbI2*,n*J=]1Eo9rLjk℄enx)¥v e!c~?puujruT[:HW!)_6a)5ϟ(V8.3'Ѯњ +=YГ%V ]5%]I >ws +}'1w7ZkWg/fͅ>1؝~6WNcA_ |=wsZ'e:H `U%yZңO.ŭmK ," [ ܦ|Ys^«aE׊ӨhpCO[1.]fal,F|1{gkF/N~< ȁzǏH +TZL立6xїNj,{$= d/{ekԽ֢a%v+į04.zM}:qr}Ir-:e"\[]//7^&~"]k/YN^g&pqtrǣgž`]*k %o^,}\3gkB,}U%-f>/ &T__Ed03Fǟ51⮻#(y].I`'u7ϝX&^]?N)UZ$7;qc9ۓu\Zea +aGp5sg8iJ:͆n5PX5(pUYz!.FO wϦh?2V谒>('K&.䡖 cPyg+R.>\mpѵZ1S)K%R\\3<{j:n82"<`rJ" FUfwVx-$]qa}X /E&d·{}"HY[;=y~>FyYsB^fs>V@<"ZNyߜ@2EL{/.( ;s^ո'x#,~~R$I:q7B7,ux 1oP4,߇I]nv~wMjv\xf֗ioƛJ'|=g jhJQwuavރ{Xqk'# n)(LZT&Fn;C_Rg9u.kKKq?帼 (m7m>޶z_.Tޱ e=xHOkˠ:9. W=` + ~9KKsn۲+-K˷>7LaC_q bUV>[nK_ԽBT!&-Y%߫><`F/^h?wɝ==^p m4J~5J+y{ ?^kNa)B|{i$TI~"Cw.$E>"I޻"M^>Yc$>?{*^ +\z&A]EdF(լEӎk=λF7jϷ89Ny{6q9;<E{7ӏ24/iq:ub orP\PĖ?cz~SY{@*u_XsO?a&Rp,G[G $gP{NO?iܼϚ8N3u[ήO~sl~K17+!`ڒpYs0<:8jmbd|2O{e?֪㮼"n#7@zDŽeape: (@.Jn-Jbn6^[QlEJ{ʾ*0EPcuF("ԗ@{?~Cs߈eũnvߜ$9xIҠ/'lb -t4כs_]?ث)ͥo\r{Z6,-&2^6}TFnfY#oX?;9k]OǪ` +que)өy,lj;Mg Qc]&zeI?; + \Ϣ\+.BlMmOJyK:|[]"T%ڧ%_Zct݃+u$B{7cJDktéy#IsXЪo;z*+P =$N+ N%^‰esMRu_nu4bS(mD%Ql^׆ 7쌬lOfZmNݛl}y|sЮ1_wK7o"j+6mcq8/B0t̋6U 뵡P Bt!X2oqn֙io4d+9@ t/!P '@KSDmfB*pJp^ytxr;*fo mk͡Gk;)a(1mt"g8a:0o洛C& wJN`o@1攤/]_\MZTckm-WV66fN_,h19iPC7GE-Ah0Sdw0 l}&WձL+}0f=M^biL %t| W6;Z7tj<)x4P={XJIuS[s"0mDY{5F@SǭG1uE`owr6 0uQ¬Re83!n6Xh7"9F5t+y#jobxf øVIC5 ^&S37cah +@$% +fL?uOYݸp4{}aBcP).p:`˕tzIfmqHK! +5τM Ğ@0tKwl|vbFַXMt^M Ϫ S%D4w./C,}:IBIU܁qLC۫KC_,jJhN.TqI ׏锲G'y`!}!)ʓH{V]ER096s9mNk}o]oĹX"9"R٩qA3{ +bB>Ӝ{Ffc_T3Q<ipT5^]Sv%sjlp:bBhyV@q +ןpq ,wů=NU[ ; +ir*_Yݫűwi-X,b7"Xz +P񔲯.,W+ca쒅B[*%8$ {*Qp_sE(Kzlz0O8cx]_Xt'BQVc/7yӔsA~yC6$BhmϘG`-lHܟ%Oُ,C,2X9dSKÃ-2CHNKn$\iڜH6H +LaߞX 99s|Ml$؛MFz7Xt=Vz"U-&i5mg6R=B"7q5td'uQQ╾O\=ڪ\ܓA6b{K&٧QaW.lFC~ve i@Y.GmOOlj2l]CW6tͭ|X39yXJQRG!n28yvwNj]<9BPhu5LZr h7hu]@’KR>mOQ ? }*B#^Uxu*^@t/HmC@jC'dMsHS"<˓a-ǘ#( a$љ(Dҹ 2O +P0/t119`-JqDn"[BĮ9.3ŋBeUO} YEQoIl-fP̱}fc;˛c+i& b`s%mo g) fhE<D%< xd#gV*:z? ++ܜZVy~SyHPr_T/)d959U]+ńyN Rd"|+ ;naipLGpެ]*# 6` ^FhR 5}+ZfP +FJW4b9ݝ,P)vЈ=N@˜ȧY׿~cnq5bF'pddK L Q'Gᖗ*J|R!(49m\a/fh= PJB!/c&M|BKzja߮XB#'t:U׉^$R{zjrQY) n_O.B7Lꩧ@/A +x]@3)D 8ŷx=9͂0jIkQE췽{Jy ,`^0ˡ4uz +j53]2k4 Tb UV7MRܕgbfwjB=YWth5Y 2_b?LkW?ڻ gi~SO,U,+㜇˲mzdkC"BD*Scs9do($кR8YRT%f9JE@-ش7bHQZMv%Q2E5@llv̭1[1$@e?ZYE@ +9ȗutف@# 1 UI\m +A_{xZgqmCRxhI4Y͜A'FRCLq %ff4Oa~tsze4k=Εh-LϜ1Ѐ19k4MG w7y *C@d{'!_$1m +) egr`0[dw +~XRP5oVtG.UU֓gFoJn9'/m+~8|Uuu~0m'OQ P" w4xv!|8#yaPPQAeH{)N|9#biaG9ve&qEYU^ ~J0a:!XV- O' V;ө.B2*6hۼ0j 4d>yk^/\nYC izf/l`7>Lfx0Nm22.g5~6RR'yf S +l{E=rQL,AX(y&~GCDX}f6513P}lCm&slt@%d[@9BbrYpEyH=,Cųc'mabNmySq-ɶ$ ,uF F$C%V(EL(/pi" ͫ:v,d#0AR]_VItBI\v?+zMZJjC<:@681D2ysE=(ܜ9fN|XAY"z"VEU5rNZ 0Z!|J̢tyK}-s`0}[oMx*}xG +4' yB.1t겜ʄQ=8b)$g8aLcq9©4pK)\ߝ ?<$XL)ݽ Mq<_e+e_%v3?>Mޫ[3PuPEJCY ?iCGcKd +u!~VB4+lz!3ۂIА-! X)_Ľ@sQL= ` aufZgr^54FY.W+*/ b#r6bkQSGu~sɅZ>:}ߊx껅CiZ%6e.Mz4Gq%r$^V=; =4hPN2TTe]y1埝yʚm˕ڮ=K[r>M}v4|nɂdfnQ{",廖a18ga`u)b,ù:_]uz&c +:(/*x"Ծܙ3JE1]Z8kK( 'm0^G1HzJ!SYGm`h67&x7 Dhv]^fSkZ|`a=l +\nU(Y7[趈fNJ7 Z D3,P-zdzYU. ?+6uo m T2#:{e9D0aJ-s)9R8"McWq|9",و%tH t<tH`}@-ret40VSej+KwN@osHc_k$%L;X{]A +?X8\äZ(5xY=Eԕ%3P;+]laU4W:0 +wWhK0gq1vgT/1|*dM$yX1{ x.;#"Jޔ[0~(C-Fލ2\vY+mSFo s +REb7[\~IF)sɶ/n4(Xx;ٶ/II|\<XXI,I\,r}JK'~X@DŇ.?/GTPY'`!q +**&eT86VeKsH0,~0]&=4Op,QiM+&=}1'##ȣߎb2BTci?Ȳۃ48Gd-VbI6ǍEm&?QlHs[j2Cv9^թ\2u$ȹ[U&wM㐤QqHa]7ξq̔}?/rLAS vd}{{sJ1 @o +Jw8@B ecĤѻO[aUvݬ'_RDV {c[ʃSF5YʞK<MIomﱺϹ/ j,:^=A%X+!t"󃈙T/6?(%SD7Rb7Μ75e1qⲇS]MS~p8!k.,?W;j +82lZH:GE&4Ni)ۺ7wD1`q@|ln4.7HSqY]Y)4+S(XhRJܰ +m!7Dup%e8 7OSG"* \kc+'JN̡d]oCU +nq +9P,f8\-|Zr0[3v1X$fxidYrݼʁ= AU/ w8DSFX\E-C9awJ+TMgh?Ѡbc L5e{ltTF)^sjFΔ.~JR-,aڊac#>gۍPO GꝏyCqbr3zleQȤf_~/z0Gwa-1,+:& 1,2g+FQѡQY,3SަlN˕/h"nQQ-$*ݣ +lv*TJ=C%۔xIK8fL=>#om(qTՅl\Mŕ }g`ފиbQ߼Ȍ%#a ]IFuJdL kFwe&e*KT6e2%l;f\ \eqbXzh*2&@,%`B̬NJ-Vˆph慘h?1[axU[VWxOjHrZQVR%*Uy[Qʎ;KKm`$+iY_ZFoE.X/-EE?5t3)#41Q"r/'qBM)M^1Fek`bszH{}ه0HXvrN`5ɳPQ~Uklݡ] +Ki|To +]Oy;+.c1o +]7*tyؓńZ40t.+9" 4XS]#ȦHTߏ9LB0Kހ=HDmb+>x/:)Hb#ж/Ҿ 3݋<X{Tfz xoL~-.M?N ;Q|3UhRk1\bЏfe= ++3ga4R6q{0Ucn$ȇ=Mme` MMYL" +FCT߿Y +[e,6wܷҘٺ"jl*ͦ{BdS9 Xr©W +fجڎ M?{Ȗ)!C{ec2n|ǫ6bfq͜MeUH?bs:D0B{o;ګw}ܳ=8ۜ*1:NfXh@sŸuQFٍ)Oc4^"l*\iƒQqxt``fOWcu$^V8:NU`zx\[ +qI5/S B[\!%@Ly>1k9FVK#:3M:PP:8fLk,ҷ +X+}];6/qnugQy + f=W7V09|Es%jAmթAc>,g'eb,owfX)J$9uɀvͶGO[g +X枎џ,E⾸Xw;'8ܭDg=&E$:\FlmGjNs~eoHxQ 'Gp~󋀯կO'Ia3QۿKd-m-]'<:8ӞE9ogY:/Ы5uhg&ƒ#utOؙkwt@]NUQ]rp#-)XTnSK?Bz&vOheS.lRSS#Z- +~C5Xwcu&Iڒ(ͳ?˘gqJ7UW +'fvl-X㫱@:w1vga3%1;w0 Ȣ(ۚ07 YKjsmz[eؔ-#'.gltղE5޹1>$LMrS? +O?_P;u?IbtL]sX"u#.=Jti'O)z Vi]{꬘ ڱŏ0}0P<؜'!9iEfw`Cih4&|br@'|L1P]z +R6,ME,@KIH|}ĩBJ=tV*Pwx.a!zQq~CTc|d$Cfy#աׇwvZ]iF6u~K)v,lTLX2YILO 9t?# Dd<:8@:)({۩ 1YYB`Y]*@cf8S'~TE"P̄&%BP06,)[JI]PoC/N#ǬU(sOIU;E$˧usޱNQ-sΦHS4V~s;._=L7^ē&toGm $Rr,x*A!r~.gej"]h"-HZU.þ_ڂYvz睖-mҩp~NH;CC#ȸ/N8ò; t8QJdo=Ғ]G]?.?:]z|JwӏR7OwCE/TLT2q,R(N\O ݃序?/O oĄ1kY\`}ҍM"Z.5 ɬ#ZRX<1zs؇c鎧{|a}~w>f&٫Kb,=M:B4?gw[44cNn %;HۺT(\ڧbﺌ&%ѐ6Ö˽,uu@T!y ѣ| + T+v)4ޮ:-b59c~Znܨݿ>gKegEn/'kvHi5X`'3?y/u-;⼗LdA!uup#'v9 +|_|Y\0\̋ŲӖ9°;;s=0re~wNWmW3cׅqr98Z%9"_a8$bNdqF]Ϊ;Һ +$om{= +c`-<lgEnޜ X)۹SKK־:J2)3a4҇ډ曏G>GY` t^Ʉlp{'fj=@,1}c +h=ʴ=}hQ㏇,zdV_}ȹbϝ!x"#fcARB~ t9f#H^B;%%lb:ډ|=V842#MW>G~iq}FK˻fgWpS T]1(~jiF<`:V/z{Btbm> 5tkiS˳dNuMet/UQ/dp}7lSvG%ښeÇN/Ŗ +̃EqV7:Zx"[J"9*F'S#L +jG4zH)\}&v_x :ItPrhUOfbpzw^xƍX.p63^I듨h}eO=gu'guil(_n+Fѫu꺼,9H)t oJm?YD7xС7:nzꔽ^ 74?Q&G9],L˦"Gh=m:xW򡐛wkr+9cZ;u[Ew}Zw׻#Z]b?lYV[I+*9RVKB 69lBs]GtB7o$s3oiD(oX|Db]"oH mBn'+]Opjx|C)adk-t?qk! f*cK 0% +@]hreM,]L)f7Azf:nZyE=yv{ +F/M~jv? `Tg9cS@":Ns4Ç뗳e!U,TFLf\+a٭ӥ68nrwb+>딂{wژ&00#&G*JE?|< ZFrs%oB'78#_9񡾯oNoL_ݍވ;ʜdJj\g+|T#;{|7jBI/tsrs~0SR=!׵77ږͅ}iOm+K:WF[SۯDȓ]nzx|3{ҟ6=*Ly46MC +ְ4"Fk4-yoU,Ǜ 1j81UmbJԦWaE7[_߼9餗ǃo׈7Ko-_i,]5^z! .mebRcz[MJVǮl?զL\~!hTݎqhϿ}q㑍pom3 o)  ̡=ǡCOLsN>]^l!B#Wi7pT|RY d:? ^h^z7E= q %ơI؈Lf =H-3zm/Vg̞dZu f~Nh>YJ8C ;.> + BP/L!%9B[  c|yUX Vlb\$0SRVlGp#pS%$<㬩f|GFԸeRPi !&f4m(t"KB^zʗA\D2S$K !QFD%4;WF8Ǜw! !n +fF] l`@^|ˈt~n" LL:Z"sr5h 6ٙl ^BG ̙Ju$ܕA"3ENz%MuL"Djj~_{+L<+a%Ʉ0rk\O0➷ ++_-$ +'NEw}.̓0W\.f^p.h]D,Z;]rAx3 +,#CkfX(Q\QQG9B=ze4#CPTDBYʧ=&$Wai2FxV":+m/8 G]h.^aW9dIg%.Qbu!8Xű( Y&ARg +1,iA+pTg=Oj;F a$_*!KE1In ePYa6 *̳){Q(TϾ +r}..!:؏#HU0QQN 0YWq߅*xgc +7PnEd)1HEtGkS@撩 -ajLoό[0=WqU09Y`\y\"x9bI,_OR2=/+Cu_'+Ƿ$ +atțALoй0e+S@&B)M4JQͼ=HQ3c>YvR(h)܍xU&Վ#,*d4h@~G\q̔ }먄7=20 sLE%0sIyHqnyT­W%tqF[+*!MXbYTvؿQ {RF OY.O? k7<jɆ} +N%!N6ʪ 2ݡW=nܾŕS,D4N;BZ=h@x0 5GCAk;5^%3-e#3v+e&UI=*)${UKaeT^~A},P$ؠ;!H4B'( sPr!V~a~ːh BuHޘV`Z^Lc :)II Qq^!~(?Mj1`p%!~`ҔX~.+AUJ$xTǑX`lPD)`Z8, MpU _[)Vr 㢼Q$ǡ'aCr|< oI:Kz2KkZGY<9({ښOyqW7Q9`7t +(. Ts 5Bx=/:Wg24 +[[yP M6s2TP@Se&'mV_*ekqZH[ȏm &L)p«nf +:P> *4:\D~<$a9ɴÉi*5_#_?̄VA3@GURhaPr"uԯTT,lp"͓zCڐ>N$$/$H*DŤ%l; 6xהo XXM:R_ ޤ14d2x~-Gs;yָ9hr+xҷ9?I_u'˭F{3$Hn<>UVF‚VgNf6|B[hRS@slZBuPTH(bĎ ]^+ L8m\;yLΎL@Jha4PPY[],Y@ ߱VAѠ jeU \ ^b9A*SkE%J79scc^՛rJmi]QQmCpX2ɛ3Rr 8=ga[D;~2CUWOkP Ϳ"Y9($VD)Ԃ:ArjI+YH%ƬG}#w),"*D{>EsA$ܜ~T*ᶨPpDx[UIFyh&NG.ZӑiY7ʩ~^'(X7D@k-2LK}OK _ G ulZ-/vmo[jvr}f7ܷqP?2]Fex}x+L׋RW XON/M iQ2+5~8vPRʴ] UR'gʷx4 \qL@\Nuc +OuM*+~qL n_H?t նfI^Y o$g7uy sv-<9%)4 +| #H}nHB- I^0ʲdFK}}/r +^n uR,HwE(زb~*ϒ1 F؜-%(c Y-Yv6wJ =3-%,b ̘#MKTP}L䶒{9o@3JP4'LTj/yBZcCk!6hKVx1Ձv^|X&P In"A12S eZelYaNSI`:2#P&8ZZ-j戻9RR7 ˳eyN7+}۴!Z4j%Ûuw} cutq8γ__H7оnRo{|[UTI7凣_F['ǷR̅2ܐXHy "le2aƧ́o+vbJ@XO!lqtܰcdDP!E: vLJ'Ϩ|ؾ5S~=bTWd{M3I"_U׺-"]_iI3*[W*HFګ,CGaS@&& AΜ/go߫D=W]|?Dq7 S@0HN!P1pvU44 +JA_Oq[ 'R.q*$$ /I"5I˞)֠fq7Fk,BV0],MWU7KPE*,qcmdn.U߬h߳JrBU ^FR]Q AdôzweIlPz XV4 qM +27⤂FzT=NII=/'l7/ZZ K{c @Z,ZdWt2`4uΒzwb:dMLwtVMl&]Ka)vsb<%OHrf΁۾T,T%ZBr4^rqVr8=E]{NҫVk67fC?[qVh9ӳS{ $i f+~ GmOD7 @o.k@LҘ:ɠ)08j!cE P-7mDM:S9 o$LHW[fʤn7+qj&E~3Њ[<"V|( U<B,NhNƏգ[v,)$SX+A0]h{5Yupith)9KCt0 $?, =>`vܻ-gn)RaƮ*#Tֺ[Ϻ!QՑP q@A4K,e_]Jeg!Κ'` ל _9i""6ZXv|qܭV>ѥ4\uLL 't<J `Ř_As+pIذ?hiz8\. nb@e{JB_jrVZ |x,SW!rGZuD^IM4:X &^ +렷>NuHvMF˺"~,x>|TW*ⲫ<IY +NP6QxD,Xcʦ3$OawEt>v#!Ht:ֆAJ] )NOZYk cM*n6X{S S[Ɗ"-#ٰ1cŌ!:qĴ?B%`h(c㩧Frh"=jwF!(S HՖ1R"MSFAᙠcx F%ɪNZtfY>bԲ:XLձxw14QK0 MbB=*Ҧ +}K~;fu&7\3h23wkU>. ꫘G3N*ˈ܏j)n]V~*Uq{@k\ÙVX(4x4G"z{J0>`׳^*Iʧr|V'`/ T"cf + kCwﶄ`pl>ݢu[xXr#r-OBit"\Ymg%{{+-pݯP"\ KKi:b7;B/Myxup7k?T%[Jy<*$»A@Y Hu#nV2 +Ǎu>DJMc4yLLyBL +H]Eh!3sG1l{Ù1( +\ /Xf1,uJZ,naZ^$/<-E(6P&v0JXrTx~S1^.S(߯=v na3S`2 CR}߭.Ce bP zw>uz4LFh'@-+7SAu֘%C/VL06ƿ'Fz8W~.#4e3cTD3iTv_<3"O)nJ!ٯ:(f4Q$:PmN+~?Wvhd1{kTGF{ڈ'ʌHō!eL>z'`/Eo-ӳU \Q94G+ +ONwH,zoޅ-3gC,-%C?j#Okz6aD_)1|3P덍xQ"dn*xj. Q +Nx 2o|jHgqAki(32#b'H@ա}(q%Vj>fj]``/f9,D TtywoNiV:wJUiż55t>(Lx ,SF0D" ~v7cLCx%nld̼}'RBϏvFW,W#=*u:=iB +*KDşR_d7 SSY&gek+g vI*:ʔ si<ò; x֦+vFv{n-ov1HU{wy&nI7 's UCߺL'{'Z?_ok(;m?Şgޡm`-Yjt.̫]!o 'e}.%{罳l-MEcJc|~aoZG,}:/j%FʜsW-rэ[u4/m]X;_׻v0;Mŗ6RϷM4jkXe^!y<|9p2oO&F-/<'G1Q?k<~.JK=X|R֏Su^GI:ŤL]T1{!4nSwqw\K +K0-ߒQ#qFY},+fعZ+% ^%[MD_LY*r,M.d=q1x{_bwYg{3oQ؝jsy{?]X;d^*gT䨓MBa{펼q#J|en 1ӊ/c{4?6DzyI׈6RKؙ  [I)؉; 鱳{Y- ba#l~0v}I@^/yvdL'`~Y TZN1Yµ$S@9v ObKI C}ӥK[DK +ϻSkVס=<栞m&418E}GV3?eR6UbFe ͤJOpv=iCl_!| ׺HJLId[)=L,+D"=ܼOj4{kh lƫX^dYNsw?1?37OR2wR1{ L)=bO&|P њj~2 +CgzD;ڄaWk KMμ=^!EAZyt +{jyr ߭ ,04ȷ$*tUrw`"R.,?*$K,$1]n8տW0FKkE+bw4[xĖ8^3#c~*vn-bR`m#1;?u[ĕ6,HJDn "i g#M7ǘEo!u}ma:/LSq*KAA%'#28,i=<5$3e&""b.:ڢdQ4@GeӴ~)5$nP X] "gm=$\Iuu +7gp-ziQRK1_9Og rfu9שVB#4Y +Z]:%N3i#q]=/DD)i?/Tg,H6":6G'Fڿa" 7 ' -uHZM؈9p&DXUfuZ% %m ,u tIZV*'=൏;,q-O2.O. f<;!W!n~e脱R␚F j`^Pw$DT:ӗKb+_99BSm@ˊZ,r#v&EgVa\縢%Z7]wK|‡m|p8';Ŷg!#TZ|`\ [^ 6VJ/5yb-VhD-a )cA ˌU !IHICNi~``"Pw/fZgclƱ' <4 +'Sܐ6eyz#<.`O4,h!1>{]ϡƞGjRޮ,Dke9X:.z@jyOk.uHI$AL'nJ4euF.43a +b85_ Տ138E[C9*&*kAi}8p)9,Ⱦ&<>S98r KFܚ_Rյ|ARo;%M$=ElJP8;85_.sX䉮/ ƣ-HcʞRԩ&Ec C?Eڈ}:Dv6qrewczY>h\u`QOE[sd1Qhę }/(QF0.f孻Tp\*3H0RY hW*8Sq'xI5'|xs8;N&tqe)MNE%WMPIJx-dTBqJo+.P+^@=GWK%Z]¸3kx2z߱m0/-Qװww!R+Xp, Y$m\9=j)aX/,FR + ]pX~jF*bH粤+@Nku$`H/ʲXڊG9zJʄ.Q{0q + +ǯFgUXHZW@  =3{qꒂ/_eK3{Y4Ҍ IT'I-Jagƅ7Zb)ǝM%>`6(c]I6r,eoMqLR6dULb`Rc l0M.cBɧZ mR(>E! nsQ:7XVP6'OBG]+D`,7E/Ph 4& F?`[vif  Sq2.IQanU`jCG!-;;w4c5t&>rig7a| dJX[<=wik`JOC52ݽ[R[B#I/xim@Hg[ε540<o6|:wµc}&juP}Ţ߅7oj)! i 1&8ƂGcGO+9lPwˇW,32vm. qWy}{\:UbI( (h!+ +Y9՘BM+󟗥z>t:') SN[Ţҥ~z5R7;Rٖ1(CrYb@ϪZiA{xqiժUa֜3o4(D?poM[vGRJ/ϽyB{6S {:͖n3gr6n[_ErG"#vkV\Bˑs\ܬj8S7NS*_{9p]"oeÿ|,2l+|ُ_] yQ .Cw3]H"/]lˡ@( +dF¡ΊD9$mk8ei%6J\|ZZpoM];ִp7q쌅[+QaIrab,K#W4{;}EiQS u(X ?!Cٔ='9MA.uʙ{q )12գQ8/'W~AZUes}i)p`O ӠAeo?\ GYx9 DEH-M;z?ЂSIf(Ig_3mv$|9J>o~9ho#~ +%ីIgpy &O-OlK00E|rWr6t;5)%F_BD{#npJQ?G o}w$ =hE},ȿt_hYüy0O ©|^9%Lt`Bs%lVZTMOgEhZD%Hޭ3hKh`„y 5}g]m=C:M̀l zϓsDIiSH6z8eB(+äxcx`Etw|芦|$Jݰ3q +U݂yWL}{ C@u@lB]S) ;xAz0$MI@sXۈ>POJcN,J)bXO%aKa|@.x: +lx^bng.=2FMd m=? %IP1ΉCnB(JI>cX\21Pyu<9_|@}ˀu앑7[M74)rhc1W7᭮pwP+-Pb%[e=Ǫ5Rةcl]ٓ>e s a +u> %b4#5px<ϭYoZ_+<2n \. ZGnwtqv,hgO +6#/\ 78Q C렽~zTIrj $]*9[)bg۹>C| zX۴$25:Hgds/:gMd / kHIs@"2}g-Nu <ƈW9tlyٓYiǵϪ$+Ф4)V㡛/$<f GUy0r%pYj ugT)." 3yZ\)%囻MNC2bU*!~gsr'2mO,ỲN $;>q{p$y8 C?5Q .W@{8s'K'w"mT߁T׺r%4ř@GnϙEz +^gF_:+v`EpFLS?^ofƤ 3bVtbe62U l8B.0%Xχw<~24qxk sN!dG-`xy(^_2c.ͽ?xmDě@ !MYX{hݘ|?M y?fl \LbB $m5![Jg#`'x7Ut2% {q˚j! +0mCFT  opz$0nqͦ³KT|{9[qNکdeP%"B}k&Wc v <VHh-B&ښ;X4յ:MOڲ,4iঘaB? +M/bU ?1)!a ] 4v(oO5ۣf +8$p|T6Y'Gu_5qJPyOu1 +  8V@2E ߐV(`}8jt[HvI~/JŢAKչc~2eL:iK": +#@eu9q +v5Qg͹ ްEz [>Բ==9ϪPSr}'ÞssU(kI."B!:ҊF@F^ v +ܭhU8A6'>h]`fw;eMZIPw= [+ lKpj^k@R 3Wu]z3j1A(Mf(w5.SjN97h3 'Ȳ,fk@ eO~8sQOy} fՏҁǟMC _<󢹻 &!%͂I #jBs1r%ɱҬӤ4pF|?j?_EZ&t?G()99Ϻ\_si> LGD2ʨg%^ˠY϶ūqYrVKYiS?.C޽}xq\j9n%mv\Jqyɣ69B`vHےqvY,*a5lΜ¯U +IZ2L#"\tʿ穄lW +BMi6ʖɒikY#`}ކz)/&* +kCRA*.jHj3k@*2њ.B%QQ"Oކ+WZEA)SVצjsEh& ,+LW|RhǰՓhèQΫTMG`>4DH􂄏0\n +s /I[?_ċ"guR0K~6({j(1XeEdm@s$!d4vnXPU,'ƹְd/٥qq>'#\8ws9>&[+fJcv11r +09 Y5ONht^}R=fc4uth\1!o[y<D P-)* Q8{Y}|c.ڿ\Bt_f/в~n!pw=6k;*}6^ }8_Dt⾞~yj;?KDqrr\{䂧g]Xp9q%w +SHϫǑcӟ]ݻRdǥ`7xy]7qo+ -yթ +GO/xʙr~nb.G:x,{w ]l>c{>|skؒz-MO(`dlKpO0HVıyd0W̃3Xq=p +hEo3)93Xʗ3spnXܐoݰ:۠P 9PKI]Hm5ݦՓ֛lEC0mm WUk(\s^:huԫm.hŒ(pI +d&ƴ<|¶^UHR',Ro}:R7 getQ~~q:CK6yT^u }.H1Vxx}'RŬUCcśSiddҝFt2[ +t+CS*Txr$|JJdRL}1=;S v䁇=lu@GGDX<ۖv=2-τ|eJOn'V^I Fe(8tH +eDJ$MWvR-+jTO$ ڮDשv,['vsDك2F((hߚEHvӔEMDs+A^:7gF Dq^|[GzVDQ yQɓ6y*FIP}ElÂw2Q:A4Z;xo}ROK$D +1D":M +=G.iˑxy0hCbR90CWHN袭6j[{Cްr={# ןPR~‡EW8~ Q( +endstream endobj 98 0 obj <>stream +:a'ёZk\/Gb*wwPDUp*qUL 48 b WG &>=P)ǍK X [ +dCg f-{o#f3{D5h̾x`wzM uAdL~s YJ99j+P +|Dn2ueݎ;xK^/6ԤiY%4NJ,=f64 @+U?MԗI aw>#ω?It2T泯S'w(\hL*3Gn606!bItXHMNIHUY5B 'rMP>*A |kWϓW1 `XjUPp8N3em`tܶ=g;'RM:_<6YV;V%JJMX_Ðn6"wn2Уy -UG!Q.WGY#gJXβ_LJ=Bc5*'.^yj/\=RP|/ErH`pݻH [|lm7_ _Fp$C̄鵳bX+ Kίf.=x*4+W4"7e999ϾevQt\>pOs" {dXCt]7ǹ=fcǐ_ޔc`tN< %K9]I6wLnUte)0Ѫ|%>,{0b+<0$n.B+:;VT:t}\iB̧('& +/ty +jn: oӻ(‰_ lV*۽l޴icBޭ{S~*="#_kQ_ǙJp2#`TE٤v7d׽hhzPp~M( +m%,05.AvtSgN?ĿpӤo:*dx^DΚ;pl6)Eo#Tm76a6/.қ!׍VM5L崟?{oߞ*i˞AyT-/=5{]}ܝ> J''O{xK8>CǢ'qKC^Hy/'{7n`-^=EEp&g "*[b.-EtQ>?-[儣8#?;6 ǰ\_KrIpQ8T'E+ +?TqMƛsO*ϵ 7zh}}^9;0&2FI*;.|>R܎ۚᏐM[g91n|=Y2I:_V;!)d<^=^K/sK]Y:zEIR|p[s+F"c޸ +J?9GHW˴o6Sqqd8rL~"d;ؼ ['-v)EtGK&@~~v^ڭuWlNI8cOBuo>O7D8x?>eT;z=!30fDb_ܰԺb[ؔ+#!9L6{^A>ۺ|m,&s>[^ v >9eZ'OQz=(^]0Ϗu>JtnRF|kщ1[vd@ٙSus sltvoʄ#pz=J/Xv9 ;w߿zH)ZNx!wzj=<%}%~dwϙcz3ȭ:vc?=Ovw/o>Z^/>U2?9Nɯwٙ< dܲy:??T;ل<>/"G+'!7T//8ƆʂEL4^d}}"&D~驺O&6<ӒD0.No}5o؛ojo-~9RJm%hZ"؇p9es"0,`RܓJ2XS{ 7A|ؿ9t*:Z&\@%"l?jE(bŨUCK\,vzq_mMZ;tSF5 Gv`ޓ o63;1TګVSg.ODžg6~5 ,Xa_Yakq]-B}ꫬZ5}նE3POϝů)Y,q +KpMT`ΘlYpSV.nZz37m[MQDLy?DXROЩN|&"`m:W)ζv~S9^ұG;5efPIBiߘ8k0a0I`؟1 zP JJ?R ikvrPLٿܞ`sbWc<Xݣovq)7/߭ei]ˬJ0?PǗC<3)կ_Tjw. +oJ_޹6/WMy)?x90[ˬGbw~ mG+sX~zH[@$kc5){毽YX)| { /MqaʦlB`ry8h:7/Gc#ɤi332WV~gJ6ʥِ\?~_n˩_rZC?0 Ԕ~Z#hSr7/'ͿU_NiEtX>k?9hW/oN?: ~PUQWt䔣UK맜AN?<?-lL?#Ap) LV@)9=uOgaN9f҇_VW[Eq$\硉Օ8h['K.#[D)PL\R'}9LաU䬚% e[K>pY)lI}Hi͏hKaHcoCi Z?wQ\VfVfd?}Ń෧ܿ=z;>Do&CՃgr6jbOφ `/}LRZ7x \'dJ%m$*1٠ A90e*Uөa6#x[>M+EwKF a@Cw B{ 3Ȍo`R^lEw >%'N5\{ Lq ګhx&pmfa:7.C쾀MQoL.Yx.ZGYkkݓHM;~KՉs\imgALSmVl7)f GweqPz,a#1?q3+R<7qԮ=H p+D +5~sBIKiTdegNip2&_0/+@g 1?*NqkL +`׼QB gXlGE* ~6DTI/K]b{#)E&$ =Q qmga}o+#/ 됋B\~\]_ypg%^ѰM"f۝'ߢm:>C,86{vsU4(bv Ҳ'z,E! dje̠|\R[H,"75}E>m["*E2qNd 4I€H'iHt(tFz5?nٷc!Fhؒy~u7EpJ γn$Yq8 G+ г$fiAذP~9Aiet]E:[$M"\T9H<ҺJbH 93m)Իi/yS8~| '&+Їv$Rf4(7j$%M"}'$_ 'e NngۻwZɗ+6a Yi*4zrjoݙ*hC X TAFs}ʇo903O d0bB=7U| R\}4ׄ#[o!ݞ-Cͥ!2%xWE23>:%IÜ<,U),6-nc"!~x->D}3q|K ;c$lO0;hHI纲 PŚqEiEP#0QKcqzMrth+bҘ/}b8٧}rY<佼V@#}ΖAq1=-{"fІauR\&,W +L5?8gIT]"d!ܝ8< ^8ȥGHɇxta˽{IU{Cؔ5 vNvY.@/m4 ׅ@u*|ʑߨjіdpQ"Hܓ7;c4 WԳħi92o +soh%˸b@lT B?TߓG0bE%G <58`gWϓ|#a m IXk%NTJU>uK&%TC:A<ĀM U$tXv!GDz˓@ Ilċ1I x nNR><'FJ +zGF*h&X )~ضaH"h!X+RJ9 RH+t0rǏqBxHVJ_05RΑ'ؕrk>lOBAhHF닏l}-ϕQ Ѝw*CJi{H`JuBI e{PG*>xH)[!OYj9.f HPYX VISpW_哳/t6ui* ]ꩼrq|(x7B\@b ˶=Igv慚Z$~&z_qXP9 [^n0E3ȱ͐@-ck(b!C %4(47>`_< CVĜu-IA)5g8pleZ.&q;%ZPÎrm!`7)/2/+iŻ)!BuQP"ol~&`)->l In?i?"SCOќ kV2]<Df =fpBc^%aqrh@ 7nveP'{Ƞ(sx@͐@wӾx9HK[M !3ٙ 9ytm.+0 G 0 @O?Yeø)v#xaҶSz .yZ߻XANJ AEev-'m*>8vZ7Ԑ1Be٭lI #e[ 8=Hy(Vk pLkXy"Wsr%93k;sM7PG +9)N*mJӢy3Ng< l=ya&(A+OojڳܭW53&jA9mBA`X4 HDoUJu8d+UGH h F%%)h+%V~E4xL,iQP$k[< 10\7xot?<|*_%9F]&bypY =m`RS:& 3oIO? 4~ B,+ *˳.4 +WT.8NūH@8E?|HxwLV{P[q84J„H(+2,tҀՁ +s. \]tXF%6W2#~TLeQ*?e# 7eaMDBҗ Zm󫾌զ Vյ}/}\xJj_jSƘFٗ0ZAYM݀E"14V%`jB#!=,Byp0ٖRh#w^sX@gltnMӡh4rtJm@(-C(!$z C'cR :LgX :& +޸@2S]N 6ʖ5D;SX>ltrY1,dR{մcߞ 7:e( '$1䨞`{^1Pjb aߤ|pc.3Bq\)n]Yye6NclR8"W-n)CQiS0'D,AlVM 7ԄGR;;~P59tf1Ag4 (T8#!lr(}CE rMϙiS+~Ǚbp{m']q6?/I4ȹplaڻC@:9*#;#VHȯdKQ+*.Dsݘ q,6yObmp1(FAdIMɕp )mQM} +n2 ӴmctR?xd"HȵYv8\(+6FFzuc,Q:$㈯T,. 3<$Fq$k/ES7قfP5Eފ!%"GExW+MAP#HK zHT)vߒ Z2特.%do"6 {Elsۑr٨ߥUEA8v20ߕP0l]Io( * fIB~+K]c]N%@ϴ0."eSCAn QL_U! 0X\G(jO!;2aBdyœ-1C{\860{fO>U)ҢJЎ,,PLs~k4AA).`<0au(m8( IL)/L#f! &ěR`{s"ĝk!9yFsdpv +U!&QL~XmPBUtht1M +&4ˈoV w5HD^a[s ikI\ @%2kgHqu(ZPq.|HcCrc}oŔE1^ZS'VLK$> I}&5ݫJKS Ei"w#n:j#I^7>d>cAeF5HM>i݋ZOc֊ʡu/ݸI8rE=E5HcF]u/cONiqW2{-FURYEC!'vBȃcp h}'af:EHTVP]0*U' ȡ;wpҥw*5nIװЫ7* ݫQiGX"{U6;fNDO,/k D- W.|8 @GݽU$fG6QxrEXHӛ:\V[m2sU_k1 \9x:<a|kM5Y9E ܍\4+ۉfhV{@hV*p "F򙟶d*M8 &sdGqiG<$E᱖°ʴ؊^tD<^P܍:~]"dZ(dӜn"~/2ߜl8tخ}Bð]<^Ԑk?!{^vN!zPEHU5~[iϭʕa2lwNs i4*DXrhp)iϐ )ޖ*7pu U)ew_r4 |Ua= o\`A&f d,2ߞAl lONe32sTonO!`fa(ydŔűM69~4T*^J$4X J:Ȑ|Q[DR''DdҋRwzVʺWYe O/LcPgGwD x~ku57gd?ÛTuq[XT\]dNJl.dC=}bkHqɎ T>NUC32̈́)U؊ngoM2?:b53'7v]5LA@+ (hv9~$FuqAtK](7sPJyC1eT?k\j$:e<m"$3#1b:X#aCz XY ¹wLIaw2qvI(hbnyQVfV|rϼixx+ |\bH㊌2л8)jSv2pɤ}GVV +QrIb`5;]'2z-^yVvr&ׇF}0>6:4,(D1#]-j#dDblt 鏳UdN*)}BQ]2hH?)WLZQ6@>iK>6| >RIՒT\eٯfEh8[W`H%k!NB)g5(PB_NINgq6jqw$],KFÒۓ%X]Y4xhL|l1Sm=^^=9?$&=0hۺOpd\֦AGggvS/\6;@nĴowaN:= G JQNH IpPMR䂯 +RJ(v +\71PTӥ8Ϛo(vۨ6 =(Nb~^rso {Q3{>4G_\ڥ/FP GP}G3~ BRlizuGF:Q[}M_`ݩ@ZDd4|X[}9 y Z'LH*I =D+϶nj_oNyޚ=*3Hr$ea?$T 4n@ *()NNu;+7E\W1&f*=k$ -`}J_DN*  b9J@{usLmOfkoxdw.{ ϟD~Br+}`֮LYyq#|27/zTB7,W\-ŒX{у˗Uq?W&]r&ϟq{>,$qJGR9;p썙j>$_M<_cI-^Տɓ"]89מc/x[L13}:slM䫻;r'G: k/`Vx^/#LLKF ̯l9b=FAb;}3Gb/լ߳ 8ǟz\ew4sl0h5Fbbʔ)17aI~{:W<659tήYebP!,񍥑m&\18h˧ٛٔ_7^-⦐zM9UkɏɇIz ֣HNң~0p}M?xnʻ/N;UGڨiQk;NFk@#= oUvpkUMfG8zPxOܕ^)LD`)ﹳm'Wih_ 0=zE0[|x\vh:*,z$ț}~Zf +UTx..Wd.;MjOʩ\]{뾻Po=I4M^ w||#LaY裑-!89HxwpȏPau#>x,x"v| ;_o=bOsXcquX62^y9+^xE\F:T>')xh}3f(#9_/z8{x%5YWmO.#hoZgg!n&h0JKfp?$=B^]\<qW^% T${R<+]q؉Z5*rwE. @So|W4U\V_cUycZ= M] ̈'dU3fi韯~U*vL+.V2rhQ]ø/w!WE@3VO- ƃ +|6ezqЮs4fWJ+MWvHl9iJT +yV /Q%]*;THPmv (_p ! 5YX"{P5i+*N+:2]ܼHq9o_T@ sҾ0/p/ ldk Iiȯ?ցC685KER-1 +d9*E%fHgPeCHJiY#$zH-.'B~b$Ջ10āpCd,Ns 'SIw[QTR|ўT) tSz)RD;9_Ma0QY(&3V J/a=(#p5d%_*5@[\ +=Cq(NoP.-8;>Jjk伇UʤuxJU5As!( Vmm +0( G*Ú $h#'^*mdnRɉnE;|Xxqt@Z^h0H +U%ztm~ eh'=|F_@N Y&eSQa< U>Kܖ0BŔȒ@Rz s1%N xo $БAwƬu;<z!,|A~/y<@o"9bg0vfR kD +"H#CR{iD["7?0&t,T%4-!ES +'`@{j&TPzaKQgedlgO'΃219!H{\ +58Ip$ոE7Wy!,{sAe"+FB޾ fmQ<0@] +hd`;3oH'rd](JG#R +4,3r\iPCaꪂ t$E+*|wԨo\C(N#/WaTϗZ0C('|EZZo0&<4u׷u:P"܆wQEKh#=\"H1 'GX c-Gc7׋D#Mvz$IGe'aWD=8uV7QؾIE%MC=6ĥɦXVd%'D/ Gbj +(EΠMImf N`ܨ.R,B1-!b _nCV,` ~/Dנ> +;``qnc1SݐZAI'01C'ļ͍$2djXX."Ql9xn|sGtf0B%2pՂO%1P (Tc7 + Țd}pI-rm(t擢ϾpŬ ZVd4k2LWQz1ͮaAch:Sf\X aLʦ>e^E]Q]Lc|>Wێ<~ŭױ\. ^!>OrmJμ׊Gʁ[5ff` LP6{Ddk&=$ + +ُ3; *m5S#Z5?^STI/{q?ȧ k A`wи Er,:dY@ްF\>9Ľ: '[ܺ~"">lb"Plmo1k}__6V "~MAy$pxݡx^{˳@ٗt2%D/'g@1}V[ִu L*ax0Y(DFiG9/lJ%A{ SmUٴR Hy5F/=[4f3},۳Y)bUy9e~, +H}3OXС}cTmdK=JWږm)eUD9dOݖb!N+8-Wen^ Ām=@#c ^A*Pq#OYF$WdfYe"r;"]CI^@_z]تnJ ^'kX/{{CR{M/GkR¿^{Mv^.Z/"飌f.^{Mtge:0 *WvvB-$Js]C^2^g.ܛYGٖo^eQy^'^{M:K+Ity[/k48 F5c*sm[!)&e="-w':DWC'! o! r=?wc7j}hohyE-yc78d9޽(T](k$l&PM&*SɺJ~e~DUxEC"x::F2-E<ơUd9,,.dV'(2RK{*q <r(BZ,5A&M֥tسٺY e]1kϦ䋗~pZy6\/%i{6c|IbgCa6I䠳ʐWAP,~pf5V`hL]Y [ r3\ޭY`lκ[vip}v\#Ăh(i*)]WbQCptAέ N 4i5XdxBskw֓gxb#h}b Щ/t'l F%! +eė<$Em*4~J[ -|$`r1jn_Dj{BNwj!r'y#}ǛAy2áQBé6L:b[;[p=05"pXYvqWb7*P{er[SO~- ^67piW"lqښCbv,7q6DjRZI$ +[Ei`8Q6GvsB6Ғy(z;HϏ.H.s,f–N9?zFl :dn3ypS-_ zF:Lvkz<[PS4!6Mopv,[$_[ BWHkJPDhA7ub+ϣ#`vcuo ",3eConZ{a&G$(݄AZs^B E]8N>`$aNr.I@" T858%^;117M+̓/Sp] o1 + ήj[9q[L/lL$}a}='8a27Q+a/ O2|Xgc^_vuO[ 2ˇ8~i"s1/nՈ8m~Ժ|=ТrE%{]@15A.dG:dX9i.4@A_RϷ{ǫvFw$rz $-6&nQ=Qlz(jDT)S]D3$ʋ49iEբ;9Q[u< ҜlaOҗyEd}m8l_j3iPt<-ݝ4,'DLB\ :Bl|~d-|؈n )Z<3-*%šzuO3sHVyDn'1c"ICmGW GA_Ok{d*O#ט?Qooh dF} +o.+e !3SCFV ʏ1ӵ]{op5=f6w[+ 8< ]UzΣsG\;q,зm7Ў Ő(0h0k#S0 +(8 e1G:ؾ< JG7Rx`my2K(tv h +!^_m;bmGKϠs? ;CNzPx#|{b,Ŭէ9˸bw;h%x):r,tjweU*udsV(-"z7t"ql|揭RmO7Pr2#^5_n*~zeW屘<ƶUڳ8Cy..^o+P2\oe7{[]T7nӥ$t7ɔ3ݗ$zs9W5Rd©|1505{zU~"sX)xBln]~Fu=gBz` z ~g$OE^WÍ7[ۗwW:C*^,bo>|j$#s4G*_mn\_od)1ēZ*.ی>FZrL6L&t%[2lճ>Z#:sSfw=gNbP`{!/ҋؼҵ?31XHehbúɰHww.O]s͝No^OP?i]O+sͿNxG#Idz|[V\rψH?ǃثFq2μ_F4{-] GϙT˧\.W"gJ!J@ a q9c^oHnY/lxLa#*&x +-Ŭpqpq$rda_R6Ux}ZGW2So)u=^!g~.8RK%뷏g_k:y;BkuEՎo&D~~uXۥOqv3}۹= Qh1װ9sXmr ~+}  A[Vbop;U +)Ľf?qbg,븈b2]tv=FXbQ"-rUZC-, rv6m6s^7_ֻ {olmڰWA+t,] [cgɛaF;֏Gq\6RHԏ=Ed.* +43px4?xu\왤ce!=OEtGPMaE&O3D(/*aVrו}.lyrJRVu;7_SuTP?St;#y<'nd jXn;riJYikUlW*ݕk^pLk&I^ص\y2Źgӫh#[7`P]AZm,!"Öqr5R+(xx-ϝ6z>Utڎ-Y[dXm9xp+1y|t<@<13ӮmdACؑ=(Ekibq [bj3%6,[ jw|q/p{|I?-TŧT=9 +1)yf-vsd_'ɑ2>IО쩍> Ep&dY$.0Ym xxr +{ExY[ce1wܭIΕhKx1OU.ľn䜤؍!Ҁj&9Ĭe#HW 10̼@X \56<->ViϑX\qH!nJ{MU`]yNe޶Ee;(7O[7 .ଦEFw\S|jDYfųw<1mQ9h:,MZ["x4hM| I۩p7tdwV7 AN+KoP7t*حt=ӕf"8>P( @ߥ#&Pyle db` _jh]!nbGGD*۟9)t9N8  }Ex`1dEA{vfa} Л9ف{ L+Y<0[ͻ"&4l=z1sC}^*Fm<~B㎅tO4N!L(:h1Uf btB'W +5l*wdlPEqFS&^й*7C/DȢ5 * LNCo{B +H|- 2^P" |fzg]Ȭ_01ZF4OuJ kǮHٓiG =10R @_x̙ăhZ^>2@  5%G;2H[X>7Gi-eJfo6qE&).d+ɛ2FE Bč|$X!ET(b2Q !-! ]HH,#m"O|F(k- 'hquIl@!_Q[ EV e+}6nER{6þt)KԴ׺ԴDU锢i%.QhK*,YSx5EhRfaW|tۘQx4YE`[aYT"#aLoʪ +P>Ш o}%gѝ|t>/x.ͨ80hwCį{AH3ZϘ't Ǯ;]D_D&0FBI xJG9 ;yЁ *P@iyAAP>LmZ +S3s~ bd OZo! qBQS}V1u,8gA7BXfYJv(,} rܗ8 v Q4,RQ1!IGPu<D9YcjH%@d+Ԑk&RuH) eԐQ +o +Ew\O"o*CQ = T3*:~ CRON>vNR ] 0Tj8]Csj7җS#*GTg5j5ƨ.D3~Nd'6aQ歒c7KL]'h @ >E,H` F,A@D*|7GV]#]}oȗ]s7Xt*F}ۢśYt4kϑf4vȫ +t0D˒3 + u,g +- ޶ b)\{^9A- a1[V?uEځ,[ HL]մEEQ[ U@ʼr^8xG?+Sc m ~S2 $F!$!3ja4 ýؒq1H\`ހKr=$Va@24 fp'_cdFoC|7ܕ>`Cr{WD" jE@akvrz#P'bf iG+?\!J'HH![1P/-Ex(7N:@]?UEP`83ܡed(7ZCI}ȣE[⿓tx=:e, ZF`5X[wPr{$X$_pUၼnK@w!rkY3`4+oC[DfKTKz @c8burqڇe|M 9;`gmCv/,d;!7\7K{7|a@u}.] +L~ؾ@D_[ @78_+{fIa^]" ށ,s5$~R< +(Ёw_)@9`Wu[,8?r>.e7q)WG|]$12P(=lΗq\N%hL$z_-_Mҽ&:jDA^'τL>)(㽡 .󌗅݄043}6[w,]%,,1y-Yi?{.(oRKc0_9dE⥟alXtc9{ʊ:te񨲢>O{- +m5R҂\֑} S՜N*)9*h>$ '8E)ݍg)%5Vm5V[U0`~4l#L&0FIs؜'x5Nx)n)=z Pk? +Tǂdi}-E@P&!Kz# d6uJȜ4u+W|lM'9@ W݃+l'xȪ՚ m$ VˡӾH~>{iww87IuL.1$=ecS<&LDNp0J}@Gnɑ"N +zs&=wj=_3a*k @{ۃM*[VL49^(t%ԣ +7A\?f)?\ +A6 tw C{JJQfL:2@U.&A OnYM+ Q bƼ|c 8 )J2m3/yyKJ7!>KQgrN]tMLSGkEW.*֔9@i, ؽLmzvLpA~ȯE+5qK{RЛe4 +n07Ʀb$<lEFl^=9}6|_Li#ebD94KDnh*@7YiFKNK^'|}~O9n;oSRmanj +٬p,iEF"7.8:M, pki`[ +Jh)g)r<*DGIdH%ϹM=O뫢WIז*sĮ*^nE0Z3KBa ̄DMҢ\-,.FhFO+Fxhg10ExV1SKe␎ iX#h'- V ȭч&W O͖f2k%&4]:B?$AA9C&Sub,)1:} &1Ң{ "AY~N*Aެk1d9(`{79%#AA5dCTKi,db>߁'מdg9(LI s5q6%XvVHwO  +St3{㢁IsD)]pSQmq+X`-PW!vr+Ƹ1@t s$9SEb$Pb f܌y)iciƛ$:ad$bG)\pj8[x? wn=[ = ^|%F % ñEh`HTs~!wCQDػ i2r>=-]A9$|=sЎsUdESk)/B@ E0snڨjoi<TzcJ=i{*xon3(YvTv:" gm)Ii)q9؃U+E17 Wmt~]TMVXN{=N;Sq&F&Jyy}xob5cJr.#?jj1#Lf=0Vsa.7x伓wژ<9#fqJfIY%Z/Cuf^y7߫%o'Kz"zi,g"2Srr]u9dDkrg ۪v7.&U-t^.ãdVQJ3:*֔ʐS\Vq`dynL?ZJ wIަrg'HOߋ\cmԫs_y#썽Z_|ޭǍU[~xui|e~/,V{Ͳgݜ8kz]d\g'D^xc# ?IL%>7`by !Iz`z}:ϼ3E04ªwگUk:Y\gQӢg]usՉ5塏N U/&gfM?U!3a|R'@ : Ѩ>ŝng;}2` 0d<:tP}mU5i(W'gRu , +y=Pdmo>H`/m1„/Z1m׵qFeEq3C`/´VES˓)YsOb遴&"2hԨ=_DayLw}A[_Fz}Q)L{ kMc34NUI@cֽOc[X _dhh1h% +9 [![ؙؠ+EO%fULB8تA􃨸%RCq{,"8j28VoH1pL;h^85ѠV, ̙I,+v$"ϔs+NMMc,Z^DH#@#NZ#!"й$bg@g4?  cs&Vw .wMig6`)[<(t +뫐u1}WғVHLҋn?Z{K +籝 +t)..^av^H/r5p4úNT/_+:GTճz +/e#WƗ:Zn\o}Q2/KWOh[6Χڔ|80[u>YNk?ku{@X(K.{ XH#[|⩯ol,DJЕ-Ri_q&Ot́ڌ.6Ow9>]YFY)]x}kxyϕ| +',5]oχ!;L~æ'g޴_l8{h(>")\>rd1 wwzt>yt9}uF-Y, ) k9gKBLnP>M<5 #zLvR &_tGtγUK}0Ԓc<~ci-bms‡؜eŦ鍗b6\Hpg_Cƙ(/%sy 41 xoFpu[U]\>Txij5 vbpr_z0'9 +]ά5nן,v]&i L5\dSyrcD6JqtNI~tD *c_޹t{(}cȍ;3z}vJ}+Ӽ WmWw~0\4Mqy4ԓVMQ*ݎuQd'/FDbNREcӫbD1x%Jn <} bAP6.YRůg-B83L?KޚƳ?~YA9\4if}*DfXe' +7ǫX6}iO3rPt{ {f<|F UMIJ'9qx~xpDuLt8Enl*>ORlX<a#gJJﮦ^"tUfE=3ZݿI,w{Q63x}DtI Cۣm&W8hkQl<^ض3wD*_̫J*0iJ. +P06x^WCfꭳ3_fd1Ou⊝*P%e5-wŷBsI" 7 =g5Ȝݹj[BEXc,m|l8[qMWYZe.R LY ^Ί%m8VzqkHgNܦ>3Mg; e|Ջ%0T3Xu>pXReu˯Y/|{zo&Xx|!Th|njӆ, +Rrs%(l6888Ҿ"Ny&Z n S2;S{Lo*m̭8:ǡ~IWA"~;\=ڜ/vD{<ٓ!hvŀ ON KnN`;Ofe _XP j܉tcN +&Bη"o8b4#؏$"c*[SߒYC2:i +H\OD({B%H7o(w!xX=s{~x?ֻ7T.̈́)ڡǿ2?)&Bן`{nƴ&"CHs{!}F}KCVsQ'Z(۠fOSW-Mz=޼mO")~<ɧ%gDx'ī($)=?~NnZ6Q_mO9V&gd +WU`}^jcNlos9|f7 ~-*&$].QDى6>y,d[u+ݲ^ٲN>cEb)>t\yѽ4RFHI ~Ш,]O?< 䟛!LU35I Fc({BZqφwYJΎ5Pe9&e9&v"JdqM,*/,ޕ۾514*fYǙBGnp"olq]/0,*gk~zM޿? ]F#w'_ԹdY ڛcXTȚP_|YIOUJń1qfnř3gq YwV +(f=ыpa`ouk/eߚ~A6N jv^n~ESѳvt~h9r>aq>G?9˱;g?Xso$@`H8T}cf%Dp 3c ~JL3)'0χa #H%B{%5Y`r>dy;l`!¾8ONkQweU;{BRLxN%:.H4y^4g#Ad[Ɓ4F"G'g F=6rB%EIPȥnAL\RY&Ddp:Ӏk7/$n*PG~Lp !巗%0{T0 9h/i`U,X3&RIܨH3eHźѦvApձ+||B݃Yg:$s*Pw}Il3f~CW.vb)N* 2M_սtPyT +!S +11 >$`a6ƈ}ScD,Y\LV\m2 %-H<ƗvWhXHf`#{N+ɔ~ʵk,rr 5;t@sg,֋? +Ak nB9-1L>A~m! m3E w.*m$H?$Oi'#3Pӥ QْShD+QCO @}HzQP &*`jTN e@7 ʫ_ .UrySAgKŐ0I=;i!d)JT.r7sp7ҷ@,33O?3hщ z˪fC\R1:kabʯai<%[?`q7҈SüҮĹ`w-~LyApZE@mvv$gҫńSj.Z|8 N-.vrӌ.t2NqTtjP't]P W_sG] |IT( +Ey;F'xR0t( OwlʘhJ-{+wJRx%,% XPS)b.`\-J7B7'-zFFHC8A S&uLPjW[h)F1h9 idcb 2;)8s̘ŔVJ ϱ)tաL߲h0.H)B:oliMOӴݒ/q ?˒]a?SyW%}$g4 ُ8'5hz¯CR57P+hY99}s}etY>\E.<R"tϥvfc9L`:)fX|-`!09V1%O"s3 HN3 !'A+#u݆-d!: +s/>&D>)G,wH򩚠OBr0 &<W2%ƔDF+z&Sڗ>MU=?"w3c`D\nlp +@MlɧTF +ŀ䫦d Y2O310~38~dU^PoLk9i2 ע 8}6{K~5~R%978yQ%PGy.gPF_U4]\|>Pk_PBqM=9VkIcHd5Ʈj^:d6E.9g|q]Fi>IzDOx : _,/C9:2M/cྤSD_T +Ϧ,.2fMrii +&*LM\HaN3V[:WpR w +f8}[^4N#AOcELY+Y5`RՍĂ($.Sq6cELEΔ*:t2s +bdfǎ*BYm +H\V[>L"FMʓ4ch-NfZ{f9oMrZԆy3v1bN4+ͤQ!UE>_8 + MVV`|-pra1Brs +z%ˇG΄$S&*GarLa~ @4Uj hJ5 !5"=6\v*ӗqVoGI#%,r_vOlG>ꍝ̯+I% +_Ofy#2q/s*s౻@xb&K)RCNGSX}Iƚ#}5"(%۴բPXdyV )/B6sXYزj(<~Yj̦Z# S3rjN洬zG^PF⾦NM&j͵DbC{cZWbFBEd#0p]RM CU4U:l;6qdDk٬Cϗ:⡘W2Svx:sSڃ47O O,0X '}V%(}~wi_jxuonclwnNo۾z¨;IYN<Cj1d)Dl,eBRiP4<JM毈1[pV*enj|75(yT|M +NQHMز3:Ѫ;=PΥo;Byi*Cj *S%-IլvE:435NAaQɨB@|c"5򃔀nLJ@ NC}h1FJS穃BZ@7ohkҲO־SYmpaEX÷Dy2=o/ёDN̹B8hO;wEFX8T("M`Vi&$>ńKYgk|< oՒ_b$h!;SṊkcAӶ8P=5&ر-t-PQ8g>os D%8.1`ɎgWfQN΃3 NLie @b=Ve"$Wa}pI }(pRe +dZɶ(S,]R+GnS*g>IxMzRFNS-s퉄+bt3'-9-ʏDP F!S3Z ij,Uހb_,$R&EwՆThosl{O/c:XQ;~pYqPE)3Xj6J27vL:x +E?1pЛffV#>YPU>ez&r2]<L`!3ݢ*X3}W.(a]I(T^>d;MA)z@+$)-4u"Bi2l*|+Bl?IfDzn ӐݱwԙfEۭV%`wm@(ʫW5 bu37z_+)xVJV564+(#0Ɨ10BTGL7ZrZlށ]~ nR_-cm~j?;gj'T=Lf$87Q]am.Gt2 :ʃbOD5/؜)U~w+`3u|tzo4k% ;Q:h,7`n\ +l[V8wy< =>#!Aop8a`}Gq8@񕹊{/ʹG-.Pvyc +/]#NP買s9*5?W + #x'sÝ6!+ { wU]%2|rUg :[chJ&]U*_bmٲh=.OBI4Y1QTY&Ͳr9}iaHd +bݶcneF~].KfJh6^ }V船[O3qh͏B/?x@me.C!lNӶP[ΒRuVA0( p̃ESt5t!@vs7BoƤ0>Aw~$OCniBҊX W =Fs,Ŗ̅X- +X EX qEkxM?pyԎ?h(Q(Ju-ʧ0J]Q50aJnLr]nK$`艌8p}FCP%s(QU߃(>CVg2 `pzԼtZm襝A!,-mCHɁ4wW/xggXQ^A¬aǃe;ÊԶ'-ê"gnX:Vl$;1iU/mkSVl5~.78La3sma Yo6ƛU +[ B]!;o6Fw1 P1?&:%wkk+j`:!NZqGVȫZj ` sh>ń21"(pQSR2'4YRTWX`2BJ1 +7!O!ӌJˋHf< U4?gv[Y(P}ʃI)>31ltA7tݗ@gA:-U{rqJpm7pnaRTV&9Xx+snMRB~6ciGwx߀jUd˦Q*g=\Q'Fje*\:  K,?3-qe@/^>vd]<('C`˔$"P @3Ę}j8L@.SlY-URpu׹DZ:*Oҫ(C.0*u5]W.vKiLWVʼno)LOW|x6:eSr_0923a\QmPLj=MoO(EboISԫy5gcV՚|kAI&C*hRY䷡R3qϷNf!-6g +<`'9tDXEU߆ohNwQ*ml-gkE( Uc+z|őbmTy2.Pɉ ٙVJ],i$(VϴH8`U[$b'{E⤜dHeiGaƪ8 j:P?@ {vBέqs۳y9O4G7nv,Ntm=4qŁ" +.b2өqխfM;Ab +qشP,Wzġe䑿2{lК}_3g'ƻ,% 1oNF#d['.;o-VLfZ8Ue-r=-PDuYq9V 3 d_^ph_0W5}|$ L<+uO1a$M|~ |)S(բ)faf,}$*\e{UDţP߬J$ѐ3eHCk >ڊ2^"Pj|&Uu(uZDߺa@`򥛽t[8}Fg[^e`8"Mv߭CTE@+"t\WHHۘsRg`jL.!s_KHH8#ɳ#b ,[~]ѽf 6]_9}c|tp:qr5Exn[82AO 6r74C:S CƏWӪi̡׮g[̽|wfu 'P} 붂uk6 +Dx8?,M>S\5'Sdɮ@t`,nu7uZl}ᚦӔmR^e&(RÛ1*kPa8V;d~/ЖtSH@e8tvyN&Fע2a=(]&_uﺐ5n +ѹ 50}V&7-INEHl':9zʋ uq$ 2-8>{3/oKHeRA &FMS4E(a+d1:WegԟĨ暴M|ߒy\\e[*9%36%&dӄL t2?'L7ͬ9C֜-Sn2y@,ܬp|a=sQ,a9.E &jdNjL3yPu5!}]gcsrrLJmql.>L&i}Q`g|XWcSNN/`iqdշNfYlĂQ~ï󬞁lIk\apr #:M/CaO LXH3t_r,FCF7|Lv}3c2sPg׭Ȣ U䑶iD~HXWu1 bݠ{q2+.TFc ',*v!Q'@Y.)o7+!Q=`Gcui >(P_4{19PzœIK4wG5= _#9(@tw^5Cj̔ -AnEB[$iWέk N8k]TeRvVP rge6fXd&7n%!&Zjz6{òr):rLRpkLJ?=3sϼ?/FAbrj7ܖW|06M +W7 C,hK$8>q`YTS^@sBu6ڵPr: A%AVv+akP> Azb { yX6Uu:*C*[WTrxLOʘƱ$RD{Kc̊[gOC1ֺv Bقf#YkkP?4< +ď=5Yzi-e1RLΝ*#bm. +z¯:`RRpb/RuZYba(ැ + ?ъ^ ;*t E"gv,i|3K5]=VԻN!r6܀FQ \n#U_hjx& aRB+B)>UT7=mi)Ug^nɣ[.zqp룉A5x>:p1]ߦ(k:Z`2"{t(u޻:]v9?q>0fNW); +IkE&|ExaVf)BtnIQlHߝ ))ߞAj Pgbn3* b$hc VC40ݵ>܄IfDڰtsTIN? >H|GtU,k[\qyȄʖ-z Kồ.+롚#{\T',4, +Y\HNC`ٷq7b"{t >>k/jo,z^\ˇ;5>g\y:iն&F5?1m%9WYܒM K|4R,RҍiX7 #<9g7T9XZZ4Cb|ӡTMB^#k|.Q2yDpq6{QqDPm ]~oQ):+R2if3=.ŴƢW8 {.K)ƳQ*)Kb~D 8E=.PH;(Va|[DҜp +m9̊LZAdm_XrjKkwOq ,G훵 +LV<̳OKy L 0I~q'j@k?d {[@{ b6LIۙKR6tT Cme8҉ɾ0L!3h)hŠ.B2G0ML]\dõ<_;s^ +')C{d+ip!q!3%[ʍv DQ-w4U:O,4cZ^6 |C/K=ڴ;`AsWaDr0FrBvN,q ۼmw` ڴqyU&Mb- i|sک΃2͔V.r[fΎcmcw5ڵ?]3֧]ULyV(,ǩzMQML]d]/es~'$c`%ߍ^: F^WS wbh+fo~<}Sb?9B  9|{T:M#A'-yBmYtM42e@Mb@¬G5)0*,1RNvJ z8(q0F/۠(8;{grʆ +qKG:13P vuU*:?m;|Y%F~}&mAF ݜ,=ۡwLj- +ʹ;t=Sv`FZr)ݗ1)p5 r :} ɔU-0?%BY}7O&f@Ʃ|0j¯˞ڪ%7T ^`ch!q?ֶ ?h%n}N`~\-BKzq ]8,Li_,>a +.| D 1}=&kᴣZx<;pI^i_Wr]1&ư:9u$!6 S?VN ([O/^/nР#٫(ҷL9I0Pŏ鈳j#7`Fk_LD :ZPJKzRRЮrmM>fA"u̔ &EkòюbBp,(Qף:e F!9 B Cjb}uu40=,nQ؍nCHvS&S cf+X'8=jpm#{~"UgV_hSw*OmoXn3>0Ϡ ^1//~[eVX~M3bJ +%Ne䂚PmC +vK";{3^j–_KkK V3~|ڍq/'x2M1\{>O iE] lJ7HcږSZx jC<{"arM4}(CZ5a~08c:rɤlc۴< }۾b aApZƂրm=mcE[-PJ8*\x3Y2ά!:ϟ-,k3- +PxyE=fjHMUH|@|l&s4=lA4GpȃXxU ËkJUwf1AQ^kpT҉qZ5FqiG $Ԕaԧ;4!^7xvakKMfU!)wa,1<ޗ]7W tGGٞ:Cdk|>i! ,2F,eJ$&;3UAll_"L^`is+̊`^2b|kY4cU0IAh3l"v.,2' G0=u/u^iF/)mvװ\ђY3TcܪK>'I6>ϪW'ݸ~k[Ǿn9} '>6_=?g~+d0X Yns{݋SvIO9;ʇ\@~e6_/yS? ˆEnw t$.t^'N &Uc0Y}^yriП9]͂T[y*3gHNW^3AK xqnb8 7I]+ ~`?3>ۥ^⬽7RǓa`PFvw/Jûn&]EfCRNKm57UZ'Q|.]swj:t*.O۽a5soMOtp"c?wpo 摫v3oom_u=R]M׉);vrsewN3J䛣?ȃu=Wm\)cR5CڐRןr;*JHsQN +Ufcs{|Uw6:E"ro]d51T q?'$2I;;38:zo0 +{¥SD"zr٨q2w6}}3<::.Z0QL 1|8ut ^nTF1_v+tR +CrZ,y|`s[o/;^ٟ{%L֧ʹ'/ -蜸! OZeXMdgV}t1hR˺R ˌ'0_Y%V{~f? +?J?zk[-%WI}ѭÿz$_=8VW~rkNwsjY?اU6l~="(U6شE[,e_qT[jF"{;ԿBv֢zB?EJrH0- ҔͿ +Y; +K\1-# +ָ`?,^\%ku]HKBxyn~ϩv=CFo}=9v{ҦյKX +[~=m^@ۼﰻE[Ze!R۞d r;QjUVxꭉĨbC5F|s˔pV:(3ɷ1 7'6VAڠiwBt-mP6`0P!Ӿq +xfпaA;͏Eo1pyw7+길Yq:TPbyOcn:YRUnAseZcp=.:OQ[C&Q\ҽ2d 6GQHX,ELd+;5XˀutBq&R=gfM(?6N?5hv+bP -i3@#9k&nÐoWLi1Ѱ~i1hedLDlE`,ȳ-叉5sEI3Y,̲k|oKś!,9͆u1cel.Vl/@_A'!+ ViMW id!^ (Cf/WYSn$M#2}PÇerͲIiF ֞w1x K+ݍAB+}RDUh/WԒ{;!^тU?FB寅DjDֻI m48`xhB{7BWk+tsBه Ά &CU͍>ܹ#:O*&fbMr;4xЗb?O+Ug  ΡZtkFC-+]:!;4L_L]@|dSu ]˨a{Qnk9dK +z]f(m؁Hw̐#wh]߂?= (ã> + +F/6[#ӆ| ++U_MG~ Lʍ-gbu0mys(ؼ*#dAcEyH 0u;lqKuq uW< *7䣈 ORGq!ߡ0 &CJ'Sjatt݋ԫ*]D)t"xh9B\u볙P݋$Wb更Q-DCs1QJV=8G6Nf`:3dL +O3Mow{YDK"g$1 Ɂ'%PElۆ_ק34!w+^ΊbSڍ1?40F/޿gm>4]zFŜ=jD<<̝:lGHLAZ +lB9tȝ~*Rg(tDNJvɬg -> ooi!2A]p'"?1Vx:ZMeA=NGH~@3V_t +/!kN#"I7/tS~Gf?a?d: Yҧ>h)c V۠9D&ѯ6h0uKOQ_iŘ65; Q _iRhZb.}1 {)d9Cڠf@{..a9§\Bla}حٺknκg-qZn9̴%$뽎#X,)/NN:n/<fJ% _ {IKElc?~q +6^ +@ؾE$36[ӽlV%MPMcT6GL9K"FѵH?x=U}?# ƍcgLAg$'BQIZ _TQK>&uxlIRexfn,e޹ii)L7?h4dv eA{i= ]S,<$.iH/w=ZBc,eBpqX\Ss.~ +GlQqzo&nYqF`@Kn8X7$Eݰp"Y0u6l]ְejaþGg˱J@~U&[հǀ5:-AOxsVh8XYWeѽmGG~HىO F a yCvE z'1~i bP_Zj&EtN)esOI\2dJӼD6Z­1 I8fUkd0h/]bxi>l ,KA~$E1WxcUG#KTECfZ+g/N |V/MӞeF/5 z֧')$s8A0ɛM9f,N7KU [Λs=m^TԢ/ف2lƜh4L ަE3$?&uC)zFyAPHx 4cAdDS5Hk3ek:-Sh8j<˛N'C ~@8YЙzPD-ƹLCE.YX쇩jMrm7,gb8WnȻQ5i%{<)Mo)][cE d<2ׄy?86ټ_8<б8ʠ'wV.rJB+m$ZՇc1UNRP&4}.mEf駣&JeG$c㥌|.l{`1?ch#>*']rd[;?bW\v[aքZ7\i(S6A(fC|$hb4o68<&/JR)*jd{!! *eO1)Sꤐt!MTSW]u"IdUCJ}JXLkU‚(,n8H' n-%ܳ[BA#/=eK+DPTLʃw0m*, r7 Oi6iyhq9'cʹTƱYdgi'+ 6k [زB17uaZ6^Q] OE;"~p+Tyj5\r횓 ]h>VK3i +Ө1DS 1aGV('A2 +W…e@wp6_p),$ٗ + d 8Uw,tz '%9*J01y ɐ +, ։WO&dH7U)"x#J?q`aqXZA" %{^$oRԤ)+?U@<ͅ$J3P}oq5q+6lx8 &k5###o(޸!Gl-EZ&|1:vZ5ɒ+̼"op\@1^p(K k(6U;S/ʅcxwfH +Mfc +=KYb1odi6k酾Mcg(kwAjg Ň +a5ABGϻ xCF6@U(@@B .+zj씧kۧMӒm| H3L?N=WQ NzT0ѽa[KNAyR;u.(RchEZ-T 8X&A-9ęhA'9+ Vd X!je +4J{sdrLv T_Yp0Nd@2IĞJY=eU03,?%XU@HCZ +7X1Z7? v&yZ~.~3X_GRM_Gě9A8|†YN$( ԃ@jg/HR8ļP<$vņ>xGJѡhf;D +e#Y]ZC~[ )՟j(UzCA]O7#cxFZ= ZkOEq˶6Md2))=C*C(e((MOKGE`S?e@ŮO#" U`u$pX­? +wauIPm:Ùk +}W=AE"T ۱*f2RXRߍ.z!;^絵FdF7-La9L ]|;iaaCi*5*Sd.m_#,rjH)} f + yiC +'qxW\zHah.Ty9HUM\ftqhYfO RОj`{`|0Jl/~۬e_O[g|spWt˔ܧE[hO Knp3 +LH7&/ZcbBuBPC7:9F޲k@;@M{XV@EǴƻⱯ蘦׾-ƴ N۞Gɷ 3&5E:]2"l^0E]C.OpzUZZ#/K;⏁u.ƦV^]Mm2XxѲ| 2:3q8"ԡ 2`#蠴=[Za_{(޸Szѷ }kqշ{8Ы6la,rd^d"cR\FԄUE-ZPE|0T{Zd +KzrW[a$&9Pb.XP^m"LUZaPt  +0,~.h0&_̍|{^_{24גVy@tbA~ZeZ+ c#pšrpYOr[1yd;YbX GZLeo'3RyҲٓ=oDC'hNKU>| +vzPۛzl:K5at av#GpZy]e(/ 7w=H`|kQ+zt Ó5c -73Lg ed_>.A>i'7/©CG:FvL13&/l|Ҟ -=I֤

#dloLv7 lVV[B{>Ì"}.VĹ-."QPmѼ:4+ֵŌS̙}2Şc4DZ`(>(w%$ux[`mexp 1@|+MG8LlcTxN ڈ>&){OFoi7"v48kX{?:Pͪ[_4K)M1vbkWNSڷU>+~WcޛKa"9.$N MW?1JӝfKh0=U2q&71זn;&9Ρ,33]!V_",- 58BՎ4FaQGͮ=RA C kNVdYzAfjKPވT$k8a=  +kڝZ ru0.8[- *N:y*"FGfF +').SPgޚAG@܊I_a!9x @yfp~9pcU:ݑfعmیp| #@h "@㧱~|b ^;X'Ϋ(:(Wyˤvk +Ot2GѠ aeUa3.FE4 ;Ԡ[7vG|w +h WăLMױ"ݔiSKFs@v.{15gU%3>P](Ws0K$G*WM;$o`eAuSe֚&diW&4!`ߘZJUY̴_|9^נWWekam݅Ma9/C?L).:%XB6,(wB{N|``W0?gYm6HGz^ ]Qj=͇ƧPTtZ Z"㼒H$w'`cKPF +uNM/qu4_wU:)B.Cp"SeP ]hMtXیg1-wXC5fJ,0-5jڑBCn^m!MYuu~C6yAen3[9Z۲ mggOnR/M v0@&NOYSzZeAJ:T3Îtuu9JS*`eɸjD,~,u\3d `K2?)^T%q3]UF3e[؈ ZQ+V&qZhڧ@IܞX #f%xz] 9*yh1MO}X6{Hnc;]cFӭu WkX֓x +#T>ϊ߬Kw'y1̮Iz23Pjgyq\n4ƱWUb3/@r)Lho{1f'n*d;UHR$_V?<)2g*xKr ܴt9 9 oQ:誴#ƞJgy"-<{Ϋ۱?s{rGI&uVPxܨm'RU') Gru>lK#5uTʮwozl=>~M8ػߜǹb.^sg@;Md4ˆvZ>LOCYsO=- +O{ o sົ;KކwS,$_ _;u %BV4\vGL~juI&f:opM!3՟>͞nfXڼeëo?rڹml{*|Gf*:9Y &/K_$MQqt5g$W{~g.C~WJ87(*m)\&ܼ +endstream endobj 99 0 obj <>stream +?#ҿN|;eH_̷qSR_I*Eco'>jه^1mJ[>)=շ ƥ?;(w" 2'HƆ<>:`J"ڮz ͊upIgP}jp ʵg{75 ==ncgD;IJZqFP OR)=r(mB8Ag˞ugp)gwz7{n]CjϽ!8rfC 'MؽFk7V}X9 +ӡy^v@=soi>&گX6m\0V傇ao@> ".cLrvfKoZ֕ ێi{\DI[wMK 2H4݅D J, YnM:f)WL+z@'(Ušܠgb>XnmIm[#/-{,hh}>'.t ̞=Zߺu}0 E]gipֽߊ[;4qp/ gxx"hZtc/ff'江9xbm, +wVڬx~s-B]6]q*I_`9&J3e.5 _pgYcZ;Tju|ԝ4#TØ0Z bPmї8 +U'3(Q7y/*W|3v‹gDikLC=xzb1H+b=|q׬.0c91Xl Dzfq8s 6FG\\2"堷[*R& m9qei:VTWKwfl 9,Բ=piaԋ~v6b+A..Ps3u1[*noAR̲0(Ugl{ՎaRM'JR- kKpÒ f&/a-h$e1= dq +k 3y[õiGm9rVM֢i3S Nsn>[[&% +jX4 :b)Q+oEaM%1 5goUfY͎x#:|r3R'-kTk}v-咼7II`eFuu%ɢG,-olxC^$Bor0͹|%Տ&Q26X@40ZjH? E8ϵHXi{r"w/Yn 6g)&о19D "OF![b_锽zBu- Tdk)Z˕ .[/h=0"YvMDѝ ?DVI=& Fd?7YU8p$Z*KJUfFcZ'Ve65(ޥ.;ȷ8hc/QU4vb-mdpg*} b_ aK, wUZٔIT2sBx:{~9ہe\P>_biyJ2{ +XEK}~zL Ohd%Mz.-C[ Az[8Bv.NPǾ$UQEQ6i 9 +4H@W[! {ϷpV9{,0ua +IF֠dK={BE+ݼ%Ϯ+ +UP CBbఊ(Ry&xDL C@}_j60mfunfLS. BY }7b1'e:͏vjq:<BϲX؜b/2Ӝa +HU~fT#h6m'5~7\94؃|lwc`:sdkc]U,ֽqXY$ QiH[ZֻC 9L%킝D2h +: DQlފ`y +oK~І+Gp֭۬`[u Ղ5=Qb+=&8!48+ǐsyqx`-q~S nއynR* $;^|cIRPnI^ȅEg^"p8CsFe u%/B߾\SȻJDtfe$;FC [Fu#wT=BԽzm"|6J!_iq.$`Fj^{Bd1y`cN@2;J.J>.PaSwEXh+#ʰH+(ҁFy!r6C 4)ؒ @oVOګ1S^!H"] 7uk_T^@nUc>ai4tgJ">rvrb QQMO 5ﺖ|<%]Ӡv[MF rVQ`V~^qtm=j;N_i["䚝AG_,O%3Y0KF@-yJGK*7)y%2 J="2De|Dj>%; 5zBGǑ糐֘ +Ê_ ^"C2eW}]N'*Z适{- {j0,i&Iw2\Y'@֚~A-A›W\:Ɵ,lMa S(Ls/-(ˌ+ksZx I1u㒳-W)[>QfQz~حo5`VIL[ځg I.{ƻyeE:Ͳ6Q9;f"#4,%W4RvKE:|3-c- 0F,)xDEsLE΅[t-szs*Tq U/g;GP`s'gLP#׽psY0zv'4ĺɅt9G*vJU~|/ՋBNTNkغtH={p:]T/V?KʍGeO6t#ys+qWܥ +Obx?bju6:V^du_{թWh#*ؤ'sw~䝦 +J*O +ݣ՚ڟ2PECQwF֬xsBNSNEg[5IUQMm߫;xx xr9]aB#z"'·3LփDB(6 qkfOK^KU}[ NcSWfn'w۩)޶MqαW9OC_ށL^P!H<4G3k5I̕?ضvv\I/|/eH)w/l@Ij( *ǞN΋=[sNsC쮜j) }|?qաNgA:J]"]֜}˕z8jO/Ѳn=x/ǫch9~JhO%IӺWxawi BFz1@V?rXUGVwkaS|ѿ._nsg / G!նN{'mbBYik<0eyl+Eoi*J]ɴ=/;>}j)CXDļN2>bmQxtn6%H9}uH.<ڿuUX둌p-yv}wqeKѣ[$Ï^z~~)ۙ0SfݹZ+zַs\]er .9Z4@&s C-3v +S+]/)éٿFJ_SuL~;!׈(\VI?B^ n`Oyg9%{^XK|Co$1b&0Wjh;78_' 7'桯X4+Ol~"ߞ?%G[v׿h4mẌ́"-HӸ(U_~ rYtmI3xq9PI;Ϗ/'7|{1mw_^VU_;/*?|,ml%ՍoV+i+A婶XZuD\&a[7R wnҫʅ|׮}GLy@-zbY_NikFFEYlrlI(6ٶ=l+ʺkrobXͲo5CnTB; ٜY~t;͒zIGDOڕnYžv1PpAf+}O}^=D l/@J'-ANO}ڛq–-bC GkFhCIc%f;U? >f-?|so( ]>=>u@93927o:٪nvsBQmp]6i-ݜeE'3v+lX!s^E&91KI3{:V5fg0yz5]MIZMgHhoiJ8z$0 !Ue .7++he85a1sI+B + K-QbL? MI +U+ +=[31ݼ;.f2#.!u +  Jcv<[|sH)b{`̶BշFC;5e6plMNb~udY0p=b+M3O{+zo`2x,;={#8=_Dc>P8v$8lW읿OQ~`t%,8 +\XfC̹-+ޢv59SndqP+;0MJCtpf@2:J7s!JVeӳ l)J,W,CoUG詼X2ugˆ}S?;kǗ~ i Ӝ+"#K4ZRnb$޿sH}9:M``"F_Ɩ G߅2DQ}x 2 d8fs +xhaf1Iq;T1/4 ~tUyYgų6+,JY8) <0|C-81z1oWU+KK4Jf7N=~K#QZ#Fc؂0K0i0pH _j㎚Bdc Wՙ fT JƩ3[ct +'˛CU2U:|jP#l;GP #t.ZM%H5XK>C=E{%mkb{f{i4`Wq7|i ,D%ݕ+JQ~QL + pMy6ahw(ݝM}Nf^[ 8%ZTZ  qAb{L6nfj+zN:$Fܱ2>(ؗ;p{$C7BCȠFt6/p1z 0f ̝B#.atd %tƢfE6g,4?-`8Ίq_f2,ND=lADs[.j.T利|N,y )4X8\iٚA:NIS6Cl,8؉/V%:@jozv C¶ZcgvZ)H؋pE =TT@ܵ%bcbB"y<&x?a!={@>[x|X^ H{KZκ`B@&0HfI)TgڦvԮ+7[Aƚ?b֭,mh%g[2WY9wIsgpˢgͻ"J T.VK~l_p1tZ]C݋tPv=d,"+9"dd'z=öE xݷDkO2R@6%5yy4Hi'URM[WV\|/0|QЛ +(Mh⡼Lh2r4 !BUasH{&X= Y8dK!98ʥmL%uA0ArGbZ F1Z;MXrC .׶C=# Yi +EMRba1֜5Ss+=w?gvRԹkwZJRMZox"Ƞ+ pڬ BEjY7+1rf-ɒ(cf?kHu_=Xj{(1Vʹl&U4eS$.yl,Y-YebW^"mUwiR~b3΂΅*0T˚&^J2å\k&` +rNԗ`!*2(-_B3@wgGdpz4Ϣ6_B`M 38,ꍄK'4羥ГZ$,"rzm1?!@Ղm4ԫuZ.\# +|eԴ:_{b'H: 3ЧXjA7V Sht_yd5Zx-tf8BVa|!B-iw ?.,eTY,F~e;,Wng:)ZήE*K$TzbŃx$\Y|,Elu ]kcWg˓{ɼu h]NдyQxͤwj Sihx*ڶRłUg!K«a& !$')H|0!k?Ft3J@*HQRw3xQEUG0?ɨͺ#_nL_5ѺQi-?eG*3T|;s^Jώd,cNbNp ڒ~N3B4E$%DYy<堍]7% PqIyt$?*.álj +%n[ pq0iApn-]-5kEQP%q,n|ڕE\lFjW~Z +]N`>"SeځeV!a'm1ڜ2aM ח.`8Ƽ]>#lPZ`GU>vR59(F1á͸GR^HF`b"~YfI@*Py93V2XpeHoWJKy²^ib v̍ٶzG຃<&hG 4 BUuGtF 7B"Xl/vI,@:_Ő5BK/33<4H1N-p_%9G OkS- +_Ky|ϴHivttZ$F6;կ ψZҩ0@| ]Mlz'.՞:T( MR0S 6YFVCeDjfA+x#EMzh +'vPCKyv~!" 0Ab?0TT !Z)nAsfCNa6Zl4y=,c膀k~NHkQЬ"AC,:"aD/g?9c(A)1O<v2kEJ^`nUYV`(`/\2:4ܠϫU=D"fn<E~V ݇[&b)sMkҢf< \ +cYq9 +U'`)-ߨ.Kd!@6}v]=59G9 bq?L( FsE)SBS5bnX_k0sBTI(-~C-V,#<8yfmWt7kWaM:etcňz\轊o54Te&p3pִJREi'=iQ`Go`D$ieM+H6$~.mY@@ڝ]]gADQ'myfЮiVЍ 0/`"ѝ^JgBY!oKSF7SB +!u6F~2A#k8ݪ7SOP{]ʰl vA׍o謽ۥԯgs:zOI?G,'rB JeIx@sz/?ӾSuعj'k_D;v + %Qv +>|W(pp]9!܏Ԓl^8B#I!:aoz5 +Rr0_hDI |[u [TIVyYj"{-\1{fkvEчO}\& 5^ҙ(e+@0חt&, +vzD~GEZ +Q٨-X |"-2Wa.XÍR=e jS/6 Ff5q\~b̏imE/(kW}MٓcsJ7o Xr(8^sG%mn-x04cq. 1u +5o=Z|zhvɁ XU$.Z4:NUICSl&|ˡø:y%%;3/cs3_G#E CYeo'GFTLyLO(?I4A,/p9Z 9ًd̸&H\(䬢pZ~1!A"@EB'z  G 0$UOpgC+[Z@|4?" lop]5#Y"\I|>f=EAEg`J:}:h/bLT t cHf9o vv^xpmН OͧG"NF-7k76nL /-Fw\e`<$ԏ|n!({Ò\X#[b|=]FC9Q@aϤF^=jf-Lb;Cl[|C%4jkt- +F'JМyi:FhsB?9#{r)RQey_7za, ʜ%ۉ*:=E8F88]L9˥IsNK{CMaji؞A ŀ' Ω+nM2lΖhkyq}ˍ/f3_d5)ڠPy6ĕp석L4i(S;Ů'#?w` +MyY$Rj H =}&ͰckǘrB"z@=YKofPP-XSb8cVzUѷ0 ]hh` cHl }ٚYp?`M͔͗ZzR~]1KԢr[:8=ƜN3Wgі[\G>p9X&VSo$̮٧ɢSbfV>r[ +oÀqa! P{$]Kl)tP @v \au}m QPx=& B\?bmͨ5uQl4,n6=v 32#$9W!JX |<]Ki%D)_3C#&2; !x*$j/em"ĵx +8ВhDAAxu+B0u+phCs{J_\II/qˆ}$/w/ /`}ΟS?6gDYhn^[C(aaٚ +<5'*xmpP¸{a0*(`_Y2a_i|Gʌ $2Ue*\,XG"Wh }ӣ7@}74xu>PX^ X1KXU,8Cf}Д-H->ZqgK!{ݍt Q_rY[es-Lz%Oe$e0b % Pc9o4O&pvX?'٪/dҋVc$Uo;[ ?Ƌrq07aΞ~wo~N3bV%5q^&Fò?9{6=rčaPgfs#w +ƒZ Ӭ9n=V!VH2^Q ʋQ}%ɠҖĒ@꥗G+ˢėek2b_\ek#*_ade=`"#9i}YT:ʺ`gxV~26C)-3:ݍ$Gۡi;+$zx*VA6uu$%)&AgqԱ̼S o:_KZ:;l]\ ο<A ?T6uR]*x37h%wvV$ꑊ Ym-WM{ZC 5B9_>v3^=a~==Mݞt>^zrLlt>^JigO߿͌}ϳ3$oV(k'%@LJ?D,!2HѢs?lj况ncQ03t2 +O! +'#3.g5Bnϑ!fڬI} ]:K(O? ;[]b} "m(ʹ7AdUy3 Eii`*g*PTDX̒[FJDz=WHfEG{~q}֪Wv%/^^}nn%gq-7Ww6~ߡUTfa!KӪ췳8mtpC~_2ڮp_g ˧ք.HA1-i'6#BWvbH(4JJwס1(XSlU &X43kz{Yן k-fnUgn_hr~]Hς&CTsU Eq dRT|9<ȨA4BY Ϛ\)d4D.o>̧hQq`d>lSi&aD8O#R_aKƪh0K{( kC5qAMg$T (xglULO!Ӗ:D2=n]+[_4(Tٝf/Vf;_DCV?v zNl>@Tγw^\7fS:mv-rvhj-幁g*xt~j տZ]*$#ȇt`Y`XnKD*P@ 1UFɧ7AMlCgN*ҿ f!,)-œ-ߤmƹKG7ndQ\֢Y +6J»&?|e$g5WS^QYm9@ݨRk(Nedx +P̉!Z2&s~) îM*e>^_u٠*Z!-}ݰH;Jb] fh +͵!e9Mh<5̦§Q#$NT]yc^ezT`~m]@L`8JmAL]]HlhHQ!\@,l $o4%{UC#߸Y\䰂" +Kh$JηF~]{:5cEZ/ -~FI,BJ<xu +iU\FXLM[vztlЖtrO{ +3߽m{g~%|plˆr>B J\g *'ꃇӕ<ݷ* @iAn {6h4#_dɷ;PGl4F>c&gOySkNo 㟯ɳ~-fзZ=s3rGrclXmf#޿j٪.:ތڭUr7p̴V;p3CH"z)9IunsoL.U^xE#_x=r@->Ň:YZ*x2MBݏDه L6Ӽӓ[nQڵdJoWֽ|vobgL-f@#fqǹ1Pn3+Q- [qQ͟z[͡wSluKqo:Jav]fAo5=W÷Zϻ4iؠ +?XɄOea۝p)n5"5Wd1!hںW;4YtyMϬNVAz[x&kD} ~ԺͳN`4/V$ƛTe!\#)e9ېb 睜TxVq%C;Di@huJ3Z0cVnJFDd^[ R6>'i +9pR0/}B5v[2k+3f΅Oy "XNHszm MCV7,Hk5X*Q^>ZM9Q]/̑#(2<,c[P2JD j`׀SBכfE${aX`9E_J^:K\:&SBS[ӑQwPjg~{afntEC7ʳvf/QO!%82A dPqo@anT$L A _7 3"Ě597Q@'f_bz:@E0ǁj9oB\"ץfsL)*!/t D^CeeD=IbFQLc\PaĦZ~+=3_u>kXݠuV 9*7f (`oMxH[sTKh?{~hcDX +l5̉iRe歹H.s}#oru#^bam)X~ o\ꉳ a|1X )\5GIK5kB|0rTc[ɥ6PT_7+V6J!l")=_XLс+3zXր1Ke1E`& J +ɆZH[ {&xcTZs տ>Pegp0IU4S7Q\Cu?#f M Z3pQ,g*[ D7hБnL-^Z=4oؽڎvvR0mGRyRuSU^&pD5 Ty+CߤB.Ϥ$.R&"H FP~ ;~hmȺiY2-Eh>r ePzKc^8&ʶ3')0ԉe TB-5 h\gD#B+x֋!&%s%^ (7 Z!eV3,P'L8s'Bn I7ȶֶ[͎nN™ݗR* m]U@7|#X{nqX7A$Xxx+j9T3 9GvT+-lU5eY7; &}A3yfv:B0GfIM[VCMk@x~* \`:Ë Ҿx> x&8^w,<ڛޝ7lH91w."^ksG=]hGS{(LW9O V}!~xO O6ЖEqFnKTE6ejFlQjߓ/So@ԖߌD˩N7mHAM if]t Ll+%?%KI*9`.v.듐(ގᢗdE MBiƢ UH6mZR+biZҖ>vjUwdgE2t:=ox +,_#{9a;ZK_Xn:-Sٮ*"b-أQ7=@u\wt07l?s̕D3^R/ 5n>="@=>"Ryh,Ϥ\=d̛B;[J3##6qTQVZf)؏%:4K%"z:NH(T*"4ZGzA5߶Rl_ȃO8ȹꬬ3^L֥7$E;*D f%?unנyr\6gSz> imPAJE4(H9WG%j_Sg;(K?diۛ^RTkϘ㌶8tԔ6nNdnKv4>߂+F 'Q0̣)C!~rwQ@VH>{0PyA귑x8*| ̅ƛ6*MD,%Ig錇$}0A.B/$. f" ̝3\wZkh`،u ̈́R'^#Lja_F;G6H%E];$j1mƩڋav +EM-5_{;C\wB[Τ6swGI~wΝrK[vʺm!͋+NiەRcKUw#q-:?tp+`?Ǫ{1CtTHU63@÷Ta U-ż qbvފUd,\i-Ϡ;AYˆcY?D 9.XTH&ug'JH?GãH?VkJICc]ιZHg-[c6m ?CZ:,ю B[k6&kMh ^>>R_)y+S>Q}`Emїay&5J2^"KU{,(Z$3WչQB<%y.&NiX1wO;N8/NG Th[3IML8A0,{Y=LP%4"7WtYϫ{PFOr Tc[2jΫQIt !7Bƕa.c. ާfΓ%g5VLϜdE +iV..^ urհģ9#n:WZI bMN|1< @CcyRB"cgzs1@%P,7Ò^1>4Uu]G$>B>HBU7bc8j\7O+/䣐j"'ݔEDltҪ=7C͠WN깳*>/9 Zpe](B4|Q0mj`/ͺ+ Qb`2Obnv W8tnr" ixjEvMfx0]fQ5݀{G;T>J4gO/@Dԥ <MAE0CvYU%BkU{G[=]h[+d[QdyU[VQaMP:ĄB= Ӝ4`=,JmV:FՑ~yki>] ?[8>77U&:ٞ.](HX6[?^dڋ!wZSIۧZ- 229])_IG\u șRϋGgn\a9PwTf]u D*_#|$-ϿuFqa, N9M._<)<QOH_ɢbcmTն)b2Q eŲ+BK@qtG},;(O +E SAĎq-K""3",<-צ}|ˌ0cv7LBZ܄C[o* +id.m5mFMڞLy#wr/a xIZ +‚3 &>m-k"d*? 99^t,ͽ<68ÛƲaBoEGX8CZ}/OЫn1'Z<plw7U[2z.ȿz[=rM:L\:lJgķ g+#Vs=_I/P#shĂ`m_NAjp b~-ퟂxpU1/,̊U*rkKY"ާHFp U>6;ƶ5lne.isw`i=lxEy>WodOA̙eb^%wvE[c#J7iv="{B@@_8**s ~]yh`EHh1@d[2R>dr̰),(H1*$ɃV 61t` Ϭ@Q91myAa$rDT=@V$ ToE!֧WM@6\raT)C7Wa>_Zr4=XI +T/ޢ m ( d(bZDwe>-7ڭr99{vKKI +#n>逅[NB+dƲ~:*[8/~:7 +]$ +T k5fJVFXN:;KEdSKV3"^Q~xpJAՠ0x1mǑ +㡁Ǘh&䗀3ƛWoK?>Dtl!&tId|kp^`KJ{Y.N5ypEO>zX}.:2uenj{3Ȓ8{2ޅpćtɽޕWg\f@彐-|/eX#zwKw<ԹN |:{r/UdbN JO ޺3ϓ#nY]/×?.Y(P{R$:K;a\L3>|Åk֋bo"3{Sw'UW)x^o)o xn}ovWpJrI1ĈäơђȑY 8[.Zs/3hAi -čFmh}SH-KCF&?NtwPs-;Tpm1UX#S8>r 94x #9jl#SkԧNHȇk!LnC/p~{;Pt9Ow "H1͑9Z4y7L!&9o!iJk @Щh@Z׵T#KMP)9 iRܩI%Y_QGXԏ9(fG q 6u^$Rv>SǨŽቐё̡|Dpwе@В@9l;'s%4@dE%oy/Uc̡n7y@ӜGӺpIܐ2{<{,|@~-Pc46lEN rfd84;C3mhؓx,oSiY &#Q qQ@f q>[0tFd !D\~PhBj)_i<@MesCAh :fE)/@Ҧa0H4qUAVdLL;WZ頋u9~(|hP2H(QhL +@U?Ges: +?!tur}ߑA/)K*gd!_a AZ0 1d(+r߰ QOOa!gVy]4k,Fn|d"PYd0)/ziS֙^4hΖ6BL܋>}אm)0\G+Y>]f<)e""],$k8v̊r~ %[A<)_ij~qNiW@K:Zn`u!6{(sG S]N.F!]ZR8&,߸gj r3/Du|rEoWwb3n0@Y!"!_=蠙YRRH*6^ 09#-eQGpH{^0d&YG[Hx:L&6k̩ &ƀK&rBnߌHCgI +q> +߬xPZ$!HrZ{z"ck'·G&RQ +PYOKYDpwFI:`)8Ϩc⍆yk)opۤTqA5:OjS*\T7ZhEJnܑH-N  }N%oOpM^c+wP:0v+s$`A8!-`/sTsRCwp{5Vyeit=,HMs[ŝ@.:!n2 g捡mH ¬]g^_U˘Cp"_xK[>x[*012 W#iZ]a  rmvD5~\жu_^8jv"|zy+:PZ_c.3iԾ7I'0M`Ӄpyr& <4AB#{Ȼ= ݵȴMTx(NoУ˼Lq xm5? N0yE9ٙ3Vsrv!Iv)IMhWx϶;$ ͳ#$w.u "Փx(4Og:Ւ#W%KN +$2b[6t rbt']gsLe7pOKmYyǩit~s4&*",axsMރ3e*&!S7\<Фq%u@b5 shK6xX&bD.nC\<hs>r'4qa.c*=KuImajT '-:z5 `ne +T6e);q`>yQEkv8: Z:;l0 ׌[ t"]t"1eW`UTa,Ǘ`sIjH:[fwm!㻼j&W C#-o{Ju)?^aIBz&zJ%X2z&qgGNq~p@%l-C:h!_Cn +OCMLH}=2C /d7%Hԓ[hO^ؐ +! TpgBƴY%=p-@},Y[ӌW؋P+/D栶᜝e?W'!`$˰ZgK> gF6UD J0h{W&!>WfRĞZaѼkë$r@ې , + mv={)@X @$!Y6;[~2LYid4f +6aݟ4É#2zxD'i]66aͯ +!#m0o+:\ X('JjySڞF ?p+/!>3(H$9xTzwu%*"h#8 +h^؜NnV6k ߤ@u1ȋW{~x%`1/ +Pf1:9./HFElfwHHXV%!n?¹ۣ9R*~uhCN~".3<do&K|r? rJ߼3A#H 8&rI[=ϊr^'4 $UB)-8ؤ4}[g(q ic2aLqG/J)E]1.H4RLߴtx3A*0ު[2Eo7B(gű]'f咘}E_Kޯ5_duwݩXMA#_6)ʞL3}@fZ QfؤYs#67;Xqm!ƹ|}s1hjIrCvЌ8*-w'61}ZŇ}׫YCl,] )3وAxzJZf ꑏ ]8G`D^ O+첬X8Ҧ/NRE.C;G頵:xnC痽NIJE}PJrS o೔"|$_7)Q6}@:*@$NBq1o~pTfoݱ՛L$ݱк-4bz׭L)2ǵIk!.H)aB<Ίt/qt /f`n>RsSkF7k|zP}O?Hu=|Fs ?O.2B62v\`!)G/ױz21H" fX5{[~uzkY䀳3xdu.W"N61d\%)僕 ;g|^߽-r 02w$4婚{۩Vƅ!Z,_c;_J;ovFVRC*[J׈/fS~˜LqMYA`֙_>m-/eCbWtȏߒh9vJ6x]9n]S%Y}Bo::aKيԼs0]ۜ¿hffI{Z!_)ֳ7WP5K >&̐|o )`\rsӎ9ev O;;:S's]7@eQ%FU )G6 NL}vfvjkF/:Xa߱qTfEw_^|yee_l` Od<Ѫ~n |ϭ^X|iI<ܴi['@!fȚh<̜ɂ>Z=〙;Ө~xK5c5ZZs?E -g\@HLJxDj\,z͚kR}mA"“Btk֑z%,Bc[+b`՗ +tCPtwBCXs!0GsXJ P3;-zi]LLwO-(T<0%[t/PdۛOx0BFF\ȒbQa!lQQ+§18YA*І#5J!7-,4@4\(tHȧ 8rO+9yr/lB(20׋gamGAm}?y6WT +BmϹ@B&K6{;|1(@`K*Tu!hPڿ-6x}+R6,7NE{'o7Xȟ6Pwc*J +)M!  >vnY4ٍ@wNBFce[6*HT5 :P(Se`/q{T5!E܆Q~B]"E 7)-Kj6K|f"T)KL\B\JI~z+ uY5"VKfVbѿ BM +ޠpkkWO A6r/:|B\,hmik:dT-to= SMRyْ%E}l̆@y .F^ 5<'l  +epӬg2 ,8{݉ "gAFO;8wAd}E8gXH_>H昣ΉS!=%htm Iq]jX+H|I  ,d_/ YSxtwU09Pce UQ^'j 痐hBZ8HsZy2M! !KK=$iՁ{6rhCoeة mi#p%? XA) t&i * Eခ:â +GϹz}Uq43h% EOo3 kIlH\ KjFT uR/Q@!Ļ}ćlEF]n<(a 9š~s(t=A+EInp[dPrX!PPƣ5JP]Mo yHPs۽il9 PK(YuډNM5 rZ|OfdPX!!>"A/_ n cՠZJJ`v1yЩ`vol򻦦|YM1d&3 hd|P;l 6,{ +OwQ=G![]%g +<7m&5;ĬϒI2K4%I|%13NP- i`K :e!ӝDbfm6 C]4P@WDYtYg$1dvCc456ʵiGxn̤7 $0Q̝5^n 4AgSa"8P J.!I-S+h +rI/;8¾ݟ4&/`ҟzSY=,րNvô02OLf?S +w+bMa>1ŻhwiYD%:ѦρqSs#3bIO?KY멛ɾѤ8DS汳$~t* :b=^?/DZonPmΗ.gt?~8C#c)_MKRp~`%Phsi8:/}dQc,'7[ ?QgEׯ`,8 w)q~}g(WLURū³U vYYKe勰۳ y'`mPy w]dߙ{sѸuy>Yno=W#;=7vL-?fmk矏:.>{Cr*,Ju?`ݱ#~xZ ?z{9Gy>?W1S'd;rqWOWxާզߑ פ!O+ W tܪ}y{w;ԈH/{!{2++0Ľ]>Moҕ#Yr#)u[VZ*4`gj^K7kӲ-KZj3XFYPp~|#Xi12!@>³}`:Touw(|W$F(/lU1BJշ$7xILQuP_/Ys VA3cR;7e0uȴ{W=|g)Xc嵕I=m5]T3 !{JmW"}TL$9\n>rIkz>*5a|6-T:TNtKljEI[4SI6.ϻHrqfm+ɒ\WoaAiV}rgl~, S[a; fDlɦPV\6Żksy]6r#`B/Jo 6^g歘߈*8ґJ [+Gނ5Of?l7xfp!d|I4qdM\B?}Jqߺ_?˩R$%Jf-xg|vvsk9/x`0z_absIuР{212do#+~ZBcÙK,1r.iflm$ 5[ޔikwknԭZlk} +[s|0aLKyN ʶ _ +GSh>/9tz)CZ}ACp$u"1BUskd$XiwЯT|,,>%&Sd3ˬ~=QFX19mҺ=qw_YXWNNN%S ׏ w6(oMP:䪶q&SOf[j X[0++^G]SVIJ^uJAyrz |[mOˋZ"ɻxnZYSa=rCz`_۸*t#q~٦ɕ:6Ĉʼnqv7߿k|ؕo#:D}ط<=SF bXK{/.&.?<\vi&RFjdZ8\Y7%:%]E`BWOsW'jbo~L͟'_|ؒDo|׬u8kƙ eu $dwTj4ɺ +4ؿ_G#yST&v&I-|ŗOk*ּO^B걐MF-1Ƹp ?{+bQtVbkj.,4Q@l_m}p>QRng8𰠁RceZ/9aETapʕQpSh,t1y~A Mapm(67* +U|=y&Nf=h<ܸ>Od3|?uD;gZRm%ı4fOxw/[kN[/nvӷ>ӱ]C6|v[m7s7M?DzlҲ+i ;[kc"Ӌ涋cfnQER?nSɫ7|,m@~iߤR[4=U3U^@7{t }M e oLGݼEU(U_eC0C3wE +l^,{ę{H(YzJ^}2 +fwbͮһrynLuZ#x4K>K㛖[8O.%.rA܀H-%Uˠ'd+Ml&n0Tm<|ӊtԋ0Fʼnf>2˵iaEFn&"WE.N ] Plɑ[wzi}SO +.'eBOS#BOm~?d>?mAho&їm:Ra=<,EazE'1H¼=0e:ʒuԽw <di֒JNB@) +v1&l;/2kLN>"ndsBXxYU7}l )>Ugz@ܷ! (}!lɲs4lHwwCHOƆRl_ZL9eV%IW`%8eRdosA|ǧ]Oj>hv,mp8?#7$HtXVf(Pރ"mtgo9Qo<=|Ը,>pW5# U|}#g@5fB_Y+Ȯ_.BMpC|C)*{кY>gU [ju5z)O "scx ^YZ/yF`bIOH`\TE("9V#M#ShcĹd'SL6-sǟQ$xehi| +p?Wq?eQW).cŀB1NJy}fe,9AQ4_pw@}̛:u.ޛޡx9 ~59LJ9J-ƣ!FS3ʥCMq&Gd"AON$VV=1}!}LPjd/8;"t +[nY&;KM8֋pp12e@fJ9 jBU4j>f7?4"#ڭ>yk m&lEEDR׿9]Ir bEO2)(iY\Z+RudaMTS<hIQ۸veѕ#v> +q+Mk +ɲ1ax٢*KQ>+@MWXHbDnJ +j)7#gF^/}칡dUD,"049uߚI+xԗ1i#!m$^d +PΑv wяV4aĭXùLf(z-堲erZVpQν[)L )AVP0p ΏAfmmA*ʚ Jmo wBK d3拾O>~ yDy!{ hkx(Jۜ/~!12d_.TDH,HiC /(ȣVT!-H|PrÐAF9=Q=Px!d) c8S"+Ϣ4W7 ΓʛZQc8Bn}s^@67Fߦ*** jlmIi df P\vuAFpri^ ;f*D&O +, +9ZP+T{5L"n4*A7QK ϝ+YO6F fefF $dZ7$VfxyNB}0Cv+ 0Qa32k%,Z[$j-71e7)7.-~<c/~,a>cqrI!4C_wo1 )L-+dtEiRweP&=j!#[N*Qc rb1YQlM؉K +'QhsH@@ +H#m:Vp ʯlH-EyEޗFөK~[~my1o?D eG)ōjFݻ@?Ѣ>b +ZЉ>*u9\Yb H`m Íu)&q̧UQ<̿Z&bNEEZVd%D Gc)UJuR=gxXh(7xghlLOYRp9F dV&f"Q(unf ^2ƙGj'G2p bK | 0ߚ(u*w*DdPk1Dt+^k C>&R~eja "2 J^a߲d'xyyK&mQz/Xi5:qFO;ƶb2>MѻmEs$!H8 ̦5#P#ޕM6&!w=%` n2-ybޗ#Ifh +>e0f=e#]9;TyPѮJwyF%`s@W9OʐN@ qoZA_ATIx1駨 }umNudjX}u +AU*-rU VL'߳? +u]r8/Q(s.Xa8hN/]ƻIMT%C,Y$Gi.f^VC=\"j9d?v@E(~1ZV0ĶԅH7̱5s0s/fwRaN{++]k,&OVZ:BvӌҠ@ܬ8y`א=I.i@ د߮4߭%=tWK.Huj%ؘ$>3y tts~iʬVNDf2 Ket>x nw,A&.Z(l!J鮇_ ۦ]!B򧕉H3@4 .HrspEj2heD{{q2h Ģ&I4H$:*6I,0.C^Kib8Hzb + Na^x`5㦅R/lhL{˘c ++%E \t/pIdXmh#V 04a[Y(Txh%2Syz]dh%%w l<wa.Pn%SPO]zO.6BF"շ;1zhVIKӧ4^i& _es(''l:tG3&nfd!kHv2w (be37QӴ +*̓;p2rcyt+PF)ŕ (Y/<f9,^j{d1юV@t b/phBcjw=`hC6? 4Mcev`u%f7.DžslxLB3B{\FQy"p&D#!芘bc-5GmYxx, | ;oŸ~C%hJFa^ O '8WxDk]$lTM\?f$D.5[V>h3f*";~e9uA6aol(;Sc {9[/n5S[=nD@EM'/L(MYSBGMrN"˨K|GN(UJXҀz)A^) 6#cB7LSS[&haEz@]N=4 +]COds1+'^~}ʩV`By+EДesϿIybBM28_sC`>C$bYƺCsO6 0@imsB,e;vm;:7-n88(BU ePSsLv r5 Y(d 1^"9K =ĚB1iv9KM@5nST ภxiMns1D:^T4Iߦ̺hmȝ#WQTp zw^'}pJJFthk΃+En7!}/o,kLqA2W`~@ i9"X0>e+Cz T}$dzX #0 he14W5cKTI@OMi5ŵDio$ߡ;_:w_[ĉÙWynKzM^Bu0ָ7В~ LɓL7!]eOmMRϭa |XkS%}>{lO)4ؚ.fZ +i3$|C9 Q^dõqQ{;SX /CX z XU1`aݍF1ʌPmHDrYiQ42Y[7S7|-Py9sMm\ъ_٣})0s=@70Ewʯ!@(t>v.:7ѹU:7D:&^˫pd4D$:+9; @Rv5ߵ 8SJ d|ɟb핻Cj]U P?=:H.J|ł$ S ~ PEmfvG6m^M“p?O{L?8y} p+:Y%Ak9w@FؐcN#좡1kE INlיw( Ni!] d_`XV0Txg?_Pki97|} ++ q J#@.Q2CSdhq48lȦt,سA0e/ +93G 2aLIeO`0!a]1,CbPDCeF<,%ml uTV؄nc_T X1UE(X eS]AKģ@Y;ΐhJu]m mϭVW1fIަ_ZNN1=cp+n]ǍSCUJײ%,SּwQC{҅Clam zRvj,ٍQK3&w0ñwxZW80Y`vd5ӥT 3)ɰ0fcCn%<-ՉQ(̸| 07m +64ܪ`;TKJ]Go04N-rdw%j;oHt߷ʥ?0ւ."m~8CIɒ + +M^si3ǸoDd1A(ץiMk+L|s)7MG-^LIHV8i#tc+o]d{Q=#8o(K0h1w(kRʼ o3gro:\fRյḰ _ԙ2oX>GնR~,߆O{2 y]BۺjuF1ʩɅ`qnLCۚ5C8FE[΄ϡt-y~kZaFsR56Aj$ke0Cu]=tҠTo4ȶ+7T5t [i np AC`rx:,cwq-Q 6G%1 z$ +efB86 +F ,&ׁϋm^Pt:W9Up@5>ҡ8=S(asOrA|"ANxŜQno*$,nCe%RM{mA +JFI׋x.`nï>RvEq>;"e.WVbJv>1՘|!VXu/5_N-i˪vg${q^R~2]D"xkzsVu;uSgQ#F(ԃxˏe}r1癥f[̼`+v8QO3HZ\Dk= gRѶ5GYl19ryCl~V:؈s`_#a仏4keo{:,~:Zh7Y_>3|gLF,WY̬ZJ⋇dLD"2YlUy[L{=Zǃobaۥ}ҳZVoÁN$;_P +ܱP$,ʖZo=cOIztm%3k"[f}d]/frؙ3[=ǜ nrE XVCb̷;v׵O1w[~˻A۩<5R^ *k#WHn6C Ciqsn-_}I$CYr /Iju"G9y8&N"+GnO(Nƙ:f!l<'^dӇznjE W }^fp?$y[{4vx3~z5 ?;31Mؘ}r/{oH c-Hԥ``F]ץ !@*Hf qd#gry>V_Gp}v/*&/!90dVԷgD[hD/k61(F%9,Iڃ;fy2 Y/k߉M/ eCwo%pWhTo8oO#{R.Q3ؖoO OXls5=f ~ps;@dAp/7]-ĕ,%oy4o(nDb4)۲OkE4 i6KB^G7%sMVpOn@7;I,t'уέk{doX%'ۿ׻"`xݣ4;>0_|{1g-_֍&SIˡK)1ŎEl׹C CSWo܃PleQ3mm03S- '9y/Vtej;{hѮw!;m=L|<2CwtJOŻ0n$Pj s YWKL.óYѺcXs}6)W[6+\pNŒW|%F+EVTTK NZze֎Vjկ:וsa]xz9lE|[anB{.TaNlrHn<1Zm<@P5[IY&`[)GXǣF3S9-9&c @%ż(2q +_6%v*;v̒0$CnCQnKU#ZmS`UIFMOzZ]+?@uVh #'|eձ4Q F}X)0.=B$2㧣-DIe(T +ObORymZC~[WȋOaA'fǡK nSm$6:mkDC4J;&Qlp/[8U%#2NP 9f7ݙfd4"0]νY;r%&iF?=#1$`}gmmA>bJs4z/OBc.Q(R$ t! i=KjdL$7/C/9]%GB[Pz:G[}K1IݸX!mBELTrVvk숚]c#glTA3Uhe0d!WFtIk`ԣhd_8 2 .P|QUr)@GW;-=8zE:A' A}Kw_iH 15bp"g 0b)t0Xyl }BOXhV` Πۮx5diEF#z-0$1-N> +a"qT1*jϜ7kFȩ jȜTW};64|!2# R:;~i("G2#D $D-A4i bɋ] +QFlПFTn.7PsZe-DPG"jw,&1?,# [z*}W7fO؊*>eu%s*zÇb_ ^iSW4~+vɰl`ih>rI$g +4ʷ:<~.$N2 a?>rn^?\+yne hxl8q9 CB!"3FԡǮ3h]pډ)'D"Lv]!YgB@{5-kEAѳW]Seeh̶&U݄GZbKG2g{!+.^:|5Ph(A?` .>8^{AM=&=Uby;QtթK)dKL;0X%O% ܔTFoc᜗'2aĎ&wRVĭ(:x%(c.UWA^Ad'#uJ;X2Vیd(ʼ$OIY7ϛŴ }!c<{!=߰l]P- vj>5p=nT{{vc Gq3.ݗ A0H:`\~Y_ZU3e$P84*^Iy*,+,Xe еN';BNl`NeQҿrnjb?PjdtwS2,NlHB}8b 66?i$+" kR0 PJ@'$}ULv i' QW[ y S ZمXяMKāibg6(3GM|: 7jo4_~o@ ʎj&" A =p`h*ZE`h'9ك>tE7!&1=DqX$Ӝ.b.w2HA&#-Qs + S[f0CBnfqsJRPs >l'DzJ M!.ļ/C@Z^A%Pu6#tu' <3P@D,.1*Na;(s;$iu0 %uPA@Kӆ1,뱖)._q"%/d;ms!cZ_(h`.4+g~؞+5 +@V h(H +кX 9GA GuUGVT*d:zV%\(Fq&Trq&1rgHII$-ndmcAwS⾶[IHD#22K]Cpa+Ҷ"˽eƘ`0CQ)#&̘%MOP \l90 +-J.$Eǔ ϠQȹ kJ@>Ā'M6\8YT9HۗYȈf#CвE%ܞsot)hv3̹ZB@dUԙ4kd#}l"C%eg'$֘/x6&h\af|[7Lj0j̈́c\ jX'Oi1t@M19AGX|+ -79NX%$ 6I PO:B,QJ(Ecxz=RA2{x͢ZfRvzGg^9E6szG,CJuŴ;(>VE lt)Ꟑ)x@(2QqX +/1[Z(,t]U{dBިFHJ$:.;Q/Pz׮m<}i>hޛԁ _ {d'pʚD1%&& +vLrvON$5殠2I̺ i䟙@˟4s,2*tmke%aup/0^ +25~yᰄwxTF '$8Y#i %IGN IˬnLa#t 堹r] +mO +rWCQY%|A:wXe1@%\爽*s'sX~OũW >2ȹ v;S [vSJ6y$.ŀ `|#:( .i.5ۣV7r';k*M/SAU1t@aJ&9%Oh:1A5NUR$~n|B,9Te ぉ" k荡+$F[ɍn^>U; T+DGm}EE,+qA௕//=)9 }?'Dy&N5 *"Y'I<68h9._g)3h~jSJ\Yn"fcҖxdoY J=k \ίqoSp_OIy5Nʢ0Z,'zڋ~T8btbV[zZ'P:-dY,/5KYSžKV[>:7\7sd]S$oۓY}K:qANJ% KCM'/a21V7_NXݳ9[ޖ dlJk&jvf;w\"vկKF,D'|{{YDGf΍RE#?J]ꜙ-%xDSmf7wO8O9L~ ۏOiiz\kiSsDSm|[s_bdk.]?k?_TW,]+vӖ.Ř}?i|\窭>$ka)o*\͓I |]榭]5GI)&=s.@ۚoqbB^[=ΣL )[y_n:B;7Vh^'RXOpZFyg|W =7x;f;Z^GE\N~Ѭ=);^tAxV;/MJ1E6sfF=a󑃽J~)s:5gy +]7_v&gJ4Bƻ{O&ߔtQ6g&6`|鸪Q-BGys#֣', '9?rXD(%B 9HV_ yUq] DCM.AWqjwu)=UT J)Uv޿\"0 %7yc&NZܓ,xf|4RAn)yܼ糁N2`$]Y/-oK'ٯhˉ\ck,ٻDW[1Mp>ȦysZ) s)&Y8J3ޒVM="`wsʹr e0/>db|o9TP3ѼTxGaK:*pSj0e(:Za] +߂V80VV/m'@SQ{ l7)X9~;0$MX^sH!HR]1~&HD_B CJ(أD wf]vG7qtУ+d.!!eAhg>5P@Abȃ'urAVN PLzVj1=@S7dړ:lWAd3r ON|*ksHFWxU^lJfszPkC0Y(ܔ rɱǻ^Jo7$ -4͘ҙXOZm+C/eww):ܿ.2 %nD#3a:/W2k.e6q>ރiR$2#SyxHHP"j(h >s~ +Æv\C,5&+-c<!-֓},q)ie6b"*ܶCɣx蠿§{H[r2GI2{=:Xt&C;X&$tP54$U7Q:iC +(ӎ~(ّKe<$OIYGϗuI*UHBZY׶_xC}6OyaJʨLr3q(rO .M"yʍxz֞Clٖ0g1}n +d!-b7GڰC_ ƚJ\goZ:yfI蝫 +N3#p{9d`Zإ= +(=f/"_#k%- 05vޤ+Ak 7 @mPi +s ̃Cw4fҮ&r3,wҔNH2Iea] ~9qJN1x C|C`=A2b ԵyMY*?Ƒm hL8VW0DbK[4|j낹JV9Zr#حq<dIz0Fh \8調FXQ 4^OU. 0x+=C!a?ϖ.-]lo4/ѳGnX) ]QƷٯg}?QQ+l>$m|,ix > +'H`Kw{E+Y8>suZUuS[PB̪0t|'M㥗'}71C.Ya :yr6Y|keN$ڵ:mqitށg sq7 l o}MN0~Mw>i!qy+V#` " +|y:ZaK`]86zGq$^e[8-c!!aK"{hD66BTg֚f Aߥk|/0S2Šg^7Q+5c&Me6~cFYhPH˾2qI1\ O=&612lMb" +(r%ld ? L+Ͼt>AŠx/J}84WFN4 9"@.EX +~GJA@in' "Е|Nkc + BQnR + X0V5N򙳢LR UUcvwHAHqWM2 +/Mj1ETB(ɍ*V"5oF + :˕["[@دWªUeɾڈU"f90/ЮFƀ:"s-蕿i +Q$BD!'/ G]i+օIvsq9Fcx_<]&#p D[D-Pa:Y61i#3wh0*\̀@Y)Bc1V8-YñX\-i{:ق+`mw E%fpT!ITF,?jhCE*~Art*"L*t%KXTb r A9kstVsBQF$ K4jGF@Yߵd#,*1b F~%B}4a͒Ѹ7s5$-k`&0# +Yg<>J<$H g$M>: +o)# +E1I'aܵP6R1m1l9:XXn1ҩw]4r[6m.{XDߛ_#UgNqe|F!X B44UahA4~8 +[&qG.4!߂4 +EBzAu7ߠ]' BMJDJn1"@"S}QEҕ D]j<%>#plOːQTm%A1scms͕8  ui[/k"9iS>4νK;Ĺ87:Ls3Y"gJYvoQw{ƒGg0h몧)a:ϼǑ +s6ʩz8as 50 +eBjpxi,`<+QEL +" +=Ul%4 +n`%`Kr'C:t&@6G'vݛװaEPʉ!bԑ!ᝂQxόjZ* s+CV*1?mC/(5>Shhj&QW"VV%|\SnC,g|)`AwF5`M@*Gl"fq2 r\׌O _,sHD;2d:/B1D. +9D[N*[ELPH,e}Ya׋C.avvoL)9j-y ۧnB*=Jz;nKPBAX9*Öꏼ(q - +x"MDȄi*%*qG1Lե6['[0 9WZs?Yg8&} "7 {Cqq؋n4Ľ`I`-e +RBTg`=h"W%l0yt;(gW Q +3՚;U&aHe9ʞH$&z.?;۠kA6oD4y̓G_qnbސQJ72'[3[Q͊l + q{~<&T>tXA&@f]w=ц8du)g4cnpUāh3? _(o]?MoN2Tю-3'u"Sޓ|5dNu,m9/mKLC9Tl갊e!wf*$|lO{|;_VI%7l~ eeNn4L<27 @c]#.>Y4J} ?f<)X4*đ? T F@NQw]4we.HTٲ>#ߘ/D29Ҭ o8+$œEB[}`_Zټt +G^kͰ@X>I^ m#o^\'ޫq.}U%9W ԬY6KelVt &w%o;=P@OwC{795+hOѫjx&xi*ă obci;^\r wdVVv ):^<)MƖx`9N YOLFQQųqNPRwpOwTJ:u+T}) ;?o-n=x4q4%NsF$GPh6`#sb-:Ƙ-3$RgQ@)כϻ2wʌ5qe8y4 /^l\X{x<LOb+U֕?d}VYC)奥8uHT3>`MtFuv OҭjYFLe*Ե׫a« 4YA;/>h(P[k +c6BRAA읉lsG$=kYbwR8N?*Q<yAٴWBўHIֽc<ȳz޹inğ6-:ɡV`u3wgVX얐bW$(wxnBb4C~@IkmL(~DhݭcDHt)aWm T]KY_q#2~ +BmE +yuW{"GJȦJ# QC`_HTPUN7JV(r= +U r\5tF0Zq+yô\"V{SxkXOȿK\.VJ׍jQ׬%=ŕk4;`DhЮ&*W*A}0P  ZVѕP&Qvp2c2þD[㹭`m3:*LN^uE0W84)NEU +}˳N9Nf冻@]{;4A^B:xtCll~B hQQV"w~S \84)whr-3ȕ>bKKD} a#5:2Q)^[T 5|#T171wi-횾\,ftv{w &˘a!Û3q'BqVB߀JrҼ@Ol/ p#" (6K +R_ں[dų +h w+>t+' TISS25~<ǘ1g\TNu-P2EݾÝ7E>rSؘTSFmh:/MԎmӫ|T:^Z҉EH Ц^Z ..eu( cU\Sbi9-H +xV' V +W@tO>Vos=Hj'(?^IX"+qv'J͕%%!N\اxp2KiiUo6m~dNy"Q/dOtH1L*?]Y6Zr;R3kJS6P2byj߲ *^Z'o|TN`c`=qQm2iwN|3tYl`}mnd,l+ףL/>dN95kN\]5bT=N?6: ޝM%X"Vo/c1{7t=!XǰpsZ{溺ϣ|v Wynȑ +h4q|#s _6yy5x8Wl#} λN+ck6dKbY,W:亶؇KRټ +gVW/ LVG oEj|ʏnF֚^$Vq|Y+wX>oޥlvQR%NH%b[i=`MjYXمs_\g-\\wj|:닷&NM~#6OS.sI*B\s=[(dtd[וP9޼D>=Htr?g17G\}=>qXEM޼'VQC`u~a|v[%CY.Lw~ɼ/.G̑a1;h0Y}Q?q9槛ucz _|=bZLpnOKω=I0QSw3c +UG;0p~-!1W[U?7 ʞ(/M:S/`ÖDzuvaO91+B{S$8c>YM`l(QBߎc|ջ#ܫ2A| ЊA.5EQm-$*k];6m ڮ_{)]%s}ε,;T<^ @|w Ǖw=?S6܆wvN:2>^uevQ{-gMan;۩t:o\b6 X` kku3=W0 CB'.z2䌌\adһ3g_ѳ& +endstream endobj 100 0 obj <>stream +eBOw +* +1vG>_B_|scRg؄<$^DԞY4n} Fka*Pv0-iY6X;cV>H:姀Z-Wt@Fw'EzW< ;S}"U耲{: _籣.PO}Ѓe-@+MӷbQ7aš +}E6mDevDύ("mL@hQXQex:XH2Idgvx#.dZimy yk"˶֖KV覃v:G8k.sPFL.s nԘ/T\[G TL-"Yd=-\e1SfJFAs;MP q9R=6Aq x쭯Be1;)'ct'CVo%<$H> ȏV>dpWbPL";+H t ,獝!E y<(ć#Hmb{Gɫ%D +FP׉@P =#;0(?Nt;!O + ++(3Tgq bZt7Nc%R5+ti~f2jҾ3HlWTq6M"Ht :PIgěTC:exI**`ZQjj_aD%NF 3.)8kB%mWS|m Q ߨ?ć'Q3b{7@hmcr+|*RD KST +^{Lij T6|YƁ*o3mkrg6fFXm +"Z*T`Kx69\Аf> 8J tۏQ|F|iØCoD".zEA٬]B 8_V=05e +16r ޅ5v:dxXa0E1$*UQ7)'B\> i%F;AA"'bϾA +Q +yEP˝*>˺=G:Y9ȝ31H:\CH4_8߀GK -bpD=MS!# `=@ N!gF;vbX,LS>~W(N1]n)?M{eAy!Yp2)vtntPe[̅#,!FgSRJG~{>eHJ1HSY[]Ip#NNk-4%YuFVVƆKn']7z{L,fjW|zA +ʚ} Y +d:\Jږ7#&t$in%BPN9j ! )*p52"S +ْ2l#tB/HaP i~q$l1AT +wbO '~{\3Q*f\0tsa'4ZhpcJ MOqQЛkRxD'QISt4E^KY/ D?#m芾􉮗&LT?"blTyw;ypvC3K2۳;z_hf.<=/iNA4))G!LyznTښ Gv%U ,@p#AUeꨋ8 S`ר<2#z(sbUO"7*b9x /Ez@+rT% _r9֎zEX LZ֎)"xH1ⵓq;gNcx3l?͝2"zrT;[XPRH fJZ/nI3hJ 3$!{Ә%4jIl0 '^]4_-@$X͋w8ۚ4صW={\ke"hq 0 M=w]X0JX2R$ +F9Om|# Lٌy3G7+Nw8_"4T@]o0"wb^Mt)a *"_7:Ua%L!|Ad*7v)2&* \ݢqzջ,]̎zcXgjmSdAbM" #P1!N6b 00*ډ= jxa \pÂMPwljI -I9KUI7e'-E>ZgPahE/݁JK2{@Ve}Û-#Q^aE`{3(mgoGs*Wˁ}y0N Z4ވM~ +z#\ڌG4`$ƳOiW! ϢθQ:vNWۙhX.b;`#rˀPvCH=H{{4~G\Lxn^٪@h٥$JA"g/DB- @oFLX{mze/ٖIQ‡x+ǹԏSǁdwy2&:/\v3ĖVrYwԢF; TwrGUG՗O, +QYL-RVHJ'</ht{I,5U/D9"\ TRabH{#mlvgረk?vS=yeVz|G5R~˷[M;g?A zH}6sȖM?A\̷D t co)15iޠG4z=UKf)B-wS絊b!0%am" Ng +իJENW.>K]L4C`+y%Q/&֣껞^X@wb')3q:oǍJV3rjhj dьdmLG`kC0Oo\V].6ѠpSh?Su3^ޤZuǧ!>Q`Jט:ewAj9tSsT^|Eu-SiM|Ś' +#l#a t\9SLܐeR\2 t@M&~53bEP`Ρ3$s^\ϕh -h$`J, O`!^~ n%l+wLںLKn@"2<䒏%U8U,ihp'<|h{ +,_=Y~=zFUi.:M\JA.8}:\(؃сc.89&k0)%T-Ȳ`ALD6ЁzOK"te(xݙV7`plXvNL'}c\* {>fR{s;~G֢ar7[ASr1Ub=xTOlVERfeTMjKY9pj!b:#m鿴FHS;R Zniڰ-{NXVW_8a탘0.NQywP+o[FeOW}[eMI~1piʐ,(\$g=x7yx-bC)Ɩ#q.}8HI`Sߤ˔ =]i @b}̃{V3AE! Sp,Q6 ~ʼnjc =ѕcˉ K^`a,ֶVtR|2L<ܴ~}ڳG)˙&e}'lP{BRo_`gdqHCLc_|-TJvDԞN}h>ԌQ`Ur|FK<-/PTd\``47ssi34)_&TKU snAtZنGyYr{,}8. +N`yX!GVx,pk6#0*ǞN`ԝ2Eeos;CI>@CYO!Y{- 3|%CUbʕ_.#)nt~u~? M-tH֨D%IAD P`~v<,aM{"'&nPN, ,_nz/%l%1 AqM8_ZWlP +1[+ u%`ѿDÕ,p @?t,Hc*"_|/g3;9g&fUbGddy+rGz#OxZͺ'əp)|,X"Sy8]4ci ގ=wRC7]-INiqW2,zzidpBD\b*|A-Xrn4#~VfÇ5Ml|W<* ZBA8̏0|(CeqjwV)lKY(#c{f'SsR4E1 Y4Q%@L.8PQPXba3|t?>A$ mY\# 6xV)bEeۜQBwac~Y<$Y$vLT’`aCmQ$b㯡TC C VWD!N<Ԡkiԃ!ɟ7MnV`2Q}HL"!0)A4g$">@:z堃 Ƭ9Ώ5 +)ۙXZ9_ aQ&Sz!x>l6!+GCE "FgI%^Vib ,XzGXQ,2B,QMEeQ@NӊAȔSe DT&dp0/ΔJhyD쎵87v{:RP a"}6e"2EaRFxu|<^ٰ M)>gFVhPTAyl`)LDZ6TEV6U2CiR b 6f)FiB 8o6d=½с YԪDx= t_T% eVG9V7}! bѿvoIX<.}QfE0/i(}.3}EI{Aũbu@> o$wd̔ *iM┦&?={\VANnF%. +H00,|!Kǔ*HDgD Q_Glh Ms*.ųѧ ,HG9ɡA\ʗtM8sW2ԬiSheW؅MΈG~h'g.r@_Sg"ix["%ɁZRh 1W~is-SgiM}2^t)^~RѯނԊ^zD/|8l#Ň(_hܮӧG2z?"g R,!2>.9ӯn[M;PLɫ FMih./YVҖpcK8TC6Ϝf^W"d0k3;ׂx됹U9ɏآC13ĮjAԤD0aO<~u>կA

CY wqϔR>]|)?t<)U:,cfwy}wx@kPkQtq6J$SPX\$[(4 c7ޤlAS~ד Q:P/iGQVouژ^k^^((+jYnħkF S*:Mk^&/> uf$YQU_o~1 _ᖯjG?n2s{ `ԛbo'¿oge~5~ _S %qQ LÿaNd! +BXq^ȧ Q&B>eXcuӏGHHA[[sO-yu3+{Mަ'/u}nOn淒Ty>.7/&]̾=2^Yro-/*y65_Sŷ?a};_f/3;voϥ$q!6D6jvv}:%}Mp{);וċDC9@ nE_梁p"a#[s!',\$&,̲ 9M?[~}:oׯ#CMb ӱ5ѾYܼ,7ڨ (0 !٠fwRy;ϵw_%W;(P8DxN`BD +J d (G>又@42D③>JD ; 7XcPHE1$FHꚻ}tɿzOYnYix ggD~'M1|8 Q.*0se?kh( -ĆoP;}询h]&:""D9vhR*D!H!&78k3ujp(b$±dG7;~lѿ/mrk) paFxexi5Tvբkk7Q9U?[ծkG^? +!!/]cF|( n3[cvSg:|QBL(p?Lۮv7]wYw_UWCۿj׵# bQp$]c a6!g! n3[m jCPg!VqHM{?Ʊ5U]˺ӧڿDUpUC[DȲk>f0DLe71Ejۿ=ı Ũ(Wôhlw{juuOUU=ıjv];n]c2zI%1Ej?m6~_e?ӯ5յ]ǺӧjڿDմlM#BQGEa36l1i, KFw<%p'%UۊSh -ʊ~PKj̠&*EuObbH`33HX%\|[a|ЍdWE^k+e\+;O_Uٶl؅3Vֶlm+^1ٶK,FhyU5݆{[QlmTWB^=ڵr >^Wl]>]!]K zE+~!mbs]lvmE1Q] +>DB{+[jZxQ=#[lbнJ 5l7 zE+~!nJw;R>v5#oh{^Tv lV=sjPa@C+ԾP{BFD Cݼ "ſ\K0n$[o m-nmoE>ku mU݆{[Q\dDu+~ P0 +5Ԯ|.uʎmZ +ޅ\X7 zE+~Ao좯W^=Cn k` Ⱥ +W@Ajom>:jh=045}檨e6Q.8RD2eʊ]QP60HH[W}_wڢ"):nmy6&+^!ؔ[I+~ 60 gNDT9j)1Q]\> =f_oiߕ0V"\zlmTW쇁'6go=B3jw9jo"퇁hD+ҾCvi7F=U7Q]q>HVafE]0BV;|mT +3W A훨0sEw)Ѯ!&ۈ#ng?}D{gϰq̹ZZflhۨeHA $7QZ抴P]EMAGFu+~8 5>Ϟ/|l~?}ѷ?kzr?2>k};ɟލW}|qǿGK7~3S}I3Tya___|_;_JYS+=vOi>T[,>q\UEv-b=y_KjʮS&ɏ?a03c^bL-XE +$96}+"aѠ>-E;k eoT,W7#vAW/; ~7JNk@d/Npe|ȿ }b̭F/R+}7s%.u7/å43M%{{M~{ tύ+ʋ? +ъ֗/^g_@ >{G|t _}?~r/xY}Q>Vί~_}d\೏Uʣmǟ? !NBOc^<n$a'c>~>YpN,mݭivNZH;$jeudw_9.) teTW鰾\~ sn:?\ҩ]LHxB<*>K9a Y?[q)GV{ջπ }cqOd So(q<ޞc(].뭲nYvTC^#g.IhW={%J5/UJO'6($ +D_ٺo‹dw) KoqJwI? t!./ e1.4/ R|[U/?*xe1Ш$qߥ|wbϏt>Pu7F&u8i.PlKR$ Jm.(B$.oTdҎX`QrUIk\D$MHB!bjZq[:ȚUz9NQcO$C˝${;1@(Jz[4R23Cx(m!:d"DIiԞJ6gLtĵZcVb`ނ9e rhDaA[-Y1'/-Vl\IyW׳˷iDh$Iɤ~kAnپYӃnK୙laIp8 +7-Q*ܰ|2TfzoCwPkHdl|{//5vp+/g|hV.I,-]!O/.}HEn8_óxlF?ܝ|YpɴdpO 7z{?T?QOڛ۵kkG t}蛘Yl콂7^ e+]u$DJE +__n0a  +rӹZG(6`H5\-͙!6LCvN$0t|UMI=_cO^ͳ\γ=J+,'ݱ8 1Rԋ8lN+Ls{nwԶ!:No*>mzA7nyI79_ߑޑ9 +;|Xi93k*Lv}Ydew>z}/ +3 YںȕaJCU^*Aorn]QөͱvEZ[s\7,g,\I%ɩb~}!Moh[цۦrA "yV7Kk-PbtKݲzҤBAurH=s}z,L'E.NJYCe"K>KpBwN=`!_zly=FpKncGҹ]C$E[7N32׃0ye㱢v]v&;ɦwfnͻ%.bM.ҹ,Ka' iEF_!vnۘ\ɒ +y b;$`OBLt?<]-#NF- +Sl:s#ۿG좓\4|I'ٝ4~N;O1kSrhXwnWk# @4D> )cĺ4 +I͇u!ߛPu323B ɦca𓈋k%_82 mnD"jyv 8D:VzkwcN^tUjFheZq?^z| Gr)b{~bUI @f,3Um K+R + ͓I=0:a@Ne,\$: : +iehic68$еK(T8h{\Z4 yfe^X[lbw;$rh?pԌpQ2nScF ,%h,6%l8u0[4{ڹhzRhk;&NKLJK\"ԥĦA#VP&I&7 +T2õé)4Xo/9ݢÌLgܶAS" $V裄F%]&h9hN!9B,KVt("W}'CSѸ݂K_T~A&j7Ax޸8A*Rg_ht|(љq2\'<ўj-1 `b`Z4 T(Xzu)a-Cp#Y7qiz"`TaF#z\b-pHc8N%{DCK''B?PqG;hJ5^4Իwt[%f4v2br*v$έ(A73E7'bUsC qj4l@e8q/)gZ]-_`>т3$Ia$MA< E9J0\5ݐ̗j6-@ ?Ӣ c^ )( +¥MP0\)iS޶ `‡`ڶut:5 D^7߫4X$yT[/ˠs.nV PI*DǁRzv0[D~;L@6ۏet,z{pԘ#nҧ *:IhP%AƋyQHFJ\05J@[)p[O&I7rHi˕gg>ntlC"2rϲm#i#v9\Bu'эG5`Np b.baa 8"La:3 FCCm-OC;NjVx4+]Y%GuL`m>Jbî 2AoN.Q4 w㌋FctjƅL9v"tPcs8DSL:fD\Gؓ`B1# -HP9($x،53ʭXփm]/I-qJ`$ݱQwJׅ&ofV2 Քx#m>/ӊz$>z;'8DĘD-fay`f{$n? X/5 ɩS˨m*g' *'íB55 p5C:j@?m(4C%@fOq--qh:ɀ -I)(8sҬr]é,'3r $~pMQŋ73>(օfC̔Fw|ĽD;9~h=c+h#n@W0` tpXiafˀSZ7U(44!](lz9lF,#!;YNC1鵑@SZ .Go'A(sŽNˏ6Wy#13Jst4g{r#1lFہz7?;ތ`ěcnd>#Z7qH7vD '2v#a"iԯ + +u{Ba5_Їhpα"EL,4(qYE Ҭˆ@s>.ծ7j2սaFA|kd\+[ecQrdxI,%4#[?TN!R2mPfY q:^8ŏk0W)wXny F2Qxft ʹ7BV_tS D_8|&mRř0F cxqF cCJdD|.@\~}Y +&LllU% $LdlJ;:޹ R#J@+ӓޯ9LO 0|eb3w"+\6&%3.@۱s 9rZka2Ue6@-w4ю mF#|ŀKg"QܢnY6U#A'B܌bo<͂XӁyaAԷGp!;YWU_S yx!iJ8\7Pj:EqM0LCLV0 @`dNEPCؐC pHLՁBHpq\ pkb2Eaڗ'3CX(6x(~=Rf݄I{Xs SU?A,X,&R蔅PJ0MohR4jF~)ֲMn2r`ӕjff(&OIEMYc <AtٟcǦSJV!Ź+ \Jôc뵌.C[q[,e CF@,w7 ^aY|TWlSE{W ̉$ԍ [YhYƩv,U!5w{u>,D|GFKP0*pbCZ#=,D,ei]&D2"̞T b#R9h[`Nv_ef ` .2TF('_'<EΨ`N4Tr ʖj yϴ)&!jш{cbŅ&3 +4ŴLЭ'{J*F&@g]S6aX+ 8Gˏ% QFhGRjNO)<; ?$=fHcbuΰ+r!k٧8q.f|w{HՂdE"j!F/O]xa@iC)K%uS ;fe̽EګV?n: * FbQ, /-yyt z(yR͠DDleK#ޓ$݂V>baF&}N,DlStPoj $ZtKtG0&[Aw8{s%͆l)+Z\p5"">t$$dHB"ݬVG*prIpl>q,bU!"f$ĝI:j0Ea&UJ$ǬCmHD%YJR%L5gXe s?mBv6.t<0/S뛋QE9ǝ_ڌDԚێ|T@ekD!! Ʋx)u.J= {D<WyX {VT R$أJaLpԂǬ Bq14֠p3I  YLa'SQرsl!{G~ܑi'1%#QR:6B~Stjq$DO&䦽2Ȫajc+1'5b^?7\acAy@{T'f5/I Fөв +T:5iҴ!jidctŭYcN)?,jyWn,'?Yv> p11_dG$ȼ&J.-vcΔX,M̝tè+:: - d?kZHmյ2tK6 +(H +{d#M >W)H##Ü|Xd4|g,1{E/|IL"ul{a`cDLte 8%Hx]9q%,hr<1/M^!]đ'&97]UQ`K'R$ңV4MXDI-];$t2魹 Ɲ9eIgPBWAhjŢYY6|"=\H[(dZXj0^ɬTQ0ᩐaGJ޳'ey:(6ˬ'ȏIKGrG)bY$f Y}L-(%G"u0@fJҼL2= G԰N(ss\$,[69Q$LgdiH1(iiv4ű6H,Gpɛu]v3IVZ,ϻL( @@}b/r)E҉KF$ _w! 'qFBh w#Ec_˕$E<-,pc0AõdmMB.w[b !`L>\,v2k0r=T=RBfQq/X}/`/"B&.22>J&-q&Ic_yD\+ߒp .xCń(T&RE(_V3.9v-`>0'+0 2%l2IUtȟJ"[bG6Î?ʼP#ƛM_B_;&zD/LD!$R"bkXpąGXF%EilETH Oς5ȃ9ScK0rhDL'3n%=nO\'-MjMh"[ `L &{R ]GNL7%I5M wf)JBtfD26E{R,WKb# g!'he)%Q0> ˃~g1n |#Gy=i%)NKy `nq:)dQ2~AEأo#opcx b8﹟DyR΢ {oHfLq9UW"Y3Lpl +*pm7 +䈃enڏh: K`bTEp,ԉsԁ4.oXgxG<ˆ8ձBհ$s,IFP(uZdgp"^h٘RF2yEFsElxbBSjdyMa$s&E-0o F+Hq2NG&uڌE#ıBL; ,E@nHV(f8Ԋfխ!4ig\\|e`m/P$]q(CP'"r#D/PqfW:h"[ial\~hixG\!KNr9TJɝGLr7vQ*5e:YXͦIw9XO!uV`P%[lD<[4$A +R,L1{E@CvNM&٨->[Ť9Rfј%ÞU08h nއ# T:G.[o>"8sY|Z(W#<h旪Y%$88E ?:)g"őPut ҩIÌSfoQV1x;Qgȍ.j*pT4XC~X'YjŔ:QkHét7rK@ǺBPz1iȤSuwdȤ3vKeodEJKw{#uʖFj=`6Bl;Ek<- Ou]Ӕ;al=pւrD$M:1q#g0eYx +tMdJZMF%hp$Pk"V MfNtJk ~}:߭o5üZR.hQla^4Hhhc]էdp 6ĜNTo6xb̵VCk"FM)\S:ڂ߹w/eִ ["R z15^GA[;P>-G񌄯b!g.l]GgRe$ؤ OYjŋsf]ɢ_qLVidRZ&_ ;el5R`dHX"g!TѤ!ؒh}9fֺ#XNG p8)*+s(:ӀbkhBvE|Jﮣ|YuìƎoc+pz(@fVtJkzva}(CXv[{4}: Vh.l)BLiuڻO*Yvr͌~B!#ՔT5(V{QJr|0 cfgb@3jnv`):tGN$m1rYa\E-!W<`S,ʣ: e}"š`N{FpTS8vJfVTRMh2G3 +{]@F7Unۢ0AA mFXIt ,IA+gh g'PʡZaKF4n<2"x>HäxJ3AxJ +=?QglBxG*Orv]~cdvH yX#wF6֕<:S{V @C@'qp\8\Kgd2*(WGlVXUvaw-cT^(:+]R#4g +b.yFF`OTљc+^\s'̇N$8藵#rtFKp]{T2|<.S )k4 :P[`jW'Y +U&^!0(V&|XhE%+,fR{# (O"s 3sĺY7Y3shyJ.%iNe~̊myU>} Ȉ(sqe`֞7˖Ө~Q(a7"i$%`P'jM"BuY,vՅP)U(}_] 2+du Y@-db4;V4dVzF 6KR,l`5V2DV`J kl'c8?Z?Қz>d-[ǚ] [م9! gd[YUuN6lR.Jvanwa7?MF/eJѾw$$(>=_%ZvRqM{:FA/v^~hV|{_xŧ֯>|տ?[_|ŗ=~=>_=LjjJ8 s]?_kxߗ|~0^'H{_9O~ ?>6>0VӲ nja6#W*y {xသyÎV Ltȭd8 Z}4i3z!Y}:(F;(AmȬl(^wɪ:i"qD)cCF@V6ܳ ˬ(xAjVƬQGx"/ٳL67Tn- +G}Z!ЁcASni*xRt]']!Fe2#T U \'mva( +ܝDMnk:9̫S:9}ŀyc`8h&;L/b{$,XkR3؋hPfx:^JVX^Rfp{JF7¢Q&> dT d8Y +ЌpTD62GQ 5uNi.YZ6ڼlk^2U{rSf_XoΥē4t~HFǶ]5jЙ&c˜8Nɞ&E PH#;*~öjg,':z£nT$:|ڞ3 ]=wt=&߾-sNOW#+9.=IMTWƂ܆3N=0FL}4VRAy +"5YsxOGxN|V2 ={[Kp]_ y=}`˿⏾B\[_xW}w_p]M'3Z%pfoh*&Of~p__| kV_I^|6AzfdZ NXcSӎj;#Ip|2蟿xM@[vD6|Yc]ٵxF WNɷ;oSr Y/h? KnĊXev0C^ /[Qg)S]`>G{! QzS4<}z=deo,2[.v3mV-2ίJu]H6G4 VZŇS\X`pʨ٨yޡPٚ +z }v>UptiEھv46?~1E.ހ6Õ D=kkVLJ-boJ^Can"Y\ky褿 :K+ Z)QXݨuSY>c trCtΏd&Ig9%{ZeElz@-vٱB!ʟa4VAڴݏi*5SxaEoh͋_T\.m}gO2OM7O ):^[Tre9;ȦD3f_J5ITT4݃iwIa35^T\.ȕw Gnƺ-_]qo 4bpO*u:%v)D!ҩzYLKc}_ڵ5^uot/Qܒ*LXE7X(OD$f2:v1;]J4FKdQe7Ϫ4cnƎ^s{M/e#ZlRoQJO8YzZgJL~M{Q~<-EB,}5SaFHU/zR^OADo5oz&lv2/M[dUenyF$5U4tԽS9Z)P.@Tn5\iF3Ej 4[dMr;tmû7 +cE VF@ 0jI($̉nچS9m TN\[&^".;Z0蘪6 Qκ4/]&:H^K[ؒj+_G+ DPPL?)뚡e0x)tljmt>In.57^h5JrwfTKxme=hn\qlnH2wL#M-9'臵XYA->7?ӎj5>Edg5эgi݃U.6Z37Cg~!L\<}hd=*kb9G  2wNT薓@ `5h6\KOs71uRqidt]&Y$bxL  +y|:A8UqK*emC! +y}6с& |cyXŕLX-tl]|owqXc NvRZj׍Xŭ$8K'Y h./tkNml=eل_BGb&vj=LˏGei-䢮>\*z ;ll놡7?7.D:TJz{N7PUPU]ąX5U̿w*N#^~WM,E[c x6EXqc +ythR,"ak7 Htv-ua/7 9V +kKߊw˙VՕ)ح.!JqƦéfl@t@,d}AV$I _ڪ6\FV}OsnPJ(Vm2Zc +˗:f(>%tE+eYaqlo[gi^:S`\$uT%.擦zĦPĭ訔HaFfZf̈7SGsUK8[I-MdC0q](-eOY2,qwnn4o-bAEk֗*2lX;򊥥,M3&> @2$ '䤵Z;,m)97Z }$gI`@8PQ%.L#d9IG3v=۴P%kT4Er0*yQQwΝS{*!eᛴHb_aqB, τ2PDWP+fy0S`Q{vӥd7Y8E;]p&rzO(?X5}:JSױ/Usz$,͞&RF9}"|-鐊2i938w|R0gJva*ꂶxY J(cLq5%҃oS{m0Ui48]ŵ)$SOhi +ɆȂV w/NDxyOkFG=~]']~ +t/]s{r_fw$|EkzDN$)f>@i9uYNCiiFߗ|k(}]utYC Ƶ(WJ5cڷf"&#r_[DžJ޺z] mH,6#tLΙͥ{Xi{n{{X7T}}xaڙr7.Mp͆Ҿg!pX\d5B2|>H2+_|7xo~JK{|VIW~ZpxԂ{NjByu6G.qK0H 8zF q<_r#ژůK;haJ&F|?xٵ[og$R5հIcnHQrcwvvZ4$o҂~lϨVVR.Km׈ jm+ԾEuFw}LJW^'x{+oWt?MYiGZ*A$BI:n&6C`Ì8{t(kGA>1YC`zR:<16]K ,[R{ZoK ݧ!,&ʮnjŎ4201'[NX/oQ|eE9̶ߓ =YCCDkM3N:M~:i&0JoZ5*,H +-Y KhIS!DC+~L ix [.gDC{̞?1&y"Y5_=A|E(.!"4h'Y}/w7xˬ@k*>{נcYQO]%8DKN37h1tv/x^D=It䄚gD#˥Rspàϟ**絾B'G^\9%#$Nc!ix%M_}0 tncuB`#6xF!kM`nFIڶcM(,9w=ZBI|DvIw-ql͞&&0}k]77rKo(&F VYw#cF| +Dm>9:O4l:;e.݃~Y.y~zzBJZ$P;@wyI>СF\jr `jbWNX^딴m;O5|o[g.HIX,bF~K%F f: +w,X 2q2dnY;ǼS-Rd6L?տ«}|[V7ABM +tӐnY:#;7B/4̮̕5S_L6"xu\-{`A j|J(YQ@'olZe2oqZYVŝ-% `rbUIKȷB3Uj#HOFu>SBwYe~lY?8ph5nV^LTrIk\!{NH]heu leЧ<;q{Vj9MGR 0g"#'IYIX`v7ELF>]ťmRl:GyʟQ.&pKuttɤZsuګtoם0%s =TK'~ö t9sԜn((R|Րހ33Y553pՎ5^(]pw= ˱gf3`.xKU'YJv 7AF^sݯA{''+rVۥxN-@5]&ճ/@ \1rLy0Ǟ"oCɣRbK)=Ķ?}z7rTot}Tze/j5=SJOU1t-H"lD88̭}*oW}nA7]?H~_M~uGS*B%${M0MvI~j"\Xo)ڱ2FA~o ?ެ5!R %,^M~_MPHv+0*h;OI %rQ~?! {Q +rT!~Eo ?LziGr+r8KW}CAz_CMPWbP]?Lv_eMvU\qRQv?!d{U@F#p9(fW|sNV@szޓ%|1'wy}}nՠmdW|y_w_^MYMo4/0z9pU +?4tǼ}?aW% ,i^ːsҽxL%GDú7gx/#GGs{`{x ,~9?fc_ |˟_V\Ce DVflj Nr u].*2y +nj;G꩸ܼke.QXҞkuKGPt5JNSMY#(Pw!hĮO^nUW{# nwt:6'+b5W-iAםo{OOyL3CT瞵ޔ@4ET*quF-gֻU`T_{~~b@{А¦گ;滿WR[MxmZyv3]btl?VԺ\üPTTFO5曮otW?["ϗ:/N~1ksn$^tR@fziBVtrjWF= +7=kQIB|"ȼϰTi)A;OgF蘹}Lwx$44Woδ\d ReԶSrxL۲涓Rے=賑c=&DPf41QfP|COĆм6VtK*c=#R;tSS E/G.W(]^!{NFnzۃn$[Iq˒23vz, +铣]Sւ5dJ z6b'D׉RNB,8np7o ~},42 цe^'[YõA7 /|ɷ[ōңLgGv }n~|{luy.&ii@wF|,2;@heŇl9+Km{bV}w Gf+@/_1W0jִ+Dބz+R.|d1+1:W`Rlb 2O뚜5y 'M0ւڅβApol5J:l@BgٳA֭fKz8U@am WglK&=sK/mӜh?d.r@q琯WT;W.`g<]ˤ|Iȴ:`Dh*Ĝs 6O׌-̈́yO.P`w)SJ;kv֎9m5}Y#0%$5\]|޷;7Z,vyuNcvDgEғY]AkMIii*['I&Ii)4u,sf8Z46nIt3f~#Vùx6}g!C'/ hxoi>]DHΗD"=_'=huW4{kЍd+>٩=ΝC{_O>go}20A7>} Fz%!\L/LI .T||o}/O~g?w?gD%g?/?֟__'՟'?__|͟zG^0ɿO~? _ >}^T/?wk??{7'D?_&ѷmeVUD+5^|4w\{'/O<~ xh{} ku$6_(Zԅ\x8߀U5^)~Vcu\>hZ|yiãr&$?^6xuKT%hg;f|;wҊPG| tKU^B9S_w:pB*RDgr۠N3{k{Y>Q]XZ u%j"ыM.EEwoR|LPC_{|D[YA'H&poM+Սz4U32'd]aXFB%|H,zHYInvQZݲC/sZ)>(-3 )C[H~c2c}muƎXLvE +:ZSuJJ2@r+pH3%iC0=1\=Fip=a;e&ͩŵJ_$rRDMg!1'2j~:2.8x /t ˉyN5 Ӿ4׼ΧP VP5T"ې[QFϗf6Μs$H e.NjႮ|麚?iS?boNkx(/|RvJ.R}=ltE+j]QZOj 'VC.QH&%96l'聭up+F=E*IDQԞHe:jHRS|l)gC%cʚl{;lB?vlmEұt YgdG?\ZvR|es57<~.'gd<|kuʣƝ,cS-;0 ѡ-A_\ȃ=gҞsdJ^QYR2^n],}ˢvyBb`{Fu³n$Sb!ʋwoeߓዪR״lHJ &bbWNi3amn]g>9Ko )V jgIݬ_sYvrw @hٮKha'TA.#KhcyA;ֳ%R"qyRv̱ge.R{J)X^ 6ڃ[zjFrhnKS+Ufڤ(W?ԝvRZ 9`WҚ\KuSG7g3&hy-iM|?Ru$XA5tzAei7SΡW +YK!!N@m}\݃~!ПGK>WjPo?~cس/5jGaCm(t8zų <:D%v@Tb@b4^2Fd(z`[ +t}3!!ËD6d{;q UnyХH3 T +IҩT[v8OkUL]~9I4%c%4q]vmqt8iiIʲbB.Qݶ1@C$H$"L $q(BȄA$ƶf >gsNZY~y=hQMQѤKwnڳ;b%IC`l/x^BQJ=^gsЖRpvlkcosh tug)͗6FBVVI `y>#{xυE=|FV<펻|üqNcFH\}D4K]-DP20Du5-aۘapˆHRiyԮs4Eq2 NRT(}'(@i&'2%?ႣF*ti<̵ źAm59 k唩RX5OiTuv֢`*6T{-n s>Y7L+2-1kI-Sn0 \!4+K]1؄ +H4dCǡJ%V/脌3Y d +R8Te=ӥ1MEb*tnh"MIz6959nM8.d$IgiJPĥxWwmY'5pln2YhU mqvn*A"[7On;㼼I㣹9I+A9-dDCɞ*/v-qؖ#k%{>~&٪ӵKII:^2ځUĺݥ7ZFM.~c ߿5w~rwV>ğKKi x qʉY{i7R)R*WB3l1vL(;LWMsby^'3UB%J)x7eY?+^Teܩ"cHբEiy+K7!&=$R{]j:4:6s:;[ui@LRq5q“7IpW@ڕ& zLjYObog`÷rq$w@̋tG{c cdB϶XPY,tzp/\.% n<4t+NS.f]0ҏo@ <ss7L=~XSiF9p?L6tܳقARFanP;qgM^2qguC|ڒ E&i,;݌b,,UjmnȮ|n k\leGjN[ t M [~peUׇL:5.=i?@zk~rwT"q7AXI?jCn6ddk'~eЍd+>Q|Oֽٰ}oߋ%:~w"ĖqwI0*iAP*UU5 ѩz=_{6pr424hqzBˁ"ڦ &n\;b$d<- rU&$iWJے{\u•\z3fl]Z&MMײNuP.e?.܇3 Rk^M֘ۨֆ|Dab/Bs_D.` ia@#Xnnn}{Og@X$exC9 k L^H[W|r)BPEPR?K:A: n*V $KNUз1PZ7ZnF -I [hKg9 +ٌz/^iɝtJ=oڀEw?}-vY~l̊wFIӣ9q%o6\{p}>ϗh0)amV 1ҢRC' xׅZm/fHhgIꡤl)J6:m09.ϩցQpv_F9Mԓ(K{3ڇ`;T?gy -Jxj jG;0Ƙ9;}= ~VL ЌM}35"[\hRH2~; T!͘KLcӊ)-| +&䘷?!]'_ ԼoKh-_gTg$Rmdkcv;=d!b$|m3fU[.68PҶu~{Fo%g.E'&Ipn#[s;qJrPk5.>+fQ$Vp35mzC~Ş1F1w~"[ۗoM&;b/ݞn_M/=vq ;>ya)[(UJBm%~h`26r՝S]?V mAh=pV޵Rdo2\Իt&r*^jJ/?g|}WdbPS݈9٩pcN-Ù9Ojr)p$#NVCriԈ{R)MVV] S\@9wYAO olwQaA.46H<. c[[wɍ4}ׯX/@A׎^IAպB^[ud/́͠AsFqO=k/p#!2 [ݚMgmkِ3OQZֶNUM,DO MUӊ]pЋI}Fu6)B*߻[9Pz=@XK qNyriw; sl( ZFӉR3exzRrfJ=hUwiQn@Yp7mکX-v.^Cn3IFu=~Z:$"`hz$ FYTE72gX_91$4B'żXT +k~୍/^PNd.#("M=]}6Z5Bo +_.n|,YK໦32߹P$!KRa/.. \#d`X3ֆTc2i]h-v,U04mU6bz3ԚQ,"Bb5:j9|RT#M!ah`4 3 mc= M/֦0q_=BMɥ腵7q2va8QLI:wZ}YpgӲ.%!g+}޷˲;!W}RkTX0̩šf[˧I< 4u']:!|&v:oKXXm5Qk3G=TBhKM.&$VܔS*x057Ѕ YZqS0?T/0wo7}j[MX1vqDK;x*X~zLO3= L;t#ʠ#V-,R%_'\Y7`K[$7Ro6֝Anmg;j^z3ЏF+,~Tw*zyw>]-}UZrl {{ hlkz^~:,)J> =o?)lj$kRḌ^>^jXA!,*ِV3yg˭{"Onz83|$~4z {*K<씑TX16!wv'N~NK\pg!{#x{諠+n9 +zdVQkNv>mwp97Ṙڢ7n綏۞޸[:Ƕ6Tc#ʈ;ݡ>KM[懝>hK!Mll{Fn3F_@[V d;}muf .qqsyuh{F +mo1pn%[s絻%snbR`tg/֤էiI8CgdVg+K&_VnKgATrH)<ݷGno15nϨV-6j/֭d+cvGSv,vgn|^jX@gd׏s_(W(P;ˁ":u,کX-vv.^bG$SuD0mKVg */Q8+bU:fಮH<#L5<0quʹ:e>742)#YT_7KP.QuܷA"<;wLtt_°~Tġ)BIaդCN5 +Ȭ4H^HVձLBYZqJjk}ƃIBo>6.kSj$EP(L1*F/{SAZhWkӒTiZQBѷRJ$o:"sL,;s<ϽБ)N*uл2Z'%Gһ&Eñӆ|~e;Tѡ(Ķ$5BգDV鯖pgEFdF:Ө!@0A-s+̲GTtuKIb Xݬ3DcLc_O +k%V\g3dV{r=% i%r=hd6c}48] wͭo¬H2@ג;SzIilݏazY|Ѝd+ݓ95='T:\XOݴL{+[L-{RΨV=)h"J2nwv9eI#fIg<8kSl<'XL=|낗E=awR8p-)+bݑr,^GʽIq%6pѼƮ\{B9rH r +\u arʐ34e,A7%Fx@Ÿq!TEc2u^Cg +]1jE,T)/<)U7+dnƾRf 0t89K!Q&ݖ\5A=b1zkټNq!މf) +jq2IqD҃x (@d6NbVؚ͙9WF3K;}4jM鄡uRX )gC*J[Ԋ(a/+F1K363|9kdRQ[bl)z蒑fppa_,-JK +n1XpDEo1hcη,4kÅ6gS~6o1hG܂XeKGK6}#xHNS]Rz86]7H2)[60gݰ.Jo&\ + ^a 4@BZ0%)h& &S2KnRAU:x'Th-p)&I4z@К]FdRh)͉ig/ІFpgWۤjXmHDt[)t:II8%=(r\o9cʶޘN:)-Rt "gu$h7V 9A9n VdrDCkҹ{>~6/3v=H3.K}(-:b[|"xÏ~xrki'_\Ry5wMstdvJa>SuIs[\7@^O `+i*NZ. +qY\7L&iG"5i /e3&)zTd-{ Ni҃+11J:aM.OY@DLebI*Ġ14\ocU`N[23gC@GTJu62JjڎquebNTr%*rTT>4Rc+l m#vS R;S*ALKTF;}_?ύ5A@U|)da]tqs6qjб0(V/Fk+GuNuN%PKD?&g!7x6_.~M>;Kߵt++>fµm&xoY`sv=O9RޜDG4!{2A+_VRNVAHzanZِ@xL6 +[sZJH,-9%\\)')Z:fUC +2$.o& |se߶޳=+~|1/ pmpYz37MS.$NjC|F.p$K֥XݓiR3K1V PǒCpog۳j7Teul._NL;}̜$x);|h"٘( +?v-Q v)lkddRSs⤃A7 Zi&i,YOz@j؄uZ+B^{tpSəkwFťDbLkjwjK=dRGjͥBsd+=oqI#LW}޸3ۗlDYPwNr$-+xwWֽgn$w8zsXOmtfp|&9chkpw58vݝپ83ۗwg<_iy\U'˘ +Qd--ZV\RLm d1\IVKd.^tc=1[*Հ(Fo]b9ˀ5|Н}g{YIk/fSj蜇&j;kjV9]kOL5&M{A'eJ/{XU\v# ştK/Ojxp.Z) ]fa92u_5RkNx$H|ɜ;\lE~(+ZW UOzr&JP5Z<N.&p'jkL.UD~HidK2XLW>ޘ惱N [_L5U yM%= +of4:.kf7&So4xL9̇n&rYl76F,mԽu\'}l@~;;8gjYu/BUXZghv X~:vۀ zÏ6Ya3[x:hƉ?nC>DN8G؞ćlzX pj)H/6Kbq3l1~.x,!O־꘧1O;Vp4zԓ$, 4# ,@RS5Fsu*+&䐒mT#n:񵐔i5ǽƫYWi/6ar-O;)(n"]6 ?^Cf/]5]b%Z4nj%Ǝ&$!52/ǒ,o 1c0%&,m\LՍ.w4- I+sWɻ=ho/z%ׯ''T@\_(V˳4E/=QC[>#%4۟;`]]7\bM=a3FR6>`%ɭK:'KOss5N9PNj^q~]-8uɆ՞;Z^y+4N_wѧס_>+Ɨ9HtO}<9IN<# \e7@Vhxr6ώB8zF>HJS:D{7_'?w?['o/5\O???//~O OOWm?'C2}?>d?kO??N?ٗ}"ǿ_7&Ɨs澭Jm%$,v,}{?s~ח{b˕tN!(q<&7}$]Eb`EO a?S_)=%ň)I <%Ym3s.8&~x3Bⶶ)FB}Ҍ5^<'!vNJvW}N}ω49S s,nW/l)4OrLt03/I+Go|I~Շ$D)cEKKأ.J'#!}-g `Pfk{(Nm50]j}"=(%vn 8ZW!E16}Kn]I< Knle펐s44$nt)sw\5ʜ +<1 +YI$}LLޭA^ڄ"bKaH>J(OEV8,WO2%#X$ed= 5 ÷K͊mFmI E(Ou0iL\uzL!%CDyF$ yMЍ"_RZ _X½tUK+ddji&~I90=FAwt&B :^'ա9]]zzD7b -xM JYKE!q1y&ɰXo$(B%B7Tț`VOT!P_>)/Gt< ^Hz$<fNgmFvN(I(5?t#A gsVA!I쪔LQM#Q ^[ȮZV^7gcnZ8Yem[n||1GJ: HMۃiЍWo(oIlQkFOu 0p{W%r\apA,U=h\5Cno.H+5o'+DOt^߲q/ߌ-=&YK`Vա\ tcͰ,K%ߊTt2XQ&#$ aK)b ^WiФuTyֆP4 +Q5-wQ4Q//v1т1sh3Op0.dܡ`iLLv&XQzפ>N +AzOz0eóxv; uH MyؤwX1 C(^IwE+hsM aA]{IGp;p2\8dBG5% Nx[ҙ1uT}t)gҷJ1tIBI-警?*6nj[q9,쫝4X4V-vKN$:dɼL=T磴Vl^n!\kaҪY-5tN|imldY 鞇;i1JI4EgYE@: ֹiD,vsDF_+R< Xr!KrZ*9dVBKӲjZ +N#J V9.4li(H㬂18n QBj X]Ôuz hJڃ +8Ymo}ҁBaNy>*k`qXN]2h;7t2\LVi<<;!Qpb{rO#[ 0_@S$ޘAAs4vk? 1ѯ:d0=IS3"Iĕ: ?nȓF&iĻ* 7wN+#&;d`%| "."kT~Hha5ړ?]NCӻt!N.e%1iL[+b +8\ 0"K'x׵$%GZ8rI1#i@NSJ:ujR˹0(]yn +įhtq4z r 'Puvt(c3PeKA8ak0ю4oA@J<+$ {Gҫd)r5B*1ff~M&M'sR /EsgNTjXmdq +D )"x 0 +y|h4KሡD/4Dw,ABkWkh" ΃ħDLw t& Ŗ8; F0pLOudA7CpV G*H. N81shylcL6Yy '#ޮGT:%R&C?PhptY'u-_Ѝ$' =SCꁍ KӁREMJy*laZt*ڳ; NL#)ɤWc 0y0 i$0N + ˬE_ih ޷Q;:*~u* h|XZ +e$R- +?')ܝ JLtK8Ŕ#nL+G^1qml{pXXt +CTD3Z&ԪqkP_V4MxxHBMjʐNk2gT:b0GZ$eD.FXT#0t`\A-ig<2DD7Eս/ ?.Ŷ4eFTuli#7'+'5G&lv ZN{( i::avG7.5F&wESْ +]0znwzD ,pQ*ƭ^"*N-B"V (Zc0 fh$>ǣ$W ҙ&I Q5m9̩T쒤(ݤ/2jK, /xj8I@;T ns+OL4^.W=[d zmrKg+B3{,F77i +Mwx 5Q5,[I=4P }`u6m!^ +~,ht)Y#*Һ͍Tup°Lw#4'v)>mYjך A/@vqnp[:GҊ%gabLsb`*͇i*[ˉCw Z%Y4d|cbi1 A#6`kQOF1v&&)J0e'Η#<XN`N4t!P7D(ΰUc!2wC '_EV=Iќsa6 z"+XP't486!tsǽn̯ƹIJX7 <)elؘcnV+߻Ak%% -r&)2nPEjaZ1K+1s1/LzZz1w A1|>ƅ86rIeեViw@hףd>Q\Й)Q8>BEdZuԅWx?$td= X&"Z$cW$z٘Ds cq/4lqo8*ZO*&@A^6MUC*9lS";8E*J3ΓhPR{4TCOn8Gn:oRn#$ CsMq%ca8S 0Eӑ,yܭ#i9DMkXŵvf(CN`8[׹(LKrBscIP.;O,'XՌ9k>4#1^m Z]@ i_4c ]Ld$I]VD䩐d0 \alQCAx9SnQ(!ɬ伎%8U }B30h.)DFBN $M_qq6K>(@6ҬFhmk +I;MȀ9]6Te@y%59Vr\pLhB:θ߮5 жӂW)SmDa g2&}ѐ$6&藣j"L`aABHQxQçhU;v5G#NIb2s~1 8sÝ V@ mב2J 3uKz+Jj3Q`"b&#nN ?р# 5q8qZ?y +W +(0;^CX-SXD%!Byƅaf2"㋼dQqϞht&Rs + 89I%c5Ф8-t 0/qޟ׀L(4$5(y J Q87h5I@ !fvr:b$#a&u}ӇÈ,M-I$;wyGOA"x:u_[|.Gz C`\BWO L/,{{Φ1pda._c[B\Xly] sZ+ blջyV`F- ![d"HpnpdI%Q}-$':1i0Hx0)ڦ*ubF2hI|dhZRxc '"X:HWd2.m{"^S,gB6CZ"?z.cJJ?4r0ij8fĔ75w NwXn>+zЕ6CV5(KjVHJikD;OJ8be9vįtkč݈L֊H #K&>QƼX_yC<k)ALK;f*^p6˹ѽ/$hBHok(joR8!#9(ol<> +F#ת?X>=BU b[,dybdT9s SGYxEǴ%ӡ.up"+ .C:MG2baqiaP988=uFDdy c<A~F&#v)\N m,>,dua/Z,*SWƈTnu2/шYngjiUDqsߖB8(ීIX%=)Eϛ™E_DC ].fQɈ3AqVa15TBfR/׼r{HHƴKѺ([eqh3f7F@ϝ,B(nDZȸFmqFF9Bq#y(?ӞxmL\CIG])ǑG +I,B؋;1%1u!C=-=J2IPiETNH;MLKjNG~DlA8%" [B8w$Z2e4B8ވx#'֓077v񲎀''t !1DTFƔ@%ǔxQPK[Xdn + ɄLJRiߒA \wL<3$VK{v.c@zn#3-ܳN]6iL zGՑ7#!1UbO>:N&x&",YWEw M0@#@.oѦla4⡡.z!Rb[LL4Vf   U4A)BBU9z ጝE y7n)۷NZьaM@x!4ϟCHZJ?S_yx5Z{%Y$eҴԇg^g9`S4HҢKׁ qs(vE+WId1Xu {l/0õu!JInKjd(%:b +6YX&Uum=1rV捪ͧoFmhtS82N<3n/Ms%[7! G2}:!Of+(;~ޤ ^%y2\V"br舡Ms UƗq* q |7OWrc喲W#37Nm%NT@nC8-A8wľQBFwVRJD`ҵ'8֑J6/y/'V5sst" "*4W+|jYgǣ|Vjp.kxqeVC;zָ +an]kY&C,I!}[H'Da)B tȏ~ƄΰrBtLvȎ +(@%EphwE)lc, (%0$0=4DC ze.(:^K};(0~  aܶFQٹ܃h$ˀidǧ5N +}82ٱ+zYG:x@uD٤@9G߫6>6e'H)ƵuIyp[:BI{޳" g䵫IGV:ϥZKeIg:9k֑ pz8i༦ƊC.RSM9-n%R2gNL\ky6=id;xI<(kB@dd3#metF :vC<:8HVFXSŌσX{ k46!\iiTHXC5b9خQO4=ɭX.o %Llfďhv;҃ /WK˥4dϺQ#ឣm&lVb&>x44\“Z_;R^BɳL`&:E"{ d DbE}LjL^D4^z<" [n&n' +k_.T`$8+q"2,ݦIIc-iDشͰ +S.IROr4 g% +t5ӂI$7BC&aiz|T@20e-$ȗ M6 ՞%$Y T$1:O/b##$ DeD.4wwᨄVQ_Mq"enӡ@<0PQ3t&W~tK`;Vc(1kGNxNs !YZʣ0L1qe2]!Z<[2$ +$/؜&uʅY phQbzz0O$Uʿ>.֠K.Rw7D;}pOݭ kn[Yp7B))Z1iHZ&|cnZdđ,-9caIY׾QݎR +dک2ͨȾBFC;h4oCBNZ<5| ž6;+Q=A%+:9H&풠t J|!|I.P6mq Nv{oM{bq/ң3gls!;dtUQ2+dp[Ub/#iyJ|9p ٔ|j+C11owG)qmǮ?ziF4/wNvNgwmͥF%WaHo8n4ΎH}K /ASfYY32G.3>!jqf =yQ?'ڎKS:Y3:ʂߵw/WhZnK߱O+'.O>g\;`sfu ?THY1UfD8'+Jn {H»Pރs(CŜ!S utNv{n`TJ&*(PSaѾ[3-@,_t%h{#^b\,h%RzUGCW`G ++>#YgTl>kgc|f ȱ +'&J6P|3`iy9;9<UNLT=%63>#;_)/{%:.!31⍕&]nd[I:-YD=ѴP0?bWi`9Һ w]OcuZ쬳Lڮo}-l1[4}JѾ-£p/ Y'jE SW'DBӬHRz +*Ie[} V EE{ ʣJl2J=Y[;"{Q f!(9\*N_#:CFhvx93aR _P/ [ -okrf,y+WhfϕGݗ~Z=#BjW?h2lܾ.]|v&ߍlICXgXUͰ׎;}ޥBv=8۔o>+I,DZ2>*F.ďeRG5LOS[+2 V4\>4%j.1JS~=EM=ͤn[Vh|)~gɌKd-(vi -AzPm Sh(J*C"Elk^'kZ2@ / /V=RKϔHO O}M2]HWEK{{U˵ ruqD2S%.i1WsK8\3bSm[*J܊]s hQJBO%ج9-/zj煡hW΋glM?AVe+y(hU.sHv۬%X8+pf4=-9“3+d^ ɼZ6; {-p{CA68mBfSQGv2d+%3U̷(,ۊ]"[م8#[݃s[r\$K{N֍94nNvanwn+nIJ>q YEJBvN@VXz}Ѝd+K_ŷ~ާ?a֧Go{᷿?d67>{_쳏n>?{~4~}c~[o?6q*}v-)Ҹ?^#̻ާ/Y ws|';Hx].=a}L?KgF#?}ߙ?[$#{];>>2:_=ɏ.m`so 'd7^3aaMWZu{l]ʜ ݓX.AZ/ AKoVQ +&= ғ/J+ZZ>@c  +#UjϹ[(̊<5i +qkP)#(_kR O)j:J)LX=lK܋-g]&JHM2=Q0qWhC `"$NT$ڥXHٺBV.>1<{H'QҥdB[@S+9]mݾiݺ'qFGQ$.4鞰/dUh MɈNg.#tU؉٪ L$O=a1%B3uGziɼ:TKvu6A5OdZvb?-Ee MlM$fUJGڞJiXi9Q[ʔ~ZR±Ԅ$5Xwk4}4>e?X΄N>s՗;'+jYWMg׾8yDσ^y7y?1ZQzXV- |uzrEy:/˜dsVurX%`Q"zإDv'e" V/Z<]7Hb?)=>I, w /juICY# ܾ-7=gÈRZnE<wŽm\ af|*%õ獆X8j\Zp^I =V]},Mv=J]+drG7BWf~ԧEDѺ">l_VRӔ  Ut(4m=W6#Rif6}l]TP:h:WOhȠm0ԎD{,sv*Y;FB}P=+[F !d3D-@n"hc3Q, jn~^pnVxWNxƝz4V0b7ভV@_G:΁@6ȅG?4/BvJ4DiŎσt#ڠ?9Yz+@gd+9 4B=6N(jEVeHB.wNF?B؊K56+!4 +B dJGr'y}aЍdmAyZپ2X]ʖmԐM5jOcwiZh#smsB[]2=@ԦI0HGK6%n[G+A7 sۇt@4ȴtKi綯_[=>n btM1@JX/#n2dzGg&ZKvglUj2HHXh"EvR̡[Fu>jReys+c5]rlĽmC ܯUi7E%*/FkK0hĆP[O:8[pdKv윅jg;3Zo(Dj+%^u$T:P/vFmέ;#xZQ\U\Ggdmn<}LGzcЍdkXm(-ݚ:ƞĝپZ$+72$M3O_践ۺcփj=(sw4Q%&r5 +a׮D!z?[t#c{5}.׾ BjM1ċm^[iK{hl[okZ~[^(5"ecqnANtR]![+n$ۙl̶glC}lK+PMkpȆ㴴˗m `Y\`LTwo%;t˯S_,sʩs9$[w#pgԏ +0u%/s Co&\z;9΁?^ʯ&ٵͰk/-n[ֈ/;џ]Œj-f(|ڠ[s$\]`AwQ*4D1j|7HO_}{?Ҏeay7+_忆ZWsSkhW\R*]I@g}9˕';37y36^{߾j1/w?gbgyL۽|<5sgy΋'җ}KC;o֟7?/Ay?Ыv[uot=7߼}퍯~_;oGQRwS7TTUwۮ)}/Oi?_O;?oz7ϫk[{۪;seWgxCOУx;? _{3W|o|?g7QQRwS7m՝mM'+_f3Ͼw?u>ϫ +endstream endobj 101 0 obj <>stream +%AI12_CompressedDataxK%I/ b.jͭ%/TUz4E2QGk +Bn H\8H F Zkɍv6;ps3Uٕ==Vqٱc|[O>z{rC6:<|yxӧ^|Ώ}0}ݫ/o}v{xm>F_|z?jp~ /_HGz&|߆r_\xqpdճ'>oC5ߨ(yߺEw~tyk16mmðzr{熀|.5><~ճ?y~ŋӛ/9|}l>?ﹸyEn}'p/O?=<[^vO^W_w|;>GWWOUӫ?~'˟?!y_CPٿ_?擛^=z?wP)7a0oaA7Ͽu}3-<3S_^(#?ݿ~G +Gh|n>C/ [>~?z8ξ>j_W/?7_}y^Nn'6 ah=✳86x?8$5CnpD7[o'/r'x*`,fZkAkkRy|?G7ϮҪ잿(C;}!Ϯy),e͓3饬45W/!o<}RD<K˯( >]CmN101K7Y6J #MC8 fܨI2ҮO(H>0{~bϯ}_b4 ?Ofz3ſ[, +z: ?~TnRV4X/&;2NϞn$a +}|.^} ޫW/ӫM}WlW~¹~?}Y 2W/GO.?y9OՋgO}ͳGkHO~яO \O"Xy\_} +|t/]}){ t+ +tyhѓH7ʅG9ы.c:Fϯ=>{~W>3S(_W_>?՗Ϯva_>}v_ճGϱ/jWO}y´b}wz޼xIyϯo_z+ H>{/=zr%zw(w`@_^xꩌh{u_\>y|Fh'vj5wq~ww|GӣC£$7SuAk>(ל^~G@txÏ ?nqӏ}_z_?񋧤i?-w^/nZp=xt|粺2>tr)qyqxUj]]U+LdzxMMuM NƫxW*|~)u{"uӏ_\#0ӳ7JV.}~{6rd|?!WW*g5[Bٯt?8?>xx~?Άx?|^f,=(R=F~^^CyA}1줅~{mjM i'&imDsh{;3hM.Ўh8p{^9.)tOa8LzR1{Gox´0NhG. ӴP'si=#^;ɎYk̅9b*w&]3.I1=;4:RzP) G¿|qw_K=s&Y~7-+Wy5MveZ:vLEnnp;UNͤfK?ci>)]jS;%/Gq@F;a<.Y8=Ob&4HAv=LGf[)s p@lSQ-Cc/^b?'{g5{"Ca`F?$ 0(r8Nq8bwF1Gt/wu8vq ;ddP |>?ϐ7fOَ5!k 4JW®]X ՆEIyN9UxS d.&{J z] gİ5Mf/jcIʁF.8DL7i0V)Ѕ VᓐTOQqMP$G6O0/808CkN0zv5bD&(?dq 6F@Q0hS;q =yb\94 ^o`NZ0iEF4ݯ-Xjj xH3|[pH N{oA +!™72h8zPO[y>},[6օӡN(ͧ& Mi G-  J; <(ڲm״MdeM3M[RIm2شðڮii5q* 1miTz"2'Iw!RITJ4M5M7,m-4hSB@qWvlکiB#l{>&E=ȖphJ[-ʊK-z.5݉;e!/DIG'=ֺlԊOQuڬzmln[kԝfp[kY͚nfmyѢ[i֚XvByzL\LezJtS#A Tzv^$B!(GSxpk`PD`[kZF%\ӝFD.҂8Az&tV&R9hjo05BiG B]EE$ґ +%h&$#BB' %`PNXzm1GgD"2bʮ*b`B|xt|ǶC[ɡB88(fEZ&MGG*x_ߵk#)Aljl۸q7n༉LɼetG"8T+(b!lQ).^2kd\q"D(ڮH{Ӽ^w88wBYՖgaXvuNdH6'QFUQNI"Q$փH&aȱcr`faDzPu!:eǝ5QzeSwf1BdG0 c\s6Zu¬+R˚ds^ Xy: јu"8 {F +q zv>Pڈ>- +f d+v ذqr UER +bU@!vvuٻtF`mpVz|NV\4@7a-Р5e0B?#9خ'ChdM:v6lFCIsA9E"OSYZ;8 +Ǐ%1Ik-kYb2[(2[(Sɂg6&]e+gZQI`HrT9SA8-R +\4!BDam'*MÓKբeӔV (Rlc +NQJVz{Qƃ(^Vz: aa#t;d S8qt xI Q!$kd#Q0!@_aN',5FP$-$Ox"5.z`?ޚ4mz9#K(6]䡂{ݡ~H0>1?oUǚr0@I)C""H@Ҙ= ~tv o`uBUR GQ R0&?\1M1+ De&4H`'NH:.EB5{(i>9#g6I^8P@gOS?+/QؼIJ A-}=Q!:?SIbS#OYH*ެE.Ȑ|QlTd=qPde < “pQy FPkǢ d]` 3JB &jNtQSRFɷ+zw L_v g-4ꤕgOIl[tuťm'ؐ.DP"K Q"p1\%NbO^%zxKGx^Ύ]/N:mOl*/YI O1ZI(6Co>Z{d!w/z[=~rj&ٔr116c̉/@I9ъgb1(NAB+fM"'~/1I:.bNt8$$z(Mmf& +5|OILHНObJHYVo|rSieJ. + ҺƕYy19fcU{<:Q1 E Z[`^/NymYlFkIZ=V,K{pm,ȰY̹ +qn59͘sIMЈm⩚qj &0[.9'O:Y+b\?%;c 4A ^\PzǂV,$IQth7bC0ZxlAGd[mtYAyd͒7e8G°E*QMnqv +18#x(Ǿ:IKGSI͞JGc)q0ɂZWs !/ [h?&뙳ǍN .2^3c7QI[>,op5fK,ƒo*88ڄ&ELͳԋ4g +8!nvj._|")\jNU;} +~È3@9a?_&#ybNN8AǼݚ7\f[& ^vzg)4 ӬàG/Al .#'TAS1R3-0x;D0c\|t36KˇGpYrQ Yu;3ɘQ=4>a1#*]b' ͑CCTps&ՉS60#m<+Dže$[$y05J0VHY,}pr>JrwȮñk=b[xǥ^^y:x7^ZqE;̱xfCGqXQ$P%9_{9t]҄OJZE +LX7hicD:ֶݙ1{p^?ն +/kxc%[lGw.û?|OIDOblM5 ð&O )>Py ́3})S[[g3p.UWwK^'cCSO 6ИPFDoe<W#Ac$p}g-l|= mߺmm8-9Bmhܷl ,5=onK#N] 35@.pG Ah NqW {X dJ;~?n#">=d]8:ҳ4HeL%EALPź>/W\#RvN4Ƒ}HÔcX"]G+[?gh'cֶ91uhz+ u?R7~S{\xyŏcjl9A%Nc f,/Hg!*HCFF,8;?xoy.sFy8RI+S߱Fm-Y?M`7~S{l{۽8g?N8''Uc1YslH|0'9l0O6vK3+fr!O) b*OxUFNgSymls9W[/ƒ-{R[@zN5Q㐘d֌.âZ0g:-m\684ڭLɀFQozTooB~L Q줌qPCЊhaS^+\ %S6:Ȭ\cbFGA_,2n\ j?iݘ8 zF.]ջ0waTQ|~FxF.]ջ0waT¨ޅQ zF8Vr9e)rTtP .R )T)zAZT,,Maq5ncq&nOrꤐj&kĉz_9?*"z:,BbLj~ŴV'jĿN%̊/^R -ԹtpgWqO|@F8.n%G)Βgf-iIKR*)\9`f*iER?0Ɂou:k#비P$DoH,BGl +Xn91 Wkr.9GG"AbDTS֛tdd۳sLN>Upܮ +sš¹88>J+BVqb+A(Aaw1{ێK&xI[)\bgvc%0A_Ğd.嫮窰x>~ukXx_6l blIАeӍ uiɞ_¦$[D6^ s䔘9S_'OBU#jÄ\,Zzq&Qp@Aw8Nɿ-VNGSusHV%C?㬥a+=PD5ݦv%h6G `1ˇg_7{ ='\$d%8$)?vbTmRM,w盒h-_uڶ,JPa꧜b\âϠgpv]5^,e/URWnWQ*vܝ &e_Fe+&h:]rQ[gs59zx;|6ˌ}:'Evz{ \UN}2yEctBt=  %.!V2R3G$5K%,cr +&w)E\Tz&(Q2:lI)yeR8.p`,%*P<<@F&Eݲet T찈_A$xaU*mDRo4K!/)3 z©:o1>4uZ&n"Rʏݮ*c = /SP΅sv1!y $!IG/p $eu1'|4E>[ +HT 0yFvL97SiQtEMZo/4Lx6v5{ݳ<ST:hnqEISrH_2XW3_;7\_m_ZR|_ŽZ/z)7VUs-﹆\;j-?).6tI?%;[lv=+ӾF2>_2&g*fέѶnk [ZQy0r{;^[hg쬩u^gmBIs6\\0)L*EfVo鹊ݱȲ/),ff'!ZNYQre>SMS'e(Z1%gEd4sԙr^|#]nOlVgfwb+maHuj/h:bУ:#R֮jǪtGңsn˟~w{|4s&\*{k'VJf[& {l%nCEQM'fLL܇ 1h*ug11flqR9˜}%Fsdo]* +٠ +sVRBx fuhݹZeiƐLX$I JH7,m,";:mb$s[+6mVEa^/r=+r ޢ?eG!|}jt#/!ep?rtL)t ən*P)89T9#\"'yE'r2pb"k$y;UXv*~ɽO!?9rQegP\8{*XSKG|fsoOWFp}W~ýyIqN.!+Z B /)j!>xT+ί5oY:gT6iWM#I*q4M u1yov MK\J o-vZ#Y!w%:,6꺏N5D@5+KeXkoMžZ;I,E]= +'Ȃ7zyg7 xHqZ0prjqtshZX/sk&ek]JRYLvwOE&~Q BW +gU80C}`eJ3T3"9z6M>*@8'B6@uBf03q|^+S SWx6p%1xXLvF obIO _D!zkL=ooyFøUbT"vбί5\>h1>nHBfB ,Di4F~;eA[9Bɵ#1ZfU={]w9{]w9{]w9{]w9{]w9{]w9;ƭdž{~Yyܽrw5lΩ65J(w/+lȭs͵z\m9npNR?UdLSF97S)ZpxA!rEt>E.ѷo dXeus\z%X^D>:$li%/}e=\$ЉGS!3yXoBh|Yb/A)>HwLuPNqz\xbh:z\WUR}IVǯ%x%~+>[AvV-p$XWHUvWXiEK e-VZWZYʻ{LJE =u*}nhԻ]-ĥ254=lJ i]ECՙv'"֪`; 'iFGJcP3z3{TF~Zl#Y)x{c֚z4>~=NM iݮŝi&hlquVҮ-IhGoQ }>x[٭ԍTK}+"׬E]7RKfW Z-VYSkswz^wwFBU]+sF~7grߗ`]d +1n\|sgtPix+,@EJŌDݜ]NМϔ۝]bX('wK7Kj%Cs㒛TsK+\k* P6 p:UߡW%g?~7gz؋WvOUH IW攎pWHpPSU)9Ot '7:PcrA9䠞-\$߯zǷcm?YP)0((UEx+@p蔆,B- +3zuXaՍXK%xMjH܃Wm@YE}:5z5h P\z(g0RL uQ ]qWݗ*YLu.ARlڟ6d'C@ϐϸp(Bl2E%RԮk0JwUՅE_O@]v\iu:y <}wi[sQsխ7uzHp&Inh;@g|,)H i\@]HßI{Mpm.t ϕR ĤdYa*hT=c_fрs\#1gkNRR'hE&46"}JWrDIQ]UXJsub866mf]S*E xaݭ(o|7mz\&/?ˌ[m|i}bw];Wc,yכپf^pm܌;vk)O׵퍵w=ZLѦ6MLZ2.Rt&cMDaa#D%>ԂQJ᝹jfk"Mk*Tܫ`]XZ뭖]U+M}eŷkkvRֵ:c:ǺQmwu}wu}bGpu +++cJ1a[:.sSWB.w]D)U]fDJ+kF@[їC cUʜ La%*U]WwΩs*qb} ང2K,r-2ՙΆ9Ao%Ԧ]K1E6ֲ^nTTHoؤT2j3ۗ˗g1b ~0n)jrh$20d*jA-"|e"9'aWͨ4,leRUs=^2}A[̺ʹUB0-VLS3;Tcc+TgHOg8T1Y1/" 7YjfYV޽Wm9'ֵm/ +VWu3^WuZmD$]qX9VHHqU hk2/FqZ !:wؔa`d\Da &ׇd0Y^*aF#ړ.wΖ{xMoo??RIc/>p-*}4_F +/I =%YaF(uNwwHib)[WbJM]Ҷdr[BVےsa#@ϻf_} X*+nrGM괆>%WzlHF4/u೫jм({-򻐎]:C΋\jSNQ!KvB~cC.Kj&wֲ qԠUz䑘ȹ89[mlbN/p +ɭd #ҖDܑ[3,KZ}gXd^^[P[Ctjȑ %b=U"POcȔ +K8 Ŕ@1-:5)UA9U=S G +x\w<~,I;UbJIEz5쳯3ا7Sˬ]A@%ǜ؀0Ƙ⌥QC%:UBJ;bB\TO  +ʈiʈs!2b1"mڈY>V خ^O*>ɱ[iN5I-O^'*\z/$y:=b3R!&U¤3W8nyEv0nY\ž:EjJeeXI=tTRN"AźCV{+vhrYu:g='3"W>)^Kl,CuG. FX,7ՁMڴ!\;JX=(?O6I |)A9E9O'SFp{+C*&?;Ž2?=wuV*vҡ fLy\(!Cp)/ѡ +:9Xjd{L,4yKɕ\ X_veo|Qv+r|v’5~- &Ρwchvo!t~FW9lyS,45HXo±XRZf;N69n8n4n0n,n(n$y?I[^ u[޴ou\)mj<[}=f0gTw0H|n>f7W˫9'/Oc0k%FF /7*Р)aF20(~+UE%g_6wm7?6Ov;/yٝ`b?X}߮?z{xͳ_oonn '/o|XO?~zW_m)qA blXouq4>y}ܤ٥LfݧB+0NCsCk%p[Xo g-%ӂu$dYoq%49l*@-$1;c6Armc7rО'>G&\Yl+&nxz ~4_śv(9.̡?ـ9bRwc?f ΀t 023{҉R v>F2XA4C"e}WowHk[?m_=|zح ތ+sҞRirڎUBڢs +8:dT!1bӼaPlţp>?m&[ h&bt xq,$跄1 4p^=xq%$PHxHs;ap8Լ#:J|:m.DfS~N p٥" J +[P$:"b{p~c #N`.Ը1J.SHQER&bF+U ogf׍,@86zp[zby#hFKp0yܛ +;5,sk/)F'xVfs,= +ek'2s?1с2`(T HFz/&EcT`IU_@wmb`DѨ!)G&(W B>)"\G8Xi r3T޳Р誡&mIHi5 0*2)m=8t._ey zzJOX +OX> XaBDbs_r)W,Oq| Yq@fA[ld8I*0b@mc'Fgy%WD=l~s@-`ӖY)Yg/v1(''8!R&gD|1p1 A3#N+;8jH!4aG)gf;Y~ $fep~!hrgiBt=˃BqpHA ;hOi̘Y,f/]C +<9lI8[88ŹhpV7fp2T/ +ƛ;S,JN}pqoRBȃ t1 +K%(p>T직" ^-w·<F,jn<,e8j(C'gY !تҲ:5 q +&t yh>%*!p\I mb|Ɖf/\]o%m.<A`i־ϻ<Fe1tmo4ep&y$ R(3 +c]~Tyo?5z>}xu/_}^aA>/wYdx泫OwO1^~ ~A/٫Ϟ̤#]7{V'ƫ\Yax ?Wܠp$dxF1UX܁E 19'%z5N\Gə#xIB 8 #J.:M?M1χYlv_{+>?GRf5D.4SZ֥(,ܟ1|TUl1; B& ^ᮜI6/a]@o@z 災Q9  H;C7xony \V& +F}/ߓ}L&Jnb!NjQUq@eT B!"M/~q0a+L&6]P0GK]Q~Mù +NHu[Zl@hix8'KYQ60 KdmTKHP0-`Z*SNuFw#!ayJP!qDXc7b WvCր*VSm -CJA7;~7Kr!%c{-EFgS}a!m {Aj&( f +hĴWL$rW.\Y' RB ! r7Dˉq\b(]BP#V7MqRFV0L+~ۨ5C,_b`p!L'̫IsE61 +i_yqXI75,rp!hVJ +nP(:/KMw:p_(}$nK1¤*`ͫ_r $@2G5(Y$@dЂb)a襏ƏQo؆2iC/~!z. +ݤWeA](ؘ"q@,rȎ ?qʡ.4{ѢOT[YHqO cOTZU1<= Rm4$ ukDP/G;Eț*@⁈>o#(O˜@ j4y#uRD A9іa !sDxB,W :L!$d +,țN]+=l$%xq€[B((.=>n& " +MFV;&B)^~!?q̄AĺT08G!ILydQ<3M\LyCe !.$;qL?B $5s; p(zZDd VʄoGW7!#s$|^E]ځWQ/(E3D3!7}PHTdb@ 954 ɉրnóN @r9'c[ApCp?NXOqKA4VD33q<4y'p*Fx1[r-<ǩVchx@Tx–8X8΢ {1(2mGS\q [pzlڌjT?aoDc=qKBE}̇HdAOE_є)Z%۴i<{(bjAKO20)hUT}Yc^8WɆDS\@Ka7'}qp& AZ,s̬pqA%Q$8o azyRXq ,BtF8 |QUEa9E(eʑxrbˆ i"-I̡' {,r*#H荜Jn-YۤR)DoYdڑz\QyfOH8̍%B{.YUCát ʙt{vlH#! kά4Z +@L)4EY7DɅ2t^AK _B7hG#QzCбB}]`'Di cmʈ 0aIIp CPRvK`fYy'!Ol՝ȊUN6Ot֌8*D˸ļ#,E EPA^*&‰$А ӒBDm$nx1jmQL+Jg 4 +rz'ݡ;NY?yѵvM7)&~84N%4/If A2ì7=!L*ڭhD16є'U<*x|iMW7ꝭ]8k (Itar^:hz&_'rBSK7DkZsE;c("1rk0`ԊUSBTS+W tmwnm\86 0^!U#3>ֶ[ڑWRY775ynĆuv 딕 Y&kKΝvuStfnon{vs|ilgwΞd_庝տޝ@wt'IОHC:zճh7=;׎y{@L3ʺp9tRNvrQ,.Wu6ֹ$ѮsY ;NDY(휏:껔ָLuyv7kUA<:Es +딕Ωl]:gTU] ^Mn{Zm;G\_\睏c7A_wӺfvpE㹊{D t6jtzT\gkЩs@Gý:uܬλz7U4ssnA?:[*yeg N;sN_ő;B~ݹwߡ~wP~;YlL֍U ,#]ź L4}GkFVD#aD؛):dEiKF՚kK|kDTLwڮ;;QD22bpg zu<[crUo>KlwE\$YryZuZ#eZ(!q{LL;)|0F'xz,!$-Qh\-̽mtkr^5]?^OikL.DS|UWZH7BG 'nd߇~nwwSP"0ldzSYZ6b 7 +KaXEqM80y00AE|{oR4Kc1c C#tM[LJA1u'Kynn\W:ꦏrCAsf<LCD953Y)?[&YtXȝK71+(d<.2oa`~̄BW8;'$ AbAEqHK|_{+uy-mFg <::qd(aD*liG+5#F-H*`Ζ2f*L3) v11 ;ٮڝ޿*'먛ؖkZRټ՚o ]$Z4R2Xb;k!A-=^gd|ɞ:Za:}A]37o (~Stk=%om`&qYx cYO*RM:2 ZD@JZ4k +#D9aEБ!/(!u%$>WP:ё9q]R0i|dGcD{C)9A)rt6#Z=|گ`l˘Uf HOPMN"{)Z;x/@4$O`C,&Tab Ff[!Z" +wDG?hΉ$vQC`!z b.%vTG++AdV1Tga#HFMAc&n/+˜8@0D%ۘ! +\4uLfKnJ 6=kZJ$q6GMw 3[%HTQloy/4z/*QF):9zG6t{」4b"LK1/oHı`-+~W՜ny([gtNT̼f5"Ayn]~c{0c8MO]x c)yRͦѳۏgyK,Q`#OG6HNqr5"swȖow5,o~N2ׇ:g& SJJŠtef8PI/JRPA΢%'X4qS<^rdDs7*~ Ar\2FGS +}Pk(79:-#P"r7tԢۣJi('=$B[fSvI 78nb:J&gM[PXxݹK>-o4lSҦa2RѮy@ah+GWΉ/V\1$,p-#GrrŽC h1L:@#SJ0ު0)zƛТ ZSҞSÔ3^ +oTh'7#&˭w~0?V-觧e< |k}:حxD;*l% +92u*+%>xW_]]zs=wCuUj) pN l2풑3=ɐn{59/)9>9e:m>en/גS񠡜]dQY퓑Xo1]IF1 g6OFC?zo4ǵsO96NR Y\{\傷@L{\{Z2xD{wD^Rb`BQx  RFG~n|T숎O9E&s5vZ>:0QJ=Uû3WQ9șS +rx! +]Hl7`)sf:zj`7Ɍs +r1-x@zv3!5g+qxIF`^<3JKp!,*ӍNYT>v$ISrKJz?$R҅R ",F7\.yqHD|UƈaC!ð!zFj(v+ozFϣ2F>B^S_ψA:r +ay#12g}]HbyJA#CFs5rc_O%FHZЈkD4T#8 kWшWt߼ZHK1pji+i[a+!ꦢ@{ +I%& kl+IL"N^c_qm\GVҙ$jE#*ziJekM ++Wh\@|ET_Ɉ|0b(RTg_<+$N_׫j4Qܔ/¸臠sO+_D2YqKZqڴp}" CEF ݹMfEtmi0%,; |?eJJ9.-;TbPUf-xbY#!BH4c?Xx P,&bz ? u6V&qK pfyQ lZ YGW(yHX3\Vfƻξl +K(~hVUg;"K4!h;|(P'Lڊ}'|sj5+w/2+EKwzܧg;<&NŁ&wz&FB:[[wiu'"dЫ̃$eeg;[ior_:Vn*-]1ߐu8S.H#>/Ǿ%&$Pd6*8 Ol<wRJcX\ԗ<)h9l-gQ $!w m;pZ_ BP9^)7ȁiP,ē$dy۪:g+`rՊ,HĀ:íȁ# %/.9dEHcyc]ߕÆpdn%k/DY E + (]=4储9qR7HZSܿ%13DqX#6%17Q4Ղh})&Vl<UEXEX39W4OԨPE,gV~ZіI9 +Z$;n\֔5TäH9CS[͞M ׁqoa c97„$V|@!1LzN>"KJ҉w_,FLDrϙEdDf]VE1>j&錬iÜ]43 ` +?1p+ug\!y-HP^cNz 6L 9LM&JVz>%$ 9nR"-iq] +^R\Xs~~FT@M {>"Kd9xF 2==ƲNCJ֥X@-U.j% s%]Qi@='f pD%x6/n 8J$X/ᯖ0\Hc|xB"\խ1ebYz JaH62(呺(AcC&|.ćJ<:29nS9iʮE%xQq"ie"HOs Qhx7J"[jҴ&+܅z%Ŏ\E#NBS) @$_QvX.TEDYEyQE6O80ҝ|3kɐJȯP\]Ft 6NYiڹʍ>!yqG?X͋wb:ӹJ E8r1ucHn,G nfϠ(@D@*?x92]D#HoOL Gfx3; +IMMDY'IgA/]_ tV +85ޘuQ)Mz&eJkTb~_[e1E]Ep+8 ec<̂1L&sf#`6O`F@J3 WPHX\ۆ HQHոps-6Lf.z\w/hD 3BM8S X8,nL{5/B9Dge]\UY{v>}K`쒦eYu{ǤS,bD ˢr]hXܕrqaW&cL~j4?}AkBm|&Bu^t++FK5]M>W^Q/\he +xK +@@2_X!i/ +͗SV4Ȭ΀:ZKP"JX+վUDqvTn${hݹlT8K:6Uո{<^]lzrU]Ө6ؐѨRnf!niUR8Rs"]hbenX?儫jV/PBpUE}oM* ֈ~nU'6L{>Yj5ikĩx![eGs__J|Ezk*bzyOxOJ* n|(k3B$S~+Y|>~ǟ?_~tuTY &S$!M} '"1p[S`mNOd/]AEwRԗXQ* +fa~!ut~ Oc +cհٕ.)sDþ 7Q b]=5|"j!XI%vsb6=`c{3X#EWA^^c'F{nHcTOG>l!xQ GѤ ~z)9YvSԁOuCَrq/`-[j-6V2O(vPhiN9E2XIr\=A(*~vMj v_{Qx>P lmQ;W fky@^Аi/1d1Nc2Β:b`5>08| +y;! pt>z9OvԲa +R{@yچ'^NfqK +LOE'c!.=8d\aV2|3LABT^k>J<.poÿm`&F@Odc-!WAfgR"23'((`[:( e@#{_Qوt52 K3O*@F~ Z4mnapC܌m6qX?ոlvɟ7p˕ZX@#GCtkYF`4曷3 t(>KhC" +?!xaB/ o_縛ujEv[4B>ljkqǸ-0mf~Aۧ-R8"@>H[z~M(<-Q&M, ӗg`b,v*St,B!A2fR4n=;6ڊA K S)Ac* QL]ϜAsXl'xQ Tͼ[-,A3 jnJ8P1[bΜY~Ve"vrc_(瓊̇bt"|يXfk>ȔS7~]DߕC˼Όog\JCl"uYzܨ8P2b' +ZfT6~TU +brƳjB^u=,ĕRCvȷg|%˕+$C&`tOdUe|jk;5qꬴϒ++gϜ/C0D0XtL ER}3MDLpR]pu"R@oKۊ_Y %I6IJB!U'KhԢ"0xJ1#r"*`Omgxk3W jD]ؚ .dfrE kœh<3!{ EKKG:jQGrݞa2TpohĺN>O̘~'~C}1zLֲ(\4:H 65nfQȪQ]zWQ %5[C۬$%-+'`Q sR_>)BW0 +hoSԓ`Z@c~ɱ t|#:K++/[Wdav/ٯ0jTJ*_ڀq b +mĆH +"WH lB/s2`4VzL-jJ^~Iclt_fPX=Y&Nyp6P0z[2aoOta0SMRٙʄ{yw@c'jߢm{GfGvuM8r4:MbX޽RzoihdƲz_]yϯqO[5vHu,:DkM@+vLaR + GUT:;ET%r_*ɥJ'2Ň!l>֤CW#ϫ֙Ì_Jzȗ#8}wR:+RC_{.VN s+՚ x)|^џ E.+ᤝPڐaƲInj&S(T aUmQ(>ѪԤaIGVS5j)_ekI  f9z?{j XkFPo2kcVD]рvWoܴwc"1R/1)_x +* C=(w*: +hC@j:y+`|!G*} Bj +0H^Xf2-W/IkKmw{ULZi|/M;`- bb߷!؋Bd9_Ҫ;Ҫ R loZibRl%AQ-a _%P%*r t37Nt37h|3 GR-]&v߸I{삌)GJg}Qx Q Wѧw[k\&׏UӾ@oz7"Vߚ7v= zH\5o74w`X$7^kHML!{-mzHXЬsN NxmF? xր=V@bFlllS&O*`BհDV+Lve--Xh$llF:a0#i"G,884YZO}t p!1FVwwP Ĭ):) *ca/?m/| fx|tC</'WN])+vYmlIf{9ѢNk\g|g@QomX%$B6EqE{S{WSVnDIFoK6&>(0-Dsj ٶA?Nq'w+)p`W/dg^h{;+,ڠ;?r-/(4E<MK(B9\4k6,Tоw ,5BB`w!i Q +۠1}.C$ {uZ82̶)[,4 +t"*@[ۭ1"@ b8i3m{ҜĞW`*puqYRy$"6qA.r,ꇰ|rkhӉ9E|ˍk74*Sb擧 ͪޒdio.Q+":Y g|37zJ sy?4>$28.7W9j#xO:QZQ 7WQh)p-3LU/ +2`.U_rɬ0 ZMXSF>7W +3Yh?S"<Bh}J* +QIo-.K Oq)THHqf"=S "T_7P*c=Y p_ +xJ~sEk5WػbW4hD>pP%|m| %=R!Ai Ģ|&삱xs?Xw剮Mh}B{n.](6~mPB [^;X@V]rWvCABk(Sh|m8ܔ0bKlArAG=}­hr>mD͇Z:\W݋bP2:k߯ +x~AB/!v.0l^؟i#$3"jqvơcʡlV:r:a4mC(I9V{`[΍:Bwbg[ +ۇ'`✉s!4h^pW8 Kjw9,e98Kی_^.v/bo.[x9w%$8D+t(WqBJp#?ذVm V/7gnc_s"&N\1ЏlnU'Ztc8qV7 +4+sh[]FQx+Ed7/Fi)W^\] n nU,ٳ}ͮ^s +7Fo|/7z.np߼qnܶȶ){mci yڬSˆr:^Z#G%EGښ鴚]wBoa}ЌרxyW6TBb{@$?mg'ջڣY=|Ppjߵ~ +dEkSvϲ6?d][}ǽ=76 +gpA"T"2\AO*Q6 -V *BUv gIa 88W:PR-VS`lXµHc!|9Q- C$e\L]nobl5~BkIdt.?Q dg=" eʵ)fM/D4-:bqreyvu%1jb>-zNMڬwiKo_M4>ꘅ:rch]G3Xѱm2yvw3CA붣cSk;[*'ʉ0*La281JI{0κ&/_(mW~sƖ%zOMg;Ka\Py쮸|~k^0Df`t쮽`20sc4H(6z0׸u7b ) a~6 a9e*ndf\>k$QY<]c:#f;] 7QSD|dQ= O +ԥuӴRH*!gV:udZĥUSjy!bd}^fr@"V5optp紟e1A`ZW"6gQV320')#ݝ)G-!B9/"NB(6[ +%͍m=$TRM:f;ߡmKl^acyuRH=3 E|^7eUDor hF+ nUivXU3gEMǡvGĞw>UWBQ܁zܞfAvݨF ՍiI,B@v/r7C}K3y>Q]Z\¤xu-0!*[FZ%l!.Ikwd`nWI JHO2h464| " )MY>NZw7&ҧB# U !xаhx(Yߜ8 EK"S؏pwnɢmh^Vg +x. ~ey5>rݐ.{ڻ}q\I8|Aa4%K{ |K[ +3TVS"Q'Х@(:hl HE܎΄ ƣj ҔdJ"zn = -:dC:b}>B/FiC]L0RGpl[N"~̳ 1(Q^VRڱ{8( SrQ>:x1J> l&rِ|KTM]XNIL4o|Af3'T:(WX5E!tCH-jȪ@VTNBԁ;w %BN9. +Ёe:Vw[i˶ٜw{k I_v;mz=/a5~1Vt^7̠{΂MMfynڍ[X6KhU$-B]qC % 6(EDQֿv:"j—J秳&U6, u73x28fITx5ږjα({A$ȩūKM'3 I]1oDa+*E%+%䇡Tjvh&/( –^?? ٮCU>_i_BdуAL%*Ll[ k ]X h=qP2V+D:ÛTH\BftIb,ef>KCڂ`{)D,YǦWMwIHiT)!G }ꨊgPe=SgQ@-"H +dº%vp2@ #_F^AFlؠmbQh=/L~G'CgFϑ|= .fZa_Tp@m~+Q7ZoQWG_ Ł`_pBAH 5oG #*P^+&l.?;_v]}w/xH =ʯ\E7Ln0sùqeGּMB>4Ze{iki_ig3LO` #ri%AUi'] +aB臲qjvEEwWN/ +QIU;S#5g+Ӊ6Sinrj^Ʃ]g]FS$`TzԤyC޾{5 3Ќ?YA(RngG7lGAjul_מ^@ [^&7IPd0[_Y2`Նwk<֕Vž[,c(!|!/nfvƄ0g@ l0!sAœ2)p8kPW4-DthA7fo,'5Iٔ~~QÄf޵UU7ahIk +hS4vC3 +N~kjU=rmvz㠋V Oz(7ceI< -1|Iߠ*HU59t.a]0nn8 ~ٖhKw}{O_ 3R`cg6GyO&Lcd g3<`]L`lg|80EPigF"P{tZWBHSCTm]=6(Z_%{ G﫭vajK2gjv)"͜0uW2}x~W7F!"-y +fճ|L6]-9ل +c8rAl`gnLw51dkƍBECGY/*Í,IDCCBM:HeB+NPfJZ9}!  +?Nc( + @/Efv/ɿo_<Е&<:r/vS\/WRO5`@HkP#Y;)(ßdkk#>yG,H틺W[F R%m5m =$j+ǵ-g8tD`%#50f*B-1"nm`*x *?l%;K-ayx +_\N釰9?A:-oN7"&dVh0hζJ3A.4T:3*z KZ mCŰt. 6h{ wF< jş8nٶFhR^gN UQ˝ptsQUU)M[>vjl';i xSlGU\&KhjrtdU'i|x8~:H>\P؛}7񙗋8{l]J +ٌۚ7hGE$/@A.o$ {zQ>I)X_' af3ow{$sJ3{Mba4msTx#xȶݓ`Jl[>D\٭J9ˌ +⠽y }`KI9@ U\Үu]<'I++ +I/^s5ӛ;WH ݵHjnsԠB(S]lVug +z{[W(yKX(B*R`5Q(jGhw]UbD B %>5*[mOt)٥ 3aj8OȨ\´m`SSG%beO>\GPDrΥjjirE|j>M6N,^g BMnZ)ODpd +uj=㔷kR}z "!*j82WY w|l VКh[^&¤3`>_ػ/e)c/ƝI0 |AB6W7مs< v4$ 4׷uim/f N1"C3/@T"_`c +DX|M4H\Ͻ}\(  "4:E.'ٷ9o y\g\H)8 kC\@do +^C n-O hBBN+*65:-27g Crֆ8/ř=j kY;.xEG1(j¬q_tyL{ JV/:<d GGkb!Gwd& }G<t KG\_!sqVMk|o~՛㈃ةn4v+g1A^8X')l/]`03 O+Tpj5zX8ۯ[xOgv}4O v3M奵hT_#O U,!Qzn*[)G촙C}xQ&&ӗ;F¨AI6&+ӭB /(6 Ad\krN()m vן.fcj`"^(Bh$ ݐ?UvJ5*MY;h΁¿b(!DGI/㋺$'e%_\凇w>m^=#Dʿ,{YlǛe/,quY>#D¬[Y{- F`2X7=Z"̶.uv&sѰhmͼ1;\Ą.F?Աm:K"]#/pu L:& NIƉlt~%]yq=Ӽl2R Ю34 mxaQl2,wHjf9 xn !P͛Ip\V.I;GI0~2 j.|H; E@(2!"^N@"m]bL_X7J7\.wLPϤ'g.<9 Ձ9!hSpv lYcIv+ώ /:_I $eٽO;Ӊpyl\1~Sڪѫ4]b 7v.`j|oLO%HrBJ +&,EP 2` AgAHY-c#ԡ2L>3(D1|`"ؙr;YDKAJi5@ڔYr5Q~EW$S:]6_bJp L(aV,HT{ah&3lZAO@Lm0]`)Pc+աw/rAW9^A1ԍ-hjE:N&sQMy^F_znXElS29!B˄Ǵ qG͡ +*=FNW{b.ENo{@*f "˳hePգ_/j]fbm: H2ajyAJTmPCPtl"sWBW1AgvЩPy$D5J hYXF[Kܯg9_?X8wmDP+Q[0-JR`RslUPC#F}-F *bZF )(`VU& $@czJkR+S"c %OBS 'h!DaX.sD"Od1$" g}c3RcD?ps։^5 +x!UG EŷwdN] B>#9uTd\HK/hLY-WFq;;FUSsNR=C$kDYim2x^)eǯ T^_106< 8?e_aYEȄ~f]6SC8ʣi.q\/ +.Q,޳b;~Ɨ\Ke.waDe Ȫ_$%*b\*b P愇0KQ +/KT2 ] n~X +Ü6樔@o;!@Qi+#O@p4Rgl|])km W`:56yUv+ڹܻ|tgmCMқ/yf!UHpĺzNI}+;MW}^P/&|ig$ݽ\T\=X86X͍S n~ċ4NɶLmaazH |a+=V]NT 3;%9]aQo9 ~@3 A(h_TГ:Mh\߅OX!o4B 1moArRܸi&^B}Wj, 4,vYD[c{zdN MU Ҵ)!"BPQllD9 4PRqgvg-_eE]̙9i0%vSBy8y:& TڡjٲAǛE5~fF\dD##CTkdEB{ w5D3n3[hkgqPEr/&Ì-C爕N w|>}贚>f[F#`3/٬ qS]7 >R3t%@J ,6a>`qig^*_4nD3rn ٰsBwH?rEk4B"+sHNLo` 罈ץ5}\S AWB%c)S 464Db^"7WXT<|9%̡ߋ.~SѲ4F\m+4,bA5/ (w-67tƇ2>Ck\pe(>FOO2+ +nhIލ@[k<%ƥp?m1;l<2ۧ#ɅOZćGC;)_qUUIdƍy*X.wͬ^`N*9'. ʜǴE _XSZ1"~mKݛr b +ڹ`>ޱh0 _=}3g, n#Gth +cPfSG?=Kg #śdy\&R»6 ﹞4oA`I?&PhS-?/xϳ|UɝuF"uÉdq Zt=DQQ7t>zK 4H iȁ.]K|G(q +/砈,Q QpwP,=L>lχqen~qb[3œGFD=HdEoy<BCjOޯzǁѬYC%" +T(\,; ϡ"Y$ }cBFkAmO{.PjW,E(]}*Z0ۮڋWTT2vt9h,@UW}9b4EgAul10u:$kLM#I\ՎfDv^pha* < *OW+ps ]E^,b]bfNf`DX.C/>impADmD}3Ү4k\Qb +7%pVz)uXS[kbY諾Z>֞/O& +]j&!>W@u34UuQ[;p("T9eu=߃}@nϷSܿn̄Ԃ~4f>1 ;qw&zo扈-/ʳWٌ ŸfWUyz5ҧZ_6/9mc'ȍ$f\=PVֽ瞟Ѩ~9v$7(?-g'@uiI W7T m|Ӵ:> =y +#;nڳ0g) 3 ;KނG-n93ٿ)3VXιɝ1S wrg[L&d~7p\^2h?BHBQ"H{Oa~HG˾c){JNf:Jè#%u:tq:ԉ C8^" MUrAz\7y.U(LR)] D߽Q1vq1xS:b)Qo迖v1^F8rq_-SJ?\vF8IXm3 ^xb*fcElvbfʤCЕN8>HQ0ķs$(}B=L٢o 8Rh~~'Z^cv4QYx-|ԍa&քˢnno_kmc^$̀~7=6KnH_,hbjn66?- QG +??\ E̹E̹E̹NũP;A'霠N+rn-͹:U@'͹N9C/9B͹B͹B/͹^s^st^s X X jzz~|"0w8û2.p|'4ϒYrb|g8"9N eJ;N | vªGNN{_dC m +Hh뮐!G&VW ͉0}FIe7W,iL7 +i7g;RDy1ˈ\x әs3O:sfDic3dzPqgiRt:sjެ1zؙ=.+FfLddw䙓+CeƎ}D+Ș2lj2s%zzj2T-{92hj|^e.4#0ēSe]ep/TCSL]o"k^nn{X/ĸK"h}5+xjR|3 +e~6_-e};~s6^p4Cx{&`P4c FȌxmCݼK(E(02վ0vcf1`fö́9̯(.3bi"B9sw݀;pVí38n5ڿgufoi`yG#N띣b +GWUDynl05%Qc?bouJu6Y,ieyFTUh}rMN<+3uU8%!!U7jkG}u,z"6 pPW'j)QJ}Eѐ%1G7,0xP ̲kZ0gAu9tmT6q.x̬lHYPQg +$ YBI +:lf714Ul$1ƒ2 + ,{JY{WR5ߐy3{?JJBΈf SO@'RzBU;*YÊͻrs_ +h}z Gi`? @Y)QV:Ĩ&|kQ=TgЋEf^D8 j  GU(PiF!𞣁*z 0$ӛz'*= + MAKpV +EmMا_羂p YG-W~vvJk>6(m oNjl$-bL/o%7rGaOG?ϟg/RiH SRf-# +f/̴+:/fJ5NX$cB!D-!E44|J`t"0;%3>'hy(jzf7RM,TB>Jst]+aJ]x)@T'"b\C2(yVxl{c=N~ @ǹkDuN䢋] +1m8v#tML4/DϔaNZy͂YR6_$ +^pDlOeB3I4Mt\H.,ud ږps 5gך c[bh@;3(0,QOh¡LI" ڬ6sQ!b_۵0nI6X:~PFW5-4k9n y)|Dv1& E9P@j DRQVS=H\z[v`+6y)!fb?tM=*ѩ@BBlߐ& *]{܌SԼYDhT ~(ԣ$iMO ya܁5*w\]&]N^=>\:v?fl:1e7ҨRD/+ J'9bqSډ\0؊lw23bFƋ@g64맰ö\H9[Qa_\$6PC%% I6345$(ĨQȹ},O +5~6EEt>$h:AhR ~FSEG=&e^Stn :Q5GqGJj͞rSO;EM +y4(H(@ Ǟw_n 1ٝT銆+l.6N.?V )) &3ܒFl}_$4%`5IBPTGH"x|Q ZqW@0&  ! "()^$wEsNJTAL4Ub#ӥ>#'UѪTrp;z틘-NV$Y:YuWwAi؋.[7Mj)`n{Ghro2vS%ᾈ戛qW]文 ƏLK\E6h6_aRY_:$w'v{"CA6Ԇ [ٶt+(Q)[IGI)۝R:f9<,bj~i C[I>o1[:CIiή]["rU͆! )O1 ":j^| qP^줖 j&W ͙4KoL;#{&J@#/ ~ +ROF_GMcJCTC3[/"kqaɳE79&Yf" sJ,B8i:/A(0AQ&^ד`Vڲ +9C$C/—kޑ^J_bVzH1 z &w>r!Y ҂l*.n3>M2N[E O.إ*B#JሠJv< lG|_T;@dDԯeSH̆:p."cS(a_[/S^U\0Q&\ƹܤ>gϝc)@-?Y "R|JCE_"Gԕ̀N+Cb-Y̒5bꈀSp]ϊ]u!$ G(+YzLItZi)|_ +y%X\v +{QWMJ\ kWXp{sֳŬ\bnwgUjߟ}|$|j0# Zw=H ;)|}@q,n]EX߈ʵv5m_oրk>a,ME.ǑmzeОdctiN94MXbofH OؾβϣQr—肝MyNhAi gH@R8PhqQ1~Ķ`gjxu4l2^  9 =V=3\bNȈ! RFm4Y3v yiPw7\ɤ8Jڻ[lȶJ]Hx?1fEn31v3y"NQ?)gѝ·?":8T{AO۹0 @cV +O*|wx#̽]y,9}hs'sJB~kk;CBp!pa,'P\PXbu0{8NFItfgUNdw,kxFFfNvaSWaqG.$QfyV"0k쪵H9FP_xC&jiw{>E/Zz/Yi¹X`-o҃.#Ah,zHl7KzSjL}I$lȐ|JVmuv8n8׋M =!`}拰ߠ860!K[Nh,~s/Wk\A1f3 + 4~`f"=6rTnˆI=,ۍPurj !|t ! +m`Dwj*5Edaۨs%lfq #Q7 %*a"h#sܬ݈均OˡoIo:K +rjĿio^Q*ҫEYnؘ2k]ad $EB?JAYR+9X!9+q (tQߥ#d+~J1\L*Xn4K.bciV8˙5(Jpj%*AuX^I=8-F}a犂y%"ZIf\)Ya e0gg!Z`P !VoaMo@2*8~W K`GXj'"7W';pØ`H]qLY`*`PuQ4o +]{)E@y>bp,uHp2C* c=weiF/ZZfrYt~~Zڅ.}{cmkw L&_/Nn6_1-gmj_M;#{Ά;"V0"|X}j8έ:+O܉s" y8< EY+6i9NEp̯-0jud>~^h3vh}`q.w:+I +slga-ͿlkE1mECHVT!W`\cekBM}NV_$+ъVVH/X`_X/'+PٗaUrV"4 kAɁ}Mj,wojh9ܻ+9Zt}с]̺:F-v@ւc09 Wvs +qh7J2Kne_v,Pa\MkFeڷ8kAyG}9Yz5kEICB3RZM (A8F b1O2z,t-+{kHǿv#DkH[;l\m8E8<^֔xI7Wu綍kڤxm~~zе%imU_[\`^ۇ Sz=kUСd#yi;Ĝ_e~qF`x6-r6KŴ ,RI(~T _x?| _3eөf{ca-翚Qo-KŲS䉛+>/%n>*NH;<+VϗQAP+8Гm6cf(g Q' z/Ū^7`ɾ€wBSٍ )݄Ъd+}"\-Q֋X?ty|C.lv+@S[//QW\~o>7)h9oI|%k/;P4i[9PCaD5Dqn>3E6f/ߟD@T,(:ꌢ$ CP v΄3.db4(33t %ԤR੢v+wRm~*CWʋJ{aWHsKez B-\x@j>{N}6 RI@A-0 m/+oAca/jXA:!5D!җtpHZ֖&G(H@eaf^Ah\r"i>dD{V[rŮF{뉒3h$[ڭ2Anv%[WF@jJ;-*cN"b` +EGt |ܫQjՑ5RX(/OI1*TnQ=5q!yͣEOaܿ7wD;Nx#а(8ዩ"{srdMtHKlzŮ_Ow/ə&E\NjB̫PMjECM`D*T,o]Btnj X=2#j[ݐ=BxT7b/0 -9*/ +r +`{GD2Z ![>o?_ooӟo?juJ@iX{]< +rPϬP 28 aK DjAig<(ro͵VЭnf$9bը1]y)v RxmǑ= +3ϗFɿ+>~|!tI_Oxou? ~yA}b6G}M}66by33'kp? >;^S$K&?H~A? k _}[c {̺NƙJ@ +4Kk iBW!H6<5lV~iIÉJOzqjq/K?#exDz=t>XIuK ]&YPRPho)aGD/zD@v~8V>Hm-^k;v.Cú6VpPط. Ccح65+APE Vrݮ-)ӓgY{Cᜐx=y>4 2n<,Ռ#ŜaL129Xh]ʨ-*j[aw7ìOPtoxR,b ='dLqAH{# eTM\"VN~$WŴ>"_6ǼEƱ|#^I\UO5`t;+$эx:O\H3كjXiآ* Aqr-Yٶg Huк,.籡WC~ĹWKEZs2#0e.L,Zr uPH!ھ]и)]-Jfo8yš>< :!SL@/`kB̙XBpBƯ>Z+vR7i-_H4IJE@N8xVF;~ +4%- ®syWH(\{9[Fd$xއdqw[ `?NCmY(3 -=ll"i-eRy=vU {\1pf_G:D,PKR灚ΝZ@8$"3;o],RA {nOM];fh4Z +-keA$\-y.,9ALU Fفd+i \,W!KNKlAl$P3L_":^~}eG^:XQ-y|'k^ zO.❁BOF&V=\.Vh67{zZ.TE3`brKw&Gn^r72R> n H7= .j-cҖ$ +h6Hqq!8-qq/60 b;t+&T6bs&1v43d͘35hf܉A5+ L>0V Qn%DsEuoAӜ֊U.c1ǜ1)71QZ@/*#夈!t^([Y$6ܬ~[7ԕm m U)h e{fGLW!DA4k6BJ jVoxRio#} ӀӞgB<|~il +,zh oÈ /xe9;np/x|*iʲ,w~xؘX&)ڏP6ȓڼ XRcD=Tl;d+ #o= Lh."W@)BZD+ G6\i'pYx`CN̩ՏDX'%jBU-0d7?֕/wƀ6)'K&'Cb~mS_[ WY x! &ܦ`\ڷyNLV[ +#)ATHH6 _6XWx1) ԁlI֫$Eݺyg"Д۩5] 2|רH3bq&P"(M$gH1x> ;v4A>Nk:5噈kϽ`7X }VmRaG7YPG1Nq c?Nn֣ŕ<|2Jɚb{D jV1ZQED3^RwMH  1VĈ2\dfGyOlJ=hRPfy*Ã+c f)HD#{((N@^TK@G4LWPr]{A2)YTFptcaT%y&{DI +U3xې߃@M\>stream +&rnrCu~[w4a[}a?ߠ/[_$[7՟;-2>?yY޽3>tO; oʸ%*ܥ~[?zgM;6W7?}o8n%۪;[߿~A@=Q_}=mFiyl7|g]~'a|TxgG|?yYwkwKonqs?75Mϛv=||N.}QϾ[_ 6;cKܾMM.3/޹D{-,y޵<ī@EsϽ9zǛi(i}g:11jġ#G'&NH& =018]]{~t\(΢"ו7z WNu/I8_ ;;}D='.SpO8NwO]wr\}IpAek|snf=UO(G\YI{u[Bvfg~X_ݙ{=M'` =|95|r䋩j}o[~O(\<#=5S,rkN~#}w> fMzf}wF|; +#&z9߽=a7*}}qҬW)]^:!eQzY/nR4Ͻ(Ί^|'ʾPs9dYObn}a^uc ?'u^攜Ts߄v]Y=ϫٲ-RWC{ِ_փ&'^D‡bqY^({EhhW#A(rI@^ kŬeb+9=-ۺ5JxU}s5ޡ:`zfєV7^e1zcBe69wu +_W˃s$wY {zX[~[g/)74e+˱Ng}/*rGP7kݘDFZ^sũ%៧Z佰8+抿b\~{E  ㉺3,Vzkմ3*ΊX<_)PjuI_ +YAV/"^"Rׇu!?!Q͘DY1W]fr7U(:Ued$2Q9^7иuߺ&|}$PhUBFQ_P-#M_yg|ٗ}\W-y:|$r*l}a/T޷>N=SqNI'l7n4dtçS/^̼"df勩ݼtX!eU^cg'x۷yW/M޿}yY:>|΃GS/_{ ),߽~9+ǻT%}6b3o_߿yx|{ >?yˇ}Ow~y;3d|34ϳ~x2J\w]wYp>n>UD3} } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }}&+{{ɲ.jͿWe|u|ʝ^~~M޿{rу;Ww5Y|^yY9o߾yų/vw>s}F2N_yө/gf^B23Ӈn^:},YT(w#.ܸ;1JO={:9qƅSGIKBnyў.]r),W\t`}q7TV86;|ᑑ >sֆhU0O2!u ͙>)4ǻ9?Pӑ>yk8oڕJg:BՙIv5ţ᭛Yݕ%7xƆd|{ԭ +mX]( *7$:Օ`Y N]hilS|$D +*<,P:N)tCTZl$K P*eoS_*Uj%G_V*d|ih? O9l8phO͹P/ROsP.ZT{Lsl;::x3v-l [cF_^Jk߇RΎ鎎6IuOlW*ѱ;Ѳ#66kHN[[R{2mlvd?::VT(P3b'?^b>h_]]ҹޡTrсb |ޑ?K`Zc>{=3& }{foO!ãC_|>ysk-ETvTzNѱ[?V~)__LcH3m#ߞ)Ց޳-ʴv.r2=)#nmmOe2e7uڑt;?-Ko}ξ-|h܂M =q7~T˪~*r[]0ff? +sZCO#ڰz K;Вǟ8;? ߯\sPgѿ?]_{Yl`6?3333<ʸ54<Kwtv½E/e}{Ovծ~~9ȝA! ;)ӧz>P}Lmi=:wδg2Lg kS{O~CmOX:'1OjNdv9M:\' !h!dNcP){K}QQ(-c5N6d$PQ\X/A1Q)7~$"~'k~igY˒`^*kDnRpғCr,Vz牏aGV9d\\^jϟ,@-#y{ k]x>JG`m1kS*ΊX*+ <лUSy&QGO=-iG6T/g[wYmݚV_'n +/vП^-#V7^m|7CUd7`y_Os6"HE&A<}/{D֐&Y>^e/'BwKr_HZ`ef=UW#9vY=~{q{⼓,Ks*k~XK滟s3zBF8|O*߫sw3;;i,^?[q{$_ȩ#_L}/^V{f|Gqb3XsM8{m{I0k3{-3`w/绷Q`7} ~$VNם{ݕfݿ"'_Lub' A-dvZ{κvyEqVUz{8酵NV% zs uedׄ)>_r,bB|/FC;Q'Wt@LrZX+f}.gwWU>s_X\龸hQ֭hU« }$1Wvo|(3<ն1zX,.*+əSZD#ك>{N o)s_X\-v>{}Q8ŀ_%z5Bx(N=-  &ne|$"Ί2)ZEF w/O$#X?񚰸)Ƶd--7+%/GԮ"2z$j7mʛ8+˾ʧ/doIS 7PTlg }1-穧y9֞Y%24V4e_TOeRO4ZĠ݄Bf#@Ve,£ +[UUeIii .@ii*uNRflS|$D +*<, nSg,v܈GVTWeB΍CUnt{vLsC]8TVZ=6;|ᑑ >sֆhU0~CIYȍ7;3x¥W^#˗.99ʲo(Tm9{H +؝7o\xp)Z4gz'/p'H!p[?\<`@O9O'=~B +G'~u|T)t#.ܸ;1JO={:9qƅSGI7[" c/ݼԋ33H!yb{7/>il٨'xէ=xg/^~;r޾}Ջgo_lr}>_B +w_N=zp.glM{:6̛~ of?:ަ>CkcOgz߃Ç_L? 'L>D|5dkg}[ϟsQ}LBfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfr>W-}]ϑkcOgO +-,ϙ'cFEyul7@ +˯<<>vU%ƮWwcHϢ@L9u݉ɧϦOOOLV|ɉ7.:NlN=Sq'`]O ^{OB2>~8xb >7UF2{^~;cc?B26v/9iVnYRr pHaz {klŁ`Uu=N%dddx6Dz ,kh?xX/H9}憺pԟ[xӮT:ٵL:) oꮄ/ٸ9TFǓ M466$ۣnUhƒ@Y0TY&ש yuBKe[$!RXTYMe9uJ@`#Y]R)xÜ:JUR+)<0U2JV%$LCÿ \o(xϡ`ÁC{zozzGuZvcgbdс_C_Զ{o`K@(m(;0xTjտNWZ>ܕJuvnOwtI2{bRmmL˞t:'66kHN[[R{2mlvd2ݝt*ݾ3onAO ;c!vom!s_-~;%/JUס/*wǿsPߙѿ +533_orwg8<:?i7fܒ[t޾oJe޳gwGk{ǞT:ě?Vu~1__NcH3m#ߞ)Ց޳-ʴv.8r2=nkh#-̾c֎t#-"3-Ko}ξ-|h܂M =qw~T˪~*r[]0jf? +s#[COڰz ?t.z%ُ??p(vs1_50gc Ξ[}l~g|g|g|g|_*#P, u=ջZsO'\ w&!lv0lSw_wc줜^WLJ%@"vkkF~4Rmi5>nSy&ّnwM^5}CmOX:'!1OjNbirt(OB>ѬBȜ`7!6Ǡ;S#şXQQ4ZyMkϬȢ24m]L8ۺ5 lIz^<OQ7PTlg S>"e +6IDvx" M'뇯(Vbx*bn]^]]Y(${]{U;N&#IEe(Vbh\*Ίo]a]Yuf}jXm$9H8^bSn*CHDLObqҾ%6T!׺ݤ95'p(Yj`G'irV-ɸ?YZG"֦}ٿ?"%IcJ%Us_x)1&TVndywxMD3zX[f&Mm_;6}g-ۺ5wOz=d-^V=?ZGnL^%o܇d1#.ڝ=Ouodѿ&U}mDe1zYmxM8;Z9x(^@u!MԳ|?ӽ+^N,*r]ypĿ:QW ّ$.{Gs2 z~); wy'wY՗Tw?fSq坅TW/dgvwşߝY~pHܿS;Q9;'G^-^&߽Q]ϳ]=S]?"gq>ڜy`DgZ|g^wo:o(v>H;'+ͺEOb<}O(߫Z;|u2F;i+E܋⬘]p k͝ 53XKﻙ4,ʈ%\7 S|¿^.y`NYOY1WMh|U󼚚-"qe1 5`=oE)|X,腲^vx;NL"7V]|,抿b}qߣѢ[ѪW<7^IczVQ>gv}Mymuc*X\=&TVn3}Qy<=Gr巅}rSJS抿b[}"qd/u#֍KjTQ;GOQzX[yᬕJ b+/WTp+oO {=^?R kŬwQMq=⬘+ųϛ? >Ve停j!%"q}X2uM܌HDse&yS|]QQ~jaQu_YIF"~(5aqS k[Z+ZnrWKu;^|V]E*dH=X/| =R!n7qV͗}))_}O_ޒ'@R? 'n*&B}cZ|SOߩr49=J<ehh+ʾ ˤ if3{A !;zGɳ.6Y,)!GXʒ@`#Y]U:@٦`yIUVyypSY@*0@Y0TY&ש yJ7xƆd|{ԭ +m[J]tk/)4]tjWS<޺9P본,kh?xX/H9}憺p8{ XmhwDϩӃ##gI!<}} Ѫ` +owgK\F ++/]8?st_s eP2ڔ9s7o;o޸~lLSrSi`]O ^{OB2>~8xblŁr':s&N>zǏ&NtS(&GN]qwb鳩?"-=ztr n D2N_yө/gf^B23Ӈn^:},ٲQOO{^zwd}&߾<,Q}vr߽^zΕ]ϒ>~1rul7@ +˯<<>vu䋽My}tƟLϼÇ;ɇ~2>vMk?N<~%}jď.;,8~yB?*>>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>f>sQ}N[,8~yt#ƟLHZX>H3OǮs3o_߿yx|sK^]LJyhw!/=sexWlŪ˷O>{oߑׯ^<`w8g!s>zrf)$33/_L=}x2 lEŁr7>rOM=iԳwo\8u$tE>x`~x8RX?|8ӭ{N í? d|{wopq]۫}n6exw~$dl7_hC'zN9K +S='kmV.RiY(\Мȱ_Bsؑ3 uPY?)]tk/)4]tjWS<޺9] _qsʍn'HillHƷGݪ%9u`q#YM"S] +ԅ6˷HB˃sB7KFRf9uRVRxTaei"K6I'SPC+ݽߜ "/4=/ ~RNǚ{>7V_ ɋǿ=ؿmB؁PP5v`DժUf_;}(+ݞhdZv {vvZ:;3{ҝAY[Gjw=ڒؓi[d#Kl֞ޑNuvv9fa[-{sC_b:4p_sC__׽#]];?7aƚ8<|&6@]]zf3Mn?@BGG^}:-[r?on77]]mݙ|;3t[osW_[Vt;'1i"ϴ>ӏ|{TGzL*Һԧ?$cDЎ{RLfg=ڽt#&iY[s_~Fb͇-3mohJ?|!GD"CƱo#}`:758P p0đ n-9F~Cߞ195xo=u7e#=C;C;C;C{C{ [CCtGg?.[]Vdj}@>3PO |}rR_1}5طhVzp-tvckS}G6'LMtSާ|5 KQ'G]YG5%'I !B9}2'M1NH罥(VTy๮3G3D? i[W*⬘[WWWW +dWj^Վ ǼHuRC(>׶b[Wzf|V]-d'VIxN2N((.⠘|Pq?g?ӓX\CeIM/vnFfv7)xN}M8!\9JZX+fǰI#xZU|}2../5Or񑈼=慵rFF#w `RRlg\W,^f_ Yݪ<^ħ֖YrSmMY-,nMD?/]i^v~OvD7Y kUO;zymSW6r!Y 숪zrqvgS~<| U_bqY^wu~["^NzV>=P"]k|,t/ⲗ~;\W%\9NFտ~v$~}-2K+LB_p +?N}=8=uq]p%5?%ϹT=!uqyga'չoy ٙ`}wg4}-=/Npɑ/oiWIo3wo>Eԣ8s}Wj|WvO9&zi6{޽?|$5Qw{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{0[(|>}J_/:w1zEꄠN2CG=_gݿLzJ<8+*W{=Zs'+B ֒nf= 2bx ׍y2Dky w;;SrSqVew1gύDzz+_>UxsO]GSj[ݘzJ,e| Lq)q^-"zϑeA`mma@ԆҔX,.;yqYb@݈ucUj!{Sz֖k8k⬘+rK28$\w^'Z1r<}Tz\b8+抿bb~BϪ%}+dy gZ`{Hu\օLDG7c2>g\w}_WTT"Z;GT]}wDxMXCmz늖}w@ݎߣUjW +=G}A _CtTb6}Mse_ysyG_Cx ȉbx*ɾPywMkϬOE+o/|~v2)D'|Y^bnB!NBV duYbI )rOM=iԳwo\8u$t}n(޸%Ґ9v{Nx93/>wcȖzW}z݃oߟ|7o߾#+7_x6yF/g;M|/ԣw R}ٴc㏟ϼyRX~}f#_m366dz/>=I>|k>^q+s?MWO&~vv>g˻>Wi,i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6+9Msz>gۥ66dzFA~2>vmdn[tW?ycWu[l:>|΃GS/_{ ),߽~9+ǻg,V}vv^}ًW߼}o߼~ۗ;UŹ># c/ݼԋ33H!yb{7/>id,*Snܝ|ldHKϧ={©#[(.S{_GÉn]?s0wr}n( Voߵnݽw)$߻{뇋'^,ݐsSe)s7n޾36#)$ccwn߼qٞÙh\%e!7޼h ._zW._p~*+YVEZ>sYRHFFO9qx_kC*wJBẆGuǎܟin JH ؼ57J3]{I̤ŚJCUnt{44Pߟz' +68G^\h(y? |yn`xwXzew={&qLj`H^{sC_j:4p_sC__׽#]];?ܷaƚ8<|&6@]]zf3Mn?@BGG^}:-[r?qn77]]6exܪж/{ۡ> I}LU}~s=:{vweRζ֥>!GN}t=)qc7gM{vv36OKo@߹oi5:`CCzǷ}C+|ǿ#ղ{zG{Y2DSh6,h^tņE]zhɁhop̟W X}9p߿p=V,68W154<KwtvE/e{Ov~~9ȝI$! ;)ӧzɯ>P#~Lmi5>nKe2LgG=߱6y=utjniH>i=ʗҠu%[;rt(OB!dWq !s݄O[ꋊbEEh ;s49=JИuU3]v8Nnh4TS%yH>GRCSU/Lmꊔ+*do'UlT$\7!t8X)n*Ίu(/{uugAvvU:p̫T'X?X)nqm8+抿u^gvyg2zȚAqb$#Bz!GO #q3=YK>;_Ra^&jdfwׄ•db;O| k?Y'RS|.gjc^X*kQjd8Rkx&Y+VqVexŘPYM_ޭ5ψ:O|`mO(>*7Va8زnDJNc2ߕ>eoGtVxY̮jIѶ1zXo/绾q'w'kw<׽{ȓ=GzWW,e}WE*5섮 jx%7QI^OX,.{9ʾu^•dD].gG+3喙bQ$7SSeW_{PYZ2YO2_w{R^wٙ~w^Og }+#q"@ND b{xEߛ6s|SD=3w?ϮwHOowAoHkswOYYk||||||||||||||||||||||||||||||||||||||{9߽ŎH^w|Ox Jw|k4@>b|W=|Nj$;tԪws/bw5+I/5w/\ `-Y(fӰ[_+#pݘ'CD&O zp1+9%g=g\7]v}VyjjlTĕjP^_6$>`ѶaX\ʞ{Q4U:1rP`;oZ1{v?;;+rN}FnMD^UF_xM$w{X7G}4婶Ս׫bqY^PYMG ]֖ tMm+M+rlY닊Ǒe,ԍZ7.ѫQE=ūGq`mI龆V+y/,ΊX,./뻿^Q!Cuw=/xya>K-)G5.b+.>o,Z]җBrF T!`]HOD}4q3/#qVMuEE-2JNwDE~g~z'LTׄM14mݦ'kh=w_yG/ x=Zv#!`5TKH)nWY17_||>wU>}a?${KzI)b8[_ i=O=}8:(T(g'|J,Bd/P|Bȧj@%&B4!d@Ve,£ +[UUeIii .@ii*uNRflS|$D +*<, nSg,v܈GVTWeB΍CUnt{vLsC]8TVZ=6;|ᑑ >sֆhU0~CIYȍ7;3x¥W^#˗.99ʲo(Tm9{H +؝7o\xp)Z4gz'/p'H!p[?\<`@O9O'=~B +G'~u|T)t#.ܸ;1JO={:9qƅSGI7[" c/ݼԋ33H!yb{7/>il٨'xէ=xg/^~;r޾}Ջgo_lr}>_B +w_N=zp.glM{:6̛~ ow,Ma䄕EhM6Q +fSVBЬ^ +H3%@ El Í$@$h]wv,+=¼<_{wv윿ѷk? ~>o_}u$o_/d~<~oZs?V/;?On?t~On?t~On?t~On?t~On?t~On?t~On?t~On?t~On?t~j~2|Vߗz7\Ӽoni݇7{=>zņEDz٧U # 64Yzk~ݨni*74UzzoGGGoz~Z{?bK{??~(K\5>MNO?'ߜ?yß~O?}s[_W|͋W篿yw?8yΌT'_|_^L?O^<7f݇|֩%)SrdNNI18cNJ2Gm + dg 2gPB)[7#HVO'ow~_]78y |pg\|{7痟g_| |_.{/x.aϽzdyox9/SW//^79͏zDΟ޳sjU ƆϹƏ'_ynݗgױ®5SLO6ŠwfS6_\G>ǒU.NIA7~ /'/T$_x~vt&;J)?^Ɨ_[qlo<I8 57L( }駯_<ͫ +|+~+^o~ᮞݽ7q7/z x/'Fym7m"'T +1G}ڕ[9 |#o<9&kB*,P֫uL`Rl^";k<^cqFV9f|z(hCYn!HjR$+EJ2芛2:*oM֧dP֞BYV5>Ԛ!^dik* B!'uP(Ĭ8 kv +kU.&kv*̤L 4 8&5l6hc Y@gI?*){g\"M`@qJgtN+`]B!ڜ-\DĮHV;?8`w:Dc.ћ[ s\u\o''"Bh}m#Cuz _槿u&lu RHiPӠ32lsS0~L`w:..akpk)*0sU=dWάN㋵%3U.vZH=DSյU#C ?Zص> RW4D+ήLJiy}ub8zL'wq{Ni5z ~ۗwd9[]a.˫lܳ'o${ysϩ[&ymR~N[ nvi[\]=G@oa|{jѫlh pYZPk:N^:D H֡CDWv6ڠvXȇfycǂw83!J&Y k\1LQu +{] '/L$rŻ"3t"4hu;M;h|ԥu-;p+ z'cٙHPbA'u]ucu.=U۔I5@Ĝ۵) <'Qxz(naxQ"B첪:oydqyE +dg 2Ob-yA{WjlkE:AEJGX*X +맦`X+zWiVŜ}:;oK%3ifJPc0 +dcN@ہ-/*)CnnڶBwͭsۧ|XV4+wLMС]v}2Y=h u/&ͪuݫ14b"7D'B#:( lrnո2&k$ߎH& -~x@M[loVyL{l5D˧ݾ|myazU7[;H))9e3d˕V%j20DznЎ뵢Ďsd8䐅s&U6 ab 93\jg?u&F92r >:pW ~p^?pB%7 ho;':cnv0H&bOw eZ@+fVhs6/nT+,Žʵ1A8 etO&FVyCOotf]uzݪV;-.^ߘۆ0o&F(mvrX;Jhlof͋;/Wk^oΤ:n{>u3JotU_~H*8&D6;M1GD-'k3:v98<;yr"Y=& wO|eklBE ̦?:2IyɄȃJjYmqǣbBr%m Zou,ږ3^RʸYN½^ېw7N` />y <һRFW "}(u.擗3LآybäIei޷lmJ*L`*6@YBt [)sEk3 +"!'cޏ/T3~gjvt''J#Ќ7q~~sgˋN̓~Iu 9z|?2E};|/9gf6P?NW7wο?[_>_Y4 A1:%?J<X-|g/[ǯ󋑰{an'kr2~Rot s.ߖM7y87]4kp1r _1M-͓SQAx[[Co(:Yj3Ɖk;jЉd M(@ +ik{\ Ab!$7 `fe`<>5~,)ocW-Y8k<+1y&Q3ccn%FUxcхeMv&\D07ͮ׃N$ШmM$U)dM ϲ '#6M2{`?J2S32 +GXXX"{_2 31y`?ηC E2LEy,ٌ b + qVj44Ì`*,<  {6(%LHtY̎, 7~uT)`"&>caD}1x泺"]YbJY]W;o6o%۪G@WE@,kJ^l5:^ Lc^Mnd30#pXr]rh'τ3n蔷>9C^ TӶ=F@='Jm +U˜]i:ZEí$hnkiW^kP@MqD&ʬHvaVN$=xh}E\Nc8 'AXs1dBiDR,e"#]+_ŻkWO70٘3,GfUϋ4.-,YfT·I;9i[ +9aLrX#yΨQ # c#$%d& IzyfE)f!Z@3¬%W7+S;1ޏe8"h6gŢPFkD +o@5i+" B&u0h`ևS4 u=hEE堹=l:+aX5./{X 37&ݺW|m6Pt]O?1Aw4ڙ3^ps֡0G ^ + + ,+-%aL~~l/|sO=zsNZ [%(^\+)}KNs(RPv9W&mV^fYaFvqɕP̺)[ +@+H8i_v-v@ܤcpbyp U6 mڵVlC5Jzp:D"aB%Tr` 3ֱ9Yr 8;[7+B&)b1,,̞¾S0^Ӿ&+Y#,Ӝ=R& Et:E =YZ=Kݕ% s;S=8+jUX $7a( +^J6NaM+/5 '`l6`O{d.{ ҙ[yc`IƚYv+=4Xv.)hE Fl$ޘIlC`"[_ޑ'CmųlσG4`"o ̐jr.c?[Aܘ CϠ%a٤gk +žTEB+Yx9io*F[|$p a'f֊`S4]RPau-Jds1ڔ{-pwxH :&VV!3 (WwGV䁺:*8$: 0bK'.3yO&-wٔPaA\- ] &$&03˳SI%PnI@saE859b d#Of?gbg6*QL6***2)+ guK呟v[q%Cw+?%h/HgWe,ӦĆ-+2*Q`mQ |]rw&ٽ{6xP^bGijpCLX(3mxTdx@AW +30& {x<o"T0B)Ao +#֫V=ԫT-A`6N"3w?MI0H˥X aڙ&Z Ra;߳k*7 o|Yx8^ZtY5Gԗ&0ggGHB*B)-J?ٙJ<ݰ7'I=`Jr VirzmzCڻѶN&@DՑ##Aڍv=O󄒁 +qx&OSx0]dZ+=b/VvMϙUcVXg + k6?K`7?aV,8fc7g 5#IDnPEط۳civz̳{Kbh!׼v| KU^XF4!C dSf8̓H=L 3 @ǰdcT_dG{u[:Cth6CUS.u1b/ 2w@q6Xsr=D2iKǞ'ī_}qAJ̔ 1ў?mFb8dBy~lmkOMemWKQW}[#S2 MlC'Caa$.&ּAAU@n#;dgeb#ה6'Yiϝ+XL&Ӻ(V%y9qiЉd cq:nrMc.02UyɄ{0Pٺ7$,Jm)L>C9)&Qx+66"uε7<=ojiTp88V080hKYSXxafF3eż(d e\ٝ ɄA7 CH߄Y/x LV;MM+dIuD2,b216_a~_z򛟐fN>^^zW?/sErYw'bqZ72=Ÿ[~ӹ"dza]S LYI%)B-1 'Q}ᳯ~ ( +YI,Ch0y&rsLrFŎ,P Bq@=<(1ZD̂dUEVL=zWgGrWzr ~k +v:G/V~PM=8ޥ +ݿ#c'Nm̝`%'$3c'enXپ}l<sػ;بK|L._"ʗMʳ\޸@c6%gX]_[S`gWywO.ڙ_ ҕz G_ܼ K? +R.ZSl'Z +V?n53)d16٪ABفB)! 5`{Zw _BBE.BV7$IP F mL-M33k M?f]lO^lO>K'c'E'[UIwO4s+mt,)1S &ABمB)VAxMXByX +/QdC+-Jars1`ڔB+U|T6١ c(OVy6duWWdN:.77qx:r @͓͋ `$[9h7wq@lY:ZVչ#7|_F6uKV'mF,39x"]6?רɌo`F8\s5x,/j`vF1:P؛ l0AVnȼ+K/T] l.VC% J%fbΎ_E TP}ؕ,)< ,QF 'ǔc[Ia ~ߐ>!s>$;/ XcqKxI *]I0RaNe'5&se,r`hr0*xVXs3ÇXvRz9[ZKs˗r487{3~!u@4\^-\Y *zYb~ۧVtLeu &[EFv6%a`24qF5JUueY;/1scjrWuܵj琛T;6Јk燯yc&{vD,UJ.M [۴pC^{vEPJƷM*f-KWh$\ڹ&xvX je6s6ˆ'rWuM h禦}ڹS93 oKWYt;ͺYx(rK7KdcsQs-ݬsRR/!ߢ7ܬ*hK71x5,f56d2%A7dn*WM֔5 DݼЦnF1WhCP7<:<\)(>~Hʹ9L|3s6DY,kVyOVf Nm\ +QNC;16KTάi/ҼEZ9 dr:w)Ⱥbts_jݼrOu|Qr n>2yҰY͏@73V11"I~WkVT[$Xβ&ue*:cdڪcE|LADC5ϲ@S8 ,-Ɔ,5sMU)zֵj enzlx# +ۥ-UT6!TsށxdD|UiU{4V*=fӪ'n rP'VMo۲YKzxt2 ٗVe(LV<`{P/,dÄፚyǾӨ!%L=.q{ֱreBSā0_P10m<̄Ȃא]`9ғFw.d4'G?kO U=.0;oa; 54XV[2^itbԻlVIۼJ`}3<}ʀK[ا &)Ѡ])PSyv!.PUza}S헛$@ٺ(v(Q]E vڧ@Ў ~I6KP %SRKlh l. #!pµObR +i]e.ejBt32+<1ϚQ37O#~ad鱺F@"*>ҠA7 2eVŰfɢ*ElP˂Yi H@3 ̋$tsfVN$=0zRk +g , nCO&]$+xKXCZPy g+ &`p@[6^LgLe2-+[,bvV4Mih^˓5|8tYЍ:N,5 y`7-yJNyW&ۦ@Or,Igg<"Z + ȰsSXV;10$"Z+O 8v{O%)̮g}r4R{$΃Ye>_IYE(>xWRj.eӥ,+9CgaTt*X.d;Z],]kST3P[&pEPExhfPi4&({_0G$]+M.@QLxB`mS\%6*2r.N{$)}إi}p*W83mJ2`ݸ[ͻTxz*^ۂWʑ +6];kkJ{!XlSu9I9r)T +a歒Vi"gnnʟyC*,6Dr- +U jplV.]([äcc?k޳+`FmS)OCXNfoRn +gߤ4j4ݞm"PQ!E5=OcY3>D8ٚ*fHL 8 +/6i4f}ʓ5X^mă-FR +LSA Ol\Mj<*y眎{P(zhZ7n + +`9` ύtrK<;Ah6n %OPǓ#&cZěRӭmx,P*w'OliSbR)'[NL1ؔ'{irSteWLSFvyڣShJ=0WO̜TƗgEDyo<}yXJɻ_x惋g^?x>9"^n*Ľw- PcP)Rӟ]\~r|?VJdwS&퍷?ŽN`^{ftxwcgXJOsnqynq7Zia-3v-*-ޮc^ig+#^`sDg:un>hV>!bT[ ¾QWGфXU&Ml.eڪ#qB|<9(ghq: @v u057=V$VX⚋ּD|$NY ;:>\m Ɩ1`o A9c\ͺlS7&#l-0SgTnv{4J;C^iofvAN;eKt蕠W뻆ެyyhZG^q@oסAC3D@oI(>Lc敖䎱vJ-t nv{6 +;C^aoMR%-۽-ggw!hEvػu}+ {q ˂*f"DU=ᄍU䀨ʴAmRJH|ym Bqf}x<ۗ=z޼gނb@"a/ׁ(o*62&m#u:p&ZHu=J雊I[wʹގf߇lUn:ME]ܔq~;s@XFGQ#b/a(o*6JDLGVk~5[emso9Y]]LΫKqlM tKpv6<_JrডÀe!`>LR`:v6y/Ԯ$9OCJpb\ow*Oͪl Ә'TL_SeQzV`::F=b3T 3ٞ+j\:ˈSASؔ Lk K,fݚ\s4X~? $> DT75fy6҇X, e:'jxneӼr +[+=Tlt j}9mj3#편֣ 4Rn2mٛ odVw)|0XIYAf(P9g3kp80]*f9 dS6wlfrO2 7enڒÎ0,1 T"psk?I7C hv~L + y; LStm{_p(#'/.{z;1O%  ௝V@Mp|ThMMV|@7?.u' +#l [x!.ئ5?K?y띟|[G?oGag?5{ 2=~۟w~xټg7'uc|Okl"}O |-}3sD|@l6U!B1e@ɭ)4/7& +Ecӡ)0ya{8 -<[r̨QXgk{>݉OW5_l0֔aM]Lhnh/{%[q~Ȟ >\O}d3~0| MrUN ; ok6CL&3: .:rA'  ѻ^J˄3'CL6qM^D_%*Z`WCީlͤ /|&ivdg"/(C.%0A'I4J 0ܓX.JL(3q qރO!0IvPpb`I +oK-9|ȕz5ՙLET"Ө߁}yR=k㖬[ +Lrťq_) 9i'l VfR/H=ecἜdx+KPmVA4cq&nQd}A- tY1vo;rIN[)㳡f).^̖a`Ϗl3m2-dI ;BXe2mW9Jg@]*lK ^HHϛHR + ޷S1xfEoBG귇i]7Û6Su&O>vG݁=3,L?A' n\dq pXJz̚ 'hsHbLQPlLɄ17fq\_'iLUȰن\L6B 8[0qBIdL9jݜl堷YD3^ҫ4;6υ +O>{yzỨR% U9n`Տf-M0_= e;eY1r3喟tTx67ԑcrM>&JRȦd*y +V[S^J/ +q$;983d$XtjDzX߰SXT09JrQ{p3D=|BU1DB*,Gdg2 KdtUt"0h?a#3L~w6 _UXy0]gr g,,@?c÷~>du8)⟁ !+o\X*";TXb`ԃN$ݕ6]*V hٰVll$~ N$#[؊kVele5MCm}Ex(niޔ61YngBك,]Wps`q'+MG, _qW+3yuX0Όt"0hvYR l4Qon5i]Hɥs֥:.H1R:jZY`JRV&5 j'w=DB3:6vw+|3R=]7m Ҷ^Cl$ :wxto[cF׭% xlٛK`YSCmg|MDIYrN:bֈ1:hgљY#:yJ~QvHՃvx~dWBv<xgGgSdb<8:lgY? MS-PT6(\ٜl^uCN$Ǽ;TO9vtq-鼵7Wy=7%7XKCUvu&w1D_oSdCMs4Vd5v`S x9e~κm +U}5\o^I kJךY:nSCaU[zdg6s*B\q0dw(tqѝAmXæzh +σʣ<8URnɚFƗ42aЎ=fAwhD]j'!Tܖzux(} ཟ=lbk]1Y#6Skܬ4YY/܏-6zYȻic3,WWDIP;%O`UG7l=22uEpa[L1q eY\&Y3TxjneFd])%0,A;-޶3L@1_[3;05`4[s7UL;5^Ucvlwp?и =b=~ei\F2eLw k\ L#{7otG) 1^Y+0%8ܻv.DzЎxxadL4yM {dqGfA[y_ܥhc(!4$M%/|gvC;4x?v*nQid;?x0:̣xmlm:SE&GgZe,Qv2Y=hyxat&Y)A{t32O- :{GEg6yT'!TܖHc 3{YxkV %N7熫 :+g9$witA'ՃO |kwaІY +Fh"5٭2^K AwJ7}Z. ˯b/_M_dOÝZ MaY@&{I8IvvFlO qZ:Tg >(v@I CN$Af^T|2Y= C*AbbdyfcɄݛ'UoT{R;sz:Z}H.5{Pmisǟ|~v͋ק/>wɋ+qnN '_ʓw~?rrv9盡ɓN~`F j(Pw]Z~FfL{m\89QPxY{jUl2f&4k^bO`,W9 4φgŜ} +N"IV!f+cyF5dP)Y˲QҌ|Q!Rمn#h5G Rh=[/_ڧ94)*{s`a(fs#|E0!|Es+^9|^s/9fi /t-6"b9Lʅ 4wO>vZh~Ρ T&.4Jdc %[9Ƚ 4IeφU3q(OQ$!41Io'ĨQºTSZvZGQ:xHr<(x2ykga::?5ׅB^DIjVxX2*t44MG˫ `::3{KһhdQz*ՌVc7oƀ#Zh  4jڸӤG=iJ5")Mz;%FՏ֥ʵ; pMGf\ᱶ? Q1X=t;-GyTwAAa N*r464-GFm,G0f9,>N~en$,I5v@q z2?ưcm{(a6j8-+k#MzؓT(HѤQbS aQ\n4h46?,Rr,iVcCa1-ųDjMZhv$Vh5JOzҌjV#WGl윬.3A9#NһhdQzTzF+Wб+䂭KEp4f 6jFڶҤG=iJ5)!Mz;%FՏ^Oi:vqxжpGH4F$3`#W4R4pt7ld^E6pQK_$,`;d>)y`ISA~`<:Q5)\n<)s Aa#vу0 pFH42$@W`:J:<#Fl DҔƀ&'gr{pٚp"Sݫ=:l#Wx6Z,!((3}ɾ6=i"'!hĘqP@rr1iЪ b *&Ccw1GQ5\n6ގiU9fV9c\A"cQ$PHɉXGÄҔ%1ISv6JU3ʵ; lvk{:Hx ɴ ºډc ^V;Տ]Oi2vqxFcu1ֱlȭdQU +,C# 3"W'˰<4*6ypp3s1AMyoȵj6@Vf4(VPL`9bjd>F./bo;;#i,, 1/ܴ* +dUX?*$59cQ?⌇*:oU/A'i*Ąz#D#Ƶc)K +/'ԲT=HXj>+ۊfcѐutg+=6m"YET ؠj#fR5}'U#ijd5Y]QUA~5IZn- +A[nL}tXr[[ABʠ+V'MJ +dUXaJUYG r*l0?rh\򫲅acQldI5VTLjduůjFUդ +d'Ujcm/]rZl\"RA%Wl3QcO@#TȪ”RIUkFՏ^Oi6vsqukZ6DR_%$ Tc#L=6cT{& }U3կ&UT=bu5U+v@];hs?&\V"W lePɵj+LzƓ$j40ĬvRZQjSZv\CC6;ӕ!^!T L*6U&Po dUqjFUդjc'1Ϊ; D`rjlmuekJP[f£*ORM#a)Uej +%K5kw@}T=d{Rr86?ZcQU֫`cQhldIuVTg dU]jF` US/x.[;/v֢I?&\V jVVPK2䪴m&=jlISiٸ0q9Y儺 Rg4v[qiVL/}9 1VOO_:^|'+v5'/>'~7 t[? +endstream endobj 103 0 obj <>stream +$ 6q_z +w:UryTq?P:- Xqmy v:9xe-Տ]I4WJG qaL!h +ڈB֠GB"+%o޶G@ e4ؽwnm`"Y=$V#]]ɀGS="`ǢtbMHѻ~J/vpymLzo`{+,HJ܋.;r<,M@ 0tcibKL/BM z_)eԟꁦ)Ȩ&6ch#=:]V6MG.(-F%ggxH۴Mxr|lP%JQD1`gݎ#'@/I DR  K^i>ѭO7IÈP;' ؇. 4B=Sm}:QyЍ.%el_^1z 29rÜpXx01\[6 "oTVIBXA$ z$E+A\۶|&"b:vЂ:>q`2/o<'AC4ċ}y>\0=Y k;CGE}PVM!dIuKT|<$^ Ty:*HiUh0,IfWqƫ>|<݀A&B5PH +ك%3MؽkDSdF 4Cbst1r;*Hqz6Th]  +9++C3FRHz}ݢC3+4G@#8T0K4$9+٩O֟jjD.~`ezG(H{Lx)^1]07j-T Ik6 .Z>7!K]Sg॥Ga43 )|Gڵ䶲ar$В90A8$="$purVH\;4?|"A+nX#~^-U$ˍC^gr)L5iW \ICԙ6wUn`(98)+:Gt$֒fV<QUAtY}9= !nّg1I.;Ls(\Ò~'pnY]_9b~lI(eV*NA 8| /BSoA .*$.Ң]T:/&] K7^n% "T?_6.$Kp{5HZ ^!wRߡ'kW?ESpĸ;AeOpߨx(?u 1@ +U6v."`H4XJud= -\I@ +@2?%UkD/{O^i$g40lHIA%!6:Sp%D~8 ڎbe2O@4 +#3-yܵi}2I'YcXŁf^X༖8+)`W+47`deگ +r?R,eݧ3X!<놪3 C@P +scT8>fuoh&ځx&@ϼ|/i!;b/ +"P9z\AS +d1?uvkU"ByL1j$1h^:gnأa?" 0FK}@J +ł:n$vR7{jtνjD)LWg7,SsC[e7%;ap?7m+e`pQ oD# [};ţe&zYzH'j~ޡ:PWi5JL/͓ /[;)YҠ> 4$AcW;VmO)RA#eiuC QJsoܢ:o*K4KWI岺!Up:i%)X?r?w]9\KrgŌ ОBVs#=x;S9~lkzo8tR!biMdi$w`M *Na}4: 3R^tH)rb+QMlH[qR0})bpbr+4T$f}\VlQI`bNȮil\g2!GB$ID~OY`$|&sٯ3/k;9BU%%@.UR&Ob1!s(NjҞD(5+;(gӣ`s@OUIGZ} L90je$nŧDj,k%uӿOc7@!nݚdwM1(|if-$YCX $9QTQ$aϔ@Em1'ƔHޕ=N}Q///xfdH֤P>1(ϾK"BWxrU C3 qKur%&YapEPxR uk#! g(F#֮]c*8I@I 18YtATj<˜9\k@;xxl&临όCx\w8cPR!!aw>ñ ,L, XWѐMn9ӆ~z|/SoØL͆$R?1uP.)A)]qnKk$ŌMxcDhhB"VYI;Q(Ij٣Cc +({_i¤G??cĜ;b +Toz +͍vCR;E,MWdFqR +JDf <\:+򉭷P0>p7:V1PiE{D\= ]QB5/tEGqOUP zXb=L;qOPPv@[#`}K`xnŲ8n]AN:= ͱI>(nRs*"XRF2i5$^HE)MlCLl/7 }hiM-w}JQ#{z[bF=˰ dzqZ5ۉٽ~>nlRXЉ+q]*TPl"&{VS:l!h-vɒMQ`PK⁄ଆIGVҰ楖|躓 lhxBڈqfAOwԂEe4etF/x64Y巨 nYy2NSTIX- +0"(5$>R uTN0@ZMxU!I^V>EJ2uƁU-6V +=^˦M-1(E+=2;kfP3RO{쪈DUfnOdDn0 bM\HbN=)MGgtmI>{H@l tgnM01@ORb2 dGCy; ddݙ0FtlݏII6 t9=+0# 7z`[~OR-]g\xR #=ud~8+ɆHaJ "|EM 7R"N:؝.Iآ%bY"EȍP{$%s jV3{dtU2TocFȫELx!z pe6q9i +uLqk+W5Q^~5b4p]UD760?GCx}Ԃ4[,>OXl=]]ٜ=uO:wi:BLR@Y*$hUo}tۮ%7sh~T" KP:)s3q"%4}L>s*feܱO|7x|R"&Q&aչ/)0μu@sD0κM:] +"}fuY`1Dpڈl^&;"BbT-oxkT%qį$0z-/g ʡX3Q^aB;KU_"eG&oYe#3^e6t:i7p +nas{y}K5g9.TOwV_PrԅACvZZJ, RvRڳRuahM`\}[Z2@gj R5S{GgH߿ֲ5{ϣ#!6vT!8VLGz/>#Uzr4Y@pI)LQ#+5/, \ȇcorbQ6rJ^4yKy0j(9er.H<)/my} {9p/eGqJof' k)b.=׿T%x%fYpM,͟U}_M~u S/6i͍q) +0a|'sJ{&ɏ ]lumlLv4G+k1Met8L/U%%6aZӢq;hAԾ0+PPTpaBcx$)*bHU;Yf84rY/y<5k;803z +vfq{릈bTDxfyL*| ɬx{s  )ۮh%D@ j5rC)h1F<Je?9R)aqiIdujF)lrS' `Ri[%.WGI )=ϥ§zC) +&mtsn$#7S.: y!d̯[7=̐ +YDמAiq"X!.[(<p ST И?ߧ~7 xTi '&ؼ@ 0_ A4\H@YQIKwO:TϋR(Dmn٢aWzYGxbt*0{ApH+XD @9s=ueW(yxxkN5JhDhNK$plH#՛m4Eq^d)f>^ZPx%?@]9l>d4?jݢ' '`44wh6^#LƐ0A^;7*jX%AH ;?sS5o3ifJPS'Tԛ%xD&]4+V@=03QLWyS% s1GJ"@Hb,iY%]ZM?RD~ +nXKmD-5%(Ŷ%x`*iꎪ_#W +ųR~QdzZuCu)x9`jՁKŮo/X +tKqk|j%ie]ZrEa2]"ZN?(8)aM cpDP3o"SnJ1)t#?Kt[\O * 3% reA_JzG!H*[6 Q$^'쀊 Z< VDǁYZ+z O@DrT5Xns*lr;)2@vdmB mՙK-$Eh ,fyGX vVq'p3!]ΙC7]PS)I듅a,G7»j^ eZAmD[ic8F&a܎dKC[慠HlxU2;@V(a5*WGf u>LC|&j U%6H$ף'.W4 E H fi"$YIS&G.Ap`-ų3q+Y#ħ-2j{ rH)[ !yS ip*ԜT"SbBS +|@܏\^Pgy`߶ah>q( ;NJ +ЕPs*cRvM~•JCuMk4 mЃk +ߔ%!hi@54mY+PD:{#8+YS)?A6$9R b+i\&dŵj[X@PƑpMOQ{_~]տ9dƲb;KUA=oz|uӧy/瓼VZ?57iol)&`'Oڔ4Rp6:6]|; KkLa ^nbDYmbUSw;nִ#imJ5L3\*xxk;ߔ9NTxwWlY(^df3A 'yk,72^-{-Q3{͵c}=V8{=1Sm?ʹyT (əb{rfp7>hɴBmNpݔϴ+xtXiL&&5H:H^NF+L[g=.6HYEe+cDXPM'a/G)QZ68h`dž%$N.T cg Y\0\%Jl:,$)8Gc\H+[G~ˋUZ:IkdiX5<IJ8L>e$23M닄:7G W'D!٩L6c!$Yk:f|,@(IMJBģݟJс% +Lc3/A*=J))|i=DdOtb$V4\gF_̟843\$#_!ɴJ[mzW +PwT/2|85ޫt I|Nk]܀R b hZP\RPBbc ׵8c)K.Jgȿ:UkqZdbϭFٿlO=p1G1+:.LŢRrK^X/e`X-Ċϟk~mFk> B07grh$&RbZ>(uCN dU%ŭ"]Mly N(Zb@#E/Y 3 ֞1Ⱦ,Vs~.:%T u/RO\oEQ'mx-=փ `DAή0 AP!t^p62zͣ{LgP)ve0ik6X7wv wÞE[:26si٪ )$ҶBϯ\O&CZ$<7b R0 [>M]G[X[뙺ㆭNo߫d0% x5v[Oz +Ms LElR3Q_V#L8ۥҜ'p<"U7⦏c@ +36<<8nPptO@Y~idLk&+'@||R~kW0zA95ԄdFqַM;)SOm 4 Of̏f)ƫJMEpFdd#ƔyL'f_|ٟǿݿ7>_^ +HC + ?N !f,Q"YPT8ԟ>-g%LqX  nhBViA D} ؒCl;@4ܶ+ wE$  +)K*8nGi&1=pT=S({*»KiiOcz墓n^~o[%%- 쁝&=4L|SgBm00:1azerX9Ή)^ ';K؟=bFewTuY , Q}v"/bJ"Ẃ~jN]޾~֬Xkv`}l[0вTL|AZuc1SMguUYF$B]G&?FEn rubV% ѕފgaUe٦facyK +:q.7RLׁǴ֩\o&U}LEAh <9;cJ0F>:!+|F/Jr$ADOhw2->wI?&[ +8` ,WpSl~=`\ D\JPNڟnMȆ䭌LÑF̋E@+g~#[Q/AGH(H:׆B.aLMr'b⠓7Ѭ;bpԕTo@yh4 ðҗP,8f\viBxIs) !{J{n +: +WsqJuEwQgw! +m ww2@<`.MO6eMGZQ_MVEŷEkS +M8Ls'ʋZ4? ҙJ-W+ +!.Nde1o.[cݔa"0cY;0)>-~5h֞Z;Rq>Vީ/Ioi [.kJ5+LS CT* +q0FjE!u2s1Hcp3!l5k47%#B׀cTJA*G2.K BTjuS00`P`-pXz.@߮.xjhHy.ӂ3qopYE+!Rc!5b2 ůnԉ3(=ZKԶH̔3ps-㽀}0H/նocET"nU@Q'}'wRBYScPa(Sje`h]B6DQ?ٸP>,6O:\ۭ39ױEIJx%f_բ&GcrTftNCGQ|T@kbD~i)_o[@Uv0q3X*=J"mi*Z.P<`P8OOxA43'XP죀B(@<(7&aqUR[g8:c&Ё7U AF GavoRݰ.e0__LV1o TJ}LO#MƏ1#cҮO3B7xtt,F2֪RKy8ye"&k÷ FC:< :M"Sm)wcl)W|Jm$WE +Q֋{rAU|ɫo,D0 q-Et-z 9^͵-0^{7b7_x<)wcK?{sŢ"& - UKUV 69KB)cdYU.XƋ?{H^o.ΓJi(XA=a0ٛT.å+68Gn=⩜TdL0~%а1ND eE0 RN@{CIc_֮KF88 FsY{Z^#K$ B ߰mjFk6B$b;q(Yܕ1O#B1F=K#9a+s3_ӞaH$?Sl!5<~mEFwA$c@aZIsl1(W;֝9ǏQvĈXh +hOn#ܔ"Ɔ  p71?n$CQxiFJ= 'ٴ!+5Sqܾ xi!z6)cf{f|R҈'SZ P2pp;k\4Mi~YHc?o<=g.%Q~Ƀ.0X4!chQJ9H>eŻOSmfS(F<ɕ9~il2)P +xnz@%<3 $0AǣCr #4, W/yE;[L5Y"y! ݎm[B*Xlsѝ +) ~R!)&چSKtpڨ  two#Hi^y''p"T:yAIdkg+twOsU`Oזi#IEDHCg(1>T06'^PO:2X(8GfT)E(u]Y-TK\܂!/4fhyǩtڊ;NUnTf֓d@W~ݚi *P.{h{(/ ɄgVPyܰr,,-OEVS'*uM)9HčP:c4$V8`I}A~MN~۾ڍω\^6Ѭ`I6XSH@0TD-4ACVkWR%]~vϡp<3bZ6^µbdɍސrdmˑ=ѷn}K)㙨auǙpe4J^LOGuVʜMԁF@pң5ȑ7}ݮ( + NIv-ey qRHGJ@w/;ŋl㲇@n>kYTvj3Y?1X1zTkNص bb9n?28r2%%9aP7i^-)٦}6;(ۣA|oTn" + ?F7.>!Ƨ/=^sawpk|s [Z#:mՄSL7[ΠL4pPy3U3̀d_`Dיrkk %]z{JU?(,m0={1={nJ +F_KOL-V`?Q?xa64ڡBVc{JTJͽ;g?n6=,c>t_ZW*و2uY=qؙ*V-ӷ/7FǒYK}FCڊ\o"o^U~K&,p~𵭃lgA=^wzЉEa,ZF"{*X`#Z1MY X[:b|]351l=pŠYS:n~ijjԤMr%&fDFd]SIg+5NJ3])¬w܁!ZN}n4 2|yx\ѡ2x0ͩ %c~7[Us&#D4]][hzj\˭=^=Pԯtt9ʰft5:Öy 6d]r@$Ls C[l>(&ƩmT) .ZL P}tࣛڃkF +ו?-T&TPZ ,@v7]64) +=rL!&4l; NX#Bۏzz1 P$ʼnLN$<D/R)|)ϔ9y19>P?~Zua$-#2IT,; Mلc7P@(OxCL2}=rB!ޡ:C])6 ix9HEѴr +yF՞֡hJ64q^l Mks2`9cLWz-r]W WqzTܼkD_Vh;('4KeDjam +f@9[Qo +{^8@ +0PwyO@svܫ]'SƫlP*!+7=A=ԄXHA8"QȁO[a|Nu)Â3Pd%f !ؾk c xO҄DĴM+YO J_3"`UpXQ;&щ|c#G;nZ?P\ljb!$l]6@A2({ [; fH$D݂ R={У^eNudcʞ% {a@p^DD6͹2~( eqV3ZJNSdeW)&w\u96gIJ0yXufWW+%B +&*z EZZAF|>p+'J9r%=1`$ +~`Y 3ִ8X@{TuX`wyѦ&7fӓWw 8%-3a+bzrU!no](+E@N OWљ/($ l* DgJ.b[H}U9(;[U:rѺTOʁ{6' by&KVL :(n8w`u=J?zň3f@:&# N@54_tQlr Pd?,it1Xy`Lt +nwʭWw"Շd<-@{ +whR6EDB Sa CTO ;ѱx>4I+60p\n?HAzZSƨ2(DVZ 妰VX )n}FP@o/JQ2K[iem:\)2\ fCy16y3pu"tzIzY` &ƄTA->hQFs {+IV&3 ڠuL* +%5Zä*|ldhZS +!"ȜPX qBd)%5F,HhN8[n?^\u )b#ꠓap718>UVľt<!И*W9ղ~ Nb)qT <}v{8l j⑒!Vd_)HhB '{ZKkf#؃PsH+ ߌ8k//θ쟧h(1ͥ֩O\-a 쳑#Xȡ'hrgՙsmm!8ݲzbߚ@yAEI"Pv&\ dwMCݡaJ+KvEҥ,f-z\صe#Dh vB仕_uI(%@Jw|ml%<4g~cTDRyfv}Z.脓"JEnԲAJ^P)ڹ*Bt-TbgHRP +@(9"ort(~\ ?c(_dHSG* ܝ])- qվά +DvΗnmg{)wf=?nWJϷNrD&H$G!;Ș8Y޲ǀ,nXZ:=kY bN[=.Asa@|MG;6_E=aoQÁ5u¹ĕ y{E.# e)JMa_"v㭤p:h!Oՠ9Z{ +1 X+ΰn>F5@ɺ .P+'DWz(+'׌qi5H=u)5/SJYcOe!W%aCC_nbeQs7p^Ni(ʎށLÑHתmĵPC&7㆞_4H( <߷+ԃ9 4͸H\?Ȅu[U/j@ܕ,$!R9#OA,y +{UmMנ{UZ!~ +| #%>Z%!^F̄LU!7([>BN(1Q^zdrE!X-؆ɑM5r_BV_Kidmu1mXd|HAUd=3CiWE!N-T;: -9A}$6^f:ŷտZQյoBvZ,Z&P|HLNBKߐYQb$(R%)fbL +MKC;X%8U Ug֔*i^RD+G=ڏ{#P&qrڎ:C !xb+"7,q=:3lf9WLrNZ|TIuZBڗ`ߨy7 +Tqj%4^:\yyrٛ#x㴣Θm1$g58֫V6?=N74Ȏ:7(jvs] C fsK4"% Is*<Ɠ/s ` !]D~Q5Mp3(?,tgO8A؊ԐD3ҋP$Π;jNxa}N%` UZO 4 :rg7)k xĠHi&`3?9&zI"*?݉JI X^q/c + < +سאbqD} L24csӑ!zs> g9aG/J\AKzDJB(2QF948 .TK[ Ԣd5E6pn'Y*^vkV*O TLCQ­>tt2~oF {K=U3P`+VqheU苢BOԋpefeH)u`W;0Q0/"wjIfAʼ X,nw+J; C8x DBT~M?d=Izw$zJ%aN[J +@`h+sPCؽWޛt[@plBBf=LFJg`fJ]O . p_c%LOhyT[1)jYaqVRxO3G\KݕvV_{dZ1'qyU]xO͖BrRsx[ @ۿ`_sdpR MhTY1@P4{ywj]lqm k5 1%p`}Ȼo0YI>#:mM)K>hSk]+tKdPO6 $\|LPU3duiWp [#~)t'Z5߲ Rٞ+s# Do%5'8TTH* 9Kpc(VD>-4y,oR\e9#ťQ!!~-Y4(~qK)Vf؋EpIZj~|8Q,ؗhaκ.VI܉vO}L 5:<ֱ#˽׷̐ xT74~i9>&pfSv~.i +Ke ma..͍^ScʦS z8 .R4a$o 8~Ӊ Fhl +̰n-FR.i;#ؤH1&dSTQ>* mq2 hpֶDGڰC`m`[skߓ@l-% ӇrsZ I21+4j/GQwyY_kUZI>*b9l 9l2HF,S48x|l!>ϹIyu~* Sg0NKݽ7dTu{M!CPp]pR7q z{3GԹc +ӲG +n&0 B355 +G.^翺>0ow>E&.Z!00cY/cRm>o)z3)"UH4 R(Z T# D`8qdz +z<5Րr{Ħ{O!2_cH{ u4\w%z,N)~pGUHދHXANv%*NYE)] ZpohB z 7.=ÁH!׮ #yk5.5?G)=(j]'K;,+V`Z#x'"`-")a$7B#l恢Zw1x;;+ZP%7ԃo@ +2h% D"D#J/l')4P5u0vB6`9FbO5^VgiҠ_u%C Hqd䱐)BJ ^vEK.ޒ@@XeECTp +IN/,| Sʟo˝)iK +]\ut=oleo1]& 20lzUb*!p2W$= xx`‹#"g:+3Zʅ6M +O7˓ 2e +}Xq+> q =M#do.:NۇQO9-Z_p@Vԧ-y@ˉ9DPdN.|@t*, p١?P1Z[F%ؤ>u_JǼ@AZ?:e$Ƭ,g(J'o21qEʅ1ߍ8_tF*}ŘDɋU:/;:@B1$ܑ A|Lî j*U˟ tQ!`CuS=Z=S WT5 +s?u$/Ì{#c=8gawR+Xtt\ߋŞP}Gn?sn0ayfQ-CGb 3~IXQ*ro=LR{@7=\a@T5Tߣn%腪N&'r2B)ۿx^/Gnd]H[&VH-_`;! ی9C  iRK-2tʊG ?3AdSӆnvIW{\mkoo +!7@!:ޏxp=qlfgzXlld+2 s;D"Z, +ZT"Z:z>GozfWCc3K` =+>wci|ȓh]L~գŽ+}+BW`l2gEe.-8__ AJu2wnZ0J@G;B0V$0JGb ^g +p&-r sM q-ٿԟ(æJ6=h`mE`9^0:t4˽"* =esϩ>wS+c NQp (-c;!OM(Ը%&/]:id}h~UURL\oݞC(t9ZH劥gHpWFV$]pEAvQ_Y%mw^F}^6BX> ݌$0{8;M"z:G]21fP?8ű @RQ@3ލ I/ˬsT;pjFL!xo r"e6/քMF-AmQj S-#+)N'R?tƤۂtzAG{c-6yv}z7j I5q^J'#F\q4j*!bl U߷+\߆ΘKQU +o~ȶ“(.hx!xYyze<_xؒXkCoa׃QxESqr1dsk3I镚_ +Mgޑd& A,w]H X es-5-]5 L={_KW}%).PC5ǹy'x>G*2s,$.+zT^ +W1.Ņ/JU~t=]xN9@Wk|%}|#^ [G2PoZviZLC~~qqYٲٺv@~]\yFPpjVRa`[@L.~mk3ީT֘drV]_ӾAMѡ\ "kyNzjkԽ79:ww%>vP^֗(&=ZOÙFG5SRM+V]뭐Yygcԇ󢒃9ԧqk{2W߄E) .j` J $< UWm^\{\x((4$m Zt6%w}>Gc0@OTJ`zp{)1o$X 5e `~HO'hc.8^Wז}k߯uܗkLw?ްu8PMs@Q%m3,+L`ciEX}nh2u梄 ] 0wA#Ⱦhl%MΉ=P5anaH:> f8ڑDcHĩeDn`Xu # nQaAN @v >]jzsa0,fg<_|C-K\z@!3Z>JJ2M#$gu=SkkGhRTZBq'x 7NǾ^H7Z.TKwK2}B([BjZ>OIHjp,5FDFbyfp1(V%~"cÃNps&Ce՝ qB^?V"EynNLpӢ0jNM8̉Jj^&bYZ-rx9J֠: !2f_XAۣv(!ޚ;{k|x_~ݟ?O_wϿ_~O竼^dF^򾱉F GUB4*A)'!ci|%L {hI_5`PqCϨ`gL0б4Z.ħZԞ'K+e2z +yiPab@C$^f>FR͏ʌѷ lGo Jq/0QȠЁB(L^6a9pVBބ;N22u3GH7&kC +,Vߛ,GΧ\+Hf` ZɌbga.A wte/ɌP5o.^U ѹyXYX'J ͤ@br PL 9Ja-L~x^8ncG& +MBC@/$V{w/Li"O)h"<%ݠ-B4=MOt]7NU)"] +4ŒM-$}lk,wP]f!ƼT{1>Ө<bHt<>ߟ7~E ^?~e= zJ4:~hPK\{;w>c)&H ɉwٷ+g8?`Ǘ·>/LMAyߝw ;`>^<$r_#vʺj\ob3] >}_fn4L8,WUMp^GJԵe iPB$vOK{'Хt/J^~,iUw 0 ph WfnZ*es?sheͽ "*9hV1iaڄRވk{zl1}9۾+׉NZ=كd *[Hd #yum.l`lm݄W[Z.jfkEdseEc,J89ZcB9L'$s ه>x4Ŏ5abwZY4E]PBQp`]zu%ȲKiE{4u+ـ׏;;YL'JCEF Nِ4i^rP_;M4/u(S҇'(SP-RPڋY;?7Nyş³ 3 n!Mڱ:C!֬|Ձ* y^C*U~p .z3[tї0Np%a[Հ&g\) jX>u㙥x9'jqn3"kN +pW[ a3= q(q% | PZH9`ߤ%?\Q)R +Dϛ32jxC +NeMԲG}DaY \Vh 9ldvٿ kAuX} rc֭!{ycܭ yuzeSAoB7p]X>׀;ҲAI*%ZO Ǥ0]$dL"~umb{k)UԊۘJۆgsA(ތc){\S +Ty[q>?-5I)CXSa@i=fVӳA|Lԃ mqhP #7^`ܢC:)LwåAr7@ С}h4nHyu. 7Yߓ=4_{7Z FNhL6tf~t^S)>S._ mv{u}?RLDtn΃Eڟܢ"`4)v1phÖx+ύ =p+J 9|Z)dl{4z#SBOiy +JWC!{^@Rj~xi6w^jlTlQ}]tPzi"2^篯ά'ZWs+4>K8Q;`$HA>L nK ä&M6ӃC I3}fD*s:p#KĞ60qPI` $ o3*?糑O_w;]Cs +$ ʵ{ߊȾė9"V3џFE9*Ɔ:9h\:hg|}q33G^ #5b{R@W@*cK%jNi{2Q@4,=Z)_N Mi|{LSʁir7-2%*خ^3hRUvV$ Lȕt R^Y=*!$ZQ/kpp$&G~!<"+pkbt4D[x'Oo^7"qpxZP={'{y~[َ@_ 5$)I9xd-=~s.moJD UJ`c/A>oQEMU~= +CFPzHctہRH;Fz"6epV bqijIJO=m25GST29=PGϭwege"գ_ss#;\bLާF+ =]d&s{T3Ӗpfq)-R$! k_hf,)CZ(%vт3)cQh-gb! +s@H;6Ԣ]=k@ ߃o<]eH! -rNK E ^kT[##)Pgtj{Ex9I F$0\)Az `=ܟE/ +݋HhhPukQn !o"5q26(l>^ ^ht9w#2,{%ոՠaFf@9J&^/bG^y&iXew=O;XR[?5w\QUGw +QؐnGɈ9CuP)I+1+,,ǐvu\ߠ'#S@9Az_Ҝn$ eKQԫ/Vx +Fj.4Ѯ[V?^QJ.;@;+gTFP< D%9>\Ԉ_JkЮ/P`RbK߱ҜQcH"]^Q qD[;j^ 9*f 5?}~)Ÿm(ܢgntx58ǣu\+8&}3~T~Qj {;n\HSJo%px~23K: Ĩ$s.(CMw<۩](@7+zȇ.z1 H>Ai"#0'{{w\Ȇ8Jy)0bpN1>>Ie̴[I5հ.2!–ɗ _=}^b{pQng&grIoŕ QF;puC1<["|x7Ry6wJ:Uo *DXQ h͐ߛdQ `%kE$4pY[WO@} i 4SY1(A#\Ɣ;bLD ,d|s*S ŧ3?jIvd4tj4XO nڷy [WKC-ھ~7pp(w9UO;>t 5QO{(nXL1X/ _%SVED: ϥ򽘤,zBrZ 4!9ހq@ ŝb +TpS\,9Khn"!*B/Έ)'G,=YC .\Bi(:J){@!˟bd]g=7L9h.ԢYBlPÜXG$hr@8U~AS$N%aRmz2j4T0ۓAfcK +vn^A(8Fh+ٝ`t ~\A9ccˣ7 z@+-{H|/!Cv>bBL b,_ADu8T[R ΓB:H{ED#^T祰- NI8RD;v=r<ҁa9y[GO01}~f7YLj㧨_'ϓbЊmlyc`jwۢՃcêĩ qW,T U`F{Ng цKqO3VGdDa (&Jcԍup3j'zs\5pSI; qӇ"%;Ց}3 +Tio>y)\d(58Jy-ܱ!^.3uqx"($u b'𙳇'U;l;~ȿc!Ss?Uv9=rQ.2SJ@@س}"ƊjRe$j>H1U9MYW +֥3ӕP G-%A̧hjTvUuBN{Q~>gbEN< {w`vd>R`=k;?YPYpH5>Şޠe E --"]I 1LJz +U$1xIbE< +̍HYcNf"G% }uk{b>r2`(qC +K6!ɻذJ] ČBu(oH2@my6z,Tpz!|^ +] +Z7u"$˲>H+АI4H0l,k@ɤf^(m7BIm"׽Z%J?{45M.|{g"Ŏ7cK,ShZBJVnW b33!3afq76FGCsBZk'D!U(+uWѤ*.@Kz JE% 8S@͗TzOw~1sd4o{-H^F]XDxy3{Vf^j&*qmg (!>4ޏxMRBf01O='q\Sgo *8efAaBW[|ڙH[o aL\,HijNgJ|(st*o) b/ =<^Z ;^_R( E))%J࿝HL +l/5&Jrq4Z!0J}rQB*S"`oӰX#jXةs-ې} 9 Հj$v|Q: a#bvN>O"ܞrmʺ %՞|5|%bE附_ʍJ z ⺨2O=`H`R_O;X>ZL(FwI0Lp0/zR90*SR'h/!TĊ2~$4Y*in͗4[=Cv% +:1y/KÙxZ.1PFs+5m32{tP^+I1C㴍M!.ҥSi,3B!BfqܛLױV gaT©d Ӓ $CDv uB0Ԉj7v'+zK?{c/}w$3UݫP *q> H.]e#ٵOz_qvJ\!s Eߙ|tCX'tdyk"ړ`/6O&EEy_h1\, *~E$P b~H7!A[iX<%>w+(>28Ul밁*$FջWi/r`Z/5\zLsy4.Qn}mePeJT=6Jl8|;2a:\PVQy𐆝JkyP0)ϚNBF2ǍD!~ҍP/״C^-=o}I!'"<IZk$wvwM̵$: hyo1i +#Qb q</(<;0b"kY0Zxo9֋ypO 3-PH zah-R*f(g#\,GՐy*ݏ/w&-U@ItD@p]ٽ"0~ jRyZtn蠵9#T4mYjJ_Oz i/ "kӷzШ2vQK ɸ숱|{dڷցt9-| V%6 j%Z]k:S&@,|a؜hHG_7+:ϹL#<g5 U\*>U91cub[,&EIwW 1ܣṛ.}8)]M.wlp %t+,o2:ERae j"8Tخ-%CrR Ы 4M#1D1*~klxޒu0)T#&avE YiV|4<-k}I4Ec2*Xbv:g3€NGyqAPcuNZ!$ENx klvl<9MbhwG +]26˳Yσh tX W$᥋$OZL$9Z \q2~8HJ*} )TP + /Lbl75 pI΁H67 6Ш0ȇ,P.T죛 n@TF˳u +LA)>n`~Uf`=H!EHL'BNڙ|OG +n=NT{C.|%ZzZZC@:͎mA39ܴ³>eW@-nĦc,91}L+ T:je]q6}_$ThoGȼҾ +w{Hr_ ΗtI$Ce W4{@ Ŝ#s1 ĎP"%?,M-$zhD +0XF)(BM`nl޺SDv wYUuaBp8]7SwjG~*>uGm 54l4{op9мj +"t|q` **iؔygL)AvܮHw.?;[6m؋x?|dGV3<ۘTztv聬UIKzc5ΐ^~= + E}O)RQ'V~E oG %w_τxs8`s{S{EE64'w~Tp&SA[<8}J.fhm~#Ɍnl43m*>X\%0~z\GbI  }h؍(*oL^_ +'A8ړzq*6#(vzf@Ï8/Rc|&"rgQᜌŒ;%AbT>k](SS㐤P \dJGAz\%9(w ]=fIW27|3U'Z:umIv6W8~#G' :2_7(}ڞ-ˡoi7yFm+m.GEa~&L3%wh%9l2ݺpT}㦒TfzFE:U{<);uxTюcVkÈWjaZb-oIȷr:lx 6C9sFel'%)ộ)Xb z iwUji֍ZCkY6y}W@7Cق(dT `OCɖ;[A+w6=0dqX$72W"fp#%SsWQ +mA;&Fa^D[&L̊SoO|{vxAHQOYz# +f&Gb3{PY.i}-v! <đ_R*\@hG j|+bqB)th2jBOb= }! u]rKV b'H޻B +(؛q)vMC8(hxxwO6$5m%ϒxޤ܍:5`+CC(_Cƒ +t:7zoɞ9BmPFGn&z)vʼOEoo֠Ϯn(3`4)n>7<92z٨@Д=GȖHuEtBhÅ4;&b8^>  =anpf孌xJ# lZ6cCO ɍG74COT ̵tqK=^mfb Qd28PK<ʓRyksH% -U'5 ExRE"jISBnj33E/'nJ;SLb7Y1,.9Uh_d/aE0nG_*"q((+u?fp)k;{|_rjc2G_~/x| +$S?D4kIv4 ]JՎuU^@9ԟ3:$eAqҁz{ҁ&4GCuH3 ̈v=RL\k9h3IԛfK Vl4(S~H #][e=A:F|'zx1 +dSC9BǒF$"D}qw&D<bxQvó>X# KW=C#Ϋ 9o$,W*+K8T7^LmrqM +`oV iWhh׽_o=9czz!) |Tf;ؤ"}aTE<ɬYjhDAEe7[4 @WH~7φWӜ ƅ~_!3e L~YGd7Fn2_j0mTa(у4INmj.M~4rocϫZ|F +zXyOMf!}uq+ D"ziU}M2Bo8X&_$w1c|~PG\ou;0؃5\ uR!|@ esyytՃ;ܟog"lՓ_*H@zc {b5>ޢdRf쑅R.swHXlP?dSЖivtY+k9=;/qGUmD]Ƹ_Ds>Go7dCqj[Q9Vi kf}0i; e W%d",zxkDCB>G|iCAhu.[w[22{m`MLaGp+^+{҉aRņ׏UN^5v#x> +zzd}4^߂a+S.%c[o56 ߀oh[ 881 {=R'v3~C4>֒srQ7o3na!P&ؤ|_s؊VnGx3unSB|!̎<~(Y7Ղk:u>"@)rXi2CXy:9go$( {_& o蛤"e+fK@aͷ7nD0r:Ïo0XSc 1/9&KrqEtڰ焽ręX߲د_pZCZn{8 d7TBqGPU|Rdzkhzo]! Xn]#XꟁyzViϗ:< WU)BVwqC&ݿ~F)}k &/ +pc"SrݭeލI W@ztБ~`5_`dR(Y\R+<.;1^.ݯվQc@Pjx놉l=I#,Af`xG7L9~EDclr': hl!IɀZ|}i-z0K΂MϘ)WWh{1SΩHgS_ +6&d[0(ST -*c " + +ҴS, 5<}n9Z%vQK^7Bʀj6rr\^d$ (jiK':Dd 9njcnltÎiw#@ +E=79+tKjA{[ u==s&D ܷn[rKW [Ư^ +<. *vB2A,}=CW؍%\38$\z1Vv{ 8jqq|+_SF#td w %1[ {$ +BzaG{!<3(ψ郀-9Av@ =M4*ûbxcP&^a/=n`Sΰ8,Mq/C񾮘8Z^ μH9^pXw@m?x0,5*ҴЪaHdxwk•\G&Cp,iG`' +77{ ed'+ٮLndZ)jRt.Pӡ~9TKU"[Q"[`q> +V{6! Ԙ mʞ{M';H.cN[8CƄڜ_H3&utR( !;1F?i9,'.ii_j5lL=uvڈЭS4@`D1 HʎZ~კaCd)T'8xN{O:S"lfQw@a.QMEbko84p.a$#wB!z^D)LJR&uV% +zGx8?zv16 w?P^YMz̚d`M_eˇہ~(*~2W{Prb K|T<Ñ; ' =z7(:ae,B:aňY4vAuϒPϦj Mip#΁5ոSHֱ{m֜)ݭzʺaubWIn,;*A \c/ #=O +k9n\vT튘 +<7O\[DP?n2/V +bj/vD^@ [BϠcYǽA"CnS,@zjg6JBĜPC$_GnHM5c7w-neCD H!(=TJCb7#Tk9%W +.D7m+2K+ПJW6B2Ef_*rG +ǫ=\قB>SGsX!/B4;="|咨g^==aT# LC{!)F-${c3fE&~jcU(ַcPsZp]Aύ?8nje+J~N[EJ5{$f\vnDf3yWI>0/11w<= c_ ~88N2PKG;ŎJ\J(ǹU(nm:H1KZ?^9ktDԩ"& 6ůs4- ;SR4m<\jw Xjtef%Ԍ4/7 mx o`摕zh#;-%yh=bޫ]vhj 4>{1#E^-HD1u^=g稛R8|=p1r Sv5d5 L°%;CV,Bݿmv`ta$˳0;pcޢq"Gө[BAӔ5B,vuXZ"W&FAEޡݣb2f#tZdbA qX#k@Z+Sr&zzW76wB=ⅭIfu?pH})Z-vt3jt:Ӷ?ק=Xz^+LweK$ bWOT:?]bZkDкn +@?~ tQkTh ;cPc^'MEհ<:^\!aX e +M223XxP6Cվ^,kS/8Ydz@Z0Xhzqu#PxflǞ M2 .Ėq>g4pLT)u2NlLf,vfbӈ((L!tD \ƥ|0VFwo)22GtD Z|Tuz>Q{w';CKX<q-X9\sO=άA4X޹ʢER@7A>|_B:6HKFzGjnj'_Og숿J6aua0n(Br F9/G>4IDkzmfʒ攑RaB4}6P(/vrZIMDfD#_߅'AVmŒ-WG/ւg׾AebIC11OKK0vE՚ #(̟}ߚoB6v=-\#:V4 +C}xTv{^UAXXRd9߭Nd[,ӑ+ԉN:^!X:Ж2i=WL1]L ,A B} Bm 0n%_ALQZaH+];߀&`z&?%xk+w2-bOizz$G\vRhّGl`(?#pxT>tXE^H98YA"]0h(u+"oFM C`ؗH5ȟ؊T--Ю/b~dH'+k3U'bm8?PZqF/ DȗF旄w&%oO57fwumV'N DVKR6}~ F8_DIMӉmOݪD^ CJ KӚJ3z]3U˩d!Z$'l揈#-$~b[f*uT90: +,.-7*@lçf'=y*$:-:ixWsRԁ|eJ^͕ 5k&߬LDxTb t?Mx'CKje +;Xn*3ga+$| 0)EHB ? v7x@kA$j:h(+Hg79;2Vo|mWI.șΥn'SeBQ>)a۷ =PK}טYե8ޠJn?1zk _B&$n9]JNx <V.oŊQjTi h' i dbzT`{ҋo Ė^6kHO +a CLF-"D\3Ȩh~T0]`CDIHWd& K;fr]O*ћ/'Bv#QPΤK!!)^ղc0e"s("cftۇ- ȟISK z8 +Fo6y:OzUH>/AmMV]#'Q~3 'T"@02emRB?ܘ,!rnܱ5ί%|';dp +&,BwZa;R`Ґ_[qn`[ i%ЌEu|KG\*daιhj9̞Ra:=R!86*s}+K_zD9xTh fd֔j<h9eQ$R* (]ʲ¡$9t`IubS 3ƤWGNnהɁ,!L BTrU0oߺdXFaְ ?T9`^ T<2ʷPfP59T[ǹTj'[Η- +zO`v8R8P`cP=KY(E͎E9Ψ9^@^XnfBYOת_l7EhU4x{9Fiw,vD}L r}n[tkn.U+|Oứv:׫Θͦ{H=^0xGlݧR۱z/% {^4G\L)_oKȝ*H / +y 3:Qڂ;{eFjfM{qP:4M^)o*l-66-%X ++)EƐ/ |%BU1Qs"Rzy5):r*,npsb-Ðӓ2_!:u?E7*αJPsF3EToUtpN 亝# Қ:vuhE3 hy'Le$PjܷhD-†I->wU"m+M>}* +NDdVFT՗P"i"#h$C8ӟZ+"`w44!# 4;MDjշo7jqDb!U rTiЏ)\%̨voI,p +mUiD]_Y]8v]VsqX)]]x}eCVyH꩖J1XԂVM,䊛Zh +I#CI6\*?(Eږ5~ZUF6X/pEX-.Wk>VDnzuԆb5e[` `0"I(2ləSיLo9͈9W*ZDT?ЫqycA4 vwnNN94׌iwoa vr>ڽk'Rs%[ AM*U6S(܂nw?J|@h~SS҈՚.paE qV<9UnZC\+&NJGY-fa=WU U_h#$P-[PPYns$,S  ZOReIC%ui,OY+xdkYO󩄗rx y39jfFz~^cH7?FsU?"BNwz/fFjTUux+3u[3J.;5Z@~Dv3(DJC V r WDt\dl |+8_0uȀkJ2}CVDPV!Ta36"LhbB a"Mz`3*-J!=s nѻo 6O.ڧobg`(Ÿ'y仦RZzޜ04t@p{Ѐ8܂( 1h1$/eu y2Z3e?FHd;1>ˎpNjP4ҏV`֛j tE)ҟ$?1 cǎաDnS>*HڄZ׈{H~䦺JӔ,m%D5~kOJ>m]6vxC_ "ΟPpba'5(ē1B)#M5p>9:s#( H7y^H;Lkns]{6sHw+A^rL.erH}g; ]+%L]i|ay)4|6j}2wJf*a<Ɣ[i#bA @]Pa#"boCʌ_bP JW=x*<a5ͅQOq'Z_ _@|Sg.uUEY%\.wtSd͎z~i:@zaX:lI37@QaN5Y}#{=)BDWS!jF"ϩJD'$KU fg +l8 +4&ْF\ {u/ Ѵ1Ǿ9tW3zrɟHⶲ>{0X:^CE[mS!ITT\!M#V j)c/%] myA=M] m3itU0naaJg/eLxǭm!VEKl+UQ9Oq`G$$0@;~%?(-qL lD9~qΤDe2`mZFc[QT#Z#I>r<}]*hʴvs` D{uM.i\Mht;rs(a8RySڧ5שVTqP|\MB8Bh5@U>d M>#Wp~pOFLR n;eq*hbM]P8V||'2/c +/nCRE@ Ö](A?̌bp 5<ָ_Q'z~ }H9Hm@2=;MpT=~yY6W}S}qZpn,w9 +ӛk_M-lȒXnBww5]nV#חFYHxt +LX +:O}lv:+4_+g +Qrn[>T9leps_P>ˮ{, *&A| OJ.ӋJz}[l"$ N}^Y)y1)yFK{lܔ }-|֣QV/(-eqT NE\%;w +Ði0ZGܧ^9>bsC4-yz26Ρz}hd`>kW$fq[gqSbds$C C y&Ы*fjzV-3Ľ Cp ?JU߿0GzjT{njaI3m *@뒑|JMB̀iaq8LQz@)OtUl&,wFUVHdPC`L!BUEQ#˔B rc 3.e|~+ȈqR]pGĒ!Zc]jiՀn.J~Nn.g#ˬz(!!ն'4C҆oz>+ +G( +>{zacS2d! G鏁}bZG{Twǖ([z bg+ :{0 .`3h ?0i@全@ ? 3B $gϔ|5Ze2D U`ard2:dk7Fx:XgGڟ#G8L:pe>0t=^ԍ)jmR=>(*McĦٺIXD'zk9)/h +4jE=0WZJC5tYZgu?v,`+!;[}{յ7*oЎ""O<Rk+<*ҟ Y ¨Fd +ql7̬D( "I}| u(9Cz9 ;Fl2tܨlzP~i^$)կSmo\kpG=!e)3\^9JeSPo +IH~" +?@HC{mG$|1Ӓ_f v.*.rYP*A3W35zB.,,o"eͰ[<=, ":}naYG#Wqn[`МxwB,RUэ(W[TW0ep\IugF 4v'IY?(/m~ WK?tX+ȯ!vQIz%CRͬ$5pwLp,1\'^qN ejW z(SG\g𳮤y11W)l}kSBtQ6g#8biZ|( ЋxMOZb:FzG89 7DX_,_`$F47gVsE@Lm>M--ЮDS=Tx**B^r™C7[a_K}9*D'=j&bqf^5pe_E +ҡX@45^'FR;lW +`{t?X+#ړ +(-N!RgWp> +f_p +Ԙ>Ju(ʤG̯Z6*)h*Ɣ:E:D}EwYmQl%'8=ꂙƁ( fgF-e)i(n:O^2 |%6]>ݙ)F#j+jB_ +}ШbJهerOP]4:qn"̩o&_1EZC)B=p۝;@M>q_鮗 B˥f]b'~|7~V.|ϻ Z'DDlڅ1Fzޅan?9Nɢ |HBD3>~ ؋S:ߏcjbB}|f2p/0~qUN#Xrs$KfPrأPqƵ}7ƹܞG 2Dr!qi0eW/leG&2Z:7܍Armt̫72Vθ?ƻXMK i*ǷZEh[YiE e~0i 7/# ׫05$""_+x,}r~%o8KN}-w}l]̱s|Hk"twEcE ՚Bņ>X~*?aV62#?JEӡTrGx Լ޶M[411\LIg|; JGԠ8P4¡xz}hA<0wBhꜛiS;g{En?@a'u&8={]A_$tҧf\|c_Ywҩ@#'T(D 8TA +ӪFhΘ-Ze`Ԯ&Ԏ)RL )/h+ۡʵcPn fB/4ki8CM㸃s`۷;PK0m &.)79hԡA ,d#&7@xyo\A.o'55:`I&*{-펏1<~}$8{NuM)?D|'ӡ\P̬q%Y[j l + +SGnqOTHx 6,4= +endstream endobj 104 0 obj <>stream +(}#7k99֩kmUBLn5ݼ>0`,* 6rF,6v{׍#gANh7#l 씪< a{aFBX&le:f%C{CD]D-0VfVd9mTrme & .83H2y ]ⵆ13FqFPޅܮu7^fx}Ȕ1 +h3@79R>|~c7K"E't`rlcJTQ^{ЛF"7yt9FR/<.@τP5ځX,Ӵ{;{;ψcؾ)8Q$)hb*ܣN©P~A y5>PIh*0cRm. Ji8UPPZ8,дط|}5@GL=`U7E!4=b3)ZZ4vWnO,mW3}*_=@ÁP[קW,/T Dڄ@{s;`Yt6#Th`u?CƫA ?p0N\s @.ʦ.bjxdDJRXߑwŏ08*"JMR倎-p{ߕzUT:'lÏ@46v"uzxE~ LiQEջuɲY.mLR  +GO1?~ m?4tSnu -ڙ sFoN@j+ +hk{٨,S[ + c[krl#(yG'@pR/W."Fw92#I{KTAj!JhC. -<3?8$e>G?ʭ`2Ь22Y MyHVLX)V>#&$FŃGJE4%Q*6/e??IrW[؇"9CZ8wj }|-!x8kC1l +"^8 ̦3e sW-|'tN:%6B giYK%(km*=c+Kpir"WIss >Z'ákvSͤmpF,V`V$H5g/v& Qg^@xF5qm&3b[a*s DY8S隵Y|8%1f87k*Ԋ=nCk\|MhdGt6Q9Y.裎~u-LW Z D,TlpD_{(v`~:~QqޛRᶰ?b+o}f&w6)gp/#^A谊Q{ DІH/fwqClj%jCDCz_ul7QU:}'P0*o?ۿ~w׿x???O?Ov>ρ?O_u!=O_D8)F d퐱z2&\@My"LTAu7_%BM2*-bO(& SM-`~3:jaPsؔc'et޶cRum!@6#@4q}er>3 + fʥ}d =`hCP@#p%BXBl2l'*Bv-3DOJ_6pF{ dT@=*(v)U=tEKfwԚfz(=ANwEU#& t@QlF ȼՔ4 檶8u\R͓k!؟dtۘLr)C왰'̍&*-ɻzW@M2 cO',ʳ8W<]COP>ܗmT]2YMz( "hU#'/ @!^UO1x"-N 䐲AӗG=' [bi>ngi<'3DV!z0k舉M.7bmr&i0u8Νtd݉TZ-,=`r\d%5-i3@ DH%) F"%3 *3GImhIv +)!?$>\4g|B3œp|} p9-qva* Z,{3e1GBp~+%z~0B(ߏ0lrX*q o"+$iV#zT(F,cjZ.;*FwqC]o:lD̍KQx'P ^Mʣ_9\L +!̙N{snތUhA1@Эrņަ>+Tr$~URS"lP L6GkH*QB^|~Ŵe\|zAy>tId6\ʓRghOer +bI?ξR-|> .tJiiSwxyx)4qI~?}κPxak߹%idi-+{VGWYjH83kvYYk/׃35FR 8T52yS袢9}b.AC},ڬ _KxՀUpSVDuRޞ\aT><0u$A b5bax"Ak`VtgK c{y⌜WYwo܊8x?`=S8׉hr_vjURȴFӴlk hChxBuO$kf~*w~㮠SȳFŋ1;[ WwTA>?Dzo-ZRk: vp|w:LUP t-eL#ŒvY=ydʞY酐&  + ߹igk0a~GW*R=qT'i@w+y77&ahC|k0ofvGm%GjD3 }FJ:uKy5֚i?8RCn! 2!#ŵJTn(\ [) ]􎶸~]hn&Qlxu|i(s)L޲OUm؅M1-3i?Xn.eD(sCJ)~dbk<Jt:zW9`6fICiDĮ.rv-hyb|窖ֳY2e~#yU@8bvL `Eg6ҞսLMknr:n.<.sH4AwkEwӝ *1:*zm,s@}[2l3y. +۷=ULVgzsRm%d5XLJIOHc}՗slXxg.^LucbS{㸱Lܩi4 H3G.agL*|(sĄ`YF Y&3W;>b:ZP1,΁~}-S}g%bE~1 g>5ՙ!@lFVA3NA1O&愾dt?czZ?DۮHZ3|L0\&Ҍ)q}FDKyL܋]Wf#WW?8k;ЀP²Z 1L=\Á湭qBZ)&%`π`]SyZ˟M+ɐW0,i`<} +06kZV&܍c#Ϭ/;rv0D@ؙ#ND#X}?F?{i0y"mIH?s&Fq!70n+ꗨEu ݤ]KwjyZ=2#Nd$rV5v-fq)# +!Vvޭ+4T-ιXg<OIφ0](3ϨB$$/LëߺpH9̨i'3.ii83@,$Kgkc>?Բ$Sj ]Vu<v$ -/6pR#\񩶒~zsCI3$ qʘ*џ%j=0ru˭AܶȟfAo~HD_:b-^>-"s!*^L{$mɍKxX-gzZ{cVK^zHDFQ"ta#9W=:\JERa0S=!Sk7ph.)kj|2AԳ߮h6TR|Ւ``qN|gNFG(E +R[h48R[,Nx!YuaZPL,ml NMiYb%^ICjS: @돈+` ;   PfD`8p$ +#<3NDRf՜`߭v{;k:MQYw@Ȉ[Q.`pNH ǩ3w\qFOD54' 4a$15=SR6zS*;뚘^-L1,IeWzmJ31qLHaڂ)M3G;>31:'3r@+Yƅe1kEdqѨaXCP{h5} {m4S=_{nG@{;qnvٗ7_pzhQ[J +mKρLd=S<@>CMaSV0ܩkϟk݄qa3mhhqZU:.ڑ7o/TYL-+kp?]3`=I vpEDftC{M >WB'ƃ!.gex +O gp<9 i>_9E4 EE׉ :DSQL֜R+^z=bT'?l@sH]W3 nďLQ>"|z|,/e3xs_!5;\,3/pI]xk1nKeU0bX/7l..OcUaS +m+ ?&Sa+mn`E;a tSx)ca6 d0, UDIDyuFh +[KUw/r3fPknr}{ =⼢Wug_牸\!; F²PatMv:2FX2uv4@~WX+=NaXg+htSC;ʦc[y3u% +߯bCgUNH,(? %bCa 8X cOE +ABgSI0vn{]bmla(η $fKG"%b@aLfL7e 8`E(,{GNeAw_20?Şm13ŬB,- s ?nnJN!.NȮZ҂ t#ia7QP}[xI(ōsC7.1:}E\{Y܄&=b3[JG@#$kn}an4O#N +}ނO/ ~sS+n)C"ʹNRgHUiffU,缝 3cEn+3:7Qiq3X؋}h͍J}Eq^t\űjq?&}3w`0`@ բҶ@c +5*P< = %]zDNTkTg׉~ YT/re!EO/ 7#? r~Y۷thC,.Eً{ge͌ɵoǟ^OyfL,[𕡸W_h3IbBri 8:M^wAɾsH)n.C=m)?6GFDh?\neR$YЖ 1e\:t0 :h'uاpJ:;Ocs}]oQHk(Y_7CqXǭ4HR*QmX-[15s,0}$' beTJYy?D|QLK OtXxl)u(T8'b[ay`\70U"_i( +~%sT +ψ= i CwA9:AY\vQÌ$+գ:cx3]s S9J_݊u;h@HKU`(ZOqYکR +(9qc61"?2 Dv>14-a@F uׄUn8 +FG4OYlD}MV0=fsLcbbYE,Z͗o<}0 +j"<4%½s+5:0%e4.-h:ݢeb+Gm$`ugSA +#?Q!F΢Sl$3oSTDěKg6K&dgwXcPs`*փAMCuBCC|vԸ6d8 F]o 1T4:fAՈ:31BҏP3՜~.Cۧ+(k! +=WkSgв@>n-//q0:xE9׿];Wx~pZ4Z,'^*gCJ[pFLoݬPC+ɝu}C9՛d &Cۉr.`*2Ȼ85IJ2>0x_B]^s +-- Nm= _sUS/U;m&@kMa; +*ZunC1-n}ho҆iĮrh}:C^E鑟 ӷR"e D+/ +et +ZX]qMcF] EP0؊;|r+]Fԅs1u +*fשnS%NYibTmMO9ZTY',: ^8R%f`Y=MИ~daq|H)Arա98c}9X L &8Ӵ=B{$SR`OkzuY}Pi.k6΄[rp0/yYXS[@j~ ܜj`6JSh歕s6]?"1AHVPZrĤu3ȷ]/x\@.+!db,Z#l +Nz&D0*$!`$,v없$oۨ>s2=/aqe[O-#Z i EjUePU E7Y1wcGD} 4'ƴ;r4as$bfe^^ZV'_+u<7ȏI GTInefņNc (d8ͭfS2F,k|Wo()R3%J!1/H+")AoqigR}Jº6nݚX^PaHSh: `E)'(t'̟OΠƖ$POw[ @. =GoUInonX*<ϭe r1z|+ 4s%{kk@:\L8̌ +LJ+1>5@//]pWVr-*ZiQ=y[GXI(1j-m L~0Q\fWtjN'lE%BV~աj)s (]ߴPQ]p|A+ ȗ0̩g2BkE*4pe2PdULUtr +P +F:Zs2'0'6HLtp'Vօ ҝ/zY,5](uy$6 _=["Fv"ֲBPW䮿.. Sm*R~uuՒ/ +\B4s7\~a}c(}`qἠoYK1tf:mC +_I ]ὥPA սU@ZL]ND~5H'==;F<*hHlY2QXk?ԡy"5(뤯1s_@Lti5Y&zH409]P5V7IT蠕@mx_;.rKMڷWG? Ƥ0&ȁEnQIg!-}KK`*xѿti4J5TS<%>uKm"_\Ay蜶w9[n +b-qp/< ˖d&2't#?M/gC=o 5iw$AؘۮI8}BM9pyGC6ZsG\oDiF Q?d{ 'v1e[ݳ=l'4"B\;-%A2l!o#ޟg8/og6[vKi)`-{^/0[~[sm\LI@M*JKPA["SՎ*xX.,wѹ:^񀁣"OU6|E)D0.zC\E]S= z1&qЊ~fI-Uu$k׭`pkt*Z rH@ܘUzfNi`-u+rXύP1 H(1+cK1Z壤D 6B#]y!to%+a f +ɾV#1JDL1@#F d:0ʘ\z-w +ؾ! ,Qq>Ze7Gk +Ƈʦ%K^a _0s1JJym#-|!SY\JSAu$Y<8DڅS*vF\# +؅?8w n1HJ_- 5 +MUbpA|ͥ#KI:#]F#OGD EV"PE/ ' +om+yq㬴v:6+-3ˣ3bK cu&txM >$eMaPzhlD~A)$1Q뤋4]gOSZEЭ%߇NBkU(X Z +~B0^Q>:}`)lW +r®2zʊ]JJĊnVNZ.5xHRY2[`|4,FX~G/\XDpEXb<hݛ GGn4nX̄;{E)ѽEpYIEж}VCh*vDc{ +(2th`@6dىa11hjN5f|Dq67-CЏG0>tgbNיAL BYSR:]iqBDյե6_@ c:>%|q_l;'aPyr0:#7גѥ;Uc܅_)KI6R2iwaV75zWZg$х4)?TS$< +:wʼnf=y!޷,4^pFH #`&2an~w(>5Ran*k?3P/|Q +et'8=:NmعuI:A6UU!e#rg$-ttxK^`+M]!uw.< X!Gdh@Vhzh\4!5_h{h¦VET$t3kSMTk)w"t: cw3X"L_gz#2|Sk~WP|G$wi}r\U/۱ܩ|8,x*eJ/ΈQ^,J ^~V8ɓ#-nWJR[0p\T3=bamM+#ԅ ,DD_tXs|+4KKmKZޛQ'^H[&U%UC{B_k[C5l熥nXi7%dD)vuZ|(CUC|͡.rK)١V>@=*]5$?/LJ^4:J}2qUf( ߑF=~GT⩚ m"0 !xE'gvyP# ۺ[]}p8 Ä ^L' p-HCb;-U#nBp!٘K1Y6Mo>}=2)V"hqܿ Pa2 *DY 69f[NuJS&]ۻ0.18l:\G؋dp}8}*j s]Tl3ܔZ۸ZH O.U DL[&Vߴ0 +vSM{ P&?䇤xơs HL 8# +jbQN{y؛gg;OM-嫲n4Fb:,ع tdLt,{G~ vcȰ~6?`,Hܕ] |Hk=nKsMHM +$wa'o}!۷²"IGppڦOa89_~(1֝ed2l3"<Žț2?^/<tE2߼Z]gXWv{?go/TkL1#k = i##zz%U/5 Dϧ3JF 8C-L7 W1pX!.Eh눊V{XQ䡱w*C ) +.wJYVRPW>GT}Ciۊ8P6-">û};Tsm蒩vP beݧ!A;-dR3YQݧXK0䮙c N !I\f/b'Q!0MtTaHZQ^0>UjtNļmt(V r-6z[9.?ii{֧e.7ԀE#R.8~>D:|vksMW͂ sX)MhOJi"DMrS[Ks%J#k3)'pp+laI$Z5!EU Q5JnFduu{<)i<w92,zeπ#q_j%ן@j{(Mx0b!+Q܌I]ꐟsbPUEϡ]hu) 3 &ӲODȯD%4OU#3B g^l8y7{U"A :̙'vc`)3s~Y&X @u$ >.PR8\p[&٣7YMhPz0RK :J\cw򮍭Axɛ+WK#8ߙISrz:>#ryEQeY#4T񟽄꿼4Ěz<e}T5R?ż&W3qƦ4kG,80^A͡(ܻ_s/Ӭ:SZ RysCl RBXoHy)ȑH4S)P&(K@ +M{ 0OVxurSl#2`Bf3ԗ \ɁwS#1G[ +pe6^ScM5̏gA3Sš 0Nw ,h}serbІo!-mcE +a\.C({Ճo"q.)tyM +77% Gu-BKv7;ˈ}eѵL""MN r dC 3.W {"|Ni25W#V 7 p mTρߝs!M;Gyg\IP-o!NQcj3.4Nu`3TSZC8- %,+B5.6簜,^rp%!&FtY}D15FK9f8}3j9;,*Sc밂zz.rtoOdvLz1 )KRܾ4U30T" +:z8hΨ_dT[FAE~⎤n`W} LTsW8I}nJf#̞R:)7BG>=DinL Y4ۨcac *zn.%aDZג 'ncDEd2ain =cC#<SE lh7ob3tivamx~i<5FW;GF 9.6P 7ts-I+1׆_1&իWw@reZ~43Vbם  yP4z= C+wI ~ ܿ % :ۣ1_ǟ[l[S T#j& [I[z$R- ŵ{EX boq͝.-i|F7 !6ZTQsKsn 4ll7_nFGa[Y{ɀRmfy:bkLRИߨ/*dl9h,N,hm8KH>_;Q&EdoyW[+5#~C;CYJN7 s9~}P #xrĩ|)3SfuM cl\")M2ΎWW'-ƕ0i:mA)콵$5a_W@pK1wYޜln)58Ϡ2Qs3Y׷ߋh~kڍ;йIW/lpZ gT=;J~mWXn׷cO0 +" hu<H6PZ<"z1xo %*9ρW{`0W}qŕƺYC[?%+>xǙuZ?mVI:F3n} cB,#)UN7_[}#8om#|"N[s߃|+CK.Kse8SZ>Gع5+.'ۋP*Oĵ#6O=cE*44M4Ǖk}FtN9Pnn!wA~$ͧyE0>#v/XYD*-) WM~Үj5 j7Z$5KC%R= +G"$VO$`E\us%#_}wGRk,ؕsg1<[j>J ]E#B4Rl/S =S8hsluy֫9cK=rHη5)JD*'i27܃'K>uk*B|nSˆ +;z1Lr&kڽrZ֙ߥoPڊ`?yIE)]WH!}IK,:FQ.*_mw)QNaԓFJW.2t"ӫ=SԞ,7G?FToYGyS̰QVwRo{n³U\XtiS_jˀ?AìMr=C4|ϒ!EEuǚa_3T9Dm/X a* A&q_[=\|#-F@SL_Z˄i{fKmHOɬ]((8?;ZX&klE4;i%:=1{z H}%Z՜"cCi8Eƥ8) +<"ca<Პ/Ը(АctBMbcTCs[p +F8d?H% ~(op*>kE@(0Q"ŤobLR)#-+h=5=& |MCVYGup4TGN$ĈQ  U̎/>NٮRb7_ʚ&L=?)2P,-z2Xk;ɈsG+9UpGH^!rj$SD 4/aʳU`8wYYEdKRб2b԰Kۓ!]<i?3 /2Z&RaE,W7Kr_WTaI`W|^RRԵ?ڲʩܠ)SLbXmXAڎ5^Ո=@ sw7jj){զ-Y\3֟BЫËřEU&xn sR#Ljx숿L7_Yقp-^ +{9J)2 2*ЧĮ3lVhnn:8ɪE͈_.N%>؉ ۆHKpԁa I7SN%jw\vL7r[xRSJ]CL?|RI1CRVlPjz|]cE1uZxjs;5 "AwaH2j1}-Kf.ٸWJ]ԕAaRZ-q-f' RrhDwbT$9O8?f6X]-_Թҽ"X:_6K2^4pZaM#W趸Cc(wD4 w_p?\k҄Z O[tN=R=\AcaYq?czSI-_"zP-8_I!{cM>g*,'$+v4 +#Ҽ%u _}#Vѩlލ mľ(_Ô- r JiDיfԭQbiҵ(L*̹v_mDU1R*`'{╚`ukr#WoM~Xm<wI Sx˚OA5ކAIJ Ցb91'8C8ǫW5 8Ť{渟hǁ`lMEa=r,_<L,&KD*h A6CO&T:I޿] KqP,ɭWuL=XZgߣ(`^O$g=ޮ^;Ssޚm5,~[rZ$Q G1'}+]plj ZU:c20]#*2Vt<u! SMP$[A"÷r0o2;2ެ?5=5# <7ؿ8\gP3"ٮjx-ѯ~^ϥ1FX7tNjQckk_WSv0}S%ϜHl%.F1T"(J:(vKi|LeC}E,?9#_e{EKR?\6GǗ>0X]=FΫtCk\~|K[GC>'W!M`8CyH y 6kU!^4}{QZ6OiQXs"%qzam?QmwHBJ\iʠR9##*>y=O@B_oam3֧~`'V>*ZKj6-JWZdŒKdv`o 1)|S(F%z3܊hL 1אMeHѿ#^\DCO޾z<>p2 {. 979sӨ|6w"t{ؚt(iYbzxj;C\(g{zZ5NZT~-Pݚ_{oJ {[6HP +cՉ@U`I_P2kx}+3@W:t_vvT橿б5۝ϞL?^JJ'֕gcċJ%uao\} 5gĪЏ밄 +. EPaɵ RHJb->\ ;f#L:BY6QVUཿ=`0A _~?a׿E˯~_O?_:Pqi::d 됟AJy JUJCdzB?9}nRTDXI]G;c&  +9Ў'dׂه(RaM ͍*W|Oѣ>("@鑔a/-?q\׭R.;ߛ设Uxf =PP5Q`O`_'%\a5F3ƣn+:cC;[٨ :ϥT|lv~~#:Dϼ|J+ +- kH^.Ld/?lV>K%wW_?SjY;Z?lѺ/BM!`"AGkl**ŋ sE;Ǐo>bH"Qww%^l6vbߎt?uըsu@F)Z 䅒(Ȯ6T[TwIP;;HnN@c_AeTw8J@uʽ(͞fOǣ[bLSU jQ]rkCشmHfh7xG_4.T0/ں[&Bk?0Pe;Ȓ(>\dԷl+Ŀ;;h2>@ +F٩hҨ^ L5۵메5wDwͤU~"jWѮQ׼Ro.N +<)TWzM+GEY*n* +gϯis\_K@ "m,bOQwRkєuZ=:ؤ[VAM7S&St2TAӭf-U[%u?7u:ґ u. +wo G)mð&}W",tW(S2ˈH*Xf XRb+tߍSg3/I/l7Ohz[ ']gdv!luZ0tjjobz[ςƪZelޮ2jbq=+GuT7^cѱQP0!ҭCA]QW~,Dle/DouV6ܹy.k8NDa,HG=(҆D7lOmPޕ?|]Vk_"r{4]! +2"{eh +7<~Oc[c2WAOa}.0Uy\zgpǣۢrǂp~ޫ|PJP!2؉~FdZюu3(8Y#DkXjẳS5]x;X8:`]0\*L?b'EzTzBu+˽xj*#߈rJR}MEHe4k"pkQN>I1%U](P";X}1˼ , ^&nXvH>y~?}Z/4p`C=@}H:w<;*P +Sv5f̚xZLԶ?Szv[jq l:*SkDc;N+JyE7>wȀdSn[?WFz:H:/Rjex$6:[/{@/_O&ulMǔۘ@̠݃ApH-oVv8Q6hQTּfb'3<z: +B aR3׭.= +vq8WE3kkL⬟?83ƇyzxK\i %_ +륦= (A#Wsp+oO\ +@c;㬂+2D|n%a%kƕ*ŢΎow] NUn६qEPM391Q๕*D#<<š$>' +lO.#p^I Nb7}% r0%zPP80IrbO'WY:Aۇ+OZ&$cDO uy<5h:e5h\TZj ʣ%\ +^Nw-o1 Jh)!@{s  vh"@Xam2p\D֏ vEC4/g7"l!EӜ \C DY\#ev.*IG4?Ս=E7ujסxaB^7tY7/10#@nG*7~?=j ƕqu(σƆ;^8p%xքψL>utQ9MTE wݼ +:Y1QZ2ܱ5kDzb|ø~5;Vn3dL}ݽ6@!;bЌe')Oa*1*ȞN- ɤ4+?mi9{ WJG~y qm yBڀPCeN4UwUC{ݰH#iN|+A \8UO"62Ls4@-UVr֫rBtyޑ؊r+o8s)S}K%q"\/Ucޮ)2 as>/[ZXV9ye'| K 3m=p<ͩb{`n?E11#|`inlEC*،y~?VLo'r+[Y[ꂱF<;"F*J|!*hk%wZA`+ koӻ{&J5?|mľ}Wg=LLZcҠ\,0=D$( a?gTPscdPtθθQn0!K^co氭%Ƌ=6m +6"VYdHӖ};=5޿rTe&27A<֩*ZG%3]s4}IZ +o=8aӺHG&LgFFl|#8,/^bv"' oz-F"aNܓQ(sotQs5,p 0_Hh~I=;lWUQc.+|!гFpG*H+U¸LHew ~pK],Z/d  e;#\EE&+1k]sbb_Tew fz| Z/QxԌL5 SDmΙN`aeA"+*&є +UoR>#J7R.,SyGy +W(o ZW F^ C jᡭI҆W_=v-Eir؟W6ZiXnᄃ=8F-b sd^ $Pz˩QؚN+hA3nSCylx€'6dρ9@0:q{n'[?\řVx9_% +s^_BrH9C_+MO{wdiei=&k4qr|SefA^u -m3uD&"<לcw~yFŰ_ȟ#~w=[6PwtSrc)ilDCpVm~ZW캲*5BrCW|KNnZ*l1g}:0O-|?@;3VұR(qp~"~˧TpN wjk =J5'uLଏ3MYI1ƿlFlzOPy1?DoI+hQ7{HM`#4l[χJrPvANG)cD(OR#DX'e^q\O+Ϝ!"[ÃB߸zldla-fY-Y+6i(HcV(COH3*@i\.M/1nVd+ATMrJ+][rFBŦ]߇o5FPuvRhC'*$-[m)k[a%?SkGpX[y 7vJǰR?O{o:5<[".ֲ|m Qͳ)?fkp1kp:~ +|e~P}Xw|&U&~GOmϕBMCt.,Ԟo"CF~bWODs#ˉTtɱ8T +a݄Qx3Di7㊲Q#DL>*3WEA Vx8VYRbjN}gK +#F0y&b +'yylj 6ㅰL Ea̿^aNhW-f!%bn& d-~8 /`T' +~.ܲ)DIs.] +Me*+G#CV|K>hO?9$a 4@c ׈ kq{|nmmHlвJT m@=-T9;#xi5u,+>2)O$mlX"(JvERl5W$DL5h*Kµa#V٩A`DX,2=y8g(NwtҽLF%ĄIҙP/&j)FuinoK=*2 +;D_aC Gׄ #h'|; j mKS(*>Jl kk$LFD:] +GTl';x.qx >wUA$ )}&)J9x"(w"`g*sВE=C=1sG#)*lIM^) Q쓡Y{h=(Α ߩ;to9tTeE}}t~"9ܔILq'%gKcco]yg0T )_ ǍuXͱ6"ef;c gw;`|d-G/Q8{ϐ<,s|<7x7kf|,kh5ߺ ̋RBJ`yӯ2Gyy2{S$֦\ =f{u`NKWAQ7Z{>u@ٔRG Zq,E>Cb?s [m$GqR5=fJtxW"I')ëqU7uOWNZ猆-_qwOmGԿ NCFќQ LJ ?OTiz_KdqRf&p?"/1= gғel\-։Ty$'i(ߏ^tǞavf]3 +"&P!9'LF,)1RkNؗ3 +"-a^ L +5bxk/G6_puP!O_3Sc+3 +Wޑ#&eͰD籵A#Mګך -q&FtK$!;~E-꟰0*r"q e9<C]C@0++ 5 oץSiv58i +H"H{f}}lCһºNP%2X ۰1+֧bf) V-3*d8d>[ffuY>m2}j5Da슒% F0C</g8\>!;;qGۈz)fV +/"#)πd;"vbMiWX`CnPCϺxAozjfL%HVC 8{,pHIE| ͿÝJf*McuV.l ,eShcWGz(r+м hc ҴGy=tyV֬KjnUD#6h$chns/~32"x!YyQS@bڡץ,R2i|p[v橕mϥ@ .;<4aԝ'38 +Z߰(b-Q7B冝D;71 3n vTL!ȡ1Roz<(.GsWq M@ng2TWjߗu)f_r|lp)b ?_kЪ;֧L2BuZzI~D^5IjxwMk*0_U^ާ +.c* `ÚҦ eO)azѭ0쁀၎g@"~#A+a:bቬxC8EV<퓾Eۺ526?*i(y]UC4+@Q2A Yᖧb[s_{_΢٨`1DeN#6F8"c4}%K)\*'qo|w_>4zk-wrjtIqfIq]Mߗ_RHun&M1#> +L ߕ|uuf埣St8FX +ts:wPwE[1쁒)TؗNT$UoTdS &=:Z&I~t#?d9xrG2EBk =̣KA{܏-ZE3Hp tͤe[8tM bdw8|ɌQ?4;=C@H4LRtUc4P?îq['c v Suۅ݀=nnK(ӲbS -G;%o_hsu8s{:^8XB֑Hb]LP7<iԨׯoZDJq?}ؠ*A +KQ :"=/G%*T XMWq#"zi|FK@xk?v:m!`eN3v+E]ps)q=vSOc)5x0z>-tp,Α6Jx)~W2HJ@R.&SԹ<4Yo kNk_L c7v3L9dV'S+*\Dihs:[=i|D<~iÚ4/OdOSsone)y|zm]N/ vCyC5x oBR9uCV؂uC}/pLTHυDW#BND9Uu6#BԷr5_FLn3*b.T +tq}W6mRz=GZ|ZH 6'Ŀ +Le5n9wNde}]oP#l_>1Ǔw9P}dr_8 +z /mZ gk|>ԦnYY1\WսXhE73C_LE~禤**jhiA:+{_B~hg Vu-kvcz="c;v}`/5#h>5:6@(Kvx@X{:8[%%̡⯇2hB7oFb`(W\AbSD<`M(:bܥog邺p;\ H_.#&P" +&0w'$g + Y{F +C+a/L)%a) >k9+ ++=$D(RaoPRZYS J#8Y`F*qEfM} ggzAn*TS;l6U7 8ƾvsה!A1ERxȮݴ)VߴQX~ĩt&P%եzzuHOE`|NEGr";Af[KM XsS,m|ĻS^BYtg>{X~>1wLo1n@%r4LyǛM0ޜԯ2%< )3 <˜Q+;AMD׌8&#[_!(> %Gv-Ly3Ű|إ^טMQ9_~*(LXG PX s98Mo09;m>i/#^asav3W*k캄cxp .y+GzewB0^XrM-KdfٻM714HXh5}Ӝ[C=.B:i\[2lm[ {4*Q}`浠pCM{en`L!y)C71 +_tRi u 'YӅ@S)lu~]Iyfbek +c7۶GsA'ۖ5\`tU-j|h\FU |?Au$8%Ab]3`sa6*|}߁q |!y ȡY6(k,(^CblAF}uzWk=-bOivD?k9AUli?"cƙpL[Z=Ukh$$K$_7F-Dz0X{BŤFZl{>$0C,l2ac;+~dz/wizwB63tF.y=o`MsVḃP&r)SB&l@^tTI1](A?0DP$ZAFX.$7 R |f$P,%rG1zi.JCOZ0(ۦChlD@(EQDfq9T+c-CCa !4{eHG܃ ^&=z2z.Bmߒ0C%t&] OߵKL%k P2B)'BQ {3hXPIΆ3.&Vm+R12 |]bO=1"IJK2ي渧t,lfh]pՇxs~-kH}6%4Lkj߱15JUU_(lQg-{GqH? V +J?m*u|PZG% 6 Yw@|W"s|)EÆ*8PPMXu/ +1il +"F{ k2B1֟{7&cA&ƵLfJrkŅuIAG`!gV_Qvb&`@{].$R، bЉPfwbLy3xzzX2[i-/%tBZ[e0"< \ߩ4SDezĬ_ +n{h wR%;w{b2%=TЂsQyXL[NhO R /C CoEVqĦ)Aw޸}ZV)$s0|VR<)v#5)뺲ZuTے3bBy/|0mGFˢr:GjtU+qϖL;7{ .ږARC6ƎuTCn|_KênG<}/yQv(roWg bt~95=a#f&M$]%fj\+4vJKyr#yzdN. ϷoBɦlNͧL`Txl}mµґM'_g> }bnN%뼗xo-xTf5Uv#zf{|6A߬Da +Kk.SF~[ө mkJ8G!3YU) . TwZ(<'adAi',[ШBx }_ #.g-ie+'jUpF͎T/6XzkΒ!f +rԼ"sGDQItTX{[񬶝|U?[ITG/2D6ma7p-Vb zDb:%3fMf +]>xj* ޲זbH\TT[Ft`+m#sCR, zN䦒~]e ݪÊHg8V̐t+<A DY~@V8u Ӯ%iDKӱVJ5Ue~p(ѫM{YZ\VZfl\qhqu DKDK A\aq[՚ǯk{p%6#Z+xYE:C&6PCUxx/G+NFί M83hsěJ'{ +kᘒ:t,A7|:aVJo/).̿,GgD0y1FѿvlqܾV z=!p^r&LwGyQS@N@ri"AzZ(:n`C/KJd./e/44xۼyɖr].kHS2't˷^`p}N뎏;-KrHmng +.P#d5$ʥehk ,Y֪8u֮>Wu9le׳D,XoS (i{@r;B†ٜ_nFOK wRI +*5RP))&‡" x,V9s^ۆlǕnvp!"6Ab>}* yt$J,-$fG4_~wm:ūjsȹ1:kF0tJ)PzxxE1AyU =g`Wgo%$>#r)@7#aUѮ0eˈj5ψ9vcϥ>cY kttI#Fe@dPY^Sc%"~g[-έ;utmi!Hh3`Hpe|q,JC!%[s|FcrA5_[}ƴ3҅72˫n%q^@݃77Q<9Ki|V +v\EPp8$,ZZ3ANJwܩóE_ݝxN|);R21Iziq1L\[iE3"1_{rMwb!wFZ8C<v.Q&ywψ]/ + Y լy+ɑk`%aD.s5)adN +vD:E?g|_KKv񕽲;SJhk +w&k@ }`Ie!45딻|UEzf)`)v$"Y `T]wfƴ ޻,[{ʖ_?.T!!p7|ۯe$^WJ[q; h[zp-TϨ'K1frgaRVd3*3JV 3abKA>a"tʉڕm,3|0B8슨WOy$<} +;&Lvq?f"67Vy`ܿR)"lZ"] L@ADm׳[=l ;4Rt  +}]Jg3dSTL$B=_SGpG:!>PC9ᯰ5H !Qo[(89y'.x?ۮ7XġeWj^?mD-0/ A=PHQqh )Bx. 0p]PA:7#fQ>]USɷ^z fRp[4 V82A_yQ/M񶈸 +3fWމs!wN?jU*W!ZtkvJĥ" +5f5kEpfPYhAI`u`pʮEMC ; +~!ϭnN_I{5=.L-lr\Ͷ< n}- ieö9`@vQ5X+r}Х|gd|b^O=`z+N-Vca=t%ߗfzpBQ@ h}H!y&U~y}nWgOLczf0]-9)+ہ3xPOhh)sMS}5Y̨nϟȷD*G܃^ꈆv@nu"9 -iZTN)y66b>#Yi6*aT۩SZU{9{!DB_U2!FANoփG[mV">ge(q  OG#V[,kݯ@pK&dxf:}o7 > \ GEuJT~0~N?ޕ|tĂ3 +aKKo]թ) +_9?Eb|ҳm ȫ%_l +"1HMP(ĕ؉<2OǕN/S2߼RImȝYFgDYJhS}"I}τ^K-kQ+D^E0j6@sJ,11 aqq5XOT era_n߷Wwrw'̶[@iX,?|b=t7q;79[\DFD5~~mr?m9ls5e5P#w.i5Ct_E 1c.׾@~ɦV +ֿʮBZ9]bkYJG;%i|Vb#\1ЬrWlyV +} #+c2"4 k.&*G gl۔߅z&4Lukg(65Z:꿮?ZL-a+-]u_UFCuj5Ŋ8b Q8k }m C(^'Ʒ‚@ GC.2Pa($Gf{TPs-?8V9sc>V+]Mo~ ƀDkس_k =t6X!+7uЏ\lDi׃Ä$/˷&o4s?c꙰s7z +a Dp}e/@CpʬT6ɞ'4y`EF,eC"mNwl*<,.:4-k{Ud?;k+S6klu$~8}a Jb0Im|X| w5% 7P JG}rcn`ʉ<): ,f~FJ_(cΆi)>ڱJ/ю +F(f*T @`"Ʒuwz]۶U}uux@8v@Y6nQ? p|/ș +v>/or=%3\ZzTɼ3\zZj=Y{avH*kϞzPi +ti0"Ԏƞ헀XRK}kL߉{pLޟ' 4楟:H@z>4\nJ_de[9\bt϶Z-9I_>֥y֊,k"V;F"7 [}^1| qʦ2ܢ+ +ɉX"I,x SalrWd#YΜ9Q(XHmDKEQm#97+ժy*R_N| pD[TŸw36VC۲w1)7^3G}nbrt 6ֻnk&lGD_RH2V + 3r*DpEs*0gK[~qد\N<} +ڦQ' bmI+qZ=isl'uc܈GV= Z$*_6ۚض2x +BaxÉV.6q +<\Pn):xc }pvlA6Nt\_ eQթ ڝşl_[ 2Q)Sg%̲H^[u+(>!pP&s KIQEnkԍ"鳍.H*K/XFo4R-*#QdquY~8S;Zȁދֶuk]-W[' Q@6D`g.V$0J}`2..(]`cSyu6v-ܛ)daa]٨PKP#5yҟMXYzgF@X8?tT<]7{ht}ӵ^GJ#C[;;Ϲ/ʷ58g+%KI#o;ؖNR0[[|4k*0-WŌjJAD!ke +IcHn驭 5| d%k62F"R ey'УTScY +} $G%~NJ J$-[XFrEqɭ-6ݽ+!/+`Ka + v $( +r~Y0wJ_Oy$G?_??Ͽ?_?q}b_???.!B?|F}@tco #R{' ~QE?EAw $IšA /G &=B~]Ct1;0"(WN(("Euܑ`^)H7S*_p"fgzp'@n_]H{l|ل4WE[k|Jπ؜#q9LxYXBUCFR\~-fFtxkQg"2-jY숕A)n_ +4OPzXr(3zA`lo9 y&њu̔A5*Ff#[&ԘyGd&b*#`^:ޯA(MzU[ -zCXʱEaeĞhC9W#Wb[<Q|.cF3LNGuR?c_0UqQVԭuGIyT[&0DrV֜^wPl_YA:ǡy&bN"!##Z@+@iiAc8u`2g<:pUu| t<X!zBU`+C[ûCAasɗC>6%~EՔI<(?ĸ-!Cďc#j)V/%*kHA_{z^^q쀂36t7ޙ!03K6Yh. + + hQTO" #$UDAuB +ED0G #phZvިvL8A!'- ">KJ.P[FO=3#nǐvNP +D6]˙k Xt¬@0OO +#+EYڢA.s$v.s|aHҙnZQ'[A>8/gh_iRXҒ1Oq +B6k-> |C[|5/4D3ɏ uS8;O}ƊjDPHZ]LBʠc\$젗J54vy& 4\:tN +U48>X@&2˷ѩ_9!p(# +v%D^q4dn^ԍ;7/RɊ25&C9%1FٓIarpA3ؿ46!U<j&ۅ(Iz(tLg|D8Ԝ̭o@\j"XlޤN݅'۪kg .LFeF}:C{I! vaVطVcD@R&RuRk=Cj}ճ [ IF/vf @ ;0!ö2xWMJ.N9g+t_?/ 3A_M-/%,uJ^eEPa"m菈\N @8I&L1"0[$? +iM #Ռ~O:zDϮY6q;"u u[6R%b2!!A,TrJxgN?uV~yd"tW3W q=f^T&|ԜILFXۚb.xtH"tz XQP_c/i^Z;W02TVNqSMv]l}d'QɞI|#3j!*t~$!k劉TU۩J02^,8jd?$ #4G9pYXS{{î(&xJy"`1:sϲ֦טҀx +OۯN?7R/ψ7$Œq*xD  W6H'g}ewl!n3bnQtҥ"g~ Mmu"an{첿5-,lHPȕw?PO+1%hI0b9$ނ_"\"<t`yG^" 7>wψA~~_t$8~ +`qiiyT]]>en_RCDI\MÁ *?=k,9kbpz~ ZWLVwE9!k=&~ ]Sq|L ψ +k]X%`g熛7$Y}a 1L ۨRyBhdc%6ψc2c܈>|ބs y__\nіXEν,GHɁ|m #N-I_Сe8@V HiZp%8>"%[SMi"g2E֫/-dN,0rR(B&("&%%\9q_5~ gNVq4X?n ':UTLCVt1كE+{ wJ{XfքvۍY)SMwY'_]uz0+lOGmB8(И=5."Xr!9} U/Pב 1#[Po!vAfEm5π"?ԲCw@/^ G:0o!@z,YU֕O--˟9yYE[ +z֮|]r'ŰqڜAnKWӞ *ݲ=࡮8uB=ϯInE{`~wt}ݟ% #]#t,Jj|+B_bj,2NuEnsA*2^KOGtW}bۉ#FqMY}gBV|J3cv/W,31!8m)oឱ0d`އ̟&]Sy]پ`q !py>x<><-ylA +u+ƞ yyD`؏r:)Tl!k! +0a#ןlxBqy`%op`hXOeOBRGW#%?T"n4*8jTeKf=y|#댚@uZɀNWeritiYͫhbToL,[`@xtnpg)jWaLiI|*9 [ZHA[DW~j{"&׹pdM;ޫ8aFq9SxO +] 'D2>#:YB?e{kRD4 ey*>UwAWT{Ǿg[̃3F9S)U G,vg|W\ՙ*ҭąL&tiK筑sW cpޛ)b tAN "#kai[R^Ea +X~pNr*9}+VLcΜ| +揷ߺKVQ@A4jth3=Q*[H}ÊF;n :k[CPN{%@+rYr:Ũ{UsW +=@gJ\[,u+ ++%wW{̯wr^N1~:}eܫG |/M/oag3gүe/|=4\N' +e0B<'SH?kr#?>"TZ| '3H;Xl8Cا%kE +ma3#uJ8w‚hq-dFmgWy3[瓿E[2y Doy19՛GC FE +q^L{Afgu>ū쮟gݼ‹ BlHL9Tǭ!jzWuŁr + Cԧ#[:.H = +1Q`ͪubXxSV42xL9NjۆEWz)tXKFV87 2" ܰS\3KLҿ*{qgLIzykhTwk 7%V\X"nU>cЈ2g(\X;T`4o ޭf1CƈN{[#8#n,4NaZ*3ñObW֦$·Y ]s/)s?7)"+LK %憲I5 + {{Ĕ灺\ P'qo=5 Z|7 ++'7PDtkA`x܈Ft}&&D +o"([ާg~V.=nhD&AةoS,nwZbZwˣX2@P<͹1P^eGZi Eckg LUdWf07 +@| sTu a>PA5t'*DՄ2P|^%yiPד,m9K@OSgVΪzQ&g8!iEڌ$LXIucKY_d ؐjcza +tA!3J`[9GTvjbJ#^̈:+o,AT(5 '&~"%|u;ܮ݁@‘ + H>A#Bxx -o]2? D\LQNZܤK!k >^[N8oghH\=5{J%ua 12H"32[ӿ[Ӓ.3?BeDiBR%̦dEΓ9/VF@3쯟 UB+fG ^WK׸]gPoMv-!۫O7`GthSQMt&?=Z{hC4 :a`Rl@@[EHqψxgP*י̰5ZAy)QG2`zh(aCHhY#o%=8@wznAw0a +uww=R9V! HL@Lw(qtT4Y=Y^߈/P35 ( ~Fó<|MZaQv8 iٶ9&,))!t\Zz#fwnԒMn'^"M BZ`&яR=V4z'˕8RFoLF0%`u.Y_$v0yb9w%) 嶰# ;wjJEc tl<~mHoYr[6:?=HBC&߲ ƍOzۅ_8S7O+}^6(㬖ȤZO +ڀ諆-±`{#VNϿ j[͹o-2{,σvc߷ևgP9I3W0hߔ~(w@jHD#_ǎztJ +#L@3c?ŰsaVxh P9{L!2zuWE?86C1烟<qu 'yky@I4@d\cr C.}/1~^f{f[3E\2;c7(xq;eMY3 b,2^S +b>4q,AOAc3ĕ=9.zjqFfYr*E%.q7iݕN9!!cU䀉߈I9p=PFK],[Cժr6X?4|aC]^0rXG][Q~)ܒT|-Ѫ@w27_Y]Ǒ-|#ͨ~ʗC02t6&a^Aӱ9 =V 23亹t}O/m[:aWەf tNgTĖs3PR̮@@49&MI6T_r#n5XƆ@}YaüS٥gT"No0֜3U!ˆd#ouAk%;Eׯf)b4 07Uz=p ]1fL}7dL͗TZCb=pt<ÄC1N yA4Y_Y ilR[C1j$y-5}[ՌY;Z]w<;FSX)a۶A]+$ LEPM-x^# zzph:_ }h:dn-q}kQSmy4br!ugU,V>1ωЙ+=UTsH"$5'60WOT \9[XK]fZ7ضÝ˽S^ˁTbiR{NeXQFiJ!=Ocqز\!&ҵ9#ξkʓARv#͡=ʣ7\l +y@ z]P,dflc^RMw;B[~z!Ug:q)DRMA66E#֯KaN^KTgps-^ 8pwC4IDcnMƹ| ^Z)1n_O[ClBG挅.h'-=d_## +47]9*(!X(ueTe'*zf%DZ|*M.YpԪ3pVS,f= |_tSYhAeدl]mi!Ƨ u ۈ/oNMTV#aRP=hyy@V-V +5->!Zqc̟YD ǁRf|Y5[>%X"ʖ + D &q%yy/hpz GDLBtRՂ"p"^գtZ+ςv'm>` Sj"֍eM>tr~cR}J|`;@/ llW_PB_:#\>M`PR2ɐzEl-n5fE2r[FbHTEMa:T=FﯲŕRF\CBi^r)cZF85qT$D iJ渂, ȭ4FO;8us6"yCЌP֡+Mj ="OX,`{ + qMC3%Z]0{F +`=kXDT2/|J_L1D=T2\X|aOB[^ټІ%B\wBO@\J; +)n6jdR]_ۡZ+U333TGݝ)㺪U È/@$W\2+AO+uaVDZr0hsD*F}!mm53;m BD5A%?Fp+Z8Qr {EDb7Kߊ jr^lmu 4 E# + o!ĜwQYULŵlN#^7ql5ʺ\u=` p^D3Ub +o~a}-[ֺx7JߔOAokF.!.'\c٭l!TXbS]:)'f@Mhbp}tmO0ۡĵͅဵ>Cn5Z~ԎcݛnY+=)vPPejSJK/32- l7!n3Bc PbCfLh1󃶚4a_,h9L<^D`Hz_*CRςv}DXq,[뿣#FZ^B¼Jd }G<II5ƙgAeA:kܓ?[+B+9k"AqQ%$<:؊:X9Qhvmc#+?偡y*o4D nӘ;+lJnI^f+Fghto+J浇T@n7:2M>9߅^ +'{.-C|񏴿3&Y)L]%8^N0&\@oqe]? Ⱦ#&@&?d<϶E7p#Pέxnr銨pPuTT•oDf%ͶE IDa,|)N=4 h3e Ns*&ǞnD8}*f]Ju%{#4=5Iέy#/[@Mt~nM(% cISQK!KAmz7DI#3)6{s%ֿke'1aTH 262V&)鍶 _S Ý(&:w:k*3 Cz1 ? +š/velF-\Qwk`,0Bpi&}΅d~scp!BY|s.Ǔ帼0nOIup/^)b#',"L Nas +:5n +w{`)v dH:n;ϗ5A5.+>ҩ,ʅowoYkjp$x!1Ҵ5^;E(k z0goj&t]t=5a +r^G˧Ia{+@# /=QVQw0H-t[.[M=0J{#4 +ؼ *&#^ xt@%6i;0DG1T 7%Ⱦ_}3l>^ ԧ&|#S-56Ϫ.V(#(L01BE(dĵD}ug]}ױuWK0A +s{ )@?ePSrV0q"W1Rm'fPz6UbȈrOɑ13?VpsgVC@WN}7,W`ia[q +ϙR9#kY?OU4t`Gdn,}"kO8DUāh*p>1a@e[;g׃Aj+&`>ϱҰ ^U+u|xu1Ȁ5tj۪%Pq@c^xk-ʇf\xbo?CN}] 64/bBt*i +~BN?̫DdC+oe7 $ ~_?V;Mehx\" +:dmX塸\]k K~+"h #7]#zLV*W?Gœ_ni?2kB(Y% ,n^T=@j*>VP7uzS\(kuͦF+%Ly#9<]C o iː"GRʼnu7* DǞ @ŽGKZ GzXZB{H~͹Ƥ'Mf#,3gLFՈ,/:ٕNg B5WrՒg_lKb6?* Hd< +$ڐ́HN*R=Be֗R9 +)HQv+ =hc(.W ScȩjG0crϩ|ni^V +5*d|aPΤju#'qd$֠<[X%AWXkXv57o9:ptz[=m8;V* +W]<ݠr}7p?~Ůq +ƹ'y"BDdXS5kV?ʦ<+*ZN;U+sq-@/XŰ Nj§ʺ'2n1)Evcj3I=^vF.!9E='q^4:h̢_gx28xXz<h}JgSgBNPym @h|1~mF-9u^QIJBbn1L :ِ +@sά'l}n!Dm6pUU߻v*ZTè -.}thLqê5 0PDp|BIpjw+:ż>d(RГ 5; ixDo|?bD2d,&XҐ@Wv!|%[TE=[1:J(E^3ǪBf#HJgS|{ +$AB#ĵH-qCG_ԝVzIu3W6 R2+&})lsv#|C+oV hX˗W]kO)n8c6wh¶ 20x@`UhQ!T+)Y'm8!w" WA0*U*^آ}N)j +{:Ի}AVnS>N9q xzPcx&*QeE ^!CMer#yF. ؕlmM'$0 ,0)ԮI(5 W8@Cv7Y#4J}/DQe_]- +A|?p!Jbex +u3P:Л\[3y^57L"Fh\{a)^ Ӈhf+E8ŽPx["j([4^Toxd6t +teF /8ҋ˳o)Lk- `5R׫=k4@8JzpJeљ!/Q bG[%ÿ\ J8b33r OA*"ΗwIҭ*)oyK @֟ ƘNV~tDVl6\$CSKQg ^)}2n +%@VfLix^$̐զ{)%T?:$:;xf#Rtj:+9 ?Τ\iD/ GayD32=294FD;Di {l9 O1+ f@@JIh9p~,Tʊ}3t9it[OEzF|ã9EF0JFYݔޥ+ R 9-&Ry$jvRjE}~l]K۠12LmX@\j[\GByTaTlZVq+Qqxp/xn5\)@eX#[(I@ jO,2@{g T`8 +E9Ŋ${( M w@/~*x׶rM/E Nd*n;k*V0q3zK#uh-Rd@m#*;u +NDaLN]25gp4tZD3^d7֒msa!/`P_h[y?oo7=u*nG gm`:]+Ώ(y+ch0 2{,^3dbVwق7ʬ"&d!9k5G]䭧>꛸,xͽ+lLzoc6 +hWFcK!_b}6GydhU +D Q-3T{dÌnM@HEVD=ޭk+/qdAUXXYVcy#rȦ b8-W*˪.kO1iiL^f ;Ԏҳ+6'/}+A ܹid~Fhɴ+^\]*}- :zr| ;ysi +4&$<;q#IȺOZHFliӕ/d>6+DGH;mQanBӸ6,5Q<ǵA?].!6mK>0~KE%cK6fH]{xGRT  `l(c> +u> xy- +QPQ AiR~ yK Xqt6PXu|[`6P@a#=@!ǟN4i ^Esl7Z$@+7A:#Nu Ua]vkqN6ȫ#3+kكWf)/D($k]g?>< ?lN4iF=d!` 9L{֤wRZT[GEi]'b8%U^߯? N?k`OV_ϝuE**$Ō7}hNyAr@%NjsLC3"gZDhUB +Y~AKI-zNaʊ !1@m,,J~:` DZ=#)HeG-"jnu!`IEU75.hDCg%ն5s BiqةHHeLJ9ҕ^^Sbo9jo˜vnvFG3Z?%zg>8y)Op;M|97m@֑ A?zX/m +K+4 % +f( =)uF)`-MŪrTӱ a ECsPgPiUh&RU׋0 +L)pE9DARtmh&jj){"-?eЁ(₊ҥH;qkV7`iR|#wvtG#L-MթFԿ>S +,f )M%(R+HOtxιN\| k#;D|P4t@V]ԭ!ĊE%=n8r.^.5 ##״E(QVUhA\;xqAL֎/[l +ic":4L3ʧ?a%*y;^L˚k\ BVT8ψ??Õ(@;SFuřJ2 +wT4TZUTY;ֺO>f<3nbBGdK0ׄ,'35y\ ܌О +S$G\R >4g[;Y?Oc&?;W@g9 I[%(̐lW$~N%?Dl*myvlQ) 285 \3b +`~x|?8 ;UDX5l~}~Y5sf@kYΟdDž_S$лL#(.ZQ~``C4-f?=%Hդ[vD+Bz{HsSGx{RZ.px 䦣~[ 0^ |_3(B9ZQ+B[`;cq6#]gQ#a}`^p'jp>-P"NMWD)JkIUN .c{TQ ,^z LodhNۥ&pP8J(0՟낟Fbs|)E-tnw\<xpmjcn{Vb`kGǦ=iD1ho3#6b܆VD@?7m.N,;^ +@˭?ITӶ5اm7 +z_NjiFeˆ +qB$oϱƭ:gٖ]Y"jqDhk k#y6BI0A1mHv/ T,:cЙO.$b^{ZA=?`TP }'=Έp"0ѰI O~ VQƯHIf9Ʃ(83s+tXCmu(/kL>9&2Ϙp-{VY☲= DDeQjK^8hl=k <|'pIQ]jedD-m[%c_T/bIѸKn~'%笆1u+#q[zH B0Q)6#I8_xJk۽-?%R(5JusAb8{x^=1"fbdcM%1`yF\*W&Tj*(D@.Lg}tAH#l" F3^7RD`dC-v\hqTqd!EUГ&jM*Sz y}q;z +C +Gʩ2ԡy#gľgtG îGJ$rM^3g<'ݹ,`f |+J |O7yF `jNֶ:uZ7}iJl ]*"fl>]V=b;=&jR0HgľY%8a3@) R#) Ui"L4~m+,21Z rˀFj$霂*F' +n~QQUld{<<-='◙[ѺY?SJ-&Mj@^04w0i@:{5JxiȗlD?Ԝ;&=}Q$bt([z摕ݻ}"~?DN+b{}:S}MpĘWZIՐoń[>9L̚0}TєmGXZJ'QCbU`>UfEN}S%ir"ntj~eYfCʷJc 3*p`Qcͳ؊ׯ&+CW9 kK|#"}`? G֝gbd}$΍QSwgĖo}~ck1:1csk# 9izk5^&\PTPNn#)LvŚjVE5 Զh?xZό$ SG.87Zvg cV|:LX{}N+5+1C6e4,sp1P1ncI!ZUM`?':]b)o0*A[;2(VB}|/OK*mF?u~-(@S#l9mĀ)"w1OE`D 6D"Jt0d;b$L#ȯ%,N>B6O%+w(X)uRSI7>G xC(R0"U_]Zg-L͑kO'3L0ݽ0i~c8‹]rl<@*,s܌<-DĴ-O_ϠT&>m^{ ;OE#_F#wP+WX^NE}T3?8G8l]Z;?RTdnQLӳZ0_l?E+V6&6fEЇjRV9ʟNt9-:!}HU"z')4 luC&XgygVF7vt{@Eya`DBI~jp(|su38.1u  ". ,##Td}rOR7G^Uv$jx}lm80=gQƒmvޯ /Wz1H" ba2ơ1( "b}) X`r"[+ll2#C?F1=s9-aΐσ]yu}p30;#"-t߳5XQkh aODz58 ܦ9@lHԍ>#2-=75F@#ӏk|?깑 f͐iMMKiH%"#DW.gp؝SqK =-+dOנV1qJLgב 'aH{aKwJƶ &?&š vb+ */ch +?0QVDbwu=6FoV]jQ6 ҃μ)ZM#_}k>4k}m_)@svģ<ߢ@ C4 VK#j)Fݡ=.0 |;7n-8>t{TE5Q{&J/^Nۅ1%. +"uS + e&X.n){o#RpƈNbQbE jFDT-:PI"9' d:}bjOg뵱i22gt_^lEm<7S^?E#}]36'NʏdL)|碓^o?"sFL"‡(FQ`4IkiMGQ-[0|¤Kڟ@\nSnD&5y̌8իm=CD։SȎX5:m٧ Õ-}nNPe> \:\vNB(a\Ark[UW3ޗ"|{sF)X +pZAKTljG^q 9!ԉCue3`.u޵o3J^"r'qKC̟S}!3\߈ @tPv8Qv%#b&DWBDfa4<8=q zg+7o_%95gk7a+犦n=#ӹpx3~EŘ9lK;o'o:tמ68_enaLCS:/n^I֙c4W:W0_y"- +ql!aD/>lFl92~kq9(Kz4xϮk Oj86Uwצ 31F%cYwz1g0˯ jpmphC_'/bx%n9-[EzA]o݄twOQ\6[mP&jJ2ڨ +. +TbohƮ[B4*2u#;&B*#S4h3KR9mBW agDN5|us*0검tyoZET} @@3A ߹R@3%]kjT3H<#ԕ-ik?6h}3B[d&bF%+˩$2s9Q\!G".u3™Df"bfq}0z~Y's]6Ja6]+jkzCqekZﱔcʈx^Tn7ݕ`(aׁ=ƶy[f#D_b+KX#0a { >Ųh 8jC9F9<=dUumUվAg=B !9b\aܟZ ,㜧bOOw_Я z +endstream endobj 105 0 obj <>stream +ȵgH#?^jTi?( 8[8 rH[+WsfT`ڈxp)/QncID*2A;g iӡq%uLo1V/2:-Y +zScFEԓ}4M,jqZfd)mpE_?‚]ʣ!|J˦kׯiU;[a-Dxbݝ ֝ yÇNqc@L0fPn={S608@zYQÈP=}ɦQq??=:I'[f?',xF)vHZ9q臗D"0Z;Os,6(:OE_Vd:̗MGx-{s}"{^ΰOÁ j<ڠ.j4 +D!2kYle lN tl +4!#1k" g[y< DW6zaR*vLi~)HωO~&lJ`"ު"k}7cqGƃec"H+f2nN^gQuzqxZ`>Teޘ*+l&!gbuf[Z7F\&XsWp#4f7>9jm)Cĭ|oFByu&+cpXڦ?ޙ9Ӡso^`hgr!A~^Lk ƈ˃<ԇ3Sk!^n 7 ?9,ʴw 0_uNum>ElCY*bx~%cq{9%,?X?Ǥ Qc+g_\ظ~SDVi:RM*)?Rl5BxxvkENua$1u# w +@i׆?#rv˚]בj%N*4 J O>E>`ћ&Z]XTi(#~^&V*=vm{ڝcP&y>,IE#!D+J:#I_ +sT1%Q鑲)/[œVľdz+u;\sX:e ָ0Z&`\jQ7zX"'^_4n?xOnz  +}2RFN>*+@e:;ETx '"}Nj֍GNJ>G;=^XO8&[.@MD`gEVkǟL4H}:Bd9=LbwB[Zа"`ΨҀȘTH#Kňdʴ%~\|dp+Q@Oj;'˻>ayiO(fJ[Q*o@1Haw~}z~8$u痑 cۚN6nGxI9[{>6cZnRHfC{6(0]UPg3:Vkk(f(MCg{(y5Cp̙ŮD-c܅k:Kl$Fi<:1Ya-Ŵdj+Uh ziqQVt [R?.U->B4%d_:׵әŜO+l(Sp)(~ZϏ*ҭc|ɻ[) `ѷ%s"'%exGrzI=AktL76 +x@ٙRbg|/Vܧ*\aZsM48E9X˹Ndo?8|(n+«!jU$/kv.2GD|"1q gzNNzL +kp^l;cd _ZmlP;B+{4KeKGCTG CR%̆ +;_;zdgؽq$=808$4's"kd[mÿðR]f^J~8Tjb*% "ns*o*vEZXߺ 14KTb 38k|pv+{X/:0ZJkނp ix1AVIփH3q?#3œ>s +67h;jg5^J" +\~&gn E0kGNhAQՇEr=@4ާM ,^Qa4[Нz`[z ǜAlPO8]mtmqBW2*CuNuyuP C_䤻7=S#ˆ[8} ^  m_uMX7z*Fʶ*WIc #f"jL"i݇x0FGnHʺYC}90 +xzǕh`>fO*v8Y,׊y$@a Z9-oπ3 ^$ϰ8xQ%.DfAX ks^ : Ww}kq !Ch8:HvP@(x>YGx8ȣp 4tZA*A t&N^2}'! +\jgH`"(Бg2mZyWU*n幰Wr*Kf7cw,H0"[(=q0xgø?w+[64#HhӜۂqo46]d1(rE +A #`W3[BUC|kKDh(nsWMA\rr®R\S;ZG+ЇAAE7A[Y-,U,KLzbѝktS2XW +DTK)56S d |D-5]P0S +:0jfA}pUi/ W?;C +mHx¸?Ѹ :V =쯟hܵp3lf (mFU!72-.nuj׋VF-YZZf>O_f\@YE0ZDGn]Ml"lc_#coQk +%Bi=`3+gp(܌6ÒF5ʋbqǂhEp{2o8(QX_ai:L0H9<|鴿4r .'a[\1NV^73k3k}Gt +{4K(!N(-g1 Ҕ?D`2S{ϰ#zQc6Rc+/*)0*}0~b~'?BpG> o]7S,rIHjO nOMd 1bW5pyq%>*&)z,#R/T&f_SظTÓrI7H9jtR2}W 4!9[9Sϟ+G;Y +KC yjf\Fs 9 0SorQߔ',vN(+z=(E݌r_m8)z3%j&^ ǖǞr7&肻e,iĽ=Q%z/Y?)i&qB_b$G"Tg1!?doҪO_q-C``TF}RԙT!>=ܙ!<&}ʀ"v,i]ɹKFM$|lAWsDGy\ CkBQ3wcf@KO 7 74+w.ޤz +^TR2{Z̿맛ⲡ-IG mp,$ $bU_47i^R4V [wFnp9Tvph+@eNʁd"$]xFY7t~RIXiY᠃Lޙ1E[ r1be*⵾8scpxpl b;v588QQd %WG ʉvE=YFm8::pzUL $D^Yg!p£Numz¢sND&IMzJBjS__INU䳋n9wi#өC9z &p!Sb}2eVtO+ZQH*h;Ip +4dg6>]AA]@3~leӇD1B?M6GW8Ņ xKH$^1#\sI[=]ˢ?٧]HiO4# 4|9pyFG?pU]BKfJqY8%!(B`LwjkK-ya@eӼ j|_G?&XW8x' ea|*)QMEz)} +F%D!"5{`nV\%' e0 28^ˏ@ ZmMjBb)Z166vݑD; B jp׫j[ci5ʺС׵=M*N{<I2 |k=C$z=э`&+}Hԧ#vi4ua$@ g PPdN={ΐ [e8p\[OA=)h"YF0xžS5Z}]IOrL3{\ +Q;ҽ8̩IM]lp;%9"(eU_g!$\!gc= +#9er^S*28ϩ}Az-ctOʀfk jqoH@pYCq|e3w`"M3S8<-jޅ=e %o*q*1Q^9^-q;GqH:+#  5);`Zwb wi_{nz:ŬVD,|Kߔ[ +1>q"G1h#p^oPt(RFSQ2LI$78D2ޕ +n"wz@>58'y:묣cAxO,It)-װ)Tr9x\=gAjqn}I?lPT=s DhqdU4Ck9n/(dOnܮ~sl LэDQŒhMN(e]#a/҄g׈X`e]V]GӴz0wE0Ǖt-b +xY0aq `ODg-Ǿ[3y[DY< +qK {WQ E"U0S/\%%]P؅3sDQ +NC)b/l/|H0G1v*AHmiXP>ecbRIT(59%=mQ\y_Z~a y w)ծS$U%mSp"]9F⃵ùMڽGyvI7s*6 +ľ=uR6:"Bi &>*i@k=y+Wr{!|ky KB !JV\_A-e +xXUNE'pɹoXltL<5Rŗ e94cLQiR-9Z@(YyST%xjJ-J[=tz +,NQRę)poU9ޯʢ+](Q緰Pe#q:YXL򝒉|Oʶ t ++Ȫ煤&@=eK44BDΑޢ}$=ayw~(8a@pWZ+"jyEM7 8$b]1F<%{v)Wv=xE~.LZocS21Bn)o7OX>-ےz#cwC +7w3!mYO =8N6 8xf +KrgMh b)lGҖt&yҒQUYﳚ]!tNT +:]8l@S +"K" + (l|:AMb`\Vy '3*UHd`bTm{.gU<z@cӑwZۘ|(ăI2504W+~)&\#Ů{7@ԧUi塑dlOEw)#u*XȨoL!WE⑄!VHW5" +*t0| 6B3@ָ|nK_ ??zJtc@.sHGh'P΀E?Q ~G^G{CDnîl+L<?{+h~   @iB1PcIP\J*5{ݢ΅-IA;[XiTwN"\=9->i:a͙F=o7Hj)h1Pۧҗ$cN{cD퀷4ؽ6;o#ϫHbE >#降Θ+=OJֱOx[0$Sf+PeS6݇ty3+ַഐKF @TW[/o]V(Q43wj-{,r/VV0Fv`8!&~5H#%W"uBnZ|F|cse`L2X">,h3TCRf̡0^e 7C(WWQ{``].!Y_L-a֫էx??12r?~=-݁/S5\aɒH(:Gi=ʛ<|RtuOȌ)}˨8*cJ a+;h!ű:EX z_GoL]s ";-$fA )=5sqpHwY`^gQX`Υkmxd@ ++oȵC*RЁ}"g-q$Q:ި05ɸ״/D~nv M]DyԦaͨ3B6;aio " 4B<,aoho'VCf+$+ذ@+*kycC!aBg`7Mˌ׋25mhs΀?P (K;~d q/*5LOs3"<X_~fX?Fo.ligvi5($ߧ=Xrחⱼՠ/xGc;nJabυ/ʴg׵*L.)^ b` +Xyzr d14dK2F=~/mq~#g47$?p#{sZ4L8s!p9#~><ص6as]\j;86x!mISpwח#/ꂼHz>}t%,<{\$ | +rwı"nQEi39̾%Zx`▀6j-  H XB`حov}Y̲jHP*ͷMRuTҾ8{JKb +_ 8:_bMjOC%R lk.fM`Nw#e*?\*hOr0,  `+3IkNh?BD},ʮ6jzŻ ~x"ڷXf+ ȕvj:ס 5!IA+xNo +5K¶TBea b^|O^ uE.=({W@! +'ķ jlj +t"a"Lmc&Nںu/ʺF@Q=uQcrve /[?~R/z;PǭiGLF"FҠD \MG8|^t= ;MTͰ~T64b]zx8ZI,%9ԅGuɧ2zS(`-"ݫ붃";/"|m qT@7 +QQ(nS |XO21/+=v>Ѕe+(uN|RSݷ0Y!ESo8ؠ1Ǫ,DQ:m-xW~yX%@# ;РO ÷]6cΐ@bu֌ O^q*墣'+-}Ϭ-\Em-)u`ìgւ~Vx[H;. eI&: HEK݄]Qe53݀^{[pvۗ|!!OT?En{d;|=3y=D,3i͝ @az .8JƃWEq!*hkR@4ԯo?;7RNݍ(!R,([ovM G5m셣.Z4qcYsIF76"sIjaƂxn"Ihq~8Vv*b׈4;A$L`s3(=hĆαĥW{Dݾ2V }:nacQ=%ЮMMA8 +shՅ:T:￯fe]BKwGӹ{RIi%0.#]##fn(4Bؗ670YA&A5|;>ҬIʇת;6{DkL 4T94)vx4(@l4'|62C5h"KX=Wf$qF)h_Av3'F?ҁe,Ey/9p?ט]yk# 24t/ȊvĆS2BPK`d_ׅAt Pjg/# 6HzK/#v@%rջ{LVNSaSu<#$"O.9F2,IH;TJșz\oyd 2i1*c%AEݗuC8ɣ7Ղ%l_U?͟!y>4̐WuϿ0̈́3RqG/[.5z3pi7Ǥ=k@6[k(MC,_ +b/7,X鴿G<Ɩ0. WIVZױ|+0( ." 27sM43:HpGUb/tV9ڒ&ofv7ױ-K+GToq[V3lH5HyX xXt:5d3`=rm`K"1*xnxDŏC)`L/v'cG´t@K(eDw Be/#lױLf邌DڨSlY_ c)̂\ ]D4@WKUO׀{\#ó؀UOvHV#i~HS&m)E`ISfmDkWgi|~QiKs$p$p*Sk cP%LNݫw nb-RaV#۔SqGqe T`UTM=.爹΅C_5w{rJܿ4{* IJ7mA@u0 eS/D~8]qv=3 ADx9z&(߾K9OܒxT/չ<-׻e2ށܹT`dd nzg*Bcvr63nKDZ~1窱s ؓMX@Iaf`sB{1sQ*"E A9]8Sb<[X%wJO*'2-7 Is< +N-0.EVBva )?H} ṡ6yږK# c2ҊCǦ`^k0#"~+8CThB29=*[iߢ'EƄ5fȘ}ԛA60# (R=X'B[-|9#|."Jo xg7i<wq\Ws\TL`Lӯ_\vd<ypX{p殯a "AX{Պ)4T?h'p)C0sX=>,zaS850o-_l\RNUWN&J=xES@ɮ@ſF5*SԘj#ZVOPÒI0=aB:ժQ!hZE)r% Yd;]jK另5=R@mǃU@@G%>т#Gy]EK"葚дAHɍyAGXvt!q-2O"_|dW(Y)#y[~mɤ^WZsx!ňT=㳽/l EXp[4gJ!Nra']j FHOm J/Yn +|I,^Z0yh.#Sw7<.t&E{o]?Tbc" +EZhȌ`I-K~Y;}ns=PLy\/"Rwn's:ʘǸ˘ M;0 u)4Z<ǚ)ϟ- +Mw>a>#VnS:'x]jW +,C$ 6i܀o@E Sˬ{ &W(sËA 5 ԯGF O}pv/շI˷?w??uʯ/wWy.䟣`HB:TnE'Ž~Cd-` 1 (8QE~YE>ep_R0LT* _ V(p00ӁV );H7UE\-߰bL+d{'p.% +NFʎ'~24lTR4|.a.#׳[ `/?tYrCP]4+y6=}[#]"!sMF㩉F"Zi j.\ܽ*](ˆBIz|Jx6*?׼ LO&K :U=]CŢ +r mg8p~?tJr*/\Lq 5]b*!ۣZcH"!AA( Lˁv,}Hsd YLD7fP/E8pPs=gR>䭖xG7AvO_=[eegqkop)8wžgґU0'f/fԻxf6u4!"+C1ldlt,iZAsRuj-&zaX4I"m *.2Pn.nC +>4~dwW!ӥ m *DK6 qULF Z–@-&b'(`AeDr˭}5S[9UҨS)0txGu9s ?!5{NidPzpyk, )24?xə*yъpBb:C+qnUR.3Րgʣ&((c˪m(stA^̴P XdXXP"fNJDgpK3l qxsA{ >y\~Z*8hvpu^|7i0;k1{U{[H30@慢Z3IKb\ƩaR8nX;3`"+dUraWc+. ৣ;sU MyjqZy}[DgOz dB]q4*Q4laڔ;ETHe̠ՔڲÅPz&cO`4MkN#6(Xov{S6N0@[J?9RKi$ +Z7'hX8UA4C&la>d;8Y~&qf%h :B3~RavS(8;=#ʲS\5tފ(3r [1ȺmA#A33b@9r&|jNɜJl֙gOQ;m1Na}ʙlQfj{Xϖ@/>m=XőL:ֻ_ ./Sxr*ce WaM2KF<{ĺmgLk:`Sɿ1g&3["j[7BÔթ‡Y_SdGMXnuE[vvPh^}Q= O4p5xQ3'X"WHR2Kȝ&*4ZR:t2v(+H쒝LcMmy8z.۲a'S@jK3<[=&ٗ΃Zd"8wϗA}F1z; pk#BvV՚~Xؼũ\tgɤIiTꋈ3|[{oa5PgV0N74G[ +aڎ'V~ƞi[Q~gTaN(^WdU/r_zswE[%ܘ ` oՕ+\WZFΈɸiLy"O|gt`J_9leeaǩ' 09O&],54,h@cڔHr:H^wC/R) L$O"[qMKxpUYz.b^9kk:_=ݝ]]繳|y6?}z?`RY7h/BJHt #=^wۣnwUYLr'cn;>?r#3IhmC+6i*U1j}z&n5X< (=Xzz.7ssZqDs 5q4?G_ YzVx);Ѕp^/ݮ7F:qci#~26uZ1ҠaI,Zc~~0MD8 A20]^g8C}uЇE0IH=xlzHR^u +'a6zxYX ΂U2Gn>QA@jNe40u&{Y֡5o1BxB($m5a;ϛ TdU;ҡvK!!$JkUuwLV-GK?g]s؟|Jdjl;cǷuۣzP/ +QUkVuvR +0!A7A^硞E!)~玀**Ql*H)V5ohG30q(˂#4-!wgyc[ikAc(Jmb1(]Fc∣\,1\^{ғSQEk.͜FZs*©FCKd +߯{o5h0+btu0up}b'㵵Rz\0gFs_[* /Z2f`/j_Dhyh9]n`~5N]础kЉLFT"؟_{|.%a@ZG4miD'MT"8_J0ϩ:dF6O`с[Hڨa踻 Ps"Q@+fDỌhL g[ -RSOm6[&_hT =)͸ + ꋴkt|Ĺc_TnB@͉h"+s_3[߫ x_;I q wpN=^YM`o[Cp=7VSi~Dxnh%euNe=J d\yj~(~+fNGL38W/Uj1߬UwvDŽE-rl ӻSѰ'|3E5>7wgo3k;3[ӄ6HͼJ +`?(&E-49 hqӸjȷNjuboj 7teFzZHȧhO DB I7lOonh $ +5b{p 84R }rQ8h8{Lq9EӫXEϩ\y)m1hA 7?}U÷쾱i]AwP/Eo6`Tw-l :nMӚzySꕼ +}%r:#W[xO Z]Mzu*#~3CK9  a'DkES|WN0 DҖBdABqtno2RƁt;\*Y1"/ڞ h#X+ ܦ8iQ[ +Č|BBY-3ssњm]?`jpg:ؐngrnqeUڒ9g%0ID@b!\d{SU(1%>zlJ8и#'>2j[W *Yı_v=Щx\`3ױ E[$`3)P 6S:,"s +e.:$zP_/GG?(a~}i CXm{S۟0ۅ=+H~1:QtfNJЇbI^DJ)94b9Nڢw ϒiWC*>k9y!gMCB{Ɛh_=G5s@L8*f]mFv-T>r-%U +fqh>+X@;GtGлL62PAe]g'eɇ̝\%92 +6ӯf-송+f'[5Y"(zZo8шPS!i݇r+˩d +w{Q3~=FHDjP1X8#|]yՐ8QvخR:KsZmOhx(#ô1!DQNbS$)czmPt" "L]X˨+r=5 Q!{zO \Xxx]yTS~ l(^ +ͧj'. qǶNY22ˆ"gIcL8ê; .x4 I|"#M+OSm \{t`trs +Iڟj8i&)Iه +5%Pe+A]sw+@UTkX0"֠}3vMU"̨ v/fl]m583S|HFf:M +Mo^GZ'hRTK=5Hep|2E}L6$<.U3J=mB-NDC塚bonF,gTasv"syx qu T} J Ud}vn -5yΞfR,*M$e&},R9:b\PEb^*ꆋUvsQ˜I픲X@kKfRiR$1,P tl=/ 9 5w&p|RQE_2?sT|T+/6_nkCAlњiN0[gdW}o}h }/MsN":w[QfP|&:֋kOfˮBQihBHOя5aT]ʇ48K= ڛPU@[&);rYz%ZѼ9WZdMBުm ?^(;U^2ΔC'eJ+[q=GhΩ<j232Q03xd'8 }Ebf}o-p ׶Zm2֡#,JQ*FE9C+ߗ H ȓPClw=5 +E?.PDބSJ !]A+{Kg'6xMCevMc +F~!q_%NS_KN-KT%QlD3C"Ĩ**m U9Q5iq4[vI fC\=f=k:mYrvO7f 4Kv QRp!kº>72*K-}gΓ!ҡXb~uW@ڶ-,@fmH3,-T S@ܷfzoNQ]7OP ݑ`7is^kMu |+=TYI-.es rd3+!m{

W+SgԚCAv!H@ca`R+RV +ֿtnLuW` r_VǠ&j$?$ +(L@QQa|2rXZ{-h?C߭B|#u/ i]qFw#!7 Tn='BEeXxQs5nF!2'y*RWܴG0 +`{E!S`֛7ʈtLbtTQcCʸyqzJF5G54 Md +Ya +T?O4Qq/BKB,hYԸ2FE-S+82KTG$wBRoLG!w-q1;9 gKљS&M !5GUE?WuTBwnUr#_h$Al""  {Q%qŖWF7h NnGHb$4c`$X w(;s(${HIBZ?p Dc4,2@4@ӑEQ1uȀN&/zP*78ݐ,PӈqsbBӲGlipӰHÀ6J)5 D\"Dq- 7} +5r^q8:y%=qA;" uˈ~@LHQhdTpS%@w Q7q}HWW*vA%hDnHа(?82ϛ!o=%XmPSJGV.PؓBKj 1~*l)9#&c Όh\bsHnW._S{Ni6&ZBUZh\]bɤ֙0xwlʅƕyZOEРڑZcʴ؜Ԟw"K LSyobqOO sALAf.EH`@A,jtU8"F*"R361cFa}`}v%$#3G1Ng~ZFbMe-Cr@MdUXZ< +DFND(dp82v oX0e&wwg!9ň`sT+PEXDq%Im`MG,Ȋ2U e1FFE$lj 4c=2qKܜ%&4GeG|W$WQ2OHʉ."ڕƂ5-f DdDR.Z'JLCr* faDpBMeTdV֝7y|(IXSG'ְ&b JgQGž/3J<ȜmeHE2>=nbf~0)9CmO-Q1o a⭧ ka 4LU*m 8ޫg | 0155Gfz!H)P5 +GFN&/#8㜑. zTnDS Р% xzZjm -!3 +JDRjбf@A鰈XU xhdT +\}Vxkx7,(1TQF@I;"l$ #.[!*Fﰚ;q&'7J{e[=GfU;"M4xKd|R+%?u%@WXWj,\y/K;o,\ uނWOu3-*|pHLٓJwUj95 h&,\ekKdlvfT4`[4kta6FbͣHo*-2CDh)TK~=Ff+9CLctPU4+{xP9HǨ#88@r]c Z:V<'fI;bӖԙ i.# )Ăb6ml:F{Tb wvw|@iu&@@R[\I%ޢ 5d=ek!dTRkɕ T#%Ŧ~c@+,xKLe-1yq[ZWrONnK%֌Y:]2 8ҿ&!TuD',01Whe-#Ģrk +MѶ dU#bJ{V iD/,k`Q-&b-*5j|EXጉ)"]_j8}0{ʛŹ ka լTrH<Ԗ[ a [=%]Ux%PyrwL2tl0s +Zt4,#>GwVʚB;Tր5XdW\'z0=0Q#Sn߄'05쨁b++1/х%Ov(Γq;h˯xXh:sA=2uI`ZwzmVd*@ő*ѩҒkV~f'P +gd%4XFO6["<@W6[ݰG:ڊ3Chv6yn\ogkR1@Yw`ch*{؝]Loo޻|{jҲB&&R~\}n{r&TTJMk5E[xܛUR6挷UKjɞ_C]oKR+X_;-Kh`[;lsǕZ(I WX&c=L nAtZCSG$%կwElѓ]7xHw,|A0f3idׁi5n)Ι%g|ړ_E&HǓ3krw%2IW=P8 +͞'m:(]v%zJGQYYuW]Sh(%+O.b\';ksįgTz03s*=s2^8q-;}r2b#wv x瘈*00S\urׯ<?w*GQ㮘I"&Fʑ xӝ JKKO55@w)]amW~$<>Z=v'@͟Y(.^\HU.7UfN_5qPJxm~(9ϟߑ9q +̓x|Z}h=R;8WxXXϙ_qp#NOmkVIcxsTJNSŹliS匚F<ƔPt[NEqx3_a)\tv/[bB--IuvNsU>]_Mj @y%ځKkŋ;Ntn'52J/ZbKTz+>yUF [;<ҙXhPi3[brAHg05uƷ<[ZA +_̜n,bL.X_@ܩnlbl<qWr,t/0M0ꡅBS\)9QY>[[;]P۸j:Tx- ("]ً!-SR"|( & +'=9,)d[Lv7r"Sݠ&zTR#:Tt>8ZA.])oN7B{Rԡ^I%DxWeBGi]+ۣS˕;'=xﹳ.iRfqz9 Z[|}؞ںzO?Cg֚SKgThTLq=3{s3OBkY>awo"m0?uew|iKȌؖeV23zH/_Y#m2u mΩ`uz3V$( ΗLl\ܺ;phpZGn;?f3p4^XWiojڝ +QZmH ×OXظ0袙3I7</-ͯKgA))9V|,>u19},!uW,Xvu-M +"{sx}DKQW87sMlXHɝp:lyb% V&7oML/Zu{xড়%t./':QC.G|= iG7EDD̕XKa'v&m+;pŀUgɛcr :t~eH+7IOPX&ޓ1j7oLq[>+1 ]oQ@ƨhw%Q"HE-4Sd[Bs항˭3F:srdu|I{`•T.,J+͵Kg۾tvj(K(Xojޟ]L; B=e .z'!^ ѓW#Ɛ1cuQoLVQPO©+й1MBφVjj=7qlzSۧf+%RS C';P혜)<&*HWI6l-rw<9t6TF6KSʴ1B̘;jp+F;''Puʑ;Rc0)qLԝVB jTXjR&7X mGD .e`ڛۛ;l]A푖36%zzv^jpsy&3i{ƔWD 6U4s5K(!DfbC:GfLE &hA32kVԌ ̬ 4}ޕӛ0t֑'2 JҒ5)1z/I2 ش;gd6BEF-6[Pa8 +Ι%gdbDcha?ӵ +8[*` cX{N@~1T\%gGdWIo֚)o) F&duϯa &DCLf~5z*6^A9*&ᥭ.s[~˟OoRuEcVzѣ/_{K_{}l]zʃ?>~}ziB>3ieGyP*SN.<}k]ӏ>?vw7~٫g3m| +#k ¡t7U[5R1 i&*hc.X6疏yc<̋߼w<-GYI2dA: OָB3]k&:+Ƿ]{o??;}٫?yuWNk/vQD7H$QP٢ll`s•ǟgskط.moxluXb#58Qg He&=|)jZ+KG/tW/\/?ǟ?R1 %H~C+5y&gVs*Ψdw.'wNU?!"Wkm61v /O}?û|G_7.\ۃPzd$5GΞ8煻yg^yP^~^zo}?{7~+[ Bw(VsE|efis?3>w_o>xgz{$oPb7" b#B9vdOyG cz琂KG* <=ywO_ůoG7_'}_=}:oc.Nj0 #D2מ>~]>z|wW[_??>Lyz3V[#R!QW'kS'èW~Gk?~ +3˯?ӗ=L +Ag/q=~O{W\،ZdGc +QNH'˲\X>s}{__?雿|^z W8S\w`(w#F8S[_ڸK?y?Ow>o?_c'@Ƥpܘ^X;zgr`o~gO?ӏ>mw?m-mvsu&=kr$>eC>~ßWy_/}_ҍ^;\%=T&&Dm45tǟ~~߿+'|ٟx/şOԳΆhB%5*sfE-Gv}~{Ͽ_/{0||?}|{܄B|b(V_޺kO|O?w_~ ;zw7vwN [XeFcn_}r}_y+;OO~]P_x/߹r/J6LR+L.ߚήt-}=z]W/x*[I{CN1*BE`8T^o&;ۇַ-uO=t~ʥtϽocb~͐LNLP&:.ߑcnHSbŋOǞ|'?~?~G3η漑#ZÇwn;q=T2{{go>?~7g#}J{JN̐ +r .P +=q3Ttkc{~^~o<ί_xtbJ5 6PcFZ+!XZP8U\>'z_߽/˻}<[n Sk PC:< 4 1 qEt{+K;gNv]wuK/~{^|k'wtu(0`s]:3.>7cL$#bӛ<~zncK&a5 +$WbǵPG$.]aOA.° Jt2U6gp86'B Ra'1_RAre0xPΥq>傫k|!iu|hu3o4d +1:*1t"㿟dtB//R\9~H)4R791۩%-b?,0&3Rь"H(a?rh"N잀ވ: -d*Shu:;KQB^9Gn!Sr+B]ZpEXI:8Yܘ; zmKzAn, +C)(5@X-"3P+CP "X4zymkv~!Aёx"_ltc4F,`L2r\r̿gD{DOlumՕ29Jۘ6֐i54,GDGk->)+0y"Xy%B%}:umlFIczΞ8 ÿ:$#ԃyVZ#&'/;ZTDOV#yɨ3a3@)n6AҁQ׵D.8:G*7y{XurI,IdZyC4b I }XMo-- }02\sj=:̏*KHdY$Vm~yʌ[G5LoЯ +R!;A:j<0$59*_rq &XpVmp!V JP%UWjZ*&[cGTvA2Ԣ3L~NsD{rxRݲ_2+ج͜uN̞QèАnטaXa6!q%61#QهF5_n+IɧB[\H9#}tH_9 I +sPH9&;c\МٗC=Y%!bzgP""7UFv52fO`%+iP'2P-;@s*3C:2Bg M#1C+jHQrcZLpţ*KU\|Bǵ-!D*#g5X<-oTlP`]?| + >3G{P[fl|leJD˗uOjܮAJȹ@Yc I-R%ޝ;a J*lQ3kuo}DFAU&q$1e$5{K! +1q?Oh*G+[L Ocm2<ExdJR<m1-WZxW$C="tP>#-h'άƃh(̯4Flp>:g7y;*S`>@kT&,LSaCsz*r*{N*9#!"hI-֞Ԓ ԝ2hy;: xs$jBXK툚z"t뚝)+* 63=KeTBaTɢ!7:2##xp1%D2$hp-=Բ0U'F:%2'>-XuM:c|d7PQ94L *ҹpx@ٹ`um;2s#w'Dt@lU@ ɴn6cH&ܹQ>" L,t($8FĨ9uЈUKPgݡĨ4 +.5p&:vaOZD5:M级 +I=)#VV{L-شŽ5Ιi x/݋f^x(|}(;97[4yWy4K+YYˇQ_l"z@nאiۢ ‘m̒5Vn(aCkY +RLm╧˷ M4]9{r&9wbY$()ĉ4qS0\jd"gDE\*-uJ@˔Udb0Kjrejh:rb\m`$0Mα-{ܰOi|\A[?C-Q ƞjU}FdPlT"^HL h՛zjbLp(f <B|ēw[&WFʱښRB2G֯%(gQw D;?$lYbQXw- @F5 fm73*URDXh*m1J|sdf0iux-ZVcڽ֖!pV\kDCɴv}2 Q:M{[Z6".n<pHL٥c^'܄bQ?8Z9:bKR2)q1\Zru=5z?g7/dvr×\{zG|ꬉcot.^6RT1"+ZHwepq1E:ǰݩ۞#*՛ ";GR19#`Q~3qF ǰ@1?=WP$Ԧ[ܑUقWٲѓC[_dd;cmn=cjtǰ($rj"XB"ZgڕӋoE)xdtII$+`&w!@j0At )x"1(O16(BjJdat@ F{B*@h=cJ(6gN~9:1r\cۛ[bdwm̠ 79S`PB _ L.\^/GE[T_^ǧ=/2l-E[\e5:inљy5HE:q'4+ksR""*1[ly{r/مцKj'HLCDq{y' g@1mUS*g-.K+X,8"hbr؝X48 6 jkT'0xm\S1 WNk+ϓhO.fۇ%,P2NRX\pLhℍ뎨]>x(sƑeWqC>kGReLⓧN= 21Ԥ':S{55j |u,Ђt‚2eFWBpk'9snbɣf/-H{o"SVs +D`x+d[1geܖRS*GcPgFmk@+jHU'戠/38qDN~έ产 e(ʒLNaaEj+ +/6HOՕV ^;o/.TP8oΗ_pfLj${R ˾dܙ6 7Y[P~ɯ<60|mUd֠5P";(bJ6_?cy2m=<=vJ .+.s;W]yzص%gz~V:HymDC1gdRie+b5W Xqe+oU0 #u3-n2 -x*81{Ėb~Md)bV{ n%21C6ZHChY)$6"gR P(69*pl9-3 +uly/WaBSԢéS|c*ya󋝃?Iƕw;smeD@PB*T@(#A91I$RVmY9m=nw;3g֙3w{f/wg-| j}Sn}V|luJy9P LπJz"nʘn!ܡX(i01iP21_c+b,ʃ ʵSDˣ+sPFSm251IH GF"c:$ X&#DQڈ8'/8#JBf0s 8:P\ٺOox`;>f@@A}v5ifXFXD{6\!8{nP( D\*`L `R&@]Ĭ+;'` 2Q5#RX]PQiC#9v ̞?5<`g{m ]ǥ o^n2fvոSx|*T:<:ҥWYpg7(?W*جKEدGMإs'f +h1|3ojmO (TFH1jDA E8|IY&\zNGt 3S[ J8?z5^q!96\ʰT6M(᫸\yA` _@l SZ,qԶF6&/n`ӓ6ni] :M ֓5/#b<=`?0`g*Mۯƃ)_hi_GFlV4}&fVJ4`rll 5SZal (,3']  +RXݛVo !>9}Go -O}lG +~G x7(+|1ht΀@sɅq_eM*e'.kT|DIl&к( Z[aZ[]FP߬ 4"Putaa):r]$ .%Ss[@U{q|#V,(GV̧? NKGtDoezL;Vތ'P +5 c~7Yn-lo\ܾ3s%}3مԸxy`~SZߌʇ{τ̞9X7Qn.]\Y i˧.<*9"XLp/LWLԁnk"!LJCE@p4~ +8F%}nq̩^3kpfFiDa6̟brDh!A唰`](-'gLn>V7|zƛ[v+cO!V,%5S@"ik1I_58mZNw36v}6K7=:[_ z= +GM_cڒDf.4t.a@ȅSHz$09 9 /0Ni :zdGr\;LJC#pcE(.AaBVn *U\K:IHXqAu |vm+k&{q༝߬CO'X6^{o sTs>5>)y.XRʰCȡ^{Ǡ ZN-qqҥq0fCCK]6JxLJ-PZWАUڒ[x,7*Mw9:U oB]:<`K!C0NC%3c{L83"9ɰ}JG,l%"\D HdzhVŇG2#j%䒅iwڷ\LJV{C4*%_;~br@-LLTNNӝF3Btba,@B ?ͥZ*R&ȩĹ٭ڽcXȢ #6 z>[ +elj:L9[ ٣d +{ ;‡bq96tF.,#@cA./8!Ts+>bQg +.oTpw뱊*tQCcO>Z_sUoқcb+f2f@E6Zɏ뜜k`E +q͘\>$v.-vtyp\Ըޜ d \έ,210nv򒯸†[K2~+1i9=KNy XaXPYe莩oBZx~T ANVWW &by P@Nuvͣb;Az4 ~ ~\չL +IRťD7N?Ԥ0GJq$fB6C +3|>N19\V[vTAmNe.e { nK4$3|MZS,k*).5r%XLn\)] +.!)LСJ y(rP>*uct'Jeq샵Ʒn|{|zBl\Rs[lfMg6Í5&>+M=To/g938\\V)-:ؘ έo|_[RT޸3~'$2G()%M&O﷈jg@ +~ܭv-)PWTZզNd!>"d+קO?(^aCJd<1JyF,bB# 0B==q@q] &>J&+SkA69d6wU`.ѭC0*K 9`hZgpO>Q>1N"L^l-t$P*ԛm\]߹8=A 'I\IBDj#֣E.*roUHujSŜ +sʈrNȰw +MMʌ_ \[ٹ "XSDM-]1x"G *ʌ }& p)I9 E"lgFVS[/\ +v_~E,ΌnX|ƶ'N=3 cJ C\@K뒺0.fwƏ.4`ܠ/ +s0p6t'Zpet1u6Sg\#'p]&.s`<.Uۧ}sTִZ\W?՚>y̛U6\#"&Pe!2)Mj Fw;E@Ы C+a"ɍݻc2V$V.}_%}&LIb#jR`4b^[m"Ͱhs<8YJ1`Lj?3f:3hzm"LjO =fF +CM:1;k 1iJiv\aPQόSRI6>=epJ7O(ʵSm_>pePLH 0 =gL߭Ap(*!46v+Bvk\0c3:SQ5vש +FfbR~Z)-t}ܙ;sgWWH[Y4nɑrsjS㖞>R88he4v3Bsu(B~IB矝ݼGf, JL ͜_KOcj:۟Qݾ$;*%ƳCLtB6ozpt 1 ȗHWggWϷ,>(sO>Cĺ[cau*BACN'"fOk:"ANZ0+)'K?^T9D&lfnKj;t >VĄ}N'ɅG7?-Y*Vii'8TO=ѹ{(RA>3E#,D'"CsU% cbӉfԩ+}6\*diQ2H Zq\xU&T27j:9>@^'o : Mݱ*3b>#FN6nf/cR3ֆJx#m_vADlPzZc @|}1b=#r'2Qy#T}ZkȎnPQbB-mT˛\exܵ.0&= aq+'b +1߈GA +SSő k',}ykx24i_?J ePX5AH !QN{hk{heaae>8qqdGkn/nN4WӵϿÃk_7uBpՀ~~nh8̂KQO-S +,0 y£TbZ@!X."µHs8Z9qr+8Mǂɉs/ +X4654;`bvJ|4L>΅4\l$XΏmۛl.F0\߹1v+rf:R_dtelqV2gc'A‘ԅOtiN.dfJqzoϼ 4O2<.(M?Xoq͈|sA5i@oJˉLTZ+-IWA R8xq֎#*wqB"cZk`5hӰ3V$k?_=wKJy ڸ-_&4Hۨ^ r|pA Mɿ:::*3wo=*\؈N$FwfyᚃI֧N9s^k^fˋ{ ʚ^ykͅ=zf dS9m>29 W4NnFۨK. _ar^ѡDյpm]x hO| ORy? |I0輕 HOHs)V %s7N^}}ny@v6ycKpB\C,c)9>d@ uHX|d}2mv{WRN6W+f"R"s &{ >.oBgp_ZI6q1 ˷Nzշw>ɫ} +Le'_>F GO0h +fONbf7@NAWS3wުLb ,RAC~Ts +hP +8 +Ri6:pzzuܽFր{h LQo %6Kn}swoAabώo^~egWnyTx8Y[>Pʌ9+>nr݈PQČ,Pc->ZV[cKsZfܡ!H.ѡPTS!Ѳ9wd\zkH]JSY9X:[A@!>qHp J2qod~yJWTkag7[[Db5R-o(e7υLLT6]B[]#R&V[#ZWpʱ!7hti-y7׮ 3\&y\ߚB;d,}frʤ6vPaq0QV&|Mzmfa}񢯸`J=×_. sy<.aA(QàM4lJ DPv7 u-t${c|8Lbf=JY!ꃙ8&`.IthH)Ǎ 쵓DsRr:}vd*n8Xɨqsx r66c!;hTYe *z5`>r8yFXl҆mDr6" 9Niؔtw^e|Gz:;=zҎ 7h`f3j,t3q#DxĔ +AtWIo(ZL4 +[Ior}f2nD +,-dlXhH_ݣ-@k=*$b`v:Kr~&h͟9qc˻^?`}ϦhUs{䘜_ܼYm,Q*ZG} DON194dfIԞX?tUo/姷;?ǿ{/}яX +Lj&Tl-ڼRr97*dc&:If3פ쌝'Nr {Dl'̏]ghI3|fHmLO626kJMV9.3 D}M%#,=^'6>:&1_(ґ*rRZ Lh؇5Rbs +*1oc|&!&(5]Ԓ.6GTq~c:WpsۉR;d[3]ʩl^36vL0҃BxsD"r(䴔tt4&Fh!6FG ,| v#sVvcqBU0<`42\(7@}6^)9^Pa u`bd2R)9ŢZ(*z'z%1; `hBil#'nqdyZgn>{3/{{cgu_k,l.ߞܸ;x Vƛ^nĕwp Y<׶bѓp] DTZ&O=\.7zlz&/ Yњ=q8p+U#@}e"LleeDHbr"&އk\bW㕥k$]\>Z\^BJK~4`A`&i:RΞݺ^-%3,6 + q06|@th [!lƌouPB#.2$IaޜPT8ũ@!W[ %R F`)qƗp]3X.i#&$Jssn׮& *8}LDăin` xȄ _N;5$Oy:ts W6*.VVjrBjl'T..N^."T0(}棗Y>WZJ(.J[~vw nGŋ`m|[m,$FTӁh88|~SeK™L}| +YKX`FmBveypXn7mmQ)<4Kn6ԞX[޺M2f*(%(ux0ǸA LRB{"j3!;*3$'Lݥqw tSKP*X}ڗ2Zgu ~'>L!!iLNџC># IIelr)Kt(dQdI:Z'q+P[ 7p + tȆSO$:ʄ-FadaSnd@q܀x]L +BPc:+A Heq&ǎT  1 NPīwhdL[a/ L؂L.)ޠI8 (0V>.Oc:7!\9kԍ3 G LG]I_2)+v1/V>;<,Lkܬ-\Cw0-Y1 fBQJ4Q> o PAC@8D`P.)B|yh(T}[pO3֎YppR``u N"d\e9uo[m/סzh@zXĸolIheS|t +w@ԥXԕRܪi^`qqbb: {dbV"n;KBQFOͨ{2v}:C x,֐N\`v$$FJS|*bƎ*2?uT{zޭC{ ؀U \OwPo +քhӗnj .qɊ<@xd*=>7B$@9Ɍ<Ǻ5OmA4Ir(aD'5NƪdE 1ʅS 1\NdƕN3F /=ڌi4i@`H +tuMIb(zY`v +jLuWk1D7U & @՟MTXD0>jj[`>Ucp(ouCe-,W:PÅ 0FB[KT`Ȅ^ku{l 游c|nJOL\;}&A7V;qpRVWcl@mt8z m.Vga/A48 78X:pDb:rگX"FE8)%*n2=^G=)i`_鋍Z\>zQ#>Փ zP!|8XH o DI`tGO>uLud0F7w.RB@B]r ,EO_{tM^˰=P]jHmU +`2F *<\ȻD0s%II Z b PV1An?7{XW;3 WCB:|\eA$LL!\B+0>dPu+#5@%RZP +&耵D"J,0hD`x40  &%U dace_jDAHg,0LJI4!C1b.Lta5NfʠoqCm +ʀ`BVR64tG/R!!hl]^lE;c>xdAƽy#p4s*jxUiumzF0q"4Pm@ ذ12bE({j!џwcAGL6Nkƻl:w 0N$ +|Fn/gqcr8)74ʋf'䂡UZL`sfӂW1&])&1"؋>RJ2MeK c7ܩ vi*s'<(AI +ѨZ4 %bA9sjnDDog'ݡ@{E/$ btWm5N|%x* 7؈c}֧:HN JRmttf+66w1HbELAL(]Cy6I7C ~Q7NJI'`z}>] 3sY8Yorx 6ڝl[tVQ|hݘ)\:3|a{ܜ)Y`xǣ{`.HN P!YȒ$Z,Q hHQ)P0BtGБǴ]n;Gzz\g" $s0B0)Iq (#:ҥԻV&ac&óJ#KCZpp?qjc+z4z6#BǀnN: 8c.&E~̏g/[{G7?|W?ynT*F)}"܊g&kwNqͿw_9|?O {֗>=w6T1es^/, WW>h/~~~omw~~pncR}O`"SECKS''{nl~W\?۟,$OF$'ON_߽ō|\=7q2LGo}G'=W9PKb0d$UEr{ ㅏϼuvy(dX%Șh-4$ P:,qhkT0뿾|ڿ?:|;Td֗-!LȎp+iUTZ)j/2l0ޙ͍rЛb(:h?ҥv{(E]ɠ/j"S)JЎ{0G(owqvTڠguVRo@ˈDqzbejx+Օfo*Zj|Q-A:Ы̰-hvڃ4_,\e/)\{R@y)70 ^N 1$s,ʕR|X+XH!FGYZH,R\DD>)c5&PdI}!YN!xcb߹0A7ƁB&Wj̴GNbr o:9wFZ`Ip!*P^m:y]Ibݗ$pt&kj^9,xBtaw7>և\HdUj@*Osq P2 -\%d?3LHXJPUs"] $k>Q:cTڠO"LXM,I N~g=!r)~'.4kϚerN$,a *X[~Kr(;/(JB^ssh|#q#O1_8^B3jsxǫ_ʈrUOʌN rG]~Rl\}I+(oF単WlYJq"gʘNW\Qk=Zpf_.Ԙ*  #l9B]# T Fj3T:%E^nx!1kCBc3q"7c[q%6kN)!f3").lV[33Cd&pAA37ck~:Lf>@Ձ+$ aj}vc=1%)i-6>-:Ïۤ: ՞#. }ƜJ( \8Yw]y*O\Ł)О=%F̦y4[AǷn2wspqNx9"|jBЅڛq}8C,!YيC\e++ۮןLaJ J[Qeѽtɍ?kQI_w_ +s*)Xta9|$5X I xn}oS~fs`p&6aLjqӑblzQ !Ff)aNYsHimgv!.WG5eWܧ2%ntqy!L{%id;{)cZa-Z<>,+I>r?^Lf {Y{Ic{QyTf܃1~;1ѻz˜2o٩ѻ?k:1/a %:z Z/,uWm/%oRM" StaNk!SD!4"BJ.{K-{@78;nDG=6K_Մ>)5Sq-Vt3kA MљVz-#B+VgcR#]<QX ۈhcؕQU]O"^} %D\I3ޔs/56'U8sA"N234G>bT tP,2Mudf9!oavR_~jM_Ԏ41}OYX&X<|i߅[.P*k7zWQcÆ9b:~0zfjlo0kٝ_v|ee-oN'?wQVHS:*_!iښ0*q{Dv29~{dv|3@9ҼO7qe=T)URÏ~\[)~KqRHYܫYs?B9Y84ꉏ)`TCWbHlĔALQ*f0H֐p8*ڸֽJ;Tg^J)VP%v~*Ȗ̀>9Rȱ u";Imz2gL1NDZzTtUB3x[ \~ߕ6JfZ׈:An+9Se~sJ7$TvW(`;$biJ +,ႇ*Sa]iaP(FJJàX.nЅCš͓)_B3= [+mF>~R=r-S=zVro[?0/Uw G }O%Oc@妄1"1i+yךruu1xL`QzoO<~-& ?yQ47M}b[L=q$_ .n|ulf1L R򷥃gኴsӛ!i;!b͝rtbM|,.~:ƗN7tn'rBH^`-sJqoˤTs%u+$ǩQ$=r$V9Zi~sZ|Jj?s'nj7NK%٩>x?_Y\ +7S6fN~{ɷ|ԑZ{rp=v3AaN\rDubjW3eɛm$VhB/t8F,0W (b|-g_>V۳KSs0=*ᅥYQIKXb,60= ~Li&fb:a'//;V@Ǩn23G|͍.8{[t/tk\˿q=~U?{]q(V#B<݈M?_h-[¬P[3޻1 ! Gwr=m?L2}7>4W'~uw`U\t>|&/Ta$hz~ytVE{wR8ctB|<ߖfoU]d>n˝|?NAs@,n,GstZqu'7z9::HWxkn}"7#흘f;y׿g0WWjJ%2 uLUު[~ɑҺ0K!98~0kx .bv@_|=7]+^Z^7N|O3g\ҪN<"r1}O}t%"޷oHoOH+'j:{8zI[^篢R0{V cjiqOTiv]g[4;4J'~wO ʱ9x2/; +j{Rϲiit~v\|Ǘ vbQ;Im*T/1c270E|W/Q*w8&ʩ}8{WcͿ;[dMN~x(̽{H"Rnu3rdK738ͪ8c\oͣ;sx za)zqn\yP+t<ASZmu%W>+'`t~e4_ϯrşߗ`]p/lLuUѻ{e(OʵoWn*ϗ*`ԸSbkVX=dh]!pɋ-[>6@Sڔ6g5wŕQ>,3J,{np3\*GAR\ȍZ&|$k\>g.=8|:y(Ag5~^3qap-fbH=SGO!&~#5CB<y~ԏys{ftлţw/{O7y+)|7O1}H?c+ uk|[v)_~dgW0rKd}čoBEaT' gO_~Q)sY{N+ByopﻸLl̞{\ C^{j#{sk]x7OrqkTfҕ} XN{_]m. av\{`Yޞ ϾykscwtO)1qv, cr_Kk=K+a3&7 J=h.&tXᶓamH ̅uqsq%".[|IF * wh  eZ6j$ۿI/㙁ѽOQp({I77Qݗ5Ĕz{ǿ=cx~ + H\+Qs;v_f?2YzLc6ty0Osyo3ku5%f{~'o,O97 yLeξ+Quh÷->ucr^~j֏;-+1u׮׿9}߷.룇/lbD0fͣ7NI[Ä VkM"36gg/~uldvN)`ƈ42Y˓|nL.4@RVϨ"R\d/3^܆`v.B}=; +!^|v$N4Gw &:3bvi6A^jaO6cfY';R{W w%2dn%9WaNft#b3e~@l! %917zFZm]c/cى7W;Ƴ1->TL?BY՝z-$_-}< +ՈPFgVпH7S&W<*diƐergbBV\x]p[vw^{5}-udu;Gj駊*ggF6m@͔i>t8aN*%zY?'Ԯ/NRc܍HS7{ó閟kV*qS]O +,bBξOHXf5 xvuJjrҫƍ̘f/OrMm80WVdRR0!҆ <r0<e)\;xð +Dfdt{?c0 JкЋ[peTiXP S`jA~u[=x+XlՄ +܅ rV%FWĴE y.hk=#GDF{^j9xHu Lh$_@a\VLl(C677OQk+lй8^Y 9etyUnMVBvC|/TSi@gAZ1L=~eBn `c2bCg.`}s*Uz^Ȥ=pո{/݄sPK";r{ D$tB0Fݐ3P.NcfZK>G܁X?G:Zӓ>JxV^v}G"mq(ZezfRy,K=:wqgOb3EΞ̟}cX_مd G.7si{FeZAJ*C|v _9?n?au033 3pV.ƥ.mTG<]}/loaVoIHhDӫ!^)Lqm' @zfVqyܿct6~ w;'4gʌ]ڏ(vFrzPvB_˸QK{!fكF"rT($pmڑ^;t8}!_/ BE-L;O1so`&>^g%"R=Ӹx- rxf%:;誟cDSSVXᅈء'jj>ʕ/0}`aG +J 2㭾Z=64%s0MBn׆ckrw/m.o o<뵣o{1(Ara& 1J>݈:'amgMU0߰ԋ*C$3 +8ZSZ?]:O_Uj|ە܋ g2'Atf'&PeI| (_<.U݋,i~JĬ}e2| +0x,}QF^b;E=|9_~6/'{W_ΔW6cJ`WS@.l %?HiڎATyZ}—ʖJxv؈CbRjGBl{v.5(4Tޙ2BV= 1 +9tnb+ IHdnyBd;PH1#4Н1+j ]>vaވhXމAjhzWRnǃ螸"Kѕ}܊qjEm!~ҝrf>>W:ٌ+qF=\&YrGZUeV\ *ouX/N[&qv#21ގ9Z"%)mO#l@僷n@lx -r e +JsvAd}[qu+&"~ThHRJ=J{q> +pF0,Lv)m)7!(3avbr+eXf3.n{B%զne7 қ[v*;K1&r^ |3څh;k!馓㥥7yͤZ@2J[b1:})SNjb|;0ZWd-sK^U,݇fIBV\U!f@]:Mw@"VP\8V׼OV7֓Qc*^}BeH5u^>Ww˵؈r5Bu`{{}ujX a֊>"3r0Ou6~%I9ژލ&;\|Sœ;!D" ұ_gw-Aj /܁[ [壪 ?#BܛRS.fzb1KE[/QE,݉ͰtPZ\l!vqm_ q$P?܏1ꏦ0e|h{Y0aiSPl< ͸vۃC.f᪏YPK-?n(&+!q5@\))y;U08 ~M@Dy-n"\QpyǑ"ĆV>1ZR<ԟԢxQVi\gFXoKe&>qBOvƔxd-b4ɟl᫉l$u^;yk3faXdO¹3"ڈ1j{f? pa òCgvs$PB-iӓRC%Zr]<@隇aa27,` !ìø<-5LNHTT>sI-v4weRq{jjpf* +B}%"/&CL=TRP +y FuCE)f 4%Q- t"!a]qrӔT s:k~~E!5tb2Xz*ָčAH}Ti=] +`)nʒڈd6.Ih9AvRu+Hz7t1R\n!j"f8w%3#ȏwjATsFe' f䇟-o2_6z8 1d92]&y{[ɅN!W-PqeP>׽#HR))~eep̓;A?"+~!%4sӋcR߁,bW7|\M8m OUI,]>`#\m`TZ }Lƥbygg\_~W]IoqUt2bnN[s~k-_-n81v@Am鮟̻ D7Z$YLތoz0,]ߌq#kQ}-fjJ +k2It=nnl=*@ +z 9keT0jLr,n+$ZX9KW(S( JZ^ 0.0+N_3i/(:b|"=J=H LK.|+*"A7s&]x7ZR|Qpf aK8_TZ:W| D;rT gϖx.rD٪;|HP@]]+ь3:²wq[֙4n(tn;&_ox/S`,Ͽ>YO~lՋθEšX6B塪2U \ɥd.J+H* 'M(˓R\"[ygּ̱23Tv|ّ3ػ>6cr7&7gRpY>dt0Wv+{RzɥK&wi;XfVB'TZ6,*viĬNtOxЀ=H(M~4O)=jo%M'^XG>F/%v>(ˁ`ReDhǁaj$vꖇGS Sv& XQkqm*v QRrW,iL #L$?U Y9dtϸbrJj`J"[5tR[Zi_<or?abB#B +5׶b +|Dg|nB.bY/6c`FxLy sUގJqkyJHcRډNl-$*wFfQL,odjoĔ;ANۛ1m;eLz- n|?Z IJhyjXLCFa.!B7n9>9!t] ۫M +endstream endobj 60 0 obj <>stream +HWY~_T0Z 8BN'ē|${{nU/%/vw_߲Ys8}{CLRݟLYb +x<|ǿ_\aw9Jx㉋ƱV#fr]NXn"_]L9pU#%r +D}N]_vqWQ[@`m| dha bqJK5$wa  yҟوlvri*-oe0䞃9,"7\®k)ƓoT?蒄u>FX?KgyPlTNRl@\i6&_¾{wH<-@̉8Gf{RZ|=<΢y (Wt=h(Z˜aZK䳽}N;كFj^sZ`O~kh U g}(; g e?7EFi&- $tfF$55%\nqkR#Q/qCȁN-8Hڶ"\YNJJ|!'W`1D׀OMrX8S B"2t8Ս ggv +rijD@H<"rK8[nE]a=ircLA[hOi,12$yTrwxJQOatc_E#SQ$3akK.h"lfKp"vl;s֖?h壿Mii$K?e{aj5%Xwry"eoT\)gBxe +7u@F( L"EM1g8۹{H<ۨԛ.Zeb +;m: PH徆 "ɤg E| HFuH²!f ,ҋPd#kڜgg@g9MЬTXk +{^QՁf܍i͎$ 0;O%UaO%ϤB>M*₦{N{Ozhj+ <1WȃND-t4x]Yll$v?7>|*f ++(CаŻm;Ѭ&6e^qR:(8Ѽu᭄eUR$܇0΀~ߩ:_(hvەWp곶!kP k:VQkQH(Ӌ tOi3(MXModOI3Aͻ7hl3#WNtswVCH1dw~u{QR8O7>1{F yeڟ)4ܬ ׃h)a (5hç`Y3Gs1'0;" +SWrBJ+9} +!--~1!Iq}P]}H"`ˍkFWT6,P=GK,vOdj񲳒3*(; X# `eI1/!1RQx._ g&scL8^6b@:zcv\v@VHbٶ9삡y+>Y's:%6HL(ȱ҇YM+w@O0ntO RL&Xi<.a`i3B<'ak?*a_Gl Gf ۋ!{HDXX(A~50 M ' րm@Dh]'?3EJs1@p0leC\;@jXTQ` o[t)>/9Z%ocbOL$:NXyyS4W% +qɋ¡Kx1P!.5 ̨F1!&RډQsw0/SrFUuGV &o +t</ߩ /zEjZ7;q&(e6=wt2e {5(L1ɏýdD@콲|$mMi;{;G";wpRl>BJWks|b"bx8<wv`ȿ~Cg9{:d2$*0 +Onrqk5(N KBz~]ˢ_^Vܽ %'2+KoĄQ)W0ʸ :7-`lô %h՟rB{zK]H/.7hX+TSקN/|̈́ߊÀE+g\ķ[#~wB$|_S +endstream endobj 61 0 obj <> endobj 62 0 obj <>stream +8;Z]!0p][!&;DVm]go;IT)EQg/Q,d61)rV"DiuI%Un6nR7PI(mJP=)M/mfYQ-B\+: +(`5O92`1.RTcPlI[6.&2X/=]V@joGG;l\Q@((ESNEau,LO1^LplmjEV#jO#:0/T:L +P^pQ(5d:tF?7C`3c`3[R@,-Oi?5\Ui"pT!.%>R%1kGa*Js/YnXn&'f"@HCQ1K>6#_ +;2f":p\n3`::GPnd_]P=4mb,<=g^#3qe]1DY*eCrLrm`"Ll"^MXHu?mZ]irl>jW*3 +\*m9+#&:rW7aIDd-&^!'43sdSS#9u'hT_ik=B,o[q\>o%<_eAXiXXA9#&]aS1S=VK +ZJLdi(i]Ur@g_VP:/#S!$Tpo2*U2KCdW8.5DJ"YKcnTf8+8tLL(UZJekIX5_'ngE' +@N9!7'?$HV\3E:!M.#`?`FQ.q9$+g5$*?@a]C_GM7gcl"9;t`9'FKP:ZXHf/ifZ?M +*gi0M>XIbQ4gdsUkAM[jCsTH!b7ppTj$u`j7;@Pg9%bbnK[#*WGki3WIftk!~> +endstream endobj 14 0 obj <> endobj 110 0 obj [112 0 R] endobj 111 0 obj <>stream +H|n]E;40y N>@;bِ}Ƚn'@HaqWY_>\.><^zx˝uOo7/?]ݻ׏ן|}~۷]\_.py~ZϏ_{-㗵3Ė<}}~t}}|zά˻~/3naOO||{r>ܽ ƸEAM!rvQ2&E䍉Y=3#3=cǺ){]iYSج tr^ۃ<MPE'՜\ٴclX/@]fZfAS_E8A z/+Mt! +eֺE-STF%Ƽ|ӍCTh(7EȋMgKP26ݪx'J4RXYWUE52 Zm>l +mrjlMɉ~ٷN1aiL8YP394 +[#Ev4rhn!033w|Q]QE)ye\ ++o;n +Nh#ȉ7\Jt*ߥ)JHi!'€ȣ0d +ҨR98yQuQΠ.rpCg8Th\#*dGͨrdE{$U[YvIW#݁w[p!rKz(7Qn{[EՊ\[PU Uw8SV"V2EшGS1BXD9 (;ȷ@l"VE(P6:E/dzRffb}}\L7"Sf]c]T i*rdf 3Sed$9M#"m46iU@ۈdm]NUCIGr8Kw+ + #k#fh{*Oh]hQ:s`]fԜ8D>DBBY DH,D8Gt7B۬L,NPE/*VmTϳ߉xtkt?MSNB7cIܡE523&Φ*(W~Ƥt/(ǴPTSjzQЄȗMi uu]'z{"o,JQGR53aE^d7m|mn:!i}^픖"oeg`j)c#|Oʺ$e2Q\dIT=cQTT(Q YoVoT(CG MX`L/Xn/ȋ\z PZoSKf&wmV}^3Jvݯ+_WOTbmscgzݖwT6udw(gCMl<{YL fr/,Ć1zbV&D%U@&^6ZlE:FdR - UѲYI ʓڢ< StI(YQ5n]jbrV)*ChYe(|ʀtEjxcNY,CfR1_ufqt:RuY}oHEvVΩQ+; +"ZTyQqD/4N74KuS$Q. +JPh^9YMMtÊ +WFtzաTk֦H%Pdt#*Nњ٘Y~<~C:и=44&U 4=5Q3N]*ʅ+sשׂAw; ;z]U2cjFQgBW6xuk]c hԷ*'/>ggLbՙ΋YZMޮ~z&w˷zEr%: +&{ԡx0+쥱H G0.g^I2S2**.򶨧}zUyin^E(e()UQ)POEyQwIFTf.> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <>stream +HV;n1}P8#pҸ4A +`20T\T# W V+A=@{!)l?<ˇ8l!nfJ/^ +"D+vR"e"H#Y%ygDqʇfuo ?$\NcTqzǩWHzp )9{n"n}|?3'S&}qekVLwe]|kBՑEKq $9}lq7N84ҚxlBZ2~b(/b&X{DAg-T.$lK"F3`O9?afXҁ )xi7Iڂ +h7'ŵWO0nݾx0kg?!l7j[2Nu7|$e ?*(m2. +vK}?RYﻵ7L=,1) +09a +endstream endobj 116 0 obj <>stream +H\gXiߐC7|$ t 4=B7tQa + 2"FQ|h^k羮s~A@PVA 2M& +KDv XE{Ԣfũ'}v֯h7bv߱A48hL^7:{%J8*.mFa"$CQP, (,T)K _pJ!d+ ).P@ +/pdybH(Vn|y=H[YP" ,0fXe,HN p@t X`%A Aa D1@ *@H)ZTL&Ӆa1C(^__oj7@F%dQ!?(BPIl(j1h}p4rtwr; ӄW|?1O n&6;ɈdN!ْI~I2Lٰp +,2 +^ kpW7'_d9K."&wD|v5u-stwmtśzz~ai4 F +hZz/ôa-z<]FOg{/ FC(a261IƟvw ӆc* UbYYKl+=;-e+9V +N=}#(l^? dxJZ'_}VPN]/1X;>xA 2a0GXR24?Ho<,-:;<&|$|>"b.R-Kd-Z."Q(ZT/..^}1'P"V3ŝOJf%sq*Fb+$ U’p%`I$^*QJ[ҮT\B6#{/,G˵r?y%+fe~Ȓeefd:5:[?{R9|\A~CV^TohdF)AxPt& +"i]КGנ/b1L ++fFL[}PF ]s]nG=J= Y}G &  N `|TZ&&*SCS_'f*$^pgKy+O۬ձ=cek;  +89؄6/qrrrvvn''\:\N]JܮW/3GUzfqqq <}^߀_!^SWɫҭʪ&Y׆[WUcY󡶠]]o~qpc&M7+67/TPk|eKSN--~hik]x֎A;LzvwjilSށ|Wϩ˨bw/C]g`Kojݡwy$yh1T<4wt~?#|ʓ~tG##O7יmwu>gxn|܅ K.'ؗؗ]ʽt}Fč7ފt;ړvMLӧe߷_tԇI/="<{S=ix +=xOs 􋲗 -Y_X:g 5VO6u +H +"A'yACQī@5v5[e a#6W¥ ~WS5_vqR{i`ud u\-w{PּܚM;6] l7auQ +ȥT0q`/E4E( 0@#j`ZD#@!0 (O-"bFh46徳Z=mZy^{߷7asLB\ùBf͆Pe`CaXhMcv:}N70*?fvRDaV% 9y ؃OJ'*t4!%sXd +Ia3k0ՑJ#{n1 %*Y"W{C/GG!y)hf*svQru%E>_*= C4X;Vt h$9Si2 M,x}4f d{!p(gᜀh9Fiʧ1lT=mðͅ7Zn.'xYjY* B 0paݭus a0mp&hYwJ+>zfv31wj\GpDC*ox5]9ReLJ(R?Ї3,53}Wu/RHV,{h,(൯3<Iwy= PsbIZ@ޟKᚩ2ѓ80snD!|dU$L 4v.nĢyQ#X:II1mbvޢ?ԇ pxXpMЅ#K5 ;F< +p] %-GJDx7.]hM9Q x+H5-bP ,-MzƔ5"&+b!PgpxS +zW~h`,cBwt + ~e:pd!63B6SitiHcJX̒Ҙ,kgh85Jzf=u};w1،- hf"j +Ԡ(F|;Q> | KB%`A?Vgx]Ǧzģ ia3ayQ[{pK2MG~[4d p#HZ.&|.TR@)>E[NaO`hnYWfM04G+8gw<{0Z,iOqZλ/aR-!7 D'KDL!CM(GhɤxC&A7WoI'*KSH"Wݩ¦e/YZzmCO_9EǸ'=G m8|9 "apts{REaЎs{;Ύ- + tLEI2s;тz; Wyyd9rV9L|6opk{7I/nP  )c"ǯ7~$p![(,:@$f`o ?U ৗYhIx,B[{I'wPU=֭C'zd(Jډ5صuސHgk?q~c k'+9$9~KYWrT+)p'R9yR[>7${<7`,WL륕l8tӚ!s/RЁ`wWUW4+y&hJ:/CdpHyE{ S J.kw/?yex^b;V7JY:jӤ?`MPX?拴1o_F$ZSL@:N?+^rp^!]RiTka[yb`#XwtmI?;5qXÖw2d0{pwmh jTƅfs׊ܼ|;y [="7TCf!:aa ookTSW[US\**"CQ 2|? e$A|FCy "Q /R.8XC[EMk}Z}5'/q>{s 08Ւˑf)ƸyɲqQ>l%j2 ^&E1'`Ê@n DLMXHćKen*FAqƐdD2~E,M[c<"h> v;gn*ldg;*()R%RS҂O-skDD|qt|Sk?R?h殘;хu S^Ao~3P7L8Ær"BkE KIb_aP/)ƙ$vz?kژ# ܃C:B$F:g0)iu>0ZC,;_MVm_I3#[t]¥ Yѓ_Hʠ9qk*շdMK筙 d/XʝJcd,ztIpQRRv} #aO4b?2'F,t8۬V6n⬎q5Iq%gԒr +RiK|AR1܋H¿:ƫp< ?/sf?K7IKm"}_xqnF 0XcL[VuDJI9]e7yJP?B%DNc= !JMRYQ-%sF&qhB=$ +lx8,N֏0`wZ&n/s˅KA /wGbc?k9|Tf`ctѪK3Q= P TEc]([aFً8| *0 ++P&|Rh*~˜ty(3e3"%_ 5rs CNjaՍ6v>$1huܤxYZF;REn{$S Q/c.P/8߰p a:eƷLs{S{C_B.mTxK?tAg SxW]/`4zBYT{VA=8P -43OFi民tFZfow*5coadcNRZZxmRl"{879Zmn`TT+wf3e GjʖZ%PU,E]L꽚u)PU\{`zw-vzJ+):{ۤ@!t(cHp@"95ݵn#yx6V9b'uIC4Kw=y٧p;חmޙ"~}?RkG;݁2#|\O@"v!yf Cj1V@biV0HNEwdAp\O,+$cE!D+ugÅ g/Ft\†NNr!^5+VkrX;q.q&AoT|X_@J#UX$(H$@&A R +Zk+jiw>{1Z_u0BWoxꌙYӒcqxW%E.J+Ӯ>xdzV2L(#t雎>8K}[ݚ^V&ѿm[ 0 |X"Ep]Le'?b32>61"ω\}ȕS؃GU*B .R Sh.h/j'eRubT]™K,+-ނ Y282qkC$Whqqof2NS'˧/Qfϝ7IEDM}9ѺW.FJ]_Geo`8T&v⪞mtn{q1ZSĊ',/-ËI<9#/R92&ȁlDXï/.]\Tec#tܲߥ}Tsj6aslW~' Vd;2PL>y/C",_&,`D؄H*>GpFWa<3WN76*NrJ9}l3_-n6 ]R7Q-A Sr  uh|sKQZ?(XiS|p$ʋ/߯`{y^pOam%]C]M\E*feL*pܫ9iֳl+~7cE7lh>Jq*ҝGUt) +*"B$pHއ #Yl wlJ,RnewSOGljR~AmAו8٤uuW6 +c@^9uGR_WBdr-[5) fs+"t+9,DOd7 uLn]&c֋7+T}) |gROd +?oT߬fCGXhrIh\FɊ#ug %+qe_r߄) e1Ұպr;| ˂P*յrLG@ξ𱓰B &H0ˎU_ީ.zs۶Х̥tIU㵁bX/[}=qt}Y˅[X?ZܕQ Ma>Pkl5={)Rfaj7f`LqlNz'&(b8"@ЎrF v;QJu'~BnϔkYC&opdQ14FnS4 6Fߙr)n[E +'c]rCRvkMn1Ex_p,# Pik\UWÃ>]"i!'V>56 lW,(01q4 +uW5cSRqi99g\.@QYaDEhFUKyay BCq%03 ª(aQ񱈠B#*hkY\6ۓVݪ>]u*O9ݡ,h~8"d,,ߍ*qfJ%&΂0j dw.׊=lC끖ꖌ~ gw,xKwcMW6%mb -;s~$E%Wh͉A0DpB\@y+o8a2r=ّmD{Z!~'&s(v4V*bq_6_N5{aރ7Os.sc $6a`b;&:TH~q?J'o8[%wpO0lB%}*\dv< &l;FTY +MCf˵{e Z35-[3 У9|'l&8(GVQKVByplXA" ǒƚ6*|,/޽ۧ($]^̤m^\m7 G HK+{hS+>/ $fO-M[Y+=_b)Zm8S/o[]zL .|IN ô%l5z*$=(KCXU]1 ~K+!6VVmXxEP f^p)K!&-6B[k!Y`=gl{4mWe Քޮ)k$*Ln--,-RWwE(3O'WIssfZZ)Ѫ K 4Afa4lGwKW !QN. +~I +#8`sǨ7-YV Z:ćЂ؟ 'T#Zmq6-ӔWȴ/3=35Q +HNN$EbJ.Lx&%.݌AC +`2| \_G' 9:[0'srMGj֐V߸Poaf<`8y1K:_ǵ8N1\'PWCμG\M MfD<r<4tC9N ($`:.o>3|@Q׼Bt2TQ )akSO`1_#8.OgVP /*Š y'̼?!K92Kn/0]*tr ˜xZC{VXa VjY [tE[j۲8ǖ." z6= 7]iȯDzNhr?ˍT,ڴ#aW$KfU)Ƣ!JˑG\r#& !W =Y6нHX?fM塚ds"z X>/%Jދeq̼Ou5)4SeLC96}i]Vs1k&gPP08^J HZ{Fto_@p3pl/ a m'3AD/R{/!hdp.y) +Peʋ +w;4Z.lWU ,A"%dp" MJPJio'~˄ʹ75eu\YKJ&LD mɭũyi{U1zaQ!q+xv:@R+-%|c]d] ۙ}.Tq.t#ܸ}3H`e\^} G8assʖZӓ$.BC̫'ęlunAczV + 6ȲK I@001#R=]Uz۳=kWNNv =͜oy<>ĭCElF1m-(ʍ>qPќsy50xo~ƏM&x3eS*$ +`STFXkv%g}ou nV*1ɋC|kA̬i}zfK[y'ӫzӁȺ/\ǝ_:Xy?16ڜWK8 Gm-ycU>4&%rr|(3\ITA3!0)Zf4/&aZi5g_x`ƶlŬ3)o螗Bݡvyr"`>+jbW>TR}C! ʉ0sZ[/ݟ7TS,y;V~ZL(` N%J a7Vyuu*lF~N( ʵF>?wVz:\H\65hDPBWY,e#.X#fQ4 +r-sjua~/XZ?Tx[ښ:>6Sɺ]8kʉi[깫K+C;EĤ iE%\=Zl6\/I sWD]%AKve3vki8^J{=휣j `pĢDVMD` Q՝5O򅈳J4]x)ȀS ,$!}?*s1Ͷ@01y1l<:z@ +fۖhĸuE)V,ulw>s ;lJVf^a/\=͊[_=`gb΂̢c + )zvD"nT0$5ueG+L:_~b$ +Nܽ Qsk %?2a8ayXhl.rg^pkP9,sfCߓ;I$Pb- +[0_dofdL':*<9;Xp71bkЈ폖6m*%<CAQGa"Ìu7. ;rtT`zxX!h)/.k8e +il 9#\J"jw\9$+XgjڳkLq WW^ZY F9=d@RSV2Q{d,s4PR40^4''(h/~KJЂ6轅֜_"݄T2O+M,O`덣.T:aYTE*1 fB\ me1 }8VC6nReŨkZ6UN4)R/-qTB;zY\~KbbiEb>j*BKc +].2Ľ?XשcbF; cDCڙ1WXtɯ I\6m׍P0avAޡ&'SS3T4#WLU*GpPs,ķ B3۸{K|V7ԡu#6GbAhzߌ+u@m*p +qB# "Y&'&m.On~'h1g.U/H^)?GVgh,m;p*BzZFi#ZS"o@;BlyL{ OopcklKHxŭ]Ň#ņ1?AFΥIMN˽:}'Im0.8SceRs 4LQ}2Z !r4B&)`H/`UC!phq]]V~Qr݀GNps;nzV$oc Md3l4T Su/D7[iKN^`&]eny+{sLF>L frq_,M; f`Reը7$R&4 ?p0M؋M +e?§ 3u>ȥP})} O1f+Ī4u/;:Jy>䤯<8k24CgA^V*ƹGchV2~EO` +xR +cm@E!v)_#q*ٓd8p> }`yKrN{'*dʆ/2,+ BԳQ kup8#k_=LԗЖiUNƹ(ǹ4޼pz ׺riORuIT8(ϋ(wJI#eyiXL~q fc5SwTbSyC AӵZ2g8),`$6o+5)j,"`V立OM'XJQg2/0O婆6x#Ӳe-C5rHD&Lt \4(*Lg`@^QHQTAF楣tJ(.hݜ|OUtuW׭߽]# #1~L&o`1x +&KĠ?@y!>= Vq% y5@JqvK8%w:IA>9S>Oq Nq3:5a0UC!>0Rh`l[NUFyȔi7E&'Z{ 6z%R2'>k:Z:&(G/ta߆cUeI} s CXj`X 0 +8 +'4hR8:ǝuEYi^#Z@5*#|'j_|_PFp#6*6.Nps8OT!TKm,)K776lP\I(LLew](00}Gcr&QIn(qF+}?eWj1/Jk*'WG옢t6VҥRl&(3+t6XmR==jtv>RT04M-`}Ct 9pWF#Di {e 1ݕ'_hN:$%dݶN$hp>E_fѪb۵헻r֞\ىf4d\{`6e+kE={" S/ . +.^T"3eWh-~7UtCCHj.ܘ0tg!M=uTP5vdpra $U#zU}P䭩߂jeSDf[\ _%8GeDe~}8E|䄹]=YeD4A'DS҇Ai'L#ykrVe%8Q=jWl~ߪC#3:ҫ .62rvy$̚μNJ>#m4=?5(# ;mFU*Ev}%" 8 /ѡDF`Qe4fܤ,IvԹ\ꮮ|}UܙՅ\'tW&3݋O- (Õ֖;#ʺy3wp85ufU hq1*KU5'+-yConpUT2 %zɟ@Z Qͩa %>Z7)`:\݄|w\_?MM'mqUr]Wyk ]Ta7)OݲC-2"VTsY~6>h 6fEW62J•U癑%iJ +QM=<2FyiS+`S+n~t7#zi( ߊS3'~s~˂jZyxw?-HJpw9 +xV< ܜ`b$HfL 7hյ{- w^5ID +*tIW+NNfkG>5:$@D"PFNӥ?B%BU'兜M!S[ΎvA:JG + +#59rJrJɑGXRh l$J>U;=c#@,%{GTBR+p !ՈƩBsIsdYMm()kT8* al'a1 :&:p/Mwɻ2Oc11m ,:^G:DU"H#ݯb"q1CI2%2b))((˼9!A ɜA/g( Zj0vήS" hGiP>b + %+X-\sͣCr?boo/.8]҉:IP@";0菸17j8؂v]{C}הɿѧenlҏ8B30 k +`o j$jj f:8o&i 2o\>GUr^=2XK[k[S[z=e-:B-_W/vf74ƖcCLkzރ;S{xpm{ !7z#`0|Т7RhJp; l!P.ڒZGaE \q˓'Y<+cE{O]a do=+; +vfC2jaW Y_W X2˭[{7}3S&|yKvǵ`7lTba qjmƙkx.iےUӶK)ZiGjl6j[û:x'YhqԒ`>b#b +W9^P7ZΟ+n`)8ѪW6pl0~';W5f簾F'c 10˟|l ¼td+8<`ٶdS7?7$%#be;W1qqB 3^@SFNU))B}dϧz&8)7I1]w!5&qm)ގKG|{~?j#.hNd^[YR]j*ɪ >>"nL:;O  `U6VDuG;L%m1 JNX oAd Ggx, ZNd2U/ L~fѰ"|f=LS(,C(L6+)n[^d, `.cEWJIFIN·:l +," 5ٕL6&GxL `qAgd9?IjT +w!]1?^T֟"{_ > VK극U̍J kҍ 8Ma25<9A +jߥſ YѨ-!r2d%&3vWE_]n#^wa!yޯ%LWC/ϩNse!Di/Zl0$w2"-En嚚m-Tٱkt)yL>b@ ++j8Ne0vmġϜ(B#ɺjk*gknx7j \`/ Xp"yDw82G Ǝ^?Uz.7n7C]wOnWৃ:pʇ"Bt蔏wa2+&X޴ݿ5b{YP.ktե~F]e)Q:t2]D 85gNejT}t$vx$oGScIJfTʦك\wIN QWfIC[,LB(yQq +5t!7W0`70ݸ +롓_N VC _A*RâTmA*RHɅVL+V8)jMZ{7rJ?x9#\X[Ox8,J eNnM*y z*K,3LJ+SS\w+P܂Wo>ٔhl?r7r_*+3y@Vp{ +άm;mʄw1.iP?c·I:i!b`g'+Y l)ַއ1tw?P4-> !Zt#pI{{/;=xxVN3q:.ZbŬ$050 s#< BFI8}K菔 Iðo-죽t2>"2,Cb ?<τZpAjsdK?+Q?>!->e|"!ؙvj^qu9e&ȶlN#-!#sG^X` # $gtRkc6/t37dg;w\P^uuܻLjn_i[ٔobIz3t5`Bb 漉 5_2[[ 5]TkSdzevy ^OmTmTBL/&_y|X#Gl{ a$+Nި#l_8,ĵ}!M+~!+9:-ehgyGxV(}n  fWf^pCV@&ˋ+ݏ 8_qqA 8 bàx$ow|F{y8c1d ٬,{TSW5^]KǞMX@GhEETG QB! +E  cH"֎S#U|}㾩su׹}>}33xGl-}2K̄)XF/ 䦹rC5p'9sM "K0F&hY5= 6.sP[Tkȋ &Ke3KoTTUܼJyv`(GYJ܇CC2pпDG+rGwdfǔ:^*k0)ETޞgzf>8 (f- +J-pG+b)j\ӐwЪU0CG^C&k1xRl(ؐc7Y/H@*^?K(&t0oB0R +1H R A~apKƀU >vsWv!Ft]M9$:XS2oCZ`h;63/s=*Bb6pbRPeX:&C.i^Gh|}N%DppEdk zJӏ)ݕl;06R0A}4K%0BC V9W~C)ݝ~s"[(pN3Edf>B1lh#x dP܌äng{:nدsButTNŶ j6a\L@-EV[4o$i.z`}M:$%3QEv?V;Y!E.MPvA%^S8c3ƈIArPoևɴzW%nТ;? *|K4h&)sMB8%X?ED60:aB!WS|$"$\s u1I0 F@m`a$% +>ڔMt]Ay40~kbp Ō8FΰM`A,(Mֲ\ɉG,AO.H޽XsqN1s5={MH_5616>>yNx`9f(P;v>g)z:QC^i?jo_ѵivrL Q3ER00 fpO3(FCgNc%HMr*bqG ˧Q/"Я>xz}ԧMfNgA%+v˖Ȉ~Mw6묁@a07[#0nf4MnRPP 59RqC^MYAVC[%j5-lE+w[s o{t~7y7:yV~l5:@'0j!*=FRC5KfKةw0ZM*^ւz zz[Y.YfA|_ 3&|4ZR=a΃g,~vXۉ$F\Fډy?ԡ7f5iKx*XB(rNe2>+N+/%rT :RkvOYH^I\x\^WB3Ձog`~_A`D;-~Q)\XxH$~i}AN8$㊶r]iQMM~$˟#Z׊⠙>jA׈6%-3B+Lvk*$\wF>GfZ{{kZC!K<0 mPq((+c)4xB^wvL `x=UE K?=#֣*{޶c.2Ҍet/(M jt5jh])߀bdqjUIf?Xml<[j^Fӧ[ͧ1-}=,_jh|a0\z^lDi&xj͚.?`0Pa.2Vrͺd]]`T\WxۊcXLcY{Fmn,"?]%?TH/巒n.ܞr86( L:-uE4_0ե̓"Q⌓O7CE,7G_Jfޫ`q%r4Kp8Q+@;駱i\SDEk5ZNFReXG.,?2<~(W( U-:/W(g& =b/Wʞ60d6Gzh@?0D=!U%┒;.Ba.)*.vKddmm^U\SI#; ԕb8`Y0J47;&qWFQ>͕K]jJ gzx|LUf\P8{Y[&AكvHVQv]oԼVvW0I/2&XNpٶ#!17tv^>2#F>2q5߬:Y!ԍ4$p>#)J~%A[}A7l,} #eCbuS1??, jJclAH0 ԝ\l9)%AD$7a{Fr  쀗72DžKDQ_D;DGLn;GWXaDG=X+ˤlZjka.Q50X;+*fPޙkהW$as㍞ nޕ$^!Q~s5S%{v,,W95-\X/e(xNk!!T`VF0;pS'F0^K wbj&6wW^JIiW}x.E6E򲳊:;qɂd͞PC츻LTy7]D314\'КֲpOh)},*) +)VJ$0ͤ +D-9'Zu"S8gwo ǒrO]n6ѩ}kNgqG܌/`%MU UTww]^ $_ơ$j`򷶱܄FƊ;GO?M((Wvv|QAOV  зfu9 /l/5:yG69G#s;厸`#PWᾉ2Iݫή&|gtqҥxF]8𥠡>tMt3 ʚq5(l1FBu?Hޜ&#O2[[I@w'%9:r{j6JIyg#Z属nՄH!J!窂[T +us^z9 Ѐ赨}7􃑱cܹ&~ɑlш+\SII3^pl封Uh PU/lq}5 +_kU*g)o[lOt9ڭj}JKŮE&v޽y&)8q vɺ['9v}罹FIx;xR3iCLi+|<*N4kuITfԢek{=^mHapy#d2џo5]ڎZ%V+E[ +? +Nɉg^\o /I:!pz˖,V`{zu-뎶Đy܉/uQg7G:s2遤[!}|LJ?*`b+IQC;2"L!n%p'3s)S n􇫾CދD>aVglpXvtOTY"9TТvV,;\?AwԎ44/2P↗SdMqSkټZG('҃2A~hj/Ta*ѰuKkF}f[=SG3&"AJemh1ֽ*MT'd1~j*]6].ڝ]]!ÝSϕUZF\xDtE7H )M B0 X@e22amf87yW߻v#W&<HZy %zc ~L&y{l?znzX ޒlVmH[*d ,ӛazvc+B_Ru+ߤrMK @q{5sn؟wPFQA+=z cURoiyTҜ%H0@Ԕ nu z񓄩>Ikߧ/3v \Ll}2<(j?b)c2`qْX+o4ܠ$yqNB(!ΖӴ>H.t+hbHL*]e 0Ɋ`$,('8/TfR[Eᕬ*k(J=:Aڋ^EuX9VtN5S8/G,jvZ)UU0X4:;ْ?h1L,Q$T/gT+UF06(٥)(UdKlII RnU`%YqAit;:S7\"0S?yödj+^늎˸ᒑ#zcA bϻoQV;bX;c'I߫J奃-Bu5:ސ>6!u@%MHE9aaڷ`~E"3ӜյT<{.q:J-ڬ.]PWWI  WkkZ**17SDV Rk3EE;Ӯ]q>n'A#t-` 5L\ +&AكZѨfg%UeMޅ>x"*Xa.;0l2uOf˯Ս/02c=b~\Ý.1ŸPjDnr~"tmPTithbЊ_9pNJӖH,W"5erS˩}6Ct%f$0"T_aQ:fbh;sU%_0υIY)227^(e2us\P6{2?UMC:"hI F*`, p/fX0C͹L֪DæhUwxKkJřȅgrͭ;/K8q<9Vk@D|[p:0$n.-Z)fcNPK\tt. ЀG: +pE!! +WIݑ;V0Ca5;pH@ծ_S]A߽m~c7tqN{#ڗGGJNp~GW),,Gm×콷." ?6,~8%"n'i+5k \DfDnr#D`q!_E_? +뎿./&yj0Ӌ?'Q0_URG !iOcqc*RDe\=M Ir7jV*(u!}Fg|>om[8`XU6<E-E=:KŸG E?lxXz v;R9| fP"tz(ZDXwxWrSiC&Wk>{gv- Ojz}7`5/arpɏß2XzUc :+4QilQfӗTj6-7k5 h9(i+#0V+ *e_ j*t~(njL({ƖH44 +F4'@@ATY@PbbEb(E " Q5bG1դ6纺/;nX\cFvoW .KW`xɟfq歏D K('eZP70YpX𓲓󱄚lS`ɋˊTn-[rW +TbE77.V9 PJҹB Iſ} l 0[ W 6a7ol;jI?,f.XgKb}cRa7Gl Z)><=qn9,"!0>O~. ~!G?b/e#×`vgӝz)oP1y4^otzkq5i=ߖ;)*jO`&ьAK1¸_Aߛovq t|6`wdga!VR+Ԣnn.V> +1lE6~([k؃!.Lk ]..k8ي!1pp{I/ q{+^݀a\QgwE-Gܘ+I:avK +N +(%/PT݅Q#p4H\^wU-Q}$A{+XQ@җĄl>Q v_6g]uMbcd>b?v$3*tu\Izq:Rű!nG846A":IY}sr p +SGa5-'0頹:2h>x2/BE1Ua{Tn>khNTȤϿ$Pcv&2G,h?@wg = {F)ĺЋ/"Ky xѳKB!$埠+2\4W|\@4DZtvxLFA "JpAPFP%FY +TJr7LY"е]8 ΃R'iS!m2cdVpN-#W 0)?}F gZc1 >EcͲfS^ؑq/̖\zB؏$_ + +t^+=}xiπ@/޼Ճ8ZxjJXY,U e_>/.NcUbtCS q`;>حD_/+jx(†Ҍ;w洁$L# fiKe 3fs"3|0j\>eC'̾ !:&at>NIWcWv>/.N+ & 7Oԋ)]a#ژ@Ӥ LʳtM>W{ +L泫 >u&%#{]Wz##Q6dho.+?)U9y5o4gʟ8uTIMZm'?=bC\KPոzo2]+y- Kԅ*mhhrEqa9n烞x1(,⠜bR. 34LБAHH%(sB x@^kVb`kv$MWMUz_gҫ:v\w+K4Q}BSެhȤpAK 'ppAte%'9C'|P11UW? sxÊ*7:1а_Dik`0Rv:3ч @hv /IV_ߧ=t@ +py4d @HYQ]c^6F02:Op|c'i0C_1CDwV Q^y(0g `f_F^9E ;b<,0lQBdA*5e7(qx * +eq38:tfG:``\ʼn7]rHgac)5,w OXN6YeS Hj1J1֟qE^.M.J$9\ߐٹ1Q)Vݏzbrz 5(y M")!9dIRĔ( +'ڎ` WlCbt*v YSn'`@&8s1*Q{&NX6 +WB8 + #D-J&U$^ .5}S:GU+P1vcjVfZK :PfX[g\D +62LcR PF_DזzCJDӟOFեqDkUW\kO-;i˯NYUE_' #gYR2ܵoh,1 ?Hv$2`Տݺj&+A$$P[x?epHft00e+8MI_';W^,xc-Ѷ}< xODS.4 }߬1_sis֓$W&xt 1N/,0gaX׉fvLi>$n,B  +A +hc!Ja@ ujy][Dq'Xp0I3M{QZ;2試$ Q3)0][Yl"ψХ|-Qʞp >!}Ol/xp婙T=GM-1 +DӚؓmܶߍ7Kc4 [CF8QԳYOX@b Y(1 ~_q+t6mChH2(cp!3Cח_ӊއ"8DN>O%>7c^rҪb_~ +j6oMb| +a OacsL0 8(P6n ==o9|`VCiE2L'M}z9mag8< ̖ͥ^~^Xߋ𵶞~qe8ڰFNșgnO kumM6|DFc"N2ևtDMZYӔ7X.Øg84=Y]{U]ɯŹ+pBwBǟ9gMonN%6d7`$T*_YE! 0Kd8bѹ" AIJ"CL1m-onS΃8Bc =lXݝOCz]mކ[:HgH֕5??;&p9g P]q' һs9%/8&~`8gXbҗE94P-Nx .Lfn@]O>,,ʓsC_ A; 29s>NB+uBv-Ry* ?Uʹ +~9bZ |'cX'ۨ6]%^R}yE drɺ|N ̸NMa>K(H,{EG57+0 ?eTqGL޳k؃ +`YDh 4"" ˀH%-Dp$HD[Fg[]kڪ9/sUs[{wEuysx¨7gx//z{/ubmɤ}* bf#0GhKfe-,‰\U09j+uPvB-d8]H,TIgȏɵN0$a:1@1&> ݜ%yD*ipܺ/4p[W.]"d۝_wb(~v ar?ktXXuCUx"ª;r{>g:1n dߒXcEESf +gI1%|D=זky66Q݆v2vsIo-Jэ&:}{P2(e62;Dm9nbOqv2V%k[!$8nޏ}æQP'[]~s5kO 70"?NMn`.6ƅ·2v UZ%NƜ̉I=>-+}4h۬9fY'9 ]U_I.LuZ5kzSUgcXU,' eHnd,#2&]f"Dk-b~^[r8뛛n],e$(w>\8n3ä8H\쌃L0\VPT|0H,\y^ :P]vN2I2#ΟEۛuAa#پeuV\K;O֞<*8in`mBO{Oj'5IMHfTsm.C6Q6v }W$8vCNM60c7HUO+9e`t%SSL!}bwKcH+$Tw`=v߶Sx*1w/ EQ83ֵ%3?. 97c`@b>[2RvտbXr\堪UWĘ_s>[?C]-zhcʜ,a0񖼼Ek +USX +²˜;(Xx +3`MX@Nᯢ7>NЉ_ؐK6m\ iSbYNOX(,"ݝ@6q5jR+uJ42 A1f80ܗq`0r:0 CAE J,M\KW_YڿUWu{s;& )h ^7aN zFEaُDZ6U[ B/Ih76U򚳛rxX>S'n]cNȄOIKBLe|zߎq2HUqI03?駩{ QB3.9P;i沨'GN֔|%^2ojTE=b_R*`n-aRG|+2cq\ O"m;4D͎x[Y1yt^Y'܂S|by2t cg׏_|aà*υOF,X!Ō)2y7Ti@~<,Ut |oZMT8ʖ).vb?!njEp,Gt.c&1b4V:~OӻDu'piiQ[ĂHe|}hnh+ i*S+l5nvs_mlOÚU<Rݲ pGtA7p4Lx"Vq¬Wawִ4 4e4zՔYEFx6j`{$(.A2:&Mo %P n)ES|)?ԂBOUzN +QMb%ˌ_ wՆ֢!}=eLΐiL-Dg@&}|(DpFp%a%KLT g@9P;{[fHN, ΢VɌ(o#!/~|Q?'~熡А(GO<@0DpzwΖ5r%ЁVBz1ڗ'[-Uxn[R[0/TjVDmLT:jBd[g(!N=ZЮ-6犌ia{݁^y|UA קIFqjFkA1L9X6 v:⪓]*gN-@6bKeb%n0nWO!ԌV 4f1 +GMb YCʕ,nJ( sruE%f>@(P9ʎڋ2>'&zU[ +PKba?CXGᚍ#5WiJ8|w-5&S"]`Z畖WDxiIA8tD*INhڇ)Ju||o[GꑒnW1`>@>:Wx_|2rsu3'0ENjI,Nt^tqxԔ̷7O0UMRm|.{zV&/Zx;05&^} o)au'mh/K :ydy(klFDf–zB./3 +>yOY9(gk^fv|h)=wOZ{2hK ~Vn*dabBfI띬u:j feр1k'W QTp5De0&шk"00ofEw1࣢+ZQKEYO݆ݷVb|7=XvO4P` 1ʏ`@,ݕ+#_'a&8(el3BԘ5gɿ^-.]^QCӢDv6 +(Qm,G$.mzZ~Ԩ[3ɖ]B_+nqp:i"?׺%_ 4i]tS"R7 :!}@L._} &WOI#%*D=\|/hU x[EgU7mQGVF0=^sv.͵5fs;nK@?-[Ke6,t8|CX^Mp^-2 u"s0"yr_)̅Wt8;#i;o8EPVallh2 + ;thCxX|ch@rM@,6Bx{}AާAOh +ձ{H"/ oSCQ= V] +#0\VN#!b-m~9ń^Q˫r:0Щ78c|yDLxxQ%W6Y5c\j<iJp N= c$en,ޝgSm4H k0 n0,k"7NxljC)rs\8C!HO758H|A@pm?[ \x&B?X%tGLƩs5߉tD%gJ& aa7Lοh8"}Mg1ts"Y"=-5%v{ի᭳2p(^APM:>-Z_B`JʐDe-epzIr񢹵8DPJ2T*µ$ӓp%؎<.an7foFu"En*i+.?ᘄlBr4Ut(]I՘FRv*TWP;l5F-Kpv~I8%Z%zkĥ^M֓ IVU6U8XQfm/6M˼Tw:kuâk%B<ƕ=ٖϷʖ KZ `60;8XCC.a96Rڳd>' ) 'AiJy#IJ5(Jlkᅪ;!+ひSv6{(kL,uI+>v67) +m4Ȅd4duSV +(RݱzWyB#gͽp=c< rC+ 5Y(ELJCt\hk\v$__x'A,Ro%% $I^ T֎7Y4dR$7V}6r- 86j]$?]68J\yTSw$9?B+uUljŢQ"([BbYRIX D +D|AXAъ +UGk-3:eƥmn8ys~ neo* <3Bz ) 9ZL6fjqV}Ji l1WLJ<^^I$Ɔ37Irm4DYRER}VԀTW,™(^y@B 0OxsJ92 z*(=2dtKsIs&1K6.{2Vhu+Yb.}]$o$? 9:ƙ,>Z6v-ݩkL cLEJ9%ʬ!Q_itF~BB3ck 5\,B +f, +.VTԢ0,ꄩ < +N- +#g.rI('f]h`=eq1M兩8b0YjcCqJv,ɖm_!t8 +b%t.vG ,E7Ql='_uƻ _I"83wߚ/X́فv!)p8.m3{I̻sw/Hh{ŏt#a4OO<.褶ԤatzZcb +V)|+OͶk]J 1Gh!vG1G> G{LFօ=f& +'nIGĚ jf5r}u =,3:!M},tT*JShNL{R^YhryW+z-8.h}BsPjI{HyG*u%HWR!&8H[d6d{ GݯkIXPe+ӈTt n{ߊW[&'bo&A{ö{է7Fk\b$Sd?g"]Vz}ƨeu ]K,%te"kIvDyVw q+ØEdIWְ7o{ 3# s<&>aTիP'Aw\Yv0@]~By- I!&I^ȋP#Of]2v"o;JIF&>BB66$lL>/WUTJ*:JZIIj\E<.gZ-=*mSմWF`zǨ$|gD*YJbcgڣ13h[NBDED +EԵ*(RA7""! / &ky (D)ŢP>Պh}/]CzGۿ93'}~Vc3␍F!qq4tI,9."TB-vQLg"6M{Z?C2tFbATh7(PsfBjfLհA*g iz!pڡ9{殛*4bU!hҐLe|{rv6tƜqtӢ3va)%9c?K6%\FA\xb:q70GKWBcؼ-HVOJ0KH%۶/?޵h";ce'P[GCUix|ە`24m.NT-7dd)sna7m6^dj=ù8Iokw[}#[Ҍ{ML2fAeł +X+޵b'Y%^I睪{cBXd˅צ!tNז bߺaLR[0^Kr9/Sm [ࣖ?"we[L`?ĿzTl`7~7F!Vdx8|w(*.˹#|eɿ5yW˔ýpυV!{uO4 :GI8hRyg^yIIbޝ(,F5zO6Ii*9kS+)ލ M&J! +dQKJkI'PS"p+xtD'/e̽|>=w@hrܴHilXF'VskvD:vFW^W"N;B.k_ DߛVธ }fVjLe3I靬& GDJja;ƀc05@~*qa`U}WYrQ HKi}|ɵm-Kn$ k=J|ܸCCA\㈡e r.(cCtE{qf.dMjV20 +Rk'$ +1~sPI:~jpgdD)ӲҳpV,S8=UZ `JNcaY}SALئܟUK+<0_y|E[1c p#Q cqnF\DSЍ,65K{ǓN-rʰ]'j33q&Zny,0Rr-B7b()߿Z@W^`Gȩ-d p@#.q/$xޮVsƜCVݤ'-?\oc`!R/PRdah;;m}jq6SSVJeO3V/̓=ʯ*Q1xYCfFӜ틪`~G΁HgTuM`"LD6[R 졓q7cf%1?׈S~FpP]٬2!$J4@{bEKa9hX\`Gky h693A>MGgnΎeV +)Eg]ã_OVi)e`HDTxwh<ݜ'|UVx1ɭ> ~S\hxĻݲ]ݏ zIì %Ԋ=8&#?F=ͫ-_^ZlӰ.R{ %h9< +b^5)\ۯ?a:8SZ9tƾ)"f+̳ro J0"T=3vFˌ1n"t7,B@ٺiYdiEQ(`PK0̙[+ΙsN~=ǫw}tnKniR2A)Q **B cz;R[}"G?oLx]ܧ|c"Kn2*Xz rSm9Bf@ڢ<lz2W09t0eX^XAx +Tz/΁uhw8VE"i3Jaw^wAwcUm~7ijSr=4b&2UOwD鑉)NiǸaJDr nmIbO_jTy%deJ"*c+jx鐺>tbEjC# swg/t.o&ۙ;`s9.yyG0e ޚ[piU~KhMygU7P5%)a_ױ>-.-}:;ZCѓсqoia?p{F32tOtɥ_i+٘~RCx,Lw:"hGV*u;%:PR@LaXl )\l2]'!M;g;*1 :s!i]IPZ*;fRKJ4;@-##T,\ܲ!带0(- Uusd +\zMrV/a] 044 hB6J6vy4yj1+{>}+j%0A'8mts584wO?+Wݼ=g"1d2]c:0C \f0 ]`}Q>G,rqmĻs1+.Ľ]JOPf(|m^Y2V`ˌ t4>.ƒz_ڈ_ݵ2Vjּƶ`[~[Dcs[w kއ73srNھI jMAY +itٮ ~`M&/\doC&}!'4BA#GN) c;` +o{S#I4 WL+in0FDbz% "Dq cY' M8q DeFvf#]=}kgTW7WDC ʏm++)uX2uO[#8+3q<ۮCNm{ F'/䯙(p|U%ۑlFޏ#B>R]|/Re +/YxA +פt&w:esAjL[]S4݅g ZC3Ӻቤt jw&(fQg6 WQx?cU }?ds;;.|X;Ñ L,߆)D Z(@=*\HTJ2ߜelA +ykNio @BKf`lMa"0k RJ8Yo{f}5F?4*+ {<ʰyZcATP(AL\z͢*, +MMw {7K4ʨFqtOn[kN}p|uTa #hI=@VKlћQf +QZ9'egtʾtOdVvWe + ++ +*9XhB㮖Pc4 ȋ +{K%V vLFnFFq3~앜+B"5Fo쭺j@1[XHp7趰`؊Nc5FU[2NSOe/b c і[أ59>$Ϧr=;wrZ/08݈$ň#I8EAC,7@ 2(`AtɨʳYa(ESVHw*\£6̇/0HYW݉|s%YYf97)CyɊ愊2^^[v`g(YKKe~)^Q6]F3_(UDd(`9;:Ĝ_D;##c:/|J"K})Oѥ;×PO04Väjhu 6ujrCj% H6pY6Gs&]b{"h VɋMj1ˌ~6eCgw\sHsa= ye9K uS/_2Xfl >ʟG:zA{kpXo_Ys'gU4זwoDo'х tJg:CI#n]WD70tH* +xWj8r֝[6Q9i"DM3[CZ+01Ap>D%f5ߕa`2K0N't,=P39':".^8uH%jQ +ݰt3[oFk3+.#rLz~;`ẓCGk@=jRpU̐դ-ZY +~c4rbDt]4a9Utʯ;xFs-|x͖Nk/HI!"iɉ2lcE-7j$ Ƃ3}eH^Kla"G5ȥDZmu}ɸ^ sA߉rEqea\WIVḧ́HP_ -X_8 $feQAf0qQD@EDEJ\RqOTڿ]s߷%)AA4/eG@[gP݀տOV(b $A;v$pʶʳI9NFA +QfjrwFNỲBx]n6PmQS^4?eQ &wUn+_֋<|وvK쾇?Z3L: v`:S^VƭGhVJn_n?c`ID, ׺{W{c?2Ĥ7aU{~wHfM1ɂ' [ƃ0z +dcM4HTXOc= +}Vzciz_`PtAG#a`smleGx,У."0rq!9 9 c6(Y0 hjt>iP6W{(Omz$^C8+Mf.!H߆7sNhY -Wp:"\$g*DUn"L K,J6""@;bLƒUDʹ#f NdG}3X ֬am>?!`{`wI͕f!GXr ъ'MRSY}I"*jOa̰ j2Z,En/p`0$uZx6MqAOټ`Chq=vt/O_ C|& ֲ +2{vQ"w0Z)Sk5jRhm&,x;D"48qIHSMep1=b&T nlYa^_2oN8 c'p vT$<X6OlzQuV:ct^{Yڒnu/֦jʎ +~);^kdPŦ!ޛÔ&VڥZVꅮ_kɚ;'DMtVTT!O:N LeI͗s/ W7DJsd _jL +_u\~Ƶ޸flrw8LSvSqNRB"_ƶ4߬e2^DdtncOb1_0hb-I~Ҍ.a0ͯ0iCMVeEMkJd`-^^M~`J; l#+>VX,ֵZ--c el{JI)dpm^9Uz] V]{KFK}pp=r4b̆ N? D5* O)+2%t)'_("g:&VcuxQOѣ- /:J.8onǞONF6̱*wmOL\wsp 1m}\n+%nE˞+28k_d3ZW>VXԌnϞuDUgl ΆJ]8>}eo2qUYeL,2*I_J $[i5դ{~1H_1t`x%+ĝLjo@,9YӞ&QmIU0H_v^Ft:R45/,+&+*,,&e5 & mmT)_"TWyPg_;K6cAf`D,`)lJspEȢQ`dL"g 5nSbHG@$QJv}MNjfnUwW]](:~bʷ#(+0(R/ JA:LjlghdʝD˲`$uts 8^n2Ox# {}7Xpܘ7seB Fmh%щ{ooz)?*6LjJqE7xHeԅ{vԐEV.-+ޫL4|s +˭v4n9a+n:Nt'5dm{GTDD mI00[= "Yx@T֨E\)/Oi"T@+Lb6 UF{|PV\U@(`fz ]mKS 8=v4?WEtk?jJ27-?۹8UX`=|4Ds5c_VB>Peۆmq`+PG"/Eׯ6al}ֻ陮3=iNE9Ea-sp& 8W"`JnE,\xm4v̏0P,&m[͇հ:-:7% /t^EU \%0k;O,\84=aۘkjySbhp&F ӽ]]9|Ϟ6/@N-!-Ό޲@ٔA5@ClÆ9x@ #YT:ڇ;L*ot>ES>R/N|( ![,!~|6AXJ讥 Zf9i!9Kܟ.8 -yHLK4 baN6YvVǰ\;E!{'P,(}@Q^I-BRE B-i4Y ! W`k1qq[1KgڴF}of2)!VDs:8a8Q rO{qpJ$8װŴ9?& (Kq)0nJN~4$)Yx{(.q@ñۓ> z_qPAۙ&x OnқxI vi.`;AiB3.[W eIuO/e tO.6,<{\obTԧ/ ?;ˎ{ˀYJqfJ=]jKYwC4 +Q`a80/*`a:LG 叨˿5p]!VoZ; 1\d()| - "3Ό1ѳuRז7'R)~@mї4 yY|{h9%ҔI1LB]%UfjeP^a1Jq[ 5SsL$K06q|B|ַ6VU{BULbXK(cּ;j0_HSu8n P*sE5'oT ҷdM$3A%B-g;*,\ohqt^تS7p9.Dg=$7J\iR 9 \7/ Rq'^t[#R2[\"yc.Gх4㔚d[ҭ<$WyXTЀ&Ø>P  +:V1`Fga~Tp%ð@vfhqqƅh-ڈMyks9X m$ބ(c! +0|ֆ:}__MJv_e&_Or1=Ї$}NP+ߡ87wha${Ŏ@&^E0s]ZΠ&w`51.,@5][6 +!RK?/NJ>W+RNN cqMMNҞ5`ĦK^_c;iF)څؤj+fMH*$B|aYV(7΢wXĒQZ jeh&Q; _1׳UU66ipf}#af5X+ч+;癹מhw\I%~hW j_ +d *դOU7S +S!rmY8 p8ޤ1׮`Íh3ދ ]ί?ގӳ!I~V$K0ԅ0zzy˥qԆޣՇt8aN_9)M{k1ٴ__瘡 .8@aA nL-.0?#SO--4{@hi]Kb;TO;0]_wprRy'gxCv`,f8bGblXuK$Ɏt@8ن|b&bC3?I?hU6'zc'4?NtJ` 9?8l)ږ-ԥW)/+-%p +ELZ;v| ݧ/Z=NKW=s>F>}^PSJPI^mCmYq5HF=DOXDD6`V53ybT;v̈́L\= =W)4|+}TJ5C![,JmwwvRLs4bpQsw~rhY*tYDi^}|A6-pZpjh~p^gBKRۻ`HP9&ۃ󅀂 +͝2Ӳ*iq:Q(sŧrxiE?ʺj":B'w7,f:DŽrBV@Z!ݣ>Y0ۦ< A!d+:_Kݐ@|0_qc~kt*bSQX^X;^1eݍUnvFO﫧5lRi\׼lxZ4k,Y `cVⶹJȣ4ed2w)΄EǨB2"J]w^n +BI b-XJ?cXOE)[*5R] +]LfVj+FʺR loAk4(.(G BXaYqR3fR(|ԶYyf3hom V+!$+'1Q ^@ 20u \cqKp|H]pX61!\2LPTǁ=$zcc !Jј ʂ (?EXe~Xw%˲.BQc5T1jJ(kiyyҦ33|=ϗ4d/0 +tuoŗ4:"6N =јudZ8%2eQ$%hȎ|ڍ[砺 x.:\/s +>y B YCٞ:> %>#Ӝ~SbPG %cB#%;<hȼpF2[gj{.*$V,d ~K ʂ #z֍`#;xXˎ**3*4S0G>Z n :OvP+ɦc8@!Lp f Yl (4W~B}zBG;nT?8 {毤 0Т;JiT;[[7WKvpBXNC4:xkeJ6|Em*^p-GbG(ϔ%4t3ŤRٯV F pmlDqdt~lV8yvxy+mRX@__d<8Mj5G!LJZӞꔍ| +jq!7{0H.G=~7JD_%V٦aͺh (qۥI +@̌[Uȷ)F's P +ڙ%GkòO +.A70("xOPP@ŏƁ2#J {Q7ÿ0cwFh3`A_O z:1n MEo7ulpXmG HdR~A\INWaaf8H +[X|32>ɁHxx>CO-堈xK{[;]鞅?C v3@Θ4oj{9ECjt69JPS ǦVI-6?1#)Ug:B;6vy/fژKe4Kk8, +`o1MW98_QnuON_{HzEu^̂dQKW<3a.S@O\´6E >e 3KV55'i tA|t|P0GlQƽ&s +s%XsjDvx˄ [ +endstream endobj 57 0 obj <>stream +HWۊ}ﯨgÔ2" +CC% ށ}Y+۬W'2oP՝w 2˧û??2|w?ӿf0Knhiiam[]DMЯh +|Y^98~#Q2s4 ;nzsxDe*l 23`&]Sϛz.-eA3[К=g$Yި*aeEp,Tر0{Zx /U5w;YlsF|UF~6\G;|I H#/fd  X39T?]YYf;%c#D,="F[i0+~Y`0ÌOdf;bizp-+^kYQk} +H-7Y `y˛4 c$!rd1AJ-ş1Mқ}?zv>-v h*B%&vBRi՜& BbizO4+,S@ˆ8ҒUf)F\mS@I"75]_+ڠvrwGO7Dߓn)qEw$e$4AMUGl6x+xDЯ_uBdoE&P%Z=8L''U'W@lZN`+jJ:ys7ϴQZCwwfoWlJo)y6)gw .+܊51Hv+hZ.,*5 kj3hˡ۞_j˚=жk +v4k4S!D;ÍjQis_:Nkf1ɗCTxh/ebq&M [OFv&P]@<Ƃi{e"x5\J짬UYnc>imNuƔ9S+-P{3Q=ZslUFȼLʷ@#$:o|m7d\2H/Z @î7$1:}ZTXek!쪓) b͉!IaIeyMpQ!{!=VP>$UF;dv$m>ʠՙ@H<ܬ氊T~S\ϤWn+H[f NAkEyW*( gFTq`HûNA{gRhv%6/fR{}7sxRsOp|JҎjNa`[#`Otgz_ɗ3VoE {fsヷ.Wy \*}~s2tῬWɎ6W +;À* pb 89K~?Z3=3-X*ނ:v } +DGe s2AE@>[;^OZ D@XuFOh$p*Y47b!ɛRɰ j>|+*x+~M,cQ^<ڕu=-8B&X%G#01eN N vU /&?M9wI`u K^C6фѽEVac5` OXTO83"NJDqMr+az2e2F6gŗ{mI2(i3.$L lgI6ШpqH$9sp`N|\<^MyvI5_Btef9ffbfCۊaf ́FoB!V !`*FN[5-|@: +ph|ӈFj"ki0@2{CLc5J;makd.X !nq (XĎ`8Qvʡv@s6ՈfP?EXo@'0Ԡkb=8,+_ 6* 싢xDD+ԝx ūN!XܒCv;cm'(I:937<%sknN$;pGV^pEbZ̩9耗)C<2HTdC{U9 ;3y\]GV8y|kX,fTi懲O?2"By@>E6B F{vﭢ[b]vr\`' /F~CqԾ|WlM:p~O3~~~2HgJBla\P{U,o K"@N+y&ΥB͊mDjҐD}h&7"&b3Lk +B٩!zv:_J_ 58! ifH9E@Ff과;Lcbb*&%TvEТCs 'Tѐ% VK4ZxrBx$y< s#X1ti(@~g)<312JPPUNE52i +[Ƃ.AM|Oeޒ 6qm3ODm'+]';Z μ6:дF>1h7jI<-/n76uq)'u1Q~r㯾P8SG=D]k?on"{o/Erf9YE}t޼>|:H`>^Yc@(MC Hv +MU!oKC'{LUBLC|{LM8 Bl_u1Y?;5>_yݰXKdLB +=w !w +3:`;/Kݾiq8Eerdp(DeZ'k{ku&I?Ԯ~KJ J+7j,+>$Ƨ)ElL|09^z;j)e62z)zMBy<пe #I +endstream endobj 58 0 obj <> endobj 59 0 obj <>stream +8;ZD/4a)H3%/*fs*.\F2m-U$AGg)DqE/8,J9sUQfAmM;8j*qr.Y\Dt[a)ajuI$TGf +:GT`#_57'o;Rsttgn4IAZhj8C"4'kp@@Cqkreqn="E$n-o>)Z7EGTeRZj>@MMb)d +)DDUO/iq46KW>79?aE?[16m)`%;$VkMd4q_A*+rP4h^1&1ml!tAb\9iS.h2G3*+os +-G6u^ie,Or*4)"_[1@@["#5k&=#,KY33@P$k!;K.G0;6KN+tX\BBDdtj<#1E/YYN+ +lF<.5eJL"7H'We!Cd"6d?_]>uiC+;H"lML;==FKjru+7b7R69;EY2E=^'FnT]L_l] +M#0@aeaMVnCA9oAMYaq/NhDJ)]j56H4&>%cf[FGYaR#%+hEOKm/Vi%Jc"N\q/Bi6n +Y+#q^M+3H70&1.BjqX!9*HhWZ"qjksh7P&fSsuDgi:lkm +8)^2*?)i9LhhIXhY`rS]r!i^d>G(K~> +endstream endobj 16 0 obj <> endobj 117 0 obj [119 0 R] endobj 118 0 obj <>stream +Hdn7E, QL  FBޱ8,du벪mޖp^_^yr%hŧTccyYlI7vU) QF83r qfu=M'P Ț5*HN}5 7b6' :N足M%t`Y.%_~8˸OPn-PFpBxSGRsv3\G%@]ƂFa Ln")X` ,> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <>stream +HUm 5(SZ~vt!#$mH$~IQ pyZ՞9(z';v̠:_6|:LAp 4RfYa'ŹG>Go,[F.vS8țki~WI>[πq<_Me920"eJjw83{)P>9Ц&ߩ^uZ΀.ܲuPR!xÈRe1-I ׀=hϲYZ▵J yUf)Ip<(H\ +NKBz:q`:od" 6sL,_r+x*Wn 0&7BbBY9 +0 +endstream endobj 123 0 obj <>stream +HdRiXSW> 7AI^B'A0oаnPkYۊJQ(Uej--Xp{:i]uœL̏s=X,N)i,nvc9fځsb- 'qC6L3 F$EeS$TU5j6*&X*d3ɕ+ r}UM?ZWhZTR[bj()֘ +A+֖0LqI49"gQ b$A $E2BQ +GH"Q)P\Bf^c^z򞒔J:%}}^6v>[~ke$eIIBQjJId`֐!{B< y[>4/6lQ2,.'Q&y=ye$/Ryԁo(~p,;OuZ PGBS}6Qˤ[hR6*|x' BΟo> +ܲٶC|X0 "qQ>>P +QC_ce;7tvquaQr5X%/t+Ƈ'wa엮ݾ]m?`@pL:.JDgZyD|,ҖIcw_ [) B0Ty\nX# R=z^M;4LRqp}P|Yv  ̧.vX=|P_,B>7_Mw5'q 0H7M=cD#x9f6jrkۘjVi RǾM4po% p!!ɠXHKЌƬۨ͞nvt\rw{6as1>, ܮȷS 2.$o'̘m)x % +hHYcFfvfVV$$De (+{!K Bs I+2XVV@}H^0G1P@ +u $=0PjiCWApN2&a,2N@;yڞsqOGd_;yl!A; (h*lI ͋6kГ.4fnqt-[ ,-VMiGEa:hi"(! + AUQUDV]0 +"Y}uc {U}U}_y+ź̗0-zz#:iyE6(Є{9c)>. $VLXw., &[ס)Jb5 +!'bziV*0,=y4Z Z)XpݸHޒͭkJ|D!hѰs5鷕WE(0Li0Xu=Hog镮yÒBətYG54;$JTPI7rls #=X]$`'X;왋"QkyX?BR7W[FՊCV4ԽZJGI#Art *\x_.#-6x |UZw\ R8TDaX(Iq<-TB G0*٣g*ɮ)>r4oxè9sybۗsF*o/5&=w+D4j>aF(,40R1dP]Cw/<[GDwYy(IrKvfj~PP* dF7fĂPf4c " B;1}X%+wbK-Ivzt潅-0,F3ĩ6jT@vdw|kb؅kC.4ՈE ɭ5;g7L, :UC]/ `܉̟l +t[\%=k@ qNQ.7!o.0v`Y44T.^[+6"VHBMGqb?]~E7w쎼cA%lW0Q3oߔKv7ʚ??qZrE U=*9pu1$;gB-[sdŠ7v: O! Z5V)Q SA{x("NEdȲun.?ᙈގBQB @4(',:zKuNz'8 >пq"gn;,f\ hƉp<%hP?[MR&{N޻ХAT4laJ .k`TA&,*#PjS`~ݲ{j]Ws-Qk}$?/4&px(#6Q{A¼wNfƆ`t/#/[+ο FfwFp (9_q:7+* IVM[z6UI=|+UVFI1LtIHz5pB`Ƣ *%Tب{#-m= .6^bsW|YHCx]^ۤn).Di0+1E's|oO3S6fD .4Rmۑjw!97`U-㖣T,r/ct Nٷ 9X f=4t)q029[*At92+\E VhV0[mUg1 X;Д4l U͏`XpOpV64>Oa5a z=vFkJzPdu*0[TUZ/ +dXƼ]ִs6\ARaTFNbCgb +ى%-G!o}%ciEw9G}XT֣3o}xӗfЖ޹sW[P 8oEzك?z )cmV y,<.dBKAF2$k"{CjCv\6Wa1y3 Ã8$N0G)>Re>%Vi??|iy9Շ$czKg7kѩ>С)8N{ݱ<>׸;Fl:Dַfs겺\a1k>쾮gRKk*dE[hMҡ萐]ZF8Y;uM5i:MhE?T:#D~t9v=9s~}~ﭮ#aKݥ"םgh~g,;jVJ+tJ ֦i_xi +Vd$D|1V'ԗ5?_Qԥ&F0 $l0FΑ*u<}^c݋Vh/E;hхVU;?1\ U u1Yxo]S! + +~c-COEF .sEƄc^]ګ68\`wV_VȮ_a9o|P̰QQ$Ѥu3rKԲbM,_ +L{1m4kdowqW>9yT# 7\{q%WȔB>' ZJMz,5pg>惥\`򠡏.mq-:Pv|Lk: -qX;QRLM϶͙W.!ķ&o@O}*(LwtǍ葋Yw1 b 2[ʪ35gj+'9+wnL2A9Ji#6#'l@=%=hT"渷&{lO=bqE7Q}Ҵ?{Wu1()m%Zon-&)*͹`c.dJCÛDq+(Lnm|b1e2Nl[ dlJN٤V{P,FZV[TscBc~H`͚4ͼl,akS +oC^M0|R[uijczdwYZQQhK.Yp .즗`f([`p)x4[ V]S+KM~[ueNr!ww&\G% ^eh ^4w~SCGtʯ],:_:q\&?-su)8uk7Ia'?,TC)!6%-,)~PzF'_}RvSr}]7"eƔ]8)aU%E*5 OeĥKgrl [aBDtiJrhƷ 'Hx֡ӗS D=ъ/v^Qd^tL9_eCmE{.Q}vLLa`R pfvOYEj Y>q܏;_fTgVWN{Y?dٍSie@A!ChbA$'V3pc3SVɗS +{~q5uo`a^ +wV~ߑlظwo>del+̏w (ߍUx$rY37x>@ǚĜB%`Ng1Da?.'6ռp`s> TO/>3ݡ"Y_ 7;]m+χxm]ˈ&f;OB޹=Ewc^ ̅4±lxDۅ?۵1xkj]|da yp"}q*X%ɑZTԷU 4!8^֘_T %+\R>XK6eB +K)7oR>7Mi*`ƌaJ;3zF(W < <+sQ"\n8e3\7M1&ЯsG9K%H_7ńRoLs.fqe'jWlEY'[;bfDF{`_!l᱇ sXȆmc>u]ӂ +q~,JHbDAX`˧w;(yl"^!G7e1Ӵ.}WJ=RW6(23l[-YuU|LJS3Em\_7E u`LTol |` +JL<> W{muNt8>%.! +h`l% I{y"i`.jrAZiS _$p+` G`xlW +8Xss +$R2k| +Lf|tU'Qۣ0I q[=!pKTT:bEQ\`,*|7gh`%Ktv#$$*7OKS+O-KbvJ2lUF'+pʏ%,=RW ӭ}Q2g-}|<5Mziƒ +"a{Ґ$Ó M1L+. }1S|-N>H7z|]PשE\>UhKMӣMt,cےF p$W=P_X\Xp$f`+I{6:ob|cFv"VYMɬU,>1#?:DO'mf`6zN]ɥe*u:gcF))>3眮Cn$OQn}FqZW_:Ȩ[5SfG̭-;>U(=w޻p& +[4˽oao9/t>O55 3V&v͊ !;I aG{=r2a_1D\L{[JMeIHIt#)u5imL?iYjӎ4&72tV7*?ނZzEGtD4a +K x3"{+xmeNTߧ kxgИ*W$~5[]%v6 +Ƅ0̠,>%*! s#E*mn9*D@W?NBx ^dJkOV>͡@_QoE_ &lKa6c9L[2s`J+xhb zAIQLi?it7j!՞3#b݄]frG$~o0͓vCI8]75wTslkHCqG1)3_/=9[8ьv&idKF+' XQ"ZLyL 0!l e:oGƇI_ՔےrK0g2;<sZַPS~׽9_}.جN"9B`ZA︖)*RERp +1a +bU1R4eJ%+'RXg-ahzŽ/Qerh_ՁMkx7m꛹*ŧkϯG@˅*$$!f9K)pb@MЙT>A 6 dl~Ιn^x!X> zCOH 1ϔlD-ׁlBAElZtZDJlrtBɼzuk֓KYҌR`2,e X'b4(R;ĮÞv% ~ݣ+=0k֊J MD K"q +4,d(XszhhsǃKދՏՊa=[Ly-s9n3{<`#VB$ϤxaPR+!-isj̈́U"ɬ*2na8n3\nMVYNɱMƃ囁W7ۉs6pXD&ǁfhX=,r +;Y\atJRt+sLner +#$h~R'-c\E"'L + u560 ^ɬ,Aǧ[BTOU._bU8>HRISbcNqa̫WsMKMOM1PǕZjkhC.ŗSӯ*:8TIF9G =M,Μ=~58qW 7g} ]]WiTUW˝/nx{}i{W|O׽{'Xғړ{ 7BwrW>y}|gc!|}{V<$8|u^Y>s^2zzH: M40!>6=@K| 4_!|t0\LNKvk/g-'=N3fhqDvs_|[|m}5~kS[AZ7oOq*pnr/g!]YfTt3qhuoUX %%32eVmzX:PKOh[zE!;ʟb3 + Npfjl='zpˬ2KEׅևon|Wֺ}!A>T# ixU>YD1^Cλ9Jp1 )<ԝ#Y'/@\".a+; +5FѸ$ˆ&kCejmF[ j*]]fLLWkSA$.$!.D-I :aʌ\#jw[mri"uPM=.R-y]|ϳ߻]>[#[b:} ONta22sQY%9y93e;Cw%>' 0a@AFT~Ye<񎠣fLG=-d8%mC5Эn$}FxjTƣ#q(vw?D樝lPh$J̉""9E4'^,QXBx'~)7VtVY,'.Gmvv eӓ'(&a"#7A?U* + ~Ⳣ!)tk Q5,oEĩ!6ߑ^U):?`5>QMNEUT - LqKMIeT}Ts*n\m\e2-+5! +ft}"h04 ?K_t [k^ja*YC1b4>jop0|+ddAÂbM<%)svUjB^ -VX@Hj>SK'-&x1{2å8hd'rӿj0> /:xk/]79!e20eUyj%bqikl~19a6Nd*k*' ᤸSH1N*1|.əeZVL D00 oRcWy4X7[9[[O߷ڹU!/ثP`98,N"4-F9P-1'Z wH+$L}a*~ 0z F! 04ƠGu-y,JZq<͗A lbEbX MvpV'6CL +{a+a?EguR钡S#Z Y="wCc GEP@HmSRh{\N ܫ %Uk&j`ƚ3#1{Ǔ0bpGyU +̊ C 4V,b3I8Z Ӟ^ZV[T=xU̍ZJ38또 ^:GLgH/)@Fzm`?,|\ 9Xs|nhfmGX{IXD8%.GuD2Z*%Rg[H=|T|>u\q&K;oQwp/ë79tB?QW0]0|- %[X7*TK 숌ǰFhWߗ/Zš:[r,Qx]R(X6˽~L(C + u,(UЉqvvV@MO7tbfvfi5vW@0!5.TD%/Q,Y\4Mtwا{M$~yePm>m+7ukz~003-ɨu8 H 8 iB2ANHc`5}F*X;`֍(i!٩`C*Z믕y+[ +%,UtS-/\_PJw03a[p)grMYyش;C2Yzp+[&:Cm/WnS\ǡ1M9z*[I&]&2^Ēw|lo@*7?$)8)8Y +YÅؔc)xZ%jR\\T\X6/m|sQ?iX[ɼl)nubi9.&4]wjv耭ZE"Rf PR$\u2 KAH\J0B 0\qX\Txc9ag?oy= A{Qt +G"gE#(,bvHZS\Vч,Fȴ|3̻?z橋P.H^!pޓWCbHQ8 Fqo-5r떥 oes4{ukkX`$(4)-Ő3S'DY80}>xT kXNJZ=v3"[9:v*+%xX wR˺œǮ-rrõ[ďʼnd UZXmC%k;H0".-/**[k*W{AI#O[=}U =Ο2 +q,vH{|VNLU)EۤR^PQnsB7|3y?J//hRzk,=.a +9/qZҎ``ëI5gCŚ. -@Hs=0eb/[ R.(J1E)J}c%Qh٨쵼bZ$ӞmA3YZBvgm]mtM2uNš8GIop: 3Tk` 4k?bnfARwaai'hyaA< X?PK}x?NpB TmH +E8qY+n;}eB8pi˝9Ƥ3:J5æPy&WV%&Kc=ϴ^ ߝtZKUy\-+W~9g YPS`_7g; +jޑÎ +5i9M'ytlCIS9?pѷshmsm7Wq33ڈ k(]Bk ]V"-[ƒI3榷6 ypZC@}4'Jb'Df\Ih ¡7'U舠YʤȔ:f@уoϞY(4~Oj;Vp'YxX@nFXZY,+Ba?s"CIGޤ0N:rͅγ~dcFn:|7%`ZP_4mb=_t&>/p@T~lIU:^N?Ȗ3N9XWBrP5zsʍs/1vw}ZGdcs2 Xؒxͣqg.YIbE|#~/*U+qа^g +r_D=D A,>[$U]4REq"!\1Qmi~}n嘫kNLy{r7" +OFX Kފ%Z[iyRPz99ԛ]S}v2~ >˥)x]䂝f^?XkX +h/D@q\ ۫z$XbIXGfS{M 0<LEDIIZuԴnc\,)H; `?]h/Ạ8lĮW 5Vd@bdQ n؂@#piT\"hwD#l" 6آ@p +f[-s9޽}wZ)uų tw4ʺzp,zFC~[MqiuZ!Ѓ.޽ۯ7bD#m%Emy5p q래`;$c2L&36S1 DV1ƻ!PT׬yՎN_C/hsx ȞQ֛I Ț=48/ɨϹJ &1iXU̺ ya,6ȠTfY5q 66mKħnKaaAXHf@O>9pƆ/;UӐb:WiBuҁc,.| Jr1" ~=osb#!Y^g5Ve`˶2tc8N*D9 èG]ͮEX ڢLB %N>8MN{NOoÒO-r+IȁqiFkd!gD4m  3iZtg_  ';=rz9[KC٠㖢}7H,v^DgX9{Jp+NFBt%%2rh˯"E|# ,q'ZB&2)8IƘƈ~vs-Q0Yi&W؉Yܓ_ܽ*(YD>b#\<.ߢ*/"1j hru ,vhZ]̚t3ݗIwDX 782mqH"#MLt9oxc:7NB L"Љ($ +ԇ=Ip'z %>/ćU&,:üODe#D~`&Æ/=U=Rn{ɶT}*RwTVg?͋W 7;?ٷ rb8A)׏d%XAZ^"!L? -28 +~0Dه;m ?PZkbZyDN [ʝoK2Ο!cILkZ^ y uyxf6$p*1DPN V4!}M9c౓̇ɹ/IIzq,N[3?5+o܃:0nߐŞ5ŠQ`y@ 00H0.A!c-0ED@(]3xڽjꮮ}N ޽ej-I|xBv).k)onm4۳51*6ZR_8ȁ#Yma :26,z˵W c}$;Xxf ԅaIP\dkO5Ղln>u*Sځ P40M3щdO@U*ߎ 'F[m9M 0P8<(#LzYV7=iT"Bg ho,82ȡ+.2p| #d AA IF>Ņ+u*%:^I_{FO3xz=zKO5vK)Yq4p<;#YkڗE=0Uas [Xm{g&Z j+AƦ< 9w :=d+jW2V,aƝѻ,f qACO  zc`ƂGJ$RHDdg.QMrDp柰B+pFY[U,QeOVEY[7jNʛ:[bqh .-he>w{4ـ_n.?IzqdLuX> +(A),9ȩ|q~h sєQUU)kehb ;a*TD+gDz[b\c힒=R0.yWRӚ|Y~B Bq cC?om~ߝ0gܝ@yo=A?J<|[]?7vDӵ8kU7m-g+yq(NWBa)}%hqMbRz Z{뢮SXlAHfUs{,@4q~^&7g.#トrfB!Y?q?|bί|s!?u`n0h#1b[9HLoC@{?]kx8YEYACl2#U;ȓ F~h`ﲖ' +х @U-xiZh+H|#YnZ| ZÏ 0mh˗:ӈ@~qMm9gT4Ŕ6DjU] 1t)VJ =E#&+:OaWe|3KͯY왇B@zI9^Y> Ԇ^Ic#bҍ;^y2 ,X:@)iT7pl.>$ (z"V^~̵l˨tZ\$ +JگcwU}8Eg S2ܲ2i邇hkB/%B}U +jэ'G]D!fIOPG(}ٸu/NՂ2p4νDcʶ>QQ" +, +e6deFeXD eC6ppD@ETΥε޻T/y j8%%HrΚx myM8 g;`nèM` y))IaWA%4:ȌQ1|pK>U؆|\2UcrMT];[T{Nq|2% )n]l1K-PE^県%E*6eP6ye>,-ޝ(*x?D'PI%ho&c~YA 1h]`a'1(uzmUKKݎ}j%['5 q\sڰ]~p g_^..c9-?vH..aV}_P*/>>ax &# +js 9U>r61*5wP2m@tz]l +3k3܈ciT[Ӗ.z6~mo9/3`D."O.JA;S$7:;D` ۇ!Ec.=WJxޡp/=e8='mnM5V +߆]Bӫ_eWvׅpxpsq7((T5yYYfžcqQE @ׁN4+@1($יUHӊۅE/`vG%$~Cc)8#BvFjnqnI(a >uX B6()*!+ؠa6W¤m6.Ld% WB[C]q\oIBD&V]t1S&X\Z"VQf٦GRV[.¶qxIk~:pk?7*uo+zB r? d)%^ V32|o?&&J)m|G: -vbrhN h|q]]e_v?t)B/K.vJ ٧_KՅu*B_KɒSCt1GHgT`Lo!PNKsNٙR荲!7ZIPC@P`A ٜ3ٹړ:ۅ#l#p'hoZ09:ӒuO%#BNL^-&ZrV\t3 D1/7D/;mN)4'm4/|"""5"6M*^De+*$5e]U٠^Ρbi/i_r\X!8"n:*/, 0(Skّ<p +5e5׊iY)т4žc_\b#^ΐbx)$|9a>"8 (5FuO1LpfllZa"6זhL%<2ho2MMg91uaf`O6\T_V]?dmEj_19A&֋]GcoCv$ޱ89v3 bAATژ"lhC3 q bG=oم\yM;:s|`j6kMԴ'):tW"EJ*PKZ!BmNT5U\EXN=v':PW}Sau]6sv.- +|;Q7O9[:e%eYq{6Hy}xB}!MJJRytϼΨUa3_{WÜ 6"}OX8of,H_߄IvizҥHuO)76$ߺ +;URWXQ2$PpV5n^AF +{LҝUjPo X<G'G4NKcfA{Tj>'a2yMIl ') /vGfޤon=;z?0S8+ى_>f3Ŗyޛ$Ԩ2{Z9|~m:zft4R[PsEYᢄX:"ZeCv bkX Jlt5a8%vL[و˞JG&4G\u*:Z( Qtj չZ  +@V'B^b, ;a^.f}.0>jml5v`!֋joлO#9g[E%{2Q~%2(t 9ޤ pW񲠢5ʬT48CBq& |6$ M b9SHٍ?5 g6sVlHזSY)%:@5 +B*LةYh&Gr703v~n3d$/FǮ(/:=Y/;"5Du:95{ӰP)ԥjM)Peoe< bKqvY N?$?sl"W<ٸ+D%6Ep1l7ңtaػggOeW]ǫyyZmǑE(Oy(h uTFD)G &@$4ܠQD^Z1UtU[u9]0'5Y>|w{ lxcIȶA3 ?JWP!-.T6zlh2!P[DboazCpa,MtRnW pd^%T*21Z]|_?vO;VUeRJ +Yt}i|{r̓7ч=W^T]^T:R5mN]'x^({Zr'Y%^UwݶFg#49g[W^ˉN/2KcEx9E-昼{ i|:v{sZqJy4~|{iyz.+pMLII%rF#!ަc@URvRjDL-cSKbpU!ht1.MQqY\BZpBZ qZ{$fOXCC fLXT)457T62yHT~TgpރFB jyyY {~2x17[RK%>dӛXe0C;;2 4VC ꭑaˠK(?/B   |sc9|Ip7kw٫G~. A (+ sC?@VkSwKr{ZgFTT^?,=0t7I056[[xN/{gHWCg}}N&+NpM>E@ D4 =: +aI]7] +>Q.fik44=2*d:.8}pn&cpJkwсؙ4g]R;%hpl.ua ykww|DI?ɯH7ӧ8+>3[at=]bw48n׽v2=/c-(G i<~b=A޶u:ԥiVq]v&$AAD >qQ+ +8D\3adp a@ ^"a"PPW;m/8{_o}{#~mF8 KQ;yxF,_|&,9@]ne+j&Dޑ" +8D%rȠMűqL_v؏׋hÖa3;{T+9҉~_.Qu!GcDڝZ#R(X_|SD}_|SOF y6dŴpwO~ EB\?$!+4_HH62r F]pYR:Dy$_h7~ ypv?rsLtJ2,g&'4x*K9{IϠô)Y54VVU=%ɕG7 `g!Ҙ VҜ֒ޜ1Z?3e\,-e7~  uڟ؞/{%zqĜ#+⥍lIļ9WY:XePP$%Rb5F{f; ڜxC> iA[iCڢ5RjRsWQ fieL{>릸To[*BfPM4H$b%|!ܝOEO?koiE҂a1G`r>Ļ +M1Ss2MȠ>xW}:h?x31Z)\6<=5Nz[ƨĘ?UY-GN vN s%G Z +Uof!pnKy,dq^*Q=(Q{KYi~~6LpNҖxAZ>zfHSJjI#$!Ah~?3j;X6oJRR`wjvȤhs:CPo8ZiҤ{g5^F1GSĺFR-ń<JK} U-7; SG˹Q A1E)al"C< GBqguc]m=H~B]n2Q_;nb*ߙLJ-u+e+'kCkŻkɭesZeE^qz|=t**@-qV9%z]R #`'/`5(h(2w1\ b2'- .pi=QFNU&$$axQѧ委q_@>M*g`)m=|tPli,q1}]xzMD B 9a+YDc@"86"x5pRˢۮz_9K/:dkO)rA:h6\aF9K-p: `RI]I~F[| ti~iMNޖ&yd>=!Qv@_ bU>KXzlG$(ח,L(2yHS~ :}1"А<,Pe3lu))gY#2 +J WtR`눥3]Ԙ%n=݆ܾ/ot:#],ꢤ.tRưAqܣj8ΰ/#w؇wVVE QIJEIHjbΈjHQ袣IIH%^-fD+T&dz{׻?{^k|绾ϳ`*џޏ 3@*#)$a(_ ` 2L\欄r$= >sCNS9Xڠd:c0{ao  +jm4 oZWI;.VnjAP"FKH]=FU m*Pys,]ͩCKXO`|jTEaT(/CfyHp5UcCCeqj3@g~OoN0ɹio_kЂp ؓTI>~ѹ7Ϋ0Fz[<uc A ~hYkYA#2B9./Wᤃ҆ewo7{NSĕY;%^J., eo  +#|FZCƑ>gk_⧡ע$'Zye +111۵3Бk=a݋Y3 8 M[sFp;F +h SN.gTx7Nw1u, opM/Vо@J.Y֓ 2/ `B)7~x./ Jxga V(|RvคI{UN pzrD=w[*J%g31p- X h=['))ǢE!|# "( Gh=q{q&r&cLD(Qb%4X+?/)W64togΆ>.̷1F +qnUo}`}?3q42{J + +NgI׋cGlWdB|ݭRSרVKΚeBE*S2HQx/ڹd{[OxTw5r1# l1ˤL|381%%'kF6[y%VGaHʀ |]ȯd0ާTEYŖZ0wbOc8c&Jl;:4UK^QA%"Ȗ#4:F ADܪpvQ鶮-AΆ/}*ݞ[Jt a#dσ ٕ|4$MZfzV]e9IVߐtcF쾶a` .$ =%FzLB ?+h1Xid&fc{8;~ a;Nޘ%[北* 8PÜ50;*AFG¿VmÙubU"MP߇u0؇=3 ` CgcdT4C,L;hwŜZ`qNY0 0+×^#4LnXY"`FMLьiv@'SJ;S +>'zF`5j+Rͻ( -S(Ar\Kg<~KB#ʯFFl9IW{lF/UcnφEb0/¤py5k8Rd +T_*Ѱ0@+R"$TyJ0Qe-2-v,^ޙ=3F"j ++tj5v)(h_aQԕq˪4L;^^|m( ,,!sۺ:YM ށ;vd;GOԸ2̼ yl,F˯q8]B5Edszp% V60402([}I8w ,FfowWW9Uu@{6Y6 i`V`ÕhdѰx~AN+O"~sɿ&S|b&21  X +.׭+H8tu̩[.5 +}orVuB6t 4ytjf=KS i(HBL& GlCH4v{%CB }iN)CH3gV~wnNk=kϏu_L/2xI]k!m6>q2B^10E-./?TUv?z.wW`|莮[qӗk/tp;>`CaEj{nW =L#ʵ-͎Β l3ru2pqO8h1+JXxJE𱾎tEV5</v ]z͞{sW/ :YwwWS fZ3;͕n/I(eq>vO-ɹyC:TT)9"t0c>kp >0=$ȓ۞wʦK%*8qی/ðĘ2#˒4'4RI娬bПC<:Hu09^*FR^5T=‚KdDGP ?"tDdd;#tӁyy~0 a$Άd?xNӈ~€;:,q׽/Ӭ3IDYq?ESexU0 $,Dmuktt޴L) +*G+x|Dk9'QŽW0QN_ہsZ(ڗS,I)?q w\aIOJ$knyu0QJ1^cR`QIp/.\[k=` +, +'98WɗVPtlb[קL=n<L_%)P ^Z vXAd3u1~5 (~*"DED@jM.P|X(zC\RGv]53 CjX,v,ibM}G\[E "q 84Aὢ+Y#C>C*v!` ?cřMG +#|%-͚}{T U,(>.@_@^AY~;htG[`! `t(ass΋;ew^%.:v|wFv6:OCG2p^0&;EHS:QB7Mo7P4 ^7&Rr4 h=$F%TnnT7ilo +X %h*v SQ +n7h +aK3dpF'~Z?T{zH 0쁹$1iU#Xh^y HtQ )׀!tFz%kp10J,~5x38=LipD8g#G[ "l3Ie~=6mS?m#p%NdCԹ4onaAۤ gܪ.զ[q$98JOǷ$^c!I +~ӎ7tDԈTJ4\a1 jDRְ,u=awk9 +X8 !1ƓY\zh#GlA~{qp);p?J;o[qZCP #ngdC^6Ķ?x&*ZzCȔɇ20h(Wca5c b(?K-|yښDGs(tb=Gj$_uFY +4 Kqs3lf#-LmAcs0Wf)3eu%uN\̢ uZ/(zwe%_u*JKjFz*R&9yfd w7dXObO^cIL~T1O|q%hQ3F>Lc/'xq^͡,A K$\[gK,~(@Ϡ+3ЯV.:1? Q} 5\QJQZY.(S{G$[ꕱ9D7KAN*9t6"cs M&*inEt*"d9: Q%sMvYoy<?8BI1nzR3ssIS[c'q[u١;Gf۲';+ Ȭ| ,fyJdj})Vيm%ֽGUa{WT0,ag#Eb9QC#ka!Ws_l#U5j]v~Zp38x QNm wq|L]D'&RN)o_qجg)y?9B3J!R†+AYo$Ł~pK#1te]{w8>up6q!Y_6nXǷ|wZ8}W)Zʢ^1Y +9+)/;* KEGv>stream +HWۊ}ﯨgÔ2# +b Ŗw`1Fvm$cTtK# =]'"_n^a^d}{/='3ϓ%!9;<|yppv_UE* 51Q4ݧ gMX~^rucXuj$|m)vjnmkMbӀ6~2,XG|㽇.7CLosVd. c4ŏ1NV Yhp@d5ſAaSKT}Tmʘ8+SThDBZ7tTԌѻl/5H43%ft51!a:MƂ#" /Ё=&Vy K7Tk&D /YI$,{Gu >k κꨉ;_GZ!<܊apOKcxF{0EW"&2o@݋kXb%] :`?SHL;>Y"B1Y\ ʅ@/7ʔ<+v PVݡ٪7Q-:A{BY`/ad mY +VdNr|# *aP +ǐ9Ka@J!Qin@_psa:S9n?'HN!ֆ3 ÈR:^tvh^񓪙5= +7w6[MQ bh#̲ZJ!gfzy!yCBUԩ l#=سd/dK~0{.<"s3[ud_NL 73!I}c8𽰈opA_\J{o^ۥ>-B\D!8_ +0p 3 ]XQB>BnvNX'W8.U3- aň$Tk"@ ? LȶZlӝDUBjo0mݰ vng! EWMXK_KL|j H СxTkϭ?^6OAfq6.6Rط\4 {wos^Zt.w͢Qql3/ٹsҧ['2z1+Q9;ΜEn7mX: WT#e .rfevA +1i1vTkr0ADl'sPOQxġ2xgAFZ~>C$=cb¦NEe_DhoFNt\e$M9<9OڍGDE}%Mn36]rMqegukdrp͉g ,s-QQgy >-Q 7!΅gwN| ,<M+~zpzsUQ%)jcp?Hyd6GҋiD.7@xoH0~}Md38gp=@OesGbX +Fݼ*ّF +;F%0GÞp_~/(LUu2\xmⷬ!~kS^OLPj)c$%d >ql2|yav^uf5IZEQo.vck4'|"IyG״0bJ m[Ԙ:!/VE VV V1 76ST *}g?Bl`F "g]r:) f4}QjVT_^jd8D;NX=$ ͐IenWn&,Q#T* ^rt[}0Mg!q hN,Ix$'7dZS/l oO칁i]KFc2ƻmjBFD* C;;DnNZX!)Uæ nk5EVd%d-MN!yH%R "H` itfA*0Xl 0T(("HW-c?T0avA;Bޤ-NZ>x^Ag n,@r=?e +yD/ݛg: rDbU1_BWhQ+ƣZ+q)M:L)$SACCiڙq,j4^^#$t 3(5>9 -?SY*sΣϤ6B1x[@.(MgfmMx 24ŌdjQÈ1a`N֨9m:VáUpM.n }? +G 9Dkay2:}`6͉XA@UHyIQ~\gy(ü`s:(l!"6xVئCmmMўnmzG>um(WX9xW}40)fM=C 6!QWT2ml\慷fj.*N^N&'ߢ6Lh&uHDNVpjE} /&{OJK_ )hw9H:s=k}lB˲H\̊G/&eCX2 V~+AT+6x.fZr'Q0c&b9 GQN!m mĭ>P|w3\r/gZZR#$h`}K,+[;ݳiL=1=N,yGţ^hғWHXi^Wz$(nPCP͸ÿ2H"$ ǝ?rLE?m'RBrxȒXeZ>vZ9ey1ZKmmq_nx<5x(hU9s<2~S!ٹ7!i2˾dgfQvG{;f!Ldsv6T(Цid8[LA !ಎ%1]4,2=۵-Ȫ=lL圄@9CmfVрfx޳.AfUP\bl ڈfTU\hԖZ*2e@ɀˍNTp(QQ{-iWekA1gϽPIO WΟ'FZjG1ыgxWx'tS-0M$1;&齔-  kt + ̌Re~"w萱'$6hifxTQy/4-ڌl|AQ֭cFh. DU$#:B+0V3{ g> endobj 56 0 obj <>stream +8;ZD/4-IK(%/"GEmW/M4@FFUF\V84+\Vq'(C!uhlBsLHJ?"\"jYRnYU)1+-FO!/L^ +"T"dH!;JL_k+>Q%;a\IIV9(SFT!pUC.lCDe;WS52L_(2\g/OB11;RLkb+0<*J>s;3 +J?"+aITB'*l/rVXrk/pq"]-U,G+W&q@j0?H1K:AN_9RrQa$Q3.YHh"B,%[8BXlDRa +S4$7c7rNkmKt"o5V:k8DEFXn\rZ/]jheR]T-egTThgd$+SF#f;l!/O)3;K=j$ZmGL +hgrEi5JW6+WdD\ +L>?-!-_O#82JK:KmW47ud>j.lu&DKUW,DC3]A +o@ra>+K"I6c9M`;-(-]mD0LGC2!-,0sG +%@KB!loX:do@FkmS'NE]hr-+#Ht.Ur`8g$cdn7+,SJHgtD3]@0Z;g,M(MBG+V,f,M +9lo-.-+Ii+#)g4s!2glOTE~> +endstream endobj 51 0 obj <>stream +HW]$I}_Q­ɈO2EauvTv{"+oߙAA{'_*OfZ~/}Rg37̲A_ž">Gb˕{ϕ7Z[^cIHD +"F$'6MZpNᕸĹNcиٜjm:|` >ÞȎ:&8b]&X jn?;Rc_`PDY;\ŕ԰.F}VcdXJdAq%ʶBp Nkd<]\jc(C͊FC*K* +Valp|}F8]JZַz%kkT j9aW@LbRD.ِc$d9805>"DK WBt%>M{EM7 :>#ykU4!f&e4P9 kdtَ_~u6-nc^Z.qFV@%DA(*+.BŊ ,u( b.$j}]K%ղBr&}^$4z}n!)juxS ҞvKj)#_@Vq,OuO\'a썓F9}_tBG4֏x!peB\h3rgsJPƁCM;xCp.NΒg6*J F@ӥ`S.T\~txhvi +<( I{eݮgnې]nft`6OH{d5* SǢv(xqEqNk[ENaO8- +Ĉi[)IC@2-%g2S^*n=fhت4^ʥJz܊H^=({/(hzܣSHx%H@#a*2L7Mh4x fF~#NPx\uZYTk6 G!|DmlQ- + G#?59k*GwHfs q#@x\6܆/qT;y!=jۍĨ6_!`hܞ69qpuI/dxD1 W3_K~AyF% +77q8O.q]_C[m>Ҿ#24m"q 3лGX^9}h1H%v;@rn+ykK;AXA]ԥOYĻo0G-1s\zdlGœE;kL}-k;RU*kàXu6Z=19Ύ~W Q'#0J  +LӉ0-D~cԛkJ!=) +rca>ͬW^H@mJЧۉ#q'F~:-P=\\ǪvP~N(^-'x 2V c:|}){ZYyHOQ} ˕vG&j lZp^iUe1BBEPst\})G&quC._]BȒ0vV@[1:yZ=B\oAGS=N*=9y<|xr&ɡ%MO8E_-qPt?_ua~F*( ANv9|h8z]AeÀ!rQb8 +NlXk<.̴?fέUv,W{mϳ'nsS)6:ʐ:Ez+{gqNKЕl05q%9p&$zJLQ&\Ei1-ԗsLXDgD1 H-g6d9'0{0K,+KЈvC  / !s1"F0QA9c};е +Ńt.2dFD;>N# >vkl(eC?幜.!CMrrqUg PC'ڪnSo0W &\ADus`#|6Su\n*eOCt "Dw1h0a^/Pװ W36-sw; iNC/jKϸڻuͷȉ} +>05=0+.GcP켑v)`҇Al1x̕X:Evje0׆GBo'iaAY% #I ʬ p~Gufꠘ8!-Oh8r;Tu.PNVM\VW>֤{r(/G~|cnG#ìo'S .$".PgŶ СPIŽOAyYd^HBH4띞4e'vQE;H< &0M8)@-PnRF 9:]J۹O + +:hJj) 䪆FÂcEJ&ьC,r|*(W=;yjҥ^ЉR@cEH ='Ҏp(w__[oaݜ[Oы2i`,;r9aq/]kpj b׷*ȹue<2Χ[KqH0s 3=`R) N=Rk 0j +endstream endobj 52 0 obj <> endobj 53 0 obj <>stream +8;ZD/4dNr-&C0$&HB2HFSs@Q(H&Hc;PoM-+=<$"b_T$Gok;l6Y$,^Z]8_iKX4:lcU +k)UAaJ:E24s-@4B)d7,nRql*DIoMY7"J+@;P+K1@?Ip\X=-p +!r\>fMb_:'U!m,g_pF%m;bh0lIS,7WQ/V);Ec08rIlSt.`QNCE`=qq.Uf7hESkZ-i +kf1#CM#8fj7AA#C_S^)V@RR<@Hg#bFqC5mY\l'+?cI"PPP[(BSF,NM%!a9>Z9q]>&U0egj$E!_48%8n`,frkW +["q]-+fq[uW,SjDZSpM1"+I)$bD5PaJBq$Gn?&>"q=Dg[Q(/SVXl;+jp7*Pjqr%0r +>D^hjB-g#d]0&M'o/;Ia*\L$*5/Y$l=Qs*E`sJitmumGd!#*1>dJ~> +endstream endobj 18 0 obj <> endobj 124 0 obj [126 0 R] endobj 125 0 obj <>stream +H\_k0yl&Āynޙ +(a}vVPqrΉC{&ⷰGySr#\fI%yܾuXm(D⩚71uX W1^xAϊbfe:H)ESFty|BT(H\K$aJS鐌HsǤwސv T%͵ie͵{9퉬PLN3Ք%ȹ=3LV=Q* )eC3]7ܮۆۭv&򿷔mJ) +ӈ2M>mzrI]OYg Yaߓ!hnﻵ.@ѧ] +endstream endobj 126 0 obj <> endobj 127 0 obj <> endobj 46 0 obj <>stream +HWَ%I }_HcJ%#!F0tI<BCOǒ7t5=ҭ\"˱}x2<~a^D}|zջ߾?:=~ ~2\r#7DKcLwN]_XQUԨ0RY ~( +>ĀOoN?`I$Jft 9Ql?f4P%wuoNY +b~^; $~orBixpz2F'cP7{ 1#ԮqnN!T !(琪vY|?u1vo}mW}.7 yDs!?%tj;Vg8ٍ!(@HjaUUsRi"?:11=Cyl!;<ѸxT֌w܊x;0F` ɸ1!g)L/ 5w`TS0(G!U!Ȥؚ887ކWEvӘ #{9H"Fy Xb!dhjJ/TֿR`bDGBJA){5jU+|݀ 7^"Kqν?_ׁoYk?v^%F(jr>vӈU ZH%kϣxKW.hMRZ1MXN:M`b;t@V OiQ38wcuQf[T '| ^! U$>w'5'to_~~ ;o\d)<,tYnY&1`-6ͺFۄByIw OTK<Df^C3sQ46\n37J\Qx }f;`8Ҏb%"TVmؼM| i3*ha#ږJ:DUyl3R9mO"/ TH0jFVt%^e010a]JChn +[MYߞ!Jɔ=~"kK)rdw,j.='ީ +G_ht(!$ԓrv`T8N(vf'l:#Cu Dݳ:_C_SVӵidnϘ!J}V+eLk]ץl\S-TnnŸ<򋍏W~MV%c{B>瓔"5P>vb08R$IvߓWѻ˷+5j{,='&eI"8JgDmEPy nD{<.qFYSfE ]S-Zwm+m<Ĩy/T%/L˛69v#nρ;:?H +]؂ 7J26}yCl)el6HQX;.I7$h)V:a HL7J륺wj+iY +8lCIo=1jf__Zo[aj+]ZapC=<WӘbޱ:cd +BT&n >Xs͗rx,휳Z(c;/\zJos6YD%pSO?`Qydw'2F.g;$4UjPɔ~7S!/u䬃+1se;ڇŽNLj™uzjb s~캀cSyꮓ^?lq|Ni nS9 +r9jNTGEmq'к:*M|EΓq4: iv{NSֲ +mB:/ +T%z?N0UL +-,][mE]ARtP"H Y?YN%](PFzlIrF5HFUl\}9M1a/t]˷8HRfZ磮@x|^5׃9(kg-#.#m0!9[cxV錭L~*HћpDrwHƠ7xGU$"mvV˗V/wg.X<$ҋ^mwD.cUd ldl0>B oGd[&l]YuY5vuS[m8=Zb +xΐO^ΒHZTCy6a ̣Ҙ0xH9ݘj l)VJ} 0+ +endstream endobj 47 0 obj <> endobj 50 0 obj <>stream +8;Z\74-lZb'IB9lHO30\l+AD/9p?A2\IW0c0pP`'.OoENj0tTFAgjId[V(81s@WNuI#hH-V15QQM'VBOI:,,HCK2%O.oe3`boL +isHW/s7Sqs!*+`?13oYr8=bD2m5u;#0Q.j*qC4a0&,K=a"I)jUkak'M+8$498(om& +c^t3MI[t%b0M#:3A#!DG*l$#V"lf&uSEg.UcR8_JBT8!!?g!4P^q\/Q32h,ZSgSSb +[BEZ%aWX\4=LEa--O%H!o:/s[n?fCteH;Ee=C/7RTb:d8D+?Ya9s-`ebgY9(GoD(' +7=c#u4#\O`kfFiK,-Xib +Kq=A$(>>IA;ABZ"cu";!>YfC[ZboZe2+9LD*+C0mPIN@E7\KPu$CrIYOD`tj<)Ym6 +B_\+G?O23Xm=XSn +7$9@B+K?nFa.=[(B[TalQ[:RDSTMuh]b0@-koK66a.A)uXZBd\;PA9>L&J%9'J>qT +*.,(\DP'&!:Nk608a\K=FUk-,#?@IMWqg\^L`@=mR;R-/okZh6REsUAMX)f5!or]B +T$s[Garqf`o-kGn[>7"1CJfMorN*s0;2M2+6>H"#FP8`(8Ym($gYnGc?h>Gp^n1W- +ccq4_~> +endstream endobj 49 0 obj <>>>/Subtype/Form>>stream +0.965 0.678 0.196 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 406.2877 565.4614 cm +0 0 m +152.231 -179.365 l +-332.917 -193.021 l +h +f* +Q + +endstream endobj 128 0 obj <> endobj 48 0 obj <> endobj 43 0 obj <>stream +HWۊ$}ﯨgCfDJAز 1F#c}"/=3+ݙʩʌPwl{YNOw߿<'%rpKƴ<<5O'51`83> Dɬr~ɬbӢi7WZSMw|-ߝ;r4E X~4#Pԅeh2>W" 2J~j BTo8؏૽ Bqe^xQ[]( *8Ү\?=#—J#Q}&ifLYi1ѝV( >Y/Zfi]q;Ւ8"D: f#\̼ s9.Bm~cրs)ٜ,%lLlKԵJ7P<R|mː X.RϨթgmHs; `$omQ5'r`OM0r0 v18c.4=7#r8p +7dȈe=Ƌarn"gVk;yA_ʡ !@O¹Kx ,D%CJUA1h(|4H. '{(8j:?4RD)26/v45oN3\kͭrE<7kE6Mqx:55*j\ڙv:0[945=uAҩY9aӥ9Lw)5- Ȥ&st3aR)TeN}hc8d~2iCLH +`-u1\Gʱ M-|̾VC*s(^w[FrtԈTk $Ekdւ &Er(?\BKvQF=5KbsdĻ9O_GX$`>jx =ᖥaS+xKQa&p0f)ztSݫza ?!=_Ť>^l@Jw) &۳4Kpnt W؆~9noK^i=[ yQڪlMZ<*qנhؗ G䢝0S&HϿqn"kV!0JnQTv+lRs)t6Z[%t7ʌy@v] `JSH _h,@3*,vNQw:sјD^L g|"΂B5)m~4*@Y>pkDEh~0x42`9K@֮MUPԺ* 0gs nHjlY=9/z! %t]bWu9{Zb=3*> <9~Ϙ>G[\ocp۵8.y=_:陽pNo-g21-Dɬ<^<ͭd1p͗O't:bgj˳7(W_Q_5=G_s98x@︈ON璿爵nKX"9==QU7\g/ םՌ|6vW\_մ?I:V-T\8rדtk("у8s5%` &zEU`<"ۖޛJ߸i>@`X9u2t3ʠZENHs`W߷k;N٨FllJ!6DB됷"ra +}Yn4:dD۞7 +}qG]3A;4,F^l N^DS.~=!t9_ffp;W6*~&&{!Ȓ=&&@kn-Jm@Њ]qTJ& &X#8M+rc:#.'/:An4{VWl=}i:]zpUA|p؄exeH@09;\_"χPyaDKr 8H*KV,Ju9W3_) +u=FSsolLeWelԲQԊm"pN?#n*971u핯`.G(vrb12l53UjU19|;~G^jBHC!WC>7mH܅t-<+IO:JqwNk%vZ6|E۞oہo:|vͦfƀu^\yJ ELcm}VtLHB u+}dpsw33T- I8e٬=Q?9 ~"{XJT:tʿ7W9IJ3f@A?L!mӻ rafEkvZ5$puyuv{(ava>2K䒸1eqje߲'"xkv$_pF]C( DF}v( +|{:ߦ/2DbAo/̆5\\~wZ:Y +%fJp Dz:jij,e`\'M]&3`EĐ9;ãFX0L؁8TqPN}D*s"Fgzj0.{3ݨE! vHvOk5"˜u/n"23ro,l:TadP gv>f}%i: YxiRq'9d`QT^tt2`Q9ٴ;J6vS̤ .,^ՊCs F2]e- 8`]٣`p(ϲ@Өټ:l!hctҘf$^-txJnZ?Γ,|g\saŽ;c-KtЃmmdm P P$sani$ (q݋Gz):J)__| ސ$@~h[rPдngTX݃H TWVw`=GBCڂQv1n Q%#;)B{=hc*R:>lZh6OF-1ZbqU !znj.{UρQI87vDT4\Y%|}jTL@<6T^mT鐀˛ɾXUgFh*TL,H7|~CשPbeq.t}ԥh <2봍mLAvR5-f +.`1k Z.}A1w,}чK:(:FQu^ۜ"N!1=?M?4x>/gJۤoz:Ird}|G: M(ݍU`U!5tL`Ĉ;|}j]iֵ7=vVuXo7~=9\ +UHAtzנ6ǀ]1/$)q T ճ +endstream endobj 44 0 obj <> endobj 45 0 obj <>stream +8;Z\799OoM&9U#$F+gX7ar,5X/@4n&*l;`6PAHbKlb:XI0\AVmg424ao.6mqU$9SK +561]!7rt/l'k6"i?1GY<%jKbh_`1>I]!/1RJZ/6DdI8-@UAOgj+h8Z3W2Ep*<)XPh +BCg\\rJQ%s+hcI5qXa_^BWAObF2UK5oh/ln^6dl9YZY1dlFUg#!:*o#=%^TNkC5#n +oA$V_d$J>^>7UM:5Zr!_X.JKR2!Ht#1uk7CeF>s.ONc+@YbFC!A7j*VZ[%'>Jdk3W +Y;,u/YB_q9RRr=@l.AIc9\.0=SL[\XE@B^%_`>q5Jm4)Y%.iGEJgJt2'B^cb'g!'> +*(G0-;#0\T+X!-Rl*fS^DS74GA$N"B_4UPoAO++YH<>4dKQIS/J="Z*]a[ql4B]Ag +omAM6K#MVO=$jWMaJr/FBZ47*OS+Rh_NH3cA,tUA[)DR7pqbY3hIH9g)R$S[4Af6, +PZ<74::oA0.'.&O`W-+eIX2X./I*%A\q?p?DslsJQq,u?+BF+B]8V2uaCr]8EBA_= +f-`'!hk(VL3&-+`-Qf9cV?i4`P=8W85`V7L3+dg*8$JlXD-U@RC?+$[%-m7[^`Ea' +pOM`tmE=G_hA1jNU!A:"#O&`Nf"Pb$.Eb/kF$l.OUF70J>#Q1)pHVm+_Q/1*(PU71 +2%#!A$Ee)=`+Pgi".4Wr4An+G_=/Un6@;\]XkL%r!SmqS3pg^g^83f+VWrK]9%.C0 +rWp)uS)4ZD"]\u"cuj1c:!a[S@K_,b!331]-N~> +endstream endobj 35 0 obj <>stream +HWk,>?WZ2LxL0I &9L#,ӒyTyy:erҋ<=篾UԢJ.5|7Wj"5"LWb?5N8ϧ7_0$jj^.*[yR+=髃_-|sȑpdHyzφ ?Nڬ}>\Y) +ي,Bw+44]x@*,ؿ*hȵI)u ]ƌojA2؜%sɮ>剰 |ҰE .G=CaaH!,F@kc Z/INy(!>UpTY +A.F0]Lƃ2n'azXEҝT\Z)w4?EV#‚V :1yZsA;$ ezH}A+4VlWKlQrefl ȃ8~HLYeWGLw6MI!*\8kUbjgk'QQg&^`dž) cӪ63"ɋCϵ<1])]c")6]L68hǿEV٣1Ql)pw@#, 5[8kQzPZw==]5-P+Nfڕ BJ5!|a4Jz릶ؗ9UǞ)ɌgvF )iϦ}2!X)l$.b(14keUqK7(-D૞Cpb$3n;TѪlwjx90Rs}5)#%R~킺r e9c_iќg8H +@UuIE*4mUY\#c7b&[nw@/٭)ӭ/w8ֵZ]PoH3&9XͺcFaxr3:XPH=7jtџ l]g,UB36{ ~pZvmMAIjA܈H0dZ!_YPu9.F~#Cv@v-u) ̸VY֡nU?x +ۖeI*x^r!8lmd[)#ZY2'#}'EkJq\B6g ϢH}vll+j?ӹ^h?sRNǝ{P):0גQj3Ͷ>l, xzz䓵*#CZ~H/}3'ۜfK CFeeǵ/} <;8#B6:dq !SLi3 +I2C&*A5:W)Dk6gtu_wHbb?(Rj ]sdb!Ag|2` dOUMv:v0<cЉ1T]`0[sMb xfGD;)f7`]# zNHhGøcp'"L\d!  (t2G GۄsYޚ[cꥸ]u.ezج.=Dp=W/ v#gn[ PRc/% Qwẏo+chp=tΨ|/d-TnҙГ ڡ~|u G!&Soev۸~{rfzZ2\[K.Ȥ=a|@E>JFUvam4sM@!#ʸJ.«m z2Iע^&s:%lbu{o ^0joIpIYA]cmMb(:."Itp)>|Q%g\i.& +)}-j5?syajdU*H\ G {?qD-iJEv~nn51}XSr!18IvU^ LArMt?- Ac~8P٪a_B&+]pѫNu"r5iC Y%0ld4Ayz,9rQHjM2%Kx4Y<Ylfȏ:|4L?$6՝M)\m(rt_'e̙7io 33uݺv:qяGX/ "Q~GLZ92|eݦ Yʜ½ulSZ.0m }ιۖw-"_sc:ކ]q!%79-@IchK[ص#lHGC[ղ#9 +zWIh%?VFp-~*w۽‰mv2##"!wG]ȯƩ%"슘*@8(VʪaÉFj^X%~VE?ot\M+͠]~JE&T> + f̧.Z#[&QpJY[ϹAcEz88ßvCJGk *ƞ/Jgh? zvLK'/ݓ ?: 3qdbRJǝsWU~X^U}F|wX6_}uSLܕG} y~>o)X #a!BCaA$k܏f@1[p2 M xQŝ,:9!B+udS r,XB^>PM73a|6xhL:%FJeeG)9 P!+ޙ:Bv)íK6z:2ffc~5u{ihIB5vS|*nRֆmR%,Z G (s_vgބ< !BޘZ$ZloWXotrb4|Д*Z]yitK ]FAWc=& '=ߏ.f bؽnoV@=@7`&5c(Z#r +Zݬnd5^YҦxLlGgfJ9R ;"+[E:sne h4X=3&a5zB[0yn˃-R8gi) 赀p6flDž;\VgIHoc )F/Yq\e66 ;r.q@cW?l=hm½-߻Ԅޔ>mrhb.`[k L|6fO!5|_AV^9ʌ|FKg |5=oσ_R]W#D[$uc|Hc.}忝RMI +w(h#ǍEOnP.jݜ7"8!5fWu&n +.@@mȕK cy%}b(|.# )]V_Ǭ}c,Ĕ)tS1KMp3} yEfF6֦[I9EE!)@b.{f7VH~ϫZۄ^M˵ .~α +v^^Oʮ3cvY`!W[wGMSCḏx]=FVkWO/2u峾fx;?Կ{yK&qC,v9lEHU:0n4SQeᦷ䴴?,E`M.$G14Kj-_D0x;!CIza}{\KG* ◝~YjÉ9rˉ{&mwQ .QFs +;e%51a>9x~x=*k*Q'G Wb➿>fUBp>զ~/ۉ +*8vw,B&'^;$|BlODOx^nQ%vEF&]4eu%&^|8HU/ېwUS׵8|q"v +cpSmR4čG_:`tK_>`Ij0NT.yvha.QUPuV 1 +VwpNO?~'p)?}!d Y$cT?'b_}'W&>`jO^:-O݌]b%dZf ֫> N_ښ#i[bn|n^ݻwoS,e(9>4bXw?Asxѩձv7u}5̷c1,}Ssdi1+`1Q1dQ  ' bWqZ[-wȢ +endstream endobj 36 0 obj <> endobj 42 0 obj <>stream +8;Z\7]lJ`Z%*j"=hFGX$Y#@E(b?JqVR.;G[IL*6`ne>6jP$+te"#eg&&!h0tp9#L8 +$ZR^jZ@2oF%mGkkH1#aRH#BUD9iC4A[_r,'7)e?F^W@jKpK7bV]esX_:uAY%Oqa`Y +<'75X>CVhPmF*@5fG00.',^0R_#`&F[C92B0]Wq[j3Ai6hrj\2b?e>j&4;!h"%kaN +1p2e0j#SUE?n"mM]P,oZVB\oFcY7dD$j5 +Th],gRBlstP:!I6@]resAacb9!mQP[K>8`cQ7OF@iT6[* +QpCHLdq#R)CJ"LdMY-fCM^&^3FkrmBF_0"[9WZq]FKU9\nJ:DS&D[i)URLX9l_g7lds4P-EA +GO0)$!BsPmA3`#7=41%mU6E#u;Xc2ANZo`sbtD.:;W)h=RWcn8O,tS,rc7hK#.>i\ +fi/-`>ar^0V"tgc^"Oh<*1L(%Snh8Db9c8SXU)k:m]7i)A9S2qInI+_6$.E,]sXm1 +\kP +endstream endobj 40 0 obj <>stream +HSSWsO1 +-E@+ +ؖ*ݮmqkk댶?ֵUŶaVnUo$H;psrgnI0}*1eeX>_O7&= ?'3 ' W9wfO*tOS$_y4vңQ{?{[p}Nɩ>G^#g^{aÖ0e y{W|SjI&Q̞T_^"MD\[C!F䑷1usg4v ax#h^hlhAn^5M#"M.$l² m^y^T)sн\(e%~Cyayy1y **v]QQjy7qUE%fuDy|$Q̼Ds慁ɆLlɓ.1KKD2nveqh-t~MV& 6W wd] Z\8{nEMqZ4f,K[]X6n&㲪%qʩvM)w$V7/D8M*g:rv"V̘7?jyayyټԱ1.aΆw?ȯ~MԽ]*D' 6/gכz->&6{kY Q + گ̦d,jZwf\v/a7ht1)'zv}u_kPJ⊊Q9EUfS'ZVEjDӼljoi^ۣ^T2 ]U/,__ZRc?jk<er.nQom|ByyT؂w_=aHoL?"gV5mִAHs_^u7/:crWW{Ӗ//k<ֺdo#k/:q3DxD*{jO~5uea $\pAQv#08.uX[qcZluƢEG`]0E!!!$nB63?2e#{|yw߹{;X6A&VyWkH| ԰4HZ 0o>9:K`#hxp[<7K>̼zOPuA~!)i' BG'tUͱݯ6PQuȩe;}ҷ0r/5*9gޜ^}u&AL|vxJ? ޞ̛dJz ߰@ f +niԴ ܣʰlZ';S|zO $g2O|w hq/m7Lw:cAQ '|c#c#Ffo?0l8v@UǢFd6h8JWsEHxpJAN쥋 LvjZ8x9Ӹ?5|B4y;pMn[)LF,#n[Hdv1K:R0e.(uJT[T4Ƅ(FGk^/;'Wh'HzwJVlZ[Α^hd6{~W%FS J(+8>#,k˟\*5IC<NsRk8GCbyl'μϲNa̽of<'kwr;dCV%H\:Ec1?y4qҔB'ȋ?u}ah}\O؈a$^]'2zh۷)iFnZ9itǸ5kEǭs"mybmM(L2SڂS+3fZIW u-@ȥk1J3*?9#ii +uS/5w`B蓙B 7/?b[me]0[,v?َPng^j#%P; LA[ +%(`D{byHmeQؚӖO#5H;rIY-" c7rҭGU':Nk]CrjZya`*BMFn4,t!~tEK;XXSM@Uʪ9ahKF=wOi=r[l? 1EzIotX-1Hma6oKspa&tV\#U?R]pv(=zccN Ͷm4wnau7V5IxlxuSߍ(e9tMtg᱄-s%ytY;ֶPj :ǼuSfnv됤LF 8/:z`18V !Q(F\FFcF Sdb[VR \Ց6 gNyO޲;v07yK>ϚkEE +-<(w[ϛ>O 477yyjh[n:j~{yHA$ VT)"*V*:n:.Heui]ZQTT +XMBHi9|o 3s;w7o vp!_8`cg0V.HeOE5AnvVX%aQUФBCkogwй=)Df#ޜ֢!pazې?STL- Ǽ 8Jd"wo+{7$t'(^Be0I7ph˶ׇuu93c>,2#4:gxz[ypCO W1JC)eƠ=I/Oۊn],7C)s@z 'ͯ ϵiX-U$nkg'm?%PzKѤucu^%ع{<Egu1ox+aGw T-?BsΈyvqh^"!ذyp+pbfqhpۡ5 +ͫ4ό=)92~O3<[oɬ ـ匯yCyTaPv'B;ql +}o5 `)1XCejoDx*:kc:}11Wq͓|" #`/=:m8x-邆WaBO+~A` +"].GU⥵UŻ"Z]EZ"wP\vya=g@ !dٞdr33Uۚ`<&~;E^UʻR(u-A?:CaP[Y:L#qnçy6c\R|/ufF¥<Àt?ES%t Z=W|6@c0i +v2b<>~{Cusvљ݀梃}< 춛a[p7#u=,Rq",HRf!fh;= m.<3ϼ㎡b=Jik~5hy;A[<3)$Bjoh2wύ0I~F>1Fxy~ܔyL1ׅK1/'Qynuuշ@]e?'=#I؂yLxwO@xR9s)~~ni;t7?牌͢?aro^Ս{GF5c3ǘy{ߏj 3g@x荘x1jnuSo2t~^8К$A̦~oF?g]?zڔ7og{Ip~1V +>?ftZ X^ .wI<$/yNB9ey)Kg\g..Mۚ%Axf<= g' zr]F_ƻ!Ĝ+H˜6!9.,c=aݖD0>l6 8uP)TGraDy4&O%ErΟf;猭8'_^12xKZLVcbC|(1X [3. GrHedc1 +DSlJ dT.7U̔y}kp.ByE=D`~Efndd&huӲӌyɫ1k#{ ^ g%3%4%fw?x;g<'B-q:veMKP{wŘe񱹎)c^5 lJm`W971c^l|6*uQt7i%Te^u3x7Jb2X~#c޻bg؆y 'ؼrC0>/Filter/FlateDecode/Height 590/Intent/Perceptual/Length 124708/Name/X/SMask 130 0 R/Subtype/Image/Type/XObject/Width 1475>>stream +HOTY?QB%XQ(]@ibXPTDR"`HSt0tv8 3kss.>:44dee`0nӧN XMMM{{h6Fhnn[ٙy&fXZZx.....//kwZq-Ҝ45%-YFͯI}Tdbb¼A3kiaO*l#nkM^v__Ϥ;55e-E|544488߾}o2reM)'%%i!J5(QX fIEEŞ={bbbQ7=w\ii]W}3}KLLT c}flllT Xו۷o{{{~}Utttll˗/ vlyyy/^$˚tÎ%… 񕕕ͰEF5**JKA(?XliizG瞕eZgNNζ&~zDDDaaWQ9SQv)a<r?ǏT***6i5DGGG__lVQVx uqqٿXXXAAoGFFƦ 3]uK +..VNpvvNMMtuv~{466>|ԩSM244xv] X?^^^n47PN]O ===..wA}333S[8ycǎ='yԈ4[tttQQRvڊݻwGFF|uqttT]Jt?UUUKKK'z1^BBڧ׷qu5tvvNMMiSRRޣӧOcmM'&& צKFFFFDD\t)66ʕ+S,Q+/,,TLMMݹsgHHOJJ + ۱cXmJ Y1ŋ~~~W__VnWIL:.'JMd"JKKKڸN@9!_zv:k׮),..Z܎PÇDOG(&9;;'&&*hEӎt:HKtUԤGf~*#;;{ݦZZZZ[[^> 3ј 1= +-Y]]H[F@@ƂuӰޣ&8@՟L^k tssӃv?^cᑗ9ֶ$%Y5P8g*ͩ7&O>[ljj*[˙+K(~ׯ7TV9PFM=:%%EݻWYNڍ +ڑ%T8qǦٳgjɖ(&$$*8o =}z˗33336z~0PWWq}*Tq>/vttDEEVVV͙.k*<OlW833STT䤆nLB}s߾}eeeOJ(((Q㭢_کiVeCUUUi +0L_|}t5hjdduuuTX ,aa*rXvvvi$ "mz⢩d TW# &8LLLPr>,<YUUC%$$Aollddd|,@`ɒqX|:kO°<K=8 ϹK‡`;y槑"az# sss43_~ x:)ZHU%&&Ev҈`vvQ&tL-889蹜rUHbȝnj+**jkk7tiii}`HiĝpX a0:SWWWkkkAAASSJ;)@M8>$?44ttttPss +94]|}}땰rjoooqq1&&KsV:{{{T`puue + W"6../>77<ηJwwwM` %ũg\" ʊ$淓ޫW8E 8"c©)bfXCA{1՗ArSd~񻫫3C)Po %%%%y%Q~xkkK B#z||AAAwvvTVVb +0,,,llln7n`Lư@ZYY=z^;/|*-~~~7o>99p!'&&rss xÇ@u)ԜS+e+V + وmBɘznnFz rpp@fvvVZئ]u;0RJJ +d0==MtF`!1pNuu5IY_h̢4r9ҜFe )avӜ|u5"Uv־*g(x`0[b8B&b/(Qhh&7N?L3?F))))VpӧO_?0('D#|%Zx}6t;+ cFq}|0_'''Gc(rc->>>k Kzky/(xyy T$2R(vjџ*Y`ll,+V)xQQ 233,aGGGAĎ[YYt:.v2::+.٤$kkv+...??42fpXb[HFFF*gQR05E9 ÇaRooovvƶ~0F#ub"]]]566633&[p2Rm 3~޿D*U/kpS+~۷oYRRRRRxlQ(ȼ9,~)Cga>X-1}n˴}~z5`7.iƍeuu5x*A8 Ύ-3R b) ^ ΈwttT' Tp<Á"u,DHHmzz:DZcۛ2IR__)3 W]F{cc=C4&. + 5ErohhOR(gggkmmrŬy=4 НxV#0NNN~~Cٽq/(Óc"H )B ElI97r6NE(~=WϚ~nz^=}k_ϖ^b0d2>>g28Z8'(lpcVVV_'DŜ,⁏...0h [KKK'E`uFں-}/Ér EmXQ^%011p + 9W2LEEE0a\\k$F!GƦ#L6=}C䜛[UUEIEN9삳]RRB٩?)uuu- s*:K9$A\r?SA"%E "+Vk4)hDL`lvrGPloooSӱS6]*UT)`0O?x\˜@sc=&Z[[ lAB~QP=qݠ)@Iz鰗/_)5&իO3MMM Y$R---xqggbFLs\?7z8!!Aqz.;;hr`|yJIIh4!!!`< `d9zs'V{, +W{{{L= aaaԔT +eM$_6H@M^S"BCCAQ^^xIb'Ǐ`tl{{[>ŋQXXH@{2s977'Րa/_REȠPR>{Qoii)GTtTQ@RC4:BTDsK;Rhgg&$)D2 0==͏pu`` unMTRJb0"##1 fxxTwVN`\#??ߑϫWy(IaLnnnbC 'XC鑾 A]]]إA#'''0888`.. i"UkE.ϟ?GXK766VZ8}6Y*UTRunmmrՍ􌈈vyxxp4dwEn\flׯ111F.\'''r+++|\H[liiEB\c2ϟ?EEEEyy~عhjj"=oool /,5LTTG("UGGJ,`{5HiHd_III:l6Y,0БP8` @Hр:R ȼx +#&'<!'חH)###.. +utth˗/Dȱxlll0CCCT?_\\)8[Y`M~yTqDpwP$t +AR)*MDJREZ@L>' s{M>5{wޙi(>ُd+WFs*ZM>Ù6y%%%%WNj'?<1Qee0 oJEa=f_K`tZa522"A𣳳X9...%%XOOeVvtYYYlL vIqp^ 33#r˻~"L#渲"###sss-eNnnnvvvN?u27 L=>>"{"Hc%Q`%Pa:88 +银\jjh:cmd#W2&+ +0P"T#cQ.Jni<1551j¨PhҢ] -b nJx-l1I8coJ;aio7n܈e8Ǐ`naHHHUUv޺uֶиtΒ'E,9ƲϡB|> +hz}XXߠ~+a@(̢Z4F-tZIII###;;;_cqc!<ĕ@{yzzGGG@_l#iX cEHe7o0%%%TN+@d2|x]]]}sKᄽ=&j+)))))aO88na@&|ns+򺾾>::J.'b;7]昞MV)]Y]rONN㚚FUVVbCCC\rCxG"Z+^=z,bkk"X CLc^LS7^???QX~bFu eddz(l$8P AHѴT-W]]޿_fB邃]]]®Y...4655<3EYM;c`[vv6%$$Dnnnciu섈%$YQXKn<r`(LZJlAAAN֢aGfv9TTTXBbC|&cIIIVE+)))))V߬Hv²qX=w \?I#KO-#IcdBKOOt%-0wϞ=9NAYiA|4--Mk .ե鲲pd `ϟʧ?Enp Gtׯ_Jpe7ӱʢ"^3\3>|ovwws/--9Fqo߾222+anXERMMMcoo>>>zdzY3rb}333]]]_z588XUUe uP +k@)BCCN  +s#B4r<<=99i6p,-wa nb}Ŏ\iWJ4=--mqqQ6C9NKE 2<)YbuuL%C!ZYlrr2<`JJJJJJaO}}}a̚Z0 eFA&e(2aQP*P02 +(B@E52G@k ;ǻs.{z鵵5h00J ˡ\\\,--UKkXI9866ӳhs\ZZa X3|ssd2sUc8x6I0?MOOEEE Mg<##ҥKˍOv +?deeIPr^b4y+33s||\x{{z#kppblr7驩rp~~-..*kkk+++وGf=i ÃĠC&rz[[֖ZINB ?j,IaUJd39p9˗9 iddqB333(žRe VWW35&? ֫MÇx=դI&Mey)}ϟ:u*$$G$,, ¸+Dpݻwϝ;$LpZW%r! `}}]DNMM<8wNjwvv=RqἼot&! '3=881IRZZ:;;+3j_RRP1LK;V$~Ԫ$'0! 7((Bt/ ɓ'" Ċϱvww>}z؉ F_niiWƦflxP[[=6-ܲ$Q3>>3jҤIW %Ǐ...X#[śFFF/ +D333jALTGVWW={FrE9>00N9s+H``!!!$𾸸8†hend3tg5L.j򢓓1̫'Y;y$EwG _6piҤI&Mjepht05ͱٳxÇgggE qv. ]`eeeiq/^ fdddʕ+mۓ@&'(YYYJyljj$X_SRR(ϟrfB,pBڛ7o@|(ͼW2j}1QQQa3#?AP yI~>IKB͞dh8t4l63}̏? 09&&4Q"""VWW'3L&^okkR魄jz}bb" F'lj!| +"K>DC#`wN [RUUS[[gE*++َ9R,vͅf3P+&M4iwA'?sruuU& [fyy7LBds\:P( SSSК>騇EA5 }UAtdm'ŝ; xvCbe)*,tuuݾ};???%%%+++` 9&M4iҤ°lLZb?NLLH丕ijj + b(LzjYY}ڙϟ? xyyc٘;7Б%ńt:ZM }jjC8ʴd͌V5++‘.XuCll,d>lcubB%X &ڶ:Frz+GMzPgg'@E8-3 ,>h#P'gSK% I"HV@H=EQAr^$\SNͻPaj駟jj CʏuKn,,``իWj; j4ooonu읐Eq"ȐUHHHHH2V1`m˨ܱ ĭ ;;鑊,:`IA2ʘ{{{CCC%6888Puppq;C3X csZaN5A>r!Kh +\ !32271t@8~b:Zy Okkk)xCwkjjBCCsrrF*8>xW \zǸ8+++Sj^^ +!,--X\\,֒|b-IQQQLMJL?^XX߯jvt+F왙o=Z`:p G111=\ Ǎ.%CPP6<< V!I\XX_aRZZZxm_bObb"$I(uPI'Y}%##= F`Ozzz-att455ޞ]+*֭vJJJE vvvJ333s{_]]5?f5A K$$$$$O >cTWWomm齲S5iii˴|h8O%]\\%x^< ްrI?ZZZJ}H󂲀???fDĠ 81sssAGj...Qmnn0\ 8 F9555n {8XӧFavvN555{{{kFC,YYY^^^NNN\1z䰳*++`Kϖrđf^ftòH)D4ɉ2,> J_|7o$F}ddd޼y&9;;{xx444{||Ly `wvv ghhHd rvvfA2 d1-PɄY!8-ƆcqX2KY* 37*6-n===cbb()ۏbuγgaw}}]o +`dge"M[ݻOɊ J-$$$$Vwǟ+Wa|q[7M3lx@1<<g?11qeeEj_\\$dkkKO3kH677Ǒ 08-,,^qIX>T΅ɍܶGEE`|"L}0 tAnpo.$$$$$qؐ{}6۷oD933la@PA駒Al:7708谱ijjR>9755C$=^H@(F `.OC4g H4899A&Sooo778|IH(v@l[nqczcRCVAƤ$jk +HՂvdA/?Y} +  [v`tt4|W[;;;S^OX5eoB_ +FyΝ/^H(?ImYq+ޠ2 ]]]뗜;Hbc+YZښ||||?~LY>%4v dKش Ė`lTV + ssssvn1|>|WW[o¹LDƒzzzcvr;;YYYTUUR*,,^\~FdUTTcXH-.RVVMMM)7-= O2;* X`KAO> @x(P;>>'i z_]NNNNFFZ88<,--;}FnjjZpjjj(..VFxk fO)wʂXYtVe"*)%.. 0URpʢhv,x`h*I`PiՇa6GVmhhs~~uttП?fP̮4!~G&? + IIIkkkʀyhw[Ӝz2YNW`2&&ʁ>|(%竦AnnnY4@l;;;* 1Mf˗/\!@&D]ʏ?dOKK44 믿vwwtXb{{Cbkk!p.S^>ԅb +8]bb"qOMMOẶKƇp^h + A?N\HHHH?*γiiiUVVj8)1>>٩t0d@3:77's,--MMM=991?C@vv6ԡlCHXZZ"U|eEGGk4 &-.//+lll +rppQ)VKg+++Bm E2tbY#wwIKaaOVVt~&m1Z5h_AJxb"m-1JZeL[cJLp#"hB \ޔwr Q/9cC3{3kt"i|;k}qq 6鿕﴿yǎ;ݸqC'Oԙ,o{{h4i廐AcE[[7o,</>+˗/oٲE*N>3SÇ;D]޽|UUzi&$O{fDB~֟ ++ae<@KDO7Jur2gaaAȍj,K]\Akr,WoݺsN)/+&&&w&dS}Պ ٠t ;֒'vZbD"Ť!Fn֭Ǐՙ/v#zN0`lP +ٲ<0reF }+u&K2Yo_ʜxB0z'eN*TVj_V)Rmi||\ H',y>|wgJ7_z^َf +Ï?$Pjrcccd2kF`0ܻw/֞d,[\\tvӧ˞)VrD?~X*>eFFFFGGaX0O央 Ǐ/ΆVӧjdqqٳ@`ٓ +377wիW߹s'JUv۷oƍ6m +MF<f I9>r}vwye+Ͻ{ٳ{nǓJ$NEٿ+W>~(AáN}.k͚5۶m;pÇVH]}LxlbZ~։w4 $IGQi/&''3d:sܜ)}/_lv/VRsN{{{].W0rڦ _6h4*L&% +ZZZ^oP!ATUo?v}^W%LJ< _~vvvΟ?-@OOO8z^Qd2)`SSS(x:;;N6hիWr ^(J2a0ljj +B=Oggl&w޽~:h3p*Z>/ ={6Nٳgz^Qd2)Ci㛚BPt:K>O$x|ygʫXޟKZ,P9"L&#`0vH$RDQs j.F"n7l6JG}… Eq쾁 ;CmedRWA!FZA'@$&I$dcR1SmnvIk*(vc~4uN. +N +`ww>xYccceee}}}oo|SSә3gZ[[?$>|iŢO8ZYY߿f/_nhhhllvZғd2dsaaa}?ެ8zhuuuE_$=dȵM#29|~a*~x.]@92@6\?. uKv TIPㅺ ;f*׏(BRF3Gexn)d#2qPaLt8^[ʰhrH r/-e؁l4S~$]@92@6\?. uKv TIPㅺ ;f*׏(BRF3Gexn)d#2qPaLt8^[ʰhrH r/-e؁l4S~$]@92@6\?.b>@E\nqq1\?0;;;66x&80BRF3GeB>=tЮ]n ][[KRǎK${իW$>pPaLtOݻ;޽۹sgWWW<>>8N[[[n]x[`\9^[ʰhrH U*}3۷7~ٻwO>{ xn)d#2[l6^'gt2LR2#8^[ʰhrH Y[[;#Glۮd2p"fd2Jdf68V7[ʰ|as 2[X,޻wuuu>D6x8N'T*߿433S(&M25597;yͰVNKg튊ͽlWTTtuuˑݻwrg+WRo|gTzmm&y96;rkGO?x566&ϙT~ECٗ/3_z_˛~Jbq'ٳwܙ?p@'O!R _?T*]zղ7o={vrru]n?z̙3of;6??Od۴#HL3je$Dsxb:^H$@{s۷k.ĉq{f~~ӣcccSSSKKKVݔ̲yviF(b΢]ϐVL dvqo[t:oPAwS2m$52j9v})e6ӌuQFŜE>!R_M,iGfԨH?2-, it$KAwS2m$52j9v}N OY}D`Z bux¤֨HdF;AbQ.#y ʨh3B>H }V +Ջ;?nS'؎VxX0ir|+5>)NfԨH?2-, itYqJc4J>)uXH:!Rzxίv6J{ɁәWS؎VxX0ir|+5>)NfԨH?2-, it^j^|ZǝNvly?G+Ti6_4!R˗/:::wSN---qr|ȑݻwٳѣsssawn˿l\nLߘh~~{N6RGئVxX0ir|+5>)NfԨH?2-, itz~֭bhcӥRɓ'mNjǎsν{fgg?^T@u +~zqG?oV?Zz|Kj&UxFGt7%3 ӌuQFŜE>!R}q陙t޽;666770t钦im9|С .Z-FoVqS?sLŧ>u+aCu Sݔw'HL3je$Dsx/7_?67 !-YXrscVq ro^ҦxUnTN[ZZZ{)-?zZtuͲ6x'c/^8<<,JPy&0333ܹs###@-#B2JB{;mlE:ٯ!HqPhث) =,R೓h(3 +ē9ɯ4`Gz`UD\.J7+L棏>-G}~GGΛE!P-?̞6v'}ӕr ;$jK@aard:'CdTKNl(tOT&A:.,--={l6 d2vioosP!`t}![c۸nɴfQ\)DHdR*GJzBidNe+>z:@B, ì>VUU%{nw[[!BgF; a[k>/Bo_n!QJqPhث) =,R೓h(3 +ē9ɯ4`Gz`U۷[[[dT"+X*Hv\.rP!B} |!:mvZٞO'tSVXs!z;)W[ + {#%y=4t"cZ +|v esFx22FHr=py +eYqrŪnr677711FGB!-Fj$<*'ƺm6a?f[$Ów{{^|CvR*GJzBidNe+>z:@<<xցw)B!ގP,>Q;kocjp-ܗ-M"jK@aard:'CdTKNl(tOT&A:Tnurr"o>}2==m:;;3;m!BoGH.u۸J=L:'ĠChSIqPhث) =,R೓h(3 +ē9ɯ4`Gz`UDٳgqb+W=W^l}}}Ѝ#BhKb"m0?bw{OW?KC76rf_~MTe٥%fCP o)҃\O#t"\.8PUUU-<:ujppl,y۴mYY~^KBw6-]vqr<|j}IPx޽{yСY7VՖ@^Ht^O( ȘaDCٜQ0'̩L~;>҃\O#t"X}y$Ycxxxrr2ͮ!|>3B!i)^iNl.cYۼ<(eЦJzzzf[^3gjjj8y +/]ѣNv0)W[ + {#%y=4t"cZ +|v esFx22FHr=pyW.rB!OB:^^w=4t,|m/&CÇO҃\O#t!B x0S\ocr~>|A=~˱XT*<_WWwƍٙ3f֪amڪV@6EƳd.$$,J²lPJdhmfU(h63 6I@e):yxbh4 +yxQO4(GF}ȌSi) c$]Z#f&@!BODa%8Z82{l3׹un+j{xq +]VզZ[[n|.kll * +i, Q,34ShH Ig-`G2L8CB!;INFzc/w׸dޡqR&;#D(be*jiiY z<-Njz*0G9T&7CfΘHNa# 2'tɠ638B!lb_:X9sefx5{GZ@D gΜ|2?8SLLL477g2{|>ぉz*0G9T&>d#.]2gZ#f"t!BI(T'B!bu۹܉\G~:etщFvP&YV:nmm[{\Cd-멐R H$V|HWvgLig0=#_u^51Wق{ j3n}S!BHV$-_wwa۷p[XjWʁjZ: BST__h2|?ٶ6W,_thKO*z*0G9T&݇]1@;FeZ#f&(@B!$QewO^b;m-{KoW%: BrW:|8{ƍGWzzz.\ —E=XأY*C!3vgLig0Ўt +:[Pk dPp!Bkb^yxl&yc+׽s•ڽ4t>m||p ߺu+J?133S.j,q\p|@ |xQO4(GF}ȌSi) c$]Z#f&@!jTj-,sw:r];//ߗ:t8yd4}' vwwK׵hb=_wW:?+V"$A~˲(>ڳB^>P;v$ːtVقZkv|$̄"RARc9)'.לu*m5moLڥ.C>nO|v>!ZN<gXy;cijwO6:|}$u;hr"zP!V&vJ4]2D7hY}l)k_8ËϱOvVeᥗǝ+K!u@E23C2ZM픔iTeB3o'2DVé"+7/^6+z;sݾσnrSN\$S9>$Uj$NIFK]|ܞ(4|"C4k:<4ˊ33j&pu: <}$u;hr"zP!V&vJ4]2D7hY}, '[W_bYVcG?zS|yX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVS [K*nV3ᅗ`ic#MIݎ,ڧH^s}HFմI2j =?Qh Dhju8uRy~x+NҬo[8snCARc9)'.לu*m5moLڥ.C>nO|v>!ZNd_u]?=껬4؞?E2Uj$NIFK]|ܞ(4|"C4k:ygWobYvp;;_yeK>YO9qL Vii|;%e.uq{~Ќ Ѭp>$1Y_"?sڹx6 u>xE23C2ZM픔iTeB3o'2DVé@O.8O}oyX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVSOeOq滓}|yX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVSYߺO'S4ˎ|kZvu>xE23C2ZM픔iTeB3o'2DVéؔOFN ++ΰC;YyUϽ0J>YO9qL Vii|;%e.uq{~Ќ Ѭp>6puyžpGs4?;aHyX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVS~foO'Yy+x?.]zy& w>YO9qL Vii|;%e.uq{~Ќ Ѭp>6 |nOfv-7~z˛XIݎ,ڧH^s}HFմI2j =?Qh Dhju8uh'|et ?W>YO9qL Vii|;%e.uq{~Ќ Ѭp>~Cvh'+}u'];5/uyeئnmZI[ЄDz6n'$| h܀Se2m5`{m\$P`$&^;_.{jM|t9ύB5aQk]H) g44;Cr= >;"aHO,Xjv| <B! V?&=|owԭ~Rb6B, +y52)&fgHg'6W: _m4B!27w+%t˸۹-|G]4X.B7-B^k L,*GJa`< <$itCzbW}#=(l0,@B!B4 sÞ<߾pˍ;,tZ(ր®r3Cb!LG\0'Ok,~;>҃t!BIBfG]|ο}=`{9YOyE?+J\P(G|>wVōp, +y52)&fgHg'6iů6`GzP`X!Bh㔦h(%ߵ?QϵȟܽZn!iXYY{ ƺΞ=[Tuia9ooo(E!T&v#00t 4d:@!=xZc>F6@!Z7IZȷn;vu|מVVN<!)YZZ (|gg^tÇXZk@ebaW9R +M@!1ΐ\ONmt5Aida:B!VK=*]|g=|Vxg"tIn(#Gfggoݺt:_E!T&v#00t 4d:@!=xZc>F6@!Z{U.\vD;빶ۓ~/*? ,tIn($Ff$!Bhb%Po]{8Hjtmvh4033S}z~w.Jl6NgjL'XL}f314db!N}LOwf\,SgxXHe\O3s?G!X]8;zD=jokb)Bn($644Vz^vmEQL&SSSHQ|,;j3*Ge3S&c/ ?;۬ \cvjvcX|nohn>}Μ^^^^K!B_{e?N+:uKQ~:IBfc)>bzIŋ^\TJRZk@ebaW9R ̍$j:i(Jrz|v2שkLJc7`GzxBK5#7'?G!&''?Q^Oڶq[S[4_$!9vOfggXd2dAk L,*GJacKyHLq^m(L.d5AidF"I<B!GBV'ws[m|g}›gSdqC6?㸁{}sH$Μ9+}Z2X6rg4ҶHNF ٞg5FVʄN!LҾQ|6: - w9eNjvKoEIfI3ӟ(x" +S+͔}L\TA|;G@ +uSX3J̨x`r_ҹW3OkS#8[f kK1iݻwST?v:˲LӜK&Ǐj$ pyMDQhr\lԠf 9 U˰jhv>VeFz_/ۮ7MzjL߷v|y6Qx<)z'&&7'l2ܱcݻ/\`&uL(O9~P6SjPa3qQueY*eOfbyo4G;+2n]2H7%=Y߷Aѧ?9[QQx5r|ʕ˗/_zڵk[XX0Mi7oQUaf~' +B +e3u6UgP&B]Tk/Fs R,3>+}73׿mϓzrggngeQGWg?QDڧ?W()5:2v,H2Z3|7gpbQ ٿnX/h'}QZ\DBDQhr\lԠf 9 U˰jhv>VeFb,^=ڤƙp>OHDQhr\lԠf 9 U˰jhv>VeFݺdI7goѓcԈoտ}P!Rg?QDڧ?W()5:2v,H2Z3|7gpbQ,C_.lKAmzO-}v魣[*u@:ufOD}sR3(oȂT.~5{9xwX)ubKK?og>=lmwN Zu0' +B +e3u6UgP&B]Tk/Fs R,3>X+\.m3ܨǛiݿy:3'>BLA݇EɷsdAŸVX3J̨x@mۜ驱.9Yz߬5k@ZDQhr\lԠf 9 U˰jhv>VeFڠ}o_~ܨMh{׳C_:we' +B +e3u6UgP&B]Tk/Fs R,3>`Yލwg,9m:mz-r`u>ՙO<)fJ >l&.ΠL# R _,haXf}Vc"-==yRި7t~5Z#u>3ӟ(x" +S+͔}L\TA|;G@ +uSX3J̨!կw>SO驱w_~ƍT9` wWs_&65OO-ƙ"u:OPg?QDڧ?W()5:2v,H2Z3|7gpbQeYNӓ333n;;;k׮;w~m۶NowjF*u?"x[»o]|{ޟ6"WDa (,-P/Xh".C}Ra)v&@MQVը!(=唥t*ŵV|v MeO*#\3 ;>%D"t) +0X,޾}/,,@%D!!"~p߱?G݀BOe58أtP0CeܾJNc@ Ie$+btaǧdۙhB5EXLR 硡!$w*Ȉr P@B{_}-+Zأ;Z%}Cv^B_'fkp0G9el`,݇ʸ}qB$tH&W ÎOɠ3фj:HܹS(~rTP!B%jK+=wgV8vg@C.ADoe58أtP0CeܾJNc@ Ie$+btaǧdۙhB5EQ$IyǏ;v}bb"CD!w*)^}X +]7Zv:B}s(=唥t*ŵV|v MeO*#\3 ;>%D"t("IrNPtR[[p\vVAD!T3R?{S +W%]*@Cg‰ QNY:[(A2n_\kgD ]21:ðS2L4!B($wlnn޿;A?>N?mF>_YY"z /ScN_=]=tey)糹|6O ~|\Bl8Q6{X=)Kg c9>Tk44$PTF2"Fgv|J&D>PQE䓯F^v˗/;&I2'LAog tE$s^jh4lNNN>!ԬV&R&}U +ׅCbJS/@Cĉ QNY:[(A2n_\kgD ]21:ðS2L4!B($w ,[*l <|!T.VB!m;nTt@M(=唥t*ŵV|v MeO*#\3 ;>%D"th5_wdYeܹsXtGGիW+ BH%Ax'D(x[!v'fkp0G9el`,݇ʸ}qB$tH&W ÎOɠ3фjt:}Ν>͛sssrYwvww*7n'"CG!«תfŷ;|>}]rz_B{'fkp0G9el` ~=n_\kgD ]21:ðS2L4!BeN˿:ur,Kx#B8Q6{X=)Kg c9>Tk44$PTF2"Fgv|J&D>PS4s ``B/Z~qΐH ]o}x÷*t:j:N``rBXqZ+ >;&I2'LAog Bj{{+x[|KtyА7!^SSSt ,[,C_?>MweqŽ2rfa(jAE0*=fP P+J\ڢ)]ޯ|ɷI~4Sf,2= ^0k["ݏSJ7]jZ9Kǵ.*!N_NJ#Du#DaV+z{{_744t2%K`G¤,,,9sh4zoܸqǏ 4Sf,2= ^0k["ݏSJ7]jZ9Kǵ.*!NUIogӂb v>F: DžnBC*lN5L('TzPmt?Lb*-D|vyj,f$B0d8Bv|BB&Ck)Y +U|u:9'yt@)yСϟo\ﯯ7Bm2/Y3drB ږH#*MggVΒnFq-K-d'd(4iQV^D{We _O};)is֪sq@Gnn޸'ˍF#Pl|P2? 8aI9>2~$bTA*YH<.O(В^`&; +?ΐ>ڈ'A}6u:>It:sssnž>\n4_s8FY_y^9?l3V +Ģ-]I hbH,grU}}=.Ƨ\v9WYXIQtf!_s +&_D@q]JLR(.lj*汓 t}}}rh4<0̓'OfggiY(;$jOekׯt7#<}4l?:_0u賩tO&na';9:Ǒo\,s\CCC߷Z0҉ Q9Ç/..n\P(mmm93hd-&mHEM `xO sbY6oƇQlIvWo5o逰sssIGQ D" C]](` >Ɨ\kJ_~&~~(<1x<===h4*J1 C:$e\~+@VX" cú,I(dɔ,>q:ϓ[yܬ@V WK:#$p8lZ%-//APYYI:1 +9T;4W=p;7.XY]]u:wUTPk5jK:#$$eݻ'J=zر'Oz}ؾ:A%Mo*b."u5p +<ؘphiiZxۼK>y!QQ599)}!&Q]~B2Q |HWWW{{{KKNST`̟>8tXRήvά:Y*"p$pr@G .73 $\!dD֚jd}9>y>/`qX|^Q]uH$U&>l!Qz9Av)Nq&Rqhdϖu $%ơ!LV]]]^^\nqq1a, |L6_9@<<6L~"X5/@zo\mi|Eonحj=#css$999!!?v]O#!Td"%GFFt:$SSS322vuh᡾~mm{mU*>Ԁ999BӽWC|; Gh4x$%%>4UTT6,2l/6:rs[(uMLL@H <_eeej(:X!뉥wtt8,mEc@)ͺ0Dh}p!< ~(ű^deO.766VUU.`,b +JyMŽvq}W:v^gȽF}$;u?>=z9I4LI&VfwI T:WA-Ɛ2JnW((%rwww[[ +{4Q$""ؘf۶NEEE\.`_v-;;ߏ +v[] c݃Bwfoo/=,~ee[JMNNN.w;>0GA$ONNuzzƤ 6>NDó0n*BD.NE)gyy9"P) Zy +fٻ #xE\x@ +?|tFTCҝ===Z{T*E< SRRxQ r枻f@W&!(Jii)zݱa^X a6d;".R]k@ѐb;@x: Y}gOSNZs $ܵ666F̳gP%544澐/.`l6VW6FakYq@AHL.ĪRdK!  j9J6?\:_Y vejj*44oB Vt:wcL +r%a̎r +^s`@FWk\p- 2t糳漻$I``իWU*٩kܹPG<}IDRRRrssS%***--P$u+ Oqڪjd,q򦦦bHbL#nyX +^ > pva1uzz:,QD4G{ `v@ŕ]@ aWNa"c/Nn0:h}hg7_fpu K +\POq\Ҳ:XT{GdS=ȍ'Cdgo]IRa Vf |mLLLdddPTTOTAyL7nuW|(P(~?u]qIδ!:Miɤt2=x̎رbYf_j 6b3Xl",̾ؒX1 7U_&S3t9{{ϷC + +:~8mhh ALJJNaGWvvv(|||EZVJB`ׯ_'p/NNNNj\ԫPǬz^VSFi:8;;H[QQ:<=*=L&U@5!/]tԉ >y>R啞S("/^h4af BHH#`0PbO<nݺu *E&:::88/_quuuqq,8lP P +r@CݻWXXH^!@˶Qy3*&f_/j2dȐ!CĶa-E%g>\Z;g<س8h`:Z/:j|B힞tΫ+/}ڿjgod(o{vɟz>qsrgn-{޿31}i˯[|iϻ!Cƿu:331A`@MMMf + +Yb#!S .@h48(ð6773~BB8+++3b˄ۅSSSKJJ@1k|3q=.**zWRhZ<@츟Ey..e rc;,ddd}Z^Z+No{{{ccvI kDϗNд4_Ӄ;;;o7GDpvw4nvvMv;lvvg&a7$3Ĭ, r2"W;7EUZFBʥh-`r)h OY;{is>}_{$!p8đtѢR2 0t:e2$R "tZtQnZaE.f``roΝ5j10N2ƞ|abii… lg}} r]3cA.ө8Vg.wӅ?%^]PZf5Y$H A‡ ӍG+a_;8~򻕫> s\.Xw"DžյMr}}Ns:>* J`s +aݖģ(|8!C^Ցo~۷on6Hݠ M}ithњ1Bw엳ҥK*j~~~.WsMf΋8jEjh4(_H Y {fff~~~`dCCfXzzzrss4pI5^GGGSSS!:{ //d2 jAxĄ_f#&A.)) u'W;22B%ݲ|MMMpJIfeeQqVAAA|mBEl&J^PnPȭnmmp0 >bdff'̢Pl4dedT+vwhh/%A $H9N=977'c/lw?vVލvP¿B.^T___[[[UUuuT\˯\RVVVSSV=&L~Y1(οt)R߇}.|q-87AS^\^wy66KŋA8Pf=x1_0??OE>}zs#)bjj3݇0D68q"dgg%>D!Z@rɓ'ѷnz)ÔJs񁍰; 6ֆMYfl644ڱ|UThǏťs*|@4rݻ!]n%nV`0pzT(axUKV;Z&==^WHMM`煅>gϞ> EKlbƍ!Q^)U@M&_ᐐ~!e2 I@H۷o=QP\A~Ӭ,$?8#͖M2wܙ`0FGGE + 988СC 4S,TVVbncS|>Rg*--yƁ:ʓeNguu񱱱 O<ȬDn Dʼn$H Agk+FjE3DZ~҉/] Ogk?a.?ܯ/Z+׹ |2T.˃9%So7va B5R5A/7TEEEk׮QP, +bVhhh(YAEı(t$ l [>|HLMM1iZ,G|>477,OI0-CCC0ῦu\$H A=w-&r1_,Xޥ\WWW `q*++"qee%T:ih`m:|gX(yϜ~{P#TLLwO,.uov%HxJKKJ@;M;pl~5Ų͋܈FCBW*..nbzq jiDh722!"Devvv}}=4** +d,AQaaaT(٬x[?$vݻxEOt&&&UЗ`^@_5 #*JO.unm6c /hNHHH}Lo&4o *3L_?mi_VZiUwUwۨ?tTB-IJx!‘`\!$@0!&p`pc}[/v +my?w晙b8$$2<2xcBrh˃"xS|JJJJ"\ENd2YVV8 , -'9pG>|X <l,7߸qYX%fMM Qs1KY$: !333<<<,,Lōmp#G0= A $?⺝Ӡ4?e++g^sȶƻz}ۤdwoFF/kȻJKK+**jI k7;-ţT_TNY{jc~eӽ; g nYݾvwP^(84B@!*}Q$ɅkkkDVzN@W7DDkZZZbb"B &E6VFE~GZ6`"$ ߻ߟիWd%%%zITfW(\6ָvۧHl@`ݸL1uuuOpTBRR秧w%Z233߿\p .M MAi\\\VVCxUNS~~>ojj*777!!p6B{TTt:U*e7n܀:fk  򔔔ׯ` +#7 r;qr|)TCKtt4{'2 P1`ѕgq@,oK A +f˶ZUZ^*_֖@}iWOAJCbF! .+++--%-/@2LU^^NZHV0t,{Ւ&yNuM/xd'ӼV=mxܞmwgw,A;ggg + +2HgGVTT$&&r'B!!JOB!P^TTVE“ ;DDDps#{dDӈY.ioݺ/FFFpeԫR4td&gX[XX`6O[[2˙3gǩ_tO NS&x!8.+77ZfK A ;M]䷬XO 뵉[S};ε^߾]__͛7s/\v DR/Eڶǵ5ri6p`ЙwkTm?z^Uo69aہN /sssfn uuu+++eHG###Iֶ:::boVt2'HP#G-㢣iD-IjFFdB=zm7~0Y?V,--֞8qb``/^i߽{WPCJqgg\~w0)))=YZZj41ڪT*^/Uގի0eÌvD'%%ǏΞ=K?x`SSí[_@2>>~ҥQ›C +)|BC `Xd6ncy܉q+@rrX|?duuuhhp0.Y[/Ν;>72s By=!A $?rq//kWC\Be|׷"u$S"&٫ %&rII y2wVy8o69W.ʖnQ}Ye=i^}#Lmh.@[;٠ ]ޱ QSWW[t(tZ_C\| Gqܾ};>>>++Euu5wx<f~e,X {zz/v[XXB3L?+z=ϟnll\^^}dd?0;;+v t +ohhqӝ;w ;<[[[CcHbonnҲc6^{Zby4 ^~!@<"|B ;7o[p$0ߧZlSS _ZZ688H'EhĭjZPv;~ʕ<ʬytttiibH1N=Ogt|S|k͍skʋ"Dށ 0v.f !ʫ of!!/ $!=a79lo2dyfgϓ<Jt *X___QQQ[[k4є!BT ꂂ rGп9s;HF) }@!s*dvGBXN60͡ZEQww9*4ID5_jo:uX; x܉D"(uנĭΝ;(+D gk gwQS.bfgdool(3}!EouVUUD~N-?ݠEfffcuBr}zVTTOנzmm@ pBeG}X,VNFh wwwʐ^/ h~48u:]cc u`lc )hKD"X,!ѠTKA\e4Qrҟ~ϴZ[O G/ gmCCz*ȼ! K }**Nn8OGR_:D"&MR) +L&J1 H$"$iX<O, qC}]lgW :X@?ٗK&>8_;!^4Z.Obbt"՝6+L?PWyދ?ʷ~fM۔8R]zb+++GR8./HaÇ bYZz +:t[Iwmq˪cÙy=9ĞlbY|kf9tـZTwFZ|E?JPW +71S.0  +<$AD"X,H>J$%Y{ւ/-ETs{r}f.zo/Ws _sXE)טs`$^iKN>J]~+6J@_NuxiD"0L(r8zS*bf\T*;::t:niO2, gcډcr5k +\:Vup޴Xr,Gy> +c I)N|;U䗔pGuN,L04rJB2 qTkiiQf* M&g-uܗU'Ju_~X4|PV!y0d_7l5:Wc41qoGb?延+xwd>_6%VmI.7x-9THfi=đ go?{`lXrpMaG|t_DU&[;Tf1Ju˲`pyyf=yDtvvd2X,$B@GFFf Di~iD3n?׌ݝM:ޓC% NTJ1jSo M _^u'ſJPe[)ERqMӑHϛLL&Hb1aRq\եjV+EQkO쪏3ܩ[[13O;@dVyXiߘ +&Ӕ?Oa4vCHWJ*{*J]cMIMu|˲gjjjppMP(&''nw<yFx軩 +tYCPcX=.F{n=A wRzKO9ReRZzURrǥR)aD$dG NQT8iDz] Xa:Y?^*$?8!vgn-ɥвw-Y.}޿٭ק4vf֮hEXk^fmwSA( .c]-\b@!܌IHN!ד {ıX@px~Ι7oydfz0.#5y_EME Ō}MN%l,333fYѨT*\. +y<H$===ܷ.OEQkCB)h檼iqPDWPSsBv/'/ s?L8p` ah:8=N|ɏTq7$o0\緩,N XZZzCCC V BDѡRL&L fkC%R?~8LHϴ%}'uoUxa/,7m_w/-Tz:ێտ5.&,:\gI,0 MәL0á;:: +S$ⶶ6D"Jr-a%=Z V=>{Jt*;{X̷S_Jr͂ʼnlN +%ىD%~g&mWb::si$d$qF[$|*AbL&S(Jl6?z(?]Y!3 ʼn|U-SO*ӆw=4i,8|qI?uwjau;#}J{MVX& ^:X,}}}2m3JR;)^dYѢ rsYci:Ti8XUd$7\"2$zqX8јZտɋc_Ot]zFt, EQ`n(ݭP($ BP |)jj|h4Hd2ep.7&uݰ~t#ŧ N{KuOh>G:k5Fxкd3{xat}|8V#Rz߹V:^ْsEQZ#Hx<@ PZ'u'Df3]|ƴL_P?ՍT޴]ZɎ40 L&0MkϽ^T6\YZZ4/bw DqKfbApU (^ +lj9x<m:9 vv7⊌7m4nKRܰ ndwT*mmmUp'JRR걱1Fם iY_(5&#ο]2w-սQ?p +=R5aاW'ExfkC$Ir}k.!EQrEonnniij6rNn-BaoqcwwvN^.444d2. 466NNNf2Osp8֦=ggg:&,/շ ۱bu;r; uv3U(l6 7r3$ UbMCpB7fXfi1Wh~TX?p +=XVf3ٝnft:vL6;f٩PUoժ  +ToTX.ިUlKp8>qkml~rr{53|unxȷ cvD}1HƐiD wǍFc^^^]]ċ< +7ׂ$"f0+++ mE)y 333appS V]]]PPraaacH$[]]}444`%}ʢ VTTDm}H@ Hlv8$J{K>2?ο~R/O&I ^KxY^V;;;JeGGL&J,bkkk{{F1N3 ?H$^0J&̏ͷdlf(\0M0slI+~ԭ_] +x$Jũw#b+?, STp % F7o޼x"-++p8 FeeeWu:]<OP~%8ޓݿYPx%8Za 9??B!uH$ +b1 J +kkkǀV _`۟@ bǡ0'ߴv}Xѯ_]1"/ɽmiiibbBjB!HZ[[D"xd0== ` ̏bȲ*]پc5|4cxٟ#t鋖sa +Cݼ5@ ~n\2`0X,Vss39}4nkk%bs!SmmR|bl6[ׯC$0@ tzYYbZ uxUTZDs:իWqw:p˗/K^@ bIج.-_u$q$mL&a pll |7"D"q +t?b[%Ē2@ N:#'O`h1"CE-3[Uv.7o|>P~dzyJ.\V].דp81 K&t:덍,k||ӧHQlp8CCCDΜ9׏+//</''ujj& !D08BNg} Noii +0j AO@ bGHF@=+%VWq(,"mIܿ h/37]Noc?t;:b-K`BPjИKAE Mb (`H8$+.Jݾ9s9>o2|/lP?[SS(Lե0 vf,+聇fiDWKP؛>rEH궻Wͪ ؟>bG/l6޺uK.+ +hYGGǝ;wpYWWbˉ~ŋMz[__VXQQ188zC7(jq'N gwwws\DbXF#q x@ SKR1i||<`8|6- +1dxb7Y@ Y[ :gCdppЃ2wq|+Ɏr~꽓xjv,kkkr͍ݾ}6L$UWW# kllliiU*f333˯Lvo≧tLjKz8վD$/4Ɵ0s MјTl] _]@ 'h̎jEt GT)6]ZZZVV^\\\AaaaQQu:ɉZ8?~8 F& +DrZJvq޻wm ree%.."*))bL܌riݎ +fEN'J F(xʕ+XxZZCq +R[ @ ސsIPY- 칙Aeb2wS- >_Sow[g}@3==}Nx os +7>>r^WY0__醩͓q{?>=tF2GMcjgJxP1a0>))IY֔Νɡi:8N{{ܜL&}(@ *pbqq\.G E0(/zrݨP(l6[dR`Ⲳ2 ?ԕBn2Pj-@xly!7~~YFqP]CEqP^2w8(gv7E`a)к[[[o޼ K&HjkkkjjE"R0 {4tdĥ#܃ˍQepٱm``>0pe---FL΍x>|81W_Y L/Kek#_?adh~%ī&>Ч^Tݞ꼿`w}c[}wv@ hH8?i +v+nZ QKKKkoow\#\Bv{d&'OX,.i#e?}4fDSNfL 6pRe2YSSjEzB{Pa@]l=HR.rq,۴Jth2x<~7>yiiihh/crss#Ǜf/]b***ٮ %,]WQ"H( ?եj ew AeOeHS"NuUneeeUUUbq]]b\>88 qee"Mss\2LNdn7_Bן`➞ r4Mo auu5^g|gRSS + +"nLOA[[?˝CMOA`m}\v>ٙ{`2v}#_.NMWg]kǮ[vwm̬ (^֐m +8qE 6Ry@"BC77!g{ u9o=wn&|V1 tcAE +,흝BѣG a7D99'W4W<%MTq\s+ɼ>]c}5( σ۟re_o͖24-P*++R)T4SxYPz6//p\.χePL޻wĉ. ޠ*v~4`$ fh + >|,D8))͛Y`nܸ/Zؓ۔ | &^'}~A6bDwB2G>]XX ﹹgƫWξ`A^A_8t\?n, Y&iΫ#TA8unu iPrV%ykPzf811W*q{C*ߘT>yӌO.ťK>JNJ8/&N͛=Do p9p`0j322VL&ӳ5п@5zッEAɁ~,2,!!!// ?3gθnX +(lZshBښrԩ:H$[Y*xԃ^2M|Ra}4jFOm]/[ &4v{4?)gffbo0LA%d{W}:F}G!wY;K?'2~Ffu6x) S [z@6 r$‰f׃la zlxxX׀ήٳ%%%,$L&NZ o?~2LڵkLlt ?Zg[!Fdn'2;mWدlv*vȢH5NI"ں466B1&ɦM&质7w~3Issl9$$ޤEGI5q¯ "nw̅a\8VWW,˃N`WHS$^$lN3j 2KKK~---R{)OrA DÀ_ +dXZ7ͱF@bx<ޛAdsn9'G;n~ڗ$m7ӖVb]> 05q xjj +\[[[}}=(%9NCCCSSS{{;wzzzbR%hDS9IT$DRćS%f +>RzGVώ  oP:"AքdXZk,(AK0¡09vJyVf\;{_\am%AEG0F"ttt4Ed$.J<+al׌I1J` +޶0zhT JB캺: `BP*bUl3fal }RMet*k"/h5.9*0E9焟]%[Zvk7%SN(TTN/A +|UAAd2tzE$$$X,Xc___UUUgg=|>aCyY(A-(Of¬_^W)555l6SS?봣BU\ukXw(HDŊXղv]DIB! %<HbC!H{7Ai˶<9I~9|lI~ v='r6licNEhP=˺g-'v'$^FbJɛ=9y;4?߂GDoEWA,W~~~nn䁁-..6 7qPy,k/#܀fnD|9>"J?^t &b`& "255eۍFcCCCEED"JE2kڮ.~4kU/uL;2ʹq51>ɰaYÞsNI;'~9|& 77l~~>aYΝ;M>=NGd Otn(9Ỻ X7YQ4n9=u߃?Ei&IqhX, 2L"myy9].WVV*JJVf_Fn'N^iƄd}b{S.t}(Xd>qv]|5ZX{ + ^V+jkkk?Bo#.⧞ju#k@mAE/V`uʮeqM.0uo(vTWW+ʊ +\.[$JG:p[aY^ȃ'O>ܞ3wO3M||gbaϹ;5vS .o Q~wDV$s#X\Cn#J? 537͑Xw&^4---j?WRdQYYX,j<66677x$aY8nh*s&O>|Dpy_qY3$}|#7% Y4ghhH&}{L&aLMM566 ߿_WWxb2`-zN=kw|wˉG.!^zi3D`MvPF v0 Ɨi =<<۫ +E""U*|j:bYvY'z4%oе.!I*?ͱ(RT\fύDVhp6'bi.ie'TCHƺnB]ێo?8vy%}/,I@Eщ \YY)^$]$ +Jh4&t"]V-f@5.'ٖ$}B~YCba_PW#g/k|2)ffj8ei#bxģ-=%O~ѕ2nĺ7C4zv{{{R2L_Z[[>}x菪@Rl.Lؽ/įӌY3!XMl:C_n]ہA?G`@) -Ubn.L,0t_ðaTWWR +L&+//JEr\Xq Idf06wXRQ9֏E{w&3:kHH>k8kU1lq*f[ +ԅ;JYXh "XdC2 ?Cnÿ>Pf]K\uKAޮVJT*F.?~X8F[f1wwAӋkӅ}G.[S J'$Jw)"J6`0LXb^ONrv q8Dl@EnƋ~lAZUǬr4Mcv].|$Wy<1ͦjkjjbqYY)YTYY'ju[[lv:^ 'fC=X}Lr䫢i$]B~癗q hCOMy9|ױ +*>S9kmADksyDMAlb4HH`H&&ms)R|gg|q +Zݭکgl4b KTgK!~=^[Kԯ'65o].%oIa="1r862 EQ0>>iFcccZFD,;ZP(Je{{{wwP f ΰ\f9&N?5G8aWYe_`mw5>HfE9ڒsĚ766uĥ-dY*sL~+p04r\Z$4MWWNP(9BQADZrr$IaYvJqֶZ~ֲe) ++0;|6;6$Sy:P>SڤĽOZJxf^Kfuo;(IEk]zW120T  ÔJ% "E]&D,D"P?j8<<#EQ4_ ( o=ǯ>l/K/9ףI q2n-^?˥{d(52\ 4MQsss~|||dddhhn'Ot:ZT*QŢׄ?d*JvuuFƗ e}>L8bh4/|$O + Rk Ѽ7Vam;nUm8oN#[hp<ij{É`p8|AuJD~h؈.X׮Ѹ9e9y}JYZ5? 04Mg2d2I$pxvvy<izZd""Q5ARBh4:c2vz~o.{M&mnB3sfΓ-nj%'eU؁恊fWtfh%P(n0LAX,)B^CE2L^P(Emmmj}}}v}dd/)LyLSGS7\J+MeUS؞ӖZU>N?7qqc: ispcdmmv|6& +(c:Ȗd&%eIXXFF,#۲,YcuvWrךǤL@>wlН7Bk [ɳ/g~Hn$O?r?=,fBnc}bHQT$z.bi4eBq\.c&ɤRd -C X q +D.+1 ò,qեR+aCO=i{zֺu1˶c_*.,2y.sl U1g|gi!uĵ=-bcMb|+ֲ7 "JKLu +EQHdnnnzz\. L&htZVV8.JQEDkk=?ݻgZGGG'&&|h4Jd*f4Ms"'69g?xʃg뉭5f>1rxNwk M'"t}Tb \,8h&kD b߉5~;ִlZoِvVVK]a]g͗VV +tHb( ~;66p8fN"KwDkH$8Ꞟd2t:nd XXX/JR4Md'2:#a7M|ui*Nͧ1i +6co4^>4-GͻNXqca_4<K3R3$G#u7Md:zgp{r5ٱ?!oedR:_ vvd2 * +EQP(*C2qT*dr\P(JZhZmooAz@ 'Ia*5 +-w&jj]~ r!L}i-|QU,;OXuĞ&ۛwΏt=~s)p8L&`PTH5?R*z/t:333p8NswUZS񬲎oyDu95 yfk UuV{ IܣY+3*}ikHz02uzCԆhۏwM]?q6iQÑnWQk4J +q $X,Fː2QP(Uz~pppddv|`0H$RT:f4M3 q\]|Uznu]?ֺeke39/TC'Th9L3 [txVJ`uc' +~?p'{<zp׎C77O~yErC+G +MW#LE"kPF l6x?~痖x:iX,VzA*L/dl]ݓw9՘뉿FPG8n|ļ۫cďE`h,H3nςcY:KeȥTd|2vN<4~grfOJX0jdJD# KT (O,d2BR4MOO^7CCCv}|||jj* F"B6Ep,52A*L [wꬂz*~_Gk|cŴn$<Tʊe]Et2EC czw]s+JQ.2LG*+odepnhX\.띝D"EVzOK W*l[XΙƢwuOoOs ~Uk +zbwj~u}q J?Oed2gff<2tFRTJ.eĈLJ%TG,#Ab#( H$TT/t:~qq"4](/8X,JJYs,:؁6OO4j;OXl ;tĝ__nn^7m)C[{Nzތzs&<6jc ,@HPH$A$!!!t)V2n*,- a:O0lkrCVUU4|zpO xp FҊ"EQ$Irl6NST<B~tZVN7::*H\. 4N6`2L2Q6 eh2~&ǸGz[7ǘuw<8%BXyPd>yID~w_ G[KmXMfo; LmSRߨeLU +~ .fXf99cӰ9;+-ۻ3pfc,3bbۿ,D2:?d۪y٢)w454ۛmXuimk|DiByFkvHl6KD x44$HbP(\.EQ&(CLϹ7(z {O\9]o,uGpN%1$ܫj>]I|af.)7-ݑxM^8eK_vh-ԛ7֩jU(w4/;h!ߨeyD6&IX6+t:FCP zNѣGEcP(b@ p8:bxx0p8|>_(Jg2?Af[~p-㧑mm1| +{3|-] nK/  SU(Tx l?.Zvn=ֈm/ iw4whv9Uw%K/ؽtt`-rAeǕJT* +|>s86(b1ʐ2:NJOKd2Je4^b<OәL&͖N$)Z]-YIaGG7E: +n[S.'cl1Esbƒ{A\ag{P/?8բi·5b ؖMR7ax|8p,O,ERJւBN >tNNN FT=ziY4i@ȋuiIɺlZ6chBʳKCE .ߔѐu*<d"Eo4&FQT2F8BxfX,FQժjT* +W+X,dJǝ:A15;;˕0,sc{li!c}A˷[hȃ$e)GEX45YG[ rUSvSBcN1C%Zx#wix7z`aiRId2HDErV+ *J, d32D"Je2Ykk\.W(g```|||zz(JnNKHc2>r'Zªwc5{rD~3u'6/kprfd%(<^@îp!pC>u{B#!#KMG*̿8^cwwuĩH0MMMl6ɤڤRx *M++P(Z-霟_\\L$E1+?[JQD_0qE)zð ΥWE {B˶hN.{Ә,OSI6R95Qcut?^~Ta=m.|9+_8UޖZo Qu1 CQID"E"~힘FDөjXy AP(D\T*J[h:::Fqhhn +Wqc^:vXhb;ZZůo<<WԒr:Y^/e$.|Ĕ/f@kMS_ݲ)7g2drw/9Tb:Ziŕ/o*LSx=(Am4vfE2DQ\QɤjJessP(l *ͫ3ZZZT*Uwwwf8$Σ.2f!r=& +~ޅ]܃p} }nDŽZi`6 +4D5Y.?pq.@)Srr,tYr|K8qARt0̰,a* ͍F ~iχnn1 FRIҁD"|~S ѶAEZdZN3zIEE~w؀ |-<_~JT%bE밂Ǖ+\#?{5}x hW}5hhk|s,ZM4iR|_З_NkmUlB;)/z~P(d6{zzACCÝ;w4 >mCQtpp4<}mccD"iiinW(###z~zzzvvnG p}%OaƽD/B)iWtuqV;VŊ K{#^I %PƋq=Ӷ"z5Ά.k`&MbKJU)]&xjd=Cȍ!/bbH$z^򞞞VP{#Ab "I,G_rj`2l6APDؠUG k +x]}tq&uaGPi롟eW4C#^УE_ՒW3q\%ߒ)KΒo͑*Rs;U{OJGΏ7"}$r H̭B˜l8H$Bt$aY<w/5D/6%𒟹/5m acj^e7_,wtt+ +F311a2l60ry< ifYplpQ}u\*^>^+Zx#H^,k R$S(O!WGΏ<=xh{29K%ߒ)K̐%ƧIitȌw^_1Iݷ=~y#Bt:D"n ] ¶~LFFbleMQT$:O}衤rCDf, V8,Mml +a_s9%kh7024׃@Leµfsͩ?]b8%W&ݔ.VbwslW!zќo 8jX)pҫq}0uu0 EQ$I9cCmPyp]KM!*xm +|8Ar*~تcK,EF^{ԬshZ9ߞ9PS~xBؖHΖ'e7gJ?<ㅱjA:ˮrt\A<⺴/+Zak7+cΟL8/ zTmݶbpFNADeE-1eQUIBB a!@7h(WǗv3Dɴ!ID$$շm.6*=rlGgNj~Dn5yUa}Lfn&M2N_ V|bw6Qze+n7nSȇof|0?^ٓ[+%Baꘌ<_.wTrn V|;k^} Xȱ"9W8*w'Jeor]t(zwos؞&2j^Yxx'CW3:UliCTMD&2]%h;Qc?H|)`ԵZ,% KCO=՛k}w1*]HHZ%D+%e?8[֣/?ZE_ oBl' nm;ݎ5 4[WͯJf:Qd< IRK$3$ hxW}E׬wclp5^Uw?'r3 vZ.GZ+l5R/[0Am.nt8F-;o=<_;t;F޶'շDbI"R2o* yD=ݍ|KAJTm?rS;_Ѕ(\O/-۾QEWpyx;2hn7W<~ZwDKVHDkd1򶃙J'g.zcl쪦O0hu +tQ]EQۨ"*mW2+weE\ժ%]iʾ9p~D?;-Fk#4ᩚ})$oPV|:ڳ<ಹ8Nj:'8)ixiURm!d&2gj7 qlyEV/gzswk+NtP.3xxGTfxH7D$?>vxCyY~sϏ9;XkK1P6JHJ}ȴTүܳ:4'@[pVZ٩C':>RMF%kaGT!bUpSD5퓵 +ukΐٜn^Vz~`/ܐ/~BIo$֑iud&TYI[nTÓ7R,v~ڪg*_I)Iꀸ@s)xbT{T@aZfۆiJ[V? osczR#cQ~dʏH)󥲷3w/ƚ'5ƹt/0Ĭmh¬j n%%>RU;n +ADp*DHRjc?](aX>9avώ:Z̕tn%LLJN 7U?)&=nr8r鞚zˏ&ʡCMXHRQɚ=?j.iO/滉ƞs6޻ߪ鴶?tn0Rl[(/nOZZnXZOo2+jPAzKL6&RHR'CBĪx"&ž7u[yilN7yo& eKKK?~d2Y}}ZW7!XHNV5=y1  St4>)@J}ȴd:*x1r[h΍jܳ:,~>ii]dZQ1pyQɚ*8'ED@\71/ +ʡ/gY;mܼ`٬VӧOryqq%yyyk] ^`O _2m=]ebmն +L/p86W *$JeqqqeeeUUՕ+Wt:˲k] ^i`-L))VJQD;r=Ny_ѧ75tW=p{,P|QH&(񪠥)-9ٝT2{mmի_o_Q]w=._ҵQp3i5jS{/52 #j 0-*KTQ&*2sf0,"ЙaҝXWfjgٗg8?"h~8.KєWWWwvv&5N8>(1u煮?uU3|@l!?m_@t +?$``|N9<U[3ԆٺstsKKUiEe=Ҫ[5gv}dLpP .f+?Ȃ`$yN_ )n1񦦦 6TVV<O___ww +3_Sw\jwlv&vQ_A<.kWmkwώޭM +4%=_PKjCVaY"/_]Yjz{rͭ鸤vt{wz=aOMx߄ AXy<@ 0UD4MEEjMj1 eE< &ed3G"M4"x\ȡcpڽl7]k 2RFoҧ2Ն߿zB?xc/CbH4S|KGDgZc$!O[j=Æg}i;pvwOG~oG̶;ySʰx(W_{ycKZfO;rJV>vrT t:ʦ#GܺuK?_//nY{n娻45 n{&PRǝOjNϗTҫE?"JG0txw*ļ4tD3T$x#[vrT`&Jϑbihhp,JǢH$GGG\btww}H fАsر6p:;vPԈiۋx԰%Bh4hTUu\sMIIMjm6gΜUVq(6JD4o~"+W\vm}}fO6:qիj"1 ---tFn';qZY֯_oX$I>.'rUyhh(//oYn]oookyK/4o޼s%3ٻwoJJʞ={gVTb܃8(^FjwaLJӔк.()mZ&qIBJj4D05eu%xβvgz?vys||ho `bb}}}۷ +X|>|  +esXtiAAsСEa{zzF { ֦z{{7mDՙLfrrr}}r&@ 7RRR<<<555gӛ4iҿ;q0/%%~Y[[r A!@L4<</֖MFGGgSNl62fٚ.]Bb?~뼼3g%K\xsessslpسrrrDxłzUGĨ]7z[ZZ;fii+**|R2@YYYqqիWvPX"FZ PS!5O ڳg|||N>#6c> @=x1ojhhH6`h41--ׯ]E^ |yy96d0T]ƫV +3%2kHc_z3ajt:{ɲ}RUUU///4_D>|HHH`2WWW'A @ nRRR<<LD\<1[UU%ϭuӦMpSWW}6 +W2Q200oϟ?ӧO ;gggK%%%ZZZ<==ᣥAПxGGTb 08hL ^\3L%K m+++ &Y:lVVVllldddDD~huօFGGmٲESSСCDEE۷'镎yvxxĉoݺ%c"7􍲘ٕJLooo [퍌0 ^???j$ȮRwwSp~O\)S0CKaSRR914qqq۷og Ġ^ @ j\_vm (//WWW߰aC^^ްA .\!"K㩪r8Xh55QbQEEeܸqӦMKOOW^///MM͙3gyn(ՕFn۶ GLѢC755I/_3gٳʄ355E444$urrzRkd)p<[YY F}P5@u#5e5:֦,~OOV`֮] yhf ,Xg;;ReE}}}|Cv!,;]]]ؠɓ'o޼Fİ}, M63MIc[ F@  7H")n?GNٰakiiR۰q.\k.ٿL^<Jbi;o^x1gkkklnnn.n׬U2dn@s`466Æ DfffsMLLZ]XX˗Ǐkii1>}~& +ސFwww$kQA===o߾E>[lqvv)s188`0233G?`H$ .XZZؠ7n|8(L#JvuuőɛIF퍉999n={lϞ/6`B$dCJ~NeRMecEAIa.LmJZLx蜓{>?Μ~{}g滆46:(y(E7nСW 9fW%#}pKv=***P•+W:u~z%$$p-n {]{@L +䔗/իW ҥKkAP*Hl榥d2BR~J]~ >r\DDl-$H A $HP[[{ԩI&amllt5nBn6oތ{xΘ1#)) 7R wE8p8/V%KJJ\\\RRR0hTb?ntj0֭[C 9rHbbK^/>OO&&&%Ν;޽O߿O>ollL xVyo=~z48700 ,,,׃!,,k׮ӧO'*;v,],//}Zjn۷oZ7TUU4aҥEmn]]]yTz/^xmhp^q=((s111nСׯo!gX6lnذknF!Z?:k֬ Pz\\܈#d|| +5HyyeCCüo޼7)΢E`gg'ǎ8;wh (((+++|'#gźf2'N%%%0$!}a޽{u⩛7o76뢔nnnGe/[6"P 9 䤕::y$Z~~~tXYY͟?}]W"J .\$L& +JPhɓVIMM% $H A $ubGlŀ:v_S߆ľmSiiiW#333 мMQ`rss'ڹs6."ϙ3'**ע6 !Ȕ)S,YmlrXZAz>|6Ly? ⭃CnTǛ7ozic'N)0<< 00P\ + +"TLL ^:f̘f +$"ٳ#Gtqqj $cuu… L_Z"dHuR>|3>~FV׮]Z/@Ewʕ0//Osシ͏;cee%"2dݻTƺ^xQXQT߿? +A9k֬m۶޽{yȧ}%&&j&CÈ+gHHxR6TTT r6BzJECCóglll ZblbbG?f'r9䄳FrrrRizؾ};\| W*""===]&) +je@x|mVXF +ˍ7EFFj $H A $_SB⤰o/_p ޾}ۦMggg76FfO7tЄݻw"%% v-Y733Y(,ۋ/222uW\)Zdrrrկaqzsΰ3<^|zxxDW|ĉ&>}QS$U|v\~=Ԗ#D,-Tmۆ"Erqss"r>XBFDPgeeVii)^3@[=y &''Y(,,ӫa]077uU +5RRRTTTY#ݻlvuu322оaXGGGUUU+VY.Ҟ3ZZZNLLTTTg3đ߽{҂Iloo1/whhh׮]H\###QQQh{Kcc#vijj"]]]-99O:UPPT|aYúYv -ALLl֭ⰣGfsƍsss?700())qrssM',OUuuu]]]*uHG16m%Y z$)))))iii.//nN$UUU~~~LK>}999`mm DD^ +155%h\I!b]]]by` 0`(Bh%%%M (# /^`KС?]ЪK0oooKRQNN1-- h"糳ñeb K S7Dzjjj05#v,,,̌?H-! Tdzz^ +++WHA+244!i?iflnnFd߿O+P>gnn.244%3gDVVg!PXPPkHHiǴXZZ388WZ۷prrjkkZ/@_pa +GFFbbb茌 (--}={JN$deeQDXְ1_v-..Ӌfff/_~:: 0޹s秥(#11qzzׇtDŽςnFRkmmt*/|ܲ'O"׮]Çyyyϝ;ܮ\rElL}آ"<zzz JPPPQQo>E.!ZFoo/ +ڹO{:0` 0`𷡮RBLL "񿥥رc_ƙZ j ݝ5!dK u :}5> \\\Z|riqqq9|I|EDDdjjVJJJEE:nvv>]]]k׮555}9k +g=2T-(?i@'&&𙐐 ,,788H^]]P6>!] Q -QvvΝ;F O999h+7ZaHBBBH{ZZ$۱cէOl?{ D`jB"%%%b*X#""8pK[[[ڤ$666??gffSh:7 yPho߈#,kqlrĉ/_:B`WHHܼ3D^?͛_zEXp%$$2Ѯ ###ɸYT +޽{xd%%%a <RAA]UVVXRUUaY+511=jmm]LX 0` U:񉎎vpp+777HBBBII# +w-,,<==YC9rUdggyr*w188xQWWWRPPjVuttTQQ{ӧO7 + [TT9aÆq2tVGGGRR۷577{((( Tmhh(`?i珏GM&&&>|͚ nAmn"ٳg}jjwI] ]PP$$$HKKa|~`n/++|***⳶ޞ68@ff&N]ɓ'ׯ_~@Oh4fccCj%%%?POOp@j... 'bNNN655E1-))):::(2887?WWWB###nnn<<< bee7~ @ܜ#,T]]3 t*228s Z ޸qzSSSwލw(cI lkkc]EHp^wwK/*>Dac߸Cal +)tH1uj,TF44EjeْNQ%$%Zm 1Dq>;__돳~~i63222_|VСÓX"F0@=O)FDD@. +/::4,,#% +#..Iwppرc,, r*+++eeEv + ՒZ HPGSRR rjj1d2a򭩩ۋz\MMmٌП Ǐenn5;;r+ԥmlln׮]...8 +-»{.v+++_xgggmmm-#egMf"[7n/ݥtzzzDoNOO#wwwXI{JJJW\cH + Ҝ`ƙ:#<(ׯ_wF&zUSS>7nEB놄`m!#ZKWW ϟkN╉ !" k0;;kKKKUUUɜ.T·o ʠ-iooO OU`0 Ty<I +fzMxdff߿ˆ>x {)))PH HB(V͛7qfw%$$ /^?eVV֧OFGG )d,e8EBCCQA,KKKMLLPkL~~>łX999djnnnccckkk BՒZ H4ITTT__mG-˥,h3d^|I勦1(_555bbbz… 6l@R{]tuu333h00n}} /N1q7nLMMuvv:::H]!Դe-qqqW9 pE"P`Ш:ujӦM(qrrrppu늋rTVVFh9ʂq EC}pp0&&F֨EQQo .))ںh \VV&// J.##s91١ĈJge466 /qqq***;dggCq8c-Ǐ_I@A޽;((h $U[[`0/lhFȮލݷoٳg===KJJIj yHb 5B9;;խtq~~ U EEEz{{i{xxTBB0e999%88z*}+??buttƉ pg333,"""а+EG"##$QQQ}}}=%%R!mۨQļ<}}}OOOVMM g5]d29RyssKnݺFc-TSOOˊ +EEE??cǎhhh`wffQ[[[0 ]]]hiiݻuu\@NKK 7655EDD 6@"ʾh9ʂ汲Zi@O555jЀrxyy"4\bb"L^^ۻSH Q;|<|9N>yDW@%@r۷oEEEz{{i; %% )hRR͛CBBڲe ȁ~oX,;;233͛۷5555777񡥥` ]___ $QQQ:88FezzJEEٹkrr$зjjj<==螜*..޺uٳgϚ4dp&ExϿ N\]]|JFGF50>}ZSS y "fjkllĉJJJF}U<]VVV644է?x`3-##t@%u(`|TUUEDDu𒒒uYYwgg0ytBAAϋ]O>E' +<yj %pϴBbxxxTWW/$<<\__2gRE`ܾ}~|gVTUUф|djii(AHcTEEWy0mSRB eIM4lfxeP$1CLli+"FHӴ([ fBilc Ǿ 9}x{8s}mCzqaaa++ +.] H;733CXP\J755[Wff&B6112??$$$.^Hs+/++nԿ + +B"]=55UKKz||zȑ#Aqqq{{riNLL Z8Ң //pbb"**\M{SSȼ$ ={vii մQVV^/|#77=ósNNHHQ>0700(..gEsrrPJmmm$ + ;.Gر}N1Άl |KKK|%0>>O;;;rx^^J۷|6an;7РA 4hРA {qqxY^^^k/266$h+nJ'''|̢r3gff KUTT"aihhprr + +B$I_<)zܹz0hUU.}aaa~~~CCC_PP0..PϧC***Rw333uuuMLL= AZTTÃZZZ8XZZt522#rjj*C$###OhiizׯUb]pvpp۷oq Ɂ⭩پ})s,WVV0vvvXVTT=\aI%%SN-..-l<_|A8C<*&$ϟoss3ub-,,`*ggg #АH{~~>k׮!?"p p8|0^IJ+66v޽Crrϟ_Dn߾!o_AЍ W """=|L&gGnㆯРA 4hРAP>>>>T#͛<|jnn>>>$ g2ԭO>ajՈٳg2A ̲wܡڑ𘘘%ʄӧOc⢦ 񫮮~H좂666JJJD + ۧ+**byddh@s1H汴tCNvttPcǠeggSx葎r||<==Q|j^BV#H/A+++wvv0Oi |0>( 8c@cӦMyyyd 4hРA <lmm}||Ʈ[Bpmٲs`KJJחbejj}m۶Byyy*zMKKKBB"99yCPRйݭ{…?rumm-@)))X6446]pp0! 4~"##BBB.tww",+@`CATwrnn ܺuKDDIX"WZ͛PUй/_|<ٱc0!LMMp +򭨨HOtt4T(n +^II TP0ۆgM6- `(2)c``gdqې'WTT@ hoo@!xDu:;;EtwwL8;EQ8)NEuuua?, @^(,2/~EC𳹹Y<^DpD< +҂W虯["GҥK:uuu4NX,T_4_-B177G/\pʔ)hEEUV999pPAd7o޼Y8q , mmmv/|ڳg̙36lؐ%vf\0'=o/wI68VXKutEp*v&''KMAAAAAAPFFFu#?~xpp"7mڄqqq@FAڵkΝP7ݺu%K =z6wvv3g΄ 6nx#YBÇ^Ufx5u vvvc#Z)56-.|'444"""))CR^1?rajjQld6]\\UTT޼yEyqqܹskjjF4sCCCi0#[.{ ?~A?~\UU5c455޽{1·oF +_%ݶm3f رc999<!@e |jkkf_---)LLL<<<<]nnʕ+9RWWǰ>==}hߊ/"K.a%M"r`fKMAAA'O]p8VVV#*++"JJJnkmmMHH>uꔧ3g!߿Uȅ'O:88gYcI!CO>: s~޾}"h_u\nTT`r?Xp;;;wwwVcc[@PQQlkk~uVAA-̧pv\277WPPPVVj +ۇS3fPTT\hWggԃh /r"HqXrFCCBBf6]ZZֿ|bҴJJJN@  &GT=fԣ#??2G)""ח~***JGGb655I=KkkkPP󳳳N.gϞ=   7w``GB|@ * _z{{ѷR7cR!N                    _ǟß*ʙYIoAAAAnn]dd$aݝ…ցҖ~ 555yקOF|VQQ[ꂂ= {I]rw$$$ڈT!:Ν; +{{>HړU^^.|d? z-;;+<o222N>`ѽB SKII}\Yg?˕sU;;;OOO Œ1Jbǎׯ+++[XXܹsL,aDDĒ%K'LLLҠM+nXXfqd?Z@ @PWWy]/^ 0'Olll˼X,==/ +$f7n$''D˗/wܹs{+ ~~~555)EAAմiӸ\A777%%%SSӢz|xx8;;XKK 󝜜ձk"0 8Wb>^33џ­BsڵziyyyKy捫%Va[[[1]iAeHsɓq0..V[\\:::gϞSx677'''xOׯ=ehh~:_^coo/3%00srredFBӮ}\RR"m"F́dG3N2 ޞiNMMM&EEE贀znkkoS&=igg7{px葪LJ&_ y^^_@ @#222ӳ޽ mbBBlx ݱc>ܜʌ3444.]A===3g`ŧO憄?Z[[=<},78\Ti + +c_)s8Kxʈ{;}tK.{dddZZZKK ^v#wppe}ǎ#{2JJJN8C +cu-|NLMMMȌd@΍7P &Q iiiݽ{?Ǐ\.[ f&N"##YZPPȥKzzz&q NNNjjj###L66vٳg[ZZr(dBp_A@$((hpp͛zB<-8 JΛ7a[,Lݻw7n<9P=Zx +++8 \pF]Rb`p@p0)-%˖ 2k14$ EϏx?6åa$Ȥ(+#'/ g _ӓ@oވ/MQWW߹s'hddd;88~%Xxb5kΝkmmLDnQQQpdp^_|a뷶TWW.\PAAu_j"̙30-- ~ϟ2I +߿_)j?lWAA.^q`o:Tش bjj*]ff&:&,x!9Ŀ}ЀR譪ɓ'[lYhQݢ=t˘W^ꘘn7⢦622~jlllnn~eLآ\yxxar>c۷oO :$4@ +++/aa<{,"""!!!%%KJJ*++ HFFǧ]quujNNNW^&%q"VVVVIIio߾ea@ 9#q cRfe|!3gǏ^j-{a4(o 88|C8Y8a'x~T6JHDD)tmllpkKݻwcZ6IԒ%K.\;͛u':tgIHHRZJ&ffDU" !ϒK$% v))JdzaN|X bjdddJpCCC0<8uL@ ..n޽0HBBRRRoo/N^^ަM|r]v:;;K" o|~pp0 Zll+WPٳHƫq Ztܫd99gQQ*ĴOʕ+ TTTdddb +LV06ٶmGFFЧyyÇQm]&Aq +---D_IJJUklltqqQSS^lp``jϟ?np<***:88֊7s=)))d444`d ⨬AcldttzhmmmE`TVV.--e`v{nnn۷ogVٓ6NѣGA 066!3gΰS$&&!Hkkx<GiVV8~pj3_XX/dss.455M||u)؃x||>^GG7FFFЛSgg'Uqq1vӧO___\[{iK.388K0DB̙ſe(95U))!%S͏E]#DRxyHh(QQ!Αgd0<|zafܠ.t=|ӦM ,-PbHT\tjBww7322Ph#۶m˭b`8<<<""T=E +rLX*닼 ~%,<@uuugg禦&¬a3z 066----===]]]h{{{[nڵȔ[``@ gH6GGGSSS•KJJ.D"tʠ}&322+mȸ\nUU3trr +NII9}ѣG=ȅ +Y5kV^^ڼK 0Y͛7AA>Bihh)#e6NC("tpЎ +-,,RSS( zzz >### $"#cPPP[[ưE汱1>>^KK {144E z2nJL*!!ʕ+ب)S̐ijgnܸ@o\\\NNΧO `7A){ ݝIɢx]]]~x>NILLpj|]\\vc߾}}_ y\Lqq!~^޾%==080P/{'?g>dHlFɁ$*xxwwჴ^i +ب_  ,X` ,PQQ +iv߿5 +@(iiin@JJʴiӸ\ӧ!`x񢝝ɓ')VKJJ|葽u]],9v옆&ݵk Ο?O'-//߰a9\("իWܹ~mmtZ3A0tI@HGG1~r500P LԔ*))  +HZDBtwwx<~h0UUU j6`~~>rLX*$3߾}{ 8a+ʃ!WOOGGGrN̙3XE†;wRI;;;Qv/_fAwmmm1\,-mZ2  GGG) ⢣cuud9~8v w% F;pχ3ٱc'VXXrJ]]] RSSL?"xzxˣ1"v(3w\ggg<Dd𠪪ODȮ]Y듩Soww~+Q̜̌IO'&&!99pRO$pkIL ٽ[ʊ\,o +/ |V,X` ,X`!۷ooݺu͚5奥Jjjj!!!D}/AFGGJ?UPP`mm w%Klٲƀ[[[` D t|^ٳg999o555-7oٳg4ᐐ`aaL]P{ \zx*Н-e\l2333 ;ԫ /L + y.**-JJJ!,DD"aP4\r)@ӑ#G)Kss {{{i7|dR.Ԅ/?p[&XLM4R +ԩSzzz.?yuLݻwX +(++Naد`(6a*tD|i!t脎GjvۗƈTs`Ҙvϒ$cuo=vWy߿kv~}߿g綶6 Ix@@Ecbb +L&^8vAGGGP '::>bʕ+TFGGMLL>Θ޽{.]+9\.Ye="vpptKwy?8RQQD`}`ٲHD~XDMXY_%˖I =="VYǏdYdzIUay J5r!+Wmmc䆈V  0` 5|}}I/Ѓ233!H###eZ `/^?>>KAAԊ!bB?ӂA]]"ׯ۶m...555kT|^¨qqqqvB=B(e Bzz:Ud/u|;i|ZxG `t&444@0?~<;;KeQ+HTUXX866F$ZHII/ Q})`bb?.xđzsssTѼy{?=&ݻUUUʕ 'J*)4???cccVP@:f>"',QS#D[s"؅gI@ٰAboJr,mc#Z)̮G%h9p$1%$,lLlmdBr*پÒ 0`>>>tuu| +H<-hv{!!!nnnvSB_|I +Ң\L`` hc\\@ HHH~z-]f M.tttD^`fZZڂ rss_z/\pɓ'}MM &XYYMihhx]ss3"QsVVhs,((044\jիWU<##ښFvp;(𶧧˸e˖saSz{{?|PeԄ%33422RT2R|:{,:d)<@a^"C~xHt%5)g/`-!퐇򭘙ijjjll@r͛7TgT"00޽{X1rъ () %?QS¼y +[[[SGGGϟ?ӦMHG S@uuu544:::>}ZVVVxb8 E֮]Յ˗|I hi E(PH qss]#ˢ-TjDx<^KK1PLDEEƄV033 8 BBoߎ@;v(DKKKlll>*Dq+W`sȰr}}}E,b˖-XK, + +O"""bݘ644Єh0YTEmCfeIRҬd_>,Y"yklL Uɀu|YO?a$Fhh{{h!!Iq#%M%_ss󰰰c 0`(.. 066{{{iÇ!]o޼9::L>h1VRBee%TbbbY(2ܤ$zgg_X]D*D4!5/$JhP"Dɔ(a^-S H^Cd1_M.'jޙo4ss=]o߾CN_?C¢css3hmm-##ô;;;/_Rz +@].\P[[r:444~~~`lRZZ +*ܹԶ(%Ѻ333۳gOpp0گGCC<|MM s΁ +tW8+%%ej={fbb}v<())IHHKL dcccDK]]ҥKh?1w;;;QQQ?00@a=<|AӤrP + +syAIIIUUտƁL`t--- i"''w…$6Qbs'N#}6߸q*ΞIL|􉲀,#nOqs15c 7`ӦM`=22"A,ŋT_Yf}8_??"$D*woyQP{+/ V9ONܹCqA޽# 1$>_7D45I[qsߵL\L!!!DZ` ,X`:|0m+%%)EŠ!3<<:V(OB[NVVvfmm xԩ +AAA\? P!{PQQjD!CXXϟ +hU[[[V<755edd\uuu+++???_>;;;oܸQUU5DU[[[.]4nnnPϟ?g/_бPS355x̃wR]]=/^_'YмSQqm===g5556m aVKuQ7ohczz#]ׯ_7o޼rʸ8fiii3gd,Ʊcnj& wŊʹۆ~*[oX'///3I|QLgdd PGG';;{'?###17ogKKKgƍ<[lQVV/wmll:::!-4*//?s挒ŀqqc!Eݽ{#MqAA" @֮%HVY|쭂IJ"m1gIK Z[ɑ#DYBMMFI{;ʱ` ,X`/jaaa7001 UyA$!Cw]]]Sгk֬SSS0e˖g(\AAAɡ!.111()vƌW^WC}~ +AP1g(YGDfjju9U +Wtuuˠ^edd@vqqY555߿@deea:B%dff2غu+9FFF"y}}=Rj2UGvvvxvpp̂ CBBբ___utt8WZ%//7-\PKKYyTT< ~kk+b)Ĥr["Z[[*D***^^^RRR/_aoopEYZZZ,,,ܿ,O,ȣGX9,v5t`TT>Ku޽ǏS()))**Lի_q rssQ<222={6ׯ8 K98H""' wHFyɇaLLxk.EE~=ik#nnc{`ls3yW` ,X`@ZZ 㓓SSScbbDEEO>= +7D@NB_R===CiiGSS~#ɭ[.FFF|BOODΝ;߼ySTT Ъo4 @cvww'**JGG!BBBǎؿ9(><ɓ[nE;jɒ%~~~ULL VPPѣ fP$ׇdff2@ ...555j(rqVJJO ڵkՋg)x{{ڵ+447##c 0''ɓ'Ç۶mgϞEGA/^`seaaa'TUU#""],-- r*2??:99EZ쭗m;8剝G (;;6 @AAapkΝ FpF##ұݻwia{{{@@8_RRB]k@L\vrr=uzKJJYcpPvv*...l6;99Y@)[ZZޢ)k@DZUU9744׏C͚5kű6wm``+/((Y2*] wt***Ʈ"dD 2nܸ@>eJoSS6yKҲnݺɓ']RRhcۛ>>JJJ`6l())wz~~><<`WXXtRVp̔PŮ.z133۹s'?׮];z5k׳gF3g{vtt |Ktt4Ud8L>}hh%6a[ċ-p.]\v'( \EfؤbiiN{ *z <|0۷o?zrvv^jծ]N> +^.lDn߿+O8 ߐÐ$6 t|ᨫB4pRRU{{{?}Mt26[;zɓ'QA 233%duD1#F&NTڼyГ[[[y@>1/8"44ŋ߿'a4͛1& + + + .|sEkr@~ڈ=!,&zzҒ~J12"ɎDT+ jjԔXXWI_|Wښqb9"$DhjyyM(2-ZiaÁkMK5//F_0` 0`X9(( KA!m!ݳgOKK ?---333P9ZhjjX[[K AA-srr + + +V^M>|ǎ 222ޏ?<bcc㛛ǮzyyCƞ Ŀڌǂ0K,Aiatt4fP>a>>Ȋ3g(rg{{{lKP(++C%$$(kjj޽+4| e2_...ÇGTu%Z`͛7!Hct;;ĽwTõ:q觟~B"LLLrΝ\ +qʷ,GGٳgwsbG~U;WXXwEHME +vF>`g' +?,oŽB@b\ͅwER`e%:;@>8)7 TTDDDDD] 6m%K0aBJJJbPa͚5BCCMMM(1J6ggjŋxz!Clܸ4TNU=z߫F666Ǐe#FXr%SRtƌ +رc˖- b!+)((@7TlccU<<Щ|rQ^|nҤI(KQEfΜPذaMMMQM>5ʻhqww7nBy#JQ +(vܙݏ555mٲeӦM233eYYYw,FFFo)I{,G"HRd2۷okjjƺ:b~ԨQX?ݻw +""""v +^ssw%Crʭ[^x!/zpSyy1Ⱦ}Pp[.<<Çݾ^VVviT_*{{/m333++/ys猍_z%oOt a(4BV__۷oK$6PmmL&Snooo1cN:{l''<ܭ"He:kkk^ + +sULff&(55U:# ~zrrrUU՗zbnݪ: y-5c+++Μ9]ݻwիEV7o䍸J'O?~9stuuݻ_)p>|[,Bc"uo۶T166ҥKjTǥÿb };}UQQ~ xQaboݏ?vѣG~~~)))= W٩տASr<==0E}[X,677swwTF&Ǐ~=>}ޮ[/^֧Y\]]7oJ];dKHHpssr7nܸwbo[ZZ={Io~`(n\?'#E166ȁgttt t_x"D_pǎʍqqq $H!!!"h#"""""""l/_啖&o)++;}t```}}FDDDDDDD4D'O+Wxxx$&&thDDDDDDDDN{{{bb-[SSS[[[:."""""""i#"""""""""""""""""""""""""""""""""""""""""""ocC RӕL&DbqcFFFFMM TpG333kkk/HӋrR \R\կfLܶ8W?hdFXP,ePd. CPF) eyҝ4^ss*z>4{=  ( CCC ..gEEEQQQ"̜߳glʪU݋0'"E]+   pvvv4Miij컜FNgXeE N県'&`0\D<###E +   ?3FCFvw93:bP~^]?8==fnoo܋."##E +/m!  Pi4Eeꚟt:GFF*++ C^^^MM‚{b陜4` 577 'e˗/m6ZB*;11͛lFi̸7`tlp8~ bqRVǏ?𝝝_|qs__Ӻ322|||;::jkk}թUKKKMMMX|KJJ)'^g Ă֓eIǍ .hv;vOMM~`Wׯ_y>Kj{{ \_dID&fB\Jw+q-,,D>e߾}XN,>A-$r=u  9!5F\YY;??o0H鎎~A`` 5rZ^A]Վ*Pl%[>s$djPYht,W @#sss(65cVVVTTԽ{|}}yA|j̔ +_~MĂl6Kq>,9880LaaaXPD\\G tݻw҇ʲ<66zWә4^rÇ\xA݆B &&AˋlѣfuX:Bcc + J1rkkQ""4 ~9EE"B;!ayI  ꌬh4a莌0G;--Mu٪[\\LL;==}zzϡUUUduuuԆDF?\blYQQ'RQR---QgeeQ1:88Zj~}}=hyyy&&&X vr||[ϟtjj*!!ڵkf]7 ===ZHYsssqٙ}cў'{{{}}}=== + 1ɓ',ݥqeee\RIoccC7n % [[[oݺGnll DB#7^.AAj4ʮ.֘95<<<|Cd$j4,,9Mv;vww˗/#""Tzrcp8~ E4 KKKwjR1!!!112PYҪh)))jԽ8)N9ߖu3:::**JUj8looϞ=Wqx5㿹I؝NZOt@&CCCL3W]]x$CP]>3@@@@^^ީ 5Jܶ=.[as·[܄ƙ+RjGGGB8]yONNT80]ƪ_󓓓v%""}@#p|{+&s]VSSGI@+W  :;;Qw=Kfܺ0zݹQ/pQ:H=2ԑP@:H$(!tCQI$BHay}:"]0^kl{=xwygJ!B["MLLDE/J!(Yccc־6CP'p,(QHkZޒu2$'X(q/Z>;;GȥUQQQVVf٠hvvFathB*{nnNJiE(S$H;wHV!!!aooDB>ca}-))YXXvvv#z}ZZ˗/8F`dtt6449hLJJsq9 +E6%c0|>0޺u åP(=' ao#B!$PgJ "q}}=$$DѸ\.ݻ7<<ЀІ333biZޒZ8www/NVU*a79RQQQVVf}hvvFath +=}dAH-.."/`q:rtt,իWЧH+o۷uuu^WX%%%Zr_PPDuۍYYYF`0DGG^3;;>66P(FFF<\Xqbb1Lxӱ ]orfggg·B!3Rrӧ2 *\(\U*BǨEǔ4bj+%Q=>>MNNF,\0MHH,JtB~2r4!$Z(,:ͮ.|Ri6hR4DP‚Ĝ HHFXIIIWc_ Q7==XVVuݻwz=GONN +כ7ojkk1">> +gD{gg'vc BWfbb"$$nll`h ϟ?St L&$͛7r6p + + +BbiGccFZWwB!eLLL}}=!yyy}uQpfffA0OAA\}}}b,tԮlKKK~%mPuc\FQ5-dfnn.F~vvvuG@aKJJ + "&$& h~!h{pp|$Ύ4b1..障l _`0!p744ԟhMh,**¥x2,(((55}E!/z=˰?VWW5Arݸqk;77HsEieJR2!BA*%LNN pffPWq:gWWޕi6Kn[2{gggusss>|900 -ߏST˄V>{ckk A4wvv7 !ڧhB v'O/b6!*BCC!3[ZZ4 Rz?͸\R?==C^qR#""pJ?>>(…oyQ^^]Zbd2\.W՘ybxuu5{@:==1dXkX]]ngffE7^FFxU,!ϓ}_"CW„B!B!?ɉhLNNh4׽B!B!7>>y{!B!BVB!B!{ B!B!B!B!B!BȥGqqqkkuoc~~gyyTX|>lF͋ƍbD5wYZZBHɂ,CH Hs ")GRK?Vl@Raoll6GFFb -B!Bˁι@^^^ZZUTT:; 1|zz&33vd%͠T*aFA~˅=XρS111SSS6 t_\{{{aaa 8 X +Exx\.DZ?>>X׻h4OeeZ@`wwN۷Rkkkk]tqpaŕ_g?WYS[_  |( +iӮ]vzacZrssGFFOMMI2XReXh༼|Y1`cL N{{;j#d27ߨR?ff>FRPT'Ou??q +r333m6yїPPmЃATurŷ힛jP>}{Oh4l|PTo}U~jjjju$Ij2tVj\zU$mooBr۷QģTNs, `0_4ҕ+WrrrD|4&9</9"H$&T*#d#N!^| +:MXz}uuuNNhkkSfxxo__-**`d *Jjb}8>ܹs7"љo޼rf%!ܑp}URRz3?~CCCG;;;fYZ=~t:݋/1. 뙙@t:\4P~TQQy#+,,Bb99eeePt܎'ᨼE|APDǵ54UG UUUF$ ~2vA0^1Bavvvgg___7G|R^P|---+++s)[WWT*X/ +H}_&hబ A>}D5ŠRJJJh4lX ܂Df] {{{p bi4*|>G,|'''&)//ւQ(j(x̠MSCPÃp8O??o9g{`XJJJD"ƯJzt:'Z{VVVF`c`` ~GxYYYGG:]]]]Fղ9ʁ1Md҈{uuu6 l777C0D]*bv`VZZPgn<>>.,,DhT)l>uċilf70h߀E OI~+gv%cByAAzN)a Ps\.B/555==`P<XcfCZ6551FE( Ӿ_<SwNz/ +ʔF-//;LF7|>?##b%zBfggr\RwRPAjA L&nőbQ*555V5~j%ٯ#Uo4*{jj(rQ(@Y 0o8@0K1bB̾`ۤ_97ht>Y793ôӓ bLLL477#a[[dGxT*h$>/« nZ.**"ڧ*p8USSCrd +ǃ IZZFkbݾ}C`0cpQ8Lnp訑5gggwvvb](+|Xo`foܸn!cKL1Z SPPPPPPPPPPP|5L,lɛ磊G>1[C1D?2&GF>jY2FJT77:kwqm {"*kkkblXL&MLn˗/F#:]|'''G155RzjnnN:::>DrrZӽ<<Ȯ{K ּUGZmCw%)_[HTSS*gbii $clll@-((H>߿B|hl6tbNSTg].SըT*Eԕ|xsssTyx0LJ8 l!Q}}}ggVO;. #BH$nBh$PKKK,vuu4{Nww\ _3s)T=ݱV |WvOƃ Ǯt}}[~~>V*,ؤ4Myy9La_c0X}0XlvN|[ZZeGGG__< [[ ?33~̉}9a1G~cfg_lfi]nNLL`?())z={ݍߢ"5ZMRA o[[xqqqxr0r!*lTHX,L&e||<** +<ں'Jh$!ԄZ퍧!T4%/.ǒP(@[.ˏNuu5# E$rR氙srr + |~~!ZL,Y2ƍ |||>?""D"Q2Dt{zz:yjllLCUUUT!Woo/& 3<ʊ {g`j+p[Ds99 V_Ybm=`]YYIHH&[XXRRRL&H0//Q!BN111`844ZPP0<>>9Pp8N@@ +DhTը5`15====|q}nn.އ0==-B999 +D@Qneggաdx<B?Zb#<88Hntt$R\\S!8/--_f _\ 2Xz遻I,h؛^I011hnW;V-lݾ1 X,N+Bc ae-Ը8,=ի'8p=s9?1glN-KsssRR>]..&IRA)BRAT%ceeeDHR\<<.8\C@`4p88ؾr[6I^j%`0p\OPFzqVVVEE璒yppPUU%jﰁ_  +[[[---K.Fb% + + +yyy`%@ÿOj + 1P4GimmEՐw`iZb1ޙ5 ڵk0ܹ0BHU7պfEhz`OǤb$vbx&*[ATj0f"jyF-H ň jN7v1ʢ>>V- + + + + + + + + + +P X:= +1 snnfE"& 044Ӄr\~?xZcx;iuuoU +' +@!F#T煰PA_c ;N$;4FP7/n_=ܿ;&Sϱڢ`XPjXj +¡X!uVR{zz`Rt +-I,yyy"TTUUommiOF,z}ZZfy7өP(nݺ +G ]]](u\~aɍRVVVYYI,bT*-uuurd8<<,t݅|>B }L&C>p#### .<*q4}/]|277p8 h"g䉹bxzh"JtL&1o>::4q.l.0554 + + +vvvX8K^㶍S"D|^؂z <bffY\uuuSжQ*XB{:.%%r}^MW\$?8徰q l gffzcc#$-T*x $.Zmh4(Ӷ ih#,lL&KkkkE.755o6^X+**@\722 > h2PUTP@tS7!fannG28nX@P`2'&&@/pFL={ MNN* +g1H_vn6{)((((((((((((.^ ×i4lHDVYYx +2pll pcc$͛798dee+;`ii +jr BH;NH$姧y{{ld2, >}cPdlT*ZhիW<oxxnOOz*rrrY +J%j322yB,//644r!&<==K, cގA>22x.D"v)#x!m6 Zmmmvvv``ӒZFXfffVTTc0!N!7]$ry  [ , g6-`;::zttDźw" )((((((((((((*:@[Av566NNNB]&@ݻw/P(Ip.,,@3B-\{~k(6JYb `秦BNLL|8L OCȁW 8a$,ɽ-g,hD0\]l!%cSL*"2gEh'eR6p6[w PHMMMn+==`ffϳX \j#+t9`qsstyooO"^шdݭvy~! +\wޡR\E dGGGfb$P^YP[IeV.(AǣBmmmA~f8N s}}}yyYՂKZ|S5RDh4;5GӡCƆdr\sZx||LPa#8e[ +endstream endobj 130 0 obj <>/Filter/FlateDecode/Height 590/Intent/Perceptual/Length 881/Name/X/Subtype/Image/Type/XObject/Width 1475>>stream +H +كCA_\ +endstream endobj 38 0 obj [/Indexed/DeviceRGB 225 131 0 R] endobj 129 0 obj <>/Filter/FlateDecode/Height 137/Intent/Perceptual/Length 2530/Name/X/Subtype/Image/Type/XObject/Width 1268>>stream +Hlg88KPs*ѭq4D 8g "D`L6/]ȐMFe'-\d̘dQ2Bbf&eP +I~y|O/mOs?- +K=kCU [o&Sy?:Om;~.M;˂M=U_LFyoYOϼy"ٸdc-,H:/ddgc-,#:/dS+!u0>o;NґU4 EZ:۬7UvKznٺi`CӪM;[mϽmYz/5{VϮ+za-[[mW +endstream endobj 131 0 obj <>stream +~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnmmmlllkkkjjjiiihhhgggfffeeedddcccbbbaaa```___^^^]]]\\\[[[ZZZYYYXXXWWWVVVUUUTTTSSSRRRQQQPPPOOONNNMMMLLLKKKJJJIIIHHHGGGFFFEEEDDDCCCBBBAAA@@@???>>>===<<<;;;:::999888777666555444333222111000///...---,,,+++***)))((('''&&&%%%$$$""" +endstream endobj 10 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 137 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 11 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 148 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 12 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 152 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 13 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 155 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 26 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 171 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 156 0 obj <>stream +HWێ}WsvUX F"lIN`9: 9rMFSU{f28Oݎ:yO?|}0_w3Kh{kUlu"*B +ϐBd_v8jbϻp+@dz۟5|3'om웚p]hyW(^?zYl{ 9҅Rw{4Fpl%;×TAnȭ{Un0Ǝx&|cA[ߑ"}a$f)āwMv}Hs P;I*`uV b4}/}~=1h} .xzVM?,q7DX%X߅#[:^~.SRRLHlOπp/R B` Ȥl 48 mtݞ=>:1)`doEY"rٕ;GG3Ic"7jqMiSԛ#0@&HYH8xinkRa#62Z2ZUi~M +;r>QVNZ ;lx8i;)Md'12EE̸*z.YtM6*J4Z7 k涟,P׌$:e pg@~.ݢV8 c-x^r S)4YՈZȦ"Xߛ;sZ/9?X>-MIpMj/e]|L77+6ÊG.C;\9Yuhn%`n:7瓶 X,pUj;{,쑝!SCٍ=57s5FƊ+.&M(vW1Ir_QBII#˖"GIt['$"A1;F=l(*+I2/3p$h!^*^}l,-<%˲8Mzgtɣ(휬]C9 (*9q}`#@f^S۳)}q6><5S Ŵz ƢQUMNY;rh=(Dde@.>^6)#Smi!wQuIfz{,cXMl (5TWY+Rz熀iɣAdTNj2`>Kz^%ras>[AL|.# +p$X%K`ۀ~WKF~OyMjn:T95jRYmU '3cCԳ=}/#F œ/a[#e+>X~ %~n!1=\lIex]HQ6Ni/a0ڄ1H.u- + uj&=i'aW͘Lgde.~W +"l>z##I2"d-]\;rĒ:R}E$]*톣R+^H܎ᡪ /YQftԿk|EEK}LJ%"]K}x?ab_X^((A${Au*@ھ7 Zj"y8CUSҁ4f|ԾL1kd[,)EC6ry}Q o-qG>z"y|?A3wcX 7Iy˛^ $2c-M/.L)s1E`=oe8a>p7%r@@rq辿BDJ|BAEV9E-xYt˲IVVսP u=8央OGd^4_@Ħ/&o`Fg(<" yy}ϘҴo&>%)^8y N^ZK#qUʛGfbCQ>\/~ƔɳMH0M=ӗCL5@MM xIf9VN_p6?8\!EK^5MyٿK'gHdP\~:< 임h8esq)'Ž}msWVy(WXqg7{XYԅ5xL aN!MJ+;fָ)κ+]ziB^JCX!k@c[.Z +ljSNn>ᖫ:p%# cuA$%R/>)8-T~-BU^-XKr)uۺ{9-Lt{x-2UןA@T@ځ("46ܣÒ6/rCX2[N#e͸(`bNҶz㼽_BtsJnv齐cr! @g,ᧅa`\ wZ8s3B̆ Y?w3wT;^/CJI'Õߚ@qڹigLtUZcT?,=aaDԍ@xH ^h8V0Q{WWn/۾C7۫w~_ y_9ZTRnq.Kdtr ş +endstream endobj 157 0 obj <> endobj 171 0 obj <>stream +8;Z\74dOhF&6A&_pB[ptW03$[\V4B?Btq2VrU4+Q/:q;lIrCT +&2Qq/@A.D)p(6R#_@>X&+&Khip2h+UDE`/.R:GTWLT +Eict!rQl=M#0je^;'$J;Ng:Qf!=PG)mN[-u;7O@r5bC2Sa@)PRr(DUr#alb3#c)M9 +MpU);&nN,t6=_.PJQ^l)2/b]/EZoc_\aq4u/IKoCde.52c)]E5jV*pV:d'7TqDW!j +o2'c3j#7^g0U6AaDt\UG=uDPM?Ad>"""lDc@1t(Cf!`V2T6TLnqYVdL:!u*=!TDL- +%9(YoS8[7('(C`A5Wd&C=96Io5M-e7H4$1V&Qfab]U+`?VLtD(c2;ngF)/!c)k]*2 +5B+]_C3n]N[$:+Giu-iDA@PU9q0^'?$'riaR7u.K.M5s7n-gm"fV@P:MF6:9bn_ih +8#EN40.2s_iob@leua#,JD[YONNH)W/ie5\f\!="k*8$'H?]32F$pG#YeT6AFq^$4 +bg>gbfl+]Sb!tS_A$.Dq2i-0ncYD.P4M%0;:E,ZrKB&R44q3hZp#s;X*]!C#3c\t: +q"r%&:M[Z,-kSB)0QeE2a4,GIc:mE8CZ4qm7YJ.rB(NUjS'@?[&+E!//)(3r~> +endstream endobj 161 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 430.793 -113.267 17.008 re +f + +endstream endobj 162 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 412.785 -113.267 17.009 re +f + +endstream endobj 163 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 430.793 -113.267 17.008 re +f + +endstream endobj 164 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 412.785 -113.267 17.009 re +f + +endstream endobj 165 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 160.985 -113.267 17.009 re +f + +endstream endobj 166 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 142.977 -113.267 17.008 re +f + +endstream endobj 167 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 160.985 -113.267 17.009 re +f + +endstream endobj 168 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 142.977 -113.267 17.008 re +f + +endstream endobj 169 0 obj <>stream +H]kq9)lbApa!e}x#Y}|JK>(х 0~QA;f+Abp!&&0ոm +DJ̴#>[?ۓ< 6説q\>Q)&ƪ~=6.9F.̱d>1R$Gжl_]q"U9) 2p=]0c1;u0GTG~o}zh'L#gӧR=M8#@}Mn&]YmW婲+JZ0ocrB㶹ٙF}_\C,&K%u|r_XIm8x;v&-˱]%ڹĮW7RF ~쒷;qr$hWQV|6Kr1Q.n.QIGVmhn̫O=HVr ,}7bccl|Hd9LF&Y[h6?Nc7بsl=q;LmKm+)&EN{"Zv'58dM9Ur\Itp `+XSv uq/"cO3r]9.na͆39NF丙)7?92Xs# n|D.7JI%t3v3xc.ϱ]EZy`q>ŕV`ϱXsyre<[1Rzﭶ9k9.^&Gg(DC0!Xs\qh$j;dnRS9ocr`N؝l>L<<>CjON>MG,AmvrSۯpxB:AGr;C&Z`B_qNT9މi2iS9VD'.[58$R/iC,106ART IG۬_nq m* +Jwj|uH>Fu +`sD] +[{MO߰jYOqU86M计#9B]$ap"Ǒ-톼Y{sSUo3l|Xe}׍sNvAM[]8LܾvP8 ̴} skyshMؘ\YWe-vn9wOUZ'mfɪ1-TuDb½ac"G'.Gb'P>o=%uQAPnpc^d:5ݼS꣫t8=/'m*% $` 0@x3@ ørC`W_F];k%-K^y>gIvPATEB݁vFU=6IKhnj׭4#Z~33kVFM5 +i|Iy܊YKڏ:#Wy=(q) NB:PQ&s p`dKU8?21 ;gjx,L;VJ0c2R^E~jGw:4~7d>}[NfYKڽYd` + |˒]|CKra yx|2R ?)i֒vOD^o/,(7jI[NaLC^q9IKx-!2u3&c< :1Y8?q/gj(O3Ale__=6SX+&0S__In8;\=izWM{<{( ]Lޠ@=,v=O/43u0,{F3GO5Skfj%cϘZ:LzXbjǞAsuzz"gP5ə끚,ub2fj cZL+#X`WBuGc"4:P_Z;VLFKcP^c4ȏ{5jI3Ƞ^A!HFҪ%.t3\^=!?P8oݏ EҪ%. +3^qXⰎUheY; j +jid1{zZ~ 3c=4$C½1䈘YF*NV-iw\2;=6 nM>{رQKڏY`235z%a'r$)jI!SkcFcdyV9OLMfj=6 k2Ux+a)S~|Xm4|f:[6e>zNfZV^nU?lj|/xR|QEXai!S?VUc ^q +@y1:d]ok; c3_q⦰1jre~z~Y{ 9S[rLC뢻twwjSc_9L1Ug+kҩ-?9'žrL[Uo~ʹ_Y^Nm!Ox2rb۰Kr5nԖԩ-9S.74NFW߯ԷCJөqq{?x;x֩sL=:m#ٶ9-s^6WoܩS[8Nmmc:5FܩS[{=mc:5.NpUf9S⎝Ml?nO/ck;gpOHvN ާc`FvFStJ˫N .5qU6ŕNxtT/Lvdgb N5C:5 |':5 oN 9~xasαә(}땥dcAbzNURsA]cܦWsz$&i]Usm'w/SUrY^%EZ;y=梏{cW"DyajiɆwist}ؤ=U;)Ɖ}רhyU#AXģ Wn~GSGRZ6T.3ke](ȳ8IM]c0X5pWfC]ݻbM6AH7Uw,/Ƹk7MsY5Jl%yyZMɅl-7FMY|2)f82l\dw`^J i,S^8F 9>3/Ws?YϱIN0y/C |IrY)(q|K] /^v 29FXF=g`,Sۜr>stream +H엽Fyq219 ! $#R f3}Όl +aI˹z-Xr)Ęa53͕HOZnO=f!^HZvjcΘT4Q9^OS5uYf VWm!0dbXYe? 2D_qB?7vΙ8fjkM&xYT"9'_g|Yq/A=k|oldWy`cx}]êrvw +WBZ8FgOJU໙SG(N*DF5"-x:^JLkAg.6y~7ue\d4dIuϲxW ~gOW(OW#=F`^GUյ3}N.D?^$]r4Ͻy6/6{]c>H3\E[=<{Pׂ4?걽aԷΎD%T:9ZmdCZ6ܽ(b \l|DRy/k`_y]mB\DGUBӤRBUx_,{2Mnc} .ocL[}QM6Hm F'7:AS97]@; 58rZXÎ",I.!8tb^C5F;7$Ebs!_^-oƔ\ŒvR?W޽쵰5j^l44Ť1#~?{^">^D1\zC(h\3*m3* +/(g:˧^>:坍R-z&fu:$kU o ~Ksz(BZ:CFos>c$"L6s:=.C13\3ν֣n +5XqzjP[3y6l,'smWE&ݚ9VGkd^oik~HuJuџ:T^x=9f.^OU`UXb 30qZx4ꜽ6,vk1 +F_{=:SU^3c^騖܇'I[{}W' [p"O3b7fnO}.ݬ}%&zNNuT\y'?ʳקV*_ENۃZV/I!l6uqɧbf֎^E0l 9+)S$Kz}?ʳ6Zh߷D|`YwE3s[ۡ]k ԩnZ[H}xXE09-DvgykY7X|p/>^h JÑf.6V{-)rӮ*-"otnV%FnkyI3?^mj;[JfA X%-B·8z)Q/6ع}}_ڦ]VwE+OUy-}hkX ΦWZͺ>x˚YJ5}6_:w:\u]p5Q>DEa.2T2yIaʾof]GdN+{?'vX-+ghv~WlZ:]s1.$*o^ՐrAO;o A.KQuٕTݧk=WUث6 ץ}mz3 H V:˩׊⁲ד|k~'ާͲVg'i&UߴQ}#L1K2i ӖvdmFe +"r8t+d,=Uo<駧}xx5Nj8sA(sokmYLGZmE~E}0n9:Vi;=k6C[g|5vD3dmÆѳOnڞmLm!y!i5 x UNiv|eb1{p{Ä-\3PU$3dI:8e74ov|97V/EV,۽tWow٭Ǒ2 +n}b{[3Ɉ+(iF #<;%2L.;鎝N2\t*v(mcu7A={`Vf.qX :8ܨX +:8tpA? kyA/lF3077Axk{0*tp {`Vf`v3Swp`T~tpA;tpfFup`Vf`^`v`ff {Q̎G~4k\ 0>= C4 OOOm p2׏u=wñT&LQu)Cl?X?sG7mkpmkp y0]kp]R:8atKkp'[Ǩ:PҐ\[H4dЍ5r å~BICV;8r 06uwfS>-bI)eYk¬l\,wpLHEݛ(Dj!~P:8azGazQYW⪊LT?T#05^K=uzaf:8r ;z4=)C;Fa vpñ>kEޚ\࿽\USfN2?I5r &ȴ˔| NLws5r F+g?66sk5a'KJ& ]WGar1IJv mӾ!;~#0J5s tpup&9 uʙZr!Yvgw]aP?\Rc\HJ.P\AQ\{Eq}M/̵\AE +YQ6;rw=O){kpQ&u=|VYDJEw=̠ U*Dky~/bk)|158jUȴuO@VGt~0+5*F5o5|c7d~u`ɠo赋eѼj˝ ˅47Ax=ž_g;!_m!Wי6y'ˏ }y? BLJkp3j?6\JmoakI৆kpY&s[huqŲ~rwձfxtsC5%ZQb{ WuZ;;r X{\ʦ(XY2\X\ʼ>]dng+\AERk,ml!t庐'>;):\r~pr .6g~r NzRٚT\AIUҼpf"7l?t kp+e{eBĆw0]WkpS2溮M>}ŅEUu]=/GOܕҥ䦞;mWkpX앬<5kp~#' +r N^73exk!?3N!\P$2m^l5*JOF:\ctX +3UqjIC5H6ir9T#vp!\|ֽ,c3wA<UUQ0\Fk"|\WkpdI*sm\yFNk'4BQeʛ2z\&r7"}uV?3e*Hwzkqbu.׷K!ahers&wp K+v{`HWk^,G-zo? isΝ4fେup ٞUb&Իb:|1ts5s.s޽TfevpVVQyJYs^5}\xm :s&OՅHz8]B?VܑkpC'k0ZWkktC5}uBp =P:!;\XuG !68=+ PuZ; !$..& +r=4\s^m oholᵢ2Jp3߾GGs,d\A0|OkW™ A@!D;xkzz,k/."i^Mo}ӾHCrrGTXg1:q˨yNR Y: ٧s6 #upPñ>V^8ueYw~Haۂ,F](!F HY"DD^>. *Iuw`Ssvı7:7 kϸÌ8an7WcZ'nz_vW4^BfE#Zvήì ~<?~L/epm *]|, +G8p<=<$+xy!zZ+S4?oh ץ:*I%w|j拟可^Z(*c yw<_m^Wx= ׮w ~m^*NL4z {G4d]Ӝ $x= ;&N9IzxwzzM&.ܩ=e$=珧gp^`^#ˤ4}YXDJk׾gM;?CuZnԟ1Z yE7x5^)Ȑu+dY|=zu𚒺 IL\W75׾dpO^#oj^Gx3EǓ nko2#afג 0꼖>͉ӳ&53`|K5"ןlfp/^ x VOl9O}+PQׂ{-oA7ߖx52fEZ3V2Kg2ڷ nkd uS![R5F qu7K,<_ރDqfnSI^)9y)pz\^ s;^p@6Jg:QQeZ 1\{^4zAIgAݗe] np쵗Ϯ.[yvC +Z; np52ݲF78Ú^2:wr起kdppqudp;Yk^㰶s_lV78ky n 8;{eR^;ޯw7G^֮ mzk3~gpa=^(e̥5vV/"gCq&yn787 28%g23}V^ vx]!;W.r7؆/~dCkt^Gn W^WON>O-II)g!q;󚱸#di{ kSRey XJޝ,,(cEbwdp6 + +l>dph ꈀ2F`*{{\NGh Ĕssldp6>ע!֣؈ֺufɇ#28{J< UMmc!r"~dpr!W/@QoB6XNHaݖAn\M}xxsϲWe@u^+dp(׽> F^ `loD7ݮ!u GQԉXPBH]"aNTDWVdKČG2JXKdJmBfWX%lVp4*ˋVwﵮjOl*TEA5I˺8WpDܪ/ȔkQ}V: EBhY7,pˬJ⼬O d%ol=ږ~ Qx´nΥEYյ;瀢7gx[RS56k$/n.˻ /^mB\'nE$<66y!%b-“2N2w+<#ESF 8W6U^XhÌ=-8:j(ͻz }뷩q}U +oVi-cpJJ*mGCyWE~߳*۵eZʢ-n>stream +J~0í¬گؽDћwХ˧j(Ȇ[LJZ‹grrs@a%^$hײ\#{V]#ίcZ"X!W!e:U!˚SP|||yrrrjjjgaaa^u[YYYUyNkIgDrD^Ao>h;e4V3T2R0P/O-M-K,K*H~ +endstream endobj 158 0 obj [/Indexed/DeviceRGB 108 181 0 R] endobj 181 0 obj <>stream +ϲ}ʭʬ~0弞í¬ෙگڂFؽؽյԹӷћwm*˧ɯɮȆ[þrs@n;^$ײ\#ήZ"X!W!e:U!ݟS ؚ˚SPۆ|||ysrrrjjjgaaa^uYYYNkIgGaDrD_D^?Z:b:a5Z4V3T0P/O-M-K,K*H~ +endstream endobj 179 0 obj <> endobj 178 0 obj <> endobj 177 0 obj <> endobj 176 0 obj <> endobj 175 0 obj <> endobj 174 0 obj <> endobj 173 0 obj <> endobj 172 0 obj <> endobj 160 0 obj <> endobj 153 0 obj <>stream +HW[}ׯs`U}R&qLˮkT_fY{ ۨUS!Kj\4zߗw|߿~cxj߃h1=8~y?|;ݾwU>C~"z|T| +x$jdO? jbG9vӷ;5h~X^ȑp$a`=iT{CãW;~Q6S`_{g!zV]qPnVdZ|b=RaIyGM2 {+[2]ȿd)RUj&miҵ1כjy(LȺ1"KN>DX+:'D,r0 CaƉS' 3y lU'D +;7 ( a،e':a{YEGNG*VM˝qr%$41 u^hw +Ý=)(v\FxޓB<Rf;Yb3j"PXO33A(ty S,T̨@|R%} !yRa|Z=q ~bp> Ȧ(uQkcc=4RʱKAo1-1lrp{fzs"aMTz[rD-٪A](-iJ63o5)v^+Y +,a +r WbQ^lVʪT_sR[8B9l˟_x^6|c5˼n&1pYBa(oخk7DP3y28S(fwgd "SP*ZӂTd;|V@i'ԐwpO|F=8OgYșrŤJ$NNjoKD9&R:wpǿ% EK&ɺmX5x bGgЩ 3qI`!5!a6*w8ئĈ.Pc7'V1 +DnИuTNjnC;E?ƞnW 'y! :/5}hհP*-RJwh!У :z`lO[k:r"}`Щ$tP66*wJ"bY-Lݳ]3o)̤{ <73 hP\fkC2 +i#Q>j#&heu|;$w# VO|tLU_#c>K׽U«Q0oA֠ObOWҚ@+)^NNgsڭGEZɒ)f4ԖJMZq6/eby_Z디v'O;"qjGef!΄0c s[j`dž'Q®~*02af +o3QD<]D 2)3d]ɂ%_%jl2}*YS}0HCX3@eLֹk!f]łsYۯGj?3B f~L.;pds,?g*x4޼Œbٟ]6-u+*q& `ޫe&UIN2,:W:|F&S@Af~q;Se{R( L?#|s6ގoyi8;E=?1f vDSt~9oa#N"QMN5ԧ7w8=UM@{߆XSJm0|:hqY" R S8 {!IZT1Xr")fYE#@]8z`*i >j=̩cԄ Ҍ3)eҝ%uH̯2e汿 +WM0qTJ_Zl=ƈym}]6a1z躥nfh{p]a3I͆7895_cB>>#<gwGRfF1ұT;5ggdFnH,Dpo26[lyٛ*C"a̓k.ܿBnmG@n0D {ޮ*|CB"C3Y.Rve"IE\ 1#>(x8o/|7:Fc?ꫤE"޿_gax ID?o)ͪ kEŝZnaSBͶ +t mNC= +X$BO:QVd3sTra"Ntfsf\H9eBOS.=#j9h\n7"{IY + +[&XU8ӌ2P~EASpr4`UM SQqyG.H<ﭭ=MEVTEZ qtPygP+)߿]FQzUƦ^F_G/"KϢםׯґ[B13Lb^kCu{Mmʷ!qlx .N3n"+ץZ⃶/%ر0O8<-e/`\l0s`;XFoc1/?ѹ|9^.2Fd`qx?<Ӡ+7ۮ>^jw;OvdEfhlv#~/vRR7sBKFhS->7k {|~E?=.YHcU9!? AWnk _KiRP;nyrعG< A bxM dc0OOT{ʛahCy4` Ov#X-PX"df~Bj-b@@*v.My z,)^H&No +.Uu.Pm +! !F'eF*2g*4I +=ͷ).= eio:B)PvI5er6KP7‘njcy}ÇlZ@Iu yu摺hpPrOr*i^a7{EÁ=a'#7:޶z< +\X*|Զg(vEh6hvhYFig}鑤cY!IY"ɛ%Hk +t'[%V'~_:Jz} +@t56cUM 9[/sgDy;'y'=d[pS$)VL|2N|F6ؾ_˷?,÷/nW}'Cv}6cѾZk?08I#dx cZݿˋWֱFlcvOے|Ϗ5 H %tbQNYf 6BH}zFۿ 'I +endstream endobj 154 0 obj <> endobj 155 0 obj <>stream +8;Z\70m81'%-;U]H]O7;]^4HpMi:=i6#Y^LOJOnXOtOti:,+ZJQ>D-]L@i0.ScdqS +QA"mA);lV$W%N>V=k-gP112t6QN1&jr,4sQU?V+mH#]do9AfVZqqkZRgs +MTQU_1`r``GZCK4pTo@Zo=EQb$qirg&p]MonPC+91%,_`BaJT +endstream endobj 149 0 obj <>stream +HWۊ$}gCeKBS ? Ƙfx6}Х*&ĉmRӺ'?~y//?<|~AMjC|H~fMQ#96,Io!\0 lC:Bq0 ?v {~Vk-/44hg54f# +n1bs3r4F׍@1JA CAIGwYE|QneȊ +snw y[TWWIfhruG.Wm=g7lhGN4ղ?z3x ̸?9xOBz&䷧ghmwp 7J}|ϧv,j{[->TNQtASƳ=Pi >6:@ +8vڰ#J$yX#Z %mcxB%h+I_gƾ@$5,u OMvCV~OͲ&eyq(}^[ljAȦHBU>*SFkARw^PRӎF:GBh{\="T ÆT =QGjb>+.R\k@#ʏJ\(%2!0%ƘhltQ+3IdWcsj^(&lUDm[䝈䒬ycRA&2j A={_k}u^`3KJN9l&ubm4B1U}2g擃GiVVe_Zς0*ms{$ vI,3d tNg:I,}q`5 oE_ORRNa?sk8D)‚q ;TPC;VPf[znh{16TLaYY3y88Pp8!t))2m`㢙=6β+ȶW.>P!=> 5`=A3rf*4^ϛCɶs!0' +&sPX A|7zvKHuǶXm H|d =B{ѳ:^>#_)z}[!XEU]ew23͜.Ys_TK苹텾 +Ȅe^9WhӉU dr4)?@ED^ ]I>g=ňHUC~Dz>I<}aN3 pq1|=,~_7͒$)18GcGi/b!9:(:)MFІ1ee5q A|9(ɇ!ś:kWK_\ڃέ@ wA;>8X[TKRdba(j͡栻#^r?qo' hat9mtx,@fG硼b0?(u`ֈBo+y4c3J"1Xb@ YRJO'LaFeSE:)Yn3:N`d!7#NLrIծ(H+)6h 2X&(+uOiZo0GuIDJ Iq6ߠ;d_ƐmgHij j @P&ؖv@t.a`zKHJ^4@LlgW@U CÄӡ%0i-6$\bI@2-"+oE׃*&;5old6O>Twrčx53;5 _ԌvE,HK@J>2-3w4Qa5 5aQق]qT#b|f5WrB&u %I7_z?;𥉉7k&N}+k0Zݾvq]ٵv]MS{Kءv#,(_*{ 2=As*J0/7D5,,^V7SIts +sCPq K7N2>y>a^qఒ3Mcj(h@.tA!u#lp614L_]~L q =)WKQgThakWR4  Gbr)D{ azkĥM&_Ô?Սv +endstream endobj 150 0 obj <> endobj 152 0 obj <>stream +8;Z\74dt+J&>b?_4b>0TD83&t$^IlBJlK:4R[bMS-EXZX!A^=`hF5_ +UZN6t\eU7/`HZ_7itW4f/"H*KgWLoLRfIVB;Fdln;),IRok2EeT\lMm49#1G4F"o7 +Xa)Bkj$a@p4VJRmIm:X>%;0H8Y7qc?9$e+D\De/T6"*$pia/shUaBBi0&!lXA(mNF@GuM +'pHt/q\jhH^cS,sK_s>k7QK]);f"4:P.UelK&!$UL%Qp/"S>QlI?IA_b(SKnYq>V# +*#8"V\3*3mJf2NDFZ&1&IQ5O-d+]dQORMA2Ia\VQ[aj$?*Ot2E<,oI5i"WNF62*rg +_rCLM(Q0I\N(q6#=MAu04ZR(AF,m[?\XnDk%Jp,Nl8dYP7`T!9(e'S5JiO,i:p2b( +D=.9injJT>P_P;ISM-5cR]*?^DHT*meG+)!'u*2>&-;DI3a<7Mm?*Ou_9)1[k%F6L +,jm'tOiABoQbDIP4QN'?/[d![^Jo$0T?5gJFb"3OuCq-:maQ&J.2^Qc- +GrQnfKJNu)ZX9(ru1~> +endstream endobj 151 0 obj <>/Filter/FlateDecode/Height 606/Intent/Perceptual/Length 64368/Name/X/SMask 182 0 R/Subtype/Image/Type/XObject/Width 593>>stream +H엋? 1-"$DэtYٳζڔ$]PY Auiݺ4\|̳gI}o{ޯ7AAAAAAAA?eH"1MXYI ʛ:|/((((((AAs ^oqKwwƍ &zxN88Ѩ\__7oޜɓ'ݎ['=!!QD| XGg㍍^xNBrOԨ 幻dw!ؾ}.eCCChEٳ]=|YE>> g\Q/WN>,,K Q7%3TRSB? +˃2F-ӆNa3˗/M' 1)1޾Ok)"d4J삧Ox=4>?ĭ(de%N ;ka!444xx̆+ ٳ]n-!!^&A7!77R۷5ڵh*==- > HyaWXX>kL{W^^1WYw/b[ìCuu5w DtOZ7PY=]<;tL)T .#"0atcbǥyhB_(2{TNO<Ԥ')1r.ao%oܸpqqb1>g;WuvzwvDA祿7oںuKp40϶m[1C٨a7a^3fte"iAL <ǰcqI@"1+,,`ל9sXsf.;P(B166FkeFykll~pLJ{Ő  6eeevZJs{;w ߽[T\|޽bsԁtԹsGOcRcnܸzEE|.ѪI5p Ξ=^pAGKkԫO?.V2#gΜN_¥Jg)F._U[[袵7B#xիW`.XXY9̄5* +}we8W ,Xf/]JD… ZZZ#*Uyت\711Q`o^f "ƷNKKH/)):mlO? ӁG𘔔d}bӧoaa; D#)7jk:#۷oqЊ8 oݺேڵkZܹׯ" ['pn5>H#.Nyp ;FFF:a7MR]VH`o?icAUU# I_فGRcٍw ;vRoĩkGA6Qd]>Z*id2".(bt*ZރǢ>ԅ*Q@DL@ $`|_@B1M~9;sn8|ɿ3/111dtaxavaȦM + + +dz-~wϚ3227o}}WAΎZ4  c#W_L``vtFGsqq123[oϟ764UTpQH݀G*"QΝA8*NBL'Wn(j6oClE1pگaÊm!9tt355<ڂ=okHNNR}Tii)|ס\Q@߸q=ZNy0_j[f5stH/rpãm߾ ˜[|uyQ6G|)å"`XÁ?WWW˹ $..'%p,\]<<\ll..p)}Ҍ̿v1pAAA唇KatT" (,,d7-ܾ}K57o^_+tuunnnºBX,_ %66OJ~)fkk#9xv<,.4PTT}_R{ܸq5Drssbd_ز͛7nn>0 V9 dfX!Ǐ;s&맟3ppjU|(H}{xTTLԡGF;;[_ߕW@i6)Euҁ}}}G[zʔXŋL,iǎ6[/_thh+ˣ&HyZҩ{ˑ˗sPhRRNDz /]QVK PXnO'뻉{DJ$#*>ԳgϠ$ K'Ox']I4>=E~oưIkGdxxX$]}]U =GA < BO Az) HyA@# RA'̅CCԨ56>; ǫeB>ަy[DDݬw)-s</##33cj䚱֭jm'lQ?nnNNt:9;;TC]jbbhjjٷ7ذx̺\\6h_x嫪*U8bwvtt5ʃ`1X, +ߴiǏ_"^99o?OyDS*T2rQTT$vs()))¾*+/(X{vFFJxiV*,,_@yuc:rVӏxS(ȉǍ7tH[''+ˇjj +h-WK&NZW{lŨ({NNc]VV|47wIbG kmmq@|޽MM \)YtR^QQ(sg!UUUH<ʫff&F9?n]  Y<1qAOH Y<5 8w򂃿#W8pٸ1':t/nmCF .YO!-m޻wҼFGV/,ς!!uNS,ӧ =gɓXoQQ^JJW57o޴;wxxLbT(4''+$$<(@D+/ʋ_/}Ey'NLyݒޡήޭS]<;8S҈./??蘦oW曈B##Åsoߎ&<|CSx_/+(΢܊1ѢSӔw\yzzw|Μܝ*UfrrNpqwÇ6j)ά^ WnҥR[SjS@K=<=GtZY t@Gs͚5+CwNLl\hё-Y%ڵ&ԄOCgnQZA6KyzN=ڑٳg1kѢTZ@v*4+^| i/IPPTݻcƌR2M(!,KKɓ)t5S3 HCmPۥKd`%H;ϔg4兇*EYEd>>s#&8B? v__gEEaúhtt/鼗m+))޲eӶm[Дd +xD*+So>G:sL쉉tJ#hT&_)uΫVEID5yeeM#̜7U~6"Gٿk׮K.E'!9姟9:h%>0(R@RvdGkkkLqE9a!G^[n ˵kW)~'xmnn>vȏ?"}%&nTרqjj!jKKK[[[>!aCi]Ӕ)tO慀P8rM_*N#:S'kN|𡇇`Ϟ]e7nL /I()22(>xZ%33#,l>`>aX.Q^^>yEHH6 uRޮ]tu(6dTrQ&rTL}3ݹs G\А!^x%S-_PN8.4ǯUb48mKK3 +c| S`@ 'Nʫ+ RK{2'iYY*qNII32Ӥ!ҥN?q/^BD*hx]>550 +3ƱA~cCyXb'% Yfq%Qޞ=un9+Wзe}l2AAmm_Gyr(p(?~??P*| +U*ptzXF)!{UUUj +-w ~yvwwuf~~B1Ox;G5h5'J…[Ƈ1PީSh_B H9rї/_mmIVVVJ+9s~477xDQޮ]qLA?@gϞ N27Jyqq\B#(4%%frKKhEE9HH2> b)ኊ +JH56ML*SS#Fy&q/i(Pt_~sVĉll, VHHpOOFNj-,&Μ{{{=߿p,,Tѡ \xvBWų9ݔ[-X.KJʧ]]]O>4WUUݾ}cFmOwrr,..\DrssE23?g:`3RDAp@_*YTYry6?$ ЌIk_Nee'_(h%fv矇2e2Z)P9=Z`FyIIՅcWؠtڴ {@^xxs׭ v9pxn.+̙ +汐p +H.P/o}揿tUƄyԩ6d 7lXOPu니P( +_˓,TSs H@++/p0+..!sg^S ŔMg}>}4ba/x >|p\|rO? `ټ9Eg' +n=yDv\tCCW'zѯM+,<G\SYC2<'ɋ/(<' +0iEEEueۀ!(U__߽{W}bcʕ8-NQQ¸wiiG]]Mp L4?zb!deo޼Id;& @|[ZZ(hJx51GwnioߺcǶhfdh|awor[(MѨ.[CDD`HyII dѥKaPu9S-zg Ct<< Fy|7##F +h4oS744X岲ӧ$OE"7YrjpeK˗/ɰc#WP^wwWPPHJ}a$XtU)"ffi:~uE)]DFndP555kÇz?~X2vu=WRUUI[&'M"Q[[ch`Nj񡄋禦Jo<;gllXSsI2RDݾ=899)r,-wttد_jݔNzJXQQa"6%k*,:A,~ڷso.RR>۹3^,11> `1!| 0 +!#c?qΎ722ų[WWrIqj M eQ q^قXu4Y~_Jy׮]7Nt߇Gyn;v xռ:˔w5[[j6)YW2fͽ{=7n8s";[~r]HH0D&Bg|ϛ>}s'Np):m|DG(mc ͦMǎMIvңPrT3ȠBZ33Sb"/VI-Bnj+((x'3lŔGlee!$5YI+ +>Cq B<噪+߼YBB\ mm=jGLt, qWT4e+,9ӵF-##7r2Lu>H/ZX899WP^s(%qh WUUӣ#l'o`HF1=}d)eX*'OH)ɷ YZZP0/II&66FX'3#GS-_R}Lfޑ+VvTonGG;T_OlD{]y==D&fC< _YY)N򂽽mHaRHq۶E6uQQ%#ސch8_;wngee)GV{[|YڦGRt,YLL 9aΜٓ^mRb:DasT&vK?[xPP (JK557eTcZ aEEe" +d1ÎmlTR$@ D6U "AeJGS`d${.s}Չ<"C"كbϞQ&w)rI')yC#>{Ɵ| pthϓ +; Cb>G%#"0\S +5%#Jpԕ Qݽ[UVvEp{CB +ܾwz{K092Gr,8"&&ԧ8#R˚"~+eElhkk% =}bnyyW +#f4 86<<k1ƍݝ_”y ]*))f>tp7J[MMUۂۿ& ++4YKII^DKkkKx%9,]\R߿òL +y7{7`XS DӃ.\ Ƀ<)Cf{zHnʏ<%7xOT%ڔy'p)BXpGOO\ AC6̹sɉm*}. x* Q)AMM t|6pKKKpeqq¾ ovacf?>>E4Aޙ3 ܈"N _W"'1YrP;(Pa vv6K y_ɱ}}}/hJ?lPAW LR': +Z]KKc.E䉾q%UcS]b}}R +ܹ+V,-[\!hhP.M;mbby G*Ɂ]]iIǏ3AK*粢kjjǮsrr޾y<;R4i |>իWccݺuCuq[`F]O> + +4qFs<"/A 9SS).VWWy1RVSQY:_ȃ='boFU**nܸtnjjBBPd6$&&@_V u=]RtɄVRR":#z3_߶p V퐔tt"{{{ S 5mm2%m444xl ا&>D>a%\}АJ!ùma>6 y CCC~4)?g_0=ٳĈȞ˗߹'QG ^v5#fooKH}cui' f !BBY^^&PZޱ y + qKp/ 2 <<ܮ^-m y\n-besEp8;wR'{.)dn1xvѼPw7ymmMH9 +C ꪪ*s2e@lppps=zuGxBoS Nj  $wt[YYwigicc-7:֭s}TTfe!b1˗.DvВvvv65=j---;ws<)==H +GZ[[P%$=r䐟/Be>|8f^T͛7[$,-7r\|"MI7GqRޭTc;"U~x5ua?Dd &e K㱣Zg:RҊQ-3Zʪ1(pHPVe 8IsFwރ~rwͦMTUUYÿ#(,`3hjŵt:v`2=B?13LOO/.*''KZQk Aޑq]B뗓sw.:yoկ8qG$yF<FAOFGDD#""`D0H"yDD$<""FI#$GDD#""`D0H"yDD$<""WFRpɒX,G-U#ǛFެY1*ʍbX,1 UUu{4L"""""""""""""""""""""""""""""""""""""""""""""""""""za׮OSSSX,Y!ggg#X,%0AVQQn<բE EDD$ϟ??qormy/\xDOyDD$z<""FI#$GDD#)}o0,OÜ*"2FӧOwr5?|4Fy󦒒mdݺUyKKK_ c_uuځ3\"c޽K&Qׯ[u;AMf]3hhHގrRj[q˗/x){QQ)}}/2Qӽ~̲eqfn޼1"bZYY۸R#q+.T*yxΣ@ֳg0ہ~l]t0v|||3~oƌiƥ;vIp~]aɓ<=' 5KXd1.8+&-yɓH4ɑ30=577*zĉZk"F^4g,L6)`Z;v|n04ty^^S3:wa;,,2uj)={ȑ#8Pj;4_nn80W11m< + +x^Yxy7".+pK?0<\x\Pxp(l`%,@I͊r$JKKDFB!)ihXϟ + DΞKFgf;y򄣣ب 煄s6t{Vd8DaNζAh@Xs KaI'y7o0.^Pw9x5+*w:8 ٿ?s]\xo`n_u:|nB׉R*H[Zj]+}D#Gىܑ98=~ܜP8?چf}KK ASg>.11AwAqwwՆ zBaښ{455\HOOja8)bJKK5Aᣏ1xhqy7ygd6 wXqgG[!)i5*9yԩS]z%wH&#y$>mqqE$77WDD;vyaːqqqKOV]]7nAp8ƒoݺ58EffÇnhT]Xn4&&֭J\ :s @*`06,,D{$ kjj iDc#ħ>66رt7xnnooǝvm"&Fzƙyy 5kۻwȳD$ݗ'/w ~n-D^kkˢE *\x6vB\j~~l]#Q3uuu^~QQQ||ɓ'[__;_BC7n>a~mmƍɇE`tLo!:nn.~rvvs #Q*fcS#566"ysmؐ|ӧO> +?,X0wu֬k׊<}jyy-G2\.Cd8992~/,5+ax#/+0F~WQQĿlL8H? NxBqq1مKN^ /Nm zG1H;CCѭDFt53:Zm693Bt~" ˆ`@kn r,x"p~85yqXp_ A.8*i$c]tVQmWErڕ$9V (AP"r)&(W5t}L{^7yXKva0W9Eff˗r iթ`U!ɰ ,qbbBmzzZ(Ƶ98|NNj%(`@yp +;L~333:00_Y5A@l9=|}nܨ{5)O={$AΝCK5t$855޲0I0(gk K ZXXz˃LLpib=G +Qvm~#"艨(۰b|R;HNNV^^NnnvP(9s1} ]ҕ+W0hggf8Wj͍EN{Mhh0'&&TGyǙL:#pk/^ k|{yys׽y(|6߷oo``@CCJF  pd}~~TERݼyrS%B99ٚ?pyuwlĥ +c0=3ځ"G% DyO8FmDWT^zYnN %Pm撀v Q^NYY)6ZXiүrWWFpr +ߵ8:gk\/"v:wBX(T2?q"_e-Qy b +]>KA0jMo"ѕOuB'a.O>:W[[|"55YO9sÃBBv:geb1bTUB .<\.d}jjJG;wdL֌]]޷Nqvv|~韣UzHB­BdV@֭3˩J \t7hLG[l) Kb '8UԔ;::D  9[pAxx+\$QX`XYYzGzw@xq: #|+*`[FFFPɣ'Dbcc1TUUB:8;;1Y⑼:-%X~;`3=SxBO>y`ll PGW3o߾UVVZUUUXǝ;NygNq-|Mkk+$`/__o??_#[ׯYNBX,$ T KK +AUU-#y 544,p*yT4I(NlęR(yhμ\"[ }CCS +l 3J&g~򡭭QPISSCHz5=l8[Q=㜷%'õ9}"3c 7$8b{!"蠒'\f%y ]###~^C wvv"ZKx +y0::F"da'9moop[Db8im=J :M3"gϮ]vp:?թ~-<ӧAšx Ys{t=goݺym۶Z@ G*(( q·Tf (y{'f ąנ&*ꢧǽwcggzJصk}} ɃJcm`? s***Noذlkks©ss;s}hh*8;5Tˬ$хb\M3AY Ҍ a,c'Owt܉RWW;Z]]]޿:8عB>~::9_<Ε ౠ1p^z gDjj#=RR(y,LYccC\ =&PoHrQ^oakfqz+**DH/Z$Gٖ-ӌ ~/-,--|%577[YYx5^s'`ohj~S$NΑxG)(0@̦<(iXXlJ].-KHH@Pάsz33#yy +e;#j YIa{#SJիWq W_ɓTXܹ)***RP۷o%=E..9:I 7B󢲹0@&(Yo,,pX)P~-DH||h9y mS I14+#ޱf$pJvvF656 KK/:;;qpbu_;7/***;xvpeU*ԐbvGG}L7%_Q%[{3yfϓ;MMwbl<=ݐ,,,;sbb}}}>iyQE쳲-ARO@!" +/LDfF ,_ oRՕ y =ٱwl混0-B R+ +e#=Wgg mm5:G`ǫT*iXW'%%2JB557\<Dd+F`)lWUULNLLw튆^,ikEFrE@lE@6ڻ76dP`9<<4D?qg|dn>S?z왆RPndV̠eJJi0;x ]cCnՑClӧ3AL EjiiVXzzz\\a(v@7DV0@bPh++v67-Շ"Cl.hPWˁ@ +Ŗ]F"ou:/ o" OQm?:u2:Ts\djpE6ݾ}kBSogVȋCc*c%P阘CdW_bx/M +!ЂzLoxN}hdf1]w=s,+Fbh{9 ® ee?ⶆ))Ɍ)c1ۃ^ձxyyzelltϞXJ˽~#ёFPoܹsGrr҅ +]xի1$Jr9 Gޓ'haloMSS蘋v(;;4wbw]m o" {{ڕivvqkk nb WW't|L&ݺu33 [T]*Ozz$ &&&ptX} EEƏ?vssƨ^ό0ȋ7|܈<!y')׳:;;KJyj@ÉfͪQD@ Z6vse˖MeСjeeWS#J%{u`,?ЧGO]]"j ottSԭVnԫ5ٵ+}r_ D"뺺qAHaR޽{Shh`#\6Fn1ES]ݞvy&+WaHKORl<4vjjBw۷onyOMOOXonVy$T)?"IWΜV'ż}{)=D"Ш{0<* *S򣁼Rswߕ/K~*$b! 3( ݰ! \'))Ʉ˓'* tԩGt(E) +U7oּڴ)]!!8f4:b.YVTT1 krx:-l53_QQ2b=DJA1q3W#)..Fpzx7<,344xZ^XoSNFFFڀEAbcĪbccp-DG7Ny@jxO>ձ_B,ׯUT\/,p-VBɅN7d >x1@ WT(b{}DG&tL%EvT}V&یg|m)^^v$.9Ry~[xƤyM!]b5dybtR:f99ɞ?Wr#GGlv3W<}O!##i%]T>v y$E + +!g2{x>dBL[z1mӦի +(9v(`AȻwB"۶m$1 ]򚛛1 +eBa%䩷l374 tr488@$ZBNХ655jBtA3vl00ЏH,AQ"K^AKݝ[Z1Cuo"&RW +޺u3>[,-- ˳}koh/ -"n'cΜ..|>v"ӄ@cT1U&aa??k~|..f8Z)ݲ%CTJ`k79¹sg\2dOOC-688j{whnFU <>];w6_>EBUWW3d0qℜ{Qkٳi/^0x*8/d.:y7[ZCyإq\߻JiRRF`4-&Qv+s88H7"#vs[G3٭sZ[ngbgWdŊ翡 ޛ[dٖp||.y:c[n O?Fc +ZK17o0<Ùm{W߃sԉ!1=z}rrzs2/:i _zaOC<|}}r9{/tjzzՉ<#9]X.//g7ץ\Z~(q#CϜJ"t\XF_롊)p\]/X2Ґk~h!mƳgeMR* +䁿/MѩS'hiuHiST͙$k?LpMf)L-w'ʞ~Ȧ76^lR{{s NS__ץP@#GWN. (*}}J477QCz^[[ximɓ_fffjB +u"P`yXAO>YLQmm,˳8܅ 88ܹiYJ1A?̝ `yXfi`v`yXfi`v`yXfi0͛7w ..ΫW )>7n[spqYc!5vM6V\>}S'CִiS&O&R(fO2m AX+J`yX+J`y-ol  mhGA4Dh¼<9LIH *?ʼn_CAP%!#AAQ(On:=ayšAAY"z Zk9B.,J`yX+J`yX99-_)W6;XP4] +ׅ]YW֤yyx#riIf!`y:fwR)L\,J)n4#DÃyCxcZ*},XjZdǃK#pBV(wiYNܙ.߄.xQx66([z I{'sN<"Bhpœ8!K8.3'CeѩV]Ej.!wFN5*["ϹPh̛:js'fHn׺n6^L{y#]]ȝ彛/iÐ%6Bޑ?#&\T)<`Y?J{ABJNo`ɰ/Bl9myפ~;va6"ɦ̹Y.̔~&Bq@7;mu +w"jt6ӅByK˛U i$6O#œNsOzUw4Rdj}K9&b0c U6zoCWEoWOaj&NM1)*zyd+ۮz5?09) o{_h+O) :16p'ۇZUU6@}=An4Qu4*yE$WõpSGq_PJ#4iԄ$ZeM -U_` yp}@0$)BdJML)!i&LhW!\ 8 p$& +(BMb%Km7l _e,۲-ْ%Yoղaʼi=>nCg6YC[[v{^`Wg6VLk-vi +o*=Uȅ1Ӛ%h56huOFw:e6KIYwIJ˸,Jn5#88"04b1 x@Ҷo1MDX+ Ζ紑| jk_SF7eзEPwX<9y{t0U=x.azW[3GSR^W>NY[hop?NO+;qqC^wEh|Rr&2hE ?D*)f筵H8.F>SI Ce`Uv6:."ۧ%=Z_@ZEy8>a'YYx<9.>`dzXnNP-ܶQǹN,&J;{B!ɯγVCB];RC LӽxX\(|f +niE7B)wHbNTk pl*,zCg)?WE M۰#6wP/BCh_yLtoBW Cw @IL9sx>dY{ģE58@ydu$g7.9&[ *{kx,I TNNB-m뇆S _Պ%={<ցX+DBBC#6?Z4dWm=^~ F/|$iBVJV^oEaf 87( +piѥ$8e=)D/z>`R$dlgwDb6 : oGl_ 9CE"!_!!-%$}^8[ߺiRDɯ2(1 B@B35IUcUԋD^A{(B~tm|4g[]vl[")rXM gūSSv5z>g4KJ Sf7Z\N';[#2^ِi6wEBIGbǑ Xy&4QBՆ\2kVږvw0V;)~ᢱtx79[z<З l$)zrª`RGPȫ@B + a2san76vBFj>BJ4zzPaOF)]PS RYS0s缝q DBɅGJk)A)Xx[vBR(7ңov5In7^dCcB(768Z{`v XDXg8?4ϘmZ%@J[vi'04|J I`mvmc&SHYfa 5Wox"[xY`[mٖdFC"l#g(}w=ҽw[xxG?2L ़ZQvtN^yp80Id2}j9 [ ںׅq '9u0lD7>'G_^4P4r(;h367޻#B` +`yP5Tzoz=G'ZD!? ky"w8&ء12)вƁ٥7]}iI2K>B0÷&6~Ms@y{.͇sx~Ø-^wDV[ wD>U}R0:=)\O0_c\%?3X"M#đþ] +,-=uKeAa7{ᘃςrpܜMOw;>ˈgrX SE 3~ky .5^qi.uAA+%K^Ġ! ZTo}SG!ezq +oY fkyqY2tlP[ CRp?lGCB<$ -/3#iU &Ke1)J/)[Ӟ\ƶ+[k.ojr9WYjG5Wi43[df3;9-%^8o qE #Cf"O򞺛ܖ5lH)q6=^J8Xs'S+X^ݔיּQ{Rbu>Qp%Y*֦CJP.a|pc iU%קo}ߣ*Vi\T e"B9X\ީxWuf̿nGީ+v^;([@$AC +}(Wѥ]*oԤiu?.K!OX ?- w[޽`@8E#DtR)f_QfR{Zpϟ֌@c-鄚3I;7"1VL-{pW[Xr Id8]zퟆDRB8> ۏڞ < Tbܜ6@%IcNLɼ',h&y&}Cק9`k(-\ơbr/$Tjx`_yMFr@VIu >I%4#(NGBk3I2B?p絼m5W=. ^_*z;- +{!]wI JU +xZ l8r?oq': +:j;D"XTAKOY0ciRFE$0yau,>=Iˡǔ/쨩O'*t^>)BC9< L"ݶշJ~_QMinE::m=sʴjujkv@@A@@ t\HEZ-QGK$DK`@yKi>ɇOyޛww>/%WMkwsp 5Ʉ"Oo3C ^SiCMM3^<2x +nyڡv윥0'؊ڡgHH]? 9ۇpFɉ<i*t&h̺/ O@S_`B5GtT\r6\_(Ȝ$`ܬEVz5NF5SA Nۇ_Mr"Ôu^EaVZRuFDw-,4Mo5ScuYh ;[yh5eXh,``3oQ[*+-i3BVbn(f뜸p GI%y +Ozv[<NSuj:סAd#]/'z#99XE.ôT6ʉu~)AihdL"`^n^Ώ0.mLk}u|#C]X=.7@*AvwɯV} @U֥y(;[-R>} v3 mvvY:w04Lc"lL"uV6*::J +kƢDA&ONqɻʮY߱ yS(ĕxsjw͢B9m^zJ%]h2J]ȇ]d=?b:T}:!@5ƒ^ ڎ=;2q`ɷ@< +ymҋF{!2׋0cY[y +]]? OfA7ZyHB\MuYXiPOmJnx 6g]i^D|^…GI%iy0l3}MNFw(i)4|Von +a-`.3AB h:I_ e4+EpȣW :F#3^LAF]y{yIS)DL"@d Qč*״N A"X;Yw9Uxk{oD,L F#*M79F$ s7({+2gl^gn[̋Z) FCsI/l?(F W},5 Põ9($hN<n"/:^pB#פ @?_|[tC'w)}+I[K/nn5t@7 Ej!y[G!"OrA{{^+]x-WƑ &j?{rԛNv!#S6>%CX3 z*Bc]"\gYei`3?KxvR /^Ή׻Z ^9vvAFx… <\JhqwY)y7792M3;ݖ'f-:ƪ w?^f(O+y 1ā MSn"u#.)N2Yl֘L|Gڹm|QhP8;N=p2˯`oZ_p"M055?5VlM<~,:**K'݁"5冼v!wy|J>FZ4aU}聾(@I?B X[gȵInx|6fÿ2.6iP(>uFߺkA?䄉jȍ\oF= {V2~,-t|: Zg1zqs+cH| ,/io;Oӗ}RzhE(v7eCpyβ!m1/j(Ve@f,ˀ:߄#ׯ GI%~#\:9_QMwڮuvcUϬ{9[ln;vQZZ]ά +֣KmPHB =B(&B 䝐&=E \ >wo|gAnHy>~9w࠰Cf޶ыEi]{~jjHה,nG{-f0ioQ}'3LDzÔ-ytI~Ȏ -MWBii_Yz̰ +v-sb':NE[NtH32¨#uu4iEE^U r70?_2r~TsS_4G~\L>Sc*u9L6 ezhm>V6r^H/T.6ƞХFeQ98_n[͐(M^{*@m1mo5j54B(A |!3vk)ٵP沣x?mu_<MVݲkJrEj$U!Y/fE] 00:XG}/IДCvu@ Tsܿ GWՂZ캀)7P$  U M<@jarGBy5MC=`HL@ HGNVpZZ !1w-nI(@y@P$Cy=.qȐo:lt+L~ds`,m]ZWy fĹ&NgnM  a@ ї:l+ӱ&EBV(T0JbR$1'# 'CɏNV4v}wn?h.zqY.Sܢmv A度FJ {0 ` ^bEQG=tu8L +l-T$r)ev4( P@y' Vr" >T5`4;ѱl&ȍK=2'6b{)ƤÉ{aR)MgsT9A0jct y ?\5֖/lDz}lFU\##bsU&?F"~wQOn_U(p8wyA{_tcӸR˘KSrP1?m)OA8^vtoS_lN\Zw|% +Z &;,s6c0NDfmon{ؒ$N&<܅GC;V4Z~Uei._a +Mq7 :),xf0hF +J{?S~w:O?5t +g2su5dw[/r93>)bXͶ_ڃ1ՕpDYTvi=$x;%VWfDd (!yvNU&O'ÅJ'o9A+]|V0KX;jrCg3v[9[;t^Z]pъΡP*OuxrFk屢uU:OPa=(aȳ\tMyZ[R +=Q9<3Bnq&҃9?GOX,?Uommg;k[GmgZgw]] !Z("ZţJAEvrW"W!J$ȱOD6ewo|y}>ϛPSڎ"˚\P@;Q&&~Si9X\Pr.9UK/s9qGpEMf}<샸 0;%byJ9N]">EAn Cy}pЕu:3.pcףk +Y{}1 ߆Kە6*Hwm("lcUQY튼[I?)Oah|_2AtWuoIp1=:Y//j)9rH^fas[v\ t*W}e7FfpDc_jTi x@Nץ,i02<6-9:( gL _}Wd9ml8`57">x6sz ()X52̱)jaz APƠK{Guvw-DW&߄T\,@m'1Vz)$Vp:E}IK &>ۗI5ZS'qR׈z,A1 CWx z&Q&P%x|TN ̃3ȴZ]kE;zKm*!`Rn )ţ<&"FdL|ֲ~pexQmGɕ{<o?"c~S8keC&1gPxf0 }z:d!㘀r%E^I>ف_xu>m~|&?t!H'Aú H(Bў*C۪t$WkSkp>As%rƨWIPm['tiQULa(^MRbw|[vS+UW6ۓ +C/f .r4+%̓N ?9qnm)o*7!QmpQR} hNv3 + U?I߅o(2^ɫ36+ *YxcPODFl1-CY{햢8k +DP;lo!Mlϰc/ǡ;Acw"(3FeG$MPQbX9+BhA=]!Ȑ}"kuƯV)o}9@)^g)r&׋φE8|PѩB3Ek畆 7o3O[opRtx uhP3܇h! i䙑Fe +{ƢXq[Es8 "&PPm;Jk#Wx (= )7XY @%X/Sʐ僒l.VE $)Mv J+"6Ѯk4N:Jy+9<esսL`cTin?0(+=7ݪkgl Ҏ a̪N5W٭8OF7TaYnhΒCM?Q+Γ,LaJ]PWmh|' DŽiH ,D(} LyDccwJuc[8FӍ\mx;9.N<ݍ$@,6*+d-}nN`lFqW,ʈw8k~;%.[zI:_k-ڇ.Svձ FVBlOfbLHwZJq) LMx=xE4 2,⭃t4)Z,WPd3yAn;.'XC/eM` mb #VN%B _<! ڣIT BOZVQ6md5-mܪT0eD5Nw6?4ub䄬(:|@nBylq&3nU ىf^ƿWjHܔ'ƫѿ/,ֺZg:j=XqљӎgޮE]dozo%fQ 2yEO4p[Kڢ~ʡDYBJN#;jMQnݖR##t7"/Y0Y#ZFZdW/OXƖh܄8 g+b!q +/ X5Uﮠ9>.S :< xAVul;XphUlZ&s} Jy%%!q]}Xdo>"2Gǧ|Ų=e{݄~ O"$O.EcuJ"K7czdӄR]>X:y5Ejl*  3AKFsY5t7O:&'12/1xЏR~0'Tێŵ%T=8SDPcua|/lyxi Ӷ4%L8`|f8<|=y Э]7GэUKqDy5ŸCTPbkV+5!gIBb"4aI9W\[TWTOocF8hꕁyMx ڥq]pzz$DxPBkmyGf +*B^vSs<2e"O{N;3\M;Ϲ\HYgpƞVҷ ݝ{0_q__;TrUf`eks#Wȴg7KO$ꌓÊr@݈}Wn?iº\|ts UbgQ6 }q!Ӂ'"Ð )"O٘8U◈2]Ӆt/ \@ iZMȑa6KSpY_KZ8"*1;+3bms3})ݤr_e! $>,jRkIώO\q;J/7[{;c0SYcɰ۵ +ds6=i pෲvf,u7-M Emե BDScxg|Q̰Q\+u:YآŚAyI;bסK)|v# =bNqJy_GXyȓ +Hf읩0Ql(UT?iQMgVա 92@+ xQ-ȋGWeGxm07/L9J^x)T\׻R<ϝFr$tNn*E Ԧ (Me:iDl(@i$~?g 1ؙ$Y/a5yw#+D򧅼a/̾D^i[ͬq1u Ndn]$9XK!?_U^r 7jx4@"3l r#auT]>Y33@4;22-SDnp6fIkWZ5ҝ8Bl[%(AՕ =F7h`G2z9՝ 3Ł }OMnN!e\7h;뙃3CۉXx$!`sF>۩!}̖5Tv!22L#]CW`E +Uy^ +p=}hn-0E+;++ B& +yl#^siBG~uEya5vX{;=g2+dREJ@i +^Ec,%7vK_)KGXX`a{vřyM ݩs}gv5Wݭ˄{8A%.9 Iy)sxR|YwtKf - +D`BMms9^؆~X[ +x +إ?xZLWBy?Ummmt|q WT4A5A +=Iy-b+cP=QӐ@Y+錰-qFZ,`8͒0eS0kT9\O Piר+;_Z7EA8S^dvHJ'V-Irqq'`;%ltg t:>`;WCC~mm3 ?8V)ϔ>tuj6*m)Mg3@up~CRS9;mL3[U"4jI8IoyNeUO7|K:Tv6y4.=|oJOWQg&h\}MߠUʃ +ڕ<8eVxH^O)g (1ij>KI9&;lǡ{\&S9%ZBB.}cOV6I0ݟGﱤ<1|v\N}= gmUsݯPAu_r5&f`LzB ZR0 +jsT㑢{FDlr:|v*qxS!Lf݅,$v; +N"s^wkSYnH鯁 .b6\'Tҫ0[ v=\oQ9Iq;&E{( 2Q`:{XӴ75SImXr]rT-\FQR9 CȬ"ItDV-b +n,c86 +̿h#v>"2> +\- +(ޏg:/DhpX(E|vCQ,t{A I/s\$C}!ql1L:bZq[x :a + a`jk)AQ4. 2E39\uw }fX'rbKIlw|ky#m K8žB` %6 vR[<0`=>UΆ4+3ߧ2P2?'pCnQ/)T6Dx";% b0+AkE a-h(` ~2hS@)6aST9_P^\}榤I?-Ir^Uz +23F$ =\tY2WTzČMt=Y%d5vڝ{/z^U6| 6DfAcXE"ȈnX:5O>7|@ӪĠc}buo. -J.E YjN ؜^ Y% +cɻ}4!pzOM){-Ɣu4h߽zcҔ6SYnmt#A0jx"(hZ`xqbU-qe*0jIPgd?)O$=.jS<)Z|.j7} R$s[w+;2)_v)ݲ|e}6YV ~c+D\}gbTvP=vFCm͌uřqiت (F*(jP(G&{րK~FF~rrwk[kjTJ2r|8fG|`R婖H.łW]׾Fd ?~.毒#7Zܺ]>KmL.7eꮾ]`S.o6UcS^!97_eoA+SKNJݍF'_wQRIcT'0 %~DL{cV7ʙj>䟺b!Ӿc9&3Bd:UXjuq9UZ\JU?Do߭Ѿn#t1.ۚLl-9Sq=!ʵȃ!^D'zyp;""< +yHD܎k,;&;6jk y"vD^+tfc}.Oȃ#˓4r1cbǎV U>Z^^~իe|ƿKY}%:ʮ7ƍ#GT^^2ӑM D' şw5G^ڵUu-.7^{;6y۰WJY=5%%zRݻm ^sbcl6]j䥤,)++ "L:*++ 6qq***FxykW#U^^Kڷ7J6X|8266mVj#;FGzwye1typfeeggMLhK=L C2\g`ĄVj#]m\ 8RX39YG$#҅8ܹ3$ĊEQgpt~ѪJd%:x͚̏_H"yDD$<""FI#$GDD#""`D0H"yDD$<""FI#$GDD#""`D0H"yDD$<""FI#$GDD#""`D#Vzy{{ դ_b2M5 JvvGzZEGGDDKT"ˀÍE%2ffF))*sP7Q3nN\`ǛyEEorD5111{mrrqFI# 1yDG$#2H<"1FAb1 #HGdyDb<"#c$F# 1yDG$#2H<"1FAbj䵵BDP9큐0 2aa!zд?r力7oݑH6fٳgredd|644xdQTTРl]O{٭ޝ}'B֖{s'Ϣyql=p`dove`Vuu;#!iF:'glggWS54]Ǐw}1Z/\rttt :8 .tww'&;8ػdݺ]\Ο?? +lyg.8rGew) it~58a߱Z__ߪU+1C$|[.Ôܷ/OS99Tm __oB4033Bxmj66&XPrrrfp/{a сdڅ% Guǥ,q*1溺[: ѿdI˚"QM&sq:vWy*>cl?<=P||y_|I<،<_Ed߿/4A + EpۿC +rswcv,#mhhioo`㺷n^P(!6js練ey۷WX|]//Ǜ@l!kx1^`eeSOÀ0ݴ) ~\QQti7nYSS <>~eYY,Ǐ$űȏ?^ObW>z3!0쑑S%]-[*XQ7o&O,Yk׮AX?Zyy֍돁E^kk3}~GxΝQ??ejW۾[[,002ۼ9uv#L;w̛7ޫW#AΞmsj)n߮sw㴴4?>#z'O6xy޾#dXȯ ###SO t~˕ *>xЈ݋-)9fp#9vxY˄‘Wivu++,F!KFZH;vdb-Eo1*0 3 fF1y╯>C }i---B5!mۊ{Q)c +ſ/='"&]$ r=I2$HC$Y!nÑKGX>x;H5k5ֻz>>_yII ?|ޔȋehQGFQ3V&&Υ>ʭu %=} Kk&[k tm&'66JJ1lO8gFvFFc/)z^ՙΝ;O*$dą5GzJeySSӂnvi݅ddlt檱޽$iQHsc _!-O>N+S?-!oNl|}DImӡCq򜝝C|İO^<:%%BL,^Pz-raa㥤$"Z}egg4q ݻ׽=گ*Űɑ-]MDƏ+@FdH +D٪&0Ǜ&MTej۷o(sryyyy]H`UTWWstNxAٚ2s̙uS~C+W.c3gNUqq1233Iiiil{Ǽx.Pn?~_y4TpW!/99GR"o^_J ] qeJKKZF#3ɥHk]f៷z+))m8 XVVv\;s$}bjUڗL;6Z[ǃCcƄC>$4tqJU[[HSey֥ sЁ11Qm@4)CMVx?Ed8ɓ#DIM]* +((? 򪪪N +Brsrr +2$`fQKy/%%7Us9ܗ/_%=>lB|~. +U^.Z .(˽ზ̊ > ̙3ߥ`z +FӍ:9w ]YyOgg'iW575I-蘗gQemyO?C:WWg/Yy .0G3յy:s<"^RRSN7UC\Tгr? +$!҆o2i$ -w%_V$zf8z7!pkKc-,ǧE}`:u +`-ZԌ9YfՃN#Y +(ױM߾ı 8N7y CCÈls;`~ݓ'=611[" +* QiI5 9H-JH"ygzdJF..lW[[М}RS14h޵kvI֎Μ9#66G(#x7Z? k'OЪ?~r3A@ +ׯ{L7bplףG+[{l5Z´+VN#;;y`8Aa.]Dh"Hryw1̍Owl-_U&ǠA>gΜG8o^2*h:3fL=2VPP)uOyedl'"<3?Gۡ!-~葚999,Z$,FĠs([q +\gX%B.jUZZ*F Sgv%kۿ!LVDގ;ġcg wޞDy0wyqq <#+"b@Dr)WM(G]&#JyJw3ǭ,DjMbQ11VyR*jYU+*̙'6"Ԉ18x'OTɓfhT.seƆ)׎ryuuWO!l+W.'mllT~B*899`VI֎<ܹý}Li $_$50tf'Jan۶__Q]IP&$ADP4*EA@4B@$'nsdQa,|J^{MwAݪ{oB >ݺuKKK ;71RxzzMCcQmW+i(؂R|?Fy*JCCΝ;-##Roo4KoArM<<4!!^fܘEv2gffLm2ͦHmmrKyin~'N) qe[7VXk%R^A9Unn牉 250mD:1KC&XP᷵r_ag̤gϞQ呠1sPG||SR,XZ|)^ee%СlOo__Ҿ?tjlOKKa( (-Z[[[E(obbuj9F)zi^ϐFy6L5hR~}ÖUU\K.$=+Gy0_ia)@bsgR45[4S:`(V ey'XX,%&T@ V + Q +ور?.4F&M)y{5μBYAmm>I "" r5Cù/2 I%S"7::34yg322as.u?E?0ʳ@NFGG=߽{׉۷SQ^vv6￉kq4<AΝ;2Ns711AJIeHn+(O"Ļ@9R!%?##{㭖&_aZZ*+%::Z,8%ZJe#HxXPژ4 v%''a~++˫sndQ.qWuuDmbb|曭\X $&& à< Y/ڴ+H9gg' Cyzz_` 5kollTF.+V-ⴄh1&A,DȢ_ft2g4X4f˖@g4`UiLrOLL` FE}SX,0H˗/es-jA eQviv`|CJ zD("#WWgggʿNzf(o:ee% ꠷iiixyy};!$mg$̴'ıeQVp.EFF*R}\8l 6^|fU(Ayo޼ ,t"PStG=44T^^F-|䔇11ѪF@V+9lh'趸/ǎ\ SEzիҖ2&&<ʥp@s55Po߾RV r_@AdQnP氰PGG;XnZ?6V$-3+ =;ktu$&Mp=WVV$+Duc$ߘ(q8O$))rsx!!؆8gOY]v677.ciddc;ZS~"hd--͋BCwCݖCT<~:/oF}NK>f58o_ ݿ߈>Mqہhɇn5i~*/)V۶?Ga*q"9TAsRDG`& ۓ.(JfX#v` ѱ!"Qd\8ƷcttT"EKx{i괷%?}N<_`ǵk0I\\\Yejt7|9=6yrDx@L 04oثVʛ%c5<}j-[/==?kyk=j:{LIP(֭_P N]d`!8W6m +eP؂-^_޴)Yx҆ d" )aaqP{! ߲e۷B$ll aBx|kkkHHJp"V"N)";1}:ut8'C7n tpu@?gv:ٵ{Tm\w4X=0U|gsF?-ro'j.f P 9χ%?2; +u<,T f钒Ǽ=))}vwr8ϟoǏAlm78JKjλwn,+/)n===]YCBY!`p "eg oDJ0{.(K/cݝ/!i$ִEL`H-]_)aZppѲ̺&y?/XaO`$Rl ,HNc_&X,Spӽ3W{wÍps.W\܏~!$1Ub7MGg!<6{Wlxܹ-9D==w.[wDaN0{P㙿|raUUU&&FRgf̎B$O>qUy^^H#"0x?Gh```6Ū<v> ٳ]pdggcd_|9&oo8F!zm*QRݸQs6>>nGVyK.Bn: +aHjXOQAtpJ,74𴶶²%yc3ŝ׬YhS\\4;b#̅86䘆( ׯ_E=%j#y;wFX19 .W͘GA@ҡg֬/7oEYDG0222֭JDCt.\ c}2m& +{ܹ]XXE+*;vlĨRr(d8-nkkJJ^II1"`G8}ĸ<8|ĚDJ/6\^Y@GEcq+M)hVV(BB6FFFKɓ'Qa.'44[,A +ͳ6m>uDEjii`lވɓoA'&˖PfLHH0:k1VQOϋGӑ #YF3eee(z{{z'B<ڵ||~vx8uwăFf+[ZZ B֭EUVC411D(`m\ ww@1^|YH3H ̙ׯ_VhOOOgggSSӋD>y򤻻{Yo߾Au'6%$ͽ._]}wB6oTIA2 %xL|Ƀ66::ZnnK~)255̙S |,,xL̈́Bx[,$y! IBN>>?r8FFn9C kCߩ!~T$y! IZbcclmW^Q]}wm{n..Ζx899,_oUIABGW^yfkGww7쬭_]]HŐ,$y,$y,$y,$y,$y,$y,$y,$y|Jqp{]ϳI^TvP8ޯNLuu5i$ƊѠFsivvcvIq_j&Cy{Cfg Q weޮٯ(4 0x!&1&*}U"(E"!hjWQˀ,r0#Oq_5tM;Y,97\oyDDDC<"" F#dGDD2#""`L0H&yDD$<"" F#dGDD2#""`L0H&yDD$<"" F#dGDD2#""`L0H&yDD$Fci}}]eebXQNTy9TJ%bXVj쿑s5+K}bX,+6%VPPq13bXW_}*D^HHJeTX,eV+J RWWWWgU*R1LzIDDdZ^xq<""2q<"" F#dGDD2#""`L0H&yDD$<"" F#dGt:]E/z~߿|QXXhIIoG2hd!:eeγ4;zBabgOOϫX-?vaa;VAA~ee1} fo)*k)D#d̙?_԰-sJG}¸ݒu /ll!ÇoCDcǎ6\Jsڛ4,,DF}$oydz<( Zz5kV]|h__7Jk;:: 200TBbSm߾J.6~7Opńwo^o{F{{ IO]]]]m0`)蚛! mmmEZ*88a͌ b棏fT.iLAgg'.I.ϞM:vva:Ǿ ~5"mݺx S'F]V+Ϙx\:FBlg#g=2<2a!qI_{ggiӦZvb/؂LyEEwmmK"LKKξfS~~>B…U.] _>k1|UG>3 &+11ٳhll())XVV<|}z41T,[掌r%[ySZF^ff&KFF[l7Ȼ{<~r'NGJ^cv1N7oNUU5d#\0B۷w,aóg;bt=t ^nkWOO77puGG;\8W<fc<2Uj +[#?xpqIBY[OB4445))/\ѣZ41`8R* #SyXp׮ seed'ǎ[+Vx;w +#[Bsd߶P^ Nt eD +66Pq#H=o MMMoOA{#SgO7|#jkG6 ? ƙM1򺻻1 F^q$cǎ;y x)Ғ?' ůZ*555g, ^^1օGDFFnNLLJ:ykrsss + +n#C1f";;;d | + FGӧOAdL< VuJIfC]]=s:T~~>qq{u͚U8^{wTLL4-X0y1._β0SHZ)F޽{EvVxf|?&7>T'>ᇺ1O:p87,(*Dؽkk׾H@r֨é+Z-7^wYd-:݌=GW?ڵ˖-7*/?:=t_纕mVg<"<"V)GOuuu%''S칩34o\ǎ,re(T'AH^4u+++E.T^GDGĊ<:l6㴵"|@EEB!S_}Uq@VmtzS#d2B"("KN~G/**,$ lL6Eql/8Gd#bʃȠ` B LJJlkks8< ^rsT T+PެY:JY]kc`8tpsQAy>U^l6ɔM@b6Fvtt w \>U ذaݚ5ϫ2ߴișׯۿg6xY&0]W*,I@?vh0'333`+ly$ȑ#Bӧ׭{N MJZm=Wy|R,YM,rT Tt6~˗?%3r56>}l11<?na;HhΝku<|7x}p/w׬ydSyDPyD:XxDan#;|[[Ҋzk+W]MM]4_~YpႂWxN+++ЖFG6Z|}6'!!?i"쟔k(!wTh[ݑRC 79BWp:,:t/ox;!H*BD!H*BD!H*BD!H*BD!H*BD!H*BDgUBP^Uמ[:Gɦ2 !P*e^yM `/_t B!D-6ԝ +endstream endobj 182 0 obj <>/Filter/FlateDecode/Height 606/Intent/Perceptual/Length 373/Name/X/Subtype/Image/Type/XObject/Width 593>>stream +H  o 0#}- +endstream endobj 138 0 obj <>stream +HWۊ}gdD@] b>,YHkKD^{z.L]ՙYq=q"ܾۧ?|{ן>o9ܾ~gͧg?p&9R6>>Z g* +5*LcK$KQgm|Ͽ=|FH=̯;Fz=a"G1?$sC9VrCX!WyԮR+ZA1Wbdp~1pGk݄+=t9׮_{O~Gd8 +c4GE77!F<,̣dn,79uesD "9 !Z>i!cZ)@& i)y 4CNCB͸.C%(n< <=;v8 紷?Pn%@ ټӐZƈrP1M(Dqȇ d +\1Yȡ#r;sH BIf' 3`p.@YϠJ0!Kcu7s +'S}./[kki&'#Ol g"mv.#0aYmnx&egzBJCzyB4]v!BZlQœz8UB%i#Yv!٪ˀ@ ?#/  d*PX`T^,Es gymB|M&du*!ж]5tp¥D-3Ma]{>6 E1PDKRHcX{y>#iL3n-np3XFVHylF]FiŸMXdPL0h/m~nCQmdpzQ=ZƍTWvAPssU)n-z];Ӝ0uxA iOQu ys2N咅g(Yat! *rZiV~t'bdWӇ5^ B5TG v@Q-Q]e` 9/a/-|l dJlΦP-*p' gZl=nRѮ1>cLUWP st55mM⪚5”( ![!iZh%)-.qtj֠$*[k6$Ž@]5tTVMj%B\WTp5Kx.-/YuhrNs-}_١FѼ! +QPM@8-Q}kSZaJB-̦j.:U}J,Me pLFJ2SeP5m ͪ{2 ('c`FGS<1C,*ӬyH)bqlOleNЦ]q?ze6γq;GLs*V +G+\gՃEoH.[-23\t+swJJ !rknMU{iu(Fh{1Ov:u|65#7|jǹM@ÆX|&ͮSpPn0^vd@wd1P&z?ϹfwGW7NP`ܡ!pv}~ $\ZEpw\]TNڣ@>{}̞TR]/c$ =]Ez}}z|}Z˜=Kd)ޕZtZw oF,U&EqӶtsM~Z5=L\r:޿Yϝc潰V{_)-}ŧVkW䙽9;f.8ci|_7Ԡ^)!>&Ǟq{5N)` (<}"k6k8}fBܺ>f  p.g>@#CӦ)\_N"^7,)1S,$;7(eЧyp/,; ìHC}̯8UxT sdބ FQAC$xU7O +Jr<)28s oy2opinTh4!}0rM~|Ȃ0U-dƒ4(^i#$R)ARiyZG%Cft P1`b EK)D[/7.A~׭㌌~`W`Vl3FE{?~9|,R QM[hxͿ+uE點!?q}3}3{QhBp : i `X3Yehba`R 6 = N Xt8"6fv +endstream endobj 139 0 obj <> endobj 148 0 obj <>stream +8;ZD/Yu\ab']h\%cEM@\g\)6q5nAXnbDXZB.,&eUh9+J5qTmDrD$(0#RFB/WFi +#*71H!5b`+IC-X<5!eeJ_XaU;X9d7 +8`nin'HqFbf_:XKUcn&1RP)O.!L?h'Dl,BB$F'2"d>'Ti?InDRbS@pC#FmVbH]hG& +rMl\C@91qUmC?u3pD2g@!U+tgkRZg>FCE^?X*2ahl"0.f=#a#:!G87BRFJ1uaZ6:?W^-g̛ǂw +h"Bd|=FKh*?2oa#̛L2BnT{p}=✌Xȗ-g̛-=^tū'~!wU:h_VX뼙f]޻#t(7K.)~/$P@*UWޮ>BwŃK.YzqjI.S;˯xJ)6Y7Zm#Y^F*V᠘EEFŒK=&BG띫НX2vn_w}S't #dڟVЛ m^%Ty|jqE;[AF{ +mlKo7/W؄-eܼ,έvHf*00cTh~ 4Cټ8'VZcv #Tn/B{=r}{Jcrޱkm~l[U/` ;Z:Ҵ6_b0k(=z's9Hs#ͳe2BK;K`ɓ:ʶ^ v7YԪ[,ZSͿ3#F^cDh56?U/ݏ>KBd|k3\rI3ݴ6^|W/$B!2oUDd"B!2o:ȼzh ""롡P̛"B!2o:ȼzh ""롡P̛ +éH!%4t:O+:4L_ uiJhN"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B4NQ[ DTO/P"D!B! +uCdxY7=D(@֍G +uCdxY7=D(@֍G +uCdxY7= +"dB[`حI[ZrGȺoՋ3zxvĭߪ۫73tMީs;0Bmj#4[UjF +eUC>Pr뚑F +!u?D\l]q85B{v^w)iyșK}[ۛ,~/!z3q0έ1B7u-GvO+]gd%1wy6Κ<ˀuS;R s i3U[ѳvjF'Ԏ)_gțBoz#%yos)B~yz-P%P̽LL0uv_=^>@SZm~lSۼ-nȮzw7rO$y3Fq~P^rfݬwomX:] I"s/3ѳ_>{TF;837/ 2 P7=4=M=~㶌Pv9L$^ѳ_?{k`BQFIR!Bh&g莇\,"B#B*[]376|ֺڸlartm!TX+mv` #dܘX;8>ܵ^BDHQ9FΰM9薛:Y׻ !e=n<"I3>rj!)E縵QxYDYDYnNEŪN:BYrpDDȘ;apDDȘS#"BOOcpDDϟ>stream +H c6f mIڲ&nnmDX,__ ܓ˝IVB!B!B!B!~sg EI&CBKܒg$r.]lşO +!AS*.Kf>Ͳ3M]k`|zd3$SR$ cm;/17,xsM!B!B!B!B!Bz3؝N 9ŒΈ@ ČΈ@ ČΈ@ ČΈ@ ČΈ@ hgbg %D @ I$3 (PH$ + 4A23%D @ I$3 (PH$ + 4A23%D @ I$3 (PH$ + 4FH($LIXr"QL 3m\I=tgJD2A&ptSMC[?WbFqE@ (`P&HSG흫K]X"QL \jY,~i(`P&H٫mO\(`P&H_7Vsn{NM(C+1AF($^_r1DhઽKjl>d]r15RsU?o \V윃-q7.ԣh:>$QGSos'=oO}#y]T.&v=tĶGl>ӝK}p:-Tůwaߎxe6盈 Q'XM:vD)ҺNQAʘAn7^HtVo˨ @YM\vIfANJ?]KV&e\If}Ql2)}Ks%k[ pR[Ŏ竤۞pAF"[eqMKs_>r] @Y,xy]v;v✨ZQ=S\:g5UTT4m{z.wk({a'T>stream +HcӸ']h[Z|Ǎr?$YNM%!Yl?_1B#):2hӝՕDXt%J8XgXGbFDL;zy{,Cgo9{z (K% +bDX@,Q (q]Yzx5>%{K 6@l ,X'#g~O` ƞjLPPll{|] ,YF(+F +ׄO`ubnV;V謖1>5o27S1T%+ZZT6O*ݽ|]Gai38ĶɣEWH)c4};fl4tX2K/ِg̑@CA2;?蟌Tcr2ZQA+vZ~MWm Bݛ<@l{běnC!Orq |/ۊWlJJerp Bg ݡգ-ؓbqW82>aVٰ Q\W~{vOfo+έmꊋMd'<VI:{fyxr[<ݭ_''IfAFxՉ"nYjdlsf2\WΕGXYdkCbw#숭quWeρdXs[+ww*V]6!v.iYP 'ؾS\{Oc3 v+^Wӝt$UMbs͓,8j6F>%Zm2}|c럶lR;L_YшMf m;Lb"M|~=J9c4MWڈT6@P̄˻8{cq@M + |/+b?ƒqer@wPO̪bLIbF^eV؛0Zy}ǞoQSVA+z4}6]1dV-Mn6Yy^~pMԂgG챭%Vtk'dG,-K:1֊&Sq4NŬi*f.2ZQ'vZ~MWm Bݛ<@SZ;,Ċ7- +B,;*V_)*bi9X=.VxՊ.)6uE&Nf$ \\ƚxֱ@MۛŬXDssWʐ/5[79?Hf/[b=ڿb.vhUV<ƶbk6¯Bw{uG;bj'^Օ4>Ew !VJ+U&Uw2+b;^X=.Vf.^֘s9Ot"+3gLئ(Dv#^l#7~WU^>O4#zŖQι8hڔ=BT->G5/wqXiՈT/Qϣز?4e3_T(~[ ϣam&'f~;u[~kbF^e67Ãۏ|qN`=ɵ*<]w NU#vKI>7mcO[XO|, IݨbO|/ Jk.Fyk1wPb&'$eڅHea `m\rjb#+,?N.FB|>F.X%>Bi>e_b98b%\pw/u~SQ(ak?qbDX@,Q (K% +bDX,@,Q (K% +bb)5rF\؈fmχoCE= t;m @t +endstream endobj 147 0 obj <>stream +H엱Yyu% (Xh. 6tpb3N.3 O,,ϸ^U{{RtzUI1(zp `7 z `7 z `7 z `7ft78Z>2uѻb!DZ/qkNUGзR> QOzGd,ۖG(kJȽ̯.D"SڇڥQ9n3ͼАB j9ol>a{]O9E{vf+?*:OKr?QsmTJ+ekhɳƞ4(Өsr {+qDkݍ.郩6= G<:Rˏһ|xJz۞*cuCg׏ɫ5WQ&{S; "3mFq3"Ruˡ0I5jKa~O{"תfGV^=7":wKIV)j|kRW1:q|Fq><%ftˢ) +&^Bu;z'{&kZX#u9ӫZ_ + E2)wҨ\VqJ0t7 +zK1َ%O6qzLosDlꝚj[]Olt<'<̯w zzb+UAWl 5-=K^ڽz+z8P{\OIG-FzsQXnΩ}KbݪN)0'Z~mݎn)z:ޅIf3ޥ!;žw1`7o8[f:{hzOJz l0U'߁r%WOyiORstQ>Bo1Fwm>' fޫ# .>[CS8wbD /N:j9<;H Kq%A@o0 A@o0 A@o0 A@o0 A@o0 Al6C`.A@o0 A@o0 sޝPt 1ٻH!5-*eoz1=Pz7X7]Qdop w\ sD8YJ_Ð旌dwۆE#B_W˙x.COY: 5-t ֣TҁpX;ґPX+ª߿zt( 6!X~0 ~vX@){P}uۥ!&пo*|t4 V6ʗ G`}z^h_/}֤wd>?V꿋n5#r_j__2pI/ 5c_Ͼ[,k'?U~?f`@Vϔw[$kϷufh@IN~{"gMzlzߟX"pZ~gMz{I۫G`MzWwOv4 V'__9k}рX޿x}h@Igkn{//_1pI_8G_-c|~I84Ef{wuzff7H0"E+FC>aHs!F4K"T *wGnvHw{ğ^I.ss'XiP*p{N9BJC$woaYMgכ5ro}-\mkujɋכ1%KX*,T⥠mK%KX5w(lls7. Zo]ք X+K5L3PBmDa +MD2 wްY>3Ԫ=ـmN$z[Ya[1ӂpˎ3!lw"՛Gl %?9ܟHV.7T!@~u95GabOsM=Uka_~JC$8]=PHqp3̑4Dޟ ~J NzvC3/i'Bh[5GAbޟ (^!Ɵ8]a&qgflGo!@mہ5` z ;sHR)99~2 t~k䝏 +bHЛug8'g$:ׄs]4DoK~@i'?/}O~!@~Gra9IC$8mhLr4D_̋| %35G1$Lo]~/uN~*Ո&Nz”~01&Nzξ5cKT ;s 1$Rov~U$ƒ8=WQA JcHBfYw,JazT7YMg2d1gY=ׅJīi$օSmز1uΘ{XossM0pbf=m, \S1tabLhYBoW@hLr`Y5w﯂V4|41J{ʦ7{fl9N{F]u'NȻwݴe#if +[Nн*^ꪨNěÉٻ7Y͜Ul[Iy"]{Q7cBSQ}"ݪZUCuUu[j@m-],oٶ]e|CY2]eXw}:h JZ1$hٲ(I bT؃z[-CKc .e; /Y[J- Jq_o;kYfc+]ԖwօSm}05q|[u=T݈ zV/p|Gy;PމnUQ0 YcVߊAoּ"{W M,c4iO F7"Z|g|5RG].ݫ.J;"J̶ҚfVQ8z3gE=GDG.բ+8Fa4-.b5$"b1ZVkM8tw>ZG"|=9V}}>p3wZࣷ+eN~~BI7c%Ǩ`-+=yX&fSٻfUm7{<+^qPJ#CveB/GԊqdz3g]=FnL`w6m8WS- -O6Oss' 6znW7kLpz׻6|z'ˏq8 ApbԞS[W“b{_=8!sIY| 1Tt[_yq BDp[3-,-Ƭ'xjm"B2szaxo='(2#w͜'xvtY|iKeGo:)O]OL٣R~f x ،(!Is?7MDH7lv t{/b&"$?ENz~kmD$qz_x< b%"$K[N"B[s/8mr%ބ'xJ"Bmɳzf /lzٟۚQFŝ'}UIJesFTor&!?"_ d;Q$@-~ +Nkޝ=ODHw]|uHz@a7HzZ2i΄'p"B[ƇI=^=N me*N#<]V&"$ NWfdi3w$ޛNmtJ%-S6v)xO8JDHWns+ ?IDHw,LNQg߹ޔҚvv!!T%! 4FўCZ(ijDs.1Xg<]B$^{L?޽[uv%i13Rm^)GKO()ZNe 4vP 0/P F!%WI:G&eʍ+ȦJa[/fX5RaxUp ;ˉlYwNK6&H'K;yݛ,/v#7՜$-/<;:Siϲv3cUFp|䞰޽UuBY3*˻2K/u?tn\qHy[)Y)`+hc%q=eT)6)~7`3L Zn )"/5?L4Zhm"6Y{nh{eS†`m{J`_>g= =eahP)HyrȌ{J}ɳSD{?"qjº4=/}QϽ7籲 rOa5of}7JЎc`kS:xmbg9񄲚YInoZneѫ\6OwHEnt;o0|m{iuOi{wo՗;KAi촃bHX)n +{ޡ\Cy $)yݛ,e:Rz(M{y +k_QG!,;ھ2[Z +wtmš3,籲T_uO)o*=ƣ%7 ܊Hyo)U=vY7T& {J>w)MtZEmŶȼMy/!"Ro[3S&9Dc`g7ֺ-WŊbOylkN-^R9O("} [_P{b=%_ B5ؿKzxuuO*=EG1S2dS})!RwXW P8bcD##R`N C)V`81Ii~쏂M3(z`-FcDq{"6@:=%-7"= ++օt)`?:҉X,C`M@zK4r̵ 7ؿ +ܟp[0XTx4_Ҙ'>/cDb$6n @?$Rc`^9<y/7nofD؏W`|2,75n>98F~_)R`ؿ&%"}_)69*H ؿ)Rg`!_A?RςC`zãHy?/9<2)?=t#aі5oy=q Z#ٗ5Ef#wLNcؿ ~ͼ#4%BzI6ؿ_/OYϓNc'4Y?J?Ri_9޴gAM$v)~ͼ5gӎcؿ( }gH~Hy9y\`?"g`"O? C#e&`Q-"/c#E{ +/'" O#~?P| ++`iKwG?^ρ^^2om?sxy~G``2o1D?R#u*HyG ϒ! +qxHA 쟤i3zNў忴AͼUUW=h1~y{| +sO!KފD6oIgvoΥc;D&ͼ!Y$b-dޒF-)`dޒF-)`dޒF-)`dޒF-)`~? /[RzEѐFԮGO!,Jޚ x[U婇CJd6oJ}WUg { `g&lleMgG}#]ۣey_ɻ+.us?Z-q 777777777777-} j$cDw ^F%[^f{2[}+au[yf򾎼Kj}Ǟ6l޼o~򾌼Kr39Lu-|le=ޞw9n6x~G=xg>f9w}?y_Gyg5ogm]7ya%u a a a a a a a a a a a a a a˲D_pVo#o#o#o#o#o#o#o#o#o󼿢ɷB +endstream endobj 143 0 obj [/Indexed/DeviceRGB 219 183 0 R] endobj 183 0 obj <>stream +ߪߩߩߨާަޥݥݤݣݣܢܡܠܠ۟۞۞۝ڜڛٚٚٙ٘ؗؗؖؕהדד֑֒֐ՏՎՍԌԌԋԊӉӈ҇҆҆хфууЂЁЀ~}|{zyxxwvvuttsrqponmmlkkjiihgffedcbba`_^]\[[ZYXWWVUTSRQPO +endstream endobj 142 0 obj [/Indexed/DeviceRGB 86 184 0 R] endobj 184 0 obj <>stream +}X}0XX0}}}}}}0X}00xxxwwwuulhZXXXX}}X0}X0XX00RQPONNNNMMMMLLL@@@8884440}0v0X00}00X000/w/v/u-v-u,t*s*s)r)q$o$n#n###"h"hcW~%/7P +endstream endobj 141 0 obj [/Indexed/DeviceRGB 48 185 0 R] endobj 185 0 obj <>stream +}X}0XX0}}}}}}0X}00xxxwwwXXXX}}X0}X0XX00NNNMMMLLL@@@8884440}0X00}00X000###c +endstream endobj 140 0 obj [/Indexed/DeviceRGB 62 186 0 R] endobj 186 0 obj <>stream +θxxxwwwuusclhZQPONNNNMMMMLLLL@@@:~8884440v/w/v/v/u-v-u,t*s*s)r)q$o$n#n###cccW~ +endstream endobj 132 0 obj <>stream +HWk ޿>n$~Bdw !Ll'NB~s;,I%s~żaf^3ѿWx??06z55Xc~Mr4l> ^=~WUG`B=Ӛ_̯cGJ Q42u&Cb?>2p~ ~qc +q8Qr.ڍ<Ȧa;Wp[> 4(ny58C=1Ŷ="o?4S^YgG(.OOOXsYP#EȴG [? ; +I<Fl?w ;A +8zqV1Is$UpvďvՖFA5 +gm0]?3~ +x˹vb pQ-005&]=|=ctɘ9EgaG +r={sбb_lfQux! ^^-8C؜)/wNKOg_ۘCxōqFƋm*h +Lov81m?!;Dp3 Z?N'H =pӘ|OoR* NJ;(x ~0NFQ˶SׅqA9:;Ă<;3,'9v\y7 +3@rvB9?*n%'lxɩ DM..z~y!3!i"/N`g"ڙl)*l}q' szL)#(Ї;C)5`8;KtF |Rȴ@;U@R+kBǚ7wg rfDDSLd}y\E":vz [Y<!6 pAYe>gu]egn K⾉ e߲kݸH+5#j;y^$[6490*rUp/XԞEvgP %2a$_EZ@+I|lM-(;?W7 h-S4/Q-{ѯ^Z|: X^}6M@ 2J(|Xʭ?k~0O#B wTsZOEw萈REm=Sum j< ]5Q-rЄ14OLbBVv)ݓ_%+׸ ΋[чMLy1'q'e}G73UptLqUDRsH9˜G׎.ZB')t\Q_ 0tWp`Zmi~DnE_$QvA2vCAdBZ2 {3/.N =F yN"@>a,a>~ -;FAmd͘Pf5Yh]l\Ս-訌%:q_]o!eq8ծ)fuҺe]aC&˙VC {yA+uy^,;G6h@NT"! +endstream endobj 133 0 obj <> endobj 137 0 obj <>stream +8;Z\7]lKl%&8&(#rB13^2"%Qj,=&)g.Slau;@aA.Pij[eda>u^4EFNrF\[G+&s?X> +&;`RG1i';uqe>_;K`pmtlTsaFV"&3sV'dh66j$Q8q$l:a^46lUO*mF8,>DCpWo%O/ +IFq5_4P$32[cJG2dfq``+tD)`@kNkh7?o(Mgb*tE4Cf^)fPI.<'R)Kd`Va0?L<)bf +9!-r8RoSplp&8uZ=fI%opZ"k>Jncm7L%0(qL[8r`RdS1:J3WRd[TPa3T]VuegJC(W +qQblG=;2sV>$A!Z:ea-kY4fjZ:bhK2A=/aQrpE/+>P,HRcM?.jrJj1J2"?rHa_Re^ +>e]oUc>4F?]gKd(P>YnJ7F69:]C:GipWQ65F0?^C6>f/5LTYD'P_#To;2\d-ffhNC +?/#CE9UPV(8&$b:3AU_a$Xj0jW/k(mrcY,LrNds.<'@J;fd +endstream endobj 134 0 obj <>>>/Subtype/Form>>stream +0.922 0.427 0.396 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 160.5998 508.1125 cm +0 0 m +88.092 -175.92 l +-121.187 -73.838 l +h +f* +Q + +endstream endobj 135 0 obj <>>>/Subtype/Form>>stream +0.514 0.745 0.91 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 167.3349 566.5065 cm +0 0 m +315.984 -120.537 l +-46.905 -217.983 l +h +f* +Q + +endstream endobj 136 0 obj <>/Filter/FlateDecode/Height 298/Intent/Perceptual/Length 27033/Name/X/SMask 189 0 R/Subtype/Image/Type/XObject/Width 523>>stream +HyXgy}TB)*x+EE얂AmV@E(HbVND.!@p!ɐcLffsxOZ 5ϓ?w!K(`ޑ*4&+@I& zMS(;U9F4w7T]cֱ2rx/ ({N٨f;"2ڱ1Ye{HzNޯ(2bB}#G>Wp<"`SiN En^غ!ZjP̼!mK[zEǷ:8Q"s!p:_i'Kr}UdۍvN8̗@E$IQkT7:zɅ~K,~VQ~Sދ)nQ৾0۷b*D=бo?34gTP}rN )Rl3YzJbwucyu4,.%fITNI?j"Wf^joo/++Rn 64 .'ؙUUי5ML^ZX]ɭ]PyXڟcudn[q,l]sxaLv_˕.E%YYYE8{KҢƟ`!"1%6Ĥci +nd$&$&'M.Iw,69\>{H\$!Fb ч<gr t3>@h3>@h3>@h3>@h3>@h1$),,$IϬ@ +C&?GR B ]jAqssCD9A*ji ]L?v6.z($|/+DrbSسBrrA^x@ %BPSpppx|acc|ȑ$<.[qo:Lz;^rc|V_h{)#B,BDUnFBf4w@+7&.#lOTT4I" pZʫN(w3Lqj;C2>/A ŨP޲+hRuS7睿`yb%mVEhaxZ? pShwxO6 50][eg: M,|6ġ=q&??3jy9uMq2fU!듦19UTed1p&0E0C//R L;51>ugƿ3",GWh)oxK&z.T~/欍]l}ovb\7_A CQloϕp>5MN-.1,P"}8h.*cb0z^:8*EWB ]aXZzzOYhTNhnn~'|CyJTaxZy{Ya'{0l~#u \9~ŚȮii&*<˩$Fp\K NG<: ,ZΊOxxyѭCTJgf~~=u*[k=xA[Yўd(Z__ݻ|LBB9R.jҌ}E7p5y;UPr3<~5'Yt,%VҖF1=Y|IHzyXX@ h$b^9ȑF5 ˟sE1$P~[ggz7 oMOLlj@hK z${tΕ>g"qh}DӔZ\} +{%] G{E] TKSmL;jѤYEx~LjF |Vp ]]i7LIj*=p@h1$D(F>c@ @\rHP@RiuCsk[-cU|rX\*F~5uq\vlǺ~iުq-"N]twn--UV8UPL0E.X@"RQLHȕK8p|`ޜ<{sEI=/5l(B.'#LZ-Њ jET*T[NDvv/&'x+%@4E|߳a JHN4Ւ3?Iv` + EoE缵5Z~pEkoPe%F?B[ ;G  QQ@0w%:^m#Q~9w B0""bejjZR) +2L*׿ڊYoe#7mڴy/Lذa˷ׇ6lᠨ(O +l|~ǵ) KK+Ec뎆'$/W#n*{uw/sAҮV&RՑҌ+5Y;,)))gL8} + + +rrr322RSSI0<3{(.7ɓ'CM8~ÇY+BښvĺuHgxX ZE~7 BV[kDo:DVT/OytݠJÊ:j ?ZQn̠Ԗ1@`))ׯ_?zmLC;$$d̙\.e靚6e˖M wVaco 'anlOJբ/'{aiaEoe;gVs(ֹ +E4C@YmÇ +˦@sssSSAMMMQQѭ[|>N~ӈ>xข` a(u66?8񆱷 1رc{1C9C b4ٶm)uuuPQor[Je$IoJ՚ކ|ZXyl^L4x՝4Ͼ:'S]$Nq˒;(?%Z9L0PzJ%H***pX0G=e9NRRRrr2JjjjZZ>efffgg߾};''yyy + ݻ.\M>e**b1U[[ۡC=qww3ˣ)/GCoVt1&7&&&:TČ퀮 W@bFfTtS>@%{KȎ{/n5)m?sҦ$\;m@Zn.Grrl/LX +/Nપqqq:",, '6>{xxN.]rrrzm$rs3 +ǏG(>fc,8JHoA-Fcy~IW;$Izۛ*D5mPzBRY&nh +qUI" +ގJb&B룹v>D{PtSRRKKKS R)qzp3컶ҙx1RǽJ ~,hz3 b*A[tvvرhqcM0|Mll,>.dxӇYNf`1==-((-A!bBz?f>t냂&BDDDVVVyy9T*" ILwǣ2Xtdnc?.9n鲻x1zC۱rq"t& -m-T#O +EhֵPJ[o~_B~w}ߩYbANXh4`1:8]!`@X +P㰷7 *J$ڵk !e2B1lXA7SUZkKhG+,,T{/OꑻLC6V^"@a^tiΝi/TVVjM&: TuTލXBbZp0IѠwߥRO=ri X  $l;;;>|əLLLܷo_DDDLL̹Y<s9ra|>R*8ڷJ緐`nCp ܜ""EQF}"l3ǥ + + +`A餤0 + Y X tcmm-ԣ@ pQCff&X`0LNNrs1Μ.zdBkR>#"82A p@pBFFFnnnSSb:]zX#O|zN.& + +wzTVfR8$xDBGnA +A׫jB! +;۷oWaZJ..iUoz{>5x\IXQ;vIO܄":??.jJMMMCCC+[ 3TV"__~sp^(X,F6o - X! addX" _$//O uR|R ?W,`R8I#@L㏩6߂"K4}}}^x:n5\OgDHPX2-w `r{`Ѩj޽; nR(\F#w7UhMMM3>G.gמ DUNLLL T*L.pVP(///\upORZ_1`llL*K'=bpYʹu+DAV=111}Hg5DQud">ލ݊ +z|S97l@f3;A@AX$$$8q"ʉ`3(=zh}$7Y )g+e(+" i UUUbtmFU?so X^^RbMLFQQA@AXvmC +"""l6s#::oS /ܞ@P(RiÁw<7Ce}}sPoٖ aaنJH$:p@ddE'?uLASGR' , cRtwwޡn܈FF 6CH¿p_N ?~*J] x{YC.?'1!>>>2DcAV(3;.)H\N "Np:}5Ûr^7o/} 0F;{l/ bk)WeO>S之II}|.k1a%jd.j:r``vV,#U*:XR&sp0^ _8[i=Z{15X(:ƍ%%%N6˘rl2j$33~X20D?w NfKLov7c^ +P5dgg;痗wuuMLLpsٓʔXFZV\N?D d +0ƍTfxu8'[:_I{!^1/DB__BpQ5X,v$` :s~(Lfعv-:A)k|ltӧDGGPAAX 28&!77WvU ,Ԟ=TӾ**HFܻwC g>%%s"Z[wՔYd^1/Def5lM@ H1ѶmTǏ1ξsL&(5Dr2|wFL彷! ,CPO<.jSR4 @j5j~RpjA;q0'7GΞ,qˮ  +a4kkkr9ǣ ^444 5\\ttM}=40q6@?JQK ؁q0'p 7Ӯ]Kgzj igδ(u3y7q EFaAMA}74ȳhlnnf4h t: Skqj?|**ӦYڬ_)8 &:; )eYIpyſռ7,\p9[X*qqJq 6xxxX;66v$%% xV:~c˃cDNNi!bpмtE96rRdᢥۊZ`ЩQUF^b6MȊv AC^A@(A&[ìZ +}>eN:h4ADE^` +9jEK/brRdVUj @=j/p_oޖJFbbr2=!1sqt1&&&qW|C7ؙV.\NVDӛF&&¥N@ |@ikk۴i +RTTkSDr#vhoo𡍬Q\-ʧNB$AA`oB /YlvҩD+>p$Gk?:A8 Z[[ALx n +.$'5{ KT뙖Sm,ʧL1s8䔥 Z+oVnip:𕂖#~+٭L21d 򛍥/ޒ(D'_\,. 4T*1'O|`j?ĝ;A\A0Li},_|LPs h+<ѯt%NDˡUܳ^n~q»o.z#_Dv,[_/D0{Ƭʽo$e\SSS(@ 8ʜ67Ν;;W^^NɌb2AE(! Rv9ᅎpRjD"QEEo/q]~z?q}>'Xpso]l])^Z-=dB8kxne4=>Ԅ/e40m_̟3ăc0 3WRRA Eѡ!0[J|IpURNe1@"?%zjZTty`9+jG_drv[>76|wٌ̌2 Hy]'28]CؑA{dpqt{7B u:\.8RG^̙'??z, + EABQUWWU)1 R9~`xHHHhhhppȧaM`GmfZ:n@7 /?W3`EK19yM`C5<.-!!%P/  ;d2% HT |0ԩ;wC"f6 +"(x~(ZùSP]/Qy,diV0 +hG`4kkkY,SܺuKTOxk]¡[itPT$߼PcfQ^eDUwt B:RegglKt0&@%vC]XXh=}T{66^M(1ey|q)t{_ .;YƸ@ 8'$$ND"ASWgk[8z5H$V C` {gR ~ӗ&c'hR'77x!fsE:z7Fd <(/_NLj Bs#5qfpO +Yd b?b&IkkkAZ; + +l 6, YC||<6vS*m]\HHAAZ>sؿر.>pq RP( +h4ZqqL&wbKV< r9bە%FIAj岞ەZ{/ FV`0䈦&NgW+8&`u†z>33z7gL=,$A \B1k~L6}cte 40LP$''̊׮]3 T<˗mq6vڋt{CJD boަ!#=`'hx*J$h4OHH`X(R-dm=R)qhiioXϘA@j BՔvV^~lsz*ke 4SAy<Ƀ +5B/QQ6/TvQagttgke2֊>X+bWVkwG +,,>p]b$"A"o؀B K{^|{w|ΏggOZbk"=>",JZۇc3X1A ء 0c!mii)f]bky{3eA<Gs2r7[M1NX{LӮ 1͍"mLQYYj0cڶrdՁZĞ͍xlO6^W>=z_B5!WvMŘ HWd2dԀa;> D"ֶZW^%TZԞl, +ǬV֦YwAJ tfTUUpH 3pJb1kۂ,!>o4=YLŃ"7ɥ:Nj Ϟ9}&bA@ЉIII9f^c8 5׹?=ȑ VRROaDRS)A$$l$M(Z,-"ܹL"SGE+SnԪm<淛cY$O>H$\.V@0S ;8-.QpG1}3Ťws?TPAVMkO==~|wFujY$WqBzv:ě5JP"^xr|T$HFG.U[g&+6 uVsCy<^qq^}:`CB`'/77l6OMʿx1Sy>z't:.:hęsS/򯖍`,y)H.ammm/_A$ףU˩6(VdhhhoS-c*AX/ȹ"3St,C}y† +ٵ:##lL.{֭Nd:`mᐥP(&fG*@>õM81Z.N?.e A87?T*MKK_*++A_; E۩V +* +j27J*Syªnܱ?$E矓ʯ-g%6 $ѣG+`WWWGIJ57r*@Sy| \#xJrB'=Zü$`(--p8dr\Lh\𻻻XOOAfszz:YP5Ğ=L"h7?ο|W_+Ap>0 ._Ҳ*++- t̝k?`}n8%htNf&%P@H_/[Ð 1HI֩}q"c8 w3R)vkkk% ,Zd?`Z!ill$3--;ɔ JEDž>>[7PUAp.**d륧_| +; bv-uNL~c /*COIa* A]Kidzsw)`9C pDIssd 1m ؆Al6\yk8T(xqFGƌ>nqH3PaUWWs8$F1QX7KSSb_5bnn S1LmFQf R$_٭}E{B bFݻw󋋋AN~R̄l6Z%붨\u^-o5~S1]^LvScǽE*+dUg_4Z_qٓ>'ͨTܓIݺ#A\, tb !+%xiSHH$/WnO~{ P,4X}|kMO~5uq|th;ctZ3]WQX ElwAdwwE6Z$@#ᆇD 1 $y']s9?~9g롕w$!1)6bW|zƨ%)jAJ#7.{PgL?p"qG${"tDfɨ=_1zFs(r&I/*ks98m68vXN0''4PyTV+ zmV_ԏuzE;:AzkskkY%Jg4*:{,L +bҁD"Fրľq:o+Vbdԋӧ|a%Et=uW2.n)("x6X40t>yuA!uM~VU;Rw6_-|ɻ=cօʡё=.xl曣ԐLJx<^UUh$(=]kcmvdڊ +y@2LW{ɵ3gXA,++B@Qp_sC/s&y;KnZw7(k#FuENku|j4gs2n;.5jxcقt:j"ܹsQN<1pr2 vFIH̙3fyt]],o;"Ê񩨨Zu褢]w^Vj^{uảg Ka@bכP> Gۇ?,<6/p"V}A9i葟J$$CĜ6;c&dmp̂P1^:e×zme iQDVt@:R7ZUJ`dX0);GV<,???AK@xymv4ӵ4mTj[[#&gݡ54 +.eFPDΡ-mB +žQ*W^]|Âظq#t$6edNcB.3L + +1Zqw8@QĨo+ZG +AGfXༀ͛ndrr挹R(Ә@ V{ f3Ϙaݡ¨>+Gc7blc\HA!)))82t:<%E v48 a`A}}}̙5A(ns>pvS6,<᳉"5uy;lc\HAP(JKK`0U*t$ /v^b6 ϖRPl7O#$Bmc\HA\.F'fD"V ;ɳ`o7W_ŌF؁pQ)))ry ""/AZE>NfΜ*2K61. X`AzzzOO}W)ڵ~ ; N[[q5RMMMowi0ͺB(bԎ(v75J#1 P,UUUST(<[; Pjj*QNeg[w_(@4׳gOFS#8δVL +.jHNN#ÁibCp_RզWJ ECuY hY\^Yc )ƾ,K;\p|٥{%zx`vSlgXΞ[wS(Pwo +ͭiT8Ƹx 444Y .A`#yij~os` @8zN.)NӺZ]gP(D;W8:.q[61. |>ŲCii\.7]HH*2d r_̺u£_xw"ie#WXAٯqq!a{j5ǣRv @b oS`@fbbbqԩs͂((Pw^mT&W(561. l l6R K]\{Zs96dHA Vbڧ陙v4| `1 ccQ"OcG B^WxT.ki5܏MSri*f2$5a&àfX Q4QR +"0  Њ"BWyP Z^m)-`)>i/~m|Q4?)y2H[׃Aj"))ZG @q2 ^?6[W_rt իWGDD'*2ծ]v"͂PHYaZ^%k}=.+<:q\i X4;B~~> V;h4aWL&dSL"(--g喯]k i77RDa2di@wܱ}v{gť=Vۙ`A6PW)‹F#T\)ȉ3HA%׬$ЄlHddzC @|@h s-`A «t:ݜ{ʣG;{5i09;[іCe0!,00U \.H31##''RK @@}dItq&%QTZZZ?A3|#0:t`D}eSaw`OdbNMMmhhy1c0vCB~K +LDL o<)PXݸq^Vf.Q = WX=}rEcia_`mllʢ!//b:ChDdvp@/3y绻[Rp/ + a$ (_9l*+~Rh1- (*-99Zrh嗉tJd6ggd)55zkjjl zKxLJ{1If[611J<`0 .MxRDLfO+ hxTGq+((P*ozh-Zt-ͯM4ǘ,0QEReff^rZG477c5`:wOBӌڲL`Ξ| .h\.k׮I7twInxcJ l ,,+"""<<J4!!!;;[&a;`:=2d-_NrtD/ +f3l6J@6CTs\#|>; ^A(sW5 {tX9`ALX`RiAAexbddd\\\qqqKKK^cb06qZl!$B!rt$|lh}}}ZZ7oެjUAU;s3bϱ" +uÞӱϟ+lPҜU`ALCcccff&rrrb1t: fhJ-)Kr2ZLp6;;;l&&&X/cDNL? + +8=+FNsW1%0TVV&''SPRRk, d[(fb2|MA444\~z~E8ڈ!A5N˖-sYfi[kTOHHL# [*v }*WWHy#2Ú5`- '˳\\\jDu递S* |8ԢJIIimmj@7NC#FF ^юZKbbb`{n8}dQB讻m_߀\aeH;Û#JRG}qF~_*~&+G+H=gϺ{#kL&ÐO,u X ^Hcc#u-B˓Jw2x1٢/G-C @~J>/Db''x<QQQ7n=pHHHPP}YLtd䩟iǾ89NtrmwDE/ͥעsxygO^L2|goTjHѐ:s!;%q` &R˭p***LG`faaqKģhfǏX{^Yzu_{KԈm| Z;R *Qnލ2ə9rOl)vGW +UGɫ+Zۂkg}Tv).he,ѪBku\t,"V""QcR  +@ yA 80wN3"A<˥R0/ ]6qqq0쀘+D2LiTT#`mp!`Ǯ\XXH `*D"D*Sb/9dz;:rk4~ֱjitV6kVdV.gIѮyoVn7PثbZ L6p ˆ}| uU7n܆I lm_Bg'Ex}?܆I |~qqqׯ_///we",I[e jV{Y!b}#TT8a)"6N"쐔`0d2C*d2s( n"ػXXwNރ*SH۪i?>p%A3Wpo^p3X쐘(0lxD` T5TZ f3{D߆B%ls~+$29.}>6L2 +**CF‡"1r`d_~ wVz Ƽ@ i6`J$bo0d4RThjp8QQQ:;$$$+Et%`~OAf&&`hk$O~ +%<; D{B3WV$md2 B&fjIKK 9}Gxx8CFF5@LHJ@&5vMs'HHwj 2R VE)BVꨱ>?xy77eyyyh7QM ;0~5 $kC+S>FCb"|4#ަw*b?a?i *lt_0o߾Ḻb(I:Ӥ YM74Ұ 'NH$fhfG !P1/~b&$x.v z{{n (NӇ` _8n\ooq'k8a! ø\nrr/qvvF@ ܻ@@8y @|<2'h!D8aI h&CcHDtbB ȱ:Ffnm{-8a.BDPbbb#T*Vn@SYŻ'Raz:MhA(AH$b1ѭ!΂h.`勗,[񉝽 ߓpkcL\A|hc;4Rn @LpϜ;YNInm(Z=00@b ɭe^c:8ڛU_V4Ƌ4 +oVCrQYCKtPU Z6 -Ѝ)\B J1v/!!Wĉ~qH/$_b {4<?V"t:Imu())ys@9m[kaN\ +0###$4\zU׻\.M""v ?Ob}HIFï`zRJ@|_[1)YAܬT*x߿ 9z:HVR⍜ǮXhc,IL&? dwbF gG?~;sVb޽{_Z=88(\ +DQ)ns p8u(--l@*9e8^\\̯^w:@@ ,@T*~FC 3E`2fggQ/B +ATZ,eR!`Yj{{{QHB2 IW^֡dtta@X8n||;nJ !$Ij-((סh Ary4 2.H2 K }1a?yBD334P~7% D hkk/Jl6cqѤD 8{GzA~~f9C @lu3ߣ`g"= 兪@]8sJC%BZldyHgvFq/yE:ç;s=&d?=9]? +cSܲt_?c̻~6?:;h4Q TG;ǟhYSۿ{6njKk?YܓZYd2v +q||X@@bvYs gyawo~< Mmɖ'm\[۪uw'ֽQppk+9WFFF_O,(~ʺDE[=>8fto3Clc:Ԛy[ϱQw.`;5}Lqga|5^{S]a6\~lذa߾}%tA0?>[X4i:iTfʼt_i.9} WN~S%SvιϏMo}36!999'Ns){ ,[Zl$Pjh 䯘LJkp瞰LAGsNgh8leN@!ɤT*ut eND@ ,1Ǒ"EH$s$!`)(ZCe;'@" ^-dq2L +"\^SSp8PHW f/d  A64M[,JůCYYyE6č +w\>Od2~ܹHF\Hr-X󻻻H^rl6+hq֭ eE  u(*ZR +xě 1`ƍyR! 6dqx<*ZZZ8jND@ A`0۫T*idvuԃ@.!Z\Hu@xx + 6 + QX,*… ϟ}^N7110c$Zj۶mp֭[W^MJqc$by/ڲe˗8@@ b4vz4 ^ )hA bdڵ_sN%hA b,;88844d65<0ԣӆ!t@@ !Hg!t8}KY:c#-\B`Y,lv7_s[4DDs*gi6p\ڱ"K53vgt[;nӱ+޵ErAE墀T @*jAE)RE!bD \%- $pK Bn'MN/)9's~yp%p@s<^O/p|F[>H=_U˭u%\Z{`CCOK_u*6L_fg⹦R+ +a̐jkk0X/@(x<@@ PrX`.'Lb @@Jrjjb $Vj@,LǕsJݻG?'XrL__H$"U__al6@* + w$. +8rX`> cr  BA@@@fnCyyԸ +bFQ&g&&&FGGa}d2&' ^j0Hr + TO kEbɁ"yDB(G;8aE^2i $.z):%\r%~"Fƨc灳 ?2(8fZ?aĊ;n@0tfRwOLm0p5Oz3 +:{M&ݘ/PuξKFgQ `WfZ~Q럽*j e&sLhTzdfUnx xQhQ7%2+P@ N[͚@د؝awufBIfz$p`BF8aJ*K `!b{a{Qx`[1Gg`_n'pDfB[ŔmeVzgU/&C +(8wt{s4SSM_onW}NȠN*BCK2kgGY'QdzbѸ֮nӣ}"w„U 8xrv{ ȜA%S!Y;PD+a(]#>)ɩݾBaooky{7i0ͤ FθM8HKt?v  +L:I<3sEu! ZhdJ a&I ڍ2NdiyEH`qo${WV)N ӟ=۬8N-Ns`*+/Z +'H:eK9H <aanp_5>]q|հ,I[ltUSP(ʦll鯈۳ kN?VWsX놛xST2V=ң'ZM6{]PPیcߢjA-,rb_# BP_i_$T澃38ý- [$W){6+ZA?Wh3ձ IAg ;6O贪!QZg`߯>V[ék[!z׽SQ>ĬOw]Es|? u%_P(Y A]%=Tڦ`Z/̎JojT!nR +0y?>nQ9 AyEE'xGB{/)V)d鵽SPQX5y@z.*yH "fֶUѩTVd|mvל:+5 +Qѕ̨LjjK.1o5>)yg5̀pt)#=韚/h>Y$lQ3۝WPtSE~rl> †JϧQ}}u W"^]q}ZtD~4$MSHh9)X7!b7Mt  prAqJ^O`yZCTtJ؟;&,-;\'H\D9d%p(C'[UV..AMGJXХو<||? LS[ׅߚCq>10O ̎!QY|ʄ HOȪO-({󷷞h6\šV'0WvrvBk˷[`PX8f(L .-Аȕ*P1m_=> Ct:q~J1(ԉ~)J{ef+Ff̬aF=6(/gƸՒGՆq z>9 + S[?eVQ܎ ¥}SJ=n?źH +F>fM3)Wr  0g_&+k+v_P$a T#Μ};+!0Dek.Nmq9YLޘ&9C?R̪=cf<˞h/kԵJn=\AJq9i.w0EjsjA#uXlHܾ)3@NҨA$'wUa`Oisd*̦!RXLIe{׬lz*KFNVw|iqe:)HaI+O.v )4 ~ .?pyil(+-ᕤkUA2Ah[sK]LOcYN[.Ϥe&MkOj&&=v164k**wFנXM |UGڅ4+FUX%E_MƱ: Ԩ3jzp9Wa0uؠQ0S7,Z-9`t +endstream endobj 189 0 obj <>/Filter/FlateDecode/Height 298/Intent/Perceptual/Length 176/Name/X/Subtype/Image/Type/XObject/Width 523>>stream +H ]U<`8 +endstream endobj 188 0 obj <> endobj 187 0 obj <> endobj 5 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 192 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 6 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 197 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 7 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 202 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 8 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 212 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 9 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 217 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 213 0 obj <>stream +HWێ#I}W3RdDUTו+؝x!9{eWyě_Ûog;L<hпo~oyg8>{ɑIy֟PjgQes4,>)ß gZ+9$}b-'\]{ե^P[Զ{MLiFMu>3#xa˹vUwtLi&)]6!%3{]M#~@MɒOYNI}V0"9 1f>C,Š3B%io53bG-eK:-9& # vZ"|_oBS|)4 MB}9#}6XN')ш=; +у2zK/8/d3ȾhR\.٨(<Wd ?xIKjfU6 ./B0Pd/MڄVFx0PϚGBB Q!*? +l"fUGcWTLS018F}Ფ xk9F39\$.$8L(<3#6ԏ%zRW´m-ٹ-h'bV}-~u3mq}Lgbg˞v<y,cƆ8r\nk,1Ig8RgqhL)H\KH[Ƌ,&"1.}N\%C+4rwul-nBfނ{81E ;޲r#,kThhYsJ3/J[ kbuhC^" M%VZ/hGz"~ϋ6_(-&]և/襌t+BCv8B]-v^rBHN⦰zIyC OS߿UHRsgF)0*W5Vp??*,w=wRW黳U +趄[ci;R:O"З(Tuyog:u8RhN>/>L#L-iui!%Θe*=d +DƁjgf90&G]{"aɟ$A(VS @ww+įi8}yT9|: +O\B]{lt6!.xiB r<}|LVZV#%/J̳ݖw}ׂہҶMIQ\ʷw/I9%D_$Yac@ >Ika(&ŖԘr޵l}:A2g>](0As3|BÝ&sAͧo D ;g.lb'; Pꦀ}VV*/ r9mQCR>Iznd$c\?];VKdIrTP% +XDZv{'GXsԐz >γ8O)BJC)a=!+qYX2r~QSt'c3x?y;A,|]i1|м۔aw$Mr>*yYL=Y2yoF3KG/RwgjG;: nv,B]m4>\[[Ml)+QU 4C[Pg"6uX )b8bN 'leRK*t`G5|B.ZETq +NVC6 55J}WU݀+$TC@J~@~QﻔqUF> endobj 217 0 obj <>stream +8;ZD/4-H?m&>_:+A-^VS^l`&h+dn17$fm,bLG=S:9q:4!)`V7=@U3WX,pX`]O>+Q. +Xa+2Xa9K5$2#S#_59&^Y]9BlDf7s)At^=B\c?/@2PYf:1$ +#1KMqY$5-!reummWY_Rjep'7Vm8n21cNF5miLL77W70X/Vcc9gf?!AF,]FW>ZeV(6`#U@/89pJQMK+ +D\"$[$+aS!0;TFj;_0bZ]YZd?bR@Pi+jPp)@69QZUeD#!5095=<\I-A(a\`J.!_^N +*-3?"<\h>8nK)9'B?d>iT&qIro1k%&RWr[%d35*Pj;'.b^AV'mciR:W])?[5\YMf1=+bp/B_*m-fK9$n]>92d8G65rUPV-u&+&nZ7Ho)k +.rF,V_WF$Gq+8D\K2pN'G.0W7_;=XsSi[1>ASQAU#b=e(^Da\cQmC8@1i#Qf#%bjP +aLjIXPut;S.X/_AcPq7N#e_i-%N3o":PAkdW,]\)DZ6H2W]2~> +endstream endobj 216 0 obj <>>>/Subtype/Form>>stream +0.043 0.188 0.557 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 165.0288 513.1763 cm +0 0 m +143.396 -126.674 l +-92.73 -72.859 l +h +f* +Q + +endstream endobj 218 0 obj <> endobj 215 0 obj <> endobj 203 0 obj <>stream +HWk%I~E}:/9(.vDewUvԙU̺UUʌljwofM]/w׿=|q|G%!e 7_o * sCTlr MLsKE I'!J~)IcGۥxӯ.B )D!w|Drr . AĨoJDvB eӡCb +q[6b'|hn"ʰC?v Dx)簿xR_z۳_cy=] j]=Ս=vj7y{oZWlw&"X/^kSUǏw ?B:$;g1݇rr8 WjWxkdT h昫v)uX?9qqw]jEQFPM:WBBht伣vTX p꾈sz[SVQ7\N)%DFG`%f; JLDB>Χؠ؍ ]7*T8FG4CPOvdz z%HL@J"I9:8*jx=vw Cmd IuymuQ?(aFzEF%"sʢio<;Y2nL>Lnd6n~E=[J>^}["1R/Nu+WQJBUH.#4`u*Aڍ:k3iSLk(!9Y1?ë濫X^&piӄ!>{n),leenrM\u5YFzYwMyS n%~7t2>kSeWSN3{e5Y,n>B' I8"|XKWHB`F@V͔``̚2RfD` P*; %h4qި0qSb~$;1-L,J+@?2e!a-iv[rQ[gWW,>ft 5@.uA; {1`"w叻Xۯ]8H>8n\fqhڷ6(~-(C(/襖BZd3'(KW7QAZə!ᬂ8?:IT%:N YDZcDƪ&(%!N+ Skh*34\I)2c~7lZ%t6QvgH|ehtrp)mx_SKO#S~T/Jđ(]S_Izif.xW 7$c*B"#Y{wC6=<C½.DΧIhN=f Dp ?> +}%E1OS\.(Y7}^STUK1&~@J)KkW4<{R +PVw 'vC7F/y_ +ei(ሥpѯKMݖB\ғKI^?#9do?r׽{_A}Ӧ*,\^9$;1`OB:*~r@*6XV?Wy=j /%dC:wL>L,n\D\)zkaHNRp5!K?=]C܏Q;mm\0˷F~r݆k4A3ѝ{sȊ c8ѬsQ`sa +endstream endobj 204 0 obj <> endobj 212 0 obj <>stream +8;Z\7]5jZ#'QpshdP,\&/laamFr]6GT=V1R=-5KB^Hlf72*'5Bo^.L,4DNF44\?,_OAJ!:C\adXW55a$ +-0T'1B_g\g.fJnES;HI57UGRS:)8nS',,Q^sR4#@J3Xfdh#Mh<:;D_*P"7b)A1?b8EtOA/Bp8c:fPN +->MnHm*VsQG$\]\FA]O%:kh]0BXp7T/WanPRQ(OHM?peq%QdTNT/pEVST6.j%b8Pj +1#s#EPbD#jllGRDDcabU8`(t;(Cb3#MN#:e_olAN2p$f/j%bl +d<\ouMPE0.[;HPX>t*d6Qb/97\0o0\P]k6X4k.4Jh`[7=;JP7TI_YVoO+HQn2>ki] +kg>')"GAaL&$%)N44c$q*b/nckXfXO8%?&hWH)O+&7IK>#Z/1$6(fR-:U_i7?r?<7K2O +endstream endobj 206 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 32.1599993 663.5654297 613.0302473 cm +/Im0 Do +Q + +endstream endobj 207 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 61.1999986 663.5654297 552.5503065 cm +/Im0 Do +Q + +endstream endobj 208 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 38.1599991 663.5654297 515.1102645 cm +/Im0 Do +Q + +endstream endobj 209 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 54.2399988 663.5654297 461.5902624 cm +/Im0 Do +Q + +endstream endobj 210 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 20.1599995 663.5654297 443.1102641 cm +/Im0 Do +Q + +endstream endobj 211 0 obj <>/Filter/FlateDecode/Height 695/Intent/Perceptual/Length 95274/Name/X/Subtype/Image/Type/XObject/Width 1402>>stream +H]oFolћ~mzM 4Ͷ ^$i$~Cɶ,l.NUL>t$I:6PU@ +]88X(}I$i~?l8si"tähhU1n٧$IbW +b766ug+]lFG5ǟ$I\VâXǽb]^p,z ԈyG_}óϾQ$I'VX²Vo}jbm\)l\Ͻ04PXX3 *&Ͳ/a<nu9z$It k^Xz%0a-\]&Je{&gh=Q秗?.g}$Z:mz2a!\f\ n#`DM/~ϗn0"IqHeY  +0[2ŲVMJ~XT姗dr霛}F~( ݯݯ kaXRVq\g;'c=P"o<|6t*qIѐ&+c\v_0,aE\dXǚRb]pp&776N~LTc'<}q99k0ufMeRu2y4/lsOvoz'|eXoV%vNDS`kbiw_2a^9oRxPs@-)WNJ;׭ +w)aQ?alze;zH_]8WO~c4\n3 h\Cݚۖ;}Fm{ve۱KG|&8hԛ'b149FWrtG|}ONVİ(Jza\gp~A.4g^͗&b!|#^I4| '_xG^*Za)OG/NGnbtw|+w߄EqY_\źl.~[qwof4Gi%ҾRݽ5F:~tM$rcYyRNӑGy"پ[W2n薵ٸO_e?1,bKoqشvp~ (Njz4GFkhƕNmoLޤt߫vF5iw|LUR[ΚӑK6F_]"Eq8?Bs)Ozj?eT*2&iNίWt7M/dK蕪vxWé9< [~Cc~Xbt8 {=yG_VߵrQ?s0uHW[毱2MJ'5*U]xr˓t4ٲQ9ǽ鲧]nǍNY6ݶ(x[\g)mD/otJ7uŗێ-q}Q~Z>GsdYm|MC<KMo~7)}]Um~wxi?LNӑ~Ë_?te 3\pa߅f+Bp-qyբpk9r!Z?w|Q*8zA7)@v]oٮ88L/SO_So4tF'F#fehGwO=/g8e 3\pa-otJl/nWn˃.5`rj/M٪SN, z'oRx~c#RxC@g]cvH{ /q/ ˹0[3ʟvL@`!`2=KrM;:BT맿sFյݙL=y)ՇgV>ԵČ l!v=>yyS8ydRIEjA-!~lTbozB@ V'kȴ*·Jt1.,9OIg($D*"!06j0R?Vfj˃c2SĤ=8F~>/CJzAXdw.F//ђqqCjGë *7=H @%ud*E(vER줂֫'䤈"ilWGָ-#u}#΄>Y*|M}.VcVg{Mmj\{PǠ{S@HD%`#S)"Z:ıA5Mj2=;|v$w)*Hwgf-wK$>XRo]k uç< i&B#Bx mTboJB@ iuĿ\ /h{tϿؙg"HA N N\]ԇWO,,xTs)D~tw +8)bRhï>2C-ot;Bŗqq۾$ZS=kp7%TboB@ )(uĿc0*<5qgϒJC" 2L x'˓䤈Itq.F/ڨAtqbskL#"зe۾]qlLJW.)_Gyg)K44"@ RQ 1(suzpSٜ1AdU1 ͤeIuvOM"΄qN +tUc<fj)b"8އ}DJbS_D\_/ғt5Bb CEY]*G>NYA%! 2b\G$< kD-h=7Tv'up|tNN c6骽5q0S/LgK7bl}^ հ?Yk]*ْh84"@ RQ gQeT +ɳPs A+D&M6G^K_!9)]RrRqtUu[bX3u3}f#}h_=W3vrAv-h]:QPW/cOyG[Q% @HD1`#E$κ`t\\bt'Tǥ8 JּRZĹ1F( +|'EL7QDi&#wfQq=]'_dxΙoč^T.|'*}tqX\ WA1`&C/EAI4P$B s,"FB,LfϪ{y)1b=QM\bIGQ]KW ,2.fjf=YGn5׿˯XU¯74Ζ +c/aWM&{ @/ņ6ʕDw;"f{Z:P}Ɔ.7A`(Q\_kb<ųDm̵aWuD! E@ bhey8s˧pSw|9V +b=&0̹|'EL+%'*Nb4]\@{a ].,X*fccylN<)v~_X3,jXYe.yƚKKll6oC%gMq z+ղގJ17] ƛfMt'yOlZvUoT6X3[3j+xg=RF\]}NPXS;W }3禈 zViާx / >8"2EN?Z1 ^Ƙ&Cx|?7夈@xCMYN +lv1Y֪jJǝn+7GI˱!xjg~Nl75v(8`?2[Բjqq)WwAA *:帘.1 E@ bL:TF> + X t"s#9NzԲqR,]}`s˰K3P$B(-:TVTv &WcbM[ܧ3wRyb㡜[bExbA,,-=fÆƮ>XWKI4ɚn/IS(T6 ժx&]uccR\B?څGے +wDX_sA cnvc&@H(Fu8VuRWN"n5 3&T)lxKXMYnwR,]}<ӢwKv;2>A~'mo)y-Xhɛ͆p&`C%piAV|6gCN\.I 9A|ILțvK}/sS~.Has˰K3!@ o X*= oֵ2ZbF&4SZB%&O[+wt{'C9-*yߑBa bq5J VE<'O:YsiI6OJ*;-/ =؏0P; +`Kl {n +wDX_vA[] I aw(: jSvD&ddVjJK?6&Tw!Z*=%V-w?KW崨ݒ|G' ~T/aV@eai8?\y,0wJ`1JP``` A~;Kn +B7YRoo|h Mj9{WIۻP 쇰"ONzW;!i3b3椬(ya؝MLb hVQ&1DXnÓVuRbЕ:MnZԢɝMc.7ˍ@啔ҵݾ96r5I~3w5PWpт!Lv:=E38!Y)Ѩ81N35'7~Koy6c^vg5UUjSrYҖIHXjE Ի8V{Q^I)]kjY{]_ݝnNwq9noq8H !ṉBx|pxrY Abv2D7]l:<'w،9) x\O\fln>>I@ע\"grge,[ Ǽ0&& 1k4(^m@cҮ"},Ƀ|'V܎%ןڛ+P2H/պ,7zWRJךj֢vg[ j*?RnN)7'CS.K_*!O\ߕQVA[sRZ~ebfOB']r.VxFV'!I%-DقrV!u%[°;0@ Ѭl:FhڶH+&ՊB =*W " Ԃ-պ,7zWRJךj֢vgDܱ>ʇXeW1w5uK.B/ܫ# q&]%=}HoagflIi6/p,OS Y>opxɐC禜Q{AX°;0@ Ѭl:bjDӨv%`_XKr#Gy%tf-jo~FtwqMa2{ V_uZuW7Wsk}oYg'a^mmvt ,( S4a-mRa͊(?#6ckNJ3߭ '/VFdқi Rn- Qsjw1/ C @*fCZ|~UFܬV*bH<$ZB!wj]ro@=+)kM 5kQW}33TqJ7m/( Ỵ{:u>it|F[sR~ox.aF2}s<!ۻU}6|8-UiGW$s*E"aMcy1/ C @*f#Fa_4u<\^Iv<>:Ƀ %H6ۻ8V{Q^I)]kjY-HP~Fl֜foɺ5GN'p nd +q<$tzʩ,Hf=zЋ+9Kve[U!91/ C @*ft]<"Ơxg~AooC)q;FIH .պ,7zWRJךj֢v3*5'ћ ׫ryRq=sr#]>? IA1hCy lb@ F@cH6 =8Z@ l()^^M{{j]ro@=+)kM 5kQW |ψؚҌAup(<z =Ac_ -_oRȏF P°;0@ Ѭl:P#! 'JY 'R ƒg'?RXKr#Gy%tf-j8#B[sRn67ϟZa%6SFXg'haQ1/ C @*ƪXfԣRPu[W،9)yx|/~>?:Oz noʢn672^'gm[! Ãk/ya؝MLb hVQW.jp5ˍ@啔ҵ +gflIi]םNg|n(u,S.@{n p{ \[qvq}=@\<,?7ekDCfB߬۫r<=~>D;l}}{E}l9ysΘb +|a,FݰNgh/?gy?cn {` %B|%YELuco !WRܮ15TIMgD ;6?;l<]Wht_,[}|~_ݨL&wp9wwx3׀`ai3X-X捉158BdU99V+"{%SC4tFPψccNJ{6{N<#>oo` vhīel ok`~78ЂuWvZ:=ưPb@!WU T9V+"{%SC4tFPψccNcn {` %B|%YE)as W!DI;CFrY8sckp(1 +*d ~ÕlovZMn:#b(g߱1'%ٽ\>_]}o2~|YNF|>ļ&d}E t--[{̍aĀB$(3s W $%~N6g[vOТ)W`xڈvZMnψccNJ{ j4oKuu}|tzm j=?dr9CMx+:17=' B*d ~Õlo$~]n*~{T,-iy3f٢jm5H PxH<{%SC4.6Ɯ>jUP9SX|ȋq)q{+1߃=ưĀB"YERutUJ7zzҗЖh@9u{fzոIHu ڗAZ{!\!DUq-i^-`WRܮ15TIbӚwlI9ϴߘT٭&}a˫HyWu@7d~G5 n믁ˀO³K/ +{` B!NdeJ9V+ވz l^AThgx-!?~;xvD,[PpU\ji6{/S⺯r z`PڮJ vZMnψccNJ{Y?&u.o6/ű)\‡F$R$|wK +,8[17=!'H28:Ǫp%@y"3JPyį֋U7)*bF"BJV~ RmRybxFg~"G]h`@9qK&['@'†^IqP& jMkbpg߱1'%ٽ[y;$I4jh5 +zOQzJ +zCgܟ}:]Lr1{%SC4^__?==7j⒰ƜcLPșHLDy#A!`̙~C[4" S7g1K ?H>T5=ưĀB"YEylqNtUJ7"N\Pavl|QIRA~"Q/Vo ͲEq %%3_wamp_^t/< g 6.thp"xvw)KqbkL jҠv3No߾.x{"X}?տ)xLQ!!`3ؘG:|\6p+NgqT]4.V}j|hsckp8Bq$(s W ea)`-وNu}=T@~j0яxm^qXᐸh}j:UB(&WDK-Ht'SѐЀO8u]yp;igJ"qSC2jj.?¤S]WHȯFOnLzN^~1i1;/bٵ0/|amE{tc^1M+-7_~o;O)vg"n/cVä_*ǍgݴG@***** +*b# 27+ G +Ytrh&̃cp;{Am~HL+NFPԒ4ٚ,1;Eg6WZOo3CwI~I7u\Pv9i$mWM)W j4Κa L`>QIJ">wN|~ص]jzK=X~}J;+|].D1J{_'"M.yiy@ө>dEcү?bv:8*(ҼאXC x>7W$oԜvN3 X7\^,{Wtz1,9'kPIr +|/fWQm:E-0f)r+Pr~~&!aox%mrR;a.L#z_G9M15T/v3Fqk\G $10րMl)( .Ѡ{kTaE+)dkZ cQ +J_"c"ԶKwGlZ.?O?ؽ9M'R߀k|UƤ_*}<3u(<2PQQQQqT(VQc1@ÄFsFQHqe 3F)^^`^ON/ЗY m}5Jb$SXpV` bk4CQ;An劌p3(=lv۩&]xg|,ngQS8x^׃!ݵE"0F3hDy cիNԉ' f>9̨"w +tB#vLX x"tUF/&+s\_Z=_K'v̟R_VHVxa b jlq#?a7CB"IۂP' ZT,t7"V܋de/''S!~xݾfWv1ȩ||mZfSZ8%_ ) ~NBe>rh+7%KX! PQS8x^6ejEJK'lUQNj$Wh`1L͋W&=FFh_#'ĂK}v;(xh,[pw]  * jT=>~J;\Z!p1)=z~~}l?d lS[71<r:cj^FMf^;wy4(+P$"40YWAg'Qn@:j\·c6ppPȇ>HAR @E,`1+2{g'v̟r{gF~3nZƒ#DXaH !uSi>X7\Hw?w/FSzbSjϟgK/ b}N/b 1)_y;Nekh~QS8x^66ʢ0U$GCb_כ~5V/fz_`$=tEp!F@lWiF$pqЗ8Ӎk%xN4mV󟛍;O9{gC~3nZƒ#DHX39X_Q ^f#ĎS̰֡Q<, .JC:,>$ C& ZT®Q~~/bgbU&؉&kU$&E3:|ة6SMÏj {A\5}|+ uDnp0y_#K'v̟r{D~3nZJ*****~DPOy597r6>5ߵQ7 N%& ~/bgb% T18V WQQ19M15T/vK+vmBU`WF`/e8aÀ"%  0itL}qnA.^]77jM@ѶTՔ?U,rYuο8-zm?[A]m8)>Ƽ4{~8˴"#vd^~ӑ0I6>tO,;vgtD1Ir򪣮KMEj˝2JB]~]d8=B;}5,6YC<7?T}KsOV]5X햝_ - + ?Ԯ Wi&KN$9bGOL~ez\.ȣh$ i'#Yv%:90b@`UvaI#1˜nPtvEK;Wb WצNS;b}2esEQDb}^"ylh^?tOKYv%dFUGyϙnwFA(gUuH)tm)˒t<'y8O][`_`?NʄOkSwC>2s%EQ\/;"|3(4 Q~crj\w wR&\}z^:rL?GɔrWy|E6I64ϲc@K}Vi0s6>gQ h*Uq,6Ipzmn0#'SʹݾDтF6ˎ4_AMMz(г|ovgtD1ITs`uW~'eէ굩ӻ!GTsĎXL~h\>5MFݾVGEA4b4猱ϙnwFA(D1j\w wR&\}z^:rL?GɔUu^hi7ni4HMheG#I6ݾ8Q>gQ hO!TJyyZ1]b WצNS;b}2e>=QH}^2D]Wՙ4lHNγL; Mu:JN5nZ(2c^}5;)>=TM 9#vd|{T9I64ɲc-tZ=a4X HN3߀s۝a&:TRJTZ9ǦQE]b WצNS;b}2e>~'YvEoʷۗ49>Z0VIg̗L; Mu:JN5"˲7%L }5;)>=TM 9#vd|NE4;$ِ(&:- !|3(4 QNUue)y^?v$LhG=K#Rq75Wb WצNS;b}2esYvEmI14[lp:}zivgtD1Ir>UGJ)G,Z& əfYzw]b WצNS;b}2e>~'YvEk\>( +# ݒ 6$UvgtD1Ir>Ub92sCh(OUu$!-jHO][ij|3(4 QΤPJq|-vB[v$eId_JIWq1hVM ո +LP6uz7 +~)399d1WGl/UuLKQs,#$U՛}t3: $XGIUG+s!ziqlKR,8]ͳRʛK$vS}5,6Ipzmn0#'S> HN:;j$Uu90b@`XUF,!R*c["/=Y%٧f?k/Vq}5,6Ipzmn0#'S: |>gQ h:~]}gYB)=y}+͕R +D*ߗ}_<_{ wR&\}z^:rL?Gs ϙnwFA(_G~_WcB()Y@jDJ1]iN{j$7j|;Wbj]H~ͫl^l3ުԒug& F A>u[}%9N00j]=IqP^* ; ){ˮ0@%xבߑ>UQ9Ŀ|ͣGLߗ=~C>sgw>EZ^C;JğYTKfឤĸd(Cٔxǂ½eW@eȪħJF5?~';U ᚢ{opORb\c2סJvÎC}GlJcA^sDz+ly PGoT6 +åmX+Y`qm6 IJkL:Tn`(ؘMY؋q{ˮ0@%J~P:ɪ9*()#Ľx')11P%aG#|bc6gAlW + v 5o---QSs,P?~<4X#_7ae*̤{opORb\c2סJvCiy}A#v5ZsKy<fD*1|/~ȋTS:T ̚4HUZZ^9Xܻ $)')11P%!L1&lς4^ JUհ斲+41(3'"f|TƎ1$LSү1z 05R6a +왭9qb])[dL,K f'Zٓz͕Pf vn9ZDQDۯ\eقjBlRY2ޑPY $)p(umIRb\Y >aj,23=sHW~)}yn*bIGA eL`ʞ/% +-\څQ 2XDfeݜgMc}piycE^BP +PTӬnl$lHR`tORb\D}(a +mIցvw\ (I#J*+w*( _(L59tǒC^z/znu"/\ +K"Sy(%E`>0 EGY yI] +Jd>*Xv;IF$CkzO#_Qi S[#L9tO)r&Rnfd3,:B|wiu:xeTF*& +KU~߄M]bڵQ 0]Dq֑fԧWnDzL> $zxHIcI)b`V18F5caj.L#L6|94~jϡ;uDI8jxɳ50TF*& +pS!/C>KLیbO6IDrf}5e]Ѥo/@%Rt<(I-lP’ƏFR|P'/7<P 9͡WB&ɫh+7c-hlT,.15Ei <\YҤ#&ꦞR3)jK N^^v^éO4g(jHw^\o~seխƏFRgRm1\|/ _y6 7*;"Fk=*ם`Y^ɔ_i~r{\([QZEb"4IDWW߇nDvr!i*R7/$.T.4t9 U^Y)КvL٥Ľ&Tn-F`.QNP̀PFEDZPehXM4˷HR༲qL[_A(TYКvDWeM)_Y4K,Q0 N@J ϛd6KfqʙNݑew@Se֗B33G0lӳ3/vu_N,k_ ;h_w$^걹r$`LYsyRre"QL׬e1?vyO+5iR|]Wnc ʰ"ǻF;O ťԿޞ:y084ݙ;GGBS/S=6D1I}e`*T| 꺯_hd(/FgJ ,/eEIIϿs_E\Jt9h`Eń^OyW|;Lg0| 6Ƿ(]d?/m9/紱3]mozv&Y;g|ر6N$ɑH# sy7Lyϫy@Dڗ}7H.IcYT\p +BD\So ~ bqb'EQUe061>Nʆw>VO=YM6cBٴr&3Qr3T֚N\Ymaj3{`a7v6ڗ]&^ag8Ԓx#g|?Ii4A-(;}D!_j"&֔3+nUWs Z_h\}N{Me N"&(*ƌbIsv:CGxLL2uwݟ:;MڗMT Se!\3fwWGV+޷G5CO]3@*InMR.ŲwڵQďIRfN(:RD AjrNgu|Q6!Eƽ}X7fh_6p>]^bN,tݭf(?0Zۄ,9P_^!$[R(H"a~ [M8KgL {F"y&:i;Mli_9.Sz~T3vb@VlZgr9|AsnBV9jQ0gHyRĄRڤ(*$f޺i貳ٖ =A͇%m{2œYQ9Y;,m'x`U8?9|o"??~wdnt[g[VT<=D>?Ŀ\ t2ɓa/IQEUPD#bbOw !{1]B@DCi_-3_o7Ӿш=)(izyRNEQTeyA2J-×|ě8NyEȊib1$}CZu>~kZ sUlmReϓ"FHJ(2GS&⧆;Bf+{$}lXR +AtvÜq!BBȊd04Cq%EQUqE/YRP|e!ʵ+& 9]?.L+}d#:yٴ͋kѿxh"BVOO?).&1LSe-)(J0 GR ܿ׌к?ȭKaj_-AY7CTgV/o\Y)Kp$p s2Jd#-Kk%JfB*($\\tW(jSvCHf>yvj|hZ_o7v""R\ᛋgGmÞhu^/ Bֈb+Hwp(K9S$⇦}'e<8{&P9:om vt!N4(OӜr7otL:O09:Q@D@MK5ʛ pNP#l[B6b,(ťYkzvGmq,H8AXn0*}m7ų<ڷtPF x((Y_:2=LFˆ}X[S%#}1ՖrǞ<ڷqwjs@75!EQEQAϺi0wUo-~zѾ{^@G`QY@((* ®cȺ치0bޞ0LdڧB`CJj̰K#}t +3 bKqvo+PR*KQEQEQE-.hEt/j07Ǧ5_(e1RV;3:mۺxЮQ]zh6 ajS`.w)2USt* ܄I"6.Hn#Brg8 BYHDLKN\(ޣr(j}~>w/{\A}ٵ0}}>KM蠷#:wx Z,4N_ЍvW;LLxԧR{CkRYJc+V7v 1r&3B<}cy WۋWcu@܋绠?'UHT*KChaOOru{.+J|sYNy86:VƎIQ4k,F!TASKDZ]左?iI͝o6# ?o~zg+e13r&3B1 +V7v,/LlRanPeQ hD.Z6(ͯ,DZis^z6mKЋn=͝n`Lfcmv-/LlRq^M҄*0 +l9 @Јre~ɳXmzn|EJ?f9bk] h:[c0 +l9 @Јre~ɳXmznCJ 4V/[ٵ0)gfq}.+6[N?4\rQ~U(P=_"lfSIʲIMe\n zѭjtЌ|}?{-}IQ4=3g|7A ig@(l|U %).?s^AXUwiCoO]g=0)gf&aX1 L?,ߍƮnfXZj.~Xmbmm8o:a?r%᝭G&EtVyf&JR0 + {DcVL>F,\{'=<<>O-@UsCM.\,htI~~/G4#PBzdyaRMgg |aG3C3Q ht}"{"͙U5WoJeP?]}$?qI8ZYY^EY<;_kУLQ~˷撔,OJ 벝.#L٠6k{Uo,I^5=Іv¤(LQN؟Z>t<zA#bηZ>-Th!u]a(dy"IYDZii\X>YߋZd\-j^%{&ELfrٟIF!ah̊igѮ܇-VCVtnTjTݷ zcynibeoJqP~Dv;02->U{jDZo,/Ll:gCX1 L74:݈FtfKҼ,OKC-H^z #*y[~OSg)+[~f=¤(glnm82ƹX1 N+hz#UO)l"K%wڷ&yA;8 @_A^-ǿy)NxYFWL^nzaRyJ}7>)v쑹庬jXqhWЈɎJ 鴍f&ٞ铏or? 4@-mD@HJ-&@IVPhZ(iرN\'Nlbgwdf㱽Wgʯ{zή_}dm3ٵ((jGMccpc INU 0* K/e|警 m=Q3b+w~)vb|YF3&;ѿ/hvF±ln2>N{=5-|ώ]t ]LG%5#y9mcpF

/}v}7n=|7o)EL[s]_5X7.<܂y*zW^ڳw=Z_8I­J]ȫsse]§ҧAI:jnb]v1hz-{j]$d 5vy +=sϞ.ة8tN83t1軈C 9*> xV!\c[%37Ll<,W_ 3ܝO>öM/S]z2Uۑz +}=vЇN_\T+jIaI \ rH6Yx@ԂH{@}=?ōEH7>&p~«$P^;|Hop{%#+=i2n8w( Fl|j|'N]b#!G3@Ā\ a|.v*N+z<}uUL;nZMx`pxeՑm rK cO7u:UZ +uv;wI#Ѳ +L/nff ZBԅ (Gg/>m`H@cjJ];.n.hvůNWq=oB(4U kKzB4Y pmX}Rܭl͎dt:UwBf0|]bCK%r` OpOv1M9ba֗*u`hvȚn+gkf-FV`يB3˖tߚ:}Ă! Q!hKjǛ+Xȳ t1ߙ&CJE3 T)l_P7/؅w*zh)Ej@R8q]PAVcěYolg 0)EK:)֌( eQ;=|B݌=u<0Ħ zC 'MMy9nnq~x!̕jɹ%rn ^N~tC k7_{_L[YvԮB/j}d^ݮ} vꔢuoՕ< Aj * + + je,HXPx8ޤ@sjhi&*5?}FJb֗*1GVk' u`N)ښza u52%,Q̆6 1ƀfⳛq6}](x5@0ÃATpml#jD?y)邝:kY `3!AAAA4-Xhx8xznh2M@ƃX'ޏd)ӊi!=VYuZ$Ѩ'9%vni;^1 o%s /!X-Q݋@nBQO !r^!uՈ=DuY8Rf! n+ћM@w Blw4[H[W !챾H0"G!T#>Ã-Ƒjtǽo̍%sѯKS^zw!<{>SLNݫӻB3`z;D?@uT#$Jѽ"bÕ=:7ֽL*C-0u) Ĉ7y<|k&n:ҥDQv^ݰ!E_$XL+tIT)KILPѥ&Eh}WM^t/}p$1 76 cK?mXn ؒEW͉ O,oNRcKrB G[)~ѧ߼V5?>wt4UrfB Mr$Ilb.ι?YS}X_m\(cW*p,-UveQB!>|/|OvK|?~٣gV7icG֞;ͥ;Y޽g WEmەyinB|21vE"-KvٮB!Ʊ=+[4<i1 7![@{cdQicu2j +{WTؑWI .Vb/@beDzcۏRߢ_մ +( +!RoVn?>QN vUQmHZp΢΁mQ3o6w#g08E{uCKYbZܐL/8eIB!ԃUm]Qmc?~wЪPY!|#R5Fc +`o*@aH)==; 5k$y3l6.3^ī<{ŷ.g].BMHkO_'F%BlBۇnmH7U@-/ϽT?}x<S% C,Tj㇑yt: 0Nc{q/i^fƽ [^&ɴ&'u!BjC6+z^׈xHv=%m)@MFÇ7$pxVV/Nv#gi[)+wxj(leQ.,{I | ܋53bօB UX\__'=z|N) J6&Bhh#kbC}fC?LeҶ b )?D!m6w% >k ɅilmoYQKU!]YU4`9Ee!rxQ-#AFSA't~_12Š v?1aGvY.eG!²d߽X3E  !R""^#8T|ʢ 5(ko +B$IUZb! Sj'}%UIвU`#?ڨ,-56;j4v6^_sr1Ň(D=_p2x(A}upp^DWz}KCH)w/2%+˒BinJk%Il]UU=C,4q֠mc:F:VeiUvNv-6uJxBI:dA jdoj,Ks{_'?\_.!nʽdt/BHmP4tڼHws|P<|(mpl( Th}ۂU5TJ;+$3W8D:2-;lGYUZmܠ_Ӎ:oWN{A6[s(o5 r"SVQX$;{2)'sL ZԖ$IJ/ENJC b2pP<˯yNH$1B(1z=^N[8(%TNFj!LAg(_O0Q'cA'?Dg.-6[]tWcN(={);8s'3cZ?n~Lz-rw|'E{9{!B6J^OdqHۈP!Ra|Uv{_GtVAc~>N"I ++m[{Gb$qqw!05CsPU$7R:ê 5s`fU8?\IT?ғܘ^nx뿃 I{9{!$ȒȃПY@'k͌48:;rF6t`8< }I Ckk翲AZݫ؂-߬}J$r fsHnğ댩;6^>Zt j)]9 O=MHrNBe62<q l=ڿZ{+#wI +T殎ϵĀpT}?v~"PL[yx5E.QUd1 ǜs u~6\̻@?`n?5 yH;0a+M0i2 }$v9:ucYg/⨮uYL&^9^fQ1^DV5 4^/C|rmk`0<"Wzaa!UFz}8F@ADZt:.AZ!AW)`ag`zWҫiSeW%RB9DCz euh(sҷaKh!۸TғAtD~.ABzbh<2hw_ )9!4]r*իՖ 5#'U|!vETYMO92І`tzŒ|Ƌ%h& 0`L6nUfQt/<(Oj0^/^ =IΕy Fv6}ڰې3TQHURRFIENs))G\U|!vETY[f[{i2ladh&s$u̓I84x> )Q;&Ee`pzn3/,7J KfC#qśr-$g^ KWvB}ڰBrJUx +uԕisYX WӦDzm #@͛vC]kӫ04Eh0GS?vX6 NYTzV2^X>+s%e !4^/7~t̤$M}fj'7MQC]h׆d2)S4eh[e*CidtPHPy2e`J*TYUzGNib:ee@]OFmtx|-!VvD 2px0Ԥ}hL rmLmYdh^/^ ' ft\ Q˂O"{O0yAw6 `}ڰGec(DeUsjLLQ)el8OW\Q(-kCZ*R0ʅ$̺m$m"`&hN8D9`paMSГc^} v-Ý$xIu꫍TR"/*gvTjAs_/6aWog/Ύ-a7K@zv+̇0áY.h gv@Ĉc"Fҟ64KfþCn'WaȽm}"Gdr%噙ovr׎v_ʜP/./_"Rƞ;V]Yr%rm+IL&DzGUp䘘QLՆfBzbk0iFXYy}YRш#+Ȑz!,űol%4׆2' vkֲpY.4ԂvPUL&vŰNWۍH7g!u:ѹ%N^Xch'>=}pn=ydz15n_ Bz/^L̥1\$%}~K5ͥࢄL7t)gA}$|oMS`0KfBn' ?}\~J n_>m+WP -T>@q zG{km<"vQT]\ঀM%:P2C\p0? G#>hx8~>LYhNQ^lT/z ǝ;Q,4@3WyS/w2OS{AzQ,7`!Uɼ͛~!LiJ->>;=W8A yo=T/6PPPe,4@3ƫ֧_ ,aj>JeNOTEshzP^lT/zˠXh|gWO]Y@N/g'j{^H|}@ +B[F + +w WyF:-~!^J-E]]^׶G4NT ((ޟ(%DXh|R/_<Ӿ|EӕW($FRI>&G|\lcաRب^@AAnf-^.I j_CW+e2C.7XCfxI5^&W*ުQ^lT/g-2'-~./#bZ͛`sL E:-h[h]giLӓuRب^@A1X/`0Dzz1S] #bǣFc`z]y! . oG87|#m  +-d2rq4z AvJW/_tJWJe&A:&z6F +ꝛn^AX>VeW1S] x^oDa@34\a'$l ߎ.WgFD[K)h`0_la&Gáy.ϼϛ]iJuc|}pvz8If4yfns(:w`CP^lT/޹zA :\XV=9,/V0TO3;c6|`p@qoN^gYBzy뺎NOhB|I>`U*DU"?gOwwɄ>vi_T/v bz#dSi<#˓Gh}`Yu +jM +U rUoH~BzF5aȟn'˓G߾kk&2h#Z=BdXTyNs^zO}{э]t#/=P|el|˼pZFáy 7A1Z;;=Ѩos@q7 w$,5l:3ԗɗ4ٺ-&.R 'k 4BQoȮp# #+<ه7Fv Pi_\ZT;5`zLuVurӴxDj0e)ru7AA"m6N8tL#t (8߅D앢G׊{~Vw|Fw>@|xd̬tt:cݙ@{CDT.e)`X,IP#uL$aM3bXoZ)xZ߸}ȧ{6ؽD$ؽ%iR($M[@8̼"Y ~-@ b0rZZrʮ.$ѳ2\Ȳ9?F +Ɇs RFMflOX1 +}2S9IieHdM`Cޞ;ZtV tVH"daBC>(I_7H7(3#BH7MrK!eT)RTco_&6^(`+X yw2,e<Aq^]1 W[t2 CV dYp׹\x|.b° {'HTc3А|z~n5j O=\<|%zp)Se +m( pb4ƀjFKH 5GJۯ"Đҹd=4\ +" +&QSҺ Du*S՗C>˶%R_$Mcx<%iQ9֝j,zD[[ Clv'1Klv,aMfx5^v}q#eC[p)jW{&֛ۧ&\,LyS.6O@!a6x{"Z=љ$@ÅATnphݤXG|m#KHS;$M #*Y2ٝ{X"٩ +s/o8^ S(g +e0Ls= tI5v% G0Tq# m`WmGT[tîr;qR_W&e{%R$MX`z px!i}Z-1wKI^A$ (R:6 S ° v4S'n)]wvq%4RXFɎ+sԆn"X]{Xsp2F<X‡J|tO=p)R[TcβIYSk ̋hOX#naa?v;`X {xrlvpqN!#e$q6܁N|v LW%4RX’-gɏOOsд~Lۏ ǧ16c%F.%)G0}~6 PXZQMCR*s]]wpE4 0R[ƍ=F*ߓ[;XT#c=GI?s]>KH-R;kT&eOyL.yL=Xpk<|\8#'˲2ԡ!GG6(8v{>9 p p6+#v 8a,dp)jWaɶ^<ÐnXTj{qr+.e n`>-4VI]6ā_v6sʈ:[ +c:IƊ=y*,DY*FU7"rJ!R vEyl6^^"EjjY40ڠ@&_e7x.T6`1()tRq# +fFe{%R$MFic<iµ6O&\ j-{+3h08@N%L.B 㚗fwXxf~#&q"2Q-;IyY0XKh^$[Iô^ar=?2u]ӽlֽD.ؽR%i`L5hȁ.vN0~,˨s:rD2!A +#Ljv<:KEP3l$Xk%>Ha\KO,zlͦyZ"ec,2f+7m(ѻv{s‹&Zft9E:.PIvD58 D-N_u]ӽlֽD.ؽ%K$,4$g> >#1v:GOWZ`W3!O%o=1 kme,>fw<"ja?{ljnxDWEwpdr>"@O,zlw6'<σ?/ +q2ZW;odgxf/}exf|\4=Y6p1?~lUVV#~%c<Hn'?էTo^wp%7P(X\ۣc'_y3PuEVÃ} c]JvJd[^GgF5#rٸV^/2#c\+Oz KK/[{X=_{Z_!}{{$h|wd;緔"7y9&v;r[,v{ޓO=uBzhXb)qWnꢻMN%%yua/^ꞯXB`qR4[f,1Ɣ8+,?+´Z3+KV1&!;I?da~.N V{EQtdkI/aipmzGݩ*3cJ|^@թ/ۅgD5#ouey)HˆCm2xd:{(ʜr<%i rQwvʌ%Ƙ'_ytkATzyifV{ Odl!gk(s:2ʵ򤗐-xmzGݩ*3cJ| ^@֖Ãfs"ga~.gmY1|ĺU(ʜr<%i rQwvʌ%Ƙ'_yWhkQU|^/2#c\+Oz yڂܦwԝh!(]2c1W[r:u^zQ9cZyK<6C AzK1%Nܪp^e.2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<I9;;[1Csݥ󤗐-xmzGݩ*3H)q@++:A g]:Oz yڂܦwԝh!(]218nOM;uBPp^ecLqۙUyK<6C AzH1%Nqng' _yK<6C AzI1%Nqngw@F\OM;uBPp^ecLq#;A c\+Oz yڂܦwԝh!(^+8'' օ򤗐OQh!(^[8''x<%$SwZ +W8vIR =v/'x"C A +qn<9l[?^);P-+`]ǧݮq<%$SwZ +W^򤗐OQh!(^zɓ^B |oy/_\QOl4.J;7Vz<{Ԣ'v>SՕ:οՈUso߾ye|Ǐ߸qݻ#e?ޞgvvvWkyɓ'o7o?_wot)BSSe?Rܐ:a|!/gK:e^9+ϔ(jue+F5"cjB۸x4Gq Pl]Bͺ:LI=iAe{ 2] +C7ttAnC!,Ie۾}H3zo|m6,jZni +=xظAe86 VY(TUUbHT*5g2gY1!BF>y˗_}+W~)OΞ|_Z.?D>?|>/~@Jl+`ZEp#q_{#{ű4a„ G=m2ZGZ&B&7rz> Jٗebf݊PUlنaP(]'?}Ν(J>93!H҉[~{a!9|;VBfsXCE",#E *c,+} &L8jgѽtkkhZ 4eYlVY!3roQUUVBa] ŰErT*$v&ZF>Iŋ~[Q3}G~G~[}KS\_wܫ>P>×)EYư>h6!ByiZ?cI5LLrUDϦ I\@VE +f P/ +7ngd}t80}{1Ǿ҄ &5FvC3F^:S5t! acZ-YfeqSEUq`Ú阋%b3f2s]Ird09_.(Rҹs_~M<ϟKKi%_) G(ϔ,cXx²>p!2 VPك>q`%a4&!j۶hZM3dH\ +R"CUX0WJ&Lp  ѣ{LV0M20 jdY!ZE +2%rӳ` :ɅصF>1oOE?%)}ŏ>-ϟRSssvw^Ӑ ~>xL)2`O4:Cִu *#P ,-ڠ6aUnBHi2䶑AjξQ#*c,+} &L8j?K( nҐ܂`voG48h}m1)KD>6^:5^u]zDc&TNvJL.TIi%(}V \8VYzRCzmqmgc=lq_F#{ű4a„ GޜnQ~Q,.A2+8n=e}m{CGҙʯ1>`Ѓth `]EO?I˲-ԣ*ՠ0zDd;w/O|B6z3gNu2?3 GHQq)%PbjueV°HA8On8 nX->HYn6¸bo#ǂW0a„Fk>?{f~S҉()Ogg#o^dTۜ^סWe Mo7#!M>{BYذJD5`vL -}hIGWzl}{9Ǿ҄ &5zܙn!1² FOȬ;;Ut |}_ax&r^:50MSeAt]gBaPdY?a3 k*PhQT/#}w-J/SƟI\Ǐǽ /_Zݶ+e(Όh` @X Y#ȺЪ@sw V mH Jq_F#{ű4a„ Gnf}~x{~|67HCZ,.JGw=|}7Jj0xgx#=^:5hZD,RSa=_"ʲjh4;\*>VP(h.'_EQ +̙c ݻg(GHJ?UгfLYM u>9de.[{"dD/ܧz`3ڇuKfݲ0+"K3t)Mۀi"{űd„ 2on02|[e5BBX\a%}kȏ#q3&Kgi +eYF!Vhl~P(mfǸ_ѽO_YL%S33)'1JK҉TJOo޼{C@3#^wFQomjV묍~HmQ3ɲ˂B5d7H 0lIHR!MJhJ$TWj*HlxTRy%R!)KCʡIH2<,t¦cړ+x= {{Ϟ;''eCa{ *%Ц!=뺟^%*OhUCUDhoNEc& +cə <-/ʈxnCY0\ɳκ'2uj~QLQ@*"o[z/7_(ğ4<4tэ7H[Y^;g~D~lbaccc9=)AjBUJۻ!]hwxO?JHtOaSd{)Ͱfi Ȳl۶Բ,a,XU(\]Yg?zEq/W(ܫx`&m^a6JpH½7w'*)IJCCCg8l2Q$)MIQ>|̙^O>]ٳCv=Tg8zX4Լ깅rm+fh88aS" +< VxafSTX8FS9=8Y.Gű:~Dy}3!H^D +P"k&(tP(1ĽfV,ar9f2O|>4۶EA?hP(PJ(@D(Oge\-p;f +4w܁/^,_}uΝm%1%)IJ>00p|3>>ԩ TG=ܻ>i"ԼHIW- +\ٞLJO2Epk2pvPSd~M'''`ó\.߾};#:O:EmH!I$׍4ڕXIpALt%t`ݐR!4þ +dG 00XifH|>K,Ke )4MR0ciJ%Z$ޛ};n ~ܹsuuǎ۷o0:<<ALIi\-:~[o#7<+ڵ>q,I޽j?{ q$$Ϋ(| ߇Tr/J1#XNs6R<971iU-'8999u;käC6 (1\"'%u.ȥ~!4->d%$0  +QM0EQl,ippbdYF#KxfY:KqHUU՝*(%Z$_<s}rJ.\.lYwZfٯ(+^η'P_&NERTJ(NUc>R +vIB/%pJ`|> B1g +Mfݻۛ=t}͛7o_Za2`B0+,t\nuL۷.] +zQt1X. I׏K(/vkjj_ߵsǏ70` +07׽h-LڧD'(Jz{+G?+(uc3tYpxp0Itf.C0^TGͽȵ4%5UЭ,h,Y"ܕjx5]' h PAL@`: Bd(+L]`0𗅬h1ߦĎ=;ߒ D" X.tyE[^}ח6iZYS[rS=WwDfzŋF}wI~_ByC츯LvqtK0jgYhVIkSq(h(i +"t&{nj,|bX`i@r%]9BW-a"ĥ MpO{Qj7^~w Jsss J0eS:::Ȕ/<3xjxQFbX(,a1lCzٴ  lvs/uޱ(]󳺻&,ˠG@  +D a +AA\04Z'i;K*ٰak5mM&υN)~HAn_3 K(ݹxՅFϖ(Z!t/#V^I( Vgɲt@ +:::loo׍$766¨Ui;K&.A{Ǘ.ź:~ߵsmox4O~H~D|ks?6~nz|6F9vu35\i1gü7$]?/!.̯ ҙ_7b}Ž Ч(}KpiA€W]f쒼jiBEہ{)Z`f0:K0饇pԓk1d&sP 99"AC]I EsVIwxZ!t/#/m;dѽgg[[)_ѾWlr;R4xt+Yʅ&Ԉ_=<lkn%,y7nht8:{dl34 d~iŎ{ G(Kpin( cʰWhd"IxF ٮUW6 0)l0\WKPĜW"33 AB[nςatQHN9/,Л2NtNf{~r݋-(#{ѼX;KVPr\?`xOE=W?,}R#)Tٍs_|WjtP ɨ|әWwu3nAp"W\T%qv Jn̯Kގ{+bw[򸁻,L0|X3!I # W0j_KI5CNatDϴ)ỵٮ; l`dfVs 30vŠGf2WݼGt/#iA/Dn*/Ŏ=;ߒD"SͩtouuSMXw`O+ G%ç+F{f+}ODR/LQ|2Z6WvCq϶/(C7$]?.i3:;+mdN?6:jwC@WS3#ӂX"GcHkހYQ"1$"` mZzE&0 ++j0 &iN$0fYL X +铢p4::Ğc0z(8 ~yI^TG-Ea缃 g{$x|ƌ'=;s~? wJI鍳??ooDB+/Zz=Eǚw<7yX DWFSǩ%#3lc`2Mb}Ž #u ;! _xĿ %p͐Y`X*E k.Ixf,GB?bH<`FJH⢺[Ӛ }A OpBqUDծ !8r61ӽ`[L 8?;;KǧOz{#{}#1ifCGվ +T/vJ轰{i_Mv K]n)^ӦUkJt8:{d01@`LpZ[6c-}7׽4MK`(Q!#\ ;4H4e`HN Bjlf Je0 ,6|i4&9y V! LD{(zTw1xZ!t/#ؖ;p;Kg̨rg~Fq]yw)DPpQU~ @,EI%!-TvHKqPhyPGc{S? +]@಩Y`SN:ǝvGVsϽs=sW^ݓSSSSy39#3_iZ;ZߧWv?}a{nժU-ye8xsQ}ΟK@2XcD 0~KL+ꕞB$PdH &Ar84lʎ{+@B%B9J2>U}zPlA z{ R{E( Fxvִ7_z5_4cS9nP<~aʉ?۶SrwKB޹um fϞf͚-[\p+?~촻pY +)k1jcXQ5 jHQSWD:Gp!g1N MF4'l~_|q\^*U8$Rt d + 1 w Wȿ E2 +ۑj )\MF]m]B(D#!2:-T3УD[3:ysˬi?f"P8YSFmo7~)ˈ4䂸Qs**ʝ;w,(cvŭ'O^q=1A_/zxV'\=-P`X,y#[PIJL:y*1)\+bQ.,S$$ j:Y\={q' z]bE+TQMFGG_'0 [^榦3x4no=vߘYOc?掼!q}q뮥CP(H$xf֭UUU&|"ETT,ro#b8 ɔQct*>zll]t@D56vĎ{[RK!.Os=≳3f(E|V5%M["1IC"艑Qd(0^"&/&BOd$ga'GqThkƁ̮KHPIZ.bRNrmؘq +~JTr)i@OcK'X( }(ˈؖu#/[ĊT"ccc?ٶӦy0/r*t,N/_@4OoBwݾ}O&&Iʟ=_7z {w3UKCßg2s疆B!pkbb<Bgg$FHo8%bޞ7nܻwɓLf 倨k ,q"f(ik;t )HNr:zŊzea6IQR.mG츧-丩"Co +U`cko[7 і&z* 7nRSBYSĊݵT.D9aooG3eb88d O PRTJӗPЧ ɅT^x[C +ADI#Yi6 s绽3{/ޱ0;|invvg~3|'E}]]_ |HDDMCzoݺys=qxM&EAHfPFUeED,6 +577wJJyޙo>^y7~< uz#,@W p+6X#e0 0NP0b5:KFVyؽHLýpU,(Hᄏ煟zk< ,)x< +NÃKRRZ4r,6 ݻw'&&n~{ۑE|7l8NpxO/+-`ͱ&:d G"=leKL44t@ H$EVU~E1133#H< B*iA,6?55u͑ޞnPe*/FPrҳW['5--1H 6%LP($> c# ܋Hm '=gezb 0eZʁI}nWĽ-lG`03[FaSa^Dn[?7ɄI8;%WE,]S[SSq|ecǎ .E5J2)JBGJqGj* H$<111<i!.[R"dK-48qa ,[b2 m̖` a:ج.8.38PWWv_gݶp#27&|*(wù7o)--8]F^x +> eHfVBAOjүˋDbzzzdddxx8477C0Vnhh(/+ikz{{I\?6B<N Xm$-1H 6%Lp@0y38PWW _q3.榦1p/"}->?Lt {ꪸTwܩp8˗m߾r9ө4UGU~T!hX=)>ndGH￟rZENƳn7:%36& )Ip2A|RѦXӏhfBV)jVD JIԗdVt#JJO+64H +0tw{< +O3{}!Gb$lvff>=ޤn}Ď>| H8](>)L%a,grv{7ۿYۿVU9A:rHSS(A8u/^LA0TX{@^!V)UUMNO|/^_w=>t'Iv>daaeSqW*W]SQv^1=*}b;p8lbgb1{uy +u +قd[~_\ 3 +;B%avϼtr~\nt&W֗_^Ez Nݻ0icUӠr#CPu'N}>_*ǜgGGc 7I|T\[+4l5)ZV,( ᘍB'xiiiK*v; %G!xe9ބK|?Lv>rTVGFFl*{=po.Ԫ!x҆xVWWJn 3"lpfG7. ^;w>t@]E[}>r]ikk#ܠO^hlZZvXhZc6X<*j/pHۑE%'-[KMWXLWVV>췂 >)6A|W0FS%vƀ +333*az +Hfu[K}! IIM쐕|F=4###OqJ?z-ia}Rʚb +r8`]󨨽}<&H8D<` 6crrt/=ѽlmiu^\,eѣGOfRdzeM1o9l.yTF~0(HYF!W#& ЋT9Ğ^KMWX'X?~|,6o H \p!X4 +h"xyyQfTͬHǚ!I<~18 ucccr]%ߟJB5e͔?)AjGdzeY1o9l.yT.,{W7?`(E%'fXg^ޯ]&Iv .Ν;01XEHCFMC+SSSsss䕌jzT3k+5QDpZ/{zM2Nf}*TRCXVi͢).J;%+ˊy+p8fuaΣw!`0@{n޸Yp`+=cu"G p!4Ĭ3b/tztuvvA=Q41BHغ1<թx|f"U4 ' I k' HݠNmpXJ?wrh(k'G2jAY^YY[A1 sE xe`0DC“pu_(rt/=ѽ=翧Xe +Y{O&gϞ$(nOwwɓ^|5 `bG]YYO<>Pxu#Io̢Wg!R)H,9s v{Ukkk6YθSYW(1Ҕ?2$˟ +b +r8`](o7o\WEɲ ' ^'A&^{{3՟/jJx3y@ p$.6s F'˚1V5 S6"N奉YY)*Ś'6ħR8\={wdHt:]. l,..>5|* +"F)&[a_P,. օ9 +߈d Qop7!G 9}|9Y粭FGG]%̽uLgkkk[ZZZ˰ 9E-k}bb]IhyKQ{]zUUWS)icS奉9Tje&Yd@$b}MS)&K"EZ:, +k >QFcpd%<  9ТmCnPES7PFKC#Il6]uVcT6?Cq\1H?o߼y;ު_| +ػڈHCCÊX9>?Mt*'<9KB5>9@bO}EWi"T/閨^Hyu:au"fȲT1VEyg&C&&&!Jf$)X T9-_?ڼyÇ7nzf2HT]HW'v2sA!gRvրsIȇdpQaEQU&:B"<9KnZCϡ(H9ԉ(TTTTv3V*^-Q@{3\@  M." <I 0H$<ϛĐeYdBg-,iٳN't 81cN=w$14UHK x,bǫE@.Rz +Ҡ=uj~VF.jhhXQ5G秉j Oek 4>򪞊nbJ%K%_WjQ6fM)\EpBkx`s ? +I$rJF~^FЮ/ջ(G>trD׶{'s{\ .@#Լ~11Z51 c!Ո1(ߛ5FFN +:ٽri駏&I6GYPu'gGo5~uciHו־(U=dLJtKT/`u +ctV&EBkxA9~6@/S-yBV)KƖ̳:ZzO$v:9"cYn@aHci*!X,N' 7(hLFKGw8XЎ;veٶ6fs:W ?([,Gj“@_ 4~z)RIKeѩ|S3bDQ,9 ,,,$I,Y1 + (ZC>L^2dV}:qڇ?9}WEz?}>}ݻ@1iJd<(EQEQ10,Y0 =X}Z|q _/u]_-o>}̙@cUTETpŢh:䝤7i"΢.bҽGt*o\~-C]n`NnX8tΞ]gff%>?Mt(issE x0uyuU=dLJt3mٓ`00,˕E@hBB:ƣ N$ _XXyy#?Mq(v +n9z1u|uU=dż.X|~B%K9L0dSEx\ %$H$S<e FHn/ܙrd&k$A#Դg.ϻ>&!uї{?xF~ƶq\q|H0cV65R`~Q(@Q6|RBŶd[2嘇cgeIV얪9L\ڤHIqExo̾ou5h [n`e,'dYR).>áY$%RN0mlթ/7Ud7ghH# -϶5jD^54O?I~Fr5MR#yx_ɲx&EQwh^caaa՚}1?cJ^uUW<2| F9Afɤs\.@/(9$y6Ғן"k, +Z!Bko~Ѯ|sH OX}m[#GV!Dhfcymv+PH,t~FscBQQQ. O~G-|,qejSvn~*) պ:z<%(ʺJիz,,,ZS/懂x,~B)KB(>Ds\.l6(pfLB3daH'/1˩λ\)E6D3Nh4 CKK f5 0. ܲH;s݄P} j~8LO=1fv`}Ms a+qQ΅mlh>yBVKh!s۷_xAQEe)T[ DʿXaۡ?nzMǾA@"' ^i!zhO?;޷sN?*)dYzE{ #!ߢ&;'iY6x9Le9BU4 fx"Л c+/U거jMվ + +T/Zڪ_xGejiiq:`Ъ~!] +inn^O{DQ37X,fpBVk/ eS} ώ~Y9.lVڈ8R/L)dv6 rO?'B!E!yT[Z9X,'el3崭Q xāA/oy{w}(uſ=T߫]d/Sg^%mߦi)f p+(U>_Rzk `֍x,VK^U<E! X<,F4rbl*,L&B>`fuy{|lJzxdscw73o6.Ȑ=pd\+4"DhKBHCԮ] ,'E!j/JеxKCكW}|Cw}$sG]u jo@9w[=r(=̈́\$ [ܽ +NY+)U>_RğS`0 SGc"L^Jկy(fFc^?zWDa8M&Sfą$֮17[݄R}\Vv?rsaE DhKBHi_[H Y%RZ|T9L{1PA͍_׹iiZW'Aj>|P>frk +kr۷E7*y(U>_R_`0LŊV3y)KB&I(u6i6QKU`yt:꜐?t*eo,"R^go}Hrs\ıb\._l'jj`}vs֧(HAH?fHJewc(4|ꦏ3}C6ӓo&RE1!kv!i?5Ɖ +cǻ~uR~T6THN#J4VWe +R[J*A#EꏪI#mB,10,T*0]ά{f{;c~:s=՝sѥ𬦃">?9B6BeT`0 i# +iƸ%oVz ~~R,|p8xԭL&B!ŚbKc`nPPb|={o+gkI9)K-|e'ؿ ,fsE`W\5::arQDI*>(Y^֩t}e߽ˏ^L$"/ggg0ʄ~Ǎk*92sqQh:k5w31´W,è"0ڪ1  A1%{զx^xf|>L CGn71iZ!V55x@bQ_q(U6^tޛzjh38nBوP.Q,itc:I0Yn^zb%I,T,KRn:~(E8_<$wyWVw mEtLI1Yfq">pnǿ-ޝ^č1´W,è"0ڪ1  A1%{զx^x%ISL +P. +u\.Gt~B5MXZr8V_q( {$Scg>ݲn>:y +` +/UO!4k-{vKRQŪ(j)I~Q+Y=!wU,G7YwX٣tO'9" tdC"}ϏqbF%VE`0 eAҌq-K6,r`0S`b @ P0L8.Ky?n^9gE=&4aŪqCks@Yes3 +ovtޛ$=vvhn:y + L)͢P6N?FSCh/q?K/oذs$ʲ$IERXmǰY|A~daΆluP("/zia+aTRmU `ZFAT ג j#X`*2Jg(N(}>e +MӠVJj^/'I a"3[BP L0RB(+VuFr)Mq}ݳ&285myБ .x$D*0+ɜFǬ=;w6,!ˢ"T#5C|P4ivK< ߮b+l['ا$--]$2#!L}2J*0 AP4c\K7kH& +^(kBj|Ci9CdAP)5J~?A!\.F5#UVjqu u{$Wl9NC8(㈧P.Q*K/-elLNY&e(IEr4jOͨeY{uyݺuV dA6/_?;mSaUnLm:sIzBv|c#i#tXQIEw3G m· +Ah]Z_[T*B!h`*`0FOL 곔pF7?={o_m~0EC|(KT Lh*N>&?h6y$XJYEҔP +B__ /H&B,_vZ{;޲8h:F|\)ǜSȑn X{? =?9BBeTF[=50L۠}o? +кxd/y0&={o|m+:rd!>8%4$#oQ8y]ߊSKɲ,JHJEY.K\)u6S֮]p L'f a,uY~mo+nSP6&{_  + !L{}2J*xD m· +Ah]ZQ_[L螽7åo;m̀!BD#+E lݿ1ݻv3duffdYdYIՈ '֯_0f*qG[ ;l{鰓m e!lFG,k1´W,è"0ڪȍAD`+|Pū%{4{sf?9BNGE| qP.1[ x~L8}nۑ?t_AϜ93>>qӢX|6;=5Ŏ]oܸ{k^ Qd6[lr7:mMڧN~rc\8~wwpb;cǖv:LLZGکڱRGFQJ#V#*"HDAlA;^6#V J{h8?r=wwvvo+4Ueʮ|EO{aP| 1&<_ÊtڹDB 2pfrl;bek}MS!۳%SMԴIKkiӫ~D%KÈ؛kQvQm'Hx`1@"dɓ>} FEX%-Y`yM{'@.yT&ʀ9eDU'ID +z; ȁ*%Z+iɠF; +)S=,QU$/}Vmi;(<^ǏBrL&YڼDB 2~C0Cv{@G{u:͢-2>bekmcOr1 6Cz:y+g:E=C?Ku*rfUڨQjiKm- #6>yzڬuOW`V"e%X;L$ $rDrP]~0!ueJVeŠ5Ԏ,è  {X8I~vR/3G ! 9W7P޹ӈYOܗԻ2çB㸎i1 ƻT&Z2zA@8!|܋M;w_Zc*\&^޸^LSɫiQz}M˥PŊR@ʨu+ڑ'Tӝyԍ RIߜ $ $( X8KG\H3T_ʨگM eO@~yzll?IvQ=ʁJ6iT& j*ng`Dc L |T +"y1)o> ۳aW!;|\bU5S, ;NmǨK):^~kz]Gpϕ^ǏB*!_NhK,K@/&xQdƘ[N94jԋCvuܴq8ј<=龍&\QΔfN|69zC0CvgߘV4D|܋M5bp~Šת-kzV4CqDft;ᕿV>~ѢWf~ JIF|^ׂ7 ^x5 zPHuQԽl r*YV@:^Ǐ8C#rĐlV+f0r +!DDBy?u5ɨ=j1&jG2]B7{o+%x uq N|c#z4 C(p " =wMB?Yág&}=#4߫)j7^l!Rma0"M=q ZMLog[SaM̷\; +["k=Cn;amL^J%[#[QKf X~ siSK/&^E/d2Fԫ3VƪDѠl6lzz~Ȁ|^H5x+̌T6d|yaĉ4c +x.<2KSB̮QwYdY>8|;O)aMl| EkBsQw|4fx%hl*Z(zQ78z]K>j1@3hξ(gZsb':s-P=tp- ѽ|4!Ol;Y> &ZOH㈳Dv4쎚)L/U񗬾E ⻰D(GQC[vQ4&hA >k(>`>{}Ib*-tE׭&ifg7a{2f?{rɹ{gν'_;g=|OvWk!H}#P*QS brԈDvpL-ߊ*XKvfm{Y2M6lcJbX?g%@ +ƖduSo4|H w{ACsI/&n uJAxkn^\~s}k/\߽uvcg5C>Kx?çբO4IRz< U_hql<6h2A􈥲]2c';Sݜi9zoVt RYGY?;e=Zvvi3LOLD+֓r*aRW)eWaz ;0|ҋۂSN{@77W6xb׽۹}kq_77_Om2`ԭ^ݿ?x"JES Zl`ddg +d].y zt%7-Jm9vpV^.y +mUjuxnSIkB[]r!NU"~_trbNAwhj`!PPz<U*x ^q9=ո =#S\S<=A(^[BCLqndM(J:M:RW)yTM KQͷ\[Rʻ(~𿠼vwA=q4>mA0CP z֫>ʹYJ|&Js1D6~0)\מS71{ a]tos/%GsWj)7oU18G=OqilL= jveC/^ DJ=;4(s *ύ#_97[Ix&;>%Oz1t[)uNPBhow7xp67ݓd7S:B͔h9%alc"ȅw~-UЄemcES _VNI.ya_Qt +ˆ'=Sޮ;;w{=ٲ͛o;`Q|ҋۂHyzMW{{{w]4aܘaIy:G-dn(mTЄ%~ڪAV#<0?'J-y-u:T{''b{L\S0ޡ@>5ojg[E9r5;gf|rӹ"3E sVv\W&w%A Mn`' D +ʠԫ;Ao'ˁ#>Ő^ RHP(^ՇA&-5Nk sk5=Z2?\GVj۳K_Qt +fqd%>Ő^ RHP(^ՇA&-!NUA/}I/Bz2@>5QCzE Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP 4 bH/)w(?XPYCzH!CBz' D +ʠ+h>Ő^ RHP(^@I/Bz2@ +Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP 4 bH/)w(?XPYCzH!CBz' D +ʠ+h>Ő^ RHP(^@I/Bz2@ +Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP jB:h{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKtjg sj;+1]E}m5PU^[3ǢwQ +b R¦wh:j`!P^ϖ)jM'\?--/-HrngfD=<Ԉ@Hε+.!W.aw(ςP^[r/V7./{oMOz1t[)a;4([gKZt,/-۳ٟd<5f^[:3sZ)D2߭#?ɉɑwKXa%|ɻ Be4ƽ6(GՍ_t8_K޸N{,Oz1t[)a;4([gKWoW?,f +TF- *j'DjW*Ѐل4)I(-AbwaԀ?/ &%6I1qG&3nmνw=yۨCW4# re.Ao4=yUdJٟ kJ%y"ߟG g^T E{ M8ٟHܾVfʱ ٖ -ɨKz-]^m쬊t0D9taB靰GbWϖDTt.A`UTYܨnK -T2 +!V kM&9m dӆ}`&D$ׅγb[]Iu.4~ ("P=;b??b@JْHMCWt fTY++RRij}"1YC@30o]3"k Ϫ7$8o .)Im|Ƀ￿o?k+N.1sŹ,]?^:kC!N#D+gK"qP*J: 0J򪡏#1Ke3܇5V+e$>(쟄gJ f!x`$f7N$n/[+/|W.%1 h[9]K5uB 1 }%lI$`"1V }\QҸM$s%d c.A"f-UeЈ*q6 4Oދ;Dbl[qM˅$.{_iw]B' ~3>BGvrzl_[p!4M20+۶Y=ϋ2d[u](qeh+"ʫ9w]yFW(!ľ-L$ƪ+JTT@fD\!l ,gB , /<7DZ؄а9{ѿ\W77f<5x0QN/-k@Ğy:K`Yi +4qB%uk)mzb@JْHDbZ)qJ%KFE GzOG=W]׏Oλr)5)xPM98/|sKO9>rK9:}bա7饳e~mÅDvX"̟ߚ%Q`^ְ=<7B 1 }%lI$`"1`4J%qkr }\QҼTQ B%֨p`W$qpP3Jp>sWx[Ͽ>u~GSHlKz1 Vk3k6rzl_[p!>(bF?tM.47Hm-K{8 ,4m.ι$cZ%2ikChK̋(6fIC)(ň 7 +$ +  kS{,T2?>*t@A#)yaź"ũ+ ݋ah.v⺮T3,KӴ8 lcrEKdPT-:X3OߏKj%L,_ʊv]3\ƒHP AU%A ]<1x)%=Ddߥws$GOۑߛ?;q' {swocEF^_kϝC˾yq䕎A%•H} ]??dXX\1}8?̎g}V$Hm-n.eYiϨJ]ץUιx4ͶjisjQs(dOhLq4|ȘT(hP-1Zrv"]?،{_[BAP ߵ 3wu#\,==7_,B$F%bVT.g ݋h +vضeYsIZ2Md YҼ!*:'WR;CMӄ}|ȘT(^;!]?B 03\Hmuwlv_9.3+=%H{m&mVU4z\ץι?VDz,2pM5(Ky#M$O4ONhL֌(S)o<+H+菏 }L03q3RtR"\ѹؾX,HKt/ЦlseY1mcuiLNWlqi 4M]q@P]^Tt +l +x]838m+4IpE/+̥;''$Hjgg(Y^GF~E&b’=-Y3s?B .܎>'fL*NRUK]okSب^@HA!~ !Wn,*U>6RI{e&,'x2bQ +vZڀ/Iq0Y4-X,N2,ϘSrVfѱOnHte^F 3s3_˛>FB +w0  jV"ԡSӅ1W䷬*ZACcԴ=R8X,ʹ&fs7~C1iS1dg^[O-d%L1x-Y=w䁧zQ C`@B 8' DT58u=}$ONeUDQ2Zïi^xҰͅ[Wg>ťv+wCUXc 3ON^h4;Obz!;@p^!YoAdeU;MˑZ,N49 }AU̘L151]>|Լ>脧zQ C`@B 8hZN"U>uT5'XX{z S>I];8%)ι(F#*1 +Rs~Nx )[?%#`T"IX,!˪,' M S>ʻ C:u_ +}N*KR`R/T/6RFU7v?@k~;JG(+ IIJQլ{< QKX,ꍡGI&wf&e9'r̴yǯi9zS9 +bdĒŧgJl%:^lT/ _w4v +Jk5~ m0y0hZN"Uu^a~]ϓF}; }`YNuQmFx3߫bdt?ίնT/6Rޝ slvCa\8bl~l6{n%7y5!r/In?9!+iTUSZ8,2S&f]j;Obz!ūFOVݟ +tsҏS΀#ǫ^t=/nŢ!MFa^,'|o4#$}#-:?SKb dbxyq<Ջ;#z&[ۢp/v +Pk㍶l=~ҏ銧#<~k^fz1z[3&S^lT/ xh#{ZY{LlxMXح6W6[mt\H9>q^&w^T)% b|Y;^lT/ x;3:/qyK/θ9:7^_{dҏr\4''O u k`9tILb71Uf9jo{=^lT/ x\kgkKMun-ϱq##~:dL'{]pN-/k_>m#W?I +za nR^c]]lm΢(HP?5e9<7oߐ36_s?64|}w?];~No62_ܺ +ɾ/ q82{Qz@lJ).'i&\?DlkB!ͯowƅ޽o2<Ώ?~Y9K __ =NoTḱVuRGOo"t9X<œ'~~Myp7l'$ [KKp5QԆ}!3z~b=|ۿym?Yf%/x|孭Wä7zWD_/( "T1قAy2r fœ`__2[|JvnðNP .ϫ;NPn 2Xt[YEqAd7"`szyz! H'e`۝>-+ZP'@9/CEk  鱡 =<p&D9mlN/1O/d0 7F]IזaZ͗JZ5!3 [(f 裨m;NhAukhx^{tc FTb=bC %nx|OBџB$/Z 9ʾEJoQ0ВdK#Z5!3 [KKm*fPJ +^4 t1( 9yMzaS%aSNEYn'>``L;)I#$"M˗//>p}݀6Hi.R<jrVe/e6b|n#%$O*)v4T#a_p&dak)|uGy5iA3h{ǩcEo^ 9vxD1Ή"ATXnLbp)y}JDx OȻI$.]xիW>euuuccx;NZ][[n +K Y0G4&Z(Pf[Kjdi)?* Y-ujX㪔W`#\!AЄÕDQq*մLL !-I7[Rᘝn#Gs(hzC$rtt*lN/1O/dP4&y-9CQW_i/%{޿~bEO>%#_GqFO^Kbpp@oUUFx') + <-48a1qszI0j2L7M5>c["H3L#g~ \ibcvW~ +VUU (j7J y$ dt/e'|eŐτ`0²:f)Wk}}8;;;IEѢ5Tۋ/)r(--u;x1szxyL$޿x3]B1#' N>ukAE,kkkgE@ccǏ9ZYYE ,sK&'{zz{ +Y^^<==q@@~8vޜ=}4Einn&i bmo:I(FylvɜJ$|3"2NKk[]]}Zڵk4^zUU^|`5{ %-2]4^?C(_GqFA\4CQ4ðmD_XX* 644ܻw͛7xfs#O 掎C\TT55֒ɤbUӚLM_(/ c()ᗖ(dd}Nte!aƉKqzoFUdYytim06oFDEwc>^}\-s^?1>@ʲ_GqFA\tvv2 KQ`x豶jllTԩ!PωIҥ4CCCC, n:r~iP,+l4VABUAavvEQV+FJm׮5f7'.I Q3NKUպw߾39s8W߯۷XN/< HVng~ӲQܯA$+Ph׮f mÇ + E3 }(ƍZOAN:uuyX,&xxo[OAǽ^o}wʫWm嗇V|<5{I^5e5}D_+qd$].A' ?}(inI [ckkΝ R + +6%ɭ[%nnn]׫ biϣ}nO$UU+++Vu~;vʲu-ڳZ^;~Ѻ¢<5{y[}(+"%xћ7o655%-JjTjs9Z]zuϞ=lǏ u={Vl)ˍ.\8uo{=v^]TT4bx[^nj.j#kTZZoܸI%A:EwygϞ@ H.@It#6??φO!;ݞҲ/^du>kWi~Iz#ZUUKO|FGǬǧ7VTTФ(KKK_?4 Ӽ5L&w"[4 O}гh1JMNNgcMc\z@Դ8텼셗^覽mc5jz.}PrwwOUU$TR}x r <=z~&lnnvqqTii :thvv>YiC]]=UUK-Eo;\r޸{woCCCHĚ4 ̙"ú[zi>ںgJJ?r䨢(l(9ןlɆfڋ^[^x Vf_fY}M ^9ZI=*H&}}}PMMM<AQ\.AӧA/]t\;OOqk׮566twwOOOaDvikk;;;_|I+[N&&&l0<<|Ν/5772r"x?iZOO-ۗbp8| 4@}jjvuu elE1K"}$o!{.y{a£C]alJSf5Y)3l^M?VC Eں֟[]/^$xFil95ݬeT6F(J.@P(֟n08`$DTLaڣs.հYLH/TzLNϫhm`AQ\.Ph?g9[(-d/YEyf|nw/YhmoK[D:޽{w?g{nJb + -[d[T[ x 7 kov<^8lbPԏFC6ݧ_{0gi)$IR uQ5!;$T8lʩ|N]_Mo}<5m86PK$m\tZK#,C9͏f1q>|(܎: G?$I;^ gVG7F3֎O#'O3+oqmy/]}jӛ$Iڢ{#G[fF=P7XJ>}^73 g}}ޭ'fB$IC"l4c*UM3/Ͱ}o0x۱:j itOWÆC$[vEXac*MP3֎3O&`A]v3*=7G?zmb$I%¢"1◫;UOv.ݸavA>}K.z5=õ.|꽧~sV/>W$IE),Š[",+kUI4TqtzU삡OWMwNU%zw_t'_>=}s_|He { ;!r!%kɛ$N6~:fݑ0.Վ5e3V΀t}x~\;$i { B;!9q6-CLڴU4cvJxlY[9 Vv$I"/=8Kb En*ux.{}]\ya"IvզPG^#]Z)tl֧ލIϦu1 9!I- oMX&q]|v0O=/~$P-g$Igڢ3#C,Y*E1̊=xT= մnj$Iڅ~]Ѧg[l8EX|HK϶Xi6T$Ik)E]:M}HG?o.<btN I?m\y3ѦiFk=~Syti'4Ň;G$-[9 6CW,1ֶG'%6@9hH}4 CWxcy!-#G$-X7 -[P̆~+$I~֝ + 1~>F$ZySsB$[[FIt0$iwx07 +endstream endobj 232 0 obj <> endobj 234 0 obj <>stream +Hms8=ĪAJJj:^ww2sg~C0,7Bb>b-iEuwBeKZvhVM5d5Z]Mz >Ee5۶A;Tq~nG~eUGg5|X?f`Yb<]cT<%l+59%9xEj=&'씱,uLB=gMC^' X#u>`^8=U;q0gRgm~ +T{\8a<.^3Pe*բn21ZƻxY~ J{t+5}vxLAg+agXR+iHW¥gω:{>E ֯ދ#Ly yk΋wzv=Zn뤞OW墼QUJyN+z =zCOSo7z =zCOSo7z =zCOSo7z =zCOSo7z =zCOSo詷"-EegΕg!4 ޣ.Ef O B{O0J ߲z|Ʋt"ҭѫ\zj,qR`|9)0VjVp򔠻x9̬3jPB ZEYdbw'N1p.: +1P)&8<ϞѪݝ8th'*P΄1Τ^Eg4|Đ׉:>X#u>`^8=I7䄘2I6p8="BWo8 +~Ltad,ekwy=]nG~eUGNqm{XlZ0^$3Ftk.vKx&Qz΢P(lInR @Um:b5&iİa 0ܖ +endstream endobj 220 0 obj [/Indexed/DeviceRGB 63 236 0 R] endobj 235 0 obj <>/Filter/FlateDecode/Height 84/Intent/Perceptual/Length 1320/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +Hջk*yxm AQ+X; lDVATlX +* +Vj +A &dٳv  -gwlʦ&߃aB)'Kdr%ܰrD1IyrbbPi5-Q)p)J F 2$TWP^Ib;;,f=bsOPoVCP0zV c2%iuT$'IE"E#T5JvfbaEz1FoRR Gch85rIH &|X0dk@zKf+d\pAӫloUрè?xjtlw=nݬAsOl^7f5vxi{HќގÖB'޳xpq<Ÿ(?LzŚ_`zS1{uE l D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тh}s=zrv|g4rsdzҋqQL|y޳vܼ|m{^~irzg8[mWaY͆z>r~=XLvۃvz9kX{j@4[i'劦׀ ^-g~F?.7{t6_,/+Ll:to7rqۼTT}p3j)Eymz͹'O(S,p,Xmڝnv;V=J&zJᣒRR7OF^K$sIS }ORl._(n +\6QnłSO>&S[/LEx"\$X4B}[#a?;b\}c:<^ z\oԸXǤWjRopr:6YOi")$H`4̀+hHBKE߃bbPi5-Q)p=Kdr%ܰrD ?dLR!`}#) +cSU , П +endstream endobj 236 0 obj <>stream +++'$$$$$############""""""""""""!!!!!!          +endstream endobj 233 0 obj <> endobj 237 0 obj <> endobj 238 0 obj [0.0 0.0 0.0] endobj 239 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 20.1599995 663.5654297 443.1102641 cm +/Im0 Do +Q + +endstream endobj 240 0 obj <> endobj 242 0 obj <>/Filter/FlateDecode/Height 84/Intent/Perceptual/Length 1320/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +Hջk*yxm AQ+X; lDVATlX +* +Vj +A &dٳv  -gwlʦ&߃aB)'Kdr%ܰrD1IyrbbPi5-Q)p)J F 2$TWP^Ib;;,f=bsOPoVCP0zV c2%iuT$'IE"E#T5JvfbaEz1FoRR Gch85rIH &|X0dk@zKf+d\pAӫloUрè?xjtlw=nݬAsOl^7f5vxi{HќގÖB'޳xpq<Ÿ(?LzŚ_`zS1{uE l D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тh}s=zrv|g4rsdzҋqQL|y޳vܼ|m{^~irzg8[mWaY͆z>r~=XLvۃvz9kX{j@4[i'劦׀ ^-g~F?.7{t6_,/+Ll:to7rqۼTT}p3j)Eymz͹'O(S,p,Xmڝnv;V=J&zJᣒRR7OF^K$sIS }ORl._(n +\6QnłSO>&S[/LEx"\$X4B}[#a?;b\}c:<^ z\oԸXǤWjRopr:6YOi")$H`4̀+hHBKE߃bbPi5-Q)p=Kdr%ܰrD ?dLR!`}#) +cSU , П +endstream endobj 241 0 obj <> endobj 243 0 obj [/ICCBased 244 0 R] endobj 244 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km +endstream endobj 229 0 obj <> endobj 231 0 obj <>stream +HnH&ᔩ2b![M&'F b\?~0v3eQ跘w~Iz"? ]*gɊvm0=jr +z9s~UoCvYxU?_@c sy=aeJľ/rҥ%zvzγPR,KRݖ2S3ӂӉ?tma(-!D%)dQwݡ?<]q-PJXמb-Svy\$-g,IG̒f=H{VZZ%5%onU~><;/-&Mqxy_{~MG7*pnXK|ʦ;=/!ODOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOl/&Vktʳ~nVh7WLf=SgJKKQPRXJքԭJg\$->0X>HUVj=w-gB)a]XV eʮS}xFp7]TMI34iG-em3ܮHhmyݩط}h歷'`Ym{[39յGT -S޸Q]'0]]fI,Y]#lwO'>gY-e$sg}c)icI2ٝǟGギޜ;rcIk5f4v괞}}_ް1뻹#KZ%g_瞇 +endstream endobj 245 0 obj <>/Filter/FlateDecode/Height 226/Intent/Perceptual/Length 1695/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qW'@"Q ĭ!huk ѶZ1qii)ZEAR}n]s;} wb跡גjSU9FIAj5rO9No4$")#2z %U})茢b;6,u‡RI8cs,8]nKJyh=!"[瞟uZxq^ +nFcD—H$Fp1 +4:7ãd4Mʜ'Gf紉UZoD3ً|//0Fbh7v|+K2)Q*oo +nhqbT &sy=z]+Zתu.s]_vZMzZ c|Hrh/ⲍzԓSvk${Soڝ3)[MdOM?xgu;>_^u_[ۋdl{37{"eh̠nԊx$ ]IKNw6$ec?My?{f:AJ NO?> endobj 246 0 obj <> endobj 247 0 obj [0.0 0.0 0.0] endobj 248 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 54.2399988 663.5654297 461.5902624 cm +/Im0 Do +Q + +endstream endobj 249 0 obj <> endobj 250 0 obj <>/Filter/FlateDecode/Height 226/Intent/Perceptual/Length 1695/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qW'@"Q ĭ!huk ѶZ1qii)ZEAR}n]s;} wb跡גjSU9FIAj5rO9No4$")#2z %U})茢b;6,u‡RI8cs,8]nKJyh=!"[瞟uZxq^ +nFcD—H$Fp1 +4:7ãd4Mʜ'Gf紉UZoD3ً|//0Fbh7v|+K2)Q*oo +nhqbT &sy=z]+Zתu.s]_vZMzZ c|Hrh/ⲍzԓSvk${Soڝ3)[MdOM?xgu;>_^u_[ۋdl{37{"eh̠nԊx$ ]IKNw6$ec?My?{f:AJ NO?> endobj 228 0 obj <>stream +HnH&ᔩ*Sb![MuOLk_!M}c,J~y.뗤/`٥R{j'Уf,aa.}??_N=dIkW 4|_ް1뻹#KZ%g_=՛3p#lXZͲ=m`tЙm}]dJ-zV3geY%e$sg=ZB4KR$etmaC2=yjcSݚ a_IZWƍ28ynl$*7Qy 1ys.ZՔT'KQK颥"|xw3Fמ1X)NawwO0`T>ȟs~`٥R{jӣ翠qwNr>u`gLidw8^ +endstream endobj 251 0 obj <>/Filter/FlateDecode/Height 159/Intent/Perceptual/Length 1531/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HձK: Իδ @t! \HZhii )ZѵE'Ak(y漢ty/o𝘀 % zJ ð$eƢGSrV>=nr%'xZqYoOASS˒<iٽ$ +N~j& ;53'jp-Fւ-LQO3s?ƶwvX4Ks<ǘGsgmNQZو񄲟Ldr_IƊ$:mp& nƖO2`L$}|x[~sC#r2/B!8;JɑWtXQOosO9:^Kr(K[ {Y;β7}wفySX^/+Ft:RlT+0i2ON`,q|y{hu{Fjj^'bA5= m%+Vǧ~??=vb.lyF=-zIt=1/O}){Z~&3r>g]+2u吏GBQoo``W;r'gRZ9'/ݷzO/o`Su_ʟx%x(GZv/lcv^p-8\q짜Ai vc/9&aI2ZLKIZV0Ns/Ua , ,N+ +endstream endobj 227 0 obj <> endobj 252 0 obj <> endobj 253 0 obj [0.0 0.0 0.0] endobj 254 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 38.1599991 663.5654297 515.1102645 cm +/Im0 Do +Q + +endstream endobj 255 0 obj <> endobj 256 0 obj <>/Filter/FlateDecode/Height 159/Intent/Perceptual/Length 1531/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HձK: Իδ @t! \HZhii )ZѵE'Ak(y漢ty/o𝘀 % zJ ð$eƢGSrV>=nr%'xZqYoOASS˒<iٽ$ +N~j& ;53'jp-Fւ-LQO3s?ƶwvX4Ks<ǘGsgmNQZو񄲟Ldr_IƊ$:mp& nƖO2`L$}|x[~sC#r2/B!8;JɑWtXQOosO9:^Kr(K[ {Y;β7}wفySX^/+Ft:RlT+0i2ON`,q|y{hu{Fjj^'bA5= m%+Vǧ~??=vb.lyF=-zIt=1/O}){Z~&3r>g]+2u吏GBQoo``W;r'gRZ9'/ݷzO/o`Su_ʟx%x(GZv/lcv^p-8\q짜Ai vc/9&aI2ZLKIZV0Ns/Ua , ,N+ +endstream endobj 223 0 obj <> endobj 225 0 obj <>stream +HnH&ᔩ*Sb![MuOLk_!M}c,J~y.뗤/`٥R{j'Уf,aa.}??_N=dIkW 4|_ް1뻹#KZ%g_=՛3p#lXZͲ=m`tЙm}]dJ-zV3geY%e$sg=ZB4KR$etmaC2=yjcSݚ a_IZWƍ28ynl$*7Qy 1ys.ZՔT'KQK颥"|xw3Fמ1X)NawwO0`T>ȟs~`٥R{jӣ翠qwNr>u`gLidw3 +endstream endobj 257 0 obj <>/Filter/FlateDecode/Height 255/Intent/Perceptual/Length 1770/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qԴii H b`Pdh-B8 +-"DA szu˽>>|'&ےjUU9F} h9꧜RLAo0LScLF^>Fq2gwجsѨ>r&Eվpn)vE,NӳvǻWIJ8ӓfSՋ ._`}cs{'KJw77>¬תsfki-ُ)Hc^hme7Uhuֶ"d*}t|!eNҩd,sXEh*a "\P,IRX粇Pc1h=E^\VkDZ)_]ֽ㨧Z097"e~s{Gԯkgddc1gVs?͇VH_*=4E.wZG=Ujݔ؎WSLJt:OU>lS/wĎ +zZ>r(=qr|^^IAyS)AgOnT}^ކKp[-$vW=z=3]#%~uW-e{{dkwg}uW;=Ȟ |dObO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO{䞭/zSk=RՑz22CguW-e{N<)Uo:!)tb2/SR<=rϕQ\o~@_{v^.vVqO+M篮N癔t|:pF='Ԃor}j+Rf^ȥ7NIPOz97"e~s{Gԯkgddc17-URHjR8;={-Fj0cBl._(JDT,sÃH(=5zmEbT$CʜSXdk簊zͨZ0^d?'D"E#{%l~w!iX R͍ϵ0+?ޑT*e%`r?T%~`Ȅܵ +endstream endobj 224 0 obj <> endobj 258 0 obj <> endobj 259 0 obj [0.0 0.0 0.0] endobj 260 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 61.1999986 663.5654297 552.5503065 cm +/Im0 Do +Q + +endstream endobj 261 0 obj <> endobj 262 0 obj <>/Filter/FlateDecode/Height 255/Intent/Perceptual/Length 1770/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qԴii H b`Pdh-B8 +-"DA szu˽>>|'&ےjUU9F} h9꧜RLAo0LScLF^>Fq2gwجsѨ>r&Eվpn)vE,NӳvǻWIJ8ӓfSՋ ._`}cs{'KJw77>¬תsfki-ُ)Hc^hme7Uhuֶ"d*}t|!eNҩd,sXEh*a "\P,IRX粇Pc1h=E^\VkDZ)_]ֽ㨧Z097"e~s{Gԯkgddc1gVs?͇VH_*=4E.wZG=Ujݔ؎WSLJt:OU>lS/wĎ +zZ>r(=qr|^^IAyS)AgOnT}^ކKp[-$vW=z=3]#%~uW-e{{dkwg}uW;=Ȟ |dObO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO{䞭/zSk=RՑz22CguW-e{N<)Uo:!)tb2/SR<=rϕQ\o~@_{v^.vVqO+M篮N癔t|:pF='Ԃor}j+Rf^ȥ7NIPOz97"e~s{Gԯkgddc17-URHjR8;={-Fj0cBl._(JDT,sÃH(=5zmEbT$CʜSXdk簊zͨZ0^d?'D"E#{%l~w!iX R͍ϵ0+?ޑT*e%`r?T%~`Ȅܵ +endstream endobj 219 0 obj <> endobj 222 0 obj <>stream +HosJjeW.DKW'S>{31\ewwLtY/-=oI/ʳ`rjT3MXq%Ujs[zZg-.3Єc{|O(k;Gx;,Gwq'c]tmnױQ3 7m& 5~F?;ZA2Z"\d=C0LŹ*,Lc1^pMk2=PU.cyXJhf#:;yf{bc/s1+'*8y6|̔L0^{ԛ(ጽVfw܆ˡfU +Cp{LZBVMp{<˭WL&= %حPw>=sNԩqOZf:;ltO5řL7\uzlmKKLm?<RֵGZb>QkwS%Z"_OT䮞/>Ó&xOI>/Filter/FlateDecode/Height 134/Intent/Perceptual/Length 1463/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qdX'瞙;7dA67 ^(_y~s +j0) CH4FŢp( +)c4[Yγ .E[6Llm"K₇c .Hfwl6#S(L;MK%0Xdisush&-"IRj|r|x+Gnt,v䃣˫kEr}uy~zt gf5 ťӋMqcnyg]yܓ7R}n?WJzx?&mrNls'7wNWUUvZw7'VD?x?} kAԹ_r"=cLrhu{/`sj\W +dLi3-V6c^íR-fWzr=KUV`p:PMZz}[:5OZ߆ݬv= >=AdГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'{/zӰ=lZO5fTMZ~9޳XUny{JsCO,)Tnyyu[J!4= 9_wz6{OU9/'zOJN.oZ>n.Or魈879af\/?>[vUzhkw1QYo(.^n&sۨ.Nx;;i:gk;յE9><ؕ#m]Zݔ\P,1B>'KK^c-f9-˫;R*-g]0"锴, +N{< Rd-HnQF|-$.x8gS‘hlE#P0Te`zT%`L +endstream endobj 221 0 obj <> endobj 264 0 obj <> endobj 265 0 obj [0.0 0.0 0.0] endobj 266 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 32.1599993 663.5654297 613.0302473 cm +/Im0 Do +Q + +endstream endobj 267 0 obj <> endobj 268 0 obj <>/Filter/FlateDecode/Height 134/Intent/Perceptual/Length 1463/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qdX'瞙;7dA67 ^(_y~s +j0) CH4FŢp( +)c4[Yγ .E[6Llm"K₇c .Hfwl6#S(L;MK%0Xdisush&-"IRj|r|x+Gnt,v䃣˫kEr}uy~zt gf5 ťӋMqcnyg]yܓ7R}n?WJzx?&mrNls'7wNWUUvZw7'VD?x?} kAԹ_r"=cLrhu{/`sj\W +dLi3-V6c^íR-fWzr=KUV`p:PMZz}[:5OZ߆ݬv= >=AdГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'{/zӰ=lZO5fTMZ~9޳XUny{JsCO,)Tnyyu[J!4= 9_wz6{OU9/'zOJN.oZ>n.Or魈879af\/?>[vUzhkw1QYo(.^n&sۨ.Nx;;i:gk;յE9><ؕ#m]Zݔ\P,1B>'KK^c-f9-˫;R*-g]0"锴, +N{< Rd-HnQF|-$.x8gS‘hlE#P0Te`zT%`L +endstream endobj 205 0 obj <> endobj 198 0 obj <>stream +HWَ5}3R{|oR]˼AHyD($2}uUwUd rϹ˱]=; Uw͋/~_ .X]Q򥺻8v|Ξ}5L4F䥤r>Zs1d{' 2Q >Fr ^:k F}i$FO65{L tW݉siVbRv 秚fVT<*`R>`Y7Q^̸Y}ѐDi*>ItkI +HϊJ){1FXrd'$`T3J;MvLt  +׵Eptk -wfNȓTn"Zq7ݣ#łS%.hiiqa4[A`\gإć\Q n܇\=-Gp.7dD[FDKaqA3<h$4pSE [ +);G\:mR;ËcWsӅy#A+>[{hc xNhZ]EJf(K8MfxB|= (<l.Β2z̠MU*/x9a抠[Pm>1`(EdKH3s1B^B:*a=̺{F _,ճF^v7Wxel*gK@|>Q҂ș=A0M5SDضIAI}V{V2T1a`$0\.pFgMXƨ<g-5q_0y:d\Ӂ=ߑ7Ŗ{dsl~ uĻ{}vp4Y;c[Sh*CP4U1wNe5<ԇ(b~lұ5dT΋Y}Ϣ0*i¹+!PeHc[-m<RKid6"*l$[ܥb*ic߶r2%%M[ql"96hNJF  ffFp nS6K +l=Ů{gܝ9VEE0l+4Ǵvd#t):ZdwByzK?~9oj!mu 9=valG +Fslx+d-mhoy to2#4&ۃ`ccTRʰ9v#]Y +r5] %m~ʋZ-xJ +endstream endobj 199 0 obj <> endobj 202 0 obj <>stream +8;Z]"4cY1L%##uWI$PN!Tqn.#j:]r&-8aC&[BHos':-EFL'^VNe`O3^cNs)PhBWrV +7Qt2>Dj2-)@f:^[&5sJX&0&9e@t70j)k +Kmm!=Bfl\1EG=G?GURYOPV-HSW:./)2nWdO:CLFWmWDXok'O:0.PuLpm +@CJj$79&T(:p=C'KP)U%q)R&)RSu)[E&"LFh0sTMQ14[R;G;X11kAJYE.pVoG,*Gu +1`Cjs,&c85.uI]>We_@2YSY0C03B+eS(Dd3,mN6=[sC7@!2X1XE<~> +endstream endobj 201 0 obj <>>>/Subtype/Form>>stream +0.141 0.69 0.502 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 160.5998 508.1125 cm +0 0 m +119.431 -172.677 l +-89.847 -70.594 l +h +f* +Q + +endstream endobj 269 0 obj <> endobj 200 0 obj <> endobj 193 0 obj <>stream +HWn#E}g$7 !Ŏe}@l%_ם5NUw:U=}3w9uS7{={#G.%}.mm~{.=T0vR9{˚O/H=wm ̅|&;Wy2u9gW_H.>)d.E_2c|ҚqQ_6qaT8*b`A{ap>%]q,PKȊB:G쒏Z+nSK1bB.C9|DFv7MI=gRJ`hi\/v2, P<CG@3Q1oڝDZ>b]T*utB'lW`U>+v=J."UV{6٬r1C +RQ1*=ݱuX7q%?TګC#(lrishc-Kg+z)/6~(.)#/fiW,؆eŠK6Z7K VV +,pPǛjX e iQ&4-o| JbqbF%A&q0țb:k<yx0Zcxsu1le`{Û ˠ#u ,AB +2 (A҈VW6#PuR=! yc}@x,< E6?|_G2'^υ+69OjMdPf T:KY+裌QOO ĉH%i%XO ?ʇ$(a JCKޯc`BO0(] !Y>̹0LTrBF +ʥ^Y ^':Mg7ˢ_n/n}4!)1!xe+8)qΗc(*ˊVcXH:rh.(c{1de #/9 +*RZFYCžiyC3VDU3Cv3#.Bk4g|Lѹg> |L 藙cYfs"p{LߣcTCJ͐Guĺiv@4`>9DcG0=cQ{Gsh@ +endstream endobj 194 0 obj <> endobj 197 0 obj <>stream +8;Z\74-kIP'KsLZoPT<D<=+*R=0 +VTo[8:@f_nNk>0:2'!/!'%GIDc-s%)W_K]J%6MbO3YPJ^k)"Q*9!6Zl/TZ_j(8Xu[ +\e0j5/Z94Im`Wi8ImtCj +O8]+RP_+G\<'VginMQlZBCFBt@)dj2q4aY`EfB!6;;;0FChc7$bRJ,-IVef_%VE`n +bU]5EX,&gEig>8?s.Hpn*uL+i7EgB7`QH@@gTqAIDIRfMofoG`U8J,oaZL1_VZc;h +[b.DCbER;*7/GAFj2>\;LY:1"CU'U;!M9VIaQZ=u9^P;Ib +m8!]2bgMV8F>TkWXSh0UgiHF:oUrM(D.u[Z5T=e+I*odk:l-eH3?];K0eG]Achd[+ +#FRAf$d/83JoWaQk`fbp:\Q1mLXj8^-G99*?":#l1O"f;j%mL:\JF:K$J9\/G!mC! +Ud%;BJ$Ah)=0I*;ZArRVh>Q@]/!2,jm%5/@lrccLOf;=*\>1ar+u]kM7fFNZ#6<7YVBQ~> +endstream endobj 196 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +0.043 0.188 0.557 rg +/Perceptual ri +/GS0 gs +/C0_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 118.6989 0 0 118.6989 591.2881 698.2305 Tm +[<0026003200310037002800310037>12 <0036>]TJ +ET + +endstream endobj 270 0 obj <> endobj 195 0 obj <> endobj 190 0 obj <>stream +HWˮeG ?pw]Sʨ#ƨHY=.^^v}7ׇߔ7z_~x}_>}//{}rW5θqs}׳|0'Ɯw)m]=ƽ>c~zEw-z.w[rv|~u FXU=΅?}_dOeܽk0ޯ +cckp\o=S,Yۭ/{*okuڸ\[ĎC'Bsvz7"=V>]T\kkAJFr;|NB!cJnoZgݣ| s W]xDhp{Ր# q9AaͥLj6/& +"w*7 }#6'Y`8^`߸ZlU^a'^$5 Ҩ҅mAG!.nq vjƳ+˂ܔGU6JĻjYF^)P3SJy^f 8ͻ}t;Rv}7Nio鎲p* ߐ:4N& _Q2X%*GIllk[gPN( +1n ^!;=mvòE(Ħ %mg)Ϊ |Z98-T2R[UQg!nhT +$&πغwX>bv 6G u; +P𻵙F'Q?#m>)ߤWXX,W݀UX$*6.T)RjHud2lZdהf+*P-lD&S_$vT$8ŕ)w@^߇ ikɏwlzY0ߢًWi rUjV` C4# o6 X9W;bVXo|?!B-$=2w0@٦8XٕRϰi;|,lQk!1"s^Gzq4Յmځ0/QKڏwz}>Y!0;Ur\h2\X;#8{_`ĉ덓ſCU5Fd@Ad0HK%<<8a24(V42xv}lm(Ojڱ],hd9@(; 6<*)<6țXV@A%X$V9:1]NMET]3MhfnsqlС[7]rQK?nj2Xʨ` + =[H}}p`3b-J͈ qtվ5xifm)xqV-W^E ljtׅz7jy\*>l[l:";Kz4kC@;ͳT`Yt9c;ž]zw T=݀3ӄΤ cEoVڱs=zHJvtrZil0UA߯gԫOF]UB-a/g9t?f^][tV6ݥvT-}dI v2 9z=>l+02MeJlbazC3LXyM2ώ9{هmh3i[ZaR=97$sc1rrj*B3+a +%\> ՘s0zb*fГBI'T1v2i{97 ?4Ew}+[Ǭ66CGK[= ^J1ISeZ9Mi7; OX Ka.=VCODzLֳ<'cO5Vp"[佦^،1'jnJ+l`ą-XGVjvnK؅vז3XRŀciGDZҸ *柽NTYfR5Xq/~=kc߹ |QeNǼE{R;<zeSgRn{M>ֺ_6JET4CB扽%䚚x6yRdiUwF\+N!K2ץ'M_I5~ jP|7Sf"V̈́E7 vԤbN-Cp/+ZV!0M: +Ի:[DXꈥ(a]%ά-:*}xTc& iVE8!iׇ:dW)SX۴4tfE!WаQC٠MMf _Ŋq!!BnFXTelwUʿ2[HTدQYj5=Yd~CAXVZ=7R[ =Tdۉk. 9(hran7^"aZ8 ˧tL;UR7/jQ^ +5B$yQXSUuA߁B2pڀ!T34Iƞ3z.<,k7e^0ұMoeFgcCǴ(FUT& Yb\ZkX$ !JG_[pvBr#8.MfڑYf? \V}Į)yTjɷ0/KB(9K#Up!mX a?wj5J9;w +,HP!Ą L|:$Q gXL  G ˏ/?]C™Q4vGnf{U0xI%&BY(!Fp)GXِvi[ȵ^7u.۪TEQ԰GH~W)c*j1k-vfn p. hC+e@Jk#}S#d@嬄e!9D@!@QŻ삒do.T<,vr_b?\H+.i13Y#I_m:Ҍ&L%daufn’POrݽ_ju/?j H *Polje];]F9`V;B[ve2 `a9T6H=QDgGFvKbM^vJXYhʙIԔa"њjib sLMpIsWۦnc*QQ5ר,?ai4d&2SUUByzu oLqx@!/-@1w>lL4K?^Yf0ZEt7y~_ɇfh9:8"MD^dKV̜ nsHy36bymk] zb EĎ˥U.<^@4Z)43q+*FǏ-ܹ%y&sd's2L>dt$s_(F +M &aJF&q72:v=b3v ~;pb ddhY6T?HgSHhA@90[Pܡ,]}av,!4.ߐ9G:;FK*\C{Nʴԅ=ѶDFw܏L,Z%P +QmS4,[oq:0( +иc$bCHjpк>J~\shGC%q;>ᱝQ^|qA;d܈Bw47ȴ- i:CS*WN3 .M_Bl'sBD-6IŨ]`5vڜDٿ9@R4Ѽ'zncO1]oZmDp9sL/QJ/Kǘ|tULSqk'ۜ;kلQ:&{`Ů8$x:$ Ǧb[AXM][=S +w>'y= dGg{+;"=*8r`[>1,}aE)H%Y-P$U^-OEO DF;?ߨxq.~@OL/[x@]!R2u|}˟OD*X0$MMh}LWB]!Jʪw)]ThE.&j+cOXpcjf|e ZE+RP$0Vlj%A+P-\rLѽ&&3X,Rj^MKNrsA1 юILǥb2,̈́ʟX٦F+:2p vE~u@V@?MsW(.IfYv$kwe%; +"X)9ۧ\f78uJZȶCbU,b~Zqy +{N_~s:T}H<0U{-g% +Nn:TtCf 3::n0FrVo65Ϳj{??v*q#l+\2TMMFj}'v[@ ?C>Pobx§Ƌ`e$d +M~bwO!M\ՓOTt,UZ(ՍY@z$a מɽ΅@7f5{ˣ QQ `M+ʱ]sW%!#  ӝSxB;xsX}h=R0#K 5%G:h.yBnH[-XC}[>1ΐn毶-P%7`Ly#nI5wm '}hj + z,H15$uQ1ĪKhA(]~>0>I-ab!TY͒Cj{mPqZs%c<$gG;#P6GuYǒV-R1eZݹ#`oi w H[r4&%lBa $_y}&`Φ8EYc`%Wi^E`oT5=q+ @l/`KHMX}S{dj?&A +aY!Sv'!D VznФ8Ȃ`J գ1B9!٘d?𖹽P*@D&lM#Xu +V S{;s2wyd_8*DbDɽ`0nڲ9JE,W wfDAAtڭ)=_ՈQappZrh#N(Cn.AtQ<͏Ί^)ai9|mi訠.;~2Cf%Zb'VS=ؑɷSKwm ?O!{W"F,')ϦP C1v5-[/OAFyVg*0 YԎ^9Le:C,w:Y1O%8MG{Vu׊dVT:Lbaw*9ݼo&F }-f!ڻNL"bNN'?VҧRxJj]YhԪ(^I&P/vNV?v0sի<`UT#Vm{ tG$C/.HEAaD"=ܥ?wf.I`IT^FE iviŜ)>9TLOh%@ƻJq+O%NOV;%qF>tQ(M̈́(mзʠiYkv:Dnj@d.6}]~I_׋ce]>.?yl*uyA@ ߲[ ]_kǮGi;$XBUrSJ8}Yp8W{[E/{#,m;;LqOUټLx l>hf9cf5u+˳ߊ} l[NŨ8i\Q1[ib],G_ Yy\;O_Ŵczf"|V;e};7 }^ṫQk=|woni:['u1 +`^)j\(Y"xy]2f:+B쭬륂{$<ՄJl, +s?o{kBqxe8E'j^nn$!twoӿ樽fm>w&YjۓIaj/^&l9=[-^>qCXp_Sn{//c: +[j]UCKK $ +'#EUᒔU#L(XӧpURM[9sˤHMc͎+ks#NpuGc'd(.WEjNSRιU[A.PAO}b%~ ыҔ6LR_"]XjE& +̢J+oA&\JGSynGƃrWx+2b4NBwnE.Xۘ GS۞J 0eSP ,MmS,JcG0p +Q+y$L6Ƕoniȡ^`M7~v/s*6ÈM"_+t ! %KZ K#]UhW&]^<' L)w`ÅF #EpQn`)R{zT|zr[ I! bi<WwM}4q!;%sv_6Bih'sJ֟2hԋQi\mHCˆVM>mCwj4+#(j3R[q%PՖFA˩^2!8n+VʻF@Vl+hjr޶"$}B\(\h%?TT %GN /[I[u0I9ݣKM%:q,ҔMC8͗pv[d8eҹuZg2ruPIF=SCω({}RIcQhC1ұTIU6dCѮP <p`Uw}fP#fh3DΨ^,k7e0ұ|Ooߗ/zg\6pL@28iUEeR!婇6P K@ х Pbݽ-jΏoaCɏ%0 4ъ:# !xWy<$DŐ/KB*)*rH,\][+N?eI5|qtQ۔UMjT~.2 JTQ@ P~)3Iq5@ eF:ZyF sxٳZI ,ęmsXաnno.@5B(ך'-k*z3,^:P +\4ح*ϽkTݢl`Z% CK*a%bHfO.kV߶#UAuǘp-LYB!&Q7sI@ &f1@=Ye-,,TyvAid*,9hK晷U ~$"Tdm.:dL'e.h"BUO+LWɨKJݏ|9Bh Gdc+TȗCk9sf[UZv aeHιC)vk +WŴ ~yvD-,m?u#a95QEݶ2T *DM^Ã\W8U۾dN NTCGasFT5j󩄦Z2eDzRcl7M+NV=gK(_람', [Q' GWax8rιJsC"~4EL7 ?KpDm6͒Sj[?2yؾc >̟ǝrǭ+,KK +osKL6NX8>SItrzP*%R3L'l*B K ]1yhK%skc `OB$q= v4SJw$?C u6uvXeɰ* n{ʸ!1o.J|ߥjsQ1JR iJ؈JeirK @`eY*4ؗ"F0iꝹb_fC + u !T%>BYk519v@FmʆlH[]}3%wþytD:лoš*|e^>C: +nbÉ7>Ά鼔>.R~9oz`r +4c2φ887cʈd+hhAaQIZHIjzky1ׁռc1Gy +|{sP$HMJ 4l cӿsD-%l 9 v 4l{ja0;*Z95n7b`H"qiR> endobj 192 0 obj <>stream +8;Z]"0p7/C$q3<`iBBbNAIj3tb"Ye$78e/^V+KuOct&Wq]$AHYP7SiZgK:ega_):i +6hEjhQ41Q5Inpdq8Ck(iUG?57Jgr38(nlSI6t&bY(_s+tl,C$am'^R9Us8(7LIQN/ +T8VE49O#Yl9p8/c=%@R^c+^_VQ!OWM=o&IJOLSnY2Y9;Y;NmY!bZ):a%UH*h[DE4j +cLq.m=OpB`A"CVC%14h/*RV-qh[!8%)lGu^FeF;m5f^$6K/\:^I6khnn5o]e$`p2F +FcFKkB?$#3b23_L54;:UpUdAoc=7rNOuak?H6&=(AZ\a*4NXPViHGeX=\GCN'1fTe +?;amNkmuC/I#L?HJ*1MpZcVm'=N@K<[BAMQNEqCglKQ8Ts6rV"eD."#8*7Jg/N' +=lEFp'tmapidI,7q81B!oh+(gQ7C[TjR9H(;dk!EQNUNmH7i-sOHu.9C:b0Z$E7fj +;Z;u:8r5$S`"uG.I*k[5p)H82s: +U +endstream endobj 22 0 obj [21 0 R 20 0 R 19 0 R] endobj 271 0 obj <> endobj xref +0 272 +0000000000 65535 f +0000000016 00000 n +0000000175 00000 n +0000058814 00000 n +0000000000 00000 f +0001930001 00000 n +0001930461 00000 n +0001930969 00000 n +0001931477 00000 n +0001932064 00000 n +0001770288 00000 n +0001770839 00000 n +0001771461 00000 n +0001771977 00000 n +0001495182 00000 n +0000066473 00000 n +0001564409 00000 n +0000066610 00000 n +0001612840 00000 n +0000065908 00000 n +0000065980 00000 n +0000066055 00000 n +0002088872 00000 n +0000058881 00000 n +0000058970 00000 n +0000059064 00000 n +0001772462 00000 n +0000059179 00000 n +0000059735 00000 n +0000060217 00000 n +0000060733 00000 n +0000061227 00000 n +0000061709 00000 n +0000062191 00000 n +0000062661 00000 n +0001624433 00000 n +0001629166 00000 n +0000254766 00000 n +0001766735 00000 n +0000254653 00000 n +0001630190 00000 n +0001640645 00000 n +0001629231 00000 n +0001618539 00000 n +0001623460 00000 n +0001623525 00000 n +0001613919 00000 n +0001616974 00000 n +0001618424 00000 n +0001618047 00000 n +0001617039 00000 n +0001607292 00000 n +0001611786 00000 n +0001611851 00000 n +0001601208 00000 n +0001606268 00000 n +0001606333 00000 n +0001558661 00000 n +0001563404 00000 n +0001563469 00000 n +0001491480 00000 n +0001494450 00000 n +0001494515 00000 n +0000063119 00000 n +0000064730 00000 n +0000064795 00000 n +0000065346 00000 n +0000065394 00000 n +0000066357 00000 n +0000066388 00000 n +0000066241 00000 n +0000066272 00000 n +0000066125 00000 n +0000066156 00000 n +0000239884 00000 n +0000239909 00000 n +0000066747 00000 n +0000066772 00000 n +0000071901 00000 n +0000080989 00000 n +0000081058 00000 n +0000081341 00000 n +0000082348 00000 n +0000240793 00000 n +0000241737 00000 n +0000241806 00000 n +0000242090 00000 n +0000242359 00000 n +0000254840 00000 n +0000255492 00000 n +0000258003 00000 n +0000264373 00000 n +0000329962 00000 n +0000395551 00000 n +0000461140 00000 n +0000526729 00000 n +0000592318 00000 n +0000657907 00000 n +0000723496 00000 n +0000789085 00000 n +0000854674 00000 n +0000920264 00000 n +0000985854 00000 n +0001032350 00000 n +0001097940 00000 n +0001163530 00000 n +0001229120 00000 n +0001294710 00000 n +0001360300 00000 n +0001425890 00000 n +0001495321 00000 n +0001495348 00000 n +0001497873 00000 n +0001501743 00000 n +0001501813 00000 n +0001502099 00000 n +0001502705 00000 n +0001564548 00000 n +0001564575 00000 n +0001566192 00000 n +0001568398 00000 n +0001568468 00000 n +0001568755 00000 n +0001569206 00000 n +0001612979 00000 n +0001613006 00000 n +0001613469 00000 n +0001613849 00000 n +0001618360 00000 n +0001766784 00000 n +0001765611 00000 n +0001769558 00000 n +0001897758 00000 n +0001900524 00000 n +0001901543 00000 n +0001901855 00000 n +0001902167 00000 n +0001900590 00000 n +0001874418 00000 n +0001877104 00000 n +0001897468 00000 n +0001897220 00000 n +0001896858 00000 n +0001896096 00000 n +0001878059 00000 n +0001880833 00000 n +0001882992 00000 n +0001886087 00000 n +0001877170 00000 n +0001803179 00000 n +0001808123 00000 n +0001809180 00000 n +0001808189 00000 n +0001797461 00000 n +0001802186 00000 n +0001802252 00000 n +0001773144 00000 n +0001776914 00000 n +0001796406 00000 n +0001795983 00000 n +0001797347 00000 n +0001778041 00000 n +0001778309 00000 n +0001778577 00000 n +0001778845 00000 n +0001779113 00000 n +0001779381 00000 n +0001779649 00000 n +0001779917 00000 n +0001780185 00000 n +0001787472 00000 n +0001776980 00000 n +0001797283 00000 n +0001797219 00000 n +0001797155 00000 n +0001797091 00000 n +0001797027 00000 n +0001796963 00000 n +0001796899 00000 n +0001796835 00000 n +0001796033 00000 n +0001796456 00000 n +0001873804 00000 n +0001896146 00000 n +0001896907 00000 n +0001897269 00000 n +0001897517 00000 n +0001929937 00000 n +0001929873 00000 n +0001929456 00000 n +0002077464 00000 n +0002088024 00000 n +0002088090 00000 n +0002074432 00000 n +0002075867 00000 n +0002077340 00000 n +0002076873 00000 n +0002075933 00000 n +0002071838 00000 n +0002073215 00000 n +0002074317 00000 n +0002073941 00000 n +0002073281 00000 n +0001937469 00000 n +0001941306 00000 n +0002071723 00000 n +0001942580 00000 n +0001942933 00000 n +0001943286 00000 n +0001943639 00000 n +0001943992 00000 n +0001944345 00000 n +0001941372 00000 n +0001932584 00000 n +0001935768 00000 n +0001937345 00000 n +0001936969 00000 n +0001935834 00000 n +0001937281 00000 n +0002066249 00000 n +0002041185 00000 n +0002069411 00000 n +0002066313 00000 n +0002059854 00000 n +0002063630 00000 n +0002059918 00000 n +0002054177 00000 n +0002057474 00000 n +0002054241 00000 n +0002048007 00000 n +0002051633 00000 n +0002048071 00000 n +0002039863 00000 n +0002043039 00000 n +0002039927 00000 n +0002041234 00000 n +0002042795 00000 n +0002043155 00000 n +0002043221 00000 n +0002043252 00000 n +0002043571 00000 n +0002045207 00000 n +0002043646 00000 n +0002045320 00000 n +0002045357 00000 n +0002049696 00000 n +0002051749 00000 n +0002051815 00000 n +0002051846 00000 n +0002052165 00000 n +0002052240 00000 n +0002055701 00000 n +0002057590 00000 n +0002057656 00000 n +0002057687 00000 n +0002058006 00000 n +0002058081 00000 n +0002061618 00000 n +0002063746 00000 n +0002063812 00000 n +0002063843 00000 n +0002064162 00000 n +0002064237 00000 n +0002067706 00000 n +0002069527 00000 n +0002069593 00000 n +0002069624 00000 n +0002069943 00000 n +0002070018 00000 n +0002074253 00000 n +0002077276 00000 n +0002088911 00000 n +trailer +<]>> +startxref +2089113 +%%EOF diff --git "a/web-ui/docs/.vuepress/public/openEuler\347\241\254\344\273\266\345\205\274\345\256\271\346\200\247\346\265\213\350\257\225\345\267\245\345\205\267\344\275\277\347\224\250\346\214\207\345\215\227.pdf" "b/web-ui/docs/.vuepress/public/openEuler\347\241\254\344\273\266\345\205\274\345\256\271\346\200\247\346\265\213\350\257\225\345\267\245\345\205\267\344\275\277\347\224\250\346\214\207\345\215\227.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..04dedede51b8d708d32b695c817b7419cd3ce49e Binary files /dev/null and "b/web-ui/docs/.vuepress/public/openEuler\347\241\254\344\273\266\345\205\274\345\256\271\346\200\247\346\265\213\350\257\225\345\267\245\345\205\267\344\275\277\347\224\250\346\214\207\345\215\227.pdf" differ diff --git a/web-ui/docs/.vuepress/public/openeuler-logo.png b/web-ui/docs/.vuepress/public/openeuler-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..06e8b4f2916131cc5de5f72075635269123ff1c0 Binary files /dev/null and b/web-ui/docs/.vuepress/public/openeuler-logo.png differ diff --git a/web-ui/docs/.vuepress/public/openeuler-trail-chess-en.pdf b/web-ui/docs/.vuepress/public/openeuler-trail-chess-en.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b2462385bf52581cc9bf613ede5c752a54fff0fb Binary files /dev/null and b/web-ui/docs/.vuepress/public/openeuler-trail-chess-en.pdf differ diff --git a/web-ui/docs/.vuepress/public/openeuler-trail-chess.pdf b/web-ui/docs/.vuepress/public/openeuler-trail-chess.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d0562e00ddef41f6be47756d85b62b631fac3c50 Binary files /dev/null and b/web-ui/docs/.vuepress/public/openeuler-trail-chess.pdf differ diff --git a/web-ui/docs/.vuepress/public/os_list_imagingutility_openeuler.json b/web-ui/docs/.vuepress/public/os_list_imagingutility_openeuler.json new file mode 100644 index 0000000000000000000000000000000000000000..6273a0d8f5d29627e6fe848f3c4654a2d5e6fabc --- /dev/null +++ b/web-ui/docs/.vuepress/public/os_list_imagingutility_openeuler.json @@ -0,0 +1,26 @@ +{ + "os_list": [ + { + "name": "openEuler 21.03 (Raspberry Pi 3/4/400)", + "description": "64-bit server OS for arm64 architectures (Linux Kernel 5.10)", + "url": "https://repo.openeuler.org/openEuler-21.03/raspi_img/openEuler-21.03-raspi-aarch64.img.xz", + "icon": "https://openeuler.org/Raspberry_Pi_OS_openEuler.png", + "extract_size": 2346713088, + "extract_sha256": "58712d218b7320901faf1b41b448a1be21b9cc5dd450205c33fcc0c8c780db40", + "image_download_size": 248386916, + "release_date": "2021-04-01", + "image_download_sha256": "0b157cc68dc6c1687da30c1f9731f475951bdf0c5da08dd5cb24e575b59c166b" + }, + { + "name": "openEuler 20.03 LTS SP2 (Raspberry Pi 3/4/400)", + "description": "64-bit server OS for arm64 architectures (Linux kernel 4.19)", + "url": "https://repo.openeuler.org/openEuler-20.03-LTS-SP2/raspi_img/openEuler-20.03-LTS-SP2-raspi-aarch64.img.xz", + "icon": "https://openeuler.org/Raspberry_Pi_OS_openEuler.png", + "extract_size": 2652897280, + "extract_sha256": "2f469da6365bd6025f1559557645bd4ddbf142f23a1a16370cf8862b1b6d9c5c", + "image_download_size": 276996588, + "release_date": "2021-07-14", + "image_download_sha256": "5f6a595a46cd8486d31e10bad35810985ddabf170c9ed947f7cfcb6062580063" + } + ] +} diff --git a/web-ui/docs/.vuepress/public/qrcode.png b/web-ui/docs/.vuepress/public/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..ea524b978506fb77676aee485d468f2af3abd51a Binary files /dev/null and b/web-ui/docs/.vuepress/public/qrcode.png differ diff --git a/web-ui/docs/.vuepress/public/robots.txt b/web-ui/docs/.vuepress/public/robots.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ca8588f3a94d0c72fdee1bb1e1cca452825af3e --- /dev/null +++ b/web-ui/docs/.vuepress/public/robots.txt @@ -0,0 +1,3 @@ +Sitemap: https://openeuler.org/sitemap.xml + +User-agent: * \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/search.png b/web-ui/docs/.vuepress/public/search.png new file mode 100644 index 0000000000000000000000000000000000000000..11ee04ea7e4fa8872035b5b1451e3f8e06954f9b Binary files /dev/null and b/web-ui/docs/.vuepress/public/search.png differ diff --git a/web-ui/docs/.vuepress/public/style/base.css b/web-ui/docs/.vuepress/public/style/base.css new file mode 100644 index 0000000000000000000000000000000000000000..2a72f13debda3c3747d494b31cad0b952d5a23b3 --- /dev/null +++ b/web-ui/docs/.vuepress/public/style/base.css @@ -0,0 +1,191 @@ +/* CSS Document */ +/*css reset*/ +html { + box-sizing: border-box; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6, +pre, +form, +fieldset, +input, +textarea, +p, +blockquote, +th, +td { + margin: 0; + padding: 0; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +fieldest, +img { + border: 0; +} + +address, +caption, +cite, +code, +dfn, +em, +strong, +th, +var { + font-style: normal; + font-weight: normal; +} + +ol, +ul { + list-style: none; +} + +caption, +th { + text-align: left; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: normal; +} + +p:before, +q:after { + content: ""; +} + +abbr, +acronym { + border: 0; +} + +/*定位*/ +.tl { + text-align: left; +} + +.tc { + text-align: center; +} + +.tr { + text-align: right; +} + +.bc { + margin-left: auto; + margin-right: auto; +} + +.fl { + float: left; +} + +.fr { + float: right; +} + +.cb { + clear: both; +} + +.cl { + clear: left; +} + +.cr { + clear: right; +} + +.clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.clearfix { + display: inline-block; +} + +.fade-in { + opacity: 0; + transition: 0.8s all ease-out; + transform: scale(0.8); +} +#hm_t_undefined { + display: none; +} +@font-face { + font-family: 'icomoon'; + src: url('../fonts/icomoon.eot?4mtq8t'); + src: url('../fonts/icomoon.eot?4mtq8t#iefix') format('embedded-opentype'), + url('../fonts/icomoon.ttf?4mtq8t') format('truetype'), + url('../fonts/icomoon.woff?4mtq8t') format('woff'), + url('../fonts/icomoon.svg?4mtq8t#icomoon') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; + } + + [class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'icomoon' !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + .icon-menu:before { + content: "\e900"; + } + + .icon-arrow:before { + content: "\e901"; + } + + .icon-search:before { + content: "\e902"; + } + + body { + font-family: Helvetica Neue,Helvetica,Arial,PingFang SC,Hiragino Sans GB,STHeiti,Microsoft YaHei,Microsoft JhengHei,SimSun,sans-serif; + } \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/style/markdown.less b/web-ui/docs/.vuepress/public/style/markdown.less new file mode 100644 index 0000000000000000000000000000000000000000..14e397ebe631e91237475d65b2180ca4cc72e989 --- /dev/null +++ b/web-ui/docs/.vuepress/public/style/markdown.less @@ -0,0 +1,174 @@ +.lang-en { + .other.markdown { + p { + font-weight: 400; + } + } +} +.other.markdown { + p { + line-height: 32px; + font-weight: normal; + margin-top: 20px; + } + li { + margin-top: 20px; + } + li p { + font-size: 16px; + } +} +.markdown { + [id]::before { + content: ''; + display: block; + height: 60px; + margin-top: -60px; + visibility: hidden; + } + width: 1120px; + margin: 0 auto; + margin-bottom: 200px; + @media (max-width: 1000px) { + width: 100%; + padding: 0 30px; + margin-bottom: 80px; + margin-top: 40px; + } + div[class*="language-"]{ + margin-bottom: 16px; + background:rgba(225,230,238,0.3); + border:1px solid rgba(151,151,151,1); + border-radius: 0; + @media (max-width: 1000px) { + margin-bottom: 8px; + } + pre{ + padding: 1em; + margin: .5em 0; + overflow: auto; + code{ + color:rgba(0,0,0,0.5); + } + } + } + h2 { + line-height: 24px; + font-size: 24px; + margin: 40px 0 20px; + + @media (max-width: 1000px) { + font-size: 18px; + line-height: 18px; + + margin: 30px 0 20px; + } + } + h3 { + line-height: 20px; + font-size: 20px; + margin: 30px 0 20px; + + @media (max-width: 1000px) { + font-size: 16px; + line-height: 16px; + + margin: 30px 0 20px; + } + } + h4 { + line-height: 18px; + font-size: 18px; + margin: 30px 0 20px; + + @media (max-width: 1000px) { + font-size: 15px; + line-height: 15px; + + margin: 30px 0 20px; + } + } + h5 { + line-height: 16px; + font-size: 16px; + margin: 30px 0 20px; + + @media (max-width: 1000px) { + font-size: 14px; + line-height: 14px; + + margin: 30px 0 20px; + } + } + p, ul li, ol li { + font-size: 14px; + color: rgba(0, 0, 0, .5); + line-height: 24px; + + letter-spacing: 0.8px; + @media (max-width: 1000px) { + line-height: 30px; + } + a { + color: #002fa7; + text-decoration: none; + cursor: pointer; + } + b{ + color: rgba(0, 0, 0, 1); + } + } + a[href^='#'] { + display: none; + } + .icon.outbound { + display: none; + } + a,li,p{ + @media (max-width: 1000px) { + word-break:break-all; + word-wrap:break-word; + } + } + table { + width: 100%; + font-size: 14px; + table-layout: fixed; + word-break: break-word; + tr { + height: 60px; + color: rgba(0, 0, 0, .5); + @media (max-width: 1000px) { + height: 52px; + } + th { + background-color: #f2f2f2; + color: #000; + } + th, td { + padding-left: 30px; + @media (max-width: 1000px) { + padding-left: 10px; + } + } + } + tr:nth-child(even) { + th, td { + background-color: #f2f2f2; + } + } + } + ul, ol { + list-style: initial; + padding-left: 30px; + } + ol { + list-style: decimal; + } + strong { + font-weight: bold; + } + img { + max-width: 100%; + } +} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.ttf b/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..91b74de36778b0ff8958d37d07ce70fb3b26f50b Binary files /dev/null and b/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.ttf differ diff --git a/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.woff b/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..02b9a2539e425a7a8c244faba92527602be76212 Binary files /dev/null and b/web-ui/docs/.vuepress/public/style/theme/fonts/element-icons.woff differ diff --git a/web-ui/docs/.vuepress/public/style/theme/index.css b/web-ui/docs/.vuepress/public/style/theme/index.css new file mode 100644 index 0000000000000000000000000000000000000000..6b3ad7d47edf6e18086c82d104e440f861e3afa0 --- /dev/null +++ b/web-ui/docs/.vuepress/public/style/theme/index.css @@ -0,0 +1 @@ +@charset "UTF-8";.el-pagination--small .arrow.disabled,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*,.el-table--hidden{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format("woff"),url(fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#002FA7}.el-pagination button:disabled{color:#3F3F3F;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#3F3F3F;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#002FA7}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#3F3F3F}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#002FA7}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#002FA7;color:#FFF}.el-dialog,.el-pager li{background:#FFF;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-date-table,.el-table th{-webkit-user-select:none;-moz-user-select:none}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#3F3F3F}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#002FA7}.el-pager li.active{color:#002FA7;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#002FA7}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(187,187,187,.5)}.el-dropdown .el-dropdown__caret-button:hover::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#e6eaf6;color:#3359b9}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #002FA7;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #002FA7;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #E4E7ED;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#e6eaf6}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#002FA7}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#e6eaf6}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#e6eaf6}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#002FA7}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#FFF;border:1px solid #BBB;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#002FA7}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #BBB;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#002FA7;border-color:#002FA7;-webkit-box-shadow:-1px 0 0 0 #002FA7;box-shadow:-1px 0 0 0 #002FA7}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#3F3F3F;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:5px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:5px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #002FA7;box-shadow:0 0 2px 2px #002FA7}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#002FA7}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #BBB;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#BBB;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#002FA7;background-color:#002FA7}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#002FA7;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#3F3F3F;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#002FA7;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#3F3F3F}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#002FA7}.el-select .el-input .el-select__caret{color:#3F3F3F;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#3F3F3F;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-select .el-input.is-focus .el-input__inner{border-color:#002FA7}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#3F3F3F;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#3F3F3F;right:-7px;top:0;color:#FFF}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#F5F7FA}.el-table th,.el-table tr{background-color:#FFF}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table--border td:first-child .cell,.el-table--border th:first-child .cell{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.is-sortable{cursor:pointer}.el-table th{overflow:hidden;-ms-user-select:none;user-select:none}.el-table th>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th>.cell.highlight{color:#002FA7}.el-table th.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border th.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#3F3F3F;top:5px}.el-table .sort-caret.descending{border-top-color:#3F3F3F;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#002FA7}.el-table .descending .sort-caret.descending{border-top-color:#002FA7}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td{background-color:#e6eaf6}.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#F5F7FA}.el-table__body tr.current-row>td{background-color:#e6eaf6}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#e6eaf6;color:#3359b9}.el-table-filter__list-item.is-active{background-color:#002FA7;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#002FA7}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#3F3F3F;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{padding:3px 0;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#3F3F3F}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#002FA7;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#002FA7}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#002FA7}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#002FA7}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#3F3F3F}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#002FA7;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#002FA7;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#3F3F3F}.el-month-table td.disabled .cell:hover{color:#3F3F3F}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#002FA7}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#002FA7}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#002FA7}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#002FA7;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#3F3F3F}.el-year-table td.disabled .cell:hover{color:#3F3F3F}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#002FA7}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#002FA7}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#002FA7;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#3F3F3F;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#3F3F3F}.el-date-editor .el-range-input::-ms-input-placeholder{color:#3F3F3F}.el-date-editor .el-range-input::placeholder{color:#3F3F3F}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#3F3F3F;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#002FA7}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#3F3F3F;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#3F3F3F;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#3F3F3F}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#3F3F3F}.el-range-editor.is-disabled input::placeholder{color:#3F3F3F}.el-range-editor.is-disabled .el-range-separator{color:#3F3F3F}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#002FA7}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#002FA7}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#002FA7}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#002FA7}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#3F3F3F;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-slider__button,.el-slider__button-wrapper{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#002FA7}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#002FA7}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#3F3F3F}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#002FA7;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:16px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#002FA7;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-collapse-item__arrow,.el-tabs__nav{-webkit-transition:-webkit-transform .3s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#002FA7}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #002FA7 inset;box-shadow:0 0 2px 2px #002FA7 inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#3F3F3F;color:#FFF}.el-tabs__item.is-active{color:#002FA7}.el-tabs__item:hover{color:#002FA7;cursor:pointer}.el-tabs__item.is-disabled{color:#3F3F3F;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#FFF;border:1px solid #BBB;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#002FA7;background-color:#FFF;border-right-color:#BBB;border-left-color:#BBB}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#002FA7}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#3F3F3F}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #BBB}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#002FA7}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#002FA7;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#F5F7FA}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#3F3F3F;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#3F3F3F}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#ebeef8}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#3F3F3F}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:30px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:42px;padding-right:42px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:32px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#002FA7}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#002FA7}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#3F3F3F;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #BBB}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #BBB}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:42px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:15px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #BBB}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #BBB;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-upload-cover::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{vertical-align:middle;display:inline-block}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#3F3F3F}.el-slider__runway.disabled .el-slider__button{border-color:#3F3F3F}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#002FA7;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;user-select:none;line-height:normal}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #002FA7;background-color:#FFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;user-select:none}.el-image-viewer__btn,.el-step__icon-inner{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#FFF;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #BBB;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#3F3F3F}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#002FA7}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#002FA7;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#002FA7;stroke-linecap:round}.el-loading-spinner i{color:#002FA7}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0%}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#002FA7;color:#002FA7}.el-upload:focus .el-upload-dragger{border-color:#002FA7}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#3F3F3F;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #BBB;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#002FA7;font-style:normal}.el-upload-dragger:hover{border-color:#002FA7}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #002FA7}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#002FA7}.el-upload-list__item:hover{background-color:#F5F7FA}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#002FA7;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#002FA7}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#002FA7;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner::after{height:100%}.el-progress-bar__innerText{color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#3F3F3F;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#F56C6C;border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#002FA7}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border:1px solid #EBEEF5;background-color:#FFF;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#3F3F3F;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#3F3F3F;border-color:#3F3F3F}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#002FA7;border-color:#002FA7}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#3F3F3F}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#3F3F3F}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#002FA7}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#3F3F3F}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#002FA7}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#3F3F3F}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#3F3F3F;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#002FA7}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:#e6eaf6;border-color:#ccd5ed;display:inline-block;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#002FA7;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#002FA7}.el-tag .el-tag__close{color:#002fa7}.el-tag .el-tag__close:hover{color:#FFF;background-color:#002fa7}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#002fa7;border-color:#002fa7;color:#fff}.el-tag--dark.is-hit{border-color:#002FA7}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:#3359b9}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#99acdc;color:#002fa7}.el-tag--plain.is-hit{border-color:#002FA7}.el-tag--plain .el-tag__close{color:#002fa7}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#002fa7}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:32px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#3F3F3F}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#002FA7}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#3F3F3F}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#3F3F3F;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#002FA7;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#3F3F3F}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#3F3F3F}.el-cascader__search-input::-ms-input-placeholder{color:#3F3F3F}.el-cascader__search-input::placeholder{color:#3F3F3F}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #002FA7;box-shadow:0 0 3px 2px #002FA7}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#002FA7;border-color:#002FA7}.el-color-dropdown__link-btn{cursor:pointer;color:#002FA7;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#002FA7,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;background-image:none;border:1px solid #BBB;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#3F3F3F}.el-textarea__inner::-ms-input-placeholder{color:#3F3F3F}.el-textarea__inner::placeholder{color:#3F3F3F}.el-textarea__inner:hover{border-color:#3F3F3F}.el-textarea__inner:focus{outline:0;border-color:#002FA7}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#3F3F3F;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#3F3F3F}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#3F3F3F}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#3F3F3F}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#3F3F3F;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;background-image:none;border-radius:4px;border:1px solid #BBB;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:32px;line-height:32px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#3F3F3F;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#3F3F3F}.el-input__inner::-ms-input-placeholder{color:#3F3F3F}.el-input__inner::placeholder{color:#3F3F3F}.el-input__inner:hover{border-color:#3F3F3F}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#002FA7;outline:0}.el-input__suffix{right:5px;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:32px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#3F3F3F;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#3F3F3F}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#3F3F3F}.el-input.is-disabled .el-input__inner::placeholder{color:#3F3F3F}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #BBB;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;background-color:#002FA7;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #BBB;background-color:#F5F7FA;color:#3F3F3F}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#002FA7}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-divider__text,.el-link{font-weight:500;font-size:14px}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-aside,.el-header{-webkit-box-sizing:border-box}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;box-sizing:border-box;padding:20px}.el-footer{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#002FA7}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0}.el-link.is-underline:hover:after{content:"";position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #002FA7}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#002FA7}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#002FA7}.el-link.el-link--default.is-disabled{color:#3F3F3F}.el-link.el-link--primary{color:#002FA7}.el-link.el-link--primary:hover{color:#3359b9}.el-link.el-link--primary.is-disabled{color:#8097d3}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#BBB;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;color:#303133}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#3F3F3F;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;user-select:none}.el-button,.el-checkbox{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:40px}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{top:50%;width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #BBB;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#002FA7;border-color:#b3c1e5;background-color:#e6eaf6}.el-button:active{color:#002a96;border-color:#002a96;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#002FA7;color:#002FA7}.el-button.is-active,.el-button.is-plain:active{color:#002a96;border-color:#002a96}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#3F3F3F;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#3F3F3F}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#002FA7;border-color:#002FA7}.el-button--primary:focus,.el-button--primary:hover{background:#3359b9;border-color:#3359b9;color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:#002a96;border-color:#002a96;color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:#8097d3;border-color:#8097d3}.el-button--primary.is-plain{color:#002FA7;background:#e6eaf6;border-color:#99acdc}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#002FA7;border-color:#002FA7;color:#FFF}.el-button--primary.is-plain:active{background:#002a96;border-color:#002a96;color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#6682ca;background-color:#e6eaf6;border-color:#ccd5ed}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:5px 15px}.el-button--mini.is-circle{padding:5px}.el-button--text{color:#002FA7;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#3359b9;border-color:transparent;background-color:transparent}.el-button--text:active{color:#002a96;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table;content:""}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-button.is-active,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#3F3F3F}.el-backtop,.el-calendar-table td.is-today{color:#002FA7}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{content:"";position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#BBB}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox-button__inner,.el-radio{font-weight:500;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #BBB;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#002FA7}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#BBB;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#3F3F3F}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#BBB}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#3F3F3F}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#BBB}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#3F3F3F;border-color:#3F3F3F}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#002FA7;border-color:#002FA7}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#3F3F3F;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#002FA7}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#002FA7}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #BBB;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#002FA7}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #BBB;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#002FA7}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-radio,.el-radio__input{line-height:1;outline:0;white-space:nowrap}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#002FA7;border-color:#002FA7;-webkit-box-shadow:-1px 0 0 0 #6682ca;box-shadow:-1px 0 0 0 #6682ca}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#002FA7}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#3F3F3F;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #BBB;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#002FA7}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:5px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:5px 15px}.el-checkbox-group{font-size:0}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio{color:#606266;cursor:pointer;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #BBB;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#002FA7}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#3F3F3F}.el-radio__input.is-disabled+span.el-radio__label{color:#3F3F3F;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#002FA7;background:#002FA7}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#002FA7}.el-radio__input.is-focus .el-radio__inner{border-color:#002FA7}.el-radio__inner{border:1px solid #BBB;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#002FA7}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #002FA7;box-shadow:0 0 2px 2px #002FA7}.el-radio__label{font-size:14px;padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;-webkit-box-sizing:border-box;box-sizing:border-box}.el-avatar,.el-drawer{-webkit-box-sizing:border-box;overflow:hidden}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#3F3F3F}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#002FA7;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#3F3F3F;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;box-sizing:border-box;text-align:center;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-drawer,.el-drawer__header{display:-webkit-box;display:-ms-flexbox}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}.el-drawer.btt,.el-drawer.ttb,.el-drawer__container{left:0;right:0;width:100%}.el-drawer.ltr,.el-drawer.rtl,.el-drawer__container{top:0;bottom:0;height:100%}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__body>*{-webkit-box-sizing:border-box;box-sizing:border-box}.el-drawer__container{position:relative}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-popconfirm__main{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0} \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/submenu-arrow.svg b/web-ui/docs/.vuepress/public/submenu-arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..b1e041263a5c55d307ffdcee5626eb1b503ac899 --- /dev/null +++ b/web-ui/docs/.vuepress/public/submenu-arrow.svg @@ -0,0 +1,28 @@ + + + 编组 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_guoxiaoqi.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_guoxiaoqi.asc new file mode 100644 index 0000000000000000000000000000000000000000..3805ace0f543e9a4e884050ff98cec465ae1f425 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_guoxiaoqi.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBF/ESXcBDAC7wpY4oZGmfdnSC6NT7tgah9rAmaZA8DuDucTSj/BjGlWdeOCz +/akk+VzmO7hYwjbXwrUilH/wryOnKTmqfhEkMzGSJcEc2HA0OYTDQ2njd9VCY5+k +uXnKKjvczrch9VUSvT5xvimU261KaY0Xwea2SYVZXa2zcVrRhUbGcoPg5r+bBME1 +77V9L8ez4dfKHB6H1rzvWrJPzdCqBo0qSRT9efqd7OLxL1MR6itv/+KDoVQxRicP +P4Mn58mI8ZuvccExqATMuClb/+Dh4+eqFnLzaEbLyoylaLBMxcthfg6nZXqjX/Zq +hWwP5ejvZEhyOJy+g3rspJP2S0HWI19sxy8PF2FGtvlfZHFtz700kzl18yzgmR49 +7aG4rsoIfPp4oLij78LW5HTHahELvbIGqcovsR45tap6yIyt7vlQ69RKkYmyNpne +mSmNmYbAMPEHoxtfW1VXmJ36+u5FD39lAQUzDu1sKDLMRENck4cBjjpABfDoxnKi +1AvyJBhDlcisgiUAEQEAAbQhZ3VveGlhb3FpIDxndW94aWFvcWkyQGh1YXdlaS5j +b20+iQHUBBMBCAA+FiEEXhZaOr+8PByaVN9srmhLU7+tgQ0FAl/ESXcCGwMFCQPC +i8kFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQrmhLU7+tgQ1pIQv/fmHVLZRw +6xq8IEVKuh3e2Hq5xyynFaES/sLhcbTOPAWqOa8caTyFQ6EAm42wcJVkvsz9fSN7 +t+ZqoxnpEhtAznel4bqltwzMxXUz2hDZfZ+Jr2Of012uinRJ3CaJj5Ye5CksYOID +qjJWmrn6Qe1iUzmElAXN5P+tKH8zEJ/nWleYZxfNYZCtxnup4aMD3tKnv2TBMhOt +gr6UoXj4LPyf1nCPNyKlIOdpfYfZh5Fr7IKdm4nEjygwJP2KIsVFqR3kMvKj1p14 +MIfHb/OChZHyV2miZbUuC2wGDPrW7a/w7/L2OpBYyF6ZeQQ1CCazwWkZovp3TFCB +R6mP3ZtK4tuxNknO2XcLN0zRgZFWmZbRxkUhNOg6a3VUz+lts20O3kZYqdnsb3+M +aGsvtohhJeC6qHNB28iOFzozrtsqqAgewmR5VdASLvAM8N8U7WSh/2YyM+rdTBF1 +F00g/3pLHW3qfnbSoAbG5dbVdCHXqSRfKh1eTA2+KGVNWyHOcDLaGyaVuQGNBF/E +SXcBDACn2qB9++2FTSjc5mYYWxtmXkmpUfuNN+An42jmIt/PUG5+CaDes43wr03/ +Oa3/gL8kH0uolMgXkNfUMpH3T7gLlR4kQxbzkPqXDy5UIbNH3L9czv2IMK4i5uzM +QIG6ydtZvlhVEocnDKFkYS9PxzR5J8jAgFq8I6NWF6DNpxx1u9W8nEKZHLGktWoJ +WGsQNic0fdANJ3dP7d/i6Itr1+2XHIiSwNwWAtmxqge5m7bR3byN59DMBazmtB/d +BUtzVcn9qNp251ja5BD/LpkZw7M9PXK6ILAEfkOfqSyFVTSo3xwMm4CIBxZnfGue +VJpkD8nRiOb7S3uMpCyXZEgA1qESW1Ul9FxvrtUbHfiC1IcQWj0Pn5QnDx0vMe3K +CLKkLoZkFNh0C6jEYNj7o9msnwsbkesb6k5+2Nvn+0udMIKj64LGdGhEmDvSLUCx +bybo8FVZ60vHxLFnQDSAXANutgxnnzE/fpyc3TYFZoGvZrg6eYPZGF6TbtZMCF2y +bTJo7WEAEQEAAYkBvAQYAQgAJhYhBF4WWjq/vDwcmlTfbK5oS1O/rYENBQJfxEl3 +AhsMBQkDwovJAAoJEK5oS1O/rYENoY0MAK3nEXi+kUJx2GPsSZA8AJt8YNQ6I6tP +yR08Z80Q42AyfOOHVX4lFWdskOQB70+2YgT33As2RfOE9Mrhx0C/EHtqinZBY6fW +ttbgZE+pU1c18eSHFM8xNs8Y7ZP5bOWQyzBq5ClqXhOL4eWpZjfjrvssffHoS+T5 ++eaRT9YyUu/g274UeYARoCgL0rsp5L05RveIdSgYGGFmb5kKxfsWapoVH9BdkUQ1 +kzM1lcNz0eyH7dgmPezrfkWjZB5jDWpH8p93tYnES/q4ppeGO/guYyySIS/Mg+Pu +usAWw2aPhY9s8zh+u+KraV9AerBYYQU46jvw8v6roQ4SVdlSgCebNhtLGclvMiak +cfiPlETyFd/e7pMsO/vRZTek5w+DmW8elsOpc3Fzqkn1p3tlAZll40ZnF1YTnKM8 +oCtUYeQhI7lPcrxqVlhIMdI0zb4QzujCd8AktPZdrbKNjMUwQO2O4Q8urr+9+STr +CWyNnzgOurcoA1BFPsIM5YhepDJ4meVorw== +=dd9c +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_liujingang.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_liujingang.asc new file mode 100644 index 0000000000000000000000000000000000000000..919fec664196e05549deff46a8496568dd82ce53 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_liujingang.asc @@ -0,0 +1,55 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: Keybase OpenPGP v1.0.0 +Comment: https://keybase.io/crypto + +xsBNBF5xhD4BCADDQ/2a6Q9Fy3jLP45kBEp74ckr390toKLwJTvtHP159ihOzedT +OWgRtaKfTabrrO/A9nqwRLr6743j0h62X9x7jlPO9TZ6yXYEebS/RMNjm7+GhGUB +cu6SM0J2owUO9zv64d9IuS8q9j+rre58OA2cMcQ0do82q7QBmgv3AqOFWBmdFM3n +CG17tsAAGw+pM5G3c5wtMkYAjgv4KbBkw7snPFukxK3/Mb6raA5XTDiCoVLBGloO +Yk+eaaNOLWHg2rp2Z9buWGLSZzbTWF2kflHl7+Fs6WgdKjsj9ovBGDEc+QzFJTTW +TDEqXEJZY7VRL8kSpjEvkQjlxbs8pc5vZQZZABEBAAHNJExpdWppbmdhbmcgPGxp +dWppbmdhbmcwOUBodWF3ZWkuY29tPsLAbQQTAQoAFwUCXnGEPgIbLwMLCQcDFQoI +Ah4BAheAAAoJEE1VlxMQXuvDLFEH/2AeSiIImykVVRHZ91xcVjwCGPujGd7JHRm5 +tCJXTAHJ2dXlcRUP5jURZ8pOJKPuvrQy+QoxfqQUuGrlftwOQ36uVu4TJspCWdDJ +MwLmfw1fT+RiM23oAK0Y6XrIxofbVhzHlZLM2265M7skZUNt+VorWXSfURpG1IV0 +7Kp/BfjnLIbzJjX9fh8/Ah3DwKxGom9G1BOfE4o11wEKXqwxf9Z2rfvRMMpD8c4X +a9Gbxu+SR5QAb1zkVBLr7aDirD8kRdEprvzANDkJiRSw4EhTGrAiwnoNFgsC/Pm1 +qpjRI+S9n2E9kJnV3TC6aFTKLI63koXJNgRd9+f7Hpxk1khQi3nOwE0EXnGEPgEI +AK7GrwRmgVo8tS2W+tXMctkuHL/M46e/nTXXkNV367pbp5gZSNRsHh9wU36wfBdV +T1c5+dvOAlNub5ErZTDEsqlVHV+nSQHPC5ogNl23jBAkvO0t55Lze6n4boZOi5Ri +ob8tquKBZX1EJ1j7I38CIelvzyoDZ95vriXObkpI+JDsb1i9zwUpXQSRGM/N0d3z +sygTDU6p5MuegiIyTyQ1IDN6YQwmuaS6wk12mbUxtNSmJian/nHCC+t/EUkkMve6 +ANnJ0XUUb8JwYZqPh4iIs/EqaTu3g292AMaWTnXwe+xMG9xl0aB4HhEJ7dDFf+Bg +4ltA+PdN7csPma2S4oMEs/cAEQEAAcLBhAQYAQoADwUCXnGEPgUJDwmcAAIbLgEp +CRBNVZcTEF7rw8BdIAQZAQoABgUCXnGEPgAKCRDLPG8ya5Og+4CzB/0TduA6HMx2 +kkad8xfrT0UMJTylM3NfNgY8oD6Q6zzVrdH8hVCWywrf87lhL/CDl4xw3nry6bBx +7LjG3WBueD4+InFh1Su2W2qBTzZKDuV2+IyxYp+zfUgLyjID3IHTJHPIXbneTUMp +i/cfXVUdafO0B46AO1UTrP+gPJL3BX39gMDMYNbrkEgBUPY9srAKn0niXSODoUjZ +efqVXSTXguQnEDoDhTbsOi9b9+9nKllVNNfrI6g5u5FREM8HIwOXaMJrLTZvoJQG +jUdiWzQeFBT2rs/+bm8QlVU+6ZhWmLXZG40xiw1vw1t3QWRj+zoKhkHDPrgBLt+F +Y35zrl7C61aH5BwIAKposmd79zDxrBN/0fNjCL4Rm5EhI4NS6gGu0hPQMIUGeVjv +kYDhw3bx4fw/PAoaqjpDWrdcHhUf4cl+48XGMrJJGC1DB/Q3JBxrR6vY6HPZ8x9Z +3rfyiVhT4B0X60GV1gxMlw0kPozPCgvYHZEgTg8ymGGn4QcU69DT6heJWss0kY3n +MEb9Vl6nvn8H1SpIPV8A7FlKZILlMVjKDt8vDG7KlveZ6eOp4h+OGSWp+dAqoS1U +5YKYB53/5pVa/SkV5JSZ6JV2hsUGLK5KRqcFs8tgH6VC8lyeCykVpDFnI4Gw14vT +zBWkwoSCRZ393WGnVbnKbOTSPSAAoQCeRxKIdaPOwE0EXnGEPgEIAM/27CDwVHHd +4WZ64a87H5TAQzBfzwb2eVacG1vvVj1YU/cg5Z4P6GGAMTQesZnM7SVuLvzJZDGr +3pdYa8dRV+2XpT6RVCdloTxu6z8JI+kTMM3LpL2kfVE/i/3eUhjDrkBTKWc97miH +q8pivK1nkXnOdzUdx8NSY22LuqZuGufWyHUuVxqdOvB5/uzm9WL2UNuvjoRk8fsH +sTymdcVbq2dnZbcyS8euxYUo+ycwvgatl3CEWN8usrGTXRW/f84b2YvSZAX8fGBB +vgENzNAuiVNrl/BLQndCYBXcPdy9H5L5rMe1FUEEi9fL6kX091vXIkBgrzFGPuXu +YkxphS8ojj8AEQEAAcLBhAQYAQoADwUCXnGEPgUJDwmcAAIbLgEpCRBNVZcTEF7r +w8BdIAQZAQoABgUCXnGEPgAKCRDuuWUBGxedpwgaB/9OL0KbMY7EWg8GCukkuzIf +dXH3rQMwV7x2XIjWYN5XB211SjTgl4yHwu05aey9xYZn3Wk205Rzzrli8oI80pKB +AXssZD+Wxe9MuxwLnQ/VN4om7FeYWc+z4FC9hQt8TyfHq7ELDKLQNLS/Ag9jfRrX +8FYxcRzs1oOzcqGxC19NLNC1rgEDHSWSLhGidviscRR+E2wb4aY6PogFqrb3kTWL +iXTWZQS6b0j5etfOLCq77b9g5THrFljz6VEznt/dNqdPTwoBBMToqWCvTcuK8MVK +T3nMy6pWvimwzJB7v+2ZAwk7QbKMKOMnhcCakH+mGVMfelyynCDidue05CPGw9w6 +XHoH/ibZVFM1ZlKG+dMyHZRTActO54B/SBsPDa2EiEF1Q0G1VVmnY8T8x5P5Z6CX +/o5jMHF/XlUHYVQ4/1jOPzG9xjzXjhDmLXSvwOZgJH5v2ymnffKJkRv7pTjVraYV +0knoEjWwN7NMAp2cgECWmT7l8hJdQ6hi/NH9BMF9IK2to15Nm2Fra/xp5a8S3CeV +yU6Nnjxm8PBaDCsNQJe41PtqRoDhG87Ht7GP3nlwOgCTnzshh5v2Lnv3rKmLazrH +Y53xKMkf4cYA1Bq8cUulwGGQ4yaivFSn+lS7MzHyl9ugyESdUa66hWdTQ2MDbW2N +NauofdI761JMh8XGnOWVOyqeeFA= +=Kjb+ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_openeuler_security.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_openeuler_security.asc new file mode 100644 index 0000000000000000000000000000000000000000..97a0d9bf1c13f9f334ccd3cd2c7b94f094870967 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_openeuler_security.asc @@ -0,0 +1,55 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: Keybase OpenPGP v1.0.0 +Comment: https://keybase.io/crypto + +xsBNBF/EUBgBCADIotctW6ggGfmJaYg4td3+gMFNlNLMNT0Q6xxk0siLlrnjX1zK +q3H6F+/MRCVnzZymSt0q3Bgdn4djtcHmzmZaaCv0EH/d0B4Xhtb+jwfUOVy3buM/ +W+C3HS4lnaHAAa1r7JCIgpnvCEC+7l7VEGGPOleL9QByHdLbLcbNxW95VbZOZQ0M +RC1tOCInSPdW5IWGhkEghke21mx9KPMMuiPngW5drhKCHL3Uf8w+4qOcnouAQecO +zMnlOKIjvUEkZ06Cq8r9fKkvfC/YaM8RhpGex3L8OZrMYvphSa1b8k7kfCAaABLl +Alv/ERTfvd5h+eQsV39rJaFZ+rcWYzwtMCxPABEBAAHNNW9wZW5ldWxlci1zZWN1 +cml0eSA8b3BlbmV1bGVyLXNlY3VyaXR5QG9wZW5ldWxlci5vcmc+wsBtBBMBCgAX +BQJfxFAYAhsvAwsJBwMVCggCHgECF4AACgkQzk1FIbnp2ymLnggAlyLd6MFpTsVl +eQpUjdN88dgUcHc5THc1+YWQpZpk2GDTQEyj3DjqR5v1QjKmgFXe8CazIpx91fLV +BmXhZgg7F5I8+JzB75gyuGMbv1XnOQY2+R0+cG4ixQwHY9wjjpAnW3mBicQnJ/YX +jpIcN3N9AKZ6XCSYeGfJODMQ2MV+GmB4mpgbKeGBzBMu4v0dkJ+UNEZVUerVMIsm +WouWa3+3i6uYsjyWmDZnirGq4LPCwmkFi3jX6k1l4pk+eM44/Q+JknqMIYyfI92I +/3y29xnfpJTLNFnqi58vSPJlSbzj97sVh95iKU+IfGj8nCK85FP4ot7ifmLAaedq +naRjfsNsZc7ATQRfxFAYAQgAtLdTt990EyDMsau1sg0XIa3OAlICxFtSXhAhF1hm +VLRHXZwyLeJ4UUrPlSUGasvkGSXu5nkvEIQiwMmGmuvBuEAwcCJsZTXBzHW/4RL/ +2Wzjvd8DoLOPfsQvKoW7DX281XxKEHFQpq+MfexHaaY4xfxcf+vFhZVFliyXTvjg +EOqtVqYmgMtN3Cq5WYP+2/NRuwt7zNWfpPucNNR38eCZ+hb0Qt0bcZ/dlXiFgd1Y +P1j1vlldFCNfYPuP90uHjUNhcC80ph0a52ksK+XCbwlrWRHXEu0ZeQJipzJftg9B +lakpc/c+hgK+w7cA2asLXKflBT6uJwxTQJkDGPglSOguRQARAQABwsGEBBgBCgAP +BQJfxFAYBQkPCZwAAhsuASkJEM5NRSG56dspwF0gBBkBCgAGBQJfxFAYAAoJEPpF +ntMnKa9qnvoH/2U1f9exNAQws7pLUtm068Ul5XznVH2AsJTwYA9vAQungdvQOD2B +fjYahmxwiP9TCZXkkHVn1l036zsf6Fz6Er9EUi13kB9uJUSzxOCG9d57LBA+uv6U +fZRLjpbherVjCGbdDHskV7x+6GXzmCkwvcAkVGxNR7wee1dOYaTctyj0sNZx5fOM +Vf/OPWh8Ydx26YKczCExNNjEy6LaBHafjscHUz85aWtsQlQsG+fTSqWdo1o0+FtF +9hHgSDbAP78jMe5k1TBJGVU2M0t389cCp4CCZXBH6Dk2KMSbj5oS9BI6R4SLwdl+ +fFsMUYVHEIacYHgdJjV4zNte+3OYz5CWsSllJwf+LgqyzPHy1rTbrisKro1jHRbc +WHGl/4wAriPThzFYsGb1EYVYOPsCRlGhGADzdLoh/9FQRCUYrkTJlX36O/cCW8UQ +QjXkDzb+sLcwHdtISdgb+Xh2qg/irn7NYGyzOuxXRJ4vQMNWgsqUumCkEiR1Rg4b +ieBzP1d7MIIjJ7oIb12IMLTNm479GgJnZlR8y87lWrE0LQAdxJamMDWGBkQBqSKM +orsZxOhKIDPBm6ddhy6OViy2YAN8rPY/xTWK4mmfFhhl3JJJtcKfxIPgp35sFHUV +enYfqcncSD+++zg5tm6MOD5Ibey/hZ6wCb+YiRafv09tCZ0Qi4wrZtcEz4+rgs7A +TQRfxFAYAQgAz85zznqVzPBmDToLzwk9nMR4bys4ME4QkNuvXovIpZhzgQ7qaTsC +s1mjUcoChX6jCmz0Z39PLgSrMFSMyjdPmVNP97cGyxPmlWqMbOfVfTwYOrT10V0o +0aHwbwLtSTxwCSfmTiphTvPh2oNrfH1MckYlEuYV5KETV7/MPmDstNqBYcB8yiHB +1y+PcotqeImcGxrL/+0Qf93aw1ysjmGEUaiG6Vx+PTAPaAQQoN0FTofZ137BapUc +cmp1t8dZTq8XkobJk39QWt5ohvnBPhZOCei+cEJoUA/doWQWaAdtYkWB2rJ4HuYt +wJef+5NvjY0SR3AOb8ljkk/5EZS3Uf1nAQARAQABwsGEBBgBCgAPBQJfxFAYBQkP +CZwAAhsuASkJEM5NRSG56dspwF0gBBkBCgAGBQJfxFAYAAoJEMzpT5rs4Tna7f0I +AJu4N7mqkTKVKUr39wm0Ux0oZkbIhlssvImYzFrzVqGH6Kls/xTw/tS08U2Dba7n +hzjdvL1cRD1O2j4nag3FeUO/8WgMI7Tl4WvPksxhA4iv7fwCNGylM32O7DF57B3i +idKod6XS1fvgi7AFgmA2iikXXKhM9pXlq55WCvwX0IUEKdfsgE3Xykn6ynWmiOaJ +fCK2XAccMU3AZpSxTtq5cRycI6NQRuWLpx/SQWCGrYue1HjbaXFLSQFSlHoNyg4u +Pl4kJLGcpOgK8ZjGpdjnY1p6Gmxq6qrQuLDCmkds/tkRmLFZ1WY0Q0/ocXkV18u3 +1dLRSRJtqMH9m4aVrs8ynzQSPwf/ZpqAV1gmAn/TMm0D27DnlNSB89pTls4snZWY +TIpjIvsYuOFc6S5zZhWet4QYcong8Daa1qEP4sKs6Wknex1ghoxjyrnJPxMs+tmk +/TOQQZBt5zbcQwfaqITI7XUOkYYK2dgkZIFHE2kErlTvh4xpNyqn33u1dgqFhmQS +X49b9G9SxQKQ1I/4a1Nftk2dXsx/1JM1JYNhEEp64DJru+vGztGNjjMpy7PN3Yhh +WzFz1eha3jsM3BsCaQYvASXouWXFW+vCdifIyUoK405HMqzRoJOqv3EbCra5WXBd +hoKgCBXcbLrYmBNrOFiHyI43/LlAhys3dO4X6aPWliDVTVqC1Q== +=HLPu +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_securities.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_securities.asc new file mode 100644 index 0000000000000000000000000000000000000000..8504aa9a00f1fa80a36edc8c4e8127510ed62bd7 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_securities.asc @@ -0,0 +1,55 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: Keybase OpenPGP v1.0.0 +Comment: https://keybase.io/crypto + +xsBNBF6D9JMBCADd/wOo1j7KFoXNMZ2/1iHj1K7urPMrJ40s0AzqejM05QOSNFDl +t5cje0z6AZdoJJiERQAGJVTxJgizDQfnQjKYr9pLmf/b3bcUG4YP5kvw/B8fcNNZ +pBJXAQrfHjWNrbN2gOJB7YZtDDUpzHgDxZcZNjY4AJvmqJSgu0UjnF4MUzfphc/B +tK5kKvvwl+NaddM8jKyzXj9OaIe8crCctw926WeuC8T0LYSv7IvnsoZXhJPUPOpN +C/ISR/8sKYALmbLdYXbCR2I5Re4tJyOMbsTAMRBY+36TX//Vtor+TWUgAIBDUYM5 +VRi3zwzh+Zc1+cHU79FWRnuMp2tVI7O1HwchABEBAAHNL29wZW5FdWxlciBzZWN1 +cml0aWVzIDxzZWN1cml0aWVzQG9wZW5ldWxlci5vcmc+wsBtBBMBCgAXBQJeg/ST +AhsvAwsJBwMVCggCHgECF4AACgkQxSF6fXJ8kE4ulwf+JHYvG/1sS0CZ9EISJVGJ +QC8+wUgC9ChcaDG9/oTZuTCcGNeTZ3yzL/+k1h3QsMljuyIgJ98jqROdS2Dxo9Ws +/25AYLTulYJ/qFI6HvM6aX/GaqfNEhG5fLeRJ449ltvratXPgTMcggtHTL3ysGmv +VBYBryyKePMTXb+QfEYBqqvlgIIWw2z5HS/kmuhcdMmxIr8vBp6i07WrOAQz2ZlM +y7dA6cUbOnt93NSwZXBycF9vKsqLQQ5uvhDJip9IDjgzvpMtaBI2McM7BfldFZ0G +Jo99/v3vGScnxl8se7AI6oNAzr03mVDQzMlWY5s53tMV4Kac9S1fRg8vgKv6ZAt2 +Bs7ATQReg/STAQgAs9Ltf57xO+4vZVc5Q/56V48RJoyLA4hVwDniZS+5o1SwqF/d +ZUzr3z+kHr5V0FiEUZtytjaQ2TnrMUaHDGns232R/yOWmWRItZH4rZkpmMZ9fYJT +u/hbgcDXlbcci9NcURjG9EJbELgKWMORW4NVC4lfpmB4IRRT6WYKdzBdaukM0Lob +IxT8I1PoijMWLLgb5/+gwu5CW8FhTtaw4cMrw6vQQT+aOjYM2n6wHmiqMZ2nWkN7 +e4mZgYgYRIdPs1ADXsP/Z7UGXNEouauWhU+hvuexZwdZ2bjA95YqjXOSu5l+SxzE +qCubaZ185QQb2rKFoB3R7annX4qZG0NVYK4hhwARAQABwsGEBBgBCgAPBQJeg/ST +BQkPCZwAAhsuASkJEMUhen1yfJBOwF0gBBkBCgAGBQJeg/STAAoJEO2J7B7NNsnx +4Y0H/23/W+xSVAOEoTNKBIgsS/9MHGV3I8fFwZKfBhXwyQ5R9DSQ7cJDcR9mb0hI +HF1IU0SGRxV0B9vCPy5sMqJ3L9hERLHEpmNasg8MS+z4mq+5JxHNhMdADEtMkeP3 +kwjk6OnIYNgQtBCVuMZxMQapobuODEhmoDxKgExg5uPF6vQdVMCWe96HVfxY5kbe +pf8Y1dCtwq61yyeiuDS0cXd63QYDdpzDl7Qe8iHe4v8LlSyLFXcXRpxZmXr0OVTP +LfV6Z4Ef8dKv9RZp5AkYfqFch5DqLStSOBkjqD+yIsl3d7nHyIUjTslkVYwznd10 +g9+6JnCgv998AyQfaFEPkJ5lrQHi/Af/cp8YMvj5mJl/2X//O5PFWDERd+zIt4CT +TlGH9Vm+J+tu/e1LF1G0/WKSDHGoagWct/VAdgEKQGdDzBYTl/AkQckccEJKLAzS +WGDY2MW9eavajZJfbWpJY1gZKULJz8uUdqEwNXF37VqzcEy1kRXwaKuwb83s3rCD +P1qHhy9XSJf76T1Z+knz+i7Fh+SnEBPiADUX3TKjRaKuJVkmf+jAukV+AK49b4ww +jqmw5zxB2ObYAkzPbiRdKQ0mG7ilQnEFPVoJ4HQzEpkGlUNwsRCLdY0hUhWynTxn +IGln7E5QmOx3tiuwARBHpqwacS1OX9+c8cmvGHW59mzUwhwzojiQgM7ATQReg/ST +AQgAz1lgQyFp3FogS7xqc/k66iktkmV4Dawd3j1KibMMbe1A+FwC3QaU5yUd2E0W +iLjdlj5y4Z0hJp2vyWFxYEWqQvqQHmE1SYd+JoiLjbk+qEJWz8v7SH+htWDb6amQ +yLFFUnjHJahOb3BlBZvtklj2QE0Em9gkbjqRS2PEvT6Pd86rL7dN44U8xlcnQ7xL +fsj8iEB/Cl1It26s60NgCWwlEsg22rcNi5cpQPta+AKTFYR7KDCyFck+MyEC918F +HFI0Ud1mdv6o5Pg/JiBCTBP5dtV144DbPz4x08avL5bfytunb2AlThspadwUByrj +bkVtji/IsXJbcUFjAPjCpjA1fwARAQABwsGEBBgBCgAPBQJeg/STBQkPCZwAAhsu +ASkJEMUhen1yfJBOwF0gBBkBCgAGBQJeg/STAAoJEAhsBx/+aNVHB50H/RzEHAGj +irGdeuIS5vCIgg5EM8R3fNDUJWB9+LRDBlBrFWujPgxuma/BuNUjzehDEpueqNB9 +BRdy1u0ofgTGRn1GopLHFouq2V6exBKqNP97kPO7uRv5xpht2093mPytRuN2yDvA +Yd2gtJHjfWV42VIOePTixP2vDqLDg+IRBSzSrspcJ7rb1G65UF5vgFtM5TJEzx6L +r3JRyY6a2HEQlNiTvzAfutI7dnzWVhMOQ7/5fSLHr1+7qDa5+CDAJVRZz7vTho6L +8w8Mw3BF8aHk5Fj33WZYGWzyItxw6YkiGlH0kKsc1w3sQ7xWcHWJ+ESLDzdQdAyJ +6nzLDsgq4KjHm+/GrggAg/a2+6A4FWfDE6O2jiTYvIrizLc9OxC8pl5/Z8BLhJtC +X4L0YAopghThsqP/530v+3MaKJu9xS+Hydkd8gn2Ppoaw5oAxgkvQK9dFeXga04f +3oXtfPDDlFznEojaAOkguc3Y59zYsYbSee5d3vzxGBJE4JUvwcWz8Km2rooyGmN7 +tEoK+r9Yr/x7eHkisiCpRDJMv8SmGlYQ3/trJPEBwnLr3YjU4/bg2VietbL7EBIf +4iqPQg784zRHsj1qh26+0y6bfSbL1zF5GcpqTCOdBzeBUXV/DruK7NVo70ogsU6l ++7yyvKcSwt9QQhOCexMS6wk4f74Mdx7fGM5Y509aWg== +=pZjL +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_weigang.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_weigang.asc new file mode 100644 index 0000000000000000000000000000000000000000..5c19813db5c06f105cdca970c176ded231749e8d --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_weigang.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBF/Cj7gBDACtLHxhGCdFXgDFZVTEwguyTHvAQVQBuNBRLDYdBQ7glTSCXh7e +kuWasgeEuwlCzwMfMZlHAM6Wxspf+23rFPhVvBAgLEQ0sTkOtzwOzBC84Az8rBis +GYN04t6mnFx285sNob5v1IXTFX9PWgcqORB4NTtlF2xeEbvcWWBrv+V9gouwlcSY +XX6lXTTlGp5LVm5qfFcyB/JqGkTAXXSRCTiaREpmNjzAS94Fis9wVJhQ4NZMOw4O +a33PicPLNv4lczFQeHpJoUuitcp/Q9b1tF86DY1ODwrCXewR17n5GI/IvINYubqO +PsOT67btTB+Uu7oxGg+M1Dq9qO9r3egcOO9lgpSohqKLr1kYA9y5dLaod7uiKS0D +8iEvVQpJD9bNTXZapxPps+HPjt8Y9xKj8czLPvlSuk1rHwnKamgfydl7QvXoCNnA +9HbsloT4gqme0mWIzpoHlHnsuyJMCLpFiWvl5XuqqwNkdsO20KFY3mD0Jkn13or9 +XEVJ5PxPjrCV3mMAEQEAAbQhR2FuZyhKaW1teSkgV2VpIDwxMTAxNTEwMEBxcS5j +b20+iQHUBBMBCgA+FiEEYAgOin9/2EC89DMhLc+x8jVEWYQFAl/Cj7gCGwMFCQHh +M4AFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQLc+x8jVEWYQVVgv7B0ijkiy0 +NviUMHr89r5hhXIU7X7l7gi4AlzWd3KFP8ey+aw6btA0qq9miTApt6HVH24xQUVN +cKqcvRnvVR8g8OCTQgmQJYr/JD7VRbwL0bGh+/lUR1LBUlVGoLaSD6wNwjTTdfzK +w3PXwDJgKMCdMAJXQ48qGCyz5ISN4XuqN4I0jQBjmcQt2OF5uBoIH8pPtlXb3l0q +0L6Zsl4UlbDUd8+4yt+iDqU9Zh4YvCHPHILp5oSnLzzDkE9odCR4PWJe5Z9un6nT +H2Y8OYe8pYWRizA/i+4+j7UrRD3AkMwRp+xL1cfzHDR6Q8JzR/HFHXBVHsPnBkar +qmx8gEVfpJC+HRLv+w/rKiK8hsNduNOBwYxCYinpSbYLv57djkCPXuKeDVCVlgiP +fvFLdHDXq3O3EP8s6+gn7Ecyk9mtO4Joq+gqebpgdY47n+k7aufiU1dJldqE54Vf +Gkxkh9xf0cPHKK/f/trxV1ANOWJX6/Wx6uiDHI/WeT9Ymuv31FkL84tIuQGNBF/C +j7gBDADWp5M+Qwig911EYl5HXYGL4d7GJQ+L/jRGcx16BNZTq3pF4JxcEN1tyL4b +ttlCzBLbFS6vJfWq9PGfnHWpPVxMfDnRqEIo136ho4pBOP2w6EBBjetRbDsfkDA5 +26gFq/4eePK4Iwc2F3nPyWzQyTc2fb/Jejv/n5hTRCoUwyhPB+fyK6LzKr1DK2XV +7J0JZ83arSn5BMTCEGV96Qj5cIHttnGmGIt9rTM8Kn4GhsDb3ANivxs8SsAwudR2 +tjR4e7Xv5yWoDd8yzCHQhcI//2CE3ILg6GhQF55/gxwK9g+eDXsL+uI0cWfSiFcC +2cN9/WZ5W4RgJWh0QU/0uJzeebUgQBi8FGp2He1yit+OKXsgrvF6ZYw4+Njoi83d +eEE6DejBO6eWyDQRw2q/PpCZ7xUiSa0RnGwLZ40KpiSERiHBqxY18jRb4Z7OeCht +PCKR40ZzhDAlhByuSAbH3rVXRp+0DmrwBDKmamJUIxxiCwSZSAoOKnsBZGdfPOI5 +WpmnieEAEQEAAYkBvAQYAQoAJhYhBGAIDop/f9hAvPQzIS3PsfI1RFmEBQJfwo+4 +AhsMBQkB4TOAAAoJEC3PsfI1RFmEspUMAIJ7ORvB6YIFyGSVaKAuOoP6cKyk/l++ +UEterzi/j8QVGP7DZyuVHT+bidu3TcXuPSOX79TCzSh0r/CXqyrRF3oliJ/FsvHj +xcL9R02tUY9KhhOJ15UdvCxmsLjS8KqqiS2m806ke26i3qzNjNjVPKHfbTowMmCM +aQMXyBJearrQnnkBafX9NeRHRexbP/Rl1URVmX209H9U1/yLPQ38naTwgWPkmsVA +l9zG6ODQm6qe97rSfTVe6SjZwT9O2h1ihfvZ9bRXJEYknr2akjUcn7poCWNRzOqB +Fm5yRItx0Fnn6PKLFvjPCWYsiBZOnIcOgo7xMKBKw7WuxUzg/75c4TUeZOjF/SNj +vhzKW91I1Z/Pxw+wW3d8g+QXqy7/dkjiRtXRxGZp3d2dQn01xA+8LllcoiQL3nBQ +sTLpL4upv3wIqJrEig1CCu3jV/xCLZ2scX1BZF5F1Nuxrg4u98m+IASZyelI3n+l +8gNJatLN+S7o+tEY674IFESZaN9/NLT6pA== +=AS9I +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_yanxiaobing.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_yanxiaobing.asc new file mode 100644 index 0000000000000000000000000000000000000000..93ec6214501d745cab157b48e3f99a7f4eeb9db0 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_yanxiaobing.asc @@ -0,0 +1,98 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: Keybase OpenPGP v1.0.0 +Comment: https://keybase.io/crypto + +xsFNBF5yzKMBEADF0Au5nt773FJVV0/D1vHhKkuSn+mFMoRwjXXX9J2RygZYQyQK +RpGWQcy640y+1vk872MSfeQFcMj98JLi9qjQuc+F87EjIMw46phxqFCL3BT6jpx9 +kzmLJpJsrzpaLuDiIczIDP6g0ap0KqnxmIDsrNCpEf4LynnXdef9iQHUp8JER1qe +MjSGCnWss4Aad+DQXF5hzTYjbtlD6WsfST9dEE2iPrnn6E+XofNWEpmL3ZqX5aZS +dRKGSLd8z6yR+0eFADGHwCLvaOUIwGY8hJhSm4rp33yDR9VIuz4G4bK3I2lLMJqf +SgzcIn/QBQHbTGeFcli+4J1z//7T0FRk+If/+c4ZJx1q4rw6fHhaML7ynAhJ1zT3 +jfDWHqQjfHH5wnP1xUoyeJz/AwC93TjrUq0um9aO1iOkNrrxkY6/Z9ZQDy3r56gk +DwJFyjNQicO8zaIW1Ydr1Kd6+N3HZHYrQEMD3FwSlvVpGGLCICy1wF7+IR2YB1Y7 +8Yx2/31fbt7VOnbwSJ/DYzgM786fN1UivLVWez4SIeqgKd7+0bnS3q3IUpmSxTO/ +FPf7qYoE8u5CWkGkKClImpM4BzKI81MUU2dV4eouWF02Cx7xuUirUGeaQoS/hgkw +LxEhrEf7xoaECr3TaN5oSOmzW1ppIDqG8ct2OeX1XAc01WFgKx9YU0Q9GQARAQAB +zSR5YW54aWFvYmluZyA8eWFueGlhb2JpbmdAaHVhd2VpLmNvbT7CwW0EEwEKABcF +Al5yzKMCGy8DCwkHAxUKCAIeAQIXgAAKCRAaOqMV9M+SrzlND/9gyo/hkjIwYd7i +SG74+ZcWkWAcEqR9SnfBZNKwGO7Zls20i6ZzykruD+d0pPLIGaq7+qCRFb/eb1BI +lHQEXxlX2rO31gxE4M3kOpxOKsHXu0CQUaeVwpaLISpshmedvCZh1ipdiOYdVjax +B8LNSUAlEMy0YEkDBmZao0QrPGVPk2oaVKT0lsKEDRi/5BGWRpD0KGd1ohqqYyb5 +wpfcG1mNPN8h83sAHYoL61htTcc9LLmbwCFuO9+TJHwf7wFng17cnZPJ9Vey8NDz +2cZZTgZehccQpQhn4WDyujxCyBJiWMdUlPGHW6RE9/8yiSPhEc0jEkWZGwy6KTWG +VX+1HaJtk73sPxP+1IfAdaAFy2nrXz4iNRjiKI83s0yeYTO9DMxXLQRavacgmJtV +gPeOHw4iWkjSavbPsKJFfonCnfS4RrlT281n7D0I9KuXR8bZbQvoDGStkTEGptSI +hGeB7YULfsCIh1EW7Y4eyo7PkqQ8b8HvO0Ec5IZFMFP8EWnGqlyJNC+KrOtr6p/4 +OcCRBYULwt2OqNbnLKUHCoqsY1hv9SmdT4lsEmG4ExFJ57OjO6NMddHVrLNvymV4 +tsa376fzQMHit5yHFdFSX4jOjYohw0Yirir6gOrszUsnK4bqyZOL6ZuLXEW2nDUA +NfeUvSQMwJgFnQgZQAe6q17TdqQEg87BTQRecsyjARAAvt5pRqsbMDTEluSAHHsW +pg2hMxnZGfOFVUriTQy+9ACdF8i4E0pidGGbs1fbm78U+FEmJCdGm7fGY1FDmV/F ++CRD21wannuJgPGChBfYz4UNjMQ+GBTHOiP3+TDOEw489IEiGD1wZ/XG2U7hR7Fc +vnUuGYsZ291Yv11cht8BM6u1w1WRFPIDJOqwPr9ikP/pGNgbKqHwmA86qmBtKdFY +85m5V18b3hozVubIflZJ1U7El+ntQfLIoB3Iwspz7zxYqoUh7ykqIfEewHL5etW7 +bihgb4BXiywzsh0pQHibliAH4SWBNswcvtA7uybyns4caaogogxHOe56b4bTJkat +fDGufsLxWpuaupcmydF8ZpI10lksDje/r6QurVqf6G0WQPXyon4UQ4oKAZ1lxKqB +PbQ3baK2RznNZ6p/Wnq575SBpRFkQSwYJsmQZ9XBua20FT/+YWiYxdaQRlkQThxc +i/LVL1tjLtWouBlJqQVaDv97SuZQTodofmC5Gu9JUWhrg+cnPhi/we7dk4wEeWP3 +juYW2AjUcVpPL3ry/805ynGtZ3Z6ZL8VZkP3yTKq6kFhESkx3FkeSQKRCxj0ahqd +FlzjTBsJWCy1uBKmltZX5zC5X8zPiBKPIdud2C1tm49y/ApqRY66ShT+r976dHry +lh8pdSMJBHBTvaKti8YedQcAEQEAAcLDhAQYAQoADwUCXnLMowUJDwmcAAIbLgIp +CRAaOqMV9M+Sr8FdIAQZAQoABgUCXnLMowAKCRCCvPTn3Lv85VDPD/4ixdutdijq +m4yKs9oLQJyuU/ronMGMVSMs+NwR2q9bhBzQWAGntfqXvbhhdocHEMikbgLi/1W1 +XUXnyTSU1K9cfPoDQtl079O17vRkZ7qEwJUJOLm/O4X9MmWlyKl1qk4JpZiDvZ12 +hL4X9pm/OwI9Ro+eBkjJE4TA9T/n0u5arV+J41JTVcF40RwBkDSZrZpGU+gajzDe +k/MbYNI6nR4VZl2yKItYwBGi76xbWRNFFI0hdAbtn0BZH7f3KSNVioPDsYaN30Wb +F/qU9Ghc9OUAmKrmgrcvneQiO9qwsflft3X2tqBoXguuwSTBC69lwFyj9tGsNVlJ +89/lLbq3HAZ1ohKwnERYlEUvUTBEs1cjtjM9DKzwoYSB8fsoKJUrthOdLpA/GCae +EFTPzqUYkGh0oxU6OF5T/fi7VpfKBkvlCEu2vatI2VwiyaAQo+dTvytghOVk06oz +YY2o5S5aYXE5JWY4cmbovmzvfIG8Ez45b8nkpr1GCTNUKfxkkJe61CmEG+2A/UNw +ECuVk8KLuRpcJICIOCDT/AdXLnm8ShAXJ/C+UpqeTl/G8aCDwbmA1j8acezsofyo +pebQnVf+cY7vOahcSPWsDbj9KCL78+dyGaxSqoE1jDY+qyXo/GCF9uazvtFI/N2S +L8iiVi8kIcJAYQbZTYdSin05bXbXk/R9LOk9D/9w8kAoSx2GYuoNT89SaZYSVp3f +iZ3uygaFxOSTTHDtbpJEZFKVtILXMFFVt2bZwtUk0l5i9viqvqZjm1wD8iX2O3uH +2KZqBr2c17gXJkOtRfhs4Z3r2D7G1Pvo2VPm+jMNagKmXwlCPcRJQYUfabFkvB3a +QN4k7up0QLZeQst5AYmopATVVIi07YCRNQBO6O0chZcvfrgRONfowuGGFHOVO5rc +EWL/pQ4nK9v1RBd/3iodbJgsd/DJaNl3fxhOeM5HxN2qdK57ZNqh1sjUUaog36nY +uMnuvQ3cM9Xxlp1eyWorDeNhGEhZYJqe86kPM82xPTqT424QO9ZKxDj9ibrSkzD3 +ldxV3wc0PKfoK4RlX8QyzhOgWhzsncLSvTBeUwMiBLmQHVWhoGdocXUEiIdyCgax +Eawa3jfsri/3xyLyBYdqupbL95BGDwlnXx5j8FLDZjAyH4vyVhuuMCi9niK1/fEm +e1TBeoZH2BWX82yKMRdma4EyjlHho7PCEwfrgAbWB5Djn3VxjR+8fTQqoDfLv/QW +mVBCprUQHJhlJw+t4XrXWq9p/nyyPP7gzBzrlHASu9JaeilJfVPhzyfmRSnEaajb +6MygN5LB7c+/sDGjYhZwdEuB3OQ72kCg1238bXgKMttMc6g8g4pM/Kd79SnDt6Qg +d1jbFJXv3qGlkeyprs7BTQRecsyjARAAq2ECc8kdZxYQkRsCcGoMPuguKiIf8+no +0ELBg7fI81m0oJMW9txWuS6vWL8rF6CIXUMP2BwHBddwmelOFeLKO0xpVKHOLEh8 +wIIqKor8vuWH992KGfz8/5qB0DD0c2HNyZ9/znkf1P5RmipB8UHI019+G0HDHG+e +CULFFmzJzjAd8VWxCn6XDs6i6fNCb0i9cPzMbTBQBwbixz/LPVwuBAAic01wxva5 +pbALIvgf61QTo/u0YwLnhMEnnqpA19ELkRrP71eUmcnD15qEo6EC7nvHeYkARVR1 +I+Su5OL2ZAeSQSQIpfOsior9zOfURmCqabOVewqxOqY2/jiHXspAvp7PYoz9j5jx +2jEBKGiUFb2mLA5z1ZeWpdi0eK76GG+ypusxf5k1LF5/HcKIWZPWWI0wb3ceA3me +yHnl7qd2EviAqJCRXsckpVFEmp+ildwrxxXuMBYN6FvhcjVuVgu4Mk54BogCIf1w +RirIH2fKOWY0UIuHHBt92bG56jwznntrIjWrMy6PuuMWLg8hUVTqzr28weZ7KTqk +YJf0feV7mgRLHfoJoOCVXtx2wdJEbaLKcCuFmmaWSDqjCv1TYRNJ1w2941M+jMos +yBfUUXAeis5UxsUJG/lEKOXz6v6lWwBeLB099QlX/g0BZ6mBNyBqzRiMzeUNTmrv +a6OpVaswrAsAEQEAAcLDhAQYAQoADwUCXnLMowUJDwmcAAIbLgIpCRAaOqMV9M+S +r8FdIAQZAQoABgUCXnLMowAKCRAQeyU6E9R7UWdkD/0WTDCqr369+d/S8DfYX0TO +bCqMrGzPuAzd9GW3UJu5VsBluFqC4Q8iLrzK762bQLHXBNlW7O6frl/Ojc432l5a +8oRRXkdHD82WY81Qua+urVz5R1+v9/7cFlG+HShPLhP8EZuyz9D71wQl2afvyr93 +kuSmlntvSE50mB/Y+2jAriDApw121O2B29B9k2Y2O4kH6/NRmY7Sowt6yqXJ03Vb +yJNMMW9ie/WmDXBNpPQ8UPUDiNjZ8j0U3U/hffvt49+y78EvkFYR3KVknL8KfTDP +dHSHxsuqmHhu3lFm3jQIPbllr3QMXowxASeuDCG5JBsVCQO04vYButPf2dlLaP39 +g3IKfr9UaqQ8486DGkAPQnjenjxX65A1S9HlS2wSQNOWmCqgNin1ICOkti6xrTRe +ncaDl5K2SViX1ADZFPD710rZ0HZlzzAmIPEgDRlScSCJ9omjfnpfAvFW4imjcsTi +r7BGILJRacAst6t41LcFjQVYfvNhWO0o1Qjm50bqHHnZ07gVwCV3SqKGkfcjepwC +hLRF9WJrEtyJs76OwuiIwnFV+aBMWzMs27Iz8hDe22CKpR6hJpAJcLrfoT+XgB0y +/0ypNn3QTw8OYcjJ3oB1Mmqa0CFvYtPYW2jk45u4fSd+lol//jGrFP4rbN2QGK8p +f9hMntmub85NF2rmXUve2l1fEACP7+Dd8PH6miY6cYpMxFamV5IaELk9tpE4kV0S +d7h2JDqOMYhp0aJoyBQKbBCsD5kUb7l9qs2su57cksom7yXF6jkpOvjoP0AyZxsw +Q4zHaAxihiemAxoGfGKx6tZ6upfTTBPprgINP8UDl339FzDGc4HpvQfTo9wVlDyq +qXBezW4I7b32PGeyPz2SIakWOSt0cyvTf1EnrBQIKyqVzidAhBl8W050RPvmKobz +f+kj1I1l/rPngyx5iVcVj5KCzfX8nnSFHp59Z4PaX41MtwMfNckA9PNgOvILtd0r +V+iTRfJ+g99tpXMtM0qj/zuTWlgWfUjb2grZG5M9kQbKOOXnWGLsOMNDN1JVK3Ox +q/NR0jcJNDpVwrWXiOM0gTtiryrRErY1eLBerM84uS+l5iE2AYHvVTpEpTtCBgjy +mfKcbjg9j4S4zRGDbtFFtcrOpK6WS9ZU2WoNF+p2+H+l0p2tELfALX59dMMwVnz3 +rwV6haCaTwSxiwK2jIDTu+7h4H3IySMvHUuIfLx6xyu4HCS/7F/6wRtXNhZdsFq5 +pAknrrXX/ekRM87oPUqS7eZObOrVWZkYQIIppy6xChxgS25hvqmhqqzRJXhdo27l +AfTn9QJ3oGAyuP/BYQriAhAsDcHakmvXzlfqfWJ8GPB24oAVw/7HI7BYJzH5ZOeJ +vC56bg== +=Qk+F +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_zhujianwei.asc b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_zhujianwei.asc new file mode 100644 index 0000000000000000000000000000000000000000..79f33eede0941430b973289903a85047b3e30454 --- /dev/null +++ b/web-ui/docs/.vuepress/public/vulnerability-reporting/public_key_zhujianwei.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBF/G/EQBDADA3ZEFpeLHnijwgKDVzsN5UBfDd+ZzBsL1Nbt+OtUlV+oLRO+h +/b6CfwgDWWBaa6POoCihfiY+QW25m7QZJCIUNzbG48IRwcUf4Mee1xz6uE7KcotG +iMyLkdRlwp7jaPL9QMuJKn/DQ2nkRpOEk5SNQyqr+9EseNHj30A/Ykvp4v4wji8I +AAz9HL7UdngtTm3kQl29eUMt/S9s6XBW2I0WZ+vrLRzKssiBAH1qQTcQponr3KBY +aHlzLXLmlgq2Yr6Q+m+7OaRH3nAx0t47dV9xWG+v18nDqdfwRQwVux4oR2rGGWAS +h/ERM8aAuwxtxSdg50JxdoNH51k1kyvaVSrqqfWHNJOURGkeaF4u9PmZrJDUkjZY +G/2cROf4QVxUPsWYhjlHkIeD0xGfoSJlydjFoHWifpXtBrI8kFSJf2zyo2ddwUAu +lPZdp+I2XjC3NbC1CzclRTTMMeAE06PMPxmlT+AbW1zZLeZjd/kvoZQWBaB7T+gH +dXqSgD58NEymPdsAEQEAAbQjemh1amlhbndlaSA8emh1amlhbndlaTdAaHVhd2Vp +LmNvbT6JAdQEEwEIAD4WIQSHz8aDdDRksV4d9PTtfs/sIkOr8gUCX8b8RAIbAwUJ +A8J7/AULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRDtfs/sIkOr8iNSC/9+Kyba +3rdUcRCpmnrri62qarakk7y+g/90xNUKXUJoDZSADWq4AcYYu6RyOPHF+mZzAuRh +Pvju+drAoQcwwaJJ2IvmGNwtzWKNPI1ITGByuVWKZubUxlRNDhGKbYUbQpCxYglw +0gq6A5NiwTcf59B2b2O4KrYQxNOTVXLIpT8RtZQS4WZtsqtDjNaZML84ieVbP7iO +1bxYb+jeg405Ma4aJiqZOrn5sF4j6n26o9l8VwrJVXnZIKO0CKBtpqjPZIcSLbFI +Jd1c7uo/xvgD2hSwK7i9V2ZsN5u4RfjFKji1KpdY8CKwv3LA0ZD/boPj+1kcwmOR +AcVmoaFj4RRP5ri8C0l0yPXYdSDuSdT4LYNUaq146IEayv98MCdqF5lORL0k3r4F +PZGfpGxxtZT+4ytHyB38ZjOSdISVVioswv2KAWQbFCEDOqkfM6712N0K8g2CnTHX +semkw5IO7M1I5Sp11ai15O4Hcce3pKYXjWXVM0pQxGU5KVe8FPvvpoQslkG5AY0E +X8b8RAEMALUfFQAyKsL7wz6nqYBUEPwK5yNd2WGkAcbDc8cyS8LyG0wz0qhqxluV +7SiPaUn0wtfYfihJcUA3KYS+yVdBCxgywTy/cWtB5E+Hm9W0UmOLY31zEGFkETaF +9HkHwxgRwOX8gycLHsBPvSbqcX69atxNdHHHBuNK3ACpFrj8zF1rYfA862anOFlV +YWC2mCMEHG2D83wbQQ+8RJQOcbvVczkHB/EjQGtTJK1TjPZoj4vADVLxiqZI89pf +aWBQv+fieijNV5HexLYmilRvIZdF4NlEkDIQrlGpHPKb85mNkAEC3/TcfsLxfp2D +PyI4QmelJRn3uQHwRShdpP000HK/4cNO8poJcxsbdx+XO3pOhvveqtJwkTr6d3J7 +ezfnc2ujdugO0fn6SNmRhht+DU52qGpLt/Tog3WOhS6ISSkzMkrzUbeOYMrm0OAE +GpB7kRpbNxq1LqgR10W5jyIU4FdmNNZE4MdaxIdQXPotcrAuZT8pa4FTV3mFD8Hn +l5x99NQcTQARAQABiQG8BBgBCAAmFiEEh8/Gg3Q0ZLFeHfT07X7P7CJDq/IFAl/G +/EQCGwwFCQPCe/wACgkQ7X7P7CJDq/L2CwwAlc8VxXK0D2qItScqEEY1wWpU1/WX +aX4cIZ1gV1FXtedONQPJlZgAJtw494msgp3MG+Mg+eJBdwf1UJW/hw1stIRe6Q7w +mPHYUJg13dp+E+PFafAcvpYB83q/wOfxqCX7sRrFsKYV8YmnHMGJ2INkWptxeyRu +gh1xxgOaqJ7P+STntn0cm0h4mSoozJjv1tVTpYI/Bq2XqdCwVKG126XmuLj04qr/ +U1F9+aUqj1wCNMc2GNRGn9rKP3bsdanuxtEW9l6CPsZbfD+xvDZZTYFMdeiNtp/6 +rhvePrLfqjeb2MnUsenkMYDB7NdahkramWUU9s0CoieDH/c/yZeWhdxzWvFX996s +EEMpo8SS/+KHMmcqrEWV8A1Y/gdcQXZNlsPqAqyK2eDtO1J0JPIP/0keoXvFOyYO +cg/5rMiiOqtsRwQF+P+KvmUAABKswsTyFXxmYs8BE00rhIEoXG3cmDKL4/F7hVQP +R+bTbMSrEM0yZ4Qiu3u0aQ2X/2oCLeGjazkP +=E80q +-----END PGP PUBLIC KEY BLOCK----- diff --git a/web-ui/docs/.vuepress/public/whitepaper/en/openEuler-21.03-Technical-White-Paper.pdf b/web-ui/docs/.vuepress/public/whitepaper/en/openEuler-21.03-Technical-White-Paper.pdf new file mode 100644 index 0000000000000000000000000000000000000000..adfc6cfdf60952b56a9217a3a15e2560b209f466 Binary files /dev/null and b/web-ui/docs/.vuepress/public/whitepaper/en/openEuler-21.03-Technical-White-Paper.pdf differ diff --git a/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2009.pdf b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2009.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3798e6b1323d69a2509f0e16ca0b15df760216ba --- /dev/null +++ b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2009.pdf @@ -0,0 +1,9246 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[19 0 R 20 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + 白皮书9-23-B + + + 2020-09-23T09:50:01+08:00 + 2020-09-23T09:50:01+08:00 + 2020-09-23T09:50:01+09:00 + Adobe Illustrator CC 23.0 (Windows) + + + + 220 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADcAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9Cf4J8jSzT2z+WLCNUC8 ZjaWyrJyBJ9NlHP4ab7DFiJkkijt9rd/5S/LuwtJbu80LSoLSBGlnuJLO3EcaRqXZ3YpRVUL1OID K2KTa3+QEyOLSfy0bpUZoCY7Zo+RVqF1QLzApUiuSERe/wB4Uksr8ladpUVpNeWllpdvLJLJCZtK t/QQrE3Ao5KqzMkisrdqjxyNUtskxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KqP1dvrbTtKzIUVEgPHgpUsWcUHKrcgDU0+EUA3qb2QqShWUxsOSuCGXxXocCWN3f5 feSri9t9Zv8ATYJNQs41C30nIMqxnmNy2wRviG/w4Yk0L3PuU18GQWaW6wBreQyQy0kjfmZAQwFC rEtseuMr6oCtgS7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUEk2s fX2SW1tl04cuNytw7TGgHGsJgVBXev73b3wlUQtuRPJIZGdJAtIWoUUrsSu1fi775Gt2RlYArkqO iOjI6hkYEMpFQQdiCDhYqFnCbdTbRwxwWduEjs0j6CNUApxoAvHoAO2Skb36oCIyKXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqx7zZ5v8u6LC1pql39WuLuJxbIY5GD lvgADIrLXkwFK9xl+HBOe8Rya5zA5ovSNb0vzDYLqekXxuNOPNBJGpRXZaVIaRVPw9NtsqyYZwmO Lby2ZxyRMdvmgV1kyykRTcIyOcXNoGJBAB+IXC1ofAbVGXyxcPP9P6mnHlExY6+79aaaPNLNHI7S iRVbhtxrUAHqkko7/PKpim2KYZWydirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirHPPXl19Y8uXNvaXkmmXkdJoL63PGRCkizMAR/MYx9ND2zI0+XhmCRY7mvJCxtsmljp Vtpmn29rZ8lisoTHEhcgNUA8n61YkV5HxOVSkZSs9U8NcuiS2uo3IuPTW7t2JVWMourfkQw+JqCC tBxUdN6+2ZGSA7j8j+tpwSJiNwfiP1BPdLleSKVnmSciQgOjpIAOK7EokW/tTMeYcgIzIJdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqAN1bTWs1zexyWdrAsnrG5ZYk 9MD4najEBeK1q3QYYgkiua3QRysrKGUhlYVVhuCD3GBVjiKINMI6sF34LViBvQU64bWlDTnBRx+/ LGR3JuFKtR2LBRsBxUHiveg38cSbUBF4FdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdiqQa95jfTpvT+rJcW/H98rSKr/ESuyHkSP9jksEoTyeHdT5jz+22rPKcI8YFx6r tP10XNqDp9jLGsETCK1aLhExUDiiSqGVQAKdMsy6eUZAmQrr3scOojMbRN/Y3D5oZokaXS72OUqD IgjVgrEbgNyFaHvTE4fMNnH5JjpeojUbQXS281sjEhEuFCOQP2uILbHtXK5x4TTIG0XkUuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVDHT7SSb15oYpZ1blHMUXmvE1U cuu2MwJVfT70AVurRRGOPhzZ92PJjU/ESafRWgwAMpGypfVZ/wDlsm+6H/qnk7HcxpUt04pX1mm5 HkHbj0IHTiFFMBUKmBLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV Q9lFeRowupUlYsxUxp6YAJJ6VbFV13LNDBJNHH6xRCRCCFZj7MxCj6cVA3SB/OcEkCcInt5W2fk9 s9DuKCk4B+LCBbGchHckBNNDkSWzEkUiPASQoSNY6EbU+BmXtgEuLe7SK6Jjil2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kse8yaZ5i1CORNPmjtH4lIbhZSsg5Hckei xH+xcH38QYRJBrcOHqo55xMYHhB8/wDjv6Us8t6N5l8uaHerdXcepwem81vEnqF1c7kKzdVbr88Q bGzV2dpcuAGOSXFH7mHfUjDCLuJru3a8lEc0STMzF/SpyHF1biQo7gDbqcAFF20skjEAVty2+O/f 8XpXk9SuiR1LMS7EtJXkSdzXr39z88IAHJqpO8KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxVpVUFiF4ljVvcgUr9wxQAtiWYc/VdXqxKcVK0XsDUtU+/wCGAM5EdFO4 tElikQgHmpRlKqQy70VqjoKnCGBVl7/Dx+7vv2xS3irsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVQUMenadIttbQCIzszssSfCOrFnpso67nFiZUQO9bcXNpd2l39WuR zijZGmjanAkV+30rtlWLUQyWIkGudNs8Uo0ZCrYBB5x8y/UKXsXrQBKO6J67Sb8fsrHvv3JzI8M/ i2nxB+K/Wzfysto2kxXEEXptPV3JXiSWNehAIHgKbYJCiyibTSeCG4heGdFlhkHF43AKkHsQcilQ E2n2UTRckgigHJgfhVQxJ6nbc1ymeeEL4jVc2yOKUqoXaWeZ72ZfLdzf6ZKTKUVoZEYgUB+4dd/x yWOcZjiibBRKJieE9GL22ua1qJjjvolMqKQDIIvTPQk0NFqeO22WWxpm+iKyaeiSQpbzKSJokCgB q7EhdqstG+nFCOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVKL/AMuWt9IJJ5Z/ UYj1fTnlRCoG6iPky8WPVf6ZDNATiYyFwlzH9lMsczEgj6gqPp9rpulXMWnxrEXV2VWLOGfj3qwJ 2HjlOn02LBHhgOEE/b8WzLmnkNyNvOdDg0u5FwLmsbN6D3ETy8o2dUAjZYzG/wBoLyrXMsRLQZAf 2PTdKt4LW1W2hJZIgAGK8RToAKADYDAQoKMwJSW+8rw30/qXN5PIhrWIiEDtShWNWBFOtcwdV2fD OKyEn5fqb8GoliNxS7zLpUWl+S9ZhtpGMJtpWpM3IK3H9kce/fJ6PRQ08TGJNea59RLLIEgMB8p6 zwto0u7uxjiXdYrhYgePXjyj33J75lNRexWDBrG3YcQGiQgJXjuo+zXemFir4q7FXYq7FXYq1JJH GheRgiLuzMaAfMnFW8VdirsVdirsVdirsVdirsVdirsVdirXqJTlyHGvGtdq140+ddsVQ1nO1zWV oZoChZAs3FeQLfa4qzfy7V3xTe1LluLGW3+uLNHJbcSfWDhouK1q1a8NvHCY70QxHegxpugTQfWo rWG4jK/C8Sq/IIOIC8etKUxIpNomxvLedpY4w6PGRzidSpWoBFfnjSql9N6FnNL6Us/BCfRg/vW9 k3Xf6RgUi0DZeZNIuIogbhI5nLIYZJIzIrR1B5hGcD7Pj+OFHJGXF1pj2csk80Js6FZndl9Oh6hi TTvgSl09/wCWojGFjhn9VWZWhjWRaIVBq6jiDVhQE1O9Ohoa2tUzsbmK5t1li5emSQvJePQ4FV8V dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqz0IOHD014cvU48RTny58qePP4q+O+KpBq HnC0s9Way+FysYd42kRZN2Kfu4t5Duu/IAdKGmWYMfGSL3+xjqCcURIjY/j3JtFJb6jayJ6bC2lU qyurxseVeXUCvXqME4cOxRCfFuELH5c0eLjF6b8QoVOUr70B/wAqtadcrpstMbW0t7WL0oF4JUml STU+JNThQqmtDTr2rirz3RdHt9J1G6kupmNzc3TtGLeMMkYlkKmvqL15VBK1qMsjhkRbXLNEGmQ+ ZJYZ/JupSWVHSSCShIKHYUJoy9RTuMiRwncM4yEhs810P9KI9ssOrRvckCMKTKXY9CQPTYAtkCze v6PFPFpkCXDs83Elmc1b4iWFSFToD/KMLFGYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYqovZWj3C3RhjN1GCI7goC61BBo3Xv44qCRddUJr0d1Lol9DEvOZrdghFRycg7ACpGJUPJdL 8u+Z4iqDT3Mn7JMEBINN/jkQ5Fk9N8mx6vFpskWp2/oSJJSOvpgleCj7MQVR0whBpOrhylvK68iV RiAg5NUCvwjepwsZGhbCNN0jzbd3Mi6gzWzI/wANwUhkVyjF1f4QtKtU9MmMshtbE4oHek31DSLp fK+oaW0v167mikeGJAsbFaAcaVAPxePjkZSJO/NnGFDYbMf8s/l8j26XV5FLpuoRk7KkFKGtCpAY 9DQ5GkkvQow6oA7c2G3KlK/PEX1UrsKHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F UntpvM0XqLLa29wvNjHIsph+HkaVQo/68ANppXjuNZUXE1zbwiJYw0MMbkuGWvLlIRQgihHwinvk tkJbY+ctO1O2cWpkin47tRCEb2LlA2RBZEUmulpqCrIbuT1AxqjMipJ0oeQQlabbd8kxRN0ZxbSm 3IE4UmMspccgNqqCpP34FYVpv5lWsgWOZYoRExSVpGkVtq/CEWKgKmgONrTIJ/NenHRrvVbAm9hs xWVVDJ0FTuy9hvsMU0lsvnC5mMfo2s8ER3dzBI7bkUoCq9q7Y2tMi0uYz2UcxcvzqQWjMLddwyHv XFCKxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVJ5fK9rJK8n13UE5sWKpe3CqKm tAA+wxW0RZaTa6exn+sXEnFGUvdXEkoCkhif3jED7PXFXzmnlnWjC3+464aUspSQU4BQG5ArTck0 oeW1Dsa7dJ+ax/zg6P8ALz/ml7J+UGlalpnlq5g1C2ktZmvXkWOVSjFTFEA1D2qpzU9oTjKYIN7f rdjo4GMCCOrNZyggkL14BTypuaU3zBct4JYWEP1ueeK5EcEkrtFKYYGcryNCVcoR9kYk2yAp6XDZ WNl5C1NbS5W9RklkkkgCp8fAAqAOmyjrgQxS1066uhBPBbzsYY1QkOC2zEgsDEaMOn0Ypeq6a7PY QFwwcIFfnUtyXY1JC13HWmINoKJwodirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVYZ d+RtTlvbq5i1Hgk8hkWIhxT/AIBx1xpNp1pGgSWkZ+sz+uZUKXMPH90wJ2oCT0GKEVFoGiwrxiso UUmtAg64raJt7aKAuIl4IafAKBa0+0Kb7+/hjSbXzxtJBJGrBWdSoYioBIpWlRX78UFiVr5BMNuk QuVIUftRivjvQ0wUm00ufLKHRrjSraT047sUmkf4qgmjUTYAle+KpbF5CSJw8U6Iw6MqEHw8caW2 S6bafVLKK35FzHWrHuSST+vbChE4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8o svMeu6fqepw6eiPardSAxoIhwp2FESm++4xtkQGU6VrGt3cN604aF2tC8UnKI8HXpxUMRX4+pXsM bRTF7Pzf53ubNYvSiuogoimdo2kJIA5c+MfHl3IwEppn3lmMCxLlU5uamRIPq/8AsSh+LanXEE2g hM7uCG4tZYZ1DwyIVdSAagjwNRhQ8t0Xzbq1sXs/U5w28zpA8ghVySxFd2CqKHBaSGX3Grai3lbV L1ZpBNFEzQShYRQhagrwZwfpOKpHpxvNV021uLzzRCsvp/FBPDa1QsASCHG52G+G1pnOkwxRafCs TxSLSplgCqjn+YBdt/bFCLxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV5L54tdM tdTvpzMZr17lOVtHNGHETxKS3prGX5B9uNPs/Fy/ZwKJb0yXyhMb/Rr2zuLWUQ+iB+9TiX5Ka/HR eXLbf2xSxfQpYrW2EM+kEoTyVh6PICncMprv75GN9Wcq6PRfK81tJYOtugjVJCDGOIpUA1ooXrk2 tNpVZonVacipC8txUjv7Yq8S0mOG2uZnkuFjuI3dWjFvG6K9WU8fUkoRX2yLJmcUxn8ha2zziUen KAFhjioOA34Rlwa+PthQxfyn5e0q+Ma3FtPIVAImigj4FgwHEsR79a4pL1rTIEgso4EiMKR1VEYI ppWvRPhGIKCisKHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUki8xaJO80c5aCaJ6 OkgAfY1U/uy2xA79uuIkOimKNi1nSZgyRzKwVSWXi32Rt0p74qhWj8s/VTIiW5ThVQnDlSm1Ae+B TaI0e602aKVbFeCI9JF48QG4qe21aEYVRd5IkdrK7xtKioS0SgFmFNwASB+OKCLSK38x+UFQfvYY mkZjIrKteXdm4cl3p2xSmMFzoepWk3oyQz2fExXCbenRhUhgcUoOWfyrZslsiQs5UssMIViFWgqQ Dt9oY0hNNOltpbRWtlKw1bipXjTc4qicVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVeSNq9gnmHVVuYp2eW54RBW+KqkrQ81oB0pTEiI5MrPVkei3UQjv5bW3kWdLWQrHcOnFqFdvhHf 54EMb8uaVfavCvpaYkZWMOZJCUQ12orcWrgAZEvTdFt5rexWKW2itXWgKQtyVqKBy2VKVp0yTBHO pZGUGhIIr164q8l8vWWvQpeHT7F7hTcSJJMkq0JQ7CjbgAHp74GTMzYX175WltriycXRdf3MrCpI 4nlyiZDxqT1NcUJNbeSdRZ/VNlZooUIIpPUrtvy5By2/zxpbZnolk9jpcNrIkcbx8qpDy4Dk5bbk Se+FCOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV5/N5c1M67qksdhHcWU8qyQS yCJ9wKMFrv8AargISCm1vaavBZag7WqRztA0duFWFSzvsF3BBqfHbCgljOkaRqlpbxRy+XnZolA5 NEj8iR8RYLcRJ9y4lLOvLbXhsnW4sxZBWpHGEEZpQDdA8v38vowKaTVyFRiQWABJUCpPsBhYkqNt YWVuxe3hSMt1KACtfl8sUq3JeXGvxEVp7DFNN4oaVUUUQACpNBsKk1P44AAOSSbbwodirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVeeWnny7hv760mvbcpbTsim5jYOV5H/fAC127jBaaZ FpHmR9TMywS28rpE0kaIkwBIIFS7hRQeHX7sd7VVvNYntgYb29tbCUxSTGSQOqJHGY1Z/UkpHQGd Bv3PscMtomR2iK+3ksQZS4QLP6kfpsGoxGX65dC4qRwARUptuSVArhQiLwSG1mEcjRScDwkUKSpp 1AYMv3jArBtK/M5HtEWaxmeVCEeSqqpqeooqj6KYrTK9C1tdXilmSIxJGwQK1Ca0qTUfPwwb2lGX MFxKV9K4aBQDy4KjEk0pu4Ybb9sKF1rGyRcWlaY8mq7BVNa77Kqjr7YrVKuKuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KsKvtAtFvhfX0lrbC9uxHC0zrHI8kqlI4lLqrF2O/HkT4DJC JPIXTG/NMdI07jYi5SSGS0ubRWiYRemzIY61YkIw5EhtxtlYmJRBHItpgYyMZcwwrQdQuwg9S7eT gSfQS4kI+mjVpvkYGwyyRovRvLczy6VGzKy0ZgrMxcsK9eTEt7b+GWNRTPriqXf4c8v/APVttv8A kUn9MVRNrZWdn+7tLZIEerN6Sqq1FBvSmKojFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FUqisNG1CR7mKb6x+8LN6U7OgahQiitQfLxw2ikXb6dBaqBCC3wJGRI7N8K7E713p9 +C19yiuh6HCpIs4I1G5PFQMAADIklGQujcjGytGNlCUIHc9PnkmKpgS0pk5fEAFoKEGprvXt06Yo 3bxS7FXCvfFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8rPmTzHZa7qltZTTP arM5SOT0iQx6kF/Uag7b0wWypkFhrmpahpl+kjXK3yW7yxLSIKpWgBR4wGr8XQjDaCGFaZceZLmF Hk1LVPqsm7rHCZA1DRlqGp2ORAZEvR/JNkINPmlZrh5JZPtXSem/EKpAC1bbfJMCyLFXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8Sv9TtbfzNqcjMY3kmeMhbcONjQ FRKGWM17qAa98izplvk6a31HVLhHufXlNpKlAgiSjtEGJjjEaN9haVG29KcmqWJUoPIGp2Fu8kWp KFiUlzFbtI9AOZAVSzsf8kCp7Yxh0TKbLfK0Ih03h60sxdjJymhkt3ofhAKSKjD7B7ZKUaNMeYtO MCuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViSaz5fhv5oL6wjiv 45C3FeErEk8gxNE3oa0wXunh2Tkanp6xTTCBkigT1JZY/T2CkGn7ty3atO4GN7oI2QI856FLGZLd GmdVqqgIDvvTrtWmG00mulXzXkTubdoAGoAXjcdB0MbNihG4q7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXhmterdeZNTu2tfWLXBUq8YYjgAKHiNjT3wFkOTKPJMFwL m+ieyit4jZSgEDYnkmx36YqWPaFq+nwkfW4pJQlKAXBRDQUoeKHACkh6x5fu1vbQ3RtVtpCRFUOJ GZIxVeT0U9WbY/PvkrYUmmKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV 2KuxVgq6N5ut72/eCx0+9gubh5YnuHoyg0XiPTjT+X9qp98T7lCbadp+v+nOLm2s7GSaJo0kswWd Wam55mhUb1wKSk9l+WEkSqtxqsr9eZjULXwpWuIjTIytlei6UdMhltxObiMvzDOAGDEAEHjQUoBT bDSLCY4odirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir//2Q== + + + + uuid:f544664d-7d96-4379-affb-eb90d5ca524e + xmp.did:673c0d8e-2689-8743-ba13-31c8a886331e + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:a4a338e4-0537-5149-805a-c39b0de2eaa0 + xmp.did:a4a338e4-0537-5149-805a-c39b0de2eaa0 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:62d1feef-b515-4552-a7ca-5e46bdebd44c + 2020-09-07T10:17:26+08:00 + Adobe Illustrator CC 22.1 (Macintosh) + / + + + saved + xmp.iid:673c0d8e-2689-8743-ba13-31c8a886331e + 2020-09-23T09:49:58+08:00 + Adobe Illustrator CC 23.0 (Windows) + / + + + + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\112.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image003.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-9.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image015.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-8.png + xmp.did:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + xmp.iid:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-7.png + xmp.did:073824fc-ba0b-484f-ba1d-4c100325c479 + xmp.iid:073824fc-ba0b-484f-ba1d-4c100325c479 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image007.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image006.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image005.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image004.png + 0 + 0 + + + + EmbedByReference + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image002.png + 0 + 0 + + + + + + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\112.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image003.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-9.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image015.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-8.png + xmp.did:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + xmp.iid:2449f74f-00a5-bf4f-8b08-fb87c049e8c3 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\1-7.png + xmp.did:073824fc-ba0b-484f-ba1d-4c100325c479 + xmp.iid:073824fc-ba0b-484f-ba1d-4c100325c479 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image007.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image006.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image005.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image004.png + 0 + 0 + + + D:\工作文件-于赛\2020\20200914-李婷-华为白皮书\openEuler 技术白皮书\openEuler 20.09 技术白皮书图片\image002.png + 0 + 0 + + + + Print + False + True + 1 + + 420.000000 + 297.000000 + Millimeters + + + + + AlibabaPuHuiTiR + 阿里巴巴普惠体 + Regular + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiM + 阿里巴巴普惠体 + Medium + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiL + 阿里巴巴普惠体 + Light + Open Type + Version 1.00 + False + + + + AlibabaPuHuiTiB + 阿里巴巴普惠体 + Bold + Open Type + Version 1.00 + False + + + + + + + Cyan + Magenta + Yellow + Black + + + + + + 默认色板组 + 0 + + + + 白色 + RGB + PROCESS + 255 + 255 + 255 + + + 黑色 + RGB + PROCESS + 35 + 24 + 21 + + + CMYK 红 + RGB + PROCESS + 229 + 0 + 18 + + + CMYK 黄 + RGB + PROCESS + 255 + 240 + 0 + + + CMYK 绿 + RGB + PROCESS + 0 + 152 + 68 + + + CMYK 青 + RGB + PROCESS + 0 + 159 + 232 + + + CMYK 蓝 + RGB + PROCESS + 29 + 32 + 135 + + + CMYK 洋红 + RGB + PROCESS + 227 + 0 + 127 + + + C=15 M=100 Y=90 K=10 + RGB + PROCESS + 195 + 13 + 35 + + + C=0 M=90 Y=85 K=0 + RGB + PROCESS + 231 + 56 + 40 + + + C=0 M=80 Y=95 K=0 + RGB + PROCESS + 233 + 85 + 19 + + + C=0 M=50 Y=100 K=0 + RGB + PROCESS + 242 + 150 + 0 + + + C=0 M=35 Y=85 K=0 + RGB + PROCESS + 247 + 181 + 44 + + + C=5 M=0 Y=90 K=0 + RGB + PROCESS + 250 + 237 + 0 + + + C=20 M=0 Y=100 K=0 + RGB + PROCESS + 218 + 223 + 0 + + + C=50 M=0 Y=100 K=0 + RGB + PROCESS + 141 + 194 + 31 + + + C=75 M=0 Y=100 K=0 + RGB + PROCESS + 30 + 170 + 57 + + + C=85 M=10 Y=100 K=10 + RGB + PROCESS + 0 + 145 + 58 + + + C=90 M=30 Y=95 K=30 + RGB + PROCESS + 0 + 105 + 52 + + + C=75 M=0 Y=75 K=0 + RGB + PROCESS + 13 + 172 + 103 + + + C=80 M=10 Y=45 K=0 + RGB + PROCESS + 0 + 161 + 153 + + + C=70 M=15 Y=0 K=0 + RGB + PROCESS + 44 + 166 + 224 + + + C=85 M=50 Y=0 K=0 + RGB + PROCESS + 3 + 110 + 183 + + + C=100 M=95 Y=5 K=0 + RGB + PROCESS + 24 + 41 + 135 + + + C=100 M=100 Y=25 K=25 + RGB + PROCESS + 23 + 28 + 97 + + + C=75 M=100 Y=0 K=0 + RGB + PROCESS + 95 + 25 + 133 + + + C=50 M=100 Y=0 K=0 + RGB + PROCESS + 145 + 7 + 130 + + + C=35 M=100 Y=35 K=10 + RGB + PROCESS + 164 + 11 + 94 + + + C=10 M=100 Y=50 K=0 + RGB + PROCESS + 214 + 0 + 80 + + + C=0 M=95 Y=20 K=0 + RGB + PROCESS + 229 + 19 + 115 + + + C=25 M=25 Y=40 K=0 + RGB + PROCESS + 200 + 187 + 155 + + + C=40 M=45 Y=50 K=5 + RGB + PROCESS + 163 + 138 + 119 + + + C=50 M=50 Y=60 K=25 + RGB + PROCESS + 121 + 106 + 86 + + + C=55 M=60 Y=65 K=40 + RGB + PROCESS + 96 + 76 + 63 + + + C=25 M=40 Y=65 K=0 + RGB + PROCESS + 199 + 159 + 98 + + + C=30 M=50 Y=75 K=10 + RGB + PROCESS + 178 + 129 + 70 + + + C=35 M=60 Y=80 K=25 + RGB + PROCESS + 148 + 97 + 52 + + + C=40 M=65 Y=90 K=35 + RGB + PROCESS + 128 + 79 + 33 + + + C=40 M=70 Y=100 K=50 + RGB + PROCESS + 106 + 57 + 6 + + + C=50 M=70 Y=80 K=70 + RGB + PROCESS + 64 + 33 + 15 + + + C=100 M=90 Y=0 K=0 1 + RGB + PROCESS + 11 + 48 + 142 + + + C=0 M=39 Y=83 K=0 1 + RGB + PROCESS + 246 + 173 + 50 + + + C=0 M=70 Y=50 K=0 1 + RGB + PROCESS + 235 + 109 + 101 + + + C=73 M=0 Y=61 K=0 1 + RGB + PROCESS + 36 + 176 + 128 + + + C=50 M=11 Y=0 K=0 1 + RGB + PROCESS + 131 + 190 + 232 + + + + + + 灰色 + 1 + + + + C=0 M=0 Y=0 K=100 + RGB + PROCESS + 35 + 24 + 21 + + + C=0 M=0 Y=0 K=90 + RGB + PROCESS + 62 + 58 + 57 + + + C=0 M=0 Y=0 K=80 + RGB + PROCESS + 89 + 87 + 87 + + + C=0 M=0 Y=0 K=70 + RGB + PROCESS + 113 + 112 + 113 + + + C=0 M=0 Y=0 K=60 + RGB + PROCESS + 136 + 136 + 136 + + + C=0 M=0 Y=0 K=50 + RGB + PROCESS + 158 + 158 + 159 + + + C=0 M=0 Y=0 K=40 + RGB + PROCESS + 180 + 180 + 181 + + + C=0 M=0 Y=0 K=30 + RGB + PROCESS + 200 + 201 + 202 + + + C=0 M=0 Y=0 K=20 + RGB + PROCESS + 219 + 220 + 220 + + + C=0 M=0 Y=0 K=10 + RGB + PROCESS + 238 + 238 + 239 + + + C=0 M=0 Y=0 K=5 + RGB + PROCESS + 247 + 247 + 247 + + + + + + 明亮 + 1 + + + + C=0 M=100 Y=100 K=0 + RGB + PROCESS + 229 + 0 + 18 + + + C=0 M=75 Y=100 K=0 + RGB + PROCESS + 234 + 96 + 0 + + + C=0 M=10 Y=95 K=0 + RGB + PROCESS + 255 + 225 + 0 + + + C=85 M=10 Y=100 K=0 + RGB + PROCESS + 0 + 153 + 62 + + + C=100 M=90 Y=0 K=0 + RGB + PROCESS + 11 + 48 + 142 + + + C=60 M=90 Y=0 K=0 + RGB + PROCESS + 126 + 48 + 141 + + + + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 27 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 42 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 28 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 45 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 29 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 50 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 30 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 53 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 31 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 56 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 32 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 59 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 33 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 62 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 34 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 65 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 63 0 obj <>stream +HWI$EȳPؠ)u@\H;3*3{ՙUPTfdċW_m߯~ﻫ޼~]zu}(q +}Vrowݸ75P_ h ]3J{w1s| +oWrw±_h J.u>$/jO2q6G:PůD ^(uL(~"^'7sPeߺݡh #F)}`1cUxI"#NYx4M;D}X̱G?`F!D!s~*9 3_|~"NbexjUE_D=UijX,`$ 1jBoenHJQއ?޺[g{۟^>RX1zi XLg);C_Nbgp*)FRBkêM! %1_\4=-W*.ۢ88pҳvgx[pF:M|A'j>yc@1%21$Oܫ 'Bo#o#ޙFpŹn{Mن0 +U)+؈M7IF 6yAIGrЌTVlTOQڑ3cy$f'^#((2ޕ(꽗3JKHóJ˹ +&Xi9'CA)IJ+̨1XDTcڬ +CRh&ەVz܈}Z <)kMHP\BO+r;ԥ?WKßO9Z^cĬ앖+>=~ʧZڏWd< 1sy[']wa6Tffޮxe]-zx&،yLAvv%a*6^SK,= eDc@Ҿ 1 _RܲK Zb}R׎FR}o +E겤|\GF;C.ss[ׄJd`q \)pKS;v`chfJ mz38Ti򓑌KH NN; ZPĪ%fZ_@hN3 1vH #Kd&p H2LI0靲A(f ^6PH{4B`”B r!'*"8'ef +3N@@T}9@RO2VcGˑ@u5Ge +UdA0ziV? j+q*>#7 ިjL1~ kǚ> endobj 65 0 obj <>stream +8;Z]!0lFl_$q37tH]F2IaPJMXi92U+dATDh937_%MmHsFF\40%6l0_-aHR;?I"EK_ +1&+=#qG7Ge5(KVtM(7QFLl+a0(D.tfL&&C*$8nISOY8BF&TPrHqWF"$<&I +SdF&cgX%%5LF2't[ae!1:GN(ta.6*uR'-8ZeMR@O3HPBkk/bDm/7,%ta'k;+oeh`K +7,RDHa7op-E\,`9:>k-O?#u&ODk@uWo"*sB1hukAcFnELVt4c:n12&^RSM\ZD9i,' +>$g3 +endstream endobj 66 0 obj [/Indexed/DeviceRGB 255 67 0 R] endobj 67 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 70 0 obj [/View/Design] endobj 71 0 obj <>>> endobj 68 0 obj [/View/Design] endobj 69 0 obj <>>> endobj 15 0 obj <> endobj 17 0 obj <> endobj 76 0 obj [78 0 R] endobj 77 0 obj <>stream +H|nFzY MVI0dw^qteC, 0Z8 Y?l~Uuǻӗ_=\>}yz|ݚ._^^I~~w?ӧowo\6<=~x/Ϗ/O/cruz}z,o/OП>|˽qy<zI`=^|p}zfo/o?p㧇~x{G%QYE)-$_! +"Dj/A"j!Jy7)6eb7ѱiؼfNDfdNd7%- 7Ǎ +i`F@( +M*7(@!rvVvV fD>s/M\Ivl7e ":EEmMN],,q̼,A'tfCʎʎ9#۝loYԒhF}^y/9z %QXUѴybIAd'_ԗf- ;ޙ(QEQD-DST+:ᄁV4 f ++zEQn.*ȳh~ ++V + +4_:DEVD%\`xxpr(gEe2JDDe +"*؜x(xX]X)X9]2$Q]o4+k脲Sg:.M*h*)_6eT+ +-d{Q!# >37ԗQ3g&mP]CdITVQYCzƦtԗOQ96tѩ;7v D&^%5kY.5vfv. hzxohޠ:j +SmAr񌜴/~$]yӯ WL@.Q J+^w~bi`E`ͷzpc.u!Tb$Ƞ,r*kj }*AȚ".u jtlcwn=dt.Ebѷhc +hwѾ zZ~GZe`m~5j&mQ;])q:h@ 4:v4ȏ.w#7Q͝.t;ġl(݆[dN'**(2&]ұK+";wӥCD4bfQi: ^ӉBAԨQcG^.*1Gcn PhX-Afwz{Ev+8W+R\EQU\6VSGuѼ%i|jPY_w m:,76otFG%{rhjQ@KÊViǾNtes.*EÉ f*Ed!*.w{pw uQ΢H&LHA(x%Ge:HMe2& b"GFԏ6.'+Fޮ))*E-[w +Q-**w@u8"/"7Q!OR +j?hVKKFՉMZEq7tb|g|CMT!' +MVx̹/xA9D%^f(jY І=1aekE/H=IUr%x7zO{DvE7Ěw7CdMСBԢ%|./(7*QEascxAނy=qy5Lާsˉ譍Yzd阏&5Ub:ky`gfȮ胦Ȓ(-pvjS{שKGPQ-j&.$ ++ WV6 ꃻh4hCKd|7dPtEZQY11PZgȺuG7~Lj|EmRofRoD}EǬ4]Q:)'9dЀz}zYOldeaas]t-X0N@Ξas?t-N(b1b@&Y4ȠvRE-nD7)%b'O4D3AV&V߇?i$UBު[#1&;wټS:p +-CsS]\yT +mh'䔢[R-ЄTCM. H%1A[qLʗة*6)UdЀߵ/sBW;3;5ޯ7' +DyE'U6(Nt"w>Qىsg'NMXcM&UL` 30o&V%Nv/O}܃^,CkA͖""j9kqvi3e- +o"T!v;Ja%k7Q2W2 +jJ/ZXLTMyEieMU~lE&02Ȅ#jSUYLbY* eBDV;魈Y Md|WNgHxPY͞BZ=Q8;:uwQϋUdI{û̡ԗL[΃?ßD23(2ZxD] cdiD \OĚ=3:]22}R}}%q>iŸ% jeXX>D٧k ^TK-j҈NkLtNdUԛhV+jYZE,X[to䦦խ$$r(v:V"twQ?NTFeAtSD +(h2s6XKeoFeϋ̾VF78kԆM%,((rXD@:҈;E:TߚɯzW{E! rEҳnz֪A ڛV37B=dтTrQ 3zkƊ>QDv^p V*զRؤtsYEE"j2vs1U:CmhC4vzAOT(,؜uq**:~جdЄDA|g|]x۬~eBDu@Gd&u'תpIԓ(ɋ"wvCpM4ԡ^Dh'E5]*dЂ(rLkP'+(Q\CqnbAKAsZ.6b{ +ߠ3)iv Hb8K馋y)R$W[#Q=":܏YwvODH"ޙwhH==Ÿq(" +zPAͱgEӪnLS(2 +}ȦֺRTAM䱠E|1T(C"KDu1V+> (>^b4mLTU+/0Db M9Dd4tK./1{A֚EՍs0wBH6$CKA˪ōXTH$PlE7ºu@E;Tv◁ R)(hDd]chv% ~w}x4fQZngQԮ`|:`tj/4E r(IEj\DKݍT/9E!$IwtV$\9Aԡ. +kJ4ń$3df,Hs2%:UzREUTVyr*'&yB'ѻlI-tI**.ܩ~ӿrrHzԮ̢q4FhREO`±~}#TQb +]WpBpBSgQPz_;gjP:Eκƺ5I1*TB1V(AIlwtt:C*&jMxp./iu>\O|8|zzy~ޯot{b_QOc +endstream endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <>stream +HV͊Gnkc6&A6 !_jדK -$>GA0~| TuϴfFgf1&-̎=/vy.qK.sx ԯV-[6HeG`[ޭ# gcxVhuIJkqn?bhSxn(>ag &+=ovֵq. D j6cP{R0Wc>G>&dhïS2c~j(ƐF%nI.DPdO3A4A3Kccͮ _AƉ6bﮰȧJ)d^9!8pd{aw/(Ƣ"QY% d';[[OmK:9̦{L7zIâA#~yI`Xu"CctkLo!!tuÉD˃#֤Ȼ,KLGz@&}CTV;"Q m4 L7G2 =IXu[62ZiA̩nN.PWM'2>̯K0rVKV5#z-\Nޮ5K7tȑ'!ͪ(:Y .c/SuHmIRЕw6TRSxW$RL 2D<ذJT}_|Nx +3Զ Ek|R2#p7N'3>9ϛDՆ*1w"ݯ?ºc5,4wwk'۟{zrnBǢ◙#ӓh v{nC_37~7fqҡ 2UXΟX ,jN^zlsp.&|vLNœCA -J5ɝȫyRpMd[>~YK@=ԡb r +endstream endobj 82 0 obj <>stream +H\kTg*ڈVa2f&$3 I`B\$  +r/Z+VYkJ*^녮Ej`G*(E]/[kGKݳ$J06{VKale{>yh#׌ fl<4J 0X"O)W̩)UTV(AP-ύ +Ҳ9UI]S~%sK3+gSTL3 F7(0D1 +D`A, (APLj@h0@XI  Lvi 8 A<,>  @>@@%`n=$#$3r:LhW[C &d iFv"{}H r 9A!H҉D;= y!/?0 br Pu dp, +.o:k`#<Cx ^`‡| +/P):%^l@'4C.BW! +zE2TvMvCvS-# `l6Il$6C +1-X&Vb:[mƶ`bCgav;.bX6gq'V<N< ߄vo]_C )1GdSiD1QBL'fD%QE,&ˈD=XE!'[D3M!>'6,qxB%rqƉ'u?WSRިުޡ>>F}I}RéX*"b$CQ]ߩT;zDHzC#DF;hҕ;t}ЄkFh0ULkVkviZ5kwkhkjkvii{O0aPf͌e18f0)LSbʙL6ib0ۘ=~scW!:N:nΪJueuO z>U?]?CVQYߡտ2 5 7!ՐfH7x 9Pj5v:!l8;l7vmf?c[Si=˶]u}p1\hN\7p[w%2wusW'HI!WB@(aP+ KwzAx_X'4 +—ˀTS,Np¹vB{% ht8K.9xW @Km3;y!c*x-^9x= ,K0]u*N{Gz7?z̢Mz.S6N5z}lsw9LAw'T00A!x7%l$|Q Q05K""C1DU@{.!31cX~`d"#gT0z_E%e!ce +c-[@lbo3nqĝa|6F3*}XL|2)L~L!LmD3<4hvLEn=$4g$gk0#ͤoάפZKofv:K +Hw' ;2ƓqL/2'9YBY*#ۚl1wsϼwc~ BYL nESY X|%sX|cY55,ob VfʇƚM emk)ۓ䙓G^-릑ߝZ +YG6ܧЀ)ʢ#ټ-5l:8wi|wSb,?c{d_'g o-J8xb?9á[΢ė&'=JR:2s&Svh p\491;RZNy89}_J8O)Tpvg&Eqn-9| 7*Wsїw4#~\z8/q#hngsǙ;7{?QgD5꫹i<|#4T8'htq5OSyP?E!+yU\$ԙG+}&4C%H>F)O-i|, DΈA#1n~1,b&fDQ.[B'b5QDSl2;.>b_)mR^^Vi;HyIt0T\H4X/[S}%A{o~W$8^/I Xlv2TIJJh͓2J{KyR(CHD .ǴwoW# ܊ WLcv(@| !I5Fh fd#,٘93q*1;sL0w<+*DO|X  ! HF#Z`3F!|RTbcR^j,TP]@$_²X۰2X#C djV5"3 s公td! ב㋜)Zc=DD~ufX+֋0cc!6`llfز [S- }P]G +??Wb +{ƞ(j޳=ӱo =~ y\CA8<G\Pb(}c{QD4Nƣ| *2q1Nǟp2f* TǠp.n.e +7}Q_hCc>uzF84ա7Th6︝;f{z9x$t: 硫Gm||Rc9N ^[DX{HCB I6R8C_Hk0iQߙ=HE,~F/e4= rA $s"YDN'^o+hK^4DL}Hޟ*2!w4&$=dRF/a"v'2 s{Q4:hј#d9,*'M?9DG]X[&ZKAIw/rF+\Fiu\NMES,hcr$@Sijyy; Ӈ|no5%Z +(a8/PH +zGI )$e0))8Bt(n6)ffRD%Yin9 47Ѽ"%dSt!AbQ\,ŻQ'%iBOJERJؕBi`Z6ʘT>J'&RU5;Xu.i+b)#7Y*a;%. L-3Qsi.SxxZ#ocCk\ _-0MmYMo'<݃ g7F(jY;5LԢ2s}+Ѵu:jKM7x f"rByҠ*, \l) +(1*>b\@-111# \#ƈl*'B"cT +:! 29OS5LRV*?n{Oss*; +08jO:=O?-3]WTWga☀iqAO]ͫW§ׇpUV rax!8{*Nw„;ǏL'oqCo$cπ}0zOEZ0 ̫y*O߲^ p@ xRq"|ACLjypr[ڶ@SCgYg ‰.MgevFr"9/~GW}4XwD +"ge0=@Kx ?-d#A Bi'wrMGU3sYMQ< nVspǒv FB w lļn |ƒo`O?"\x7V0.wa06{Ud1~-^:-bq]j<vdau]pqn<#㝱k`/I60)mP8*= +J80XGM[D ]3[⠮] Aо nBq;j]zz/;`< ' 'k l0]ȏwShjjB~'bw:hwlj8S +.@NN¼uA^Iڹ#{A, hnBzѶ:ҰxO*N:ΩAB)}_e%Et%_y4 .-ԟC;~&W<ߥZ{B?Bd'H9zD?dȳ0$=}̎0fAW]+NGYED JpoUhQ~Q[cM`KX&ꃴWPmQV0jG (iYy.M=Q`6ƙo*euƦ-*#!;v!_,8!Y[eZ[wd4N.>u&n:/-2/r<)Rv QÉW5C0gRRQHKQllNpsڤJI]< +̊:Gw%WNoXRGGٵR5SKQڿw}$޴ '2@/</ÒjWp ٦$Kz cA:wlqś_d6!92hgV'UuF֟QkRp𣠃d8NXJ iCO[˸؀^hECuCvxL\*s98hq=͇V?F8W JmBb"r'F\{ 5+2Z)BfoX,rX:5~RQ\rWؘ(w.#|{h)e5Jm_ s8\F_㱃 |_՝l,$2G}<v_La-ȯ+`Fץ{1!x Tx9"dAҢXXLt;pg&:B[݌l +yRqt!gIbL ˿'6sQ^(x~>#=I#)E8$B&7e[K6bq`:Ate~zf'lܻU^c̺B,\nULVU` Ƒ+B]e݊M~䞋Ri#_ޖێ1Sh-rQ(ߑ*kQ￸(H_]2fwb -~欜ֱݹUlwA3]7* *b98޶n qeYQQATP@ ˠhIE% BpDâ  4J*N2:rns^OIR55չ{{LCSJXLn !Wj;ņ'$;뙸,6+ZNxYrU6bP_x;{؉bu!9>?qOIN|c[64XCjX,ҌI_Q j'cm1o9IxC.}26%.ήDws 1FM% 3e otXE \<!w 0-=V^|j|2ڟkg;=BOeY@T +@(Ga6GĤl 1yBcE: [YG]s;"L4=lS“Ó׉xRm·Ft2"r.A=w+|适Eq{.9R+ϫ̽ J1f +s9S6Z3weaV!ݙX D|O h0J%wɣH s5קE}9*Dipћ@G"ƚ,C߰NŻsJ]\ҴPqziZnY"CESI}oygC7(?˨:x@s}߽7r0'|u=Pc :0'>5*50B- t^4Ǧ<۸%8ģc;00KA. dÒŖ]r Ȯ뺙&;37GH +fq6Lq7 x_x#CC?aEzQ-n}[8vbQ9t(V{ ہc\§qN7|_´o WZ>uq +f[%yI{en0ȥs_9?lr)G%eU-n!*jչ? XUTh)މ Rן\䕤\薻\@h4xY[A[QA>]ݷ_pm#JPxsI@h}Ü"$ͷ-A hVuF2 +}21hm{X;# P* Ld!^ QDBfPAphQQAEAasQ@E1.!D.#"1^dzW~u/ް8w]Pq~gR8-zAw[L Jy_r'#q_~A,v sĚY +q#PE]?#Ibk,-Gd$׼ɡa| NAj:‘rZov舌ϩR +A #a#Y2q4ٝX諳e cJ +=h+I|Omo. 7Y + ųuE@ØnI.*rh`L%#;y璥ht{htv,m&QFP_Dvv,X62I"$Ee߲LF +q@2^MfR.]x !*XM]Y%[u87pR~q֝mI0Ʀ?3ThqbZ n?7`pP[ +X[+&W-rrV__ ')k[}JYU.h戞J'g8NFlZ$&ٓ/ll(-/,,(,(}(f%D LMy((#խ}W|N+ j=<ڇc.L`Mt};1} +~'rmX<?%W>0)L/T-݇QoGcnۼ:=w'K|dsnB=)Mjhe6gx 3рn`0%fxfR-:Ӝcew- ?bLrh`'8O`x NPs4d7ʸEF>-8#i,a1'dh7-C& +b'jo餟k+]^_Y7s&(q+8aa+(pİ +.h٬z[l-ƫ@/ ϯjR69|w?ހdpcqxJ\AW-%7vc(a+wh5p5C x,*-7 uu)'J +E%g´SX÷9=eO+ tߧ7e+)8Qp"tiJ>uKjf&ZogzD&]Vl˧`-om;_t{y*V,pOAE9^TUIu5$^50/q+:Y}?ma̦<_`ӳ`q1tݜ]f.9{ֲ`HegYSvm>v>yNS"#ސ[ 5n fɿ$Lcʆ.<g`uP{b"oFΑ\z+6.-4̈́G`Ic?jN=tPZ|]E|aeE! 6ٺ(uWx˳%0| z[z6NWG ~9u#+1 )^bwqZ;8tJ^&}bFp/c| +eKq=oD_PK yJ}m;Q"\uetZ>V}1%R2WtiJ<Ž%xtJKIcFJ' Sqٶ7ωf֒e ^h}KL^8܃3T} 6 g\_{ͩj̼O|>h+qF|4b;uP˨֬nb_>ꖸ`\_qMAܨ}MӇpz6ޔ<(k .qJ7aT #H QqaW&" %:̰/ +PDIc=_;=uw=},¤B9PK,^@#钛*#!@ jqoRyB~S6P|G:4ZxU~zaz)0g%ƢJp.@sz'oow/B$\&iҳ/dYN_O Ƣ6j +\)LW=6amcWL赼1h7m@hw4L鋲kİ*}~ +XMF'&¨Rp}wa$u$y/VN #yP.[DR_<|θRť{3rZ)C[\VL^f߼2*:nӜHٜ1 3,s@+F}wyO < XSb?h,?8nh.oa?RzQʷE;DS+v`ǻltオb[s)>CO;o +^k4O m +1׸}EP 0+&7(|w?x,ЙfUdef;fa 19uԪYx8$.UpIA ,]Vrn_Xts;IޘbqJrsO ۯrC Y܁(H[{ZAFjYfS@ʬ>mSSAΔR`~[mp:}MsUKE?C0rq'u\qSo{.]πXDP+ `5X@ F)QgA 1C5#N$ͷmBO}KUn?3Ș%WY׋;浆zW<@B~3O#JZY;\gs|8jFVT,kVx)RG A bC8KۂhGh8ETTyS\lWTQŊ:z~@  Qݮ0@!1reaL$z'V8 KUC0;\8s9fc+1}ǫ,IP|<㌐P8ѠƜNy((+[~"758ih*mZ)45UD{hL#(11' 13i41 OL8 >fakJ.GS^;3mߚ9o"q\|6>Y1YnTҲ sa 5hNKK24T.!J^P64m)|r+ӦVɁ;X-eYGCb'0NwIݒ%G>d5= , +"{{hu+ħ wET-N_\O+LUs2*.b-?eŕ JUqTb"3Dq ֍hdXDD= 1AL,4B,ʾtC71F̢''řy^SU{WP'Ѳ` vIDi~'`8h&gsF ˨"`= Mh rth), tJ`xJP`BCЮ^nᏉ_?C v$>2FBp<lΪ[ZFz+I5zs RؓQHyC!EJ6|J$[ iԖ 3hI8,iIe>2 pŠk+~NSYUXm53/Jq }$;>*NdgɇZcb@<'lj5-#./ ߂(pY 2WO jZGZgW="[t( Onp]Tʚn4rbF+J94H Qa]ә »Ĝ=P_vDC.- + .!.}H=c-Ac'B(:i +6sQ]=-ܼa%YB+~gNЕV>tTt4|56fP>]lQqaISĺ ;4.h۪:4]D,d@Q?TMũ2ƝFS|+39L}^51\fiVOfWqղ ·}o Ls;b c\p_VseϪ_wsu辷=:OHA,}=I 0ҿP{q2r/᪵K:=Yʖ?Tt#?a)q-MpV&0Ǚs|kld%ZpJgB Ìh*}1lH1f]7Ta}6Jbs] %9DM +goKy^_(Y +q]c!}[t¦f]#lJ3k2k"!XǴ?E\,^|gALZJkUT4_:|PŨfrъ.}{` +В˧llm,Gza%#ȕ*{ݕq5%׷ EeBUJMa[~0lwe(`nY?y}ڇ۝ vz/}c"y!8]nVaM3:eXR,KrKr/0Pr|aتc&} *`l l#9v(A؈v~`BocB3fV÷] +8,?m9(. =&#}U / & ++.(32|еѦ ~C`KS1O 啮1!!]BKOmuhOGaZʇe|P( Rg,Pi|J.3 6>hQV.DܳADL p4x 3xWG[́LSF@7\q;PWSL]:Ŀ٣7nնWwT1FT?Gw8Xߵ4'a#u+q|"7XY )h:vPHLH-}Oo5KKr/ @6`GD-Gs7S+ ߍqqgni*lM?JmKjTunq[IG*6}(|& I9\ҷ憶G"5|հzlyNp;s0j55 ;ȟ=x&2)@qUkilZ`1iWJ,xzt,˿;Tq),8VrQ%]M:Lo>snR gVojٵY=Y$6#\4}}11#/s dfTvfdug˵7҆j*hs3,4tl2WLi''* "K‚R舻DV(1 +݀" "rhppM7Ђr͈2rvs(Ƞ\"xYe>7Gf;prO( M1fEH{G2G_b +Ϩ.t"pהUmTi]YWM5ə;Ҏ(R y)I}iSgK 1%l 3~ V\$?~#-K:lH`ݠ#ٺ#p?*QEZնTyTqXync) e9DJՕU4^g +S=Og~}}QKQKa{EwQ&Ύٟ!NS祑C;}U +h&GplhC_LWRRƠN3/^Ġ\XU2C%@? ®BHuRU\,XE߾#^VsũSȗFΎˎM +MQ䥨E[ N]C#~.-!@&gv?/\u)ȻRA?wx1Hiտ6Uuuwtl;o>'pϺ4 pB"2{쀊ɶN"TQ&)deʐlݗ Q ! +wП`8MU-;sb"۶uՕ+Ex"R\=Y} z/`()ڴ٦}y +4ÚuHx_`ZQ- Mm"|FHp `UUx#_IѬΰ9&Euokk #F1mzP K"sC)<zr\zk5i1tkR[J!+ZȃZ]+[*D-Y +h/P3F=ԁ% 2w湊^ +7z3ug}oG\FWk]!Ðx`2C|N`/["0f +СМ^L]@4_VIMϊ86N6AYXW\W[7Ά0_1ix$=E32`2aLEUև18~ f(܊Fqpz9@@\dȤ?ja!xӎ_374kA@!y/_0>] )C 3H1`g.vLvP : (5= Znc:_O]lH4 raу sVX`N7"ⷷa=\ ,9!7t:, hyFhݎeIqX]{okrú=S$bC q5Lk~/G`>=zݾ#duw@ uQ;lB; +dxg0eGڕD4sgxwfV h87V0I"i'1/`/T?z1zd~Џf xa\81x9fIF%)><>0sr 8/lj ZuiCɰ} 1>,/cTU/ڲs~ZP"$PUi5QWVqQiձ f V:_I0(oN(|QNߜ~B 0aȡ=Om,.^3Aӿ +HS4dTB"LM0&h܅I)iB +Q3K/gւ>ۭ^`zqQ]v(1V-n-hS]APLmʔdʲk/k `Qyub3m4Q 2>jyá/xr 裉'`jKVg馜.=kJa~FE&$M2 +8)Й( 53#lcrFEqeac +q|Iu4h2jak@@dD1 +BDWffT";(&(ND%qLsÓ_:w{w1?'B%1?Nhdf/b'IN +QDMkaA#P#(Xa#QTvUm4*TD*(Y+=)X'm9ڒqH9rejqzhoN`bH$f EC'{;mLVY;QguT2͌M:ReW?́)r4j9A7=g㣜Rt%v݇.H`5B iv@]| |tB1@3X`3 /b3cTȹ +ܼi|}m3Os3a cI;ہ;[%*MZ%({`7ә޼_ ^u #]Οq|50Vv 6W+÷)dk^uut8Rn +e쿳f^s ]om8*"UPjxRZ`z:IJ;M,? ib M,j ~IѓiԱfJߕ%f&uĘ%JKnLl >vV5q?'z pЉ=Y^)\ֲtna2F2okdk%"K!ע E+C+OSϐ =*nǗkt4XiFccb3jθMBaZ +^˗qS1ü^$4/2Kz?׋Z J@K^̘$@qpF]JJz Y'U\=pxf:^Rv K-x0@|\.<0@'<ؕO`em'AcЎZO,{oak*WD}O 0zGacK ROh) x r\{|`)Nă4@Ml@a4 +lcd0fewMޯ?{ִ/MU7~t!u_y3X6m~yʨMZ:J?0Ft#˖]}|h8I g|o + iϿ9I!\ #8Jr+;q)>i|DӠk˖?).п}XG8j2!J(9xʂmYZEK1ױul IG62C7R}a8_ZZsPafo3]2C.ktG &fz2j?蘱1`UU*r#o_J;r%5|i42[ʲlR_F9\ZJ_Ӈr=? pgtyƹ5g嶻Uawb2fFRߺ,:L|z7)ܜn'?J.1&>Sߞ#ڶ +0I.qxV̨g֊YpStaLA&PُBA?H6V<K CcS``De6Sb +qt紖nSΦ4lX..d©v~3(Rycf;pc3t#)<8erDڢy!_r_XLqHMoU >qmH3bPo(e]VJ(u')D+kԁVAD pLl'KGϕM9xy0!TEnNR-OcQZ@f=]< rxdGJ3&.'F,7Pt{TG^WĠskF鵛OXы+`"i4:r m)焄V(Iʶ9t5ߋ83oxN0=O]*\6pzQ4RXWֹ~M18@u'_>˂Kd_zC<.Tڸ4=DC$Eo[m\%&O44tU_g;mTsꤞPTA,|mXzQΠOߝl,/Xr8"w岵H[ *>-쭆Z$ctQӥr>I13/ ]~-in!avFf>\hIϥվ5Bx<ĝ*WDO/-U~hnéΘhR4U{e%el==A"hgp:Ofe`a+y֒ +ZZB{397~,X.j(s; V0[ّ +WHR;fE{!CW !ߓȝErXbQX}y5gs⡓kp"x 'ڛȣ.$*EW;6,:F~)F}#J30^6g1AK./W*$ϕ$U#bʷncB;8,6kV )(.}$@ӈ6;ߠ\`ae.mʓVZqKEu$dYJHi]`rMF娻Hp&EE\┙Zu, Z{9ݠ5j e +-@fA쪤Mdi~|ٓj*}}e"uں$$.:ztǹbQd~A<fJn\,-@JzSp؋?RryTSgmnctęX;2TŎKk$,AdGZ $PTPQ+ REl==Z;}yÜ<{]y^rIﲿd 7J_YFLVK<*^ZP >j4\dNʪR3=㚉8رM ; + ܵy @0 8x42U,8L%?1XC:$iXKC*\NGf׼/gw˭Gk~vFcReNC2G%/$uy Od.,lp4txC+ъ ۸J9pklug%.=.tAn&@-У BaxᶫЯuolB7O?3 Ȅ +(Џ&d9AY +^QnQ^aH KƦ@ ,1=Q]@~Dۦi2*,qzne(1Z#O{ F')SP%((ƬI> `ık;zO(AR></2`jyF"k%a֚O{pz\\ǤlkkKXWiPSYFڼlg~3/QBc#jBvPV%QBF E([,"6 츦mqԩ97ޗyοS{ν_TMUg;UW( t4jxj oΜ+{w>>[P'[ǚP(KF >U@*K !a<}xo166Y9RȜZcI0v_o"rloj+ug +{9,M~P.N<"HEy 8eF!sa[ccm6>i(0.$J20.*oիJ +爸% ef>@gir؆7T [X٤Gt|v؜0!Mj;f%=6UyLXCH~hEbzȞ5h ˳ HiwPnԷMyo~2s9b]g<6>~߻7<6k$No73t/)pꂱV!dDYmIMqwݵ~oSߨmJB.ORٸc\W` g,ymq$f.3]xŴeF$ >nBi^m}ˮtA+'(&i 3#ͩY_qhf+\ >/pbuqȃƇb+E8ANj*S3x̭!P1%8 l?*|`^)h`?B iv B [@T8|l6ǿcܾ ޸(Bم:-m"Z:x7qōY{{]`(G{vޝLK/nsuȦڣ;asÿ]@ꡱv +- ;Wz/cn^S['5n<rb*[؛ӗ׫^P_.n+herrbd}qXA*KzS$,o~Drm{`}'n42 '-xff"dr-s-{?HM`T +Wp:owE6lD**_bvƀ_%*[27+Gdydd15. +Z5qu*?.z4;IZ$&h,1H{G';a%`',A'D]Ůz&92OB=D}urK@BG>e{M2%è4z,(8!`q+Eؘ˧|=gٵ`I~BF\͞z0SxvP6lԡ*"O~ I`$Y)[O"OK>FN q4xaW8_OXGUSL% +/zWk+Tbܩ?9]LPt<6 +M}ZClMOJ=ƔgͺIq+q 4kvWCqv#j2:u0H +]*ZPe^;Y(g{'!2  hep5~D1] +ϚR q6+jv +=1)L6w=}6ՏduSE{I5_d ߒi>)a r1` g +CJjl3(qWj0|30<)YCgO\0B8 nMmih}>̿{7.U ׈wkl9Ť'S.D`JPeZ V׃yyM&>U –ѮQ| KT3Lÿ;l$2Gנ[j;bCz>݀ Re㾊YojS)4ZM(^*FQ/&=~G] )A^l Z2 +-Cq6rkhw!L,Qh蘶Ug㖍̒[#5ɢh]~csFX ȅPdpoǠG'I ʸ?XҊd@!;NhD+ k}/.PL M=h?/in')-$eU\x?RaTUBޜ9MO>R}y2:_ ý~"5W}Uzd;D^Upnyx@Y.uD]T00BRVn[BEW6ah;aQ 'r4h`NYwwS,W䐔sp̿ % +%BBG0, +jB D"-DpN`.m׃"_:FOf^oClġYԫxwANEKBs? h++luI2".2ő\Os"RSB~NKO3 +;F1duXbmQ0FR;=lrsv8Vܺͮ<Ds((>XGr$_JsGC:|@=cM֫pWn,'^a.XM\{ot$Iicp=612}\_gKF釓i:by vAsrG64,,@ LKnP@|"GZAUjw"\3of\Rߧ95/"=^/uJUqgR*9muT14{46? S~ffIfG6gsKQ碛ԌVMA&zUqk3 ͖P>B6 泸ETUGcOB?L`?笷* kJÂͽWSoRQFk$!dQ qAp)nP[ R8ZA"( +Vd 8utQw2Igc~뭝OZHuHrr%ǮD7};/0pMml+c bC=i4x2Wi`K4Hmf;/ά9&'; <'x |$78F\!{s:\y? 4QIb녣 +3mXA=.ܓl(ZGt"'4P7'ENWgMZۺv%.8TswPX&ן:w!q8O\3+aDHx2/qb_\%A%999{vHS!lwH߳!M +bZ@s;"k9fS]^2~ <j <%w i +uSHݢ0@O&ʖ@`}]Am=79% PlTbωg*fl]dA s \L ի0XtW*ks~s/r]i)sy]B{#O>/Q{]و&om)2 Y" +)2EɁC;kcq6ː0KĬTA/3Y!0nrcX@FA1 4Q +d.=]N&XisJ G2LRPS؜w-O4o#s{m>fBTpܫyӱ;*g"!ETRF/Lh +JP4B`́ ~-a-ћIة:Vɍ%KNX!qdKSӕ.B@K]$Fqv EܳywdWHƗ=4Bf^>\A{}Nb8ݥrCKr$;L\G5-̨s Ji Z'=dB**TND :."*?XaY5wJrj sM&.ꡒM!:O,<~Zw40쇹-mE0.dfc: 'aHw =Tʫ>¨Jmt Ā+zڂqh=ev4@Ӽo[P)M0Ú*uavƈ̊#FV凨ջV:[4nWz.ޮw_qUQ-AV0QcPwɜeGVk5 Mf| batWMw +im0ǹC.ھy.Y?># h5}ګ+P1"q8?026`0+3-] @ߍzP lD7B#/Fo~tޓ]'$^KM2~["?`md +~v4c9{0>0fV86N%9X xR;~6@cI]t 1)v GΚxnu˃B^g}qVo2{ehO=ɐ5!OY形ǹOk[osZ촨Y%lc AfClv\zi%'O@a_4$RO_bP?lJ?s&wrFu+{w-g0AhxQ#G+SIbbٵ'iVn~V2+Rg^UX:1,v € is}mMm_KqEsAQ~A>G+&Bka*>)]-> 1.\WaV2,?v`8)=^V_(n 6 T+iZ]/+Rhx_8)#|`* ((b{8T,To(JQ"#;AEfz)u1D,a3'`dlI..wqnUFFo.ւ$a/Ɛ[Jiэdgʾ=&&De_{DXYi>$`VpYy.a1=ͧ +oCKݓWIJea7^aďyKQuO`I?Ưi9,IOp`ZLw?mpOIJMNٍu.ahOϵKuqHʩOˁv[KpgHT/3s["$)8R0KSVO\mKKndje oi9O$>A͊,T3yFIuR&[shz\ +3P : GM!Fۤ= +M+歷{WK2qE֟LߔPuseΥ+-:nyN|W0h h a t/ԣ6*o&[U+tGA߅z.i]JOhye/٪嫵 7\ V>6J+ZCϡxX:Z[ +3.+]g; kʫ+*NGa5)R'{|T 3 + He+O4 p;KXֳƇuGi8ZlteaU󐣝\<)[)CgQI^Cs +68@qqSpWlilllh tJ7eOqBG<_pSHBXBD7iqSm( o(YgR hl&MbCcOYojss;i`u8|Ã5B-pZmLLRe fTg7f7eJYiw`ܚ8ә/890~~_8P;Ԉ#1IJ}CpZ%PsnQx]a BrZpmXSܨ Es\AQ\yWnJekgLj*Rh<dF9AV! +#rAFnE@":D5;$h hkl7Uu}~QZa)밁{w4uhGwo8An Le&_nߓ܅ƊosW'o@2b4`aΣtxNS%3voґb%?Vrl2S`pC/gmUcQzt^ԭmۣtq gyvaVG/<;x;n?p&n'ym51.ǜ=9 >ld0%~p=+e\,>gwIbj`>ɸ~L|(Ie~BWrĖ/vo_͕D-[rۥJn(VEj5ܪW䆤H۳Uqim 4W}# N:ǖc<Z שkm`16!-6|o.olGC7/ f32%=j ]x60_ڄJ(u9rRn4(\u#*v/_O7g`m2\sr^ +'eΡJrlBmX?1Lߛnq S&Mm#?k@n#4 lp>sy'X8Hb$aV  HXX]e`vމƝj&^,'~ݑB࡚|CC2Ii'O-NP4FKm{sAp8+lAEҫdd<<#w̓ɵnun<ڔ +-ptbo~^_S[xsknviѭsub"4a)vx5hiwMYٟ~I^ZN+&c(Sc"tUP4=2(AG ) e/Z1T1 q'RYG+7Ҧ]2Dﯴט^?ǣiǖ;NO888JsD,eJ0W!Of~V6vZ8,'/ Ci.t|}'4QޏZAK Lcfk?ThUgޠ^?ĩffY)Z4` =``w&he +!?VuEX?X}^ +f\F!wc:iLpHN^P2HAh>V$CPl'ER9謁%h"`Sw.c2ӛ(ȬȌ(hMڗY9 gs9U^JM904K6#'=Kf>saGDw|ϗ,\¸fZeם{_vza9]^3q7Y457bakcAhP=}4$t:^#G è%f-WNSӯ(RImHڈ~4t7o(ou&M6qWψNZ9BDAA0͜q UU-%`oÕ5lmu_['ˡWbگG_٢m\Fg<3 ^tĎε_QRPQ1a A@Q64*Zk=Vqa YXI,1싈 vc3s{{~ϖ??([w~ba:x珜~|fX2ISլ`݇&h^eu P(JBǀE)Y3q=VQzä37?Y'n0MJW~&[.B'#t5ٚ--m 3$ tI]:x `gF`^].ْGΙ'x%K16M:1.xډs ɓ4b$Q|6N?/i6cqv9A׺Cv?JUU&ZԪjyT\SUV"|]6bl|Y/`|}$$k%&ɞܝ1$_*Gl\W'lXp3Ra^sfan?jC)yPiYMo)< ?[Rw\(6MjȲ/ސ2NAmV dT,wp ƭ!DdČ!Za[)eg6n.6q'>QXP=b0L5fuZNSWG`n׫cOZN5~%it-5Mi[z\mHVU* LS;{e֚i[>͡dg4[nt&)AT+ LR8On~)B^6!y1/VYWUT=í2CxV K$[b8{tT+WHֲMU@TJ/;߯JN$Z?{ɛ2_[c:mMHZZj#y+Y5ʪ +%aT(xӷX}5p/.{ _P)UʺoXI*ѴW]ZvR9;@|[!E !ėTjqsa(^aSTH9s.0]ǐ<f܈ې'X +m\Y¶mxQt_GygȄәbx,_Q@*Flp9Df +j:'(`0Av]w& +E|ۧ|y +Oxg4.J in<{ xʧ]TWhWYi;: "Ϯ8v3zj0yqBO5,0N6yAT~ 'Җy$`U1@ oǰP{v% Hɀ?Bq-΂^tؑ#>. j7; a1l|]v:'`9CbN>z{FSv ArO8{QU +o9r0=7`PRt4Z{$z:)-1sރǎdIc~*{UTV $ 韞)H +bH5_cj6LM N`Ǵ~M6])/kr.>eAAq ɗr"AǍî_,Yiζ'nExJ"z,Cm tAzYƸV䲘wvaFyFxNo.ĕY x:]xwJ?.&ȥ Xs?*~:n9צ3kW O,N_<{E/=);ʠ萳h\{JgB|4je-odK7-/a +™1XN{ LQ% ghDAfTR N P'5#ِZ'©xcDe<ͯHHZΐ".Ih;z\~MOZ%SG[N[Ӭ&іĆ.OM;H+(T~OM%dP A{,p}4LL⯯I^gUSm,`w4i`rarc :9Ƴ5'5+%#Y>%IeWIZvmma٥(_Ŵ>b]:lLww Fi߷ +CAg}ju&#o"*0>ZVWꗭmm7o&pbH$9EEcX= udksXJ ,AvpD[ y~).T2o%kH̔;@T"!pKZ nD[M_h͑k]W +Ki+il\Y_1p̕ɜ4CApeaz[(Iש5|! +┱:d8'JБ5x| !2>(qR0}6y6F! 0̎?W/s]\!1)ixA+#1mv6P$bu`h[-QVkkL2)qҨxsK%Ú I7Y⢵'vypi,V I8xG <:NDRyg~V|Nļ1K;ʵlo0i;V +LFm6%ah:Ҩ0VΓ)ޢ_Bԅ3ƒ4Q+qHVX(S6Қw e%FV1'Mςٚu =08x )1HGQ;!J=r4ƕޜ1NU4QhD}+]k+cʞ-/-u9.yq36`]ΦJ +rȠ>Y!tnG +p?[舘Kox&5g BO,%!DCK;L-q9Q5D ʈ_5/;n1/klF6* Xʩ"eB|LPk2Vr[[2 n 0F[C)ca!5T3>F?3ʻRKrRP3_M/?f93Y\糡RGIQXJVW>r70 ޢee% (Ηᾗu)Jf%ftCL`.cr2;I?g D2%-N+R iwjB֖ͪ 'a91 \j*BNk(U~Fi/!~(i'҈y ߕy3QZ|NB[b 8 $H@"~Qpʱ/ a1DbgYdqy ^BX|)\؛FV:V^35el*,5o^pp,.̑s +Yuxpw wJi̹qsL(5"MTɮҨ(,~U:3 %.`rsDMEdYMAQTTP* ݀-J  +i6% QDg5[5ș_zo +} +:!J!훟/lR^VCQQc%s.j\%2q: \UU\%?Iݵ($;Bm6wM[12!u;j:\8(D[tokXWN%SdGׄHVTzUf$1GSjH&D&F3\OAN>-wgNRN:;2/5?HjM+R9~ pVe_ + l,*()Ur !K?0g;Wo*l]`U + ms*űx}/[ad'XƧoC\KDWKN998FYi*1;>& mBcqx^DiCMlm>T^HyxhS1Km)hvx)fi4P#]Ѯ\8}Kb1ӯ}p*^샮>s);9kř.X61=zX;fӛ\銴<@)8^`,;M~R~l~;mF<)0:;;poNTp89@ä(^~H`G5V;*.]R2Lz>VSMOSk6*[%[ӻZ)8 [*?T7sOkKk6jk|*=sܛ ?]^~*CXx !*Xu嘼xOrrw|J6~QП4e2J3{Fw5$3f8/ V@w89aZ!7^O?G{df[o V χdR_[QVUVUR^R"Sݝ7zѾK*}OAx>gstڢ S"Jq[z_n6_Vvg_PZڽ_(,CROP +!Oc2dKsͮeGR.`8̦ +>F%Vq4 |r?;|S8Y$0;[#X1+~r\ Б^랧8`ι3#ۤ9j9j +k:yQr+_<3X,UܼsYXN +pT&6+vl~f.crp4Ia:QvJ!4*l:r/Nj?;G&5 泯lД#$<{kCVŃM*x+n>̥**V=};vcCh6W^Y]z,w$w"G&CT+LgD_a7=y 0 +%k*F6c {/eJ70fj*'! +6&4t]zNouwh['+CXÉU=oJ5B0 V@bA.8״Iڰ=|p ݜ:lIh5E7KnjcT;p +ٝ{΃i/8ڢ/GL)]7(ڷ;$N|c v]*!ۗU}"lŅRBZ_xT/-t^Tx~\58Qq#yv&IE6"1iȣ:g E8EЛdaJbѳRJi.%GvOI{<Λ*GMUY+oj73?(Qw1d4FM`Lg"xT$-xq?8O nXYAxXu ql0=8Œo!Zp.pmfp8 2 YBAn܊aСWQʱԝ_~njC=i& ҸJb=-Mpl,Yڀb)Ew|4ºFBuzni7Cd> ?|=m۩'`黧 Q{|sEAFCś HAcс⍠;%NhetCrCz}v Hͽu^ѐ$yTSw{Т]}0Q+ТSq9DqcJU-n,"Q0$aKɞ" + +aPqEu=m9ιw}; }d}1ar 8}(?DoWaJ6vAz7/ W?7CU;Qh wZةՇU$uNq'd0<@op׸ɕZa(vp9"`!hK;x`V"2pz 6X?6@xO/-~pP{Ix"}[y_0T(Wb ]DN'`"G6(;j9eSKD2g4(ҷgg3O`8*L-[b@ +"xVaW_X +<"{*-J,3fxǾQq_AdɃ򝥻)g^Q\UyKC,f)S{Cm"`ujT92AWSqMٗ|ʱh)C,:<緼ܺICa-g#Om](9|_;$Xd6n>wm7jIqyQEQEP%;⎵jכ7)>ndN/ZK=Q֐\h\{9Ḿ?q0q7,"xaqzܩdW6jYfzk+WjDYp@fY+X\d˷,<*mfF l^+JFp2=_X\.XsM&i?xN"cl)h^EbÚX~9̓!aXpwDNi +Y~ω(LFuedwHZAfH_*ga |M$*#U2X}Ek\ |<#bI0-p@d|O<9`6.2`\tKd%M77wYdŦ (^]6yO|$$v-G 3:;]Jɚdu2MPFgl޻%=PM/C;;{lf +>O5MUH9}&WǶ$Y2pSk.Co j [q$Yjι8xKI]7 ٥]٩I?G/Bƻ P2G}H<%l%YK<8?ǟiU\`3; }GS6Xnfxn!&w#*HrZٿJ!5Xdx 7 _vCHˏl-k1q#RBz!~N8:rN>&NʛA"|d]N2l笞zStu>BsOpp'Ɲ~d])W`_?a ͋a; +AϋW`,'Y*#4 UW"~bDiyO\ Xpni+>#aĆeᙇ,] %1 +F$-ʲ+8IWqR8,xUHKkKjMuܞ-i[RAkY*ox\)Aݷr5um;VuM\SPƵ~Q!0P!h@ "򨂀! F-8quֶv\WٹsΜ=~Q)z\pH 8|3n-mvc'A  HșDxF߀l 8ހ =5"`Gsm#K`5C1L9- y^*Kpr?OC?iH;쯈.a‚u,TLL'x!a.t1cz9߾,0 *Xq0z{ZIDzѳscC3QPK1ض&dI۬||(N5}?\1E--WBx1)'MRnDQ`Gg14U3Xup=ج,@^w[!*`5/.38.$A'TED3w(eF# k)5HL:vKx/f 5om咢#v1K(*\Fa'\ Hl7/6E1su(C|*b(h\g4ZAIl?)8>}\꟭.QQ[N7hB"kdUfևZ%tؒ\yQN=Α=US >]_~Sbۇbve;q6\#mvI{#y SP6 +fNÈ3fӷx zXAFԏ`'89&YAd;+&[M¬bxYPOgPCtbuL 3ͮvd ~ Y<`@nxki-rg0lU I=(,v:#}pM?U'g % cO֞(t/ly#%V0ǗXDajB\%ƈ Pwc3~;{|K[OΜN-W2SRZ:#z + /9~Ƌ_ٜ a@+m`h +:UîbtN*H{\#un^T"xC'mOQ~}? ɟ ŧL3eJ"xŸD:+z/@Gy_\(e6i1NFdNccs>*g zf=iD7|JxC<|{8lbyQZSʨ0لrٷNot(V/Zk1~&g4.3J0l̳BfˉD 2FpG)mKx_R[]nf=?LSF[Vtŕc8@a\B\$-z [\ dntp=/+A$j33'WRux1̧r{r֒!K6!&XV!iwSeEQC.%3qKok`2Vf r{3hg=[=2RSꫪrSCKz`8߯`{a8cgaI{kREj.)ܥvX 1簼fBVz\Jʋ{".QkKWc4)|=d~!Z|8$\ynө|C|܀<5nRP舲\`|S~? +s\ kf42z8Wڞ~=ᩦӖӖ"KAۆFǸcqD?cyNPGZӯ(w#Iaa⪥(GbDx7(X5ij\iK|2@ƮÏiVв8Sn{#\WH؍`KPo.s==58#16R|tu| I䡱<8%3+N+S“)kVLzg !Gbkl[]͆k2/$yXWԮ*!.(uQ@PifUPAElD4[7,.=*6 Q. HH"AF=ޟnsHw47ZϿMIT"?LB6JURP\m& 6quZav·ޚ~o;˽o +C#XK_rxkzX C4- xy%ŸvɄ%FC~$i=~ G +^/bE6w(n''{JF_K:{^ A7D`;;E~>:Aw@OڢN$ݹqSĆ@vk߻ ܗ\ +fh(ǹ8#_M>I. T¢ojna͏ G&Oocx0һ&U(syvI3@3=hM{a.w +x3>L'zh9x#?8> %vt7w]IY@,OC,;a`M)0E2`"( 8 E S-ǵ[ͺ)eL\ ThFx3Qھ!r5F m*fm뜊rrgWT xIǽqY*g|&\uQ/tsq?4L30 m&A/Zdp@2k"qQƋUGrQ=@NLW&'51Qf"}-C(MC=\_GqLg٫AD$_F][K•O[*_Uhr/0ZZFB)) USC\(0,SL('gD4 uL&E̦\LPYУ=Gp< +QCzP.;AĵƳEIb<A>n{!^` +܌eifi3Ng`nqilIlaX]. $BqYB|**3! '졔(ٯo.|;Dj[C I>O ʾ;lq@FV^ 1E#g^}8 cXqI҈XȱCiGO 4LjuBLg@iwB=i8׻=:7mD^^8df/5ؒK-M߲[<|w59v`Hy}foynO!U⻹"ZXU6#{18\cnifp|쨷^5oħ1p?zފhV{6g?ɫ; zO-N[n)e:dq͠v8cȹK+qmg\e`iwp)![BYy/LF_ra+qB O m%Pt\՛0>]pQnS:r} \g:d;:swVDF8h łD6VUWT3L]SK.JCJ!r@:9՝R2}!$lN됲 62ڹ8Ұ($řDIY%f]Te@D0éD +@(3Drp 4 Dw!og~TZ7L4j h$()r:_2Huq ;h(ĉONbyS ,Ft]9A!u> t&rFn{Z54jҐVlǁ焝7i ZB#ƹ{9 +!nƞ6|fVUg1&"uUې;Ј"^? (ä!8I{{74ߊv {i}VnV06MG![nNv!Ȑwbc#\]_zshD~ڈ՟}Çd }lHÞAf?-#Qpnkw?wW(=2wZ|DTz*f7.'?<~mF^svaXt!g@ֲ"uF+Ճl,mWw2H?%! 7H?Yх{sߺ0s0 +ivQ Fh q^Z3!|őrjjj5|$jl°o>OfBvifޔO$n8t +fn>̟ \ +;> "m=5;~m` JuڣPkdtsQX{uRJCuTO U&2%4%8u??0 JT{4Ea~Ck.OK+uQ +˔bv +q^S`hf.WnCn45};lÞưTB:'gb1̃ Itz?fH(؜@)S` [%}!js.)z0T0^4'ԓ37πXkIF֩f_5!խʶv=B +XŽ{jwTaӆpοOyHtȃ7bibsMxWpd⯨ 6+_QqC`&7s)KK +˭Aѱ;C .]C}őtL#iܯP^)|o/+eЄww0ƴyd=p&*E V +|.d&JଌKƢ]D{bf-5wl| q@g=ŗ('H3X{1@,|$Tf+ KtԀvӷʰщ*yGPJ]{aS;j>^ZzIq4+sX'Lbj 2j:pq13m_[ MilL@5SSuaY1U$X +kE|,  hvLhj4nν3q!B_ %Bv$\]/ \.'_b3n;#8_:BԮM-“RٟMnG{.8e?IOa]۲o8_+YvWbgk{+3 (AA“ܺ +}I7?R(|u^w¶3i[ېI`,w }ྵm_Dv?s0f {&~"_ٝRpe@vʿLXXpܗ<]v,R1&6pVfF\]b8 lvU4PKDК:t4-_}.$~Aˋc˸#E7b1w/q[Lb:[eU ]u= i5{Xmy|UVu\Qx 2x)3r2UH >d6Os8D*u=+u Ui=k`IYd1Q, :iz w;!4x2x1.j>SBak(ڍh.@q&! 0'W)e]bU''De)WO1}6H% Ѕq{,\F,/b +8Iա#=j?.cұ +YtwBQTUQb6Su3C*x;|S!{4q7Rtdn3e~)B6 ]AMyov;lv:Zm=V9,\Qp; #L p%` GAnT ]mL۝Nfՙ 9g%'Ay爧}'4Kf4?‚-T(ױۓy{Hef<G-8Ed8/,@)X̲;AlC):/@Yt+)%1Z~/~Vc5㎆\'խM^$W { :DhYQpt>DYt!^_׋P,Btyt] +C7~F<`A +E>E6ؽ ",#c[h*81I<ՕPǢ7bΎbjdK_W3V^@y6YiLVT_P_$M4^E=e>V1KKOjjmU--,#.ֈBYpTXv+%yti[,6צVG_^Xbd^ 4Au;.~+* LBBTN`) +Tg/ҵљ}b*9g nd&ٸd1vu*S ; +?I .E%$; +#!6_SX|\7&+-,80e^aioHGoJ՚ۧܤ5k{:qP#(C@JM3iիN4$l%k`'6 f+Gv3)߁F 6lEZn6/) +1a(c#\&Q͈TVW׼L[?HzCzP-9 _ĞIE7s㣁vA< zz~WS>i#.R|,&ΙJL9Lĺۃk;DQen2VVD5U׸h#է*ƘfŘVCêVy="Qg;7^P&)hH@53 EVYWc&Oqv_Pp{8D_~e$:/NS x){)HEg,g+lD|lh$"*5 e$B|oQOzPi~ ͐?DD-b" +;ys|d^/KLJytU?lv S$&cD-7^1[PsZ7tU=T *EL Q˸W.<(Hq|znFB]E^[z׀s*g~S_-m@u0kp5hqURq,\N/NíMƜx'{Ci&읃- }oÍ`'^Xq9͸\HHB꣹80ٝ? L:Nǹ2IxIYR&K]*ivv_ox +ܕ}p?# ;>a&?2,r&-+%>Sj*/?yދb~!]=TFF8b*7[Q WUUYZI]ۛ}PNѐ{Ud67Nlf^s4FͿ1pa^)bpx>FpѹLɵn")ƙk%%E}42&rxYL@0nj3utv |qkz[΅~.Ć!iV"ۗ=dL#6uk59bDς( >p+5M,Q5>u #(k~!D;ϱK¶\QQW\OĐ7yԣh=F.XQqa 3,0 00,3*("&nY56j''>~s{߽{wHwd-uYlFS`r\C5Ia~w(67r5,A^luZkju+wl՟;Q@sfw@[S^8/9m~l7f5UE3ԀE_~LOOR +$Ot?Hhd~b^o7?:$0AМ +g~, E`KsWPj>p#+:nL%OYkiŏ]yI`% B/b>m^z|%Գ.xc*V^0 I&k  fzJ@]VAh ?Y*zi=eA ++FaS[\JQK( @<̃0B"eUw,"X\~ ޒ +)Oޕ= 1(hM>"k֦Ghd\wk5 Ɠ-)_w"X +r9bBAºtJи5j06]G,okz"u,UZDsa.ՔR7EiJvyA4`CQ_VoR#]UmUM hN栆a0cuqɦd3HcB gtxur' &T詮 -( zg 9Dh% ZwE5A@酢!E gSak_nv6Qg]y +NXirJ~4X( u|i JVrRض2bkC*`_EѶuҶv>Iϸ6-8ʊ̒@(k7IA8o=Ãd@6\=JM& +GR$t {C wP=)QJz%q`A8cH N}@!`BrtnKm=-Fy7>Hϯ+G,W5Ϥ@ve2 >}}?bURE]_ެN8\46q?c@ʸC(a8?AIk}zfNSq,N/Tza-bq<ۓt)Ϊtu[@ ((w+ $܊!` +("("(kewֺn}|q|8{╟&t +K#NA2 JMf}ɼ81ojS>A?p}f`1~Kٻl;h99H"8| $QpvPN(bꑺC((N7-1hgyІz;rZa͔,H$s K + W=R,Q(4'47^n1\.*PLlNl΋G6?vDKתl8nu +;(v`m_=o.phd8+li[#O"%[3̱C#?6*;H+} d^OJJP+/ =NdXfX7l`0^&wZB {mdM0J\t(Qag!oFP8Qdh{? lg-cy4Qx\h4qzEfD' \G%\~oݎ]E$bayQR/ӣ:2)VV`ͤ&at5ʋ+mUp0AgK;ڼglmiĖ-jWO<K,t3tvg2_;Csd"꡺+s>e|šs]w롣0Bگ{ߏcw{ڻ)G3]ЦQ׃M(lCvvB,i3!b,aM;%ɵJẑKETjo -zr 8BgKܝtF5R0nҒ/~ qa +p/WO1KR@'~`N>Hf0z[&W4}*Gtܶp i'-Y)jzf{2ő(2g_DnfZV]@*LJ9us-R'-\Oo?6y5pZNd[Sǝj:EmLF 3VǩedBY "BHX!ưl +SA +;GOm:yci?pys|rbyРWBI4 v.CV4V0~hDj |X Krz5XXb?gWҲY)$9ft(![s-=!8֞1!R~B[`?Y»j(\"ueux^&#D]AC}~ߘ0۶gQH8ѲUOE_żMHDhs<}j 霞8Y$ 7W):~$١*B]uxUsPEVTpv6f-m\w ,kQL2V0wUڌBPMWa.1M$`0haO_p}IL\T+FC8ցb֞iSc!Tu\j֕ +a' + b +E]Ľjy:'Z.Ime;K"7[&uLz=FMDf$zjAwG^q_6s,=E2ك:DzaePo"X:\\|JޟԺ2\fil*u1Y&HfymsS`$e7텓̖hM ZH\]V>C8W0`^9єQj 5>zvF~F_]Y"5-y0},YpEф;mXl-a+@3/ SYɲDl~5MoV9*Nz$'3tvL{`~yxAʼy-'N%-UX]Z*t嵥Efj`e$Ai^^p_I x`DaWmaˁ̓gG> 4L3]{[C!MaZmku2{]'\,;ȗdR!E=|h%'[G1g\s1\iU c8Wr6@[XwC~2~yt H s8r0wA6VBdLWN3L"A:5`q| > "^H3=Wtng!gy2dkzA1rv߻e4}} +\1B~ꪴ1Q'TE tΥY|1$۴k|v)jh >+J }_8Gdփ_: 1}WZOsPO^b ^9Ȍx KoL.&')Jgz +)8_N넦Pު*n㤱;h a]1]f Qm1=! hb^8Nqtiqb fT-g)#*]Η}CxP?i h gn"L'd-nŴ4P.L۸9\uWc끰%! ZkF:3 O_z$.1 LGisZȴ4 M f`E vJqs @lGP0qՠ܌khLf}z})&!֌: ޜ-4?9~n'JXVET6iU 6%L։TX +4~!ce( =-Nn/gjթk <*QrzXkpI,À( +((`ĥDdFAdS d*ui܎U{g6;̙;߻|4O_z+|2Ke5-ޅi2iLòNM |ə|Vش:jбH;ڷ+E^%QL`iVR# 5 M4̸yߴwm.DMVVN BXA!Nԗ4YC.&_8٤bd߁#Snq&'yZs^/2<ŽI` q`:?'a\AP흫`A ,x<XG11210mnv-/UkrehxP+;iiTH'T<Bz}zZKbŏsI<`v'nMy;CQ iQFGs5,)/A` -or(ztqeu0y@_{\GpMg|O{qH[#9yf9mx}]xYN` ̿cJ΢VUv9mkpRּhw{= + qI'B{!$]F†eͼn8Z 'Vtz%[wȇ5k%V77|[a/%BcO9 )+vp.P/N`DʑTU*ȴ1[x\pu:mϭ^1v-/m|0P䣰6yԻ)jΞjM,*¹MV6g0@irl7휦N}Ms06?84_%aX .vi%y10@ "V +"OKHC6F6I6 6ۀ80g5" ++7gm' b)8fp."nFˇnyX$ZX+FC0E {/Ƃxu#]xuC!ϥuo(;'8tʈE; dQ8)yBezML|b {t)L +b +:#Z)lzUrDm/Ѷ&qrUE E[`<9oA`z0YJF]]rᮁ/w׺rz.(bBd5RW% LI`<Vh2bl$}!Ric:D/y +_`+/c&PA!H$L̍Qhw`o1T ƤEq,eCM2%Y>Z mKIk3Sb&;j*[/*WBV.?Ƚe 4R8e:6QTUt MGs_%\3LOUX{?2bO%Idy*\YRxj)o4632MU=A' #+.Gr&RkJNgPw7pn'=‹ngyiy)f 7!'PZ-˚` Zzuq1bؾ n38P+VOWKg4\xu`DZ3;cFNi-ŝKohD[z~oqfVmgˠY~ ݒӚӖ\%E"uE? `U?b0 ?}dHtf?E +>&mrtU.՛hI̴.V4ݭTi qu߂"U0E _.C{E`(ػ +,vJ#"ݻ8ab7{Ck[Z1p|?x}!uvpv~TNݩQq{n=LkuZmd'hb@멮 ~D~ԉoq[tq6O1\>C3n Q$ m<>jigܶLy%wae;?xkhfRVyYNjٕ+(% LNI.^wKa}XM=^}Yt0[sc<3;sdvۏW;d.Uٮ- ibGRRTjj]O㣥6p}x8%(rnqC"cq,솿,NRXjڷ*;ukvKsG_=_,` +I"X7=)Em`"NGa~40JR]FRqlD],QUNQGXB^_2|MgpqY]T12.ƗDQO"if#Nk-F@D06Sy?6WU"S٦ԖvӛɆ0pPJԪjEK$R_M0yMMiZz^?C =RL1;ήvR^TZ /r:dTؔ NqOSfM\Xc(t^d@ܥя[ղ|ڜbsPͭnJ.]'ۖǧ-ʳcIʳ<$2a`s(y7S-|=3e%GJnpd1 k`=XiJb~73TWnXp-VIg?]G\cXUN6=yNõdY5{Dck`1rٌxevߓkENR);_+ a9TfGnP=ndtg+SMoS3ҙ܈D'LnyJM?h&_بؚ0r>qO`4KP[]pYbں&lj%@F#͗ڠk $eahihn8wwi/':G!%E"6{ox}tvE{CݟޢC,llh[7 X?rItdFE]Yy7_w.߾aEcqE"u!MZ%MZlhat WȲ¡sE +|ZWsS֣9RBGT#LU#FU"?#Yu)T6,lqsq(mih@7!ޑ]!se}#'._QP`َNs?UՕ = j&B@@$"74-(.,B+ Р +7"& l31q,ǚ8&Nsjǭ:}_W0(@_6++8 +M\o~[ٲ;e+.\˓-},{0 Jٱ (rT3TIF =ƹum8 (@*+F5Q+*+fq-n aXNokMIe]J<4Z9L~ XBZ K̄B&&[KDʻ`@/a]ߢ!4|- Џ +<{'S'ڹ#GӕrW4Ԋ= Zڋ`DA֔33=.)쵓.@s0_2\Zo<ԥۃ]PN*Bc]˃ĊP w)rb +D8K;,D ocԑ5I#n"VeyMNuU&{`+]3)w<;n8KM} _0#H[wP@ .(NhסVEEDtvfF0++"V珟O=Ơ߬IQ'$^v1FMgn?mh?~E \IqMIMuQ B2jTTʪd5M~!]-nֱ־Ó!š[.wT>cc)UR_PXm=`h04yZT}}jOv0 4W{wlcxVsh{c1IyEw'^z +j@I×X@D^/+bN =,M}Ov|ȭָmB!0nVM[4K )IlQTWDu +ob\;Ypfеk!-4ĥo޲ eA`h$!$ +ԃ]@Ʋ˶PxKųPMkbXFhohmޢҡugs3'Ӱ@7٘6a\ɨ߁%.~,z[3_'QfQqI +}4_7MD +۲PM֌: (s>Ga@^#ngMbsOVw.0-IrgB/ [s}s +#VjRlڼy23jֻi%=ԯI_jgqU R|vc4l1/. e:F:Ckߡͯ4-c\^IΫE,`l_͘\o_lh2OYpLЂ.)dTJN<>^N)?ʠ*r`pP N iT/^ռQj^5?7Ixc4>ߞfzV鼆T:" )vScLet>`qCwɢ{Lss1~ԫhufX0plu&H*]8n(3pN7 ~X, Y̡D|cʽy{4tp~RU-4PQC-=VyFړe?jiK0ɘɡ{7h{!ٝ2>(3V.[>du"~GPEC]_sQkņld&g6%`7$'qS\Ȯ{UeI ۱i44X%MZf +c"89Qk>嬧 -{~i{NߨLfqj,řU^lnx|ȥ8む,QЁi! vKNeR6JT<f{Wp) Ko̮wY)1TdkF\ +n>A<f'1(C;Q0= x8sLȲW(Swu6TW<i Y̘tO9:^J,M5&ÿ Z>>2\#TF!W+fGpi/ Mr,6RkozͥM@-vs5^o>Y,|a>}%4Yі~5?dM\q3Rx!!ӌb%"$ NNO=ޚ N(_D`άSf;B-8 AP>ITdsy]`+9>FPnX{93Q/,=(12L<b-|[h݈i_u ;̊ Lwdsӕעd'f'(L2kz}<%1!U}*VDQ-QTnHgut4?o731 +%`pB3*<uopR!7#iN?.w3AÉ0wl{ſZΝv+ΦU@].2BuQBݦWחIjC;}SՆIUiJMt"Nq7_Р##'c2 I-3ͅl/ W/af?BV +ǤO׭kתjYUT%-S554 `,)חxUƥqvrp0psn~!m'3yRHi\JΫė\-x"[ PI9:<5@дHA"r"¸m Z7ꀈu%b*yCpp@DeD A]1cfAd@ (y |뮚74u\WU_߾;>sZtT v#S.nHt C cx S;}~&A]X Ac%U +GXa#:p/Tj/^ó`Z"j!.NJ >C.YҎ p8i`D~`+=ٺM|}л3z~S N[-:-oUސu3&`$g:w0026nƕ h,lxߍ2‰VN0ԟtfJRĭ}t5bvB}idz ~Ke9rr_W%i242!R#( 3bB-Iؼg[莰q~ՍվQb=]" Ww׵4݋z}W᥈5Lo+:ƨaJHcCȤ,,lz:ZZxi#.*7t +-woxL"篟1^ D%')D=viOi@Ke`U֤͌eI.zו]8P-#p|p9'xs4rB\  +,TRmispx\<} ^O-6JZijzU:yZ2\P^b*! oƧKϾTL.hk4<;N>*(Mȧv2zsg'+Akp[* 2^ftЙHo[(Y7`Djn+kY}-V#zvwm5+==XP»w`G>s3=殇wl=pY0?O`./a\4!/p.|<5"34U`K7|>`#JFyb0L_pV0=-?48<1]AiDΕ"ўi3߄9`͏ƅM+-Zj6v6!,ŢQmPf8+ +gSEI$se1bv֚DWq፜E <JU+]ӻ}axÂ%-Կ(2b5 I|bXxVkk~eaqqݶo5B#o2R +x؎vΒ4Efvޓ%EFzld: |(q\AQYO=6Qnd5+( + )(@f7qbFc(₰rh쮥]]]~/iC־Kʮ K}Ih,l+C7}OX?u<^Z*Zk)jvII ҶJ&8m|e wzo>g$ U W )kmRF&)pNU0qL{ ^6/0dz=EkWSZSۦ"l|[]MW"`OV4/QTjhl6vWUׅ57qه/δ2O gBa;'xÄh{F̒OOzdBQvln˹B,}^) Mܙаx6yFu3'F2J ҇s7e Ƅ -9 6>cx+1Rj=\uQ0q ۞V!bˡC]oi!,>)|Y>cgG?IɔUVo) )4eZRGPxeڵ|qcYO Oh y+|/brXI% '0S;y)h&_vz ɧe`ޕF8 FJQf)(fEwe#cEy"Q鉳h)%0 vkpvTz`W Pպ1GعTd@tRŸb@[/gnRx7JmJ$r0"}9ŢlJhaH@c +ahMp ;4J,&Gs1s-xܑC+ˤx{[ɂ>;*ьY  `#;|? jx '7`!7# } 5ISaԀS3: Ȩ]H1rAgpHUHS8{#A"Bm~070>1Nܴ/]\Yx2PY50$и5W-RgNOOP.s aezI8B 7H*dFf49^{ `,O=LjibVH%~C8b΁~XvÑh%KB00B^iҍ'ϝNe(<(氟2OB80%*p#Go0wfkAX[Uav>^r$eZ~s=_t;_Y[2p4A@{ 4D=ňrO%+ʢ!i=7CIec1QyIMP[=d3X?ÿ7}}ՔM.)3/=؈$R;i=l-=p,ޙщiw0k$ }_haflHFfPNJuѹ;sUTo1*#4Zr-GHs?܊v_MEF?*[^MƐNa寣[EZ]G9j](#ƄDZ)!u"N̺9c% vT4%91'3]J=~;i98 + l!tj>R5Osw B]#Ta:䷥#J>a(Y  +j͈9zB~2FИߩk:RJqFZ+`Yߋ{Súz7sG>;!*TH-yD&Ays˲V-5q\-;CCcFL 2>݄ٶ[ud'盔Moa Y'N9^TZX_t*WNqɧ> +}?' q[K?N@:YL @;.vjŬ蛟0: + +*.߰-vĵVUVUkTa5u2PH\]M&T&Lns+gd Պo~2|q.̵=ROTLԤeIgl~a dR.!QڸVf } m:+ରI1={IH#{#a![9.YɀhnbFEu *|1p+ŸM,p)7xf8Aed9]:^u9qU=Y'?'pWcWre+wTt*k5}9ꇲ +۔p'i K!R銯avԡ(rAWaR<âk .j1@rP4}0xCow5 BZy`Yq!~u'oдۙAqa +;FAXG]|Ը$tC "+Hhg!s/.`a%B&y"w6; X'v'G RAFXXS8U >:*GHpPr\UXb`,;ӄZf3cj!|o+H<UQߗZgf/ IE/\fG2N,R.h^bMT="=,IUQWSIPN.e;^xM=nxIKe +*>wܽ<\|־4saƀ6ԝ]t-PTed/UT97y5⹰ɱgz ~nেpEaA|3_$n5Vy]t3Q}1~0ס9z߄n.`M>SR\AMei{H+O_LGEhEQY"҂t* ,ؖZ ZS~OP5zUԫ=b';{ |B>U\OQ?2>:_(բzvQG 7G6l3d_qm7kػy *xc4XcbΪy~Z8J;5k `+{j'+^~#EXVu*)+ R egԥ8d |d` a\Tzڐ^ +s6gjǬK% lH펱CmXlGiσe[x|ye5hnQaQWbH~3Uc}׈b|b KǯkH_.e4d6]fC@4p&B+|ȷVC܅+m3پZ6?gIb<ӯ] QkN;)ٹ BvSl'8wčJ2ӚH{DـyD1ELInUǗnvm4LAܐ=IQ)n@5'[RQXYPUu`APc^-4(r <)2D#qM+a` V4\4DB'ª*Ej2$/!1]^0ɀLq56<q8 ^VVeFYijrGin<1.bK׶7=30~f~.ulxMAS^fCFGqz[;؜,DQ˞",?$$ %=K,XK70@N4t"*o?ᓳ} |ɲKZON>ˢi|Hb[*OLqC^d\iϠˠTE@@H9GwɅEE"UH"Tq5z#jSIekcj*;#Z3{­\;d# +EE3 /sVI1BX.rƞ /RKs/>'7\|gQ_oz.#hL9ŶʅdBUT2չDcHm ; }EǃďxS\VWyM{.N|:e,k\ݽwnV={G%/Y?b>/2x2J¤=.DL# + "[hY\h& "Ne2 +c&I|ss> __C}dd:[{]ڇG).34H^[7KD k(^^ci@$cLNUB@*[Y1MIۓf%oDa9IsS5^bTVNqD)6 syb(԰"sܽ/q@<*XmW} vgx _Lj{Kā M&oKt7uT5b̬Ve5P>XCd?VMZb}t7wD ͕>j&H؞H V"'/W1ftLw4D;F(*O$_a_lKTq $TLǃ??qn=qZ؉8閜*,aNI~%G/US=hg7o(P`d'>ERXg{ l nw\{{`_ST#K݇dMnhUpud5_<a-️ُxm@*4څw(8BzuHJ-%Kr*_ xa$ ۽`j64t3:]n)5ٗ@՚k=7)HNIXǟ4M5IYe/7_Se &:"& jtw3A%x4>TӦݓa2HF(,} i믿bvV ~L yJ|]S}!>o)͓#sNP\C&l( ^:8jm2 f]:ßm3 6r 4Ta.^23)|0$3qZB#ƣՌSOk6OF#Mm:^?Iq~&%olqϸ c)֗Ɓ_t18?DhOǐ,E&[c&Bg+yyR8ZRwƅH^x5:>z=]*Vf6)dݬpu.:d oqwFī=be2lĻy d`=+_ Mb#Y N? RZlە=lA0H-DV oy<|TRh]f +[2^b[x /yP2`LZD+u鵙uI:\ηd>Hڼ4Fq* +.܈C։ Wg٬˙AI6( +bTbKG"M:;Q9PT-,(pr/U 4(J,59&y;x3Ϗ$>.m<|gfcKTllZG +(b +& q \((3˫9=ݜi o:,9tx_ucp n5 `:bG=\iNk ^^]xXXBX2,ꂯ\k)n:~Ht0-Ԑ#܏HX`贚=LsaU^Cދ_p&ddYMF>6xhL}ҥqs&\+:giY"i5\6j_IoLZ&m̈́w# 4HK45˴Mg!B^11ĕ1cGsOCŕX3 + *Գxpފ憖oװD i-Tա#uLI + ?XpD7nܣe4T7kO(YU\XY]w9sfVc6dm1dըۗ?yge.=xO ~eNF]Z"I1pj{bՉfpc00UsEN{ qzf-&,؁zVjK+[dA"XinV9=g7r"AQem~|/*-/TA)ƬIȔgF4c48B(5:96)*G9ZluOC몋1]s=7g!MB"bb¢eqeNdr׶_5O Gl}۬Zo-2W7CI]24*(`56<޾^È;pp{suDQwkٹL2ߛ+By%g;d՚^៯xoNN`fgDK6=ȔF +"P wZ{ ڡ>Q)0?,.oإp$1M#> +VoN_vW-v6iLY_I܃>܊`MXb%|+ހn({j+dK\?DXG;XǴM ' ׄ<-hSSr1+mN~Wp2}c |)c*-qe&;Zhx>"=5a(RHW)r9mTz]p"r4e&&}Q6K3B%4ǒ<, +%WXN՟4-HȌsrRLΥ2 N띀Qkb}YM95'r 6y4%Znh$tD{ɖh~8y%ӡ9ڦ'_u\ +e+hb8u,9KF"hQ*Mh\.S\)؉@C\?+cI.qe8^a + +]WGK"9x`vIذp<. +O6DQe +Cgs]dtZp:OVSE9 MS?q1{tG=SirGpфwY>)}|՝a +rs `uuL\O +$:F>V 5RHxw;ſ|C7;8ɃL`Z\nCΏƚ8 ϿbkP 5FX$UH܈ +AGX+XL5!=1|ZFj {+n̝;W݂/D-)0 C ܁E'+ْ5A`廅(A\Lq6 R 5J_ ^Հ-EQإn%msjtvZNi HLjLMvE=6-TEp V:{V=yCqOuEqa$NwNJƍ{LTd2k 8Ue`Dddga5TFEEE06 ] c[V*7llOqN}]~D+pf?:^ˢi'T}KsG,f?.T=m6(Z.$T[_[P1Ah>bVTeծ< ۳i`p`rg?NWxÇĺ$>Hje (y/?V#+|{Hf5>Y,$ƞت%=!\Q*=\Vmc1rC3ꉱ/ʣUU&);h~ts';7cwe#M0$f۱֎"bx4jTT +Y5FdOLr@^׾;!#k̹E IF962ɊoI*ٿ{QJ_$/ R0E׸ L7n~$+NQSbujV!hp; nnRۛz6 E@hGipy >c4(kǟX'G6o/=b!LdRqF(p{Ze~A_?V|{]""CRte+.yGG3UeRo9+ 8D z3LRdr +7mUy1q@ 29ن,[6 OWTK*b{X4YK V, +@MfY8NSy[i "=V K9K&'/pqgx&vhg/6I?9 +2ZoDk + !TI룖7vsW7}M0||hvԯ6p/!3"(1 +4u8}ΐg55t"bŅ>22$:͎ ӻ+rzp qXfj`*|\ʿ^ep'V޻NRaCN;h#9ĭph py7ĹJ/'{N]vޤFT皇!M\X@w[^A*&xǧ(z]bJ>b:M#GaN-nN.n*&Ьޅї8ArC 4,>9!87c} H_5^5kL?CN$ro;:\9e:c$>jJr n+evVǷnƦT+HzL^rѝUjkΈ6]91,x>X a.6T~h&.Xݦa>$)~kڬ/|ay +Grz6̤ V*?=R%nZ6Zˍ¢u盈iT{!>0jA0j.zg9{F +UJ,-VUc JomÞoknoc`gPFa,,{<]d NJŷ\YF:S<> HTkfs sv=_S{z!`NJTe>ulvOʳ݂,p]qY'|;v@bqCǧ0SDx8QDԔhJt(ug]`Z, dgʊvi_TmRj Q:Vu6_eS%M v;F:\ł/| f蒶Ș$gS3Lq1gV+*21knr:7Όޘ 1ze#r_"!ܧ xD@E+&r" 3 &XǪV~}_UwQxs:SL>+דCx^k/p9_ h + +r`s}[N?O}\,!ov_Q1wGq=BdyTϔ 9UtSĦj&ieJ%tU`⽚z@^J_nTTXDN,vaLտ +gT`J}7\G@{(#+/ + s7Ţd';TQ6f`aྴ* L[P7dkySyM ŭ{Ip&ЁNuj^EY~"1,%$L6̘cֿF,Yo(6gp3|M_Jo +\u_7y7\NZ,F$›XQV-YS4{|9iDn+DvndDh]%Lyle* H#QОݦmz!>z&DM @JnwQ~.{QqnsP=`:;?ư8kZ]Snqzgz)Mw:̴ 8- ?#v&'IoWD`U*!$` ނ&';! zwYqJF![۩v$ +uOQ`t=Kp.e,2+`8Ä希3^آH/T4)Sz]3"yXs6I"2d}s#r]-AW Xk*WS*-[od`ͺͶkaص̞  rhD_,Ws!ZtI9Ip,}M4n;ZBނ;ׄvl;A +ߖ:3Juʶ5|q${0qxͦ}[q` ,?FI*(34$3+S2I:QP6Sה^Zc24#imWgK\UYZQTQ,)j?;"劰&7Wr_T)W^f:Y^lVܖߡ hYG F(+NݔpMP+޿*7js2A{b-/(F02mD]`=dQ-l!"EUg&H]ԝ>_lDP2@O/RsRoNSpemic{tnJ>-q\2놚n_ }q@ +*N|1OD\bL4 a %SP J4cgp2ݛUcw:†'& V4'(d5fK RP2b7ȭ8c1X8֔Z +Y{5N+ +c ͥ 8vba̘p 4j GU@7 ~0ÊBBZy iHR̥ƒR`DTCNŤeUr 碉;ud8oG< =_Nax'tX5;yz'7`,l`c)O +bjVHa՗p'8 /Ĕ??ѥfNή?ke{ `ˣg``JfZ$:!@' ;0t' +ZTb`zL@ BKZ⤂f>ydCcg*#?x8v u1^)f +ej|sŒR0B9l޾ۓueiA}A}ժD_j.LW;,+;BXjdK71LVaVZE0 $0b֐93: N +fnqA%[VS=uɨhw5uڋ /6m kÿr}w}6It oUkUt&0IxۡȠpxRVeLރ^>8oXhX/ 86s 4ZaJN#2NՖӌ++RiN\#YLHUDn +i19>71o?ՙ$ʽ7cv]?.1]lpD) +)aiġ *Md2 4EJ($v7eɺ&g{{ǾUv_MH'HdZtZL:f`=ְ.%m}鍡=[Zx91+![?*Yq5|*mm +W]@ƒuqn ⻌sEPgԓ̦Ԟ#tس8ໆoj:>~kBzRoF8虜 '7{)vTI2 + +8:ڴj>x&,MG5|@^SrA罷$2+i$oڇKF8P'.]Էg&؅"4[;WYPˀ=R春Ofgokm4O +kkz|GHL&"Td %tm]E p}a^Gj~-$(G _$%('(Z,$Y~5w)'H8qf,Kad`͚Vdjy|Rs9tA7F[m`{mA>/'7;'0dl%OW6w s+1Nz\Q0>= }K|NtvGe h<0p Twf$9 LJpD1YH³wP.=`6mF[x%~KێX _痎*\$Vp^La":~łNё~FXC`-,`ZP8Y*X{=GOjqb>^){Bܲ=t ~ϘIj!ɨ=9̐2thIqH.44H$.HEhr1~ַۜ~߻tsɨHU!b25omQL#XrΔB}QlCG 150/8E84IaO1ReY[g'KteNnEE_DuD󙊫yIܞf'=΢}k6MmVmO77vSG̟\S6la:` ;w +Ď H໱ a$S C<:19*'D\!a 1oΝӻ>Ox~)1-)-IA"G`' rz?쉦z 5pmTwWVCC0Zh[(ZƵኖ8X4sa}k8!aF;mڬJ\9a|8Z/t1V.h.PQ^#)ꄣpLGNj_-lמ8/=ݰאaU)|neSrz ;a`F0VÉJ6Op*)]^qxKɎٞmeۑlKfɺȱЯ2wCQ$ys\hQuA&a&ї {ܔ`5|E 3Ͽ ~İې0dp˵*^ + ~0n^!θ^Ϋ9TNhb6܁ F(Dz{Y__W!=HPC/_:|EO.#3ا앀O"&gbWv  ~V)[u7R}WaI}"eqW~OuةKGopp9ߐg5HKFgpV⨄/1d`5$ۃ Pc`Cu?.W^JoaKK0-#9';;';Gy7N컖Zb̹ a O%["#.S߱%T9td%-_nB݋}ZdeB\Pq9MLoKW-5)*.<&]:&HGՀ88U!N>YPe`m ƴ)x{%e` VIG g#B>-*z}[A'U)s919Ï?3*dB~'KT7wW-THMŞYeGv>WhZ.;T3ebj-LIJJ/8UeOP,mܾ2˷B,(SƪZ#w򻨶40 f!: fB=ר kWTK}n4|oߦb=s$t-]ǡ%jO*)|mZ\Xw 1ƴbpM8in \3:'f`+'1'Wt{c&),ji@Mh˺̏џ҅?7V[wS\pRlJ+[3'Գ{t겮Z}EjJՆm166uqG5uaM9Wo!nE¾)`AqcHRZ6  a1B6рťq89{/ΙKy=o}YlE2\<@_3 O&1;jM˯RrFCWޥ1f8m7Jg;X`kaRPgvGĮgф>ֱ[N4q8G0dQDI9+4s;HF&’wYPr}5V;FBxTL\^fäH} ֶ.tEo]j($)ѲHFܜP9i/":wE1d1I.&]yyZhD3~D*3Y҂l $tBp_/>z6k֗7|j,9U"O?d"RST M[PzzQXIS2fPlce 3SRsPLxTٺ]\6| 'AC6n>YgAca"E>E'STFh(D.Kd6nf}"D6=MQ  WsC#4sG 3=qc0 Ym}ޟJִt  xac{ \?aC:~ESY8Aspi{~e(0YGf?BADb=9NNLk浽}ar3Ic'I墓yS^SFΧL`{N}m 3 Cү0NBXƌ(oڕ% f|E,7Wk4!Ybd&wR=k/g3SYޅWqa-еA4OlD/-'jr- C=3?w`' akV.;z>6\;|量4%\ЕU_uJ|:}KbmWA>o@Ȥ0%Lc6&Ci?}W&ڏ2OM>$#хqs/)( b2bU{׋4TCFaR effľE츫/tz`99&řY rᇵ\5?IEyř$]17)_e.LҬ*W):f*kfy/En!Mhf~qd1l}ܭӑaHa4 禎_˿d{ʓC1Àѿ K8c$ʅx;#H%LpbfeJd^l?i5{SB21{BM8b5Mh=72%Qm0a @Ж~?gIOizx/0pR!pnNoU7J-4[0(̍`)w.a((;W +fYq,azϛZE=❋nYgo{M$+ g#H#3:oaZ$4Г]UhGI6=0(sVK{PZm;ػ ^q: /DV%uBz#띗Zƨ~>k/_jن~>ДUW]UUfp%~7`|DK8G볎 }+.Ǒ.MC֕xP?@d-i Ś c!O{t@ԭm'p-,7elх33nt8Cq&?=:2:DꀋChHYADL&c/Y[(ɍi4r +ҶI +i{Uq5WK) /t_qr` JQ89Lx 'x1f$i SGYkaȗB;C1S}/Ӈ92رLy~T>l{%9sLRR3urGHͿwttt^٪qPa0G69eY%9TK+Xc' U&.A@Rɧ;x6>q2>M7Ig P $Sңr"!K j'>%*ʿVI5)Tb|?lNl}`垽}6bfo񂫑9HCw +uu]g8Kz7EADySAAT&8Xaz?Lrbolb 5,,"EO?Xgd@`1$DjX䱰⼗~zCg>do]mrJv!^`G=Ér|9FZⅪch[qB$A,NKTv"ɑ"-'Zƞ?U[Uy.9T!9'7rFX3/7w+ +e+u--_Ԡ|P/< n]q2RpB)=_*`ӂW+ +8p!B* 5Y7Tp#~>We6VG36bEE)FNSӶ\*TX%ߩH*n +v0?l-5bȼNԞw&٘ 7m4{:nIGI'*ʐe uX 䣤%.K#/8~}YSL&A%Rj;t YC_fY@侐Q .lRl̨V+*,uKsfPS.RuxڀmG{i<7 vZ,6o<ю1.l`np >W9hnfgY?mmЊb +^%.%ʻڧd:p${5ɾ1647K)lFU=g戀t|jibִX3$d$uʄ˵r +4:Jlo6 CfwV֫uad QI?VCȾxNUOb i#͢gJ&( +* .WF+Ȳ֪{M; W,!V#4 ?«3ˋ-rNV"z|S\VDO  )bwPnW XQ:َs)rp2mVZ_o; B~b +Vjok5;ÎLDF}i~3w@}%3 6C[G𝦤D͡kW3X9KlPYE!0!Av+ӧ4CE^+= 2/ϻsҠfɚ-dƻDtAMS˷O +x7 ݫF:btwu]4NP֛%ԫ,+-J*&P tNq+ʩI>Ga2KVU[fpo^aGm#,q.`.ރkAUw=:6:dg76M"2Cw~JHU6D} ud{%RsLBVF*gTǺgG_׌“&9TuX|#{ ]╸rOJa9 )߇A 1=p9~_ s{ +EyHru,v69%{& K{kWS7BCΤmb_MȃS;^pKn9 S~"e5Yl&F|c| 8CzPEG"zmٷ5XJn*.y=]wv]QP> +PSkNg +eIjXij RP~evz<(we`7i. xym̯bI@SWǝ<.4rR]S: # 3-v:K:5]}jWG:Z-#wrrq9z`2ޢm *32-,oLR~wiZx8K|zQ@2˒_);:oe5Wal +K ;2e69ش[7,8sRHr-eO+^hXf#m@SUz%OAZcUmU=; MqtVX: 5[lT ޓ*+#1l6[:{1p,JpɒE=!raǹWwY|,"?Id8";'~^J +7z@P2QP܄ \y}xO(zGНf)9v:ҕ+ܭ|/bYي"Z5?0!`.1py5b4N1sHD~* ̻; I +v,ofQhVtMh@tNF' Qei2QSOSWY_Y΁dMTy"N {aZv}b0<`ڃ0! _`1s2W $g0}S^ZhPI m i;qdS=X5_ ~ +D?ǐesX/eV:\`؃`J+NՌu0Ѻat8*#y-BLg0.# K}ZӣN1$).,y:y~TT;{p"@Xd @@  % "*K%aXDDuJ]F;cAy{??8j~SOS4pNbcf%ސ_qz`!)b|rG_O\A>}~T$V #7T_9zReߵ 4b:9Ka< Kdhع&iHz?e6e:G3/@^3/}n(W oTAM8 +a8[ fP +^-(3?AT[ +Pѿgڶ]!Ex_vc .|Ԣbg8oca/>ȉ:..Hi*ee/ +I 8y@i!xVqdC;O 'Hbnܺ醳tUbyRi +m +}QmrV4lR`D +{Q +{-7v[u*oJL28(0Ǿ-eG=xf檝Tǔw0Z~_L͍͕*4V.P'QXB@oT7PƉJr|u#l:r!yӹw]jKMBS_+it.ABh`]xgԉbx=0{ҳx֪J(x3#ˊˊ=4(#zR&ل>$1Ƀ&+F(QkUQPna/{.=1Rz"]A+Sϱz.!-|,׽"_{i!2|NE}ƗCҴksά=9Dmr)s .6]ou$u%xɊv|w6/4U '4!vxLUO"g=r̾2Mk1Uk[0E'ء +Um ur:5B>p ƗLw ,kFl X ױ,ζwI(幪7CEU,Yr(O\XPTAuR[%)I{'|*:Iq3 Bߐd>/KAM(-;&K +E|i֟ՌGv_DJB]QᬆYT3m<_dH FXK6/$fP +3Dԡ.UYB]:r+R<& 7aWHٽ"^)$KTcju j;) )9KFyF8 -* u /#h(\!x4.eAc1E\%G~/ѭxqv@.UɗeeL^B~D_gc.9+z3>U%S#&oDGQ`0!(4u >X@%hG&n;Ps||[p/-gnbW'xYn VTMUad@'wKZty~~7K_OtZJx辔Ե7$tmv]Gp`>i ])͍S Ӎgmeg0v [isvŷ9wv갘u爲ސSQ +~3\Vi;<[,AALŚI}M׭B3xBL!&M2ޚm%Rsy<2CLO7U(C,<> s܂RyǸ\Ny&8w`Nq8t*eݗMOбV{c +tiX%q$K#kL7Yzj׺g&ͶodUl<ۦVc")V*IK*ڠ1TSCI K +M:p"7_#tZ՛?`Ym1NǛz/l,<02cobv=lL06xa (LlLpX t{x^mI.*F a3 +0 :FJeG$&Od.6몵zVgѪ˱cN($L;z -2EH!{Ǿ*hB0E J/o(k04ס$;3]M=c;A-kG@?qklyTg] ߧUF (SjQE* +.([!V -BXH*a$-lX((Uޣ3:7̛>Ͻ+|'Pt0;#-[|:̞ +e^2$Iz)O>j;ցhxգ nxeLhrDdncJ!q ƹ9Bgw ~ +X=VMyᯮVIre6%&~(/kUe^iZM#|ۏ\ 9[Yj ++ i X+EiyxMJ6,`G3!\\0UBHC/ 8LK.wFՊ( cGطx`8P1HO$Y-N0;9gu]85)T_bc3U!E,PWTP G"TKVɥ?#~.Ax`AijqhW^T{h3Z S<bJY$/%f^M,/p9- 1ǫ`)+ejX({qn%аl/f);e}!n2Տi7L] wv]v4O3:)"ӹ6oݑ.u| T V7 )eC[O9)R.qs\>Vp=B|"2դ{UB8p\2}|=Xr s&\=2۠͂?Bdv%1*iUn32;L\h{HO:JU_)VۨPvƺRkuچ@mh[KUf7^ux&_1ifkdFH!.ȴD"RVREeA}!|_Scn^A,aXE|N_Z%Qd;_voDL0'0U1YA|úif'(<2X o(b3EZ-GU" +5f$hQ(-q8;i/yjV` Z6h[XI55ɥ`ᆍ,o%$?(ꋛVz~>-* HMŋmP9ZT[bǯaO> (%<@,u EHJI9ϔZA ?202YM4]]\av7bs >=*}_j$-Dy`30i|vXNLFNDP*E)YF^i/I4xEo(55ncpiGYZp +K؞8h.-q8ݷf Slfd*Y'Jb僿{')oZV_wIJ:k^!̯(k.t\hWt;IxJE9 3R,+(tdB 2 M$n ޅ/n-.BA8Mr@%r!8j#cLjRo1P筺@fC;C8#e+7ތS} @ >wXzK e;\C|P LJ,]WVJ'Qxܮ;/a(-Вp/IYc$75 ^&s]TE3E jKq$!oN#>g9דCG>;vӸxe:IX7VY `mO1tMt㰎)#`a|8=Eo8(GGF!';DzY.&4IN3~C:Sl,|I$d!'$a$$$@a Ug3#N33873_{_y[T&c]sV Sz&5ʫ {eT'yF^ +G"-ow!M$R(n uR veNscp6._| SW%<6=)۽չD8$C\gΉ&fxvDnHģ؊+%>5 Cy(r^E-5+f#,-**ZȨЫtJ~b2@y5%76nL>-$˕̭#H2ad+uU_3+M2jOFMh J4BƖ|T.r"fhJ*Xҋ 6Z(Zi+%iFlx؉9idjjT5`vHVjEQ$,?mVTI~D9 M}$4"L$u>Yݤ$EmwℕݓA$sNZMOd^f Ł#cm(x]3- 0Q@f`U=9H.H$.Ñ X03mtd$Laܥ&^ Ru<}$rφ;l i/8ja ͙܊9|(!ycX/%T +s9SE.f3-hW]A0Z\H3aPZ= f =DG'F;3ӣsF>MgN~ZpxWOtNG brQ$ kkjzj!^!RGȕNm|?!C! |:W#'g~1֡PD^T*5ŵ:} 3}W XkW8Kխ2c+P7ÚAq*7 72ZZh/մTЁX2Zj  9M(KUG6|Tд>&dpr9`}g Oa/Va_Veܲ zjmkd\5%հH\ˬ(*[ρVNV3Z9 =S.Yܾ i$iB Qj- |OeEkRIr ^?r'uC-N]tȺΏ(g2 +Yn=uRkU$K?/H5ƫK]@'Ӫ#e7CG2ҞI-jn#GQ>a5w0gA'.]_П;ԡ1h5D4T5JJperw).j8LO| +OxoA-RT|;(W$Qf[S(ݒ!6FLuuCmc=ʄ{0d-8;z9;3`uݩX~k^`=@iC ѝCc"S5kamp,\ک3G a[-Rӄ:I+;Ozd|s}cغs*=Ӈߠd@Cs':#^$u/0 $ y< ̨tbk,|vdL߬GIyC?PA1R`l&' '9Ofd[\n_R_a͛HmOt e5>Ir-HRgn%STa,<^Qv[uHY=^dP6ⅸIv`IqҩC4 MT¢*R+Қv*{g>j_!5Y'0E7Xh)1H(;(s3oxl^6C;-TEJ+CP% p*U{'*h> -lf~' EE- .q_=X#HmQ\W9sSŸI@Mzފs4 C+^M`iN:#B!Dl +Vr +V/zv'9r u{]b}l81_ cs ad9$#w9 MDKtӭl۱糜#070oovpJ5OՖ$..ʢrw*1~ t1}y sTF&uZ2_$a0Ǧ?ȕC.SoNL-o;{vz9I}n#oFߺpZKf8 KPMp{- _OݸtozMS . X/BsCUM]Ţ5/͹{K;rD[1])tHv\eᣪq^,ωis.9qwwz7r-}Cܾ0s_O:-,]V["{Z;aΕrXpdH|дʋ1IPe_`=֯a(ΛhO"qiPTWǭݧ)k⍯[Z%D1"n4 + jD% 4"4 ++ 4;*EDQ6D8j,f4F99rpΩszuDG%,#GV_Eٵv8WG*i9ڧ +:= +mbAixcBv=bI.&Z1V + $TF1.Q +EWqXɵWm,.%Y _Iq9 S#nB8ol>ozn]uYPmnrdtPyȄzWWn+6n+?)H+{8X +Ҏg`ST7 #ѩA,=m~ųS_FՖfH'd|km|-'[2mWOe l&zr}+$"X`=S#Zn"|4Fϡ80.$$F)(Ą +C%7fG I=^v?m^O6+CߴVv맘{.x_~vj1A3`#4 V\tԾkTXn/Ƅ,^ap&{\tŗُǟqiOmT0)z*c:TBǓof)1i5$fm亭0"FZ"o(.¹`1 E$@;,_Av @R$;4DJLŦZ?a˝[^ͩ}/]v~w@3  +zl]UoP@ۣ$͘"+Nvf>=@p}ћA<2mZ/CzKΩ!{bB"bs䏂㎡3ND˼|3W ?YPOphկnpa਻ +WN]=#,~HZ d۠,g^v@D#Ș;NUo!=8 n:/x?Nmyhn71F]t:kȦn*<"5b8tF'+jdTxmR[L{L(aa z_YS1+}c;S&jSRxgђ'{QwB(Mq#4R"i4jY%[wy'>ͽ?"C zLv쨾fKׂ2[YN Z&b_V)j)8S1yHVUjV3ErIGkqEhS誣#ю`7t-U^;#W 3= ӕMB.5L/?=*g2Nc$MliɎ4~hnG Jphb6qKxWt/ew^Zjm szs ;7E+N;Sݮ𥭱_N(g[i6F婳κ={t[!MfF+WruN3l3_{]>\b +^}ov宵vܞ^"NhuP l9i(%Okav͎anO(%JQGֺ>BE< [}clU%r~~G`c2 DiR3j#ّ6К)E3|!.w] !q?;S{{,c* +Z ZT} .Ďυ2z:ʣ j೪"\]_1*_L]qַ$~ +IrPf^{<ƒ;[d.5Uafq%/oNR'{p5Œpb(Ɖ|X"'3G "Hƽ,=[1&H_?Fߛ4H1]W+\Jk25۟⺕%?a"7ִl'u8TXDr4{PSwŒ{okeް.:>P^ IG!! «1 +P yU]wjvf_;s|ΐ`;z4|_Ѷxj V:7 k(laV(kLk?T=,K smw&KNN%pa{JaÑ!k/UIߋJ`+,^,BE)i83:C TaM \9'? w)Z-r~^"*#]筤 5֝j`GYX7px4f$@"Wdx>,Vl C$dhn#^bĖD6!ARviI3{g՗Owl,c# Pw&]s\mDD@xٲGfKcGKHiFzNZDj+k$51jR-qG42}n =75GЫg. +`I3FL&Bc!VA&q) . 5'ϠKX`E}t%R]im!R|zac~<94CW2VG/#`lDa%B[mtՋ!ǝMz)W)[{<6" | 9'e9J^WUxB+o؂r"z7tK4\vJACֆ<{t|&„* 熆#uu*˻=e**։!j446^E"?9 + Y ϓ>W/+^Ze*9kcyѯ13ˢ곆ּBJOU9v؁*Q=+9s70$ ŸĐ =sQSڹf(67=#n3\oS|w1I# =!ۏz7?Z?:RM͢zkdh$8 Oy}|ѯڦ'E CA ZO-D#kX#G7|6 GopD3 $"q0$br +:Zz.5 BO2V/ì[̻qE(w|[sHq{L +ZVJ=U(-i1ța~b%Ya# ``k=BR4PP@++6 K޺b=ZtLHd<Œhe~:O=#QᨤZ\Ͱ6 R +L6XYaM,ʂ%;?#,>FٽkhwHyߌĐY9{a0u完ҫ630|c䡒7Wk5VW6.P ա +Jx9{\QM2Z:p%B܏3b^coS'Y:&:^IgĞ'Є0&5su]h xWO{o3WKq c9$Ay )_a{$yjq~@s &*㋱z,`|ɼ88hZJbACjWܴOS:)ԒjG;4p `h(y=P=P?֨%އ2h7?<(32_kv5 +kn4 QQr} +*ȩrP 3  @PA@1fM[[f_S=Vy|tqofSRh%}]'¸qt%nI' k71̺g,'.yi >k~.Ekvk6?`jȫa%lvg2&[iq VDr+蠓}#adW#X%%-=Jc4c]1& \ z:ߒwqV6_yCLY3!stL 2G_čhZI +Sb2\Wsb,ha`K:ӐΎBR ٝ/w)Dx)V1/*})6h㖑unnFE': zqB;I$Жݽޝя\[CJTPH\؄ dRX[qV + ++8[)r3'qNC~8ssFe߁AD8$6W(F2 +j +j.qfq>T7+k%9 ,`,w5iMlp9 ǥCi|V|̓>Gkΐ3iY&aY.7;TU5|Þޮ^ͫ!nwGw{Fij>~Auŵb /+,A)\**˶V6;E8ÏuhFw۞K֜i~| g! g[0ϴ…A"~axq3 fi=[H6YҘXiNѬS4ܻ#nƳ9o nwcmh l1p }:V8M"Wǝ=ЌfO2_ ޸.n6( 'S| >$qm81S77WpӇ P|k0ʪp̗|I6epRS9s6l鸉tNS[p; .gXf =} ~lb=g U^tJ]PqATUWqىɊSJG ?{ᦼ@zdz'OfK)= e^s|La?|ogRTt?լ3ь9a*6TuQ.N(ĶT۪ɿ]\XS588e2>#pzE6#tË,폮?\4nAdN*~i8SF6$Ax~?`&7X9򧳊Yp,($WZΝ&eZFTFZPro[>Q,/&QT0=A<7cmSyh l^ +\0jw'$ر-E4"":*\ (@3M`Q" k0JXqk:[쏭sS{ԑ؀ r>H{j½B؛a7'+[Y7;"{BemoDSpk~+-}{ʔ9zoM,AP C +Q!݌D,\sBaWq edI4Cs"34BI;3A,ޡD_o9IX8sp9ؐ.p V=x.B^f*l*~,*(dc5\D):$*IXJ$QHI=㿛:&6>tkpBQU)4VAqq NJO] Z<Г?@Vi;˚}P +?;3;!kg2h^_yջN{{ofѼO}d~v].LCO_<ĤVQv 8Mڡs;jX v&\%q6bf~VܦYiӘŞBB:C" +pWGzN> (xSJ߮l5P\%-@03INONzf{/eI@E?GY[ȱю1ƦeϐzʨW 1G'G Q!~ {hpW +]az=a#XrFGQ^e1$ȿ>b~ZjKq.$ HmLBD[Td\-WG:i})% ]`Otӆ^Lkg^-@ub +BQ,x">_֘ m]tW+QJ#0٥f46Id.!aڊFvX~ K֐_vWpQqsP6n?F`A;a&@2CZ0;#lz JɕLJd4AJaqXI\D-nKh@ +ԯ @  {^^Qf{!,+*j(c2n4?4o|BpcQLqBٰo(K̄$;[5My쪙mBi6.9/3?R'92;o +ɿhc~=n`wЧXl=,( )d$譁OtFEqeqtUh4SV`*F-"Ѐ M)iY\5qaqcLOz}d7hˌcnÉxx2 9\.?\cUےۚ{r0r9_g`bmGU7׿M)WT3Wdhm7՟oj8{,'N-8g6 BSL:UFැmi%2-5Xٝ*j FZ+ ,ibTrѬO7.bVek2kjrufms޹gkn%bC1Z~28y~̠ӗqŢSLXO]/{,L\!ك٘~']NU~D򾰸LбbXڶ3$tݩS3FJ%WК`2'3l%9 PF@2^i'bEU՞V+V6(W‘kI5O*yD䶶L{U&\VOpKZ6gCBPiUt$hYHzLJnWl~U~J-rfו8*OPp`%cɇ$[e0{j#5ۓҪyzy)cŭBq_?d7ztwG4E#2BTђ.puk-qiKIY˗חޢR8t'v9Mlgǁ=5ڠz惟тУaG8p3g KcTAHgA԰5hj怆c2a!B7&]e8&m]/]m'I=~)Qʉ<~c0h3ey,c3y-XF-%}W_?H!_:;O6&ӐLxY,1 &;6F[޶L_^R(=ϫʣqs\biH rVB" + GOyp\saT8O 04ڭ`j.S(B!ߵ\0D <||+ _(efbm%bNU?Ⱦr$ a.oB-<ɃB( +Y7Q[`1sVe=;NJI`K cܢww;U7 ѽ f "J=:jxbEpK~LceVqx,߰9h +Q~5쥔EocM}{gS=17d-; S-:_0IUy$-P2RXq.XUsCPKw2#\WT=B9HK*f}vny,y,9PCerjSC _+Cp` {i^2ZtjzBg'ň;}uJc,~y X̀Ed6D+ΙIf8&(ӷӃ<`L-LU-NQ/$- O4 !TrGs.G7uqFDli3->_[b\jmS|Ss&t'\McdmB/J5 I +3<"h.'nJMɫ LDnxo/K84P{2>;|Җ+rI0rBݽȿPMOUbMKM d\[d:=1OUŷq,]$e -lUqyIy !-Ԏ=`n>XA!H\ǂZ|#͆O΍#Z/=SB'O$k zn?J@H՗hbZ":&702m.WKj'zJU,yV#k,T:J=zro*eh~{6?&$:lGƲ\AQi7+ݫ]=N\]㊮Y)$ !* +"0a徔3 = \ EP5bŃXYVŷڏT}=dz;=l`b9ܸ}p0M`im }la3Rejrfi5{ 1أyAK.7^ߙ{\_3)(b/gC14tU- |R@^~R.~ u2ú2Pk WaӝC-<x ?$I!lKLTa+"#*ـG]Y^VYAmcdPS~|DLIߗ9mvShE +SZL$`Dr&M$Ģ^zWH61ӣ"e׼55唓]Cb>z%`!Camq6S!X->A㛚8-$Kc$,IFӌ9ⓒ&c iSJVTP35Us@]l`rΞ/2-d W] 9.8a+0<cg4 n +Q_J'[e"`3 CJ..nA!]#'S4 GhA{܋Kdd98(x񊍢%])*VK9 1A! X<-= nxQ>YI q |~r4G0粱 PUUQ[W{|\BфDM>| +O"`e,L._z~*9q'Yt1 OYS` iSC_T;Ş0m񆠻u7| Xe W#$`-QX; HN+e{nH^o<7aE|J , gwI6|obƐC^6p W\+) :NB́Bm 3_V\~n[[6Ú!#Ճ8Q܇wNi:HmpN k5ҙ#7\~wvqDu]1d? ŶKN4TH/a;l9,ndTezm\gȰ]QҸ_'v=wok/8JsQ :ttTxP>2F!OKq+n"FtUFg%ʌjJMJU1}*!v}Wf&eݐNz{tzms6]ypCʊjWoMn|mYmÍzZ:>tU'W$%C=ʷAW=`HIbQRa"lïpo]>9S))V:#V: 'mmE(y[HFh0sw=B6Ҡo鸕YԱ䐤1JJ I͉弇3=(qQ% Ⱦ+.(݂("( c]]vEDq}f2G'dԌm<ԏu.fAX$xbO:B*"ҳg#NEf(R2SH=8ZSނ̙C'4~x!V$˓)Iͱ at Y`_*'L۫:Emf]`ʂ΂?ȧUAn_bR/ķV( K +o [O\l-m.VbqY\3 +\zޮ;ALa'}ךc'\K*ܘW** ʄ]A6*Wf~ݾx;CM~5O?6BgdD9I<ӫzh57D6ľv] ED;8h_4OtK=H ׃T,G)FY;KD!/w +F3\xS Nht3^OrTqEqeQ] u6eJ*&yB㤸J[ {pm6HZDߏs`^0RA`_'ƣh>j~wz3#u4LQ SQNv"J,=EƘbG=%aVXZV4ε2L Vo1GY\J|A7 eu!{g嚯  ULJ +X+E$;?,U >c\uIt&=0y̰I`)'{:bGNYj8/3ɱI󪂲d4!yQHËY1`Pgw20 ~!w<]M6f= |9{05s@x&m +MWFI`=?YЀWށkC rb~-\^ .IS c.( +ESKTT;QzAYs FӐk8 $(S#$ T;1a4&G<_JV=fҋw74w)>a=ÖYò|5MK:Y͝х]EV\&'~ 8x S후oH+*5aESXr?0,*5tvZzfڊēɇzE”UJ+JE"tv?f d N0vgm38GYT&dbZ|hPmM,{g!ALͶt\ajMx3f9'gKGr'sKg"TM\P:'>w =ls5}c(") +ŕ4/cFbt=J㊻ȹi34/ǵ✪Z1HR[a{B冇^_좜Jr(>fje{ͯ&Qrr*T0ZvϮ04?=|w9Irz|ŕeTA&ծ.EפyJY3*t*:o\M{jw0*\H>ifѨ囇.MgDO (/қCsZ`ZK` rV~_fnPGj n +r/: "F7q{OKOC 08!Va(8 /&*%-n"HQl+uD Ke[oG4WA 5=G|4 &@ + 4%6>?]κa1%Ɖav2LSai0`MA Ni:+6?44N)Z[ЍK5[VEqAYE\XB1(f"l6tk\Ftڞk憚p~M{sY, +ʩ*'C1I=\S]T{+W9'HIiA(;!ٛgP Cw^YᜨRX5C/G{%bkƜVUw.mr,g-+1Փ(pv )\4m: 3 w<$8WR/HVu'カ$'\,`Onz#ełLaAPHYjEOuڤaN&d2.@bUw_v@oggs'ʲ[USTgTU~_X`3k8H-ȜHfRrQW:=|m +2^H~aʞ^;Oj_NpA[RҴ$y_ EDT,,_L/e2-!7<ɩ NݻCE1*Ο<؟8 $^3Fy$>Mπ;QCaQ 8єLDaO HS7[۫ۙ3x>~󯍣<{vݾN<[oKbL[4$/h܀9fPㆆo"neE1U"$a|&[[&u8fJR҈L97L@"H{0Zswɯ"e@/IWbcH*#]WLe"޳ˈJNa~>.rmƛuI(KlKܛ{:{M6Nz\!a탵j QݰȲEDҁg/Qҁsde&(84O`ў2J`ko]fLTYHm$x)Ns`R\ R^DSrk@ yFzJHR7:udW_+*bm2K3ȇԄlM"7Q +/W@L,@%&i+ee5Vh +"bNO/ _@ǼE_' [҈a~7,~G̣gGQ,A<|f2ʆǦHpH$:ξ~8D67AìS\.vLP&:D2XIpJEu-os5 Sx~遗b(B[S`7iΟM109rMR ѹL)rs # !?DI"$7P(Qtv tE %$xhOGlCqf1`0;ĴE#{P =W{y+DmD\z{%s<'[CTV_ϫa$@K*6t@v${}j2HnHǦvIz&DB`e4|C8/LԤ7 +W :a+".I,l6Q|GuxEqfQ fKiA +l, +5*1diAAA9}e_DqZA4q͘3󵘜3{}>_09[C!ϭcے$3vU颱"`VXh`}Qތ-,F_Yה&>2tM2;" &MvIj^ctq)ʩ̮d>b Gs qo4c9; >=4gѩ"]fI$Nw9C$c4wR`яg156Xrr6(O7 u{lbc}IĴf3ϷK>|6ûM鰂n (nU@EbA`"xyG81di.R7]h\ 6LB퇐lE"XKicN|~5]8X fJ q[bN_ָ>sClLi5(2GSƬ-l5δir+j˾?ϸC]]/LՃdM&*Ki'#z@ B;ړC.){y?tA/h0 O75ui<=G$ҹ^*aʿ-qrVɡR`t$6)Z;1;:)%O`F XL]nSV+c(\i,W9ri+Y ꣽ-أ1P c,QQ+ڋ1]9:X1V V.>+\A=w NrFZ{*tD *KnotcaKIi!~}#j~fǛ T*<=۔UJi\ +gHU-2O+߇?iu3W;-L;g/gC`?B2lCꐪ>.²=хW}浼PB 7-7KY֧XY] ZMgJ~3*۞.)@BEcT%~3>vwЪM\uڼ\zm3M0G 絹m3qfq<%OIE'$0v^4:ZRvY8sՕ>uJQ@MTQ*C~R$w8LŠ!F~9nu/Fol#IZCik3oɎPVA[4vv+jP{\aɰ(a܂DdӐSvW뚧j\]Ȩi' +J*qhooq8k/|{#GO`-Й8Aq|;ہ6[]R%d`Fi̞FD1\L^nm8[ +zVhS60E ]`Y=rԋ˼po/ww\{pX-gQO!-p`1Y\T[A^_Wت6H F2\tH=fmY:;'KF-1 oIE9;7~G~+ 뷵&DKյApx*QgXƔ ޜ)K2Es.a3*. _tH\D溙HAZ\nǦ%6H<ıegEni+!ۦG<%B蔓빁\uLO;9\ Њlɝ*:JΔ0ZHo1`" d$W29&$N^vg`67B yLJ)=q2 K~sRPG^_ld˺ZOn}Ya?{t(ޗZ\rE _:룄 N~4 X?]¥WiPD۔ZM7E5`c$P<@SEDaEh6bR&뮯׵=`i*li{=vhb'WYa i=ca >n2uv~ަhUD\[RCLntj39Ŏ~7ALg-Q{'58՛m#ZǷ5x05!K<^~~E◨dł+@:U 9!l^om>iJ<;!]oJQ ô>.thYjЈQNp-6[t7kt-7Flݗ060A4K$XL'=B>g[*/Pe7RMK괒E'F3+N;1R&eǶ$ҩ/M7{e#d%\i=قc2i/Q;+eW)YEY’B~/nb׳ NPRsh>8A I+`3_\^Z%Ĉo xء@ L(DA:WcWo#vP"8 qAb[KGw>k +a K)7yMEjnYC8`0ˆ[HLU*|=*E2;L Dc8q;^Mq|:Eg*smH˜ED́ņ!H;ab,p +]y\,g◄/ ˜֫(ak,,G@)$λD#Xm+u.10S&Y0 _57Nӹ*e{QhAk6r(|jV1HC^ۜ,%וV|wF; + x xA{zr[$ӀJTԀwĀT3(SioY%%e3T?QhB=6@RRIj= z < +.#b .AX_( yw6?p|3TDl7Ygy7}K1L+8\LOҚy}CUidۺ71^.Z*uy | Kf +gfb^ߤ:spBE!e._O̊͊]1\7 +q-ޛ&XԪ|^@M^߷bȰ |R蛟R`c])}1shGgg7F7ǔ;D8 V"q]dD%p!Ht~aXI +[IŸQ阹G#OrɇѵhʛZCt)/, KvlEC@  -3 P,, D +A(Fe(dEclb#j6IӉVva1~]ٻ?ciN:[=uo+R9рQC+!s|tf+/ M!ނ]WruA#I\K^zBcbH/3pqcmU !QI_`FxLDo,~KbM b<_wtw_imĜV('1NIdn<+.uan^͘8šӥQ48!+9r'M%/w1VPYPR`Pa`\A,Pg-.e ~d t,o U-5Ҿ}wxv ;+kF FePi2 N f^.Mu*>G8ḥX؏LmS}[IS@7 u!ckJJIJHT'v۽Z֕{Pcg^]\i\7K'Ap•w@K6NQgOE qK?9c0nA3]C~;U^M{*82iiJ+'4 +*suZCx:e5\+ R,õ˴=ŠUFFw R Ht󐫞Af޵bz͋}?UkƛƳ G#S"eXC0jDPQ Z52 Ђ7ja LU[q ymg¶z#k=-Rb@(XE~P=VOiI` 5?|*?ye+?=$]"OvOgIsyI=B<7C0C5{*jKoj;"w'ZTӼ9} -$]Sq,dc[1-1+o#lCSֳZvCt> O,le*gs簚iIF/)N@v9.&<ּj]|ڴ)V]ƫj@8ʡ*!^x,"w (rAj,"芐.VǪGiw}cBDCe1n@#1aػO|g;,"ް b߸:OD4cbEqy|]$rXOxκ9#qō>oV[ S0>qsmkn׮v ?Զ7NIǵN]-I=i1ξ+F:rL͇zu=7,rİj@xY↔&et?~]~%ac`g|}I!/nF&a=8a/ZoIX wK|cWb +Ju-n|_3E0Ru\` @/:p +ރ~WnOx.߾ofLyTy6T)ЌÄp;m?sDzXȐJ`^ɓc498w?-yE~1Ip H#aIa|?ߛºaV0b$I{$h *;G̶92[DWY\<皵4}'w&Ao?gg!D?N ѷ ޭA0(AA?PLZC &^DF(uHe'>&oжh(A+/5_7p 6}ca1,DV(‡4 +w#Җ|\˾F~v$bIo1ţNO9\ۂ)en/=.#c|m#44_ƙX' ',e;F k0\ .1l0kgGRJm&OgRaOhd;ucTwi .i (X7+ +RDi3)|F]Mr~nJCV]UД/atMY4Γr6l1i~-)޷B:MďVFePtWtTaFF<ɷnl{c`+I_c"8FaUZ[YǏ#F0 ڙg4OHp!Γ< cSr%^GF&>*/>)""XDsL`1lfڎN +-([*ZdU|< BJ*$ڡ7n6=7+O,UiA4WrS6_Y< ?1`VǨANLhUyb[$Ap3Bٳ)l-YJZJ ˌAxj -@_kC 5WjV]qWq+qX^ߪ]`9'=x=#㯧N.]iw_[ ]C}op6Mޗd{"\e]Q^G +Ndk[\VQ q>q\d|;dSOfIJuBUh^e36CWNrJC(jX]{mr区C)UBpu2eLe (64IK`JQ*`rImD E8K;f.ZX|iɛŜbrfèVRRf4Ne?sz8Ax@7Q=:d w^VZ3fIeYֺU?ltiב0Ο2 (zrKrT~ϕ*cErwG`'d0q>gIag +r3%JUEeFj\`4,/N yK\lTHtxm{o6)xU*Vy}ΉZF5yR:5-NF9|FdT*zV{z#XkmնrDhZ-&|7.e -s3y^]Y,)5UU5* ʢU&Jtj?K'9M"Ҁ4KGP@[FA #*4 44Z@YD\@!lQc NTVvO˿~ԫ{s>A^BoM[/;r:p&u{mnܺu NptFSaR=y304|spԳNt"X$ݗ5˽8q Uc`mG}uӊ#B? +OQ8 $';mQ.rU(Ԓԑ"Y-]}^8{z-w/3El,@UcNUZQMTNwOzKXGZ"">SftoM/&: &HU +ծg~QGypAm>Md15zAHtn=`FmGa%0W>c$05LܚzVz`N2"-QRD1g di˾}g\7M=C=N J c:ElzU׹حSKoT^~Z3y:%]Y"k/"˘qO}3 a9k)?oŹs{{𸘨#Bݦ(n<2; <Ӈ k0E'0PBgN +/y{&;Hh4MXl⮤'Nq1eB![~eSe V{ooudܩii2$DɪS}E5/nN-p-\#+s4%! c&1ha -9z0F(>Ӟ +@9ԐDSv @zlɍ!)F}^ZJ'$A8o*?vV#?7W-mCWD5ڋr16aFXXb,K2ȃ2cKz*Hk wkQj/VOpň6OS%4*)|+iC^r Ǻ%kMI:{_t?qeWʴ ŒI_I!"3+ŸA-h:[^!ǟ ,}yrR>fp Uj h?!d\`Z^lHxA_p ,@'w2/_F, k+O:X7΃p1uD0N7 ]{ƱY0gڄɃ\߆26Xv;4eH^WMf-@"ԑL:fO\y+TNFŊ8$!pRzrKaXhIBpйaZ9 affݱ*%sw|uFU/Ռ@IRϝ,) Dzh2̱qJa9;9<_&bSj+aQ! C !p}uV0=bi6LOR 9l`SZYj驻W8t2Kp"T>M_mπ^G5>r]>[ݡLYRoOɯK~Ȭ&F#WaLE]]\ +(R4v iۂ)\%!4Wʪ-[mtm2á*J5dHh?Uŕ'bW= TqQGY"Fqi9bDn -.[bq9[=y1ޏ:w[H_l&Ӿu2VDXqIJD"A ϐ@*S;s9|ss3q.]FܕO,]Ҝ#{WX.'mMԼ2պO]SCʼnb0SG_gmRς-8xNw4%ErKӀً-՗'(\M`Շ T/H$k;|W[X!f㩶7옟撰t(vg-rdOaB* +e}v[ľEm'ere芄VAt#74'?Cr|O0-? 'x-moT7ʽzFzB/FLeao᨜;{AFASVW5궴luM2>@cB,W>g]1bKЌQbء +2cAAIG^KM;%"xW \L萺W ̳Lð!n "8_{ ,[8;;;U ?:$eUxN}@7+6⍶kBH芈䔋;v$Erx[ӹmUŹŹrf~#3fx~_ >CEEہ{$#L C0~_woj6_@aĝ ܶB}e]u(q| +EpH:]{nI5L|9%э|TPݱ+_ڔ#3hˁ(ѨEB>]뎗֐a䚔7ڄ^' a׉=(}'=E0I[&J8z YU>ӇX5]b&Qٌ*[2cfB +f?/9G#5avgw/Q8BpZq. 2y'LyO,5T4mSn}7P,:r +\RH|ؖ[Ζ>KMvaꓭaBۍ־ zbYoMcǻN2`,12[)ƃz{qq{5(. d/a*Li0\`j/LvJ +C,nx?(3I\@Ì2'e L 0/ҜQ cWPɭYV"D7 Kpwt^PUjn4UK +Nj4h0!|Z6;pG|ֹIHÚU5cٕ3-+oPU0Pg N\6:>&r}hHPZGumG裓!aZ挬fKs(*C%tglAi}gQ.m6* b:)ۇB{äIOoًc(J_C r!pϭ_$i46r?,V|B4rfc%vd)vm+:7>\г<90p.iMQ,ٛX5)ަ|y8jJܩS<3Hz}DV/=~cno_暲tz\ǜub\V鲺SgY&o=xgſE8 +\T Yu r, A*vpr)tF2 7p p63|1 5RpFrP\Sj/8U($+\Jkii`|yCtj/5-f 7J`te?Iн‹\AU]WM贺4[3E7Bysp@@AE5>Q V"!\  +(EPK|Mjt:n:|3kꊚUurҰ?t\V hϓ'8nƣ9S=SDžh};kxٸ kzՅwŔ7JʹI9۳wH],_W!qz +nk/U_Vyz$mS/ <`a +مոM%fҭ)/b[ GJoy 4z0Q.>_ /bݝ Qej 00uRT>!]5M?QiC)aېckїw6ʈYLɭrb{M:Ypg'w&~8r5ՂEdd#@MΕwZ00>& 6᧣0_J6223l'] [wUQ%*n2dwP[auO|$@L]~gzզK M,&(f $\k#+n<-),9ʗ`Kq¹`݁ωW`!`폖`遾Vm(c/l?rd㷜K?-dZwD/:R@~ط|:άѬMD}LP|36SH)*b;jLwt[yo|f +欁Lׁ}DLļœB rRDgTT[!~A&`-)..)+.] +ÕvDhEw?BAzL@!wCmjp TK[O6KL>=MªECsLrZ 1Ubղ()*gXMPS1=(sKy~T:ZtDsN̋ D|/d?Q B%HZf M|MdDŽHX']$+&+οxLY$#H~cA[n#w\!_k/-Kyih^׹Luܗn\.?^҉nO7s=9xz@x4&YUBa>}戱$.LYD!YLIkLC%+pGρcX0@]O@^xv&/J'p؇δ3õW *\3}8p7ė,a}vj\0ox+s }N 7S4W"%W>gZt"չgj$ңlh\rT +w}5@1:y7b(NW pP"ah@ZS3}Ӡ2)4䪯Ŏ.&f*؉ZN (Џ̉7Kk6ĀR$-&9ǻÞףdx)+|s>7"!PA$ "2A4lg_;ljAlUv1 FKF# v͈T!cCb'ѴU8ce;|e~߱Ï%%%J&֚6:f뉧?yLnrc5/9Or +OΔ5oD_vމz܈ﳨ`=+G-D$f|"ETPw&J?Of{L5Yele\|_#7~J7FNe'"m78I |c&)+. d6ueHfKljVf +֐V2^څU+ +?B9X% yF}D3Ӝ/ZM'm +<7~l#B̈́-\/j ?dv˜9w54wQp= gOo`ୈ' v]֭E<mi'Z} +",`'G#xuN >$ԺG"y/GuxlENMT&1PXWoqĤ ɎSL@ufp׆ +lbke,vr_;ŔѨ[#@^VGE.D0מ'M()iِSrgG9W'(j()$Û;:{dk8^sѭmiZIJK+{\6'4ǻ 4 nte^tw#CMa7eT) SABd\Tdt@U`ExuGN?\vNNF>tOkza'R}Al}|,3:_4DETZ}Jx~SFVy}4}c̈́̿;S`vX/4=j+?mK)8\b^&jcMSe[TĕzF 烠C2kT懆1ss??׻]4Ϝwy^ɞ'k##$*Pw{TL4pw3m u3U/AP:<35Գꎤ-5MC_|ĵr {G3c/ܼXKg%|#E_ scbi0mUya#Mq"U{*fAm! P֘qXJpƊy 7$[(Xv-q Kt%ujE`!]"~RGknkSF+鏚 Mjwl))oioZDh!*o/Lqg4' :RYiEjUdY YpgPi8ح@?b + [i/qzvRŷt"'lq7Cڻwi\6S +-!SxwE%z{8ψIŦ&IH4EL5P 9ySO=Y-iO]Lf=), +fO+1C^ɭj H&»֝f&*U-^TP5 :Jkm_ۨPI7zeUzbHm͂@yMsy'si+?"^\^'g'3r.[RNÌ{ +`pq6ĹW{tR$PGpM4p^ݦMpu12:=" ^م8Lkb%6G)dU>zPØ,9 Ƚk71Ttnk<IސuaaEó{NhZ&iЛP+H|KE(EJ(R䮙r _KV@S6g R/j+r9 mijvR"_v~i K"\9I<@~XG RtlsHQ§e\e2$m",23d~gE"BEڰa3Q<3$Sʕ; @E +< ^W<*bL*˓q!WtmK\5%_w4io0[#C%H1kiLJ`\E"Iѥqօ")]qs_ӯ|TlAV$pNT*leբ':uWZ Hb^A *p{/"Gx7wh`fS>Y6P3IAVV,zX:W> rz|+?uvc $-;>6U7gGҹLj(-?ws4ږ]Sl4MU\{ZFHD>4%MsMav٘W꟣ +ʕifJOT`b99@?LP&b2)w0 ylP6V4;(4vڰ򼲪Y`i0[RB"[QF1nUT <=6z|Q W=s5ĭlB)"N'E(23de +K='ZGب(QW<4o31}Rn^9Swv/5ʇ|c0)q>&9~¼٥|iU =7Q]sPRr6ê[6/x +֚d`\Vr-}ce!%7 ) +q^n,X8-SU +J34M:KԎ4D8f +$)nǛ>e#AjDyKCW ]w>UbOw̔jnRYrv+ktf}z`o6O\* 5hQpC8.!wZzk9Q{g|8 ֑ݵ&:<KTڽJfDOlJ'\hR5{W2ŇE.pcw J +DWKA&._if +`=LaHG^m­ף[l=">wMe;Шk^~6tyŗ1$+ >(xB ' ̓lQY,L<\uѱ +ܚ9Y^)qJ;Xw.VQtW:/*?uOldn)wO͐"y~/1#Nd ~LhM̕}5D!CuD9Y^U0V*iciBwdxGQ*9=pG /?X 5m3&G´צw1w ~?}]{nSrIܲH(ugU̇?2 _-g+vv̖WQ[-%/EϚ}Gָ- +>g20AeS]w3~חdS-[oU?>wUJ}7];o~IN[X淌%ݧ~g}(e搬jBtɇUNj ӼK PAXh0H ^k搤27{h;.>M΍3J}u[-1[Κ}wJ_YnXW-X)w/ؖSbcBc`dd6WiJnVn%\g +`He +endstream endobj 74 0 obj [83 0 R] endobj 75 0 obj <>stream +H\j+9~^޻X-JCBd1LlqyQcTuJƧl_޼/u~ǥyYΗMxͶ~/Ofkŏ|NחfzZ>n,޸foNk }i8T;-sḬ۲ٹ7rz)|Y~~n[SO_-P; +endstream endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <>stream +H= ]#(>k^IzU$ & o2g/b>sp5wh4F + ) yҩ^UUSy v$ e$[ëo;:n ULkuS7H:ȷ cOz5;uSv*Nv{ eGS;֕DE&x0./? +endstream endobj 87 0 obj <>stream +H\SiTW~MwU`B5KaW l *4.(" DqA(8 Qdd8A$e49jbge$x o3̏y?}~Ɉ„d2블g-rY>f}~j~XI'.S8E&Z)D)g={Űb=`L"'XXi&[>{3Nh61cLCQNn!$}=p4!"IPc頿 v .n {XCEèfMU?AII_KwQߖ,_Z)R;INdcAʈX;!2^-+%{agnlͤgVZ ;EJĘ +He(`'Q5npUhj42"O.}-& _ml W%@XMf}*m(^j{ 3 ۀ KTeQC` V'0 ËJ`4,X+i[n0[$F씘ǩ'8;я*K5h +D ̯r7h6HS{V\M =v}\}AX0ϭ 13Ѽ;\G.TאB[fk?jԈ3֡-W] +z#I)aDSڅHIa#Z$C}JGαqyl!b34 .9C91vut]1-E T\OIOOw~*@)N;T.;(e,JC-Ld6]rZ,ڞtVoieLI1%U +l 79^bLWLY^XY,ᄡuhS{w7^SOLJ' q8ݬci!Dx5c6J[vmWn ?fffX .$4P-^4(Y\( x4̥|߱HI7̕C-ݼeOTzZb M(^P(x~#"ĥN`P +<A`ۻ( Ot=9fMn-$mF޲12I8Xw+:, b87烯^Gxn9K8QK(]%/eE%jt@cVTZ]PcQ<8nlTjAAvDQBufw_4b7?2^3cOY@9.Ya h}q^cOt\5%.w8C9ݎ߱8k酪 wN +M + [L=FGKÉh|'й!%GEە?=a*-GHlYO?3l#.st~>F9 щC:}uaA q8ps53` j@3mmfSk=*6mau _v`m_j l;S )̖-E80fP"e U˲n=[w\0 F vk`$/Jt쟂zV<\\{x[һ~MU^|>KgG{]79W|rg\XVkjrSVghJ+6z܌0(=5oڦdVm\״"O2XM ك y&d<5}^hȩ=^Dt}.Zuz-qgQJv·S購XP\a" A(:ER u|:iYvlpbp[?ЇNzrZ@0_c5 2_P}8(Tn!(HL5+mAK,G~r~#y +(緆"L9DR b*`[L#έa `ˣR XS[ܛc4 mVsW'dt{MEwǤ_Jl.Ѧ0Ahs49q\1E+._]Ӑ03jr Zp]o-W w&&#s"[Nj[X +CX ]L A6Ah 雐 1u"OGpȂ-:-[9.k6,XJ#gJg.opܑyCo8ُ 9 *ԽGZ+(NDξ0α8}5!B_zVu l9u<*[Ѕz U yF[8߸P4z( Ux#{ek%Y>.H064KcOo?Z`b)~ +_mAi;Ž; -TA f>f~I򨦮4*y9V\K_*nU+.UQE#P@ $DDF#E6AtPG :\;?޹~o3IV 3`=Q;H_{ poɯX4& $ ڽqT{Z힆Ob2 q"B6='6V8{IF 8.a9G)gxR{cD60Giq\_` +q!|w9F\ ]<&1/|r ͯ1dͱY.;sƅ]kl. _j! #5$l_jA\_n$lg2zf^ӗ]0zcU=WhfkJ喰"*Q:Ɂ%ÚT\dl֐8u bQ ?,$iq9l36U#wLض5(7W%;OI_4%A?<ɉ ž iv*E%756艫ؖŨQbSoWq +- -aO*c<49x{(=&33xT;s:lNN9"*Џ +6FQTp"KWm_um+_]Q#_ +ž4K_i5(v*C\GЙi|b.xj63BvJV^pE>U7nV=-ж$Zm̘.->TW'ô)c9 [} 5|i2&nPĄIVW]8fm%˛s=;QPf*;h=P:BNN3emf qmF>Ƙ[%{E=$U^PmJ@%g4zyd)\etYbm)52HIY#-rtS;ľlK)B-m5vܕA2ԌT m2vc/B9Ş*`Lt7BIEpL}=IhWtE8V(˫?[|ciDZL8AH^O߭i EoqSk!6B^&$֪dc>xښ7v9ׁ9{:M#%EGK+y_,qymgFN.&i3p3O6ܜ5b*Tч|E GvI)?w$ւR& oF +~[?+@|eWyƶGxؙ&C$:yR^>Bk7W}Ⱥl1ů Ë{ gf''ke:-Fb=r 1IыâwT8.N$[Vn$W3o4IYʠԕ,Vʤ[N9P;R.087v?f).[$P(C"΂Ut뎦^\VWo#pۭVs\e#>g85p@<({S)<S^ sb&p-'g%|&n6_`(N'q \Z(^ 93rw.[q(\AmGm(h -faWx0-qF01np!dQpeZrvx@l}xd"2`K0 7p|`*> zQ''Dx !9NϠ}kpxge~eil`;<dtPe%'=`9PV!%(!OA`9p2l6g)M %ntH3K= ̤5Yn.<Z.ׄ me(kF-aq^/Zڞ+Ya:X*Ώpg*VRtc^ʢ(& q?|)||Ȼb>7&ʆ'"lx>xқT 2ɹ};|Ԡg䲏1]xjyT*{Z;R'KD^i +Ԣf4#L͔1NA3ՐS[It%"tgk:ל9O\}_w3"E"TJPUL[d=-ް[+`3h ނS|<'9\}E{1q1])j$׻H.H\?&"\V2Hi^KQ +59eG5eEzUU- ;'6-œw`2yhA 4Zы䜡S q)]>-a!v/ uIƅQZq_U[{ף#^ :v>y\/)l[PwZ|=yƺo]9, "d+2(d:;-A7٘":ݚxY[J.bg4E`R|X䖩EO]!,Z ruU#:!5LXewX?4 Skݙ0GU })dt qVq: nB!o` &VwM/#=9-Cts E=r"mkE&dtE EXo԰8ɸٜLe\ޡPP +7dգMW>@}tHEl݊\R-Xtco˘쮹k.xH`7|f&FKw$*#E9gK.\ʀhF#s iD;R(RCg nφ0pkٞ_j`9. ;h3ȝ|ZxJtݕDcNM6V,iI8> gߟAFt]ˬq6L/Ked.XֿpZ>cB<ڷo.6nd?@ ]\\t̍?m <#AkO'`WXs4[ e Er*]~L3 ]y| 1\yHu[,|-M28(E +BQ%w|E'{%E:ZIɽji@ WmLA+SSO'Hɻv +wJ%huމfqB/Hyi*`_arr(:Qy )U‚3+K5g.g +w$D,\}gA8qJԦuG4^FU;-4V#jخv_GTUml֘j +Ԫ:)BMQE{<{.jY$h|)[ۏE;?{ KoK?-KQOO򟟬r_f=k2ճ iTB͉mI\7'RO%Q, f +.J,Gz9q֣%)R,A)Uzww&ifEvZazg&z B +]}A[ aϙؾ +\\beeeM|>>/(w* x{/v:R^y)=ڒ- T;$g1  df'=g|琊 1L~nnRƅt4`=9iGSiTyPs<9ɯ;rն;Y+9%^yy%y:(ba*U-sw A''!td99SJơvVI;LX{m{ZZ X~ eڽ`OX&q'D!DBp(x~"i"Y>h)^`hoj.O7-Mmưw»GJCFf{V֚|+$e)A &s\aMi\]33^c'zuQ<j\X@pEdž@1QcÍh- BūxU\Vœo}tye% Zc"FyGe^Z k)dp\ +,pf!tE&UMS#qfEd͆wDMC&Ёk up~}$Hy|'θaAAC&XW> L`Pvv3rOrKݓ_s& ;n,,*7nkNBVö"Mi2i**Wߣ]]-nE%!Z+ЎˍL]G}qu)-8M)[ͦا1Okp1?y8g7X5B@!?e(AHBpo%DQ[A^ 0 [&SZcMy HjdکY凍+NY^[W_Y^lk\vJnBp 'Xޭl?~Do`-'E'wi|uM V[yvLp!A;t_A)iG@qPuf 5Ӗo˄@BzMݓAC`V_DG%" EXT{TؖbXobfY!{s}*t!9D{ ]kƫh +I. *:$#]y |e 荮d1{ +å5eO^pAWw-cRKYFn/[2!Y9 wQ I͑ҕa*31_3߰o; :xaef8N$1Ь3n}֯=i{׳NF')s#4S'J) 1ڒڎ='ȭQuZT6Wg\\<~P|fv8ىҝ"R5'~)rr2HR)-hMKu}0,YvV+ׂB=P?(R^ v\/o]MsX O +E0-vq@+(DFm2PX D [—u Q,LIȭ"]Ф[0$wu!P4fwʓR"DRtL[tyR\\1d*ZW $efX +m-úY-DPѶJvJ4}Ftou"XqKXm0rOybo./n3[79?IP54Jw4Х%:aQjH+={`ThR_(+K.OH%g> ѓA} +Ժْx.Q6U'Zj&Q*rU + "2GL#/ !c椧sTHsF@|s @.UM}ADEnꝞDGr|:Q(USgfu'>JkA)OGJx|^~Ag2Nxߔ`j7kE]4e-JkC E}B1@c\+=4 #W-i\EfcH@\88QHǠcLLjȠ: XLɲӲSs\AM][؀9U]O VQZDjIEDB1 +<!@ 5R$@@yh"bQ+wjV{պ]an5˟XLm8u7٪ʏT;/V1L+.4Ax,.va}yzpv'*V~`u/7֟3qYCYQ~|j*.Ү?Qg0ä7ыԕ!b۸P, X#;^m0_l"Mn.GK %%{ƣyT3Ύ`"k:򘖢ɋApZgaC7*I29(S$ȓ8f:Җ֜/ C&@؏9]IX[܌=9&&=)=y{*y;]ǩAp=85 DOO[eXfh3Z8jxIy *\sCBy"sLN`Cijviզ#r`&n/L.ثT)K7:BL&ƶm8WnUqK98Z'qe"$&dpn|t}xKvn450m {jfDyZvSⶖ?ݿ|Hvd+p<؄i۝GAy\?,ܧ}0faO=wqi} ,fb/Yڳf?W&(g&ɭJ[Zx!^<Jy#(ױa3}xN2:rKxoiw.xHk^fz^SKyKdWi&ly1AA7V\s᯴wur87+i ʆ ]~Pzo~!1ڻ9oe5I oͱ?9Ab<sorGo(ni05p1 +0C;TH>+ +A/ڍwueIg)345wm+z*.s% @oޘ¦+uF6> endobj 37 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 17.0 +%%AI8_CreatorVersion: 23.0.6 +%%For: (\723\732\710\774) () +%%Title: (白皮书9-23-B.ai) +%%CreationDate: 9/23/2020 9:49 AM +%%Canvassize: 16383 +%%BoundingBox: -3039 -10639 6131 147 +%%HiResBoundingBox: -3038.77659574466 -10638.4999950105 6130.22859775509 146.057975960672 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%%DocumentFiles:D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\112.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image003.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-9.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image015.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-8.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\1-7.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image007.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image006.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image005.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image004.png +%%+D:\ļ-\2020\20200914--ΪƤ\openEuler Ƥ\openEuler 20.09 ƤͼƬ\image002.png +%AI5_FileFormat 13.0 +%AI12_BuildNumber: 637 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([套版色]) +%AI3_Cropmarks: -3038.27659574468 -3493.59909532577 -1847.72541464228 -2651.70933154627 +%AI3_TemplateBox: 3090.5 -6532.73789579497 3090.5 -6532.73789579497 +%AI3_TileBox: -2846.00100519348 -3352.15421343602 -2063.00100519348 -2793.15421343602 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 1 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 3 +%AI9_OpenToView: -2424.88334434483 -2961.01477658441 2.73144400945827 1789 1036 18 1 0 82 125 0 0 0 1 1 0 1 1 0 0 +%AI5_OpenViewLayers: 777 +%%PageOrigin:2784 -6928.23789579497 +%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 90 0 obj <>stream +%%BoundingBox: -3039 -10639 6131 147 +%%HiResBoundingBox: -3038.77659574466 -10638.4999950105 6130.22859775509 146.057975960672 +%AI7_Thumbnail: 112 128 8 +%%BeginData: 6122 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45A87DA87DA87DA87DA87D7D7DA87DCAFD6DFFA8FD64FF84FD0AFFA8 +%A8FD63FFAEA8FFFFFFAFA852524C7D7DA9FD69FFA8A87D527DA9A9FD63FF +%A9A8FD05FFCAFDDFFFA8FFFFFF84FD68FFCAFD05FFA9A9FD63FFA9FFA8FF +%FFCACAFD6AFF7DA8FD0AFFA8FDD5FFAFFD72FFC9FFFFAFA8FFA8A9A8FD64 +%FFA8FD04FFAFA8FFA9FFA9FD63FFA9535A2FA9FFFF84A9A8AFA8AFFD64FF +%A9537EFD04FFA9FD68FFA92FA8FFAEFF84AFA8A9A8FD66FFA9FD04FFAFA8 +%AFA9FFA9FD66FFA9FFFFFF85A9A8FFA8FD66FFAFFD05FFA9FFFFFFA9FD64 +%FFCAFD09FFA9FD64FFA8FD6EFFA8FFFFA9A8FD07FFA8FFA8FD64FFA9FD6E +%FFA9FFFFFFC9FD6AFFA88585A984FFA884A8AFA8A9A8FD63FFC9A0856085 +%A8FFA8A984A97EAFFD63FFA9CFCFFD6CFFA9FFFFFFCAFFFFFFA8FFA8FFA8 +%FDD3FFAFFD0BFFA8FDD3FFA8FD05FFAFFD05FFA8FD6AFFA8A8A8FFA8FD66 +%FFCAFD05FF7DA87D8583AEFD63FFCFCF845F84FFFFA876A87DA7A8FD63FF +%AF843B123BA8FFA1A17D847DCBFD63FFA8AF84AE84FFA87DA8A87DA8A8FD +%66FFCAFFFFA97DA8A87D7DFD6EFFA8FD68FFCAFDDBFFA8FD05FFA9FD05FF +%A8FFA8FD05FFA8FD0BFFA8FD4FFFA8A8FD0AFFA8A8FD06FFA8FD0AFFA8FF +%A8FD56FF7DA8A1A8A8FD0EFFA87DFD04A8FD52FFAFFD04FF7E7D7E7DA8FD +%0EFFA87D7DFD04A8FD50FF84FFC9C9FFFF7DA8847D59FD08FFCFCACA9FFF +%FFA87DA87DA8A8FD50FFA8A9A0C7C8FFFFA87DA87DA8FD08FFA8C9C1C1C7 +%FFA87DA8FFA8FD50FFA8FFA8A8CFFFFFA87DFD04A8FD07FFA8CAA7CAC9CE +%CAA9527D7DA8A8FD56FFA87D7DFFA9FD0FFFA87D7DA8A8A8FD55FFCACF7D +%7D7DA8A8FFA9FD0DFF527D7DA17DFD1BFFA8FD31FFA8FD0AFFA8CAA8FD11 +%FFA8FFA8FD52FFCAFD6EFFA8FD11FFA8A8FD0AFFA8FD50FFA8FFFFFFA8FF +%FFFFA8FFFFFFA8A8A8FD05FF7DFD04A8FFFFFFA7FFA8A8A8CAFD55FFFD05 +%A8FFA8FD07FF76A8A8FFFFFFA87D7DA8A8FFCFFD50FFA9FD05FFA8FFCFFF +%A8FD07FFA87DA8FFA8FFFFFF52FD047DFD50FFA8A985FFAFFD0FFFA8FFA9 +%FFFFFFA87D7DA8A7A8A8FD4EFFCAA17D8584AFFD04FFA8FD09FFAFA98485 +%84AFFFFF7D7D7DA8A8FD50FFA8CAFD04FFA87D7DFD04A8FD07FFA9AFA9AF +%A9FFA8FD047DFD54FFAFFFFFA8527D7DA17DA8FD06FF7D7D7DA87DA8FFFF +%7DFD04A8FD56FFA8FD057DA1FD06FFA87DA8A8FFFFFFA87D7DFD52FFAFFD +%07FFA8A8A8FFA8FD07FFA8FFA8FFFFFFCAFFA8FFCFFDC1FFA8A8FFFFA8A9 +%A9FD05FFA8A8FD06FFA8FFAFFD07FFA8A8A8FD4FFFCAA7FD04A8FFA8A8A8 +%FFFFFFA8FD06FFA87DA8A8FFFFFFFD05A8CACFFD4EFFCFFD07FF7D7D7DA8 +%A8FD07FF7D7D7DA17D7DA8FF7DA87DA87DCAFD4FFFFD05A8FFFF5A2F5A5A +%5A7EFD06FFA8527D7DA87DFFFFA1A8A87DA8FD4FFFA8A8A8CAA8A8A8FF5A +%365A5A2F7EFD06FFA87D767D7DA8FFFF7DA87DA8A1FD57FF5A305A2F365A +%FD06FFCF7DA77DFFFFFFA8A17DA87DA8CFFD4EFFA8FD07FF7DFD047EA9FD +%06FFFD057DA8FFFF76FD04A8FD50FF7DA8A8CAA8FFCAA8A8FFA8FFCFFD06 +%FFA87DA8A1A8A7FFA8A77DA8A8CAA8FD4EFFA8FD047DA8A8FD07FFCFFD05 +%FF7DFD04A8FFFFA87DA8A8A87DFD50FFA8FFA8FD6CFFA8FD0BFFA8FFA8FD +%61FFA8A8FFFFFFAFFD07FFA8FD06FFA8A8FD09FFA8A8A8FD4EFFA27D7DFD +%04A8FF7DA87DA8A1A8FD06FF7D7D7DA8A8A8FFFF767D7DA17DFD4FFFA87D +%7D7DA87DCFA8FD047DA8CAFD07FF7CA17DA8A8FFA87DA8FD52FF7D7D7DA8 +%7DA8A8FF7D7D7DA87DFD07FFFD057DA8FFFF52FD04A8FD50FF7D7D7DA8A8 +%FFA87DA1CAA8A8A8FD06FFA87DA1A8FFA8FFA87D7D7D76A8A8FD4EFFA8A8 +%7D7D7DA8FFFF7DA8A8FFA8FD07FF7D7D7DA87DA8FFFF527DA8A8A8FD50FF +%A8A87D7D7DFFFFA17DFD04A8FD06FFA87DFD04A8FFCA7D7DA8A8FFCAFD4F +%FF847D7D7DA8A8FF7DA87DA87DA8AFFD05FFA87D7DA17DA8AFFF527D7DA8 +%A8FD50FFA8FFAFFD05FFA8FFA8AFA8FD07FFA8FD06FFA8A8FFCFFD6AFFCA +%FD56FFA8FD11FFA8FD0BFFA8FD50FFA7FD06A8AFA7FFA8A87DA8FD06FF7D +%A87DA87DA8A8FFA8FF7DA87DA8FD4EFFCF7DFD04A8FFFFA87DA87DA8CBFD +%06FFA876A8A8CAA8FFA8A87DA87DA8A8FD4EFFA87EA8A8A8CAA8FF7DA8A1 +%A8A8FD07FF7D7DA8A87DFFFFA87DA87DA87DFD4FFFA87DFD04A8FFA87D7D +%FD04A8FD06FFA87DA87D7DA8FFA8A87DCAA8A8A8FD4EFF7D7D527D7DA7A8 +%FF7D7DA8FD09FFA87DA8FFA8FFFFFFA8FD53FFA87DA8A8FFA8FFFF7DA8A8 +%A8FD09FFA8FD0BFFCFFD4EFFA87DFD05A8FF7DA8A8FFA8FD64FF7DFD04A8 +%FFA87D7DA87DA8A7FD62FFA8FFA8FFA8FFFFFFA8FFA8A8A8FD07FFA8FD05 +%FFCAFDC5FF7DFD04A8FFA8FFA8FFA8A87DA8A8FD05FF7DFD05FFCFFFFFFF +%A8A8A8FD4FFFA87DFD04A8FFFFA8A8FFFFFFA8FD06FFA87DA8A7A8A8FD56 +%FF7D7D7DA77DA1A8FFFFFF84CACAFD07FF7D76FD047DA8FD56FF7DA87DA8 +%A8FFFFA8A8A9A8A8FD08FFA8FFA8A8A8FD56FFA8A884FD04A8FF7D7D7DA8 +%A8FD64FFA8FFCFFFCFFFFFA7A1FD04A8FD62FFA8FFA8A8A7FFFFFF7CA17D +%A87DFD0DFFAFFD56FFA8A884FFA9FFFFCAA8FFA8FD64FFA9FFA8FFA8FDDB +%FFA8FD0BFFA8FFCFFD61FFA8A8FD05FFA9A8A8FFA8A87DFD62FFA87D7DFD +%05A8527D527D7DA8FD63FF7D7D7DA7A8FFA87D7DA8A7A8A8FD62FF7D7D7D +%A87DA8A8FF76A77DA87DCFFD63FF7DA8A8FFA8A8FFA1A1FD04A8FD62FFA8 +%7D7DA87DA8A8FFFD057DA8FD62FFA87CA87DA8A1FFFFFFA8FFA8AFCAFD62 +%FF7D7C52FD047DFD05FF7ECBCAFD62FFA8FFA8FFA8FD6AFFAFFD6FFFA8A8 +%FFA8FFCAFFAFFFFFFFA8A8A8FD62FFA8A17DFD05A87DA87DA8A8A8FD63FF +%7D7D7DA87DFFCFA87DA87DFD64FFA8FD047DA8A8FF7DA8A8FFA8FD63FFA8 +%7C7D7D7D7CA8FF7D7DFD04A8FD62FFFD057DA7A8FFFD057DCAFD62FFA87E +%FFCFFFA8FFFFA17DA87DA8A8FD62FF7E7DFD05A8FF527D7DA8A8A8CAFD62 +%FF7DA17DA8A8FFAFFD68FFA9FD6EFFFF +%%EndData + +endstream endobj 91 0 obj <>stream +CB٠ZJ%!v쁟S e*|CTS $wC +ѽ LEx D +ErC FނfIvC0 W v+b~Pܗj^C8S:(JR\6[P~,Tf \I0GYgj ;68T2mMAsRǃqN#7ao&OS:j z)0:IBفg1ZkSy{/!I]fʥɋ*ЌR>ԮDGe_]wBll?JFz,s' rqd?JBE6ȯ]ݒ%(UZv6SУř,8hNX< +򓵔2Fʒ#&]g-$:R^OU]9#+q`w=z@uy>@6|cNZ +w▃,lr_/:Bks3$=+w&twʂHka;Y@Wɂ3ljt՛b`qh6UiR/m%CmGȬ/LBʝ@e')rP𐹤:PkgBaړP1:쌱ˎ#B92XPWoqXf$T.‘ʭ.Y$Ī3EHDXl֌)Mzr+6XU&c(]WL 1W#b+WfTzS0}sћWBnSo짔4bKT=&erx=Eh=XzkacʋQBDS)21>] qb7䝀H 9I(le*3-?s%2!Zz&xHXqUׅ/3>\ i?ZC|I=fol&q 5϶\[>;_ [h!j>=.rV%@UB\,PuP@ʪkP!؍|=ȕSYo^N!,F"30a+9Sɜ`k*k1=-@Vl7| & +\S>y͸32Ikqǣ:ECb~B=( Q=mkQOT}v2oB\) $.' c h!.fqW ϡ0z/=D3g8m܌@nU>aʠGW=8aXo!̤\K׮)0ێI%/wv|W Dj@d/w'2vʀA@BlQ#6Wp'N@kͶV;>n;G~<3ԇJeXΑ4"i7B;ߘAPFL %xpP(i#@QOe\{*ԍgD1@D-MǠr^n([RQ')j\)NJ@BכJ롛#&DTT(SP m 4ft]\l&Z܇8`*S8*I}Z'ITmDVRm=RBدp%D"3Os{MŎvۅ%GLȤA˪ +@ĭcw݀Fʼ!v\$~-ql k#rPθ$J1aqf\ KU >s.K{ uۃYpVcQmqg׽Ήm:vp&-HlDhG;'^ ?ӆl뵳絃ov…m'L'f;ɂ%9eR yij0@>w:UBX +<)љX8@v2Gky2Sv@0\ +vCzqO"I].{$/ Hj?jW"D!x#0~%2rխqy`g:O2ŷV1)Fzv^vc\tPk>='^ (_@P?hg݋_8B3.VR-N LO-!_c@š3#4T\s5 rᛑ'int?b|&OSlƙ4ل6TkVA* A?^A]I.@{dmڔ)0lBTHMd;9x@" +@nVMt2%uBdк6 SXzs(Xn y07z"-̀yk`֡PrA;`6b-ȍAz-@jĄ:S8 L$!T4 <'dpŭd:v3? 1緃F&r-8^CfWnlŃCrtUȞq@ (cMi8H<Q7US`N1I %u.{tξjNX!u$f,w÷\T5"toުC7*oD\©8\9nzf܈@q̄'!)(c'$6HWf= 1eKQ QyZiעM7 ia&Mȭfr-$ݤv&$AAK^vyQ 2˒[h.#kޤB`O.#.;us EAq@;HvH^Of[?GaRkQ%[sQM<| 466m/HYg!ơi'$2A 0"Iŗ7jퟤ+RiJ f-G05xr@X ae=$P; py4]>ǭ)l ՍfQq }Bڇ Q|XUQC/N 9܊ŭe¼wI.Ʋ3aAm&՘PF#0 Inͨ2 +Uĺ )GE"k D^#NyiCxaGJBh ˻|텸AJl2?Y(XeUKtqT~}6Į0WDsN,j0S]27݋Xf^JN9+~鮇[f7| HڍZPJ-Q쭈TfT\E儱}lB=p&2Jk!Ù*]e'afD魇Ճ9R(xb,!! <0WzB|Σ*谾\DrmrL7.&j Px]&rÉlp|`-^G-?Wǭ]<ú[d|DG7&[<Ѝ,jOx S^L#`!ݥORB\# אkO'|y%"ElT"UJ1@Սr0̔W\Qǟ͠5ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk;򡵏ǎ|hcG>#Zؑ}ȇ>vCk{dɕGp `r_34f#\ 1p( +%(*¦CЅAZehä"WKp.| [kg<>S4%Lժܙ}XmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwXmwwVwk_|ɫ_ko}+} wOߜ]wo]߼s~zs~uyrWk}\u}x%O{};=8ϫ4+j+GI8˱=|^=S9gtyژs?v15}Cn{ʯ嫯7ү^}ӟe';O١q?/o/?::2gw_d?\|OgwY}\G#OnȯOϜ~|~Oߺ|o}냷.>?ߋxxw 7No޾zr@3f]!9<{xNf m 9nƻo\'g[lخo'{zsP +o\"?Bw'Bg/QoS;Y{77_lA}z֫`5=Zg'Փӳo^|Jgv~;|<%]}rv}rsu{0/!AwN`}rf+&CUiy՛{cƃqz0N8=_qom%6ߋ\?>XpЃuzNKif-uwՐ]QX?'ß忺KQ⃹W[5L;܊M7k6lwgЉb;OՐ6?޲NNNO;|[z;Oj?8OO.N-W8 \ly=ym0u5{7+J+[Vs}xKq}Y7U.ҕ.vl>\?FBD/;g`Z8QBDu0Lx/^<Kwњ͓'\5n Uqzûw<}9q\l#g³;S7_T[;$-Ɋ^QbEa߾l!W8okhޜycm9x.gakoA]'s &rߍ5{!!.=ˇZLy@ +Bys;ķ ! W%7g!Ob-7f!Q..>x(N. !L!\9{W_n[oZnAHDY"x6Z<ŃkZms]ο团) 7?=8yW' +1|(o?߶8VCvFY+/TJKͩw}[h `2NVd\=|\>3i|6o>ߪKZlwx뻶/xCyVfx~{-nEYWbUYB>dq\[w)y۳XFF;߽kS"ٿ'ːjtێE!3ޥLM[osnᐟsٱyq}`;>,KG `ܶzaȽ;yƭ7/]8{VhKۓmuy*^>8o.;8oGCf7yG2nq7r?rݤfq溹{=bYusG]7/S_`7q{v]H҉}sOp=z`>897W +_iѵv?m=oE<=kw/UؗٗH7yɃeFy'umk$9BZv&z-*G}'vmo7_m&"uO߲nb4v;CBcɃy; oph}Pv_~c'w T׋yO:o/䗤Qˇ{$rd>=/A.[ HG7 ^)`9^[~ [r[fۇ'Ͼq}]nQS93wsɣޜ|zEz̮'>mñoOd/suGoc;Y{77rO*/ɠ Mv j4@6>Vʼn싌~=檏NuyN~[#,vsT_w{ksٷ/s^m'ޱ}; au^r'FU{{?b y] :/Ļ}9=}ɳ36&X"O.>;|psr(Zwf\~jjĮx}F}s\}m0u5qH]-oo~nϟU!6رtryh_DNtMӻ̟Kۜ͞PRsdB5w(wi 43w7r6W+wmHiorNnK;.rK_y{rA"K{hlqj{fr(wi4~xwsXڞ1 X~x< ?OޝW:[0ڼ߿$s]nߺ}k޺ł[׬.n}>6ek ztg$|$^(𥸕\D۸s\sM6 }Maq`lۦGc4|qz0N8=8ٟE}T'$ٳ gWXNZ뾟W|\ַN+?=]q߹⋽_ +xP--*[??sw^Oj_DCC!6 +m$>]37_>8{x~̅mnJ ndY*nd9x'od>{tc8eH6V pe]st\]8_-;acyzr̞%Ҟ6wuJ|'v;(~`8@|{yё _^};{}xu!Sٟۿ\_{Y+߷^} 'Y?oG~M}o~7|ZGrG{?Q^-qc>. 9n..}rdw>tRki5po{vrJ؍ >߻8?={B6~Ld} {ߕx|sMj~A>O}uu1y'^}#>~ǟ\]T}+ ,TpmbcL!us i %/ssץ^2X .>žq}nFƻ6ǶI] |Hͱ|fGqQp]& Z<&;U: |c'\um<ᲠstSAOyA\:vM+[Q@{, DJŨ K LPvc%9bbXmh|-. *Hܮd.K9 +bcL^HoonⱬЯzb/;( +C׶@_aYʮޯ9nŽ#AG(Ok,w /M.tqcy]ӭd9~y,{3Gɲy.w!z>]cUa)7)\Y>+7 >h{YP NC9Чc mܔiă>f, A_ρ'P +;" +N/p7g(?w!Z*߂ݫQ@˓oW'go_]>)Soݿ9ᖧW3C/EE/xnU>)E wKɊ©h%/AaT/ jwB $p%Vru$'.4mk+uc+9wa@٨+tB6QHɜ}/E'SYhi6.}Ђh{w)[ᢜD=)E5)NhˮY)nQ|ܕD-ѯ 2;|9ʭlLA;2X +^AHͽ3whBPbD\H||_EK!7`MmJp{ g()|X۞J  +=ɹ:~yrUCen)d$6@E3e[c2 +:rDQS/od3L`" |ɧPh]`@I4*kVV$AY(KvK"28JX"wT*H4r(dPJTTj%sZe5ֵ!e4or2g,A.s u !9tǬgNB R'*v]Ase)d3GQ[MtD@.)K"ޔ_ H^)aD)Vp% *j +n,fG%Au"9v> 8P:%E;(^T#Gшp\U>QrN-"6ڱFrݸ6u :[Df$ZQ$d.La4 9ah WTWP]G691ӓe.c:|倰m_˾ľi:<-eLӡ `*.K9ʞ2 v!rvXTϊB AeUu|K4ΞzFׁ{xRV'0D-:T,z@"OKNQ^U>TV6BF dZ (*bBxXX1h|-d!;f-ID𦞢#>G Ur=At1m-t#<Y/3|FĢv%ZQ)rs6E~5vb۫]E *&UhHC9# +B@B)_LF:"Z_-5nܪЫQqPu|L6Pt,:{| HQ!E)P1()g)iٺ@AZxsPaG(.h)|[)P 3a &e^UvC)9=$\)\eSdoSsYOEZ ,fS+_Q%˝XT(^`}ZQƚAaSݷW^v{# F ֩&8 ēX`p9LZPPecڞҵBT@1y`x4 +aXy껁8*tдi;pLy#@T)F'au0P(ha+v:9G~gQ8<Ԫb(" 41rkڸXAdQ4z4 2Ϸ(bfp!|-![X +B>Sj:_ӵ4E% Uy+O }$^$^R+HPEXZjLّ͔&w1YvLA}U ))T(lQ+[A0DcGJ~LCј + ~2.#O|YP$ ξSU ?e`P +/)9:مSr7tDp+ ZtS4Ij 2xfZfȬ E~{+NRMa!D$ ]&'>”d$%\:K[qFxr`o͑1:kQ LZ!ک9ܫn 7N`D_PK=P5R*e$MYAzoO"z~{dgJ80V-[ Ruz[GL:ND䇎yZKO! ge :8ip Uj=*[5>yTLO\8J#9J 'sT&h) qɆiR%k1Tҩ\t~G#Qai°ȧCxB~+EEybߧ6fT=>}+h, +;&f7,`{kNq1 +j/ .Q'P=4=2,XlZj eWo幃wkhjwam??Gk'P*`їlo]^]N Ezwg~/Y!O 0gfK'Q8pB,-PBO)8x=M~[EDvSdLi~G,J;V;+ mRTf+/}'""m y;d[DaCyBj: >{a5^v"?ホLY+ܸu}o1l8Z|3g#Nu=R:AkÆ؄u+g+|T VxofE;nW~)&2`^9wAn};Q;1n_??4w_|Y#)kgӶY b"{Z[3c8-Lgf%g +yjVtdοw|rItEw- +㎙Ä&.Ak9!d$#W!o\]`jv:X+^k}/~dYxrs\{f=ŘPi/¢3#)ֲJAc2gNI,f&#Z6efjMV(!zJJo:A2ܳVY +`x1Ȥ~<e%LV 42?Cg΢bcz +M52$u\“Pf: T`+hCFXuR@D=$!h ZrA MhBuۨ}Odai,Bc%.&g~U %ԋDؒ:9o1[[0uD^+R仭m\" Xhh$(ދF ;yv>=9`\:jYlY8>Qb (l1(ʅRțMP#CGo&uN PR9?Z2-5Zbd&eH %!f%GErQC&1,`.DHNyvI:D:@:(8i ކjQ#At abke3D/ٜKZABxPdUDv Sc6(@1Ad2Vft=NBFLpTz +,N9GV$keXز^B`+iHju=aAUAB-#Rl6z^6i {(:Djd[,MЍm +"?QߊhjI=m袅_oЅ‰/$9OclcdAk.:%By*Tn̷ YJݯ) D +#INYϺteF`q'1 MYhc`V z#j}0LƂMK -Y7SK7a6N]pE%pze´th8a?в.(X}ޫ!rkfCt*=Pґ=Q8L?d}E:M.$bLGPozB$X. \Z +6_4[zcH!4#PvӾ +":UϴA=ѲS`;Cv"A)h'`Jl,7k.tJ3Oljj[ @8PNaUv}8-I Eg 5蔻®,F@Vi RS@ڣ&^3Jo2&DUлI΄PYa]ѴAlj#O0-:r%tQڠřkM( %L|m6u21u:z1C&E .n8zۈ-Ъ*0nh{UTakR;!E6wt#v-& M!̨WCR Y _U-u݆҂SM07=4YզbNI%VaƙTEw@ܨ(zn `4fTﺒ~p3*6;ɔZ 8,2F*UXaoD=RܸN{bBWrʩ6.=Mӄ(޴0_2A*mMm غCEt#ib8\~-.6nKnVh(O t֣' v VٶoFՓΈXQ{ uԴN– E[Tf7~(<;5]qI]Ψn-\}f*ôF5( G/1$',{~Ξ83!( @H2oJY{k%jE!=xLԈxѼ/Dch +U쮡d BU\ţС>MM~ @ؖ_ RX7b^Ν[VqpdB(y<(Fu5M= + 7yćKmrDP~wxWʠ&3>$LDAؾ}Eق)nQo]s9+/ 1 ZAz mPwQ-"uhK4-g +LanÍmr=XcQCoPۘ^lܴBmS7eOxBP`8)Ki^)Ă%6`kDԑTSqaN8SY~j ^|(q.TA=댵k%5 Ǿ]v Mm20eĨR,+ߢ9jXC8[׍CP5ah#ѫ&ëGZTⱲxTqDoPO:"WtP +XroAxrpagbuz["+qp+3^Z ÏP(*/=`>p*`ߖ[q@5!=3}$!B^kAQ3lṴ;0w[6 c{oQxVi4_ā.]6*)$|W vCp PՇ 3t>sfot!!`ѡyrfV뵡a{jVìAnj +2S- C}179?ͬ dhWEb4< $Odp/mdmMFwjKN#+S%ǻ䈱 +$@B) 5xՓR߭p^_04z)˔e:Z x p) Nfɍ=maBDL" +O^y`L"%*E1)4@{{ 1 v= lu L59ds-pHE覶Ɉ!;.Y;A;hB]vLk*NHOZV)NuuaU .F ?'?,Q=D=<`L9rx)Z,0H0&6HHUBR:yueY'rlZbEit`}0c%hϤy-eG);td A Ag^쳵MU=ߑa) +hʫjJG@8|# ++8G0t3bA:.&0( 'z'*ibEp+ρܔ!SH0$XZϾ ig@ h"9ԫ.λ[:=8b<.T *uҢP7V3$Г'gGZCCg0.C+F$[6 M~ܠHte ;ޙ=%_ĉzvf̧ +]]\9& <AZDGCTm*tN`t%ZISK9 6D ZrA5qe="w!)hDm1\dJzIT/c/~oo k$ A%tjЉyGf  +%zA]<pwfH)ש1" b4E*)gq:G4$MD([1Sz@ Rk 089{ +l03d"z}..di |mX~:,!w78RCAW;:VM7՟,| yNy5Ƚre?3y7\F{LCd  MiUCդb"f WvtNuΪ@J)r8L0)FRyGxU0W.AKn,6Խ%OY'Vѐv|vg77 5\ +lD텫0Z4bd(=QUO'~W?U?/4ͪg +Yz}?W]87Q"棘{T\Qq8RPekQs/zStO?G?&ߦ?G{3$?_og-L}yOR$ES̵~4QbNNx|[LؕIa,O?W6P[ab6AQp  +) { +ȉȾ7bN~L 62Ls=ЉEcmZ(Pϑ=.`֡kxMRXlbCc(sdX?(0JlsP^ z"!#SV,h܆u'Zjdccp +ns5Gn&pӂqL>dDEDXR$TTR9AI{$@JƖV >M!ty It9(ye r.BBpvyGL16fT@j2>Fު(k=R[BSR&wqwF<'djя-_ޝ3ܫ)m6~7nM5 O磒9i td]<Ԩ݃+˪%ޫc4W(? [(?3eRߒW~UYápb6ě;lb@Qku: 6Ze,`e7@xA}a ֗en2a(cWSWֿǮG`ICY fAj˷ұ5ޚjoFpQ7lx0WѾܯV,+Xdh8դG4RT` sqb@B/qHat3";˩'hh{a,Z×.4Bk #DGFM>x-~yUj +@10ݨ]*7#rc ͩ|Iy٥=p7pMP}ӉPW^m\`)XBG3K@Vr&m"ZBpކ42 I&x@vِB qv-6ahqF2~ s:j =#VK/X:4SwξMV|W&u%U 7X70:9 +\4ToLuv-&}xϨ/5[6pYBq^ҥ8{05Rr/7f3\k\QVW ^V41bo mqƱ7W"cYQ*~+ + +q\PG0ACVS3SwԖׅXDȞ8EDB# EB%JP[[ ȖZIk,%(:ͤh 6Rԣo;գQTEMУ }Q^tǝ>2kj K`#(2>C3!QjS(\Ȅ,r +jLjDx=yл˼.Ïjft.]C50!~X:'cL}=JK(HZuU譩48R!劣||hB\d6TȏR8%Sff !VEQkŔ'Oeiv) l\Y!/&/rWQ&hmB_;j`Av$_an꜉=~I5h]5d\RZFIhYh j{ WB#DDd)ktD5k$LJ۴Z8^EZz4Jծu#55܎:a\F=Y١|ݱ',Y +؛'V2(5sh2iM(/ ^9@+ry™|谲i0XղzYi˕#HIDm{R:ZU\e|v|R$h #h D'79J&Wgf!nrlŇ;fĊfgjZ 0GRakf[7ٙ41hؾJOXLPhjq qWq Lq pNb}Y=Į΀GB +jP3#tqNd^98G)nU0b.8Њ$P7b-󢜰- +U xp+=^5H+Q4~RqRFE9]87;E_;{U:9LwXgJh@KiK)ш,AF v`SW0( \T+!ډAcȳ4 u5+Ƃ6g ]jqOkhvڧjqҿAa1Y4Pgo™%V@l[\ž|XDVžJަ\=7U?Rž~ž0ž +K3>,ұI I?AIM gbcUEGΝD>PWG>+h|uX +_ +|bzl< O >d̤.4sQ #Z :,rTdcW=nu4H^Q4RBžpy]fA#nx]?Xn {r,m& + %C솰g1]ͤz{):v4=uE)Ҡk>@C,j&sÞ}˦C6PX Ƀڲ3Z@tIklt;C.g/qdQ^=$~z H>YY?b22p-2n |FKĐYеjP_tDDetes4V\2Ѭ)E3'Tgvc m$!&Mݯ9?D+ImPS*K緙&M*C471}uc- Z3)@]D ӵ1 y(w tEA4᧖Cp㚊iުQ GU ۡϕ +-LhPQtOEsNhN6QTwy:M^]ߞ]'0zmwF;gyf>N}Lɲ4qe~.Yhh+.m iVt򶴄Yz^ qh4B 6ǜ I#CJ (mtڅt"W|՜`,CcՕ3~|J; +4p3M(Ѣ#p!S\PR+@= ב\!Jx )Тe.+^s_` j0H@=ϕ6w43:f_8ӏhgSGtȰy8h2@K\ͮ!%.I*0!79"a N ʺ9?Y'v|3)ln,QMULz=8hk*cPz|xε6[\&Tm *O-E>&kʰ2:-ə[;ʙB4cgkZp3.JC j'kXj]4d҈~h) ٕ?^MͶvȺ;9KI"䚜 c۫ "h)F@铨D@^H+D$&k<ҩb+דTR1Y3LzMI-gSiD'+ ׈K1$71S-e|U:H=߄si?3.>5O* z\F\Α!k+P_8!h Q6YiYN2?U{\<h7Ճ%R:wֈ!L?2d6C㴃gV@Zrч E~M۵|:RE696:?'uLi}AZ31v0hY ҷRisd1:=8> +D̩ڕiOLb3O@xDکI W%5PƥwmSs`r}v멹B0+.0#hܚ:V;]G[]qUU'F=L%w N Ό"u&POd>bɈq>v5#:]8.j1CV1ci^JbˠP]މ ++՘ ،lmR4Tvՠqgj>W_Σ^984fe\L#Е`:t1X{:tX(sL7.[4DFEimݿB{D_[yBհ T \դ9촽Vd&ȧEƑO#e48iqӺM4ȧuG>-2|Zd.ȧyƑO#}G~P|Zd.ȧEƑO#u3|Zd8i]l[<8bKg8iqӺ#G>-2|Zq"ȧEƑO2&jƑO#e8iq㺌#G>3|\q"EQM2JƑ#?i`G>.2|\d.h)J"5G>.2|\d4hf ~a㚌#G>3|\q"EƑuЌ#GЯۡ)E>8qq"uG>.2|Xd.hƞ}\dM[2|\d8q]ƑO#G>8iq"ȧuG>-2|Zd.ȧEƑO#l ]8 +h4ISĔ7jqp@ҋcu@g: +tꀘ W#vSP\瀨] +*ĸ[fDuF19Iu@Q3 qi(.bm9 |Z8 _nt怀9 [8 9 HS@K7u@lk8 PSiNqZxꀘnM 9 .DuvQpq@P퀘9 Ж3.mξn:LZ8 拡bh+Lf-G2u@fꀘ򰊹b^ꀘbRrqps FB]5h逨p|1=jzsDu~ksPWCэХ''âȉľDmlDcI4Y!mѥq"g#SabT vNdD$p'tnjF@uCuǙ*90 o4AS! ΉtR|P::&qro"#+H2rmmSLdGSo"ɀ;uAo4 67a2}ź|ܟ}"hH֬Ʌ7Qbx|::.243p^H0u @uhqM >0&2NH΋hօ5! BHV (?F˾C.UvM QAmď*13 Uޟgb3QAg"E5Vg""Dn3Czv_?JN_yWT\4z&]M h,93 vZ5BB\~pM$ZH~jdpBb]t#hM,rM ݖm!]V\dp!, k^f{lTnSK]Gxm>FSn 0cMȄw5՝8mMɺ878ri_jD.4]?cV)^lNZ3ۛp>{pmHP +hI6%iEF5TnBq^Ċ[$⍾2 tl$hR#ȋ fWU)Kdi>WY3^[G^ȓD?rkZmZ46nh>:BKZWZ4}v<6#&L{t~i xyNG瞛u,b&{C4-bM0lllyu8`k:NY?A'QHW7,ӆ]&{zܼi\k2iu?A şQsW͙j#&BE8L;fDS2šQLёxQ'3OWbTh;:BfXkgʬk}?2NÔʒ=0Yve$OtShkpu*FIQL~"zU$N!{ԥf**3ch(lʔfMnXob:KaYD QT՟$Qc7xUf3' fzBRn6nVђj~%-VoM^jJ尶蛨Ƒ:v(ۡk+V#es~؛'/)ԛgtkӊ1b{N8@c? ů%=#t .?ػk{=[̹:aWc 9zѫhdښ;u^3ɋZR,lX%1ٙToX6Rtui8o1A۾M~%"iM:X;۸7pT,^^V owy8 +z 6*:JifX5 +T H:tv" #<ۑ6(khNpa. *Um9e´EeFa̎MZշyձ W ߏvڵL7ąǑh^B7 +c;xm[ɽs ;m*ȱMCo~/@)hށ2*it9bUh K7T*ؠS7*VoBH+[H*(%Gɽ%9kukfhmujK)tyٹj3qm5.^Lް2t]:SI"6LU* }.3d#ѕ4,GGF?tlS +f#>85` +t ."d鱔a gծj%}z+lٽ4ك:)Q';I`rBg{z;hp9C!Lm$Pf%ϡ}y2/r7}:k,vT% e]ԩ{8ՠP{A_T=>vG춻) +BIӮG[ȈơD'A7+}zTgT;0GFܞS09z 1lcԒ)zҷ{^Z +6M07=ܳnID.qȋWI Ŕq5']1&2f3 +5Cƶ9T2bc\w+9z ;7`tUʜs +E`iUK`e3Y  Y4d CqimbNhUf5qM򠹻 4zDMǵ !n6z{#5pb9* (RKK2TXnhVܢ1FT[^S6 {|ޅӌ5skHW{^NVۯڅ)͗xSz|z{u{>1`WU6b}2 SOg6dsyT`&Fu;l'^/ws \'{?Rtp"{^5tPjZ|IGH+9{/" }U7J.P4|7 +T_˪Sy?o qҰCk^ ؗ9^7`8:=Ipz$Mu$1B}24.6z P=*Op5N(kZ3Z_c vWn9Czn%ƾ[TV5أ,#d΀s-߯g pvv@>ëy 5 ͙!X6r 6షG~I?6NrQ:|F: 76&2N1nGmI%oB.ȅd⟱Vr0 vV* [2;3N1G]{Z6ĐNy6i~Ntucڏ٧(:}t>?>{4J]WBњSS}-Ǎd-}VT4_e1rYMN~0QYG_@OËT84\kFi +^|cO#5뚏\NL~J{ށ\~NtZ#s@W^o9?9<|+57޾Xַ\.wv}xu˓/~~E|,il '[ߴB7x'7?P~"|ӓˏy}WOߺ@Рo"zcc5斂|cIFEwWע?vȆVYkf[Kp}c 5˹Jrv {FA?P y~(wrhAzbOV5ZJ9.I3[6h(FϽ+\i\&YKAjO$'<v+юh=Tؾ!% +%ǽ LPy{vHHaGLӢiKdUGP֮i3`(8ᱨWI<,KI}p6am[ +Ue(SH:´*sj.Ak@({7:%FZJp2N2CQA6dF( `a2 S< +B-X +@\Ï}TIї2绷#3;8)ըְB!궨L$j\PFSޝOǶ 1#:#瓬Yuؕ~Cs#^:d/"(3+bc(8Q-Z +)$ڊ +:q3iEsrFiRtGՠPt*vQ NVqҐݴT`5abbU'b3ANV+Ks ,2m 5m۾ +6@9Ġ;ҳ?UnxN ,Hϖ}:泣EǏFg. ڕmUvȽ's7=[lfDt6(zV8C.OtgsP^] +?k.(q=5v3DN ș.qs7ޡjUB} `eGA@(?P *Bzh2:\s-W~vpqAB*b4A:UAubl?~+4V3ttPpGSdb{ٞ)+\lbfyDF<)~A%H)dv7z $!OA $k' P!'L7t`8 ]lԭf3v]^-0Aj3 0eWh"1a2+Smoȟ[x }7s&(;/['U0i)%*דEáG]6YP$OGj=?"$ϭ n#)Z +ӕ_z`4|Ha,Z@b,6EOSQTǹxs{фh 5Y8Ao3<C"$FXfŒO}Yb{.)NiQW,p{ʭx3f^>%.EkMHLMRoZ +$ƲP@KɸF09㼋>!*uOo`Qvk;= xFp=ݥ1-Ʈ @+S d?C"69`*ߠEsxa)SWN kD|(*ER^›;eũHN3:F)سE`4)%; zٯ?lNMDV*}ŧ?Eǐcާhhn/vfW*;u)GLk> lcehʀܧKG t`MC5hUJרƇT] 4|AhWEl!;eغON;k@i3' Uai<^ K M. g"y<`tpoߑ]ƉKNSup(%=W^ፊ(Q*AՎx'znfl'I31EX'v:F%k3fq,r=>:)7"CMy?}{r ,n Y  PXaYW}m=Y%W;W}Ǐ-Kc9'"2HUfq"Nx'"ESҼ1Òyʙ:\BM!,EMOYA^&zxCio&~Eb< %K2U9{B1Hļ&CP fBa@1gtޗVL]p870ծЧ}SxKH4Nv<d4'y %`\H:fk٩ 1 6Ѥt97c[yS@̣8γ +U2IJtiaN'z\YG$Onrݴ9J7jZg`W2'g2 Ҝ  b(cP.AZ.,D&]Wf;K:<7 < W7'7uJ禐@OD鉟?ݓxY=aUi8YhW[F`ܸBYb2eU+ѣfBLpdF]=z 1d -0zFt4^K':QZJ`bzLm|B0EMz[Z>d.Gہdm@x&mwf;{ϓU+˛J㘄!BreД ^J<u==Xd*#e4˦&pUv,tKfPrc1op.Zh.>BLK)YbP|p]78(dT'x}-0A$|@VH&S0-kk\-HbUK4\4 ~?]5n'c}\ze]7AaDV#tg[KK +S-⤜cniAap&LʘvP5b6,BSs XQŋ+shJl#0d7nP\1QVk IW W"'UЕOc +Ͼ)[mvsDgm&:6zݍ ]n 4Ye<[HXTftQ\a'5 +lAа5VƬ[JޛIseͽ`V=Γx6cJֹ#XG©3m͙M@nƐ4hӵb +dh6Um +H4樰P 4MESDP3%nq'l1 @( &MV+/`+j+eL拊hSAS4fJviSsz9F1G,gr;ӛ 7g{qm%(&YW{ ɲ2nM2x%!`w.w2БwhN>M$vZ)t +[tRxҫY֣3۝JfB]qO(ܡ"Tl+vw +ƘyD3k;-d '\oELy05Wbou❛9Y"߇@OףRT1+Qg*3ە }KPl-͠bIg(tD\B뗨NfdyRr@EeVʕE+˝&ShXaօ$腋K9Eoj{7/>GՕ=`pҠ=ҞlͶe}Gexڦ+~IM$=s4ϙ9TЏTh⭸*#c9s=ɐ)~KW[>8o;ŎF#|?81Δ);ʛz*Sǖ.|+4#]a޸;ǛiZ4,|am<3o7IĵS;\~YJ,k.~:H@9rq>jx +FzwgiҳYt.fqr"f0Y߸v+?!tF (Ǵ%7BR3;bjnQβo\\w?d1D!06 _C`V;b_D0+D=MО }ָ":MA*>#T`3@Є;t){66;Yv;cԨrk.w,R%dT|m؆-3$;&;*}7]em:vv/jeZdY$TMMٜNc*gEKB*`DTQs̠Ԡ+,$s m<чgFfvfX-?fb/u ݣdTmBm=0;MY04FBt +$b3?ͽg_*t^+HUӄ]q9Ohftq  @IiR3MƉ}6OcfP&Kvִ %g:-g*( +Tucn]24CG Isv#RTW17Pslt.F DGTRAwar*d>T<̮L&LX\u659.3E]1jv 3wiP<<ZDIgl;yDz8{c_Uk9Fs$?4`$lK [&l5}mPDFSZ" 5JXȬz)1Uy4,uU=I3fE^xX +jd)Ly4ll L2kWZ1OCG\6s'ʶbtyspOcޘyi[9`Pg4f,fH![.=f2m+g D=i[[M*i& ѣ v1MhD!,;m+nNSbHt> Ĵ>7 Zt~.DĥkGǦZU +ŔҊC7E"AKβMLܴQ*D؞)&*ZZ,"i?ʖij]NnfQӧFXn˗0N/l+Omsk|hr^jUh-[^jZPegKe-[*xLR )##QDʑ(~_YV3Ό8+#o\V(*ScLQ޸bO:5s&3QǪU4sW>mAe劽buYS$'M:E7EfIנ4w>O*.+9Q89E&Rj [n]!cU ="5{,b8h(§LGz 87!Dhܳ$ mK5]>ՊF@?OoNPR9ݪ4ˬTn{7؝׿OC Mvm!ϋ!22^N npd&$z:d^Qe+ét~կ l m&i&4 .~>_1Q$cE%glEeLF&z{oѿQ+zrw} ɿ/-.D5'-oJyKW#9vu)1@14B(?td`vRW&W˕/wG +hɧ0f(X/ +x +)*'lbEQv"/3,z*d_'\^* ! +yV[^}xC=Kx-)ed w$Ig؁x[-'iE!*B.Kˢ, + + K *xZԡ])8Sם9lW `@註Z==sz$ +88DVTY%QJM$x ui$>lő8w}F +Bwf}< +4[M&?1;x2&u`ޮa/{ޏ겮ixݹjx,YDDe0w!}< >t!SMhnj:j?3A CxTEbbJupkdEaw Q$z Egx~8y]p~{NF;qL +t ? +Ax;ޟ_kEׄNR7vET Y!2 +!A9^H"tRZڮīyٞ15I4]zMh@uSɏzLmf& e&HQd&{(ׁyׁy]|*Wu,X$a=D& +4Q1,-DP !`DUȈk`3ю0Ԍִa ĝ='郔ƽ/s-tCEA5DTd*BvBG\ZIyTw@d i}p7;]wP0h_o6vP_W%Q1\T%I& +"ACbJitTkwdE b,1oީ^WY+D̅Uy2FC4a*'\eoE6`SxB@+$ N kMkM_wGr1mؖmؖm%jL+_s ɍˀ%6H rU4PŁ*TqU`~5X k=E?&J&i!jЛ IaMT I]e\D'&+ቬأoD4q"vdK"Zz)s \B:s& iLDCE膬.BDu +Ua@́V'ȸ$[mu,1Pu.358l)G0]?..-5D;`M0AVeAh麢".ӥAQQ]uYP5^D {3'Ԟ +@@&H@&pY r`^MG v͂fn`Ywߐ ?+Zt ?Jl p?H! wp_3M=A^3y!Ul(mO[F,JzmTj'@wrԼ,Ⴢ9sF$z$bnk9!2cQT "I*d/ +F;G4]5YI :Q5 210uh-TNU Oc4R[1wvı\ϕj"H @]yiPgj!felv7s*o|n3E0I5 z#V +!y=X{B܍&;LjnUUAEM6$[Xo(^-RGDU<5HC>V ;0⃉>>B==#/ׯ_^^?=/p&X13ŘL-[_Tje`$[ʢJ$4&῝keF QkR!7r^idDV(ԝn+/ +{˖ +KZg캿qԗ^q,!Jj'-+ů|;F ۙ%3VMtX&Y416`w?wVɽj䳺}uѳS~/~w@Tݽ8NHoesr@>t5C +EE]R"xW*:"QS4Njc/g`j~ֲn#I{< H,ݺ'Df^hRHx$ `""7zHT=&Ȣ`ug8JhYuc(ԁE%:|b] ]!ȚȤ48!XXy'×/{//tPDsv/Vlo?ďw\:s ɆH ݠAȪ .";'+";E~:ً[Iqthw}~W?^qLe4GވQ8Y6n72 a&%3 4 @\o_8;wbJ%LF1G0WRtF5jj .mpcb}ȄlY Gs@Ә@#bRG^Q찎$M(I譇R[ !d,ogy0l&hAkG +>:}Z)o@˗0+xe#1b];teA0( #:ۢ$*Ff.\&t響w>:|yU<&ld_ +/~BTA\ CWM*<_XƠ91hEA$M34]S낤*htdTG@AE-_]E"}F^D$Jc,jDK1nAQCLh0II7\IP@a0P@T@'"0,{HLykKvihuj0cmfH]Tl:J8L1@vlI (0ГXZ0*0yL/QBB $4*=ho:B_m mu&yB4ma"b[dH +!GA 3&kC#wO I4Ha(X~`=vu L3.xj\BmIhTUFKP0ܩW( +N:AUFkT +SZRx8`ZW.aazB~#D_dcἒM_<-TV(U浌T6k:@VcZmA@o0# ,b mV-1 f<}j^uxhT;A5 dnT&_:@JjQ hlPt3έj5K Z@NE8L$mq5U&GcmM碪dk 斡 +j)aLq$0N5ejVZ7t( (C `a40A\ ؼ{@ <6=qʘ5l?'B<(g?pT}\8*'o_7Uki&;u_'#soB,M6%z> U"0E7 CT}"A4↲eH+J`L &+@?)K O-mf1G3`= a0fap^h`-S11G]:1mû4K}XB˾ }]>c3A8-?ij3@~U쬤h$b@jlJ@cN'~!*J("ЉW4AO1+T(Ry‚!v8= iN5.c0 )tI|LF %#QUtMDopDN#%nM0CNK i)Ԫ{AV; wUgXNu>#N^t;C!\{P}]=6Eec04sߠFt T|nis5EmFmb唴L (}igwfJXo|dB#4쏜7|#Y>u?Sw k3"{yUo|󗿣{7ŷT/W۟CG#/~ݐFg_=ۏ?ϿfCf%>Jy[(7 O[}l-/y=TlQ+7xk\ڔ-+БZq^ZUIi +boŽekV<ε[]sBP{Qe +4B|=/ SrWm +u<[~o;ƝbT(wmʬ ^TBgezwj{H.͒=x$ +K +1DT";ӓ(Tl5KC!QWKƠ60S.!L԰oDJ^ee`.FD֠B)Sbmaۨԋ&Xv.k\Lk"`Z畊.]) u3ʗˏKXW"KFdId0"ݱ=Dr#ua`H"`]$܌+F&wYR4/9c. *2$(2&vc`"atZ)`u`͗ՏgS""AN+ÃIS3gD"*fe P7TS*@w"ts,`߽#$4AP""aJ_Ro_?CeH^J +`DܧR|0nŠ7_T~H ԑ"hK]aH ­\#)rwHtFH0l<5D +ګt~wᮦne$C;D̪: Հ1R $t&“/3zp*""(*h tE/i"X=KN7C-rwL9s $G0NDVzD0upS %"JC4] DdQ`vEc:;2>8" :((CM'$p"DO4< :B)yG wz[qqz;R]#~wކ_O#;R= yF8Hzx4;R]|F=%HOIS0@_SS\;R=g2]f5pٯ;?~O}_ +Cg 5hYX+V_Yt?UWJM[$8>Yo6}9י3}r S쯭LR<[*Tzj:th"ݎ//J%XX9C;;ˉjSOvZC{WF!P&.hRʄЅ5"fT,Buzj+˃xFVb?ݑ67 +4Z 1s]jT5(nhKIh dT֫\+#AhS)mu;`+*Q2mʊmeZFVe!@ x׽Z,m[,| -̆JȐT6W/-im%|#6l6J^J(&-Z ȍjlQ AY+9ϓ;mB+ Du;+ M,ԖLwGҶ)w kY>)BO$5<ݼ5;&fi{5/JJ*)KҊt#BDeDSRTcPHw:ιCֈK/U@UKTxB.(Py{Z. }[h}>M_4p0vH:Zjx@l=!T:A; +p*5?f $5~qGtpN60CÇ6% y"NǬjKj }X(UMB0 "jn̪g,Ї팤X1.O:\X *QPp a~.Ԩ~QtB`g/=#yhM@t>NJxZUxGo5^M&?Vj Ԩ:(z LpfW]; zp/6om.ıM5zw;56CeQm9JKB2:1Qf:V**6)OtW띦&lEb%>%~31gmrz!j,mr/"rN6.ʝdkGuL&76 US#[ꪵHtJf3G+*4r65 g=*%΁ N!Po"yOJȚqVd|Ȕ;oW5xXڪXvسK6)*ذ`]. UC/?}z?{?z_~o߽X4;Z_&|u[yoezu}KRa,?\ +W3^jV+qt#{V|ۊ+b٥l44ѷx-0*`b*_>rU}1/#lv^E'd_ӅzZʹ#"Bbnjʕw%l Y)[]Jt*wՙѪfL'6"]R5+5"C5ՂbY|-/mϳX[YM uPvH;Q>˃ +Aqg/=(7"RvQimڕ7;& vH^[5sZ*)DN\N 'j}*Nt_,҈].mfv8;KD"×Z>)`>m%].o7f*!ŮK{@&q!6Q4춧j/7u0s:^GnbP~Nכ=-VZ(=]5Wqpl(# 3{"ht=~ryR߆'}~=Y#eM c\9es$~%NDӉN*^h_Mr8H_1DjTd%+ kGhz{9v`tazJ2B]nf6Y2"VJ}8 =IOYd6;(J-~zp!<ӿ0:|inpJ =nV5Bjd:RXPMi%#;ҋBen&|)I,_kYlT緫Z*~ dH2zJEfu: #Rm wxNE=T}J]fUKG՘: R2zN_MCI-!8/u.mL%MaUs>"\wo]*xQJ|9Qz2lg'=O>[2'bc`Y],|H-vMYATCs$#7Fxb9u8[*}fR8R;Z8Vl~x@K^ Y%H +5LWi>ܲX*Zla!9>^tVz;Yh4ήf'&Sd,N` &2P\s eU'3aOhHI%&)=Mo4*l/?iB}/?Jvml~3)B]O6GgyGS4=H M>b%}xF:ĨI7'//&1XT;0L3#  E61OZֶ dH,sS|Z`%8yfU3pu#>\]Umf#SwpzQ2R/Ʋɳe j$y@/OPPӕ <.im7 @hyVO\\l>,f}.-SdZBei+%0ovof i=y;?hiO3'0 + ZC[^ɩћC"8ٹ[M&D5cutu/%"]S:+["ꂢ̠KmLݘ^]}VlE061fe\Auϫ9V@fq09&ن`vUgxQcz*N熶gk33Q5rq4{$n7Gэù#Ĵfm8uSHrs$VXGK uREAS^=9:A+[ӈ7h14ffo20 uuq<  %C}fgFt}g)ݪ̞FswRŸqlft`0F0Kx2VmҴTGGORiCM4kڐReMw|&pTZI\D`^\zU18.Yn˧mjD+L*Wd:Ag @wijLb8#F*^؈ނ pAM<;(% +3'OcWh;<>0jU9p9[fW;@+5irS/kRTagMadJI΄ Tyz[k]Vbp-6loh<ň@be}h_IW0,4[KO6][>3'`"Ska4ܴ#rMir2v6>0fx= G8ild6*ZLOH386Xq4auq0J W314dfɰUX:Wqʎy2[@(,,#G(ic:``8k;6g2@E5U=JLUFbed$EBr\=<87 myBݨu8y穑쳅'ocXn@S +tͩZYFM\*ꓙQQ{>t#b~!AIZ^]]9kbu$܊&N̔ۈ$Y9qوBӓfyk4jloVU}O0sSԈ<$ vF˖DM/%Jr؋fvL}u:pg{`1VzTyZt)b3Xq26*V9TVZӨHX.Eh9!:ڴ{dz04*ɳpwXLY?f"N<5ژ$sꨂ6:Z˛7Ca~M'1jvfUa qS*>ur[En) S]YZȃJ,Hkh0ЀADG_`p2|RlMK{)O]eX |"NJ߅`kdzy}iKzs)@-@NJpV(P8 +S?(C1NǓk̾ Kz276`<`$˽mIFge@+3I G{'0mpTjҬJ-6ڿwk? @m$RE%6bx[ TVٝ%]Yr 4Al6aR*Zۑ̦UʕUr[HT>.{$=XWx~W~ů~~//×_gM(B0|o? 6?^׾/wQW?O_'w~׾ŏ/ T?W~_-P,^⻯^;/}m>|ӿd ?~J~CQV!sD Zzs2-uв>eadqVᲃȴo|cݵcjp*v#[gkTJ+y2+N8FicySeۼhh%_s||Gc{Vg *^)lDMB~B :$h~8Lu7v/3pϱNn TVv2ٮDq>xjl#Ps?tZ + x6}Z-Z}oiu2n@Wb-iԭ-PwqF1|}m,dmmZFSK~‡l`:ߋ$2[c0-9m$:7׷ I7aPGu{?@A]ٳ#mSnʝf|<. p^j/c߁ڡ Ŷ&~ڡr9NZm9wVXH}=ZwTrsiU㥢}{%QKUw˖|/ޯU^zls-tվP؇MmvmOϕd*Z*ND̠q;M֙ZF>%4̗}N9L=&W )ziF_LKF,qa,`P6q!Yo-o37!07>w3?F+?vFk5oT=&1h-'i#:FhZb/~I$kai jb=7,7|}z07r8&cc菉֛se 8[EZr]褛l{P7q]O;A74ozo<2})J}D} .@AL`iim,'} hQܐ@_,1/RS̊}$ےbZm'>V>*dl1]Ԏ&q|Ggsi!^S]r3$H6XoXpV- AKk d]_ıџO_Ó|pR=mS]N哈/ՓU$$WdOuOĩ1?@><n]j$;*ψ}}:w4%FXHVPUʵ6TOm?؛'}3Cd4]aqI̴Z`.sFr(^9FTC;/(P+J 1NucxEUQnO~T)tNOkW %쥺Uz2ՎҀ42}DOwgW-ѹi?ӥ9?@ +º?}!eO}>I]j[U!u|T)ظޔfʼn]Bt0"Fļ ʳ$ytrP=Z0㦺T[0ZA U_ɧNQMkcdž*aO-\מnRݞR]-lKBaat U~]]*<=<;\lKujE𢰻Z񧚖wR 3T+OR=]|`vowׅՄ?յ/eUFW6Tt^ +S}z]]7tɗrmwk}m/UiIq8 TSܲq^T㮾eG>YvD3ׇT#GІB-\\z2d5ҲU)N壱oѵB۷+rӢ}Tϕ%!9;fzjdvKM$c1[1kOٍ0Gwv\4L|:G͌5<,L>k>3(Փdy ;Nɠ+d_;U]CA[SNP[sTUtm[wCC-7J.o`u:ߢgŶToІ*QS?n]`r]nO}T7iEnK~TMLCC#ڂaҧo;)wҼ-;PMQIU*W\8nĠGQEk [dЖ-3j8 m/djc:psљ#XuK״sa@,DҒ\rXp +:6)cX)W +006yUH Z?ִ3Hf᳕yt'<B(h Ї!'VAr&ğ5Xn,l0Hڄ87B{}U5si@'kk7L;1O@f;wgǓ,DCEkɡJPOx gDDe72~tu"8br뺑Mu!m7CN44Q=lX$rk4VzqBI!lS=w[yB}PpS}_ncOM#;c Nvݜ3w:mn߰neQ\C8)Zͣ@ Y{sr#&G$hɫm$xzUUw9)aۉߝGXrܥ(nc ++6ݜ)aq{JF^]RaTWʭFiM 6 wqױhd +gޝ_z'niV[10QPH`}b!=5oˌLy(`Y8 1rb1gآZ4ڒ>یoG."D#v@&l2Zt>za$ eG@ƞȂؼ3jcf3~=$\?['5o3l)>7ڋc?syO)Bg +!-M0Dyw"hn61@Pg +Z=7ߣkJE+Tε|f3|ε|>Vr>Z>r>Z>tqr>Z>r>Z>nnϹH9TC-otqr>Z>ߢ +or>Z>xrj]LT\gC;&@;[ΖR}1m7Mܦ{xDVeNn]EMlDtOF `cʭ1 deT"5U~H(QT-os c{d=]čBJ"^t| U{>,Dm~)Q٭kepwps9 p-Qn/i9s'bۖ[42"I-)Rzm_2s5|/xҜ)6k_ޛɣBk.8A:VfPnY=:&\S5CMsspth9":y}kV5wy/쑝^O;9}Q; vXU)e7/4ՑZ*~Ln ^f*ߩnjڝ&}/mI|{{6xlzb78'{ǎ=h9r=,ZsZŽfX?ۉz#lmOǹy|qgHnYfG5R Au 觮7_c}؂ٗe} +xzZ۷Ӟ|AKI+ꗰK轱&Y'&Wm+PMF[UFM|~0_zLޛHKxpݦ@(l{Hrmr>`w[{JD=fj%T+Z{w<9UZl Z,EEFEoV-sEi2D歿Ȣh,C·Onyy?޶塌͡OWVF۳QJ<.Ҷe1<CI߱36it,~YY7MW6[ŵM[2Ov/[æ2{Jyl Wm2?ZMTtuҺ< He1m2g`Õy:wSJjyK֚]\5ukukR/mIIT_kR΅?ֈMyd*4Q3v',P^52qv΃^"1 ؝d^z"34˜ջTa_|^ +vlhWuskOmիqP&q%{޼h#RؼP?Nרz fi5"̡G }QPOdƲi._mRgNewӄ-dX}{֮j;A5Ww?Pim<5m4} 9Iq[S,e3~ؕMٽB5eNљqpҶ U +vPL~jjO X]@hT&L u[0k4q|Fv"Ĵw^)qIS 3`+I1vZa7.(znI5k[U/;(>YOmd=P`0f 0TO~~\oZzg ^ϓf>^ϪLHDaYٹڻdaՑ| +1E +!>0W}C}L*&W.쳪tw{) lϪ9kh>+:kh>>sU +T͆ $o6QgUշ@_g*쳺Åf>u6}V[ͦ +\>51 m>(oiгVg@0둶>`a}F lMY7Zg+o6[glaMA٦ Uraf6.v; V-XgoCջ۳_1rLӾ0g?+*]WmQ\UƄKjt`3g(v,~dwmz&}rkf6N43{il*Rd2)ܛKn+6j%27㢯7lly;?]ʈxMP΅K>U 6qvNH?|b?]:xڱl=Xrzo,onl[s9\)jal Gk*EAAm-=! 癍>zIj@@̌7ֹ +K +V@ ڇ/kח\rЅSh+4T+M$܍nsFYU7r(]߶FgZ9O}COW,{>Wݢ_,6mf3X06$r036}6sq#˖?R vퟟϛ)1wv^Im5'u? +u{ȍbcv%o6om FN,әQBU"^B!,ZO%N{6oe̔5ޣc#f;fWgV՗FXizy(iͳ[\x"bmsƭ:e幸@W5[};J֯nD}i7/'h[վ@xzA;iDztbmvҾ\7ϵ-ZK[*BxPt=C.!XHu=O +g1=C-pm&rRCSd$Y^h{XHeac-la[-4hOmSL7&>Wion=%}8 s9]wT^wK$HzEAL'D]t|DﴹY~\zE~hRó,krŐyu>g HPur~hrFsʼ}=ǿdHjɈ]!bf+/8U!)&J3".ƶPݻhUѐ|j>ٝńETtU&1|zm, /DLC԰yc[ǝ_;"{ {Vcӄ=TU(AW/RJFRH&/u!8)::)O;k8禕k:l '5^SݚUN1gcLE޶VlZo[Kf:j/2\L1/>> iFL})#ycr%M:1z+h[r+i[Jl'yj`M\LN>gWUM3=k]sSm)%MC|5v<6Hȼ>qli7YiDǴ4בBސ6HmVmdZkՒDzDDw5.%SI#XW+IGo{DzDBP="RIh=O#>"%P(I4|}=b7+ZZM+ ̰BFwJG4p~mzX-OB)8p +uYCB{]`aoZ2`_Vl^vhUU <YBa}Zz^)v׊Z2{wq2= ]ϔ:G45w)޳CoCg'î;9V泪^]eҽ: 8 Su+izJ[kCg罇6Am`36faݛCϾN#)2 + śuxҗϳF^Su9] 2; 7\1]DV÷ɏil\_TE ARMlNsiӝ߀8) aT/x<Ә;vtNg+?gP/ ʎHL +endstream endobj 92 0 obj <>stream +H}0Ưwb0~J耮K{U4s-̝Ef09uJ[*7\>?lzAJ 77egx}TjO~ǧt+tP8!:Ju(l& -h9=tQSk16} BFKEAG] ?-#C^Zw[@qό0bYa iN?MNw5XpV94N6#ૈH%2a'iף L[Ye{kC${R'I%VuD%iX3XU+X$ҁ+K,ټ h#3Şg#DF[V^Sx0̔p24GTD /6#FQ#nAE{`z;ƒĉ-[Q8rϕ$WBUyQjͳV'ׅ͆lcҖ#ҶVQ +VۍHQdLDdk%7c/MRi+0P)D]T+i"i79ZԪ Ԥh,)nc%[Nt!=qH7 N3-˪nV}Dfѷ"U+Zľ/l vIOLj_HqUl;!.4zoI"軷C9KEH--x,'߾qo<A}; ٷCU)3]+}G;S3YCY t:i.C@Ag,&xے:P =~2 PRE"bT˒2VꖅӢR8"[K{ۇ|szyB3jnJʎzzL@E C +'ђ AFXuL$ZA5^kyD u +1Av-Ku>wd%5h3A +9#f QkK +a8N=mYl:7} +j;JX! `x4 $vol vlhC3L}jRO*2&fF=v(0d)KcMi/1l Qi)EoM6*Z/ջ?I$t=IqAWISJO˸v͘)1$ӃR˘_j7iniU/+.c6)-dnNjZh'5~,.UǦ -Hz%3U5:<*Ƽ*e#y)Ҝ ]"-6 +[/MUI5y*2Dܼ$skp[2ԑJ?\:x"+ +;gJaN <-/j^}d׈%e RZ.i.L_:b 3Bݗ3ug~%گ[o8*+Rt=6(H7\dQTj?^!Wqj3'sӣ=ͩX> K:$Zj"`T(z K*8:PO2!8&;BM3?!7 +ok. ؒV+܋||e1iZi:+&/1wALW-\Y=yD؊4)*P 2i A +%ϞzO9bǔ5=yt|~s:aWŏM%k:!`'(USQZܯ<]*wner3]O6FP@Ц eGf#9%kҏ(I @Dx{Ёᱏ|g +ZZ+-wiw?dݸz/V{#j!#>A@ANRf;&24$@7/IYR]ρƥ,Orf)gEp-,l>aA9 ̂8d Z")$NPU2 vrxW|-c8ҜXL[#+l0Z8Um"f#e!%-T5R Xt(y]W ;xzP %'NљQ8?b|_ܺoqd݆vC˼R;EUN3ӻI{<)[.<>C5Gg[fW% {ح•z.<=#RI!Ԋ2סj 턎əVδ[i4zEciiQqySWqcXiMyO28b=Os73-s4^!`koqe%ZxP^,XYp7;J:2 BChPƼ,nyϹ*TaЏSإ*^JA 骊y*F-2Tge)+=`iDϼT9X +DW9f`fZxu +|,i\/YBK2e +Fko^2Bmcve,BE"P Y㸲jF@ǤC,>|'n'IY"ls!zg$:[ +{Bs$(}4n"Z "o(tz{Nbqj? ~Ğ%)μ~(#U c Ф \fS l4\LJv+\ >NmltM/wtR:Օگr+~^KF:~>D<Z'[,f +nWza31na?*Gj"k]4A 2z Ykna٧3\ ]uݗ+HU=đOw[KujK{6آ5P~Q=gS兴>5r#q2 IL]dI6P|hz"1td(.r %s6P%~ߍ? S}?&o~ST `!~$h۟Å.\ 9[+yJC"~gn2yӌle! v3UbB2,E|lLӡWX[<fo*PH+噯s;ooy.LܛǠvm HAUM2B-'gy3_A5,O0.P"f]d|d RU3 Ç ˶,*3H'CzL=Kx‹mN Hq@P{|$kE d ZuoJ+WW+>>$*!B;r4$a+JGv%%Dmabn| +TY+Mo83mCm{ ʥ$^5Sh& jud$0##6SӂNʊݖWur *HxՒΠZ2eKK fn`/CeސQ\΂0̣h@T#MP'*{s<trd]+8+_|NXbCxԢ=؞mՓOmDM"n3m=ωg48j{Sq-DıN #!`T]V=U3C<ʖE;`v +~ OW-o!ODY|T p|֙ؿ UP&{? 4)^I+2,S;}8oY]:=t"vEׂ?^xE}c8BtI2/ت6Jtr"{["NcUߐ@ESnwZ#!rg!IA^N/|p6F&Ti1ǐ+7/22dTNoby墊GjK^yeWcHB>#suEyCZ_M4sl#T]+,_|Υ\ VP%C 4`q3$ 02,.DT>zI;AZHZ8 +РȒTCLV3Md ry҉HSY$5xm +uY] = ' *S ⢚\ C +ށϵńI~גҕplZZ7O'1(W>ɇЕh?m [z|)<벻>=E*~㭿2U"NyBw X|B] ^=غ!nf5i"1% WpP!s:B"+߮'#a*ݽM+7Y8%t7ɆRNjޏXCLڬY_O"l‹"Aٕ&d{cpƢQ&tw(fesg\jy9Jxj^2mhZ#fn a=OVN<,hTB=S7aYLw›Nci +9-鈓@.v@hii< n(Tp4.3GWg vy+ U$թ_b(B$P;M蘍*OE/0rf(~RX7&U]B(I i\/,t܈U?n)?M 2CX@vEb/ VbRu@1cʟ,w]?[{Dn#DӬ|ɤA%!q%Ly1S`PcqФuzp@O9Fp]7~c|i|B2ֿb9-emJòq~zQn(:"tYrR6D@.k">_ zi H RaM_.Wp.m9 y`>`uwIjT'u}[j(_#7Y~dU9Tt& s$_~ +F1Tt8X:GƧ1aAeT#AԜF& kPPu+/6Ny8"j]DgkP*nLhA@>}4J:<dLlIP:vO='KbH[`%R>4p=go=GÎ6mjAE*7DfzqX̙R1n*-ʚbXN#J;.c֚;_Dd +e;ɐL˘r+҄ 1Kx}Ηa v42ڧP14Ni+%Y3:4 e;(RFMU,+D̻tXiIg\W:_ 1YQ u 'Yhk;jjofZFZeWGL3=~Bld熌J3CĜ)r:[qTO}O ];MϜ&J}@OCKMQjâEݘe 4UYK<ێ%.=]U)wFyST-9PK+`NL&oԴH/E7,QANPm8ԢURA5"U+LvK|Ɇ*C$SeYA{d[M4JwWT"+Qf[ ?6uAG{E(JQ/[EļiMQBs t*ƑNœ>KOIPՖR= } 5v=}r86mU{=LdPOruàt૘6ѭd2:6dfms[רa5hbI<İU'KgYCV}^%<7Q2ؿLa(TENz} [C`FP{\U߭b\Yl,Q.>z7s3._U;Ұ As13cMĵN-K&ieAmэcF_p{Ɠwyhr$ +й9-[3 +$j/;&t1|%L =DŅ?t褁$i^FXP? DV +TȐϬa˰ʲM_)̓K ,lWy;&Ǧ֗ċkd$3iC ˯]3!1VKZm|Z!9 l/BvH`(}GT1ܟJ:aWҸoRhbϴt<P*=d*ݼqe^wP3JO8 ح=P3Z͡JL`[4Fdč2iefl:,V͸CcQnvcmb0b0:C~, ++饥K2ϟ:N#~yҨ> +{Ef%Р-}TyJY&`XiLP=S2wDUAKM&,c[a'Qa%zsrhu,+0ڮTt#p~q0>A.'o!G +3|6 .u' ]d[2]A>s;jL-` |HOʦS3XeqD퀷X 9`?wG9*p5c=vtв11_豘h$2vubb7UY +Ra~0Ix")iҵna8ڵ܍Ƚ KF? s/h $\)VH;e +9Cw%Xx 6Ã'$t!ѵjhl[m7J_L>&@-qExKlg EW}'RqӤ';U':3 +ͬm^XyG\3NWzZƓJy+'C*x۾%Ei^7F.c +J"~7-&h: Z@k1ޏj4%j-6gɟ_XzPCUuK~%8k`bFp JO˸QDo3iX))3@e^3ÍaeڀwcR2Vhܑ +_'6HloVMja6ɂ7NnC+z\TG!U(~o`VɜOV!@s7i(.O!RWAK9%Py~o}J׎"4]L\Ji +I 2~ү~K=6Kz0: +V`1g]֜b|C_Vc)F&Ze5b&=n[} s#eLBQ^рhG x2-gJ漣Av6P #r++4Amp]@.zd`lȸ/cҬ{Jt#hJjPe=-c}^kF{e^W$XK$ ަ^=¥| O?~N`N~X+% =Nl05Q`XeA YGTվXDUE'tAA +i j Z̒#b6ߙ׳HST嵊F* >51wBnhM'<HkQ +D]oFC-l4X$'7 ,\ Q@EE /[(6 U|G 6ːY1~>KL!(PnΔ:O7h3u"00!S %tJ  WX/IuQ:q܂zW>~a5e>9#1O0O)OkP+t1cͯ/K:ԳY0J:k9yG̗6d<(Xh 聾{/-KjV6G<=Q'jf]f}Wukc=S4ǔ͋X4̮)Qidv:Fif)H$Q8(tﱽ61_|gϪ{}mxi5k3 B.i #͗TzEe3g4c ϳ%g[LD_"A +zIh}3g*-E5lœ с/3=m/8oՒ|:Qj]I OXi8q؝o ڛ':m> ~H2yE}iHՊ7XMHC sŷ+,}D̲ɔ9QY }76V5%)dǟH}?<&w3[?I>=8sqh;=qjHHG&`jE}&ɿoί9&% +V"]g@d_'oI`wY߅o 76τ5Q1L-hֶZi4;JU;W6g]M\J#n +s܈/cbMpeħUӛ1MH'U\Wcf`JXg\Ѯ֑ +YNҨQ*|̷e_cK9A,n`2:V= рӯUfbˤEi!<ʓҟ%kK]wf[J:l~k#=\fOZ<m#_d֚8oJ1k[C(<n, +)tF PDRM$'k@Urs]Њ 6-S1( k@. ^0MG{u¦Ov +EaX-yUDkAU^x1V!E㩂Q|r(T~@5jэle3Tͪ ++t%F(x',-VѷT'Mٮ<1ZA@fI>F \U_@!6T WLķ6q 7 +.޳'hZ3kVMW 1io]o"Mʨ#agnpʇd䠓y6P %?bTE Li)e+d5/fc=n(Wiuq_+a$:7\«͹a3:A֒Jhg}ޥj쫏~&qi92Y-Y +wǩL,Hc#T=54PDq4|d9c۹#VJxVAFЏ-"G< +R(kU$E _wq7Tfx%GsGl#0+%rWěK-xs|-E'&[c+KQKP9͗[*7lFjfdaG Ϡ6m&${wO{>2-F-TVpְɪÙXc:Aeuzcvl43I"/Ȭog1Eq^ö<jyBv= $5 !iN5B,c:ŨlqK" {0 >#J|TULOcɺ-H3-*+ ˶%"pE!NZ&?P? ==oq70xGL+'bEۃa(lϏoܶXP::}Quf Hxqt irـ})>SwCI%U|NZzssN?𐁋jBv~Q|FabHQ>bGiY[`䄍eK^xlKƙ؀ĂJH϶0(d?(=3{ ?FYROnpG}¼4Gl +P{8 +MWno{I5tD-ٴo6W0^ + 㯏H +WQs/}e7lih[ I 5,tG j^ s/R=qځh!CkfM0Lz.5،P6AE7v j B>*$o4V&Fq3@5c Y#y *!YðXC}CdVX$X2 ecyw[SK$pXE- Q{Ѧ%OE+ݡ%ofbo4n0Ҩ*2J}B˨> E1[cE+RTt65f*\%SS2:\@j@͛blA>L҉CqnhFeX\^rWZɗͻѽޚb +wt+5g7ez0j+헙Cx2Aa'8zHvpt5ЎrߒҾd]R "+wԒn$t"}>p#XFRX[*uDY +xxQ֕)=u$52 +A0-kj3/xB V-; }EТ:&@ZCeMMf$6*%HwMAS94T8uҠFI3T#PQWYmJ2kHXa5|@՚=CX2Jhg&@EYV`*sne÷2~+!#?V1-p~-<?)]!2&C:2Z>Y: ]<oN^!K"ܡ!TfS@x]F*&bBDmY2BY6RVRKP"@aqWl?Emg{ԙTIK5{3ͪ_^zwS64[fPMH6BM1U,LA#V`XJ)aPѤ֮7 +0+:>6oG-+uCV "f1e#Uhe +gdШHv#4cNYlʕ[lh|Gh~ " ZLαzlG#\d:M+=-c$`z[i3ar>QzÍ2~JRui~a_s'AFyC8ʔw,)wyʮʳD?܂=$Wlr,?OϾP,],_>֦|â?{:3t.%9-c$`蟍٭3tX3vX+aī~` 9 hrGVw }M-Dx +*H ,Vf9PdDƓJGS5/[jm_mUPYBϣ!F7Ta0Zk%#ba,iX`gd4O{<7Y ʰOm4;o ex\ +qdiY$ h(e\_iMΰ_J2nVY|`a" 7.LF=N}6|,i>%+Iu㩷W&Eb'eikc/7+O )$J2^JeJ%rՉ 0xǍW +#ategyT+>KNZvXSYNފ*ߜޟX.xͷHε+>#hndZ^5`EBdV6+ZrmU`&̍K3=xiC>>ͧCRگ7~(sI܇#[u&5aL: +e,%1LUVާޟ}f33jo-ۍGD^бh2vþH';fDh@x{NbM)f΍+U~`Į (~~|@lyw7]4eh- ͈\5,Lv.X_8͜8pœxZb@íFQ21VዚvLqMJm9v星 8ϢFLl<{< +\ez W#ey8O"OUXcP!j*6Ӧn+-{{8xZ9_2~ }1 z]LW}*J H^a { L-ENT#T$0ee.0@à/Qsw>.d2+ZG Լ<''FiI[$foafCLuܣGtL$?>Z z37e8<6Tٻivc-Y w6d`\c 2: t0~Ld }8mj񪈠}*[#Xƈ⭖0zz6kEvj%{U/C5cu8@j0\2C]`x~6 @\I͐7nΞ;J jL`O(np$&e.Lz$NrPC҅?gV$3f44sP[ s(D,,A= )Ii OXċ"<5e22B5=T#93!yPs&$;B5`uafAx rs-c&+r[8oRJf" +*OF|Rpt 5e^^rB[JC-Y@Wߎ |SkEI]_H C8 +QVE2ӭ~G9 +OdY uJC(%`rwB;"+Y:dN2H~ZU3jY.Xgg%`b. pH::1+ 5i=f<&QbmzPת}/*,3-z",v}o:SxCE4q1`#U;FG% + C?y j`^W -sJPsJZ5C wf_J/Vf<:Pva۞9` Z= ؟V}03d.Eg0rcCƕ޿(˿~mx;ݷF}O=~oմHtGΕb\i'׈6>Zۋ ? amcE#% ;[.>/P'6Q½`#\.?"ZGwJxJ;;nQ~<"> +_Fr?1͏+R=Y|S?ݔxz/p2OMߤ??=>';Dg-sF|!3d{v[58|ΟڻH@Mx83aWɇr7C^!q1!>GC'h[Y!t!pDfAPL ûD)FGnøGAfip=$iuAk6kѨ،m6R= +=n+=$pfTilF> ß&" U +ߵ^d6@i PZb=H(- L%s֩|uM(m="8a| i+H/>-cI,8)A߈Gp.`yMN(BB*7vbC^A$uGGX>T4QdB:ecuNrIN~0%F)#02&mR+04hlЦkL>&mq%{/KhRhzT?t)2nF[Ǖqu2N'dZ_+߷ V6{";LÏWy~hʴtDJNz>hw Q]X3JrۿLEG!帓_Hcr|],9t`捠H!{7sxή vnn!6/(/я$ݽM +K2 CU}t249b  C aT$z"ED>w^wlpynZGr3xn|ͣ&';یnk:3NHey@{|.ʸ:G1F@ !#*E M PQ'gxesg^ʎ?PP*'>qqQyLM!AxYx' H]o VZ +1W'Nx: H"3ɋm #8,\-5\l^J}G I6=g箴1 /V#A(#=Qš?<Ј]F3&rG=͛R:s˙LllRw`[dƥ|6)'F%L8MwsgK%oN?ppLnVr%Ixj2qw$HeLb5K4Tƃ8k~zQ9dc.%nqmRRV + 4Ыf޾%=#v3X.(MC~7@mbNHo?W + .w,t-Μ)OMXpc"W/[J!gZ^j3l+b.|ٷR9{HHԠѧ\!T,"@NE.rREZkWQUP w~9Zi\s"7k&N"sEmb!$C2 aEFՊp8JIⴃK%|YpJ N Xϐ  r9RZ,cqxGVhoVsxSzSJޖu [S̎9X;tCCr(T) +qPʲk޵dhS\8~ґӇ+Ye棋:O\j.F +g U_þ y׬3+rH=DT.~> JԞ_#|! T:4n 7K(-!v0RE?K\|[-5l jH@ r[ţ[Qy"B",!gbxgkjˇ?1b9 x$ =FHZE9KƂr+S/YG4 p1ښx;WeWRx.5+6bt+s ^?"r +bMySU;9 `V~V< +,6V)uX jK)FHP!lYs <Rq$)jUQ<;heEGլ%"I_b$SןS SC lX1U^s/[TYb I!4L@s^™ HWpމx!0b8P'!EvP2z%7Aa +NEhH`(De_&50L> 땙vJtDvF8Ni wNO󰴲w,eT6JvrWޟ$X^Հg+?!]#Nʞf˼B]PB)CdY|E~L}j$ 'GO9TKY:QX5H& ƁtK1.m4Fiu.Jhg΍|F'mZuE"[fͭ&v}C;Z:}4k%%f2(9 +|4zh]]Ƣ PTmBw5TbRbH`~o=UFfo&oVؑ*P1>|-ֲӢJGFz/Цn\3\;b>l73yZtGRFa.OeL›$ yq?혅¢y$7Y؜<ʗkjoBZ_b9~%ӵqX(Cݨ跓BP +QK4[CO M'Qߌ^E+mPYv<)oCx4 l#KD&ewzo&4+ Ь'?YfXl*P }#6C6úЬOlƢvBXzlFzBb +,0]5obDsldcD߬ +XQO)7\d]#9(gVhxpdo@S/p~ɦ-pɈDEdfN?+!3ڛj/v[{+ BE($R)djc%ׅ_4  زp4 $)@F#m>ȘĪ˒rdgIY n%Q6qIJ E<%yvz;,UM䌮<ԲEzlOh;C|L +m5/g}ՉP\W-{E +exBz%~iGfrײT`C(>GfK9(J^f-! p^ȋbPeHrYkJD{ k\MC?}[c$IU&g&S^^‘uǷ~RfԥSiTd4L8R"a(`s:Vo 3Vʋ^ +V.&t΍]f#5k~T$|mSQ)oS@CR%60uŧvvC'<{ 7_vCQ|ߊuNc]b1R8t-e/ įQwc|l4t1jXH*)Z>Xu?>^7ES?ZQ\]cEk :sÿΚG]xxCb{9q*vXP#M߂T;I]}`i(eC ++rAD@ K3O2/8?oC;o*j?`x)$SPv!O_/PG WBUFOgV{&h_,P9[w{#h6<DB q\h*xha)-OR1PjV,y__@&P>QP"f|LkؤtY(D &{'^XXUtI+Vxea,_uτEXkpa qT=F~u^P'`YU S`n<2#Q̣ _gj6_$Pk\^Z*lD0*H-[x+e{A,[-O5T7Xk*$MeC#+?H-c}-Vd|&U~ay'w%jpx .~wU +IIp)V-R.dYj(6['R9bW +bkK״xmZ\<a|UVkV f36ϸa-QQѲKrf՟hݒݳL Ffv)wW*q.fXù\?hm<'°=PCOD] 2t,ȗ"b#(ݍ6Y`"/ƞi9)B,DQ)(7JI+PV@+T.4T ΎְQVdT*Ro6\CJ7 P+b:OrTs]I~βFE-_JF=7lQP [0{ +D`{}LJ2zp jw`{1{ ۃMMz#l6ýkÏ- 'Q%8#S-6B( ηӮb{ξ Wb{Iҁn/`B;iwMץ4j4H8%C4OUv5j|$IԝPg J!QkgNwEaTILOpN a[CfdLl# oR/2:ޤ+kldzZYsP2n[f32n-3Xz!\4Y[ds/n-3e-3: +o̠[lm~e"(-Jg΂8hboIA% HŢ(?peA?$c"h;LRZ Ͳ@VJ?yg9XlE.o+DxJ7*J#q- !6YKF_!2Ұ 5rɏ<_8Mqk0s1eGe^wWwiqKD}iSD!8,O\P!yzG c$2Cx[!ݪaouK8DEb_*89俁yΎP8ZȫU2 WfSNQu_4;VW/RU]dlM|xEDJ\nx@g,:6MuѳUZ={rD 1 l$n39*&9 ; ї $JEvhj0Y tx%C偌-_~W(%㗑Kd7M9ڀ=a_BzCsһujv X9 +UuUm;_Jpd4 /.08Lg*d"a3X(عF@ye=MbBQlm=a&^yMW,^œիP/_VQ$beJLFs[ @pa4:OkWR6Ea Xa]ع!̛  +W7Ł4{J$DaY)g’nB9m.=Za,TZXBFItX+?W8k~ ogOv:+٩:X?=d%{KB#H0HÎSw[i뚃r$5M(XVX$k*ή нܭ=iyO(=GZݦڦIC7ԛ>Fv6KXD:}22`;8ſrO˂ +ZaXYndQ %\.WT + ΥDL .3=g4ʡs,߬ns`ώ/iz7ޙOxgE>y!ΣV;M / +qqTIf;Fc8&,v.r,"uGy]N}0p1:,e[צk_7%PȔTkԮw5n^֒ÿgD0l99Y,dO/˓eE~ϥ+J,o=(q1?[́댅Xٟ֥pFWi(pڴRmˎiE~*7r+4?.eOL0ʿfߥgudw'\`(dem:s)$=_EY{i|,7Ra)?S;WS[?N˚4aU}5 n$ +B'ZLs_}8x _t9t:Hʥ#泴Qn +8_E|ER9}|&z1G6V0} O77l7xGT^??hYo]{K%kʎ1J>h8r|ŝu̩%ˋ; p^]{ቲÕBǂc~jK"9^u1u]VF[>ԑ񖿖.A}T3L#0: J(9 /Aߋn|jzB|Խ#R-J?VNNTz8'/!v'pվUf%ISs|~Z>. ,qugCH?_Jӧ~=ieVlM?]"w +YCk_?RᣚnLGuyp(eyF7o˖=¾m *pK!<;X[}Cbs߽a(; +[oGhoZ΋Z M(?hT9:Gczg);& 'Q,ͤp=}~'SCS_p6܅ԡHl(!7LU-kc>Ps/co/ ~ efߏ%Tަ~A,=lJ_/ !ZZ%"'0ZPY@}ª۔A*6B43;mZR[Go=ҕUU{|ڱSboV(d n-6v +7t?Y}\5]_}Zzɕέmi]9Qߤe`Xk*ZN_x݃L4vW5QMpc+mxúǨJ6ةՍ^B̈́_ηX`4`z2 DtކZMjXY ͟,JXv,b1z>^[f[6j~" ɽzf7eC|/[;*A&Th^ mLS#1c\C!Rsl=YKӨ nD5ޘ*]@\l{QvǭXUG04򡈓Hu \eQ(҂R>$P2*!}_Gv%qKv}pFGiII5|-Ř]Y$- >-uߌS"D TDxuuT/Yƾc{(L?gŖgyɻ/_~ f'_E'S/Hv&𞺵L7\‑9QUŝFڔ\QHv(-bnI2 t!}GmjbăA<Q|pw67%1:q8RFzSaP^0 Y䉂૆%%ōs`-34[6 K6E5o +p)B=,xO]8!m!1Z 7ƿB;(W.,J-y) ̆)xycI1akAʪnJРn\Jt7tLD+uO: ˩z?:09\ $NvqpSA5z|hQ79=7("b'k64~6+nd@?lԇA85R#9A4/\:mq#p0'$L9~Iptqຽz ,+``59!hP.ЇmS4惿#:)p=f)>^MľF!HHx"sKEaIs/bz-D0G->pCޣC΢#K[͋4Zy~8/9ߧ'TI} EP2ZNlcbHF ?hר~gqģ2ָ z + Dޡ[wh>#\~;Cʊޤ'l(NKȟI8u,z|Z<4DNP)! +G DdFCX , +k/8PqcⓌK H`[|bQkڋȯ~X ,ߚH|[9KEVeV([| Px'fa4Y@k}&-jp+8C W.;d_QH9MмSx\>چ7,JHQOIn]`%YYu#gl/e1: 6 +XہPrvCˤ#aIkI~9 1"zl#sAO}*tX?%oQ@W$V.2+'A|9"0: ҙ%';c*,>tK q AJg<  O3ПV_IGS2cw8ėl D񰒂!"N9qǤ!ƌM2O lCǭűCCbv2m ! _aYŲYQRiF5,dSJ$Q\cX`m/x< RC{7#h/ H+V5 mM9 8s M@qSypg6VQ7 LJYX~oe3T` Yq +9RX»2&[WbDuh z + ˹v6 ?B4A)D0u읣!*õ1[b9po=S6:k e =H1X)tìyJ *O~D{S( +uWbdzς3 n؅fps?)>V{%h5=[<7"T/#!i~rU/꯸P,NtR`LťGfl?AO kG^]",˃wH!%euTm)T݁CCbm1kN#+R3I ^ڸ#jA`\[qMVS/^&Y7KDr7l%3휕W +JE '(@M5zb C waYL;~}k l2b;X SZtܹJRR~n*g8ϡu'S$tcMN(3W[[(Ut,D@jУtAX+8;.BpyK`iTBΑB5? MO~+^x1_gznUbp!#|_:AshE =9C:a#N7zJhvShD%viC{4Dv61s η 9e7!m,lW֚'ϥ dkڮ[gՆaΈ|#teaG.U[Iw$N'tqc|B!qa*f1djgQ$Q>HM*.wzM!I׮ôuZ 0:ICx9R}zܸf-LЅO$t,7{SxX(EQ9[6E}8u?T 5ja B=D+mi*,B>2~B_6K[[mnIM`(5a@W/@,J@j9gp/|.ҍv#cmaTy"P!c: i!K=i7k̏ҮgĻ_PL/X$XiKwtؿHBiN-WҌB]I(AF1u!6dk^ǔM#akݪÞEaN¦b =K<ڝ&Sh  N еm)#R_`{K܍E7ě0U1vĐm_!]%xL߲Xa#x@ ;oPr\'OH +=@ba|]pjrT[זbeԍRjm}#!o iFk[O@ +R⬉o"lY`SSD{mPK 4 +0adq]um܌eܔ1:ְRQvnUUZ 6hkP!CFzV JMC{7UzhFvB?LR?I{6A/Ͻt2CjĘZaE,[̌*1YaYS[KLSP߰v! +#gb}?;nbE +yd hX aZ%S/s.zY+ }PH8kF\S(Fwf1rX-A03 $P~^BIi~eoc<d`ݕWOFe2~@xzk8˯\!k x__F%N:^蒓((k3[lE3?MS8 ̷gWF ODpcW+"xd6VQj1 eQ#Pnr4 +U0R-\t!H$OUT?3^ƢT٦ڢ tJpeʨJwGrlS`zc%#: s=*tj`((ʠV +.<×L:.Tfz,R0:TB%wv#' Q +z쮝]Nߺ}h#i/[xBo8 ə"%凉!dA +NB]3\5B 1 2]"+Fd駈Yз:V"]+f1YU\dpcPU"-L@pO\>ڻb5&p]}hħ;dCu>*F3`l`k{ MFtx`lǵn K<8x_gxV9yM"> 8`*{~RlDA|AmiͷDzpۅuO.xڔR,E8 +O^?_ zʯm7m㧺Q;=[7 j MMb\m|pƙkO[J3O3&,'hs֬?s?1N^GEO>?rbI51=@"3TXo%oޔCEvjR,\{d:?R X{A깭eAh74]c3i:zbw̸2Ov^QuE&@̙1[>e|Oȝ +"WxsoƎƴ~'x5'E}F?26!o2 AO>\5K6aZ]zeqya"tyo6r%e忰M?D?4w᧸3tݱCD%$lOhev{au_,-Ku/W#U8xN8.1^}zw=iũ.4K`=T|.Vzxs>ls\H%qo6p;ݹDr=2i|pQ*\q]#Q;O;4`)5ǽwmI\6]nvfU޸*oT93wc\ ?` ^Owm֢3 qφGqf[<4Y:H4lӗR 3l2sn㟍;hVHgp'+FB5biӹ}ٍχ +z}%w?sWrjm]MZK+3)pK^Bgue^u3Mg7CWHو-!%NWR芇z?ŲP ߨڦ,uss1{%_Q mbX{ިrhƂw}&_lvƂoAr6?dKU/vA!wX'\4,;FVt}ҏ9 ?yv)jޘrzL"7O]Sb&f{i8JC`MJGbqꎊIFzyj \q.O/1)>r0V8R}ڨ$,U~'g?{b?݉;|zF[F<gF7Hd;wRR}ЭHbV)%fBHf=]R{цqܱ^s Eԙzmb\o{saW7eHaH u W΋n≝}i- ?ڠx9kQ~tƧV FIiopGql=C+*5&EvӹM>C5o \SHdiSrI pL=|r{y`|Lko\H`lW:g}'Hyc@{̡2GtsLڰyG `Y=O[=|v3#޷fvV+wɃwqN+bXB,⣫@XG>;=h6hy6wΧ);>kGE|U\z{xno{S+$)&z>vnFM-xN_܄Q1Y% BYn^=,x^/Tw4S/\]g5_範|5&\S >?R^M =Z3i\LpKVPlX=v>xi%rq"aWm[ц/) sTN$/.Y~M)/]1*d~~ێ|%ˋk,ÍW~w@8"'49iw>U^޳Z: /mr*>&i煵1 \ + #O;;Cdb }T0S6)gSf#JS{3XH_WS'Q a {j/EweSVnhr***ˤw_0Ʊ%p\%Bqҩ=ek7B-ٽvJn+߯sGjȰ)o +?31NUxȗ#m>7/o!;[,,Vbt~ʼnf ? 3vaxlq{[#iYa#3mv R7H#0.Km_OrBϩ߷UVa=xUX¯ʗǏo )f},SbmvZ f C2U9ڎ Qfto7tpFXګe-|j&ǮxYc}_q7Dqf]tˊ ܮ.,-s(H4t<~WR\M{f?%Jck޻ 2rϼpyZib ]`q1t7pHw~vɏW,﬜ў+mm Dw)rj=mcʱrU ěVΐx$ahu0ai rvq}IYE$4EAu4PEM}J(__bZ0SI$[ VOm_h\)#N3QcaQN + & ɿo4&۫Ӎa.zlϱh#{WLrŚnRk6?P%iѫnV1E:d[i{#;n(v -_mǾ:{ +s򲟯07TQ쳘)ɮ)XX|?+,Q wc_axh,obր~P!%_E+vFW`i6q7N[}١tag,eǭ:0 5N^=cNj!|f96†d#, +Orl&^=ۏ~#~Cr__ՐLΑ~ސ)Gt_=iHz^QEHPw`~I#Xux(n'iB3Ck[ ʌ ƽ!ScuMx[صySkNb 2A +MHU몺,ck]w" m] f|.,:h8Y>]@C:&m1ޔ JUγfHW5Pnta6[1 ']c \rz 6+`W* H{K*2vf:R%|qI 65ocE񀳸BMp[E8ٟΨ+%O4B25~T9.UE1=vɯUw<V LC +oMī99ц21DRɲDX"m ܡ +M NnF~T~Dտw+I߬Ï2K)!vx8'X T]1?;Ȯ5Ifk.HlVZowy!mTxVjBU洓kA8|3ټHA :CĞ,{跈MůF4TP/Hs 5m}:$^p_ ˣtf6 `B'TxqY BU4bI!DfqNz2H*xS#&G0Zv+W&*GLo~"X r֑o?PDT>xn㑄MK+cԨIM!{/-xӻDXCo?;@P6*oP_!&JJY'H닩żLra":DURۆpg464D?FTD>H8H"i( +\EQe# *hC/p9peꘇ5 +I3!w r\3ѠV*,TfE=y~Dn\9Dhaj>jP0B!-׷Q; ƙL,&Y<CfqV( R3;5yUklC({/`<'fz0Nh$m9#\cIȉG )@W3RXbտ}h;Vro)>P&c{;+>:iON0l" ,A֔eFVBS ޣPiƑ9Od>~((l7ZT/%""dw/Aّ(@"F˻"{ IdsUG U +,TP8cj#COC*G#”<*FP jZ}/zDU{4e"FK*@@J9p<n85F RM^cc >ꄳ^aJi(%޴Q0PǺlM-l.׶VFk3_XhKUZtshB[`dkhuYPt)1B0I#7IL tah3qR7Q):MSeC$b?US/W%X +V (LzTg"ŏy79-lྲྀyu+,ZM!G +OH>Fa7Ir7S4nb-۬OQ +]V^^f}ֿ[vR:.N| +nh[y4RCp9b}ef3r-L2VSUBqSқpc.7bK\ܞTB:vpf +E5G,X^ e"F >&$jyp1Q q;m +"+>ܐIؑ1IKJ(7Oc>@m3ɴ ͞c3 +(ԛk1v+mG,w0<-Ƴ="[bUe* HK JCb#gJ9 TVCJ3+bkiR[C=ţ[kiEOAj1-%B '-SM77(c) hX$ +,TYX`E ɍ4r* KqW2ɠwS{b_Mn3c{K&vE_Q׌FQd16䤟0 +XE_-*.| [B[h?{ 9ޟ` +LEx-,ck &#ZarrmWtӻQӉzn ڙ\pxr%s<HJ A`VW]juI)U@aIJX"?2-S/'$}6ſYkey T24)[Y:_ W"LiޥO%2ŵLp#ӳS~U7~j4WdfXMQPdWK^{s }d㲓aݎN|f}'rAlJ.q霄x^` +$:&857CYV|0iǍv凇Z FjuX8j*.Pv㱠V*/ɁV WdX9d"xψv%Ayjqߙl[hey2ӱG +e9V򻴀w +F1z+Eu7'ڥV^ii{H}*Du'D9aސq<]x1&x%%(v+̀-hI!n@4d q.w:iM[gw?trS1O#+Y 9y~r X#&$;PN&KF~TJՍ)X.V1z\Hk(lùQkm?(v(G3|XhSګ +m*(BdFTT%(ˤjP1ma5dDyD*چ:З^vEU4 !gq>x/y:PoMFA*1`!"xcb1t+-{BD*A:|jtz~<*a.٨0ݳ,㇁҄kQL$V >~ΐ%dDVU%ܠ!t1=ASzg`I3l `!Ӷ aWe _zUy}D`Ӑ^gT׊2JuC[4{q/%syL;?s,Y}ܼw#<*K) lnX *v )gqnu F]83EAc7<=<еڅ4ѴT_!%gZ쌷Lr\xV+( yL0C=sSpAcѰd2 QB 4@(7! 9YA=FOȷ|46R/;"+ Sf'ʱG<"V>DNsmD0 Ѱ +y R IJuVaOP3 s^cR'lb h`=_I n3qJBM& Z +-gD)!Kƿ_Vص@k3}TAhy3v_g͠Bȋx- &TRv +hRovոʧ1y 9̀f4C HB" j-՚@v]LҜ\MXHLP؀ 9B ‘F&Oȑ +H$l E yn: +,ap_H"$CMW MT"Ɗ!hQ"IN+be`j@UH;!-<:ϳaւەk41bZuB$؀5(vÿkmgc9~ B['pz4xtd]"%'/k$`-zx\'o-Cpk莿J<0pS{mZYzS=\gl`X3 |_fB?7 6m|}%=;jj]{fg+gxD(B3R +Xttæn 2B@F& p:BT>bnqλ"RJSfz8F6 T.9)`ܑg-5 #jLXmD@ +f.|bfTiJ +9XDpurq[.ZxF^+M86~\j1}1}usg9Բ#g3LŸ*kjWX9 +~[ôzspT]*;c +Y!Bμ@( +Eڀ^1Fͭ4C]hiG;daiqXXį rȦN{d +䃅ߠ5Ɨ/~LDU^4 5AР:o)zIUO_QT!lҴ(|6:(. YFԢ1է9!zV^`3왜 n/1t R)z nP5E9Q1㉣uE!?6{pd}=b," ڬH$Q9s٢ ];Dlf /"  + mok،M/C-tWg;9W%v KC8lRC^HrFԢMcB.D9O!ywYy|"T-rRUHfڿ$>B2:*$>zнEH,QȥU E1ֿime$,*`c1u/0AaWb-DQo(VJ__'!Cf7u"-fu/`Խ=ӯ/ESC|?c]"7lgQ]/y+~ѺVu1YUJ:iisD\`t t"KiXK/v)U{ٰA^re +O.݁|o[[p@}]UW1ei_%T+8QT<\H/Q=f2L܊x.q&mYI;#Y"I)vrT*#oU$Gsr$gi Gfo[7/e _y 7$?3s1;S]G28} r$:on?=ԗ{|p{ަC aѱ,z2{W\/<7W_ZUN6h)a3]S9sۍ%i l[` C%%Nu+f(dm>ұx?G?Rsd4H]9r'AH3qWRfgVva ⻍_\V x)6\0ctO1d>!C4 +Aw xX,B=ʥ8h"Pc;g1a*z2,fm5wn#3HH8pZE^7kY0tFE#6H kGsztP%ad8ztrY| 0{o\"3D0?sv~[*sDlS߰7w^]J"eִ䪩1}gӵ祋1ݻPT\Ebo"k/XGUg nxtMVBL".˔aȒ֎d-];R8Po%6dS d"v%Y?յ{%,m):m06 Z|6ʻ4[B V27إepFEo*U po+H6-;>Q ƁQwJJD'zݥ.sf'% +!|`>VK,qޙlͩn1_Z,j S]l$^w +~>/v]ms4I +Ky[{X4|텕Y?l d(]nKVR.W1pD,GXȸ%"_n,(UN 0 6 ly>6E4 L&@nj`&<&IP鼂SbU,ԲZ'F>/0BaY vVFxj8z˚XV)d~T_O@qQEIfI:Ҝ'c?৷bn__*oP~ V 0a3v^|n {ٔ +R-/[ +X'.i¢Q Tڨ!A\n_˰r尽InI$2uTc/bEџLa~ ;ylX"좩( 4g av1T'^ItinT/Te_Ÿ<~uuħD +O;NDfh*z 2Q̓K7VsfʼnI/@=GQea*V)'b%wc)~5l YXiWƘk'ׇ/CY-9TW(( Vʚ4G@Xv#䰅hd?l{aXO65hqpiPRx6sIj7_8 c EGB6Isb'ǼO8&RK-|M܂l5Gx{,(Ø㖽NAP#n(: OiN2)H%bBXC_D/vb4 +t|MZj& +ǡn%E9٥7= Dmo5}}5Kc#bIh|ptz(XjU^L~ A\)79)=g6>+O^l(=(,?1r^vm_{rdy2Ҕr9:0=L MU=bvz/ڸiQ baV/%)Dz %a/6vpY_[uλTjRm9&t"PZ)sS'#LC'=u ==d +M'(o+%wT;(N1ta{vb`n`檙eh<*u ` 5uU #hj(k9[ 3w\È+kUsT9'eM} V +; #SM|<7N+Im.suy+{u@?a[H(Wҕ0^8w05UYLP7Lxヵ)z^d~vԋ{e"^|z]׏GtM)p jLje5LKweo>7q62K%@<,f/()].G|{TeEc0K.Q :Öguۋ/$$ E$" paPv2Bsp>D6]CwHa2DU{CS[X1|O,<)!^:<(<3u&? r0>ЦԮ])n7z}ܴ~KU+pd 7U+kMOܮCM?,A˙Oq)hDl ,AդAd1#چ^1nJœ_oL +;Ik;x^]d.!CL{U%ؕ=[͂/^U4æS('hm1a7Ɗ3N#1VwK#~ IVq^DhKZ8CL5*sy=w/C*1`UcD)ï<(PBus`  y h?p/ T$\0I0A^lć."]pMwU!}`\C I=p RCOXazXD>2odġ}az}RO;G݈boKZ* e`=[͘jTKV4q.-&e@5c0T)Io-Odvj Ky&LƎlRH(lZgH=pu!|ء@q;'kFu6(.jp80,Q@e~x,z{ +Ȃ-cF)#%~ jo7[Z ݥ*uNFjJ.F%\ bP˜. `b35tq*V6m="B ;HgDI`!|IC<-69ܑ3Uehlփbϋ6,sRh?'|me~ e&y9GY~n_nj` DŵEo.XrW%ac'/n2f_|7Z\`;!eQH2 $5 "HPRZr>Qķ6ʣ? +X{kt9/QOc}m4;Py.`EK T8YD +-ytfi*TI +jD'HAl+pM\J|h*!ZlTcG.HwG+ĕbT~ܭw2j-}B)y)Cِ:O|R,O7Fqr(-o,EX2pnCВ-okR!3i% ύǒT仌ϑ,LpqBSۈs/Hƒibs-6Mdk۩6$e"Xyt 9Mѽ|t0ssGWݱsb +D6L!uJpFe%~.HT`Fu(A!J6 +BšNKce4qO>,XAkQmkU ڍlJ(@Tā;`ݼ 67gƔ15fXF(Ǻ!&sz/v,-$y m(`ʤeJRSKNmÐ ubMJ/GvE@Pb?^6ߍݿd\~JB٪;W&[+#WJ`BLj1O_ByӮb /3xR5OcI߅& w$ QcdU$더Nμ(˲n( ғtdIZi>REZa̢8/z>[UEPM˾kEZ"\'9z&~{W;փȽ%EsѯFqoW(4׳i U$b̕a[2+:0JȵOj(-{rvzƾռɷc;)ZLw=HO+yl9;X_dffj2~vx0o2>4wXWK ĘlJ5y@%9`򱁼 ߛOAC' cdCaZȵ\u|hLT5RDO![ulP)s0UЫZIRbRlq uUV6\5 +N99X)rB1}7P&+=Os|`^ڽ P!'$KZҶ@ +2C?xH-JuPF@ibknlՇ-`:*  =ILg%r"D-7:}tˋ5@;xjo!x8{}J}sUcg\Ӷ\o\/qlw'Kg;;G|az勫{-ڕO'o=[d<=Kwm&2Og^^ogzc֍ΆݠICydCu/$s +}|g>L7:v'־Ѩ s#tT,5&٤7+t&o-qןi]mڑk0 dkY.gu(<Ajrwb[{Kܵts~{],ޅrԏrBkw8Gdţ^f6]۞7mx+R~=%^?eW*\~m$L)ŞOyqRvOV.S8Is& +$' ˴;(Csm»ý&.!_]hz/?_/gRk_ۻ!@5'x?뾝Vxn/h{S(zJ>=NwtP5Oٱ[:V?҉մ|'yep8G{mT~;灃VkS 4jr}TPeL9P)?" u ǨqwݦXEtJ,$QÇZ"\a^LDo>SSTQq&JQ;ꗚB"3TF<JtC/}>˨ chs6ItgJ#6w$Tw7@2xRm kҘx .D]";]$XrD(ʊޣ.j ǑG>³S9Lx7jܸHxY"qZls;@{;تZ(Ӭu5aBکSjsj큩2a޻|qT*`~߰xN+nюRܮB(~/r|}2,yLjhk~ P]R},- OM /22´?% 7L7GDS a}``q#|\'|5ck/a"ʍvxM@q` gq` \frB r{sSGio<F's`2AtWBBC4ll\0)PG칀}n2QV,(Bp(.H$H.c>]qܖPo@ph1a[Q~g(]kpr(H rh`WIE7q>&6,.ͪVnng)3ĭys zBMlt+Na윚>]BΰoNڈN`-j`6%=@@3.c.Aϰܦ ۓF٘ى&dgSPGț*G}nDV7O4Y(A*f P2@!4_se/.#cro!.Y9 geu8xFxJp#nzRN&(5priw/pNwY& ۚţh-v))s$bh{CDZ"{&S =`bĄxJ_RlҖ `Ss^^"`Y {;I677Y]^n( Ŭe2gp4{p%%)I ]=x 6QV(Dwe=]VzQZrڽ;|Ǝ_wU a!>94Oj̶GLdIMk ^.;/Oe̖cFqgU~+)4@g"Uߑf%}Sh͉ NAYelM#Ry9MZi6/B~DeuOEpRGi7EX +=;!e au:;E5 #]/zB㴵GdsV*4z]CuyZ]m,a;gckϭCPxVѻmlr7Z3CJMc:0j r7+GqOU8PzZȷv{~#W.8G =?G~nEy34%W$|bHKg‰4u2(}kK-Idl M=ָjO}nX q  +zfeۡ#%=R$-G[f(:4iN;!¬u;GAC@W\[Hi}sn>v\B,l5666t{>oޚQzm*o~7_譁Wrop~?-l}z#e2@k#;x" ҥ6ŧ8I.CFDfd2AQrmFTr42V1Vi(Ql|QA= +#f'èj%5ަN DNZ6ӝi 6P|8Ҧ4iOݢ:H߻b6i<̃sGY495u0ƈVmi^~;:|qع8&f6`Q6+c%gGEk6?؛kgX&|ҟd˷sࠖ$w!ץ(| +_|UAzho}r;S{0f l^&luf\RMp<8؞Kh!4]L^m,4q*JH¥ ۱m&_)-\R"92B4~\ +q4 :^1fqAz%lTD{K 1 y6Qxެć})mI1䪑%߯]B9|WMC# +{Si]:ӵ'iڦv+䞠e$;~! 1 U$8tW3tt6 Bd \Ӌ ȑی8f8u 8(p.MAc3.Ac3t<)plF~C-:*plF~l"ozFJt'@7q}[/njYe*X%x~v.[D9GFL6fnW.ڣVn|o>+V$)"d*3pm|TUe%!h.6MGb =%bsuRmoBR< +c6nFb ִ.OԓVWچ"H"y  +S>,8:l^.㨃i a kk;E=F)qE=\ ]Bcc]()В!Q@9DAʟoO@x=J:`K |LsQL}H懡xpi}إ/a9,t2@]CmjPü(ԇnDOiU YAI i2&:M +LZ>.&1Mzd Dx%U=SH"ܘaf;2_W-@uUZkj>>,M3+yX SF0u,2H1?Z{H,#Kk"PC0m /b'3[hYb:^RXƑb)~R,є?괟84r;$xkL_ލs qsrIiq-&^1'\}U&IƉ` +s( +a\c&55yb +Ψ^!  Ep"OSرJPxrF>? +y_֩BHٯm^tIooS JQ +Hv \ʼn`Ϊ ̙aK9]ȥZ! + @)buXjdOFoC'`Kd8a=a qjd zy+'V3CL.m=%7WgY{jfyQib W@]9FYkk^gV\7@',N[w X9w7!GȊO[ +$$W"&PZ[ij=z@l$dࢆ_г]MUU47b|G+G *ٯ6> .[ats{&1qSAy +{ʤdUõ diO{ H+a9| H}w 1k^>>PE ŪKUix͋,U4%U)E)Cx=U)uy?[U8wM[2cejqLo,8g slq`;\⠅6꿲86ԪGX0ht1a_i&ƅMmFJushlYp.iBYkK]kށ.3my,}죴QRxe6}+rDlFDӰMR{ɒ8U4Txhcr- 'dwRն|bn uSp6Ɇ RLTk$U%Ӡsk?rW:*~i 0$ .c yO4mZP4LV(V`4z7^X;ލG-9t5+R &lt3PChXHh<&lD:On5$oÍFXSJ5>4Jy,ό 1GAӅ?Z-lY$f4[h[?T@N̰;1Jgg ߜ&NưN?F)ULɔ͢Rź/1t9l4UDo٥Us,SR8iFo٥ɇ,z.U:VRIEY]]EoSş;)WXYeҙTadktjN8?ILr6kJ2Rs rU*P-Ҧ ^1pLaR+SXH QzH$~{.@# K}f4FT&=Br$\&YpxhPTXb˱OYiQQOn:~|1"XO|>؊lҸ6n+M1vg1^s5kT \.UyY +ٽȚApzJK?8_6{;q36^ܰKI2S$p^vpRk?7hbq0 YekD_̀kf?,VZx~W'ƭB~XQ{ଌj$Ʌ̊WfJQژzl2!0K8z ,ECVdʧW$)l!"r%{.P],g2wp]7Eb# 9{),'̭ +߉4 Qhqpgq9|C$9iUi^aL2ByQꈐ:q zlho;34Rvg,I*QIf1#IZS&榅djeJtCXi$:> fR' +li[tx1}G1ZmvFd]-l65!Lmq bv\(6OFVT ! +6wXZ6Qmg `aL/aDkgh n2f&Zގ4_.CUt'LR\\/<\6q +:?rD`UslL^KcBjt*lN ;be4 m4@f_~LmĨ*E +;Q~˵nYU3+yM_T&?,V3(* +_.>b7'$ dd[k[$J]Nstg!.܆CQťβ66Pl+.qu~-Za~EvO>a7*nB"Dg!z1)d +]bku~-)y6ӣRTRdA]YAS4]HOYCy 57ʑs¯X@f6Z+Gͮ=]qfHB AK,gcqoMjw ɱW.]IF1є0eW,y27N!ꇊ?aQmE}k+8;ۉ D iBUqfdҘv# n3*<+]OmR8 .H8v?&! JUJGɀ z?U_Uەa9u_sǵƫT>|KgIt#@9f0)ߎV}Jirma>w)/o౲$!?˝(_&wCN>F'e$w!2^DU=I4~(նaZzC'xoe~"gm29u8S瞝O+}5@>g3I׷$ Jx"lJ , ~?Ǐ}<*]jU ֡S5m4ӓcIIN*Yu1=KO"VॣݞIA +IK&m]xb1O*3_F換A䆴[GPJB0wUelgS-H핍W̲I{MbЍ;3<3nڷ sCTWmm i&SwH@Ey.NAf۷"|x*ƂLO5ɫ_KL̢y:qia}WcX@94{)C_ŞG1!pzPnN楁avx o8 b$b{ `1C*&W*Mq]jV[)C)WnY+ +G=IKʼnzZHn×Jc$hѾEAD LFԴU56A; 66;ÝÝ aO<%VdbDW$>\G|${0D ?uVy|b)õ6އ].5ɣNa;Kז! +[?Cw;07Yy%s=(^›BBQ Ɉ.[gȍ)piiC=%BfR}[l@x&ת:D?chQ B;S&Da4i!drTæ%$Rp6v+I$H`)-Gtp7F6C5$-hӲmLYD/䱪.͖f1xl"y>.vM?Ǝ}ݽWt>e΅="yaҺQP|gucw(`?Uqǁk?2eBZܠ۫IM?jM=\ wcDW KR&TpvXVno+=T-9WO_QTp{X}0K}]*-w!P-|OZ/4 wUg +ޝHp*?sˍ!xhDᩯ ]2TÑ7)]+mܒ@4'"rGU:\Q]Ó`e=H`SI *i {4EA${,#{`xdBb7} }M bFt3,NF-8jLc9ɜLX7 GQX!026fZ ׊\E*wQa2Xp{:NGd9$k8j{H("nwa>4.H$8"W{  ]h/ML*elDQ~/a@(^ŕSQuTGpۋG? 4w]" x;V.2NcSD)[B V% 4'OĄG@#X"(f:`9,} +'eGϦCHQӔ~_f:;B-)E7WBo呏P̳la6 T['崶]x Fߍ~Yr0nK-hm6I#>u~26WN~u>?GmyX8ǹЖ,SN^.['קu0 7S~C}|ɣbsNܑtxbvDtxt?O?2f;֓^'Mŧa8^`cd5[')e۴mR?.m׹zbًRQ6d/`1fݔ:&'\z~ 0; =wJ\H ,o!rm% -DGO?yQã{4m ?Ѧ~݋K*嫠dR`^+G]Pu {|v_W:NÝEw!Bn/kTbGmB(g'4(j֛([M`Og-O }a.!!/zIJ1:pޣ+$&)Iݞ"d!]9 SJ\B^JŸ=% +}%"+LNT;[S=3%E#0w~3ea !+Îۭͫ:w,ډM,=7T<ֱ) 0F n߳gJkDPd2LXu5ij/T]ad1S+s>;x bNٹ=gMi;bH4C_RǞ,K{46/P&mS._5S`mz Y/܎8iӨw'scǥڤݑ3UzyupAwJ7 +!~lp +gud&|zt^ no[ p)Ar/ v1f{`._J,ᨡ]`JSәQtwXK%z.Z*!{DXF}0_y#2r┘g3 +endstream endobj 93 0 obj <>stream + xۄђ>*j|d'g`T{ +.!(x#漘MO3~ ?Pѹi&@U'K^#V>o잍T . !NBcTpb G:DWZ&[R[Tc;0EaW߳:OK?ɼ&eJxљvE%̴TҙM^?J~y~j3\Jqp +-GRh 4,y:͒zJh=g!cݎ[5 E!ce5;^وۋ2 |5t>Sˠ`,8K-̉՝P]EC7 +%,}娛 jD]qr{r)|ؙIa+ٍw/cwnet֟?f_;N8q>2Ktx{;S_guZjt]~wUu"w cFخYzZȠAI?C X<兗@,]߁ /(.Q,cyB ";>6Ρ(z_ 2|QdbnNy"8"'v.C=&2|N>E` k섑5c;5 !OؔKU)S>ϥ,#E*G,#{ 8{zzSO؆0h\"LaR,N3+~_3Ϳ!vV4aNZd%㯙$:7B43Iy?O|9&Qe, ( 3͈I R]]tdYʒ\ː_i.Da]8`i+OsWkB|4iWa{7{.5Ίx=&B4t{k80̗_Z>R4if.hS3lYp] $LAVCS$ gLלjt騁a7.Mk7YutQC_w0ߖOoo +,Dyy0.jFzʖ1x)%0,7IlIaM!zD R46/lba;raTFHwGY*2rzD;͸",X wfQX 移+ujrZT~FJDoɳrՒ1:7dh\f4T=ehpDJ5Ƞ6pȃO3Wڢw٤6a4zP5ũS;v'{iQ!xLt9^ͺEK)ŝHJV}13aTąãFuzJzdzN܀آTW,(ؗy5l)!y9S{i0UL jz㸂GMYFYڼ.ܮ̲.o;éCC8 =.8Iv\ky+ӵr܆!a9,B? ra'qa#؀ʅy\ +;{ºybZ?רv=[#A9@Ċ^n+쪅R$,g~LXl$X*8<%K*0U;Yj~W=>;sAs =([-ݙ6AVW͙.)2C7LHC\s'`XF,!zgWXO0Dq&v6\د_z?$|%}e[I}%v,Vp}٩rb[T*! .H7R^lJo gfFccW/_Yz+1x +d3)@:t= 1o}kFycN7,/H3hOFF"IN@kjH#8e6ߌ ;G@+f\!-=J𥻹Zr?I SV=Z>ⱌ1[Sg1j9gP2)|;>Sp~3Cp\m p7ǰx_3?!-s)r `>D m_m5?=}@LeF,|O?[5L,"'~vvI?I +EYpvvpQgQ>u{)rh}T9 nOR_o_dv MMfoy<3}$϶m.'/']|D2Y(y?OLr5>~jW^hM.' MSR'3]1َ~߄~g_9GQ:2sH{_n᪕֏Ǟń zgGއSdmN4" }@ry\E1LP|=ǃ#[91ߦ8)a:7XėXlx:H5ˡ<Q!hbeNq;M^匎_D{dj\|E Dτzk, 1END҂Y]_*DJvV yIl`Xk1e"0G]兩 QX}g +ziv1j0q7-v&-"fX9"JJ%-{0ja6~X3l©B}b)[G(+09X|![@! 'j>D r^`pW)OIS>n$UX|J7ACۭ.om-GGn?]gW~GtRhЛ d{wPϹ;^<9irKˌJ6͈UPB`҆u(LZCs"B&Ĉ|02P]P +cz0bF.5y>)Hќ@$ \"I6pDgCA9`#g,f^5!#x\Q\k#zr)g,%fPݺ'mq0]Ǝ 9w. 7~E1 &H ?& s.kI,‰s,N@_E~ ˰ǮoӷT^^ .QeX–pH ?UU!p~nF)V뛪a$W+X {!*wK<9!%ab g a=x> u$ F0p׾f6T9y[R\ +hOD1,SM^\8hbhJD +؅(imڢ@JД=@Y޶U'4"Ѻ;2}R,>.d\= O_ ܡ/_YsTA.& ;6ެ +o%1# 4 -0a5zibͽW2kLPÌn*28S\2`%e@yB ŸRd8)%n?5M>>\m2*Ǩ1bfVi>Fd>qUYn 0.hty!l(|nb;>pG"+pYR l>#jՌ7Q3y\Q5vQ ,U пt:nCf^8!*:s7:H/c*Y_tҳo $wͬ c-ʷf q{4(%Gn],`u]Y\gB-,fg8eøfW&KAe]7e_H-:,pU]S'G:Nʶg6ҐHU`d4+i + +( % bB@k&Dlcm͡|iND\( $sm2,޼ nsTD>dhOiBѲ5D%I:kMdDONT}ݰyt-" B@<𹀓UC$6Jފk8 6 B&茙C X_}/mS"ig6`@M.bx,VSp}T(!ԢK[? ׽Llv^Xm׀'^hV'mf" IkdmEF{Vw+ cJ3oox/{ &N 0dlj`;^@v;@\mȁe4ȤO%T^$>)Xs[C`dn&]jgi`9T3Ϗ3oo +/U"r5XqwkBDp*Kʲ`Z ;JQY8zÖ0dՌr˭s 牡?>[hXmtD@,pk ׂU /tEwvap*U%v@2(ZkxMQùU/|QMܐTeU+Y@ʡQQ܅I*&[YXo흚 ݳW !uƮJ\R]o%d#D[%Cx] H84#I[m78, ޹()k 8&P?'YkO}ۯ|9R']MZE#iҟ8mtj ѲGUPgl=W ޼עNvp20τW([$@>"Qe9@!tIwŷtς}stVC +vK?GZ-+Z)IOו>.Wߎ8MJw}xS{WdN]xogW`:~}eE3dZ*0{J)cq*Dž6~z}Nsﺻ;{O}݄j^[s{WNڇ7<}.B3&?:r݁ÇI'+x~2W;bOw!qO6C Jp:m;N (f3%|jv@޻G?Cl&!Zy?q΂Ҭ:+`yWk||m^ +/ш$Ο>;>ܩpd*N2q{O.'Zpz&S_T1NއvgN&k}=nOŦ7q´MF'En Wt,YEBx +([}yLEwhw'{ea%sQםgL`pz_j&ӏT/םTiwRS/Zrw1w'~>^\TuV܃7 P~QҤJg\aY6_O[ߩ"MH?s.tT=xG4z5 <>v:q\?;g=gpTB\"f.wz\4fÐpo__ᏑZ9{؍է&`ueO߾%H3oK:(f>!ΕŊ{{b/NHrGؔ\f $;(9&{sZRkDžZe__9&ǽRsp*'ȕ+]xwݤFС,{w(N1P&CAgzG_q㝗e0$2g>`^N{o'7vK|<8Cp[} j#0)kxI ˹1%h9 LKKKn8:ޱ Jjm![N+ +`ǺI(T=plAA$6ճ^EAF`뺛Rzq%r(zNHrk.](~'%dF^jFGFڗ0@X1eZZW"` 7zPsO ll<=JkEIo~+oZ3BL,jSAp6~6jQozOfmH؍Fxطf+`SXGF*,X ^e) +W[r`Vkaðv2P]7@JBYa)mF8uUicXX?2ؓzycuƮ78-*PA2~oR56I"Yj  d~GpZoGPAZUzĭjY݇ߺLHAPu#MeYDF{-&Rv8m4PZı69L}Oxnh-JѪo} `$|Whjȋ{V|4ÙvM4˲gs(2f:uص + ZW.X+ݰ*lDqaah]C5@vݏ(ٙFzVk/;R5;R]FΞY>ֆ+oLXm~h ha'Nr\!FUNrhYrK=/uRi7m\!6Nr1<5#~8W/ưP;j~*?j8آ l&recj?#iHC$[F*rx5l"}aF)P64^ڻ +u1*qUm/C]r}Q5.Bo˜-.%ӎ"0P6  zIR[ҥōz#}en# i2LщG,JSc̠럵27$I¶צߏyVh I"_ .\WF6K +EwcfG؊~51z?u^_5Z/!~ׁcL6m \"L#5_LreБƓNnamdlLk+N;DF{ +,З/\> +DI=go q,`f US(ΓPT9 1Fo0bjYYY.3u"jǙ\w؟ +$AVv9'rk yv P2C QFIiд\UP{6ǡ .Ʃf!8[! | +uc;; =aW`X0X-J?Lk Ffu`ʷ5驔62/QUvR3N{yO1h@6!l;ύ)qbFkY[sHŐO;BK"hI^Epl`"D뒶S6a]eP:+MfF<>Y=ԃ{x_\pzG9q/Oýse1>4B)H@Ӈˤ BTкrBx +qUEM$^4bݩ޲?%Jo{E-1rDu EG Afl54;?=ߣXDb 3Z=*sCqq"z`C]HGD]jtjC-ܾf£! jUș!rKʏG)=4yY 蟍V`?{dF{%t݋ؤ +$yV:x4ש8C[:ht߉ L-:+2,tlꔊm9(ʨGƅo'F4̞K9RL)` ,BV i&x˽ I#6{ 3d9Ś憣p,tLe*R⒩`ʫï#Mn3ˈVBEqeitrH`t&&LӒMP ՗9D^ 6|AиC.:Сx,$.:q#ħa\4𚲏Aq$y \BhoRnp*Ï%΂ެe"u8n ŋ]~Ö7 kxxn ?,!]_!2 /Bz(%B/5lNC}&`&' *#Ub]{y/IM +hZE0԰*$~K εRwGA R`7ɟmT~/8kAPM, . )S'^ aaN(ŅS & +h'e!u䊊hXLLoT$Q&8& Eղ +ФIhaT?imuQEuljȠQ\Y  De5:ϓ&s_!E\7!|A!YA,ޏ eCwSA,r;klI2 UĎskmN:V Úd~ެSL'giX{??F[U y䩱2VÆ(j)[HD'2V@8E4b >p.."_s@IҐIXA ։aH]Ic"%D^|ZE;,;D`sYsIHQӷ}Dd:qؚg{Męb]"_1C P{\ҘӚ<',8N7BXE$B*>'c mJҰXt?jb1j HoSJ6V:B,[18/H.U/ }PAT+ |2] 7F)4iSN|¤|Sp" C ºJ^wbr{i&E aT}P%|?9L&,!:Q;މ㦨s?t{9VlV*ӛ]sF9BSR85T48D/pu# +'0 ! Dj~J8 +QMa$䀵i:D\.0ςb:s/=pc(o1Tjs-[;֙)8s^W9!XjQt詯XY<%V֐|($6DC}dʧ27$x]D@Ɯ?I(>9޵WY&O}'ӕaiR+Pu11<aHu^)B.rucV#G#Y +&iz|1oIoqUsKi6)tp8h9|0G;X7kN)sήc椁H +#Pm_B ]/iTt"Nq] %Cܗp܆Ilҩ#ka~Kh͛l!QGGQe)(VG<Ҡ0?9A|q=]~eqaؐZ&i=q0)q5 e/ a8Ǖ/#V"c0cqOC ƝjXY[WоbH6-O6cM"8f9 ŷyXZbܤS,,[^JcyYﲝhY$~:1'XM A +ɜ޵B$J博_!"=W*dn:R VVyssTdA38w]h Q75r2BNS^oګ>EM.Qm:ГWrB6 +B1,0vHȚ@/&`!cuQ0 - "N 7"^e2`H0kPTU_q UiewD`P53藹-Uǩq*8,JqְQ +ia+)<,QQ˚^ƫX3"Qqu׀Ѧ5A5iW8 ΣE"xjVaW>K=^UV3j:A sL~+IC-*e\ܼɛ[ED|ֳbgo|Xq9&d斲"%}0Ic8!p3Uc JN~QZ'm q 2o.Дq׭y)˰luŅ\Nڏ[RP5*`3a͕,P;xU;@ +P÷"DpE_BJ~|(gV;m_؞PMR{[mZ&{}#0Y'ӘO T8GAMj̛(>q(9WJ 2:Cu+"4|QKOδMZ4*,5_ +ʪ 'W +-8'>K6|Wp('A dN:RFoOAg"!vi%g i8O&'xO>DԾRL@~lmۣqE_7Bc[~DjfOcU5&&mҮO\bwl0z) 9("X(@XhUQWn=o4 +RItwe~=4lS@cr]ե$dut=UU/You(l& V`yfi* +RA&4|Cބϙk㶚d!oZΜNq[tءG_ׁXcfA2UµB0IUF}nj\:_2lIMuÍۮ- ̟N7@zۯJC'ts=,bRAtV,gb0jޗ2:]rWUu_g)fpwRĤ^:DV+<Tyپ۹^vw=9~4l&fMZNs.'fd|D՝r~cfʇC8]^'5|jr^sȞs_~|]Nyvgd1~_=4#4yr2Oǟ罤w+7<ȧOf٣_rt $/ >KOWߣquu|?Se)qy/n=W%gM+\SYLzʁXl7]8Uڑ"3ApOɘL&+ 3pf;8/wb: >qfPDh౲7*}R'ǯa]Ax|P/YmNwG㩳{Am"g?:ݧ2%}iʼ,4й6>{>> w*OYϟC.((ˎ=xu~F@)"{׉ rE\I+gn?p#s|m=c&0{A/}?_Hݿ(x=;T@|?㘢N(#j/g3+ܡ8jun޸?>on=*{uݝ.y}Q>ۜëQbT>) Jܡ4s =x+I':UAF˹'/+elH:#d2:J.{#|Nqr]/7˞u->{lmZ|Z2R2y=:9^Nvv +d Q)=s+e6?>eItV`& ]#߂i?Yqҵ!I-[%< vRZ~>5 +YpyyIOcMC ѻ5EP/WUǥDJyOf/uu~upߥ֙7 +ojԾ<>,yJN"\ojZ3} )Aoa]t:\O^}~ƼV$O]&Dއk-~sRzxFi_A,3i9OWKCy%L{xƮD.Mbw7.tRiܖkwWPBzi??qsjZ 'Re;kDHfګUoj-dS llpAڂ7qSL/:Izpa~${ϭA;+OIXRײ& l7V}V]4-Q㱚uz!XIqq̱4olȦbDMH| YY &\):@4=9G"Dd"3YX$m~0Lg 3~0)-[W +􋬶LNצ\=GRXDҖB ٖ<ҖP%͓6ZN[ITΒ/Yr/7K=!T,}I^g |FМї9__7gWi_Q~f΄uIlw挾$g 컒ۄBޜ]Ulm}m8Fٗ*iƏHqCI;d26k ~ȭRYXؖ[w b]Hs[n5u:&#-' 5H˅o񭉞q[iQm/bmc]÷U}(#OѢp/\߿emu\]GbKI[Xzfa#36+E*fa>rWGDz}ǍrhnHgVEF?_edgIBe0k~[~gD կĿRȑ=R1-4<۞Oѣ꾼DW ]6Sl"bJxԮ5΍LV["^-daos3PKI`[645d5wkzc3]u»U xUTvq(x &i4eI.Lu`yGI4^ Þresш x* 픺D;` dUB?*gxp sz*p!i:F$'"(Uh[ rg*"hx0/DgΉiF8i"hgzsTqwt~u彄 $,<#FZ0pO .YY|EYBTv߹r\,a٬ZF-,#+;4s{y̶p3ea5T=Bԭv5{g TQYU}G!),eS: j35FnSq 0v*$΃bdGPh".Q,0_A0 < \=I #jZ* g{Yv8$N:mBsӠDH~\Eg$zrG*gmWD7$XH$ T!\S"Dn|_Rs|YC,R VGq WKCo_*Ӏ+@ + Rm= _PU㎊By-ҏ"sx %#pܔ\PҐУۘ!|Y2 o@rEpK[bO(4 ;uC?.KZe&&y_@BVLI8ۼ6k +߃G$c&~6KX&m" /#mN1{Boͨ]dnH0hʏ]t;WQ'Gi\Ø%y5A9XitYbh@#Jӏ!CGR xS~P +9no&S[M2CF7 F6‹zqϝk#"q"&ct!vYӃWa1|+t<` CsD%Sk  ^6ڤhl$n@s,9Kp허CUjOERA0 +>{q89 48&T4JxHU4(H$;БhCE|l(ۘhSUyGEhx\"yT; 2KYhA—V)|cz*ϧ:X)Xډ#ttDB\X !*6=(55g\#攀3ܴF<n8_/ TOO( 1aXhiVI%$\')3hv,THr-U[S*( ,H:!vkQAA: pIM ?CMrҟb×U_pp \Y<<rB9@ۓĄye;N,$PҬDV$- Fq5ٝO@<{I`O, ?D<'CaeI Bi&iiS{Fb0DƢ$JBZxH +$#9ĺ^*a@~ bQrjs߾i?KE,ecYVǜyM!ǯǿtk߄-ZwZ4cKa+"F B0OukG# J.'*/1 9K +\+DžM> *|1|,%?*N1XDg*Mok `3"\JT]Y]J*ӐŦ*Ȭk$"r6'֐o$ҚF I+dk#98xi,jx5pjʁk* C+Hh~%jiBqsYcO9oc@ <dE*܆P9e 5W^ʚm ꛳I\*#룋T RӁh+ﱨ%RT,D25DK0䙏' G)0%ag9xs(u8 H#lw3&+гaw%Al:ԃ^xy98˭{C Yḳ'@*67@%hn5Ͷy)lrXI.%QCz}YߥJceLrkHQ;0xpĭ(i:R+jP%/%FELӅ (be|a5~n5K Ol+BHBX7>7V6oH#RC ߿Fj)N?[42*(/6{DՉfߪ!:nU/$n(ߕ }]U6}k]Q2}Y.,FkohE?^w J0j9On,b؍aќc_݊QtcFgF aڍolފq `1Y _bYd79}%i0XrLŢGJeM~`w} VYȱ h}Tpj%'È p:< ,^.B).yUGE*0@SǤS̹. 9^2mJ7+\TgB9ڊ{Y/pRN%LZ¤7ܶK>ɭPkkbioy`lW& V#[JY;u94X^K]RQBrޅMҀ~&Ju)^wg,潮a;e{Y..cpsu r▃$Y6$Y(;k Ah?^S +H(\oj'hmYcʂhGjHؤUiB0裆N*N%[cS$|@ Ah°VSK4Dun"J͵qRi8`Fݢ釫R^zwl:y h$~Ds?dlV'Ok^Ru~<3x9v-L9*@hw:)^sYaD+kU}dS,o-.AknF6 j8q5"iVM-ydҒf #i ,Llj`y8sRD,t*HoD/Xj;#L8[Oe6*[*[z*by7V_{4/ n  xzۮ$n6r_rk18'8WZ tlzr09 +X= +L/B{y MP}]7я29Ulu.>y~*r^}vNh!$528n}mNJ#52^ztQPlJlLߛשjVPo89&Xfnc=SڊP4ߏ2AEo*6c>gS-V XkѺ&3<2瞠p x}p`]Xc!N3W{<ʰ +uV(Zр)Wzq4"UYh LӴ~uYbߏ/kGyÄ2~o*/FЁܺ͢C[w}2"H +9 + % )8U@fo.AL cBE.hni#1+Ú9%PD,=in yNixH>y *jX؍Rϯ3=fKKjXcӔVLo|/RW,ܾ zjbv}Dc;!8m@B5a.HExT6D%Q\ LDbM蹔)0rH)HBb? |Yf ;֦~sSVGtPC@4b عd(N eFHЙqtTPeu,z4i @VI> ̀ƒ(5z* <"A1?k>\$B" Ě^8\="\pQӁ[벳K|bI\gȰ*ЏpxXuˊ7XHWY5I zآ_QnS`(ӏË շ^Gf(aԹ$zwݒl\k.QC~j &JP jhw߇Y@jJCoAt(Ul!8aQ *L@ K隻1&}B@̜s}0#JgC\Dia["*POL(o c Ah c{y>$ +,CMm0OS(ni߃T1t!- 1t#.HrC1Đo%!; +Eס~!(f5nf=ٞ 'DufM0Q,q}z +/HƎ.Ʌǒ7il \yt?(#fnBc|_/+~?B؞xjMFlr޼K">" Mcr.…6 d +o#F l.`u􄃷8`onXNQyC%:XA-`4 $ Inrz"/ LDYDAJG\U&azװ.1b,;Zhokwc[\ MNҶDCWhgVL÷DGuhxmA3LM!|X/. 枼SHbޛbCX)a$_&%]ڴK'˸!~Ҙ7Fg@rA7l:K"5?ݕDhB^>m^"g.l\yAÚErr.K]AbUNݒS 18H(q + kѢ^̀ZC@(ŌO⛄ +FW>Pek@CL4m@P:~8g)vf6Y"L_9,a?.3.=πYhF1 ʆpDb4Z wv岜p$I5NEDDnV痃V3F;Yģ*#ص>Ӎ%q4F Ka(bidrjCFYԯi1Q]{%0.<4fӻgÊ/fy':eKRY3;bB#2lLlڤ| '8MJa5PϲR\qT!xNN`YE'Iu f DFKn!b5Oh+`w"@Œ#QV< +#f3iONa׷M8|5ă{6%@|Wh־Mr[B25 W$E;ԼL,l(/-qXY忙]:zO^ںsGLo 4~8٤-wEiӍ-,$lwٔH!ox^Zh6_UJ̬%J#)o-j-+0.T{FAd8HY.!ꨮ7\n7_¤. >)=C- *}o㯁C^S#jmVE1ܨIb%Ӆu +> B$QҐOQ&MU[ ғh稾yɰ`+DW$CU%%S~l}Gw+jI䠽[X #oA){/S{J{JE%[gf䌏D+C³qpU3vtBy͆rcvP(Av6~ձ:j42iM7WuCe‘;Oq.: msKEU< 2P6,]ynj,'kB<+4v`N,D3:j"@kO5!F@0k)LEPN() +Q"\3Uk2~^0Fv5Ȑí ~_s]Ub ܉ӱ {ϵD&\<ɩMhrΊ( F=]U#4y?s͌HU~(P>[v >Jqo&X FYσ@lǗ[`3U|NMlx{ wIipн|o%#eTK}}%fE0 ɵΡ Qp yѢXyP^@pT('230O ddqSK̋y|?\%&;#*P;2 ?JwL_5B]]Ye%lp5Dpg2UQܘy#dp{D!Fb_lӹŚ|ZlbwVL?_X4p-.lbA\sN5,e|A>}Y?d$0#_4ػ)򅛎<7Jc;JT -?ӧ:ȷM'sGSlj!UtP+*$&3 &=*ɞjs:sH# w.,&j8dm %ѥg|Eyˆ pi`5n] Yg *_T8υ*fa} +NU#"z~9NސDI38IJzthAWczv@άfͭ *ձ$NhDZ;SX'\f_;MlNiVnQߚ?y+xGl`ݕ،t5;,rj52`XiG*^znYZ pyWq= `B EHq~% ԗf(($Ww23-s3(2)͠ zL}F17b֍njNxiQ0x I> =t|m0h6G=H,ԭQUpic}7hԄ3p\GS̸ܽYV@;<0mUsilMqSJzmδ]fRSG;Ns+/7$;MR喺BW ĴQzz@bV0+gPO+fIaEìAh3XiO+Rar%984UF隸xճZ_FBR|iDo%}Xs,`0*\:>i^{Y:B#8v'|kI^g!zL7{W[lz cǯg% 793*?dtNP%p5P^Ā<ޱ2 kz1`NB2^pÉ6;B~IZ+JMz?{GP_vYǷqr35JcT:j9fIH ݈|.Fr[2=,Gϋ Kw#}1\le_'7_k]eJ xԀRu  ]@ܯb +jDDZV <9k&/'M=HtdΏD0QiAq/V#sk&}]r+K޵D!I +wWJ 껢1m+̣Ii{_ԭvR_ |26ۛ/m7 W. -[\=q0@ ! i+D IgwVw cӡq@u7.GDDHg_#YF3`u{e.OcnpLUߨNy>> +a[=cx7׸5Cܯ(:y aHHg&rt| +*4Ѓ  ;8]N)uHPBhXW&iR!2Gfq/xmf:B >ZDm|~΂>Z ly@uГ87*k~2Lp,޿O0m/kݾҬ7H<va +Y͝K Lfz.o4#:4v(|YrY@q-̇6B # moJhSH? AY'xGKc*#1ف Y>Z d?qr-G.S_e%qWXIk[Ը2=f9,Oكzރk V>vQ;]agu$haʅ3XTj[btA{<d{C^* jXWhuGU7mNlpE~I{ua_ϩ!9]V1uOqÔ-ƙrTfSth0@ca ƀuNFBOO0MՄzBiqBOuY3 (`/IHQY&Sv'b%\p4%rtu!/QX/T1 Qh&J CL +HiʾKӽ.ƳR&_p6{kKG4#,U,pb^5 Z5G mΣYE*,}}idoI+[,bʶq0XyIo1\`S n,{e`Oe ^j`V3,/SlO%7aqaS>zI[cLjaZQLXmړK46mMݡzZ!Hً[h~\i o ,Ybդۑ~67а026 V3`ZB!]]a^6ik5~^E2&S!ߛ_ ؁ ni'8qU1^ûlʧ*EOo]av"<^f&aU{( \ȩ vj[_xHW1qB{75$:L,.]XBR>g= aRFŵȔHn'e:h_EEn뎐T#-[YWCb}yStzs;<,]reh'=1_wp3gŚ,ŋ}eog;Weom,9&N.1J8Gl}2tefy=4l䓿llu +._[oX81NJ䂴~wܤ3PH\+|y?݅ 3z<]KlY oADcBc_ůRx^ﵖߑ K'}Wlg[UO/nqZzr݉!#$gKUjǒ<oB̠WDX3ek~9mZJi{qوielj`4zaƻ.5wVB1r+oQT2dk⍭-6w΅ -(WuuYJ/g?E^ҷ=oK W\M,R*8\qJLYsx +T&b(ù֗IweKTE\Ens8RxwϿj7}i̱:b󍣢{Cm|yw\jvQr +t\oizvV_ +m}6KG2UxtPRC>R#1gG4z=Ɏ3l":פŷ+GpK?:ζ*Yzu(m۝^f{G{FSE#k%[>},/;`z<ݸs9{%LzS:P jrZ^[7B3޺21zKM:gё7$-Pi4;~zWQS/:Nb(ޮLD +4ǃݺĐlFܷ5TfY X([:{ kg/7q۱\^_f'`̓49/Yryϳ7`^Bl|h:Yy܀@F+rݒ-ĿƹxgIgwƓlË[+}ߋfff;7Zӕj$ppgCZ۹oЛk$SǍ?xj "仕pTzudW=HTY[%[絛ر7#-O/׾#G (5|#r~.se?m2 ?X\kEQp6,tFܮexG杷z=+G5zU%8:?<:<٥/lp_Qy" BgH+%ścWen ő LzJܶd3Tq)tvrh<)g^٧(yB^GF9;-xbΑZ9zuܻE#PTgP/앴;:#6X<8t\ig_|L{v_H1\l̸\§"o+n<ek:ڐ+2L F @p>̈́q<͟*ʆφ`~(ruS@p4VB21#G=_sSKg X`0 +7G*UvH*A۾wH~0GXҮqTo@+ b ?v>xFAC + }w_!T؜9eyu/b&D1S_;al튱9l6)陳(c0T+<&Cc$_ FxXl[z`XU/4cw:̚{Aڋ>AFG:@{2T p%fDw@uPyCo6\jTsvYCs}yg:ݹVCåS^a\/ȃP+_'-<@ݍrW޹n5&K(_L{)<ْ>W4,{DK|ӹx/);/TVaF>^$a7ptX87't/C\0,r\1{/q{ PU#v/j:CdHQV^- v}o!68ko;j/U<1Q[er25΁ bAū-ٷS`y 2|!1_pC_p/{TAJ^1Y9uZ3ʕ=L1qOu$2h \0f7Fkcwj OB԰z%G): RB1@٪SݳtL[F&^0ȥ +iW} *}fPn>t5u|=,Imvⲗ-+Fw ZPnKWx(?}m^^q?+`/-ux \ҐtÛHSknbaި| +1t7[\ muSo"^ xˇ4%JpAO~tL/CS02,)tpymZ`; D6ZRSμ߈>up%nbI#[!B)@*枈@/(!^QՖk/X \W4IlֈӿWs2qo3ֽH^X Paܯxyv)nm'ÌK{XK;}77,Iޟb{ķd""u}plmRc|#A +0 +!7."GPGlh%:ۘ@6gf5Y}**.᳧s ήCN!(/ :-!Y̪ *p%;ͭܨvmT♐-,xF,8QC+{ި&c?'885NxtJGuu740ߨD M0Ty(I悸Kٟ 2;R̭EA(^R\())Kh0dPI;ۨ~wbdŻ5@ +eraHy UeAgW>D8 ,$a0Yt:Zt߽2`Q˭8x/)gHPrNnZT)OxO\9'C3&E"vYVX:#0Ol07 vʹ4,brQ<%G, lFx>Ak7 0wB66F\)Ά!7z1^G!, m$\ Kh +m=DOEW҉zQMHձ\[x bg6N=?t(/=BnT2v\@-n{AJ13H[qM q@\DZA5(栞q^B~JOzaS R첛XX4VPRL%O4a¾Su~M]=48}A-BPy0Yx)ŔHL`G GK˛MR.sc)M4Pm]u&zf\AV1Ai8P{-5QpR7K+T[zjm/oM يtE5 5#O;o8~8q J?K"nqW_wL{N0og#Z,>h/,:?MO`|j&rȅT%oB#+/dm] ?;s +Gr,{ւQ N|'X9mG4G϶.ϳ%2|QJD2[٭'yPQ'S`LV v[*?_ӿPzz ƺCc ~~H WwT!9RVs@.!AGj{9-9aWPXہgPq @+_ 2.( +QU +rĚ\ta1Fa\BrJNGJWnW^KG8eXb9SwC\h{ MM_A6!raxaZ6RlOutTp%|*r$鐊Lj?vy Ҥ:ed~K +^B%ݏeo +9tI7 2DŴǶ-CRȇJ #gu)9L{y.f?Mik\^Q;r4߾}G,3+w^ b;e(bƏJrע=]&Ѩ AFR\KR̂߀/GوCѕ^KO6,2'j@} .t-ӛ9WCӜCC#@)ZjXOMkzw2K+ᐥ j{@5Bʏ28N, yx@؊ +JZ v)m`bW(XDHdIPR0>8@e^f /1W`c-rN+x8#>aB$ز؅tǽ9 ˁOkSԐ.s%:6~֝zĆh +-C +~iƨ$/bb0_‹yM8@?uW{4!,0V^swǵQE47>582iMŤTN 'uZ&9mm N *yosླྀu7UQvٜpfՃ~_` HZUJT폳EC)PCpS6chyAg]h5J!{ŸJ jQ*n.l`);qVۡK`aDJAS{GIZu 1Y+(Q= WTLЅ߭lkM+N*v&vE0q0.]*C[ѫjªߊ\=wP;-) +jg^`ڙns z@,)4ɡܿ1Fb*xL}wh#`[$8^>>btmBٴTR70ŬF>?7tE`IWIӮ$P}O\{l0]ѺAb +$ Dɧ2E C̬ZQg _76$K@ci'Z2N!SI"?RVU _KPi8`TޓD/k5ȢaReG?YMy2LЬmڳ WױTQ%E|AHD la8^Cx]o3D 5qU3x!G/Ϯޏz^"Y4Al7oxOcod9d5I0y r],3\-yq"Q ҏgEE%sct"< r-l(I貚Rnر̢Ȼz*Kn-0> 7N&XGX`9dXc0"j PmB_d"1}on0r}sĸQ ;(nv]$a`:8=]x7La@ +emGC[p:wA@MK%)# 4/MOqu¥;0vP BԬz&ts8➨<׽8Q~Q?A+1nc5YW: aq:B>\ͦ͜ T@KpR+otd'v0v#9p 3ApFdȷG#k#UlVˡ֮aNUezLY6ƀR!\v!&)VDw +]d# xuCߨgnм&K2*eT 83>X⑉wN+"K<.tk1r18 5Ү:6rO< +I=m-xh%xA~,#CW?_U0%\7 3u%E=>##7X|LܘtMk40=[6z3[uzxpIG*k[!~ܠlh2oe~|B1]/[~ 啗Guvu.k/RR[k u"/b1,T v +ZeM|XB0Ӆ.ɹ9!ేv$q"ş pU71+>9lV'ծ#s/y2/q]8,@Ԣti =/LA,̄%KTqre,9cɔOʻܬde"} r(A8R XIn-Qd,РqLTDWC,'.)#q`J D@‚6,. ]9YxLt`ȦTvNDglEg.j.?گ 4?" +V`"͉d{sPnk5,agF'5d+S* s-lPvaxF~CŔLqت b7( {Ǿ:(9xIWݽNܚ<vßJDc%SH`&ij-YlAўu= N]'Ɋ<91O +|°!B3Z:ʩFz .x%֦C +|;J9-8'&CD&vT]QC1nxoçFX#URYb0, +%( H=aGFlan7)ow2_kyk0h.ppT *kF!?$PWiuB<:[!62W +ޠk'%3Cx!!а.J3$]- &Z\XIKڛctukpv7C\#{PPrk^ a9GUqUN_G-2GCZmGl\0ӴŴG1~7 zCQC@ +3]9+) ` MZ45eHʡ*exS!IbD/q|/g`ɋFneHtk3a#tZl|4@OpcRn(]z7‘IҴK`%_2Bt|gG_ɏ\)|mVhRć ֳ C-f7!<$N)A||W!R1V_M8wKV%¦sVژ]z٩Ŗn(MA4YV̂RoH}e]GlFʃXO31iI^^L8`ڙ+g?|ÒMzb衉@W\/Kc9Z~|7'LWViw6 U*hR J-FdB[!L^ GjdtU7xWd0=-| rށ+[]EށQdbGigP)xAZOle~Yţ~lfGQudnɉ04lQ𿃸j,6dƜ \JD`JAd$aB@̍'3| +"UyW\V3p:V`Ye!$ srR= ޾ښh(] G4S5֋h03}cߨy(Mf0WZ`e"E}GM@uPդߋnux0j|«P#G/!8ˌsqIzQʼn;!LEvȦmY88`SfZ{[E~U@[`9I_D1ud6.-WX!:%2:ѧqY-J.Zq?ܚѷظ[:=ƖL/$Sw_ӏ\4z@䟧Zbko)y*\fMw,IV#Uv֓uWKy,|jY;/4{b4~tFg.dQ;f/g%uHf3 O'ab׵~śN~x_\Z+x[$ugvD}pxwi!RrLM~ꛯjgqZ=˕ر>gw-okOycv?7;ӌ|XwǒKZ+?sϺIYܱd鼏Pl[@2t^)$?Ewӈx#Bl^y,ތжx<#Z:Nort1aeaISJǵaʴg|b9^uedJiOp!It ~ oɥR::vύX7z칫=E:6KaÅ$ۿm%?wY%M|g~8OW4N`܅7hv + \Fd]W-I#~ {9 +0P/dwΛ -CfU  )= u?ucȶS|S ьyXVd4x\o}Vza#E_tәƛ}sQ@>Z^piM/YǾrYiێKWVR(TMQu!x]E`DҌ҄b:]M̊oB'j%Npu0͆ ve=qR#A终b<#R!drj =( rfXxXLgp lh~~W͑zx`1wO]"<-OVX'4 ySMm#H~Bl]0\p"ي!XBcZ'M˛K/AqptZ fhЂq ..Y#&PsEhp +(_'4&#X +G8j]qtّ2QyFCϠ{N$$0plAL""IcaI~}MIlW{#SQVz {ZrX\F~5~S[1t1Gw_8bBRX +7YW* *>V2M a~x>i>V5/8#n>qn* 7CQ}p#[!(QF VieJ\؆ofČ*#%zCBx^։q~huEjׂN=D#7KSOe/C.jjN6I`su + ass­T0ΎѾoB܏؎w<5®u\;߅I#ʖ +xSJVxQ#^ٸ=HdSgUZW(`&IόqQI .vOm\nlG_"˱e_u# +r98F)"ÊT40*L"V#cTk~X8 KMy|a괛&LZ+ 7ʎ0Qm~j7po6,rpע  !UznI~i:@+?$B~'WƪEyA2zHS(E2$3W= d(Iq$0᰼ +\rIN])e&Te+v$DeE4eEP,eD%ft^܄ciZ{8Jc vB /dpAK] +lcHWգ %cܩ8ַqC'~L^^KS?ٸ¹\LBl*F(PJ!O-3H) kr$WQ<`lcn^ޟ&W*F䀲2?"-x@nF *EDN/`^$]D, '&I/Jn^&p#23}GK\UB ;U +;FX%ne\71̲ SO.漒4!KܬíOe,ǹ@.jKq>%\lIJT717[7[x8 àLkjB(>Qd+Ӧ'0XJ,F]!wMI!*IpONKjtöBQfkD[8iKȴ |.XIApdTp@4Q{,'3rK| 1ƨoV6J)~$<ҭ~ Y͉h%7{t"CHGD|XƗf2" #"j۩Q^cG4;Nf,L1шh[IZ#NS#3ʣ*W[KCNI:+,*~A_-H&Oy0"y8Dyu۸*Ҷ ҞhIslrS1 )'[YL}pxӒ\H[^ފؤ ʋ %%ݓD{AOyčqpJ\s>"M+^w>7so]Cܣqiy&i IUT繳:ŏ]2 hQE0#3|g GLg`.!Y )ldł@DmRcY*|~@\ϓV(=YJ!&^`%8"4$S+7rZA<,eB˪f{Ǽfp?Ҏ=ߖh|#"fꪷC{zg}rFy\ ?Ip!#].sn_L 8" Kڴ>Br^.]HlZĴ/1[a${y6Ms}h1,7[r't_,,6k` %g ʅVȱ#|16HC׿b{HȖX.d%+0JmFF|h`̿j9a?X4fKZ +e5NyLeQ!~|HhwV%G_s Q0#ܳw[~,E? <}%b(eT% HfeMV= t#IC fQ k(GoC Qm>H&Ы-O[VPX9n\m\˒/A_ު>2&/~Oup]= Yݝ@͉>2|=k*\[/g68\gGc7!5e \on7hrnox3y\N͍D]+.] +kIKٗ{.w%-5b[6}C$M9l^>^O?EL%~Pjfc٪JA 2s>VҧTO%P%T>ʿ^8#mvU eMI܄ +bD}t00YRޟ#v!#*= " wziiq5ܯ&Bts(m6DpOpf@3a-ETϮΣ@ini,~@t%v{m + 1"a!{k,ORg%]d (+I_ uZ\Vv)>^pDTΐSCxJiȄ3zZ=!Pa-{Py 0usF 'm"B)#?D"޻Y-!EpKE0Z UaӋR?.-)Qy ' 78G!V{p3EaĤ ܰ€?,y!VQ{&dZR:\;2&EVDQۅ"XT_ϖ(Rs]&'w=>r0JѲ@ϡ4x q>Xhhࡑmd1A `09ǰ1Gl;AnHZ M|r4#(EƠ˃vwY88 FPcM ,ʹQ ddNmc%Ծh ;Vۂ.YqbE˃A? ;CsH?o maU%# ?dh) > +%ƑrfaAsH(_TUR+. V`j%{uERLO6(IHOE3wLy<;6wfp^LI}z|h:~yأkű~V< |pF4/p05zW! {eLsz G-p>FsEV3&2[MіO@$.Io㳬AʂZ ~9I"^ K&0am<27|v YZH]xҧHK*8e#é8)@S&906W_|V ?"4;e!>H|ݒT +4J`#f|,pQs WJ8 +?IJE #Uݖ/^ 磶Ol6ٔWlZMz9txFP#ح3J~C0<Q 3Q8/nݕC.NGY>BԿ [+Xh]ȕc,ޣlݤ{&0Ơc2;od)n6F}TA9-wMS509wnłKy7PCQńOIJ&HFyeau(sVP+a.-$F2j&z8UY +s9<;q0ʠY.ʩT +nYM3H b"QP4ߣ/ B#,A"1B0ĀF@.a~)J (eZP' +'-.b <k*Tݐ*ƝR=z_*g`zH(C0rCT%1|OæiƧ1wԫ<%?vE]q&8)oiJ囘-JU#ZU%O*)?T)^|]¶ [M8ѓɹɍd ݤb$q(I(&KJ@ trBM9ݸ1jJs+_QjƲ/NuW(o$'Vcca!T+.[;׬6;~1zb곷p6 +t;( u]LEw1cV QoȖ5^Rmid8膷I60ӗ.G7gY ){>OB"! ckwSPܓզG6G[^dHfʐ+ܳ=5bu q[b8W;N ,Qx6 +y`z @* CJGa]xrgMaj=qѿqaںϹÍm3okMd> _.PYkӡ :? +J(RqJyqIca6!(gP((@>{j*.c\30+BGV3懒_ݵc x1.#~Lv?lNw;'عW&ebyOxmv^%m|rx/[xpQ 5Pר|%ՅܞY4|l'2g)v}dY4rZg?\Ǔ~ lBϫn$cqBZpڝ#P?-afM:Hs38UFW"]qn-! 2ԦA:O7+ f2쬺ߜ¹%"=&JY# +f$>F?X韕LQ҂ }_~ :x4#QsWg5#!9'3!Rq#@RV2IJ.#ٙNJg${<#Qa zRBGތ(Ԇ;HlVg~(1qdo؝d;="zCH^אAv+Xܧ M@x^ YK%W|Sost%6Q+P5v+AQHVa?k=۵LXp9i42SaXgT&`|.} 7EA]Ză>z%!KW)W2 HŷY2bFdcC^sS$~0u4\jGu9?)z_h0rgMcbJnGO|X* ic(_s<`7֤#0M:ׂpJ^5 9Yl7 6AvslrvkmRWUUG4^!ѝ?uŃܵͲ@z@6! }ϭtڙrwbdaa'ݛϡHI^d`TxfJx \qg.@M_W.B8-&$,j/tI7F)5<`E@sY*nj"2pAX .@$F9o9儓<o#6p|<ΪG@%RI4)ڌ+sy*礌F>TYƈ~@w鶆/Oo2)OL닁ʹ)cS4iJ M=CWxJ/Wf(̤o4Z?UZ,qbgcrx2a.cl&!ʑE%ڢQ€dDg!>;/Ywlh[U@[$)YE6%nFq +dPWl (\wNE3u:OrThL+Gy1dG.hĦ;;9{C I&;ܗ Ńg3-%ڡg|]eJ +_G9",`c77M GQ>hwmJLrJ"A|$O} ?ff5TUv]'EA I +g3cj"vl"m92=ߤ"kK+W2V(\?L|e  k9+|)2^^Cvrpm͋I] Ȅ[L m`6d~C#- 3ʝjmZ9$$Xߧ'dr 'Mc*&f u< ",qf'^%Ϳ +Y4P% zdx5Q +,J`n䷹ QBgzrj3#}4BxJd'M~:l5ir vrbGVy8h}%>P%0ѝd +h"ya`()N+vI&sPQ^Sz0Ґs%^ܺl#Z=Ų\>-sJFB)z¶J@)!JӔ] RVϕQK!IǽkKhZ$Sil 3jv^Ofs&$([z7p9 83R: p{ l6ӿmqj ~(9LmHIMxr;{@9\Cr,x%VvwOf%ٲ./wSBq,n)C1PG0 +%\ozg𞝭FY`Ϋ=[S~ea9dU5;&~k +qG)ѽkB?ZʀNt-ҫeiwHbEFҲӭ^aY)Q>-Te'_2+]3gl,;L)?f-f~5?{6˦[ $lڐ<5#s]>>j<̆yv bC6w -l,(b\x{읶S4SGDMa2[!] `E sݗDL&0:_t ௾7"pUŝ Z38 +tmyOt/do mc\kЗBB017{2XSz"4&6? .hqRklC,- (3GHSѕfV+c0H_.nΤ +T4n@D +E?9 %YfCEvɋ[\0 +`S2MyX`.S(=R.1~KgN0W\9X٣8GGG8o L83Sv ` u הeEGѬ4K!p*2'Z=r1l{h$vMڶ䶄tSݳp+ JhB#'pb +7$Pj[~0Twq礶bEL @Q'yL-IfkyAbph VPÃتЫP55z`✴`ӢZ苜Mz +t+ MT,\v~_ob4(j(A 3D +h;3-歹 Lrc6 [Ȣ52ܢ]@@ܰA'nsq$v' 3N96ɖqޡX{Y:@?rn]Rgk4ͣH%$;$- >b *pRB(GV67oALlo@OD{,Gqt@փ= m͍ j 2@g@JaNds#Ax&ݍih1dX,=M gZu1n{KNuÅR+ +Nd)ʕ~kS-_a\-ԅܓ)e/Oc>7 +Ϯh1b|/ +VXHR/f_ +gl+f +1*?Iu;qJN]L}K_fzsӟ57ȇ g'Ië*(v.g)҉+ 6/!A߹lA-BSpU_vMw嵓wG"1*?Z~f7|7ܰZ?,o8<۠GZI]]wYȠsn'3+ff=I.Gޓ"}1m*X$]ͷpI^e+b^ʫ M z8_sf\45!rIcvY , k`X8οз }:YUN x GMɬ&ѽtkђomSO,iɄ~k>${7zk2K 3_jz.UN:l|ʎUlX!?f:qm;%}?zkaЙXbH(lib@)*Y td1vVb+)43l1q߻=BAfCZ +L-9~1R",=N@ᜆ朎k&\V ݄&تcg% .NAbb=z-0Y7>?eOqhi~>s%Umo t:hQq -q0ЀT1D87n{O qd6mT\?^x&|s}D{ٚb_`7 +,@e^/ e3?\H Qi%F u [薖%(0i  +bhbn7n^`{e,I% sP &Ac<+Cg /:-Q{ LIM'c@PA`f,H}y`|JɃ˸=2瘯˛L ;qषn+9~h(. G2>{a۬cϗіiy$J pJb ȭ6J"1NH~@^#Ct!Ӳ}];bT$?4=Ebl + `:9bxPsp + +։3( +fg>`(گ5D -UIg}BWJs} +%rhW[MLbp؅7C%Uqwmȹ3G:[;x_KYBia ,)qwΝAu3nPZ 6U7txnM oPrжЭW}\adncG&mPk!^+ϝsy82$8eLidSqnIȊ[$) `ز2 Q`Rr e,AALD**( k.Kl3ٹ "%㵸NjR[08Gt^iz- 4N/nn(ua85m*!UACC#ĜaVezIǾ"3Cw#>"WAشxaELUYRѬOf#[GSܠ 7Q^2h".ApMX G +GEM{~k9 D5bsB|R)7֓})h,!CqQnDgZApVE:N?̤Ơ1ѷ{, )2"%pn FA`I$͓|/לD +]:k#qvxVLO,X&LaY0 !:-PWV%;D`bad/2F', 8xdPJB9j;E=/qHgYLh'm-bS4_?x9d]C$$/Ex[ gUs_U g0Q0'_}$1(Źg +endstream endobj 94 0 obj <>stream +LE&D1#KMFK`IjD`\SteE=) OVu&BCsJFHzwGeY-CHt*9a9`ӭӈ6Q.LbH*[)+p Lj* F1;G L +pJTH +$7*gi') uw#ѕwoSmaOb-}j+)HELIZ}|Iy]|L1zk9=h?8k9f%[`Q[8z~B>`ÿBhժJ@'Cx[MH˘HİoUSm*bD(UH}Z9C(ޟZ2Vڳx}nZX8(MCqSձbDy agMvzuB<]-WQ(?i]-aRw~"ZS>9{SKڋl5N$Vo*Z8<8?{E{e +L?kɢ>0C:6`jQ=GnJ@IUf;Ota1b@𸰘mD[oŎ$Ґaqa1 8-7b6E.䠶OG^v6f3d=KK1T$ LMg:,I~sΐj;;vJ1 vFe0!ۊQG `_;:#MaT޻tœșf0/aG̋Ru;xP1s*xJr +hvjwkL(hj?yvg.m +[C=q"pǨ @o㭰hԞA9$d12U?VH6Yd{&3"qwX`σ~,3Iq}R1mo< ;w*nhz_uWu1WAqpդd_Kuu&VoJ w (#ۡwte&B0Kz{*8"RV27Imae*}J W~>ݔ̠9qտJy̭7'qWͷپKwnvGU?qxS} s-)oc7`—fR_ʤnu!BQ> +s b_r\Tx`jxpx^G=@zYF~Yu˭r€5 +wo@ E~$8|,L~U'pU|l*CwgJ#sT{xPY)>fDp1yc(Z[3 x2](KmYc{HEE>s{nUlj|Sn{p_,{,/&k2B _XL@-%cqo m fTA h4_7!(_Lbmv S}n,0e|;^.P1wѫߤY,ٰ75wݢNz>Fxy1ϗvvΈYC5(Upe.a+Fe)xt$IW"s s:˸CP[*;g.O3)AP"49pFќx fJ;6b sԔ{}}r. .t}Uv +ICHJtЉ(upx#` Gh9Wp=ĠVf0:Y&.Q7,{$*pAd+!_aD%UQ#Q!0}dz<&<7qy o<-ulHÍo(gШJ}/fI ʫ߃A×N!qʺK@:q j{}"Qc˴V߀#-<5J2ks]&am~fF[NЕ@p[-X%m2P$R%b(*$# ~Wg0BSd#=C\/ya[:gw}yrc*[^UFJMoQH] swAҐʖJeKZ*[;lCf&4#zDx&p'aO䛀Տ1 R72Df"Jv}7`(F()AR -e (DG Т@&jgأS A;^閇 `? OF.Q˝E Tw*%Hdb}D˯}x).+?'wȒ1A-MfIPiWR#MI7]DڎӬ))DҝesH +GrʻFI {c}i"ȑ>4Hi ܛ&m!HD6$^^)5xsj^~\ptiƊnÏ G,}P'b3胋_񭧕7?2vKJ[7pW%=BIuV@wV:[gW}6Xp?W2ym=ӝ5kwvq۽է>.?L"U_7"*(U|g޹j/7v=,~0g}-|RœR&}M,߫t^e*^:cMMDZhڦXc Yc"ڿ5l~EY5.?}pέm.٭ă>m_kGmS G +$3SM[ P@űvc&Ž]_}1XU 8{E2BiJX8@3#"Ee#4Z?&Rb薩YgT#jNvmpg@PGzU1o7t1e7&G;sFC5'9ڹ܅ mpCa=hN7O;nyҺQX͓Mևv [mBnl*͹gktOP'OPMC皳C)LO15  3w.ݫ\5v"6EkYɢXYXY@xFĖb"Ve6mƏIAwˀ=4>_x@ pc ,I 68?S*Ͻ3&x$qQR\: ~h6)&}bN?Qq< +@-LݚӚ9Se6&*ǩj9Ye#mv?iQӇ1$X Ӱ=`0.0Ƒ& #ӶiwTShSy$[!hoz{s)\{@a6+D3]n+`RZJڹ?ao]&NN @=E ٷh݇KQA>+`}opwsI[$>#\zk,&7mo!qRq|'Se9 <"07UkۥJm3xJk>a^Q0#Xo#΢WL,# 0c\d{{0,ޒON+xUjA?ڀg_uМ V ErwÕphܪb-mLU GMN"L^6NjJlg5“pn X#7|k%^U['Jxi Cw͜f/kv~uwڮkv;u}T5G"bo-C5~]61aovwLꘆKFm+A`( .F@˵H] ΀˴"0,$f;~5Ii MCw,F g>9 jD(^L +0mK FĦLLn$3Y7d~zV-pO7&c4;?cMq".W&@,i4*F +;ȏgZQ'KWv( pm4|(Ę Dg9_5[ȭ`XSm;?yZb,]I6A)Ai(0g ÉPƒ95*K&X!LKF RQ3E[ +oxK9 +]}! 6@ہ2]:u"kjUB~XWbyS΃k5g:}'x\`^\?wp 4 edP914`˃vnܩ\]B$?X`.]wmN<0&W)9Vf/w(J[*mDfW- ct`0' *l_X*ӦpF)0Z\R_"'Ub}7NL Z/qE+@wgh5Gk~ dϥ4mq mtemҏp8Mǝ_mcg{6U~oƾnBg1Wq5O4N+_IR(qn1~q5^-taF,;sUdsbǬcCQ'XM9X٣8God +Ԏ!B1\߆U&2k9E(GQ< C`3ƞv8tV+O +P[$J_C ʤPKoA -覊OYC&vg7A$č̉7I7Gq"%1j ʁ=VߧIvjw'1;O/%z:Pqi(d;ԅ+4H!M:~s +(>/nB2a;gbғ^.C5z`J!UyA: jUo8PΥmdZa\І<*=xts_ 3|r +US8y%PUr9Ec};וp)Ѹ )I_n Ts=vSвHaJs P<( TFu ,a.900k +OC_ʯ-,=3R>s0:xvt[WVZ|0(<ƚg)ͻimr,"M7+[%T Jfۥh ^t쿂prjϹ~u drnl( wm$򔸱y+ږ>)(Cw1Wհ[GӾP@@.~*|Aq}7Mͧ}s~^9~9D3c-XKo!v%76IKo!6ӡ%CKo![;Ov{.@F|׳OfEg2_ClDi8!xmDbSyDbSDCjHKo!JpKw|&sC޵~:8 +(ɸZ):UŒnb~ɱ1%?1y +Ki2jɷ1E86~lmVf%ՏvЙ%Cfhw: `z$kT7pMmuܲ:e| NJ pYieDj#CQ @b0iE&+QbJԩI%E<̓qF7F?D߂i4`ջ46ʽFaТ^Q7i?\4;ou'&IiUq4.ڟS}MšeL<4ߦ_Ҧ\`/5K* XWLTϝJT~ʷǦr^CX| e.PYp]`XwqnSz>]~'X+0|_bus$4P_}kD^\ K#{&xP{-Z.faܻ7I+6h>׍z3O.?JU(,γ8kWU&t$ +Ĕ+){"Xu7-yY~.5bc(w?O\ V8Ds-i+SE\I +ZGl}քBWJtd,PMgsȗ20S5mw=mғ:NHٯj֛r1;ּr\;ou+~ثt.U{Xn@>O8׊A&J˥U+zS#VYv[uw~I}MFtqըZyo&՚/9GGkRSB()IS??ŗ[{4l8\ս%Onv9bBjt[U]otI9l \B+!dVi"" _3Ǘdor'5+c|{_=\)F |etuxle;i0Nѿ:r"AD}ahn ^ٿ\~}}-W;70*2r2=7+-[MbOXYqm{jq.e|=Щ/ޥe~Zm -m຺`й\a+YGW $+M(^ԳsJHgsw)"FgB66|cŏlƍR"dy1iwu((S`A_(ZPޡzȃR޷` M }Yi1xOLF׮ȋ*a#kԈn证Mu~ӂNʿϟSOON ?ڕ*]f(8s"rW FPd)z.r.ga/l }aMڬ7 LQz H^?xq-~x +~kvaFc vAewrV~Rղe\f2rAeK[A9׷8m<fI *kF>~t?%RjCInZLGzp̨{MnR[IxTfAe>:mvJC]i(- Vs(@!dF-?9O@W]Ռ3;׷XK_!2i|,Xv39i{]nڞ2iq쿫W_aQ:xNRBbJJ{-`Ko݌Uclʭ'Lf&,#K-j6Eth,.C)3<;v1x|푝f62(0՟Qg; +B&mVypsߐ/zO2 s`1چ1Vh{#5{UŹM^pEPil\6 0M3 t9ub~fS=#|~{djЂ[4fu~0א"f ;*7 dU#}c5N{]}@-1jv2{TUFNS8̾4="on=#Qck w54`5CU=&F,m߈܄b8ļ׊MbF `(+COYk#bsPwZP}U7*șP~<ˣ*аzJ-xt|>kNynΠZl8g<<;/6`N% +s/81y$)tU I,+,@FBԇq@O}Å4Әg@ fނ@2Cw$!a5(]"hH*vA..$`S +qD=jFuű8.2 b|$ _(z5`1@$!3הag0TM̞^+Z;ߓ<b*>P07@E̬Sm}1a +*puL/D7 HW6j1 [6g.l3f ,Eb'l@5#JRL˅|kU OD7MӾ*GA9*?,th;q-a[/{#n1Ұ8 .I:+hBR2' _i.A>3-i7ޤV:%`X41b"O'iOU`$ݫ0ϫُ +"Ty$%k.1s<p_`E1YPaPHNS 퀨DN4bX$@BW}\t;@A%gIntu* KP2N?2zCu#CNZds 'w*璅>^wA'vY?cfo%aًψrZax^i9U킒zs >0n^x`rR;4xve捥^"; &!,͘-5UXT/<@%cFyW-qncixvu# 捿kL'k2kLX=1M|GJMa7W9iJR9iSA3ٞwp,͈9IeKkHRD/Ѱ0$J\flx,'@)~"CeU|N}S|-dzAd3N]:CŽeYoӣ\/M}m7(gfÈ'\aCod󒹚~Ȁ/>,E,M/ AU5a5CY&K3xn5pz|%G0rfF˃r0'j U@0 [ABg,z!pl|n&AA$&pU Ef!HMDpZ锰W[Gnƒl(`{\ DQ)+nӃjHBlϴ]Ë{ߤ +,o/ +:Pw)`/,;3xt-oNiCX(#fK 'g?M =Yxq +1/0s%>D-#.@H'g6.QWI=FQ)t7a+o0VKlm2 s!HCh0'^MJޣ{B "4"  +Y+>.ة)8 +vS|nV A~au'vn`.@^} Bkn97Me. &RA"؎{Z7 cb,- ,X9dp:þh?R(w@#sod+п +4 Jxx5QPe>xw0  ]c`.ËDN%(p=,ʅZ;>/`Üs GyM{*TfaxWvKSJvEqݴ\=,枹И!@wb8؉!#"i';Ogԧ'TfiJ719umfx(YN ʤp.1:u7u^_?4)wdg94!MgCi6圔 + >[1+JnwX~'ÐWM9dQdzɜܣg;u*?սsd_? oi4k!"YTĕUup{ =y5 33w~p%j">ͤOZ砚.R(SX#!R__,˰?S3OԶD887O(†  5 P*~7p`!&'XP# H~LNo/Ū۠`6Zn0k#K7` ?!<#ϖ(ش~Y˝@uH\>uiQ^˼Rb[]xp0Ȳ J}xHP6\:J?3׮֔YG> *>#8TY5-vC{Ez6|\S-IԸD%&\aaY @Z\EPA [OΫW-S yyL)%=ڥJ^Grk`[h}!HȺw(I w*;5\dfI-M\5"(TŌ r),6|:0ۥexz8r?IYnd([ +yn,f^4(d$Z#\|%aYA]O,IE@g5Ɩ|t_%68 ա5$"LXG1 uw]Pс[MYeԢ,%V[G ㍹}[Un÷ +¸eK6M\1O㚜,)ɊY[l7Php Ȩ6 9asd,zX{~GNL]tE?ji yMQIF@-X(_v=a-ofW,4atBu{چB> +#hUjEX/"Q:@:&&Ux0<9PaiECQ*cٯ>u(Wn^#6z^:y'I!Xa=7g? o*1{{o}{U7,4B;{d%]C7>-\4h1Q,kvn]b1/rrJ$t4Jy~D`.{'IqS]&ˢ xL?, L@TޞVMG6) :߽ Q'kR:.fpRI -hv7a? cr+DS +@n">g4" Qэ +>+7eaOv/oы,<)-nOΜ"PC > Pf>X44Y. /r{^f4Nq6l`{k E\_lک[K69ҳs7 7INX>JcDٻt.zقS~,C9Rf1' ',r$4 <ꉟF}agY JC$Pp9՟uN,iBoPPɿgڍoXɟ_x#،#Fq +z"[$w6!ӼLyW[cZSMG٫WI|Kh8;9Bi8 ի,a+j/2ʯZ!X<űɡc'vԊXyD\Y`$~mdžIG͋[׃ <#pKҶH/%B֋M>!oءxGӇ7ADsux};@ڦkoB,[J0O[;5|^PX*L&Ў:>Qk\,{=LVe+#eGyt?zp16aB.MȖ78`3f1M uH؆!7s}ȱe;D7j_-lSʃ +ǫ!=󉁔?lWޗRxm>` 9=1b+ؽ~R=p~]k{cl㾋8&3oc|taX =MaػԚ eF +3UQ q+`4>M& LDQ'˂L%$4}c1MV|468 b)*3d{ik]euVr$G?PVhH,T>Χaׁj-vy'y~c M'O&+Y"/z!^ZWb1:nx&S4%͐^٣gJDY76{\(~6vԚip^)ˆcb[oJMnGQoq^}9Oc;``W*m $S_8zTV(Rm,xNW=ډ<+P"Oc6q@c&ç1CYh/CI<;=C:bEԳOшg&r΋4΅1$L8v[و,fR8Nj$C[sLyaK4$oHT}j@˾C|OPQ tP𹵉ב|=Z[$KKngkB=L`[ohy%ujEZzWz̑P&TN_lqv,"nO}%Py7#mH|ߪ7tu=d@)8ek^=CqOsDM+،upZ(+yς7mA\!^y1fyhQihM&pzђA/`c}kOZ g)6=3~lyC2";~U*U\v?;ZW+24jd1 c;_J~VZ?f? {"sOE- JKFwBnK\]T;B>WdgUyبU^-&Aszk +bGY}ݔ@C8`y )حhs&U$qx`O{ &XBj"ۮRlfH SJ!ϻ+[%.6Bڸb1(K3({٪vYiml|@7_~)h߫Cf:VN*KϽ:h]F2iݚEm +,%l8.yŹb`=P9e*.3)Tj>{ŚXYTfHLm&H*b͜viR}GcKv;Zh%h US܃ IB>bVAbs'ixjEˡ4K{m86Y VqyΨ$/W1z +*QBf +z> 2qZ ۚ14ƃL:̉R,gN_#3+ G/k#bX0 QarwbZ Y))($ 25Y.Ȳ4A|o}NiYnڝ@5{6bv :eA*~=sTMHPf Be(T OMw)yjsvC.|;vkmȿ;>ߌQQ/'kB3CsQ}`5D\Aʑitd7-Oy{n)p +l+'Alū oftpfC&SӗVCR&?sE.XztޏO`>$c G66ZٞzKcod\ptSa7W_i~!65n%v]yj[;2h g%{Qy4}&1([L&P,>? *k΃4kYzy O:&#O"DE"OI˂w;yw9ehǶtRjL[>-X=[O0{ 5_njS聯ۗpV/YSX#nL(b(B!*()X l +9N:0CIG@6#*7uG)LsjNbtsBag@y$ɼ}]yh[]#{G pm PsB lә*4θI7bvi j4J.+7,bhI\/Y&jWu>9 +(_(;/9g1Pը(\=:;P %vȜIi+U@f(qWk.qpW4pdQiY7i;;_t-"mO;P6 M5Ā9'`g~+Bjcp~8H`#W1]p%1&ho9r Y`<!jꊙcLZF in@l (Np6lxx)92G "XܯDH"Z} v g11kk4WV|ᩐxj0ZW%Bք![{?Eo`2љg]OotY c7ãi.}Ng/iӖWJsۣjќ7ǝ3S~15 :Q-=)(~s;=Ziҥ<:#JXlZCjuhk#]KX#"#em E m{7g4"Qpy~}8shȁmgw&4g&8e 7mҨb߄X`ch8k|l1tPKW =`/#>IǷOb)X+z(L XTXKmr-iiNM e*|m4aY$;C@{-ajQoM[Α81*"^&DOhoƉuZ} ¢G~%f= ]3(xB;q +;!p1_|Ok͗<5TI0eBl 7ϖ{fF7_g $Aۂ;/̮WW[r|B*9p']ա>ŌdnMVq^r9D4}5H]9$%#%(IBG,A N +zuTr'(x _~"C,mnߝ0I?skN!oLIsCFXwqYΛq-N}k<*c8Gڻ*=7Qu ZFH gRf#Kp/o02TPџ,,񙀎qtho mPSfq]bPj\rۥmbȘi[`qQˑ=ՠ&Y;m(lJ.H3]SSߋE,:gL2NpՊ\ղ7cfŌ,U2^XS1pW.kzbM^ǩd]΅/"9{js4});;wX"'7@#_91vb*2>:uosg Τt'H+>730Nw,Z=;,Qل=}aO2ljv7쮞~[_c^~-a +p/?z9 +YvUscy`6&pTl.SLx؊+#_^7(^{IO9%W.zoT o+:gTӦ!^wNG}tSC7bDJƱU OnryHnꗫuymenFrxR/7L'8߄=9~ewma}{732񇣾f.5fj]Aؖj޾/Ͼv6Sٲ9v_A:/|W_]l>gs~q[ {Zs@1uH@ /*Na/| 3 Zӽzw-kz#<'gO\c1O^W2N]p'JxmPqeJ5:NH]EÇjA31)U'C]YEk|gVOzt>ͮ!s8͖r V]tə&xo*S~1(t˦ٽ*i橵oMz.?.7ХyŲϘyB&`ۚ|A[yn[=yh,3yܘEgSQLy<ʾ9F/>ƾ}V?2Wܜ6 MG:t7Lsߛ"OߦzXXS Zeu.];g͌%lRm Y9*O|Vb[Bɼ)1xS̈l]Coà{ݚVkC-8j(Ɏ:>2=5sOpfk#ak5{$]xTWlgG# tŧS5:/ 84 ~$l+% ;;Cl8 K|qtq(p_g#>ZVG1GÀ]ISavgҍB8IR&xMҝ>r; Gar9eC#}={PYt^ +c^,s3Fg}t*/R),ZNaWkXA5P?rrFɯ=#Ojkͥjy%,98d2y0_bMci۵r0w,`Kf.5;55Pл=XJyȖD OS!_y7r)]l?'`\SJSd]9asu`f8'K=:s!ǫaϿC(kaY~b(_@' z^>"оSn*\g?,b.B&⍭R].V!Im/ +T!Qw]~yw*TWfyDl SL/OMۇ-㖬KAt^~ + 1 Dn_\oc›Ǜ"v~^ipӥ{:NW5|y˽Ö*2e߼!N@߬fye X_1`B /cM^F)lNts3캳%25WBoBxF|b꼭^80ZT|?ig#d$žs.hWÙHSXǕѐ΍?|pR2_4P)wSNz,7^eä֭|U2Vlw_ƛPQ|l SsgK!O`Xz!`Q6 +ˌ֙vTtVQ# +_cE@wv${tj68uӢqJx=@G8aiCvko-Ƕk+(K{ZO݋Wz(&lK~jjjBQ?=UOi=CǷrGp?X|FE!^^S궥x+N#Gk,PoQǸۢksϐP /p:M?&Ph b~ !;uرI`9aN|#ۢ}-  ?a^j `_m)HlgAN49)2'u„Ju UqWh<ⅉ/P!3m'5)/(6~ AGVl٥2'Zg^HZ9o)T켘X)iZ\&5rai{9mOAIF}Ư(etOLxeơ^>%8lob+jߚR7 +>!|24@Ys/t :Nh0̒bf)DڰiMLC&1+ z<:#ǜae7Hux7_]JB8nZU+sK6D+8Is!:8i|F(9XVAWMc$(\TH!NfC,ٜe 烰=FqA- OI$ثKzH!("J<E0{]hʇL^yhV X~ >:OJUٛ3* IS +1b@4m)Kz.8#wEHm +{|Jw[҇Ã`~Hd!H|̗.E)';<`"BqQ ONCUu{,ۡ$DpaLp(u]+ݍkU >Tů7ri޵x\N?CKTR1Z)gRb3$eNǢR~]r۝g$l}+俑 -c ۩,haG)>u%rՠaJ9{:k 1P!E +:0$ا^"]E'B3RA'"uxj B/JRM<;kժzS:4(*Nr5oD pcNuP~淚`~?Ɵ:= bbR]3‚]c >.XLX(u,0W#XY Q)dipu!萅my1 zvj"S17T 2są7iCB ->b?Xn&=~CVyu?#2T]S`A\Q[(bx@BYc:}6P,}@>gƧK=Am? +/8KQE)3j&Ai|OiQ f3m}T*YƆ3m+R?D%GKd~clG%UToP >4*qlTiu1SqQTK\lxVrq:CVZ9/  h)i;`>.hlư)݋tcNx"kغX')t mY@*:!.,T+tPԣ] $tŽ.qr2(j /b.AϩޒAM-)DV:-ha5G Ö_J.nNH~Q ׀ߑ!#{dw a?jL/ƴù,{^5y,4l^}1*G/EpT!}lǪ5%CL?~r Й),FDoRays9٩ݰhR*K^&gk5ꅗ^ˁ0Bs~,:p2;Z 쐋 *>eG&:J iuPej6.j1w E3R2ʰ|![KtQyYE%Q(I}8{_;]Q?u1-V3}3 zoa=;RUHA_OO3ꄩvGe35U+8* +/^l+|kCpgg\)/E",ȽKliQsg{4/#J *XM SvqA$#/&nG>ZRŕ.GRk߾iތE*-jB g}ܫJrI.J~FNZG?W%8m޹Yjù.uWv[&8(נu39[+.˱+`\)_Ǿ m۾~㇂G0 Y!6CK̖YVW|*;V+MM8~d!dƹQwﺄ-?4a3RP 7WoJrꚰݻ!]{Kgs/XqGY|"jDW[6δYZPL0q8 ;$6ׁcu]oUCr벬l 7q!*W{t-DiwPmT'UB3MtGz46WcwY$$z()#_plD$h̕$ɕ7d2!dI|mPc%rr_,@?t B!Y> @Y>)'=y :ԝdKwzwLD!Y$z~ p-OŲcՕ\vA-^f!=~öpy^NQuչSf}%`fy[=W]vI-Q:$w&WU#柖+;Ϳ/ IfWR) %%[F%(6sݦ$ZB94쐭&VGKA*$,\o5O}\*ݎr;H]1;+"3#]A;F#ҝ~Yݞͺ@<"_7y?z] XO?nȈ+p30JoG @yfdyyͬ &b(WtRzʠۗUTU';oSť""nz+Hc X&*%~b~~>˝痋_z0FN21ajc=tջ( |Ghm8v_c{‰I;DZ}09M˜XUbQ*[!e >*!XG9tzc2B7=48l'+,OBzח cвN7[q' cG4ˠ~OBzJ.IiI]6IӚ €󎜍l h(kt׭@J!^hM8vPe6!zGD3M`?8VӛI-r +Z^^&lL[ #&N-Rbb#1o1Q epjlck( 6;}놃 02DVALt|kv,YPAs9jGim{M^ REIjcuxZ iy9zyՙU4 +KK'LKRƾ.%$. 3Uuqeofls,TgEag)#ݢ-g4꧋ѱcb賄J4-M 45 -8LgoA΃"+E5/Eq h5`.,h6&mPv13 [W Ȱ$o=yBl r׋>KICے6*>D 5pz7B?인EkVFf8%UlZ&"կw"3""Hrs CE @x8;ʁG]7E)D^Aъ^#+PpHr")XBuWS`bv C!3;v4C8̍g*-H /jkc0i҂2xZ$1&3wWc^_596Xv ,QDmKt%:-/_cy;"(`+?|H7j[0`tXS]+ȭ +]{Iץ]w]{V`~99XD]uj+wIpg/jx#?lXp׷ ?Oe)tGdZv9*[FIN,O7Ƙj:E¶eTi9s #e~nz5f˕D}i/vX+pzHv#iYːsZKY6?}/18e1qŰޞXYA1_!D ])D?5 x ( ϥȳC(ȣCs8D1Sぴ3u;lM.3[Z0<@Q.*PA):l] #,1JPHz\.]yQk7Ib1*QU;p +^F=|{=-uq7<^I4 @i{*:bSA(egi5ָ*˕3M&ü3(5ў E4"5Z8V[CfSiqo`:͞C jMh{\4U2~sO \^YEJЌK8X9:QȀٽ{}|#5#+8Zj`Dy%Y@ۦB(wX<9 +GClYeN] (.Pizԭrs36֙MÍ|o42sD6m4f<ȥE3Jn ыHǕ 9Q'f{3ھ]3o6O'ǞMO>Y'̕F=y欕hOcbXR:74jk$;w2wS5KN#C-v7uv8srig˖l/^^b15ȓE-] 9i疝KJIK5: a,Sp:o9u,RM7:l`26znkO\UQ9c7gyylkh*-橜->ل? D25}iُ _J.Q^2a_.fUR.i\NzȱI^rWQ=m`E&^)sk +YEF 8C3wKXJKX mZ#W%9k8dO)\~ͮPtY'iQ^b*]Gnԝ3$}sX# Xj/آ^~ Ŕ-[}MvxZ39T=>ch_W7c编|jgg {XM6 _OZCz,96Xoy"ɮq5ybsl~1FiA͎Tr/NjNyܲ#|396OVލh=*O@.Y*%:)>] "nPb+?d<^|&}x)獁!T~09|۳8d˘wϼ +-wVzo)v*ۍ;*4%{V'dF_ssqVu΄s*7;v}&_,J9ˑYFͱl~NTCqwZgk]ؽ۸Y?HS{n$+;ʟ_\m6Ş+Y<~~&l|-? VoE61R#; Mqh.5>{!k˳, + 6^#yW.Ֆ_[/cqbOyiv?-Em,_=_߭2n:Uc/P~M9O>4^#G4xh=y{6%]^>;}C_]~5)%Ϣmvb W5q9cqvn#ےT*ƫXw/ߔfx*[$25-LN&rcH +ɓ8")6بt_v5%ْ>1$br<3zG7}H̢cY>o/B5~zdB"Q9 \My%{;wu=[ ֦9q}5bSјMyԉ l9YY0x۞rp-7@<3LO5u7O̡ѵީ*YR:<.1U$$ϓ;H{2l9,k1.\ [*HN<7MT}v\wjKܥn$t3n&.,CU=Ό?s==UNm"/~zbF6ODm;+joOe%\BMh civk-$:Gi89wwey}>Eg^-y {^~ fb +wT-=0߽M_; +~/Ȥ?9k!^^/峓}|5ޏr; +\ϰr>o U=W>dfxs&n:9p6OOKx|*\7Z\3ښOjҍe|^`ELJ)z]cn}wX祇>94 yH +naWh0#53'L0"pPr5-n{Ʒ o*lu~9}@8h̳ g=C\οXV|z)~i4M׵7K5~-r¶OYDxȿW݉+9,4BWxם԰8DBgyyI2`͵30 ?q=FI{MRSr|$\ĀųX秡 Э^8kT%^>ㄏH]}%ڷϫD:wvluns]fuWXO^BNn9)lTSIs"c}klmv83fS*:yJy +P= +_;9glezOJRDPz~8Z\2UtzoNy5~~;0Usϲ\ /w7Mf!>Q6X|!ֺIeGױ9xX'8]9 qB9\ A 'jt +I +D1T]qz}$W#W(]D{1vI]-b7zL0qe.V M<tZDjqJը X3oYY/ztWĬTZ^oBvmq=U`ApӍ$VI?n _gASI1 DW3}+b I(m4 %qa+M4X r&TX*ۺ\'}r s9]A_?}u94zXuo,6kwߏ`kC&OS_yA3g9E/O銋>ɷ*" aYrd,B n$n"[-2pg.fD63ajZ?բiTEVUjMKuyX"|tZK ߴ7J]iM?P9}y=<=1_]N]76y_9f'#,WCr:r u֫Lmޯ]ع_"bybO\_Z)=6ֹMKxp Q*“#vv%U{kfdNJ!_"P7DDwmCG,cx_?4l>Itp@\i|=^ݤLvk{E֬#l3߸ܖϑp]{pSDҩ{ l_ޚDPCϭ˖tR6P@Vkl@8KơC,dA$a%Ač"vY8{4R1<3SDp藦|h+_;>gMrǟ'q<0lݤ⑌_YxS6zk݋3e}$[K&ܬU[3i㹺~H3e։KǾG38k? ѬQ7٦opqo>f69 sPDqջulɱk$603UasWs %9C=7cՏy>XnivBW^+M%7W}u'Ǟ8 5ZڷIa8ZwHxޞ/Boa'"h5k쭃!ř1 8Zg^Iq ^4UWYlY0Z K,rq,f_2Ǯ(H4HHQ>0lZC6{1 BT;+e8֤; G5܉KL'7 &#Q~O&&,Ϯ g#ܕk޴%*0C|q59* +7Ja(AG/ʹI=;4ٴ@b_OMb!{prj#Dk^ k*xrэk&~xr&!cg'k&$݋Pʤ.>09m~h 2Z8x5xnS˂?Ms &YQDZ/Ǭv%ןtG;t}A9AȖN V<)%)BݘgkZR9[4dI0\t#K g F^_dw崔UQ;CEU*Ƌ]5y|t^(8nC%\߭wAxaHg$Л+ZT.!oDwkF~b) tn0pbI +ަ]#;wQ ;'sl{( CvU.bb/id U'wP&mk༐w#v +G ѿE]2-eN^|;vY(A$ɻJϣϽvQu??xU-pEhhqQ OHx)ٹq L)8qmHpxH~r~zˮگLoŅ)rBH);?۲>Sڽ1"#Bn(m9,Ii.%8|bxuaO~iu#x0m 5TG!y7!A=od/D 28J"Zop)E={GXOH{qqw9}~+[jWO6ڵO?vK|+Aj&Kv J7V,\ލ&Z[=+W #:WInSSO|mZYET8b=3Znྍ bw{>*x:f- O2̋N -g\Amd$M6\u \!e Uaww)\z35/UX._pQ/B 9PF[]z~!m$$\k) #k+yu|>$}Er(Ʀ??U2!~ + z,S,ĺFAi5VFojNG尲l{}F _QJ[?#16rbaR41X|MmY1-d.+=ZmhևqlRu)=0g +fFfxެDiH[oˌHp\'PᅫecPS -80Edo:-iM#~=\,@ +{g,֕u,IzzՆc;ue{|Z4g12&.1"'iY7"I&FխhZ Uϝx)| Cb\NI=W:C:(SptsmeAd :W^17*2^7W5`uܜ_HĐSjWd:BFShvDuI; A xTkŅgCս#[[#ڷ XN'] }hoq5Jئp|Xھ%O4-TI4 ++5<nBo(np*m GS`shYk/O\駸m@ZcF~FB`$%\qcK޼& *|VLnϋnp/Mjr/Sq\kVf[ >h*ٽW'e]ȧ=AlYpLu:Ah tHZ6lvmbj8LMF36IF4wpOɩyVJg+O" ͷĹsη] v1`լ! F+qP rՄM3.`b .J̌PLz9(Q>1YBi_q-j7$vR&+L:LtB4^Te[d>,PT񗴽i(=QABYa {\c]'A/.aԼo؎XgJq[-~44,|sjaf dyI=1IgQ_I`*qB")&C + WKt]=}MLG.@!|AQhEGH)ӸD7؈ MVуE_ؙɐdÃOa^x2Ͱ}j X}]-@,C[44&/fy /2z&JVihIk&Քwr/nK4oBtɌynd2J.VqޘmIfh2\#,p`*3Ũ&b9ޣJ!nM˱̙ #((7i$G1ӚMh#'xqu*,] a#R >K)Rw\*hcUgU(|optl\taxqQ1Y،k9Gu+4aK+}@+7Y) 0É˲k!\X +~*x(W7Ia, A]b%MDv=r6Cw+l9A٤ ++Ad@⛵z,KOIm ?'3DZym5\"%9C\/={# +ߨ8US2:!'A/ + 9f%6*_kC@h& 2R + w +L' />*SsWy_&yOĊST@^*իfWNlr2pr + (0"s{ij Fe4 s{maR6P$Jf5˾qu@Ս}ѝ(/rm'HHzvɃP$ fakXH^|ox[RE^l|9UNmNN lSbҠ +GÄ 84ᷰ-\ +asspWir]tyjJwy9zɑeQbGxAeB `僸㼋j:љRVeM#&wtzwb*H^5ֱ9~l rc Kd~;uu;vYW7lTc"@R !#R($5`#4򽃥.f'#sGo;X7%}ۮ|B1Έz˫',9XaY53)D?/Qo6NwIlG/āacЇ-e>xVak`K*z#Rp~C (jiVW]OI=D.dPR!r9-E1qF +߆xS~nQ[z6wH WGU!=tc)$"v\aM%P7 +SAR]ZU^h 'i&$]#|D6ZnrkIs b"YQ~~~%R?~T̂BKSSN< '8Bf4A*j}ZV@<6J []`Gjr9AԨ̐})$)e5RRJPAa?Au}2SEqۈ뫽|6Yanp3D8# +21@^e<-\%@G.` F`S,j~(Ag .)ICoσ- +%BiRz(hGEU;Y0@r +,xEˠ(BTKXDY-L"PTke2T#(J.L.WpRO5p&-RٕɃ<Yl +-D ,+n*7El0Io0&OiK ))טa7ds`5NS4JMT$.nU44soO"k7k{Qrz-R1z_̌pmƧ@`5bxtivloW`xݜP ) +iheo) !nm^Q׳U|Ʊ_w>[N.]^`\(ڷ4,MQbq[1NӨQЗ +o)KjB X}AeL3U"{[թL%LO< r2\f4 ;DjH΢ҴQhtDbB!o{ٵC00ޔCA{[vh~LaX,Y*qW'ԾgOoc PA~= Fi;)gxAE"<)7OXĦ{hĞL]᫖p^%O&SK7D? %74{r2RC }ыs^3E2N[I*yؙփ5[(i~q*yJeFNLݮN9d;=㡌ܺx,Y +\F_~8+-iѰ0[eJ\H/=+>>P$0e#=#q-L' LLi5X^_3Qqxa\/7%jC$E$Kg 2}PLUMe}e/=BV@9 6؈% &# N;T%k142Ӫ@,ûM6%.tm~+&6Y $Չo NX"!n]_@Q2MJ@s RJU*K cbm ImYE,NNWO=ķnl-ד Zɋ4wQ_drEBzY^H&z|_&Rʥxmxٷ=A< q Й-/8嶦9I1Xz/jkTvl FR{y04EP`#p"LboB(\N fl~ݠ*K>A#~WPdUMòݑ/K 9$*ȪHx=Ptfi(ybe4ԏ(.HY.0 +48l\% *nmmS#ؠhmcLr2B!%V)Vz"9U7&E .N-.-mIf̩^`-RԹX;0IpڤK.j؎3&rV}OplS +Dd&19~:5}a+![Cj9$_}PK6%Dʪ_K{ߏ)å1j C3sTf<4 a "4xū% bi֒%2qlNP裤/R# (! ̑)5,>6CcWd /;'0lj9HZ#$m>|Ԍ#p#jQ3rb?)ޕ xFȌWKx-QEEW-۶< (1)d&j3=>iV%/qd&-l6,TY|41,JHEB848wbA_ތ3z[rIE^ҙ5R"(V)*RFDV(أ;+F J0*s~f$> b^|/!gă"+Jl/e6fvޢN(` RaVطaAl~ςsfMf}Y?utv)=giƙcsjKQLT_v9u˓džڈv>Vӛi=Jd\N1I~ uMC:;bUο eCtRYVP_0[PP~|wR<#Jj-s#[Ye/UHɺ0ebCH uC!彜Q\XhÈMAeŒݎhI4K|,U.%o@ۧ_uwߵQ+2`M\l4`]|UX/%;ƍiOManZ_k'H*8/H bUQ!_xNI:ItaZ;FZR%Oep"T8S3 P4C(F]D6m#}Hrܕ\L(W'L% %VG3D_r QVJq]4LTjBÉ`o!v[MI}jԔ&0Ltԇn=Oh1`+Z۴V;9UIAg_o/3#4w8G*rڂ:1<Ě +H($b9 +bp&I`GCG%q x1R {}X{V/ ,nkt%5A:hK*j"5V*o<%f!3] %,2dU:"ͿB6{!W 힒#dZmd<`Nc Flg0rn Jtu@ #VSM&F 0%}1wTRI!}J DqP//X${cOLrWgrs ²ǂ4W~UI[,!0Kl|]bJ-vvH-*|fkuȵHRy<=);9߳?-#Jj~Lض~g/h<]'+Q6gA4"(dX'K{B% X6H +g4Nhh^Qd`'ϙe >\j+_n\Y-v +y!a{[_ Dٯ !po +fRAQ~ddEM$KeʫP0G +sJreTĦL pCNQIـ}8d#RFDY+# 1Fu,"P\Zѷ3I'(: p> حw"6Co;3"QEy^Y8K-.phS's+kDpZ 4g0up,Pkae+˄ ކˠq]jOׅdFK3u]Ӫdl<"wgU ]l KU/V+"߈sUcT%YBXB))f_j j0BrC/6(ְ-BmBꑨE:C,LQ44vz2^2!ע[I<zᴻJ/b[#ɋ)kCJ TEC#;b$+R``= R'UCcfICkND/Ua<rk9Oic%y'Efy+6˶}ī,li$JN + HBAguIcIf,9+>|8U8M#u*yj1 Vx@Ae+~&ґ 9ŌC,j̓}`CK_D}(`b]rU[x9N;^||{1\ +N`"xK`ǧݿ7ڥpu&y= oD@ڳaO_q~ORqJ)fMˁ؁x *jF̖W|e0?咔l'TzbYiWnjXr_c-*h}L_#H%l古b9d113jEU3Z66E;wшv rBkKD[C)u /VƅT ҮSOj?g3'@0c*d1h<1[A*iY-阗3P3Pײ!䱀 ϰ%/UJN3 +q0U.+ګF̈́d}ͷRFAdEM6M̦ BS 0#x{^eY7l +Ove7Ȉn o`R.,@L/vP | 0ˡ_0cb`MuKjk.J%_AET)FÇ t؜E )k H! F4hS݁2D[@쬉؃nXdU7X .y:9sΕ|IےޜAyG"srk^Lx(6zì2HXu:9h,UTc)OaY81{xl`Rfj\-wW w%;9!#.:OVªRQS +6 ɴ|.+=qMp"5c'f5RV)LL~Yl|-l5I$GAJ ]вUa]%Ps*(\ϔEpR7SC J? +0OϿOBBLfњXE WE6IJD}P 8~7+<|[ .1sn d*|I2&dC9,!Z5,oJrnllv!(aOw/2YP{"< CVF/SC\ЧF5EH柤J7o?"~[߾,/m6g1IbLN4jWyː:qү.Dy\5O.Otb䇠!jkcb̸P+E`ʶ--Ms)GNzm3 4ͪlgA 1$t`D=uf׊5".-㖷L]"UlC_]r*/R\TvtચGG%@t:,MU"R{A6noGǶJ{5K9$%2fp"C5.ib.2 =JaUfé~of/xOpNbi=n5'{d4|}1eL\` lcx "l ,;S-OLa96H=U+b#(RM4~ +[7TQ8>p?r8rQ; GIdU~ b$P[ՐKKl23)JDj^FEq`MAfKfx + Mޤ`.L)%Y$h ,xfUbw*8 qm -j,sL{EoR{X~-oRHͨS'A +T6@ozϔ!CF}I1tYrAhaޖB8d%t'5-L=,]IHNmrIb.mPe]}ja +3*`:/H=6QGD~@$^'ezxq +lMCsy/*xT [pȮ۸f|ja=?(`{r'T(=nڻ1lqpD{Iw1QюO6O) wjALZ3$x|Dj^"fb_T= Ev18q3AE8+rYġ ;$|-pV/S}>u= +a)/<"hVٰJtp:zق7)LRݘ*ۡd/q"8_*IWkZF33fdG{h0,A7Ö + Lꮈi|,p">jCdlZUega~g(C֣ +Ppˈc +APq&ep%"%vt9_-%1yix>эz)ʍn@&_l_E&jT7pH=BnzAΪnLzd/.ۉH }+&WŶI֬XmF6g R8 Ck !. +6$Cx/V}J%OmĆ) )me% CMEKCiCa +4f>Ur)ZǽUO/_+Gm7 #oaNttϏݯ+\jќp.31`WqNn$:DJOIO0@$"DdlltgF3m|ɥowtQTxDDMp\!QcnJ4Qc6S,C*lOS"ȁt5o ~HޕF:u&# IutQAlT%GB6 +O(6Mo:_N]_1Eo4 yIy= =?1<Q<W8 lկ X9d ǂ?BP4Ysh#t0.Ff +9RKѭݔvQ; ~H.e!`0;, ²YQ9m嚥.Ÿnft[0e1u7I7yHhu-VG*}&_Ro$zv׶0TB9$4<7Qj:i(\CL Z(20NRĤU`%9 ]p&弴Ž%ё `, +$1C^(* & G#JfzfFHGh&:-$'1 +ZwղHn)"l"piNa2:B'RڀݯP|6J.wNX\WX갍Zi@5JSFCW"8ĒdGS +2yI"k;RCJ<~d_d:l]JmN%dsRx^:;devG,kb?XB̗uN|=XZIP9Ya5a{VuXd|8LJ^ +RLއZh9E}m}aMaT~*˖W^"M:Ɲ[\U?o?ꓰ] Ц;?XW~t +*zq0%TFVlJGGYao_j>y?׫=;k=X,9#$FySˀQ1O8R\Iϥ?0#JtȘ~U}fISxquZbY& ."-ͥ_WN/{/06J1*I|0qfx ++of`jx5t+U̘I" /2g˧9wޜYE(ě_t3̠~sv8cd>.q: gRR[`c+lN*wEZrĚPcp`aTJkAN +Ok2O»g"B.hM!]OFV#!?CtaN0 |M2FZTsr6`j% v3򒎍Ev-,'sumNo }ޚ|ip?t +$.klX.YjEGjtK?XE}aq$"22;&0;8~5ͩĨ$,uLPurWL2ez>nzsqMD՗4Kao;o^Nϥ'C>Px|c%fDN۽e4S槓Ikq[[ Z\glwNTtRfwmT.lj@L5Sodɗ 4ҍ~Xm(oy_DSN%>Z֑Tjh*zk6Pj>sKW ͣU =I]yw>jkl-HM̛pY)fwyfŧ%,SI6"8uuuos;YW +f6LXE.si>ʼ'/d;9d'J| ooL-8?mZΏY6ћc\{jfWӉB4ON/fKߏNaV)uK'р|=Rk.ҽTR.=|S%JcN'q/;}jݚ0: F9_r sx4Zbks-s}X>ayL26olpA%lGrz| b7? _FOQ@".ǂנZEW'{皽Fn=4=KqEPyn.hq/zҞZa {xKWx!*-ssti6ډgCR]=I- AѨJ7Vw^<<.Yv|vTWW~{'(?jcCrz_4/rKesoѭͩ(p|Q.{֏{_U_g7}Wr[M^ZnYG֣a$ӨŒϼ-WT(TY'nܒ ڰTdҍ gý~"`HJ~‘a] |˻`ݣH-R;Zl\{m?罏ykB%|Rѫ8+=\8:ϔgUC'wS=.gEhtw0Pxtg{q'i,6*kg9ɸ2s;nW`vXC%>5X+OϹY|ˈϒ"ies:N8>V7 1OCw}nPOWI=L~o&t_\]=Xvf{IeVos~rWf]3> htvf6ۑk{z on<g7oM{Lσg1Rx U|V*ܘʻQ1+y=r||讎j<6FV<LJvZwԠ\-y%OgVǒp_xn\D6M0wG9A;n~sJ>j.%𸁠eJ 4(ަYbC/[K%a5;_SD4MW)Sz._u, Uv 7'#ܬ>{>=Zv>F_rE@xX5n +x/1y^zy*n7lW5o}W~[OmLݚTѯM,i37^TtjCS$M#NxIaO-[; +C6`[;=BSs]?7*(ESKet_urkk-aK1Y%d4I _@#D]Rtb739z[{f1- ۣvNZkwywwCMQE-h/==>)U\V"6uFWlμӓ;ݴ;[Ͳl2YDv,畹EHG<{FI0q/a|<M9t61OU*~cSjLtI' +>v3NBTb 0:Jܮ%5%N9l|"C|,t&&e7"|%Wi:CX>)Gc^7]83NpVop\U s3^d?=wl8jv&/ajJ{my̆Λ埫Λ̯nE]et,{[j~!y~{y86v oYҐ0ipb tң:)caj]Z r^Y7M,rh3<_0Inńm R3+&~L L$FRwߙmyf"O csEԥ +(sGvYw ;a7H5 O؉L/,*}*ÜT߈QOda`f. 9jZmѥ3t=ʡvj|̓ݙ3 U-£)"p4?M[9DäDFkGCmGDNc5)`nƐ"4eڞ^eҽĈQliMki5hYbԓHL=I-#_ D<EõAPA{N|ea X' +/b! +x,ørl"FĨSᧃT12"Yh";qof@'hȫyb*bY\-Aobٗ3| ( 2` +B92оYbIN^EAV  t B7rIaܰ5H?2#[W,;Mvߞ3tT?j#!e}_Kxb:ژ/Sf< Μѕ ^R ~+W*Y{(ٚI]}"0#BlO"I&V OAD":NlO>mr<plRu#D9h#@:G)ΟR!jx#q8q:Ż`|RM)L~* Cl+&[HI,fQ=H5Ar@ z E7{hֈb1rislHإm>p?킑1Yx%/rU腅xVAb6R*H0 +v=i\'AFI6Mg҂H"m r:Ր4[WjXqJcbKoU$SB1ϖ5[8DN>Q|D.j˗<'Fn7Zh0: %ztDl;N/M\"?MSw~n.ƃVq:XDb:^)Mj aH RhK J7Pޕ2P"[({Kb y qO+.{kO->~({^-+Z5xq]h:*u|sțDq\,[PTGDA%r rIUygN}3.6/aY=5!DC5u|Tq1g3ΧioK}t !yȘp4qcVJߞK0k :dT7C +3y&ַ8df/|o XgGt pLn ֛r}K_v$&ku?)![X!1{8qܢ۷Δ޷q$p,&#}fnƱ@-lȱTvM"з9jw(ři6f1M7AD ɡj,< @pKY#um׃bBi?* m0a !ԉ9mW}vk]eT}X*" ^fR^W^zT֟TV.ӜEREs2I2Iw H +ngMER=Eӈk(xtLmpR/4"PR +읮=FةFOnHZBM\}"{ +Ձ.n9pH7WILbLܖ3(8bFiqn2I`HBflS `p9k)g0OE_}dU1omd8$UژVclŴFvYt_H"vVj.ʧnHQ7$LM #yφi+9lYC7.QVm) +@hfB9 u&u1[3/B)r# #KoZ֎C'}8ѯaI#׈dXW::#6Ǹwi}s3C.r{-rG` q/eכ8MAXb,=qg(s CYǝ~M>CΖpWvxnf'ΖvLl_lavovۗl=DB +[ɢDswG,w +l5,:MbqsQx 1ٕ6H;_F@t7{v45 +Nojr]{JbA­5Np +BU,i F=Jɓ"?^ mf̂ٹ4w%gvAG73L{s<"A1fƷ73)a{'ŭ7ޙ`)-9~`3wy#ߤmvf f6S&TDF10PBx '[IJhZv]5 i(hͷE?@Ry_2vϿ)dD?86Toe%ȈH#=*ɛ(@#S [FYPh(@WeV{!= A8G0ѐQ帋 ]x_>J7XgmطK4JJھyL![ҮaAR/ξs?آDUQBbi +z1C0IMZ<u,*HzZ˷.-O{ H^Anx\F&lk֝_[܎5]qkP0-YJ-ra"Ncle%? :1H3# RCnh]&+4Ԋ+MVECa8/  w}8HѺپ VKS(gj4k?wa*P/}0yA6(_hE  *A)LmkՖl_ Rk[QHvUENmٕЖh6%t%ƤS\zs?rv'z$!L˖5!CgKX I[7%OZgW>.Kuo6_s`6?l\Nmo jlo[|x@ ϸT~.z %0s+y咋EZUtqՙaۣ9kpTm[q`:Pv[,}J~F?yDJ^)ōN s(rKr>fi1K! H(dT4(\@=-b6mJqoc Ըr6@u6W|iآ@OvlK:daK0zlз):_% M\*$S=NMx`n\܂4fgw==fH.!ϲU-Q1IϤ"Tpg8>kQ Ae=P8G~ 쭡w + soSCaSƛ߅(IZ5i(XI“+2NQ }՜:Qy^;sh3퓷 +]٥*ddj"@l)q4BڊlQ@ło&%:YX}}0U=U(D-?S1Gb,nǁ^ TBQ/zC'y7C)3 2B\SUmu~OE_$>=Qc)sb[m[(ɉ$=ifo;LB9!8P2x͕5Z~o^Z5rLe|}hHb"}J׎ +r.Ƨ?9rM-af^I'Yui\1v`XɅ'ɫJ>ƀgNFYyihm-yp# +4vh'0o iW8iJбˡSR}'G#Nͫ8P//;+4| b*FyqWs{4O"[bOWpE1uRw1`حyXɬþݴoV)yDi߀\l<[FK:tE-ԜXM}&="*ȎY]8Oa+jq>Mzu,OIy)-ٰjiVܧ nFtk *fNQяKNh&ž˛Q8#fZpی# +M,&̞Y2}_X Cat1l"͝7,дxVvXm;n)] +w +M/yD6 !*)%0-} =3-(CJ-@.ۋ#m"ycgŃCL+&%0jM,RYX+1WPoj.;x#Nm-ø0z []`dQ :J +ߝ FJ?T;CÄDXW'я`CƳ,u0]צ%u&ƑAT 1pRB |2=eheSe 묌;AŽqp' ݵs h󀃽^Հc(n Ӱ9v,DM+,3Ρ{ɂ0 lqk<pSTiQ_)DUÉ t_׌$'Ka9g3ՌJ|N֮̂Rv0;W,-kkP]hC@t!9N0,atY~ `nI͈FBuE(b*˹n*D77qL50Cَ}GżJ=IZ擪kQ҄LyO\j*VvKgCFأ,F/|S֌DI4|g1Ca3l +l<̧2PT@BDiQA9WQ4%2[CvK,RKU`B ;X58M:P(4]ڢr1G>2>8ܷDEņ_1e#)Q! i׻ުB_V ]42ӄ\\PJbٽҜ ~- u4ZЇh(f1.O,97@a~e0kz; XbN# ԥ(L'G]*ݩu*ʧQSݩadɠ@J4L4TFbeF/%()9R{`X=t*~높'-UEj\mQK5`41c+2z~QZg$ޒI)zI +'MH *Er~KßxěYoO0%4Lr94#z. @4 P96eDz) /<_JS.rOƠd7̪^xsw fLB}.]}2ʈ5Q.w)JEF=N%J(|]/ȥ2>WլVu^5z|lE:/yܾ +靈̅]K(so;?gaBUmo_JxlǸl!> +HCNix}v"{K +ak}\Jlzͱ^a ,lGx]tbi{'FL-{ja$j-1 ? ~CӸcx=@Nܨ&Kjb=M\pJKjKPaAZKiV. g'' K_RM`WXA辊OY'. +endstream endobj 95 0 obj <>stream +JiN'{H8_y* z1!;IJܤR4^Lwn MLqETdϜ6jiPb4(^n. VlAu3F^)GLX6O{0X\i`GRV{0yz~ac(#;#f b*皫"01 d̓7Y]m剔 Q'1 d_$i@S|xZִ`1Yha_ +ǰwoԧ~<{ߺM}xhm]TYP[6nX)1] ' emnX2%fQWh:1KMfmI>E̗utXc#; 4|9hVTD~GhVt + isp%,]?o^g;ǝqMBW+/?yb9_Q9΅#CcD)¶hؖXdKѝbI.s ^-biw}w<'W2i LPc-8<|TGAdK&6Mٔ6O^f@8 )j_-c2߻xu%wܹ<&>xH^k d?+~&ZtwT DփFtaۇc U.it.W#6߽ybTqk t KoajȺdN%P&hA(ڠ7vjR3́ iF00 y ,U.xM4vA *$5UZMZqMsԗ7z_r154;$󳲄)vApME0 B!k`l>(k֚ɠ4"V#u`I"-Eu:CSi|=!}CTjG\(%qrAaۧp6qiF(! X;|N_O$S3 jXsǪe4-d*85ԁœkd!e{"( +[Pf4jBa+ RaP|ia]u)n7dhMHͤ\n(-ÕZRr;+c`K(F>z_իɓں{f7s{puU9YVq)NKHšwD!0)RZxzȥks8VƠ3;U3Gx{N~Phfs>c_Lǘ- &b՟)ϴ8@qL)X[=Y#Fa%:8q-NZ<bv?%4yE i^1Rc?!BZ&/*5A`+dE3/: N "/s#H؛@T_a@o/Uh”)}gV]@!gg8̐ r#A/#no'^[tn[͒tpu/&[iyr]R꒺<9y#6 AN7@בj\ ]!scJIµp_zR#ٰxˇ-O־IuXWKzL ܲå6݊_OYZ2-39ȝ{g)PLbŃѣgޢyz?4 "Z75J\b$D\Uȋ){\OfPb:{)kW^1Sei`&[y6󪇎(-y^| T ҋ/(#/yb6nU$sVn]lܻC]7{Ь[n`|q䍠^;f+pD0un;08S UZĉ`~ƙ J杻eL$p>jL`2ꦀ[}V9̒hrPuvۤ4؋Mn)~b +/N"!ėkvD;ToF;mvYvxWGצwXb9lYu, ,>̌%e5nPNOԞ5fZ{w @j[2=HrT\,#)NZJ@Ax\B{s ;?i;t&a;aliهz@d!Qm"Ea ~W+!}Tu2*:gaρ9,(bmߡo/D4>;y|oW0McAP4?>-tXQ X*kpiVW g4N_fd{'scyP))Dqu?țIӡYݛ8xR:Ζ7_f<0g?>vHIvZwK0bRT衳:[-Ŷ8Wqv7jf[Q;6V9^ +T M48&LJaw,)넸7]e܍PQ=)F:JOC碫+;.,{ȵ+; b_:٫6Z΂.hvHFDo*拠2hvĨmxf"F|4F7U)b$C"V$,ξH6yMlYh˼LOr,b/#d'?Ay1B8uQb֜A>iƁbϼDpȹ$NDoP&m} +2m. M. ȳ1GbrrF\.ge?JxaKjt^t4=wr͂N3h'( VrzY[wYJE~:  +22,y}Aj.$"M_ap-*U{\c9q[oa 5N"G Xc Ao+)C _)6i\9%$N"Q"P.Pv'V@^?c RId>f_tysHR0z}LuZ׹TVrDη +9mCQjPX,hb3KSC{ \-vrP <4(5bŦ,+uL8hd)Lpj" Z(BY<1A噠 ۗ]c+=vbyTm͉ 5W\8`vCk}':.FfxgHq<(%Sgg>qM Y@{Ym :IXaiɹҒrRZq46~W=R t>G/ia0:FW+~iH%263lfRy4bk&_ȹ3?% , TG[sf'$3n1@y,&zcIpC|X X'oPRjT[V=Ǻ&F5<$b\FtrJC0,H:kK3^{5B.Շ{OyI(V/22~G7qpOlCs-6Cr~ZV77Y>yY ?,,ɣ|ST x$jXS7uG%9A7_#pyO?=iyO[Nq +5TR-Bs,"/WmI~!Òlƒo{jpm_mJ2ƶ}Fź9HIhJ&!}A5נ)⨪M5;'nA %HfO@AuT~ƔRkKe6ݔxG_{I3AIF|Q!z:uxZ7bd[E̋wԐ\OJ4:23aЉbth|,/3(\VFI ل=7 ;t9PZ(΄rukA<lU|iȓnyY1ͽ+ϖ0י.W^fY#EF>c%̘3PF-&?kQn˖Ѭj(jVDחĈ ?kh?}Cm#zs5~ dd(=MápҐ-ᙦUx+>\_!]`FH,K;v]D"tykB*_*8 ,fb0,Sn}B:e(~,L3GxC@eҖf3G,z4e"i2ͳZreأzAZ$ ] ?1ẘZQhTtiR@}i,TQMe<ڒ'LA%Huj}[]Ɖ5lZRmgJbweuvYz"LK +MCaTkC{jg)[؁,;Iϝ+N\+8TDRew +}E1FLKؤ/<Ӽ:E$\{e0 +X;X2%c-YS?+bA80Yz6y&x~m˂4/FJ gxa̾â_"kݗ2m"VScT6,ż 9?E~Hjvp%ɓS}Ȯ cH$P+#BSQ1UV+P!zDᵂۋ ++P[U8uv +n7@媜[烫t9j4Fs͕pg966FXD7 {.쌮ϱ8Bhϱ8isl.>ǯ0fuٯ9s>Ǻj>Ǧ9+v7B!-kRs^ߐ%,jjGt '@ȐjD}ƞ4y-.QfB#"[Dh&OKC,U"ב܁:-5s'Oas8VXWLHA*GUogT'I>M50זjhT3ߨP>#wKȅ"ß]Ec^ye8nЀN^HC\D*yBcw{ExD%ˤGOU^cPX,4mM#lxU1rv֋ ` cő.o>{ K} (QP[cR3e-מL"H +MZ|$U "rOڴ^P'ToK!_z!Nh_?&|$WMGu$UI#2I31vv8)]߾teq_h3LEc0K#g[ur4+4Y.{rqI.,x]H<U0DQ|:j`J^E20&?,V7*sDW#E-5*Z*dR + Wh9pu~@iu:Dz &#2 !nyC߬;5b[ lU1-NM90P1)pQ[z@AP"F@QBPWBE.J!EJco$`KSɀ;<k7V 0.⟑T >TOG69Owt< +7=B 4,u?龛zTϚkOyzωU +@T1Mvy$' {@0K}0>5E˹dteҒmҰ=,:u wSBH.߲-a2}/F/J4hÏfkb1?S[څl'8߳5[ apJ nԏAJl~`?־ Ah!gy5NA<"b!v:< o AP~pi a#QC,AM2īÏ֊Tw2=h %;*D6+L!ѓLT8qS©|Ei^k,O;MGepZ) An-so&0B͵VZu"|/>yjnkjArVkAj`JrP]U2@?벪{k@P~kAa?l\ag̡Md+/NNlWΊ5t6X)kΉ[ysR}Y馊\Mg +U䢒 xRgiyt[ɨ?7Җ(MRos</}+pV;]gq|Oxo.G䲿IގIݘ+LNs[߫Uœt)l%OUY=>m=gc\{,K mʳk^w5^4|^O .gBȑ)jhN雟zg>$M?uhSà׼/O}ȿ&gO_;k|Ԇ*ۯ{KKSO`Cs寔+^ bQS:͗2Xģ&p68)ZV!pPb= (R .m*KKG?iRXh)bq#{x#H@+:r;\u'rV}oS n73Hcw;1|ܐA-&V{=Y5[YVU r3(kE_pۭr;&kkŚv5W\=67/;jsv5(8]lɛM>&uD@  KKDl_a5![i<;ts0W%i%1 پ.0~wפhE܌3S}N{ӎ8f@Rܥ}xLYkl4ƪE1b`-R)04ˋA +܊FFW}%:`x;W?xX2%oCRt7:S}jNĶ/%PKp=8QUBS7S8۔HEdiz-03CPNg qhJ&$4U؅=qȢv 3ZQ"SEiV Z %bQG Nd\w6CV>ьF?e aG"GHrG7%2c+)sMzf6汀CizuG]v6O؍L~=3a" gDu(G,vz@c^$Otiv'GL R Sxöw}U#v;,9䯃A'RQ,$o<ңȏ2{=AB:1mW\򥨯8:~^t۴Z\m=z {R]G|!/(j <4[? +-7*Bem.W+nǺ w݊[s{S͊;~تrSMV܃ T,1Ij? :ᛴ 0A:¸ͺu{7X5⬂*TwR& aqҚ hf\O5hCjiA ,Ӄ%mmq- + +z*;)օmB؋2IHQۤQw'fBDin+"c]3'Lgꨫ&s-3ښ_QE}?R#J]oW0D07cu`ݣgگGzwϹavE^'kWB%j7!F沯X_%HJuCHyYE<."A̎䋐d,Tho*dޖ<˯^Iȩ+w)3Lc5ݑmAg5K^YX "o5ގy#x^dOʫ ψ v*;g}}pAAazg@{! sNPHH% HCr6̂ťi20e[<"[ѪiݪZ&q+3NBi'}hGi=nĄXj!#PHt+EQj;t{r_| (i9u ^DDh3id%z'>[ys!760zw^b #z7CF_N+Tߒ(11i[AX ˦P-%lf-]s5tQp0qs~UЈ7A/srs/5z˔W 䩽)kmZ4!`/& fm7 U%VmoGZ̤n&Tka^)y(&<$jGS$<((E0KݵҜ_,䳳SГ vkqii7AN,I% N:<'ݾvxvpoR3HE +t"[ =Dߪn,x`JR"c̕.MEE= +C+NX}$y3pL_+dU;;N.uцc)Ϻ>ilg床X ٯ6q0#=E(׫UI&8ƎD[ՏMV3|2X=*y_db]iF2kAPGq7p qf sdOV'`nb?,cבӃ.Xp@1hkX h!!lx4_}:Ff7 )Y"dMm~_h5KnTUf) {|aXiN- |xĺ(: E\ytmaڝuKxߟAZOãL0{J߶*;eZ*|y$âx DhH7 eq2@ ĮսzYht/CҸӯ`%!BDnx#aGS(򣕗?γt9 Gܩ3'tf ?*L}v֩&O05*hl(n^ n5fl ޽.h$ n:xlߍ$IHG>*ݜLɓ?^Hw YnO_:sӏmbBVd"EA  P%}B }eҙyצ鞢|MDs=wG%0"W!PL{pY +4AGX +XX\K.DPe)"B^'ej!X\;uYkn?cgeA/߼$ {jiZ3b:{" +LaN6K o' XlY^EfϪ=T擏[iGqm=-%}|0YfQRuU|Iyxy5w얟M\Z+wib&?6 *q=45$4s#ϧ#r:'#<p9bS{~T$Q)<u_[vqO]lVFd*\n{8?$S^\~FDa^nڮ밸_xNc9Ng>d~kرA-mv>a؈ܿ!-Bү_qHr^/U:se^P8un wۃ#r=3 +q9S7ܹ!_m>x23I&Ou+BL6ShJ>O (;n4Gt#U2_8~"8N>g6R&;A#Kb d7gvTC^,y:"!JK muc1I-&c\2%SCR7uӉ\GרYujCF-2u?^R]J,BK5.Kq l6zP@*ZբA} D%I"IJ!i}U\0":ǩ$Q]]TxӔ?>~%z4;kY]d=LR-uDKx[1‰]y"^P."gNb}%p]('<r=J`b yR楨B0=dG!G.ZVF:_;~C#w1 'P+N<xz~ӝ3qAZ^)l + Uv-ۚVOTձ_h2TUQ=m.*$DYE%/Oifa@cYE=/mj~_diYܺu”ϧ6 ӌ6jլFm0h}ɹ?tc~V# '4Vr-I(* M#XfBY W6tXQA3#`?@M+k6lBs/waaنv,.nffdTwn3%mhŒDG]H|NGfrLe:=?n + a ^8 ypYE<5T]㗘=}I#0^O`iYWq$9<f].L88XKyYzcRk&_ƹЗQ˄ nYGVʒZR32SEw= +n.*?d.c;-6d`҂%:o1YT {R.xjGګ{ͪt"#qME}aGF[z9n7=tҽ&òVosCUbi6qXx6vW8q,h*#i0Ub`Qz1֜`Dq0u<0Z(uf=P&!лD& L^6T4́x>ݼ 1c]*h՘v5vd1YLɠ yP5Qg^7&N^ vyC⇊^^ M3#umy o%y<C&=%f!JZ 3 $Ɇtb/,eE70T1G[֍Na~b E{l/\uj̓qA^+l^YO|x8P[G,`Nb|[Ԟw& Q-8Y|b7N%*@5"NLq$ڢ87J``H1?XyV:QvnR4"<0IfUUٙԎ.D8iVcGPLOX%{Vu'-z+^%fSr"dS|\)3D4+fI +5MlR̅CsR*C(|vǼ[LC Np]A cœc*/]}:ɖa(Jbc1J-G@BytfՖoBYmhX,%v(=-yqsxTf'%1lP6ɠM c:base*[ag}^ݵD~r76îEE/5>IVWbFVP`0==`$qfABԍ.cumb怛EP +rQyy,T}[CV3hu8?t&o':̇9٬Z6G0E`]ѱR7b.# LZMiKqB\6o\mZkNx`]J(~T7 +g茤Z`@ s~"q#qP J}G՜s0MKPIkeC.uǧ;*sY%ϡ#϶Nݩ,`$ JbGqNLpj sP_<㘾 E"*DdW C%O!UX8qgJusJ47ݘ?wx* _8' s>:Zza=m; v\=>LZ-pPN]>>i}.pNS>_DSEINFW3e^{_w͓Uq@OzNw.T]Ꞽ4tb4C~!JɄrW\?o.=Ru.q NXg,8C۟U{?W J9gO}r=?=I9X2ˣTj\#5{TҸ=(1pn~x:q_qׇ=*!_k\MNcs$(U){5:HF5!W+tq>ߒРUzµT%([{./ R`]=ZKw,xenQ n)هGjd2u^8~O۷Tqܾ B_I83WGUPq'tXI8*W\sN2z.`D]q8ç⟾qh n֞w0[φOjxKRבz-|t?'$݂IW Oz)$=%Xtx]ܯ#1n9]И&t>L?1bLi:e砐lTY4;^r@9fa }3 ߻7qnԩٻ^8m{za-^$FgZ~tLqq%5$yJ +v/_oQn!tڦߵ1M3-#/Uc>8GBdx*\B8 9ydž%ӯu~?q@oN4 +r\h;qܟko9 {QTJU}\q=Fy^KIWh3VZLY>H +[)"Tk݄oG#٪OXמS4+Fdz!t.6|`4כDZ٤ߺ䍥2v7Bo߿s[aiӋQiKSe#dS}wc3Au-,zP9Z +l[uuls(^vBdnSfY)8p\ZYvo,6Oi":Ň\#-K{ɷQA9TAK};}_,w>ͳf`v"'z4bڍ. *X.[9/tO¼|+K,0\bkDרDג[>=^`5(6]u/b<9oa1\7K>šDS-f ^Y`Fgr̐`c ^Y^MDP}Lc;F3PUb1 +0Yz@$p>4% H+A;9F`JW4Щ5,*y {Ut`Mb rɌJmi]QD֏Y<.nޛ-sR6ͦ]L,H9f$bTë@ c: +TZe@A]LlG8mڌIuJ&jXubxW{C[LA1n$ì dE͌|t46 rmcqS@10^-}%<;omb~J|~ƄՎ Den`02^YZyo^Xj8֯bnnⴰgp*٢THc7~9ɠ`e6fur#c)ag@fVPr4%xnP|20lIƘ}\Q*00r9q,RM`%˩=23/v,HTf짅uןjvאAQv|ę  R`{r>*Vf+-U3DBKTNܽ8# &qڌWbq*"B2oxC7~_[O~*y8ZWUW9n۩+MDq +]c@8-ELBtTi +I faZN@ ް` y\aXC XߗY+&a"|*:!oW^>.ɻed"I`D"Koue{I0BSkm+ߛҤBo +^dl?~ 79zȝF!R~2Htbf G1s&u[\zȮnLg M[`# ޟ]_: iL=.DPOr6ETOsPA/ʏW zݱEyзThJȽwѵE}[w:ЄC9eэp5IQ;4q(,=F1lto$-'2f`))@E6G]sf|k[рCi .jLQӭɴW(0Ix!ҷtcম*V. +{ZAmH%}2(``Tb&s!9jFpFX2%\uu9hnmE$nRf +wךIźYs~B[ KkA]MI<#Pq 0cqb#XKԀR{}f($98#B=2,JtUC&*%aT,3M=ON! -f:ۈAĕaBҼB(\_@)\?:Z`Tv&v{% +]r yt@"f DOgzAI=0Lk|5Ɗs_0gטUL H{7 +svzU +s̝U*}.Q&? $!,NGz<3 RR31i@5AIw*6t%&HB=q +$ˍ< +Z]rm?8$ +2̠#7< + H^~kro _G +3FiR+D^d?uhs8OJqݔYtֲe6Ѣ-ˮ q趬GA2kWn^B$fj1cCP,,n4f@Qh ɚ?b[*,ACE%gxY6ңJhU$`'IV/|eIVx)qC`75 K߀W Qu /,tcly]`6l^+LiLҸ7beY f#䅥/UM=obHKb#$,,oYz`K:lͬzZ"CD[Rd"h/M~c*֡7f4kzqp_7E[RSZ[k)2[EPY`_p^UB^6e +rdh4^}ckoP(JUr5l "_nŲ5l^7FeG4~d:jH5{D3T+4UeZ?N_k<7:qxC?oDW? #0^8赼2"9XsVf3>,=*q!J|XT4ݥJuQAH,z$#4;‹voyxC^hLۄMYa,If7!牱5!Ʋ,*{"(DU k +p_qVP*k LIgo6|bVki +)cyUF_M^cWy`(S0*مJx1'SÑ<_~Wgee][12tN{]{|x,NQŽ7"QAl>m jfzxWv^I @>"t4o8YV+ w 67ݚ-/ID'JYTqyZBb̓*,#tRc4Y<=`q@etjW +>P v¨ǟC{|] E+=Cz3c]+ҸQK*_RTOBF%]Kr6zGȍ?7Ks<eUg! tv6oμs+ȗZ +a'vu\ +5IqX$3˿)tesIޥ,Ki]3S/p;ei43 :1f :ptSs&{1,(Jnb "K74@@2?*1~yd$~ĨXCPsD ٲEc:R}MT!(ќ/:raUKE.2c:,Wn7p p-nE-1yMK]`);iC'ZXVP-,+vt6oG7&#)+I_aY}Z3x]o4R + y|Nrv`l*4-ͼTYqJ:9_`w/,Ev|,ӑWCT,APSe4iA*Nu@9#! +Hw(` +E^cΫ6TeĚ4͖`AZ s16 +I5ʰvrxHۥh|m<l]|P}2)6b.I_kK1{L/\:ԗ4mt&1y)<{ă?(>^Do=O)7'b"1<|ɞHџ7LE4I˟g2Ϟ=Ξ ;{:mygbۙ2ԡ{~=NOWG'vy׭+\q|Js^{|yYP"?`gm[Ysӽl;y`6q,r*tWT1 =z(_]wO_'N.{UEQ5w%zOtq7x?Sу^6sj\&QwiOp/_' e^ʿmT/U%Cz*tfZNB fzX46(-ܳ`G +,7Cܭېڐaٲx_Z[F9 B"'ߧkSnǰɋ)$ȰfkX ]!*(p8F'Bs&oM|ףj VcU*X%/;hc4XB[ÎVQ7(^m䮌X\JPgv%+Bd/Kdo^mx 6p|{XNJ}doslPR.? u:`^YA2A#vURf ':;hG-unͦ@4@ 1@1(YBh=7l@?٬?7ӱY}w)B +Jh|VxT \'[پ;\{l1aPyp˔}tS1A@Yn<5e<|cQ`2ƮhPr|1Iu7{]Y[cP@xi(|݂sQ]A s "'[*\a%")?Z`q\RY##!p52[J0+t8yeWT]; 5hv@Osu>;xh$^qeCfE?/=\zmtmOi1Yt{f(m'ioR:9: sJJbXh!Ry3U}\@ C|< Sڼ(qzz,!N&,9b^4}8&VK?j#PvO(TtC̸Ca6ALq, Yﶜ)A{1g[50=y'X4g-!&gA)s]qH݈|b g/} Gb(ʥS1:3k q$O@˸궆0ɽMva֚t-1˽ۆ96*I +t!D]_4PH/RShXpALj;Hfn܋E5Y(c!ibV"Wej#TΩS7VdA~a1+~\c>M歝`i`juwZ=l_{Ff{Z.>7L M=a D⡸'g~agkDJY)TiH9XbwW6,9AA (Ѧ|GY2_8liYw,']kvP3Ȗ!uLkC1˭ +K<{'yR.Gc;h)|"J9rȯ6h, +6HqHq8C] cY,f z|D@6k mRn' l<-}&Rm|RE +[~+ɡW7P尗 %r0+}Z cR6պ,b& oxk Bi܅b],vq5O.aQc 8Q+ jH I1|lq{G(s{(9Ԗ1;eue@axXńhKl \ d\KqD}6 fufae{E[88OÁwNRFޟ&߽B:ɜePG9h *{&.qpkv ,ƙclHPy+F#lD!uKr f 3Gy_g2@&>/Ӄ?JΧJ,}9:?.iq*=Iǒ + 7}H +,^08 +fUDF-8ń kVw!fiCaA:~>G vkyTD?׊e줒a.ī(KF31"Ea\i)c&i\y.+n~H+d +2ck?ZK9VtYⳛY'`zX} Wh5ȡ| ?vLR|j*+5!)qj;x]SRHttNO}蠱Phkc[Z?[#쓼wMݰF4䦙pF)( 1pLe4{K'3d 4$0a(4"ɌAjx2 QI>`r[}B&̂mڰ\wFm +C(cɬL"-,į(_^7z֯6Mk[8Yݚvp_ \YsJl½[ 3e)-)bM\ޟΫRMarƱl[JhpM +Vw}2hXU%lJ_d[/|ioQ J:ORm̉Jw5a!#~y!q#hFGhs={UQBj-U,|1iLT?K<%kW@Zh +Is8 9iztŬ5l[nJHbBc*iIߧ4[eU +u=wuu[TK+4n4Sjӽ9XEY +f9"p{y*T0b}l1shO k9T3do:zo~X=VWa3h0L5'cÙt^֜3H_<ƺLfX9IIFxk!>ڂ3V‚!%fvH? 8Ï\{<vAmŊ_ <zIH7]IiNez?l[*p'ٗgE NFܮ4%0Wklp?zWȣ_XM0Sh-MG'OQS!PwrF~P硵yugI?پ:RCtȥ*$;롁\ +5gO+D҂*t0**q"H4"?jܡwͧGauXD+֨oGJ~Iwtw_$w2_ZygNOp~__Ookϗaϕ@ތ8f yDTx݉( m6R]A ۾ ^e +W3:}i 'gqY1:i^I^*Gv~)=sՋTbx4&>T~Ry7;cӆ>b* vJicߞ +D4#zQRl.ϬUcSl?>[ +>VH ϓ|SЮ;zsL 'dMrTVrT: "-N +$)&vi)յsTZ7_bɔhsGT )^DcNtt(SOtzTvY fIw?QضAIXm_jܦCf+<)S蒯ƽ7U#_+Gދ+%1!wO?ljZN9IH8"x +Y˔2̙w׺.L-0zBD㳌ruZ+f:oXZJomIb]_Z./TVrN[~Qlu~\13b4ˋX$`H +aE 9,̕` + +\E,~NOUf;a!q)Tb'^s%#>lRT4ë|qij,w/ZiNul۾n*١` w9}m*Yy(ϕ"lIɫ)hmOl'4|%߳H0fXݮ6.mƥϺ;Ua +͗e05ojcҚIq5U[hs=[ ZN~` +hA`\6ʥC>hB?-êMOeF>[ ++4A_\|gփIAbK>gCYl-?d2T꽵_U[ 6 @WB{: IXj "LfԀI  4OғJS@v6c&6 +$ 4N٨"yTsXJd $[QXϹxi$m-«jD?pFx1[n!gG`qUYRX +o~(Uru^ȮГIJ&%\|dQ\IL9.{e}ayb}Ѕ牿3|cJ=vŅ̃W^q'xqh7 9פlx&VW.Rin+4% {t3UD$}RO\ڬv5bq#jں}ț +FY6y-L +3#{Eb \.(I/k3&哲BUI7VH"iR%JvHMJBx[,cY$q"( 13#{Ո4R4Noh$s# +LT)Ӏ}NaIoIdVj&{% \[Esop[);f䑸7zVLU"eHCǚ-o7GMH;+ȔiIjeR~S+^wa ʧ$`^LzѺ>W2W5_,$L@A뻁Ѵ4;l+!ID&M4M$Op[>,aX%(;gЖ@ uf`=Dt>W:uw@\m}z[ C ʹu#*Kwvڝ~8}3_]P  +ygцp6ν3r٬CyR鶮_ZrnRν'tvsdg[Oszb/k78=/M!#νjk+rǙ-I[K./5O!ͪ },}H6~dCu햿5o]]Zfv߀C6HյD=Q;V:LM;"ŶSVr萷B^ ,I*g8 ߷)>a_0vZLzu@Aq~R0]:}0jx+$;'yAT(CNT/`u]܉qӗ:gy>ts 9_?J?^?T:Og<53yʡ|3su4<: 6s +fWoh% P \,_~rL>mx\*C|e xv1 hZ`y 418ԙi_Co ,f$;Vr%p\d1;ί<,ꉾsRB[#R4ȴ.KP !H|G"CVk&a.M2l2 X$> tP=QQ5>l 2=$E>_ԯ})3ҽ`}"l@w>b +tDsE5 0MP_H[ZmS[wΗ<3;HlI؁s^i癯b#vb_\oXze?;+y^ۺf}zTٽ<.`~X:Nӫބ tV5Ԣg˸|R`ؿ8~sgL7݃RZwo{*eaKC.zF/r%clFY?| <y^Ϳщs,;ɓ> zpӵ}ͬ g|uO h~uw'ez*8G >G:G.˧C\=꟝;ug_bq,a D>\gO/} {})rgaJE%T괸+JP ADa+~.s{ԏ=Tr.^~}8$sܘ?Fmw>|ƹzTwJi" *:7c2-#?c%'W +!Ū;nG=r9W]L_^.:U8b~пM3b1 ;=ܦd+/dի*e?RuadwvHBWXd>pP=WvU2[rr̽w?J{ݮ|/6s9ϾTAuX]Nҥz +Jn7گ_ +/Mb:,uq[v= +']d:{ShNi|p\*6p}[mKNjɝ? 7:}۸pz˹v__=-> MqRjI;}r$CٷJswfzk !>0%Ǟ{v ן#>*^ؕK{Wvޚ27>_rr&t>''/ّ({qIf(3v:t9m\xK{OO?pF_[]Fm<̏_ + A+syWV4ľel]SԵ >ri R<Ъ?<\AE=&4{xx>ag׏IA>`=mlћݫܴa**=,#؟u{`#95Y3#XZZZQX,./0k䧹v2C# hյ9EcΗt''vIu-u1:<׳e-]gCvlNX J(&`] /g7X .ч -+ ϳ O礱3/}a# VjG~a{䫴bXV?Z >mA$b(`{b=};S/l\&R.e%/b7coidi9~!&/nϵò[~ {c0*;P([͓N^q t3g[xE6sl-)~[Z^"){0_Q'cl3c#]q5`9Zo X>??W>&m-wWc,Uwt@aWtNISls.iه {>S4r 5h7-h&D„&Of G5 +}J:) rR'p51QZlăa \q}瓼uY[;##x4q4kA&;ҿ IcDJ1͗nFNA 8k0dRf-h*Z}5$5Q`Y()<7fPB er}@9/i#}*ź םqwI>/S8C-g6BPjX.fv-P[P +ʭU#5*?%DmSQe>݋ +wBefDMJCI3*pjW]"C?E'`iy }RDoHW{.IqÛi-.!v? +aM(.ās/f2QH'41'|.zqb-V9Ȣ:IrX6e<' ؗ!S_؅"%%4 0>4!ʲ3/}]vGy*N9+c ~ƾdDӓF~})%&cg +Wce7V{U HUb~ma:!Xi $PkU )>&p^Z؆ )oҫO η:[p@b"Ѓ/I[5mLtK-]Cy;lrzn^tRsz|jgaç;[Z>ILU Q04^RBe$܉4R:RO>Y Gjc#ePj.٫6rA`K嬒WqpVgUe/Y֍V%Pb4!3YwPB)|Rnh]72 C?7DΆ91 +4hgPd07ϩ1WuNaMYЎ{%-&tf'a8XmgKw3g߱rp%\&Y5^u}# |`||o3pY;DE4IyU=XĆ */\ӋB4>2'q۱HS$ip&B8Z4=JQxСgbTӣ$+ 8uƔφ?l' ȝ";B0+R)%)?i̝LMX@g)c,㔭irHKp;˓CDd[bom=׷YԱҺʫMQqsQ,o +%1)m'eSf  sCjf?ʣ3(.Q\o,QN-U2YU Y՘q7d֑}x(N4,o~kEnj %3TvXLɧL&jM_c*M_g6[~^U=46<-*( ~fR([Ķ> 78 Yb2|r l0}?у'wcINWaa6/ 5LT4(tJfLȥ"9M* +>>ݘOSVM6"Uf9ߐap׏鍒C'3ٰhlcKCai۱fa>N/Xز\}Bⶌ"6,SbUOTf.2'*u|Ṳ`dT~8ُ#ei\$Q=N3[NO)nYQM\!f%?wK:'}{ As;*` %A0B, ͔4^}tH޽ 0 |,% wq/-.-; ߗe,vL^$jHhaYe-ZG<]?eOkl^ wh K).RɥxK~MX iט +SiYJ-k^YjӀ,'DJqQXR-?y.M^ ߩ-z>m-:eJ٭а +1 CZmΜn?g%gO{1 |-dd~>C6E叚 +AS3MkAj1,t.ꍣ_iI׈*syM]#ߡC +:`#;¡ op+2S5/` + XcNj%2h $l;!?f᪭>4b]8GՅT@@M4Sy &-# s(t(,#J y,R&-JK # *<@jzeMkwӨEёg3(j.yQ Ł(=7u'Jy)g{t3sK X|8@0#^8c2FKf (lF7Fc׳$U5M,!SQ3`-B*.IcYRkg]kL5F#6(C]BMA^S}4,.M|ycn͛PL*{ 櫓HvFEvFLiUV&LzKZЫur}zfH]娗kEau$P(jCgwQc]R-lu Xղd(M1gYOh ?vX|p|怙4ԝ'COtKqtb#87Kh{n["! n%T1D%? IP@R>daZ_PS9޼vLŖ)k5T~Ojgol)a +. 1*wk$ ږ$olA)^Ö۽"`Lm`9fH;#n(5.w:I͚s_(@xTtS"]ߦv͌rܽ`Uf\TTz[33Nj}+2mw͟SP)&-%=50nE2!!ӆDbѰz+ᄂw4@ɞZCųrH&Þ!񸿑71zYRO p~-7rLYwDw1UB&7-RFMopLR K$a =ؒkJf# +F$q/)2K#*09=2Ό(X +M9=Y{A׊G5Aihc,v-]5VS^@ gau(\j߀gn D`VPa5OޞqPV).c譁?r:7 (XC +cHedJCisOGY4sif Nd~_`칹+go$7wjO{ +N^n^~ק)ROyq881eR7 y+nx@TV0[$*O\?*{WkpfE=LF"_)]i + t$.` uEtbA+BUq֛)b^P0e!3= ֙ˌQ 誏 +ĽYL:M# نMҼ?(|Ti wCg~xk1ubr)]8ů&qqځ5 =Cx{'jô(n $:oG5s&i<ΘX**UOH^F˫A,i^our|S{ c\z}ʳ\39Gq> 6_(tga`"+*-n\`-gc 9A#>婭~kc9.so]]eFϨAHE6ܱ,T教x,Q֝ҖH[ +\mʿY,U6!ApX9z5$CnDuc"ʳ-,RTDʧD5䐼ZWPŜl}TqY;7".k,QJV+Y⃂Snf[9EnfҒƨ*r/mBϓROKr(Fj fSDWB{N%!A m=B}ƨƆ!A\JGާ +4catV7N?ݴ=2YfPpl,}۝ 'b3%$>UJΊ(¤a'5o U;A77N,EݧM:]ċ>RǑ{.]HPi*ԙE+j9=fw3Jd x*& +^}5Uau۱(F4vEq<a?(٢P/ADU8ã^!Ó y ai,kiDh+^}'Qk,)lZ.Wy.x)| 1vm@{:ЈjPK/2r.g8 + zf0Kqqͳo2TJ:`}]gxCP`a|:I8ݴ{">eWYIr2# |J] h˂ +yG.5$ kyY1( K')L rP!Yҟʣ)|j]:qY}ҢqqSZKnJ9] j96S֝WA Bd (;ËJͤ21e>c/-j3ݨOZ'.6|~i:sWR3S+!<9ƌ!bqDˤcmd)|mhmROS!њS3@q&ؕūƔ<烳l\1OjkBb 悏ƻ|de@vk^LQ 2ep] TjjT™p) 2oy*ErwdY}#4+h8 ѯZK`@KPe|5NHM<֋آ1#~F }ك<sxS9яHiѽfcΊ" +;s$rO+9"G?$d0?CVXU5X X!Z,l{%o+O&b<#@Yn*yB:#36}JYey٢]!Ћ6⬬hҀ|hNÝXYwl*6.fS]5DSN0s\ +í`'ϠBT%v\Cm=yw7T`i,DQ; |B9:o'jWխu|n>GL`<g6(4;`ֻnP~;fc@9S z˷WI(g@U +%aLMEz:E|i㓰wt@tIhHI7` ˗ZUxL[U@8ߔ B.N.BGegkxo= |hW՘&1|\zfrhL}lyz*Ě#v +X>>0># +eBU B ;#(k@fuB;FğڢɤZN4UUBΦT)83` +<` П )$ø801$q;Ou*<ŜPƜC]zOAp'V[Ui6m\6k.7.GN=,H8>) #~H-և9#Ujaڹh]^fGsufV jQ{3k:4 z +xw mA +~Tՙ.IM4 T/+nPODu|VbYM@ǝ}WG6*;Q« w[>SWݿ)M&| {t?ҭxE>DLO<\WqYש +SRLu|p@$jN6,!v]r:|@7whҎr,BYdUGgܩt)W=N+Q$Cʿ׳,\4L}[ +PEVYS f Ϊh~|~7Kr)̃dP$U t$;- +[hkxTP%t4dF6 ,u8XhH2nj8v5@ s1,ڰ2vMSs/b+aד`Eα2E0Ϟ jRE|4L4vgû̘ Sr۪]( G(#xȆ<ϪGZ+|U 2䊙K +}̵Of}Q%&N'w;O𖇙yi:H!TbN9-H3#BhQ3i2;9 +t _轸 P _=io\?۬Uu)p(u斪H 6dn꺌 +ɯQշZ?%4OsfPgc-B(GgĞBI$P5T@?bdL nv>1%f3!!pA.)A"8hG"19*G߳ gAݸà`Y,M9@\J;9cCT3 䝵;5#u#sx7B-+aȹ's={wom+]2J yK?V@7mFne[ٽ;@ٮ̷k[9#N`5c.Pstsr^]fÍ +Ipq&zWpt(ɓjV{zڻȅs893 GKWv\l9*3 &r[əs}gWPg-~DzCo4 v?{&so:G!;ɞ=}+׃la4U۽<^= Y tdAokO Uow?@L~Zrh,9K`?* +HL Myx:By+v#㷛ޙӇ{`Z8!` WOlՈ_[X٪0Iڪ2nm?5iśF.0sAjd%ݧFSUvkǛPPҎ nnGKԦ[{wSkwP3&4RPȁ@dRٚ'!ta\^ X<#&<-9(/ꝒOdGyT:]Qb: +L+n=6-yZ };ă@$/!mU^0}j%DqeA ]iYO^kpٍu<1rCH5ୈ\Ar)dzoLxxAZ;q=ty`p E.OT}{& nȓS [i~\SY5 J (2ٺR%1FdEafYWiȃ1Wa47ˁbJB& -8;,MnCfLV0j 1e%p„`xwŷt$z e q/$v !H@ǮyiU:̯ѴZi!!32R]?Uߎb_=yLEpBQha0Ĩ`'/`w񬵜 RQ(}fQj`X^D58vzj)ƹkDRf T +rYU~qt}ݞ_wNqDdiwf\+ťEa\ic\3aف_2D=(AmHKV(s.i\LF*G/k}L`t[L\_LbR+sK*°{T&YAe^SL7I[F8E00sE|7UɞN3wybJk\NX],/y"mxsGn3\&l̓L5L%ڢ7ObE/Mн{t6*q57dыzU!z&{X 2[b+qp6l ๐=O5g9 +wZI]Se/PrE]K}ʊݻgآg`L}B q1Z9ʖ/MU]0s"NT8:Љ*On‰×dy`&\W 8u9:Hb6ΣεRI068'wرp! ei=W7tHC qI*'8ϭkhid 1PJA1}0MjGU/btpO&iIACfimCQ"vrwJ^I/m #ai?@F QצɴzgGTϝտfxQfA6}AƼe\gAr^25L VN1L&[Oom;jNdWA#]&EYnv:;q#ZD)<H"!` +A>.ݳpD(KJ3 xa\Ã;6*JO7ȢKE,d@b`#svh,L4 +5n!n)֧a}EFW>JUIxK@չn33i'2>V}B4iB<aۅfI $y"}QQ?/ҁ Q̆}WRM}{A@ER-5?(OбA F |zQ@c (OXE:KvonIGφ4ʧv;~IC`¹ 1,nޱ#Ш,$,!5/▟a8C;}9_,8 vׅdv7xj@3lATF`t(r֐F'5_O 7EܞvS:!i1#j}? `9 d 93tb͇ $oKФn(U"L@~7 -L%F "jтhqqbjyhnux#STL2=g2=V-Njmv_! -|OVt@q_{R|Bd8iDa_9{cr?]y#R8+>vLNo4Ą?7;r1)Mq4c c->v4Еdv"LFgF:H$SUz2zriI߸wά]3 |B.ɞhR \;Z0ҞF=04U|hU|92>r>M ]i3JR #2lM!mD=Y"dK7!# 1%k؃XU8hQj ܫ @gT+i d%l$.Xק )UnZ><ЈE-x[ + w&"4kGsҫ, 1`3g9 +i:2z$SwM}5n/yY~\*^'u:`Tϴ\w?_%/U7b9{c |,;bB.xwfQp_mkeɪ7%UQ`|`(!^(}_*5sOUQe @ y}00wcW*$dimJsK_M}7mˏݵD?ԆŖmq yYfXodT ;㻮s8 N/F7Rn]ͺ˙yvizaSFKMKz㾜IQ2< ULUM3WoK"VBe!.R_1mJP'r|3!pbM.2wm%np6n\A}b寁:)u=Snjdi*FE &V{Af̵~'t&rTO.sVᡝ?[4Lrٗ{./ f.nn(z,8y^nore㶩Io/ wMp^|˘2:w['}H+J ]\Tq> +-[KI^Fk&b}p~i^~Mj_ODz՗])Q5;*Sn U&qtr-hUس@'^k8nJwӋ +կV䜓!]Xf_{)t ikX9g#Oc2q]LWz'OyոK)2~&ne`FdBU_a [˨r`rZ|lYQqq8LpJ·T>>`2,c͛k?(|5jV4ߊ[O2pѱkf!.9DWgo-L;܁ER1¬ሥ+Ar NPe',zL3s Fleѫcr86w#~/Dieԙ6G ~2>NVz*zG+l5 i+lxYH!k z|~\x+!QL%ݍR:yyqe<~|МK=& Pa{! s2 +Q-G u 9 SG7)=s8VV,$.-tIAYO 7.@owZdK%gδ! b + O`lm~l1"PW FIKC$}|Oesv:ݑGNq&`%1'/ͨ&\zڋ4Jፕ$,8_7KI˜4~Ke~Ώ.Q + + g/m ;k28I{ KL9#Ke\Pߍ.5]ܼM?SgZM Bfh0zGUչ+d,1!#kE;6nRp9~ f"*F%lD`ZI "  8c)xt4͡groۍߡ3Qf_6'l=ߥw)fM7Ur|%=48n<Zۙڛ J;؝,n{sjhaXܰ<Z7*d{32;<-t[4A-/Ͼze/eUgŗOp&_Yָl[ԚZ%A+i)PSWaQ3V? fҡmi;Y柈fvzQ%Q>4mFkzN -@{OiYsu16ʹNsk}ytӇZ|fQY^C1-fyJGҴ#zILS:3ޏiOhSs  ^BNx6[ϰrlN\_RAop90FmHuќ#()W@ ϥ0i+$W4>NqH7[ց<] \m+ @"phǸd!Gp >Aα&%`a] 2xxP:s'>ilU]IrqZWg3[Mh<0ӓ-tzS`].  <],e"@-C~ + 4KvOAYꇇ˒}H`gh!7N@/ ZGOdf)ɬs˰9/pF2Ǻn9][ TCy{FkOʃd8OcK(16:!.-|@z9-kt<C$Y+`ލLj&FOtA}B62RPa"@uBQs0򙝣%Pʣ0=(d7f}?C$y# (A0z oӐRkm~ifȉρQzȝsp2B!l( +Nxdқ UuB|}y0!֣%Ej%ojk1HDOG帚,!긯:@U2Ti7x +5*7FrT4NŝAh#Cs} +T4`9d`?KCbJX68] qfQ DQc]C@xE3D?Er$0P#w];|Ҡݾh' +93ctB4j}Hj;T.M.(#)ᓸ?y +tċޒQ'ۗѓ/4$g]ݺ~Kb;z͓r0c.f9e(t=F^@k^d +W&b*ᆢ6n-5ѥ(8̈́a7nzVn4_N<**$/%f|+˺# +0 `>vi-N$|\KQ& +vWY+\~M+ -/ O)5m +͙:Q^u%EuZb-y7$rs5"EyW[z_wO98q;LRC܍y>/73 8~New'dI4/R@%iji`o- {zL9|9S,jqkՎa3쏙S&Qf68C%1 oIdrݜm*n]R0*-7pWl0kGņM(A,_+MVlvss34v@~*hQ} Jm`J,ժS|d/k;Fd3^ד#qP7B8Ů@.D}YrUenax%C/;8Iq SJ^ ށ-SY@*s HH.30 p=*"$;jRAׁ٘Ct XLg@U297"< l҉w +qG4&'(ǜZ~+:,Nb8p"VATQNb`Xc| +OnĜ@)2'rx + zN! ӽDs3m3y9汕 EvRid:6s K*K0ܸ!0nt,Rz?ĵ<%f%eVBL_Lk3e x s'K3IWM۲4(KչR#g@3B;`Ƃ& 9#^u~,& +&#Mt5FPD(\Y6p0ơ$PF@Ћtm<y*~moaENy6c% 3xPnqi P8{"г9O\>؛*~C.%ŒO7,vd04bM1@[;Z7[L0@JAe_y)c8O\!R&3:Aұ]"ձ~Il'@T ؗ\7 FWAޠHS/+X~PӋA6 IUgR5hԔrvp +CEfbȜ;m*'ȦYJgg0cFWP`y@c(!RcyPu}6\|'^Xf)8JHI u? +Q1@* :=2|aҍo dC"jT1n0JnNˆ< A ;c4hH wANLRHN qHŅ6xvc6Qw%b$)!5< ᡓAeniuX9Q̓qXh.ߧ7Mdl; Ua5sqj$kbzj>Q} }B/ɅG0/Hj+qy;r,ɜA YhK D%׹*Ohí=fUN7TZɱ'q3'{&ܒ}wC {nE7Ce8 zQkσ*'8G6K"b"ж|:5(XQ/LgI8rnB/[TK\U>?wiЮDuI@m'4,Yj{R,.csC + 󖓨ݛ$&Ŀ-H>H(̵W'-תW"$`ӛ(%˱9SJJ(C*(hbxfΣ7vݞ{'ǞĽhS9IyĿ~m&{Il6|̶SSL<(L>r + R8J\u0A|F=)@Sh{."~ɓirDf#9BDHPΙ~Eh݆`KD -?9%0o!.\VF˜8v P=kl+DTy.' b CpI/$m~;Op J >cl %z?jFP:?:XwՙLJ[d~H +YQܙr5j]*b?v 8nV.bho5h-fA_BKn"ea>SZȹPfe,7l /5YGUM< Y%? _lL. +Ֆ>1gsJ@1gsN?"c̟38"}fΆV2Y TU׉5*bGuvbg +@kA*n2T;#[ejg$딲騶rU-I)eӏ:j̛iôy+wfM_'YM = m@ܶi =Q1Qwq +W,@"CJX.]RwCoF|M +[pFR P " kmvE 1kb5АFi|"L:>ܠ74\-–qGv1p'/S#GBX W%j/2]} +M跜3-e_NȗJEgϧQԁ! +][\D|_iy/4M +*œ~sЄe"R) x)TtMgLGӿ*Z`g;MQyL&f[$*d8+d*^IMsk4DA إ9:#7YK?U#д&C7ut696wv uOaGIuM'#'|z||Ms7||Ms6h'cH(;:lr*m`VǠI3E-i+?myuq%rUl(Bj߹-GwknWP5 VBVX9`h8hZ5,0WsԒf;7ΐ׹亵ay~k0!wl-?*F*g^SgBTkF8ލgs#Up_%C@?}~t@'c뱓9 OMPGY U76o_7VwC]@flS'!2a&U 8;gҦXQp~hz*.tGIZ{}W* `)% ^ t<2Kυ`:c#8Sc`(twl$l%lcǥLe $4RC +BQ @+. R.H43j}r\t.y-aAd:WMTRt Y/A<v$^t0n&âM(!!V's4{lFM̻r\ڎB:)Dڂ1ƳWƝVInXo@GB\:H%AV&MsC&as! HVp lc/?.PٳZ-A UC]bi5}?iTvֈW@Dֺ"qS]vn 6:^Ⱦ7>G ={h¨v33-j7n2 KQErq6%򳀽dkgi6S]Rj,]pi@b͡G~F|-T[TSWoZK#^[Zs) Oi|(2ܠG'pYB}l*9fFCS* + /Sd<*./:h[(s򗽃?*Í$;a: +ucM5`mLzV5CEAF/=pQB;y8 X5\`مlB % rC(? szן@U9%Ue샒vV礲sN礲~?}IexiU~NRjK'_yjCuXX({sOy)T y%&aM'ˬ$,Vڧ4+ D|<83"_&n7|%&J\'Vzs-WB3OlniaFq~Dzu$S'n}䕛豞=潶1!/nЪ8wZ}+ %9<ړk͇o a= qUGaϜ]r~ӔJ:Up +]+˵ꮽm~zitg`8?FE8kR6r{gw_"6$ȗtRil rWjv/bjdj~Gi~& Ėu4e5#j/_ĉS90I>%_Lid}09یC9-NDP&,c1Y#^␯ 섞geOaDM{_VTY4ش5s**.>&SvtF= r`=K<0bobRZ/ߊ|k'7go2cd/py9nZiw"Sx{y)6")(@= fRÝ)7$ǚQtkOz bDP&vw@T}[jjd.ߠeND 0dc an0Mqúnff.ñ `G80(#%IbH+#jR1)%R\v +{:ddvs AO URzQ{r=^%G=q6eZǩ(e tC-HZ?6 +SqD9O0 =}D֋o*Ͱ`І.'~%H@V5Xa{\@VlNEUGg%$&9QJՌ#C$#[+!f yDS,m%p]sl 7"Rߴ9ޱN/Γ{hW{8[c>ߟ=%th/S3.;RI{,s~BŞ!zfSdWi}Rmݳ^:x0mj2\C+@3pMxUN#55Q}"<|uX_v\l-V"ޏ-vxJ tt &zmF652T!9`k $RS&$?X3~ ׇsk&{<Ȗ*"˜j`G}hTEr>?KrxD4(9o;uV*5oVaJ''طJ|F֪;e:c֮{eLb'0i Fte[dFVGeR1"BnWBBL0Ȕdp(8Sܰ5mLyTwJ_P=_]@i/eXjj>vj&vbj^9~'_DV˵u8v4Ѩ3Z]PU +0~UK*!߷U66b֣N2G/eKZDCFG5>r0YS.UGvѾH<- +p@\-60"Po`hb\%Yʃځ]l[IZ +I .蜼+,g)U(7P'^nU>˘]n0i!E|)St^V0.Öw3ᯱ$ pgVl+DžbMl?.Ù*۝B8r݅=zjM%Zy-'I#3x4½`b]5φBM=Pnֆ>xnQL*=Q9X놝oJ7@eZp9$vz ++ҤM{re^^1QgY3{rD?|!swc"ܕ11ګ ƝD_9C֔~y +;wfW:?8gnޘZ(eCҘ,)Y2 ۠Fn͆._jdA;9Xnreyz/Aِw-vfaR銰X{25y/cs~ty5v,^tsB於 2gZ)o?яa>NWpfң Ծ5[ykLR>!Y [U)] uf PH_?{(ن\L>(Sqۮ2("S7q-\RBGyRs)_p{x~SH QW>[((ƒmPPق%t +JAk^dž[A[uYUQQAK{&L}a1wRnl]}:vCme̫Fէ个9 DDzK*g:kn?J *r3|y/ɺ"9T*<ۮ,y) CHZ=&{-O+:;ȐxHtQc ,4%E1 ʜE5q~O%ʆ:}kvH|1^Y[:PunˏR$YT&p꯶ѳOa23 uWB%9=O_Q^˄Ce7%l<4@MaCY Ea1 NFM* ]*Vzg59Y ++r_ UhnMOXXRet^b[\1AJ]ډE?uixIY!6/ H" KOb 5߷zzpªJ@q(D)}DuݦT̙'Twzz/$i[DT2lDq!-TKDL{[1/Cq*ևc|ӁIY=a 2"S  'SӚn +\(}A:2ġ21mFLspil=6R~⺝@ѓƶMZZxɒڽ + 6Ȥ@>A/͸Yh㲰QT6;;aR/t3vvq3d淳flN6k!m:'+?VQXNN-'&mmO-'k_@ώG$m4m=Q-|i1%v[F(~-'2r[qrOV?Ӛm :Zw۲ja,:m[pOL[Гb[-'&dۢ(:'nի\_Xc'j` H97To U[{vn'm 7 |}1sw`&g;!H`n9{/'x|$q?a*l f ]-PPzd_'NU;'7G6c_ D@34&uC_řb&-a4R\Fx󲓀x'ܰ +; ~gI+;g]I蘶w*{ +endstream endobj 96 0 obj <>stream +VAWҷ&J:%%qML͡ L#4Р\fFR*NL-ϊx*G $Gny 9Wvn9)~57rz&|M[Xޛ׈ДSSzqZ2᪜vNF#__zSzEk(w=Ŷ],z:2Y]꼘rnhCs(c.n +WOl>QJU (4m)f$7ܳr2 +EEձf޹5ޡS1M7xsŭ}_pwux`H9Tj9|(D6Gֶ#.h]HjFl&iHr8$=Q5YܕYZ}Ћ@d<$rjzyAatbښ0n㆑n8{JJfqc중ckp'Cΰ!H?dTX3 LoZAn};[F < 9N +[@LXڠ8g7*tźq`"(U&v#J;Dq\J62ln jᆭ 0o$٘Ž$߬~H޼̬[uU#Dug ډg'WC6`R*% Ne|X. +8 b]{{rP㑂zO|A򂎤嗦{^<#_e8<0*r){ rc*j+xuBOoPymj ȮKJgiv 2@,U7T2oc]\I8zDBBtaA#L<P@ Q!Qtɬ,Z <Yt:IP{G׋_Pu*hA[ݹϝnLUrTGJ4@E"`(fۀ߅G kL3Rd4q tȋ ZӚpqXㄡU +o;'ơ/c֢>@k';x<rǃ&ZpۺAIBJ0~%v(ߖC(=rͽGI-}];Q{+pG,H|Sx*N?`wH6CbB? c|u^փm_y1q)pn{[I4k|U8Pupwax}l (4y#Cɒ;.f}P1?Bv;/TBxη8G\)UasZĕ! YT]veq[ci]e~@wCQ:XnAn-hW7?K(ہy έT 1MXe/f'6[7޽@.@% *<,cS&Sրߐhb"/mTƹwoe/Z#0r$Æ;|1R 2et醴ƥiˆx'um [x@i m `M0.qny6gbX6Y{yY0p}!8(I3t5⭜)Qm#VG+] N Ϥ5 +U܏s9-@5!:ϭp\f:D)J"YVǎض1r+;xAW,y- 9ˍ4h79p;&;le pٯ+Rmd؊$EeYֺ5sI1$2$4Ѐ]yF3QA\): g?f7zN"ߙF\k^_lo!XXwrۻxbGdI]62ƉCH5=ؖ=4-_꾳+m3?Er@lrhrE1bZi}}qiժU5k, +k#IL-O=B *(ir9#JK蠏diQ,ŧ1䓊@h1'yzNPFw,>mu%5(bW!5UI9ȯ=3AR({4oiFwְ~_twx}Ŏ }颣n~|T(|<+$ 'wK|CaBƳnw6/!C];EXG Ts8Az/l%Vzbs}~+j ?sӌkQMwlL%aKzD  +XcU88"$!? EI8r&\,Q$UcO(J2F?i/{(Gzu!}}d#B`7,Rav"(`Y4f@Ú#{i̔:Vf# _"<\U;VH\9~CƢ׮)\UC#zfCZ;1wxq L +'7-:N;솢j1 6&0+'Zt 4a{'ba0 [MZ2` +Zj~V{ vW }8Q5GX"lH\iG8O!MAB /$u9X%w/~bqڞ%q"0gO\:$>SYCWBLM巺d]_uY~~.T:e'S۠PBٔ|wpq C\G(cW`k] o=GszIxUr'fIpLDHP2hifv`l lo;;أoʸvP')J#)_,NȋP:fG3ʂe$C0r1H߉ J,*neQkS8fFV3Ҩ"$#|vrĒ: +h?Ƃ$Ikmx༜3<;ŒtB q*t~4NS@fPc \ی\%I~CnfA20(pf0߬tD?LQ(CR|u Erh,/auMaIuQgܧa)-6'/!G`5alA\[+iG/xl >]y`Y8~9R#f1^ӏrub X[w ݭ)*ׅ//?.+;ZЅw٬(.cR &gW9tW)$}w=75woJ3~iG*< UQ=|W\.v1x7kꮂ"=VH8&;U1!~Qh(}b K9x S3SAA +?>ȩ SmDNJX[+ OnPgSR=TL hk T)Rs&0X,^x|?KQ~w\#qeZIkb=%w|j Kb:/`4*o3 +hLƢS?ƌE :hYtAK~v7,F,""7]O3 Kl, @9xCjh7ye+LVE4_F9(-釽$W̃ |U@^C0er_4  +x=eQ^#,ɛZ؀Ls><СA4=e"; +\ 5ØcAÂdeX J{ +(katevhak]E.Dit9DWMJGN3.%W"קbICʫ\[f|[$=b |[8 +Zno_u7L} 贘2?Fw`C85s 1`0\߂+еW9C5?oRol৕,ݙmEfc%}K}nm匯b[Knϫ.wšPQ΀&#&O+;cg[7֝4˒'GQ@-4iY S>Đ4j |lbq uD)콣uJ0s,M<82` ˟EJ&'s vC!de^>M7YՠƐyU\h DBr]sOAZ-(ԓp]6N`S@܋1՗1G%i[R[ .8ٺJT"EVgHbG֒H9|p`<݃\ztGՈݫPgH53P7VC59T cW('d- Ri)ֽ>25>– ANE >vEEBk0N;P$f?;"ao?F$ Bo9× lR5 cEĽ:~*Ҷ #2 +xEl RypoM.'ppq]2qp7;Wlr)~34/BHD;ݹ0y'5;=AXz'F 'bB"O!}*9G&auMbdFTⲖZrF$tEL&h{t44@[MHlQ$UFT-ҺVVnip>]Ӯq߲3.]ۭ%#@9[Z +hxÒr RLiAlc5ڛOOqD6YQx NV`\\吳e" d1o$ɸOO"`.\7aKW&BMy!Ǎaa~v6jVINi#3ؚ?-BmM 9V-͌N@+P`mZ0~ai'Ȉ`jG)3ysE_%Jy}5t >P^`  ٯ O08;;;JIh$}<7G8=XsKrc2r-*F/* n{gɧϕ'J%Wf&NYd?ȹU7a|]2|~9¾n/cu6c{ؤL-$lZ>lh2M ԘINc[kƥ6o@R 炞&֔)Źp@oEaYPϯOQG<홁͟VG1Decޠ?mN.!9c{j2li rxxLv0]ɔ'쀻ὠlW2rh%C a-K[MLV⳷Ҙj+K}I+8&Z)x1N#&I` L/yP{D=91QPO-\ lܷ+EIIJ* C?J?qcÛ"'̶OQ=OQ'bF5ՂF7l P#SPӂ1ErO!K# j1X`@ +E#GRtgĶiR*waVϑC=-},}wptkludBB +2nODv."$4#kXw^.O~O4evuOh G'هlCKcG͸CI#P +*F $= gj5-wh֪DI +SE̞Ao`e qII(IE?[P`Oj*Po%Rw~wPۋ.`lfڷkծ͋tXYxyVQ2uO9c=|;rF#?14=y,,sa ,(y źͮ'#2衵?cGXb#&gNvDq3x.'yleV/ephhtuNi.| ɦb#h dHu) !07bl@%:OrYx|7e鬄lLZ|<9$'vc|k  `Z/ +Uw陟 +Tg#))m(GQzOhxr"?C'.#A k5E_/߱Dbbq:)lȉ)DQpxZ)Oi3* T`/u.1_ \tK7[.O坍*=cm!}z1M^e MxqNh^H{Bb/4?T#K&nwθmwqlf̤p:XKfs"3c/d}&Y>?B[cҫC:YX󒻞?,3^&A^\Krjg_WcZ)x9O=/o^ĿM3^Vɀ湊_ղz5o{ݺtz}\]Z Wۦ{Yy='9; V_FUW#߽pgF=A{Qokj2tFxo8 +2Cu}^?j]i] Af0oeq k'_f/˷m=N]j<Չ|OzjKΛhuvO!hr5ݘ'bmuyܺˉ&W?<SE}Wv&_0nC,ǻQH|Mg?Elqq.Nvkkx +uk^XFl{$}܏ Pn6b+ZjKYuv37r 'B44l~ݨ2ia:-+oUCHڍ?WrN.Br6$_ +/}H|v +Nk&_dr~`FpI|σW VeVK*܉.n 6 .;9Y\GW|dŌ|4ig_0 +:dE}7pnf:sI!o䜽${>.~4~S,ً|wU-{]u'E[5jֽg6A>篍\3L?W贅H:,|J>k\i!lX81vPux}:?1yqACN'|J2oI)"aL &#ʤ"_jhQ +FT%;#v}1ޞ+Bz/`Tz29Gcb>K Pv>t_Z}Y~bK:_VŸcr##Iv6mqBǛN=욲; IgoTXj;"qtU꼐kRiL羄ưN3|+~ǝ5lp؂xϿ}9%6' +w}r"7{{5} +njX&z̶m4'AJNG[XExCZ=GVGFxC 4/LA 8-m6e{wU%} 8x#?ڮN{<w1v>N4?^!,tH9B1v<v+F?ؙa%·LМ~Ge@ D":ߜK"w'|p7 T?>3 .C  + H5l/[[=d./G"3?˷omы3~?"γ鸡~"!ĻN +&k:~69.[~M~ZV5zջTV~;>Y/S˯A{sv>VFvWm?!_)wn }sEq!~)ڽ-~XFR̬ -_[y=?18g.l{9)o.!AԄB_(#WV0[ Pt#O +l_R9:IzĂO >q: + BNƄ2՗n7o ʇ$1t +CV> T˰(fȇY`<YI ~*jDɏG +Ģbj9dyJ%WH;Wd `2](@6YX Ƹ=ƃ'I%ԡhS:l)^_Ppm.oPsϭP*M}W:WWv_>K/2|9]`q=jVVӖ"xC;䱾} ^1U(:Jt0`x 9~,N]=+5"6p +_ o~1!qX};)=VV2au+$Xf*e !mMm*0s,j`WfI?Z[?TE8\4 o=C,ÃHtmExͳ"Mȱqy8БDCF㊐bv]D]MExmEDf}usw=[qܓĹVPƘ`pEt ^B"{~1 +4LðH/X 5N7nɍ)=yƣAԑ3'[[|JF:oJeD -/;l|+E~MȥxWܭ5m>* o*$ǕPԫe[8 .>$ @*`;A>/=aH]N+)ɦӱL4YIM|:5ǁt Ð +9{`Tu5kk'hj5O1h -*!Nt߀‹x 0iTdiby^)V!JНU|NjFe5F~Fy`W(H+B;pll6k}*~4)ʍ&%ewg 3Qkr&asY&z+}xo͆*h\C! +s q3i Xa/igRedi͡P,gwǨaGN(}ڂ ^ -0^o[NPmIP§!~tp.nvG7RF ԬJRAش#/hg5 6LFq'2SGZ܉(i[W$lB0/ +UȰ{N&! eI< $h'AfeMJ0 * )8eE%mw(!Yx^)J_: +jb%8!%#[np#^ATVS:7Dj GjhpFQ|v7pqdi ۓz.A=W /"70l7NC5I\'F|R.ot4B?:[\>M9G~Hچ6J¶W$A6~ ^C6`$H_0UDq[Y3);òj/ȈP 6*hƨ'ƗYՔ4e! 2S>,iOiǁ \z +g&9VtPjARܥK{ҋ4ӕzySyK?HGm`bRɓ#]FĴʑ$RȐw%)>17C=m$7At DLincWwL!eܚCE=˦:ĺQ(n&< NyK(7׉C( $Ы v3`U_ +UIJJan{Klo.NoY$/+c0}b< Ϡ:ZP5`BFN'ڔۃ|.ퟍ@btTzBt> ~4 {K26u h27^2Ve< _t9L#l,93#?b#_(ĚnQT:CMSBd)T^Wl E/p ]u_e5 +gPo{Zh)΃n[k`%Q^!Ճɓwah\Y:zZԽDҘb{%S +m͒Zچe$7T<,n/}N[gQ[4"G®yp,jA|IZ&8N -N $es.gPܧхAnA9Ί8EܽSUF< @`h1q &{>3d4cN}WOYOG &g >@;8,C(͡ar2B"RXۇ }hr G\pSEB"pWȡSO!@򕞠 fhNOq4ΜT e.`)4MQ4`0(cmnZlX3 (ǝ(#ʸgNKS*WT5BMTk]Ź澢Na(G+ %+oc|0hHBQa+$BP<9!(?84'k &uaXXZ3!өBb-R0V u` +4@M+&o!}]9JVgd[Y&y(x)/c9R MBχ5% SRPl[i4 Xͪ۝aqBlZ9򀝨v155EVnE4|h(t DM(of{ztp @U=YƢ z>30Jy:aa=(axeQ咤eXg^$zh:|gKyya ,`A;@9,iJi.%k%*MpRLā +٨I nFii t{DfIG_DF,ĉDfuL'iL 5v:utWủlۑ5Z!u>FW*o7,HNK'v'o*ut^p ]tjDGu ]-[Uw=WQ/ H.]yU–31/Ʈxz]%k "MN` VIVHY蕁:?7+n)qLGBj2e,M2fʸ[7mJƽLS+9 Ǒ(2->m1}xHA( W 4S 4C`S;{rwA[XI<> U6jW6 B-:Q_QX%Df6ԥWơ[sGT\`/AU ȣ`Fg6-5Aʱ^{8\mReN_ab>ҏ4ֈ-OH;[3G"C5x`pH_r̿%{910?B c{xytg&5+ _uYGDfm L g'5v.1ˆj;Wђ +k@` sβJ,3j+5&ˠM"JLj؆MŠ2rH79WY WLo0(jj҉\akUwi` E}Z&V(+X_ۘHb C( ZxZHz  A /:dp1JmǰlқllTGp>DJ_VsN&= <.@eXꗡ~t4E_v[Sdqqiʯ/)ن9b$88MjiZB>kşvn'y;+63Ryb&땋I׏C|ğQ.]w hٻ@nX2Mz*}Z&!|ZVYӢB|g|5$T&M)lRJ1/.Wrl:}Yq~Wu2KN;~"y <9L.tk[yÀؘC5!C!Fi0q%Y|ZZFrgZMrzHg;Vנ+w*jc% `) m8U* coWj}r7>%_B;6MŁBPq^i&KjB }նV|лPo>J> + w9} Рݱc0%ÚJ-*f^ +KV꒤YZ_m׋Xh|fplIi,G<8Z=Q@֊$Y2 Q"w,/TxX@yX>}(фdn +C)񥭚1]^?/OܾFPֿ6'> D'"&4yP\기x/IlίF$rl$Sqr˓ Q8ux$X$Fo֞Glh|'qJu0 ’;B^O)L5}8BLMRRvD5Jd8u;YPA?Ҫq02gu RTO4Nkn&PEsBESYЌT$Īzۘp!rx +I iA;{(B?7'l W.1b+tš{i$O5T]֬Ц;V?k,IW?hy[A%F S$aǯ~7]"? c^Ȣ*޺6AYbx4Kp|2_U>ELCJY;<~'Vc6m׫|2[ܝ~cgq{Lq:Q=ϓ{n.yo@Xoe]qUfHcyYe.uaHRtAjΓHpG +a F_|qE,WgBD1/Gu咞-QL|x 6Tl~J-,?@Aa.)4g ">_0+|c p$W߀5NVCPGŐH*vox S!c$HVCc( W A +XGOEwZ@5VڲO$/aCWNl?upmSbaq.ٞ[Cz⿐a,^Rx-9X2*`_q#gբ?^`HzC8WɎ)bpTvGLl5B1x +DQM5L{y"gr/% A VNH.m>lR8[PFv_ڻ\ vIVH]v5-%4Xfɇ %ivO@gQ4*I4Js8`rـzɠ "iO ːޘI(GȋrN݈ZXǓ|^WleQ?V_^۝Zjq%&qq ٢Z eKs 4e6l^'*{zM/̲?9EBǺ)ӖP:9&@yuv6562i)Z/odGMDɫ'M(8@YI"9l"QD0l%$)MDuL"W->?<]1/W⍰|vI+ ^%vMqw21& f@N3GF&̳&ɥZy n>$Մp$MEHsyV\D1 "SI`u04(.u .s1. xM:|4\Tl$(E"Fv"Sl9 PW/ȹfw7ο$e#A\m%M>>E{WV*9!B#5Lh 6IB8X3U.*0^&7i:h:[+;SL- uΑb 8ҭqĝi ҧfm슐y Q*yasG, g`6;: 3l@@a`O3vi3&)S}ϑ|Ho3|/=ɽO,$ՓOO0 z] ⑆6;܈fciч@2*TF@{ӓP"+=nD ]wŷHDW#)V_gN^;+E@KwۗN8hMDNX3wۗHը߻% 0d=[s G6X:(`Iϓv.BݏlUdcSr%Q&+)(XSiXAXC_NYם'Emg2y$/bG,bi xIQ>؎F6EU#YTOyonG. x; d!@>o*_:%s#>e( 'Ixm,ɿH/84le7EҤ%$ݛհP-D\_`F ?gu±HMWq#$?1@Lߠt4[DIGH qQA> +IRckШ.dߴ(ݫ8Zˠ,ŕEἘR8@;! [VƳs +O9v )3\SS> +8$[I4ꡙ\nu-E+m2 + 2]f2W0[d tEG-d} @4 ĵIsElt(Wk8ɶLM`v!A;e?^CwFMKLDŴH\#-4M8,^,R{6+PZ}o.028= 3b:u,v,+>|1 fc؝[grv ׈i`ǐcx7$ɘglBh`ODB!}y0=n):lq5=RWnTV:EWm^?e~eY=*Fg\p{dS~5Mf}0IFl)_rn+Bl>TK@BvC0Bb9= rl۟ZPt}J8t,!2m:L4Q(0L2pan;zPJ0B Xi?zEC 쬂#SPf8 u5K2v>',~-)Yف YYAl(W;U ȍ1ۃ%?u+6om衱ƺ'r. 4?~fhazhuV<EGOcXHؘ:Z>#;%UTr[c"q{*Z%!=}[2䩑-!_.s]o-隟 .mi y&'_J1Qʛ0agGq: II{dܣCkB:_W<]kA@j#G:Vocطf|2>M:B'WT3LV}y4q["~s̤j=|߃gV[!xc[ûDtvL\:ZL=ꎺ7LNHNIe]0 jת52|MeW^ +4 dmL$$s_._Vgz jerk$uDk&Y SI+\|? AIatnܜK[#x-9>ɒbirgG{*7{V}v^g»L b u5= 5ګs1Q |8qƥD#[uZeOӑ{[sh/ȿn;BUlJ!M__ʾ_>3qrKwk>ɍb/iƽE + Zl'%dg11WǏ&I))}cs?&]vm==TN'D78:q=|\g:ݫV`p'k2Olqp9 N'Mu5Ǟv1W7\nr'gag8y[5#X`zm4zֹմ2X):H(lwi9.tpU8'?m({vD&QMܤ޸p-''o-i,}9,ϫ`{+0-Ӥ|%?Y o\彂6 ρ'b7gaE>},ՂW+tH?=,1d|9O,l=/MO?w1d_0mdxq{Ȇbb-5f[辙÷YJuRES'wB*<U:0~VYZE5q3J;!Z;4UY)wj̜o?Ov;O]$|^=m=H/LcX Ni W~Azү'Nj2XZO8LzT)=/N:'VOqI䏎^)Tu%҉z;,svǾdZ_kv~&$Ξe FdzIuODO#4ˌ7X^[ +#ozy+ysso^^ڭ\ƈgsM$\nNjh{nNfwʿ8_oy=C>?_ݻG_ ͅ567.\/ׯvn>O#;~Y]:a4pumVϫo!1řLsk_vIaYZ|ZKk[r4c}>v\l3!VZj~8'3s3R'fVijguz9ep?=ϺZ=LZP,5Ds~#Sdz&i0\4Z.;)m|dRdPҽlc~߃+!͟/a%C^iubV¢̍0>jX@-aX jQWg@֬{#m$ H¨S׊p%Q\ +|3ej54q*Z&ff=T-:荹r;ݶ7n1#!f'S +(n0$%G/"Gj d1 E߈gaX r_-a%-a%ݩ2Sv5-۸s[ ʰ^t=*t+/uډ(6ހ7clr_OJYev8v`5WgchaȈN׏Gk[{LOM :k~q&>[ӛwb9[]>e1]K$PQiPP^ +lɧrd F6r +s{wyR\yУcۡvMbډ5Sm];6[S>yv*+LKM2LG)Zd #K4h, |M8یvpAyuV 7c%=j*M"-".l`A*E׺Fm Vκ{@!/z;81hf US>Sfe +Lh iAF-tf.[c!`Р%ڈnO,͌rL!`Mrt{F\߽/.c#4wݫ럨zEVEa(ؐa&E$HQ r]9>6 b"haCJQA'֘|QP:t1Y狐5v5uNTmxWk>[׋y7bsGͱR^c # ̑3 q] ώh́ΰac5X +b#Q5rE(W3Aﰝ,s}䑿ً\{:Qlb) Asa?M+r=ÈYZ//0Vyik#T^9 Z q;u1Er=M.iڀ69p^~BؒOiVL +x2zwa dq.YefSںYI^sM 푄qN^Ze +!"YgBw È9 )L,36c,{8VĆZŬaqȦjಌ`U? +B*`:b6j͌9LuM~]֌0QCRs(p=aMqт;BsI<\  +:s>9(*vunPb9 Dɾ7{tlq15vZRj~^/&Y>*KG~p」l?$zAT:>y;c~Pq%ȟ(Fj%b k?_&J;L$ugGU?ƵN;H. '.`^7P-KVI{}I{^(2{/ʿFԁzpϜyEڠ?VXE΁*3:̔([EۆIt$ 0O\iqGYũTU8яimqb "LofJ?1=BkB8)=ey8%qH h +rC GȠ/D޻@Žr]AϜ-X1-_bE_q46XN_I !+m +/c I4%uͿ +cX-\a-˶ͻWW+(]ߞ$eS{ߊrDpp){Ʊ3 I, ~JzQ" }IcPݣ4VB;NO~jeU˂32^C'=Ony.}U^ f\d9+Kr:*n4IJBzEbZu˭IQ`;LZkdM:gf9 +o"LnĦ6W@lɇBwEXa +X-+|Mϋ xɇoÏB]hAoe$rp:wy U\T=Rђ})i߀lCZ X>.'%$LLZB}J^$ভ!!H@^9:qԚŠǡ[TkQ-.oӤm%e$([9ҥCEFS|.N~+I4v[_w9cѦA>+.9˹bmMAb;2_zcN]l٬Ȯ=6%8w:P_xg'=o,;OO9c Y%%n6_=O#,N~юKl~/xOs+_Ր D;|ݨf5#serp:B@ߥߠB zV^堠wќS!TVҰ,*\~"Ύ\ m+v fȱqjDJ ߉ibv1J;ā1[ w;i [BЇY1\;.(r+/ݝ~T~Vb&G #3m)({$s)\-"jaB*ɾ_>p~Wsе7nWZ8eE>i3} 7hU),BLy'smiibd ܼ˯2[!`v}\X Ո|1#0Gt]C +JCiVXqT:O }J^IA ?# k? rSU`':IA ,1J)_?$h!(fl 4{O.9ή؞_T\7S;惠V{Vn%Αz7͞).h`%ks ́!}WZ_JZL)f{ji1ppqv}PcczS 88 M, ?׬e3 +pNW;=M;HЛSfD7c=lFP9$5A.^/2鄕5WD}8wL(H8=NzCzhxU[XVi|YyYLzHN1'ff{[ x'T2F-iCсJh2y@eo +tN[]{UPqp +wEqzݕ)okԽȽ[[+B:>GK聾%YQӫ7jcPdg&T(:dS^Xϰ5dǭeȢ? AYX% {0; s]ڕSC˥YRP8cmu' irx" +I@=CMr쉙K[.B>` {s5tAa*׌KVp\<}F rzW/A;n =~\ +}T^Vل2z"hX2xןĠH#}SPx8o"8`1% z/ADI{ 0T_Z˪]'AWJkG8NQ N.5 .]fLf|+Ku1hߤτX/*RU _D4ڠ kt艾ZU&˒Q:[ų .M#P_^&j4`}ySG鷒]2ʥk:lDWmgFULQ Pv9H4y gz.#q6$p䮆y8TmίRhUʧụ} af9)Rۓg 6/B"E7[/ȾE) V@.u +ou:_Qqpƽ>1X]TkFZ +a6(/_OC]g̴c">Jk,DkrKFq)ReMV+G,1znIkE`aB!ݥؚKd H8,,R3iÖE%f"*% S%D`~3RE+8tRkG B`50 V>p ɵɁV +FkTT9lO6wG ~9,1(,nҢRw @6/G/~5RnQ}݆ j(WhmiE68<$0=aw4nmܩ㗻ʼ@(Jm8[iX0(ߦ[l}1;ɂց ' + +vt{þV@\ &v_'rBTdžaBɽay\PG'c pOQ T ZA#\3ACNjZGW7(,h nϧ"ZQnm+P]%疨ni H%QJ16|}),^>f)JwR_8n]غVVW4'X^wzOY̱Zk];1znϫ(<'=Ys\a|EI F<`rA.QigGAvՆi{:`ҩ wSSZ/7Yh`g4ie%:!S@t(J(nqH]M;ӷ\҅«wgˉo3y/ƕQt\jh9!VKE[v9vi bR:MtW#gnGGGF `gঌU'<(h鷐+6Z\D2U(̦!Ы&D>K +Id(CUC@PpEy!;Jidس1wܑaM|~R}i9f]GդɓW%UMi>Q4x}9/ZDmJ2V?Q?c33 +'*/荠Z'΁ZRDUj瑗Hl6%n$Ag + С`ʆYYxn2c:ju#ҤTrA\+YIO&|?|n*|}iUR>GJ%d\f^͔pw{aݻowfW)U6g51EhˆlnYx +(еy?NzB4QKmf0z˭F4^Yu\κH1b+ѿYӊDZPtJiPtnLjXKVaߦT?`y*_:LN:GMS3߷^搯O{.#\u".RUaV$` "aL$Jyx)wHy{ :`˨'$2>1ys-3]'Hb4NQ6(^GbTNK(ElmT+&TtٔwOZ`sM˜j|4*kys92,Bz(ry(~\sJw +oB}X l$U[Ljn=wR~jctf5Arw~ ACCQ +"?abpa&,j>N\z'L|֌a;Ӳhұg-͎ͦKj7a"I䖣aϢnx֌^BHbQL/7~ +=!/+Ӛ]3ӋZf[nؿ44A Np~Գ,̇eџ&[-8,Bj +nqa@;" f⼜9We74H@7zclf0wq|hצvmc0Z2 fyy(UX24qҋ·U."_Mp@\8};$.{p@E^at_Ԋ4sp.83?Ju双;s~w>k|w{U?7ەƏf(?7̆3o!<(5(Y%.YR%twWGtِx/I#$m$4c|{4'hD"+ͯ1~b7iK2j0idYl 4G0|͖O{GCWo >bA|D[ͯ Gj*LaC +V_Kі,vt&0P12 f'$v!P<IǢ62 W>zN +hDc%t0Xʾig6C= 묆Y78{rSw9gO2B8rpo3)fYtS*N|yzz{ݛ"//xQ,ȗ?i_(ǝdt%U:ZR߭/ًnW\S'G mt<֣M[nt<_Lh&~8_ ]QgQMfgG|wt>=+T e?vu;({+óJ]>G}*/GH{엃ϣWVV I]ں}+-y8.&G({=")٤#zxiˣox[Ko]ܿd}Vدp#!|;'oQx笚(7kZk\q-FIVv8,vAuށ\C3N9s~vtKKmV7 R=.`KK=[ lZ9ei+ՑDi쐲EOPy^>HVW v ھ2gu!&lI8Z*X"=mQdRAENCx +Ob az=Odڲ8kB͌#F'l$C%ή@+X>4亲G̊θıAShiH͒9-,Bq/:'ǽxAw,S%2[jFG$6I-F~Oʖ;*[oo: ^>'d:%!JD H!;~ wue((>ڭݳ +bйgB&GgbPyJ}Ka{~{{o8?&n@r{'2ԩy PacJD >SJlk%-ċO_?mYQ9 e%1Q?:@KC}z;=&oßa=VoyZk/r]pM,c.PXKg{N :J'eȣ,O|jZO{Pz&~.5{.MSO l4]"Aؼ#N#nHgӤB 0:?$\ww[@u)9)N7eu)egpJ3GS7f1]LaXMZ9l +v hjvs<~A1Kog +6=QfRBJςt 5M?\S3҂BV)<8[l9h)0^GEV\Gm>x3W5iqtvm:kZxH^1*=Bov\gUP.Ƥ鼱y @̈́zqu'";}߬":|v5X[l"t]yA D]|w{.<|IzceNrA3;b|C<#0D#L==4ss0*LvJ2ÐVp>]yJ`1i:ʖKkIܦ^<Ґogv<ڃ{Q);ވ=ŶF0u{ +JJiqzfWbZVZjvIOɘYe(xPNHm7dSA_dsoR 7q;0*N,W`7~xQUS:>q)te|X{؊(˦!mhk܅Уlns'hoq?aJjE+AX;) 1cMwo+|HM,j8Wӫz8qjpDTP"߄>r+riҘڅnS gn~oYÙ DV8-j]ߊ(Vף.XIVI5)fQ@4K˛dk>!T P-a}b8hQ <B U+VtBۣt@vfAGj( Fq+J^h KhX?w1ڡÈZ54f~5]俽)` &ە@rCpfؼWv̓>3|AIg+R@'*M]Ʃ}`sa|>6'-W=G@a89g-L\^}+Ѝf9 +atcʏUΥWHh +:yנ8u_j+@oR\"%c V^6[ %!&$1mp):aNG;:+ HRiY5 9cZ%ЃT3pAC&,!P6Q樨xU6iN||Q(1UK@K5f:U>V75{[ܦ zV]8[ q3n[Q)|/'Z> #;j5 ̝~R)1-brkMEU + r.gctQӫ}QBջwIq%EcOmf Tb4Co1BG nqyn>jK;$%2V9R8gm'zc l! U +7`(t=&9 +=&{*4$氆S ZJX3hlŘQf-t"=Uw.{P}1xu0LQIm(];ޕ fmLTӔr[㬺Z>LjnG%2o>~l驠]/uC_Ѡ Q<,D9*]a]cȳ౏{GE +zJ/6X rcQx +QЗ|SފnB ݲyIa=cirD 9|-ڱ%<q3,@#A>o6ا}bd9*zHhBg_8 +aAQER}r-,$5gO}#f,sεtm [tpMS#&6 =b'RS!*9]{.r%B7'Fõ!׊w)L:byļ^uM!U MZhXDϋHяf#H'N_l9Xgkx>}'GsOz ňeNFֈ+9?J)[˙ϛȷ\$NJ?rl1=r O(O Kw"jKY!_kӂcόbf5뒸XjF|6IWm^=s/Cj'4Rp2O%/53)Ƌ39=m(DAnIg-eg,b$v0bV$d(; 6?W$|ެшqq w[~cu9tOo_J3qC: +7T$~#2Ta]tޟKwU{*~6H"HRzeޟ4\S +$#ʛzWc V21I:}c :j;SwK+AQtg^T~ +*No6A밚eyFq+HjISF:`o򭷷B~\+׊tuJ:qiV0LmHڐX +T6`!औk#Qm IȾ#IQJSOGAѩ2QTϬџ?.{ErY:h_7+̗f8g0LhBkDe'IRjaE +﫜tGtHr]lB/5ri@yuWڔV\Ya@3jijE8.ʭh@1M<ߺ?8xfqgYSc~vZ-@ 4u2F9ȋ-f+;QlZk 14]Qj^OF47镬(jY4eS&W^CއM3=.yß O!>0a#aZw:{8B$vaŁuC4O P'Gf%G9O` Ov!E*GwȳT*/*Yv6g[Zkҹ;cx ; +>ѿQ0tY.Ejn +װCJ[GH~Qy*"[`ҸFY^J{s{nOOcn)LYR??̝q`A~<xQm xՈMkfFL_.icђ6ZvQgmsQd_{YqT8m-e6;ۍ/HP"#`l)A'/ 8&TrEp)+wqXZa)IX] !!$E, +& 5S|PE9qziyj 6L~*4/b,LGCS 8˝KNS$AU(s$r-R =k~a +赉o#׊7e({ f0ZUrv&Tbc2{Mnd*[ B#́FPKD&\'>I\^Fj_}YŽUV\-|m^O xhqg&4 +ZA2wUɕ=_ynq-Nu:EY؇k8h+=jvZeb9c}G:v +A/nLCumqU;lflzU E+@&BXײX`Q}|_Ct5~\PH\p4-t&b}ɰܶa;Ϭ_;Ru0DF:˜m8+A졸_̑qZ>72>2zgLV63r>p,V<~39h%?}n&9=V}B#8o;ڧNok-"mA`4/Th& oĤn r-(%LYP۞\ )"{ +Wv rN)I۴l ~$!]z)_RnL;Dy"F0) V(',7;qoXp\M$~X3LH'{-> ]fCDEsD]utFa3DMӐ0DmŔM*"jIulHscD7^K$[P7^K$%dA7^K$L';Hڐ@'KJa0[LRjnwM"z!7wUmhb,\ +O@d%xw2,YQh]+ӆM7-&| IwjѲ)F>tg͢6鉞;a5Q3 |{BK3m{×у&q% ü~?z[3(9dEIAs0 M~l5 +oЦgNK^,u2)P("L%Ʊ TTJ)k7$SHMGbϡ+8P{s58 KDuMyNtۜ~ffNJFhX趾#V5Km'tӊͼ[P bTmLhRVFa/Mzb]#0VZhziC(~,K-R$d((5{u!s5dta[QfJ=#}|A^ǿ77Ҵ1 o.suې GU@n|M8[f8#0Ai fXT4;2}UK~pJg>KXZF95Oq-wxJKӼ' )V{(U/T +f:,f1.!x6/8p&܀Qn.hr0mZYtZ(ʐ+N6t՛qHp~Vv*0mtV(7Jbjl+׭iAq|1lc1‘2x 4{g\6z{aFOs?PѮLihR͉3kVjZ҉gI-_.5(+ +XX=*XHY}W~Ya}pU,j6HH@ =7v@D\& S3?:KqA',,L,`};(e+'VOlʿ} S|GNe&Iafn+߳7e*gϯ{?z;wI|˾=]y.>OOtQm0{&)ΪGT&8vOXkg)v=ݭDgHuD'/¡nO&AApFO7{Csv@TZ + Kۿj7t*(taZ?xxՃGvԊg75e0} +W|JyAЗ )q{%bq)Q Qqÿe[v˕:z Q$|пɝT +,m!c|&*=|Z%dkm4aIՙ,?eB?o w;I)<8ύw Ce~^s&;xnڍb}@`.C@ 0#ujv1͛gѼ_Z./]a~] F)ᇫ#OSlT~%>d!ʲ+dͤ>?6ԡו2 Ra컢3!Rwr7d|QRl`3.q6Bj3h&Ncfն贉P1t"@pu,Ȃ:ؙ? P:++yIeU3=:${EG>xƑhd@iMW Nqfؾ !1w0 +)eo;Jy*mLnJ%w<n&Ⲡ,ӹϠt8dLz7ʖ+y807Ӄ[[-K؁WCbkBR%6Q86j +("( @]-yu!M$zXM`3C7{vki„KHF2f~Z29 On !stɠkhzSbc:߲\! Wm*x@0 lo86$eDflqp٘"g$WmPF nj^D)jSyh,ų?o5n\T9fTǏvf3j|uK֒1gqtٸ])\I:0(G]tҏDQn?=W`.7tC(tmgݍ)I k}{R7 Q.X=B!$/Ѻfz{] +thhJR2w.0,;Ď?G'~)c p˪Qg4cJ;k-:+nO,jr`䐅R^<*4-(Կ+}͔i' oLIb.Z4l %j*OR*p`j^tm,jH=sax8gnH.PG\YV֜}_әOeoSmuc-aYil101*ZG}mmw +s9l ?&o͹g.Bu񁸪q4+Ĩ\ q&ϖba3~؟ae,p= &D^kӏ1\,cPo+*jRn/<.Ӝ\ks _7(,aC&rG:4iXG r0Hޛc\g<>N]+#ëv< U>J[qYB6mYCzc*ƣ|歊8B[87mz#-'YGTGWfWObm_D:&$LQڳ&oT+Cjׂ$5geMz9Q٪GV0}+Q̼>(OӣC: /M|X&Af(u~_҉)&[?ǓnGiv_ӹJ!pQ ^e>}u{ơ62ܨ A _l1\[BxvUm:-/n'cܠ]pi 5R\R.f͠0tn:Cho[*b^XBw>wBĢe% Lʰ_ t&j\0}ʃW0 +nZ.M]+cWh\9Wzs4U6G?% +AY +Jҳd_f2mL3j1 $zs˳쇹 qQũ J E4{EQuHܴ)??.x0P};okLaC_?;BWM>B1VX"C;X0H9IHAQV@_H:-$[5yOФ nXEpֺт>&ne C [kH]]-vkGQj6I^'Êӫ*l+T_9. e~=!P ޻H;<ޔ6l>˹~K9]{dvM]jm}&&n UKRIE52O2 QbJnem| +PplFv'UN]@MPN[tg~,Cd[Q) T?Mfɠ{m4^j=ۉ~f6jeid^1skd|TEXϏ +R+h}P֫ϛuuz{eJ)C~D_߮GZ,\ޮm5@Oܟ50@*`G5M%UVDZ?6T?Nt" J^z5`' 0~8A};B,QqZ%c@/ݔk +ϑ61 `* +{5ϺuK5Vctih!VZp3K{SpmPX {%9e+˷ eNޞUJP +.&3Db`=|ҨKmFtqn^.B!ap8V4@^߳iCٙn °vm`[mƔg]"R]&X>{TUL8 FUJ9mfLyBh7} ^(*Uic~.>T B\T8Vᷮxߓk$5On&*=>]r[֘6^ʑi5y]n%Ft<5eiZL[n z.1BxYyN~Zy-8iurv6E?Zh|fi2yAL r_(%YjeJOH<-_Olt̉/Q#9ygL`G)ȗƯ_-&*be`aL3"&Prc$Kkr^}rɾNppNMmP*p?Eܡ5BÏg{w{ (nhcLo{~)ಗB;7WHxmoFi/[{m si1 NǽL%6*?yk"!gLW=u:o^fS'J69ciI R;q-{RU|qNr}|ۂR*ӜR'乽P5ouW0E7%w2K^=p0#l֟׏8w7cN:[JyǠslfq[h#a 74[,Uϛ9Лe΍6SpIї$KA)]EY!xPcT)'фve-Lp(XTCO]]NP \[)֝6g2(?=QD@}Kt.ETˤQbƴ4PoJKp1ePiP#\<%i#7+?Bd'FP^ƧT3mΝy[ kƁdP*y=g~,H4 +5Ӱ'؇¥yc|=41"^tL͓6:쎪F;Л +gbnٚV+NAL +^S{ힻ_q?a uR~ږ!tsm׭;:yG\U + u=N6=/?Uͅ\tn~%mZ_֨~Z*Ji@[~{v]][(1pBfCj,l 蛘)+jr_mZ-RhH!;dWSF1K8Vfo J# yKW0x4f^r4mp loM/{ ɾv=f۬Պ;%BV(x])%S(x:@^~_~Jd#!1ϵ`KW?G#罐A`J1Xr?>`?G]]?XZtȜvӼ[ g^e~X=]SML7t!ݪȘ*.\IIGHj:ʅt[5a]iC}G!J2"QoCc͍I1UL1t+j)Zk,q6l&F1OǍm*Q +^c֎5:dk& KR:iG | +GFߵ(c/ԲB<T/G&GEܢ#l 5Ec&;E #5^!P"tԍ jpuVuXzRԂX/@g]?\&W,kCK6qEPPyI{߼U ]fч9ƥ+h>dc| )pirRzۼt/7Yhf;Ih 5!5:|z ou_o)]Jnrvk*a*?0l<_)]~W^5!?DlJy+H9-KFQDIb#~=]X_[O=oQagz:Owr .u@mܶaueF +fP+kTj&M#q9K1c#lͦLFlX)2nǖ +{=-/gfdl蠪C6gj!{kJqp^;9I:e9UT PeVC__O;&PpwTlZ9CUj4t4JxWPϣC#vWL3~q; 1ԐޛJU{$N¶w*[_LFlgX8kF$[2dO;/]CE  xuqԩ{VJD5h,X]6Ƨ#5{0p pl6QcX3x(P\|-|&P^m . r1gsU}nA-0n ]F$z)&۽WP]&{,zoreɷ)ԷӫF]\n8k )Ǭ*AMv,6JH.wjulm2ԩ17\@5*oj;@M/uPϾOJRegOӧݻ4*+:H;wT˶B|â PِF.:g^YBњ-\|c܅9;M+i1 +M9 /tE@ϴNfpo/o#FV9'M7&0/? a8~4ܻiUTb-/ixU,dCFRͳY=b66٧"~v>i_kci5]f.Sa7+*uIOgSAf[MD,}zڢf[i;_oO>O찛>ͱ(|ђ xaMO6͑65\5touΎdj}k4~u8ݵ|g\~Ijoʧ'6TTĜݹC#ޙq=lo9t.vWhnT b{ϻ6I7LW妣ޤ}j?_-t1kcGrrp]nv]k:T)78bSIa7;$o!4Z_M4,F'k^&jN߷Э:Ԫ!wN +Ƽ ZNo,^c9U[R* pMtp)`OܝMٜҴ-T}`l/]\-CS +xD}T$7O ׭ nwAcdz{|*YA#P&)ȽIMD]NNGc{.G%tyGjl'q , FRMwA$>ė +it;Vyp&N36Lڣ`~icC6 fC:Jʢd_޶њTfqhY:^S#߾3\cԊ5l g3TvwuJ'F{g t<[׳mbiܟ"S MV2[3%FsԖ?̭d_'s[7r|ܭr$|?Ο<\g|njW+e;s8cwjkܚ6C R_uJ{OzJEGh=IآCs'M133;{R7{=fUZ,L~a]L10M栖ުł`UdUx_Y6qUVq; )z\,U@ЉU#頴ٜ;e1^eUDod}s(myzd۷?zypuޮUԎ wk`kk RPk7@74_KOA79fc 7{73Gjk-DLdtP1UN᢮5w!X2zCZm )"qa1SKny|psY*J͹-P)>B܇uf~-1%brKY7,8)e Ap.DөRƓ>ƴwiĀO[2D8;e?k8ҊKoN6B:D'L}ND*Bg XfiP[TB`N6MCb0. #6KML9sAkg#{,H?BK|꼵 IןVl;5ރǛ&V'fIpu4XR\Zқz7 r},Nub!Y=r<(ݰ%f@Ci A+>GhMZ5~/~gkcO/o⏗ifYq(E](G턯⒉v'xmwb6 2t7JiR&`; KcͻFD69~8so!G=;k"6hkoӄ˃2rЉ~s:Wp)6Jh\gqM +ā%4=?8Z& 6 4\!X>f%WHM 6球i9ZZoDEMO9{^kb܄v@L’Ÿ} q 4R6rA`Lt_saHhWx\BYZ݌[6}6LdXSI2]Yg35&úo&c9U1=4'9We1^bן+5pOخ룰>og5R[_29#H#QAVUMiTוkK\S{ݤ}G%n7ʖ ԈMS%C%R@.+cP%iBWJ7UCWbܛb +.m頞ȯP${r7Y[i5ʖ+%vgAv xzL2wH þ}{:tpȣ~Ӧ{f{mۣN +IWOr?S.GUsTnPE`ŗsD-\ +qt=9.p\z1qjqu{۳9tJsn^w|ݞUҽd04]{RT窏>41&g&^m]ϦDfBɎr)w\+gԁ5>[QҮOg8cɏTsƃ-;ӷ^)ټE|7G+嫫38dB.t>v*߁5AB.ߌ孇"krŖ5'^8gAǐq~d;F\RżXڕ6V[}]*{ߕGAFc.G7m~jgw+5(soGw-PWahx^Wt'd$ȱLȵ]=;sN&Rr>FfA9`Tsp^jRΫO Z*?#vBPjI+5qrHu\תÔԲ5+4tX~5ڣ ++S Rµ6!> YLb[.:wFb)"G,~Vc|_6~E:y۫0/r=H6O4!qL\B0K7(+Yt;(:}ZK ӾWīԀjd,ݲ5.;1 @bs@'g^IJ#eɟa/d:*[R-Wڜ"5i2=>)@Af`l˻#&4 ~ NZ$s ^W,jr``Σj9U)sB *]qWl'x# <ѭn +ʶ1qsIX`""8|t0'q|tTYP+QF4("'vFVp,=9Nrzb _ 5ɻLp/_ YUP7>!M# +`=7шi5iht\] ̜pk'/2]ey? gs?dWP)png4lsG*:t5C$e=`nZkW\CNȋ[[dTM񥙟j(F4_},7}٧kFgI,dIh&`RB%6K +Ilyb$',[i2LO>t#whȣQԢVG-^GMC%3+05زBÐilryn)^h)ɩ 'љ*֠ A%FKU(߁+h6zA[{K-*ukB9$6+ +OL%jFe&;>ȗP-az$>ubu@ʡiRG2 *# +8ix)V:|w=%$w ;7XWx]lh/v2Jȸ|U(Tϫe!?% ?'u3UrٖiAJH/:(@/]YDb s hYͽј䈪b(˻#3.&)1;슜= +^U *=\t;P,Ю!(\Z(8.=Pc Dvہz02_rzbTzK)T0t9nIP+(@r3aj4kT!"Y*8uA LPs^% Q`wf~hԍH@d0`cW+vP e}~ bN$':YBt7QDQCcI!/䉜}PoC ^_b">3;`9NU9=kC_iRa UO +(X5ʰ-p79%-%tl}n3eβ`8/.°:LdpKYF*N}Zĸu"lM@{C۵Gjͱ~(g0|D- ]'`%<)ad3 񴟌 zrX7àsh))icÁ^T(J\o;I]u /3sNO# p 緯<R g + vۉt=AQGM}n:`s(x܇y6;ɱOAs\!t>Uf҂ +ܳl(b:aĸݎt~v [yxx<q(j2$N)39f0-j2Zu&mVAA[MIz xA߯*htS`C.5Pfn$'}s-0wkǎ "h/YP7a蘑Zhi6Ǐ 7[x uHxλuKB^A ] [$9(^|¦(xS/A/}+ۙWZ=dj#~BCwrwYb̦*8n/W?*xޝ/v8u{ Xs1@gK}J4WHU9&̒xf)TR9Pn m2"*hseڴ[$wE`9_^$ʙ,ox{UB*iT{sI4Hv˓+U" a?TaeD >*ln89X5HUvieC;P_znld32zk,[Ok`_9R_JI0:^, `,8# +98a!U6>j@n- k0Z),X7'x\~d$<&ThOMŇ%N[OP෯0haH +1y"5лd<.W_|#?i?dO4f2<8W_wg'Nv:p;g:Eipv#e<0RՙQY/Ca=@g%M +vZ[\# aģo1Ou@TuH>:͹nyw_ eS g )>q+Xl(~EHy!23^2jZL(*A 3?x_*1F8'.3^Vi:O2mt`D 'r =Pj{U~ݱKj",ls{̐v`n95?\fV\B!M`ED4sD r8aŪ }%aF<ydom?+ӄ)^\ԭ'n !rGQ + +=G| +Q) +c-11\T?o.M៨4x\ˆ4Ɠ \%jL80,^²ia)f@̃Y+ 79!͇BאTUe$=`g)`&ڿucE`[_biȍ` +YAA:`4l /nd;z!Ǣ.f(-ʞ1+I~Z Ӿ"{OoůX yq( Af$Oq.R88$J#5e |{ ?ߎ|&_ķ c?]si+, -;w>6M=U2aQ09 !U":Dr9Ϋ1+cZFH \ c + 2f1/3?GtP'$K 5N0Llh{j0J0LΆ Y-",VK! hy!ޅ:RmN*oZ59 i H^=W,aPs2̒$W9|*aV99*mwPt4Lu +endstream endobj 97 0 obj <>stream +cX$ͣ&(_ǂͫuMШ AH{c!4%mDRF}_2 Flhb.E1&Y4eimԺ1 1[M%ȍ#qaJ5ՑS4'P :󘀳A.,AfgUr\o%ҕ¥dG('F (:Yg~̅]$?L<1i%0 _hmNKývbgTEHϡEQta)o >Eѫ+j#Eyp#]P1%t3DȀXސ:ɧX~^ B 0LH UZGD'f$%J}a1)7.yM>yo>bb{C!76ox^Rx-o +m@#aV/P;"bdJ'%*+):XS *)y)H q(U@P68HA%HV0bXFk:П㨏xix"p|+l~˘V֡ qӒdv}`S*i!w-!U*4D\VʀPukF)dD:ws{͔x122 4qr2!# +5eLFn0|B MAULTff{W:J;{́Wt>d)BĿ +4玼6aCR? R_Y1M:[o @%NDҝZ@P]6M9n,xÆq-jtpUǍz,E)^ߠ9}@WŊ"FB-<;ܣ%sb4d" .QM|o :w +P[@+VAܮVVCUV+`3AlFSmWG#OdWN˰ Kд&x54 ɍL4Asp,c;YP[tt %/ƐdFe !=tf +6TD"q'*ȪTzOml̃wE{$t1CmzWD|.%K _L=4A~VsHi)B)=/Lùz$: 0hZwǪ5TYٸ]ySU +`ʏpn4'_ܽ:\rQ"r.b)޸O/yI.x[LrsltX'@mwK4\bEXxIW8t~yAxHG *gGnMQ^lBxb\!+S Ń͡e o>ϓJ 904\|Qvrpy $n]%OGGhcT=e-ta S~f~y` CPJi x /g <~A3aK-9ԲWV0+0`T{(b{,}@hV܈sj6jĢQY> %DJ @ kی^PGLkP; R7l=%B +nB^bHcUL/ ||R>1ՏE9|PkI!zS;B0Y`Y AeH @z,FktV<Qj$we0f!`>Y'o1J{3 PXԝlq(#:7}~fB=t,E#.0<* @dED!M#m{aLj 'u| ߂5H[-D,+؃䵍yMJձEJ/p8~Ӽ=y"r"`53:],+Bw"ޅ%@SfWFHNiHp/T ɍUH>~HۤVBfQ +@Pwo2OXsPgX\.72o +WpPjPtKZ RK2sT|/#:_uB)Y`cbt'8nʊ¿bM'095sT"WB0|f|-%㇟*^)[턴i˰3,Ň8˺[:{񜥘1Pĩ?kj $ hkN4g#?6AR&sgSp!NߺoT{]r@MEm8}#69z*C}h7`tM, Nx;nk@.l(j$[$*HxXgay$. 4 +H &<61A"aY[}oxQV= ]ny&BiV/~C2]E'fXKzV'r~@(:UsH|dVyRNӍx9ůOEPl" cy?W`+{-Uϖ+=Ii~Oi_.=]=?ĻL +!}yMsJ{݉G*fsLDx\D/+]mf?ML/7d.BomCʯ9˥zөJP+}Ș>~fDtN_~IZկE۫_jG>fԿ>N5:l:xp_xokuáẎۦէYGP3vOJGHg pq 8ar0K'z,0ӽM.bB:\϶`o%"m{q6cXh +`CqKZxú ;?n%ׄϯ4IN]ebNK/5qM=?4 +Wߌk gt.Uo<•`x_(?o] +c*UKQm~ZI-bnpeq^u7밭3[-quozWZscw)]ޖ׾}upBt I-{3e OAI8ǔnCȾ M>D9{F-w+=K᳞# |j\^9S +T +G[XH|vu]OowAoyߗK,=cRػu-1BIÅX%u(m{K֓O鸳Zl~h?&Q||'luTۻr +JҶR`Ng ^NdzqTAx ,55y5oyg<,[c-]?mw79{_Ewsmt:/۟PI53eK~\<1{J{F7lӻm{ +}sg+ݗ-1M=\gŧ7o~9d/7pvZ;?lˋQ >x|/T>{ dz}÷f|o;l뻸uS*䎭ؗ־ʳTyR}x ;=Uͳlȭp>vLK2+Cs:疹|Ϳ3u5NNۄʞ|' cXAQbry:Q IDyYV)#c_Zr/ݵߴTH&Svى}˴2dlճF#xP=>ؽ=W62_њKi!}xlކY"9K<0ept8fq;i$3E$y޺SgThGOq j̤*Wz,8=K(c\{뭏5g;W(v%ݕN2130cXOƣ?~<\2 jsvD.p(]ݗ/=G B)Ǎg[+>ҮQAFϟJ;[ޅ/?G엟{w^ annnϩ*&Wo\qo5 +_e iavv3H+~w?ջ/ Q%S}ݽ 7y-e?^VCCE\õ{Q\F+j^?We>5kզ; +׶iν` qmO_7Tҗ9kyHOtfemYTq9 mu{Ql]l=\کg[ܹc~"?IA72ICcEKum4Xȭn9%4䐓G\/4ϓ6 r"qS^++3wxsrt;$s@fYɝl*$v{Nd:vEGmEMⰛh27Btj7g\WrF731C#PkV4FdZ@FB+TSHI}矍9CGBleZh!ZFK Gbǡ) 1[|/֋+,/HIu:rk=I39?;iot̚_1cߝ~s ?4tӉbHH) +Lg升5+VMg~ҵ O.dxXIFp&ʳՐ4XX Xh%0, fITakݥq2ˆ_I"uxzDu;e\佦KX%~WqvG[I{a7ttNzdz!)-HЅ>Wݶ +䁬@4M|nwGy{*TdJ?]BB"t*mV=yB&g> ^FwE"&X=Gz\]^ +LR7Q TX K IfsS*߯59/6V?Y si {%t^}bmG.Y +E/E[lظԼLdt*k/[Y2vs^',,$5)j;' rKҨH/$qYefal-7.40\گS].Iy1٧ƪ,C{A<1+ ]B>ى`7yކOZƁX~t 6=*Ζӎ&g1u}|{6i4xuck||sᙟ$~4 V79#IZ#Y§2[3W$ػTPSc'q"!mBir>+ @{lFat.㖗zvDwEUEk }IeS-O +Aw,\&3uO8Q93_9Ƨ"OZO}g#}WD$wa: +=wڎO^0lՁU.{.ooy#  nC$ V` Wgyu5/\l `@^<ŢJ,|U(Dd[]Y5b O.FU"}#2mDΩn/p7Q z"S9Gnq5j3dIsZ4/a`#IbD!W0Q,MzcA=0>yϡ) je ʉ"1c"X6gjC6 +o +0hCyƋNh=ꤧ/?.aGe:Z(5)/ !fPq.i_V5ipJT M(5vmԣ6n)JB> #& dPi4HD-`5MmqgX1:IKV:Cr#~]$&G=g!W rysV2:  Ĕ:uP͙kT!q*)|CM@GHsMrQȤDtr=4Fldؤ@0VG +r?#>3Z;QBqGԢ +-vSACQ5}/]v2`W2Mͺ>;‡;_I<%Ҿ!^ؙ'Q?9 ,!r6Dsn|TYyw.9Z[O "YAGhﱅSu)bf f)MiGQHp ͤb{A]:8ѤmpRq Hq`|Y޾Y'p9BiFt9G}^dJt/, 1YNjFfj&Op^^kW _,RN(S*Q G/hfF(W*Tu1@L3LT=VnEqƐ1!?^rA"$sd8(,%Dc!nW^ž) Z'ҭI@@p>XYˮw+BTE% Y=,\H#19[Fr@F&_gJnb裁xӔ}lJ}Ad,|vA&$/n[ W  NJMo +6GĈ~UBH{kW=V{ˌ&WeU'%_9oW#o:ˠ2v3b(&;e}4}{~9%%8RYdn(L,68nQhCQ/HnܿS3@ ژDt9(B=!Ͻ"_@Ĝu{9Mm%YM~۬ +6n$nk\a8JBA|m:G^"l/eZVl ++I[MFGel +?*^`.^ JFA}@8K S:*nB4{w=Cj@ËI}eҨ8e|s6V.~酄{Ϯdm?SCC/4E좈${(yz˹N읝I$Cqx0Ic~f%o ܵhthp-]ơٰF:,ҋ`q0o| 'ʰ?T0Ý4dP ;HBb`!ZJLلdGA-1}d-Ur8D0c ʿjܩ۷CD +4<&早̝yLOu1wıbɿv"UA!e"Tb <YGʞ]]XT pG3xY`t_  ]V{>Gz#zŵWP%R9u ذ:8(j#nu }@ 6[%'CE/`/)D6h=>n(5",r%"^ +:6ݬnt@h) C!1ՙ0$,;V:/(O>ލڍ7 +0yYYjܨEW~,i)Nٽ48],~Tc "!:€c"bRcj(FR:D\5-RTNMHR|DԢ sv.j7& +Sb^( CRp<@\H%K"NϲgJnRd!ܽ_~ ǻdLyY*Pf=kRY'JzU˽ gۮmDNk)w O0xs>:f* \`XڝRFT ";#;8vA xw>iSbL)qE沚Av`a72ڎ!eQT% JNNڛяD,ՙCBqSKEA;|2?B9nòQl1BIg6CK0GMI!ֽJKE]$KҲ͋y.(\ᰫSqd3t.?SKV݀⋿c3,rKIfIKzQ=qel7@2+ƋqʟPh 4޼xy)D(S@cA:šL}?Nϭc~0[D"G+ KIŬKto^3ڊ.||,hT<UM${W%[isz@ENp5uLq̀=:=("DuNe&h"L߬٤wElUODౢ\q]| H}L{0| g&RSڍkk5Wy)M;et|_'0؄*!ɪ{98F28t&1V̡P-ap TRA`Gt T-pq wn1W܂DA.\VxKt,"Jk.2Q6R`k#@A@cA1xg +grf6 aZ(ƱG$(^9Ś

<49=.d= yuN_;U?sEDz>Bϰ2BQ*w0olDvmKl5%B͚q[Iq]a2 ^)}XffkLvHG(eVaBm%/=ij3+R`GC8 C;&pKA-|π㿎zTcBvn.Df)uOZzb*59Z W*GN_Gȿ1oKxCX 5o}O([z|p$+G6VʼOp!S~`I1Gn3 1!d%1Y2P1B0U &*Ҍ"J3r 5m3EaV_Qx@c|T*EE ֺ4(Nm7` ưΠG &sD~p(s(>152}GaSk}g:nQ&@ۑfZ K-3۸cC6I .g"#m Ha½9;07R|+%o\Z-BOz6܃@9 FL4oC(s"XY.n8i]^fn VLL@@ޤ\}$#!'ޡs5%aXH٬fR?#N}*Hڇ8tb\e#ENe0e'+Px<8=gfrgv>yŚ<ÃEH;u:(ōBG$ւl[Lge'1hSr9*Ǡߴ(!%L*#*vRDB ւ +H*!ig~HIO#@D|= +wpEH=%@_VԡQzؿ$]T|Sz&߬[+{@# fUC !&:qiHig`FUdC-Eb"4 q)$ tn5 b +4%M{,r7rQ/٣,῝O>z$HRm+`)Y174 :[MjtGċ^H"RD'3!rŎelX\Fw껢D 8z^go%WLbpꏴg5 +u}H@KEjq ך2;Ea )@1/ALlI {{m'fO3<q7u[~ԀV 7\~ Iʮ 6,0*"9aqYfޖ:qo<ÂO:{1lgN݂dzӛ|?C!l +XRhp`, B+2`wFFn\cJ7*,4.E7~ɩ}} A Bj'>YLv_Mr=xgӟ 0{˒^ T˘O#fVykIg9TI;h8> ܳ1K [o_ [IwrT΄1b m66P5ΌѶJ=`ַY;a0:Ŋ:9<(xb?WLdG!Vh&1J ({3/ʫ۬[HbB6X>@)FGȋuUxm1zB䩙q>I=)>n"3HV +daV)"$<]R]>C߀?HX$[X |/sQ~\y*Obwfvedq&$:ng'Iݶ ʩx4ʹ#~o6|x t-"YȤ ݅܋볛N{' +J•Ո^'/ҙZr,qJJmԓܑ{؊xaNnrhpNgɢ-RqL7xXHz25ݳworԾb}ZaX}9,*[ϼpg+:#T,ս<:{sv,ď_Fc[|^ׅ;-{g/[nȯcogF))9żw RrROwcUX+هr?{I5m9܅oڷg޺ZoZ)%rpaPGzvݪ@?8XsuL33K̟K7 +5klQ{ +,kE'[mPs}Ō+_K1$W ~mof?S7d^o4>/^㧇T-IgQHϼ4q}mfqO$ܠ;;U^%<ɧ/8XSOp,& +/ sY>}Zܷ;W5Zq''t蛵 +p(nRVNFb5*A!LJ'RZ.7ٛ pzB,`ɇWKQ4;vOH۳8ʝ*1_̽VJWW\dz=lv;~}t3UrxGdwkܞ~ܟUFsB0J۲=Fwn4no|g0(6㹩[z<\˧שs`8:.]Y/ݕ.Hމ"žN/A2ADj<.vTV·׊UtcAOag&w WOi(guضʧ&NU1skHu.l9-yH^$H*, a8^ͫU A%v,tYQ/J_uǣkSu6-'@/ +|>^cG ?UX3CWpT6s ͏d&9X$r /N6&2mU뿦o{pNO+#{bA H< kɓ(>Cjyty;|gK +u~倔iRPۖxi>QiOm}d}N]_^]t5]_9YJe]w;qvu,׳EUCz8>K9K6</k7(MøW/`=%U%NL#Ԝ^=f5^VDzES P̄3KV9?_R+rDj^AnDyعYl\[۳I%Diyb%avEU;Z*ke]2v^LnX4+f,_U?kե<|޷U_Jl=ཅDҀjєZ5jWKd,ia '˽LZB~ǃudiF&{qZ>憅sppoSeDRwFZC,^x`1-{0l `lh1kfBVWz=O' +EnӋPTQF< F` ghO׵״sbi~yll;mmj6,kX r݉Aоy3 :+ͳ+=RbOh8t~#eý |^ku@Â˞d+\~vm/02)oq.'Dgݎ|tU]MYI|>_|=T ~cZ`4Jl^gxH꺈}.08Vc +]S /f*S#Jݖ?ﯟH٢GW'Z !cCEwDtq*08#5tUKs_ 7H,?fHM1A:4r)^Y#S3ѱ6WCˢ< X@Ka$,4dxN'ϗ'Ჸ'Q]_JOQz}AͲ8*ᬱ֩G?8(?8(O’^Yfl(Qy43HǨcݫ ڷ&pNkcЋAآrIV9łTJ|ݣm)֍V<,[9'a'TݔwREjՏ>zW "{sxkZ^Zr#nSſVEGjh6?t^uZtҳT%7a^zN[טy>=8ϭ_`OF+AL"ֽZ:Ȝoz9\4^YidKYIMp榇M{ +Fڛ<]W8JOKRdLͪ-De1u޹s;2mo޿9Uٸ:;S3K/_H9cw}c'nJO$/wDU?)5&[[5`ǓU8TF6(ҕ[+w&SQ?s*LE$8(Sqk.)=QI$=ѹ?#0Jp򟩚ښSGq#a!]N{qZ F+J^azw=CI}fWwlØT>Bn-]~쀝S7;b1rkȁ˗[NzE/vI-c޼tjڡ/|jaϟ"s/:Ykvr BW06O&#YOŋ5 I`W~T%%E 4iE99~VC{`eݮwPXlz Q9#JRy wv@DcrkcAd"Q#ޓB$S{~lFL<Пrn|m?,1Wߑ!sGԠ7g-h5kBuLdḓկ.2vF(vU'.,NaNmTbq'kYلtꊕ--䵨s!kJ(AXʁywejׄuc8u0`Ix*ʯ8^DP([y(쀐CRNw3]緦nCS1}2och& 49GJq`s`_KX\nsLO 죂J8е[GtqO:}װ_Qڐ@:lYuR/txs\ 1Ŀջ!D~O{-?[ٻ{uȏkְwrXkr‰-cW}pŇ$}+Rκpr`#0lXx`17LSu1F,N+W5`#jA+t5hYoRF`ۇ &@]}&7O"vas4EXl +J|PNDH(橻mq$O[sbmA++!# lw=ſ4ua*γ^o #] ftR2E~ڷ%>t9J vjkBÛ / ÓlIӈ'-F#p"5qquU6RTg{ݬm.B Uܜ"cGlBYP™>4e g 9Vk:l$㥣&1qXR58Np`Y_Ls!+_ / /t{bkw1ƁNσ ?vGltPLۄe\ێᔍBB ;hbX;vۚ #>oڨVXhkكd<ҋ8ܻ/zQX }ǤQ>cɒqq(aF'`[*upFd99-z-W+9K@t4; eEX-΋|/ +(@A GXMB܌P_?L[lv=V؞  ` +8@R2mn +T4`\ +LR'u):XeKwx#vz]:5X=gnjaos\3DkR0钢r^b&۾ڒ8\pṅj +[b38\(`/SbF[,_ѠCo+@' K1h@fy}ԝ`?`=d +;>j +%j+Fy@a7uFCwA=sz{bǷ>= EmVS|ȘN7ulHUs _`Lt{(&hF^CY)Z6Q7/}fy@3?[R'C1iE.m6Xƈ谔 ;4,@6մcx9/1~Srq# q"Yc*M7Qu qC?6` #(cvi("ƹ`H;3z H>Z,1e2h̼vj.>b1՗a|K sI߀Y@P_w +jzF_c#B DQYj"G]@⋆3`1"dQ0YSB!8 4^= 8/<;px=.%lՔE\D4%:ٺC7o-O!7|a]}GhjR]Hƙb:9!*vS;ӕ (50p 硝Ǽz= (ix0l:]|6fsy{ +y-y!2tZM^"t1 5W"z(PErguOKtY"%y :1ǘ5bx-BayԱY\Jcxn1 r.94}0]r$ _L:!#W|9j#Gr.89i5C +Ikb{b5&;O-Dq<ٮ {WXwJ[x"kVc0\qtEч:aGJktoHhC(RlI?a L( ߡHQ$@k ]e}QT:8 nm@lDd#E\ sƑ]d< 7QMR1ƄfjnADx3E,X^jԯ¦>HwvisZD +f傧{ 8ZSpdP!Q5, @|n!=R:iTym)iVFc(')Ȟ: C/8S_;Y@/x~o:ǫ;Il5Ivڑf3&" )!bU&Fna +4NMHXEjm`C8a<:=\%Wft5zk;/$R$ؒk`UzՅϙߋK|#9bXN3kI>|M]$mr5MPmbNYrpӴK SHo&nc5Fm|XFa`. t@F3Gr{v|l.6Ǐ9^U;T{xRn=baA0de33fXsK]Y+X29'FҮ9P؏Zu]o_X߁̱w ++ c HW5Ć'<I$l5lfdG1ERӈFR< 5DbF)u +pTY[5_ŤեҋJ4BQOF|!0ZW3 e !pEaLY}bQ|bȁOJU +n`^FkֈBlr'tNw[J՘ORĚaz :M6o;eWZ^>)2_I}(E@v#{EhW]D'b^'"E"pHh:D{E`/E͒E@Ѩ8a;褶I o].]8 mA.@"W  d‰@'Œw5|iV!Jx]B?bw$BȽ,tfon>Xa Ro#U#by}51!sᯔ8ꖺj+p4犓{@}) +T]mtz2qSKawI({7PDV u./h3/h!jFo1f|-oLzDA V[wF0zQ< $cz\$,:ꢔ>"VJe@͆T},)\y\&KQf))gpm8e7X*?pQy 7<4DN3FVEa>"JFȚo{ aO +-nkx‘$Te_ JcR1;Hڔcak0KŲKhNb~5fX~Ca#6Y2=4&뒋l^׎ʆb>l'@,F> +* +P0~T&Nڐ]fbcdںXDCb'T -(`Ib,%"&,+\%)Cʌ Q3ZO$ Vu=:QM0Xs+sELGQ4Jњ:#lT$B 9qye50y6@ZyOw-/ޱEOuFnCVpJ *.bÑY&J;A2Y14B4)\lVK:7kHR[2bn R# sTDW7\8uR +lKBiw_:9o&u7I͵ +8TZCيg*:ȲG4_ٛ>Gĩ@y,<:zN9vE Y7uꇟhQ#(e%ZX ekU:aC”JudjAO[QM[jk LcV.BldpY6'ntk¢Ji| c|yjVp^ ߈,TT#+6Dzb$Gm[xff@%*.aձg7s<}x߼+m-UbozooC$k@O +-&>j5dR!n~,}W^=^`imz#a#}#v6ϕN1C?siP{⻦H:YHNLNNW)Onu:cֶԧ3wlM‰J(0"#;60cFJҢE/52 zln6Iu0Y"aҭ&ujOsIY'ṫe'(ﱉIT6QD@4`~>:i`jz!{nڂK[!a +lq!3O#!o-3C<ɒrqU 4'ڛ1h J$_rgK[6tyKx,qFWۅ$<,9Fj7X'i$V1j V59sE*IC@ ˚dfݰ" 896-P){H^e2 J(W !#D> *#, !=2LrfSJ`i,R!&k<+:[X&/*xԃظii_]ɨK Қ[է66S&T|G8 w[ܟr /߸B\Ysb-Ϋܛ2|aG;}J%p**QxѳzC~jNn-iT;)kCl:{J03gbc!Xq^_fׁ;s )M~VEXy9&o䦐i,I XYO#Qj|9٭O>2Ffzh/^Ms~i_R6JwM#)G? +/gHGdT@! w +$)I)9`RB=5{]No1-")3+\ בi7 +#h)n;ƅw-ujz@~I4_9xd`فM3 +w,I]N<;O~mBă5N<}|7vɇkL .^(kԫu͖|EMDl&ynZͪOI2c^~DJfz@Uqc J]sRV4WߚAԉbC Qi:JpT>#{2Qs֒ph6/Pq&G)ԡ/@k1f8f;%Vb8WH0ǐӝc]fʍxȕ"#΋%FGA=xU @ydnj  _W +Vs|f-x%w`s]`E5"S_KS>U񘮜![֛pz][qR@|5, 7#fGT)Y}y"/@?,b\$Aa+G"Dv)4փ'Nrljx$d\:li KIuB?GM_ȃFI+V/ *`)ʰgB QRJYHL]GBo5bڼƗ_{ҜIIΑ]9}'}T0yIҞ}T&85dU)~<薐 x  #GZV+ÕBDe{56Bq6wUٰcL5Zwɗ~bo^cG+jyucMlmB!0< ůsEGƲ邤~d8\|OZ۬y n#K|^[qVlt O{.ϟ{ayЗ.]YPӜ‰+ o3/ Vs^!ho3۬g:m[#غ&,_Nwj#5 1X!*Kd`tppPGlfLPU^ C2vAߊnz;f h+{FȁfD#2+!*'{;R=L^8P_YAY܁+K*f% w%osW&TɂMPl.]=ǣe|';J_^FiNvyv%;d%`{y?m ݓ܄ yX<(b0d +VELe'#h +|O]]A؋Ps CF R"D箖hvݘ,Y"]0GZw\w;^B,eJi)u + 1_8P^ׇGȿWO6lbX̛PLSI b{IE&`S ZoIn" D=uL:IdTג=8V mĉ/i*=Z I66C +S;fZcKBbI2*,n*J=]1Eo9rLjk℄enx)¥v e!c~?puujruT[:HW!)_6a)5ϟ(V8.3'Ѯњ +=YГ%V ]5%]I >ws +}'1w7ZkWg/fͅ>1؝~6WNcA_ |=wsZ'e:H `U%yZңO.ŭmK ," [ ܦ|Ys^«aE׊ӨhpCO[1.]fal,F|1{gkF/N~< ȁzǏH +TZL立6xїNj,{$= d/{ekԽ֢a%v+į04.zM}:qr}Ir-:e"\[]//7^&~"]k/YN^g&pqtrǣgž`]*k %o^,}\3gkB,}U%-f>/ &T__Ed03Fǟ51⮻#(y].I`'u7ϝX&^]?N)UZ$7;qc9ۓu\Zea +aGp5sg8iJ:͆n5PX5(pUYz!.FO wϦh?2V谒>('K&.䡖 cPyg+R.>\mpѵZ1S)K%R\\3<{j:n82"<`rJ" FUfwVx-$]qa}X /E&d·{}"HY[;=y~>FyYsB^fs>V@<"ZNyߜ@2EL{/.( ;s^ո'x#,~~R$I:q7B7,ux 1oP4,߇I]nv~wMjv\xf֗ioƛJ'|=g jhJQwuavރ{Xqk'# n)(LZT&Fn;C_Rg9u.kKKq?帼 (m7m>޶z_.Tޱ e=xHOkˠ:9. W=` + ~9KKsn۲+-K˷>7LaC_q bUV>[nK_ԽBT!&-Y%߫><`F/^h?wɝ==^p m4J~5J+y{ ?^kNa)B|{i$TI~"Cw.$E>"I޻"M^>Yc$>?{*^ +\z&A]EdF(լEӎk=λF7jϷ89Ny{6q9;<E{7ӏ24/iq:ub orP\PĖ?cz~SY{@*u_XsO?a&Rp,G[G $gP{NO?iܼϚ8N3u[ήO~sl~K17+!`ڒpYs0<:8jmbd|2O{e?֪㮼"n#7@zDŽeape: (@.Jn-Jbn6^[QlEJ{ʾ*0EPcuF("ԗ@{?~Cs߈eũnvߜ$9xIҠ/'lb -t4כs_]?ث)ͥo\r{Z6,-&2^6}TFnfY#oX?;9k]OǪ` +que)өy,lj;Mg Qc]&zeI?; + \Ϣ\+.BlMmOJyK:|[]"T%ڧ%_Zct݃+u$B{7cJDktéy#IsXЪo;z*+P =$N+ N%^‰esMRu_nu4bS(mD%Ql^׆ 7쌬lOfZmNݛl}y|sЮ1_wK7o"j+6mcq8/B0t̋6U 뵡P Bt!X2oqn֙io4d+9@ t/!P '@KSDmfB*pJp^ytxr;*fo mk͡Gk;)a(1mt"g8a:0o洛C& wJN`o@1攤/]_\MZTckm-WV66fN_,h19iPC7GE-Ah0Sdw0 l}&WձL+}0f=M^biL %t| W6;Z7tj<)x4P={XJIuS[s"0mDY{5F@SǭG1uE`owr6 0uQ¬Re83!n6Xh7"9F5t+y#jobxf øVIC5 ^&S37cah +@$% +fL?uOYݸp4{}aBcP).p:`˕tzIfmqHK! +5τM Ğ@0tKwl|vbFַXMt^M Ϫ S%D4w./C,}:IBIU܁qLC۫KC_,jJhN.TqI ׏锲G'y`!}!)ʓH{V]ER096s9mNk}o]oĹX"9"R٩qA3{ +bB>Ӝ{Ffc_T3Q<ipT5^]Sv%sjlp:bBhyV@q +ןpq ,wů=NU[ ; +ir*_Yݫűwi-X,b7"Xz +P񔲯.,W+ca쒅B[*%8$ {*Qp_sE(Kzlz0O8cx]_Xt'BQVc/7yӔsA~yC6$BhmϘG`-lHܟ%Oُ,C,2X9dSKÃ-2CHNKn$\iڜH6H +LaߞX 99s|Ml$؛MFz7Xt=Vz"U-&i5mg6R=B"7q5td'uQQ╾O\=ڪ\ܓA6b{K&٧QaW.lFC~ve i@Y.GmOOlj2l]CW6tͭ|X39yXJQRG!n28yvwNj]<9BPhu5LZr h7hu]@’KR>mOQ ? }*B#^Uxu*^@t/HmC@jC'dMsHS"<˓a-ǘ#( a$љ(Dҹ 2O +P0/t119`-JqDn"[BĮ9.3ŋBeUO} YEQoIl-fP̱}fc;˛c+i& b`s%mo g) fhE<D%< xd#gV*:z? ++ܜZVy~SyHPr_T/)d959U]+ńyN Rd"|+ ;naipLGpެ]*# 6` ^FhR 5}+ZfP +FJW4b9ݝ,P)vЈ=N@˜ȧY׿~cnq5bF'pddK L Q'Gᖗ*J|R!(49m\a/fh= PJB!/c&M|BKzja߮XB#'t:U׉^$R{zjrQY) n_O.B7Lꩧ@/A +x]@3)D 8ŷx=9͂0jIkQE췽{Jy ,`^0ˡ4uz +j53]2k4 Tb UV7MRܕgbfwjB=YWth5Y 2_b?LkW?ڻ gi~SO,U,+㜇˲mzdkC"BD*Scs9do($кR8YRT%f9JE@-ش7bHQZMv%Q2E5@llv̭1[1$@e?ZYE@ +9ȗutف@# 1 UI\m +A_{xZgqmCRxhI4Y͜A'FRCLq %ff4Oa~tsze4k=Εh-LϜ1Ѐ19k4MG w7y *C@d{'!_$1m +) egr`0[dw +~XRP5oVtG.UU֓gFoJn9'/m+~8|Uuu~0m'OQ P" w4xv!|8#yaPPQAeH{)N|9#biaG9ve&qEYU^ ~J0a:!XV- O' V;ө.B2*6hۼ0j 4d>yk^/\nYC izf/l`7>Lfx0Nm22.g5~6RR'yf S +l{E=rQL,AX(y&~GCDX}f6513P}lCm&slt@%d[@9BbrYpEyH=,Cųc'mabNmySq-ɶ$ ,uF F$C%V(EL(/pi" ͫ:v,d#0AR]_VItBI\v?+zMZJjC<:@681D2ysE=(ܜ9fN|XAY"z"VEU5rNZ 0Z!|J̢tyK}-s`0}[oMx*}xG +4' yB.1t겜ʄQ=8b)$g8aLcq9©4pK)\ߝ ?<$XL)ݽ Mq<_e+e_%v3?>Mޫ[3PuPEJCY ?iCGcKd +u!~VB4+lz!3ۂIА-! X)_Ľ@sQL= ` aufZgr^54FY.W+*/ b#r6bkQSGu~sɅZ>:}ߊx껅CiZ%6e.Mz4Gq%r$^V=; =4hPN2TTe]y1埝yʚm˕ڮ=K[r>M}v4|nɂdfnQ{",廖a18ga`u)b,ù:_]uz&c +:(/*x"Ծܙ3JE1]Z8kK( 'm0^G1HzJ!SYGm`h67&x7 Dhv]^fSkZ|`a=l +\nU(Y7[趈fNJ7 Z D3,P-zdzYU. ?+6uo m T2#:{e9D0aJ-s)9R8"McWq|9",و%tH t<tH`}@-ret40VSej+KwN@osHc_k$%L;X{]A +?X8\äZ(5xY=Eԕ%3P;+]laU4W:0 +wWhK0gq1vgT/1|*dM$yX1{ x.;#"Jޔ[0~(C-Fލ2\vY+mSFo s +REb7[\~IF)sɶ/n4(Xx;ٶ/II|\<XXI,I\,r}JK'~X@DŇ.?/GTPY'`!q +**&eT86VeKsH0,~0]&=4Op,QiM+&=}1'##ȣߎb2BTci?Ȳۃ48Gd-VbI6ǍEm&?QlHs[j2Cv9^թ\2u$ȹ[U&wM㐤QqHa]7ξq̔}?/rLAS vd}{{sJ1 @o +Jw8@B ecĤѻO[aUvݬ'_RDV {c[ʃSF5YʞK<MIomﱺϹ/ j,:^=A%X+!t"󃈙T/6?(%SD7Rb7Μ75e1qⲇS]MS~p8!k.,?W;j +82lZH:GE&4Ni)ۺ7wD1`q@|ln4.7HSqY]Y)4+S(XhRJܰ +m!7Dup%e8 7OSG"* \kc+'JN̡d]oCU +nq +9P,f8\-|Zr0[3v1X$fxidYrݼʁ= AU/ w8DSFX\E-C9awJ+TMgh?Ѡbc L5e{ltTF)^sjFΔ.~JR-,aڊac#>gۍPO GꝏyCqbr3zleQȤf_~/z0Gwa-1,+:& 1,2g+FQѡQY,3SަlN˕/h"nQQ-$*ݣ +lv*TJ=C%۔xIK8fL=>#om(qTՅl\Mŕ }g`ފиbQ߼Ȍ%#a ]IFuJdL kFwe&e*KT6e2%l;f\ \eqbXzh*2&@,%`B̬NJ-Vˆph慘h?1[axU[VWxOjHrZQVR%*Uy[Qʎ;KKm`$+iY_ZFoE.X/-EE?5t3)#41Q"r/'qBM)M^1Fek`bszH{}ه0HXvrN`5ɳPQ~Uklݡ] +Ki|To +]Oy;+.c1o +]7*tyؓńZ40t.+9" 4XS]#ȦHTߏ9LB0Kހ=HDmb+>x/:)Hb#ж/Ҿ 3݋<X{Tfz xoL~-.M?N ;Q|3UhRk1\bЏfe= ++3ga4R6q{0Ucn$ȇ=Mme` MMYL" +FCT߿Y +[e,6wܷҘٺ"jl*ͦ{BdS9 Xr©W +fجڎ M?{Ȗ)!C{ec2n|ǫ6bfq͜MeUH?bs:D0B{o;ګw}ܳ=8ۜ*1:NfXh@sŸuQFٍ)Oc4^"l*\iƒQqxt``fOWcu$^V8:NU`zx\[ +qI5/S B[\!%@Ly>1k9FVK#:3M:PP:8fLk,ҷ +X+}];6/qnugQy + f=W7V09|Es%jAmթAc>,g'eb,owfX)J$9uɀvͶGO[g +X枎џ,E⾸Xw;'8ܭDg=&E$:\FlmGjNs~eoHxQ 'Gp~󋀯կO'Ia3QۿKd-m-]'<:8ӞE9ogY:/Ы5uhg&ƒ#utOؙkwt@]NUQ]rp#-)XTnSK?Bz&vOheS.lRSS#Z- +~C5Xwcu&Iڒ(ͳ?˘gqJ7UW +'fvl-X㫱@:w1vga3%1;w0 Ȣ(ۚ07 YKjsmz[eؔ-#'.gltղE5޹1>$LMrS? +O?_P;u?IbtL]sX"u#.=Jti'O)z Vi]{꬘ ڱŏ0}0P<؜'!9iEfw`Cih4&|br@'|L1P]z +R6,ME,@KIH|}ĩBJ=tV*Pwx.a!zQq~CTc|d$Cfy#աׇwvZ]iF6u~K)v,lTLX2YILO 9t?# Dd<:8@:)({۩ 1YYB`Y]*@cf8S'~TE"P̄&%BP06,)[JI]PoC/N#ǬU(sOIU;E$˧usޱNQ-sΦHS4V~s;._=L7^ē&toGm $Rr,x*A!r~.gej"]h"-HZU.þ_ڂYvz睖-mҩp~NH;CC#ȸ/N8ò; t8QJdo=Ғ]G]?.?:]z|JwӏR7OwCE/TLT2q,R(N\O ݃序?/O oĄ1kY\`}ҍM"Z.5 ɬ#ZRX<1zs؇c鎧{|a}~w>f&٫Kb,=M:B4?gw[44cNn %;HۺT(\ڧbﺌ&%ѐ6Ö˽,uu@T!y ѣ| + T+v)4ޮ:-b59c~Znܨݿ>gKegEn/'kvHi5X`'3?y/u-;⼗LdA!uup#'v9 +|_|Y\0\̋ŲӖ9°;;s=0re~wNWmW3cׅqr98Z%9"_a8$bNdqF]Ϊ;Һ +$om{= +c`-<lgEnޜ X)۹SKK־:J2)3a4҇ډ曏G>GY` t^Ʉlp{'fj=@,1}c +h=ʴ=}hQ㏇,zdV_}ȹbϝ!x"#fcARB~ t9f#H^B;%%lb:ډ|=V842#MW>G~iq}FK˻fgWpS T]1(~jiF<`:V/z{Btbm> 5tkiS˳dNuMet/UQ/dp}7lSvG%ښeÇN/Ŗ +̃EqV7:Zx"[J"9*F'S#L +jG4zH)\}&v_x :ItPrhUOfbpzw^xƍX.p63^I듨h}eO=gu'guil(_n+Fѫu꺼,9H)t oJm?YD7xС7:nzꔽ^ 74?Q&G9],L˦"Gh=m:xW򡐛wkr+9cZ;u[Ew}Zw׻#Z]b?lYV[I+*9RVKB 69lBs]GtB7o$s3oiD(oX|Db]"oH mBn'+]Opjx|C)adk-t?qk! f*cK 0% +@]hreM,]L)f7Azf:nZyE=yv{ +F/M~jv? `Tg9cS@":Ns4Ç뗳e!U,TFLf\+a٭ӥ68nrwb+>딂{wژ&00#&G*JE?|< ZFrs%oB'78#_9񡾯oNoL_ݍވ;ʜdJj\g+|T#;{|7jBI/tsrs~0SR=!׵77ږͅ}iOm+K:WF[SۯDȓ]nzx|3{ҟ6=*Ly46MC +ְ4"Fk4-yoU,Ǜ 1j81UmbJԦWaE7[_߼9餗ǃo׈7Ko-_i,]5^z! .mebRcz[MJVǮl?զL\~!hTݎqhϿ}q㑍pom3 o)  ̡=ǡCOLsN>]^l!B#Wi7pT|RY d:? ^h^z7E= q %ơI؈Lf =H-3zm/Vg̞dZu f~Nh>YJ8C ;.> + BP/L!%9B[  c|yUX Vlb\$0SRVlGp#pS%$<㬩f|GFԸeRPi !&f4m(t"KB^zʗA\D2S$K !QFD%4;WF8Ǜw! !n +fF] l`@^|ˈt~n" LL:Z"sr5h 6ٙl ^BG ̙Ju$ܕA"3ENz%MuL"Djj~_{+L<+a%Ʉ0rk\O0➷ ++_-$ +'NEw}.̓0W\.f^p.h]D,Z;]rAx3 +,#CkfX(Q\QQG9B=ze4#CPTDBYʧ=&$Wai2FxV":+m/8 G]h.^aW9dIg%.Qbu!8Xű( Y&ARg +1,iA+pTg=Oj;F a$_*!KE1In ePYa6 *̳){Q(TϾ +r}..!:؏#HU0QQN 0YWq߅*xgc +7PnEd)1HEtGkS@撩 -ajLoό[0=WqU09Y`\y\"x9bI,_OR2=/+Cu_'+Ƿ$ +atțALoй0e+S@&B)M4JQͼ=HQ3c>YvR(h)܍xU&Վ#,*d4h@~G\q̔ }먄7=20 sLE%0sIyHqnyT­W%tqF[+*!MXbYTvؿQ {RF OY.O? k7<jɆ} +N%!N6ʪ 2ݡW=nܾŕS,D4N;BZ=h@x0 5GCAk;5^%3-e#3v+e&UI=*)${UKaeT^~A},P$ؠ;!H4B'( sPr!V~a~ːh BuHޘV`Z^Lc :)II Qq^!~(?Mj1`p%!~`ҔX~.+AUJ$xTǑX`lPD)`Z8, MpU _[)Vr 㢼Q$ǡ'aCr|< oI:Kz2KkZGY<9({ښOyqW7Q9`7t +(. Ts 5Bx=/:Wg24 +[[yP M6s2TP@Se&'mV_*ekqZH[ȏm &L)p«nf +:P> *4:\D~<$a9ɴÉi*5_#_?̄VA3@GURhaPr"uԯTT,lp"͓zCڐ>N$$/$H*DŤ%l; 6xהo XXM:R_ ޤ14d2x~-Gs;yָ9hr+xҷ9?I_u'˭F{3$Hn<>UVF‚VgNf6|B[hRS@slZBuPTH(bĎ ]^+ L8m\;yLΎL@Jha4PPY[],Y@ ߱VAѠ jeU \ ^b9A*SkE%J79scc^՛rJmi]QQmCpX2ɛ3Rr 8=ga[D;~2CUWOkP Ϳ"Y9($VD)Ԃ:ArjI+YH%ƬG}#w),"*D{>EsA$ܜ~T*ᶨPpDx[UIFyh&NG.ZӑiY7ʩ~^'(X7D@k-2LK}OK _ G ulZ-/vmo[jvr}f7ܷqP?2]Fex}x+L׋RW XON/M iQ2+5~8vPRʴ] UR'gʷx4 \qL@\Nuc +OuM*+~qL n_H?t նfI^Y o$g7uy sv-<9%)4 +| #H}nHB- I^0ʲdFK}}/r +^n uR,HwE(زb~*ϒ1 F؜-%(c Y-Yv6wJ =3-%,b ̘#MKTP}L䶒{9o@3JP4'LTj/yBZcCk!6hKVx1Ձv^|X&P In"A12S eZelYaNSI`:2#P&8ZZ-j戻9RR7 ˳eyN7+}۴!Z4j%Ûuw} cutq8γ__H7оnRo{|[UTI7凣_F['ǷR̅2ܐXHy "le2aƧ́o+vbJ@XO!lqtܰcdDP!E: vLJ'Ϩ|ؾ5S~=bTWd{M3I"_U׺-"]_iI3*[W*HFګ,CGaS@&& AΜ/go߫D=W]|?Dq7 S@0HN!P1pvU44 +JA_Oq[ 'R.q*$$ /I"5I˞)֠fq7Fk,BV0],MWU7KPE*,qcmdn.U߬h߳JrBU ^FR]Q AdôzweIlPz XV4 qM +27⤂FzT=NII=/'l7/ZZ K{c @Z,ZdWt2`4uΒzwb:dMLwtVMl&]Ka)vsb<%OHrf΁۾T,T%ZBr4^rqVr8=E]{NҫVk67fC?[qVh9ӳS{ $i f+~ GmOD7 @o.k@LҘ:ɠ)08j!cE P-7mDM:S9 o$LHW[fʤn7+qj&E~3Њ[<"V|( U<B,NhNƏգ[v,)$SX+A0]h{5Yupith)9KCt0 $?, =>`vܻ-gn)RaƮ*#Tֺ[Ϻ!QՑP q@A4K,e_]Jeg!Κ'` ל _9i""6ZXv|qܭV>ѥ4\uLL 't<J `Ř_As+pIذ?hiz8\. nb@e{JB_jrVZ |x,SW!rGZuD^IM4:X &^ +렷>NuHvMF˺"~,x>|TW*ⲫ<IY +NP6QxD,Xcʦ3$OawEt>v#!Ht:ֆAJ] )NOZYk cM*n6X{S S[Ɗ"-#ٰ1cŌ!:qĴ?B%`h(c㩧Frh"=jwF!(S HՖ1R"MSFAᙠcx F%ɪNZtfY>bԲ:XLձxw14QK0 MbB=*Ҧ +}K~;fu&7\3h23wkU>. ꫘G3N*ˈ܏j)n]V~*Uq{@k\ÙVX(4x4G"z{J0>`׳^*Iʧr|V'`/ T"cf + kCwﶄ`pl>ݢu[xXr#r-OBit"\Ymg%{{+-pݯP"\ KKi:b7;B/Myxup7k?T%[Jy<*$»A@Y Hu#nV2 +Ǎu>DJMc4yLLyBL +H]Eh!3sG1l{Ù1( +\ /Xf1,uJZ,naZ^$/<-E(6P&v0JXrTx~S1^.S(߯=v na3S`2 CR}߭.Ce bP zw>uz4LFh'@-+7SAu֘%C/VL06ƿ'Fz8W~.#4e3cTD3iTv_<3"O)nJ!ٯ:(f4Q$:PmN+~?Wvhd1{kTGF{ڈ'ʌHō!eL>z'`/Eo-ӳU \Q94G+ +ONwH,zoޅ-3gC,-%C?j#Okz6aD_)1|3P덍xQ"dn*xj. Q +Nx 2o|jHgqAki(32#b'H@ա}(q%Vj>fj]``/f9,D TtywoNiV:wJUiż55t>(Lx ,SF0D" ~v7cLCx%nld̼}'RBϏvFW,W#=*u:=iB +*KDşR_d7 SSY&gek+g vI*:ʔ si<ò; x֦+vFv{n-ov1HU{wy&nI7 's UCߺL'{'Z?_ok(;m?Şgޡm`-Yjt.̫]!o 'e}.%{罳l-MEcJc|~aoZG,}:/j%FʜsW-rэ[u4/m]X;_׻v0;Mŗ6RϷM4jkXe^!y<|9p2oO&F-/<'G1Q?k<~.JK=X|R֏Su^GI:ŤL]T1{!4nSwqw\K +K0-ߒQ#qFY},+fعZ+% ^%[MD_LY*r,M.d=q1x{_bwYg{3oQ؝jsy{?]X;d^*gT䨓MBa{펼q#J|en 1ӊ/c{4?6DzyI׈6RKؙ  [I)؉; 鱳{Y- ba#l~0v}I@^/yvdL'`~Y TZN1Yµ$S@9v ObKI C}ӥK[DK +ϻSkVס=<栞m&418E}GV3?eR6UbFe ͤJOpv=iCl_!| ׺HJLId[)=L,+D"=ܼOj4{kh lƫX^dYNsw?1?37OR2wR1{ L)=bO&|P њj~2 +CgzD;ڄaWk KMμ=^!EAZyt +{jyr ߭ ,04ȷ$*tUrw`"R.,?*$K,$1]n8տW0FKkE+bw4[xĖ8^3#c~*vn-bR`m#1;?u[ĕ6,HJDn "i g#M7ǘEo!u}ma:/LSq*KAA%'#28,i=<5$3e&""b.:ڢdQ4@GeӴ~)5$nP X] "gm=$\Iuu +7gp-ziQRK1_9Og rfu9שVB#4Y +Z]:%N3i#q]=/DD)i?/Tg,H6":6G'Fڿa" 7 ' -uHZM؈9p&DXUfuZ% %m ,u tIZV*'=൏;,q-O2.O. f<;!W!n~e脱R␚F j`^Pw$DT:ӗKb+_99BSm@ˊZ,r#v&EgVa\縢%Z7]wK|‡m|p8';Ŷg!#TZ|`\ [^ 6VJ/5yb-VhD-a )cA ˌU !IHICNi~``"Pw/fZgclƱ' <4 +'Sܐ6eyz#<.`O4,h!1>{]ϡƞGjRޮ,Dke9X:.z@jyOk.uHI$AL'nJ4euF.43a +b85_ Տ138E[C9*&*kAi}8p)9,Ⱦ&<>S98r KFܚ_Rյ|ARo;%M$=ElJP8;85_.sX䉮/ ƣ-HcʞRԩ&Ec C?Eڈ}:Dv6qrewczY>h\u`QOE[sd1Qhę }/(QF0.f孻Tp\*3H0RY hW*8Sq'xI5'|xs8;N&tqe)MNE%WMPIJx-dTBqJo+.P+^@=GWK%Z]¸3kx2z߱m0/-Qװww!R+Xp, Y$m\9=j)aX/,FR + ]pX~jF*bH粤+@Nku$`H/ʲXڊG9zJʄ.Q{0q + +ǯFgUXHZW@  =3{qꒂ/_eK3{Y4Ҍ IT'I-Jagƅ7Zb)ǝM%>`6(c]I6r,eoMqLR6dULb`Rc l0M.cBɧZ mR(>E! nsQ:7XVP6'OBG]+D`,7E/Ph 4& F?`[vif  Sq2.IQanU`jCG!-;;w4c5t&>rig7a| dJX[<=wik`JOC52ݽ[R[B#I/xim@Hg[ε540<o6|:wµc}&juP}Ţ߅7oj)! i 1&8ƂGcGO+9lPwˇW,32vm. qWy}{\:UbI( (h!+ +Y9՘BM+󟗥z>t:') SN[Ţҥ~z5R7;Rٖ1(CrYb@ϪZiA{xqiժUa֜3o4(D?poM[vGRJ/ϽyB{6S {:͖n3gr6n[_ErG"#vkV\Bˑs\ܬj8S7NS*_{9p]"oeÿ|,2l+|ُ_] yQ .Cw3]H"/]lˡ@( +dF¡ΊD9$mk8ei%6J\|ZZpoM];ִp7q쌅[+QaIrab,K#W4{;}EiQS u(X ?!Cٔ='9MA.uʙ{q )12գQ8/'W~AZUes}i)p`O ӠAeo?\ GYx9 DEH-M;z?ЂSIf(Ig_3mv$|9J>o~9ho#~ +%ីIgpy &O-OlK00E|rWr6t;5)%F_BD{#npJQ?G o}w$ =hE},ȿt_hYüy0O ©|^9%Lt`Bs%lVZTMOgEhZD%Hޭ3hKh`„y 5}g]m=C:M̀l zϓsDIiSH6z8eB(+äxcx`Etw|芦|$Jݰ3q +U݂yWL}{ C@u@lB]S) ;xAz0$MI@sXۈ>POJcN,J)bXO%aKa|@.x: +lx^bng.=2FMd m=? %IP1ΉCnB(JI>cX\21Pyu<9_|@}ˀu앑7[M74)rhc1W7᭮pwP+-Pb%[e=Ǫ5Rةcl]ٓ>e s a +u> %b4#5px<ϭYoZ_+<2n \. ZGnwtqv,hgO +6#/\ 78Q C렽~zTIrj $]*9[)bg۹>C| zX۴$25:Hgds/:gMd / kHIs@"2}g-Nu <ƈW9tlyٓYiǵϪ$+Ф4)V㡛/$<f GUy0r%pYj ugT)." 3yZ\)%囻MNC2bU*!~gsr'2mO,ỲN $;>q{p$y8 C?5Q .W@{8s'K'w"mT߁T׺r%4ř@GnϙEz +^gF_:+v`EpFLS?^ofƤ 3bVtbe62U l8B.0%Xχw<~24qxk sN!dG-`xy(^_2c.ͽ?xmDě@ !MYX{hݘ|?M y?fl \LbB $m5![Jg#`'x7Ut2% {q˚j! +0mCFT  opz$0nqͦ³KT|{9[qNکdeP%"B}k&Wc v <VHh-B&ښ;X4յ:MOڲ,4iঘaB? +M/bU ?1)!a ] 4v(oO5ۣf +8$p|T6Y'Gu_5qJPyOu1 +  8V@2E ߐV(`}8jt[HvI~/JŢAKչc~2eL:iK": +#@eu9q +v5Qg͹ ްEz [>Բ==9ϪPSr}'ÞssU(kI."B!:ҊF@F^ v +ܭhU8A6'>h]`fw;eMZIPw= [+ lKpj^k@R 3Wu]z3j1A(Mf(w5.SjN97h3 'Ȳ,fk@ eO~8sQOy} fՏҁǟMC _<󢹻 &!%͂I #jBs1r%ɱҬӤ4pF|?j?_EZ&t?G()99Ϻ\_si> LGD2ʨg%^ˠY϶ūqYrVKYiS?.C޽}xq\j9n%mv\Jqyɣ69B`vHےqvY,*a5lΜ¯U +IZ2L#"\tʿ穄lW +BMi6ʖɒikY#`}ކz)/&* +kCRA*.jHj3k@*2њ.B%QQ"Oކ+WZEA)SVצjsEh& ,+LW|RhǰՓhèQΫTMG`>4DH􂄏0\n +s /I[?_ċ"guR0K~6({j(1XeEdm@s$!d4vnXPU,'ƹְd/٥qq>'#\8ws9>&[+fJcv11r +09 Y5ONht^}R=fc4uth\1!o[y<D P-)* Q8{Y}|c.ڿ\Bt_f/в~n!pw=6k;*}6^ }8_Dt⾞~yj;?KDqrr\{䂧g]Xp9q%w +SHϫǑcӟ]ݻRdǥ`7xy]7qo+ -yթ +GO/xʙr~nb.G:x,{w ]l>c{>|skؒz-MO(`dlKpO0HVıyd0W̃3Xq=p +hEo3)93Xʗ3spnXܐoݰ:۠P 9PKI]Hm5ݦՓ֛lEC0mm WUk(\s^:huԫm.hŒ(pI +d&ƴ<|¶^UHR',Ro}:R7 getQ~~q:CK6yT^u }.H1Vxx}'RŬUCcśSiddҝFt2[ +t+CS*Txr$|JJdRL}1=;S v䁇=lu@GGDX<ۖv=2-τ|eJOn'V^I Fe(8tH +eDJ$MWvR-+jTO$ ڮDשv,['vsDك2F((hߚEHvӔEMDs+A^:7gF Dq^|[GzVDQ yQɓ6y*FIP}ElÂw2Q:A4Z;xo}ROK$D +1D":M +=G.iˑxy0hCbR90CWHN袭6j[{Cްr={# ןPR~‡EW8~ Q( +endstream endobj 98 0 obj <>stream +:a'ёZk\/Gb*wwPDUp*qUL 48 b WG &>=P)ǍK X [ +dCg f-{o#f3{D5h̾x`wzM uAdL~s YJ99j+P +|Dn2ueݎ;xK^/6ԤiY%4NJ,=f64 @+U?MԗI aw>#ω?It2T泯S'w(\hL*3Gn606!bItXHMNIHUY5B 'rMP>*A |kWϓW1 `XjUPp8N3em`tܶ=g;'RM:_<6YV;V%JJMX_Ðn6"wn2Уy -UG!Q.WGY#gJXβ_LJ=Bc5*'.^yj/\=RP|/ErH`pݻH [|lm7_ _Fp$C̄鵳bX+ Kίf.=x*4+W4"7e999ϾevQt\>pOs" {dXCt]7ǹ=fcǐ_ޔc`tN< %K9]I6wLnUte)0Ѫ|%>,{0b+<0$n.B+:;VT:t}\iB̧('& +/ty +jn: oӻ(‰_ lV*۽l޴icBޭ{S~*="#_kQ_ǙJp2#`TE٤v7d׽hhzPp~M( +m%,05.AvtSgN?ĿpӤo:*dx^DΚ;pl6)Eo#Tm76a6/.қ!׍VM5L崟?{oߞ*i˞AyT-/=5{]}ܝ> J''O{xK8>CǢ'qKC^Hy/'{7n`-^=EEp&g "*[b.-EtQ>?-[儣8#?;6 ǰ\_KrIpQ8T'E+ +?TqMƛsO*ϵ 7zh}}^9;0&2FI*;.|>R܎ۚᏐM[g91n|=Y2I:_V;!)d<^=^K/sK]Y:zEIR|p[s+F"c޸ +J?9GHW˴o6Sqqd8rL~"d;ؼ ['-v)EtGK&@~~v^ڭuWlNI8cOBuo>O7D8x?>eT;z=!30fDb_ܰԺb[ؔ+#!9L6{^A>ۺ|m,&s>[^ v >9eZ'OQz=(^]0Ϗu>JtnRF|kщ1[vd@ٙSus sltvoʄ#pz=J/Xv9 ;w߿zH)ZNx!wzj=<%}%~dwϙcz3ȭ:vc?=Ovw/o>Z^/>U2?9Nɯwٙ< dܲy:??T;ل<>/"G+'!7T//8ƆʂEL4^d}}"&D~驺O&6<ӒD0.No}5o؛ojo-~9RJm%hZ"؇p9es"0,`RܓJ2XS{ 7A|ؿ9t*:Z&\@%"l?jE(bŨUCK\,vzq_mMZ;tSF5 Gv`ޓ o63;1TګVSg.ODžg6~5 ,Xa_Yakq]-B}ꫬZ5}նE3POϝů)Y,q +KpMT`ΘlYpSV.nZz37m[MQDLy?DXROЩN|&"`m:W)ζv~S9^ұG;5efPIBiߘ8k0a0I`؟1 zP JJ?R ikvrPLٿܞ`sbWc<Xݣovq)7/߭ei]ˬJ0?PǗC<3)կ_Tjw. +oJ_޹6/WMy)?x90[ˬGbw~ mG+sX~zH[@$kc5){毽YX)| { /MqaʦlB`ry8h:7/Gc#ɤi332WV~gJ6ʥِ\?~_n˩_rZC?0 Ԕ~Z#hSr7/'ͿU_NiEtX>k?9hW/oN?: ~PUQWt䔣UK맜AN?<?-lL?#Ap) LV@)9=uOgaN9f҇_VW[Eq$\硉Օ8h['K.#[D)PL\R'}9LաU䬚% e[K>pY)lI}Hi͏hKaHcoCi Z?wQ\VfVfd?}Ń෧ܿ=z;>Do&CՃgr6jbOφ `/}LRZ7x \'dJ%m$*1٠ A90e*Uөa6#x[>M+EwKF a@Cw B{ 3Ȍo`R^lEw >%'N5\{ Lq ګhx&pmfa:7.C쾀MQoL.Yx.ZGYkkݓHM;~KՉs\imgALSmVl7)f GweqPz,a#1?q3+R<7qԮ=H p+D +5~sBIKiTdegNip2&_0/+@g 1?*NqkL +`׼QB gXlGE* ~6DTI/K]b{#)E&$ =Q qmga}o+#/ 됋B\~\]_ypg%^ѰM"f۝'ߢm:>C,86{vsU4(bv Ҳ'z,E! dje̠|\R[H,"75}E>m["*E2qNd 4I€H'iHt(tFz5?nٷc!Fhؒy~u7EpJ γn$Yq8 G+ г$fiAذP~9Aiet]E:[$M"\T9H<ҺJbH 93m)Իi/yS8~| '&+Їv$Rf4(7j$%M"}'$_ 'e NngۻwZɗ+6a Yi*4zrjoݙ*hC X TAFs}ʇo903O d0bB=7U| R\}4ׄ#[o!ݞ-Cͥ!2%xWE23>:%IÜ<,U),6-nc"!~x->D}3q|K ;c$lO0;hHI纲 PŚqEiEP#0QKcqzMrth+bҘ/}b8٧}rY<佼V@#}ΖAq1=-{"fІauR\&,W +L5?8gIT]"d!ܝ8< ^8ȥGHɇxta˽{IU{Cؔ5 vNvY.@/m4 ׅ@u*|ʑߨjіdpQ"Hܓ7;c4 WԳħi92o +soh%˸b@lT B?TߓG0bE%G <58`gWϓ|#a m IXk%NTJU>uK&%TC:A<ĀM U$tXv!GDz˓@ Ilċ1I x nNR><'FJ +zGF*h&X )~ضaH"h!X+RJ9 RH+t0rǏqBxHVJ_05RΑ'ؕrk>lOBAhHF닏l}-ϕQ Ѝw*CJi{H`JuBI e{PG*>xH)[!OYj9.f HPYX VISpW_哳/t6ui* ]ꩼrq|(x7B\@b ˶=Igv慚Z$~&z_qXP9 [^n0E3ȱ͐@-ck(b!C %4(47>`_< CVĜu-IA)5g8pleZ.&q;%ZPÎrm!`7)/2/+iŻ)!BuQP"ol~&`)->l In?i?"SCOќ kV2]<Df =fpBc^%aqrh@ 7nveP'{Ƞ(sx@͐@wӾx9HK[M !3ٙ 9ytm.+0 G 0 @O?Yeø)v#xaҶSz .yZ߻XANJ AEev-'m*>8vZ7Ԑ1Be٭lI #e[ 8=Hy(Vk pLkXy"Wsr%93k;sM7PG +9)N*mJӢy3Ng< l=ya&(A+OojڳܭW53&jA9mBA`X4 HDoUJu8d+UGH h F%%)h+%V~E4xL,iQP$k[< 10\7xot?<|*_%9F]&bypY =m`RS:& 3oIO? 4~ B,+ *˳.4 +WT.8NūH@8E?|HxwLV{P[q84J„H(+2,tҀՁ +s. \]tXF%6W2#~TLeQ*?e# 7eaMDBҗ Zm󫾌զ Vյ}/}\xJj_jSƘFٗ0ZAYM݀E"14V%`jB#!=,Byp0ٖRh#w^sX@gltnMӡh4rtJm@(-C(!$z C'cR :LgX :& +޸@2S]N 6ʖ5D;SX>ltrY1,dR{մcߞ 7:e( '$1䨞`{^1Pjb aߤ|pc.3Bq\)n]Yye6NclR8"W-n)CQiS0'D,AlVM 7ԄGR;;~P59tf1Ag4 (T8#!lr(}CE rMϙiS+~Ǚbp{m']q6?/I4ȹplaڻC@:9*#;#VHȯdKQ+*.Dsݘ q,6yObmp1(FAdIMɕp )mQM} +n2 ӴmctR?xd"HȵYv8\(+6FFzuc,Q:$㈯T,. 3<$Fq$k/ES7قfP5Eފ!%"GExW+MAP#HK zHT)vߒ Z2特.%do"6 {Elsۑr٨ߥUEA8v20ߕP0l]Io( * fIB~+K]c]N%@ϴ0."eSCAn QL_U! 0X\G(jO!;2aBdyœ-1C{\860{fO>U)ҢJЎ,,PLs~k4AA).`<0au(m8( IL)/L#f! &ěR`{s"ĝk!9yFsdpv +U!&QL~XmPBUtht1M +&4ˈoV w5HD^a[s ikI\ @%2kgHqu(ZPq.|HcCrc}oŔE1^ZS'VLK$> I}&5ݫJKS Ei"w#n:j#I^7>d>cAeF5HM>i݋ZOc֊ʡu/ݸI8rE=E5HcF]u/cONiqW2{-FURYEC!'vBȃcp h}'af:EHTVP]0*U' ȡ;wpҥw*5nIװЫ7* ݫQiGX"{U6;fNDO,/k D- W.|8 @GݽU$fG6QxrEXHӛ:\V[m2sU_k1 \9x:<a|kM5Y9E ܍\4+ۉfhV{@hV*p "F򙟶d*M8 &sdGqiG<$E᱖°ʴ؊^tD<^P܍:~]"dZ(dӜn"~/2ߜl8tخ}Bð]<^Ԑk?!{^vN!zPEHU5~[iϭʕa2lwNs i4*DXrhp)iϐ )ޖ*7pu U)ew_r4 |Ua= o\`A&f d,2ߞAl lONe32sTonO!`fa(ydŔűM69~4T*^J$4X J:Ȑ|Q[DR''DdҋRwzVʺWYe O/LcPgGwD x~ku57gd?ÛTuq[XT\]dNJl.dC=}bkHqɎ T>NUC32̈́)U؊ngoM2?:b53'7v]5LA@+ (hv9~$FuqAtK](7sPJyC1eT?k\j$:e<m"$3#1b:X#aCz XY ¹wLIaw2qvI(hbnyQVfV|rϼixx+ |\bH㊌2л8)jSv2pɤ}GVV +QrIb`5;]'2z-^yVvr&ׇF}0>6:4,(D1#]-j#dDblt 鏳UdN*)}BQ]2hH?)WLZQ6@>iK>6| >RIՒT\eٯfEh8[W`H%k!NB)g5(PB_NINgq6jqw$],KFÒۓ%X]Y4xhL|l1Sm=^^=9?$&=0hۺOpd\֦AGggvS/\6;@nĴowaN:= G JQNH IpPMR䂯 +RJ(v +\71PTӥ8Ϛo(vۨ6 =(Nb~^rso {Q3{>4G_\ڥ/FP GP}G3~ BRlizuGF:Q[}M_`ݩ@ZDd4|X[}9 y Z'LH*I =D+϶nj_oNyޚ=*3Hr$ea?$T 4n@ *()NNu;+7E\W1&f*=k$ -`}J_DN*  b9J@{usLmOfkoxdw.{ ϟD~Br+}`֮LYyq#|27/zTB7,W\-ŒX{у˗Uq?W&]r&ϟq{>,$qJGR9;p썙j>$_M<_cI-^Տɓ"]89מc/x[L13}:slM䫻;r'G: k/`Vx^/#LLKF ̯l9b=FAb;}3Gb/լ߳ 8ǟz\ew4sl0h5Fbbʔ)17aI~{:W<659tήYebP!,񍥑m&\18h˧ٛٔ_7^-⦐zM9UkɏɇIz ֣HNң~0p}M?xnʻ/N;UGڨiQk;NFk@#= oUvpkUMfG8zPxOܕ^)LD`)ﹳm'Wih_ 0=zE0[|x\vh:*,z$ț}~Zf +UTx..Wd.;MjOʩ\]{뾻Po=I4M^ w||#LaY裑-!89HxwpȏPau#>x,x"v| ;_o=bOsXcquX62^y9+^xE\F:T>')xh}3f(#9_/z8{x%5YWmO.#hoZgg!n&h0JKfp?$=B^]\<qW^% T${R<+]q؉Z5*rwE. @So|W4U\V_cUycZ= M] ̈'dU3fi韯~U*vL+.V2rhQ]ø/w!WE@3VO- ƃ +|6ezqЮs4fWJ+MWvHl9iJT +yV /Q%]*;THPmv (_p ! 5YX"{P5i+*N+:2]ܼHq9o_T@ sҾ0/p/ ldk Iiȯ?ցC685KER-1 +d9*E%fHgPeCHJiY#$zH-.'B~b$Ջ10āpCd,Ns 'SIw[QTR|ўT) tSz)RD;9_Ma0QY(&3V J/a=(#p5d%_*5@[\ +=Cq(NoP.-8;>Jjk伇UʤuxJU5As!( Vmm +0( G*Ú $h#'^*mdnRɉnE;|Xxqt@Z^h0H +U%ztm~ eh'=|F_@N Y&eSQa< U>Kܖ0BŔȒ@Rz s1%N xo $БAwƬu;<z!,|A~/y<@o"9bg0vfR kD +"H#CR{iD["7?0&t,T%4-!ES +'`@{j&TPzaKQgedlgO'΃219!H{\ +58Ip$ոE7Wy!,{sAe"+FB޾ fmQ<0@] +hd`;3oH'rd](JG#R +4,3r\iPCaꪂ t$E+*|wԨo\C(N#/WaTϗZ0C('|EZZo0&<4u׷u:P"܆wQEKh#=\"H1 'GX c-Gc7׋D#Mvz$IGe'aWD=8uV7QؾIE%MC=6ĥɦXVd%'D/ Gbj +(EΠMImf N`ܨ.R,B1-!b _nCV,` ~/Dנ> +;``qnc1SݐZAI'01C'ļ͍$2djXX."Ql9xn|sGtf0B%2pՂO%1P (Tc7 + Țd}pI-rm(t擢ϾpŬ ZVd4k2LWQz1ͮaAch:Sf\X aLʦ>e^E]Q]Lc|>Wێ<~ŭױ\. ^!>OrmJμ׊Gʁ[5ff` LP6{Ddk&=$ + +ُ3; *m5S#Z5?^STI/{q?ȧ k A`wи Er,:dY@ްF\>9Ľ: '[ܺ~"">lb"Plmo1k}__6V "~MAy$pxݡx^{˳@ٗt2%D/'g@1}V[ִu L*ax0Y(DFiG9/lJ%A{ SmUٴR Hy5F/=[4f3},۳Y)bUy9e~, +H}3OXС}cTmdK=JWږm)eUD9dOݖb!N+8-Wen^ Ām=@#c ^A*Pq#OYF$WdfYe"r;"]CI^@_z]تnJ ^'kX/{{CR{M/GkR¿^{Mv^.Z/"飌f.^{Mtge:0 *WvvB-$Js]C^2^g.ܛYGٖo^eQy^'^{M:K+Ity[/k48 F5c*sm[!)&e="-w':DWC'! o! r=?wc7j}hohyE-yc78d9޽(T](k$l&PM&*SɺJ~e~DUxEC"x::F2-E<ơUd9,,.dV'(2RK{*q <r(BZ,5A&M֥tسٺY e]1kϦ䋗~pZy6\/%i{6c|IbgCa6I䠳ʐWAP,~pf5V`hL]Y [ r3\ޭY`lκ[vip}v\#Ăh(i*)]WbQCptAέ N 4i5XdxBskw֓gxb#h}b Щ/t'l F%! +eė<$Em*4~J[ -|$`r1jn_Dj{BNwj!r'y#}ǛAy2áQBé6L:b[;[p=05"pXYvqWb7*P{er[SO~- ^67piW"lqښCbv,7q6DjRZI$ +[Ei`8Q6GvsB6Ғy(z;HϏ.H.s,f–N9?zFl :dn3ypS-_ zF:Lvkz<[PS4!6Mopv,[$_[ BWHkJPDhA7ub+ϣ#`vcuo ",3eConZ{a&G$(݄AZs^B E]8N>`$aNr.I@" T858%^;117M+̓/Sp] o1 + ήj[9q[L/lL$}a}='8a27Q+a/ O2|Xgc^_vuO[ 2ˇ8~i"s1/nՈ8m~Ժ|=ТrE%{]@15A.dG:dX9i.4@A_RϷ{ǫvFw$rz $-6&nQ=Qlz(jDT)S]D3$ʋ49iEբ;9Q[u< ҜlaOҗyEd}m8l_j3iPt<-ݝ4,'DLB\ :Bl|~d-|؈n )Z<3-*%šzuO3sHVyDn'1c"ICmGW GA_Ok{d*O#ט?Qooh dF} +o.+e !3SCFV ʏ1ӵ]{op5=f6w[+ 8< ]UzΣsG\;q,зm7Ў Ő(0h0k#S0 +(8 e1G:ؾ< JG7Rx`my2K(tv h +!^_m;bmGKϠs? ;CNzPx#|{b,Ŭէ9˸bw;h%x):r,tjweU*udsV(-"z7t"ql|揭RmO7Pr2#^5_n*~zeW屘<ƶUڳ8Cy..^o+P2\oe7{[]T7nӥ$t7ɔ3ݗ$zs9W5Rd©|1505{zU~"sX)xBln]~Fu=gBz` z ~g$OE^WÍ7[ۗwW:C*^,bo>|j$#s4G*_mn\_od)1ēZ*.ی>FZrL6L&t%[2lճ>Z#:sSfw=gNbP`{!/ҋؼҵ?31XHehbúɰHww.O]s͝No^OP?i]O+sͿNxG#Idz|[V\rψH?ǃثFq2μ_F4{-] GϙT˧\.W"gJ!J@ a q9c^oHnY/lxLa#*&x +-Ŭpqpq$rda_R6Ux}ZGW2So)u=^!g~.8RK%뷏g_k:y;BkuEՎo&D~~uXۥOqv3}۹= Qh1װ9sXmr ~+}  A[Vbop;U +)Ľf?qbg,븈b2]tv=FXbQ"-rUZC-, rv6m6s^7_ֻ {olmڰWA+t,] [cgɛaF;֏Gq\6RHԏ=Ed.* +43px4?xu\왤ce!=OEtGPMaE&O3D(/*aVrו}.lyrJRVu;7_SuTP?St;#y<'nd jXn;riJYikUlW*ݕk^pLk&I^ص\y2Źgӫh#[7`P]AZm,!"Öqr5R+(xx-ϝ6z>Utڎ-Y[dXm9xp+1y|t<@<13ӮmdACؑ=(Ekibq [bj3%6,[ jw|q/p{|I?-TŧT=9 +1)yf-vsd_'ɑ2>IО쩍> Ep&dY$.0Ym xxr +{ExY[ce1wܭIΕhKx1OU.ľn䜤؍!Ҁj&9Ĭe#HW 10̼@X \56<->ViϑX\qH!nJ{MU`]yNe޶Ee;(7O[7 .ଦEFw\S|jDYfųw<1mQ9h:,MZ["x4hM| I۩p7tdwV7 AN+KoP7t*حt=ӕf"8>P( @ߥ#&Pyle db` _jh]!nbGGD*۟9)t9N8  }Ex`1dEA{vfa} Л9ف{ L+Y<0[ͻ"&4l=z1sC}^*Fm<~B㎅tO4N!L(:h1Uf btB'W +5l*wdlPEqFS&^й*7C/DȢ5 * LNCo{B +H|- 2^P" |fzg]Ȭ_01ZF4OuJ kǮHٓiG =10R @_x̙ăhZ^>2@  5%G;2H[X>7Gi-eJfo6qE&).d+ɛ2FE Bč|$X!ET(b2Q !-! ]HH,#m"O|F(k- 'hquIl@!_Q[ EV e+}6nER{6þt)KԴ׺ԴDU锢i%.QhK*,YSx5EhRfaW|tۘQx4YE`[aYT"#aLoʪ +P>Ш o}%gѝ|t>/x.ͨ80hwCį{AH3ZϘ't Ǯ;]D_D&0FBI xJG9 ;yЁ *P@iyAAP>LmZ +S3s~ bd OZo! qBQS}V1u,8gA7BXfYJv(,} rܗ8 v Q4,RQ1!IGPu<D9YcjH%@d+Ԑk&RuH) eԐQ +o +Ew\O"o*CQ = T3*:~ CRON>vNR ] 0Tj8]Csj7җS#*GTg5j5ƨ.D3~Nd'6aQ歒c7KL]'h @ >E,H` F,A@D*|7GV]#]}oȗ]s7Xt*F}ۢśYt4kϑf4vȫ +t0D˒3 + u,g +- ޶ b)\{^9A- a1[V?uEځ,[ HL]մEEQ[ U@ʼr^8xG?+Sc m ~S2 $F!$!3ja4 ýؒq1H\`ހKr=$Va@24 fp'_cdFoC|7ܕ>`Cr{WD" jE@akvrz#P'bf iG+?\!J'HH![1P/-Ex(7N:@]?UEP`83ܡed(7ZCI}ȣE[⿓tx=:e, ZF`5X[wPr{$X$_pUၼnK@w!rkY3`4+oC[DfKTKz @c8burqڇe|M 9;`gmCv/,d;!7\7K{7|a@u}.] +L~ؾ@D_[ @78_+{fIa^]" ށ,s5$~R< +(Ёw_)@9`Wu[,8?r>.e7q)WG|]$12P(=lΗq\N%hL$z_-_Mҽ&:jDA^'τL>)(㽡 .󌗅݄043}6[w,]%,,1y-Yi?{.(oRKc0_9dE⥟alXtc9{ʊ:te񨲢>O{- +m5R҂\֑} S՜N*)9*h>$ '8E)ݍg)%5Vm5V[U0`~4l#L&0FIs؜'x5Nx)n)=z Pk? +Tǂdi}-E@P&!Kz# d6uJȜ4u+W|lM'9@ W݃+l'xȪ՚ m$ VˡӾH~>{iww87IuL.1$=ecS<&LDNp0J}@Gnɑ"N +zs&=wj=_3a*k @{ۃM*[VL49^(t%ԣ +7A\?f)?\ +A6 tw C{JJQfL:2@U.&A OnYM+ Q bƼ|c 8 )J2m3/yyKJ7!>KQgrN]tMLSGkEW.*֔9@i, ؽLmzvLpA~ȯE+5qK{RЛe4 +n07Ʀb$<lEFl^=9}6|_Li#ebD94KDnh*@7YiFKNK^'|}~O9n;oSRmanj +٬p,iEF"7.8:M, pki`[ +Jh)g)r<*DGIdH%ϹM=O뫢WIז*sĮ*^nE0Z3KBa ̄DMҢ\-,.FhFO+Fxhg10ExV1SKe␎ iX#h'- V ȭч&W O͖f2k%&4]:B?$AA9C&Sub,)1:} &1Ң{ "AY~N*Aެk1d9(`{79%#AA5dCTKi,db>߁'מdg9(LI s5q6%XvVHwO  +St3{㢁IsD)]pSQmq+X`-PW!vr+Ƹ1@t s$9SEb$Pb f܌y)iciƛ$:ad$bG)\pj8[x? wn=[ = ^|%F % ñEh`HTs~!wCQDػ i2r>=-]A9$|=sЎsUdESk)/B@ E0snڨjoi<TzcJ=i{*xon3(YvTv:" gm)Ii)q9؃U+E17 Wmt~]TMVXN{=N;Sq&F&Jyy}xob5cJr.#?jj1#Lf=0Vsa.7x伓wژ<9#fqJfIY%Z/Cuf^y7߫%o'Kz"zi,g"2Srr]u9dDkrg ۪v7.&U-t^.ãdVQJ3:*֔ʐS\Vq`dynL?ZJ wIަrg'HOߋ\cmԫs_y#썽Z_|ޭǍU[~xui|e~/,V{Ͳgݜ8kz]d\g'D^xc# ?IL%>7`by !Iz`z}:ϼ3E04ªwگUk:Y\gQӢg]usՉ5塏N U/&gfM?U!3a|R'@ : Ѩ>ŝng;}2` 0d<:tP}mU5i(W'gRu , +y=Pdmo>H`/m1„/Z1m׵qFeEq3C`/´VES˓)YsOb遴&"2hԨ=_DayLw}A[_Fz}Q)L{ kMc34NUI@cֽOc[X _dhh1h% +9 [![ؙؠ+EO%fULB8تA􃨸%RCq{,"8j28VoH1pL;h^85ѠV, ̙I,+v$"ϔs+NMMc,Z^DH#@#NZ#!"й$bg@g4?  cs&Vw .wMig6`)[<(t +뫐u1}WғVHLҋn?Z{K +籝 +t)..^av^H/r5p4úNT/_+:GTճz +/e#WƗ:Zn\o}Q2/KWOh[6Χڔ|80[u>YNk?ku{@X(K.{ XH#[|⩯ol,DJЕ-Ri_q&Ot́ڌ.6Ow9>]YFY)]x}kxyϕ| +',5]oχ!;L~æ'g޴_l8{h(>")\>rd1 wwzt>yt9}uF-Y, ) k9gKBLnP>M<5 #zLvR &_tGtγUK}0Ԓc<~ci-bms‡؜eŦ鍗b6\Hpg_Cƙ(/%sy 41 xoFpu[U]\>Txij5 vbpr_z0'9 +]ά5nן,v]&i L5\dSyrcD6JqtNI~tD *c_޹t{(}cȍ;3z}vJ}+Ӽ WmWw~0\4Mqy4ԓVMQ*ݎuQd'/FDbNREcӫbD1x%Jn <} bAP6.YRůg-B83L?KޚƳ?~YA9\4if}*DfXe' +7ǫX6}iO3rPt{ {f<|F UMIJ'9qx~xpDuLt8Enl*>ORlX<a#gJJﮦ^"tUfE=3ZݿI,w{Q63x}DtI Cۣm&W8hkQl<^ض3wD*_̫J*0iJ. +P06x^WCfꭳ3_fd1Ou⊝*P%e5-wŷBsI" 7 =g5Ȝݹj[BEXc,m|l8[qMWYZe.R LY ^Ί%m8VzqkHgNܦ>3Mg; e|Ջ%0T3Xu>pXReu˯Y/|{zo&Xx|!Th|njӆ, +Rrs%(l6888Ҿ"Ny&Z n S2;S{Lo*m̭8:ǡ~IWA"~;\=ڜ/vD{<ٓ!hvŀ ON KnN`;Ofe _XP j܉tcN +&Bη"o8b4#؏$"c*[SߒYC2:i +H\OD({B%H7o(w!xX=s{~x?ֻ7T.̈́)ڡǿ2?)&Bן`{nƴ&"CHs{!}F}KCVsQ'Z(۠fOSW-Mz=޼mO")~<ɧ%gDx'ī($)=?~NnZ6Q_mO9V&gd +WU`}^jcNlos9|f7 ~-*&$].QDى6>y,d[u+ݲ^ٲN>cEb)>t\yѽ4RFHI ~Ш,]O?< 䟛!LU35I Fc({BZqφwYJΎ5Pe9&e9&v"JdqM,*/,ޕ۾514*fYǙBGnp"olq]/0,*gk~zM޿? ]F#w'_ԹdY ڛcXTȚP_|YIOUJń1qfnř3gq YwV +(f=ыpa`ouk/eߚ~A6N jv^n~ESѳvt~h9r>aq>G?9˱;g?Xso$@`H8T}cf%Dp 3c ~JL3)'0χa #H%B{%5Y`r>dy;l`!¾8ONkQweU;{BRLxN%:.H4y^4g#Ad[Ɓ4F"G'g F=6rB%EIPȥnAL\RY&Ddp:Ӏk7/$n*PG~Lp !巗%0{T0 9h/i`U,X3&RIܨH3eHźѦvApձ+||B݃Yg:$s*Pw}Il3f~CW.vb)N* 2M_սtPyT +!S +11 >$`a6ƈ}ScD,Y\LV\m2 %-H<ƗvWhXHf`#{N+ɔ~ʵk,rr 5;t@sg,֋? +Ak nB9-1L>A~m! m3E w.*m$H?$Oi'#3Pӥ QْShD+QCO @}HzQP &*`jTN e@7 ʫ_ .UrySAgKŐ0I=;i!d)JT.r7sp7ҷ@,33O?3hщ z˪fC\R1:kabʯai<%[?`q7҈SüҮĹ`w-~LyApZE@mvv$gҫńSj.Z|8 N-.vrӌ.t2NqTtjP't]P W_sG] |IT( +Ey;F'xR0t( OwlʘhJ-{+wJRx%,% XPS)b.`\-J7B7'-zFFHC8A S&uLPjW[h)F1h9 idcb 2;)8s̘ŔVJ ϱ)tաL߲h0.H)B:oliMOӴݒ/q ?˒]a?SyW%}$g4 ُ8'5hz¯CR57P+hY99}s}etY>\E.<R"tϥvfc9L`:)fX|-`!09V1%O"s3 HN3 !'A+#u݆-d!: +s/>&D>)G,wH򩚠OBr0 &<W2%ƔDF+z&Sڗ>MU=?"w3c`D\nlp +@MlɧTF +ŀ䫦d Y2O310~38~dU^PoLk9i2 ע 8}6{K~5~R%978yQ%PGy.gPF_U4]\|>Pk_PBqM=9VkIcHd5Ʈj^:d6E.9g|q]Fi>IzDOx : _,/C9:2M/cྤSD_T +Ϧ,.2fMrii +&*LM\HaN3V[:WpR w +f8}[^4N#AOcELY+Y5`RՍĂ($.Sq6cELEΔ*:t2s +bdfǎ*BYm +H\V[>L"FMʓ4ch-NfZ{f9oMrZԆy3v1bN4+ͤQ!UE>_8 + MVV`|-pra1Brs +z%ˇG΄$S&*GarLa~ @4Uj hJ5 !5"=6\v*ӗqVoGI#%,r_vOlG>ꍝ̯+I% +_Ofy#2q/s*s౻@xb&K)RCNGSX}Iƚ#}5"(%۴բPXdyV )/B6sXYزj(<~Yj̦Z# S3rjN洬zG^PF⾦NM&j͵DbC{cZWbFBEd#0p]RM CU4U:l;6qdDk٬Cϗ:⡘W2Svx:sSڃ47O O,0X '}V%(}~wi_jxuonclwnNo۾z¨;IYN<Cj1d)Dl,eBRiP4<JM毈1[pV*enj|75(yT|M +NQHMز3:Ѫ;=PΥo;Byi*Cj *S%-IլvE:435NAaQɨB@|c"5򃔀nLJ@ NC}h1FJS穃BZ@7ohkҲO־SYmpaEX÷Dy2=o/ёDN̹B8hO;wEFX8T("M`Vi&$>ńKYgk|< oՒ_b$h!;SṊkcAӶ8P=5&ر-t-PQ8g>os D%8.1`ɎgWfQN΃3 NLie @b=Ve"$Wa}pI }(pRe +dZɶ(S,]R+GnS*g>IxMzRFNS-s퉄+bt3'-9-ʏDP F!S3Z ij,Uހb_,$R&EwՆThosl{O/c:XQ;~pYqPE)3Xj6J27vL:x +E?1pЛffV#>YPU>ez&r2]<L`!3ݢ*X3}W.(a]I(T^>d;MA)z@+$)-4u"Bi2l*|+Bl?IfDzn ӐݱwԙfEۭV%`wm@(ʫW5 bu37z_+)xVJV564+(#0Ɨ10BTGL7ZrZlށ]~ nR_-cm~j?;gj'T=Lf$87Q]am.Gt2 :ʃbOD5/؜)U~w+`3u|tzo4k% ;Q:h,7`n\ +l[V8wy< =>#!Aop8a`}Gq8@񕹊{/ʹG-.Pvyc +/]#NP買s9*5?W + #x'sÝ6!+ { wU]%2|rUg :[chJ&]U*_bmٲh=.OBI4Y1QTY&Ͳr9}iaHd +bݶcneF~].KfJh6^ }V船[O3qh͏B/?x@me.C!lNӶP[ΒRuVA0( p̃ESt5t!@vs7BoƤ0>Aw~$OCniBҊX W =Fs,Ŗ̅X- +X EX qEkxM?pyԎ?h(Q(Ju-ʧ0J]Q50aJnLr]nK$`艌8p}FCP%s(QU߃(>CVg2 `pzԼtZm襝A!,-mCHɁ4wW/xggXQ^A¬aǃe;ÊԶ'-ê"gnX:Vl$;1iU/mkSVl5~.78La3sma Yo6ƛU +[ B]!;o6Fw1 P1?&:%wkk+j`:!NZqGVȫZj ` sh>ń21"(pQSR2'4YRTWX`2BJ1 +7!O!ӌJˋHf< U4?gv[Y(P}ʃI)>31ltA7tݗ@gA:-U{rqJpm7pnaRTV&9Xx+snMRB~6ciGwx߀jUd˦Q*g=\Q'Fje*\:  K,?3-qe@/^>vd]<('C`˔$"P @3Ę}j8L@.SlY-URpu׹DZ:*Oҫ(C.0*u5]W.vKiLWVʼno)LOW|x6:eSr_0923a\QmPLj=MoO(EboISԫy5gcV՚|kAI&C*hRY䷡R3qϷNf!-6g +<`'9tDXEU߆ohNwQ*ml-gkE( Uc+z|őbmTy2.Pɉ ٙVJ],i$(VϴH8`U[$b'{E⤜dHeiGaƪ8 j:P?@ {vBέqs۳y9O4G7nv,Ntm=4qŁ" +.b2өqխfM;Ab +qشP,Wzġe䑿2{lК}_3g'ƻ,% 1oNF#d['.;o-VLfZ8Ue-r=-PDuYq9V 3 d_^ph_0W5}|$ L<+uO1a$M|~ |)S(բ)faf,}$*\e{UDţP߬J$ѐ3eHCk >ڊ2^"Pj|&Uu(uZDߺa@`򥛽t[8}Fg[^e`8"Mv߭CTE@+"t\WHHۘsRg`jL.!s_KHH8#ɳ#b ,[~]ѽf 6]_9}c|tp:qr5Exn[82AO 6r74C:S CƏWӪi̡׮g[̽|wfu 'P} 붂uk6 +Dx8?,M>S\5'Sdɮ@t`,nu7uZl}ᚦӔmR^e&(RÛ1*kPa8V;d~/ЖtSH@e8tvyN&Fע2a=(]&_uﺐ5n +ѹ 50}V&7-INEHl':9zʋ uq$ 2-8>{3/oKHeRA &FMS4E(a+d1:WegԟĨ暴M|ߒy\\e[*9%36%&dӄL t2?'L7ͬ9C֜-Sn2y@,ܬp|a=sQ,a9.E &jdNjL3yPu5!}]gcsrrLJmql.>L&i}Q`g|XWcSNN/`iqdշNfYlĂQ~ï󬞁lIk\apr #:M/CaO LXH3t_r,FCF7|Lv}3c2sPg׭Ȣ U䑶iD~HXWu1 bݠ{q2+.TFc ',*v!Q'@Y.)o7+!Q=`Gcui >(P_4{19PzœIK4wG5= _#9(@tw^5Cj̔ -AnEB[$iWέk N8k]TeRvVP rge6fXd&7n%!&Zjz6{òr):rLRpkLJ?=3sϼ?/FAbrj7ܖW|06M +W7 C,hK$8>q`YTS^@sBu6ڵPr: A%AVv+akP> Azb { yX6Uu:*C*[WTrxLOʘƱ$RD{Kc̊[gOC1ֺv Bقf#YkkP?4< +ď=5Yzi-e1RLΝ*#bm. +z¯:`RRpb/RuZYba(ැ + ?ъ^ ;*t E"gv,i|3K5]=VԻN!r6܀FQ \n#U_hjx& aRB+B)>UT7=mi)Ug^nɣ[.zqp룉A5x>:p1]ߦ(k:Z`2"{t(u޻:]v9?q>0fNW); +IkE&|ExaVf)BtnIQlHߝ ))ߞAj Pgbn3* b$hc VC40ݵ>܄IfDڰtsTIN? >H|GtU,k[\qyȄʖ-z Kồ.+롚#{\T',4, +Y\HNC`ٷq7b"{t >>k/jo,z^\ˇ;5>g\y:iն&F5?1m%9WYܒM K|4R,RҍiX7 #<9g7T9XZZ4Cb|ӡTMB^#k|.Q2yDpq6{QqDPm ]~oQ):+R2if3=.ŴƢW8 {.K)ƳQ*)Kb~D 8E=.PH;(Va|[DҜp +m9̊LZAdm_XrjKkwOq ,G훵 +LV<̳OKy L 0I~q'j@k?d {[@{ b6LIۙKR6tT Cme8҉ɾ0L!3h)hŠ.B2G0ML]\dõ<_;s^ +')C{d+ip!q!3%[ʍv DQ-w4U:O,4cZ^6 |C/K=ڴ;`AsWaDr0FrBvN,q ۼmw` ڴqyU&Mb- i|sک΃2͔V.r[fΎcmcw5ڵ?]3֧]ULyV(,ǩzMQML]d]/es~'$c`%ߍ^: F^WS wbh+fo~<}Sb?9B  9|{T:M#A'-yBmYtM42e@Mb@¬G5)0*,1RNvJ z8(q0F/۠(8;{grʆ +qKG:13P vuU*:?m;|Y%F~}&mAF ݜ,=ۡwLj- +ʹ;t=Sv`FZr)ݗ1)p5 r :} ɔU-0?%BY}7O&f@Ʃ|0j¯˞ڪ%7T ^`ch!q?ֶ ?h%n}N`~\-BKzq ]8,Li_,>a +.| D 1}=&kᴣZx<;pI^i_Wr]1&ư:9u$!6 S?VN ([O/^/nР#٫(ҷL9I0Pŏ鈳j#7`Fk_LD :ZPJKzRRЮrmM>fA"u̔ &EkòюbBp,(Qף:e F!9 B Cjb}uu40=,nQ؍nCHvS&S cf+X'8=jpm#{~"UgV_hSw*OmoXn3>0Ϡ ^1//~[eVX~M3bJ +%Ne䂚PmC +vK";{3^j–_KkK V3~|ڍq/'x2M1\{>O iE] lJ7HcږSZx jC<{"arM4}(CZ5a~08c:rɤlc۴< }۾b aApZƂրm=mcE[-PJ8*\x3Y2ά!:ϟ-,k3- +PxyE=fjHMUH|@|l&s4=lA4GpȃXxU ËkJUwf1AQ^kpT҉qZ5FqiG $Ԕaԧ;4!^7xvakKMfU!)wa,1<ޗ]7W tGGٞ:Cdk|>i! ,2F,eJ$&;3UAll_"L^`is+̊`^2b|kY4cU0IAh3l"v.,2' G0=u/u^iF/)mvװ\ђY3TcܪK>'I6>ϪW'ݸ~k[Ǿn9} '>6_=?g~+d0X Yns{݋SvIO9;ʇ\@~e6_/yS? ˆEnw t$.t^'N &Uc0Y}^yriП9]͂T[y*3gHNW^3AK xqnb8 7I]+ ~`?3>ۥ^⬽7RǓa`PFvw/Jûn&]EfCRNKm57UZ'Q|.]swj:t*.O۽a5soMOtp"c?wpo 摫v3oom_u=R]M׉);vrsewN3J䛣?ȃu=Wm\)cR5CڐRןr;*JHsQN +Ufcs{|Uw6:E"ro]d51T q?'$2I;;38:zo0 +{¥SD"zr٨q2w6}}3<::.Z0QL 1|8ut ^nTF1_v+tR +CrZ,y|`s[o/;^ٟ{%L֧ʹ'/ -蜸! OZeXMdgV}t1hR˺R ˌ'0_Y%V{~f? +?J?zk[-%WI}ѭÿz$_=8VW~rkNwsjY?اU6l~="(U6شE[,e_qT[jF"{;ԿBv֢zB?EJrH0- ҔͿ +Y; +K\1-# +ָ`?,^\%ku]HKBxyn~ϩv=CFo}=9v{ҦյKX +[~=m^@ۼﰻE[Ze!R۞d r;QjUVxꭉĨbC5F|s˔pV:(3ɷ1 7'6VAڠiwBt-mP6`0P!Ӿq +xfпaA;͏Eo1pyw7+길Yq:TPbyOcn:YRUnAseZcp=.:OQ[C&Q\ҽ2d 6GQHX,ELd+;5XˀutBq&R=gfM(?6N?5hv+bP -i3@#9k&nÐoWLi1Ѱ~i1hedLDlE`,ȳ-叉5sEI3Y,̲k|oKś!,9͆u1cel.Vl/@_A'!+ ViMW id!^ (Cf/WYSn$M#2}PÇerͲIiF ֞w1x K+ݍAB+}RDUh/WԒ{;!^тU?FB寅DjDֻI m48`xhB{7BWk+tsBه Ά &CU͍>ܹ#:O*&fbMr;4xЗb?O+Ug  ΡZtkFC-+]:!;4L_L]@|dSu ]˨a{Qnk9dK +z]f(m؁Hw̐#wh]߂?= (ã> + +F/6[#ӆ| ++U_MG~ Lʍ-gbu0mys(ؼ*#dAcEyH 0u;lqKuq uW< *7䣈 ORGq!ߡ0 &CJ'Sjatt݋ԫ*]D)t"xh9B\u볙P݋$Wb更Q-DCs1QJV=8G6Nf`:3dL +O3Mow{YDK"g$1 Ɂ'%PElۆ_ק34!w+^ΊbSڍ1?40F/޿gm>4]zFŜ=jD<<̝:lGHLAZ +lB9tȝ~*Rg(tDNJvɬg -> ooi!2A]p'"?1Vx:ZMeA=NGH~@3V_t +/!kN#"I7/tS~Gf?a?d: Yҧ>h)c V۠9D&ѯ6h0uKOQ_iŘ65; Q _iRhZb.}1 {)d9Cڠf@{..a9§\Bla}حٺknκg-qZn9̴%$뽎#X,)/NN:n/<fJ% _ {IKElc?~q +6^ +@ؾE$36[ӽlV%MPMcT6GL9K"FѵH?x=U}?# ƍcgLAg$'BQIZ _TQK>&uxlIRexfn,e޹ii)L7?h4dv eA{i= ]S,<$.iH/w=ZBc,eBpqX\Ss.~ +GlQqzo&nYqF`@Kn8X7$Eݰp"Y0u6l]ְejaþGg˱J@~U&[հǀ5:-AOxsVh8XYWeѽmGG~HىO F a yCvE z'1~i bP_Zj&EtN)esOI\2dJӼD6Z­1 I8fUkd0h/]bxi>l ,KA~$E1WxcUG#KTECfZ+g/N |V/MӞeF/5 z֧')$s8A0ɛM9f,N7KU [Λs=m^TԢ/ف2lƜh4L ަE3$?&uC)zFyAPHx 4cAdDS5Hk3ek:-Sh8j<˛N'C ~@8YЙzPD-ƹLCE.YX쇩jMrm7,gb8WnȻQ5i%{<)Mo)][cE d<2ׄy?86ټ_8<б8ʠ'wV.rJB+m$ZՇc1UNRP&4}.mEf駣&JeG$c㥌|.l{`1?ch#>*']rd[;?bW\v[aքZ7\i(S6A(fC|$hb4o68<&/JR)*jd{!! *eO1)Sꤐt!MTSW]u"IdUCJ}JXLkU‚(,n8H' n-%ܳ[BA#/=eK+DPTLʃw0m*, r7 Oi6iyhq9'cʹTƱYdgi'+ 6k [زB17uaZ6^Q] OE;"~p+Tyj5\r횓 ]h>VK3i +Ө1DS 1aGV('A2 +W…e@wp6_p),$ٗ + d 8Uw,tz '%9*J01y ɐ +, ։WO&dH7U)"x#J?q`aqXZA" %{^$oRԤ)+?U@<ͅ$J3P}oq5q+6lx8 &k5###o(޸!Gl-EZ&|1:vZ5ɒ+̼"op\@1^p(K k(6U;S/ʅcxwfH +Mfc +=KYb1odi6k酾Mcg(kwAjg Ň +a5ABGϻ xCF6@U(@@B .+zj씧kۧMӒm| H3L?N=WQ NzT0ѽa[KNAyR;u.(RchEZ-T 8X&A-9ęhA'9+ Vd X!je +4J{sdrLv T_Yp0Nd@2IĞJY=eU03,?%XU@HCZ +7X1Z7? v&yZ~.~3X_GRM_Gě9A8|†YN$( ԃ@jg/HR8ļP<$vņ>xGJѡhf;D +e#Y]ZC~[ )՟j(UzCA]O7#cxFZ= ZkOEq˶6Md2))=C*C(e((MOKGE`S?e@ŮO#" U`u$pX­? +wauIPm:Ùk +}W=AE"T ۱*f2RXRߍ.z!;^絵FdF7-La9L ]|;iaaCi*5*Sd.m_#,rjH)} f + yiC +'qxW\zHah.Ty9HUM\ftqhYfO RОj`{`|0Jl/~۬e_O[g|spWt˔ܧE[hO Knp3 +LH7&/ZcbBuBPC7:9F޲k@;@M{XV@EǴƻⱯ蘦׾-ƴ N۞Gɷ 3&5E:]2"l^0E]C.OpzUZZ#/K;⏁u.ƦV^]Mm2XxѲ| 2:3q8"ԡ 2`#蠴=[Za_{(޸Szѷ }kqշ{8Ы6la,rd^d"cR\FԄUE-ZPE|0T{Zd +KzrW[a$&9Pb.XP^m"LUZaPt  +0,~.h0&_̍|{^_{24גVy@tbA~ZeZ+ c#pšrpYOr[1yd;YbX GZLeo'3RyҲٓ=oDC'hNKU>| +vzPۛzl:K5at av#GpZy]e(/ 7w=H`|kQ+zt Ó5c -73Lg ed_>.A>i'7/©CG:FvL13&/l|Ҟ -=I֤

#dloLv7 lVV[B{>Ì"}.VĹ-."QPmѼ:4+ֵŌS̙}2Şc4DZ`(>(w%$ux[`mexp 1@|+MG8LlcTxN ڈ>&){OFoi7"v48kX{?:Pͪ[_4K)M1vbkWNSڷU>+~WcޛKa"9.$N MW?1JӝfKh0=U2q&71זn;&9Ρ,33]!V_",- 58BՎ4FaQGͮ=RA C kNVdYzAfjKPވT$k8a=  +kڝZ ru0.8[- *N:y*"FGfF +').SPgޚAG@܊I_a!9x @yfp~9pcU:ݑfعmیp| #@h "@㧱~|b ^;X'Ϋ(:(Wyˤvk +Ot2GѠ aeUa3.FE4 ;Ԡ[7vG|w +h WăLMױ"ݔiSKFs@v.{15gU%3>P](Ws0K$G*WM;$o`eAuSe֚&diW&4!`ߘZJUY̴_|9^נWWekam݅Ma9/C?L).:%XB6,(wB{N|``W0?gYm6HGz^ ]Qj=͇ƧPTtZ Z"㼒H$w'`cKPF +uNM/qu4_wU:)B.Cp"SeP ]hMtXیg1-wXC5fJ,0-5jڑBCn^m!MYuu~C6yAen3[9Z۲ mggOnR/M v0@&NOYSzZeAJ:T3Îtuu9JS*`eɸjD,~,u\3d `K2?)^T%q3]UF3e[؈ ZQ+V&qZhڧ@IܞX #f%xz] 9*yh1MO}X6{Hnc;]cFӭu WkX֓x +#T>ϊ߬Kw'y1̮Iz23Pjgyq\n4ƱWUb3/@r)Lho{1f'n*d;UHR$_V?<)2g*xKr ܴt9 9 oQ:誴#ƞJgy"-<{Ϋ۱?s{rGI&uVPxܨm'RU') Gru>lK#5uTʮwozl=>~M8ػߜǹb.^sg@;Md4ˆvZ>LOCYsO=- +O{ o sົ;KކwS,$_ _;u %BV4\vGL~juI&f:opM!3՟>͞nfXڼeëo?rڹml{*|Gf*:9Y &/K_$MQqt5g$W{~g.C~WJ87(*m)\&ܼ +endstream endobj 99 0 obj <>stream +?#ҿN|;eH_̷qSR_I*Eco'>jه^1mJ[>)=շ ƥ?;(w" 2'HƆ<>:`J"ڮz ͊upIgP}jp ʵg{75 ==ncgD;IJZqFP OR)=r(mB8Ag˞ugp)gwz7{n]CjϽ!8rfC 'MؽFk7V}X9 +ӡy^v@=soi>&گX6m\0V傇ao@> ".cLrvfKoZ֕ ێi{\DI[wMK 2H4݅D J, YnM:f)WL+z@'(Ušܠgb>XnmIm[#/-{,hh}>'.t ̞=Zߺu}0 E]gipֽߊ[;4qp/ gxx"hZtc/ff'江9xbm, +wVڬx~s-B]6]q*I_`9&J3e.5 _pgYcZ;Tju|ԝ4#TØ0Z bPmї8 +U'3(Q7y/*W|3v‹gDikLC=xzb1H+b=|q׬.0c91Xl Dzfq8s 6FG\\2"堷[*R& m9qei:VTWKwfl 9,Բ=piaԋ~v6b+A..Ps3u1[*noAR̲0(Ugl{ՎaRM'JR- kKpÒ f&/a-h$e1= dq +k 3y[õiGm9rVM֢i3S Nsn>[[&% +jX4 :b)Q+oEaM%1 5goUfY͎x#:|r3R'-kTk}v-咼7II`eFuu%ɢG,-olxC^$Bor0͹|%Տ&Q26X@40ZjH? E8ϵHXi{r"w/Yn 6g)&о19D "OF![b_锽zBu- Tdk)Z˕ .[/h=0"YvMDѝ ?DVI=& Fd?7YU8p$Z*KJUfFcZ'Ve65(ޥ.;ȷ8hc/QU4vb-mdpg*} b_ aK, wUZٔIT2sBx:{~9ہe\P>_biyJ2{ +XEK}~zL Ohd%Mz.-C[ Az[8Bv.NPǾ$UQEQ6i 9 +4H@W[! {ϷpV9{,0ua +IF֠dK={BE+ݼ%Ϯ+ +UP CBbఊ(Ry&xDL C@}_j60mfunfLS. BY }7b1'e:͏vjq:<BϲX؜b/2Ӝa +HU~fT#h6m'5~7\94؃|lwc`:sdkc]U,ֽqXY$ QiH[ZֻC 9L%킝D2h +: DQlފ`y +oK~І+Gp֭۬`[u Ղ5=Qb+=&8!48+ǐsyqx`-q~S nއynR* $;^|cIRPnI^ȅEg^"p8CsFe u%/B߾\SȻJDtfe$;FC [Fu#wT=BԽzm"|6J!_iq.$`Fj^{Bd1y`cN@2;J.J>.PaSwEXh+#ʰH+(ҁFy!r6C 4)ؒ @oVOګ1S^!H"] 7uk_T^@nUc>ai4tgJ">rvrb QQMO 5ﺖ|<%]Ӡv[MF rVQ`V~^qtm=j;N_i["䚝AG_,O%3Y0KF@-yJGK*7)y%2 J="2De|Dj>%; 5zBGǑ糐֘ +Ê_ ^"C2eW}]N'*Z适{- {j0,i&Iw2\Y'@֚~A-A›W\:Ɵ,lMa S(Ls/-(ˌ+ksZx I1u㒳-W)[>QfQz~حo5`VIL[ځg I.{ƻyeE:Ͳ6Q9;f"#4,%W4RvKE:|3-c- 0F,)xDEsLE΅[t-szs*Tq U/g;GP`s'gLP#׽psY0zv'4ĺɅt9G*vJU~|/ՋBNTNkغtH={p:]T/V?KʍGeO6t#ys+qWܥ +Obx?bju6:V^du_{թWh#*ؤ'sw~䝦 +J*O +ݣ՚ڟ2PECQwF֬xsBNSNEg[5IUQMm߫;xx xr9]aB#z"'·3LփDB(6 qkfOK^KU}[ NcSWfn'w۩)޶MqαW9OC_ށL^P!H<4G3k5I̕?ضvv\I/|/eH)w/l@Ij( *ǞN΋=[sNsC쮜j) }|?qաNgA:J]"]֜}˕z8jO/Ѳn=x/ǫch9~JhO%IӺWxawi BFz1@V?rXUGVwkaS|ѿ._nsg / G!նN{'mbBYik<0eyl+Eoi*J]ɴ=/;>}j)CXDļN2>bmQxtn6%H9}uH.<ڿuUX둌p-yv}wqeKѣ[$Ï^z~~)ۙ0SfݹZ+zַs\]er .9Z4@&s C-3v +S+]/)éٿFJ_SuL~;!׈(\VI?B^ n`Oyg9%{^XK|Co$1b&0Wjh;78_' 7'桯X4+Ol~"ߞ?%G[v׿h4mẌ́"-HӸ(U_~ rYtmI3xq9PI;Ϗ/'7|{1mw_^VU_;/*?|,ml%ՍoV+i+A婶XZuD\&a[7R wnҫʅ|׮}GLy@-zbY_NikFFEYlrlI(6ٶ=l+ʺkrobXͲo5CnTB; ٜY~t;͒zIGDOڕnYžv1PpAf+}O}^=D l/@J'-ANO}ڛq–-bC GkFhCIc%f;U? >f-?|so( ]>=>u@93927o:٪nvsBQmp]6i-ݜeE'3v+lX!s^E&91KI3{:V5fg0yz5]MIZMgHhoiJ8z$0 !Ue .7++he85a1sI+B + K-QbL? MI +U+ +=[31ݼ;.f2#.!u +  Jcv<[|sH)b{`̶BշFC;5e6plMNb~udY0p=b+M3O{+zo`2x,;={#8=_Dc>P8v$8lW읿OQ~`t%,8 +\XfC̹-+ޢv59SndqP+;0MJCtpf@2:J7s!JVeӳ l)J,W,CoUG詼X2ugˆ}S?;kǗ~ i Ӝ+"#K4ZRnb$޿sH}9:M``"F_Ɩ G߅2DQ}x 2 d8fs +xhaf1Iq;T1/4 ~tUyYgų6+,JY8) <0|C-81z1oWU+KK4Jf7N=~K#QZ#Fc؂0K0i0pH _j㎚Bdc Wՙ fT JƩ3[ct +'˛CU2U:|jP#l;GP #t.ZM%H5XK>C=E{%mkb{f{i4`Wq7|i ,D%ݕ+JQ~QL + pMy6ahw(ݝM}Nf^[ 8%ZTZ  qAb{L6nfj+zN:$Fܱ2>(ؗ;p{$C7BCȠFt6/p1z 0f ̝B#.atd %tƢfE6g,4?-`8Ίq_f2,ND=lADs[.j.T利|N,y )4X8\iٚA:NIS6Cl,8؉/V%:@jozv C¶ZcgvZ)H؋pE =TT@ܵ%bcbB"y<&x?a!={@>[x|X^ H{KZκ`B@&0HfI)TgڦvԮ+7[Aƚ?b֭,mh%g[2WY9wIsgpˢgͻ"J T.VK~l_p1tZ]C݋tPv=d,"+9"dd'z=öE xݷDkO2R@6%5yy4Hi'URM[WV\|/0|QЛ +(Mh⡼Lh2r4 !BUasH{&X= Y8dK!98ʥmL%uA0ArGbZ F1Z;MXrC .׶C=# Yi +EMRba1֜5Ss+=w?gvRԹkwZJRMZox"Ƞ+ pڬ BEjY7+1rf-ɒ(cf?kHu_=Xj{(1Vʹl&U4eS$.yl,Y-YebW^"mUwiR~b3΂΅*0T˚&^J2å\k&` +rNԗ`!*2(-_B3@wgGdpz4Ϣ6_B`M 38,ꍄK'4羥ГZ$,"rzm1?!@Ղm4ԫuZ.\# +|eԴ:_{b'H: 3ЧXjA7V Sht_yd5Zx-tf8BVa|!B-iw ?.,eTY,F~e;,Wng:)ZήE*K$TzbŃx$\Y|,Elu ]kcWg˓{ɼu h]NдyQxͤwj Sihx*ڶRłUg!K«a& !$')H|0!k?Ft3J@*HQRw3xQEUG0?ɨͺ#_nL_5ѺQi-?eG*3T|;s^Jώd,cNbNp ڒ~N3B4E$%DYy<堍]7% PqIyt$?*.álj +%n[ pq0iApn-]-5kEQP%q,n|ڕE\lFjW~Z +]N`>"SeځeV!a'm1ڜ2aM ח.`8Ƽ]>#lPZ`GU>vR59(F1á͸GR^HF`b"~YfI@*Py93V2XpeHoWJKy²^ib v̍ٶzG຃<&hG 4 BUuGtF 7B"Xl/vI,@:_Ő5BK/33<4H1N-p_%9G OkS- +_Ky|ϴHivttZ$F6;կ ψZҩ0@| ]Mlz'.՞:T( MR0S 6YFVCeDjfA+x#EMzh +'vPCKyv~!" 0Ab?0TT !Z)nAsfCNa6Zl4y=,c膀k~NHkQЬ"AC,:"aD/g?9c(A)1O<v2kEJ^`nUYV`(`/\2:4ܠϫU=D"fn<E~V ݇[&b)sMkҢf< \ +cYq9 +U'`)-ߨ.Kd!@6}v]=59G9 bq?L( FsE)SBS5bnX_k0sBTI(-~C-V,#<8yfmWt7kWaM:etcňz\轊o54Te&p3pִJREi'=iQ`Go`D$ieM+H6$~.mY@@ڝ]]gADQ'myfЮiVЍ 0/`"ѝ^JgBY!oKSF7SB +!u6F~2A#k8ݪ7SOP{]ʰl vA׍o謽ۥԯgs:zOI?G,'rB JeIx@sz/?ӾSuعj'k_D;v + %Qv +>|W(pp]9!܏Ԓl^8B#I!:aoz5 +Rr0_hDI |[u [TIVyYj"{-\1{fkvEчO}\& 5^ҙ(e+@0חt&, +vzD~GEZ +Q٨-X |"-2Wa.XÍR=e jS/6 Ff5q\~b̏imE/(kW}MٓcsJ7o Xr(8^sG%mn-x04cq. 1u +5o=Z|zhvɁ XU$.Z4:NUICSl&|ˡø:y%%;3/cs3_G#E CYeo'GFTLyLO(?I4A,/p9Z 9ًd̸&H\(䬢pZ~1!A"@EB'z  G 0$UOpgC+[Z@|4?" lop]5#Y"\I|>f=EAEg`J:}:h/bLT t cHf9o vv^xpmН OͧG"NF-7k76nL /-Fw\e`<$ԏ|n!({Ò\X#[b|=]FC9Q@aϤF^=jf-Lb;Cl[|C%4jkt- +F'JМyi:FhsB?9#{r)RQey_7za, ʜ%ۉ*:=E8F88]L9˥IsNK{CMaji؞A ŀ' Ω+nM2lΖhkyq}ˍ/f3_d5)ڠPy6ĕp석L4i(S;Ů'#?w` +MyY$Rj H =}&ͰckǘrB"z@=YKofPP-XSb8cVzUѷ0 ]hh` cHl }ٚYp?`M͔͗ZzR~]1KԢr[:8=ƜN3Wgі[\G>p9X&VSo$̮٧ɢSbfV>r[ +oÀqa! P{$]Kl)tP @v \au}m QPx=& B\?bmͨ5uQl4,n6=v 32#$9W!JX |<]Ki%D)_3C#&2; !x*$j/em"ĵx +8ВhDAAxu+B0u+phCs{J_\II/qˆ}$/w/ /`}ΟS?6gDYhn^[C(aaٚ +<5'*xmpP¸{a0*(`_Y2a_i|Gʌ $2Ue*\,XG"Wh }ӣ7@}74xu>PX^ X1KXU,8Cf}Д-H->ZqgK!{ݍt Q_rY[es-Lz%Oe$e0b % Pc9o4O&pvX?'٪/dҋVc$Uo;[ ?Ƌrq07aΞ~wo~N3bV%5q^&Fò?9{6=rčaPgfs#w +ƒZ Ӭ9n=V!VH2^Q ʋQ}%ɠҖĒ@꥗G+ˢėek2b_\ek#*_ade=`"#9i}YT:ʺ`gxV~26C)-3:ݍ$Gۡi;+$zx*VA6uu$%)&AgqԱ̼S o:_KZ:;l]\ ο<A ?T6uR]*x37h%wvV$ꑊ Ym-WM{ZC 5B9_>v3^=a~==Mݞt>^zrLlt>^JigO߿͌}ϳ3$oV(k'%@LJ?D,!2HѢs?lj况ncQ03t2 +O! +'#3.g5Bnϑ!fڬI} ]:K(O? ;[]b} "m(ʹ7AdUy3 Eii`*g*PTDX̒[FJDz=WHfEG{~q}֪Wv%/^^}nn%gq-7Ww6~ߡUTfa!KӪ췳8mtpC~_2ڮp_g ˧ք.HA1-i'6#BWvbH(4JJwס1(XSlU &X43kz{Yן k-fnUgn_hr~]Hς&CTsU Eq dRT|9<ȨA4BY Ϛ\)d4D.o>̧hQq`d>lSi&aD8O#R_aKƪh0K{( kC5qAMg$T (xglULO!Ӗ:D2=n]+[_4(Tٝf/Vf;_DCV?v zNl>@Tγw^\7fS:mv-rvhj-幁g*xt~j տZ]*$#ȇt`Y`XnKD*P@ 1UFɧ7AMlCgN*ҿ f!,)-œ-ߤmƹKG7ndQ\֢Y +6J»&?|e$g5WS^QYm9@ݨRk(Nedx +P̉!Z2&s~) îM*e>^_u٠*Z!-}ݰH;Jb] fh +͵!e9Mh<5̦§Q#$NT]yc^ezT`~m]@L`8JmAL]]HlhHQ!\@,l $o4%{UC#߸Y\䰂" +Kh$JηF~]{:5cEZ/ -~FI,BJ<xu +iU\FXLM[vztlЖtrO{ +3߽m{g~%|plˆr>B J\g *'ꃇӕ<ݷ* @iAn {6h4#_dɷ;PGl4F>c&gOySkNo 㟯ɳ~-fзZ=s3rGrclXmf#޿j٪.:ތڭUr7p̴V;p3CH"z)9IunsoL.U^xE#_x=r@->Ň:YZ*x2MBݏDه L6Ӽӓ[nQڵdJoWֽ|vobgL-f@#fqǹ1Pn3+Q- [qQ͟z[͡wSluKqo:Jav]fAo5=W÷Zϻ4iؠ +?XɄOea۝p)n5"5Wd1!hںW;4YtyMϬNVAz[x&kD} ~ԺͳN`4/V$ƛTe!\#)e9ېb 睜TxVq%C;Di@huJ3Z0cVnJFDd^[ R6>'i +9pR0/}B5v[2k+3f΅Oy "XNHszm MCV7,Hk5X*Q^>ZM9Q]/̑#(2<,c[P2JD j`׀SBכfE${aX`9E_J^:K\:&SBS[ӑQwPjg~{afntEC7ʳvf/QO!%82A dPqo@anT$L A _7 3"Ě597Q@'f_bz:@E0ǁj9oB\"ץfsL)*!/t D^CeeD=IbFQLc\PaĦZ~+=3_u>kXݠuV 9*7f (`oMxH[sTKh?{~hcDX +l5̉iRe歹H.s}#oru#^bam)X~ o\ꉳ a|1X )\5GIK5kB|0rTc[ɥ6PT_7+V6J!l")=_XLс+3zXր1Ke1E`& J +ɆZH[ {&xcTZs տ>Pegp0IU4S7Q\Cu?#f M Z3pQ,g*[ D7hБnL-^Z=4oؽڎvvR0mGRyRuSU^&pD5 Ty+CߤB.Ϥ$.R&"H FP~ ;~hmȺiY2-Eh>r ePzKc^8&ʶ3')0ԉe TB-5 h\gD#B+x֋!&%s%^ (7 Z!eV3,P'L8s'Bn I7ȶֶ[͎nN™ݗR* m]U@7|#X{nqX7A$Xxx+j9T3 9GvT+-lU5eY7; &}A3yfv:B0GfIM[VCMk@x~* \`:Ë Ҿx> x&8^w,<ڛޝ7lH91w."^ksG=]hGS{(LW9O V}!~xO O6ЖEqFnKTE6ejFlQjߓ/So@ԖߌD˩N7mHAM if]t Ll+%?%KI*9`.v.듐(ގᢗdE MBiƢ UH6mZR+biZҖ>vjUwdgE2t:=ox +,_#{9a;ZK_Xn:-Sٮ*"b-أQ7=@u\wt07l?s̕D3^R/ 5n>="@=>"Ryh,Ϥ\=d̛B;[J3##6qTQVZf)؏%:4K%"z:NH(T*"4ZGzA5߶Rl_ȃO8ȹꬬ3^L֥7$E;*D f%?unנyr\6gSz> imPAJE4(H9WG%j_Sg;(K?diۛ^RTkϘ㌶8tԔ6nNdnKv4>߂+F 'Q0̣)C!~rwQ@VH>{0PyA귑x8*| ̅ƛ6*MD,%Ig錇$}0A.B/$. f" ̝3\wZkh`،u ̈́R'^#Lja_F;G6H%E];$j1mƩڋav +EM-5_{;C\wB[Τ6swGI~wΝrK[vʺm!͋+NiەRcKUw#q-:?tp+`?Ǫ{1CtTHU63@÷Ta U-ż qbvފUd,\i-Ϡ;AYˆcY?D 9.XTH&ug'JH?GãH?VkJICc]ιZHg-[c6m ?CZ:,ю B[k6&kMh ^>>R_)y+S>Q}`Emїay&5J2^"KU{,(Z$3WչQB<%y.&NiX1wO;N8/NG Th[3IML8A0,{Y=LP%4"7WtYϫ{PFOr Tc[2jΫQIt !7Bƕa.c. ާfΓ%g5VLϜdE +iV..^ urհģ9#n:WZI bMN|1< @CcyRB"cgzs1@%P,7Ò^1>4Uu]G$>B>HBU7bc8j\7O+/䣐j"'ݔEDltҪ=7C͠WN깳*>/9 Zpe](B4|Q0mj`/ͺ+ Qb`2Obnv W8tnr" ixjEvMfx0]fQ5݀{G;T>J4gO/@Dԥ <MAE0CvYU%BkU{G[=]h[+d[QdyU[VQaMP:ĄB= Ӝ4`=,JmV:FՑ~yki>] ?[8>77U&:ٞ.](HX6[?^dڋ!wZSIۧZ- 229])_IG\u șRϋGgn\a9PwTf]u D*_#|$-ϿuFqa, N9M._<)<QOH_ɢbcmTն)b2Q eŲ+BK@qtG},;(O +E SAĎq-K""3",<-צ}|ˌ0cv7LBZ܄C[o* +id.m5mFMڞLy#wr/a xIZ +‚3 &>m-k"d*? 99^t,ͽ<68ÛƲaBoEGX8CZ}/OЫn1'Z<plw7U[2z.ȿz[=rM:L\:lJgķ g+#Vs=_I/P#shĂ`m_NAjp b~-ퟂxpU1/,̊U*rkKY"ާHFp U>6;ƶ5lne.isw`i=lxEy>WodOA̙eb^%wvE[c#J7iv="{B@@_8**s ~]yh`EHh1@d[2R>dr̰),(H1*$ɃV 61t` Ϭ@Q91myAa$rDT=@V$ ToE!֧WM@6\raT)C7Wa>_Zr4=XI +T/ޢ m ( d(bZDwe>-7ڭr99{vKKI +#n>逅[NB+dƲ~:*[8/~:7 +]$ +T k5fJVFXN:;KEdSKV3"^Q~xpJAՠ0x1mǑ +㡁Ǘh&䗀3ƛWoK?>Dtl!&tId|kp^`KJ{Y.N5ypEO>zX}.:2uenj{3Ȓ8{2ޅpćtɽޕWg\f@彐-|/eX#zwKw<ԹN |:{r/UdbN JO ޺3ϓ#nY]/×?.Y(P{R$:K;a\L3>|Åk֋bo"3{Sw'UW)x^o)o xn}ovWpJrI1ĈäơђȑY 8[.Zs/3hAi -čFmh}SH-KCF&?NtwPs-;Tpm1UX#S8>r 94x #9jl#SkԧNHȇk!LnC/p~{;Pt9Ow "H1͑9Z4y7L!&9o!iJk @Щh@Z׵T#KMP)9 iRܩI%Y_QGXԏ9(fG q 6u^$Rv>SǨŽቐё̡|Dpwе@В@9l;'s%4@dE%oy/Uc̡n7y@ӜGӺpIܐ2{<{,|@~-Pc46lEN rfd84;C3mhؓx,oSiY &#Q qQ@f q>[0tFd !D\~PhBj)_i<@MesCAh :fE)/@Ҧa0H4qUAVdLL;WZ頋u9~(|hP2H(QhL +@U?Ges: +?!tur}ߑA/)K*gd!_a AZ0 1d(+r߰ QOOa!gVy]4k,Fn|d"PYd0)/ziS֙^4hΖ6BL܋>}אm)0\G+Y>]f<)e""],$k8v̊r~ %[A<)_ij~qNiW@K:Zn`u!6{(sG S]N.F!]ZR8&,߸gj r3/Du|rEoWwb3n0@Y!"!_=蠙YRRH*6^ 09#-eQGpH{^0d&YG[Hx:L&6k̩ &ƀK&rBnߌHCgI +q> +߬xPZ$!HrZ{z"ck'·G&RQ +PYOKYDpwFI:`)8Ϩc⍆yk)opۤTqA5:OjS*\T7ZhEJnܑH-N  }N%oOpM^c+wP:0v+s$`A8!-`/sTsRCwp{5Vyeit=,HMs[ŝ@.:!n2 g捡mH ¬]g^_U˘Cp"_xK[>x[*012 W#iZ]a  rmvD5~\жu_^8jv"|zy+:PZ_c.3iԾ7I'0M`Ӄpyr& <4AB#{Ȼ= ݵȴMTx(NoУ˼Lq xm5? N0yE9ٙ3Vsrv!Iv)IMhWx϶;$ ͳ#$w.u "Փx(4Og:Ւ#W%KN +$2b[6t rbt']gsLe7pOKmYyǩit~s4&*",axsMރ3e*&!S7\<Фq%u@b5 shK6xX&bD.nC\<hs>r'4qa.c*=KuImajT '-:z5 `ne +T6e);q`>yQEkv8: Z:;l0 ׌[ t"]t"1eW`UTa,Ǘ`sIjH:[fwm!㻼j&W C#-o{Ju)?^aIBz&zJ%X2z&qgGNq~p@%l-C:h!_Cn +OCMLH}=2C /d7%Hԓ[hO^ؐ +! TpgBƴY%=p-@},Y[ӌW؋P+/D栶᜝e?W'!`$˰ZgK> gF6UD J0h{W&!>WfRĞZaѼkë$r@ې , + mv={)@X @$!Y6;[~2LYid4f +6aݟ4É#2zxD'i]66aͯ +!#m0o+:\ X('JjySڞF ?p+/!>3(H$9xTzwu%*"h#8 +h^؜NnV6k ߤ@u1ȋW{~x%`1/ +Pf1:9./HFElfwHHXV%!n?¹ۣ9R*~uhCN~".3<do&K|r? rJ߼3A#H 8&rI[=ϊr^'4 $UB)-8ؤ4}[g(q ic2aLqG/J)E]1.H4RLߴtx3A*0ު[2Eo7B(gű]'f咘}E_Kޯ5_duwݩXMA#_6)ʞL3}@fZ QfؤYs#67;Xqm!ƹ|}s1hjIrCvЌ8*-w'61}ZŇ}׫YCl,] )3وAxzJZf ꑏ ]8G`D^ O+첬X8Ҧ/NRE.C;G頵:xnC痽NIJE}PJrS o೔"|$_7)Q6}@:*@$NBq1o~pTfoݱ՛L$ݱк-4bz׭L)2ǵIk!.H)aB<Ίt/qt /f`n>RsSkF7k|zP}O?Hu=|Fs ?O.2B62v\`!)G/ױz21H" fX5{[~uzkY䀳3xdu.W"N61d\%)僕 ;g|^߽-r 02w$4婚{۩Vƅ!Z,_c;_J;ovFVRC*[J׈/fS~˜LqMYA`֙_>m-/eCbWtȏߒh9vJ6x]9n]S%Y}Bo::aKيԼs0]ۜ¿hffI{Z!_)ֳ7WP5K >&̐|o )`\rsӎ9ev O;;:S's]7@eQ%FU )G6 NL}vfvjkF/:Xa߱qTfEw_^|yee_l` Od<Ѫ~n |ϭ^X|iI<ܴi['@!fȚh<̜ɂ>Z=〙;Ө~xK5c5ZZs?E -g\@HLJxDj\,z͚kR}mA"“Btk֑z%,Bc[+b`՗ +tCPtwBCXs!0GsXJ P3;-zi]LLwO-(T<0%[t/PdۛOx0BFF\ȒbQa!lQQ+§18YA*І#5J!7-,4@4\(tHȧ 8rO+9yr/lB(20׋gamGAm}?y6WT +BmϹ@B&K6{;|1(@`K*Tu!hPڿ-6x}+R6,7NE{'o7Xȟ6Pwc*J +)M!  >vnY4ٍ@wNBFce[6*HT5 :P(Se`/q{T5!E܆Q~B]"E 7)-Kj6K|f"T)KL\B\JI~z+ uY5"VKfVbѿ BM +ޠpkkWO A6r/:|B\,hmik:dT-to= SMRyْ%E}l̆@y .F^ 5<'l  +epӬg2 ,8{݉ "gAFO;8wAd}E8gXH_>H昣ΉS!=%htm Iq]jX+H|I  ,d_/ YSxtwU09Pce UQ^'j 痐hBZ8HsZy2M! !KK=$iՁ{6rhCoeة mi#p%? XA) t&i * Eခ:â +GϹz}Uq43h% EOo3 kIlH\ KjFT uR/Q@!Ļ}ćlEF]n<(a 9š~s(t=A+EInp[dPrX!PPƣ5JP]Mo yHPs۽il9 PK(YuډNM5 rZ|OfdPX!!>"A/_ n cՠZJJ`v1yЩ`vol򻦦|YM1d&3 hd|P;l 6,{ +OwQ=G![]%g +<7m&5;ĬϒI2K4%I|%13NP- i`K :e!ӝDbfm6 C]4P@WDYtYg$1dvCc456ʵiGxn̤7 $0Q̝5^n 4AgSa"8P J.!I-S+h +rI/;8¾ݟ4&/`ҟzSY=,րNvô02OLf?S +w+bMa>1ŻhwiYD%:ѦρqSs#3bIO?KY멛ɾѤ8DS汳$~t* :b=^?/DZonPmΗ.gt?~8C#c)_MKRp~`%Phsi8:/}dQc,'7[ ?QgEׯ`,8 w)q~}g(WLURū³U vYYKe勰۳ y'`mPy w]dߙ{sѸuy>Yno=W#;=7vL-?fmk矏:.>{Cr*,Ju?`ݱ#~xZ ?z{9Gy>?W1S'd;rqWOWxާզߑ פ!O+ W tܪ}y{w;ԈH/{!{2++0Ľ]>Moҕ#Yr#)u[VZ*4`gj^K7kӲ-KZj3XFYPp~|#Xi12!@>³}`:Touw(|W$F(/lU1BJշ$7xILQuP_/Ys VA3cR;7e0uȴ{W=|g)Xc嵕I=m5]T3 !{JmW"}TL$9\n>rIkz>*5a|6-T:TNtKljEI[4SI6.ϻHrqfm+ɒ\WoaAiV}rgl~, S[a; fDlɦPV\6Żksy]6r#`B/Jo 6^g歘߈*8ґJ [+Gނ5Of?l7xfp!d|I4qdM\B?}Jqߺ_?˩R$%Jf-xg|vvsk9/x`0z_absIuР{212do#+~ZBcÙK,1r.iflm$ 5[ޔikwknԭZlk} +[s|0aLKyN ʶ _ +GSh>/9tz)CZ}ACp$u"1BUskd$XiwЯT|,,>%&Sd3ˬ~=QFX19mҺ=qw_YXWNNN%S ׏ w6(oMP:䪶q&SOf[j X[0++^G]SVIJ^uJAyrz |[mOˋZ"ɻxnZYSa=rCz`_۸*t#q~٦ɕ:6Ĉʼnqv7߿k|ؕo#:D}ط<=SF bXK{/.&.?<\vi&RFjdZ8\Y7%:%]E`BWOsW'jbo~L͟'_|ؒDo|׬u8kƙ eu $dwTj4ɺ +4ؿ_G#yST&v&I-|ŗOk*ּO^B걐MF-1Ƹp ?{+bQtVbkj.,4Q@l_m}p>QRng8𰠁RceZ/9aETapʕQpSh,t1y~A Mapm(67* +U|=y&Nf=h<ܸ>Od3|?uD;gZRm%ı4fOxw/[kN[/nvӷ>ӱ]C6|v[m7s7M?DzlҲ+i ;[kc"Ӌ涋cfnQER?nSɫ7|,m@~iߤR[4=U3U^@7{t }M e oLGݼEU(U_eC0C3wE +l^,{ę{H(YzJ^}2 +fwbͮһrynLuZ#x4K>K㛖[8O.%.rA܀H-%Uˠ'd+Ml&n0Tm<|ӊtԋ0Fʼnf>2˵iaEFn&"WE.N ] Plɑ[wzi}SO +.'eBOS#BOm~?d>?mAho&їm:Ra=<,EazE'1H¼=0e:ʒuԽw <di֒JNB@) +v1&l;/2kLN>"ndsBXxYU7}l )>Ugz@ܷ! (}!lɲs4lHwwCHOƆRl_ZL9eV%IW`%8eRdosA|ǧ]Oj>hv,mp8?#7$HtXVf(Pރ"mtgo9Qo<=|Ը,>pW5# U|}#g@5fB_Y+Ȯ_.BMpC|C)*{кY>gU [ju5z)O "scx ^YZ/yF`bIOH`\TE("9V#M#ShcĹd'SL6-sǟQ$xehi| +p?Wq?eQW).cŀB1NJy}fe,9AQ4_pw@}̛:u.ޛޡx9 ~59LJ9J-ƣ!FS3ʥCMq&Gd"AON$VV=1}!}LPjd/8;"t +[nY&;KM8֋pp12e@fJ9 jBU4j>f7?4"#ڭ>yk m&lEEDR׿9]Ir bEO2)(iY\Z+RudaMTS<hIQ۸veѕ#v> +q+Mk +ɲ1ax٢*KQ>+@MWXHbDnJ +j)7#gF^/}칡dUD,"049uߚI+xԗ1i#!m$^d +PΑv wяV4aĭXùLf(z-堲erZVpQν[)L )AVP0p ΏAfmmA*ʚ Jmo wBK d3拾O>~ yDy!{ hkx(Jۜ/~!12d_.TDH,HiC /(ȣVT!-H|PrÐAF9=Q=Px!d) c8S"+Ϣ4W7 ΓʛZQc8Bn}s^@67Fߦ*** jlmIi df P\vuAFpri^ ;f*D&O +, +9ZP+T{5L"n4*A7QK ϝ+YO6F fefF $dZ7$VfxyNB}0Cv+ 0Qa32k%,Z[$j-71e7)7.-~<c/~,a>cqrI!4C_wo1 )L-+dtEiRweP&=j!#[N*Qc rb1YQlM؉K +'QhsH@@ +H#m:Vp ʯlH-EyEޗFөK~[~my1o?D eG)ōjFݻ@?Ѣ>b +ZЉ>*u9\Yb H`m Íu)&q̧UQ<̿Z&bNEEZVd%D Gc)UJuR=gxXh(7xghlLOYRp9F dV&f"Q(unf ^2ƙGj'G2p bK | 0ߚ(u*w*DdPk1Dt+^k C>&R~eja "2 J^a߲d'xyyK&mQz/Xi5:qFO;ƶb2>MѻmEs$!H8 ̦5#P#ޕM6&!w=%` n2-ybޗ#Ifh +>e0f=e#]9;TyPѮJwyF%`s@W9OʐN@ qoZA_ATIx1駨 }umNudjX}u +AU*-rU VL'߳? +u]r8/Q(s.Xa8hN/]ƻIMT%C,Y$Gi.f^VC=\"j9d?v@E(~1ZV0ĶԅH7̱5s0s/fwRaN{++]k,&OVZ:BvӌҠ@ܬ8y`א=I.i@ د߮4߭%=tWK.Huj%ؘ$>3y tts~iʬVNDf2 Ket>x nw,A&.Z(l!J鮇_ ۦ]!B򧕉H3@4 .HrspEj2heD{{q2h Ģ&I4H$:*6I,0.C^Kib8Hzb + Na^x`5㦅R/lhL{˘c ++%E \t/pIdXmh#V 04a[Y(Txh%2Syz]dh%%w l<wa.Pn%SPO]zO.6BF"շ;1zhVIKӧ4^i& _es(''l:tG3&nfd!kHv2w (be37QӴ +*̓;p2rcyt+PF)ŕ (Y/<f9,^j{d1юV@t b/phBcjw=`hC6? 4Mcev`u%f7.DžslxLB3B{\FQy"p&D#!芘bc-5GmYxx, | ;oŸ~C%hJFa^ O '8WxDk]$lTM\?f$D.5[V>h3f*";~e9uA6aol(;Sc {9[/n5S[=nD@EM'/L(MYSBGMrN"˨K|GN(UJXҀz)A^) 6#cB7LSS[&haEz@]N=4 +]COds1+'^~}ʩV`By+EДesϿIybBM28_sC`>C$bYƺCsO6 0@imsB,e;vm;:7-n88(BU ePSsLv r5 Y(d 1^"9K =ĚB1iv9KM@5nST ภxiMns1D:^T4Iߦ̺hmȝ#WQTp zw^'}pJJFthk΃+En7!}/o,kLqA2W`~@ i9"X0>e+Cz T}$dzX #0 he14W5cKTI@OMi5ŵDio$ߡ;_:w_[ĉÙWynKzM^Bu0ָ7В~ LɓL7!]eOmMRϭa |XkS%}>{lO)4ؚ.fZ +i3$|C9 Q^dõqQ{;SX /CX z XU1`aݍF1ʌPmHDrYiQ42Y[7S7|-Py9sMm\ъ_٣})0s=@70Ewʯ!@(t>v.:7ѹU:7D:&^˫pd4D$:+9; @Rv5ߵ 8SJ d|ɟb핻Cj]U P?=:H.J|ł$ S ~ PEmfvG6m^M“p?O{L?8y} p+:Y%Ak9w@FؐcN#좡1kE INlיw( Ni!] d_`XV0Txg?_Pki97|} ++ q J#@.Q2CSdhq48lȦt,سA0e/ +93G 2aLIeO`0!a]1,CbPDCeF<,%ml uTV؄nc_T X1UE(X eS]AKģ@Y;ΐhJu]m mϭVW1fIަ_ZNN1=cp+n]ǍSCUJײ%,SּwQC{҅Clam zRvj,ٍQK3&w0ñwxZW80Y`vd5ӥT 3)ɰ0fcCn%<-ՉQ(̸| 07m +64ܪ`;TKJ]Go04N-rdw%j;oHt߷ʥ?0ւ."m~8CIɒ + +M^si3ǸoDd1A(ץiMk+L|s)7MG-^LIHV8i#tc+o]d{Q=#8o(K0h1w(kRʼ o3gro:\fRյḰ _ԙ2oX>GնR~,߆O{2 y]BۺjuF1ʩɅ`qnLCۚ5C8FE[΄ϡt-y~kZaFsR56Aj$ke0Cu]=tҠTo4ȶ+7T5t [i np AC`rx:,cwq-Q 6G%1 z$ +efB86 +F ,&ׁϋm^Pt:W9Up@5>ҡ8=S(asOrA|"ANxŜQno*$,nCe%RM{mA +JFI׋x.`nï>RvEq>;"e.WVbJv>1՘|!VXu/5_N-i˪vg${q^R~2]D"xkzsVu;uSgQ#F(ԃxˏe}r1癥f[̼`+v8QO3HZ\Dk= gRѶ5GYl19ryCl~V:؈s`_#a仏4keo{:,~:Zh7Y_>3|gLF,WY̬ZJ⋇dLD"2YlUy[L{=Zǃobaۥ}ҳZVoÁN$;_P +ܱP$,ʖZo=cOIztm%3k"[f}d]/frؙ3[=ǜ nrE XVCb̷;v׵O1w[~˻A۩<5R^ *k#WHn6C Ciqsn-_}I$CYr /Iju"G9y8&N"+GnO(Nƙ:f!l<'^dӇznjE W }^fp?$y[{4vx3~z5 ?;31Mؘ}r/{oH c-Hԥ``F]ץ !@*Hf qd#gry>V_Gp}v/*&/!90dVԷgD[hD/k61(F%9,Iڃ;fy2 Y/k߉M/ eCwo%pWhTo8oO#{R.Q3ؖoO OXls5=f ~ps;@dAp/7]-ĕ,%oy4o(nDb4)۲OkE4 i6KB^G7%sMVpOn@7;I,t'уέk{doX%'ۿ׻"`xݣ4;>0_|{1g-_֍&SIˡK)1ŎEl׹C CSWo܃PleQ3mm03S- '9y/Vtej;{hѮw!;m=L|<2CwtJOŻ0n$Pj s YWKL.óYѺcXs}6)W[6+\pNŒW|%F+EVTTK NZze֎Vjկ:וsa]xz9lE|[anB{.TaNlrHn<1Zm<@P5[IY&`[)GXǣF3S9-9&c @%ż(2q +_6%v*;v̒0$CnCQnKU#ZmS`UIFMOzZ]+?@uVh #'|eձ4Q F}X)0.=B$2㧣-DIe(T +ObORymZC~[WȋOaA'fǡK nSm$6:mkDC4J;&Qlp/[8U%#2NP 9f7ݙfd4"0]νY;r%&iF?=#1$`}gmmA>bJs4z/OBc.Q(R$ t! i=KjdL$7/C/9]%GB[Pz:G[}K1IݸX!mBELTrVvk숚]c#glTA3Uhe0d!WFtIk`ԣhd_8 2 .P|QUr)@GW;-=8zE:A' A}Kw_iH 15bp"g 0b)t0Xyl }BOXhV` Πۮx5diEF#z-0$1-N> +a"qT1*jϜ7kFȩ jȜTW};64|!2# R:;~i("G2#D $D-A4i bɋ] +QFlПFTn.7PsZe-DPG"jw,&1?,# [z*}W7fO؊*>eu%s*zÇb_ ^iSW4~+vɰl`ih>rI$g +4ʷ:<~.$N2 a?>rn^?\+yne hxl8q9 CB!"3FԡǮ3h]pډ)'D"Lv]!YgB@{5-kEAѳW]Seeh̶&U݄GZbKG2g{!+.^:|5Ph(A?` .>8^{AM=&=Uby;QtթK)dKL;0X%O% ܔTFoc᜗'2aĎ&wRVĭ(:x%(c.UWA^Ad'#uJ;X2Vیd(ʼ$OIY7ϛŴ }!c<{!=߰l]P- vj>5p=nT{{vc Gq3.ݗ A0H:`\~Y_ZU3e$P84*^Iy*,+,Xe еN';BNl`NeQҿrnjb?PjdtwS2,NlHB}8b 66?i$+" kR0 PJ@'$}ULv i' QW[ y S ZمXяMKāibg6(3GM|: 7jo4_~o@ ʎj&" A =p`h*ZE`h'9ك>tE7!&1=DqX$Ӝ.b.w2HA&#-Qs + S[f0CBnfqsJRPs >l'DzJ M!.ļ/C@Z^A%Pu6#tu' <3P@D,.1*Na;(s;$iu0 %uPA@Kӆ1,뱖)._q"%/d;ms!cZ_(h`.4+g~؞+5 +@V h(H +кX 9GA GuUGVT*d:zV%\(Fq&Trq&1rgHII$-ndmcAwS⾶[IHD#22K]Cpa+Ҷ"˽eƘ`0CQ)#&̘%MOP \l90 +-J.$Eǔ ϠQȹ kJ@>Ā'M6\8YT9HۗYȈf#CвE%ܞsot)hv3̹ZB@dUԙ4kd#}l"C%eg'$֘/x6&h\af|[7Lj0j̈́c\ jX'Oi1t@M19AGX|+ -79NX%$ 6I PO:B,QJ(Ecxz=RA2{x͢ZfRvzGg^9E6szG,CJuŴ;(>VE lt)Ꟑ)x@(2QqX +/1[Z(,t]U{dBިFHJ$:.;Q/Pz׮m<}i>hޛԁ _ {d'pʚD1%&& +vLrvON$5殠2I̺ i䟙@˟4s,2*tmke%aup/0^ +25~yᰄwxTF '$8Y#i %IGN IˬnLa#t 堹r] +mO +rWCQY%|A:wXe1@%\爽*s'sX~OũW >2ȹ v;S [vSJ6y$.ŀ `|#:( .i.5ۣV7r';k*M/SAU1t@aJ&9%Oh:1A5NUR$~n|B,9Te ぉ" k荡+$F[ɍn^>U; T+DGm}EE,+qA௕//=)9 }?'Dy&N5 *"Y'I<68h9._g)3h~jSJ\Yn"fcҖxdoY J=k \ίqoSp_OIy5Nʢ0Z,'zڋ~T8btbV[zZ'P:-dY,/5KYSžKV[>:7\7sd]S$oۓY}K:qANJ% KCM'/a21V7_NXݳ9[ޖ dlJk&jvf;w\"vկKF,D'|{{YDGf΍RE#?J]ꜙ-%xDSmf7wO8O9L~ ۏOiiz\kiSsDSm|[s_bdk.]?k?_TW,]+vӖ.Ř}?i|\窭>$ka)o*\͓I |]榭]5GI)&=s.@ۚoqbB^[=ΣL )[y_n:B;7Vh^'RXOpZFyg|W =7x;f;Z^GE\N~Ѭ=);^tAxV;/MJ1E6sfF=a󑃽J~)s:5gy +]7_v&gJ4Bƻ{O&ߔtQ6g&6`|鸪Q-BGys#֣', '9?rXD(%B 9HV_ yUq] DCM.AWqjwu)=UT J)Uv޿\"0 %7yc&NZܓ,xf|4RAn)yܼ糁N2`$]Y/-oK'ٯhˉ\ck,ٻDW[1Mp>ȦysZ) s)&Y8J3ޒVM="`wsʹr e0/>db|o9TP3ѼTxGaK:*pSj0e(:Za] +߂V80VV/m'@SQ{ l7)X9~;0$MX^sH!HR]1~&HD_B CJ(أD wf]vG7qtУ+d.!!eAhg>5P@Abȃ'urAVN PLzVj1=@S7dړ:lWAd3r ON|*ksHFWxU^lJfszPkC0Y(ܔ rɱǻ^Jo7$ -4͘ҙXOZm+C/eww):ܿ.2 %nD#3a:/W2k.e6q>ރiR$2#SyxHHP"j(h >s~ +Æv\C,5&+-c<!-֓},q)ie6b"*ܶCɣx蠿§{H[r2GI2{=:Xt&C;X&$tP54$U7Q:iC +(ӎ~(ّKe<$OIYGϗuI*UHBZY׶_xC}6OyaJʨLr3q(rO .M"yʍxz֞Clٖ0g1}n +d!-b7GڰC_ ƚJ\goZ:yfI蝫 +N3#p{9d`Zإ= +(=f/"_#k%- 05vޤ+Ak 7 @mPi +s ̃Cw4fҮ&r3,wҔNH2Iea] ~9qJN1x C|C`=A2b ԵyMY*?Ƒm hL8VW0DbK[4|j낹JV9Zr#حq<dIz0Fh \8調FXQ 4^OU. 0x+=C!a?ϖ.-]lo4/ѳGnX) ]QƷٯg}?QQ+l>$m|,ix > +'H`Kw{E+Y8>suZUuS[PB̪0t|'M㥗'}71C.Ya :yr6Y|keN$ڵ:mqitށg sq7 l o}MN0~Mw>i!qy+V#` " +|y:ZaK`]86zGq$^e[8-c!!aK"{hD66BTg֚f Aߥk|/0S2Šg^7Q+5c&Me6~cFYhPH˾2qI1\ O=&612lMb" +(r%ld ? L+Ͼt>AŠx/J}84WFN4 9"@.EX +~GJA@in' "Е|Nkc + BQnR + X0V5N򙳢LR UUcvwHAHqWM2 +/Mj1ETB(ɍ*V"5oF + :˕["[@دWªUeɾڈU"f90/ЮFƀ:"s-蕿i +Q$BD!'/ G]i+օIvsq9Fcx_<]&#p D[D-Pa:Y61i#3wh0*\̀@Y)Bc1V8-YñX\-i{:ق+`mw E%fpT!ITF,?jhCE*~Art*"L*t%KXTb r A9kstVsBQF$ K4jGF@Yߵd#,*1b F~%B}4a͒Ѹ7s5$-k`&0# +Yg<>J<$H g$M>: +o)# +E1I'aܵP6R1m1l9:XXn1ҩw]4r[6m.{XDߛ_#UgNqe|F!X B44UahA4~8 +[&qG.4!߂4 +EBzAu7ߠ]' BMJDJn1"@"S}QEҕ D]j<%>#plOːQTm%A1scms͕8  ui[/k"9iS>4νK;Ĺ87:Ls3Y"gJYvoQw{ƒGg0h몧)a:ϼǑ +s6ʩz8as 50 +eBjpxi,`<+QEL +" +=Ul%4 +n`%`Kr'C:t&@6G'vݛװaEPʉ!bԑ!ᝂQxόjZ* s+CV*1?mC/(5>Shhj&QW"VV%|\SnC,g|)`AwF5`M@*Gl"fq2 r\׌O _,sHD;2d:/B1D. +9D[N*[ELPH,e}Ya׋C.avvoL)9j-y ۧnB*=Jz;nKPBAX9*Öꏼ(q - +x"MDȄi*%*qG1Lե6['[0 9WZs?Yg8&} "7 {Cqq؋n4Ľ`I`-e +RBTg`=h"W%l0yt;(gW Q +3՚;U&aHe9ʞH$&z.?;۠kA6oD4y̓G_qnbސQJ72'[3[Q͊l + q{~<&T>tXA&@f]w=ц8du)g4cnpUāh3? _(o]?MoN2Tю-3'u"Sޓ|5dNu,m9/mKLC9Tl갊e!wf*$|lO{|;_VI%7l~ eeNn4L<27 @c]#.>Y4J} ?f<)X4*đ? T F@NQw]4we.HTٲ>#ߘ/D29Ҭ o8+$œEB[}`_Zټt +G^kͰ@X>I^ m#o^\'ޫq.}U%9W ԬY6KelVt &w%o;=P@OwC{795+hOѫjx&xi*ă obci;^\r wdVVv ):^<)MƖx`9N YOLFQQųqNPRwpOwTJ:u+T}) ;?o-n=x4q4%NsF$GPh6`#sb-:Ƙ-3$RgQ@)כϻ2wʌ5qe8y4 /^l\X{x<LOb+U֕?d}VYC)奥8uHT3>`MtFuv OҭjYFLe*Ե׫a« 4YA;/>h(P[k +c6BRAA읉lsG$=kYbwR8N?*Q<yAٴWBўHIֽc<ȳz޹inğ6-:ɡV`u3wgVX얐bW$(wxnBb4C~@IkmL(~DhݭcDHt)aWm T]KY_q#2~ +BmE +yuW{"GJȦJ# QC`_HTPUN7JV(r= +U r\5tF0Zq+yô\"V{SxkXOȿK\.VJ׍jQ׬%=ŕk4;`DhЮ&*W*A}0P  ZVѕP&Qvp2c2þD[㹭`m3:*LN^uE0W84)NEU +}˳N9Nf冻@]{;4A^B:xtCll~B hQQV"w~S \84)whr-3ȕ>bKKD} a#5:2Q)^[T 5|#T171wi-횾\,ftv{w &˘a!Û3q'BqVB߀JrҼ@Ol/ p#" (6K +R_ں[dų +h w+>t+' TISS25~<ǘ1g\TNu-P2EݾÝ7E>rSؘTSFmh:/MԎmӫ|T:^Z҉EH Ц^Z ..eu( cU\Sbi9-H +xV' V +W@tO>Vos=Hj'(?^IX"+qv'J͕%%!N\اxp2KiiUo6m~dNy"Q/dOtH1L*?]Y6Zr;R3kJS6P2byj߲ *^Z'o|TN`c`=qQm2iwN|3tYl`}mnd,l+ףL/>dN95kN\]5bT=N?6: ޝM%X"Vo/c1{7t=!XǰpsZ{溺ϣ|v Wynȑ +h4q|#s _6yy5x8Wl#} λN+ck6dKbY,W:亶؇KRټ +gVW/ LVG oEj|ʏnF֚^$Vq|Y+wX>oޥlvQR%NH%b[i=`MjYXمs_\g-\\wj|:닷&NM~#6OS.sI*B\s=[(dtd[וP9޼D>=Htr?g17G\}=>qXEM޼'VQC`u~a|v[%CY.Lw~ɼ/.G̑a1;h0Y}Q?q9槛ucz _|=bZLpnOKω=I0QSw3c +UG;0p~-!1W[U?7 ʞ(/M:S/`ÖDzuvaO91+B{S$8c>YM`l(QBߎc|ջ#ܫ2A| ЊA.5EQm-$*k];6m ڮ_{)]%s}ε,;T<^ @|w Ǖw=?S6܆wvN:2>^uevQ{-gMan;۩t:o\b6 X` kku3=W0 CB'.z2䌌\adһ3g_ѳ& +endstream endobj 100 0 obj <>stream +eBOw +* +1vG>_B_|scRg؄<$^DԞY4n} Fka*Pv0-iY6X;cV>H:姀Z-Wt@Fw'EzW< ;S}"U耲{: _籣.PO}Ѓe-@+MӷbQ7aš +}E6mDevDύ("mL@hQXQex:XH2Idgvx#.dZimy yk"˶֖KV覃v:G8k.sPFL.s nԘ/T\[G TL-"Yd=-\e1SfJFAs;MP q9R=6Aq x쭯Be1;)'ct'CVo%<$H> ȏV>dpWbPL";+H t ,獝!E y<(ć#Hmb{Gɫ%D +FP׉@P =#;0(?Nt;!O + ++(3Tgq bZt7Nc%R5+ti~f2jҾ3HlWTq6M"Ht :PIgěTC:exI**`ZQjj_aD%NF 3.)8kB%mWS|m Q ߨ?ć'Q3b{7@hmcr+|*RD KST +^{Lij T6|YƁ*o3mkrg6fFXm +"Z*T`Kx69\Аf> 8J tۏQ|F|iØCoD".zEA٬]B 8_V=05e +16r ޅ5v:dxXa0E1$*UQ7)'B\> i%F;AA"'bϾA +Q +yEP˝*>˺=G:Y9ȝ31H:\CH4_8߀GK -bpD=MS!# `=@ N!gF;vbX,LS>~W(N1]n)?M{eAy!Yp2)vtntPe[̅#,!FgSRJG~{>eHJ1HSY[]Ip#NNk-4%YuFVVƆKn']7z{L,fjW|zA +ʚ} Y +d:\Jږ7#&t$in%BPN9j ! )*p52"S +ْ2l#tB/HaP i~q$l1AT +wbO '~{\3Q*f\0tsa'4ZhpcJ MOqQЛkRxD'QISt4E^KY/ D?#m芾􉮗&LT?"blTyw;ypvC3K2۳;z_hf.<=/iNA4))G!LyznTښ Gv%U ,@p#AUeꨋ8 S`ר<2#z(sbUO"7*b9x /Ez@+rT% _r9֎zEX LZ֎)"xH1ⵓq;gNcx3l?͝2"zrT;[XPRH fJZ/nI3hJ 3$!{Ә%4jIl0 '^]4_-@$X͋w8ۚ4صW={\ke"hq 0 M=w]X0JX2R$ +F9Om|# Lٌy3G7+Nw8_"4T@]o0"wb^Mt)a *"_7:Ua%L!|Ad*7v)2&* \ݢqzջ,]̎zcXgjmSdAbM" #P1!N6b 00*ډ= jxa \pÂMPwljI -I9KUI7e'-E>ZgPahE/݁JK2{@Ve}Û-#Q^aE`{3(mgoGs*Wˁ}y0N Z4ވM~ +z#\ڌG4`$ƳOiW! ϢθQ:vNWۙhX.b;`#rˀPvCH=H{{4~G\Lxn^٪@h٥$JA"g/DB- @oFLX{mze/ٖIQ‡x+ǹԏSǁdwy2&:/\v3ĖVrYwԢF; TwrGUG՗O, +QYL-RVHJ'</ht{I,5U/D9"\ TRabH{#mlvgረk?vS=yeVz|G5R~˷[M;g?A zH}6sȖM?A\̷D t co)15iޠG4z=UKf)B-wS絊b!0%am" Ng +իJENW.>K]L4C`+y%Q/&֣껞^X@wb')3q:oǍJV3rjhj dьdmLG`kC0Oo\V].6ѠpSh?Su3^ޤZuǧ!>Q`Jט:ewAj9tSsT^|Eu-SiM|Ś' +#l#a t\9SLܐeR\2 t@M&~53bEP`Ρ3$s^\ϕh -h$`J, O`!^~ n%l+wLںLKn@"2<䒏%U8U,ihp'<|h{ +,_=Y~=zFUi.:M\JA.8}:\(؃сc.89&k0)%T-Ȳ`ALD6ЁzOK"te(xݙV7`plXvNL'}c\* {>fR{s;~G֢ar7[ASr1Ub=xTOlVERfeTMjKY9pj!b:#m鿴FHS;R Zniڰ-{NXVW_8a탘0.NQywP+o[FeOW}[eMI~1piʐ,(\$g=x7yx-bC)Ɩ#q.}8HI`Sߤ˔ =]i @b}̃{V3AE! Sp,Q6 ~ʼnjc =ѕcˉ K^`a,ֶVtR|2L<ܴ~}ڳG)˙&e}'lP{BRo_`gdqHCLc_|-TJvDԞN}h>ԌQ`Ur|FK<-/PTd\``47ssi34)_&TKU snAtZنGyYr{,}8. +N`yX!GVx,pk6#0*ǞN`ԝ2Eeos;CI>@CYO!Y{- 3|%CUbʕ_.#)nt~u~? M-tH֨D%IAD P`~v<,aM{"'&nPN, ,_nz/%l%1 AqM8_ZWlP +1[+ u%`ѿDÕ,p @?t,Hc*"_|/g3;9g&fUbGddy+rGz#OxZͺ'əp)|,X"Sy8]4ci ގ=wRC7]-INiqW2,zzidpBD\b*|A-Xrn4#~VfÇ5Ml|W<* ZBA8̏0|(CeqjwV)lKY(#c{f'SsR4E1 Y4Q%@L.8PQPXba3|t?>A$ mY\# 6xV)bEeۜQBwac~Y<$Y$vLT’`aCmQ$b㯡TC C VWD!N<Ԡkiԃ!ɟ7MnV`2Q}HL"!0)A4g$">@:z堃 Ƭ9Ώ5 +)ۙXZ9_ aQ&Sz!x>l6!+GCE "FgI%^Vib ,XzGXQ,2B,QMEeQ@NӊAȔSe DT&dp0/ΔJhyD쎵87v{:RP a"}6e"2EaRFxu|<^ٰ M)>gFVhPTAyl`)LDZ6TEV6U2CiR b 6f)FiB 8o6d=½с YԪDx= t_T% eVG9V7}! bѿvoIX<.}QfE0/i(}.3}EI{Aũbu@> o$wd̔ *iM┦&?={\VANnF%. +H00,|!Kǔ*HDgD Q_Glh Ms*.ųѧ ,HG9ɡA\ʗtM8sW2ԬiSheW؅MΈG~h'g.r@_Sg"ix["%ɁZRh 1W~is-SgiM}2^t)^~RѯނԊ^zD/|8l#Ň(_hܮӧG2z?"g R,!2>.9ӯn[M;PLɫ FMih./YVҖpcK8TC6Ϝf^W"d0k3;ׂx됹U9ɏآC13ĮjAԤD0aO<~u>կA

CY wqϔR>]|)?t<)U:,cfwy}wx@kPkQtq6J$SPX\$[(4 c7ޤlAS~ד Q:P/iGQVouژ^k^^((+jYnħkF S*:Mk^&/> uf$YQU_o~1 _ᖯjG?n2s{ `ԛbo'¿oge~5~ _S %qQ LÿaNd! +BXq^ȧ Q&B>eXcuӏGHHA[[sO-yu3+{Mަ'/u}nOn淒Ty>.7/&]̾=2^Yro-/*y65_Sŷ?a};_f/3;voϥ$q!6D6jvv}:%}Mp{);וċDC9@ nE_梁p"a#[s!',\$&,̲ 9M?[~}:oׯ#CMb ӱ5ѾYܼ,7ڨ (0 !٠fwRy;ϵw_%W;(P8DxN`BD +J d (G>又@42D③>JD ; 7XcPHE1$FHꚻ}tɿzOYnYix ggD~'M1|8 Q.*0se?kh( -ĆoP;}询h]&:""D9vhR*D!H!&78k3ujp(b$±dG7;~lѿ/mrk) paFxexi5Tvբkk7Q9U?[ծkG^? +!!/]cF|( n3[cvSg:|QBL(p?Lۮv7]wYw_UWCۿj׵# bQp$]c a6!g! n3[m jCPg!VqHM{?Ʊ5U]˺ӧڿDUpUC[DȲk>f0DLe71Ejۿ=ı Ũ(Wôhlw{juuOUU=ıjv];n]c2zI%1Ej?m6~_e?ӯ5յ]ǺӧjڿDմlM#BQGEa36l1i, KFw<%p'%UۊSh -ʊ~PKj̠&*EuObbH`33HX%\|[a|ЍdWE^k+e\+;O_Uٶl؅3Vֶlm+^1ٶK,FhyU5݆{[QlmTWB^=ڵr >^Wl]>]!]K zE+~!mbs]lvmE1Q] +>DB{+[jZxQ=#[lbнJ 5l7 zE+~!nJw;R>v5#oh{^Tv lV=sjPa@C+ԾP{BFD Cݼ "ſ\K0n$[o m-nmoE>ku mU݆{[Q\dDu+~ P0 +5Ԯ|.uʎmZ +ޅ\X7 zE+~Ao좯W^=Cn k` Ⱥ +W@Ajom>:jh=045}檨e6Q.8RD2eʊ]QP60HH[W}_wڢ"):nmy6&+^!ؔ[I+~ 60 gNDT9j)1Q]\> =f_oiߕ0V"\zlmTW쇁'6go=B3jw9jo"퇁hD+ҾCvi7F=U7Q]q>HVafE]0BV;|mT +3W A훨0sEw)Ѯ!&ۈ#ng?}D{gϰq̹ZZflhۨeHA $7QZ抴P]EMAGFu+~8 5>Ϟ/|l~?}ѷ?kzr?2>k};ɟލW}|qǿGK7~3S}I3Tya___|_;_JYS+=vOi>T[,>q\UEv-b=y_KjʮS&ɏ?a03c^bL-XE +$96}+"aѠ>-E;k eoT,W7#vAW/; ~7JNk@d/Npe|ȿ }b̭F/R+}7s%.u7/å43M%{{M~{ tύ+ʋ? +ъ֗/^g_@ >{G|t _}?~r/xY}Q>Vί~_}d\೏Uʣmǟ? !NBOc^<n$a'c>~>YpN,mݭivNZH;$jeudw_9.) teTW鰾\~ sn:?\ҩ]LHxB<*>K9a Y?[q)GV{ջπ }cqOd So(q<ޞc(].뭲nYvTC^#g.IhW={%J5/UJO'6($ +D_ٺo‹dw) KoqJwI? t!./ e1.4/ R|[U/?*xe1Ш$qߥ|wbϏt>Pu7F&u8i.PlKR$ Jm.(B$.oTdҎX`QrUIk\D$MHB!bjZq[:ȚUz9NQcO$C˝${;1@(Jz[4R23Cx(m!:d"DIiԞJ6gLtĵZcVb`ނ9e rhDaA[-Y1'/-Vl\IyW׳˷iDh$Iɤ~kAnپYӃnK୙laIp8 +7-Q*ܰ|2TfzoCwPkHdl|{//5vp+/g|hV.I,-]!O/.}HEn8_óxlF?ܝ|YpɴdpO 7z{?T?QOڛ۵kkG t}蛘Yl콂7^ e+]u$DJE +__n0a  +rӹZG(6`H5\-͙!6LCvN$0t|UMI=_cO^ͳ\γ=J+,'ݱ8 1Rԋ8lN+Ls{nwԶ!:No*>mzA7nyI79_ߑޑ9 +;|Xi93k*Lv}Ydew>z}/ +3 YںȕaJCU^*Aorn]QөͱvEZ[s\7,g,\I%ɩb~}!Moh[цۦrA "yV7Kk-PbtKݲzҤBAurH=s}z,L'E.NJYCe"K>KpBwN=`!_zly=FpKncGҹ]C$E[7N32׃0ye㱢v]v&;ɦwfnͻ%.bM.ҹ,Ka' iEF_!vnۘ\ɒ +y b;$`OBLt?<]-#NF- +Sl:s#ۿG좓\4|I'ٝ4~N;O1kSrhXwnWk# @4D> )cĺ4 +I͇u!ߛPu323B ɦca𓈋k%_82 mnD"jyv 8D:VzkwcN^tUjFheZq?^z| Gr)b{~bUI @f,3Um K+R + ͓I=0:a@Ne,\$: : +iehic68$еK(T8h{\Z4 yfe^X[lbw;$rh?pԌpQ2nScF ,%h,6%l8u0[4{ڹhzRhk;&NKLJK\"ԥĦA#VP&I&7 +T2õé)4Xo/9ݢÌLgܶAS" $V裄F%]&h9hN!9B,KVt("W}'CSѸ݂K_T~A&j7Ax޸8A*Rg_ht|(љq2\'<ўj-1 `b`Z4 T(Xzu)a-Cp#Y7qiz"`TaF#z\b-pHc8N%{DCK''B?PqG;hJ5^4Իwt[%f4v2br*v$έ(A73E7'bUsC qj4l@e8q/)gZ]-_`>т3$Ia$MA< E9J0\5ݐ̗j6-@ ?Ӣ c^ )( +¥MP0\)iS޶ `‡`ڶut:5 D^7߫4X$yT[/ˠs.nV PI*DǁRzv0[D~;L@6ۏet,z{pԘ#nҧ *:IhP%AƋyQHFJ\05J@[)p[O&I7rHi˕gg>ntlC"2rϲm#i#v9\Bu'эG5`Np b.baa 8"La:3 FCCm-OC;NjVx4+]Y%GuL`m>Jbî 2AoN.Q4 w㌋FctjƅL9v"tPcs8DSL:fD\Gؓ`B1# -HP9($x،53ʭXփm]/I-qJ`$ݱQwJׅ&ofV2 Քx#m>/ӊz$>z;'8DĘD-fay`f{$n? X/5 ɩS˨m*g' *'íB55 p5C:j@?m(4C%@fOq--qh:ɀ -I)(8sҬr]é,'3r $~pMQŋ73>(օfC̔Fw|ĽD;9~h=c+h#n@W0` tpXiafˀSZ7U(44!](lz9lF,#!;YNC1鵑@SZ .Go'A(sŽNˏ6Wy#13Jst4g{r#1lFہz7?;ތ`ěcnd>#Z7qH7vD '2v#a"iԯ + +u{Ba5_Їhpα"EL,4(qYE Ҭˆ@s>.ծ7j2սaFA|kd\+[ecQrdxI,%4#[?TN!R2mPfY q:^8ŏk0W)wXny F2Qxft ʹ7BV_tS D_8|&mRř0F cxqF cCJdD|.@\~}Y +&LllU% $LdlJ;:޹ R#J@+ӓޯ9LO 0|eb3w"+\6&%3.@۱s 9rZka2Ue6@-w4ю mF#|ŀKg"QܢnY6U#A'B܌bo<͂XӁyaAԷGp!;YWU_S yx!iJ8\7Pj:EqM0LCLV0 @`dNEPCؐC pHLՁBHpq\ pkb2Eaڗ'3CX(6x(~=Rf݄I{Xs SU?A,X,&R蔅PJ0MohR4jF~)ֲMn2r`ӕjff(&OIEMYc <AtٟcǦSJV!Ź+ \Jôc뵌.C[q[,e CF@,w7 ^aY|TWlSE{W ̉$ԍ [YhYƩv,U!5w{u>,D|GFKP0*pbCZ#=,D,ei]&D2"̞T b#R9h[`Nv_ef ` .2TF('_'<EΨ`N4Tr ʖj yϴ)&!jш{cbŅ&3 +4ŴLЭ'{J*F&@g]S6aX+ 8Gˏ% QFhGRjNO)<; ?$=fHcbuΰ+r!k٧8q.f|w{HՂdE"j!F/O]xa@iC)K%uS ;fe̽EګV?n: * FbQ, /-yyt z(yR͠DDleK#ޓ$݂V>baF&}N,DlStPoj $ZtKtG0&[Aw8{s%͆l)+Z\p5"">t$$dHB"ݬVG*prIpl>q,bU!"f$ĝI:j0Ea&UJ$ǬCmHD%YJR%L5gXe s?mBv6.t<0/S뛋QE9ǝ_ڌDԚێ|T@ekD!! Ʋx)u.J= {D<WyX {VT R$أJaLpԂǬ Bq14֠p3I  YLa'SQرsl!{G~ܑi'1%#QR:6B~Stjq$DO&䦽2Ȫajc+1'5b^?7\acAy@{T'f5/I Fөв +T:5iҴ!jidctŭYcN)?,jyWn,'?Yv> p11_dG$ȼ&J.-vcΔX,M̝tè+:: - d?kZHmյ2tK6 +(H +{d#M >W)H##Ü|Xd4|g,1{E/|IL"ul{a`cDLte 8%Hx]9q%,hr<1/M^!]đ'&97]UQ`K'R$ңV4MXDI-];$t2魹 Ɲ9eIgPBWAhjŢYY6|"=\H[(dZXj0^ɬTQ0ᩐaGJ޳'ey:(6ˬ'ȏIKGrG)bY$f Y}L-(%G"u0@fJҼL2= G԰N(ss\$,[69Q$LgdiH1(iiv4ű6H,Gpɛu]v3IVZ,ϻL( @@}b/r)E҉KF$ _w! 'qFBh w#Ec_˕$E<-,pc0AõdmMB.w[b !`L>\,v2k0r=T=RBfQq/X}/`/"B&.22>J&-q&Ic_yD\+ߒp .xCń(T&RE(_V3.9v-`>0'+0 2%l2IUtȟJ"[bG6Î?ʼP#ƛM_B_;&zD/LD!$R"bkXpąGXF%EilETH Oς5ȃ9ScK0rhDL'3n%=nO\'-MjMh"[ `L &{R ]GNL7%I5M wf)JBtfD26E{R,WKb# g!'he)%Q0> ˃~g1n |#Gy=i%)NKy `nq:)dQ2~AEأo#opcx b8﹟DyR΢ {oHfLq9UW"Y3Lpl +*pm7 +䈃enڏh: K`bTEp,ԉsԁ4.oXgxG<ˆ8ձBհ$s,IFP(uZdgp"^h٘RF2yEFsElxbBSjdyMa$s&E-0o F+Hq2NG&uڌE#ıBL; ,E@nHV(f8Ԋfխ!4ig\\|e`m/P$]q(CP'"r#D/PqfW:h"[ial\~hixG\!KNr9TJɝGLr7vQ*5e:YXͦIw9XO!uV`P%[lD<[4$A +R,L1{E@CvNM&٨->[Ť9Rfј%ÞU08h nއ# T:G.[o>"8sY|Z(W#<h旪Y%$88E ?:)g"őPut ҩIÌSfoQV1x;Qgȍ.j*pT4XC~X'YjŔ:QkHét7rK@ǺBPz1iȤSuwdȤ3vKeodEJKw{#uʖFj=`6Bl;Ek<- Ou]Ӕ;al=pւrD$M:1q#g0eYx +tMdJZMF%hp$Pk"V MfNtJk ~}:߭o5üZR.hQla^4Hhhc]էdp 6ĜNTo6xb̵VCk"FM)\S:ڂ߹w/eִ ["R z15^GA[;P>-G񌄯b!g.l]GgRe$ؤ OYjŋsf]ɢ_qLVidRZ&_ ;el5R`dHX"g!TѤ!ؒh}9fֺ#XNG p8)*+s(:ӀbkhBvE|Jﮣ|YuìƎoc+pz(@fVtJkzva}(CXv[{4}: Vh.l)BLiuڻO*Yvr͌~B!#ՔT5(V{QJr|0 cfgb@3jnv`):tGN$m1rYa\E-!W<`S,ʣ: e}"š`N{FpTS8vJfVTRMh2G3 +{]@F7Unۢ0AA mFXIt ,IA+gh g'PʡZaKF4n<2"x>HäxJ3AxJ +=?QglBxG*Orv]~cdvH yX#wF6֕<:S{V @C@'qp\8\Kgd2*(WGlVXUvaw-cT^(:+]R#4g +b.yFF`OTљc+^\s'̇N$8藵#rtFKp]{T2|<.S )k4 :P[`jW'Y +U&^!0(V&|XhE%+,fR{# (O"s 3sĺY7Y3shyJ.%iNe~̊myU>} Ȉ(sqe`֞7˖Ө~Q(a7"i$%`P'jM"BuY,vՅP)U(}_] 2+du Y@-db4;V4dVzF 6KR,l`5V2DV`J kl'c8?Z?Қz>d-[ǚ] [م9! gd[YUuN6lR.Jvanwa7?MF/eJѾw$$(>=_%ZvRqM{:FA/v^~hV|{_xŧ֯>|տ?[_|ŗ=~=>_=LjjJ8 s]?_kxߗ|~0^'H{_9O~ ?>6>0VӲ nja6#W*y {xသyÎV Ltȭd8 Z}4i3z!Y}:(F;(AmȬl(^wɪ:i"qD)cCF@V6ܳ ˬ(xAjVƬQGx"/ٳL67Tn- +G}Z!ЁcASni*xRt]']!Fe2#T U \'mva( +ܝDMnk:9̫S:9}ŀyc`8h&;L/b{$,XkR3؋hPfx:^JVX^Rfp{JF7¢Q&> dT d8Y +ЌpTD62GQ 5uNi.YZ6ڼlk^2U{rSf_XoΥē4t~HFǶ]5jЙ&c˜8Nɞ&E PH#;*~öjg,':z£nT$:|ڞ3 ]=wt=&߾-sNOW#+9.=IMTWƂ܆3N=0FL}4VRAy +"5YsxOGxN|V2 ={[Kp]_ y=}`˿⏾B\[_xW}w_p]M'3Z%pfoh*&Of~p__| kV_I^|6AzfdZ NXcSӎj;#Ip|2蟿xM@[vD6|Yc]ٵxF WNɷ;oSr Y/h? KnĊXev0C^ /[Qg)S]`>G{! QzS4<}z=deo,2[.v3mV-2ίJu]H6G4 VZŇS\X`pʨ٨yޡPٚ +z }v>UptiEھv46?~1E.ހ6Õ D=kkVLJ-boJ^Can"Y\ky褿 :K+ Z)QXݨuSY>c trCtΏd&Ig9%{ZeElz@-vٱB!ʟa4VAڴݏi*5SxaEoh͋_T\.m}gO2OM7O ):^[Tre9;ȦD3f_J5ITT4݃iwIa35^T\.ȕw Gnƺ-_]qo 4bpO*u:%v)D!ҩzYLKc}_ڵ5^uot/Qܒ*LXE7X(OD$f2:v1;]J4FKdQe7Ϫ4cnƎ^s{M/e#ZlRoQJO8YzZgJL~M{Q~<-EB,}5SaFHU/zR^OADo5oz&lv2/M[dUenyF$5U4tԽS9Z)P.@Tn5\iF3Ej 4[dMr;tmû7 +cE VF@ 0jI($̉nچS9m TN\[&^".;Z0蘪6 Qκ4/]&:H^K[ؒj+_G+ DPPL?)뚡e0x)tljmt>In.57^h5JrwfTKxme=hn\qlnH2wL#M-9'臵XYA->7?ӎj5>Edg5эgi݃U.6Z37Cg~!L\<}hd=*kb9G  2wNT薓@ `5h6\KOs71uRqidt]&Y$bxL  +y|:A8UqK*emC! +y}6с& |cyXŕLX-tl]|owqXc NvRZj׍Xŭ$8K'Y h./tkNml=eل_BGb&vj=LˏGei-䢮>\*z ;ll놡7?7.D:TJz{N7PUPU]ąX5U̿w*N#^~WM,E[c x6EXqc +ythR,"ak7 Htv-ua/7 9V +kKߊw˙VՕ)ح.!JqƦéfl@t@,d}AV$I _ڪ6\FV}OsnPJ(Vm2Zc +˗:f(>%tE+eYaqlo[gi^:S`\$uT%.擦zĦPĭ訔HaFfZf̈7SGsUK8[I-MdC0q](-eOY2,qwnn4o-bAEk֗*2lX;򊥥,M3&> @2$ '䤵Z;,m)97Z }$gI`@8PQ%.L#d9IG3v=۴P%kT4Er0*yQQwΝS{*!eᛴHb_aqB, τ2PDWP+fy0S`Q{vӥd7Y8E;]p&rzO(?X5}:JSױ/Usz$,͞&RF9}"|-鐊2i938w|R0gJva*ꂶxY J(cLq5%҃oS{m0Ui48]ŵ)$SOhi +ɆȂV w/NDxyOkFG=~]']~ +t/]s{r_fw$|EkzDN$)f>@i9uYNCiiFߗ|k(}]utYC Ƶ(WJ5cڷf"&#r_[DžJ޺z] mH,6#tLΙͥ{Xi{n{{X7T}}xaڙr7.Mp͆Ҿg!pX\d5B2|>H2+_|7xo~JK{|VIW~ZpxԂ{NjByu6G.qK0H 8zF q<_r#ژůK;haJ&F|?xٵ[og$R5հIcnHQrcwvvZ4$o҂~lϨVVR.Km׈ jm+ԾEuFw}LJW^'x{+oWt?MYiGZ*A$BI:n&6C`Ì8{t(kGA>1YC`zR:<16]K ,[R{ZoK ݧ!,&ʮnjŎ4201'[NX/oQ|eE9̶ߓ =YCCDkM3N:M~:i&0JoZ5*,H +-Y KhIS!DC+~L ix [.gDC{̞?1&y"Y5_=A|E(.!"4h'Y}/w7xˬ@k*>{נcYQO]%8DKN37h1tv/x^D=It䄚gD#˥Rspàϟ**絾B'G^\9%#$Nc!ix%M_}0 tncuB`#6xF!kM`nFIڶcM(,9w=ZBI|DvIw-ql͞&&0}k]77rKo(&F VYw#cF| +Dm>9:O4l:;e.݃~Y.y~zzBJZ$P;@wyI>СF\jr `jbWNX^딴m;O5|o[g.HIX,bF~K%F f: +w,X 2q2dnY;ǼS-Rd6L?տ«}|[V7ABM +tӐnY:#;7B/4̮̕5S_L6"xu\-{`A j|J(YQ@'olZe2oqZYVŝ-% `rbUIKȷB3Uj#HOFu>SBwYe~lY?8ph5nV^LTrIk\!{NH]heu leЧ<;q{Vj9MGR 0g"#'IYIX`v7ELF>]ťmRl:GyʟQ.&pKuttɤZsuګtoם0%s =TK'~ö t9sԜn((R|Րހ33Y553pՎ5^(]pw= ˱gf3`.xKU'YJv 7AF^sݯA{''+rVۥxN-@5]&ճ/@ \1rLy0Ǟ"oCɣRbK)=Ķ?}z7rTot}Tze/j5=SJOU1t-H"lD88̭}*oW}nA7]?H~_M~uGS*B%${M0MvI~j"\Xo)ڱ2FA~o ?ެ5!R %,^M~_MPHv+0*h;OI %rQ~?! {Q +rT!~Eo ?LziGr+r8KW}CAz_CMPWbP]?Lv_eMvU\qRQv?!d{U@F#p9(fW|sNV@szޓ%|1'wy}}nՠmdW|y_w_^MYMo4/0z9pU +?4tǼ}?aW% ,i^ːsҽxL%GDú7gx/#GGs{`{x ,~9?fc_ |˟_V\Ce DVflj Nr u].*2y +nj;G꩸ܼke.QXҞkuKGPt5JNSMY#(Pw!hĮO^nUW{# nwt:6'+b5W-iAםo{OOyL3CT瞵ޔ@4ET*quF-gֻU`T_{~~b@{А¦گ;滿WR[MxmZyv3]btl?VԺ\üPTTFO5曮otW?["ϗ:/N~1ksn$^tR@fziBVtrjWF= +7=kQIB|"ȼϰTi)A;OgF蘹}Lwx$44Woδ\d ReԶSrxL۲涓Rے=賑c=&DPf41QfP|COĆм6VtK*c=#R;tSS E/G.W(]^!{NFnzۃn$[Iq˒23vz, +铣]Sւ5dJ z6b'D׉RNB,8np7o ~},42 цe^'[YõA7 /|ɷ[ōңLgGv }n~|{luy.&ii@wF|,2;@heŇl9+Km{bV}w Gf+@/_1W0jִ+Dބz+R.|d1+1:W`Rlb 2O뚜5y 'M0ւڅβApol5J:l@BgٳA֭fKz8U@am WglK&=sK/mӜh?d.r@q琯WT;W.`g<]ˤ|Iȴ:`Dh*Ĝs 6O׌-̈́yO.P`w)SJ;kv֎9m5}Y#0%$5\]|޷;7Z,vyuNcvDgEғY]AkMIii*['I&Ii)4u,sf8Z46nIt3f~#Vùx6}g!C'/ hxoi>]DHΗD"=_'=huW4{kЍd+>٩=ΝC{_O>go}20A7>} Fz%!\L/LI .T||o}/O~g?w?gD%g?/?֟__'՟'?__|͟zG^0ɿO~? _ >}^T/?wk??{7'D?_&ѷmeVUD+5^|4w\{'/O<~ xh{} ku$6_(Zԅ\x8߀U5^)~Vcu\>hZ|yiãr&$?^6xuKT%hg;f|;wҊPG| tKU^B9S_w:pB*RDgr۠N3{k{Y>Q]XZ u%j"ыM.EEwoR|LPC_{|D[YA'H&poM+Սz4U32'd]aXFB%|H,zHYInvQZݲC/sZ)>(-3 )C[H~c2c}muƎXLvE +:ZSuJJ2@r+pH3%iC0=1\=Fip=a;e&ͩŵJ_$rRDMg!1'2j~:2.8x /t ˉyN5 Ӿ4׼ΧP VP5T"ې[QFϗf6Μs$H e.NjႮ|麚?iS?boNkx(/|RvJ.R}=ltE+j]QZOj 'VC.QH&%96l'聭up+F=E*IDQԞHe:jHRS|l)gC%cʚl{;lB?vlmEұt YgdG?\ZvR|es57<~.'gd<|kuʣƝ,cS-;0 ѡ-A_\ȃ=gҞsdJ^QYR2^n],}ˢvyBb`{Fu³n$Sb!ʋwoeߓዪR״lHJ &bbWNi3amn]g>9Ko )V jgIݬ_sYvrw @hٮKha'TA.#KhcyA;ֳ%R"qyRv̱ge.R{J)X^ 6ڃ[zjFrhnKS+Ufڤ(W?ԝvRZ 9`WҚ\KuSG7g3&hy-iM|?Ru$XA5tzAei7SΡW +YK!!N@m}\݃~!ПGK>WjPo?~cس/5jGaCm(t8zų <:D%v@Tb@b4^2Fd(z`[ +t}3!!ËD6d{;q UnyХH3 T +IҩT[v8OkUL]~9I4%c%4q]vmqt8iiIʲbB.Qݶ1@C$H$"L $q(BȄA$ƶf >gsNZY~y=hQMQѤKwnڳ;b%IC`l/x^BQJ=^gsЖRpvlkcosh tug)͗6FBVVI `y>#{xυE=|FV<펻|üqNcFH\}D4K]-DP20Du5-aۘapˆHRiyԮs4Eq2 NRT(}'(@i&'2%?ႣF*ti<̵ źAm59 k唩RX5OiTuv֢`*6T{-n s>Y7L+2-1kI-Sn0 \!4+K]1؄ +H4dCǡJ%V/脌3Y d +R8Te=ӥ1MEb*tnh"MIz6959nM8.d$IgiJPĥxWwmY'5pln2YhU mqvn*A"[7On;㼼I㣹9I+A9-dDCɞ*/v-qؖ#k%{>~&٪ӵKII:^2ځUĺݥ7ZFM.~c ߿5w~rwV>ğKKi x qʉY{i7R)R*WB3l1vL(;LWMsby^'3UB%J)x7eY?+^Teܩ"cHբEiy+K7!&=$R{]j:4:6s:;[ui@LRq5q“7IpW@ڕ& zLjYObog`÷rq$w@̋tG{c cdB϶XPY,tzp/\.% n<4t+NS.f]0ҏo@ <ss7L=~XSiF9p?L6tܳقARFanP;qgM^2qguC|ڒ E&i,;݌b,,UjmnȮ|n k\leGjN[ t M [~peUׇL:5.=i?@zk~rwT"q7AXI?jCn6ddk'~eЍd+>Q|Oֽٰ}oߋ%:~w"ĖqwI0*iAP*UU5 ѩz=_{6pr424hqzBˁ"ڦ &n\;b$d<- rU&$iWJے{\u•\z3fl]Z&MMײNuP.e?.܇3 Rk^M֘ۨֆ|Dab/Bs_D.` ia@#Xnnn}{Og@X$exC9 k L^H[W|r)BPEPR?K:A: n*V $KNUз1PZ7ZnF -I [hKg9 +ٌz/^iɝtJ=oڀEw?}-vY~l̊wFIӣ9q%o6\{p}>ϗh0)amV 1ҢRC' xׅZm/fHhgIꡤl)J6:m09.ϩցQpv_F9Mԓ(K{3ڇ`;T?gy -Jxj jG;0Ƙ9;}= ~VL ЌM}35"[\hRH2~; T!͘KLcӊ)-| +&䘷?!]'_ ԼoKh-_gTg$Rmdkcv;=d!b$|m3fU[.68PҶu~{Fo%g.E'&Ipn#[s;qJrPk5.>+fQ$Vp35mzC~Ş1F1w~"[ۗoM&;b/ݞn_M/=vq ;>ya)[(UJBm%~h`26r՝S]?V mAh=pV޵Rdo2\Իt&r*^jJ/?g|}WdbPS݈9٩pcN-Ù9Ojr)p$#NVCriԈ{R)MVV] S\@9wYAO olwQaA.46H<. c[[wɍ4}ׯX/@A׎^IAպB^[ud/́͠AsFqO=k/p#!2 [ݚMgmkِ3OQZֶNUM,DO MUӊ]pЋI}Fu6)B*߻[9Pz=@XK qNyriw; sl( ZFӉR3exzRrfJ=hUwiQn@Yp7mکX-v.^Cn3IFu=~Z:$"`hz$ FYTE72gX_91$4B'żXT +k~୍/^PNd.#("M=]}6Z5Bo +_.n|,YK໦32߹P$!KRa/.. \#d`X3ֆTc2i]h-v,U04mU6bz3ԚQ,"Bb5:j9|RT#M!ah`4 3 mc= M/֦0q_=BMɥ腵7q2va8QLI:wZ}YpgӲ.%!g+}޷˲;!W}RkTX0̩šf[˧I< 4u']:!|&v:oKXXm5Qk3G=TBhKM.&$VܔS*x057Ѕ YZqS0?T/0wo7}j[MX1vqDK;x*X~zLO3= L;t#ʠ#V-,R%_'\Y7`K[$7Ro6֝Anmg;j^z3ЏF+,~Tw*zyw>]-}UZrl {{ hlkz^~:,)J> =o?)lj$kRḌ^>^jXA!,*ِV3yg˭{"Onz83|$~4z {*K<씑TX16!wv'N~NK\pg!{#x{諠+n9 +zdVQkNv>mwp97Ṙڢ7n綏۞޸[:Ƕ6Tc#ʈ;ݡ>KM[懝>hK!Mll{Fn3F_@[V d;}muf .qqsyuh{F +mo1pn%[s絻%snbR`tg/֤էiI8CgdVg+K&_VnKgATrH)<ݷGno15nϨV-6j/֭d+cvGSv,vgn|^jX@gd׏s_(W(P;ˁ":u,کX-vv.^bG$SuD0mKVg */Q8+bU:fಮH<#L5<0quʹ:e>742)#YT_7KP.QuܷA"<;wLtt_°~Tġ)BIaդCN5 +Ȭ4H^HVձLBYZqJjk}ƃIBo>6.kSj$EP(L1*F/{SAZhWkӒTiZQBѷRJ$o:"sL,;s<ϽБ)N*uл2Z'%Gһ&Eñӆ|~e;Tѡ(Ķ$5BգDV鯖pgEFdF:Ө!@0A-s+̲GTtuKIb Xݬ3DcLc_O +k%V\g3dV{r=% i%r=hd6c}48] wͭo¬H2@ג;SzIilݏazY|Ѝd+ݓ95='T:\XOݴL{+[L-{RΨV=)h"J2nwv9eI#fIg<8kSl<'XL=|낗E=awR8p-)+bݑr,^GʽIq%6pѼƮ\{B9rH r +\u arʐ34e,A7%Fx@Ÿq!TEc2u^Cg +]1jE,T)/<)U7+dnƾRf 0t89K!Q&ݖ\5A=b1zkټNq!މf) +jq2IqD҃x (@d6NbVؚ͙9WF3K;}4jM鄡uRX )gC*J[Ԋ(a/+F1K363|9kdRQ[bl)z蒑fppa_,-JK +n1XpDEo1hcη,4kÅ6gS~6o1hG܂XeKGK6}#xHNS]Rz86]7H2)[60gݰ.Jo&\ + ^a 4@BZ0%)h& &S2KnRAU:x'Th-p)&I4z@К]FdRh)͉ig/ІFpgWۤjXmHDt[)t:II8%=(r\o9cʶޘN:)-Rt "gu$h7V 9A9n VdrDCkҹ{>~6/3v=H3.K}(-:b[|"xÏ~xrki'_\Ry5wMstdvJa>SuIs[\7@^O `+i*NZ. +qY\7L&iG"5i /e3&)zTd-{ Ni҃+11J:aM.OY@DLebI*Ġ14\ocU`N[23gC@GTJu62JjڎquebNTr%*rTT>4Rc+l m#vS R;S*ALKTF;}_?ύ5A@U|)da]tqs6qjб0(V/Fk+GuNuN%PKD?&g!7x6_.~M>;Kߵt++>fµm&xoY`sv=O9RޜDG4!{2A+_VRNVAHzanZِ@xL6 +[sZJH,-9%\\)')Z:fUC +2$.o& |se߶޳=+~|1/ pmpYz37MS.$NjC|F.p$K֥XݓiR3K1V PǒCpog۳j7Teul._NL;}̜$x);|h"٘( +?v-Q v)lkddRSs⤃A7 Zi&i,YOz@j؄uZ+B^{tpSəkwFťDbLkjwjK=dRGjͥBsd+=oqI#LW}޸3ۗlDYPwNr$-+xwWֽgn$w8zsXOmtfp|&9chkpw58vݝپ83ۗwg<_iy\U'˘ +Qd--ZV\RLm d1\IVKd.^tc=1[*Հ(Fo]b9ˀ5|Н}g{YIk/fSj蜇&j;kjV9]kOL5&M{A'eJ/{XU\v# ştK/Ojxp.Z) ]fa92u_5RkNx$H|ɜ;\lE~(+ZW UOzr&JP5Z<N.&p'jkL.UD~HidK2XLW>ޘ惱N [_L5U yM%= +of4:.kf7&So4xL9̇n&rYl76F,mԽu\'}l@~;;8gjYu/BUXZghv X~:vۀ zÏ6Ya3[x:hƉ?nC>DN8G؞ćlzX pj)H/6Kbq3l1~.x,!O־꘧1O;Vp4zԓ$, 4# ,@RS5Fsu*+&䐒mT#n:񵐔i5ǽƫYWi/6ar-O;)(n"]6 ?^Cf/]5]b%Z4nj%Ǝ&$!52/ǒ,o 1c0%&,m\LՍ.w4- I+sWɻ=ho/z%ׯ''T@\_(V˳4E/=QC[>#%4۟;`]]7\bM=a3FR6>`%ɭK:'KOss5N9PNj^q~]-8uɆ՞;Z^y+4N_wѧס_>+Ɨ9HtO}<9IN<# \e7@Vhxr6ώB8zF>HJS:D{7_'?w?['o/5\O???//~O OOWm?'C2}?>d?kO??N?ٗ}"ǿ_7&Ɨs澭Jm%$,v,}{?s~ח{b˕tN!(q<&7}$]Eb`EO a?S_)=%ň)I <%Ym3s.8&~x3Bⶶ)FB}Ҍ5^<'!vNJvW}N}ω49S s,nW/l)4OrLt03/I+Go|I~Շ$D)cEKKأ.J'#!}-g `Pfk{(Nm50]j}"=(%vn 8ZW!E16}Kn]I< Knle펐s44$nt)sw\5ʜ +<1 +YI$}LLޭA^ڄ"bKaH>J(OEV8,WO2%#X$ed= 5 ÷K͊mFmI E(Ou0iL\uzL!%CDyF$ yMЍ"_RZ _X½tUK+ddji&~I90=FAwt&B :^'ա9]]zzD7b -xM JYKE!q1y&ɰXo$(B%B7Tț`VOT!P_>)/Gt< ^Hz$<fNgmFvN(I(5?t#A gsVA!I쪔LQM#Q ^[ȮZV^7gcnZ8Yem[n||1GJ: HMۃiЍWo(oIlQkFOu 0p{W%r\apA,U=h\5Cno.H+5o'+DOt^߲q/ߌ-=&YK`Vա\ tcͰ,K%ߊTt2XQ&#$ aK)b ^WiФuTyֆP4 +Q5-wQ4Q//v1т1sh3Op0.dܡ`iLLv&XQzפ>N +AzOz0eóxv; uH MyؤwX1 C(^IwE+hsM aA]{IGp;p2\8dBG5% Nx[ҙ1uT}t)gҷJ1tIBI-警?*6nj[q9,쫝4X4V-vKN$:dɼL=T磴Vl^n!\kaҪY-5tN|imldY 鞇;i1JI4EgYE@: ֹiD,vsDF_+R< Xr!KrZ*9dVBKӲjZ +N#J V9.4li(H㬂18n QBj X]Ôuz hJڃ +8Ymo}ҁBaNy>*k`qXN]2h;7t2\LVi<<;!Qpb{rO#[ 0_@S$ޘAAs4vk? 1ѯ:d0=IS3"Iĕ: ?nȓF&iĻ* 7wN+#&;d`%| "."kT~Hha5ړ?]NCӻt!N.e%1iL[+b +8\ 0"K'x׵$%GZ8rI1#i@NSJ:ujR˹0(]yn +įhtq4z r 'Puvt(c3PeKA8ak0ю4oA@J<+$ {Gҫd)r5B*1ff~M&M'sR /EsgNTjXmdq +D )"x 0 +y|h4KሡD/4Dw,ABkWkh" ΃ħDLw t& Ŗ8; F0pLOudA7CpV G*H. N81shylcL6Yy '#ޮGT:%R&C?PhptY'u-_Ѝ$' =SCꁍ KӁREMJy*laZt*ڳ; NL#)ɤWc 0y0 i$0N + ˬE_ih ޷Q;:*~u* h|XZ +e$R- +?')ܝ JLtK8Ŕ#nL+G^1qml{pXXt +CTD3Z&ԪqkP_V4MxxHBMjʐNk2gT:b0GZ$eD.FXT#0t`\A-ig<2DD7Eս/ ?.Ŷ4eFTuli#7'+'5G&lv ZN{( i::avG7.5F&wESْ +]0znwzD ,pQ*ƭ^"*N-B"V (Zc0 fh$>ǣ$W ҙ&I Q5m9̩T쒤(ݤ/2jK, /xj8I@;T ns+OL4^.W=[d zmrKg+B3{,F77i +Mwx 5Q5,[I=4P }`u6m!^ +~,ht)Y#*Һ͍Tup°Lw#4'v)>mYjך A/@vqnp[:GҊ%gabLsb`*͇i*[ˉCw Z%Y4d|cbi1 A#6`kQOF1v&&)J0e'Η#<XN`N4t!P7D(ΰUc!2wC '_EV=Iќsa6 z"+XP't486!tsǽn̯ƹIJX7 <)elؘcnV+߻Ak%% -r&)2nPEjaZ1K+1s1/LzZz1w A1|>ƅ86rIeեViw@hףd>Q\Й)Q8>BEdZuԅWx?$td= X&"Z$cW$z٘Ds cq/4lqo8*ZO*&@A^6MUC*9lS";8E*J3ΓhPR{4TCOn8Gn:oRn#$ CsMq%ca8S 0Eӑ,yܭ#i9DMkXŵvf(CN`8[׹(LKrBscIP.;O,'XՌ9k>4#1^m Z]@ i_4c ]Ld$I]VD䩐d0 \alQCAx9SnQ(!ɬ伎%8U }B30h.)DFBN $M_qq6K>(@6ҬFhmk +I;MȀ9]6Te@y%59Vr\pLhB:θ߮5 жӂW)SmDa g2&}ѐ$6&藣j"L`aABHQxQçhU;v5G#NIb2s~1 8sÝ V@ mב2J 3uKz+Jj3Q`"b&#nN ?р# 5q8qZ?y +W +(0;^CX-SXD%!Byƅaf2"㋼dQqϞht&Rs + 89I%c5Ф8-t 0/qޟ׀L(4$5(y J Q87h5I@ !fvr:b$#a&u}ӇÈ,M-I$;wyGOA"x:u_[|.Gz C`\BWO L/,{{Φ1pda._c[B\Xly] sZ+ blջyV`F- ![d"HpnpdI%Q}-$':1i0Hx0)ڦ*ubF2hI|dhZRxc '"X:HWd2.m{"^S,gB6CZ"?z.cJJ?4r0ij8fĔ75w NwXn>+zЕ6CV5(KjVHJikD;OJ8be9vįtkč݈L֊H #K&>QƼX_yC<k)ALK;f*^p6˹ѽ/$hBHok(joR8!#9(ol<> +F#ת?X>=BU b[,dybdT9s SGYxEǴ%ӡ.up"+ .C:MG2baqiaP988=uFDdy c<A~F&#v)\N m,>,dua/Z,*SWƈTnu2/шYngjiUDqsߖB8(ීIX%=)Eϛ™E_DC ].fQɈ3AqVa15TBfR/׼r{HHƴKѺ([eqh3f7F@ϝ,B(nDZȸFmqFF9Bq#y(?ӞxmL\CIG])ǑG +I,B؋;1%1u!C=-=J2IPiETNH;MLKjNG~DlA8%" [B8w$Z2e4B8ވx#'֓077v񲎀''t !1DTFƔ@%ǔxQPK[Xdn + ɄLJRiߒA \wL<3$VK{v.c@zn#3-ܳN]6iL zGՑ7#!1UbO>:N&x&",YWEw M0@#@.oѦla4⡡.z!Rb[LL4Vf   U4A)BBU9z ጝE y7n)۷NZьaM@x!4ϟCHZJ?S_yx5Z{%Y$eҴԇg^g9`S4HҢKׁ qs(vE+WId1Xu {l/0õu!JInKjd(%:b +6YX&Uum=1rV捪ͧoFmhtS82N<3n/Ms%[7! G2}:!Of+(;~ޤ ^%y2\V"br舡Ms UƗq* q |7OWrc喲W#37Nm%NT@nC8-A8wľQBFwVRJD`ҵ'8֑J6/y/'V5sst" "*4W+|jYgǣ|Vjp.kxqeVC;zָ +an]kY&C,I!}[H'Da)B tȏ~ƄΰrBtLvȎ +(@%EphwE)lc, (%0$0=4DC ze.(:^K};(0~  aܶFQٹ܃h$ˀidǧ5N +}82ٱ+zYG:x@uD٤@9G߫6>6e'H)ƵuIyp[:BI{޳" g䵫IGV:ϥZKeIg:9k֑ pz8i༦ƊC.RSM9-n%R2gNL\ky6=id;xI<(kB@dd3#metF :vC<:8HVFXSŌσX{ k46!\iiTHXC5b9خQO4=ɭX.o %Llfďhv;҃ /WK˥4dϺQ#ឣm&lVb&>x44\“Z_;R^BɳL`&:E"{ d DbE}LjL^D4^z<" [n&n' +k_.T`$8+q"2,ݦIIc-iDشͰ +S.IROr4 g% +t5ӂI$7BC&aiz|T@20e-$ȗ M6 ՞%$Y T$1:O/b##$ DeD.4wwᨄVQ_Mq"enӡ@<0PQ3t&W~tK`;Vc(1kGNxNs !YZʣ0L1qe2]!Z<[2$ +$/؜&uʅY phQbzz0O$Uʿ>.֠K.Rw7D;}pOݭ kn[Yp7B))Z1iHZ&|cnZdđ,-9caIY׾QݎR +dک2ͨȾBFC;h4oCBNZ<5| ž6;+Q=A%+:9H&풠t J|!|I.P6mq Nv{oM{bq/ң3gls!;dtUQ2+dp[Ub/#iyJ|9p ٔ|j+C11owG)qmǮ?ziF4/wNvNgwmͥF%WaHo8n4ΎH}K /ASfYY32G.3>!jqf =yQ?'ڎKS:Y3:ʂߵw/WhZnK߱O+'.O>g\;`sfu ?THY1UfD8'+Jn {H»Pރs(CŜ!S utNv{n`TJ&*(PSaѾ[3-@,_t%h{#^b\,h%RzUGCW`G ++>#YgTl>kgc|f ȱ +'&J6P|3`iy9;9<UNLT=%63>#;_)/{%:.!31⍕&]nd[I:-YD=ѴP0?bWi`9Һ w]OcuZ쬳Lڮo}-l1[4}JѾ-£p/ Y'jE SW'DBӬHRz +*Ie[} V EE{ ʣJl2J=Y[;"{Q f!(9\*N_#:CFhvx93aR _P/ [ -okrf,y+WhfϕGݗ~Z=#BjW?h2lܾ.]|v&ߍlICXgXUͰ׎;}ޥBv=8۔o>+I,DZ2>*F.ďeRG5LOS[+2 V4\>4%j.1JS~=EM=ͤn[Vh|)~gɌKd-(vi -AzPm Sh(J*C"Elk^'kZ2@ / /V=RKϔHO O}M2]HWEK{{U˵ ruqD2S%.i1WsK8\3bSm[*J܊]s hQJBO%ج9-/zj煡hW΋glM?AVe+y(hU.sHv۬%X8+pf4=-9“3+d^ ɼZ6; {-p{CA68mBfSQGv2d+%3U̷(,ۊ]"[م8#[݃s[r\$K{N֍94nNvanwn+nIJ>q YEJBvN@VXz}Ѝd+K_ŷ~ާ?a֧Go{᷿?d67>{_쳏n>?{~4~}c~[o?6q*}v-)Ҹ?^#̻ާ/Y ws|';Hx].=a}L?KgF#?}ߙ?[$#{];>>2:_=ɏ.m`so 'd7^3aaMWZu{l]ʜ ݓX.AZ/ AKoVQ +&= ғ/J+ZZ>@c  +#UjϹ[(̊<5i +qkP)#(_kR O)j:J)LX=lK܋-g]&JHM2=Q0qWhC `"$NT$ڥXHٺBV.>1<{H'QҥdB[@S+9]mݾiݺ'qFGQ$.4鞰/dUh MɈNg.#tU؉٪ L$O=a1%B3uGziɼ:TKvu6A5OdZvb?-Ee MlM$fUJGڞJiXi9Q[ʔ~ZR±Ԅ$5Xwk4}4>e?X΄N>s՗;'+jYWMg׾8yDσ^y7y?1ZQzXV- |uzrEy:/˜dsVurX%`Q"zإDv'e" V/Z<]7Hb?)=>I, w /juICY# ܾ-7=gÈRZnE<wŽm\ af|*%õ獆X8j\Zp^I =V]},Mv=J]+drG7BWf~ԧEDѺ">l_VRӔ  Ut(4m=W6#Rif6}l]TP:h:WOhȠm0ԎD{,sv*Y;FB}P=+[F !d3D-@n"hc3Q, jn~^pnVxWNxƝz4V0b7ভV@_G:΁@6ȅG?4/BvJ4DiŎσt#ڠ?9Yz+@gd+9 4B=6N(jEVeHB.wNF?B؊K56+!4 +B dJGr'y}aЍdmAyZپ2X]ʖmԐM5jOcwiZh#smsB[]2=@ԦI0HGK6%n[G+A7 sۇt@4ȴtKi綯_[=>n btM1@JX/#n2dzGg&ZKvglUj2HHXh"EvR̡[Fu>jReys+c5]rlĽmC ܯUi7E%*/FkK0hĆP[O:8[pdKv윅jg;3Zo(Dj+%^u$T:P/vFmέ;#xZQ\U\Ggdmn<}LGzcЍdkXm(-ݚ:ƞĝپZ$+72$M3O_践ۺcփj=(sw4Q%&r5 +a׮D!z?[t#c{5}.׾ BjM1ċm^[iK{hl[okZ~[^(5"ecqnANtR]![+n$ۙl̶glC}lK+PMkpȆ㴴˗m `Y\`LTwo%;t˯S_,sʩs9$[w#pgԏ +0u%/s Co&\z;9΁?^ʯ&ٵͰk/-n[ֈ/;џ]Œj-f(|ڠ[s$\]`AwQ*4D1j|7HO_}{?Ҏeay7+_忆ZWsSkhW\R*]I@g}9˕';37y36^{߾j1/w?gbgyL۽|<5sgy΋'җ}KC;o֟7?/Ay?Ыv[uot=7߼}퍯~_;oGQRwS7TTUwۮ)}/Oi?_O;?oz7ϫk[{۪;seWgxCOУx;? _{3W|o|?g7QQRwS7m՝mM'+_f3Ͼw?u>ϫ +endstream endobj 101 0 obj <>stream +%AI12_CompressedDataxK%I/ b.jͭ%/TUz4E2QGk +Bn H\8H F Zkɍv6;ps3Uٕ==Vqٱc|[O>z{rC6:<|yxӧ^|Ώ}0}ݫ/o}v{xm>F_|z?jp~ /_HGz&|߆r_\xqpdճ'>oC5ߨ(yߺEw~tyk16mmðzr{熀|.5><~ճ?y~ŋӛ/9|}l>?ﹸyEn}'p/O?=<[^vO^W_w|;>GWWOUӫ?~'˟?!y_CPٿ_?擛^=z?wP)7a0oaA7Ͽu}3-<3S_^(#?ݿ~G +Gh|n>C/ [>~?z8ξ>j_W/?7_}y^Nn'6 ah=✳86x?8$5CnpD7[o'/r'x*`,fZkAkkRy|?G7ϮҪ잿(C;}!Ϯy),e͓3饬45W/!o<}RD<K˯( >]CmN101K7Y6J #MC8 fܨI2ҮO(H>0{~bϯ}_b4 ?Ofz3ſ[, +z: ?~TnRV4X/&;2NϞn$a +}|.^} ޫW/ӫM}WlW~¹~?}Y 2W/GO.?y9OՋgO}ͳGkHO~яO \O"Xy\_} +|t/]}){ t+ +tyhѓH7ʅG9ы.c:Fϯ=>{~W>3S(_W_>?՗Ϯva_>}v_ճGϱ/jWO}y´b}wz޼xIyϯo_z+ H>{/=zr%zw(w`@_^xꩌh{u_\>y|Fh'vj5wq~ww|GӣC£$7SuAk>(ל^~G@txÏ ?nqӏ}_z_?񋧤i?-w^/nZp=xt|粺2>tr)qyqxUj]]U+LdzxMMuM NƫxW*|~)u{"uӏ_\#0ӳ7JV.}~{6rd|?!WW*g5[Bٯt?8?>xx~?Άx?|^f,=(R=F~^^CyA}1줅~{mjM i'&imDsh{;3hM.Ўh8p{^9.)tOa8LzR1{Gox´0NhG. ӴP'si=#^;ɎYk̅9b*w&]3.I1=;4:RzP) G¿|qw_K=s&Y~7-+Wy5MveZ:vLEnnp;UNͤfK?ci>)]jS;%/Gq@F;a<.Y8=Ob&4HAv=LGf[)s p@lSQ-Cc/^b?'{g5{"Ca`F?$ 0(r8Nq8bwF1Gt/wu8vq ;ddP |>?ϐ7fOَ5!k 4JW®]X ՆEIyN9UxS d.&{J z] gİ5Mf/jcIʁF.8DL7i0V)Ѕ VᓐTOQqMP$G6O0/808CkN0zv5bD&(?dq 6F@Q0hS;q =yb\94 ^o`NZ0iEF4ݯ-Xjj xH3|[pH N{oA +!™72h8zPO[y>},[6օӡN(ͧ& Mi G-  J; <(ڲm״MdeM3M[RIm2شðڮii5q* 1miTz"2'Iw!RITJ4M5M7,m-4hSB@qWvlکiB#l{>&E=ȖphJ[-ʊK-z.5݉;e!/DIG'=ֺlԊOQuڬzmln[kԝfp[kY͚nfmyѢ[i֚XvByzL\LezJtS#A Tzv^$B!(GSxpk`PD`[kZF%\ӝFD.҂8Az&tV&R9hjo05BiG B]EE$ґ +%h&$#BB' %`PNXzm1GgD"2bʮ*b`B|xt|ǶC[ɡB88(fEZ&MGG*x_ߵk#)Aljl۸q7n༉LɼetG"8T+(b!lQ).^2kd\q"D(ڮH{Ӽ^w88wBYՖgaXvuNdH6'QFUQNI"Q$փH&aȱcr`faDzPu!:eǝ5QzeSwf1BdG0 c\s6Zu¬+R˚ds^ Xy: јu"8 {F +q zv>Pڈ>- +f d+v ذqr UER +bU@!vvuٻtF`mpVz|NV\4@7a-Р5e0B?#9خ'ChdM:v6lFCIsA9E"OSYZ;8 +Ǐ%1Ik-kYb2[(2[(Sɂg6&]e+gZQI`HrT9SA8-R +\4!BDam'*MÓKբeӔV (Rlc +NQJVz{Qƃ(^Vz: aa#t;d S8qt xI Q!$kd#Q0!@_aN',5FP$-$Ox"5.z`?ޚ4mz9#K(6]䡂{ݡ~H0>1?oUǚr0@I)C""H@Ҙ= ~tv o`uBUR GQ R0&?\1M1+ De&4H`'NH:.EB5{(i>9#g6I^8P@gOS?+/QؼIJ A-}=Q!:?SIbS#OYH*ެE.Ȑ|QlTd=qPde < “pQy FPkǢ d]` 3JB &jNtQSRFɷ+zw L_v g-4ꤕgOIl[tuťm'ؐ.DP"K Q"p1\%NbO^%zxKGx^Ύ]/N:mOl*/YI O1ZI(6Co>Z{d!w/z[=~rj&ٔr116c̉/@I9ъgb1(NAB+fM"'~/1I:.bNt8$$z(Mmf& +5|OILHНObJHYVo|rSieJ. + ҺƕYy19fcU{<:Q1 E Z[`^/NymYlFkIZ=V,K{pm,ȰY̹ +qn59͘sIMЈm⩚qj &0[.9'O:Y+b\?%;c 4A ^\PzǂV,$IQth7bC0ZxlAGd[mtYAyd͒7e8G°E*QMnqv +18#x(Ǿ:IKGSI͞JGc)q0ɂZWs !/ [h?&뙳ǍN .2^3c7QI[>,op5fK,ƒo*88ڄ&ELͳԋ4g +8!nvj._|")\jNU;} +~È3@9a?_&#ybNN8AǼݚ7\f[& ^vzg)4 ӬàG/Al .#'TAS1R3-0x;D0c\|t36KˇGpYrQ Yu;3ɘQ=4>a1#*]b' ͑CCTps&ՉS60#m<+Dže$[$y05J0VHY,}pr>JrwȮñk=b[xǥ^^y:x7^ZqE;̱xfCGqXQ$P%9_{9t]҄OJZE +LX7hicD:ֶݙ1{p^?ն +/kxc%[lGw.û?|OIDOblM5 ð&O )>Py ́3})S[[g3p.UWwK^'cCSO 6ИPFDoe<W#Ac$p}g-l|= mߺmm8-9Bmhܷl ,5=onK#N] 35@.pG Ah NqW {X dJ;~?n#">=d]8:ҳ4HeL%EALPź>/W\#RvN4Ƒ}HÔcX"]G+[?gh'cֶ91uhz+ u?R7~S{\xyŏcjl9A%Nc f,/Hg!*HCFF,8;?xoy.sFy8RI+S߱Fm-Y?M`7~S{l{۽8g?N8''Uc1YslH|0'9l0O6vK3+fr!O) b*OxUFNgSymls9W[/ƒ-{R[@zN5Q㐘d֌.âZ0g:-m\684ڭLɀFQozTooB~L Q줌qPCЊhaS^+\ %S6:Ȭ\cbFGA_,2n\ j?iݘ8 zF.]ջ0waTQ|~FxF.]ջ0waT¨ޅQ zF8Vr9e)rTtP .R )T)zAZT,,Maq5ncq&nOrꤐj&kĉz_9?*"z:,BbLj~ŴV'jĿN%̊/^R -ԹtpgWqO|@F8.n%G)Βgf-iIKR*)\9`f*iER?0Ɂou:k#비P$DoH,BGl +Xn91 Wkr.9GG"AbDTS֛tdd۳sLN>Upܮ +sš¹88>J+BVqb+A(Aaw1{ێK&xI[)\bgvc%0A_Ğd.嫮窰x>~ukXx_6l blIАeӍ uiɞ_¦$[D6^ s䔘9S_'OBU#jÄ\,Zzq&Qp@Aw8Nɿ-VNGSusHV%C?㬥a+=PD5ݦv%h6G `1ˇg_7{ ='\$d%8$)?vbTmRM,w盒h-_uڶ,JPa꧜b\âϠgpv]5^,e/URWnWQ*vܝ &e_Fe+&h:]rQ[gs59zx;|6ˌ}:'Evz{ \UN}2yEctBt=  %.!V2R3G$5K%,cr +&w)E\Tz&(Q2:lI)yeR8.p`,%*P<<@F&Eݲet T찈_A$xaU*mDRo4K!/)3 z©:o1>4uZ&n"Rʏݮ*c = /SP΅sv1!y $!IG/p $eu1'|4E>[ +HT 0yFvL97SiQtEMZo/4Lx6v5{ݳ<ST:hnqEISrH_2XW3_;7\_m_ZR|_ŽZ/z)7VUs-﹆\;j-?).6tI?%;[lv=+ӾF2>_2&g*fέѶnk [ZQy0r{;^[hg쬩u^gmBIs6\\0)L*EfVo鹊ݱȲ/),ff'!ZNYQre>SMS'e(Z1%gEd4sԙr^|#]nOlVgfwb+maHuj/h:bУ:#R֮jǪtGңsn˟~w{|4s&\*{k'VJf[& {l%nCEQM'fLL܇ 1h*ug11flqR9˜}%Fsdo]* +٠ +sVRBx fuhݹZeiƐLX$I JH7,m,";:mb$s[+6mVEa^/r=+r ޢ?eG!|}jt#/!ep?rtL)t ən*P)89T9#\"'yE'r2pb"k$y;UXv*~ɽO!?9rQegP\8{*XSKG|fsoOWFp}W~ýyIqN.!+Z B /)j!>xT+ί5oY:gT6iWM#I*q4M u1yov MK\J o-vZ#Y!w%:,6꺏N5D@5+KeXkoMžZ;I,E]= +'Ȃ7zyg7 xHqZ0prjqtshZX/sk&ek]JRYLvwOE&~Q BW +gU80C}`eJ3T3"9z6M>*@8'B6@uBf03q|^+S SWx6p%1xXLvF obIO _D!zkL=ooyFøUbT"vбί5\>h1>nHBfB ,Di4F~;eA[9Bɵ#1ZfU={]w9{]w9{]w9{]w9{]w9{]w9;ƭdž{~Yyܽrw5lΩ65J(w/+lȭs͵z\m9npNR?UdLSF97S)ZpxA!rEt>E.ѷo dXeus\z%X^D>:$li%/}e=\$ЉGS!3yXoBh|Yb/A)>HwLuPNqz\xbh:z\WUR}IVǯ%x%~+>[AvV-p$XWHUvWXiEK e-VZWZYʻ{LJE =u*}nhԻ]-ĥ254=lJ i]ECՙv'"֪`; 'iFGJcP3z3{TF~Zl#Y)x{c֚z4>~=NM iݮŝi&hlquVҮ-IhGoQ }>x[٭ԍTK}+"׬E]7RKfW Z-VYSkswz^wwFBU]+sF~7grߗ`]d +1n\|sgtPix+,@EJŌDݜ]NМϔ۝]bX('wK7Kj%Cs㒛TsK+\k* P6 p:UߡW%g?~7gz؋WvOUH IW攎pWHpPSU)9Ot '7:PcrA9䠞-\$߯zǷcm?YP)0((UEx+@p蔆,B- +3zuXaՍXK%xMjH܃Wm@YE}:5z5h P\z(g0RL uQ ]qWݗ*YLu.ARlڟ6d'C@ϐϸp(Bl2E%RԮk0JwUՅE_O@]v\iu:y <}wi[sQsխ7uzHp&Inh;@g|,)H i\@]HßI{Mpm.t ϕR ĤdYa*hT=c_fрs\#1gkNRR'hE&46"}JWrDIQ]UXJsub866mf]S*E xaݭ(o|7mz\&/?ˌ[m|i}bw];Wc,yכپf^pm܌;vk)O׵퍵w=ZLѦ6MLZ2.Rt&cMDaa#D%>ԂQJ᝹jfk"Mk*Tܫ`]XZ뭖]U+M}eŷkkvRֵ:c:ǺQmwu}wu}bGpu +++cJ1a[:.sSWB.w]D)U]fDJ+kF@[їC cUʜ La%*U]WwΩs*qb} ང2K,r-2ՙΆ9Ao%Ԧ]K1E6ֲ^nTTHoؤT2j3ۗ˗g1b ~0n)jrh$20d*jA-"|e"9'aWͨ4,leRUs=^2}A[̺ʹUB0-VLS3;Tcc+TgHOg8T1Y1/" 7YjfYV޽Wm9'ֵm/ +VWu3^WuZmD$]qX9VHHqU hk2/FqZ !:wؔa`d\Da &ׇd0Y^*aF#ړ.wΖ{xMoo??RIc/>p-*}4_F +/I =%YaF(uNwwHib)[WbJM]Ҷdr[BVےsa#@ϻf_} X*+nrGM괆>%WzlHF4/u೫jм({-򻐎]:C΋\jSNQ!KvB~cC.Kj&wֲ qԠUz䑘ȹ89[mlbN/p +ɭd #ҖDܑ[3,KZ}gXd^^[P[Ctjȑ %b=U"POcȔ +K8 Ŕ@1-:5)UA9U=S G +x\w<~,I;UbJIEz5쳯3ا7Sˬ]A@%ǜ؀0Ƙ⌥QC%:UBJ;bB\TO  +ʈiʈs!2b1"mڈY>V خ^O*>ɱ[iN5I-O^'*\z/$y:=b3R!&U¤3W8nyEv0nY\ž:EjJeeXI=tTRN"AźCV{+vhrYu:g='3"W>)^Kl,CuG. FX,7ՁMڴ!\;JX=(?O6I |)A9E9O'SFp{+C*&?;Ž2?=wuV*vҡ fLy\(!Cp)/ѡ +:9Xjd{L,4yKɕ\ X_veo|Qv+r|v’5~- &Ρwchvo!t~FW9lyS,45HXo±XRZf;N69n8n4n0n,n(n$y?I[^ u[޴ou\)mj<[}=f0gTw0H|n>f7W˫9'/Oc0k%FF /7*Р)aF20(~+UE%g_6wm7?6Ov;/yٝ`b?X}߮?z{xͳ_oonn '/o|XO?~zW_m)qA blXouq4>y}ܤ٥LfݧB+0NCsCk%p[Xo g-%ӂu$dYoq%49l*@-$1;c6Armc7rО'>G&\Yl+&nxz ~4_śv(9.̡?ـ9bRwc?f ΀t 023{҉R v>F2XA4C"e}WowHk[?m_=|zح ތ+sҞRirڎUBڢs +8:dT!1bӼaPlţp>?m&[ h&bt xq,$跄1 4p^=xq%$PHxHs;ap8Լ#:J|:m.DfS~N p٥" J +[P$:"b{p~c #N`.Ը1J.SHQER&bF+U ogf׍,@86zp[zby#hFKp0yܛ +;5,sk/)F'xVfs,= +ek'2s?1с2`(T HFz/&EcT`IU_@wmb`DѨ!)G&(W B>)"\G8Xi r3T޳Р誡&mIHi5 0*2)m=8t._ey zzJOX +OX> XaBDbs_r)W,Oq| Yq@fA[ld8I*0b@mc'Fgy%WD=l~s@-`ӖY)Yg/v1(''8!R&gD|1p1 A3#N+;8jH!4aG)gf;Y~ $fep~!hrgiBt=˃BqpHA ;hOi̘Y,f/]C +<9lI8[88ŹhpV7fp2T/ +ƛ;S,JN}pqoRBȃ t1 +K%(p>T직" ^-w·<F,jn<,e8j(C'gY !تҲ:5 q +&t yh>%*!p\I mb|Ɖf/\]o%m.<A`i־ϻ<Fe1tmo4ep&y$ R(3 +c]~Tyo?5z>}xu/_}^aA>/wYdx泫OwO1^~ ~A/٫Ϟ̤#]7{V'ƫ\Yax ?Wܠp$dxF1UX܁E 19'%z5N\Gə#xIB 8 #J.:M?M1χYlv_{+>?GRf5D.4SZ֥(,ܟ1|TUl1; B& ^ᮜI6/a]@o@z 災Q9  H;C7xony \V& +F}/ߓ}L&Jnb!NjQUq@eT B!"M/~q0a+L&6]P0GK]Q~Mù +NHu[Zl@hix8'KYQ60 KdmTKHP0-`Z*SNuFw#!ayJP!qDXc7b WvCր*VSm -CJA7;~7Kr!%c{-EFgS}a!m {Aj&( f +hĴWL$rW.\Y' RB ! r7Dˉq\b(]BP#V7MqRFV0L+~ۨ5C,_b`p!L'̫IsE61 +i_yqXI75,rp!hVJ +nP(:/KMw:p_(}$nK1¤*`ͫ_r $@2G5(Y$@dЂb)a襏ƏQo؆2iC/~!z. +ݤWeA](ؘ"q@,rȎ ?qʡ.4{ѢOT[YHqO cOTZU1<= Rm4$ ukDP/G;Eț*@⁈>o#(O˜@ j4y#uRD A9іa !sDxB,W :L!$d +,țN]+=l$%xq€[B((.=>n& " +MFV;&B)^~!?q̄AĺT08G!ILydQ<3M\LyCe !.$;qL?B $5s; p(zZDd VʄoGW7!#s$|^E]ځWQ/(E3D3!7}PHTdb@ 954 ɉրnóN @r9'c[ApCp?NXOqKA4VD33q<4y'p*Fx1[r-<ǩVchx@Tx–8X8΢ {1(2mGS\q [pzlڌjT?aoDc=qKBE}̇HdAOE_є)Z%۴i<{(bjAKO20)hUT}Yc^8WɆDS\@Ka7'}qp& AZ,s̬pqA%Q$8o azyRXq ,BtF8 |QUEa9E(eʑxrbˆ i"-I̡' {,r*#H荜Jn-YۤR)DoYdڑz\QyfOH8̍%B{.YUCát ʙt{vlH#! kά4Z +@L)4EY7DɅ2t^AK _B7hG#QzCбB}]`'Di cmʈ 0aIIp CPRvK`fYy'!Ol՝ȊUN6Ot֌8*D˸ļ#,E EPA^*&‰$А ӒBDm$nx1jmQL+Jg 4 +rz'ݡ;NY?yѵvM7)&~84N%4/If A2ì7=!L*ڭhD16є'U<*x|iMW7ꝭ]8k (Itar^:hz&_'rBSK7DkZsE;c("1rk0`ԊUSBTS+W tmwnm\86 0^!U#3>ֶ[ڑWRY775ynĆuv 딕 Y&kKΝvuStfnon{vs|ilgwΞd_庝տޝ@wt'IОHC:zճh7=;׎y{@L3ʺp9tRNvrQ,.Wu6ֹ$ѮsY ;NDY(휏:껔ָLuyv7kUA<:Es +딕Ωl]:gTU] ^Mn{Zm;G\_\睏c7A_wӺfvpE㹊{D t6jtzT\gkЩs@Gý:uܬλz7U4ssnA?:[*yeg N;sN_ő;B~ݹwߡ~wP~;YlL֍U ,#]ź L4}GkFVD#aD؛):dEiKF՚kK|kDTLwڮ;;QD22bpg zu<[crUo>KlwE\$YryZuZ#eZ(!q{LL;)|0F'xz,!$-Qh\-̽mtkr^5]?^OikL.DS|UWZH7BG 'nd߇~nwwSP"0ldzSYZ6b 7 +KaXEqM80y00AE|{oR4Kc1c C#tM[LJA1u'Kynn\W:ꦏrCAsf<LCD953Y)?[&YtXȝK71+(d<.2oa`~̄BW8;'$ AbAEqHK|_{+uy-mFg <::qd(aD*liG+5#F-H*`Ζ2f*L3) v11 ;ٮڝ޿*'먛ؖkZRټ՚o ]$Z4R2Xb;k!A-=^gd|ɞ:Za:}A]37o (~Stk=%om`&qYx cYO*RM:2 ZD@JZ4k +#D9aEБ!/(!u%$>WP:ё9q]R0i|dGcD{C)9A)rt6#Z=|گ`l˘Uf HOPMN"{)Z;x/@4$O`C,&Tab Ff[!Z" +wDG?hΉ$vQC`!z b.%vTG++AdV1Tga#HFMAc&n/+˜8@0D%ۘ! +\4uLfKnJ 6=kZJ$q6GMw 3[%HTQloy/4z/*QF):9zG6t{」4b"LK1/oHı`-+~W՜ny([gtNT̼f5"Ayn]~c{0c8MO]x c)yRͦѳۏgyK,Q`#OG6HNqr5"swȖow5,o~N2ׇ:g& SJJŠtef8PI/JRPA΢%'X4qS<^rdDs7*~ Ar\2FGS +}Pk(79:-#P"r7tԢۣJi('=$B[fSvI 78nb:J&gM[PXxݹK>-o4lSҦa2RѮy@ah+GWΉ/V\1$,p-#GrrŽC h1L:@#SJ0ު0)zƛТ ZSҞSÔ3^ +oTh'7#&˭w~0?V-觧e< |k}:حxD;*l% +92u*+%>xW_]]zs=wCuUj) pN l2풑3=ɐn{59/)9>9e:m>en/גS񠡜]dQY퓑Xo1]IF1 g6OFC?zo4ǵsO96NR Y\{\傷@L{\{Z2xD{wD^Rb`BQx  RFG~n|T숎O9E&s5vZ>:0QJ=Uû3WQ9șS +rx! +]Hl7`)sf:zj`7Ɍs +r1-x@zv3!5g+qxIF`^<3JKp!,*ӍNYT>v$ISrKJz?$R҅R ",F7\.yqHD|UƈaC!ð!zFj(v+ozFϣ2F>B^S_ψA:r +ay#12g}]HbyJA#CFs5rc_O%FHZЈkD4T#8 kWшWt߼ZHK1pji+i[a+!ꦢ@{ +I%& kl+IL"N^c_qm\GVҙ$jE#*ziJekM ++Wh\@|ET_Ɉ|0b(RTg_<+$N_׫j4Qܔ/¸臠sO+_D2YqKZqڴp}" CEF ݹMfEtmi0%,; |?eJJ9.-;TbPUf-xbY#!BH4c?Xx P,&bz ? u6V&qK pfyQ lZ YGW(yHX3\Vfƻξl +K(~hVUg;"K4!h;|(P'Lڊ}'|sj5+w/2+EKwzܧg;<&NŁ&wz&FB:[[wiu'"dЫ̃$eeg;[ior_:Vn*-]1ߐu8S.H#>/Ǿ%&$Pd6*8 Ol<wRJcX\ԗ<)h9l-gQ $!w m;pZ_ BP9^)7ȁiP,ē$dy۪:g+`rՊ,HĀ:íȁ# %/.9dEHcyc]ߕÆpdn%k/DY E + (]=4储9qR7HZSܿ%13DqX#6%17Q4Ղh})&Vl<UEXEX39W4OԨPE,gV~ZіI9 +Z$;n\֔5TäH9CS[͞M ׁqoa c97„$V|@!1LzN>"KJ҉w_,FLDrϙEdDf]VE1>j&錬iÜ]43 ` +?1p+ug\!y-HP^cNz 6L 9LM&JVz>%$ 9nR"-iq] +^R\Xs~~FT@M {>"Kd9xF 2==ƲNCJ֥X@-U.j% s%]Qi@='f pD%x6/n 8J$X/ᯖ0\Hc|xB"\խ1ebYz JaH62(呺(AcC&|.ćJ<:29nS9iʮE%xQq"ie"HOs Qhx7J"[jҴ&+܅z%Ŏ\E#NBS) @$_QvX.TEDYEyQE6O80ҝ|3kɐJȯP\]Ft 6NYiڹʍ>!yqG?X͋wb:ӹJ E8r1ucHn,G nfϠ(@D@*?x92]D#HoOL Gfx3; +IMMDY'IgA/]_ tV +85ޘuQ)Mz&eJkTb~_[e1E]Ep+8 ec<̂1L&sf#`6O`F@J3 WPHX\ۆ HQHոps-6Lf.z\w/hD 3BM8S X8,nL{5/B9Dge]\UY{v>}K`쒦eYu{ǤS,bD ˢr]hXܕrqaW&cL~j4?}AkBm|&Bu^t++FK5]M>W^Q/\he +xK +@@2_X!i/ +͗SV4Ȭ΀:ZKP"JX+վUDqvTn${hݹlT8K:6Uո{<^]lzrU]Ө6ؐѨRnf!niUR8Rs"]hbenX?儫jV/PBpUE}oM* ֈ~nU'6L{>Yj5ikĩx![eGs__J|Ezk*bzyOxOJ* n|(k3B$S~+Y|>~ǟ?_~tuTY &S$!M} '"1p[S`mNOd/]AEwRԗXQ* +fa~!ut~ Oc +cհٕ.)sDþ 7Q b]=5|"j!XI%vsb6=`c{3X#EWA^^c'F{nHcTOG>l!xQ GѤ ~z)9YvSԁOuCَrq/`-[j-6V2O(vPhiN9E2XIr\=A(*~vMj v_{Qx>P lmQ;W fky@^Аi/1d1Nc2Β:b`5>08| +y;! pt>z9OvԲa +R{@yچ'^NfqK +LOE'c!.=8d\aV2|3LABT^k>J<.poÿm`&F@Odc-!WAfgR"23'((`[:( e@#{_Qوt52 K3O*@F~ Z4mnapC܌m6qX?ոlvɟ7p˕ZX@#GCtkYF`4曷3 t(>KhC" +?!xaB/ o_縛ujEv[4B>ljkqǸ-0mf~Aۧ-R8"@>H[z~M(<-Q&M, ӗg`b,v*St,B!A2fR4n=;6ڊA K S)Ac* QL]ϜAsXl'xQ Tͼ[-,A3 jnJ8P1[bΜY~Ve"vrc_(瓊̇bt"|يXfk>ȔS7~]DߕC˼Όog\JCl"uYzܨ8P2b' +ZfT6~TU +brƳjB^u=,ĕRCvȷg|%˕+$C&`tOdUe|jk;5qꬴϒ++gϜ/C0D0XtL ER}3MDLpR]pu"R@oKۊ_Y %I6IJB!U'KhԢ"0xJ1#r"*`Omgxk3W jD]ؚ .dfrE kœh<3!{ EKKG:jQGrݞa2TpohĺN>O̘~'~C}1zLֲ(\4:H 65nfQȪQ]zWQ %5[C۬$%-+'`Q sR_>)BW0 +hoSԓ`Z@c~ɱ t|#:K++/[Wdav/ٯ0jTJ*_ڀq b +mĆH +"WH lB/s2`4VzL-jJ^~Iclt_fPX=Y&Nyp6P0z[2aoOta0SMRٙʄ{yw@c'jߢm{GfGvuM8r4:MbX޽RzoihdƲz_]yϯqO[5vHu,:DkM@+vLaR + GUT:;ET%r_*ɥJ'2Ň!l>֤CW#ϫ֙Ì_Jzȗ#8}wR:+RC_{.VN s+՚ x)|^џ E.+ᤝPڐaƲInj&S(T aUmQ(>ѪԤaIGVS5j)_ekI  f9z?{j XkFPo2kcVD]рvWoܴwc"1R/1)_x +* C=(w*: +hC@j:y+`|!G*} Bj +0H^Xf2-W/IkKmw{ULZi|/M;`- bb߷!؋Bd9_Ҫ;Ҫ R loZibRl%AQ-a _%P%*r t37Nt37h|3 GR-]&v߸I{삌)GJg}Qx Q Wѧw[k\&׏UӾ@oz7"Vߚ7v= zH\5o74w`X$7^kHML!{-mzHXЬsN NxmF? xր=V@bFlllS&O*`BհDV+Lve--Xh$llF:a0#i"G,884YZO}t p!1FVwwP Ĭ):) *ca/?m/| fx|tC</'WN])+vYmlIf{9ѢNk\g|g@QomX%$B6EqE{S{WSVnDIFoK6&>(0-Dsj ٶA?Nq'w+)p`W/dg^h{;+,ڠ;?r-/(4E<MK(B9\4k6,Tоw ,5BB`w!i Q +۠1}.C$ {uZ82̶)[,4 +t"*@[ۭ1"@ b8i3m{ҜĞW`*puqYRy$"6qA.r,ꇰ|rkhӉ9E|ˍk74*Sb擧 ͪޒdio.Q+":Y g|37zJ sy?4>$28.7W9j#xO:QZQ 7WQh)p-3LU/ +2`.U_rɬ0 ZMXSF>7W +3Yh?S"<Bh}J* +QIo-.K Oq)THHqf"=S "T_7P*c=Y p_ +xJ~sEk5WػbW4hD>pP%|m| %=R!Ai Ģ|&삱xs?Xw剮Mh}B{n.](6~mPB [^;X@V]rWvCABk(Sh|m8ܔ0bKlArAG=}­hr>mD͇Z:\W݋bP2:k߯ +x~AB/!v.0l^؟i#$3"jqvơcʡlV:r:a4mC(I9V{`[΍:Bwbg[ +ۇ'`✉s!4h^pW8 Kjw9,e98Kی_^.v/bo.[x9w%$8D+t(WqBJp#?ذVm V/7gnc_s"&N\1ЏlnU'Ztc8qV7 +4+sh[]FQx+Ed7/Fi)W^\] n nU,ٳ}ͮ^s +7Fo|/7z.np߼qnܶȶ){mci yڬSˆr:^Z#G%EGښ鴚]wBoa}ЌרxyW6TBb{@$?mg'ջڣY=|Ppjߵ~ +dEkSvϲ6?d][}ǽ=76 +gpA"T"2\AO*Q6 -V *BUv gIa 88W:PR-VS`lXµHc!|9Q- C$e\L]nobl5~BkIdt.?Q dg=" eʵ)fM/D4-:bqreyvu%1jb>-zNMڬwiKo_M4>ꘅ:rch]G3Xѱm2yvw3CA붣cSk;[*'ʉ0*La281JI{0κ&/_(mW~sƖ%zOMg;Ka\Py쮸|~k^0Df`t쮽`20sc4H(6z0׸u7b ) a~6 a9e*ndf\>k$QY<]c:#f;] 7QSD|dQ= O +ԥuӴRH*!gV:udZĥUSjy!bd}^fr@"V5optp紟e1A`ZW"6gQV320')#ݝ)G-!B9/"NB(6[ +%͍m=$TRM:f;ߡmKl^acyuRH=3 E|^7eUDor hF+ nUivXU3gEMǡvGĞw>UWBQ܁zܞfAvݨF ՍiI,B@v/r7C}K3y>Q]Z\¤xu-0!*[FZ%l!.Ikwd`nWI JHO2h464| " )MY>NZw7&ҧB# U !xаhx(Yߜ8 EK"S؏pwnɢmh^Vg +x. ~ey5>rݐ.{ڻ}q\I8|Aa4%K{ |K[ +3TVS"Q'Х@(:hl HE܎΄ ƣj ҔdJ"zn = -:dC:b}>B/FiC]L0RGpl[N"~̳ 1(Q^VRڱ{8( SrQ>:x1J> l&rِ|KTM]XNIL4o|Af3'T:(WX5E!tCH-jȪ@VTNBԁ;w %BN9. +Ёe:Vw[i˶ٜw{k I_v;mz=/a5~1Vt^7̠{΂MMfynڍ[X6KhU$-B]qC % 6(EDQֿv:"j—J秳&U6, u73x28fITx5ږjα({A$ȩūKM'3 I]1oDa+*E%+%䇡Tjvh&/( –^?? ٮCU>_i_BdуAL%*Ll[ k ]X h=qP2V+D:ÛTH\BftIb,ef>KCڂ`{)D,YǦWMwIHiT)!G }ꨊgPe=SgQ@-"H +dº%vp2@ #_F^AFlؠmbQh=/L~G'CgFϑ|= .fZa_Tp@m~+Q7ZoQWG_ Ł`_pBAH 5oG #*P^+&l.?;_v]}w/xH =ʯ\E7Ln0sùqeGּMB>4Ze{iki_ig3LO` #ri%AUi'] +aB臲qjvEEwWN/ +QIU;S#5g+Ӊ6Sinrj^Ʃ]g]FS$`TzԤyC޾{5 3Ќ?YA(RngG7lGAjul_מ^@ [^&7IPd0[_Y2`Նwk<֕Vž[,c(!|!/nfvƄ0g@ l0!sAœ2)p8kPW4-DthA7fo,'5Iٔ~~QÄf޵UU7ahIk +hS4vC3 +N~kjU=rmvz㠋V Oz(7ceI< -1|Iߠ*HU59t.a]0nn8 ~ٖhKw}{O_ 3R`cg6GyO&Lcd g3<`]L`lg|80EPigF"P{tZWBHSCTm]=6(Z_%{ G﫭vajK2gjv)"͜0uW2}x~W7F!"-y +fճ|L6]-9ل +c8rAl`gnLw51dkƍBECGY/*Í,IDCCBM:HeB+NPfJZ9}!  +?Nc( + @/Efv/ɿo_<Е&<:r/vS\/WRO5`@HkP#Y;)(ßdkk#>yG,H틺W[F R%m5m =$j+ǵ-g8tD`%#50f*B-1"nm`*x *?l%;K-ayx +_\N釰9?A:-oN7"&dVh0hζJ3A.4T:3*z KZ mCŰt. 6h{ wF< jş8nٶFhR^gN UQ˝ptsQUU)M[>vjl';i xSlGU\&KhjrtdU'i|x8~:H>\P؛}7񙗋8{l]J +ٌۚ7hGE$/@A.o$ {zQ>I)X_' af3ow{$sJ3{Mba4msTx#xȶݓ`Jl[>D\٭J9ˌ +⠽y }`KI9@ U\Үu]<'I++ +I/^s5ӛ;WH ݵHjnsԠB(S]lVug +z{[W(yKX(B*R`5Q(jGhw]UbD B %>5*[mOt)٥ 3aj8OȨ\´m`SSG%beO>\GPDrΥjjirE|j>M6N,^g BMnZ)ODpd +uj=㔷kR}z "!*j82WY w|l VКh[^&¤3`>_ػ/e)c/ƝI0 |AB6W7مs< v4$ 4׷uim/f N1"C3/@T"_`c +DX|M4H\Ͻ}\(  "4:E.'ٷ9o y\g\H)8 kC\@do +^C n-O hBBN+*65:-27g Crֆ8/ř=j kY;.xEG1(j¬q_tyL{ JV/:<d GGkb!Gwd& }G<t KG\_!sqVMk|o~՛㈃ةn4v+g1A^8X')l/]`03 O+Tpj5zX8ۯ[xOgv}4O v3M奵hT_#O U,!Qzn*[)G촙C}xQ&&ӗ;F¨AI6&+ӭB /(6 Ad\krN()m vן.fcj`"^(Bh$ ݐ?UvJ5*MY;h΁¿b(!DGI/㋺$'e%_\凇w>m^=#Dʿ,{YlǛe/,quY>#D¬[Y{- F`2X7=Z"̶.uv&sѰhmͼ1;\Ą.F?Աm:K"]#/pu L:& NIƉlt~%]yq=Ӽl2R Ю34 mxaQl2,wHjf9 xn !P͛Ip\V.I;GI0~2 j.|H; E@(2!"^N@"m]bL_X7J7\.wLPϤ'g.<9 Ձ9!hSpv lYcIv+ώ /:_I $eٽO;Ӊpyl\1~Sڪѫ4]b 7v.`j|oLO%HrBJ +&,EP 2` AgAHY-c#ԡ2L>3(D1|`"ؙr;YDKAJi5@ڔYr5Q~EW$S:]6_bJp L(aV,HT{ah&3lZAO@Lm0]`)Pc+աw/rAW9^A1ԍ-hjE:N&sQMy^F_znXElS29!B˄Ǵ qG͡ +*=FNW{b.ENo{@*f "˳hePգ_/j]fbm: H2ajyAJTmPCPtl"sWBW1AgvЩPy$D5J hYXF[Kܯg9_?X8wmDP+Q[0-JR`RslUPC#F}-F *bZF )(`VU& $@czJkR+S"c %OBS 'h!DaX.sD"Od1$" g}c3RcD?ps։^5 +x!UG EŷwdN] B>#9uTd\HK/hLY-WFq;;FUSsNR=C$kDYim2x^)eǯ T^_106< 8?e_aYEȄ~f]6SC8ʣi.q\/ +.Q,޳b;~Ɨ\Ke.waDe Ȫ_$%*b\*b P愇0KQ +/KT2 ] n~X +Ü6樔@o;!@Qi+#O@p4Rgl|])km W`:56yUv+ڹܻ|tgmCMқ/yf!UHpĺzNI}+;MW}^P/&|ig$ݽ\T\=X86X͍S n~ċ4NɶLmaazH |a+=V]NT 3;%9]aQo9 ~@3 A(h_TГ:Mh\߅OX!o4B 1moArRܸi&^B}Wj, 4,vYD[c{zdN MU Ҵ)!"BPQllD9 4PRqgvg-_eE]̙9i0%vSBy8y:& TڡjٲAǛE5~fF\dD##CTkdEB{ w5D3n3[hkgqPEr/&Ì-C爕N w|>}贚>f[F#`3/٬ qS]7 >R3t%@J ,6a>`qig^*_4nD3rn ٰsBwH?rEk4B"+sHNLo` 罈ץ5}\S AWB%c)S 464Db^"7WXT<|9%̡ߋ.~SѲ4F\m+4,bA5/ (w-67tƇ2>Ck\pe(>FOO2+ +nhIލ@[k<%ƥp?m1;l<2ۧ#ɅOZćGC;)_qUUIdƍy*X.wͬ^`N*9'. ʜǴE _XSZ1"~mKݛr b +ڹ`>ޱh0 _=}3g, n#Gth +cPfSG?=Kg #śdy\&R»6 ﹞4oA`I?&PhS-?/xϳ|UɝuF"uÉdq Zt=DQQ7t>zK 4H iȁ.]K|G(q +/砈,Q QpwP,=L>lχqen~qb[3œGFD=HdEoy<BCjOޯzǁѬYC%" +T(\,; ϡ"Y$ }cBFkAmO{.PjW,E(]}*Z0ۮڋWTT2vt9h,@UW}9b4EgAul10u:$kLM#I\ՎfDv^pha* < *OW+ps ]E^,b]bfNf`DX.C/>impADmD}3Ү4k\Qb +7%pVz)uXS[kbY諾Z>֞/O& +]j&!>W@u34UuQ[;p("T9eu=߃}@nϷSܿn̄Ԃ~4f>1 ;qw&zo扈-/ʳWٌ ŸfWUyz5ҧZ_6/9mc'ȍ$f\=PVֽ瞟Ѩ~9v$7(?-g'@uiI W7T m|Ӵ:> =y +#;nڳ0g) 3 ;KނG-n93ٿ)3VXιɝ1S wrg[L&d~7p\^2h?BHBQ"H{Oa~HG˾c){JNf:Jè#%u:tq:ԉ C8^" MUrAz\7y.U(LR)] D߽Q1vq1xS:b)Qo迖v1^F8rq_-SJ?\vF8IXm3 ^xb*fcElvbfʤCЕN8>HQ0ķs$(}B=L٢o 8Rh~~'Z^cv4QYx-|ԍa&քˢnno_kmc^$̀~7=6KnH_,hbjn66?- QG +??\ E̹E̹E̹NũP;A'霠N+rn-͹:U@'͹N9C/9B͹B͹B/͹^s^st^s X X jzz~|"0w8û2.p|'4ϒYrb|g8"9N eJ;N | vªGNN{_dC m +Hh뮐!G&VW ͉0}FIe7W,iL7 +i7g;RDy1ˈ\x әs3O:sfDic3dzPqgiRt:sjެ1zؙ=.+FfLddw䙓+CeƎ}D+Ș2lj2s%zzj2T-{92hj|^e.4#0ēSe]ep/TCSL]o"k^nn{X/ĸK"h}5+xjR|3 +e~6_-e};~s6^p4Cx{&`P4c FȌxmCݼK(E(02վ0vcf1`fö́9̯(.3bi"B9sw݀;pVí38n5ڿgufoi`yG#N띣b +GWUDynl05%Qc?bouJu6Y,ieyFTUh}rMN<+3uU8%!!U7jkG}u,z"6 pPW'j)QJ}Eѐ%1G7,0xP ̲kZ0gAu9tmT6q.x̬lHYPQg +$ YBI +:lf714Ul$1ƒ2 + ,{JY{WR5ߐy3{?JJBΈf SO@'RzBU;*YÊͻrs_ +h}z Gi`? @Y)QV:Ĩ&|kQ=TgЋEf^D8 j  GU(PiF!𞣁*z 0$ӛz'*= + MAKpV +EmMا_羂p YG-W~vvJk>6(m oNjl$-bL/o%7rGaOG?ϟg/RiH SRf-# +f/̴+:/fJ5NX$cB!D-!E44|J`t"0;%3>'hy(jzf7RM,TB>Jst]+aJ]x)@T'"b\C2(yVxl{c=N~ @ǹkDuN䢋] +1m8v#tML4/DϔaNZy͂YR6_$ +^pDlOeB3I4Mt\H.,ud ږps 5gך c[bh@;3(0,QOh¡LI" ڬ6sQ!b_۵0nI6X:~PFW5-4k9n y)|Dv1& E9P@j DRQVS=H\z[v`+6y)!fb?tM=*ѩ@BBlߐ& *]{܌SԼYDhT ~(ԣ$iMO ya܁5*w\]&]N^=>\:v?fl:1e7ҨRD/+ J'9bqSډ\0؊lw23bFƋ@g64맰ö\H9[Qa_\$6PC%% I6345$(ĨQȹ},O +5~6EEt>$h:AhR ~FSEG=&e^Stn :Q5GqGJj͞rSO;EM +y4(H(@ Ǟw_n 1ٝT銆+l.6N.?V )) &3ܒFl}_$4%`5IBPTGH"x|Q ZqW@0&  ! "()^$wEsNJTAL4Ub#ӥ>#'UѪTrp;z틘-NV$Y:YuWwAi؋.[7Mj)`n{Ghro2vS%ᾈ戛qW]文 ƏLK\E6h6_aRY_:$w'v{"CA6Ԇ [ٶt+(Q)[IGI)۝R:f9<,bj~i C[I>o1[:CIiή]["rU͆! )O1 ":j^| qP^줖 j&W ͙4KoL;#{&J@#/ ~ +ROF_GMcJCTC3[/"kqaɳE79&Yf" sJ,B8i:/A(0AQ&^ד`Vڲ +9C$C/—kޑ^J_bVzH1 z &w>r!Y ҂l*.n3>M2N[E O.إ*B#JሠJv< lG|_T;@dDԯeSH̆:p."cS(a_[/S^U\0Q&\ƹܤ>gϝc)@-?Y "R|JCE_"Gԕ̀N+Cb-Y̒5bꈀSp]ϊ]u!$ G(+YzLItZi)|_ +y%X\v +{QWMJ\ kWXp{sֳŬ\bnwgUjߟ}|$|j0# Zw=H ;)|}@q,n]EX߈ʵv5m_oրk>a,ME.ǑmzeОdctiN94MXbofH OؾβϣQr—肝MyNhAi gH@R8PhqQ1~Ķ`gjxu4l2^  9 =V=3\bNȈ! RFm4Y3v yiPw7\ɤ8Jڻ[lȶJ]Hx?1fEn31v3y"NQ?)gѝ·?":8T{AO۹0 @cV +O*|wx#̽]y,9}hs'sJB~kk;CBp!pa,'P\PXbu0{8NFItfgUNdw,kxFFfNvaSWaqG.$QfyV"0k쪵H9FP_xC&jiw{>E/Zz/Yi¹X`-o҃.#Ah,zHl7KzSjL}I$lȐ|JVmuv8n8׋M =!`}拰ߠ860!K[Nh,~s/Wk\A1f3 + 4~`f"=6rTnˆI=,ۍPurj !|t ! +m`Dwj*5Edaۨs%lfq #Q7 %*a"h#sܬ݈均OˡoIo:K +rjĿio^Q*ҫEYnؘ2k]ad $EB?JAYR+9X!9+q (tQߥ#d+~J1\L*Xn4K.bciV8˙5(Jpj%*AuX^I=8-F}a犂y%"ZIf\)Ya e0gg!Z`P !VoaMo@2*8~W K`GXj'"7W';pØ`H]qLY`*`PuQ4o +]{)E@y>bp,uHp2C* c=weiF/ZZfrYt~~Zڅ.}{cmkw L&_/Nn6_1-gmj_M;#{Ά;"V0"|X}j8έ:+O܉s" y8< EY+6i9NEp̯-0jud>~^h3vh}`q.w:+I +slga-ͿlkE1mECHVT!W`\cekBM}NV_$+ъVVH/X`_X/'+PٗaUrV"4 kAɁ}Mj,wojh9ܻ+9Zt}с]̺:F-v@ւc09 Wvs +qh7J2Kne_v,Pa\MkFeڷ8kAyG}9Yz5kEICB3RZM (A8F b1O2z,t-+{kHǿv#DkH[;l\m8E8<^֔xI7Wu綍kڤxm~~zе%imU_[\`^ۇ Sz=kUСd#yi;Ĝ_e~qF`x6-r6KŴ ,RI(~T _x?| _3eөf{ca-翚Qo-KŲS䉛+>/%n>*NH;<+VϗQAP+8Гm6cf(g Q' z/Ū^7`ɾ€wBSٍ )݄Ъd+}"\-Q֋X?ty|C.lv+@S[//QW\~o>7)h9oI|%k/;P4i[9PCaD5Dqn>3E6f/ߟD@T,(:ꌢ$ CP v΄3.db4(33t %ԤR੢v+wRm~*CWʋJ{aWHsKez B-\x@j>{N}6 RI@A-0 m/+oAca/jXA:!5D!җtpHZ֖&G(H@eaf^Ah\r"i>dD{V[rŮF{뉒3h$[ڭ2Anv%[WF@jJ;-*cN"b` +EGt |ܫQjՑ5RX(/OI1*TnQ=5q!yͣEOaܿ7wD;Nx#а(8ዩ"{srdMtHKlzŮ_Ow/ə&E\NjB̫PMjECM`D*T,o]Btnj X=2#j[ݐ=BxT7b/0 -9*/ +r +`{GD2Z ![>o?_ooӟo?juJ@iX{]< +rPϬP 28 aK DjAig<(ro͵VЭnf$9bը1]y)v RxmǑ= +3ϗFɿ+>~|!tI_Oxou? ~yA}b6G}M}66by33'kp? >;^S$K&?H~A? k _}[c {̺NƙJ@ +4Kk iBW!H6<5lV~iIÉJOzqjq/K?#exDz=t>XIuK ]&YPRPho)aGD/zD@v~8V>Hm-^k;v.Cú6VpPط. Ccح65+APE Vrݮ-)ӓgY{Cᜐx=y>4 2n<,Ռ#ŜaL129Xh]ʨ-*j[aw7ìOPtoxR,b ='dLqAH{# eTM\"VN~$WŴ>"_6ǼEƱ|#^I\UO5`t;+$эx:O\H3كjXiآ* Aqr-Yٶg Huк,.籡WC~ĹWKEZs2#0e.L,Zr uPH!ھ]и)]-Jfo8yš>< :!SL@/`kB̙XBpBƯ>Z+vR7i-_H4IJE@N8xVF;~ +4%- ®syWH(\{9[Fd$xއdqw[ `?NCmY(3 -=ll"i-eRy=vU {\1pf_G:D,PKR灚ΝZ@8$"3;o],RA {nOM];fh4Z +-keA$\-y.,9ALU Fفd+i \,W!KNKlAl$P3L_":^~}eG^:XQ-y|'k^ zO.❁BOF&V=\.Vh67{zZ.TE3`brKw&Gn^r72R> n H7= .j-cҖ$ +h6Hqq!8-qq/60 b;t+&T6bs&1v43d͘35hf܉A5+ L>0V Qn%DsEuoAӜ֊U.c1ǜ1)71QZ@/*#夈!t^([Y$6ܬ~[7ԕm m U)h e{fGLW!DA4k6BJ jVoxRio#} ӀӞgB<|~il +,zh oÈ /xe9;np/x|*iʲ,w~xؘX&)ڏP6ȓڼ XRcD=Tl;d+ #o= Lh."W@)BZD+ G6\i'pYx`CN̩ՏDX'%jBU-0d7?֕/wƀ6)'K&'Cb~mS_[ WY x! &ܦ`\ڷyNLV[ +#)ATHH6 _6XWx1) ԁlI֫$Eݺyg"Д۩5] 2|רH3bq&P"(M$gH1x> ;v4A>Nk:5噈kϽ`7X }VmRaG7YPG1Nq c?Nn֣ŕ<|2Jɚb{D jV1ZQED3^RwMH  1VĈ2\dfGyOlJ=hRPfy*Ã+c f)HD#{((N@^TK@G4LWPr]{A2)YTFptcaT%y&{DI +U3xې߃@M\>stream +&rnrCu~[w4a[}a?ߠ/[_$[7՟;-2>?yY޽3>tO; oʸ%*ܥ~[?zgM;6W7?}o8n%۪;[߿~A@=Q_}=mFiyl7|g]~'a|TxgG|?yYwkwKonqs?75Mϛv=||N.}QϾ[_ 6;cKܾMM.3/޹D{-,y޵<ī@EsϽ9zǛi(i}g:11jġ#G'&NH& =018]]{~t\(΢"ו7z WNu/I8_ ;;}D='.SpO8NwO]wr\}IpAek|snf=UO(G\YI{u[Bvfg~X_ݙ{=M'` =|95|r䋩j}o[~O(\<#=5S,rkN~#}w> fMzf}wF|; +#&z9߽=a7*}}qҬW)]^:!eQzY/nR4Ͻ(Ί^|'ʾPs9dYObn}a^uc ?'u^攜Ts߄v]Y=ϫٲ-RWC{ِ_փ&'^D‡bqY^({EhhW#A(rI@^ kŬeb+9=-ۺ5JxU}s5ޡ:`zfєV7^e1zcBe69wu +_W˃s$wY {zX[~[g/)74e+˱Ng}/*rGP7kݘDFZ^sũ%៧Z佰8+抿b\~{E  ㉺3,Vzkմ3*ΊX<_)PjuI_ +YAV/"^"Rׇu!?!Q͘DY1W]fr7U(:Ued$2Q9^7иuߺ&|}$PhUBFQ_P-#M_yg|ٗ}\W-y:|$r*l}a/T޷>N=SqNI'l7n4dtçS/^̼"df勩ݼtX!eU^cg'x۷yW/M޿}yY:>|΃GS/_{ ),߽~9+ǻT%}6b3o_߿yx|{ >?yˇ}Ow~y;3d|34ϳ~x2J\w]wYp>n>UD3} } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }}&+{{ɲ.jͿWe|u|ʝ^~~M޿{rу;Ww5Y|^yY9o߾yų/vw>s}F2N_yө/gf^B23Ӈn^:},YT(w#.ܸ;1JO={:9qƅSGIKBnyў.]r),W\t`}q7TV86;|ᑑ >sֆhU0O2!u ͙>)4ǻ9?Pӑ>yk8oڕJg:BՙIv5ţ᭛Yݕ%7xƆd|{ԭ +mX]( *7$:Օ`Y N]hilS|$D +*<,P:N)tCTZl$K P*eoS_*Uj%G_V*d|ih? O9l8phO͹P/ROsP.ZT{Lsl;::x3v-l [cF_^Jk߇RΎ鎎6IuOlW*ѱ;Ѳ#66kHN[[R{2mlvd?::VT(P3b'?^b>h_]]ҹޡTrсb |ޑ?K`Zc>{=3& }{foO!ãC_|>ysk-ETvTzNѱ[?V~)__LcH3m#ߞ)Ց޳-ʴv.r2=)#nmmOe2e7uڑt;?-Ko}ξ-|h܂M =q7~T˪~*r[]0ff? +sZCO#ڰz K;Вǟ8;? ߯\sPgѿ?]_{Yl`6?3333<ʸ54<Kwtv½E/e}{Ovծ~~9ȝA! ;)ӧz>P}Lmi=:wδg2Lg kS{O~CmOX:'1OjNdv9M:\' !h!dNcP){K}QQ(-c5N6d$PQ\X/A1Q)7~$"~'k~igY˒`^*kDnRpғCr,Vz牏aGV9d\\^jϟ,@-#y{ k]x>JG`m1kS*ΊX*+ <лUSy&QGO=-iG6T/g[wYmݚV_'n +/vП^-#V7^m|7CUd7`y_Os6"HE&A<}/{D֐&Y>^e/'BwKr_HZ`ef=UW#9vY=~{q{⼓,Ks*k~XK滟s3zBF8|O*߫sw3;;i,^?[q{$_ȩ#_L}/^V{f|Gqb3XsM8{m{I0k3{-3`w/绷Q`7} ~$VNם{ݕfݿ"'_Lub' A-dvZ{κvyEqVUz{8酵NV% zs uedׄ)>_r,bB|/FC;Q'Wt@LrZX+f}.gwWU>s_X\龸hQ֭hU« }$1Wvo|(3<ն1zX,.*+əSZD#ك>{N o)s_X\-v>{}Q8ŀ_%z5Bx(N=-  &ne|$"Ί2)ZEF w/O$#X?񚰸)Ƶd--7+%/GԮ"2z$j7mʛ8+˾ʧ/doIS 7PTlg }1-穧y9֞Y%24V4e_TOeRO4ZĠ݄Bf#@Ve,£ +[UUeIii .@ii*uNRflS|$D +*<, nSg,v܈GVTWeB΍CUnt{vLsC]8TVZ=6;|ᑑ >sֆhU0~CIYȍ7;3x¥W^#˗.99ʲo(Tm9{H +؝7o\xp)Z4gz'/p'H!p[?\<`@O9O'=~B +G'~u|T)t#.ܸ;1JO={:9qƅSGI7[" c/ݼԋ33H!yb{7/>il٨'xէ=xg/^~;r޾}Ջgo_lr}>_B +w_N=zp.glM{:6̛~ of?:ަ>CkcOgz߃Ç_L? 'L>D|5dkg}[ϟsQ}LBfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfCfr>W-}]ϑkcOgO +-,ϙ'cFEyul7@ +˯<<>vU%ƮWwcHϢ@L9u݉ɧϦOOOLV|ɉ7.:NlN=Sq'`]O ^{OB2>~8xb >7UF2{^~;cc?B26v/9iVnYRr pHaz {klŁ`Uu=N%dddx6Dz ,kh?xX/H9}憺pԟ[xӮT:ٵL:) oꮄ/ٸ9TFǓ M466$ۣnUhƒ@Y0TY&ש yuBKe[$!RXTYMe9uJ@`#Y]R)xÜ:JUR+)<0U2JV%$LCÿ \o(xϡ`ÁC{zozzGuZvcgbdс_C_Զ{o`K@(m(;0xTjտNWZ>ܕJuvnOwtI2{bRmmL˞t:'66kHN[[R{2mlvd2ݝt*ݾ3onAO ;c!vom!s_-~;%/JUס/*wǿsPߙѿ +533_orwg8<:?i7fܒ[t޾oJe޳gwGk{ǞT:ě?Vu~1__NcH3m#ߞ)Ց޳-ʴv.8r2=nkh#-̾c֎t#-"3-Ko}ξ-|h܂M =qw~T˪~*r[]0jf? +s#[COڰz ?t.z%ُ??p(vs1_50gc Ξ[}l~g|g|g|g|_*#P, u=ջZsO'\ w&!lv0lSw_wc줜^WLJ%@"vkkF~4Rmi5>nSy&ّnwM^5}CmOX:'!1OjNbirt(OB>ѬBȜ`7!6Ǡ;S#şXQQ4ZyMkϬȢ24m]L8ۺ5 lIz^<OQ7PTlg S>"e +6IDvx" M'뇯(Vbx*bn]^]]Y(${]{U;N&#IEe(Vbh\*Ίo]a]Yuf}jXm$9H8^bSn*CHDLObqҾ%6T!׺ݤ95'p(Yj`G'irV-ɸ?YZG"֦}ٿ?"%IcJ%Us_x)1&TVndywxMD3zX[f&Mm_;6}g-ۺ5wOz=d-^V=?ZGnL^%o܇d1#.ڝ=Ouodѿ&U}mDe1zYmxM8;Z9x(^@u!MԳ|?ӽ+^N,*r]ypĿ:QW ّ$.{Gs2 z~); wy'wY՗Tw?fSq坅TW/dgvwşߝY~pHܿS;Q9;'G^-^&߽Q]ϳ]=S]?"gq>ڜy`DgZ|g^wo:o(v>H;'+ͺEOb<}O(߫Z;|u2F;i+E܋⬘]p k͝ 53XKﻙ4,ʈ%\7 S|¿^.y`NYOY1WMh|U󼚚-"qe1 5`=oE)|X,腲^vx;NL"7V]|,抿b}qߣѢ[ѪW<7^IczVQ>gv}Mymuc*X\=&TVn3}Qy<=Gr巅}rSJS抿b[}"qd/u#֍KjTQ;GOQzX[yᬕJ b+/WTp+oO {=^?R kŬwQMq=⬘+ųϛ? >Ve停j!%"q}X2uM܌HDse&yS|]QQ~jaQu_YIF"~(5aqS k[Z+ZnrWKu;^|V]E*dH=X/| =R!n7qV͗}))_}O_ޒ'@R? 'n*&B}cZ|SOߩr49=J<ehh+ʾ ˤ if3{A !;zGɳ.6Y,)!GXʒ@`#Y]U:@٦`yIUVyypSY@*0@Y0TY&ש yJ7xƆd|{ԭ +m[J]tk/)4]tjWS<޺9P본,kh?xX/H9}憺p8{ XmhwDϩӃ##gI!<}} Ѫ` +owgK\F ++/]8?st_s eP2ڔ9s7o;o޸~lLSrSi`]O ^{OB2>~8xblŁr':s&N>zǏ&NtS(&GN]qwb鳩?"-=ztr n D2N_yө/gf^B23Ӈn^:},ٲQOO{^zwd}&߾<,Q}vr߽^zΕ]ϒ>~1rul7@ +˯<<>vu䋽My}tƟLϼÇ;ɇ~2>vMk?N<~%}jď.;,8~yB?*>>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>͆>f>sQ}N[,8~yt#ƟLHZX>H3OǮs3o_߿yx|sK^]LJyhw!/=sexWlŪ˷O>{oߑׯ^<`w8g!s>zrf)$33/_L=}x2 lEŁr7>rOM=iԳwo\8u$tE>x`~x8RX?|8ӭ{N í? d|{wopq]۫}n6exw~$dl7_hC'zN9K +S='kmV.RiY(\Мȱ_Bsؑ3 uPY?)]tk/)4]tjWS<޺9] _qsʍn'HillHƷGݪ%9u`q#YM"S] +ԅ6˷HB˃sB7KFRf9uRVRxTaei"K6I'SPC+ݽߜ "/4=/ ~RNǚ{>7V_ ɋǿ=ؿmB؁PP5v`DժUf_;}(+ݞhdZv {vvZ:;3{ҝAY[Gjw=ڒؓi[d#Kl֞ޑNuvv9fa[-{sC_b:4p_sC__׽#]];?7aƚ8<|&6@]]zf3Mn?@BGG^}:-[r?on77]]mݙ|;3t[osW_[Vt;'1i"ϴ>ӏ|{TGzL*Һԧ?$cDЎ{RLfg=ڽt#&iY[s_~Fb͇-3mohJ?|!GD"CƱo#}`:758P p0đ n-9F~Cߞ195xo=u7e#=C;C;C;C{C{ [CCtGg?.[]Vdj}@>3PO |}rR_1}5طhVzp-tvckS}G6'LMtSާ|5 KQ'G]YG5%'I !B9}2'M1NH罥(VTy๮3G3D? i[W*⬘[WWWW +dWj^Վ ǼHuRC(>׶b[Wzf|V]-d'VIxN2N((.⠘|Pq?g?ӓX\CeIM/vnFfv7)xN}M8!\9JZX+fǰI#xZU|}2../5Or񑈼=慵rFF#w `RRlg\W,^f_ Yݪ<^ħ֖YrSmMY-,nMD?/]i^v~OvD7Y kUO;zymSW6r!Y 숪zrqvgS~<| U_bqY^wu~["^NzV>=P"]k|,t/ⲗ~;\W%\9NFտ~v$~}-2K+LB_p +?N}=8=uq]p%5?%ϹT=!uqyga'չoy ٙ`}wg4}-=/Npɑ/oiWIo3wo>Eԣ8s}Wj|WvO9&zi6{޽?|$5Qw{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{w{0[(|>}J_/:w1zEꄠN2CG=_gݿLzJ<8+*W{=Zs'+B ֒nf= 2bx ׍y2Dky w;;SrSqVew1gύDzz+_>UxsO]GSj[ݘzJ,e| Lq)q^-"zϑeA`mma@ԆҔX,.;yqYb@݈ucUj!{Sz֖k8k⬘+rK28$\w^'Z1r<}Tz\b8+抿bb~BϪ%}+dy gZ`{Hu\օLDG7c2>g\w}_WTT"Z;GT]}wDxMXCmz늖}w@ݎߣUjW +=G}A _CtTb6}Mse_ysyG_Cx ȉbx*ɾPywMkϬOE+o/|~v2)D'|Y^bnB!NBV duYbI )rOM=iԳwo\8u$t}n(޸%Ґ9v{Nx93/>wcȖzW}z݃oߟ|7o߾#+7_x6yF/g;M|/ԣw R}ٴc㏟ϼyRX~}f#_m366dz/>=I>|k>^q+s?MWO&~vv>g˻>Wi,i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6i6+9Msz>gۥ66dzFA~2>vmdn[tW?ycWu[l:>|΃GS/_{ ),߽~9+ǻg,V}vv^}ًW߼}o߼~ۗ;UŹ># c/ݼԋ33H!yb{7/>id,*Snܝ|ldHKϧ={©#[(.S{_GÉn]?s0wr}n( Voߵnݽw)$߻{뇋'^,ݐsSe)s7n޾36#)$ccwn߼qٞÙh\%e!7޼h ._zW._p~*+YVEZ>sYRHFFO9qx_kC*wJBẆGuǎܟin JH ؼ57J3]{I̤ŚJCUnt{44Pߟz' +68G^\h(y? |yn`xwXzew={&qLj`H^{sC_j:4p_sC__׽#]];?ܷaƚ8<|&6@]]zf3Mn?@BGG^}:-[r?qn77]]6exܪж/{ۡ> I}LU}~s=:{vweRζ֥>!GN}t=)qc7gM{vv36OKo@߹oi5:`CCzǷ}C+|ǿ#ղ{zG{Y2DSh6,h^tņE]zhɁhop̟W X}9p߿p=V,68W154<KwtvE/e{Ov~~9ȝI$! ;)ӧzɯ>P#~Lmi5>nKe2LgG=߱6y=utjniH>i=ʗҠu%[;rt(OB!dWq !s݄O[ꋊbEEh ;s49=JИuU3]v8Nnh4TS%yH>GRCSU/Lmꊔ+*do'UlT$\7!t8X)n*Ίu(/{uugAvvU:p̫T'X?X)nqm8+抿u^gvyg2zȚAqb$#Bz!GO #q3=YK>;_Ra^&jdfwׄ•db;O| k?Y'RS|.gjc^X*kQjd8Rkx&Y+VqVexŘPYM_ޭ5ψ:O|`mO(>*7Va8زnDJNc2ߕ>eoGtVxY̮jIѶ1zXo/绾q'w'kw<׽{ȓ=GzWW,e}WE*5섮 jx%7QI^OX,.{9ʾu^•dD].gG+3喙bQ$7SSeW_{PYZ2YO2_w{R^wٙ~w^Og }+#q"@ND b{xEߛ6s|SD=3w?ϮwHOowAoHkswOYYk||||||||||||||||||||||||||||||||||||||{9߽ŎH^w|Ox Jw|k4@>b|W=|Nj$;tԪws/bw5+I/5w/\ `-Y(fӰ[_+#pݘ'CD&O zp1+9%g=g\7]v}VyjjlTĕjP^_6$>`ѶaX\ʞ{Q4U:1rP`;oZ1{v?;;+rN}FnMD^UF_xM$w{X7G}4婶Ս׫bqY^PYMG ]֖ tMm+M+rlY닊Ǒe,ԍZ7.ѫQE=ūGq`mI龆V+y/,ΊX,./뻿^Q!Cuw=/xya>K-)G5.b+.>o,Z]җBrF T!`]HOD}4q3/#qVMuEE-2JNwDE~g~z'LTׄM14mݦ'kh=w_yG/ x=Zv#!`5TKH)nWY17_||>wU>}a?${KzI)b8[_ i=O=}8:(T(g'|J,Bd/P|Bȧj@%&B4!d@Ve,£ +[UUeIii .@ii*uNRflS|$D +*<, nSg,v܈GVTWeB΍CUnt{vLsC]8TVZ=6;|ᑑ >sֆhU0~CIYȍ7;3x¥W^#˗.99ʲo(Tm9{H +؝7o\xp)Z4gz'/p'H!p[?\<`@O9O'=~B +G'~u|T)t#.ܸ;1JO={:9qƅSGI7[" c/ݼԋ33H!yb{7/>il٨'xէ=xg/^~;r޾}Ջgo_lr}>_B +w_N=zp.glM{:6̛~ ow,Ma䄕EhM6Q +fSVBЬ^ +H3%@ El Í$@$h]wv,+=¼<_{wv윿ѷk? ~>o_}u$o_/d~<~oZs?V/;?On?t~On?t~On?t~On?t~On?t~On?t~On?t~On?t~On?t~j~2|Vߗz7\Ӽoni݇7{=>zņEDz٧U # 64Yzk~ݨni*74UzzoGGGoz~Z{?bK{??~(K\5>MNO?'ߜ?yß~O?}s[_W|͋W篿yw?8yΌT'_|_^L?O^<7f݇|֩%)SrdNNI18cNJ2Gm + dg 2gPB)[7#HVO'ow~_]78y |pg\|{7痟g_| |_.{/x.aϽzdyox9/SW//^79͏zDΟ޳sjU ƆϹƏ'_ynݗgױ®5SLO6ŠwfS6_\G>ǒU.NIA7~ /'/T$_x~vt&;J)?^Ɨ_[qlo<I8 57L( }駯_<ͫ +|+~+^o~ᮞݽ7q7/z x/'Fym7m"'T +1G}ڕ[9 |#o<9&kB*,P֫uL`Rl^";k<^cqFV9f|z(hCYn!HjR$+EJ2芛2:*oM֧dP֞BYV5>Ԛ!^dik* B!'uP(Ĭ8 kv +kU.&kv*̤L 4 8&5l6hc Y@gI?*){g\"M`@qJgtN+`]B!ڜ-\DĮHV;?8`w:Dc.ћ[ s\u\o''"Bh}m#Cuz _槿u&lu RHiPӠ32lsS0~L`w:..akpk)*0sU=dWάN㋵%3U.vZH=DSյU#C ?Zص> RW4D+ήLJiy}ub8zL'wq{Ni5z ~ۗwd9[]a.˫lܳ'o${ysϩ[&ymR~N[ nvi[\]=G@oa|{jѫlh pYZPk:N^:D H֡CDWv6ڠvXȇfycǂw83!J&Y k\1LQu +{] '/L$rŻ"3t"4hu;M;h|ԥu-;p+ z'cٙHPbA'u]ucu.=U۔I5@Ĝ۵) <'Qxz(naxQ"B첪:oydqyE +dg 2Ob-yA{WjlkE:AEJGX*X +맦`X+zWiVŜ}:;oK%3ifJPc0 +dcN@ہ-/*)CnnڶBwͭsۧ|XV4+wLMС]v}2Y=h u/&ͪuݫ14b"7D'B#:( lrnո2&k$ߎH& -~x@M[loVyL{l5D˧ݾ|myazU7[;H))9e3d˕V%j20DznЎ뵢Ďsd8䐅s&U6 ab 93\jg?u&F92r >:pW ~p^?pB%7 ho;':cnv0H&bOw eZ@+fVhs6/nT+,Žʵ1A8 etO&FVyCOotf]uzݪV;-.^ߘۆ0o&F(mvrX;Jhlof͋;/Wk^oΤ:n{>u3JotU_~H*8&D6;M1GD-'k3:v98<;yr"Y=& wO|eklBE ̦?:2IyɄȃJjYmqǣbBr%m Zou,ږ3^RʸYN½^ېw7N` />y <һRFW "}(u.擗3LآybäIei޷lmJ*L`*6@YBt [)sEk3 +"!'cޏ/T3~gjvt''J#Ќ7q~~sgˋN̓~Iu 9z|?2E};|/9gf6P?NW7wο?[_>_Y4 A1:%?J<X-|g/[ǯ󋑰{an'kr2~Rot s.ߖM7y87]4kp1r _1M-͓SQAx[[Co(:Yj3Ɖk;jЉd M(@ +ik{\ Ab!$7 `fe`<>5~,)ocW-Y8k<+1y&Q3ccn%FUxcхeMv&\D07ͮ׃N$ШmM$U)dM ϲ '#6M2{`?J2S32 +GXXX"{_2 31y`?ηC E2LEy,ٌ b + qVj44Ì`*,<  {6(%LHtY̎, 7~uT)`"&>caD}1x泺"]YbJY]W;o6o%۪G@WE@,kJ^l5:^ Lc^Mnd30#pXr]rh'τ3n蔷>9C^ TӶ=F@='Jm +U˜]i:ZEí$hnkiW^kP@MqD&ʬHvaVN$=xh}E\Nc8 'AXs1dBiDR,e"#]+_ŻkWO70٘3,GfUϋ4.-,YfT·I;9i[ +9aLrX#yΨQ # c#$%d& IzyfE)f!Z@3¬%W7+S;1ޏe8"h6gŢPFkD +o@5i+" B&u0h`ևS4 u=hEE堹=l:+aX5./{X 37&ݺW|m6Pt]O?1Aw4ڙ3^ps֡0G ^ + + ,+-%aL~~l/|sO=zsNZ [%(^\+)}KNs(RPv9W&mV^fYaFvqɕP̺)[ +@+H8i_v-v@ܤcpbyp U6 mڵVlC5Jzp:D"aB%Tr` 3ֱ9Yr 8;[7+B&)b1,,̞¾S0^Ӿ&+Y#,Ӝ=R& Et:E =YZ=Kݕ% s;S=8+jUX $7a( +^J6NaM+/5 '`l6`O{d.{ ҙ[yc`IƚYv+=4Xv.)hE Fl$ޘIlC`"[_ޑ'CmųlσG4`"o ̐jr.c?[Aܘ CϠ%a٤gk +žTEB+Yx9io*F[|$p a'f֊`S4]RPau-Jds1ڔ{-pwxH :&VV!3 (WwGV䁺:*8$: 0bK'.3yO&-wٔPaA\- ] &$&03˳SI%PnI@saE859b d#Of?gbg6*QL6***2)+ guK呟v[q%Cw+?%h/HgWe,ӦĆ-+2*Q`mQ |]rw&ٽ{6xP^bGijpCLX(3mxTdx@AW +30& {x<o"T0B)Ao +#֫V=ԫT-A`6N"3w?MI0H˥X aڙ&Z Ra;߳k*7 o|Yx8^ZtY5Gԗ&0ggGHB*B)-J?ٙJ<ݰ7'I=`Jr VirzmzCڻѶN&@DՑ##Aڍv=O󄒁 +qx&OSx0]dZ+=b/VvMϙUcVXg + k6?K`7?aV,8fc7g 5#IDnPEط۳civz̳{Kbh!׼v| KU^XF4!C dSf8̓H=L 3 @ǰdcT_dG{u[:Cth6CUS.u1b/ 2w@q6Xsr=D2iKǞ'ī_}qAJ̔ 1ў?mFb8dBy~lmkOMemWKQW}[#S2 MlC'Caa$.&ּAAU@n#;dgeb#ה6'Yiϝ+XL&Ӻ(V%y9qiЉd cq:nrMc.02UyɄ{0Pٺ7$,Jm)L>C9)&Qx+66"uε7<=ojiTp88V080hKYSXxafF3eż(d e\ٝ ɄA7 CH߄Y/x LV;MM+dIuD2,b216_a~_z򛟐fN>^^zW?/sErYw'bqZ72=Ÿ[~ӹ"dza]S LYI%)B-1 'Q}ᳯ~ ( +YI,Ch0y&rsLrFŎ,P Bq@=<(1ZD̂dUEVL=zWgGrWzr ~k +v:G/V~PM=8ޥ +ݿ#c'Nm̝`%'$3c'enXپ}l<sػ;بK|L._"ʗMʳ\޸@c6%gX]_[S`gWywO.ڙ_ ҕz G_ܼ K? +R.ZSl'Z +V?n53)d16٪ABفB)! 5`{Zw _BBE.BV7$IP F mL-M33k M?f]lO^lO>K'c'E'[UIwO4s+mt,)1S &ABمB)VAxMXByX +/QdC+-Jars1`ڔB+U|T6١ c(OVy6duWWdN:.77qx:r @͓͋ `$[9h7wq@lY:ZVչ#7|_F6uKV'mF,39x"]6?רɌo`F8\s5x,/j`vF1:P؛ l0AVnȼ+K/T] l.VC% J%fbΎ_E TP}ؕ,)< ,QF 'ǔc[Ia ~ߐ>!s>$;/ XcqKxI *]I0RaNe'5&se,r`hr0*xVXs3ÇXvRz9[ZKs˗r487{3~!u@4\^-\Y *zYb~ۧVtLeu &[EFv6%a`24qF5JUueY;/1scjrWuܵj琛T;6Јk燯yc&{vD,UJ.M [۴pC^{vEPJƷM*f-KWh$\ڹ&xvX je6s6ˆ'rWuM h禦}ڹS93 oKWYt;ͺYx(rK7KdcsQs-ݬsRR/!ߢ7ܬ*hK71x5,f56d2%A7dn*WM֔5 DݼЦnF1WhCP7<:<\)(>~Hʹ9L|3s6DY,kVyOVf Nm\ +QNC;16KTάi/ҼEZ9 dr:w)Ⱥbts_jݼrOu|Qr n>2yҰY͏@73V11"I~WkVT[$Xβ&ue*:cdڪcE|LADC5ϲ@S8 ,-Ɔ,5sMU)zֵj enzlx# +ۥ-UT6!TsށxdD|UiU{4V*=fӪ'n rP'VMo۲YKzxt2 ٗVe(LV<`{P/,dÄፚyǾӨ!%L=.q{ֱreBSā0_P10m<̄Ȃא]`9ғFw.d4'G?kO U=.0;oa; 54XV[2^itbԻlVIۼJ`}3<}ʀK[ا &)Ѡ])PSyv!.PUza}S헛$@ٺ(v(Q]E vڧ@Ў ~I6KP %SRKlh l. #!pµObR +i]e.ejBt32+<1ϚQ37O#~ad鱺F@"*>ҠA7 2eVŰfɢ*ElP˂Yi H@3 ̋$tsfVN$=0zRk +g , nCO&]$+xKXCZPy g+ &`p@[6^LgLe2-+[,bvV4Mih^˓5|8tYЍ:N,5 y`7-yJNyW&ۦ@Or,Igg<"Z + ȰsSXV;10$"Z+O 8v{O%)̮g}r4R{$΃Ye>_IYE(>xWRj.eӥ,+9CgaTt*X.d;Z],]kST3P[&pEPExhfPi4&({_0G$]+M.@QLxB`mS\%6*2r.N{$)}إi}p*W83mJ2`ݸ[ͻTxz*^ۂWʑ +6];kkJ{!XlSu9I9r)T +a歒Vi"gnnʟyC*,6Dr- +U jplV.]([äcc?k޳+`FmS)OCXNfoRn +gߤ4j4ݞm"PQ!E5=OcY3>D8ٚ*fHL 8 +/6i4f}ʓ5X^mă-FR +LSA Ol\Mj<*y眎{P(zhZ7n + +`9` ύtrK<;Ah6n %OPǓ#&cZěRӭmx,P*w'OliSbR)'[NL1ؔ'{irSteWLSFvyڣShJ=0WO̜TƗgEDyo<}yXJɻ_x惋g^?x>9"^n*Ľw- PcP)Rӟ]\~r|?VJdwS&퍷?ŽN`^{ftxwcgXJOsnqynq7Zia-3v-*-ޮc^ig+#^`sDg:un>hV>!bT[ ¾QWGфXU&Ml.eڪ#qB|<9(ghq: @v u057=V$VX⚋ּD|$NY ;:>\m Ɩ1`o A9c\ͺlS7&#l-0SgTnv{4J;C^iofvAN;eKt蕠W뻆ެyyhZG^q@oסAC3D@oI(>Lc敖䎱vJ-t nv{6 +;C^aoMR%-۽-ggw!hEvػu}+ {q ˂*f"DU=ᄍU䀨ʴAmRJH|ym Bqf}x<ۗ=z޼gނb@"a/ׁ(o*62&m#u:p&ZHu=J雊I[wʹގf߇lUn:ME]ܔq~;s@XFGQ#b/a(o*6JDLGVk~5[emso9Y]]LΫKqlM tKpv6<_JrডÀe!`>LR`:v6y/Ԯ$9OCJpb\ow*Oͪl Ә'TL_SeQzV`::F=b3T 3ٞ+j\:ˈSASؔ Lk K,fݚ\s4X~? $> DT75fy6҇X, e:'jxneӼr +[+=Tlt j}9mj3#편֣ 4Rn2mٛ odVw)|0XIYAf(P9g3kp80]*f9 dS6wlfrO2 7enڒÎ0,1 T"psk?I7C hv~L + y; LStm{_p(#'/.{z;1O%  ௝V@Mp|ThMMV|@7?.u' +#l [x!.ئ5?K?y띟|[G?oGag?5{ 2=~۟w~xټg7'uc|Okl"}O |-}3sD|@l6U!B1e@ɭ)4/7& +Ecӡ)0ya{8 -<[r̨QXgk{>݉OW5_l0֔aM]Lhnh/{%[q~Ȟ >\O}d3~0| MrUN ; ok6CL&3: .:rA'  ѻ^J˄3'CL6qM^D_%*Z`WCީlͤ /|&ivdg"/(C.%0A'I4J 0ܓX.JL(3q qރO!0IvPpb`I +oK-9|ȕz5ՙLET"Ө߁}yR=k㖬[ +Lrťq_) 9i'l VfR/H=ecἜdx+KPmVA4cq&nQd}A- tY1vo;rIN[)㳡f).^̖a`Ϗl3m2-dI ;BXe2mW9Jg@]*lK ^HHϛHR + ޷S1xfEoBG귇i]7Û6Su&O>vG݁=3,L?A' n\dq pXJz̚ 'hsHbLQPlLɄ17fq\_'iLUȰن\L6B 8[0qBIdL9jݜl堷YD3^ҫ4;6υ +O>{yzỨR% U9n`Տf-M0_= e;eY1r3喟tTx67ԑcrM>&JRȦd*y +V[S^J/ +q$;983d$XtjDzX߰SXT09JrQ{p3D=|BU1DB*,Gdg2 KdtUt"0h?a#3L~w6 _UXy0]gr g,,@?c÷~>du8)⟁ !+o\X*";TXb`ԃN$ݕ6]*V hٰVll$~ N$#[؊kVele5MCm}Ex(niޔ61YngBك,]Wps`q'+MG, _qW+3yuX0Όt"0hvYR l4Qon5i]Hɥs֥:.H1R:jZY`JRV&5 j'w=DB3:6vw+|3R=]7m Ҷ^Cl$ :wxto[cF׭% xlٛK`YSCmg|MDIYrN:bֈ1:hgљY#:yJ~QvHՃvx~dWBv<xgGgSdb<8:lgY? MS-PT6(\ٜl^uCN$Ǽ;TO9vtq-鼵7Wy=7%7XKCUvu&w1D_oSdCMs4Vd5v`S x9e~κm +U}5\o^I kJךY:nSCaU[zdg6s*B\q0dw(tqѝAmXæzh +σʣ<8URnɚFƗ42aЎ=fAwhD]j'!Tܖzux(} ཟ=lbk]1Y#6Skܬ4YY/܏-6zYȻic3,WWDIP;%O`UG7l=22uEpa[L1q eY\&Y3TxjneFd])%0,A;-޶3L@1_[3;05`4[s7UL;5^Ucvlwp?и =b=~ei\F2eLw k\ L#{7otG) 1^Y+0%8ܻv.DzЎxxadL4yM {dqGfA[y_ܥhc(!4$M%/|gvC;4x?v*nQid;?x0:̣xmlm:SE&GgZe,Qv2Y=hyxat&Y)A{t32O- :{GEg6yT'!TܖHc 3{YxkV %N7熫 :+g9$witA'ՃO |kwaІY +Fh"5٭2^K AwJ7}Z. ˯b/_M_dOÝZ MaY@&{I8IvvFlO qZ:Tg >(v@I CN$Af^T|2Y= C*AbbdyfcɄݛ'UoT{R;sz:Z}H.5{Pmisǟ|~v͋ק/>wɋ+qnN '_ʓw~?rrv9盡ɓN~`F j(Pw]Z~FfL{m\89QPxY{jUl2f&4k^bO`,W9 4φgŜ} +N"IV!f+cyF5dP)Y˲QҌ|Q!Rمn#h5G Rh=[/_ڧ94)*{s`a(fs#|E0!|Es+^9|^s/9fi /t-6"b9Lʅ 4wO>vZh~Ρ T&.4Jdc %[9Ƚ 4IeφU3q(OQ$!41Io'ĨQºTSZvZGQ:xHr<(x2ykga::?5ׅB^DIjVxX2*t44MG˫ `::3{KһhdQz*ՌVc7oƀ#Zh  4jڸӤG=iJ5")Mz;%FՏ֥ʵ; pMGf\ᱶ? Q1X=t;-GyTwAAa N*r464-GFm,G0f9,>N~en$,I5v@q z2?ưcm{(a6j8-+k#MzؓT(HѤQbS aQ\n4h46?,Rr,iVcCa1-ųDjMZhv$Vh5JOzҌjV#WGl윬.3A9#NһhdQzTzF+Wб+䂭KEp4f 6jFڶҤG=iJ5)!Mz;%FՏ^Oi:vqxжpGH4F$3`#W4R4pt7ld^E6pQK_$,`;d>)y`ISA~`<:Q5)\n<)s Aa#vу0 pFH42$@W`:J:<#Fl DҔƀ&'gr{pٚp"Sݫ=:l#Wx6Z,!((3}ɾ6=i"'!hĘqP@rr1iЪ b *&Ccw1GQ5\n6ގiU9fV9c\A"cQ$PHɉXGÄҔ%1ISv6JU3ʵ; lvk{:Hx ɴ ºډc ^V;Տ]Oi2vqxFcu1ֱlȭdQU +,C# 3"W'˰<4*6ypp3s1AMyoȵj6@Vf4(VPL`9bjd>F./bo;;#i,, 1/ܴ* +dUX?*$59cQ?⌇*:oU/A'i*Ąz#D#Ƶc)K +/'ԲT=HXj>+ۊfcѐutg+=6m"YET ؠj#fR5}'U#ijd5Y]QUA~5IZn- +A[nL}tXr[[ABʠ+V'MJ +dUXaJUYG r*l0?rh\򫲅acQldI5VTLjduůjFUդ +d'Ujcm/]rZl\"RA%Wl3QcO@#TȪ”RIUkFՏ^Oi6vsqukZ6DR_%$ Tc#L=6cT{& }U3կ&UT=bu5U+v@];hs?&\V"W lePɵj+LzƓ$j40ĬvRZQjSZv\CC6;ӕ!^!T L*6U&Po dUqjFUդjc'1Ϊ; D`rjlmuekJP[f£*ORM#a)Uej +%K5kw@}T=d{Rr86?ZcQU֫`cQhldIuVTg dU]jF` US/x.[;/v֢I?&\V jVVPK2䪴m&=jlISiٸ0q9Y儺 Rg4v[qiVL/}9 1VOO_:^|'+v5'/>'~7 t[? +endstream endobj 103 0 obj <>stream +$ 6q_z +w:UryTq?P:- Xqmy v:9xe-Տ]I4WJG qaL!h +ڈB֠GB"+%o޶G@ e4ؽwnm`"Y=$V#]]ɀGS="`ǢtbMHѻ~J/vpymLzo`{+,HJ܋.;r<,M@ 0tcibKL/BM z_)eԟꁦ)Ȩ&6ch#=:]V6MG.(-F%ggxH۴Mxr|lP%JQD1`gݎ#'@/I DR  K^i>ѭO7IÈP;' ؇. 4B=Sm}:QyЍ.%el_^1z 29rÜpXx01\[6 "oTVIBXA$ z$E+A\۶|&"b:vЂ:>q`2/o<'AC4ċ}y>\0=Y k;CGE}PVM!dIuKT|<$^ Ty:*HiUh0,IfWqƫ>|<݀A&B5PH +ك%3MؽkDSdF 4Cbst1r;*Hqz6Th]  +9++C3FRHz}ݢC3+4G@#8T0K4$9+٩O֟jjD.~`ezG(H{Lx)^1]07j-T Ik6 .Z>7!K]Sg॥Ga43 )|Gڵ䶲ar$В90A8$="$purVH\;4?|"A+nX#~^-U$ˍC^gr)L5iW \ICԙ6wUn`(98)+:Gt$֒fV<QUAtY}9= !nّg1I.;Ls(\Ò~'pnY]_9b~lI(eV*NA 8| /BSoA .*$.Ң]T:/&] K7^n% "T?_6.$Kp{5HZ ^!wRߡ'kW?ESpĸ;AeOpߨx(?u 1@ +U6v."`H4XJud= -\I@ +@2?%UkD/{O^i$g40lHIA%!6:Sp%D~8 ڎbe2O@4 +#3-yܵi}2I'YcXŁf^X༖8+)`W+47`deگ +r?R,eݧ3X!<놪3 C@P +scT8>fuoh&ځx&@ϼ|/i!;b/ +"P9z\AS +d1?uvkU"ByL1j$1h^:gnأa?" 0FK}@J +ł:n$vR7{jtνjD)LWg7,SsC[e7%;ap?7m+e`pQ oD# [};ţe&zYzH'j~ޡ:PWi5JL/͓ /[;)YҠ> 4$AcW;VmO)RA#eiuC QJsoܢ:o*K4KWI岺!Up:i%)X?r?w]9\KrgŌ ОBVs#=x;S9~lkzo8tR!biMdi$w`M *Na}4: 3R^tH)rb+QMlH[qR0})bpbr+4T$f}\VlQI`bNȮil\g2!GB$ID~OY`$|&sٯ3/k;9BU%%@.UR&Ob1!s(NjҞD(5+;(gӣ`s@OUIGZ} L90je$nŧDj,k%uӿOc7@!nݚdwM1(|if-$YCX $9QTQ$aϔ@Em1'ƔHޕ=N}Q///xfdH֤P>1(ϾK"BWxrU C3 qKur%&YapEPxR uk#! g(F#֮]c*8I@I 18YtATj<˜9\k@;xxl&临όCx\w8cPR!!aw>ñ ,L, XWѐMn9ӆ~z|/SoØL͆$R?1uP.)A)]qnKk$ŌMxcDhhB"VYI;Q(Ij٣Cc +({_i¤G??cĜ;b +Toz +͍vCR;E,MWdFqR +JDf <\:+򉭷P0>p7:V1PiE{D\= ]QB5/tEGqOUP zXb=L;qOPPv@[#`}K`xnŲ8n]AN:= ͱI>(nRs*"XRF2i5$^HE)MlCLl/7 }hiM-w}JQ#{z[bF=˰ dzqZ5ۉٽ~>nlRXЉ+q]*TPl"&{VS:l!h-vɒMQ`PK⁄ଆIGVҰ楖|躓 lhxBڈqfAOwԂEe4etF/x64Y巨 nYy2NSTIX- +0"(5$>R uTN0@ZMxU!I^V>EJ2uƁU-6V +=^˦M-1(E+=2;kfP3RO{쪈DUfnOdDn0 bM\HbN=)MGgtmI>{H@l tgnM01@ORb2 dGCy; ddݙ0FtlݏII6 t9=+0# 7z`[~OR-]g\xR #=ud~8+ɆHaJ "|EM 7R"N:؝.Iآ%bY"EȍP{$%s jV3{dtU2TocFȫELx!z pe6q9i +uLqk+W5Q^~5b4p]UD760?GCx}Ԃ4[,>OXl=]]ٜ=uO:wi:BLR@Y*$hUo}tۮ%7sh~T" KP:)s3q"%4}L>s*feܱO|7x|R"&Q&aչ/)0μu@sD0κM:] +"}fuY`1Dpڈl^&;"BbT-oxkT%qį$0z-/g ʡX3Q^aB;KU_"eG&oYe#3^e6t:i7p +nas{y}K5g9.TOwV_PrԅACvZZJ, RvRڳRuahM`\}[Z2@gj R5S{GgH߿ֲ5{ϣ#!6vT!8VLGz/>#Uzr4Y@pI)LQ#+5/, \ȇcorbQ6rJ^4yKy0j(9er.H<)/my} {9p/eGqJof' k)b.=׿T%x%fYpM,͟U}_M~u S/6i͍q) +0a|'sJ{&ɏ ]lumlLv4G+k1Met8L/U%%6aZӢq;hAԾ0+PPTpaBcx$)*bHU;Yf84rY/y<5k;803z +vfq{릈bTDxfyL*| ɬx{s  )ۮh%D@ j5rC)h1F<Je?9R)aqiIdujF)lrS' `Ri[%.WGI )=ϥ§zC) +&mtsn$#7S.: y!d̯[7=̐ +YDמAiq"X!.[(<p ST И?ߧ~7 xTi '&ؼ@ 0_ A4\H@YQIKwO:TϋR(Dmn٢aWzYGxbt*0{ApH+XD @9s=ueW(yxxkN5JhDhNK$plH#՛m4Eq^d)f>^ZPx%?@]9l>d4?jݢ' '`44wh6^#LƐ0A^;7*jX%AH ;?sS5o3ifJPS'Tԛ%xD&]4+V@=03QLWyS% s1GJ"@Hb,iY%]ZM?RD~ +nXKmD-5%(Ŷ%x`*iꎪ_#W +ųR~QdzZuCu)x9`jՁKŮo/X +tKqk|j%ie]ZrEa2]"ZN?(8)aM cpDP3o"SnJ1)t#?Kt[\O * 3% reA_JzG!H*[6 Q$^'쀊 Z< VDǁYZ+z O@DrT5Xns*lr;)2@vdmB mՙK-$Eh ,fyGX vVq'p3!]ΙC7]PS)I듅a,G7»j^ eZAmD[ic8F&a܎dKC[慠HlxU2;@V(a5*WGf u>LC|&j U%6H$ף'.W4 E H fi"$YIS&G.Ap`-ų3q+Y#ħ-2j{ rH)[ !yS ip*ԜT"SbBS +|@܏\^Pgy`߶ah>q( ;NJ +ЕPs*cRvM~•JCuMk4 mЃk +ߔ%!hi@54mY+PD:{#8+YS)?A6$9R b+i\&dŵj[X@PƑpMOQ{_~]տ9dƲb;KUA=oz|uӧy/瓼VZ?57iol)&`'Oڔ4Rp6:6]|; KkLa ^nbDYmbUSw;nִ#imJ5L3\*xxk;ߔ9NTxwWlY(^df3A 'yk,72^-{-Q3{͵c}=V8{=1Sm?ʹyT (əb{rfp7>hɴBmNpݔϴ+xtXiL&&5H:H^NF+L[g=.6HYEe+cDXPM'a/G)QZ68h`dž%$N.T cg Y\0\%Jl:,$)8Gc\H+[G~ˋUZ:IkdiX5<IJ8L>e$23M닄:7G W'D!٩L6c!$Yk:f|,@(IMJBģݟJс% +Lc3/A*=J))|i=DdOtb$V4\gF_̟843\$#_!ɴJ[mzW +PwT/2|85ޫt I|Nk]܀R b hZP\RPBbc ׵8c)K.Jgȿ:UkqZdbϭFٿlO=p1G1+:.LŢRrK^X/e`X-Ċϟk~mFk> B07grh$&RbZ>(uCN dU%ŭ"]Mly N(Zb@#E/Y 3 ֞1Ⱦ,Vs~.:%T u/RO\oEQ'mx-=փ `DAή0 AP!t^p62zͣ{LgP)ve0ik6X7wv wÞE[:26si٪ )$ҶBϯ\O&CZ$<7b R0 [>M]G[X[뙺ㆭNo߫d0% x5v[Oz +Ms LElR3Q_V#L8ۥҜ'p<"U7⦏c@ +36<<8nPptO@Y~idLk&+'@||R~kW0zA95ԄdFqַM;)SOm 4 Of̏f)ƫJMEpFdd#ƔyL'f_|ٟǿݿ7>_^ +HC + ?N !f,Q"YPT8ԟ>-g%LqX  nhBViA D} ؒCl;@4ܶ+ wE$  +)K*8nGi&1=pT=S({*»KiiOcz墓n^~o[%%- 쁝&=4L|SgBm00:1azerX9Ή)^ ';K؟=bFewTuY , Q}v"/bJ"Ẃ~jN]޾~֬Xkv`}l[0вTL|AZuc1SMguUYF$B]G&?FEn rubV% ѕފgaUe٦facyK +:q.7RLׁǴ֩\o&U}LEAh <9;cJ0F>:!+|F/Jr$ADOhw2->wI?&[ +8` ,WpSl~=`\ D\JPNڟnMȆ䭌LÑF̋E@+g~#[Q/AGH(H:׆B.aLMr'b⠓7Ѭ;bpԕTo@yh4 ðҗP,8f\viBxIs) !{J{n +: +WsqJuEwQgw! +m ww2@<`.MO6eMGZQ_MVEŷEkS +M8Ls'ʋZ4? ҙJ-W+ +!.Nde1o.[cݔa"0cY;0)>-~5h֞Z;Rq>Vީ/Ioi [.kJ5+LS CT* +q0FjE!u2s1Hcp3!l5k47%#B׀cTJA*G2.K BTjuS00`P`-pXz.@߮.xjhHy.ӂ3qopYE+!Rc!5b2 ůnԉ3(=ZKԶH̔3ps-㽀}0H/նocET"nU@Q'}'wRBYScPa(Sje`h]B6DQ?ٸP>,6O:\ۭ39ױEIJx%f_բ&GcrTftNCGQ|T@kbD~i)_o[@Uv0q3X*=J"mi*Z.P<`P8OOxA43'XP죀B(@<(7&aqUR[g8:c&Ё7U AF GavoRݰ.e0__LV1o TJ}LO#MƏ1#cҮO3B7xtt,F2֪RKy8ye"&k÷ FC:< :M"Sm)wcl)W|Jm$WE +Q֋{rAU|ɫo,D0 q-Et-z 9^͵-0^{7b7_x<)wcK?{sŢ"& - UKUV 69KB)cdYU.XƋ?{H^o.ΓJi(XA=a0ٛT.å+68Gn=⩜TdL0~%а1ND eE0 RN@{CIc_֮KF88 FsY{Z^#K$ B ߰mjFk6B$b;q(Yܕ1O#B1F=K#9a+s3_ӞaH$?Sl!5<~mEFwA$c@aZIsl1(W;֝9ǏQvĈXh +hOn#ܔ"Ɔ  p71?n$CQxiFJ= 'ٴ!+5Sqܾ xi!z6)cf{f|R҈'SZ P2pp;k\4Mi~YHc?o<=g.%Q~Ƀ.0X4!chQJ9H>eŻOSmfS(F<ɕ9~il2)P +xnz@%<3 $0AǣCr #4, W/yE;[L5Y"y! ݎm[B*Xlsѝ +) ~R!)&چSKtpڨ  two#Hi^y''p"T:yAIdkg+twOsU`Oזi#IEDHCg(1>T06'^PO:2X(8GfT)E(u]Y-TK\܂!/4fhyǩtڊ;NUnTf֓d@W~ݚi *P.{h{(/ ɄgVPyܰr,,-OEVS'*uM)9HčP:c4$V8`I}A~MN~۾ڍω\^6Ѭ`I6XSH@0TD-4ACVkWR%]~vϡp<3bZ6^µbdɍސrdmˑ=ѷn}K)㙨auǙpe4J^LOGuVʜMԁF@pң5ȑ7}ݮ( + NIv-ey qRHGJ@w/;ŋl㲇@n>kYTvj3Y?1X1zTkNص bb9n?28r2%%9aP7i^-)٦}6;(ۣA|oTn" + ?F7.>!Ƨ/=^sawpk|s [Z#:mՄSL7[ΠL4pPy3U3̀d_`Dיrkk %]z{JU?(,m0={1={nJ +F_KOL-V`?Q?xa64ڡBVc{JTJͽ;g?n6=,c>t_ZW*و2uY=qؙ*V-ӷ/7FǒYK}FCڊ\o"o^U~K&,p~𵭃lgA=^wzЉEa,ZF"{*X`#Z1MY X[:b|]351l=pŠYS:n~ijjԤMr%&fDFd]SIg+5NJ3])¬w܁!ZN}n4 2|yx\ѡ2x0ͩ %c~7[Us&#D4]][hzj\˭=^=Pԯtt9ʰft5:Öy 6d]r@$Ls C[l>(&ƩmT) .ZL P}tࣛڃkF +ו?-T&TPZ ,@v7]64) +=rL!&4l; NX#Bۏzz1 P$ʼnLN$<D/R)|)ϔ9y19>P?~Zua$-#2IT,; Mلc7P@(OxCL2}=rB!ޡ:C])6 ix9HEѴr +yF՞֡hJ64q^l Mks2`9cLWz-r]W WqzTܼkD_Vh;('4KeDjam +f@9[Qo +{^8@ +0PwyO@svܫ]'SƫlP*!+7=A=ԄXHA8"QȁO[a|Nu)Â3Pd%f !ؾk c xO҄DĴM+YO J_3"`UpXQ;&щ|c#G;nZ?P\ljb!$l]6@A2({ [; fH$D݂ R={У^eNudcʞ% {a@p^DD6͹2~( eqV3ZJNSdeW)&w\u96gIJ0yXufWW+%B +&*z EZZAF|>p+'J9r%=1`$ +~`Y 3ִ8X@{TuX`wyѦ&7fӓWw 8%-3a+bzrU!no](+E@N OWљ/($ l* DgJ.b[H}U9(;[U:rѺTOʁ{6' by&KVL :(n8w`u=J?zň3f@:&# N@54_tQlr Pd?,it1Xy`Lt +nwʭWw"Շd<-@{ +whR6EDB Sa CTO ;ѱx>4I+60p\n?HAzZSƨ2(DVZ 妰VX )n}FP@o/JQ2K[iem:\)2\ fCy16y3pu"tzIzY` &ƄTA->hQFs {+IV&3 ڠuL* +%5Zä*|ldhZS +!"ȜPX qBd)%5F,HhN8[n?^\u )b#ꠓap718>UVľt<!И*W9ղ~ Nb)qT <}v{8l j⑒!Vd_)HhB '{ZKkf#؃PsH+ ߌ8k//θ쟧h(1ͥ֩O\-a 쳑#Xȡ'hrgՙsmm!8ݲzbߚ@yAEI"Pv&\ dwMCݡaJ+KvEҥ,f-z\صe#Dh vB仕_uI(%@Jw|ml%<4g~cTDRyfv}Z.脓"JEnԲAJ^P)ڹ*Bt-TbgHRP +@(9"ort(~\ ?c(_dHSG* ܝ])- qվά +DvΗnmg{)wf=?nWJϷNrD&H$G!;Ș8Y޲ǀ,nXZ:=kY bN[=.Asa@|MG;6_E=aoQÁ5u¹ĕ y{E.# e)JMa_"v㭤p:h!Oՠ9Z{ +1 X+ΰn>F5@ɺ .P+'DWz(+'׌qi5H=u)5/SJYcOe!W%aCC_nbeQs7p^Ni(ʎށLÑHתmĵPC&7㆞_4H( <߷+ԃ9 4͸H\?Ȅu[U/j@ܕ,$!R9#OA,y +{UmMנ{UZ!~ +| #%>Z%!^F̄LU!7([>BN(1Q^zdrE!X-؆ɑM5r_BV_Kidmu1mXd|HAUd=3CiWE!N-T;: -9A}$6^f:ŷտZQյoBvZ,Z&P|HLNBKߐYQb$(R%)fbL +MKC;X%8U Ug֔*i^RD+G=ڏ{#P&qrڎ:C !xb+"7,q=:3lf9WLrNZ|TIuZBڗ`ߨy7 +Tqj%4^:\yyrٛ#x㴣Θm1$g58֫V6?=N74Ȏ:7(jvs] C fsK4"% Is*<Ɠ/s ` !]D~Q5Mp3(?,tgO8A؊ԐD3ҋP$Π;jNxa}N%` UZO 4 :rg7)k xĠHi&`3?9&zI"*?݉JI X^q/c + < +سאbqD} L24csӑ!zs> g9aG/J\AKzDJB(2QF948 .TK[ Ԣd5E6pn'Y*^vkV*O TLCQ­>tt2~oF {K=U3P`+VqheU苢BOԋpefeH)u`W;0Q0/"wjIfAʼ X,nw+J; C8x DBT~M?d=Izw$zJ%aN[J +@`h+sPCؽWޛt[@plBBf=LFJg`fJ]O . p_c%LOhyT[1)jYaqVRxO3G\KݕvV_{dZ1'qyU]xO͖BrRsx[ @ۿ`_sdpR MhTY1@P4{ywj]lqm k5 1%p`}Ȼo0YI>#:mM)K>hSk]+tKdPO6 $\|LPU3duiWp [#~)t'Z5߲ Rٞ+s# Do%5'8TTH* 9Kpc(VD>-4y,oR\e9#ťQ!!~-Y4(~qK)Vf؋EpIZj~|8Q,ؗhaκ.VI܉vO}L 5:<ֱ#˽׷̐ xT74~i9>&pfSv~.i +Ke ma..͍^ScʦS z8 .R4a$o 8~Ӊ Fhl +̰n-FR.i;#ؤH1&dSTQ>* mq2 hpֶDGڰC`m`[skߓ@l-% ӇrsZ I21+4j/GQwyY_kUZI>*b9l 9l2HF,S48x|l!>ϹIyu~* Sg0NKݽ7dTu{M!CPp]pR7q z{3GԹc +ӲG +n&0 B355 +G.^翺>0ow>E&.Z!00cY/cRm>o)z3)"UH4 R(Z T# D`8qdz +z<5Րr{Ħ{O!2_cH{ u4\w%z,N)~pGUHދHXANv%*NYE)] ZpohB z 7.=ÁH!׮ #yk5.5?G)=(j]'K;,+V`Z#x'"`-")a$7B#l恢Zw1x;;+ZP%7ԃo@ +2h% D"D#J/l')4P5u0vB6`9FbO5^VgiҠ_u%C Hqd䱐)BJ ^vEK.ޒ@@XeECTp +IN/,| Sʟo˝)iK +]\ut=oleo1]& 20lzUb*!p2W$= xx`‹#"g:+3Zʅ6M +O7˓ 2e +}Xq+> q =M#do.:NۇQO9-Z_p@Vԧ-y@ˉ9DPdN.|@t*, p١?P1Z[F%ؤ>u_JǼ@AZ?:e$Ƭ,g(J'o21qEʅ1ߍ8_tF*}ŘDɋU:/;:@B1$ܑ A|Lî j*U˟ tQ!`CuS=Z=S WT5 +s?u$/Ì{#c=8gawR+Xtt\ߋŞP}Gn?sn0ayfQ-CGb 3~IXQ*ro=LR{@7=\a@T5Tߣn%腪N&'r2B)ۿx^/Gnd]H[&VH-_`;! ی9C  iRK-2tʊG ?3AdSӆnvIW{\mkoo +!7@!:ޏxp=qlfgzXlld+2 s;D"Z, +ZT"Z:z>GozfWCc3K` =+>wci|ȓh]L~գŽ+}+BW`l2gEe.-8__ AJu2wnZ0J@G;B0V$0JGb ^g +p&-r sM q-ٿԟ(æJ6=h`mE`9^0:t4˽"* =esϩ>wS+c NQp (-c;!OM(Ը%&/]:id}h~UURL\oݞC(t9ZH劥gHpWFV$]pEAvQ_Y%mw^F}^6BX> ݌$0{8;M"z:G]21fP?8ű @RQ@3ލ I/ˬsT;pjFL!xo r"e6/քMF-AmQj S-#+)N'R?tƤۂtzAG{c-6yv}z7j I5q^J'#F\q4j*!bl U߷+\߆ΘKQU +o~ȶ“(.hx!xYyze<_xؒXkCoa׃QxESqr1dsk3I镚_ +Mgޑd& A,w]H X es-5-]5 L={_KW}%).PC5ǹy'x>G*2s,$.+zT^ +W1.Ņ/JU~t=]xN9@Wk|%}|#^ [G2PoZviZLC~~qqYٲٺv@~]\yFPpjVRa`[@L.~mk3ީT֘drV]_ӾAMѡ\ "kyNzjkԽ79:ww%>vP^֗(&=ZOÙFG5SRM+V]뭐Yygcԇ󢒃9ԧqk{2W߄E) .j` J $< UWm^\{\x((4$m Zt6%w}>Gc0@OTJ`zp{)1o$X 5e `~HO'hc.8^Wז}k߯uܗkLw?ްu8PMs@Q%m3,+L`ciEX}nh2u梄 ] 0wA#Ⱦhl%MΉ=P5anaH:> f8ڑDcHĩeDn`Xu # nQaAN @v >]jzsa0,fg<_|C-K\z@!3Z>JJ2M#$gu=SkkGhRTZBq'x 7NǾ^H7Z.TKwK2}B([BjZ>OIHjp,5FDFbyfp1(V%~"cÃNps&Ce՝ qB^?V"EynNLpӢ0jNM8̉Jj^&bYZ-rx9J֠: !2f_XAۣv(!ޚ;{k|x_~ݟ?O_wϿ_~O竼^dF^򾱉F GUB4*A)'!ci|%L {hI_5`PqCϨ`gL0б4Z.ħZԞ'K+e2z +yiPab@C$^f>FR͏ʌѷ lGo Jq/0QȠЁB(L^6a9pVBބ;N22u3GH7&kC +,Vߛ,GΧ\+Hf` ZɌbga.A wte/ɌP5o.^U ѹyXYX'J ͤ@br PL 9Ja-L~x^8ncG& +MBC@/$V{w/Li"O)h"<%ݠ-B4=MOt]7NU)"] +4ŒM-$}lk,wP]f!ƼT{1>Ө<bHt<>ߟ7~E ^?~e= zJ4:~hPK\{;w>c)&H ɉwٷ+g8?`Ǘ·>/LMAyߝw ;`>^<$r_#vʺj\ob3] >}_fn4L8,WUMp^GJԵe iPB$vOK{'Хt/J^~,iUw 0 ph WfnZ*es?sheͽ "*9hV1iaڄRވk{zl1}9۾+׉NZ=كd *[Hd #yum.l`lm݄W[Z.jfkEdseEc,J89ZcB9L'$s ه>x4Ŏ5abwZY4E]PBQp`]zu%ȲKiE{4u+ـ׏;;YL'JCEF Nِ4i^rP_;M4/u(S҇'(SP-RPڋY;?7Nyş³ 3 n!Mڱ:C!֬|Ձ* y^C*U~p .z3[tї0Np%a[Հ&g\) jX>u㙥x9'jqn3"kN +pW[ a3= q(q% | PZH9`ߤ%?\Q)R +Dϛ32jxC +NeMԲG}DaY \Vh 9ldvٿ kAuX} rc֭!{ycܭ yuzeSAoB7p]X>׀;ҲAI*%ZO Ǥ0]$dL"~umb{k)UԊۘJۆgsA(ތc){\S +Ty[q>?-5I)CXSa@i=fVӳA|Lԃ mqhP #7^`ܢC:)LwåAr7@ С}h4nHyu. 7Yߓ=4_{7Z FNhL6tf~t^S)>S._ mv{u}?RLDtn΃Eڟܢ"`4)v1phÖx+ύ =p+J 9|Z)dl{4z#SBOiy +JWC!{^@Rj~xi6w^jlTlQ}]tPzi"2^篯ά'ZWs+4>K8Q;`$HA>L nK ä&M6ӃC I3}fD*s:p#KĞ60qPI` $ o3*?糑O_w;]Cs +$ ʵ{ߊȾė9"V3џFE9*Ɔ:9h\:hg|}q33G^ #5b{R@W@*cK%jNi{2Q@4,=Z)_N Mi|{LSʁir7-2%*خ^3hRUvV$ Lȕt R^Y=*!$ZQ/kpp$&G~!<"+pkbt4D[x'Oo^7"qpxZP={'{y~[َ@_ 5$)I9xd-=~s.moJD UJ`c/A>oQEMU~= +CFPzHctہRH;Fz"6epV bqijIJO=m25GST29=PGϭwege"գ_ss#;\bLާF+ =]d&s{T3Ӗpfq)-R$! k_hf,)CZ(%vт3)cQh-gb! +s@H;6Ԣ]=k@ ߃o<]eH! -rNK E ^kT[##)Pgtj{Ex9I F$0\)Az `=ܟE/ +݋HhhPukQn !o"5q26(l>^ ^ht9w#2,{%ոՠaFf@9J&^/bG^y&iXew=O;XR[?5w\QUGw +QؐnGɈ9CuP)I+1+,,ǐvu\ߠ'#S@9Az_Ҝn$ eKQԫ/Vx +Fj.4Ѯ[V?^QJ.;@;+gTFP< D%9>\Ԉ_JkЮ/P`RbK߱ҜQcH"]^Q qD[;j^ 9*f 5?}~)Ÿm(ܢgntx58ǣu\+8&}3~T~Qj {;n\HSJo%px~23K: Ĩ$s.(CMw<۩](@7+zȇ.z1 H>Ai"#0'{{w\Ȇ8Jy)0bpN1>>Ie̴[I5հ.2!–ɗ _=}^b{pQng&grIoŕ QF;puC1<["|x7Ry6wJ:Uo *DXQ h͐ߛdQ `%kE$4pY[WO@} i 4SY1(A#\Ɣ;bLD ,d|s*S ŧ3?jIvd4tj4XO nڷy [WKC-ھ~7pp(w9UO;>t 5QO{(nXL1X/ _%SVED: ϥ򽘤,zBrZ 4!9ހq@ ŝb +TpS\,9Khn"!*B/Έ)'G,=YC .\Bi(:J){@!˟bd]g=7L9h.ԢYBlPÜXG$hr@8U~AS$N%aRmz2j4T0ۓAfcK +vn^A(8Fh+ٝ`t ~\A9ccˣ7 z@+-{H|/!Cv>bBL b,_ADu8T[R ΓB:H{ED#^T祰- NI8RD;v=r<ҁa9y[GO01}~f7YLj㧨_'ϓbЊmlyc`jwۢՃcêĩ qW,T U`F{Ng цKqO3VGdDa (&Jcԍup3j'zs\5pSI; qӇ"%;Ց}3 +Tio>y)\d(58Jy-ܱ!^.3uqx"($u b'𙳇'U;l;~ȿc!Ss?Uv9=rQ.2SJ@@س}"ƊjRe$j>H1U9MYW +֥3ӕP G-%A̧hjTvUuBN{Q~>gbEN< {w`vd>R`=k;?YPYpH5>Şޠe E --"]I 1LJz +U$1xIbE< +̍HYcNf"G% }uk{b>r2`(qC +K6!ɻذJ] ČBu(oH2@my6z,Tpz!|^ +] +Z7u"$˲>H+АI4H0l,k@ɤf^(m7BIm"׽Z%J?{45M.|{g"Ŏ7cK,ShZBJVnW b33!3afq76FGCsBZk'D!U(+uWѤ*.@Kz JE% 8S@͗TzOw~1sd4o{-H^F]XDxy3{Vf^j&*qmg (!>4ޏxMRBf01O='q\Sgo *8efAaBW[|ڙH[o aL\,HijNgJ|(st*o) b/ =<^Z ;^_R( E))%J࿝HL +l/5&Jrq4Z!0J}rQB*S"`oӰX#jXةs-ې} 9 Հj$v|Q: a#bvN>O"ܞrmʺ %՞|5|%bE附_ʍJ z ⺨2O=`H`R_O;X>ZL(FwI0Lp0/zR90*SR'h/!TĊ2~$4Y*in͗4[=Cv% +:1y/KÙxZ.1PFs+5m32{tP^+I1C㴍M!.ҥSi,3B!BfqܛLױV gaT©d Ӓ $CDv uB0Ԉj7v'+zK?{c/}w$3UݫP *q> H.]e#ٵOz_qvJ\!s Eߙ|tCX'tdyk"ړ`/6O&EEy_h1\, *~E$P b~H7!A[iX<%>w+(>28Ul밁*$FջWi/r`Z/5\zLsy4.Qn}mePeJT=6Jl8|;2a:\PVQy𐆝JkyP0)ϚNBF2ǍD!~ҍP/״C^-=o}I!'"<IZk$wvwM̵$: hyo1i +#Qb q</(<;0b"kY0Zxo9֋ypO 3-PH zah-R*f(g#\,GՐy*ݏ/w&-U@ItD@p]ٽ"0~ jRyZtn蠵9#T4mYjJ_Oz i/ "kӷzШ2vQK ɸ숱|{dڷցt9-| V%6 j%Z]k:S&@,|a؜hHG_7+:ϹL#<g5 U\*>U91cub[,&EIwW 1ܣṛ.}8)]M.wlp %t+,o2:ERae j"8Tخ-%CrR Ы 4M#1D1*~klxޒu0)T#&avE YiV|4<-k}I4Ec2*Xbv:g3€NGyqAPcuNZ!$ENx klvl<9MbhwG +]26˳Yσh tX W$᥋$OZL$9Z \q2~8HJ*} )TP + /Lbl75 pI΁H67 6Ш0ȇ,P.T죛 n@TF˳u +LA)>n`~Uf`=H!EHL'BNڙ|OG +n=NT{C.|%ZzZZC@:͎mA39ܴ³>eW@-nĦc,91}L+ T:je]q6}_$ThoGȼҾ +w{Hr_ ΗtI$Ce W4{@ Ŝ#s1 ĎP"%?,M-$zhD +0XF)(BM`nl޺SDv wYUuaBp8]7SwjG~*>uGm 54l4{op9мj +"t|q` **iؔygL)AvܮHw.?;[6m؋x?|dGV3<ۘTztv聬UIKzc5ΐ^~= + E}O)RQ'V~E oG %w_τxs8`s{S{EE64'w~Tp&SA[<8}J.fhm~#Ɍnl43m*>X\%0~z\GbI  }h؍(*oL^_ +'A8ړzq*6#(vzf@Ï8/Rc|&"rgQᜌŒ;%AbT>k](SS㐤P \dJGAz\%9(w ]=fIW27|3U'Z:umIv6W8~#G' :2_7(}ڞ-ˡoi7yFm+m.GEa~&L3%wh%9l2ݺpT}㦒TfzFE:U{<);uxTюcVkÈWjaZb-oIȷr:lx 6C9sFel'%)ộ)Xb z iwUji֍ZCkY6y}W@7Cق(dT `OCɖ;[A+w6=0dqX$72W"fp#%SsWQ +mA;&Fa^D[&L̊SoO|{vxAHQOYz# +f&Gb3{PY.i}-v! <đ_R*\@hG j|+bqB)th2jBOb= }! u]rKV b'H޻B +(؛q)vMC8(hxxwO6$5m%ϒxޤ܍:5`+CC(_Cƒ +t:7zoɞ9BmPFGn&z)vʼOEoo֠Ϯn(3`4)n>7<92z٨@Д=GȖHuEtBhÅ4;&b8^>  =anpf孌xJ# lZ6cCO ɍG74COT ̵tqK=^mfb Qd28PK<ʓRyksH% -U'5 ExRE"jISBnj33E/'nJ;SLb7Y1,.9Uh_d/aE0nG_*"q((+u?fp)k;{|_rjc2G_~/x| +$S?D4kIv4 ]JՎuU^@9ԟ3:$eAqҁz{ҁ&4GCuH3 ̈v=RL\k9h3IԛfK Vl4(S~H #][e=A:F|'zx1 +dSC9BǒF$"D}qw&D<bxQvó>X# KW=C#Ϋ 9o$,W*+K8T7^LmrqM +`oV iWhh׽_o=9czz!) |Tf;ؤ"}aTE<ɬYjhDAEe7[4 @WH~7φWӜ ƅ~_!3e L~YGd7Fn2_j0mTa(у4INmj.M~4rocϫZ|F +zXyOMf!}uq+ D"ziU}M2Bo8X&_$w1c|~PG\ou;0؃5\ uR!|@ esyytՃ;ܟog"lՓ_*H@zc {b5>ޢdRf쑅R.swHXlP?dSЖivtY+k9=;/qGUmD]Ƹ_Ds>Go7dCqj[Q9Vi kf}0i; e W%d",zxkDCB>G|iCAhu.[w[22{m`MLaGp+^+{҉aRņ׏UN^5v#x> +zzd}4^߂a+S.%c[o56 ߀oh[ 881 {=R'v3~C4>֒srQ7o3na!P&ؤ|_s؊VnGx3unSB|!̎<~(Y7Ղk:u>"@)rXi2CXy:9go$( {_& o蛤"e+fK@aͷ7nD0r:Ïo0XSc 1/9&KrqEtڰ焽ręX߲د_pZCZn{8 d7TBqGPU|Rdzkhzo]! Xn]#XꟁyzViϗ:< WU)BVwqC&ݿ~F)}k &/ +pc"SrݭeލI W@ztБ~`5_`dR(Y\R+<.;1^.ݯվQc@Pjx놉l=I#,Af`xG7L9~EDclr': hl!IɀZ|}i-z0K΂MϘ)WWh{1SΩHgS_ +6&d[0(ST -*c " + +ҴS, 5<}n9Z%vQK^7Bʀj6rr\^d$ (jiK':Dd 9njcnltÎiw#@ +E=79+tKjA{[ u==s&D ܷn[rKW [Ư^ +<. *vB2A,}=CW؍%\38$\z1Vv{ 8jqq|+_SF#td w %1[ {$ +BzaG{!<3(ψ郀-9Av@ =M4*ûbxcP&^a/=n`Sΰ8,Mq/C񾮘8Z^ μH9^pXw@m?x0,5*ҴЪaHdxwk•\G&Cp,iG`' +77{ ed'+ٮLndZ)jRt.Pӡ~9TKU"[Q"[`q> +V{6! Ԙ mʞ{M';H.cN[8CƄڜ_H3&utR( !;1F?i9,'.ii_j5lL=uvڈЭS4@`D1 HʎZ~კaCd)T'8xN{O:S"lfQw@a.QMEbko84p.a$#wB!z^D)LJR&uV% +zGx8?zv16 w?P^YMz̚d`M_eˇہ~(*~2W{Prb K|T<Ñ; ' =z7(:ae,B:aňY4vAuϒPϦj Mip#΁5ոSHֱ{m֜)ݭzʺaubWIn,;*A \c/ #=O +k9n\vT튘 +<7O\[DP?n2/V +bj/vD^@ [BϠcYǽA"CnS,@zjg6JBĜPC$_GnHM5c7w-neCD H!(=TJCb7#Tk9%W +.D7m+2K+ПJW6B2Ef_*rG +ǫ=\قB>SGsX!/B4;="|咨g^==aT# LC{!)F-${c3fE&~jcU(ַcPsZp]Aύ?8nje+J~N[EJ5{$f\vnDf3yWI>0/11w<= c_ ~88N2PKG;ŎJ\J(ǹU(nm:H1KZ?^9ktDԩ"& 6ůs4- ;SR4m<\jw Xjtef%Ԍ4/7 mx o`摕zh#;-%yh=bޫ]vhj 4>{1#E^-HD1u^=g稛R8|=p1r Sv5d5 L°%;CV,Bݿmv`ta$˳0;pcޢq"Gө[BAӔ5B,vuXZ"W&FAEޡݣb2f#tZdbA qX#k@Z+Sr&zzW76wB=ⅭIfu?pH})Z-vt3jt:Ӷ?ק=Xz^+LweK$ bWOT:?]bZkDкn +@?~ tQkTh ;cPc^'MEհ<:^\!aX e +M223XxP6Cվ^,kS/8Ydz@Z0Xhzqu#PxflǞ M2 .Ėq>g4pLT)u2NlLf,vfbӈ((L!tD \ƥ|0VFwo)22GtD Z|Tuz>Q{w';CKX<q-X9\sO=άA4X޹ʢER@7A>|_B:6HKFzGjnj'_Og숿J6aua0n(Br F9/G>4IDkzmfʒ攑RaB4}6P(/vrZIMDfD#_߅'AVmŒ-WG/ւg׾AebIC11OKK0vE՚ #(̟}ߚoB6v=-\#:V4 +C}xTv{^UAXXRd9߭Nd[,ӑ+ԉN:^!X:Ж2i=WL1]L ,A B} Bm 0n%_ALQZaH+];߀&`z&?%xk+w2-bOizz$G\vRhّGl`(?#pxT>tXE^H98YA"]0h(u+"oFM C`ؗH5ȟ؊T--Ю/b~dH'+k3U'bm8?PZqF/ DȗF旄w&%oO57fwumV'N DVKR6}~ F8_DIMӉmOݪD^ CJ KӚJ3z]3U˩d!Z$'l揈#-$~b[f*uT90: +,.-7*@lçf'=y*$:-:ixWsRԁ|eJ^͕ 5k&߬LDxTb t?Mx'CKje +;Xn*3ga+$| 0)EHB ? v7x@kA$j:h(+Hg79;2Vo|mWI.șΥn'SeBQ>)a۷ =PK}טYե8ޠJn?1zk _B&$n9]JNx <V.oŊQjTi h' i dbzT`{ҋo Ė^6kHO +a CLF-"D\3Ȩh~T0]`CDIHWd& K;fr]O*ћ/'Bv#QPΤK!!)^ղc0e"s("cftۇ- ȟISK z8 +Fo6y:OzUH>/AmMV]#'Q~3 'T"@02emRB?ܘ,!rnܱ5ί%|';dp +&,BwZa;R`Ґ_[qn`[ i%ЌEu|KG\*daιhj9̞Ra:=R!86*s}+K_zD9xTh fd֔j<h9eQ$R* (]ʲ¡$9t`IubS 3ƤWGNnהɁ,!L BTrU0oߺdXFaְ ?T9`^ T<2ʷPfP59T[ǹTj'[Η- +zO`v8R8P`cP=KY(E͎E9Ψ9^@^XnfBYOת_l7EhU4x{9Fiw,vD}L r}n[tkn.U+|Oứv:׫Θͦ{H=^0xGlݧR۱z/% {^4G\L)_oKȝ*H / +y 3:Qڂ;{eFjfM{qP:4M^)o*l-66-%X ++)EƐ/ |%BU1Qs"Rzy5):r*,npsb-Ðӓ2_!:u?E7*αJPsF3EToUtpN 亝# Қ:vuhE3 hy'Le$PjܷhD-†I->wU"m+M>}* +NDdVFT՗P"i"#h$C8ӟZ+"`w44!# 4;MDjշo7jqDb!U rTiЏ)\%̨voI,p +mUiD]_Y]8v]VsqX)]]x}eCVyH꩖J1XԂVM,䊛Zh +I#CI6\*?(Eږ5~ZUF6X/pEX-.Wk>VDnzuԆb5e[` `0"I(2ləSיLo9͈9W*ZDT?ЫqycA4 vwnNN94׌iwoa vr>ڽk'Rs%[ AM*U6S(܂nw?J|@h~SS҈՚.paE qV<9UnZC\+&NJGY-fa=WU U_h#$P-[PPYns$,S  ZOReIC%ui,OY+xdkYO󩄗rx y39jfFz~^cH7?FsU?"BNwz/fFjTUux+3u[3J.;5Z@~Dv3(DJC V r WDt\dl |+8_0uȀkJ2}CVDPV!Ta36"LhbB a"Mz`3*-J!=s nѻo 6O.ڧobg`(Ÿ'y仦RZzޜ04t@p{Ѐ8܂( 1h1$/eu y2Z3e?FHd;1>ˎpNjP4ҏV`֛j tE)ҟ$?1 cǎաDnS>*HڄZ׈{H~䦺JӔ,m%D5~kOJ>m]6vxC_ "ΟPpba'5(ē1B)#M5p>9:s#( H7y^H;Lkns]{6sHw+A^rL.erH}g; ]+%L]i|ay)4|6j}2wJf*a<Ɣ[i#bA @]Pa#"boCʌ_bP JW=x*<a5ͅQOq'Z_ _@|Sg.uUEY%\.wtSd͎z~i:@zaX:lI37@QaN5Y}#{=)BDWS!jF"ϩJD'$KU fg +l8 +4&ْF\ {u/ Ѵ1Ǿ9tW3zrɟHⶲ>{0X:^CE[mS!ITT\!M#V j)c/%] myA=M] m3itU0naaJg/eLxǭm!VEKl+UQ9Oq`G$$0@;~%?(-qL lD9~qΤDe2`mZFc[QT#Z#I>r<}]*hʴvs` D{uM.i\Mht;rs(a8RySڧ5שVTqP|\MB8Bh5@U>d M>#Wp~pOFLR n;eq*hbM]P8V||'2/c +/nCRE@ Ö](A?̌bp 5<ָ_Q'z~ }H9Hm@2=;MpT=~yY6W}S}qZpn,w9 +ӛk_M-lȒXnBww5]nV#חFYHxt +LX +:O}lv:+4_+g +Qrn[>T9leps_P>ˮ{, *&A| OJ.ӋJz}[l"$ N}^Y)y1)yFK{lܔ }-|֣QV/(-eqT NE\%;w +Ði0ZGܧ^9>bsC4-yz26Ρz}hd`>kW$fq[gqSbds$C C y&Ы*fjzV-3Ľ Cp ?JU߿0GzjT{njaI3m *@뒑|JMB̀iaq8LQz@)OtUl&,wFUVHdPC`L!BUEQ#˔B rc 3.e|~+ȈqR]pGĒ!Zc]jiՀn.J~Nn.g#ˬz(!!ն'4C҆oz>+ +G( +>{zacS2d! G鏁}bZG{Twǖ([z bg+ :{0 .`3h ?0i@全@ ? 3B $gϔ|5Ze2D U`ard2:dk7Fx:XgGڟ#G8L:pe>0t=^ԍ)jmR=>(*McĦٺIXD'zk9)/h +4jE=0WZJC5tYZgu?v,`+!;[}{յ7*oЎ""O<Rk+<*ҟ Y ¨Fd +ql7̬D( "I}| u(9Cz9 ;Fl2tܨlzP~i^$)կSmo\kpG=!e)3\^9JeSPo +IH~" +?@HC{mG$|1Ӓ_f v.*.rYP*A3W35zB.,,o"eͰ[<=, ":}naYG#Wqn[`МxwB,RUэ(W[TW0ep\IugF 4v'IY?(/m~ WK?tX+ȯ!vQIz%CRͬ$5pwLp,1\'^qN ejW z(SG\g𳮤y11W)l}kSBtQ6g#8biZ|( ЋxMOZb:FzG89 7DX_,_`$F47gVsE@Lm>M--ЮDS=Tx**B^r™C7[a_K}9*D'=j&bqf^5pe_E +ҡX@45^'FR;lW +`{t?X+#ړ +(-N!RgWp> +f_p +Ԙ>Ju(ʤG̯Z6*)h*Ɣ:E:D}EwYmQl%'8=ꂙƁ( fgF-e)i(n:O^2 |%6]>ݙ)F#j+jB_ +}ШbJهerOP]4:qn"̩o&_1EZC)B=p۝;@M>q_鮗 B˥f]b'~|7~V.|ϻ Z'DDlڅ1Fzޅan?9Nɢ |HBD3>~ ؋S:ߏcjbB}|f2p/0~qUN#Xrs$KfPrأPqƵ}7ƹܞG 2Dr!qi0eW/leG&2Z:7܍Armt̫72Vθ?ƻXMK i*ǷZEh[YiE e~0i 7/# ׫05$""_+x,}r~%o8KN}-w}l]̱s|Hk"twEcE ՚Bņ>X~*?aV62#?JEӡTrGx Լ޶M[411\LIg|; JGԠ8P4¡xz}hA<0wBhꜛiS;g{En?@a'u&8={]A_$tҧf\|c_Ywҩ@#'T(D 8TA +ӪFhΘ-Ze`Ԯ&Ԏ)RL )/h+ۡʵcPn fB/4ki8CM㸃s`۷;PK0m &.)79hԡA ,d#&7@xyo\A.o'55:`I&*{-펏1<~}$8{NuM)?D|'ӡ\P̬q%Y[j l + +SGnqOTHx 6,4= +endstream endobj 104 0 obj <>stream +(}#7k99֩kmUBLn5ݼ>0`,* 6rF,6v{׍#gANh7#l 씪< a{aFBX&le:f%C{CD]D-0VfVd9mTrme & .83H2y ]ⵆ13FqFPޅܮu7^fx}Ȕ1 +h3@79R>|~c7K"E't`rlcJTQ^{ЛF"7yt9FR/<.@τP5ځX,Ӵ{;{;ψcؾ)8Q$)hb*ܣN©P~A y5>PIh*0cRm. Ji8UPPZ8,дط|}5@GL=`U7E!4=b3)ZZ4vWnO,mW3}*_=@ÁP[קW,/T Dڄ@{s;`Yt6#Th`u?CƫA ?p0N\s @.ʦ.bjxdDJRXߑwŏ08*"JMR倎-p{ߕzUT:'lÏ@46v"uzxE~ LiQEջuɲY.mLR  +GO1?~ m?4tSnu -ڙ sFoN@j+ +hk{٨,S[ + c[krl#(yG'@pR/W."Fw92#I{KTAj!JhC. -<3?8$e>G?ʭ`2Ь22Y MyHVLX)V>#&$FŃGJE4%Q*6/e??IrW[؇"9CZ8wj }|-!x8kC1l +"^8 ̦3e sW-|'tN:%6B giYK%(km*=c+Kpir"WIss >Z'ákvSͤmpF,V`V$H5g/v& Qg^@xF5qm&3b[a*s DY8S隵Y|8%1f87k*Ԋ=nCk\|MhdGt6Q9Y.裎~u-LW Z D,TlpD_{(v`~:~QqޛRᶰ?b+o}f&w6)gp/#^A谊Q{ DІH/fwqClj%jCDCz_ul7QU:}'P0*o?ۿ~w׿x???O?Ov>ρ?O_u!=O_D8)F d퐱z2&\@My"LTAu7_%BM2*-bO(& SM-`~3:jaPsؔc'et޶cRum!@6#@4q}er>3 + fʥ}d =`hCP@#p%BXBl2l'*Bv-3DOJ_6pF{ dT@=*(v)U=tEKfwԚfz(=ANwEU#& t@QlF ȼՔ4 檶8u\R͓k!؟dtۘLr)C왰'̍&*-ɻzW@M2 cO',ʳ8W<]COP>ܗmT]2YMz( "hU#'/ @!^UO1x"-N 䐲AӗG=' [bi>ngi<'3DV!z0k舉M.7bmr&i0u8Νtd݉TZ-,=`r\d%5-i3@ DH%) F"%3 *3GImhIv +)!?$>\4g|B3œp|} p9-qva* Z,{3e1GBp~+%z~0B(ߏ0lrX*q o"+$iV#zT(F,cjZ.;*FwqC]o:lD̍KQx'P ^Mʣ_9\L +!̙N{snތUhA1@Эrņަ>+Tr$~URS"lP L6GkH*QB^|~Ŵe\|zAy>tId6\ʓRghOer +bI?ξR-|> .tJiiSwxyx)4qI~?}κPxak߹%idi-+{VGWYjH83kvYYk/׃35FR 8T52yS袢9}b.AC},ڬ _KxՀUpSVDuRޞ\aT><0u$A b5bax"Ak`VtgK c{y⌜WYwo܊8x?`=S8׉hr_vjURȴFӴlk hChxBuO$kf~*w~㮠SȳFŋ1;[ WwTA>?Dzo-ZRk: vp|w:LUP t-eL#ŒvY=ydʞY酐&  + ߹igk0a~GW*R=qT'i@w+y77&ahC|k0ofvGm%GjD3 }FJ:uKy5֚i?8RCn! 2!#ŵJTn(\ [) ]􎶸~]hn&Qlxu|i(s)L޲OUm؅M1-3i?Xn.eD(sCJ)~dbk<Jt:zW9`6fICiDĮ.rv-hyb|窖ֳY2e~#yU@8bvL `Eg6ҞսLMknr:n.<.sH4AwkEwӝ *1:*zm,s@}[2l3y. +۷=ULVgzsRm%d5XLJIOHc}՗slXxg.^LucbS{㸱Lܩi4 H3G.agL*|(sĄ`YF Y&3W;>b:ZP1,΁~}-S}g%bE~1 g>5ՙ!@lFVA3NA1O&愾dt?czZ?DۮHZ3|L0\&Ҍ)q}FDKyL܋]Wf#WW?8k;ЀP²Z 1L=\Á湭qBZ)&%`π`]SyZ˟M+ɐW0,i`<} +06kZV&܍c#Ϭ/;rv0D@ؙ#ND#X}?F?{i0y"mIH?s&Fq!70n+ꗨEu ݤ]KwjyZ=2#Nd$rV5v-fq)# +!Vvޭ+4T-ιXg<OIφ0](3ϨB$$/LëߺpH9̨i'3.ii83@,$Kgkc>?Բ$Sj ]Vu<v$ -/6pR#\񩶒~zsCI3$ qʘ*џ%j=0ru˭AܶȟfAo~HD_:b-^>-"s!*^L{$mɍKxX-gzZ{cVK^zHDFQ"ta#9W=:\JERa0S=!Sk7ph.)kj|2AԳ߮h6TR|Ւ``qN|gNFG(E +R[h48R[,Nx!YuaZPL,ml NMiYb%^ICjS: @돈+` ;   PfD`8p$ +#<3NDRf՜`߭v{;k:MQYw@Ȉ[Q.`pNH ǩ3w\qFOD54' 4a$15=SR6zS*;뚘^-L1,IeWzmJ31qLHaڂ)M3G;>31:'3r@+Yƅe1kEdqѨaXCP{h5} {m4S=_{nG@{;qnvٗ7_pzhQ[J +mKρLd=S<@>CMaSV0ܩkϟk݄qa3mhhqZU:.ڑ7o/TYL-+kp?]3`=I vpEDftC{M >WB'ƃ!.gex +O gp<9 i>_9E4 EE׉ :DSQL֜R+^z=bT'?l@sH]W3 nďLQ>"|z|,/e3xs_!5;\,3/pI]xk1nKeU0bX/7l..OcUaS +m+ ?&Sa+mn`E;a tSx)ca6 d0, UDIDyuFh +[KUw/r3fPknr}{ =⼢Wug_牸\!; F²PatMv:2FX2uv4@~WX+=NaXg+htSC;ʦc[y3u% +߯bCgUNH,(? %bCa 8X cOE +ABgSI0vn{]bmla(η $fKG"%b@aLfL7e 8`E(,{GNeAw_20?Şm13ŬB,- s ?nnJN!.NȮZ҂ t#ia7QP}[xI(ōsC7.1:}E\{Y܄&=b3[JG@#$kn}an4O#N +}ނO/ ~sS+n)C"ʹNRgHUiffU,缝 3cEn+3:7Qiq3X؋}h͍J}Eq^t\űjq?&}3w`0`@ բҶ@c +5*P< = %]zDNTkTg׉~ YT/re!EO/ 7#? r~Y۷thC,.Eً{ge͌ɵoǟ^OyfL,[𕡸W_h3IbBri 8:M^wAɾsH)n.C=m)?6GFDh?\neR$YЖ 1e\:t0 :h'uاpJ:;Ocs}]oQHk(Y_7CqXǭ4HR*QmX-[15s,0}$' beTJYy?D|QLK OtXxl)u(T8'b[ay`\70U"_i( +~%sT +ψ= i CwA9:AY\vQÌ$+գ:cx3]s S9J_݊u;h@HKU`(ZOqYکR +(9qc61"?2 Dv>14-a@F uׄUn8 +FG4OYlD}MV0=fsLcbbYE,Z͗o<}0 +j"<4%½s+5:0%e4.-h:ݢeb+Gm$`ugSA +#?Q!F΢Sl$3oSTDěKg6K&dgwXcPs`*փAMCuBCC|vԸ6d8 F]o 1T4:fAՈ:31BҏP3՜~.Cۧ+(k! +=WkSgв@>n-//q0:xE9׿];Wx~pZ4Z,'^*gCJ[pFLoݬPC+ɝu}C9՛d &Cۉr.`*2Ȼ85IJ2>0x_B]^s +-- Nm= _sUS/U;m&@kMa; +*ZunC1-n}ho҆iĮrh}:C^E鑟 ӷR"e D+/ +et +ZX]qMcF] EP0؊;|r+]Fԅs1u +*fשnS%NYibTmMO9ZTY',: ^8R%f`Y=MИ~daq|H)Arա98c}9X L &8Ӵ=B{$SR`OkzuY}Pi.k6΄[rp0/yYXS[@j~ ܜj`6JSh歕s6]?"1AHVPZrĤu3ȷ]/x\@.+!db,Z#l +Nz&D0*$!`$,v없$oۨ>s2=/aqe[O-#Z i EjUePU E7Y1wcGD} 4'ƴ;r4as$bfe^^ZV'_+u<7ȏI GTInefņNc (d8ͭfS2F,k|Wo()R3%J!1/H+")AoqigR}Jº6nݚX^PaHSh: `E)'(t'̟OΠƖ$POw[ @. =GoUInonX*<ϭe r1z|+ 4s%{kk@:\L8̌ +LJ+1>5@//]pWVr-*ZiQ=y[GXI(1j-m L~0Q\fWtjN'lE%BV~աj)s (]ߴPQ]p|A+ ȗ0̩g2BkE*4pe2PdULUtr +P +F:Zs2'0'6HLtp'Vօ ҝ/zY,5](uy$6 _=["Fv"ֲBPW䮿.. Sm*R~uuՒ/ +\B4s7\~a}c(}`qἠoYK1tf:mC +_I ]ὥPA սU@ZL]ND~5H'==;F<*hHlY2QXk?ԡy"5(뤯1s_@Lti5Y&zH409]P5V7IT蠕@mx_;.rKMڷWG? Ƥ0&ȁEnQIg!-}KK`*xѿti4J5TS<%>uKm"_\Ay蜶w9[n +b-qp/< ˖d&2't#?M/gC=o 5iw$AؘۮI8}BM9pyGC6ZsG\oDiF Q?d{ 'v1e[ݳ=l'4"B\;-%A2l!o#ޟg8/og6[vKi)`-{^/0[~[sm\LI@M*JKPA["SՎ*xX.,wѹ:^񀁣"OU6|E)D0.zC\E]S= z1&qЊ~fI-Uu$k׭`pkt*Z rH@ܘUzfNi`-u+rXύP1 H(1+cK1Z壤D 6B#]y!to%+a f +ɾV#1JDL1@#F d:0ʘ\z-w +ؾ! ,Qq>Ze7Gk +Ƈʦ%K^a _0s1JJym#-|!SY\JSAu$Y<8DڅS*vF\# +؅?8w n1HJ_- 5 +MUbpA|ͥ#KI:#]F#OGD EV"PE/ ' +om+yq㬴v:6+-3ˣ3bK cu&txM >$eMaPzhlD~A)$1Q뤋4]gOSZEЭ%߇NBkU(X Z +~B0^Q>:}`)lW +r®2zʊ]JJĊnVNZ.5xHRY2[`|4,FX~G/\XDpEXb<hݛ GGn4nX̄;{E)ѽEpYIEж}VCh*vDc{ +(2th`@6dىa11hjN5f|Dq67-CЏG0>tgbNיAL BYSR:]iqBDյե6_@ c:>%|q_l;'aPyr0:#7גѥ;Uc܅_)KI6R2iwaV75zWZg$х4)?TS$< +:wʼnf=y!޷,4^pFH #`&2an~w(>5Ran*k?3P/|Q +et'8=:NmعuI:A6UU!e#rg$-ttxK^`+M]!uw.< X!Gdh@Vhzh\4!5_h{h¦VET$t3kSMTk)w"t: cw3X"L_gz#2|Sk~WP|G$wi}r\U/۱ܩ|8,x*eJ/ΈQ^,J ^~V8ɓ#-nWJR[0p\T3=bamM+#ԅ ,DD_tXs|+4KKmKZޛQ'^H[&U%UC{B_k[C5l熥nXi7%dD)vuZ|(CUC|͡.rK)١V>@=*]5$?/LJ^4:J}2qUf( ߑF=~GT⩚ m"0 !xE'gvyP# ۺ[]}p8 Ä ^L' p-HCb;-U#nBp!٘K1Y6Mo>}=2)V"hqܿ Pa2 *DY 69f[NuJS&]ۻ0.18l:\G؋dp}8}*j s]Tl3ܔZ۸ZH O.U DL[&Vߴ0 +vSM{ P&?䇤xơs HL 8# +jbQN{y؛gg;OM-嫲n4Fb:,ع tdLt,{G~ vcȰ~6?`,Hܕ] |Hk=nKsMHM +$wa'o}!۷²"IGppڦOa89_~(1֝ed2l3"<Žț2?^/<tE2߼Z]gXWv{?go/TkL1#k = i##zz%U/5 Dϧ3JF 8C-L7 W1pX!.Eh눊V{XQ䡱w*C ) +.wJYVRPW>GT}Ciۊ8P6-">û};Tsm蒩vP beݧ!A;-dR3YQݧXK0䮙c N !I\f/b'Q!0MtTaHZQ^0>UjtNļmt(V r-6z[9.?ii{֧e.7ԀE#R.8~>D:|vksMW͂ sX)MhOJi"DMrS[Ks%J#k3)'pp+laI$Z5!EU Q5JnFduu{<)i<w92,zeπ#q_j%ן@j{(Mx0b!+Q܌I]ꐟsbPUEϡ]hu) 3 &ӲODȯD%4OU#3B g^l8y7{U"A :̙'vc`)3s~Y&X @u$ >.PR8\p[&٣7YMhPz0RK :J\cw򮍭Axɛ+WK#8ߙISrz:>#ryEQeY#4T񟽄꿼4Ěz<e}T5R?ż&W3qƦ4kG,80^A͡(ܻ_s/Ӭ:SZ RysCl RBXoHy)ȑH4S)P&(K@ +M{ 0OVxurSl#2`Bf3ԗ \ɁwS#1G[ +pe6^ScM5̏gA3Sš 0Nw ,h}serbІo!-mcE +a\.C({Ճo"q.)tyM +77% Gu-BKv7;ˈ}eѵL""MN r dC 3.W {"|Ni25W#V 7 p mTρߝs!M;Gyg\IP-o!NQcj3.4Nu`3TSZC8- %,+B5.6簜,^rp%!&FtY}D15FK9f8}3j9;,*Sc밂zz.rtoOdvLz1 )KRܾ4U30T" +:z8hΨ_dT[FAE~⎤n`W} LTsW8I}nJf#̞R:)7BG>=DinL Y4ۨcac *zn.%aDZג 'ncDEd2ain =cC#<SE lh7ob3tivamx~i<5FW;GF 9.6P 7ts-I+1׆_1&իWw@reZ~43Vbם  yP4z= C+wI ~ ܿ % :ۣ1_ǟ[l[S T#j& [I[z$R- ŵ{EX boq͝.-i|F7 !6ZTQsKsn 4ll7_nFGa[Y{ɀRmfy:bkLRИߨ/*dl9h,N,hm8KH>_;Q&EdoyW[+5#~C;CYJN7 s9~}P #xrĩ|)3SfuM cl\")M2ΎWW'-ƕ0i:mA)콵$5a_W@pK1wYޜln)58Ϡ2Qs3Y׷ߋh~kڍ;йIW/lpZ gT=;J~mWXn׷cO0 +" hu<H6PZ<"z1xo %*9ρW{`0W}qŕƺYC[?%+>xǙuZ?mVI:F3n} cB,#)UN7_[}#8om#|"N[s߃|+CK.Kse8SZ>Gع5+.'ۋP*Oĵ#6O=cE*44M4Ǖk}FtN9Pnn!wA~$ͧyE0>#v/XYD*-) WM~Үj5 j7Z$5KC%R= +G"$VO$`E\us%#_}wGRk,ؕsg1<[j>J ]E#B4Rl/S =S8hsluy֫9cK=rHη5)JD*'i27܃'K>uk*B|nSˆ +;z1Lr&kڽrZ֙ߥoPڊ`?yIE)]WH!}IK,:FQ.*_mw)QNaԓFJW.2t"ӫ=SԞ,7G?FToYGyS̰QVwRo{n³U\XtiS_jˀ?AìMr=C4|ϒ!EEuǚa_3T9Dm/X a* A&q_[=\|#-F@SL_Z˄i{fKmHOɬ]((8?;ZX&klE4;i%:=1{z H}%Z՜"cCi8Eƥ8) +<"ca<Პ/Ը(АctBMbcTCs[p +F8d?H% ~(op*>kE@(0Q"ŤobLR)#-+h=5=& |MCVYGup4TGN$ĈQ  U̎/>NٮRb7_ʚ&L=?)2P,-z2Xk;ɈsG+9UpGH^!rj$SD 4/aʳU`8wYYEdKRб2b԰Kۓ!]<i?3 /2Z&RaE,W7Kr_WTaI`W|^RRԵ?ڲʩܠ)SLbXmXAڎ5^Ո=@ sw7jj){զ-Y\3֟BЫËřEU&xn sR#Ljx숿L7_Yقp-^ +{9J)2 2*ЧĮ3lVhnn:8ɪE͈_.N%>؉ ۆHKpԁa I7SN%jw\vL7r[xRSJ]CL?|RI1CRVlPjz|]cE1uZxjs;5 "AwaH2j1}-Kf.ٸWJ]ԕAaRZ-q-f' RrhDwbT$9O8?f6X]-_Թҽ"X:_6K2^4pZaM#W趸Cc(wD4 w_p?\k҄Z O[tN=R=\AcaYq?czSI-_"zP-8_I!{cM>g*,'$+v4 +#Ҽ%u _}#Vѩlލ mľ(_Ô- r JiDיfԭQbiҵ(L*̹v_mDU1R*`'{╚`ukr#WoM~Xm<wI Sx˚OA5ކAIJ Ցb91'8C8ǫW5 8Ť{渟hǁ`lMEa=r,_<L,&KD*h A6CO&T:I޿] KqP,ɭWuL=XZgߣ(`^O$g=ޮ^;Ssޚm5,~[rZ$Q G1'}+]plj ZU:c20]#*2Vt<u! SMP$[A"÷r0o2;2ެ?5=5# <7ؿ8\gP3"ٮjx-ѯ~^ϥ1FX7tNjQckk_WSv0}S%ϜHl%.F1T"(J:(vKi|LeC}E,?9#_e{EKR?\6GǗ>0X]=FΫtCk\~|K[GC>'W!M`8CyH y 6kU!^4}{QZ6OiQXs"%qzam?QmwHBJ\iʠR9##*>y=O@B_oam3֧~`'V>*ZKj6-JWZdŒKdv`o 1)|S(F%z3܊hL 1אMeHѿ#^\DCO޾z<>p2 {. 979sӨ|6w"t{ؚt(iYbzxj;C\(g{zZ5NZT~-Pݚ_{oJ {[6HP +cՉ@U`I_P2kx}+3@W:t_vvT橿б5۝ϞL?^JJ'֕gcċJ%uao\} 5gĪЏ밄 +. EPaɵ RHJb->\ ;f#L:BY6QVUཿ=`0A _~?a׿E˯~_O?_:Pqi::d 됟AJy JUJCdzB?9}nRTDXI]G;c&  +9Ў'dׂه(RaM ͍*W|Oѣ>("@鑔a/-?q\׭R.;ߛ设Uxf =PP5Q`O`_'%\a5F3ƣn+:cC;[٨ :ϥT|lv~~#:Dϼ|J+ +- kH^.Ld/?lV>K%wW_?SjY;Z?lѺ/BM!`"AGkl**ŋ sE;Ǐo>bH"Qww%^l6vbߎt?uըsu@F)Z 䅒(Ȯ6T[TwIP;;HnN@c_AeTw8J@uʽ(͞fOǣ[bLSU jQ]rkCشmHfh7xG_4.T0/ں[&Bk?0Pe;Ȓ(>\dԷl+Ŀ;;h2>@ +F٩hҨ^ L5۵메5wDwͤU~"jWѮQ׼Ro.N +<)TWzM+GEY*n* +gϯis\_K@ "m,bOQwRkєuZ=:ؤ[VAM7S&St2TAӭf-U[%u?7u:ґ u. +wo G)mð&}W",tW(S2ˈH*Xf XRb+tߍSg3/I/l7Ohz[ ']gdv!luZ0tjjobz[ςƪZelޮ2jbq=+GuT7^cѱQP0!ҭCA]QW~,Dle/DouV6ܹy.k8NDa,HG=(҆D7lOmPޕ?|]Vk_"r{4]! +2"{eh +7<~Oc[c2WAOa}.0Uy\zgpǣۢrǂp~ޫ|PJP!2؉~FdZюu3(8Y#DkXjẳS5]x;X8:`]0\*L?b'EzTzBu+˽xj*#߈rJR}MEHe4k"pkQN>I1%U](P";X}1˼ , ^&nXvH>y~?}Z/4p`C=@}H:w<;*P +Sv5f̚xZLԶ?Szv[jq l:*SkDc;N+JyE7>wȀdSn[?WFz:H:/Rjex$6:[/{@/_O&ulMǔۘ@̠݃ApH-oVv8Q6hQTּfb'3<z: +B aR3׭.= +vq8WE3kkL⬟?83ƇyzxK\i %_ +륦= (A#Wsp+oO\ +@c;㬂+2D|n%a%kƕ*ŢΎow] NUn६qEPM391Q๕*D#<<š$>' +lO.#p^I Nb7}% r0%zPP80IrbO'WY:Aۇ+OZ&$cDO uy<5h:e5h\TZj ʣ%\ +^Nw-o1 Jh)!@{s  vh"@Xam2p\D֏ vEC4/g7"l!EӜ \C DY\#ev.*IG4?Ս=E7ujסxaB^7tY7/10#@nG*7~?=j ƕqu(σƆ;^8p%xքψL>utQ9MTE wݼ +:Y1QZ2ܱ5kDzb|ø~5;Vn3dL}ݽ6@!;bЌe')Oa*1*ȞN- ɤ4+?mi9{ WJG~y qm yBڀPCeN4UwUC{ݰH#iN|+A \8UO"62Ls4@-UVr֫rBtyޑ؊r+o8s)S}K%q"\/Ucޮ)2 as>/[ZXV9ye'| K 3m=p<ͩb{`n?E11#|`inlEC*،y~?VLo'r+[Y[ꂱF<;"F*J|!*hk%wZA`+ koӻ{&J5?|mľ}Wg=LLZcҠ\,0=D$( a?gTPscdPtθθQn0!K^co氭%Ƌ=6m +6"VYdHӖ};=5޿rTe&27A<֩*ZG%3]s4}IZ +o=8aӺHG&LgFFl|#8,/^bv"' oz-F"aNܓQ(sotQs5,p 0_Hh~I=;lWUQc.+|!гFpG*H+U¸LHew ~pK],Z/d  e;#\EE&+1k]sbb_Tew fz| Z/QxԌL5 SDmΙN`aeA"+*&є +UoR>#J7R.,SyGy +W(o ZW F^ C jᡭI҆W_=v-Eir؟W6ZiXnᄃ=8F-b sd^ $Pz˩QؚN+hA3nSCylx€'6dρ9@0:q{n'[?\řVx9_% +s^_BrH9C_+MO{wdiei=&k4qr|SefA^u -m3uD&"<לcw~yFŰ_ȟ#~w=[6PwtSrc)ilDCpVm~ZW캲*5BrCW|KNnZ*l1g}:0O-|?@;3VұR(qp~"~˧TpN wjk =J5'uLଏ3MYI1ƿlFlzOPy1?DoI+hQ7{HM`#4l[χJrPvANG)cD(OR#DX'e^q\O+Ϝ!"[ÃB߸zldla-fY-Y+6i(HcV(COH3*@i\.M/1nVd+ATMrJ+][rFBŦ]߇o5FPuvRhC'*$-[m)k[a%?SkGpX[y 7vJǰR?O{o:5<[".ֲ|m Qͳ)?fkp1kp:~ +|e~P}Xw|&U&~GOmϕBMCt.,Ԟo"CF~bWODs#ˉTtɱ8T +a݄Qx3Di7㊲Q#DL>*3WEA Vx8VYRbjN}gK +#F0y&b +'yylj 6ㅰL Ea̿^aNhW-f!%bn& d-~8 /`T' +~.ܲ)DIs.] +Me*+G#CV|K>hO?9$a 4@c ׈ kq{|nmmHlвJT m@=-T9;#xi5u,+>2)O$mlX"(JvERl5W$DL5h*Kµa#V٩A`DX,2=y8g(NwtҽLF%ĄIҙP/&j)FuinoK=*2 +;D_aC Gׄ #h'|; j mKS(*>Jl kk$LFD:] +GTl';x.qx >wUA$ )}&)J9x"(w"`g*sВE=C=1sG#)*lIM^) Q쓡Y{h=(Α ߩ;to9tTeE}}t~"9ܔILq'%gKcco]yg0T )_ ǍuXͱ6"ef;c gw;`|d-G/Q8{ϐ<,s|<7x7kf|,kh5ߺ ̋RBJ`yӯ2Gyy2{S$֦\ =f{u`NKWAQ7Z{>u@ٔRG Zq,E>Cb?s [m$GqR5=fJtxW"I')ëqU7uOWNZ猆-_qwOmGԿ NCFќQ LJ ?OTiz_KdqRf&p?"/1= gғel\-։Ty$'i(ߏ^tǞavf]3 +"&P!9'LF,)1RkNؗ3 +"-a^ L +5bxk/G6_puP!O_3Sc+3 +Wޑ#&eͰD籵A#Mګך -q&FtK$!;~E-꟰0*r"q e9<C]C@0++ 5 oץSiv58i +H"H{f}}lCһºNP%2X ۰1+֧bf) V-3*d8d>[ffuY>m2}j5Da슒% F0C</g8\>!;;qGۈz)fV +/"#)πd;"vbMiWX`CnPCϺxAozjfL%HVC 8{,pHIE| ͿÝJf*McuV.l ,eShcWGz(r+м hc ҴGy=tyV֬KjnUD#6h$chns/~32"x!YyQS@bڡץ,R2i|p[v橕mϥ@ .;<4aԝ'38 +Z߰(b-Q7B冝D;71 3n vTL!ȡ1Roz<(.GsWq M@ng2TWjߗu)f_r|lp)b ?_kЪ;֧L2BuZzI~D^5IjxwMk*0_U^ާ +.c* `ÚҦ eO)azѭ0쁀၎g@"~#A+a:bቬxC8EV<퓾Eۺ526?*i(y]UC4+@Q2A Yᖧb[s_{_΢٨`1DeN#6F8"c4}%K)\*'qo|w_>4zk-wrjtIqfIq]Mߗ_RHun&M1#> +L ߕ|uuf埣St8FX +ts:wPwE[1쁒)TؗNT$UoTdS &=:Z&I~t#?d9xrG2EBk =̣KA{܏-ZE3Hp tͤe[8tM bdw8|ɌQ?4;=C@H4LRtUc4P?îq['c v Suۅ݀=nnK(ӲbS -G;%o_hsu8s{:^8XB֑Hb]LP7<iԨׯoZDJq?}ؠ*A +KQ :"=/G%*T XMWq#"zi|FK@xk?v:m!`eN3v+E]ps)q=vSOc)5x0z>-tp,Α6Jx)~W2HJ@R.&SԹ<4Yo kNk_L c7v3L9dV'S+*\Dihs:[=i|D<~iÚ4/OdOSsone)y|zm]N/ vCyC5x oBR9uCV؂uC}/pLTHυDW#BND9Uu6#BԷr5_FLn3*b.T +tq}W6mRz=GZ|ZH 6'Ŀ +Le5n9wNde}]oP#l_>1Ǔw9P}dr_8 +z /mZ gk|>ԦnYY1\WսXhE73C_LE~禤**jhiA:+{_B~hg Vu-kvcz="c;v}`/5#h>5:6@(Kvx@X{:8[%%̡⯇2hB7oFb`(W\AbSD<`M(:bܥog邺p;\ H_.#&P" +&0w'$g + Y{F +C+a/L)%a) >k9+ ++=$D(RaoPRZYS J#8Y`F*qEfM} ggzAn*TS;l6U7 8ƾvsה!A1ERxȮݴ)VߴQX~ĩt&P%եzzuHOE`|NEGr";Af[KM XsS,m|ĻS^BYtg>{X~>1wLo1n@%r4LyǛM0ޜԯ2%< )3 <˜Q+;AMD׌8&#[_!(> %Gv-Ly3Ű|إ^טMQ9_~*(LXG PX s98Mo09;m>i/#^asav3W*k캄cxp .y+GzewB0^XrM-KdfٻM714HXh5}Ӝ[C=.B:i\[2lm[ {4*Q}`浠pCM{en`L!y)C71 +_tRi u 'YӅ@S)lu~]Iyfbek +c7۶GsA'ۖ5\`tU-j|h\FU |?Au$8%Ab]3`sa6*|}߁q |!y ȡY6(k,(^CblAF}uzWk=-bOivD?k9AUli?"cƙpL[Z=Ukh$$K$_7F-Dz0X{BŤFZl{>$0C,l2ac;+~dz/wizwB63tF.y=o`MsVḃP&r)SB&l@^tTI1](A?0DP$ZAFX.$7 R |f$P,%rG1zi.JCOZ0(ۦChlD@(EQDfq9T+c-CCa !4{eHG܃ ^&=z2z.Bmߒ0C%t&] OߵKL%k P2B)'BQ {3hXPIΆ3.&Vm+R12 |]bO=1"IJK2ي渧t,lfh]pՇxs~-kH}6%4Lkj߱15JUU_(lQg-{GqH? V +J?m*u|PZG% 6 Yw@|W"s|)EÆ*8PPMXu/ +1il +"F{ k2B1֟{7&cA&ƵLfJrkŅuIAG`!gV_Qvb&`@{].$R، bЉPfwbLy3xzzX2[i-/%tBZ[e0"< \ߩ4SDezĬ_ +n{h wR%;w{b2%=TЂsQyXL[NhO R /C CoEVqĦ)Aw޸}ZV)$s0|VR<)v#5)뺲ZuTے3bBy/|0mGFˢr:GjtU+qϖL;7{ .ږARC6ƎuTCn|_KênG<}/yQv(roWg bt~95=a#f&M$]%fj\+4vJKyr#yzdN. ϷoBɦlNͧL`Txl}mµґM'_g> }bnN%뼗xo-xTf5Uv#zf{|6A߬Da +Kk.SF~[ө mkJ8G!3YU) . TwZ(<'adAi',[ШBx }_ #.g-ie+'jUpF͎T/6XzkΒ!f +rԼ"sGDQItTX{[񬶝|U?[ITG/2D6ma7p-Vb zDb:%3fMf +]>xj* ޲זbH\TT[Ft`+m#sCR, zN䦒~]e ݪÊHg8V̐t+<A DY~@V8u Ӯ%iDKӱVJ5Ue~p(ѫM{YZ\VZfl\qhqu DKDK A\aq[՚ǯk{p%6#Z+xYE:C&6PCUxx/G+NFί M83hsěJ'{ +kᘒ:t,A7|:aVJo/).̿,GgD0y1FѿvlqܾV z=!p^r&LwGyQS@N@ri"AzZ(:n`C/KJd./e/44xۼyɖr].kHS2't˷^`p}N뎏;-KrHmng +.P#d5$ʥehk ,Y֪8u֮>Wu9le׳D,XoS (i{@r;B†ٜ_nFOK wRI +*5RP))&‡" x,V9s^ۆlǕnvp!"6Ab>}* yt$J,-$fG4_~wm:ūjsȹ1:kF0tJ)PzxxE1AyU =g`Wgo%$>#r)@7#aUѮ0eˈj5ψ9vcϥ>cY kttI#Fe@dPY^Sc%"~g[-έ;utmi!Hh3`Hpe|q,JC!%[s|FcrA5_[}ƴ3҅72˫n%q^@݃77Q<9Ki|V +v\EPp8$,ZZ3ANJwܩóE_ݝxN|);R21Iziq1L\[iE3"1_{rMwb!wFZ8C<v.Q&ywψ]/ + Y լy+ɑk`%aD.s5)adN +vD:E?g|_KKv񕽲;SJhk +w&k@ }`Ie!45딻|UEzf)`)v$"Y `T]wfƴ ޻,[{ʖ_?.T!!p7|ۯe$^WJ[q; h[zp-TϨ'K1frgaRVd3*3JV 3abKA>a"tʉڕm,3|0B8슨WOy$<} +;&Lvq?f"67Vy`ܿR)"lZ"] L@ADm׳[=l ;4Rt  +}]Jg3dSTL$B=_SGpG:!>PC9ᯰ5H !Qo[(89y'.x?ۮ7XġeWj^?mD-0/ A=PHQqh )Bx. 0p]PA:7#fQ>]USɷ^z fRp[4 V82A_yQ/M񶈸 +3fWމs!wN?jU*W!ZtkvJĥ" +5f5kEpfPYhAI`u`pʮEMC ; +~!ϭnN_I{5=.L-lr\Ͷ< n}- ieö9`@vQ5X+r}Х|gd|b^O=`z+N-Vca=t%ߗfzpBQ@ h}H!y&U~y}nWgOLczf0]-9)+ہ3xPOhh)sMS}5Y̨nϟȷD*G܃^ꈆv@nu"9 -iZTN)y66b>#Yi6*aT۩SZU{9{!DB_U2!FANoփG[mV">ge(q  OG#V[,kݯ@pK&dxf:}o7 > \ GEuJT~0~N?ޕ|tĂ3 +aKKo]թ) +_9?Eb|ҳm ȫ%_l +"1HMP(ĕ؉<2OǕN/S2߼RImȝYFgDYJhS}"I}τ^K-kQ+D^E0j6@sJ,11 aqq5XOT era_n߷Wwrw'̶[@iX,?|b=t7q;79[\DFD5~~mr?m9ls5e5P#w.i5Ct_E 1c.׾@~ɦV +ֿʮBZ9]bkYJG;%i|Vb#\1ЬrWlyV +} #+c2"4 k.&*G gl۔߅z&4Lukg(65Z:꿮?ZL-a+-]u_UFCuj5Ŋ8b Q8k }m C(^'Ʒ‚@ GC.2Pa($Gf{TPs-?8V9sc>V+]Mo~ ƀDkس_k =t6X!+7uЏ\lDi׃Ä$/˷&o4s?c꙰s7z +a Dp}e/@CpʬT6ɞ'4y`EF,eC"mNwl*<,.:4-k{Ud?;k+S6klu$~8}a Jb0Im|X| w5% 7P JG}rcn`ʉ<): ,f~FJ_(cΆi)>ڱJ/ю +F(f*T @`"Ʒuwz]۶U}uux@8v@Y6nQ? p|/ș +v>/or=%3\ZzTɼ3\zZj=Y{avH*kϞzPi +ti0"Ԏƞ헀XRK}kL߉{pLޟ' 4楟:H@z>4\nJ_de[9\bt϶Z-9I_>֥y֊,k"V;F"7 [}^1| qʦ2ܢ+ +ɉX"I,x SalrWd#YΜ9Q(XHmDKEQm#97+ժy*R_N| pD[TŸw36VC۲w1)7^3G}nbrt 6ֻnk&lGD_RH2V + 3r*DpEs*0gK[~qد\N<} +ڦQ' bmI+qZ=isl'uc܈GV= Z$*_6ۚض2x +BaxÉV.6q +<\Pn):xc }pvlA6Nt\_ eQթ ڝşl_[ 2Q)Sg%̲H^[u+(>!pP&s KIQEnkԍ"鳍.H*K/XFo4R-*#QdquY~8S;Zȁދֶuk]-W[' Q@6D`g.V$0J}`2..(]`cSyu6v-ܛ)daa]٨PKP#5yҟMXYzgF@X8?tT<]7{ht}ӵ^GJ#C[;;Ϲ/ʷ58g+%KI#o;ؖNR0[[|4k*0-WŌjJAD!ke +IcHn驭 5| d%k62F"R ey'УTScY +} $G%~NJ J$-[XFrEqɭ-6ݽ+!/+`Ka + v $( +r~Y0wJ_Oy$G?_??Ͽ?_?q}b_???.!B?|F}@tco #R{' ~QE?EAw $IšA /G &=B~]Ct1;0"(WN(("Euܑ`^)H7S*_p"fgzp'@n_]H{l|ل4WE[k|Jπ؜#q9LxYXBUCFR\~-fFtxkQg"2-jY숕A)n_ +4OPzXr(3zA`lo9 y&њu̔A5*Ff#[&ԘyGd&b*#`^:ޯA(MzU[ -zCXʱEaeĞhC9W#Wb[<Q|.cF3LNGuR?c_0UqQVԭuGIyT[&0DrV֜^wPl_YA:ǡy&bN"!##Z@+@iiAc8u`2g<:pUu| t<X!zBU`+C[ûCAasɗC>6%~EՔI<(?ĸ-!Cďc#j)V/%*kHA_{z^^q쀂36t7ޙ!03K6Yh. + + hQTO" #$UDAuB +ED0G #phZvިvL8A!'- ">KJ.P[FO=3#nǐvNP +D6]˙k Xt¬@0OO +#+EYڢA.s$v.s|aHҙnZQ'[A>8/gh_iRXҒ1Oq +B6k-> |C[|5/4D3ɏ uS8;O}ƊjDPHZ]LBʠc\$젗J54vy& 4\:tN +U48>X@&2˷ѩ_9!p(# +v%D^q4dn^ԍ;7/RɊ25&C9%1FٓIarpA3ؿ46!U<j&ۅ(Iz(tLg|D8Ԝ̭o@\j"XlޤN݅'۪kg .LFeF}:C{I! vaVطVcD@R&RuRk=Cj}ճ [ IF/vf @ ;0!ö2xWMJ.N9g+t_?/ 3A_M-/%,uJ^eEPa"m菈\N @8I&L1"0[$? +iM #Ռ~O:zDϮY6q;"u u[6R%b2!!A,TrJxgN?uV~yd"tW3W q=f^T&|ԜILFXۚb.xtH"tz XQP_c/i^Z;W02TVNqSMv]l}d'QɞI|#3j!*t~$!k劉TU۩J02^,8jd?$ #4G9pYXS{{î(&xJy"`1:sϲ֦טҀx +OۯN?7R/ψ7$Œq*xD  W6H'g}ewl!n3bnQtҥ"g~ Mmu"an{첿5-,lHPȕw?PO+1%hI0b9$ނ_"\"<t`yG^" 7>wψA~~_t$8~ +`qiiyT]]>en_RCDI\MÁ *?=k,9kbpz~ ZWLVwE9!k=&~ ]Sq|L ψ +k]X%`g熛7$Y}a 1L ۨRyBhdc%6ψc2c܈>|ބs y__\nіXEν,GHɁ|m #N-I_Сe8@V HiZp%8>"%[SMi"g2E֫/-dN,0rR(B&("&%%\9q_5~ gNVq4X?n ':UTLCVt1كE+{ wJ{XfքvۍY)SMwY'_]uz0+lOGmB8(И=5."Xr!9} U/Pב 1#[Po!vAfEm5π"?ԲCw@/^ G:0o!@z,YU֕O--˟9yYE[ +z֮|]r'ŰqڜAnKWӞ *ݲ=࡮8uB=ϯInE{`~wt}ݟ% #]#t,Jj|+B_bj,2NuEnsA*2^KOGtW}bۉ#FqMY}gBV|J3cv/W,31!8m)oឱ0d`އ̟&]Sy]پ`q !py>x<><-ylA +u+ƞ yyD`؏r:)Tl!k! +0a#ןlxBqy`%op`hXOeOBRGW#%?T"n4*8jTeKf=y|#댚@uZɀNWeritiYͫhbToL,[`@xtnpg)jWaLiI|*9 [ZHA[DW~j{"&׹pdM;ޫ8aFq9SxO +] 'D2>#:YB?e{kRD4 ey*>UwAWT{Ǿg[̃3F9S)U G,vg|W\ՙ*ҭąL&tiK筑sW cpޛ)b tAN "#kai[R^Ea +X~pNr*9}+VLcΜ| +揷ߺKVQ@A4jth3=Q*[H}ÊF;n :k[CPN{%@+rYr:Ũ{UsW +=@gJ\[,u+ ++%wW{̯wr^N1~:}eܫG |/M/oag3gүe/|=4\N' +e0B<'SH?kr#?>"TZ| '3H;Xl8Cا%kE +ma3#uJ8w‚hq-dFmgWy3[瓿E[2y Doy19՛GC FE +q^L{Afgu>ū쮟gݼ‹ BlHL9Tǭ!jzWuŁr + Cԧ#[:.H = +1Q`ͪubXxSV42xL9NjۆEWz)tXKFV87 2" ܰS\3KLҿ*{qgLIzykhTwk 7%V\X"nU>cЈ2g(\X;T`4o ޭf1CƈN{[#8#n,4NaZ*3ñObW֦$·Y ]s/)s?7)"+LK %憲I5 + {{Ĕ灺\ P'qo=5 Z|7 ++'7PDtkA`x܈Ft}&&D +o"([ާg~V.=nhD&AةoS,nwZbZwˣX2@P<͹1P^eGZi Eckg LUdWf07 +@| sTu a>PA5t'*DՄ2P|^%yiPד,m9K@OSgVΪzQ&g8!iEڌ$LXIucKY_d ؐjcza +tA!3J`[9GTvjbJ#^̈:+o,AT(5 '&~"%|u;ܮ݁@‘ + H>A#Bxx -o]2? D\LQNZܤK!k >^[N8oghH\=5{J%ua 12H"32[ӿ[Ӓ.3?BeDiBR%̦dEΓ9/VF@3쯟 UB+fG ^WK׸]gPoMv-!۫O7`GthSQMt&?=Z{hC4 :a`Rl@@[EHqψxgP*י̰5ZAy)QG2`zh(aCHhY#o%=8@wznAw0a +uww=R9V! HL@Lw(qtT4Y=Y^߈/P35 ( ~Fó<|MZaQv8 iٶ9&,))!t\Zz#fwnԒMn'^"M BZ`&яR=V4z'˕8RFoLF0%`u.Y_$v0yb9w%) 嶰# ;wjJEc tl<~mHoYr[6:?=HBC&߲ ƍOzۅ_8S7O+}^6(㬖ȤZO +ڀ諆-±`{#VNϿ j[͹o-2{,σvc߷ևgP9I3W0hߔ~(w@jHD#_ǎztJ +#L@3c?ŰsaVxh P9{L!2zuWE?86C1烟<qu 'yky@I4@d\cr C.}/1~^f{f[3E\2;c7(xq;eMY3 b,2^S +b>4q,AOAc3ĕ=9.zjqFfYr*E%.q7iݕN9!!cU䀉߈I9p=PFK],[Cժr6X?4|aC]^0rXG][Q~)ܒT|-Ѫ@w27_Y]Ǒ-|#ͨ~ʗC02t6&a^Aӱ9 =V 23亹t}O/m[:aWەf tNgTĖs3PR̮@@49&MI6T_r#n5XƆ@}YaüS٥gT"No0֜3U!ˆd#ouAk%;Eׯf)b4 07Uz=p ]1fL}7dL͗TZCb=pt<ÄC1N yA4Y_Y ilR[C1j$y-5}[ՌY;Z]w<;FSX)a۶A]+$ LEPM-x^# zzph:_ }h:dn-q}kQSmy4br!ugU,V>1ωЙ+=UTsH"$5'60WOT \9[XK]fZ7ضÝ˽S^ˁTbiR{NeXQFiJ!=Ocqز\!&ҵ9#ξkʓARv#͡=ʣ7\l +y@ z]P,dflc^RMw;B[~z!Ug:q)DRMA66E#֯KaN^KTgps-^ 8pwC4IDcnMƹ| ^Z)1n_O[ClBG挅.h'-=d_## +47]9*(!X(ueTe'*zf%DZ|*M.YpԪ3pVS,f= |_tSYhAeدl]mi!Ƨ u ۈ/oNMTV#aRP=hyy@V-V +5->!Zqc̟YD ǁRf|Y5[>%X"ʖ + D &q%yy/hpz GDLBtRՂ"p"^գtZ+ςv'm>` Sj"֍eM>tr~cR}J|`;@/ llW_PB_:#\>M`PR2ɐzEl-n5fE2r[FbHTEMa:T=FﯲŕRF\CBi^r)cZF85qT$D iJ渂, ȭ4FO;8us6"yCЌP֡+Mj ="OX,`{ + qMC3%Z]0{F +`=kXDT2/|J_L1D=T2\X|aOB[^ټІ%B\wBO@\J; +)n6jdR]_ۡZ+U333TGݝ)㺪U È/@$W\2+AO+uaVDZr0hsD*F}!mm53;m BD5A%?Fp+Z8Qr {EDb7Kߊ jr^lmu 4 E# + o!ĜwQYULŵlN#^7ql5ʺ\u=` p^D3Ub +o~a}-[ֺx7JߔOAokF.!.'\c٭l!TXbS]:)'f@Mhbp}tmO0ۡĵͅဵ>Cn5Z~ԎcݛnY+=)vPPejSJK/32- l7!n3Bc PbCfLh1󃶚4a_,h9L<^D`Hz_*CRςv}DXq,[뿣#FZ^B¼Jd }G<II5ƙgAeA:kܓ?[+B+9k"AqQ%$<:؊:X9Qhvmc#+?偡y*o4D nӘ;+lJnI^f+Fghto+J浇T@n7:2M>9߅^ +'{.-C|񏴿3&Y)L]%8^N0&\@oqe]? Ⱦ#&@&?d<϶E7p#Pέxnr銨pPuTT•oDf%ͶE IDa,|)N=4 h3e Ns*&ǞnD8}*f]Ju%{#4=5Iέy#/[@Mt~nM(% cISQK!KAmz7DI#3)6{s%ֿke'1aTH 262V&)鍶 _S Ý(&:w:k*3 Cz1 ? +š/velF-\Qwk`,0Bpi&}΅d~scp!BY|s.Ǔ帼0nOIup/^)b#',"L Nas +:5n +w{`)v dH:n;ϗ5A5.+>ҩ,ʅowoYkjp$x!1Ҵ5^;E(k z0goj&t]t=5a +r^G˧Ia{+@# /=QVQw0H-t[.[M=0J{#4 +ؼ *&#^ xt@%6i;0DG1T 7%Ⱦ_}3l>^ ԧ&|#S-56Ϫ.V(#(L01BE(dĵD}ug]}ױuWK0A +s{ )@?ePSrV0q"W1Rm'fPz6UbȈrOɑ13?VpsgVC@WN}7,W`ia[q +ϙR9#kY?OU4t`Gdn,}"kO8DUāh*p>1a@e[;g׃Aj+&`>ϱҰ ^U+u|xu1Ȁ5tj۪%Pq@c^xk-ʇf\xbo?CN}] 64/bBt*i +~BN?̫DdC+oe7 $ ~_?V;Mehx\" +:dmX塸\]k K~+"h #7]#zLV*W?Gœ_ni?2kB(Y% ,n^T=@j*>VP7uzS\(kuͦF+%Ly#9<]C o iː"GRʼnu7* DǞ @ŽGKZ GzXZB{H~͹Ƥ'Mf#,3gLFՈ,/:ٕNg B5WrՒg_lKb6?* Hd< +$ڐ́HN*R=Be֗R9 +)HQv+ =hc(.W ScȩjG0crϩ|ni^V +5*d|aPΤju#'qd$֠<[X%AWXkXv57o9:ptz[=m8;V* +W]<ݠr}7p?~Ůq +ƹ'y"BDdXS5kV?ʦ<+*ZN;U+sq-@/XŰ Nj§ʺ'2n1)Evcj3I=^vF.!9E='q^4:h̢_gx28xXz<h}JgSgBNPym @h|1~mF-9u^QIJBbn1L :ِ +@sά'l}n!Dm6pUU߻v*ZTè -.}thLqê5 0PDp|BIpjw+:ż>d(RГ 5; ixDo|?bD2d,&XҐ@Wv!|%[TE=[1:J(E^3ǪBf#HJgS|{ +$AB#ĵH-qCG_ԝVzIu3W6 R2+&})lsv#|C+oV hX˗W]kO)n8c6wh¶ 20x@`UhQ!T+)Y'm8!w" WA0*U*^آ}N)j +{:Ի}AVnS>N9q xzPcx&*QeE ^!CMer#yF. ؕlmM'$0 ,0)ԮI(5 W8@Cv7Y#4J}/DQe_]- +A|?p!Jbex +u3P:Л\[3y^57L"Fh\{a)^ Ӈhf+E8ŽPx["j([4^Toxd6t +teF /8ҋ˳o)Lk- `5R׫=k4@8JzpJeљ!/Q bG[%ÿ\ J8b33r OA*"ΗwIҭ*)oyK @֟ ƘNV~tDVl6\$CSKQg ^)}2n +%@VfLix^$̐զ{)%T?:$:;xf#Rtj:+9 ?Τ\iD/ GayD32=294FD;Di {l9 O1+ f@@JIh9p~,Tʊ}3t9it[OEzF|ã9EF0JFYݔޥ+ R 9-&Ry$jvRjE}~l]K۠12LmX@\j[\GByTaTlZVq+Qqxp/xn5\)@eX#[(I@ jO,2@{g T`8 +E9Ŋ${( M w@/~*x׶rM/E Nd*n;k*V0q3zK#uh-Rd@m#*;u +NDaLN]25gp4tZD3^d7֒msa!/`P_h[y?oo7=u*nG gm`:]+Ώ(y+ch0 2{,^3dbVwق7ʬ"&d!9k5G]䭧>꛸,xͽ+lLzoc6 +hWFcK!_b}6GydhU +D Q-3T{dÌnM@HEVD=ޭk+/qdAUXXYVcy#rȦ b8-W*˪.kO1iiL^f ;Ԏҳ+6'/}+A ܹid~Fhɴ+^\]*}- :zr| ;ysi +4&$<;q#IȺOZHFliӕ/d>6+DGH;mQanBӸ6,5Q<ǵA?].!6mK>0~KE%cK6fH]{xGRT  `l(c> +u> xy- +QPQ AiR~ yK Xqt6PXu|[`6P@a#=@!ǟN4i ^Esl7Z$@+7A:#Nu Ua]vkqN6ȫ#3+kكWf)/D($k]g?>< ?lN4iF=d!` 9L{֤wRZT[GEi]'b8%U^߯? N?k`OV_ϝuE**$Ō7}hNyAr@%NjsLC3"gZDhUB +Y~AKI-zNaʊ !1@m,,J~:` DZ=#)HeG-"jnu!`IEU75.hDCg%ն5s BiqةHHeLJ9ҕ^^Sbo9jo˜vnvFG3Z?%zg>8y)Op;M|97m@֑ A?zX/m +K+4 % +f( =)uF)`-MŪrTӱ a ECsPgPiUh&RU׋0 +L)pE9DARtmh&jj){"-?eЁ(₊ҥH;qkV7`iR|#wvtG#L-MթFԿ>S +,f )M%(R+HOtxιN\| k#;D|P4t@V]ԭ!ĊE%=n8r.^.5 ##״E(QVUhA\;xqAL֎/[l +ic":4L3ʧ?a%*y;^L˚k\ BVT8ψ??Õ(@;SFuřJ2 +wT4TZUTY;ֺO>f<3nbBGdK0ׄ,'35y\ ܌О +S$G\R >4g[;Y?Oc&?;W@g9 I[%(̐lW$~N%?Dl*myvlQ) 285 \3b +`~x|?8 ;UDX5l~}~Y5sf@kYΟdDž_S$лL#(.ZQ~``C4-f?=%Hդ[vD+Bz{HsSGx{RZ.px 䦣~[ 0^ |_3(B9ZQ+B[`;cq6#]gQ#a}`^p'jp>-P"NMWD)JkIUN .c{TQ ,^z LodhNۥ&pP8J(0՟낟Fbs|)E-tnw\<xpmjcn{Vb`kGǦ=iD1ho3#6b܆VD@?7m.N,;^ +@˭?ITӶ5اm7 +z_NjiFeˆ +qB$oϱƭ:gٖ]Y"jqDhk k#y6BI0A1mHv/ T,:cЙO.$b^{ZA=?`TP }'=Έp"0ѰI O~ VQƯHIf9Ʃ(83s+tXCmu(/kL>9&2Ϙp-{VY☲= DDeQjK^8hl=k <|'pIQ]jedD-m[%c_T/bIѸKn~'%笆1u+#q[zH B0Q)6#I8_xJk۽-?%R(5JusAb8{x^=1"fbdcM%1`yF\*W&Tj*(D@.Lg}tAH#l" F3^7RD`dC-v\hqTqd!EUГ&jM*Sz y}q;z +C +Gʩ2ԡy#gľgtG îGJ$rM^3g<'ݹ,`f |+J |O7yF `jNֶ:uZ7}iJl ]*"fl>]V=b;=&jR0HgľY%8a3@) R#) Ui"L4~m+,21Z rˀFj$霂*F' +n~QQUld{<<-='◙[ѺY?SJ-&Mj@^04w0i@:{5JxiȗlD?Ԝ;&=}Q$bt([z摕ݻ}"~?DN+b{}:S}MpĘWZIՐoń[>9L̚0}TєmGXZJ'QCbU`>UfEN}S%ir"ntj~eYfCʷJc 3*p`Qcͳ؊ׯ&+CW9 kK|#"}`? G֝gbd}$΍QSwgĖo}~ck1:1csk# 9izk5^&\PTPNn#)LvŚjVE5 Զh?xZό$ SG.87Zvg cV|:LX{}N+5+1C6e4,sp1P1ncI!ZUM`?':]b)o0*A[;2(VB}|/OK*mF?u~-(@S#l9mĀ)"w1OE`D 6D"Jt0d;b$L#ȯ%,N>B6O%+w(X)uRSI7>G xC(R0"U_]Zg-L͑kO'3L0ݽ0i~c8‹]rl<@*,s܌<-DĴ-O_ϠT&>m^{ ;OE#_F#wP+WX^NE}T3?8G8l]Z;?RTdnQLӳZ0_l?E+V6&6fEЇjRV9ʟNt9-:!}HU"z')4 luC&XgygVF7vt{@Eya`DBI~jp(|su38.1u  ". ,##Td}rOR7G^Uv$jx}lm80=gQƒmvޯ /Wz1H" ba2ơ1( "b}) X`r"[+ll2#C?F1=s9-aΐσ]yu}p30;#"-t߳5XQkh aODz58 ܦ9@lHԍ>#2-=75F@#ӏk|?깑 f͐iMMKiH%"#DW.gp؝SqK =-+dOנV1qJLgב 'aH{aKwJƶ &?&š vb+ */ch +?0QVDbwu=6FoV]jQ6 ҃μ)ZM#_}k>4k}m_)@svģ<ߢ@ C4 VK#j)Fݡ=.0 |;7n-8>t{TE5Q{&J/^Nۅ1%. +"uS + e&X.n){o#RpƈNbQbE jFDT-:PI"9' d:}bjOg뵱i22gt_^lEm<7S^?E#}]36'NʏdL)|碓^o?"sFL"‡(FQ`4IkiMGQ-[0|¤Kڟ@\nSnD&5y̌8իm=CD։SȎX5:m٧ Õ-}nNPe> \:\vNB(a\Ark[UW3ޗ"|{sF)X +pZAKTljG^q 9!ԉCue3`.u޵o3J^"r'qKC̟S}!3\߈ @tPv8Qv%#b&DWBDfa4<8=q zg+7o_%95gk7a+犦n=#ӹpx3~EŘ9lK;o'o:tמ68_enaLCS:/n^I֙c4W:W0_y"- +ql!aD/>lFl92~kq9(Kz4xϮk Oj86Uwצ 31F%cYwz1g0˯ jpmphC_'/bx%n9-[EzA]o݄twOQ\6[mP&jJ2ڨ +. +TbohƮ[B4*2u#;&B*#S4h3KR9mBW agDN5|us*0검tyoZET} @@3A ߹R@3%]kjT3H<#ԕ-ik?6h}3B[d&bF%+˩$2s9Q\!G".u3™Df"bfq}0z~Y's]6Ja6]+jkzCqekZﱔcʈx^Tn7ݕ`(aׁ=ƶy[f#D_b+KX#0a { >Ųh 8jC9F9<=dUumUվAg=B !9b\aܟZ ,㜧bOOw_Я z +endstream endobj 105 0 obj <>stream +ȵgH#?^jTi?( 8[8 rH[+WsfT`ڈxp)/QncID*2A;g iӡq%uLo1V/2:-Y +zScFEԓ}4M,jqZfd)mpE_?‚]ʣ!|J˦kׯiU;[a-Dxbݝ ֝ yÇNqc@L0fPn={S608@zYQÈP=}ɦQq??=:I'[f?',xF)vHZ9q臗D"0Z;Os,6(:OE_Vd:̗MGx-{s}"{^ΰOÁ j<ڠ.j4 +D!2kYle lN tl +4!#1k" g[y< DW6zaR*vLi~)HωO~&lJ`"ު"k}7cqGƃec"H+f2nN^gQuzqxZ`>Teޘ*+l&!gbuf[Z7F\&XsWp#4f7>9jm)Cĭ|oFByu&+cpXڦ?ޙ9Ӡso^`hgr!A~^Lk ƈ˃<ԇ3Sk!^n 7 ?9,ʴw 0_uNum>ElCY*bx~%cq{9%,?X?Ǥ Qc+g_\ظ~SDVi:RM*)?Rl5BxxvkENua$1u# w +@i׆?#rv˚]בj%N*4 J O>E>`ћ&Z]XTi(#~^&V*=vm{ڝcP&y>,IE#!D+J:#I_ +sT1%Q鑲)/[œVľdz+u;\sX:e ָ0Z&`\jQ7zX"'^_4n?xOnz  +}2RFN>*+@e:;ETx '"}Nj֍GNJ>G;=^XO8&[.@MD`gEVkǟL4H}:Bd9=LbwB[Zа"`ΨҀȘTH#Kňdʴ%~\|dp+Q@Oj;'˻>ayiO(fJ[Q*o@1Haw~}z~8$u痑 cۚN6nGxI9[{>6cZnRHfC{6(0]UPg3:Vkk(f(MCg{(y5Cp̙ŮD-c܅k:Kl$Fi<:1Ya-Ŵdj+Uh ziqQVt [R?.U->B4%d_:׵әŜO+l(Sp)(~ZϏ*ҭc|ɻ[) `ѷ%s"'%exGrzI=AktL76 +x@ٙRbg|/Vܧ*\aZsM48E9X˹Ndo?8|(n+«!jU$/kv.2GD|"1q gzNNzL +kp^l;cd _ZmlP;B+{4KeKGCTG CR%̆ +;_;zdgؽq$=808$4's"kd[mÿðR]f^J~8Tjb*% "ns*o*vEZXߺ 14KTb 38k|pv+{X/:0ZJkނp ix1AVIփH3q?#3œ>s +67h;jg5^J" +\~&gn E0kGNhAQՇEr=@4ާM ,^Qa4[Нz`[z ǜAlPO8]mtmqBW2*CuNuyuP C_䤻7=S#ˆ[8} ^  m_uMX7z*Fʶ*WIc #f"jL"i݇x0FGnHʺYC}90 +xzǕh`>fO*v8Y,׊y$@a Z9-oπ3 ^$ϰ8xQ%.DfAX ks^ : Ww}kq !Ch8:HvP@(x>YGx8ȣp 4tZA*A t&N^2}'! +\jgH`"(Бg2mZyWU*n幰Wr*Kf7cw,H0"[(=q0xgø?w+[64#HhӜۂqo46]d1(rE +A #`W3[BUC|kKDh(nsWMA\rr®R\S;ZG+ЇAAE7A[Y-,U,KLzbѝktS2XW +DTK)56S d |D-5]P0S +:0jfA}pUi/ W?;C +mHx¸?Ѹ :V =쯟hܵp3lf (mFU!72-.nuj׋VF-YZZf>O_f\@YE0ZDGn]Ml"lc_#coQk +%Bi=`3+gp(܌6ÒF5ʋbqǂhEp{2o8(QX_ai:L0H9<|鴿4r .'a[\1NV^73k3k}Gt +{4K(!N(-g1 Ҕ?D`2S{ϰ#zQc6Rc+/*)0*}0~b~'?BpG> o]7S,rIHjO nOMd 1bW5pyq%>*&)z,#R/T&f_SظTÓrI7H9jtR2}W 4!9[9Sϟ+G;Y +KC yjf\Fs 9 0SorQߔ',vN(+z=(E݌r_m8)z3%j&^ ǖǞr7&肻e,iĽ=Q%z/Y?)i&qB_b$G"Tg1!?doҪO_q-C``TF}RԙT!>=ܙ!<&}ʀ"v,i]ɹKFM$|lAWsDGy\ CkBQ3wcf@KO 7 74+w.ޤz +^TR2{Z̿맛ⲡ-IG mp,$ $bU_47i^R4V [wFnp9Tvph+@eNʁd"$]xFY7t~RIXiY᠃Lޙ1E[ r1be*⵾8scpxpl b;v588QQd %WG ʉvE=YFm8::pzUL $D^Yg!p£Numz¢sND&IMzJBjS__INU䳋n9wi#өC9z &p!Sb}2eVtO+ZQH*h;Ip +4dg6>]AA]@3~leӇD1B?M6GW8Ņ xKH$^1#\sI[=]ˢ?٧]HiO4# 4|9pyFG?pU]BKfJqY8%!(B`LwjkK-ya@eӼ j|_G?&XW8x' ea|*)QMEz)} +F%D!"5{`nV\%' e0 28^ˏ@ ZmMjBb)Z166vݑD; B jp׫j[ci5ʺС׵=M*N{<I2 |k=C$z=э`&+}Hԧ#vi4ua$@ g PPdN={ΐ [e8p\[OA=)h"YF0xžS5Z}]IOrL3{\ +Q;ҽ8̩IM]lp;%9"(eU_g!$\!gc= +#9er^S*28ϩ}Az-ctOʀfk jqoH@pYCq|e3w`"M3S8<-jޅ=e %o*q*1Q^9^-q;GqH:+#  5);`Zwb wi_{nz:ŬVD,|Kߔ[ +1>q"G1h#p^oPt(RFSQ2LI$78D2ޕ +n"wz@>58'y:묣cAxO,It)-װ)Tr9x\=gAjqn}I?lPT=s DhqdU4Ck9n/(dOnܮ~sl LэDQŒhMN(e]#a/҄g׈X`e]V]GӴz0wE0Ǖt-b +xY0aq `ODg-Ǿ[3y[DY< +qK {WQ E"U0S/\%%]P؅3sDQ +NC)b/l/|H0G1v*AHmiXP>ecbRIT(59%=mQ\y_Z~a y w)ծS$U%mSp"]9F⃵ùMڽGyvI7s*6 +ľ=uR6:"Bi &>*i@k=y+Wr{!|ky KB !JV\_A-e +xXUNE'pɹoXltL<5Rŗ e94cLQiR-9Z@(YyST%xjJ-J[=tz +,NQRę)poU9ޯʢ+](Q緰Pe#q:YXL򝒉|Oʶ t ++Ȫ煤&@=eK44BDΑޢ}$=ayw~(8a@pWZ+"jyEM7 8$b]1F<%{v)Wv=xE~.LZocS21Bn)o7OX>-ےz#cwC +7w3!mYO =8N6 8xf +KrgMh b)lGҖt&yҒQUYﳚ]!tNT +:]8l@S +"K" + (l|:AMb`\Vy '3*UHd`bTm{.gU<z@cӑwZۘ|(ăI2504W+~)&\#Ů{7@ԧUi塑dlOEw)#u*XȨoL!WE⑄!VHW5" +*t0| 6B3@ָ|nK_ ??zJtc@.sHGh'P΀E?Q ~G^G{CDnîl+L<?{+h~   @iB1PcIP\J*5{ݢ΅-IA;[XiTwN"\=9->i:a͙F=o7Hj)h1Pۧҗ$cN{cD퀷4ؽ6;o#ϫHbE >#降Θ+=OJֱOx[0$Sf+PeS6݇ty3+ַഐKF @TW[/o]V(Q43wj-{,r/VV0Fv`8!&~5H#%W"uBnZ|F|cse`L2X">,h3TCRf̡0^e 7C(WWQ{``].!Y_L-a֫էx??12r?~=-݁/S5\aɒH(:Gi=ʛ<|RtuOȌ)}˨8*cJ a+;h!ű:EX z_GoL]s ";-$fA )=5sqpHwY`^gQX`Υkmxd@ ++oȵC*RЁ}"g-q$Q:ި05ɸ״/D~nv M]DyԦaͨ3B6;aio " 4B<,aoho'VCf+$+ذ@+*kycC!aBg`7Mˌ׋25mhs΀?P (K;~d q/*5LOs3"<X_~fX?Fo.ligvi5($ߧ=Xrחⱼՠ/xGc;nJabυ/ʴg׵*L.)^ b` +Xyzr d14dK2F=~/mq~#g47$?p#{sZ4L8s!p9#~><ص6as]\j;86x!mISpwח#/ꂼHz>}t%,<{\$ | +rwı"nQEi39̾%Zx`▀6j-  H XB`حov}Y̲jHP*ͷMRuTҾ8{JKb +_ 8:_bMjOC%R lk.fM`Nw#e*?\*hOr0,  `+3IkNh?BD},ʮ6jzŻ ~x"ڷXf+ ȕvj:ס 5!IA+xNo +5K¶TBea b^|O^ uE.=({W@! +'ķ jlj +t"a"Lmc&Nںu/ʺF@Q=uQcrve /[?~R/z;PǭiGLF"FҠD \MG8|^t= ;MTͰ~T64b]zx8ZI,%9ԅGuɧ2zS(`-"ݫ붃";/"|m qT@7 +QQ(nS |XO21/+=v>Ѕe+(uN|RSݷ0Y!ESo8ؠ1Ǫ,DQ:m-xW~yX%@# ;РO ÷]6cΐ@bu֌ O^q*墣'+-}Ϭ-\Em-)u`ìgւ~Vx[H;. eI&: HEK݄]Qe53݀^{[pvۗ|!!OT?En{d;|=3y=D,3i͝ @az .8JƃWEq!*hkR@4ԯo?;7RNݍ(!R,([ovM G5m셣.Z4qcYsIF76"sIjaƂxn"Ihq~8Vv*b׈4;A$L`s3(=hĆαĥW{Dݾ2V }:nacQ=%ЮMMA8 +shՅ:T:￯fe]BKwGӹ{RIi%0.#]##fn(4Bؗ670YA&A5|;>ҬIʇת;6{DkL 4T94)vx4(@l4'|62C5h"KX=Wf$qF)h_Av3'F?ҁe,Ey/9p?ט]yk# 24t/ȊvĆS2BPK`d_ׅAt Pjg/# 6HzK/#v@%rջ{LVNSaSu<#$"O.9F2,IH;TJșz\oyd 2i1*c%AEݗuC8ɣ7Ղ%l_U?͟!y>4̐WuϿ0̈́3RqG/[.5z3pi7Ǥ=k@6[k(MC,_ +b/7,X鴿G<Ɩ0. WIVZױ|+0( ." 27sM43:HpGUb/tV9ڒ&ofv7ױ-K+GToq[V3lH5HyX xXt:5d3`=rm`K"1*xnxDŏC)`L/v'cG´t@K(eDw Be/#lױLf邌DڨSlY_ c)̂\ ]D4@WKUO׀{\#ó؀UOvHV#i~HS&m)E`ISfmDkWgi|~QiKs$p$p*Sk cP%LNݫw nb-RaV#۔SqGqe T`UTM=.爹΅C_5w{rJܿ4{* IJ7mA@u0 eS/D~8]qv=3 ADx9z&(߾K9OܒxT/չ<-׻e2ށܹT`dd nzg*Bcvr63nKDZ~1窱s ؓMX@Iaf`sB{1sQ*"E A9]8Sb<[X%wJO*'2-7 Is< +N-0.EVBva )?H} ṡ6yږK# c2ҊCǦ`^k0#"~+8CThB29=*[iߢ'EƄ5fȘ}ԛA60# (R=X'B[-|9#|."Jo xg7i<wq\Ws\TL`Lӯ_\vd<ypX{p殯a "AX{Պ)4T?h'p)C0sX=>,zaS850o-_l\RNUWN&J=xES@ɮ@ſF5*SԘj#ZVOPÒI0=aB:ժQ!hZE)r% Yd;]jK另5=R@mǃU@@G%>т#Gy]EK"葚дAHɍyAGXvt!q-2O"_|dW(Y)#y[~mɤ^WZsx!ňT=㳽/l EXp[4gJ!Nra']j FHOm J/Yn +|I,^Z0yh.#Sw7<.t&E{o]?Tbc" +EZhȌ`I-K~Y;}ns=PLy\/"Rwn's:ʘǸ˘ M;0 u)4Z<ǚ)ϟ- +Mw>a>#VnS:'x]jW +,C$ 6i܀o@E Sˬ{ &W(sËA 5 ԯGF O}pv/շI˷?w??uʯ/wWy.䟣`HB:TnE'Ž~Cd-` 1 (8QE~YE>ep_R0LT* _ V(p00ӁV );H7UE\-߰bL+d{'p.% +NFʎ'~24lTR4|.a.#׳[ `/?tYrCP]4+y6=}[#]"!sMF㩉F"Zi j.\ܽ*](ˆBIz|Jx6*?׼ LO&K :U=]CŢ +r mg8p~?tJr*/\Lq 5]b*!ۣZcH"!AA( Lˁv,}Hsd YLD7fP/E8pPs=gR>䭖xG7AvO_=[eegqkop)8wžgґU0'f/fԻxf6u4!"+C1ldlt,iZAsRuj-&zaX4I"m *.2Pn.nC +>4~dwW!ӥ m *DK6 qULF Z–@-&b'(`AeDr˭}5S[9UҨS)0txGu9s ?!5{NidPzpyk, )24?xə*yъpBb:C+qnUR.3Րgʣ&((c˪m(stA^̴P XdXXP"fNJDgpK3l qxsA{ >y\~Z*8hvpu^|7i0;k1{U{[H30@慢Z3IKb\ƩaR8nX;3`"+dUraWc+. ৣ;sU MyjqZy}[DgOz dB]q4*Q4laڔ;ETHe̠ՔڲÅPz&cO`4MkN#6(Xov{S6N0@[J?9RKi$ +Z7'hX8UA4C&la>d;8Y~&qf%h :B3~RavS(8;=#ʲS\5tފ(3r [1ȺmA#A33b@9r&|jNɜJl֙gOQ;m1Na}ʙlQfj{Xϖ@/>m=XőL:ֻ_ ./Sxr*ce WaM2KF<{ĺmgLk:`Sɿ1g&3["j[7BÔթ‡Y_SdGMXnuE[vvPh^}Q= O4p5xQ3'X"WHR2Kȝ&*4ZR:t2v(+H쒝LcMmy8z.۲a'S@jK3<[=&ٗ΃Zd"8wϗA}F1z; pk#BvV՚~Xؼũ\tgɤIiTꋈ3|[{oa5PgV0N74G[ +aڎ'V~ƞi[Q~gTaN(^WdU/r_zswE[%ܘ ` oՕ+\WZFΈɸiLy"O|gt`J_9leeaǩ' 09O&],54,h@cڔHr:H^wC/R) L$O"[qMKxpUYz.b^9kk:_=ݝ]]繳|y6?}z?`RY7h/BJHt #=^wۣnwUYLr'cn;>?r#3IhmC+6i*U1j}z&n5X< (=Xzz.7ssZqDs 5q4?G_ YzVx);Ѕp^/ݮ7F:qci#~26uZ1ҠaI,Zc~~0MD8 A20]^g8C}uЇE0IH=xlzHR^u +'a6zxYX ΂U2Gn>QA@jNe40u&{Y֡5o1BxB($m5a;ϛ TdU;ҡvK!!$JkUuwLV-GK?g]s؟|Jdjl;cǷuۣzP/ +QUkVuvR +0!A7A^硞E!)~玀**Ql*H)V5ohG30q(˂#4-!wgyc[ikAc(Jmb1(]Fc∣\,1\^{ғSQEk.͜FZs*©FCKd +߯{o5h0+btu0up}b'㵵Rz\0gFs_[* /Z2f`/j_Dhyh9]n`~5N]础kЉLFT"؟_{|.%a@ZG4miD'MT"8_J0ϩ:dF6O`с[Hڨa踻 Ps"Q@+fDỌhL g[ -RSOm6[&_hT =)͸ + ꋴkt|Ĺc_TnB@͉h"+s_3[߫ x_;I q wpN=^YM`o[Cp=7VSi~Dxnh%euNe=J d\yj~(~+fNGL38W/Uj1߬UwvDŽE-rl ӻSѰ'|3E5>7wgo3k;3[ӄ6HͼJ +`?(&E-49 hqӸjȷNjuboj 7teFzZHȧhO DB I7lOonh $ +5b{p 84R }rQ8h8{Lq9EӫXEϩ\y)m1hA 7?}U÷쾱i]AwP/Eo6`Tw-l :nMӚzySꕼ +}%r:#W[xO Z]Mzu*#~3CK9  a'DkES|WN0 DҖBdABqtno2RƁt;\*Y1"/ڞ h#X+ ܦ8iQ[ +Č|BBY-3ssњm]?`jpg:ؐngrnqeUڒ9g%0ID@b!\d{SU(1%>zlJ8и#'>2j[W *Yı_v=Щx\`3ױ E[$`3)P 6S:,"s +e.:$zP_/GG?(a~}i CXm{S۟0ۅ=+H~1:QtfNJЇbI^DJ)94b9Nڢw ϒiWC*>k9y!gMCB{Ɛh_=G5s@L8*f]mFv-T>r-%U +fqh>+X@;GtGлL62PAe]g'eɇ̝\%92 +6ӯf-송+f'[5Y"(zZo8шPS!i݇r+˩d +w{Q3~=FHDjP1X8#|]yՐ8QvخR:KsZmOhx(#ô1!DQNbS$)czmPt" "L]X˨+r=5 Q!{zO \Xxx]yTS~ l(^ +ͧj'. qǶNY22ˆ"gIcL8ê; .x4 I|"#M+OSm \{t`trs +Iڟj8i&)Iه +5%Pe+A]sw+@UTkX0"֠}3vMU"̨ v/fl]m583S|HFf:M +Mo^GZ'hRTK=5Hep|2E}L6$<.U3J=mB-NDC塚bonF,gTasv"syx qu T} J Ud}vn -5yΞfR,*M$e&},R9:b\PEb^*ꆋUvsQ˜I픲X@kKfRiR$1,P tl=/ 9 5w&p|RQE_2?sT|T+/6_nkCAlњiN0[gdW}o}h }/MsN":w[QfP|&:֋kOfˮBQihBHOя5aT]ʇ48K= ڛPU@[&);rYz%ZѼ9WZdMBުm ?^(;U^2ΔC'eJ+[q=GhΩ<j232Q03xd'8 }Ebf}o-p ׶Zm2֡#,JQ*FE9C+ߗ H ȓPClw=5 +E?.PDބSJ !]A+{Kg'6xMCevMc +F~!q_%NS_KN-KT%QlD3C"Ĩ**m U9Q5iq4[vI fC\=f=k:mYrvO7f 4Kv QRp!kº>72*K-}gΓ!ҡXb~uW@ڶ-,@fmH3,-T S@ܷfzoNQ]7OP ݑ`7is^kMu |+=TYI-.es rd3+!m{

W+SgԚCAv!H@ca`R+RV +ֿtnLuW` r_VǠ&j$?$ +(L@QQa|2rXZ{-h?C߭B|#u/ i]qFw#!7 Tn='BEeXxQs5nF!2'y*RWܴG0 +`{E!S`֛7ʈtLbtTQcCʸyqzJF5G54 Md +Ya +T?O4Qq/BKB,hYԸ2FE-S+82KTG$wBRoLG!w-q1;9 gKљS&M !5GUE?WuTBwnUr#_h$Al""  {Q%qŖWF7h NnGHb$4c`$X w(;s(${HIBZ?p Dc4,2@4@ӑEQ1uȀN&/zP*78ݐ,PӈqsbBӲGlipӰHÀ6J)5 D\"Dq- 7} +5r^q8:y%=qA;" uˈ~@LHQhdTpS%@w Q7q}HWW*vA%hDnHа(?82ϛ!o=%XmPSJGV.PؓBKj 1~*l)9#&c Όh\bsHnW._S{Ni6&ZBUZh\]bɤ֙0xwlʅƕyZOEРڑZcʴ؜Ԟw"K LSyobqOO sALAf.EH`@A,jtU8"F*"R361cFa}`}v%$#3G1Ng~ZFbMe-Cr@MdUXZ< +DFND(dp82v oX0e&wwg!9ň`sT+PEXDq%Im`MG,Ȋ2U e1FFE$lj 4c=2qKܜ%&4GeG|W$WQ2OHʉ."ڕƂ5-f DdDR.Z'JLCr* faDpBMeTdV֝7y|(IXSG'ְ&b JgQGž/3J<ȜmeHE2>=nbf~0)9CmO-Q1o a⭧ ka 4LU*m 8ޫg | 0155Gfz!H)P5 +GFN&/#8㜑. zTnDS Р% xzZjm -!3 +JDRjбf@A鰈XU xhdT +\}Vxkx7,(1TQF@I;"l$ #.[!*Fﰚ;q&'7J{e[=GfU;"M4xKd|R+%?u%@WXWj,\y/K;o,\ uނWOu3-*|pHLٓJwUj95 h&,\ekKdlvfT4`[4kta6FbͣHo*-2CDh)TK~=Ff+9CLctPU4+{xP9HǨ#88@r]c Z:V<'fI;bӖԙ i.# )Ăb6ml:F{Tb wvw|@iu&@@R[\I%ޢ 5d=ek!dTRkɕ T#%Ŧ~c@+,xKLe-1yq[ZWrONnK%֌Y:]2 8ҿ&!TuD',01Whe-#Ģrk +MѶ dU#bJ{V iD/,k`Q-&b-*5j|EXጉ)"]_j8}0{ʛŹ ka լTrH<Ԗ[ a [=%]Ux%PyrwL2tl0s +Zt4,#>GwVʚB;Tր5XdW\'z0=0Q#Sn߄'05쨁b++1/х%Ov(Γq;h˯xXh:sA=2uI`ZwzmVd*@ő*ѩҒkV~f'P +gd%4XFO6["<@W6[ݰG:ڊ3Chv6yn\ogkR1@Yw`ch*{؝]Loo޻|{jҲB&&R~\}n{r&TTJMk5E[xܛUR6挷UKjɞ_C]oKR+X_;-Kh`[;lsǕZ(I WX&c=L nAtZCSG$%կwElѓ]7xHw,|A0f3idׁi5n)Ι%g|ړ_E&HǓ3krw%2IW=P8 +͞'m:(]v%zJGQYYuW]Sh(%+O.b\';ksįgTz03s*=s2^8q-;}r2b#wv x瘈*00S\urׯ<?w*GQ㮘I"&Fʑ xӝ JKKO55@w)]amW~$<>Z=v'@͟Y(.^\HU.7UfN_5qPJxm~(9ϟߑ9q +̓x|Z}h=R;8WxXXϙ_qp#NOmkVIcxsTJNSŹliS匚F<ƔPt[NEqx3_a)\tv/[bB--IuvNsU>]_Mj @y%ځKkŋ;Ntn'52J/ZbKTz+>yUF [;<ҙXhPi3[brAHg05uƷ<[ZA +_̜n,bL.X_@ܩnlbl<qWr,t/0M0ꡅBS\)9QY>[[;]P۸j:Tx- ("]ً!-SR"|( & +'=9,)d[Lv7r"Sݠ&zTR#:Tt>8ZA.])oN7B{Rԡ^I%DxWeBGi]+ۣS˕;'=xﹳ.iRfqz9 Z[|}؞ںzO?Cg֚SKgThTLq=3{s3OBkY>awo"m0?uew|iKȌؖeV23zH/_Y#m2u mΩ`uz3V$( ΗLl\ܺ;phpZGn;?f3p4^XWiojڝ +QZmH ×OXظ0袙3I7</-ͯKgA))9V|,>u19},!uW,Xvu-M +"{sx}DKQW87sMlXHɝp:lyb% V&7oML/Zu{xড়%t./':QC.G|= iG7EDD̕XKa'v&m+;pŀUgɛcr :t~eH+7IOPX&ޓ1j7oLq[>+1 ]oQ@ƨhw%Q"HE-4Sd[Bs항˭3F:srdu|I{`•T.,J+͵Kg۾tvj(K(Xojޟ]L; B=e .z'!^ ѓW#Ɛ1cuQoLVQPO©+й1MBφVjj=7qlzSۧf+%RS C';P혜)<&*HWI6l-rw<9t6TF6KSʴ1B̘;jp+F;''Puʑ;Rc0)qLԝVB jTXjR&7X mGD .e`ڛۛ;l]A푖36%zzv^jpsy&3i{ƔWD 6U4s5K(!DfbC:GfLE &hA32kVԌ ̬ 4}ޕӛ0t֑'2 JҒ5)1z/I2 ش;gd6BEF-6[Pa8 +Ι%gdbDcha?ӵ +8[*` cX{N@~1T\%gGdWIo֚)o) F&duϯa &DCLf~5z*6^A9*&ᥭ.s[~˟OoRuEcVzѣ/_{K_{}l]zʃ?>~}ziB>3ieGyP*SN.<}k]ӏ>?vw7~٫g3m| +#k ¡t7U[5R1 i&*hc.X6疏yc<̋߼w<-GYI2dA: OָB3]k&:+Ƿ]{o??;}٫?yuWNk/vQD7H$QP٢ll`s•ǟgskط.moxluXb#58Qg He&=|)jZ+KG/tW/\/?ǟ?R1 %H~C+5y&gVs*Ψdw.'wNU?!"Wkm61v /O}?û|G_7.\ۃPzd$5GΞ8煻yg^yP^~^zo}?{7~+[ Bw(VsE|efis?3>w_o>xgz{$oPb7" b#B9vdOyG cz琂KG* <=ywO_ůoG7_'}_=}:oc.Nj0 #D2מ>~]>z|wW[_??>Lyz3V[#R!QW'kS'èW~Gk?~ +3˯?ӗ=L +Ag/q=~O{W\،ZdGc +QNH'˲\X>s}{__?雿|^z W8S\w`(w#F8S[_ڸK?y?Ow>o?_c'@Ƥpܘ^X;zgr`o~gO?ӏ>mw?m-mvsu&=kr$>eC>~ßWy_/}_ҍ^;\%=T&&Dm45tǟ~~߿+'|ٟx/şOԳΆhB%5*sfE-Gv}~{Ͽ_/{0||?}|{܄B|b(V_޺kO|O?w_~ ;zw7vwN [XeFcn_}r}_y+;OO~]P_x/߹r/J6LR+L.ߚήt-}=z]W/x*[I{CN1*BE`8T^o&;ۇַ-uO=t~ʥtϽocb~͐LNLP&:.ߑcnHSbŋOǞ|'?~?~G3η漑#ZÇwn;q=T2{{go>?~7g#}J{JN̐ +r .P +=q3Ttkc{~^~o<ί_xtbJ5 6PcFZ+!XZP8U\>'z_߽/˻}<[n Sk PC:< 4 1 qEt{+K;gNv]wuK/~{^|k'wtu(0`s]:3.>7cL$#bӛ<~zncK&a5 +$WbǵPG$.]aOA.° Jt2U6gp86'B Ra'1_RAre0xPΥq>傫k|!iu|hu3o4d +1:*1t"㿟dtB//R\9~H)4R791۩%-b?,0&3Rь"H(a?rh"N잀ވ: -d*Shu:;KQB^9Gn!Sr+B]ZpEXI:8Yܘ; zmKzAn, +C)(5@X-"3P+CP "X4zymkv~!Aёx"_ltc4F,`L2r\r̿gD{DOlumՕ29Jۘ6֐i54,GDGk->)+0y"Xy%B%}:umlFIczΞ8 ÿ:$#ԃyVZ#&'/;ZTDOV#yɨ3a3@)n6AҁQ׵D.8:G*7y{XurI,IdZyC4b I }XMo-- }02\sj=:̏*KHdY$Vm~yʌ[G5LoЯ +R!;A:j<0$59*_rq &XpVmp!V JP%UWjZ*&[cGTvA2Ԣ3L~NsD{rxRݲ_2+ج͜uN̞QèАnטaXa6!q%61#QهF5_n+IɧB[\H9#}tH_9 I +sPH9&;c\МٗC=Y%!bzgP""7UFv52fO`%+iP'2P-;@s*3C:2Bg M#1C+jHQrcZLpţ*KU\|Bǵ-!D*#g5X<-oTlP`]?| + >3G{P[fl|leJD˗uOjܮAJȹ@Yc I-R%ޝ;a J*lQ3kuo}DFAU&q$1e$5{K! +1q?Oh*G+[L Ocm2<ExdJR<m1-WZxW$C="tP>#-h'άƃh(̯4Flp>:g7y;*S`>@kT&,LSaCsz*r*{N*9#!"hI-֞Ԓ ԝ2hy;: xs$jBXK툚z"t뚝)+* 63=KeTBaTɢ!7:2##xp1%D2$hp-=Բ0U'F:%2'>-XuM:c|d7PQ94L *ҹpx@ٹ`um;2s#w'Dt@lU@ ɴn6cH&ܹQ>" L,t($8FĨ9uЈUKPgݡĨ4 +.5p&:vaOZD5:M级 +I=)#VV{L-شŽ5Ιi x/݋f^x(|}(;97[4yWy4K+YYˇQ_l"z@nאiۢ ‘m̒5Vn(aCkY +RLm╧˷ M4]9{r&9wbY$()ĉ4qS0\jd"gDE\*-uJ@˔Udb0Kjrejh:rb\m`$0Mα-{ܰOi|\A[?C-Q ƞjU}FdPlT"^HL h՛zjbLp(f <B|ēw[&WFʱښRB2G֯%(gQw D;?$lYbQXw- @F5 fm73*URDXh*m1J|sdf0iux-ZVcڽ֖!pV\kDCɴv}2 Q:M{[Z6".n<pHL٥c^'܄bQ?8Z9:bKR2)q1\Zru=5z?g7/dvr×\{zG|ꬉcot.^6RT1"+ZHwepq1E:ǰݩ۞#*՛ ";GR19#`Q~3qF ǰ@1?=WP$Ԧ[ܑUقWٲѓC[_dd;cmn=cjtǰ($rj"XB"ZgڕӋoE)xdtII$+`&w!@j0At )x"1(O16(BjJdat@ F{B*@h=cJ(6gN~9:1r\cۛ[bdwm̠ 79S`PB _ L.\^/GE[T_^ǧ=/2l-E[\e5:inљy5HE:q'4+ksR""*1[ly{r/مцKj'HLCDq{y' g@1mUS*g-.K+X,8"hbr؝X48 6 jkT'0xm\S1 WNk+ϓhO.fۇ%,P2NRX\pLhℍ뎨]>x(sƑeWqC>kGReLⓧN= 21Ԥ':S{55j |u,Ђt‚2eFWBpk'9snbɣf/-H{o"SVs +D`x+d[1geܖRS*GcPgFmk@+jHU'戠/38qDN~έ产 e(ʒLNaaEj+ +/6HOՕV ^;o/.TP8oΗ_pfLj${R ˾dܙ6 7Y[P~ɯ<60|mUd֠5P";(bJ6_?cy2m=<=vJ .+.s;W]yzص%gz~V:HymDC1gdRie+b5W Xqe+oU0 #u3-n2 -x*81{Ėb~Md)bV{ n%21C6ZHChY)$6"gR P(69*pl9-3 +uly/WaBSԢéS|c*ya󋝃?Iƕw;smeD@PB*T@(#A91I$RVmY9m=nw;3g֙3w{f/wg-| j}Sn}V|luJy9P LπJz"nʘn!ܡX(i01iP21_c+b,ʃ ʵSDˣ+sPFSm251IH GF"c:$ X&#DQڈ8'/8#JBf0s 8:P\ٺOox`;>f@@A}v5ifXFXD{6\!8{nP( D\*`L `R&@]Ĭ+;'` 2Q5#RX]PQiC#9v ̞?5<`g{m ]ǥ o^n2fvոSx|*T:<:ҥWYpg7(?W*جKEدGMإs'f +h1|3ojmO (TFH1jDA E8|IY&\zNGt 3S[ J8?z5^q!96\ʰT6M(᫸\yA` _@l SZ,qԶF6&/n`ӓ6ni] :M ֓5/#b<=`?0`g*Mۯƃ)_hi_GFlV4}&fVJ4`rll 5SZal (,3']  +RXݛVo !>9}Go -O}lG +~G x7(+|1ht΀@sɅq_eM*e'.kT|DIl&к( Z[aZ[]FP߬ 4"Putaa):r]$ .%Ss[@U{q|#V,(GV̧? NKGtDoezL;Vތ'P +5 c~7Yn-lo\ܾ3s%}3مԸxy`~SZߌʇ{τ̞9X7Qn.]\Y i˧.<*9"XLp/LWLԁnk"!LJCE@p4~ +8F%}nq̩^3kpfFiDa6̟brDh!A唰`](-'gLn>V7|zƛ[v+cO!V,%5S@"ik1I_58mZNw36v}6K7=:[_ z= +GM_cڒDf.4t.a@ȅSHz$09 9 /0Ni :zdGr\;LJC#pcE(.AaBVn *U\K:IHXqAu |vm+k&{q༝߬CO'X6^{o sTs>5>)y.XRʰCȡ^{Ǡ ZN-qqҥq0fCCK]6JxLJ-PZWАUڒ[x,7*Mw9:U oB]:<`K!C0NC%3c{L83"9ɰ}JG,l%"\D HdzhVŇG2#j%䒅iwڷ\LJV{C4*%_;~br@-LLTNNӝF3Btba,@B ?ͥZ*R&ȩĹ٭ڽcXȢ #6 z>[ +elj:L9[ ٣d +{ ;‡bq96tF.,#@cA./8!Ts+>bQg +.oTpw뱊*tQCcO>Z_sUoқcb+f2f@E6Zɏ뜜k`E +q͘\>$v.-vtyp\Ըޜ d \έ,210nv򒯸†[K2~+1i9=KNy XaXPYe莩oBZx~T ANVWW &by P@Nuvͣb;Az4 ~ ~\չL +IRťD7N?Ԥ0GJq$fB6C +3|>N19\V[vTAmNe.e { nK4$3|MZS,k*).5r%XLn\)] +.!)LСJ y(rP>*uct'Jeq샵Ʒn|{|zBl\Rs[lfMg6Í5&>+M=To/g938\\V)-:ؘ έo|_[RT޸3~'$2G()%M&O﷈jg@ +~ܭv-)PWTZզNd!>"d+קO?(^aCJd<1JyF,bB# 0B==q@q] &>J&+SkA69d6wU`.ѭC0*K 9`hZgpO>Q>1N"L^l-t$P*ԛm\]߹8=A 'I\IBDj#֣E.*roUHujSŜ +sʈrNȰw +MMʌ_ \[ٹ "XSDM-]1x"G *ʌ }& p)I9 E"lgFVS[/\ +v_~E,ΌnX|ƶ'N=3 cJ C\@K뒺0.fwƏ.4`ܠ/ +s0p6t'Zpet1u6Sg\#'p]&.s`<.Uۧ}sTִZ\W?՚>y̛U6\#"&Pe!2)Mj Fw;E@Ы C+a"ɍݻc2V$V.}_%}&LIb#jR`4b^[m"Ͱhs<8YJ1`Lj?3f:3hzm"LjO =fF +CM:1;k 1iJiv\aPQόSRI6>=epJ7O(ʵSm_>pePLH 0 =gL߭Ap(*!46v+Bvk\0c3:SQ5vש +FfbR~Z)-t}ܙ;sgWWH[Y4nɑrsjS㖞>R88he4v3Bsu(B~IB矝ݼGf, JL ͜_KOcj:۟Qݾ$;*%ƳCLtB6ozpt 1 ȗHWggWϷ,>(sO>Cĺ[cau*BACN'"fOk:"ANZ0+)'K?^T9D&lfnKj;t >VĄ}N'ɅG7?-Y*Vii'8TO=ѹ{(RA>3E#,D'"CsU% cbӉfԩ+}6\*diQ2H Zq\xU&T27j:9>@^'o : Mݱ*3b>#FN6nf/cR3ֆJx#m_vADlPzZc @|}1b=#r'2Qy#T}ZkȎnPQbB-mT˛\exܵ.0&= aq+'b +1߈GA +SSő k',}ykx24i_?J ePX5AH !QN{hk{heaae>8qqdGkn/nN4WӵϿÃk_7uBpՀ~~nh8̂KQO-S +,0 y£TbZ@!X."µHs8Z9qr+8Mǂɉs/ +X4654;`bvJ|4L>΅4\l$XΏmۛl.F0\߹1v+rf:R_dtelqV2gc'A‘ԅOtiN.dfJqzoϼ 4O2<.(M?Xoq͈|sA5i@oJˉLTZ+-IWA R8xq֎#*wqB"cZk`5hӰ3V$k?_=wKJy ڸ-_&4Hۨ^ r|pA Mɿ:::*3wo=*\؈N$FwfyᚃI֧N9s^k^fˋ{ ʚ^ykͅ=zf dS9m>29 W4NnFۨK. _ar^ѡDյpm]x hO| ORy? |I0輕 HOHs)V %s7N^}}ny@v6ycKpB\C,c)9>d@ uHX|d}2mv{WRN6W+f"R"s &{ >.oBgp_ZI6q1 ˷Nzշw>ɫ} +Le'_>F GO0h +fONbf7@NAWS3wުLb ,RAC~Ts +hP +8 +Ri6:pzzuܽFր{h LQo %6Kn}swoAabώo^~egWnyTx8Y[>Pʌ9+>nr݈PQČ,Pc->ZV[cKsZfܡ!H.ѡPTS!Ѳ9wd\zkH]JSY9X:[A@!>qHp J2qod~yJWTkag7[[Db5R-o(e7υLLT6]B[]#R&V[#ZWpʱ!7hti-y7׮ 3\&y\ߚB;d,}frʤ6vPaq0QV&|Mzmfa}񢯸`J=×_. sy<.aA(QàM4lJ DPv7 u-t${c|8Lbf=JY!ꃙ8&`.IthH)Ǎ 쵓DsRr:}vd*n8Xɨqsx r66c!;hTYe *z5`>r8yFXl҆mDr6" 9Niؔtw^e|Gz:;=zҎ 7h`f3j,t3q#DxĔ +AtWIo(ZL4 +[Ior}f2nD +,-dlXhH_ݣ-@k=*$b`v:Kr~&h͟9qc˻^?`}ϦhUs{䘜_ܼYm,Q*ZG} DON194dfIԞX?tUo/姷;?ǿ{/}яX +Lj&Tl-ڼRr97*dc&:If3פ쌝'Nr {Dl'̏]ghI3|fHmLO626kJMV9.3 D}M%#,=^'6>:&1_(ґ*rRZ Lh؇5Rbs +*1oc|&!&(5]Ԓ.6GTq~c:WpsۉR;d[3]ʩl^36vL0҃BxsD"r(䴔tt4&Fh!6FG ,| v#sVvcqBU0<`42\(7@}6^)9^Pa u`bd2R)9ŢZ(*z'z%1; `hBil#'nqdyZgn>{3/{{cgu_k,l.ߞܸ;x Vƛ^nĕwp Y<׶bѓp] DTZ&O=\.7zlz&/ Yњ=q8p+U#@}e"LleeDHbr"&އk\bW㕥k$]\>Z\^BJK~4`A`&i:RΞݺ^-%3,6 + q06|@th [!lƌouPB#.2$IaޜPT8ũ@!W[ %R F`)qƗp]3X.i#&$Jssn׮& *8}LDăin` xȄ _N;5$Oy:ts W6*.VVjrBjl'T..N^."T0(}棗Y>WZJ(.J[~vw nGŋ`m|[m,$FTӁh88|~SeK™L}| +YKX`FmBveypXn7mmQ)<4Kn6ԞX[޺M2f*(%(ux0ǸA LRB{"j3!;*3$'Lݥqw tSKP*X}ڗ2Zgu ~'>L!!iLNџC># IIelr)Kt(dQdI:Z'q+P[ 7p + tȆSO$:ʄ-FadaSnd@q܀x]L +BPc:+A Heq&ǎT  1 NPīwhdL[a/ L؂L.)ޠI8 (0V>.Oc:7!\9kԍ3 G LG]I_2)+v1/V>;<,Lkܬ-\Cw0-Y1 fBQJ4Q> o PAC@8D`P.)B|yh(T}[pO3֎YppR``u N"d\e9uo[m/סzh@zXĸolIheS|t +w@ԥXԕRܪi^`qqbb: {dbV"n;KBQFOͨ{2v}:C x,֐N\`v$$FJS|*bƎ*2?uT{zޭC{ ؀U \OwPo +քhӗnj .qɊ<@xd*=>7B$@9Ɍ<Ǻ5OmA4Ir(aD'5NƪdE 1ʅS 1\NdƕN3F /=ڌi4i@`H +tuMIb(zY`v +jLuWk1D7U & @՟MTXD0>jj[`>Ucp(ouCe-,W:PÅ 0FB[KT`Ȅ^ku{l 游c|nJOL\;}&A7V;qpRVWcl@mt8z m.Vga/A48 78X:pDb:rگX"FE8)%*n2=^G=)i`_鋍Z\>zQ#>Փ zP!|8XH o DI`tGO>uLud0F7w.RB@B]r ,EO_{tM^˰=P]jHmU +`2F *<\ȻD0s%II Z b PV1An?7{XW;3 WCB:|\eA$LL!\B+0>dPu+#5@%RZP +&耵D"J,0hD`x40  &%U dace_jDAHg,0LJI4!C1b.Lta5NfʠoqCm +ʀ`BVR64tG/R!!hl]^lE;c>xdAƽy#p4s*jxUiumzF0q"4Pm@ ذ12bE({j!џwcAGL6Nkƻl:w 0N$ +|Fn/gqcr8)74ʋf'䂡UZL`sfӂW1&])&1"؋>RJ2MeK c7ܩ vi*s'<(AI +ѨZ4 %bA9sjnDDog'ݡ@{E/$ btWm5N|%x* 7؈c}֧:HN JRmttf+66w1HbELAL(]Cy6I7C ~Q7NJI'`z}>] 3sY8Yorx 6ڝl[tVQ|hݘ)\:3|a{ܜ)Y`xǣ{`.HN P!YȒ$Z,Q hHQ)P0BtGБǴ]n;Gzz\g" $s0B0)Iq (#:ҥԻV&ac&óJ#KCZpp?qjc+z4z6#BǀnN: 8c.&E~̏g/[{G7?|W?ynT*F)}"܊g&kwNqͿw_9|?O {֗>=w6T1es^/, WW>h/~~~omw~~pncR}O`"SECKS''{nl~W\?۟,$OF$'ON_߽ō|\=7q2LGo}G'=W9PKb0d$UEr{ ㅏϼuvy(dX%Șh-4$ P:,qhkT0뿾|ڿ?:|;Td֗-!LȎp+iUTZ)j/2l0ޙ͍rЛb(:h?ҥv{(E]ɠ/j"S)JЎ{0G(owqvTڠguVRo@ˈDqzbejx+Օfo*Zj|Q-A:Ы̰-hvڃ4_,\e/)\{R@y)70 ^N 1$s,ʕR|X+XH!FGYZH,R\DD>)c5&PdI}!YN!xcb߹0A7ƁB&Wj̴GNbr o:9wFZ`Ip!*P^m:y]Ibݗ$pt&kj^9,xBtaw7>և\HdUj@*Osq P2 -\%d?3LHXJPUs"] $k>Q:cTڠO"LXM,I N~g=!r)~'.4kϚerN$,a *X[~Kr(;/(JB^ssh|#q#O1_8^B3jsxǫ_ʈrUOʌN rG]~Rl\}I+(oF単WlYJq"gʘNW\Qk=Zpf_.Ԙ*  #l9B]# T Fj3T:%E^nx!1kCBc3q"7c[q%6kN)!f3").lV[33Cd&pAA37ck~:Lf>@Ձ+$ aj}vc=1%)i-6>-:Ïۤ: ՞#. }ƜJ( \8Yw]y*O\Ł)О=%F̦y4[AǷn2wspqNx9"|jBЅڛq}8C,!YيC\e++ۮןLaJ J[Qeѽtɍ?kQI_w_ +s*)Xta9|$5X I xn}oS~fs`p&6aLjqӑblzQ !Ff)aNYsHimgv!.WG5eWܧ2%ntqy!L{%id;{)cZa-Z<>,+I>r?^Lf {Y{Ic{QyTf܃1~;1ѻz˜2o٩ѻ?k:1/a %:z Z/,uWm/%oRM" StaNk!SD!4"BJ.{K-{@78;nDG=6K_Մ>)5Sq-Vt3kA MљVz-#B+VgcR#]<QX ۈhcؕQU]O"^} %D\I3ޔs/56'U8sA"N234G>bT tP,2Mudf9!oavR_~jM_Ԏ41}OYX&X<|i߅[.P*k7zWQcÆ9b:~0zfjlo0kٝ_v|ee-oN'?wQVHS:*_!iښ0*q{Dv29~{dv|3@9ҼO7qe=T)URÏ~\[)~KqRHYܫYs?B9Y84ꉏ)`TCWbHlĔALQ*f0H֐p8*ڸֽJ;Tg^J)VP%v~*Ȗ̀>9Rȱ u";Imz2gL1NDZzTtUB3x[ \~ߕ6JfZ׈:An+9Se~sJ7$TvW(`;$biJ +,ႇ*Sa]iaP(FJJàX.nЅCš͓)_B3= [+mF>~R=r-S=zVro[?0/Uw G }O%Oc@妄1"1i+yךruu1xL`QzoO<~-& ?yQ47M}b[L=q$_ .n|ulf1L R򷥃gኴsӛ!i;!b͝rtbM|,.~:ƗN7tn'rBH^`-sJqoˤTs%u+$ǩQ$=r$V9Zi~sZ|Jj?s'nj7NK%٩>x?_Y\ +7S6fN~{ɷ|ԑZ{rp=v3AaN\rDubjW3eɛm$VhB/t8F,0W (b|-g_>V۳KSs0=*ᅥYQIKXb,60= ~Li&fb:a'//;V@Ǩn23G|͍.8{[t/tk\˿q=~U?{]q(V#B<݈M?_h-[¬P[3޻1 ! Gwr=m?L2}7>4W'~uw`U\t>|&/Ta$hz~ytVE{wR8ctB|<ߖfoU]d>n˝|?NAs@,n,GstZqu'7z9::HWxkn}"7#흘f;y׿g0WWjJ%2 uLUު[~ɑҺ0K!98~0kx .bv@_|=7]+^Z^7N|O3g\ҪN<"r1}O}t%"޷oHoOH+'j:{8zI[^篢R0{V cjiqOTiv]g[4;4J'~wO ʱ9x2/; +j{Rϲiit~v\|Ǘ vbQ;Im*T/1c270E|W/Q*w8&ʩ}8{WcͿ;[dMN~x(̽{H"Rnu3rdK738ͪ8c\oͣ;sx za)zqn\yP+t<ASZmu%W>+'`t~e4_ϯrşߗ`]p/lLuUѻ{e(OʵoWn*ϗ*`ԸSbkVX=dh]!pɋ-[>6@Sڔ6g5wŕQ>,3J,{np3\*GAR\ȍZ&|$k\>g.=8|:y(Ag5~^3qap-fbH=SGO!&~#5CB<y~ԏys{ftлţw/{O7y+)|7O1}H?c+ uk|[v)_~dgW0rKd}čoBEaT' gO_~Q)sY{N+ByopﻸLl̞{\ C^{j#{sk]x7OrqkTfҕ} XN{_]m. av\{`Yޞ ϾykscwtO)1qv, cr_Kk=K+a3&7 J=h.&tXᶓamH ̅uqsq%".[|IF * wh  eZ6j$ۿI/㙁ѽOQp({I77Qݗ5Ĕz{ǿ=cx~ + H\+Qs;v_f?2YzLc6ty0Osyo3ku5%f{~'o,O97 yLeξ+Quh÷->ucr^~j֏;-+1u׮׿9}߷.룇/lbD0fͣ7NI[Ä VkM"36gg/~uldvN)`ƈ42Y˓|nL.4@RVϨ"R\d/3^܆`v.B}=; +!^|v$N4Gw &:3bvi6A^jaO6cfY';R{W w%2dn%9WaNft#b3e~@l! %917zFZm]c/cى7W;Ƴ1->TL?BY՝z-$_-}< +ՈPFgVпH7S&W<*diƐergbBV\x]p[vw^{5}-udu;Gj駊*ggF6m@͔i>t8aN*%zY?'Ԯ/NRc܍HS7{ó閟kV*qS]O +,bBξOHXf5 xvuJjrҫƍ̘f/OrMm80WVdRR0!҆ <r0<e)\;xð +Dfdt{?c0 JкЋ[peTiXP S`jA~u[=x+XlՄ +܅ rV%FWĴE y.hk=#GDF{^j9xHu Lh$_@a\VLl(C677OQk+lй8^Y 9etyUnMVBvC|/TSi@gAZ1L=~eBn `c2bCg.`}s*Uz^Ȥ=pո{/݄sPK";r{ D$tB0Fݐ3P.NcfZK>G܁X?G:Zӓ>JxV^v}G"mq(ZezfRy,K=:wqgOb3EΞ̟}cX_مd G.7si{FeZAJ*C|v _9?n?au033 3pV.ƥ.mTG<]}/loaVoIHhDӫ!^)Lqm' @zfVqyܿct6~ w;'4gʌ]ڏ(vFrzPvB_˸QK{!fكF"rT($pmڑ^;t8}!_/ BE-L;O1so`&>^g%"R=Ӹx- rxf%:;誟cDSSVXᅈء'jj>ʕ/0}`aG +J 2㭾Z=64%s0MBn׆ckrw/m.o o<뵣o{1(Ara& 1J>݈:'amgMU0߰ԋ*C$3 +8ZSZ?]:O_Uj|ە܋ g2'Atf'&PeI| (_<.U݋,i~JĬ}e2| +0x,}QF^b;E=|9_~6/'{W_ΔW6cJ`WS@.l %?HiڎATyZ}—ʖJxv؈CbRjGBl{v.5(4Tޙ2BV= 1 +9tnb+ IHdnyBd;PH1#4Н1+j ]>vaވhXމAjhzWRnǃ螸"Kѕ}܊qjEm!~ҝrf>>W:ٌ+qF=\&YrGZUeV\ *ouX/N[&qv#21ގ9Z"%)mO#l@僷n@lx -r e +JsvAd}[qu+&"~ThHRJ=J{q> +pF0,Lv)m)7!(3avbr+eXf3.n{B%զne7 қ[v*;K1&r^ |3څh;k!馓㥥7yͤZ@2J[b1:})SNjb|;0ZWd-sK^U,݇fIBV\U!f@]:Mw@"VP\8V׼OV7֓Qc*^}BeH5u^>Ww˵؈r5Bu`{{}ujX a֊>"3r0Ou6~%I9ژލ&;\|Sœ;!D" ұ_gw-Aj /܁[ [壪 ?#BܛRS.fzb1KE[/QE,݉ͰtPZ\l!vqm_ q$P?܏1ꏦ0e|h{Y0aiSPl< ͸vۃC.f᪏YPK-?n(&+!q5@\))y;U08 ~M@Dy-n"\QpyǑ"ĆV>1ZR<ԟԢxQVi\gFXoKe&>qBOvƔxd-b4ɟl᫉l$u^;yk3faXdO¹3"ڈ1j{f? pa òCgvs$PB-iӓRC%Zr]<@隇aa27,` !ìø<-5LNHTT>sI-v4weRq{jjpf* +B}%"/&CL=TRP +y FuCE)f 4%Q- t"!a]qrӔT s:k~~E!5tb2Xz*ָčAH}Ti=] +`)nʒڈd6.Ih9AvRu+Hz7t1R\n!j"f8w%3#ȏwjATsFe' f䇟-o2_6z8 1d92]&y{[ɅN!W-PqeP>׽#HR))~eep̓;A?"+~!%4sӋcR߁,bW7|\M8m OUI,]>`#\m`TZ }Lƥbygg\_~W]IoqUt2bnN[s~k-_-n81v@Am鮟̻ D7Z$YLތoz0,]ߌq#kQ}-fjJ +k2It=nnl=*@ +z 9keT0jLr,n+$ZX9KW(S( JZ^ 0.0+N_3i/(:b|"=J=H LK.|+*"A7s&]x7ZR|Qpf aK8_TZ:W| D;rT gϖx.rD٪;|HP@]]+ь3:²wq[֙4n(tn;&_ox/S`,Ͽ>YO~lՋθEšX6B塪2U \ɥd.J+H* 'M(˓R\"[ygּ̱23Tv|ّ3ػ>6cr7&7gRpY>dt0Wv+{RzɥK&wi;XfVB'TZ6,*viĬNtOxЀ=H(M~4O)=jo%M'^XG>F/%v>(ˁ`ReDhǁaj$vꖇGS Sv& XQkqm*v QRrW,iL #L$?U Y9dtϸbrJj`J"[5tR[Zi_<or?abB#B +5׶b +|Dg|nB.bY/6c`FxLy sUގJqkyJHcRډNl-$*wFfQL,odjoĔ;ANۛ1m;eLz- n|?Z IJhyjXLCFa.!B7n9>9!t] ۫M +endstream endobj 60 0 obj <>stream +HWY~_T0Z 8BN'ē|${{nU/%/vw_߲Ys8}{CLRݟLYb +x<|ǿ_\aw9Jx㉋ƱV#fr]NXn"_]L9pU#%r +D}N]_vqWQ[@`m| dha bqJK5$wa  yҟوlvri*-oe0䞃9,"7\®k)ƓoT?蒄u>FX?KgyPlTNRl@\i6&_¾{wH<-@̉8Gf{RZ|=<΢y (Wt=h(Z˜aZK䳽}N;كFj^sZ`O~kh U g}(; g e?7EFi&- $tfF$55%\nqkR#Q/qCȁN-8Hڶ"\YNJJ|!'W`1D׀OMrX8S B"2t8Ս ggv +rijD@H<"rK8[nE]a=ircLA[hOi,12$yTrwxJQOatc_E#SQ$3akK.h"lfKp"vl;s֖?h壿Mii$K?e{aj5%Xwry"eoT\)gBxe +7u@F( L"EM1g8۹{H<ۨԛ.Zeb +;m: PH徆 "ɤg E| HFuH²!f ,ҋPd#kڜgg@g9MЬTXk +{^QՁf܍i͎$ 0;O%UaO%ϤB>M*₦{N{Ozhj+ <1WȃND-t4x]Yll$v?7>|*f ++(CаŻm;Ѭ&6e^qR:(8Ѽu᭄eUR$܇0΀~ߩ:_(hvەWp곶!kP k:VQkQH(Ӌ tOi3(MXModOI3Aͻ7hl3#WNtswVCH1dw~u{QR8O7>1{F yeڟ)4ܬ ׃h)a (5hç`Y3Gs1'0;" +SWrBJ+9} +!--~1!Iq}P]}H"`ˍkFWT6,P=GK,vOdj񲳒3*(; X# `eI1/!1RQx._ g&scL8^6b@:zcv\v@VHbٶ9삡y+>Y's:%6HL(ȱ҇YM+w@O0ntO RL&Xi<.a`i3B<'ak?*a_Gl Gf ۋ!{HDXX(A~50 M ' րm@Dh]'?3EJs1@p0leC\;@jXTQ` o[t)>/9Z%ocbOL$:NXyyS4W% +qɋ¡Kx1P!.5 ̨F1!&RډQsw0/SrFUuGV &o +t</ߩ /zEjZ7;q&(e6=wt2e {5(L1ɏýdD@콲|$mMi;{;G";wpRl>BJWks|b"bx8<wv`ȿ~Cg9{:d2$*0 +Onrqk5(N KBz~]ˢ_^Vܽ %'2+KoĄQ)W0ʸ :7-`lô %h՟rB{zK]H/.7hX+TSקN/|̈́ߊÀE+g\ķ[#~wB$|_S +endstream endobj 61 0 obj <> endobj 62 0 obj <>stream +8;Z]!0p][!&;DVm]go;IT)EQg/Q,d61)rV"DiuI%Un6nR7PI(mJP=)M/mfYQ-B\+: +(`5O92`1.RTcPlI[6.&2X/=]V@joGG;l\Q@((ESNEau,LO1^LplmjEV#jO#:0/T:L +P^pQ(5d:tF?7C`3c`3[R@,-Oi?5\Ui"pT!.%>R%1kGa*Js/YnXn&'f"@HCQ1K>6#_ +;2f":p\n3`::GPnd_]P=4mb,<=g^#3qe]1DY*eCrLrm`"Ll"^MXHu?mZ]irl>jW*3 +\*m9+#&:rW7aIDd-&^!'43sdSS#9u'hT_ik=B,o[q\>o%<_eAXiXXA9#&]aS1S=VK +ZJLdi(i]Ur@g_VP:/#S!$Tpo2*U2KCdW8.5DJ"YKcnTf8+8tLL(UZJekIX5_'ngE' +@N9!7'?$HV\3E:!M.#`?`FQ.q9$+g5$*?@a]C_GM7gcl"9;t`9'FKP:ZXHf/ifZ?M +*gi0M>XIbQ4gdsUkAM[jCsTH!b7ppTj$u`j7;@Pg9%bbnK[#*WGki3WIftk!~> +endstream endobj 14 0 obj <> endobj 110 0 obj [112 0 R] endobj 111 0 obj <>stream +H|n]E;40y N>@;bِ}Ƚn'@HaqWY_>\.><^zx˝uOo7/?]ݻ׏ן|}~۷]\_.py~ZϏ_{-㗵3Ė<}}~t}}|zά˻~/3naOO||{r>ܽ ƸEAM!rvQ2&E䍉Y=3#3=cǺ){]iYSج tr^ۃ<MPE'՜\ٴclX/@]fZfAS_E8A z/+Mt! +eֺE-STF%Ƽ|ӍCTh(7EȋMgKP26ݪx'J4RXYWUE52 Zm>l +mrjlMɉ~ٷN1aiL8YP394 +[#Ev4rhn!033w|Q]QE)ye\ ++o;n +Nh#ȉ7\Jt*ߥ)JHi!'€ȣ0d +ҨR98yQuQΠ.rpCg8Th\#*dGͨrdE{$U[YvIW#݁w[p!rKz(7Qn{[EՊ\[PU Uw8SV"V2EшGS1BXD9 (;ȷ@l"VE(P6:E/dzRffb}}\L7"Sf]c]T i*rdf 3Sed$9M#"m46iU@ۈdm]NUCIGr8Kw+ + #k#fh{*Oh]hQ:s`]fԜ8D>DBBY DH,D8Gt7B۬L,NPE/*VmTϳ߉xtkt?MSNB7cIܡE523&Φ*(W~Ƥt/(ǴPTSjzQЄȗMi uu]'z{"o,JQGR53aE^d7m|mn:!i}^픖"oeg`j)c#|Oʺ$e2Q\dIT=cQTT(Q YoVoT(CG MX`L/Xn/ȋ\z PZoSKf&wmV}^3Jvݯ+_WOTbmscgzݖwT6udw(gCMl<{YL fr/,Ć1zbV&D%U@&^6ZlE:FdR - UѲYI ʓڢ< StI(YQ5n]jbrV)*ChYe(|ʀtEjxcNY,CfR1_ufqt:RuY}oHEvVΩQ+; +"ZTyQqD/4N74KuS$Q. +JPh^9YMMtÊ +WFtzաTk֦H%Pdt#*Nњ٘Y~<~C:и=44&U 4=5Q3N]*ʅ+sשׂAw; ;z]U2cjFQgBW6xuk]c hԷ*'/>ggLbՙ΋YZMޮ~z&w˷zEr%: +&{ԡx0+쥱H G0.g^I2S2**.򶨧}zUyin^E(e()UQ)POEyQwIFTf.> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <>stream +HV;n1}P8#pҸ4A +`20T\T# W V+A=@{!)l?<ˇ8l!nfJ/^ +"D+vR"e"H#Y%ygDqʇfuo ?$\NcTqzǩWHzp )9{n"n}|?3'S&}qekVLwe]|kBՑEKq $9}lq7N84ҚxlBZ2~b(/b&X{DAg-T.$lK"F3`O9?afXҁ )xi7Iڂ +h7'ŵWO0nݾx0kg?!l7j[2Nu7|$e ?*(m2. +vK}?RYﻵ7L=,1) +09a +endstream endobj 116 0 obj <>stream +H\gXiߐC7|$ t 4=B7tQa + 2"FQ|h^k羮s~A@PVA 2M& +KDv XE{Ԣfũ'}v֯h7bv߱A48hL^7:{%J8*.mFa"$CQP, (,T)K _pJ!d+ ).P@ +/pdybH(Vn|y=H[YP" ,0fXe,HN p@t X`%A Aa D1@ *@H)ZTL&Ӆa1C(^__oj7@F%dQ!?(BPIl(j1h}p4rtwr; ӄW|?1O n&6;ɈdN!ْI~I2Lٰp +,2 +^ kpW7'_d9K."&wD|v5u-stwmtśzz~ai4 F +hZz/ôa-z<]FOg{/ FC(a261IƟvw ӆc* UbYYKl+=;-e+9V +N=}#(l^? dxJZ'_}VPN]/1X;>xA 2a0GXR24?Ho<,-:;<&|$|>"b.R-Kd-Z."Q(ZT/..^}1'P"V3ŝOJf%sq*Fb+$ U’p%`I$^*QJ[ҮT\B6#{/,G˵r?y%+fe~Ȓeefd:5:[?{R9|\A~CV^TohdF)AxPt& +"i]КGנ/b1L ++fFL[}PF ]s]nG=J= Y}G &  N `|TZ&&*SCS_'f*$^pgKy+O۬ձ=cek;  +89؄6/qrrrvvn''\:\N]JܮW/3GUzfqqq <}^߀_!^SWɫҭʪ&Y׆[WUcY󡶠]]o~qpc&M7+67/TPk|eKSN--~hik]x֎A;LzvwjilSށ|Wϩ˨bw/C]g`Kojݡwy$yh1T<4wt~?#|ʓ~tG##O7יmwu>gxn|܅ K.'ؗؗ]ʽt}Fč7ފt;ړvMLӧe߷_tԇI/="<{S=ix +=xOs 􋲗 -Y_X:g 5VO6u +H +"A'yACQī@5v5[e a#6W¥ ~WS5_vqR{i`ud u\-w{PּܚM;6] l7auQ +ȥT0q`/E4E( 0@#j`ZD#@!0 (O-"bFh46徳Z=mZy^{߷7asLB\ùBf͆Pe`CaXhMcv:}N70*?fvRDaV% 9y ؃OJ'*t4!%sXd +Ia3k0ՑJ#{n1 %*Y"W{C/GG!y)hf*svQru%E>_*= C4X;Vt h$9Si2 M,x}4f d{!p(gᜀh9Fiʧ1lT=mðͅ7Zn.'xYjY* B 0paݭus a0mp&hYwJ+>zfv31wj\GpDC*ox5]9ReLJ(R?Ї3,53}Wu/RHV,{h,(൯3<Iwy= PsbIZ@ޟKᚩ2ѓ80snD!|dU$L 4v.nĢyQ#X:II1mbvޢ?ԇ pxXpMЅ#K5 ;F< +p] %-GJDx7.]hM9Q x+H5-bP ,-MzƔ5"&+b!PgpxS +zW~h`,cBwt + ~e:pd!63B6SitiHcJX̒Ҙ,kgh85Jzf=u};w1،- hf"j +Ԡ(F|;Q> | KB%`A?Vgx]Ǧzģ ia3ayQ[{pK2MG~[4d p#HZ.&|.TR@)>E[NaO`hnYWfM04G+8gw<{0Z,iOqZλ/aR-!7 D'KDL!CM(GhɤxC&A7WoI'*KSH"Wݩ¦e/YZzmCO_9EǸ'=G m8|9 "apts{REaЎs{;Ύ- + tLEI2s;тz; Wyyd9rV9L|6opk{7I/nP  )c"ǯ7~$p![(,:@$f`o ?U ৗYhIx,B[{I'wPU=֭C'zd(Jډ5صuސHgk?q~c k'+9$9~KYWrT+)p'R9yR[>7${<7`,WL륕l8tӚ!s/RЁ`wWUW4+y&hJ:/CdpHyE{ S J.kw/?yex^b;V7JY:jӤ?`MPX?拴1o_F$ZSL@:N?+^rp^!]RiTka[yb`#XwtmI?;5qXÖw2d0{pwmh jTƅfs׊ܼ|;y [="7TCf!:aa ookTSW[US\**"CQ 2|? e$A|FCy "Q /R.8XC[EMk}Z}5'/q>{s 08Ւˑf)ƸyɲqQ>l%j2 ^&E1'`Ê@n DLMXHćKen*FAqƐdD2~E,M[c<"h> v;gn*ldg;*()R%RS҂O-skDD|qt|Sk?R?h殘;хu S^Ao~3P7L8Ær"BkE KIb_aP/)ƙ$vz?kژ# ܃C:B$F:g0)iu>0ZC,;_MVm_I3#[t]¥ Yѓ_Hʠ9qk*շdMK筙 d/XʝJcd,ztIpQRRv} #aO4b?2'F,t8۬V6n⬎q5Iq%gԒr +RiK|AR1܋H¿:ƫp< ?/sf?K7IKm"}_xqnF 0XcL[VuDJI9]e7yJP?B%DNc= !JMRYQ-%sF&qhB=$ +lx8,N֏0`wZ&n/s˅KA /wGbc?k9|Tf`ctѪK3Q= P TEc]([aFً8| *0 ++P&|Rh*~˜ty(3e3"%_ 5rs CNjaՍ6v>$1huܤxYZF;REn{$S Q/c.P/8߰p a:eƷLs{S{C_B.mTxK?tAg SxW]/`4zBYT{VA=8P -43OFi民tFZfow*5coadcNRZZxmRl"{879Zmn`TT+wf3e GjʖZ%PU,E]L꽚u)PU\{`zw-vzJ+):{ۤ@!t(cHp@"95ݵn#yx6V9b'uIC4Kw=y٧p;חmޙ"~}?RkG;݁2#|\O@"v!yf Cj1V@biV0HNEwdAp\O,+$cE!D+ugÅ g/Ft\†NNr!^5+VkrX;q.q&AoT|X_@J#UX$(H$@&A R +Zk+jiw>{1Z_u0BWoxꌙYӒcqxW%E.J+Ӯ>xdzV2L(#t雎>8K}[ݚ^V&ѿm[ 0 |X"Ep]Le'?b32>61"ω\}ȕS؃GU*B .R Sh.h/j'eRubT]™K,+-ނ Y282qkC$Whqqof2NS'˧/Qfϝ7IEDM}9ѺW.FJ]_Geo`8T&v⪞mtn{q1ZSĊ',/-ËI<9#/R92&ȁlDXï/.]\Tec#tܲߥ}Tsj6aslW~' Vd;2PL>y/C",_&,`D؄H*>GpFWa<3WN76*NrJ9}l3_-n6 ]R7Q-A Sr  uh|sKQZ?(XiS|p$ʋ/߯`{y^pOam%]C]M\E*feL*pܫ9iֳl+~7cE7lh>Jq*ҝGUt) +*"B$pHއ #Yl wlJ,RnewSOGljR~AmAו8٤uuW6 +c@^9uGR_WBdr-[5) fs+"t+9,DOd7 uLn]&c֋7+T}) |gROd +?oT߬fCGXhrIh\FɊ#ug %+qe_r߄) e1Ұպr;| ˂P*յrLG@ξ𱓰B &H0ˎU_ީ.zs۶Х̥tIU㵁bX/[}=qt}Y˅[X?ZܕQ Ma>Pkl5={)Rfaj7f`LqlNz'&(b8"@ЎrF v;QJu'~BnϔkYC&opdQ14FnS4 6Fߙr)n[E +'c]rCRvkMn1Ex_p,# Pik\UWÃ>]"i!'V>56 lW,(01q4 +uW5cSRqi99g\.@QYaDEhFUKyay BCq%03 ª(aQ񱈠B#*hkY\6ۓVݪ>]u*O9ݡ,h~8"d,,ߍ*qfJ%&΂0j dw.׊=lC끖ꖌ~ gw,xKwcMW6%mb -;s~$E%Wh͉A0DpB\@y+o8a2r=ّmD{Z!~'&s(v4V*bq_6_N5{aރ7Os.sc $6a`b;&:TH~q?J'o8[%wpO0lB%}*\dv< &l;FTY +MCf˵{e Z35-[3 У9|'l&8(GVQKVByplXA" ǒƚ6*|,/޽ۧ($]^̤m^\m7 G HK+{hS+>/ $fO-M[Y+=_b)Zm8S/o[]zL .|IN ô%l5z*$=(KCXU]1 ~K+!6VVmXxEP f^p)K!&-6B[k!Y`=gl{4mWe Քޮ)k$*Ln--,-RWwE(3O'WIssfZZ)Ѫ K 4Afa4lGwKW !QN. +~I +#8`sǨ7-YV Z:ćЂ؟ 'T#Zmq6-ӔWȴ/3=35Q +HNN$EbJ.Lx&%.݌AC +`2| \_G' 9:[0'srMGj֐V߸Poaf<`8y1K:_ǵ8N1\'PWCμG\M MfD<r<4tC9N ($`:.o>3|@Q׼Bt2TQ )akSO`1_#8.OgVP /*Š y'̼?!K92Kn/0]*tr ˜xZC{VXa VjY [tE[j۲8ǖ." z6= 7]iȯDzNhr?ˍT,ڴ#aW$KfU)Ƣ!JˑG\r#& !W =Y6нHX?fM塚ds"z X>/%Jދeq̼Ou5)4SeLC96}i]Vs1k&gPP08^J HZ{Fto_@p3pl/ a m'3AD/R{/!hdp.y) +Peʋ +w;4Z.lWU ,A"%dp" MJPJio'~˄ʹ75eu\YKJ&LD mɭũyi{U1zaQ!q+xv:@R+-%|c]d] ۙ}.Tq.t#ܸ}3H`e\^} G8assʖZӓ$.BC̫'ęlunAczV + 6ȲK I@001#R=]Uz۳=kWNNv =͜oy<>ĭCElF1m-(ʍ>qPќsy50xo~ƏM&x3eS*$ +`STFXkv%g}ou nV*1ɋC|kA̬i}zfK[y'ӫzӁȺ/\ǝ_:Xy?16ڜWK8 Gm-ycU>4&%rr|(3\ITA3!0)Zf4/&aZi5g_x`ƶlŬ3)o螗Bݡvyr"`>+jbW>TR}C! ʉ0sZ[/ݟ7TS,y;V~ZL(` N%J a7Vyuu*lF~N( ʵF>?wVz:\H\65hDPBWY,e#.X#fQ4 +r-sjua~/XZ?Tx[ښ:>6Sɺ]8kʉi[깫K+C;EĤ iE%\=Zl6\/I sWD]%AKve3vki8^J{=휣j `pĢDVMD` Q՝5O򅈳J4]x)ȀS ,$!}?*s1Ͷ@01y1l<:z@ +fۖhĸuE)V,ulw>s ;lJVf^a/\=͊[_=`gb΂̢c + )zvD"nT0$5ueG+L:_~b$ +Nܽ Qsk %?2a8ayXhl.rg^pkP9,sfCߓ;I$Pb- +[0_dofdL':*<9;Xp71bkЈ폖6m*%<CAQGa"Ìu7. ;rtT`zxX!h)/.k8e +il 9#\J"jw\9$+XgjڳkLq WW^ZY F9=d@RSV2Q{d,s4PR40^4''(h/~KJЂ6轅֜_"݄T2O+M,O`덣.T:aYTE*1 fB\ me1 }8VC6nReŨkZ6UN4)R/-qTB;zY\~KbbiEb>j*BKc +].2Ľ?XשcbF; cDCڙ1WXtɯ I\6m׍P0avAޡ&'SS3T4#WLU*GpPs,ķ B3۸{K|V7ԡu#6GbAhzߌ+u@m*p +qB# "Y&'&m.On~'h1g.U/H^)?GVgh,m;p*BzZFi#ZS"o@;BlyL{ OopcklKHxŭ]Ň#ņ1?AFΥIMN˽:}'Im0.8SceRs 4LQ}2Z !r4B&)`H/`UC!phq]]V~Qr݀GNps;nzV$oc Md3l4T Su/D7[iKN^`&]eny+{sLF>L frq_,M; f`Reը7$R&4 ?p0M؋M +e?§ 3u>ȥP})} O1f+Ī4u/;:Jy>䤯<8k24CgA^V*ƹGchV2~EO` +xR +cm@E!v)_#q*ٓd8p> }`yKrN{'*dʆ/2,+ BԳQ kup8#k_=LԗЖiUNƹ(ǹ4޼pz ׺riORuIT8(ϋ(wJI#eyiXL~q fc5SwTbSyC AӵZ2g8),`$6o+5)j,"`V立OM'XJQg2/0O婆6x#Ӳe-C5rHD&Lt \4(*Lg`@^QHQTAF楣tJ(.hݜ|OUtuW׭߽]# #1~L&o`1x +&KĠ?@y!>= Vq% y5@JqvK8%w:IA>9S>Oq Nq3:5a0UC!>0Rh`l[NUFyȔi7E&'Z{ 6z%R2'>k:Z:&(G/ta߆cUeI} s CXj`X 0 +8 +'4hR8:ǝuEYi^#Z@5*#|'j_|_PFp#6*6.Nps8OT!TKm,)K776lP\I(LLew](00}Gcr&QIn(qF+}?eWj1/Jk*'WG옢t6VҥRl&(3+t6XmR==jtv>RT04M-`}Ct 9pWF#Di {e 1ݕ'_hN:$%dݶN$hp>E_fѪb۵헻r֞\ىf4d\{`6e+kE={" S/ . +.^T"3eWh-~7UtCCHj.ܘ0tg!M=uTP5vdpra $U#zU}P䭩߂jeSDf[\ _%8GeDe~}8E|䄹]=YeD4A'DS҇Ai'L#ykrVe%8Q=jWl~ߪC#3:ҫ .62rvy$̚μNJ>#m4=?5(# ;mFU*Ev}%" 8 /ѡDF`Qe4fܤ,IvԹ\ꮮ|}UܙՅ\'tW&3݋O- (Õ֖;#ʺy3wp85ufU hq1*KU5'+-yConpUT2 %zɟ@Z Qͩa %>Z7)`:\݄|w\_?MM'mqUr]Wyk ]Ta7)OݲC-2"VTsY~6>h 6fEW62J•U癑%iJ +QM=<2FyiS+`S+n~t7#zi( ߊS3'~s~˂jZyxw?-HJpw9 +xV< ܜ`b$HfL 7hյ{- w^5ID +*tIW+NNfkG>5:$@D"PFNӥ?B%BU'兜M!S[ΎvA:JG + +#59rJrJɑGXRh l$J>U;=c#@,%{GTBR+p !ՈƩBsIsdYMm()kT8* al'a1 :&:p/Mwɻ2Oc11m ,:^G:DU"H#ݯb"q1CI2%2b))((˼9!A ɜA/g( Zj0vήS" hGiP>b + %+X-\sͣCr?boo/.8]҉:IP@";0菸17j8؂v]{C}הɿѧenlҏ8B30 k +`o j$jj f:8o&i 2o\>GUr^=2XK[k[S[z=e-:B-_W/vf74ƖcCLkzރ;S{xpm{ !7z#`0|Т7RhJp; l!P.ڒZGaE \q˓'Y<+cE{O]a do=+; +vfC2jaW Y_W X2˭[{7}3S&|yKvǵ`7lTba qjmƙkx.iےUӶK)ZiGjl6j[û:x'YhqԒ`>b#b +W9^P7ZΟ+n`)8ѪW6pl0~';W5f簾F'c 10˟|l ¼td+8<`ٶdS7?7$%#be;W1qqB 3^@SFNU))B}dϧz&8)7I1]w!5&qm)ގKG|{~?j#.hNd^[YR]j*ɪ >>"nL:;O  `U6VDuG;L%m1 JNX oAd Ggx, ZNd2U/ L~fѰ"|f=LS(,C(L6+)n[^d, `.cEWJIFIN·:l +," 5ٕL6&GxL `qAgd9?IjT +w!]1?^T֟"{_ > VK극U̍J kҍ 8Ma25<9A +jߥſ YѨ-!r2d%&3vWE_]n#^wa!yޯ%LWC/ϩNse!Di/Zl0$w2"-En嚚m-Tٱkt)yL>b@ ++j8Ne0vmġϜ(B#ɺjk*gknx7j \`/ Xp"yDw82G Ǝ^?Uz.7n7C]wOnWৃ:pʇ"Bt蔏wa2+&X޴ݿ5b{YP.ktե~F]e)Q:t2]D 85gNejT}t$vx$oGScIJfTʦك\wIN QWfIC[,LB(yQq +5t!7W0`70ݸ +롓_N VC _A*RâTmA*RHɅVL+V8)jMZ{7rJ?x9#\X[Ox8,J eNnM*y z*K,3LJ+SS\w+P܂Wo>ٔhl?r7r_*+3y@Vp{ +άm;mʄw1.iP?c·I:i!b`g'+Y l)ַއ1tw?P4-> !Zt#pI{{/;=xxVN3q:.ZbŬ$050 s#< BFI8}K菔 Iðo-죽t2>"2,Cb ?<τZpAjsdK?+Q?>!->e|"!ؙvj^qu9e&ȶlN#-!#sG^X` # $gtRkc6/t37dg;w\P^uuܻLjn_i[ٔobIz3t5`Bb 漉 5_2[[ 5]TkSdzevy ^OmTmTBL/&_y|X#Gl{ a$+Nި#l_8,ĵ}!M+~!+9:-ehgyGxV(}n  fWf^pCV@&ˋ+ݏ 8_qqA 8 bàx$ow|F{y8c1d ٬,{TSW5^]KǞMX@GhEETG QB! +E  cH"֎S#U|}㾩su׹}>}33xGl-}2K̄)XF/ 䦹rC5p'9sM "K0F&hY5= 6.sP[Tkȋ &Ke3KoTTUܼJyv`(GYJ܇CC2pпDG+rGwdfǔ:^*k0)ETޞgzf>8 (f- +J-pG+b)j\ӐwЪU0CG^C&k1xRl(ؐc7Y/H@*^?K(&t0oB0R +1H R A~apKƀU >vsWv!Ft]M9$:XS2oCZ`h;63/s=*Bb6pbRPeX:&C.i^Gh|}N%DppEdk zJӏ)ݕl;06R0A}4K%0BC V9W~C)ݝ~s"[(pN3Edf>B1lh#x dP܌äng{:nدsButTNŶ j6a\L@-EV[4o$i.z`}M:$%3QEv?V;Y!E.MPvA%^S8c3ƈIArPoևɴzW%nТ;? *|K4h&)sMB8%X?ED60:aB!WS|$"$\s u1I0 F@m`a$% +>ڔMt]Ay40~kbp Ō8FΰM`A,(Mֲ\ɉG,AO.H޽XsqN1s5={MH_5616>>yNx`9f(P;v>g)z:QC^i?jo_ѵivrL Q3ER00 fpO3(FCgNc%HMr*bqG ˧Q/"Я>xz}ԧMfNgA%+v˖Ȉ~Mw6묁@a07[#0nf4MnRPP 59RqC^MYAVC[%j5-lE+w[s o{t~7y7:yV~l5:@'0j!*=FRC5KfKةw0ZM*^ւz zz[Y.YfA|_ 3&|4ZR=a΃g,~vXۉ$F\Fډy?ԡ7f5iKx*XB(rNe2>+N+/%rT :RkvOYH^I\x\^WB3Ձog`~_A`D;-~Q)\XxH$~i}AN8$㊶r]iQMM~$˟#Z׊⠙>jA׈6%-3B+Lvk*$\wF>GfZ{{kZC!K<0 mPq((+c)4xB^wvL `x=UE K?=#֣*{޶c.2Ҍet/(M jt5jh])߀bdqjUIf?Xml<[j^Fӧ[ͧ1-}=,_jh|a0\z^lDi&xj͚.?`0Pa.2Vrͺd]]`T\WxۊcXLcY{Fmn,"?]%?TH/巒n.ܞr86( L:-uE4_0ե̓"Q⌓O7CE,7G_Jfޫ`q%r4Kp8Q+@;駱i\SDEk5ZNFReXG.,?2<~(W( U-:/W(g& =b/Wʞ60d6Gzh@?0D=!U%┒;.Ba.)*.vKddmm^U\SI#; ԕb8`Y0J47;&qWFQ>͕K]jJ gzx|LUf\P8{Y[&AكvHVQv]oԼVvW0I/2&XNpٶ#!17tv^>2#F>2q5߬:Y!ԍ4$p>#)J~%A[}A7l,} #eCbuS1??, jJclAH0 ԝ\l9)%AD$7a{Fr  쀗72DžKDQ_D;DGLn;GWXaDG=X+ˤlZjka.Q50X;+*fPޙkהW$as㍞ nޕ$^!Q~s5S%{v,,W95-\X/e(xNk!!T`VF0;pS'F0^K wbj&6wW^JIiW}x.E6E򲳊:;qɂd͞PC츻LTy7]D314\'КֲpOh)},*) +)VJ$0ͤ +D-9'Zu"S8gwo ǒrO]n6ѩ}kNgqG܌/`%MU UTww]^ $_ơ$j`򷶱܄FƊ;GO?M((Wvv|QAOV  зfu9 /l/5:yG69G#s;厸`#PWᾉ2Iݫή&|gtqҥxF]8𥠡>tMt3 ʚq5(l1FBu?Hޜ&#O2[[I@w'%9:r{j6JIyg#Z属nՄH!J!窂[T +us^z9 Ѐ赨}7􃑱cܹ&~ɑlш+\SII3^pl封Uh PU/lq}5 +_kU*g)o[lOt9ڭj}JKŮE&v޽y&)8q vɺ['9v}罹FIx;xR3iCLi+|<*N4kuITfԢek{=^mHapy#d2џo5]ڎZ%V+E[ +? +Nɉg^\o /I:!pz˖,V`{zu-뎶Đy܉/uQg7G:s2遤[!}|LJ?*`b+IQC;2"L!n%p'3s)S n􇫾CދD>aVglpXvtOTY"9TТvV,;\?AwԎ44/2P↗SdMqSkټZG('҃2A~hj/Ta*ѰuKkF}f[=SG3&"AJemh1ֽ*MT'd1~j*]6].ڝ]]!ÝSϕUZF\xDtE7H )M B0 X@e22amf87yW߻v#W&<HZy %zc ~L&y{l?znzX ޒlVmH[*d ,ӛazvc+B_Ru+ߤrMK @q{5sn؟wPFQA+=z cURoiyTҜ%H0@Ԕ nu z񓄩>Ikߧ/3v \Ll}2<(j?b)c2`qْX+o4ܠ$yqNB(!ΖӴ>H.t+hbHL*]e 0Ɋ`$,('8/TfR[Eᕬ*k(J=:Aڋ^EuX9VtN5S8/G,jvZ)UU0X4:;ْ?h1L,Q$T/gT+UF06(٥)(UdKlII RnU`%YqAit;:S7\"0S?yödj+^늎˸ᒑ#zcA bϻoQV;bX;c'I߫J奃-Bu5:ސ>6!u@%MHE9aaڷ`~E"3ӜյT<{.q:J-ڬ.]PWWI  WkkZ**17SDV Rk3EE;Ӯ]q>n'A#t-` 5L\ +&AكZѨfg%UeMޅ>x"*Xa.;0l2uOf˯Ս/02c=b~\Ý.1ŸPjDnr~"tmPTithbЊ_9pNJӖH,W"5erS˩}6Ct%f$0"T_aQ:fbh;sU%_0υIY)227^(e2us\P6{2?UMC:"hI F*`, p/fX0C͹L֪DæhUwxKkJřȅgrͭ;/K8q<9Vk@D|[p:0$n.-Z)fcNPK\tt. ЀG: +pE!! +WIݑ;V0Ca5;pH@ծ_S]A߽m~c7tqN{#ڗGGJNp~GW),,Gm×콷." ?6,~8%"n'i+5k \DfDnr#D`q!_E_? +뎿./&yj0Ӌ?'Q0_URG !iOcqc*RDe\=M Ir7jV*(u!}Fg|>om[8`XU6<E-E=:KŸG E?lxXz v;R9| fP"tz(ZDXwxWrSiC&Wk>{gv- Ojz}7`5/arpɏß2XzUc :+4QilQfӗTj6-7k5 h9(i+#0V+ *e_ j*t~(njL({ƖH44 +F4'@@ATY@PbbEb(E " Q5bG1դ6纺/;nX\cFvoW .KW`xɟfq歏D K('eZP70YpX𓲓󱄚lS`ɋˊTn-[rW +TbE77.V9 PJҹB Iſ} l 0[ W 6a7ol;jI?,f.XgKb}cRa7Gl Z)><=qn9,"!0>O~. ~!G?b/e#×`vgӝz)oP1y4^otzkq5i=ߖ;)*jO`&ьAK1¸_Aߛovq t|6`wdga!VR+Ԣnn.V> +1lE6~([k؃!.Lk ]..k8ي!1pp{I/ q{+^݀a\QgwE-Gܘ+I:avK +N +(%/PT݅Q#p4H\^wU-Q}$A{+XQ@җĄl>Q v_6g]uMbcd>b?v$3*tu\Izq:Rű!nG846A":IY}sr p +SGa5-'0頹:2h>x2/BE1Ua{Tn>khNTȤϿ$Pcv&2G,h?@wg = {F)ĺЋ/"Ky xѳKB!$埠+2\4W|\@4DZtvxLFA "JpAPFP%FY +TJr7LY"е]8 ΃R'iS!m2cdVpN-#W 0)?}F gZc1 >EcͲfS^ؑq/̖\zB؏$_ + +t^+=}xiπ@/޼Ճ8ZxjJXY,U e_>/.NcUbtCS q`;>حD_/+jx(†Ҍ;w洁$L# fiKe 3fs"3|0j\>eC'̾ !:&at>NIWcWv>/.N+ & 7Oԋ)]a#ژ@Ӥ LʳtM>W{ +L泫 >u&%#{]Wz##Q6dho.+?)U9y5o4gʟ8uTIMZm'?=bC\KPոzo2]+y- Kԅ*mhhrEqa9n烞x1(,⠜bR. 34LБAHH%(sB x@^kVb`kv$MWMUz_gҫ:v\w+K4Q}BSެhȤpAK 'ppAte%'9C'|P11UW? sxÊ*7:1а_Dik`0Rv:3ч @hv /IV_ߧ=t@ +py4d @HYQ]c^6F02:Op|c'i0C_1CDwV Q^y(0g `f_F^9E ;b<,0lQBdA*5e7(qx * +eq38:tfG:``\ʼn7]rHgac)5,w OXN6YeS Hj1J1֟qE^.M.J$9\ߐٹ1Q)Vݏzbrz 5(y M")!9dIRĔ( +'ڎ` WlCbt*v YSn'`@&8s1*Q{&NX6 +WB8 + #D-J&U$^ .5}S:GU+P1vcjVfZK :PfX[g\D +62LcR PF_DזzCJDӟOFեqDkUW\kO-;i˯NYUE_' #gYR2ܵoh,1 ?Hv$2`Տݺj&+A$$P[x?epHft00e+8MI_';W^,xc-Ѷ}< xODS.4 }߬1_sis֓$W&xt 1N/,0gaX׉fvLi>$n,B  +A +hc!Ja@ ujy][Dq'Xp0I3M{QZ;2試$ Q3)0][Yl"ψХ|-Qʞp >!}Ol/xp婙T=GM-1 +DӚؓmܶߍ7Kc4 [CF8QԳYOX@b Y(1 ~_q+t6mChH2(cp!3Cח_ӊއ"8DN>O%>7c^rҪb_~ +j6oMb| +a OacsL0 8(P6n ==o9|`VCiE2L'M}z9mag8< ̖ͥ^~^Xߋ𵶞~qe8ڰFNșgnO kumM6|DFc"N2ևtDMZYӔ7X.Øg84=Y]{U]ɯŹ+pBwBǟ9gMonN%6d7`$T*_YE! 0Kd8bѹ" AIJ"CL1m-onS΃8Bc =lXݝOCz]mކ[:HgH֕5??;&p9g P]q' һs9%/8&~`8gXbҗE94P-Nx .Lfn@]O>,,ʓsC_ A; 29s>NB+uBv-Ry* ?Uʹ +~9bZ |'cX'ۨ6]%^R}yE drɺ|N ̸NMa>K(H,{EG57+0 ?eTqGL޳k؃ +`YDh 4"" ˀH%-Dp$HD[Fg[]kڪ9/sUs[{wEuysx¨7gx//z{/ubmɤ}* bf#0GhKfe-,‰\U09j+uPvB-d8]H,TIgȏɵN0$a:1@1&> ݜ%yD*ipܺ/4p[W.]"d۝_wb(~v ar?ktXXuCUx"ª;r{>g:1n dߒXcEESf +gI1%|D=זky66Q݆v2vsIo-Jэ&:}{P2(e62;Dm9nbOqv2V%k[!$8nޏ}æQP'[]~s5kO 70"?NMn`.6ƅ·2v UZ%NƜ̉I=>-+}4h۬9fY'9 ]U_I.LuZ5kzSUgcXU,' eHnd,#2&]f"Dk-b~^[r8뛛n],e$(w>\8n3ä8H\쌃L0\VPT|0H,\y^ :P]vN2I2#ΟEۛuAa#پeuV\K;O֞<*8in`mBO{Oj'5IMHfTsm.C6Q6v }W$8vCNM60c7HUO+9e`t%SSL!}bwKcH+$Tw`=v߶Sx*1w/ EQ83ֵ%3?. 97c`@b>[2RvտbXr\堪UWĘ_s>[?C]-zhcʜ,a0񖼼Ek +USX +²˜;(Xx +3`MX@Nᯢ7>NЉ_ؐK6m\ iSbYNOX(,"ݝ@6q5jR+uJ42 A1f80ܗq`0r:0 CAE J,M\KW_YڿUWu{s;& )h ^7aN zFEaُDZ6U[ B/Ih76U򚳛rxX>S'n]cNȄOIKBLe|zߎq2HUqI03?駩{ QB3.9P;i沨'GN֔|%^2ojTE=b_R*`n-aRG|+2cq\ O"m;4D͎x[Y1yt^Y'܂S|by2t cg׏_|aà*υOF,X!Ō)2y7Ti@~<,Ut |oZMT8ʖ).vb?!njEp,Gt.c&1b4V:~OӻDu'piiQ[ĂHe|}hnh+ i*S+l5nvs_mlOÚU<Rݲ pGtA7p4Lx"Vq¬Wawִ4 4e4zՔYEFx6j`{$(.A2:&Mo %P n)ES|)?ԂBOUzN +QMb%ˌ_ wՆ֢!}=eLΐiL-Dg@&}|(DpFp%a%KLT g@9P;{[fHN, ΢VɌ(o#!/~|Q?'~熡А(GO<@0DpzwΖ5r%ЁVBz1ڗ'[-Uxn[R[0/TjVDmLT:jBd[g(!N=ZЮ-6犌ia{݁^y|UA קIFqjFkA1L9X6 v:⪓]*gN-@6bKeb%n0nWO!ԌV 4f1 +GMb YCʕ,nJ( sruE%f>@(P9ʎڋ2>'&zU[ +PKba?CXGᚍ#5WiJ8|w-5&S"]`Z畖WDxiIA8tD*INhڇ)Ju||o[GꑒnW1`>@>:Wx_|2rsu3'0ENjI,Nt^tqxԔ̷7O0UMRm|.{zV&/Zx;05&^} o)au'mh/K :ydy(klFDf–zB./3 +>yOY9(gk^fv|h)=wOZ{2hK ~Vn*dabBfI띬u:j feр1k'W QTp5De0&шk"00ofEw1࣢+ZQKEYO݆ݷVb|7=XvO4P` 1ʏ`@,ݕ+#_'a&8(el3BԘ5gɿ^-.]^QCӢDv6 +(Qm,G$.mzZ~Ԩ[3ɖ]B_+nqp:i"?׺%_ 4i]tS"R7 :!}@L._} &WOI#%*D=\|/hU x[EgU7mQGVF0=^sv.͵5fs;nK@?-[Ke6,t8|CX^Mp^-2 u"s0"yr_)̅Wt8;#i;o8EPVallh2 + ;thCxX|ch@rM@,6Bx{}AާAOh +ձ{H"/ oSCQ= V] +#0\VN#!b-m~9ń^Q˫r:0Щ78c|yDLxxQ%W6Y5c\j<iJp N= c$en,ޝgSm4H k0 n0,k"7NxljC)rs\8C!HO758H|A@pm?[ \x&B?X%tGLƩs5߉tD%gJ& aa7Lοh8"}Mg1ts"Y"=-5%v{ի᭳2p(^APM:>-Z_B`JʐDe-epzIr񢹵8DPJ2T*µ$ӓp%؎<.an7foFu"En*i+.?ᘄlBr4Ut(]I՘FRv*TWP;l5F-Kpv~I8%Z%zkĥ^M֓ IVU6U8XQfm/6M˼Tw:kuâk%B<ƕ=ٖϷʖ KZ `60;8XCC.a96Rڳd>' ) 'AiJy#IJ5(Jlkᅪ;!+ひSv6{(kL,uI+>v67) +m4Ȅd4duSV +(RݱzWyB#gͽp=c< rC+ 5Y(ELJCt\hk\v$__x'A,Ro%% $I^ T֎7Y4dR$7V}6r- 86j]$?]68J\yTSw$9?B+uUljŢQ"([BbYRIX D +D|AXAъ +UGk-3:eƥmn8ys~ neo* <3Bz ) 9ZL6fjqV}Ji l1WLJ<^^I$Ɔ37Irm4DYRER}VԀTW,™(^y@B 0OxsJ92 z*(=2dtKsIs&1K6.{2Vhu+Yb.}]$o$? 9:ƙ,>Z6v-ݩkL cLEJ9%ʬ!Q_itF~BB3ck 5\,B +f, +.VTԢ0,ꄩ < +N- +#g.rI('f]h`=eq1M兩8b0YjcCqJv,ɖm_!t8 +b%t.vG ,E7Ql='_uƻ _I"83wߚ/X́فv!)p8.m3{I̻sw/Hh{ŏt#a4OO<.褶ԤatzZcb +V)|+OͶk]J 1Gh!vG1G> G{LFօ=f& +'nIGĚ jf5r}u =,3:!M},tT*JShNL{R^YhryW+z-8.h}BsPjI{HyG*u%HWR!&8H[d6d{ GݯkIXPe+ӈTt n{ߊW[&'bo&A{ö{է7Fk\b$Sd?g"]Vz}ƨeu ]K,%te"kIvDyVw q+ØEdIWְ7o{ 3# s<&>aTիP'Aw\Yv0@]~By- I!&I^ȋP#Of]2v"o;JIF&>BB66$lL>/WUTJ*:JZIIj\E<.gZ-=*mSմWF`zǨ$|gD*YJbcgڣ13h[NBDED +EԵ*(RA7""! / &ky (D)ŢP>Պh}/]CzGۿ93'}~Vc3␍F!qq4tI,9."TB-vQLg"6M{Z?C2tFbATh7(PsfBjfLհA*g iz!pڡ9{殛*4bU!hҐLe|{rv6tƜqtӢ3va)%9c?K6%\FA\xb:q70GKWBcؼ-HVOJ0KH%۶/?޵h";ce'P[GCUix|ە`24m.NT-7dd)sna7m6^dj=ù8Iokw[}#[Ҍ{ML2fAeł +X+޵b'Y%^I睪{cBXd˅צ!tNז bߺaLR[0^Kr9/Sm [ࣖ?"we[L`?ĿzTl`7~7F!Vdx8|w(*.˹#|eɿ5yW˔ýpυV!{uO4 :GI8hRyg^yIIbޝ(,F5zO6Ii*9kS+)ލ M&J! +dQKJkI'PS"p+xtD'/e̽|>=w@hrܴHilXF'VskvD:vFW^W"N;B.k_ DߛVธ }fVjLe3I靬& GDJja;ƀc05@~*qa`U}WYrQ HKi}|ɵm-Kn$ k=J|ܸCCA\㈡e r.(cCtE{qf.dMjV20 +Rk'$ +1~sPI:~jpgdD)ӲҳpV,S8=UZ `JNcaY}SALئܟUK+<0_y|E[1c p#Q cqnF\DSЍ,65K{ǓN-rʰ]'j33q&Zny,0Rr-B7b()߿Z@W^`Gȩ-d p@#.q/$xޮVsƜCVݤ'-?\oc`!R/PRdah;;m}jq6SSVJeO3V/̓=ʯ*Q1xYCfFӜ틪`~G΁HgTuM`"LD6[R 졓q7cf%1?׈S~FpP]٬2!$J4@{bEKa9hX\`Gky h693A>MGgnΎeV +)Eg]ã_OVi)e`HDTxwh<ݜ'|UVx1ɭ> ~S\hxĻݲ]ݏ zIì %Ԋ=8&#?F=ͫ-_^ZlӰ.R{ %h9< +b^5)\ۯ?a:8SZ9tƾ)"f+̳ro J0"T=3vFˌ1n"t7,B@ٺiYdiEQ(`PK0̙[+ΙsN~=ǫw}tnKniR2A)Q **B cz;R[}"G?oLx]ܧ|c"Kn2*Xz rSm9Bf@ڢ<lz2W09t0eX^XAx +Tz/΁uhw8VE"i3Jaw^wAwcUm~7ijSr=4b&2UOwD鑉)NiǸaJDr nmIbO_jTy%deJ"*c+jx鐺>tbEjC# swg/t.o&ۙ;`s9.yyG0e ޚ[piU~KhMygU7P5%)a_ױ>-.-}:;ZCѓсqoia?p{F32tOtɥ_i+٘~RCx,Lw:"hGV*u;%:PR@LaXl )\l2]'!M;g;*1 :s!i]IPZ*;fRKJ4;@-##T,\ܲ!带0(- Uusd +\zMrV/a] 044 hB6J6vy4yj1+{>}+j%0A'8mts584wO?+Wݼ=g"1d2]c:0C \f0 ]`}Q>G,rqmĻs1+.Ľ]JOPf(|m^Y2V`ˌ t4>.ƒz_ڈ_ݵ2Vjּƶ`[~[Dcs[w kއ73srNھI jMAY +itٮ ~`M&/\doC&}!'4BA#GN) c;` +o{S#I4 WL+in0FDbz% "Dq cY' M8q DeFvf#]=}kgTW7WDC ʏm++)uX2uO[#8+3q<ۮCNm{ F'/䯙(p|U%ۑlFޏ#B>R]|/Re +/YxA +פt&w:esAjL[]S4݅g ZC3Ӻቤt jw&(fQg6 WQx?cU }?ds;;.|X;Ñ L,߆)D Z(@=*\HTJ2ߜelA +ykNio @BKf`lMa"0k RJ8Yo{f}5F?4*+ {<ʰyZcATP(AL\z͢*, +MMw {7K4ʨFqtOn[kN}p|uTa #hI=@VKlћQf +QZ9'egtʾtOdVvWe + ++ +*9XhB㮖Pc4 ȋ +{K%V vLFnFFq3~앜+B"5Fo쭺j@1[XHp7趰`؊Nc5FU[2NSOe/b c і[أ59>$Ϧr=;wrZ/08݈$ň#I8EAC,7@ 2(`AtɨʳYa(ESVHw*\£6̇/0HYW݉|s%YYf97)CyɊ愊2^^[v`g(YKKe~)^Q6]F3_(UDd(`9;:Ĝ_D;##c:/|J"K})Oѥ;×PO04Väjhu 6ujrCj% H6pY6Gs&]b{"h VɋMj1ˌ~6eCgw\sHsa= ye9K uS/_2Xfl >ʟG:zA{kpXo_Ys'gU4זwoDo'х tJg:CI#n]WD70tH* +xWj8r֝[6Q9i"DM3[CZ+01Ap>D%f5ߕa`2K0N't,=P39':".^8uH%jQ +ݰt3[oFk3+.#rLz~;`ẓCGk@=jRpU̐դ-ZY +~c4rbDt]4a9Utʯ;xFs-|x͖Nk/HI!"iɉ2lcE-7j$ Ƃ3}eH^Kla"G5ȥDZmu}ɸ^ sA߉rEqea\WIVḧ́HP_ -X_8 $feQAf0qQD@EDEJ\RqOTڿ]s߷%)AA4/eG@[gP݀տOV(b $A;v$pʶʳI9NFA +QfjrwFNỲBx]n6PmQS^4?eQ &wUn+_֋<|وvK쾇?Z3L: v`:S^VƭGhVJn_n?c`ID, ׺{W{c?2Ĥ7aU{~wHfM1ɂ' [ƃ0z +dcM4HTXOc= +}Vzciz_`PtAG#a`smleGx,У."0rq!9 9 c6(Y0 hjt>iP6W{(Omz$^C8+Mf.!H߆7sNhY -Wp:"\$g*DUn"L K,J6""@;bLƒUDʹ#f NdG}3X ֬am>?!`{`wI͕f!GXr ъ'MRSY}I"*jOa̰ j2Z,En/p`0$uZx6MqAOټ`Chq=vt/O_ C|& ֲ +2{vQ"w0Z)Sk5jRhm&,x;D"48qIHSMep1=b&T nlYa^_2oN8 c'p vT$<X6OlzQuV:ct^{Yڒnu/֦jʎ +~);^kdPŦ!ޛÔ&VڥZVꅮ_kɚ;'DMtVTT!O:N LeI͗s/ W7DJsd _jL +_u\~Ƶ޸flrw8LSvSqNRB"_ƶ4߬e2^DdtncOb1_0hb-I~Ҍ.a0ͯ0iCMVeEMkJd`-^^M~`J; l#+>VX,ֵZ--c el{JI)dpm^9Uz] V]{KFK}pp=r4b̆ N? D5* O)+2%t)'_("g:&VcuxQOѣ- /:J.8onǞONF6̱*wmOL\wsp 1m}\n+%nE˞+28k_d3ZW>VXԌnϞuDUgl ΆJ]8>}eo2qUYeL,2*I_J $[i5դ{~1H_1t`x%+ĝLjo@,9YӞ&QmIU0H_v^Ft:R45/,+&+*,,&e5 & mmT)_"TWyPg_;K6cAf`D,`)lJspEȢQ`dL"g 5nSbHG@$QJv}MNjfnUwW]](:~bʷ#(+0(R/ JA:LjlghdʝD˲`$uts 8^n2Ox# {}7Xpܘ7seB Fmh%щ{ooz)?*6LjJqE7xHeԅ{vԐEV.-+ޫL4|s +˭v4n9a+n:Nt'5dm{GTDD mI00[= "Yx@T֨E\)/Oi"T@+Lb6 UF{|PV\U@(`fz ]mKS 8=v4?WEtk?jJ27-?۹8UX`=|4Ds5c_VB>Peۆmq`+PG"/Eׯ6al}ֻ陮3=iNE9Ea-sp& 8W"`JnE,\xm4v̏0P,&m[͇հ:-:7% /t^EU \%0k;O,\84=aۘkjySbhp&F ӽ]]9|Ϟ6/@N-!-Ό޲@ٔA5@ClÆ9x@ #YT:ڇ;L*ot>ES>R/N|( ![,!~|6AXJ讥 Zf9i!9Kܟ.8 -yHLK4 baN6YvVǰ\;E!{'P,(}@Q^I-BRE B-i4Y ! W`k1qq[1KgڴF}of2)!VDs:8a8Q rO{qpJ$8װŴ9?& (Kq)0nJN~4$)Yx{(.q@ñۓ> z_qPAۙ&x OnқxI vi.`;AiB3.[W eIuO/e tO.6,<{\obTԧ/ ?;ˎ{ˀYJqfJ=]jKYwC4 +Q`a80/*`a:LG 叨˿5p]!VoZ; 1\d()| - "3Ό1ѳuRז7'R)~@mї4 yY|{h9%ҔI1LB]%UfjeP^a1Jq[ 5SsL$K06q|B|ַ6VU{BULbXK(cּ;j0_HSu8n P*sE5'oT ҷdM$3A%B-g;*,\ohqt^تS7p9.Dg=$7J\iR 9 \7/ Rq'^t[#R2[\"yc.Gх4㔚d[ҭ<$WyXTЀ&Ø>P  +:V1`Fga~Tp%ð@vfhqqƅh-ڈMyks9X m$ބ(c! +0|ֆ:}__MJv_e&_Or1=Ї$}NP+ߡ87wha${Ŏ@&^E0s]ZΠ&w`51.,@5][6 +!RK?/NJ>W+RNN cqMMNҞ5`ĦK^_c;iF)څؤj+fMH*$B|aYV(7΢wXĒQZ jeh&Q; _1׳UU66ipf}#af5X+ч+;癹מhw\I%~hW j_ +d *դOU7S +S!rmY8 p8ޤ1׮`Íh3ދ ]ί?ގӳ!I~V$K0ԅ0zzy˥qԆޣՇt8aN_9)M{k1ٴ__瘡 .8@aA nL-.0?#SO--4{@hi]Kb;TO;0]_wprRy'gxCv`,f8bGblXuK$Ɏt@8ن|b&bC3?I?hU6'zc'4?NtJ` 9?8l)ږ-ԥW)/+-%p +ELZ;v| ݧ/Z=NKW=s>F>}^PSJPI^mCmYq5HF=DOXDD6`V53ybT;v̈́L\= =W)4|+}TJ5C![,JmwwvRLs4bpQsw~rhY*tYDi^}|A6-pZpjh~p^gBKRۻ`HP9&ۃ󅀂 +͝2Ӳ*iq:Q(sŧrxiE?ʺj":B'w7,f:DŽrBV@Z!ݣ>Y0ۦ< A!d+:_Kݐ@|0_qc~kt*bSQX^X;^1eݍUnvFO﫧5lRi\׼lxZ4k,Y `cVⶹJȣ4ed2w)΄EǨB2"J]w^n +BI b-XJ?cXOE)[*5R] +]LfVj+FʺR loAk4(.(G BXaYqR3fR(|ԶYyf3hom V+!$+'1Q ^@ 20u \cqKp|H]pX61!\2LPTǁ=$zcc !Jј ʂ (?EXe~Xw%˲.BQc5T1jJ(kiyyҦ33|=ϗ4d/0 +tuoŗ4:"6N =јudZ8%2eQ$%hȎ|ڍ[砺 x.:\/s +>y B YCٞ:> %>#Ӝ~SbPG %cB#%;<hȼpF2[gj{.*$V,d ~K ʂ #z֍`#;xXˎ**3*4S0G>Z n :OvP+ɦc8@!Lp f Yl (4W~B}zBG;nT?8 {毤 0Т;JiT;[[7WKvpBXNC4:xkeJ6|Em*^p-GbG(ϔ%4t3ŤRٯV F pmlDqdt~lV8yvxy+mRX@__d<8Mj5G!LJZӞꔍ| +jq!7{0H.G=~7JD_%V٦aͺh (qۥI +@̌[Uȷ)F's P +ڙ%GkòO +.A70("xOPP@ŏƁ2#J {Q7ÿ0cwFh3`A_O z:1n MEo7ulpXmG HdR~A\INWaaf8H +[X|32>ɁHxx>CO-堈xK{[;]鞅?C v3@Θ4oj{9ECjt69JPS ǦVI-6?1#)Ug:B;6vy/fژKe4Kk8, +`o1MW98_QnuON_{HzEu^̂dQKW<3a.S@O\´6E >e 3KV55'i tA|t|P0GlQƽ&s +s%XsjDvx˄ [ +endstream endobj 57 0 obj <>stream +HWۊ}ﯨgÔ2" +CC% ށ}Y+۬W'2oP՝w 2˧û??2|w?ӿf0Knhiiam[]DMЯh +|Y^98~#Q2s4 ;nzsxDe*l 23`&]Sϛz.-eA3[К=g$Yި*aeEp,Tر0{Zx /U5w;YlsF|UF~6\G;|I H#/fd  X39T?]YYf;%c#D,="F[i0+~Y`0ÌOdf;bizp-+^kYQk} +H-7Y `y˛4 c$!rd1AJ-ş1Mқ}?zv>-v h*B%&vBRi՜& BbizO4+,S@ˆ8ҒUf)F\mS@I"75]_+ڠvrwGO7Dߓn)qEw$e$4AMUGl6x+xDЯ_uBdoE&P%Z=8L''U'W@lZN`+jJ:ys7ϴQZCwwfoWlJo)y6)gw .+܊51Hv+hZ.,*5 kj3hˡ۞_j˚=жk +v4k4S!D;ÍjQis_:Nkf1ɗCTxh/ebq&M [OFv&P]@<Ƃi{e"x5\J짬UYnc>imNuƔ9S+-P{3Q=ZslUFȼLʷ@#$:o|m7d\2H/Z @î7$1:}ZTXek!쪓) b͉!IaIeyMpQ!{!=VP>$UF;dv$m>ʠՙ@H<ܬ氊T~S\ϤWn+H[f NAkEyW*( gFTq`HûNA{gRhv%6/fR{}7sxRsOp|JҎjNa`[#`Otgz_ɗ3VoE {fsヷ.Wy \*}~s2tῬWɎ6W +;À* pb 89K~?Z3=3-X*ނ:v } +DGe s2AE@>[;^OZ D@XuFOh$p*Y47b!ɛRɰ j>|+*x+~M,cQ^<ڕu=-8B&X%G#01eN N vU /&?M9wI`u K^C6фѽEVac5` OXTO83"NJDqMr+az2e2F6gŗ{mI2(i3.$L lgI6ШpqH$9sp`N|\<^MyvI5_Btef9ffbfCۊaf ́FoB!V !`*FN[5-|@: +ph|ӈFj"ki0@2{CLc5J;makd.X !nq (XĎ`8Qvʡv@s6ՈfP?EXo@'0Ԡkb=8,+_ 6* 싢xDD+ԝx ūN!XܒCv;cm'(I:937<%sknN$;pGV^pEbZ̩9耗)C<2HTdC{U9 ;3y\]GV8y|kX,fTi懲O?2"By@>E6B F{vﭢ[b]vr\`' /F~CqԾ|WlM:p~O3~~~2HgJBla\P{U,o K"@N+y&ΥB͊mDjҐD}h&7"&b3Lk +B٩!zv:_J_ 58! ifH9E@Ff과;Lcbb*&%TvEТCs 'Tѐ% VK4ZxrBx$y< s#X1ti(@~g)<312JPPUNE52i +[Ƃ.AM|Oeޒ 6qm3ODm'+]';Z μ6:дF>1h7jI<-/n76uq)'u1Q~r㯾P8SG=D]k?on"{o/Erf9YE}t޼>|:H`>^Yc@(MC Hv +MU!oKC'{LUBLC|{LM8 Bl_u1Y?;5>_yݰXKdLB +=w !w +3:`;/Kݾiq8Eerdp(DeZ'k{ku&I?Ԯ~KJ J+7j,+>$Ƨ)ElL|09^z;j)e62z)zMBy<пe #I +endstream endobj 58 0 obj <> endobj 59 0 obj <>stream +8;ZD/4a)H3%/*fs*.\F2m-U$AGg)DqE/8,J9sUQfAmM;8j*qr.Y\Dt[a)ajuI$TGf +:GT`#_57'o;Rsttgn4IAZhj8C"4'kp@@Cqkreqn="E$n-o>)Z7EGTeRZj>@MMb)d +)DDUO/iq46KW>79?aE?[16m)`%;$VkMd4q_A*+rP4h^1&1ml!tAb\9iS.h2G3*+os +-G6u^ie,Or*4)"_[1@@["#5k&=#,KY33@P$k!;K.G0;6KN+tX\BBDdtj<#1E/YYN+ +lF<.5eJL"7H'We!Cd"6d?_]>uiC+;H"lML;==FKjru+7b7R69;EY2E=^'FnT]L_l] +M#0@aeaMVnCA9oAMYaq/NhDJ)]j56H4&>%cf[FGYaR#%+hEOKm/Vi%Jc"N\q/Bi6n +Y+#q^M+3H70&1.BjqX!9*HhWZ"qjksh7P&fSsuDgi:lkm +8)^2*?)i9LhhIXhY`rS]r!i^d>G(K~> +endstream endobj 16 0 obj <> endobj 117 0 obj [119 0 R] endobj 118 0 obj <>stream +Hdn7E, QL  FBޱ8,du벪mޖp^_^yr%hŧTccyYlI7vU) QF83r qfu=M'P Ț5*HN}5 7b6' :N足M%t`Y.%_~8˸OPn-PFpBxSGRsv3\G%@]ƂFa Ln")X` ,> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <>stream +HUm 5(SZ~vt!#$mH$~IQ pyZ՞9(z';v̠:_6|:LAp 4RfYa'ŹG>Go,[F.vS8țki~WI>[πq<_Me920"eJjw83{)P>9Ц&ߩ^uZ΀.ܲuPR!xÈRe1-I ׀=hϲYZ▵J yUf)Ip<(H\ +NKBz:q`:od" 6sL,_r+x*Wn 0&7BbBY9 +0 +endstream endobj 123 0 obj <>stream +HdRiXSW> 7AI^B'A0oаnPkYۊJQ(Uej--Xp{:i]uœL̏s=X,N)i,nvc9fځsb- 'qC6L3 F$EeS$TU5j6*&X*d3ɕ+ r}UM?ZWhZTR[bj()֘ +A+֖0LqI49"gQ b$A $E2BQ +GH"Q)P\Bf^c^z򞒔J:%}}^6v>[~ke$eIIBQjJId`֐!{B< y[>4/6lQ2,.'Q&y=ye$/Ryԁo(~p,;OuZ PGBS}6Qˤ[hR6*|x' BΟo> +ܲٶC|X0 "qQ>>P +QC_ce;7tvquaQr5X%/t+Ƈ'wa엮ݾ]m?`@pL:.JDgZyD|,ҖIcw_ [) B0Ty\nX# R=z^M;4LRqp}P|Yv  ̧.vX=|P_,B>7_Mw5'q 0H7M=cD#x9f6jrkۘjVi RǾM4po% p!!ɠXHKЌƬۨ͞nvt\rw{6as1>, ܮȷS 2.$o'̘m)x % +hHYcFfvfVV$$De (+{!K Bs I+2XVV@}H^0G1P@ +u $=0PjiCWApN2&a,2N@;yڞsqOGd_;yl!A; (h*lI ͋6kГ.4fnqt-[ ,-VMiGEa:hi"(! + AUQUDV]0 +"Y}uc {U}U}_y+ź̗0-zz#:iyE6(Є{9c)>. $VLXw., &[ס)Jb5 +!'bziV*0,=y4Z Z)XpݸHޒͭkJ|D!hѰs5鷕WE(0Li0Xu=Hog镮yÒBətYG54;$JTPI7rls #=X]$`'X;왋"QkyX?BR7W[FՊCV4ԽZJGI#Art *\x_.#-6x |UZw\ R8TDaX(Iq<-TB G0*٣g*ɮ)>r4oxè9sybۗsF*o/5&=w+D4j>aF(,40R1dP]Cw/<[GDwYy(IrKvfj~PP* dF7fĂPf4c " B;1}X%+wbK-Ivzt潅-0,F3ĩ6jT@vdw|kb؅kC.4ՈE ɭ5;g7L, :UC]/ `܉̟l +t[\%=k@ qNQ.7!o.0v`Y44T.^[+6"VHBMGqb?]~E7w쎼cA%lW0Q3oߔKv7ʚ??qZrE U=*9pu1$;gB-[sdŠ7v: O! Z5V)Q SA{x("NEdȲun.?ᙈގBQB @4(',:zKuNz'8 >пq"gn;,f\ hƉp<%hP?[MR&{N޻ХAT4laJ .k`TA&,*#PjS`~ݲ{j]Ws-Qk}$?/4&px(#6Q{A¼wNfƆ`t/#/[+ο FfwFp (9_q:7+* IVM[z6UI=|+UVFI1LtIHz5pB`Ƣ *%Tب{#-m= .6^bsW|YHCx]^ۤn).Di0+1E's|oO3S6fD .4Rmۑjw!97`U-㖣T,r/ct Nٷ 9X f=4t)q029[*At92+\E VhV0[mUg1 X;Д4l U͏`XpOpV64>Oa5a z=vFkJzPdu*0[TUZ/ +dXƼ]ִs6\ARaTFNbCgb +ى%-G!o}%ciEw9G}XT֣3o}xӗfЖ޹sW[P 8oEzك?z )cmV y,<.dBKAF2$k"{CjCv\6Wa1y3 Ã8$N0G)>Re>%Vi??|iy9Շ$czKg7kѩ>С)8N{ݱ<>׸;Fl:Dַfs겺\a1k>쾮gRKk*dE[hMҡ萐]ZF8Y;uM5i:MhE?T:#D~t9v=9s~}~ﭮ#aKݥ"םgh~g,;jVJ+tJ ֦i_xi +Vd$D|1V'ԗ5?_Qԥ&F0 $l0FΑ*u<}^c݋Vh/E;hхVU;?1\ U u1Yxo]S! + +~c-COEF .sEƄc^]ګ68\`wV_VȮ_a9o|P̰QQ$Ѥu3rKԲbM,_ +L{1m4kdowqW>9yT# 7\{q%WȔB>' ZJMz,5pg>惥\`򠡏.mq-:Pv|Lk: -qX;QRLM϶͙W.!ķ&o@O}*(LwtǍ葋Yw1 b 2[ʪ35gj+'9+wnL2A9Ji#6#'l@=%=hT"渷&{lO=bqE7Q}Ҵ?{Wu1()m%Zon-&)*͹`c.dJCÛDq+(Lnm|b1e2Nl[ dlJN٤V{P,FZV[TscBc~H`͚4ͼl,akS +oC^M0|R[uijczdwYZQQhK.Yp .즗`f([`p)x4[ V]S+KM~[ueNr!ww&\G% ^eh ^4w~SCGtʯ],:_:q\&?-su)8uk7Ia'?,TC)!6%-,)~PzF'_}RvSr}]7"eƔ]8)aU%E*5 OeĥKgrl [aBDtiJrhƷ 'Hx֡ӗS D=ъ/v^Qd^tL9_eCmE{.Q}vLLa`R pfvOYEj Y>q܏;_fTgVWN{Y?dٍSie@A!ChbA$'V3pc3SVɗS +{~q5uo`a^ +wV~ߑlظwo>del+̏w (ߍUx$rY37x>@ǚĜB%`Ng1Da?.'6ռp`s> TO/>3ݡ"Y_ 7;]m+χxm]ˈ&f;OB޹=Ewc^ ̅4±lxDۅ?۵1xkj]|da yp"}q*X%ɑZTԷU 4!8^֘_T %+\R>XK6eB +K)7oR>7Mi*`ƌaJ;3zF(W < <+sQ"\n8e3\7M1&ЯsG9K%H_7ńRoLs.fqe'jWlEY'[;bfDF{`_!l᱇ sXȆmc>u]ӂ +q~,JHbDAX`˧w;(yl"^!G7e1Ӵ.}WJ=RW6(23l[-YuU|LJS3Em\_7E u`LTol |` +JL<> W{muNt8>%.! +h`l% I{y"i`.jrAZiS _$p+` G`xlW +8Xss +$R2k| +Lf|tU'Qۣ0I q[=!pKTT:bEQ\`,*|7gh`%Ktv#$$*7OKS+O-KbvJ2lUF'+pʏ%,=RW ӭ}Q2g-}|<5Mziƒ +"a{Ґ$Ó M1L+. }1S|-N>H7z|]PשE\>UhKMӣMt,cےF p$W=P_X\Xp$f`+I{6:ob|cFv"VYMɬU,>1#?:DO'mf`6zN]ɥe*u:gcF))>3眮Cn$OQn}FqZW_:Ȩ[5SfG̭-;>U(=w޻p& +[4˽oao9/t>O55 3V&v͊ !;I aG{=r2a_1D\L{[JMeIHIt#)u5imL?iYjӎ4&72tV7*?ނZzEGtD4a +K x3"{+xmeNTߧ kxgИ*W$~5[]%v6 +Ƅ0̠,>%*! s#E*mn9*D@W?NBx ^dJkOV>͡@_QoE_ &lKa6c9L[2s`J+xhb zAIQLi?it7j!՞3#b݄]frG$~o0͓vCI8]75wTslkHCqG1)3_/=9[8ьv&idKF+' XQ"ZLyL 0!l e:oGƇI_ՔےrK0g2;<sZַPS~׽9_}.جN"9B`ZA︖)*RERp +1a +bU1R4eJ%+'RXg-ahzŽ/Qerh_ՁMkx7m꛹*ŧkϯG@˅*$$!f9K)pb@MЙT>A 6 dl~Ιn^x!X> zCOH 1ϔlD-ׁlBAElZtZDJlrtBɼzuk֓KYҌR`2,e X'b4(R;ĮÞv% ~ݣ+=0k֊J MD K"q +4,d(XszhhsǃKދՏՊa=[Ly-s9n3{<`#VB$ϤxaPR+!-isj̈́U"ɬ*2na8n3\nMVYNɱMƃ囁W7ۉs6pXD&ǁfhX=,r +;Y\atJRt+sLner +#$h~R'-c\E"'L + u560 ^ɬ,Aǧ[BTOU._bU8>HRISbcNqa̫WsMKMOM1PǕZjkhC.ŗSӯ*:8TIF9G =M,Μ=~58qW 7g} ]]WiTUW˝/nx{}i{W|O׽{'Xғړ{ 7BwrW>y}|gc!|}{V<$8|u^Y>s^2zzH: M40!>6=@K| 4_!|t0\LNKvk/g-'=N3fhqDvs_|[|m}5~kS[AZ7oOq*pnr/g!]YfTt3qhuoUX %%32eVmzX:PKOh[zE!;ʟb3 + Npfjl='zpˬ2KEׅևon|Wֺ}!A>T# ixU>YD1^Cλ9Jp1 )<ԝ#Y'/@\".a+; +5FѸ$ˆ&kCejmF[ j*]]fLLWkSA$.$!.D-I :aʌ\#jw[mri"uPM=.R-y]|ϳ߻]>[#[b:} ONta22sQY%9y93e;Cw%>' 0a@AFT~Ye<񎠣fLG=-d8%mC5Эn$}FxjTƣ#q(vw?D樝lPh$J̉""9E4'^,QXBx'~)7VtVY,'.Gmvv eӓ'(&a"#7A?U* + ~Ⳣ!)tk Q5,oEĩ!6ߑ^U):?`5>QMNEUT - LqKMIeT}Ts*n\m\e2-+5! +ft}"h04 ?K_t [k^ja*YC1b4>jop0|+ddAÂbM<%)svUjB^ -VX@Hj>SK'-&x1{2å8hd'rӿj0> /:xk/]79!e20eUyj%bqikl~19a6Nd*k*' ᤸSH1N*1|.əeZVL D00 oRcWy4X7[9[[O߷ڹU!/ثP`98,N"4-F9P-1'Z wH+$L}a*~ 0z F! 04ƠGu-y,JZq<͗A lbEbX MvpV'6CL +{a+a?EguR钡S#Z Y="wCc GEP@HmSRh{\N ܫ %Uk&j`ƚ3#1{Ǔ0bpGyU +̊ C 4V,b3I8Z Ӟ^ZV[T=xU̍ZJ38또 ^:GLgH/)@Fzm`?,|\ 9Xs|nhfmGX{IXD8%.GuD2Z*%Rg[H=|T|>u\q&K;oQwp/ë79tB?QW0]0|- %[X7*TK 숌ǰFhWߗ/Zš:[r,Qx]R(X6˽~L(C + u,(UЉqvvV@MO7tbfvfi5vW@0!5.TD%/Q,Y\4Mtwا{M$~yePm>m+7ukz~003-ɨu8 H 8 iB2ANHc`5}F*X;`֍(i!٩`C*Z믕y+[ +%,UtS-/\_PJw03a[p)grMYyش;C2Yzp+[&:Cm/WnS\ǡ1M9z*[I&]&2^Ēw|lo@*7?$)8)8Y +YÅؔc)xZ%jR\\T\X6/m|sQ?iX[ɼl)nubi9.&4]wjv耭ZE"Rf PR$\u2 KAH\J0B 0\qX\Txc9ag?oy= A{Qt +G"gE#(,bvHZS\Vч,Fȴ|3̻?z橋P.H^!pޓWCbHQ8 Fqo-5r떥 oes4{ukkX`$(4)-Ő3S'DY80}>xT kXNJZ=v3"[9:v*+%xX wR˺œǮ-rrõ[ďʼnd UZXmC%k;H0".-/**[k*W{AI#O[=}U =Ο2 +q,vH{|VNLU)EۤR^PQnsB7|3y?J//hRzk,=.a +9/qZҎ``ëI5gCŚ. -@Hs=0eb/[ R.(J1E)J}c%Qh٨쵼bZ$ӞmA3YZBvgm]mtM2uNš8GIop: 3Tk` 4k?bnfARwaai'hyaA< X?PK}x?NpB TmH +E8qY+n;}eB8pi˝9Ƥ3:J5æPy&WV%&Kc=ϴ^ ߝtZKUy\-+W~9g YPS`_7g; +jޑÎ +5i9M'ytlCIS9?pѷshmsm7Wq33ڈ k(]Bk ]V"-[ƒI3榷6 ypZC@}4'Jb'Df\Ih ¡7'U舠YʤȔ:f@уoϞY(4~Oj;Vp'YxX@nFXZY,+Ba?s"CIGޤ0N:rͅγ~dcFn:|7%`ZP_4mb=_t&>/p@T~lIU:^N?Ȗ3N9XWBrP5zsʍs/1vw}ZGdcs2 Xؒxͣqg.YIbE|#~/*U+qа^g +r_D=D A,>[$U]4REq"!\1Qmi~}n嘫kNLy{r7" +OFX Kފ%Z[iyRPz99ԛ]S}v2~ >˥)x]䂝f^?XkX +h/D@q\ ۫z$XbIXGfS{M 0<LEDIIZuԴnc\,)H; `?]h/Ạ8lĮW 5Vd@bdQ n؂@#piT\"hwD#l" 6آ@p +f[-s9޽}wZ)uų tw4ʺzp,zFC~[MqiuZ!Ѓ.޽ۯ7bD#m%Emy5p q래`;$c2L&36S1 DV1ƻ!PT׬yՎN_C/hsx ȞQ֛I Ț=48/ɨϹJ &1iXU̺ ya,6ȠTfY5q 66mKħnKaaAXHf@O>9pƆ/;UӐb:WiBuҁc,.| Jr1" ~=osb#!Y^g5Ve`˶2tc8N*D9 èG]ͮEX ڢLB %N>8MN{NOoÒO-r+IȁqiFkd!gD4m  3iZtg_  ';=rz9[KC٠㖢}7H,v^DgX9{Jp+NFBt%%2rh˯"E|# ,q'ZB&2)8IƘƈ~vs-Q0Yi&W؉Yܓ_ܽ*(YD>b#\<.ߢ*/"1j hru ,vhZ]̚t3ݗIwDX 782mqH"#MLt9oxc:7NB L"Љ($ +ԇ=Ip'z %>/ćU&,:üODe#D~`&Æ/=U=Rn{ɶT}*RwTVg?͋W 7;?ٷ rb8A)׏d%XAZ^"!L? -28 +~0Dه;m ?PZkbZyDN [ʝoK2Ο!cILkZ^ y uyxf6$p*1DPN V4!}M9c౓̇ɹ/IIzq,N[3?5+o܃:0nߐŞ5ŠQ`y@ 00H0.A!c-0ED@(]3xڽjꮮ}N ޽ej-I|xBv).k)onm4۳51*6ZR_8ȁ#Yma :26,z˵W c}$;Xxf ԅaIP\dkO5Ղln>u*Sځ P40M3щdO@U*ߎ 'F[m9M 0P8<(#LzYV7=iT"Bg ho,82ȡ+.2p| #d AA IF>Ņ+u*%:^I_{FO3xz=zKO5vK)Yq4p<;#YkڗE=0Uas [Xm{g&Z j+AƦ< 9w :=d+jW2V,aƝѻ,f qACO  zc`ƂGJ$RHDdg.QMrDp柰B+pFY[U,QeOVEY[7jNʛ:[bqh .-he>w{4ـ_n.?IzqdLuX> +(A),9ȩ|q~h sєQUU)kehb ;a*TD+gDz[b\c힒=R0.yWRӚ|Y~B Bq cC?om~ߝ0gܝ@yo=A?J<|[]?7vDӵ8kU7m-g+yq(NWBa)}%hqMbRz Z{뢮SXlAHfUs{,@4q~^&7g.#トrfB!Y?q?|bί|s!?u`n0h#1b[9HLoC@{?]kx8YEYACl2#U;ȓ F~h`ﲖ' +х @U-xiZh+H|#YnZ| ZÏ 0mh˗:ӈ@~qMm9gT4Ŕ6DjU] 1t)VJ =E#&+:OaWe|3KͯY왇B@zI9^Y> Ԇ^Ic#bҍ;^y2 ,X:@)iT7pl.>$ (z"V^~̵l˨tZ\$ +JگcwU}8Eg S2ܲ2i邇hkB/%B}U +jэ'G]D!fIOPG(}ٸu/NՂ2p4νDcʶ>QQ" +, +e6deFeXD eC6ppD@ETΥε޻T/y j8%%HrΚx myM8 g;`nèM` y))IaWA%4:ȌQ1|pK>U؆|\2UcrMT];[T{Nq|2% )n]l1K-PE^県%E*6eP6ye>,-ޝ(*x?D'PI%ho&c~YA 1h]`a'1(uzmUKKݎ}j%['5 q\sڰ]~p g_^..c9-?vH..aV}_P*/>>ax &# +js 9U>r61*5wP2m@tz]l +3k3܈ciT[Ӗ.z6~mo9/3`D."O.JA;S$7:;D` ۇ!Ec.=WJxޡp/=e8='mnM5V +߆]Bӫ_eWvׅpxpsq7((T5yYYfžcqQE @ׁN4+@1($יUHӊۅE/`vG%$~Cc)8#BvFjnqnI(a >uX B6()*!+ؠa6W¤m6.Ld% WB[C]q\oIBD&V]t1S&X\Z"VQf٦GRV[.¶qxIk~:pk?7*uo+zB r? d)%^ V32|o?&&J)m|G: -vbrhN h|q]]e_v?t)B/K.vJ ٧_KՅu*B_KɒSCt1GHgT`Lo!PNKsNٙR荲!7ZIPC@P`A ٜ3ٹړ:ۅ#l#p'hoZ09:ӒuO%#BNL^-&ZrV\t3 D1/7D/;mN)4'm4/|"""5"6M*^De+*$5e]U٠^Ρbi/i_r\X!8"n:*/, 0(Skّ<p +5e5׊iY)т4žc_\b#^ΐbx)$|9a>"8 (5FuO1LpfllZa"6זhL%<2ho2MMg91uaf`O6\T_V]?dmEj_19A&֋]GcoCv$ޱ89v3 bAATژ"lhC3 q bG=oم\yM;:s|`j6kMԴ'):tW"EJ*PKZ!BmNT5U\EXN=v':PW}Sau]6sv.- +|;Q7O9[:e%eYq{6Hy}xB}!MJJRytϼΨUa3_{WÜ 6"}OX8of,H_߄IvizҥHuO)76$ߺ +;URWXQ2$PpV5n^AF +{LҝUjPo X<G'G4NKcfA{Tj>'a2yMIl ') /vGfޤon=;z?0S8+ى_>f3Ŗyޛ$Ԩ2{Z9|~m:zft4R[PsEYᢄX:"ZeCv bkX Jlt5a8%vL[و˞JG&4G\u*:Z( Qtj չZ  +@V'B^b, ;a^.f}.0>jml5v`!֋joлO#9g[E%{2Q~%2(t 9ޤ pW񲠢5ʬT48CBq& |6$ M b9SHٍ?5 g6sVlHזSY)%:@5 +B*LةYh&Gr703v~n3d$/FǮ(/:=Y/;"5Du:95{ӰP)ԥjM)Peoe< bKqvY N?$?sl"W<ٸ+D%6Ep1l7ңtaػggOeW]ǫyyZmǑE(Oy(h uTFD)G &@$4ܠQD^Z1UtU[u9]0'5Y>|w{ lxcIȶA3 ?JWP!-.T6zlh2!P[DboazCpa,MtRnW pd^%T*21Z]|_?vO;VUeRJ +Yt}i|{r̓7ч=W^T]^T:R5mN]'x^({Zr'Y%^UwݶFg#49g[W^ˉN/2KcEx9E-昼{ i|:v{sZqJy4~|{iyz.+pMLII%rF#!ަc@URvRjDL-cSKbpU!ht1.MQqY\BZpBZ qZ{$fOXCC fLXT)457T62yHT~TgpރFB jyyY {~2x17[RK%>dӛXe0C;;2 4VC ꭑaˠK(?/B   |sc9|Ip7kw٫G~. A (+ sC?@VkSwKr{ZgFTT^?,=0t7I056[[xN/{gHWCg}}N&+NpM>E@ D4 =: +aI]7] +>Q.fik44=2*d:.8}pn&cpJkwсؙ4g]R;%hpl.ua ykww|DI?ɯH7ӧ8+>3[at=]bw48n׽v2=/c-(G i<~b=A޶u:ԥiVq]v&$AAD >qQ+ +8D\3adp a@ ^"a"PPW;m/8{_o}{#~mF8 KQ;yxF,_|&,9@]ne+j&Dޑ" +8D%rȠMűqL_v؏׋hÖa3;{T+9҉~_.Qu!GcDڝZ#R(X_|SD}_|SOF y6dŴpwO~ EB\?$!+4_HH62r F]pYR:Dy$_h7~ ypv?rsLtJ2,g&'4x*K9{IϠô)Y54VVU=%ɕG7 `g!Ҙ VҜ֒ޜ1Z?3e\,-e7~  uڟ؞/{%zqĜ#+⥍lIļ9WY:XePP$%Rb5F{f; ڜxC> iA[iCڢ5RjRsWQ fieL{>릸To[*BfPM4H$b%|!ܝOEO?koiE҂a1G`r>Ļ +M1Ss2MȠ>xW}:h?x31Z)\6<=5Nz[ƨĘ?UY-GN vN s%G Z +Uof!pnKy,dq^*Q=(Q{KYi~~6LpNҖxAZ>zfHSJjI#$!Ah~?3j;X6oJRR`wjvȤhs:CPo8ZiҤ{g5^F1GSĺFR-ń<JK} U-7; SG˹Q A1E)al"C< GBqguc]m=H~B]n2Q_;nb*ߙLJ-u+e+'kCkŻkɭesZeE^qz|=t**@-qV9%z]R #`'/`5(h(2w1\ b2'- .pi=QFNU&$$axQѧ委q_@>M*g`)m=|tPli,q1}]xzMD B 9a+YDc@"86"x5pRˢۮz_9K/:dkO)rA:h6\aF9K-p: `RI]I~F[| ti~iMNޖ&yd>=!Qv@_ bU>KXzlG$(ח,L(2yHS~ :}1"А<,Pe3lu))gY#2 +J WtR`눥3]Ԙ%n=݆ܾ/ot:#],ꢤ.tRưAqܣj8ΰ/#w؇wVVE QIJEIHjbΈjHQ袣IIH%^-fD+T&dz{׻?{^k|绾ϳ`*џޏ 3@*#)$a(_ ` 2L\欄r$= >sCNS9Xڠd:c0{ao  +jm4 oZWI;.VnjAP"FKH]=FU m*Pys,]ͩCKXO`|jTEaT(/CfyHp5UcCCeqj3@g~OoN0ɹio_kЂp ؓTI>~ѹ7Ϋ0Fz[<uc A ~hYkYA#2B9./Wᤃ҆ewo7{NSĕY;%^J., eo  +#|FZCƑ>gk_⧡ע$'Zye +111۵3Бk=a݋Y3 8 M[sFp;F +h SN.gTx7Nw1u, opM/Vо@J.Y֓ 2/ `B)7~x./ Jxga V(|RvคI{UN pzrD=w[*J%g31p- X h=['))ǢE!|# "( Gh=q{q&r&cLD(Qb%4X+?/)W64togΆ>.̷1F +qnUo}`}?3q42{J + +NgI׋cGlWdB|ݭRSרVKΚeBE*S2HQx/ڹd{[OxTw5r1# l1ˤL|381%%'kF6[y%VGaHʀ |]ȯd0ާTEYŖZ0wbOc8c&Jl;:4UK^QA%"Ȗ#4:F ADܪpvQ鶮-AΆ/}*ݞ[Jt a#dσ ٕ|4$MZfzV]e9IVߐtcF쾶a` .$ =%FzLB ?+h1Xid&fc{8;~ a;Nޘ%[北* 8PÜ50;*AFG¿VmÙubU"MP߇u0؇=3 ` CgcdT4C,L;hwŜZ`qNY0 0+×^#4LnXY"`FMLьiv@'SJ;S +>'zF`5j+Rͻ( -S(Ar\Kg<~KB#ʯFFl9IW{lF/UcnφEb0/¤py5k8Rd +T_*Ѱ0@+R"$TyJ0Qe-2-v,^ޙ=3F"j ++tj5v)(h_aQԕq˪4L;^^|m( ,,!sۺ:YM ށ;vd;GOԸ2̼ yl,F˯q8]B5Edszp% V60402([}I8w ,FfowWW9Uu@{6Y6 i`V`ÕhdѰx~AN+O"~sɿ&S|b&21  X +.׭+H8tu̩[.5 +}orVuB6t 4ytjf=KS i(HBL& GlCH4v{%CB }iN)CH3gV~wnNk=kϏu_L/2xI]k!m6>q2B^10E-./?TUv?z.wW`|莮[qӗk/tp;>`CaEj{nW =L#ʵ-͎Β l3ru2pqO8h1+JXxJE𱾎tEV5</v ]z͞{sW/ :YwwWS fZ3;͕n/I(eq>vO-ɹyC:TT)9"t0c>kp >0=$ȓ۞wʦK%*8qی/ðĘ2#˒4'4RI娬bПC<:Hu09^*FR^5T=‚KdDGP ?"tDdd;#tӁyy~0 a$Άd?xNӈ~€;:,q׽/Ӭ3IDYq?ESexU0 $,Dmuktt޴L) +*G+x|Dk9'QŽW0QN_ہsZ(ڗS,I)?q w\aIOJ$knyu0QJ1^cR`QIp/.\[k=` +, +'98WɗVPtlb[קL=n<L_%)P ^Z vXAd3u1~5 (~*"DED@jM.P|X(zC\RGv]53 CjX,v,ibM}G\[E "q 84Aὢ+Y#C>C*v!` ?cřMG +#|%-͚}{T U,(>.@_@^AY~;htG[`! `t(ass΋;ew^%.:v|wFv6:OCG2p^0&;EHS:QB7Mo7P4 ^7&Rr4 h=$F%TnnT7ilo +X %h*v SQ +n7h +aK3dpF'~Z?T{zH 0쁹$1iU#Xh^y HtQ )׀!tFz%kp10J,~5x38=LipD8g#G[ "l3Ie~=6mS?m#p%NdCԹ4onaAۤ gܪ.զ[q$98JOǷ$^c!I +~ӎ7tDԈTJ4\a1 jDRְ,u=awk9 +X8 !1ƓY\zh#GlA~{qp);p?J;o[qZCP #ngdC^6Ķ?x&*ZzCȔɇ20h(Wca5c b(?K-|yښDGs(tb=Gj$_uFY +4 Kqs3lf#-LmAcs0Wf)3eu%uN\̢ uZ/(zwe%_u*JKjFz*R&9yfd w7dXObO^cIL~T1O|q%hQ3F>Lc/'xq^͡,A K$\[gK,~(@Ϡ+3ЯV.:1? Q} 5\QJQZY.(S{G$[ꕱ9D7KAN*9t6"cs M&*inEt*"d9: Q%sMvYoy<?8BI1nzR3ssIS[c'q[u١;Gf۲';+ Ȭ| ,fyJdj})Vيm%ֽGUa{WT0,ag#Eb9QC#ka!Ws_l#U5j]v~Zp38x QNm wq|L]D'&RN)o_qجg)y?9B3J!R†+AYo$Ł~pK#1te]{w8>up6q!Y_6nXǷ|wZ8}W)Zʢ^1Y +9+)/;* KEGv>stream +HWۊ}ﯨgÔ2# +b Ŗw`1Fvm$cTtK# =]'"_n^a^d}{/='3ϓ%!9;<|yppv_UE* 51Q4ݧ gMX~^rucXuj$|m)vjnmkMbӀ6~2,XG|㽇.7CLosVd. c4ŏ1NV Yhp@d5ſAaSKT}Tmʘ8+SThDBZ7tTԌѻl/5H43%ft51!a:MƂ#" /Ё=&Vy K7Tk&D /YI$,{Gu >k κꨉ;_GZ!<܊apOKcxF{0EW"&2o@݋kXb%] :`?SHL;>Y"B1Y\ ʅ@/7ʔ<+v PVݡ٪7Q-:A{BY`/ad mY +VdNr|# *aP +ǐ9Ka@J!Qin@_psa:S9n?'HN!ֆ3 ÈR:^tvh^񓪙5= +7w6[MQ bh#̲ZJ!gfzy!yCBUԩ l#=سd/dK~0{.<"s3[ud_NL 73!I}c8𽰈opA_\J{o^ۥ>-B\D!8_ +0p 3 ]XQB>BnvNX'W8.U3- aň$Tk"@ ? LȶZlӝDUBjo0mݰ vng! EWMXK_KL|j H СxTkϭ?^6OAfq6.6Rط\4 {wos^Zt.w͢Qql3/ٹsҧ['2z1+Q9;ΜEn7mX: WT#e .rfevA +1i1vTkr0ADl'sPOQxġ2xgAFZ~>C$=cb¦NEe_DhoFNt\e$M9<9OڍGDE}%Mn36]rMqegukdrp͉g ,s-QQgy >-Q 7!΅gwN| ,<M+~zpzsUQ%)jcp?Hyd6GҋiD.7@xoH0~}Md38gp=@OesGbX +Fݼ*ّF +;F%0GÞp_~/(LUu2\xmⷬ!~kS^OLPj)c$%d >ql2|yav^uf5IZEQo.vck4'|"IyG״0bJ m[Ԙ:!/VE VV V1 76ST *}g?Bl`F "g]r:) f4}QjVT_^jd8D;NX=$ ͐IenWn&,Q#T* ^rt[}0Mg!q hN,Ix$'7dZS/l oO칁i]KFc2ƻmjBFD* C;;DnNZX!)Uæ nk5EVd%d-MN!yH%R "H` itfA*0Xl 0T(("HW-c?T0avA;Bޤ-NZ>x^Ag n,@r=?e +yD/ݛg: rDbU1_BWhQ+ƣZ+q)M:L)$SACCiڙq,j4^^#$t 3(5>9 -?SY*sΣϤ6B1x[@.(MgfmMx 24ŌdjQÈ1a`N֨9m:VáUpM.n }? +G 9Dkay2:}`6͉XA@UHyIQ~\gy(ü`s:(l!"6xVئCmmMўnmzG>um(WX9xW}40)fM=C 6!QWT2ml\慷fj.*N^N&'ߢ6Lh&uHDNVpjE} /&{OJK_ )hw9H:s=k}lB˲H\̊G/&eCX2 V~+AT+6x.fZr'Q0c&b9 GQN!m mĭ>P|w3\r/gZZR#$h`}K,+[;ݳiL=1=N,yGţ^hғWHXi^Wz$(nPCP͸ÿ2H"$ ǝ?rLE?m'RBrxȒXeZ>vZ9ey1ZKmmq_nx<5x(hU9s<2~S!ٹ7!i2˾dgfQvG{;f!Ldsv6T(Цid8[LA !ಎ%1]4,2=۵-Ȫ=lL圄@9CmfVрfx޳.AfUP\bl ڈfTU\hԖZ*2e@ɀˍNTp(QQ{-iWekA1gϽPIO WΟ'FZjG1ыgxWx'tS-0M$1;&齔-  kt + ̌Re~"w萱'$6hifxTQy/4-ڌl|AQ֭cFh. DU$#:B+0V3{ g> endobj 56 0 obj <>stream +8;ZD/4-IK(%/"GEmW/M4@FFUF\V84+\Vq'(C!uhlBsLHJ?"\"jYRnYU)1+-FO!/L^ +"T"dH!;JL_k+>Q%;a\IIV9(SFT!pUC.lCDe;WS52L_(2\g/OB11;RLkb+0<*J>s;3 +J?"+aITB'*l/rVXrk/pq"]-U,G+W&q@j0?H1K:AN_9RrQa$Q3.YHh"B,%[8BXlDRa +S4$7c7rNkmKt"o5V:k8DEFXn\rZ/]jheR]T-egTThgd$+SF#f;l!/O)3;K=j$ZmGL +hgrEi5JW6+WdD\ +L>?-!-_O#82JK:KmW47ud>j.lu&DKUW,DC3]A +o@ra>+K"I6c9M`;-(-]mD0LGC2!-,0sG +%@KB!loX:do@FkmS'NE]hr-+#Ht.Ur`8g$cdn7+,SJHgtD3]@0Z;g,M(MBG+V,f,M +9lo-.-+Ii+#)g4s!2glOTE~> +endstream endobj 51 0 obj <>stream +HW]$I}_Q­ɈO2EauvTv{"+oߙAA{'_*OfZ~/}Rg37̲A_ž">Gb˕{ϕ7Z[^cIHD +"F$'6MZpNᕸĹNcиٜjm:|` >ÞȎ:&8b]&X jn?;Rc_`PDY;\ŕ԰.F}VcdXJdAq%ʶBp Nkd<]\jc(C͊FC*K* +Valp|}F8]JZַz%kkT j9aW@LbRD.ِc$d9805>"DK WBt%>M{EM7 :>#ykU4!f&e4P9 kdtَ_~u6-nc^Z.qFV@%DA(*+.BŊ ,u( b.$j}]K%ղBr&}^$4z}n!)juxS ҞvKj)#_@Vq,OuO\'a썓F9}_tBG4֏x!peB\h3rgsJPƁCM;xCp.NΒg6*J F@ӥ`S.T\~txhvi +<( I{eݮgnې]nft`6OH{d5* SǢv(xqEqNk[ENaO8- +Ĉi[)IC@2-%g2S^*n=fhت4^ʥJz܊H^=({/(hzܣSHx%H@#a*2L7Mh4x fF~#NPx\uZYTk6 G!|DmlQ- + G#?59k*GwHfs q#@x\6܆/qT;y!=jۍĨ6_!`hܞ69qpuI/dxD1 W3_K~AyF% +77q8O.q]_C[m>Ҿ#24m"q 3лGX^9}h1H%v;@rn+ykK;AXA]ԥOYĻo0G-1s\zdlGœE;kL}-k;RU*kàXu6Z=19Ύ~W Q'#0J  +LӉ0-D~cԛkJ!=) +rca>ͬW^H@mJЧۉ#q'F~:-P=\\ǪvP~N(^-'x 2V c:|}){ZYyHOQ} ˕vG&j lZp^iUe1BBEPst\})G&quC._]BȒ0vV@[1:yZ=B\oAGS=N*=9y<|xr&ɡ%MO8E_-qPt?_ua~F*( ANv9|h8z]AeÀ!rQb8 +NlXk<.̴?fέUv,W{mϳ'nsS)6:ʐ:Ez+{gqNKЕl05q%9p&$zJLQ&\Ei1-ԗsLXDgD1 H-g6d9'0{0K,+KЈvC  / !s1"F0QA9c};е +Ńt.2dFD;>N# >vkl(eC?幜.!CMrrqUg PC'ڪnSo0W &\ADus`#|6Su\n*eOCt "Dw1h0a^/Pװ W36-sw; iNC/jKϸڻuͷȉ} +>05=0+.GcP켑v)`҇Al1x̕X:Evje0׆GBo'iaAY% #I ʬ p~Gufꠘ8!-Oh8r;Tu.PNVM\VW>֤{r(/G~|cnG#ìo'S .$".PgŶ СPIŽOAyYd^HBH4띞4e'vQE;H< &0M8)@-PnRF 9:]J۹O + +:hJj) 䪆FÂcEJ&ьC,r|*(W=;yjҥ^ЉR@cEH ='Ҏp(w__[oaݜ[Oы2i`,;r9aq/]kpj b׷*ȹue<2Χ[KqH0s 3=`R) N=Rk 0j +endstream endobj 52 0 obj <> endobj 53 0 obj <>stream +8;ZD/4dNr-&C0$&HB2HFSs@Q(H&Hc;PoM-+=<$"b_T$Gok;l6Y$,^Z]8_iKX4:lcU +k)UAaJ:E24s-@4B)d7,nRql*DIoMY7"J+@;P+K1@?Ip\X=-p +!r\>fMb_:'U!m,g_pF%m;bh0lIS,7WQ/V);Ec08rIlSt.`QNCE`=qq.Uf7hESkZ-i +kf1#CM#8fj7AA#C_S^)V@RR<@Hg#bFqC5mY\l'+?cI"PPP[(BSF,NM%!a9>Z9q]>&U0egj$E!_48%8n`,frkW +["q]-+fq[uW,SjDZSpM1"+I)$bD5PaJBq$Gn?&>"q=Dg[Q(/SVXl;+jp7*Pjqr%0r +>D^hjB-g#d]0&M'o/;Ia*\L$*5/Y$l=Qs*E`sJitmumGd!#*1>dJ~> +endstream endobj 18 0 obj <> endobj 124 0 obj [126 0 R] endobj 125 0 obj <>stream +H\_k0yl&Āynޙ +(a}vVPqrΉC{&ⷰGySr#\fI%yܾuXm(D⩚71uX W1^xAϊbfe:H)ESFty|BT(H\K$aJS鐌HsǤwސv T%͵ie͵{9퉬PLN3Ք%ȹ=3LV=Q* )eC3]7ܮۆۭv&򿷔mJ) +ӈ2M>mzrI]OYg Yaߓ!hnﻵ.@ѧ] +endstream endobj 126 0 obj <> endobj 127 0 obj <> endobj 46 0 obj <>stream +HWَ%I }_HcJ%#!F0tI<BCOǒ7t5=ҭ\"˱}x2<~a^D}|zջ߾?:=~ ~2\r#7DKcLwN]_XQUԨ0RY ~( +>ĀOoN?`I$Jft 9Ql?f4P%wuoNY +b~^; $~orBixpz2F'cP7{ 1#ԮqnN!T !(琪vY|?u1vo}mW}.7 yDs!?%tj;Vg8ٍ!(@HjaUUsRi"?:11=Cyl!;<ѸxT֌w܊x;0F` ɸ1!g)L/ 5w`TS0(G!U!Ȥؚ887ކWEvӘ #{9H"Fy Xb!dhjJ/TֿR`bDGBJA){5jU+|݀ 7^"Kqν?_ׁoYk?v^%F(jr>vӈU ZH%kϣxKW.hMRZ1MXN:M`b;t@V OiQ38wcuQf[T '| ^! U$>w'5'to_~~ ;o\d)<,tYnY&1`-6ͺFۄByIw OTK<Df^C3sQ46\n37J\Qx }f;`8Ҏb%"TVmؼM| i3*ha#ږJ:DUyl3R9mO"/ TH0jFVt%^e010a]JChn +[MYߞ!Jɔ=~"kK)rdw,j.='ީ +G_ht(!$ԓrv`T8N(vf'l:#Cu Dݳ:_C_SVӵidnϘ!J}V+eLk]ץl\S-TnnŸ<򋍏W~MV%c{B>瓔"5P>vb08R$IvߓWѻ˷+5j{,='&eI"8JgDmEPy nD{<.qFYSfE ]S-Zwm+m<Ĩy/T%/L˛69v#nρ;:?H +]؂ 7J26}yCl)el6HQX;.I7$h)V:a HL7J륺wj+iY +8lCIo=1jf__Zo[aj+]ZapC=<WӘbޱ:cd +BT&n >Xs͗rx,휳Z(c;/\zJos6YD%pSO?`Qydw'2F.g;$4UjPɔ~7S!/u䬃+1se;ڇŽNLj™uzjb s~캀cSyꮓ^?lq|Ni nS9 +r9jNTGEmq'к:*M|EΓq4: iv{NSֲ +mB:/ +T%z?N0UL +-,][mE]ARtP"H Y?YN%](PFzlIrF5HFUl\}9M1a/t]˷8HRfZ磮@x|^5׃9(kg-#.#m0!9[cxV錭L~*HћpDrwHƠ7xGU$"mvV˗V/wg.X<$ҋ^mwD.cUd ldl0>B oGd[&l]YuY5vuS[m8=Zb +xΐO^ΒHZTCy6a ̣Ҙ0xH9ݘj l)VJ} 0+ +endstream endobj 47 0 obj <> endobj 50 0 obj <>stream +8;Z\74-lZb'IB9lHO30\l+AD/9p?A2\IW0c0pP`'.OoENj0tTFAgjId[V(81s@WNuI#hH-V15QQM'VBOI:,,HCK2%O.oe3`boL +isHW/s7Sqs!*+`?13oYr8=bD2m5u;#0Q.j*qC4a0&,K=a"I)jUkak'M+8$498(om& +c^t3MI[t%b0M#:3A#!DG*l$#V"lf&uSEg.UcR8_JBT8!!?g!4P^q\/Q32h,ZSgSSb +[BEZ%aWX\4=LEa--O%H!o:/s[n?fCteH;Ee=C/7RTb:d8D+?Ya9s-`ebgY9(GoD(' +7=c#u4#\O`kfFiK,-Xib +Kq=A$(>>IA;ABZ"cu";!>YfC[ZboZe2+9LD*+C0mPIN@E7\KPu$CrIYOD`tj<)Ym6 +B_\+G?O23Xm=XSn +7$9@B+K?nFa.=[(B[TalQ[:RDSTMuh]b0@-koK66a.A)uXZBd\;PA9>L&J%9'J>qT +*.,(\DP'&!:Nk608a\K=FUk-,#?@IMWqg\^L`@=mR;R-/okZh6REsUAMX)f5!or]B +T$s[Garqf`o-kGn[>7"1CJfMorN*s0;2M2+6>H"#FP8`(8Ym($gYnGc?h>Gp^n1W- +ccq4_~> +endstream endobj 49 0 obj <>>>/Subtype/Form>>stream +0.965 0.678 0.196 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 406.2877 565.4614 cm +0 0 m +152.231 -179.365 l +-332.917 -193.021 l +h +f* +Q + +endstream endobj 128 0 obj <> endobj 48 0 obj <> endobj 43 0 obj <>stream +HWۊ$}ﯨgCfDJAز 1F#c}"/=3+ݙʩʌPwl{YNOw߿<'%rpKƴ<<5O'51`83> Dɬr~ɬbӢi7WZSMw|-ߝ;r4E X~4#Pԅeh2>W" 2J~j BTo8؏૽ Bqe^xQ[]( *8Ү\?=#—J#Q}&ifLYi1ѝV( >Y/Zfi]q;Ւ8"D: f#\̼ s9.Bm~cրs)ٜ,%lLlKԵJ7P<R|mː X.RϨթgmHs; `$omQ5'r`OM0r0 v18c.4=7#r8p +7dȈe=Ƌarn"gVk;yA_ʡ !@O¹Kx ,D%CJUA1h(|4H. '{(8j:?4RD)26/v45oN3\kͭrE<7kE6Mqx:55*j\ڙv:0[945=uAҩY9aӥ9Lw)5- Ȥ&st3aR)TeN}hc8d~2iCLH +`-u1\Gʱ M-|̾VC*s(^w[FrtԈTk $Ekdւ &Er(?\BKvQF=5KbsdĻ9O_GX$`>jx =ᖥaS+xKQa&p0f)ztSݫza ?!=_Ť>^l@Jw) &۳4Kpnt W؆~9noK^i=[ yQڪlMZ<*qנhؗ G䢝0S&HϿqn"kV!0JnQTv+lRs)t6Z[%t7ʌy@v] `JSH _h,@3*,vNQw:sјD^L g|"΂B5)m~4*@Y>pkDEh~0x42`9K@֮MUPԺ* 0gs nHjlY=9/z! %t]bWu9{Zb=3*> <9~Ϙ>G[\ocp۵8.y=_:陽pNo-g21-Dɬ<^<ͭd1p͗O't:bgj˳7(W_Q_5=G_s98x@︈ON璿爵nKX"9==QU7\g/ םՌ|6vW\_մ?I:V-T\8rדtk("у8s5%` &zEU`<"ۖޛJ߸i>@`X9u2t3ʠZENHs`W߷k;N٨FllJ!6DB됷"ra +}Yn4:dD۞7 +}qG]3A;4,F^l N^DS.~=!t9_ffp;W6*~&&{!Ȓ=&&@kn-Jm@Њ]qTJ& &X#8M+rc:#.'/:An4{VWl=}i:]zpUA|p؄exeH@09;\_"χPyaDKr 8H*KV,Ju9W3_) +u=FSsolLeWelԲQԊm"pN?#n*971u핯`.G(vrb12l53UjU19|;~G^jBHC!WC>7mH܅t-<+IO:JqwNk%vZ6|E۞oہo:|vͦfƀu^\yJ ELcm}VtLHB u+}dpsw33T- I8e٬=Q?9 ~"{XJT:tʿ7W9IJ3f@A?L!mӻ rafEkvZ5$puyuv{(ava>2K䒸1eqje߲'"xkv$_pF]C( DF}v( +|{:ߦ/2DbAo/̆5\\~wZ:Y +%fJp Dz:jij,e`\'M]&3`EĐ9;ãFX0L؁8TqPN}D*s"Fgzj0.{3ݨE! vHvOk5"˜u/n"23ro,l:TadP gv>f}%i: YxiRq'9d`QT^tt2`Q9ٴ;J6vS̤ .,^ՊCs F2]e- 8`]٣`p(ϲ@Өټ:l!hctҘf$^-txJnZ?Γ,|g\saŽ;c-KtЃmmdm P P$sani$ (q݋Gz):J)__| ސ$@~h[rPдngTX݃H TWVw`=GBCڂQv1n Q%#;)B{=hc*R:>lZh6OF-1ZbqU !znj.{UρQI87vDT4\Y%|}jTL@<6T^mT鐀˛ɾXUgFh*TL,H7|~CשPbeq.t}ԥh <2봍mLAvR5-f +.`1k Z.}A1w,}чK:(:FQu^ۜ"N!1=?M?4x>/gJۤoz:Ird}|G: M(ݍU`U!5tL`Ĉ;|}j]iֵ7=vVuXo7~=9\ +UHAtzנ6ǀ]1/$)q T ճ +endstream endobj 44 0 obj <> endobj 45 0 obj <>stream +8;Z\799OoM&9U#$F+gX7ar,5X/@4n&*l;`6PAHbKlb:XI0\AVmg424ao.6mqU$9SK +561]!7rt/l'k6"i?1GY<%jKbh_`1>I]!/1RJZ/6DdI8-@UAOgj+h8Z3W2Ep*<)XPh +BCg\\rJQ%s+hcI5qXa_^BWAObF2UK5oh/ln^6dl9YZY1dlFUg#!:*o#=%^TNkC5#n +oA$V_d$J>^>7UM:5Zr!_X.JKR2!Ht#1uk7CeF>s.ONc+@YbFC!A7j*VZ[%'>Jdk3W +Y;,u/YB_q9RRr=@l.AIc9\.0=SL[\XE@B^%_`>q5Jm4)Y%.iGEJgJt2'B^cb'g!'> +*(G0-;#0\T+X!-Rl*fS^DS74GA$N"B_4UPoAO++YH<>4dKQIS/J="Z*]a[ql4B]Ag +omAM6K#MVO=$jWMaJr/FBZ47*OS+Rh_NH3cA,tUA[)DR7pqbY3hIH9g)R$S[4Af6, +PZ<74::oA0.'.&O`W-+eIX2X./I*%A\q?p?DslsJQq,u?+BF+B]8V2uaCr]8EBA_= +f-`'!hk(VL3&-+`-Qf9cV?i4`P=8W85`V7L3+dg*8$JlXD-U@RC?+$[%-m7[^`Ea' +pOM`tmE=G_hA1jNU!A:"#O&`Nf"Pb$.Eb/kF$l.OUF70J>#Q1)pHVm+_Q/1*(PU71 +2%#!A$Ee)=`+Pgi".4Wr4An+G_=/Un6@;\]XkL%r!SmqS3pg^g^83f+VWrK]9%.C0 +rWp)uS)4ZD"]\u"cuj1c:!a[S@K_,b!331]-N~> +endstream endobj 35 0 obj <>stream +HWk,>?WZ2LxL0I &9L#,ӒyTyy:erҋ<=篾UԢJ.5|7Wj"5"LWb?5N8ϧ7_0$jj^.*[yR+=髃_-|sȑpdHyzφ ?Nڬ}>\Y) +ي,Bw+44]x@*,ؿ*hȵI)u ]ƌojA2؜%sɮ>剰 |ҰE .G=CaaH!,F@kc Z/INy(!>UpTY +A.F0]Lƃ2n'azXEҝT\Z)w4?EV#‚V :1yZsA;$ ezH}A+4VlWKlQrefl ȃ8~HLYeWGLw6MI!*\8kUbjgk'QQg&^`dž) cӪ63"ɋCϵ<1])]c")6]L68hǿEV٣1Ql)pw@#, 5[8kQzPZw==]5-P+Nfڕ BJ5!|a4Jz릶ؗ9UǞ)ɌgvF )iϦ}2!X)l$.b(14keUqK7(-D૞Cpb$3n;TѪlwjx90Rs}5)#%R~킺r e9c_iќg8H +@UuIE*4mUY\#c7b&[nw@/٭)ӭ/w8ֵZ]PoH3&9XͺcFaxr3:XPH=7jtџ l]g,UB36{ ~pZvmMAIjA܈H0dZ!_YPu9.F~#Cv@v-u) ̸VY֡nU?x +ۖeI*x^r!8lmd[)#ZY2'#}'EkJq\B6g ϢH}vll+j?ӹ^h?sRNǝ{P):0גQj3Ͷ>l, xzz䓵*#CZ~H/}3'ۜfK CFeeǵ/} <;8#B6:dq !SLi3 +I2C&*A5:W)Dk6gtu_wHbb?(Rj ]sdb!Ag|2` dOUMv:v0<cЉ1T]`0[sMb xfGD;)f7`]# zNHhGøcp'"L\d!  (t2G GۄsYޚ[cꥸ]u.ezج.=Dp=W/ v#gn[ PRc/% Qwẏo+chp=tΨ|/d-TnҙГ ڡ~|u G!&Soev۸~{rfzZ2\[K.Ȥ=a|@E>JFUvam4sM@!#ʸJ.«m z2Iע^&s:%lbu{o ^0joIpIYA]cmMb(:."Itp)>|Q%g\i.& +)}-j5?syajdU*H\ G {?qD-iJEv~nn51}XSr!18IvU^ LArMt?- Ac~8P٪a_B&+]pѫNu"r5iC Y%0ld4Ayz,9rQHjM2%Kx4Y<Ylfȏ:|4L?$6՝M)\m(rt_'e̙7io 33uݺv:qяGX/ "Q~GLZ92|eݦ Yʜ½ulSZ.0m }ιۖw-"_sc:ކ]q!%79-@IchK[ص#lHGC[ղ#9 +zWIh%?VFp-~*w۽‰mv2##"!wG]ȯƩ%"슘*@8(VʪaÉFj^X%~VE?ot\M+͠]~JE&T> + f̧.Z#[&QpJY[ϹAcEz88ßvCJGk *ƞ/Jgh? zvLK'/ݓ ?: 3qdbRJǝsWU~X^U}F|wX6_}uSLܕG} y~>o)X #a!BCaA$k܏f@1[p2 M xQŝ,:9!B+udS r,XB^>PM73a|6xhL:%FJeeG)9 P!+ޙ:Bv)íK6z:2ffc~5u{ihIB5vS|*nRֆmR%,Z G (s_vgބ< !BޘZ$ZloWXotrb4|Д*Z]yitK ]FAWc=& '=ߏ.f bؽnoV@=@7`&5c(Z#r +Zݬnd5^YҦxLlGgfJ9R ;"+[E:sne h4X=3&a5zB[0yn˃-R8gi) 赀p6flDž;\VgIHoc )F/Yq\e66 ;r.q@cW?l=hm½-߻Ԅޔ>mrhb.`[k L|6fO!5|_AV^9ʌ|FKg |5=oσ_R]W#D[$uc|Hc.}忝RMI +w(h#ǍEOnP.jݜ7"8!5fWu&n +.@@mȕK cy%}b(|.# )]V_Ǭ}c,Ĕ)tS1KMp3} yEfF6֦[I9EE!)@b.{f7VH~ϫZۄ^M˵ .~α +v^^Oʮ3cvY`!W[wGMSCḏx]=FVkWO/2u峾fx;?Կ{yK&qC,v9lEHU:0n4SQeᦷ䴴?,E`M.$G14Kj-_D0x;!CIza}{\KG* ◝~YjÉ9rˉ{&mwQ .QFs +;e%51a>9x~x=*k*Q'G Wb➿>fUBp>զ~/ۉ +*8vw,B&'^;$|BlODOx^nQ%vEF&]4eu%&^|8HU/ېwUS׵8|q"v +cpSmR4čG_:`tK_>`Ij0NT.yvha.QUPuV 1 +VwpNO?~'p)?}!d Y$cT?'b_}'W&>`jO^:-O݌]b%dZf ֫> N_ښ#i[bn|n^ݻwoS,e(9>4bXw?Asxѩձv7u}5̷c1,}Ssdi1+`1Q1dQ  ' bWqZ[-wȢ +endstream endobj 36 0 obj <> endobj 42 0 obj <>stream +8;Z\7]lJ`Z%*j"=hFGX$Y#@E(b?JqVR.;G[IL*6`ne>6jP$+te"#eg&&!h0tp9#L8 +$ZR^jZ@2oF%mGkkH1#aRH#BUD9iC4A[_r,'7)e?F^W@jKpK7bV]esX_:uAY%Oqa`Y +<'75X>CVhPmF*@5fG00.',^0R_#`&F[C92B0]Wq[j3Ai6hrj\2b?e>j&4;!h"%kaN +1p2e0j#SUE?n"mM]P,oZVB\oFcY7dD$j5 +Th],gRBlstP:!I6@]resAacb9!mQP[K>8`cQ7OF@iT6[* +QpCHLdq#R)CJ"LdMY-fCM^&^3FkrmBF_0"[9WZq]FKU9\nJ:DS&D[i)URLX9l_g7lds4P-EA +GO0)$!BsPmA3`#7=41%mU6E#u;Xc2ANZo`sbtD.:;W)h=RWcn8O,tS,rc7hK#.>i\ +fi/-`>ar^0V"tgc^"Oh<*1L(%Snh8Db9c8SXU)k:m]7i)A9S2qInI+_6$.E,]sXm1 +\kP +endstream endobj 40 0 obj <>stream +HSSWsO1 +-E@+ +ؖ*ݮmqkk댶?ֵUŶaVnUo$H;psrgnI0}*1eeX>_O7&= ?'3 ' W9wfO*tOS$_y4vңQ{?{[p}Nɩ>G^#g^{aÖ0e y{W|SjI&Q̞T_^"MD\[C!F䑷1usg4v ax#h^hlhAn^5M#"M.$l² m^y^T)sн\(e%~Cyayy1y **v]QQjy7qUE%fuDy|$Q̼Ds慁ɆLlɓ.1KKD2nveqh-t~MV& 6W wd] Z\8{nEMqZ4f,K[]X6n&㲪%qʩvM)w$V7/D8M*g:rv"V̘7?jyayyټԱ1.aΆw?ȯ~MԽ]*D' 6/gכz->&6{kY Q + گ̦d,jZwf\v/a7ht1)'zv}u_kPJ⊊Q9EUfS'ZVEjDӼljoi^ۣ^T2 ]U/,__ZRc?jk<er.nQom|ByyT؂w_=aHoL?"gV5mִAHs_^u7/:crWW{Ӗ//k<ֺdo#k/:q3DxD*{jO~5uea $\pAQv#08.uX[qcZluƢEG`]0E!!!$nB63?2e#{|yw߹{;X6A&VyWkH| ԰4HZ 0o>9:K`#hxp[<7K>̼zOPuA~!)i' BG'tUͱݯ6PQuȩe;}ҷ0r/5*9gޜ^}u&AL|vxJ? ޞ̛dJz ߰@ f +niԴ ܣʰlZ';S|zO $g2O|w hq/m7Lw:cAQ '|c#c#Ffo?0l8v@UǢFd6h8JWsEHxpJAN쥋 LvjZ8x9Ӹ?5|B4y;pMn[)LF,#n[Hdv1K:R0e.(uJT[T4Ƅ(FGk^/;'Wh'HzwJVlZ[Α^hd6{~W%FS J(+8>#,k˟\*5IC<NsRk8GCbyl'μϲNa̽of<'kwr;dCV%H\:Ec1?y4qҔB'ȋ?u}ah}\O؈a$^]'2zh۷)iFnZ9itǸ5kEǭs"mybmM(L2SڂS+3fZIW u-@ȥk1J3*?9#ii +uS/5w`B蓙B 7/?b[me]0[,v?َPng^j#%P; LA[ +%(`D{byHmeQؚӖO#5H;rIY-" c7rҭGU':Nk]CrjZya`*BMFn4,t!~tEK;XXSM@Uʪ9ahKF=wOi=r[l? 1EzIotX-1Hma6oKspa&tV\#U?R]pv(=zccN Ͷm4wnau7V5IxlxuSߍ(e9tMtg᱄-s%ytY;ֶPj :ǼuSfnv됤LF 8/:z`18V !Q(F\FFcF Sdb[VR \Ց6 gNyO޲;v07yK>ϚkEE +-<(w[ϛ>O 477yyjh[n:j~{yHA$ VT)"*V*:n:.Heui]ZQTT +XMBHi9|o 3s;w7o vp!_8`cg0V.HeOE5AnvVX%aQUФBCkogwй=)Df#ޜ֢!pazې?STL- Ǽ 8Jd"wo+{7$t'(^Be0I7ph˶ׇuu93c>,2#4:gxz[ypCO W1JC)eƠ=I/Oۊn],7C)s@z 'ͯ ϵiX-U$nkg'm?%PzKѤucu^%ع{<Egu1ox+aGw T-?BsΈyvqh^"!ذyp+pbfqhpۡ5 +ͫ4ό=)92~O3<[oɬ ـ匯yCyTaPv'B;ql +}o5 `)1XCejoDx*:kc:}11Wq͓|" #`/=:m8x-邆WaBO+~A` +"].GU⥵UŻ"Z]EZ"wP\vya=g@ !dٞdr33Uۚ`<&~;E^UʻR(u-A?:CaP[Y:L#qnçy6c\R|/ufF¥<Àt?ES%t Z=W|6@c0i +v2b<>~{Cusvљ݀梃}< 춛a[p7#u=,Rq",HRf!fh;= m.<3ϼ㎡b=Jik~5hy;A[<3)$Bjoh2wύ0I~F>1Fxy~ܔyL1ׅK1/'Qynuuշ@]e?'=#I؂yLxwO@xR9s)~~ni;t7?牌͢?aro^Ս{GF5c3ǘy{ߏj 3g@x荘x1jnuSo2t~^8К$A̦~oF?g]?zڔ7og{Ip~1V +>?ftZ X^ .wI<$/yNB9ey)Kg\g..Mۚ%Axf<= g' zr]F_ƻ!Ĝ+H˜6!9.,c=aݖD0>l6 8uP)TGraDy4&O%ErΟf;猭8'_^12xKZLVcbC|(1X [3. GrHedc1 +DSlJ dT.7U̔y}kp.ByE=D`~Efndd&huӲӌyɫ1k#{ ^ g%3%4%fw?x;g<'B-q:veMKP{wŘe񱹎)c^5 lJm`W971c^l|6*uQt7i%Te^u3x7Jb2X~#c޻bg؆y 'ؼrC0>/Filter/FlateDecode/Height 590/Intent/Perceptual/Length 124708/Name/X/SMask 130 0 R/Subtype/Image/Type/XObject/Width 1475>>stream +HOTY?QB%XQ(]@ibXPTDR"`HSt0tv8 3kss.>:44dee`0nӧN XMMM{{h6Fhnn[ٙy&fXZZx.....//kwZq-Ҝ45%-YFͯI}Tdbb¼A3kiaO*l#nkM^v__Ϥ;55e-E|544488߾}o2reM)'%%i!J5(QX fIEEŞ={bbbQ7=w\ii]W}3}KLLT c}flllT Xו۷o{{{~}Utttll˗/ vlyyy/^$˚tÎ%… 񕕕ͰEF5**JKA(?XliizG瞕eZgNNζ&~zDDDaaWQ9SQv)a<r?ǏT***6i5DGGG__lVQVx uqqٿXXXAAoGFFƦ 3]uK +..VNpvvNMMtuv~{466>|ԩSM244xv] X?^^^n47PN]O ===..wA}333S[8ycǎ='yԈ4[tttQQRvڊݻwGFF|uqttT]Jt?UUUKKK'z1^BBڧ׷qu5tvvNMMiSRRޣӧOcmM'&& צKFFFFDD\t)66ʕ+S,Q+/,,TLMMݹsgHHOJJ + ۱cXmJ Y1ŋ~~~W__VnWIL:.'JMd"JKKKڸN@9!_zv:k׮),..Z܎PÇDOG(&9;;'&&*hEӎt:HKtUԤGf~*#;;{ݦZZZZ[[^> 3ј 1= +-Y]]H[F@@ƂuӰޣ&8@՟L^k tssӃv?^cᑗ9ֶ$%Y5P8g*ͩ7&O>[ljj*[˙+K(~ׯ7TV9PFM=:%%EݻWYNڍ +ڑ%T8qǦٳgjɖ(&$$*8o =}z˗33336z~0PWWq}*Tq>/vttDEEVVV͙.k*<OlW833STT䤆nLB}s߾}eeeOJ(((Q㭢_کiVeCUUUi +0L_|}t5hjdduuuTX ,aa*rXvvvi$ "mz⢩d TW# &8LLLPr>,<YUUC%$$Aollddd|,@`ɒqX|:kO°<K=8 ϹK‡`;y槑"az# sss43_~ x:)ZHU%&&Ev҈`vvQ&tL-889蹜rUHbȝnj+**jkk7tiii}`HiĝpX a0:SWWWkkkAAASSJ;)@M8>$?44ttttPss +94]|}}땰rjoooqq1&&KsV:{{{T`puue + W"6../>77<ηJwwwM` %ũg\" ʊ$淓ޫW8E 8"c©)bfXCA{1՗ArSd~񻫫3C)Po %%%%y%Q~xkkK B#z||AAAwvvTVVb +0,,,llln7n`Lư@ZYY=z^;/|*-~~~7o>99p!'&&rss xÇ@u)ԜS+e+V + وmBɘznnFz rpp@fvvVZئ]u;0RJJ +d0==MtF`!1pNuu5IY_h̢4r9ҜFe )avӜ|u5"Uv־*g(x`0[b8B&b/(Qhh&7N?L3?F))))VpӧO_?0('D#|%Zx}6t;+ cFq}|0_'''Gc(rc->>>k Kzky/(xyy T$2R(vjџ*Y`ll,+V)xQQ 233,aGGGAĎ[YYt:.v2::+.٤$kkv+...??42fpXb[HFFF*gQR05E9 ÇaRooovvƶ~0F#ub"]]]566633&[p2Rm 3~޿D*U/kpS+~۷oYRRRRRxlQ(ȼ9,~)Cga>X-1}n˴}~z5`7.iƍeuu5x*A8 Ύ-3R b) ^ ΈwttT' Tp<Á"u,DHHmzz:DZcۛ2IR__)3 W]F{cc=C4&. + 5ErohhOR(gggkmmrŬy=4 НxV#0NNN~~Cٽq/(Óc"H )B ElI97r6NE(~=WϚ~nz^=}k_ϖ^b0d2>>g28Z8'(lpcVVV_'DŜ,⁏...0h [KKK'E`uFں-}/Ér EmXQ^%011p + 9W2LEEE0a\\k$F!GƦ#L6=}C䜛[UUEIEN9삳]RRB٩?)uuu- s*:K9$A\r?SA"%E "+Vk4)hDL`lvrGPloooSӱS6]*UT)`0O?x\˜@sc=&Z[[ lAB~QP=qݠ)@Iz鰗/_)5&իO3MMM Y$R---xqggbFLs\?7z8!!Aqz.;;hr`|yJIIh4!!!`< `d9zs'V{, +W{{{L= aaaԔT +eM$_6H@M^S"BCCAQ^^xIb'Ǐ`tl{{[>ŋQXXH@{2s977'Րa/_REȠPR>{Qoii)GTtTQ@RC4:BTDsK;Rhgg&$)D2 0==͏pu`` unMTRJb0"##1 fxxTwVN`\#??ߑϫWy(IaLnnnbC 'XC鑾 A]]]إA#'''0888`.. i"UkE.ϟ?GXK766VZ8}6Y*UTRunmmrՍ􌈈vyxxp4dwEn\flׯ111F.\'''r+++|\H[liiEB\c2ϟ?EEEEyy~عhjj"=oool /,5LTTG("UGGJ,`{5HiHd_III:l6Y,0БP8` @Hр:R ȼx +#&'<!'חH)###.. +utth˗/Dȱxlll0CCCT?_\\)8[Y`M~yTqDpwP$t +AR)*MDJREZ@L>' s{M>5{wޙi(>ُd+WFs*ZM>Ù6y%%%%WNj'?<1Qee0 oJEa=f_K`tZa522"A𣳳X9...%%XOOeVvtYYYlL vIqp^ 33#r˻~"L#渲"###sss-eNnnnvvvN?u27 L=>>"{"Hc%Q`%Pa:88 +银\jjh:cmd#W2&+ +0P"T#cQ.Jni<1551j¨PhҢ] -b nJx-l1I8coJ;aio7n܈e8Ǐ`naHHHUUv޺uֶиtΒ'E,9ƲϡB|> +hz}XXߠ~+a@(̢Z4F-tZIII###;;;_cqc!<ĕ@{yzzGGG@_l#iX cEHe7o0%%%TN+@d2|x]]]}sKᄽ=&j+)))))aO88na@&|ns+򺾾>::J.'b;7]昞MV)]Y]rONN㚚FUVVbCCC\rCxG"Z+^=z,bkk"X CLc^LS7^???QX~bFu eddz(l$8P AHѴT-W]]޿_fB邃]]]®Y...4655<3EYM;c`[vv6%$$Dnnnciu섈%$YQXKn<r`(LZJlAAAN֢aGfv9TTTXBbC|&cIIIVE+)))))V߬Hv²qX=w \?I#KO-#IcdBKOOt%-0wϞ=9NAYiA|4--Mk .ե鲲pd `ϟʧ?Enp Gtׯ_Jpe7ӱʢ"^3\3>|ovwws/--9Fqo߾222+anXERMMMcoo>>>zdzY3rb}333]]]_z588XUUe uP +k@)BCCN  +s#B4r<<=99i6p,-wa nb}Ŏ\iWJ4=--mqqQ6C9NKE 2<)YbuuL%C!ZYlrr2<`JJJJJJaO}}}a̚Z0 eFA&e(2aQP*P02 +(B@E52G@k ;ǻs.{z鵵5h00J ˡ\\\,--UKkXI9866ӳhs\ZZa X3|ssd2sUc8x6I0?MOOEEE Mg<##ҥKˍOv +?deeIPr^b4y+33s||\x{{z#kppblr7驩rp~~-..*kkk+++وGf=i ÃĠC&rz[[֖ZINB ?j,IaUJd39p9˗9 iddqB333(žRe VWW35&? ֫MÇx=դI&Mey)}ϟ:u*$$G$,, ¸+Dpݻwϝ;$LpZW%r! `}}]DNMM<8wNjwvv=RqἼot&! '3=881IRZZ:;;+3j_RRP1LK;V$~Ԫ$'0! 7((Bt/ ɓ'" Ċϱvww>}z؉ F_niiWƦflxP[[=6-ܲ$Q3>>3jҤIW %Ǐ...X#[śFFF/ +D333jALTGVWW={FrE9>00N9s+H``!!!$𾸸8†hend3tg5L.j򢓓1̫'Y;y$EwG _6piҤI&Mjepht05ͱٳxÇgggE qv. ]`eeeiq/^ fdddʕ+mۓ@&'(YYYJyljj$X_SRR(ϟrfB,pBڛ7o@|(ͼW2j}1QQQa3#?AP yI~>IKB͞dh8t4l63}̏? 09&&4Q"""VWW'3L&^okkR魄jz}bb" F'lj!| +"K>DC#`wN [RUUS[[gE*++َ9R,vͅf3P+&M4iwA'?sruuU& [fyy7LBds\:P( SSSК>騇EA5 }UAtdm'ŝ; xvCbe)*,tuuݾ};???%%%+++` 9&M4iҤ°lLZb?NLLH丕ijj + b(LzjYY}ڙϟ? xyyc٘;7Б%ńt:ZM }jjC8ʴd͌V5++‘.XuCll,d>lcubB%X &ڶ:Frz+GMzPgg'@E8-3 ,>h#P'gSK% I"HV@H=EQAr^$\SNͻPaj駟jj CʏuKn,,``իWj; j4ooonu읐Eq"ȐUHHHHH2V1`m˨ܱ ĭ ;;鑊,:`IA2ʘ{{{CCC%6888Puppq;C3X csZaN5A>r!Kh +\ !32271t@8~b:Zy Okkk)xCwkjjBCCsrrF*8>xW \zǸ8+++Sj^^ +!,--X\\,֒|b-IQQQLMJL?^XX߯jvt+F왙o=Z`:p G111=\ Ǎ.%CPP6<< V!I\XX_aRZZZxm_bObb"$I(uPI'Y}%##= F`Ozzz-att455ޞ]+*֭vJJJE vvvJ333s{_]]5?f5A K$$$$$O >cTWWomm齲S5iii˴|h8O%]\\%x^< ްrI?ZZZJ}H󂲀???fDĠ 81sssAGj...Qmnn0\ 8 F9555n {8XӧFavvN555{{{kFC,YYY^^^NNN\1z䰳*++`Kϖrđf^ftòH)D4ɉ2,> J_|7o$F}ddd޼y&9;;{xx444{||Ly `wvv ghhHd rvvfA2 d1-PɄY!8-ƆcqX2KY* 37*6-n===cbb()ۏbuγgaw}}]o +`dge"M[ݻOɊ J-$$$$Vwǟ+Wa|q[7M3lx@1<<g?11qeeEj_\\$dkkKO3kH677Ǒ 08-,,^qIX>T΅ɍܶGEE`|"L}0 tAnpo.$$$$$qؐ{}6۷oD933la@PA駒Al:7708谱ijjR>9755C$=^H@(F `.OC4g H4899A&Sooo778|IH(v@l[nqczcRCVAƤ$jk +HՂvdA/?Y} +  [v`tt4|W[;;;S^OX5eoB_ +FyΝ/^H(?ImYq+ޠ2 ]]]뗜;Hbc+YZښ||||?~LY>%4v dKش Ė`lTV + ssssvn1|>|WW[o¹LDƒzzzcvr;;YYYTUUR*,,^\~FdUTTcXH-.RVVMMM)7-= O2;* X`KAO> @x(P;>>'i z_]NNNNFFZ88<,--;}FnjjZpjjj(..VFxk fO)wʂXYtVe"*)%.. 0URpʢhv,x`h*I`PiՇa6GVmhhs~~uttП?fP̮4!~G&? + IIIkkkʀyhw[Ӝz2YNW`2&&ʁ>|(%竦AnnnY4@l;;;* 1Mf˗/\!@&D]ʏ?dOKK44 믿vwwtXb{{Cbkk!p.S^>ԅb +8]bb"qOMMOẶKƇp^h + A?N\HHHH?*γiiiUVVj8)1>>٩t0d@3:77's,--MMM=991?C@vv6ԡlCHXZZ"U|eEGGk4 &-.//+lll +rppQ)VKg+++Bm E2tbY#wwIKaaOVVt~&m1Z5h_AJxb"m-1JZeL[cJLp#"hB \ޔwr Q/9cC3{3kt"i|;k}qq 6鿕﴿yǎ;ݸqC'Oԙ,o{{h4i廐AcE[[7o,</>+˗/oٲE*N>3SÇ;D]޽|UUzi&$O{fDB~֟ ++ae<@KDO7Jur2gaaAȍj,K]\Akr,WoݺsN)/+&&&w&dS}Պ ٠t ;֒'vZbD"Ť!Fn֭Ǐՙ/v#zN0`lP +ٲ<0reF }+u&K2Yo_ʜxB0z'eN*TVj_V)Rmi||\ H',y>|wgJ7_z^َf +Ï?$Pjrcccd2kF`0ܻw/֞d,[\\tvӧ˞)VrD?~X*>eFFFFGGaX0O央 Ǐ/ΆVӧjdqqٳ@`ٓ +377wիW߹s'JUv۷oƍ6m +MF<f I9>r}vwye+Ͻ{ٳ{nǓJ$NEٿ+W>~(AáN}.k͚5۶m;pÇVH]}LxlbZ~։w4 $IGQi/&''3d:sܜ)}/_lv/VRsN{{{].W0rڦ _6h4*L&% +ZZZ^oP!ATUo?v}^W%LJ< _~vvvΟ?-@OOO8z^Qd2)`SSS(x:;;N6hիWr ^(J2a0ljj +B=Oggl&w޽~:h3p*Z>/ ={6Nٳgz^Qd2)Ci㛚BPt:K>O$x|ygʫXޟKZ,P9"L&#`0vH$RDQs j.F"n7l6JG}… Eq쾁 ;CmedRWA!FZA'@$&I$dcR1SmnvIk*(vc~4uN. +N +`ww>xYccceee}}}oo|SSә3gZ[[?$>|iŢO8ZYY߿f/_nhhhllvZғd2dsaaa}?ެ8zhuuuE_$=dȵM#29|~a*~x.]@92@6\?. uKv TIPㅺ ;f*׏(BRF3Gexn)d#2qPaLt8^[ʰhrH r/-e؁l4S~$]@92@6\?. uKv TIPㅺ ;f*׏(BRF3Gexn)d#2qPaLt8^[ʰhrH r/-e؁l4S~$]@92@6\?.b>@E\nqq1\?0;;;66x&80BRF3GeB>=tЮ]n ][[KRǎK${իW$>pPaLtOݻ;޽۹sgWWW<>>8N[[[n]x[`\9^[ʰhrH U*}3۷7~ٻwO>{ xn)d#2[l6^'gt2LR2#8^[ʰhrH Y[[;#Glۮd2p"fd2Jdf68V7[ʰ|as 2[X,޻wuuu>D6x8N'T*߿433S(&M25597;yͰVNKg튊ͽlWTTtuuˑݻwrg+WRo|gTzmm&y96;rkGO?x566&ϙT~ECٗ/3_z_˛~Jbq'ٳwܙ?p@'O!R _?T*]zղ7o={vrru]n?z̙3of;6??Od۴#HL3je$Dsxb:^H$@{s۷k.ĉq{f~~ӣcccSSSKKKVݔ̲yviF(b΢]ϐVL dvqo[t:oPAwS2m$52j9v})e6ӌuQFŜE>!R_M,iGfԨH?2-, it$KAwS2m$52j9v}N OY}D`Z bux¤֨HdF;AbQ.#y ʨh3B>H }V +Ջ;?nS'؎VxX0ir|+5>)NfԨH?2-, itYqJc4J>)uXH:!Rzxίv6J{ɁәWS؎VxX0ir|+5>)NfԨH?2-, it^j^|ZǝNvly?G+Ti6_4!R˗/:::wSN---qr|ȑݻwٳѣsssawn˿l\nLߘh~~{N6RGئVxX0ir|+5>)NfԨH?2-, itz~֭bhcӥRɓ'mNjǎsν{fgg?^T@u +~zqG?oV?Zz|Kj&UxFGt7%3 ӌuQFŜE>!R}q陙t޽;666770t钦im9|С .Z-FoVqS?sLŧ>u+aCu Sݔw'HL3je$Dsx/7_?67 !-YXrscVq ro^ҦxUnTN[ZZZ{)-?zZtuͲ6x'c/^8<<,JPy&0333ܹs###@-#B2JB{;mlE:ٯ!HqPhث) =,R೓h(3 +ē9ɯ4`Gz`UD\.J7+L棏>-G}~GGΛE!P-?̞6v'}ӕr ;$jK@aard:'CdTKNl(tOT&A:.,--={l6 d2vioosP!`t}![c۸nɴfQ\)DHdR*GJzBidNe+>z:@B, ì>VUU%{nw[[!BgF; a[k>/Bo_n!QJqPhث) =,R೓h(3 +ē9ɯ4`Gz`U۷[[[dT"+X*Hv\.rP!B} |!:mvZٞO'tSVXs!z;)W[ + {#%y=4t"cZ +|v esFx22FHr=py +eYqrŪnr677711FGB!-Fj$<*'ƺm6a?f[$Ów{{^|CvR*GJzBidNe+>z:@<<xցw)B!ގP,>Q;kocjp-ܗ-M"jK@aard:'CdTKNl(tOT&A:Tnurr"o>}2==m:;;3;m!BoGH.u۸J=L:'ĠChSIqPhث) =,R೓h(3 +ē9ɯ4`Gz`UDٳgqb+W=W^l}}}Ѝ#BhKb"m0?bw{OW?KC76rf_~MTe٥%fCP o)҃\O#t"\.8PUUU-<:ujppl,y۴mYY~^KBw6-]vqr<|j}IPx޽{yСY7VՖ@^Ht^O( ȘaDCٜQ0'̩L~;>҃\O#t"X}y$Ycxxxrr2ͮ!|>3B!i)^iNl.cYۼ<(eЦJzzzf[^3gjjj8y +/]ѣNv0)W[ + {#%y=4t"cZ +|v esFx22FHr=pyW.rB!OB:^^w=4t,|m/&CÇO҃\O#t!B x0S\ocr~>|A=~˱XT*<_WWwƍٙ3f֪amڪV@6EƳd.$$,J²lPJdhmfU(h63 6I@e):yxbh4 +yxQO4(GF}ȌSi) c$]Z#f&@!BODa%8Z82{l3׹un+j{xq +]VզZ[[n|.kll * +i, Q,34ShH Ig-`G2L8CB!;INFzc/w׸dޡqR&;#D(be*jiiY z<-Njz*0G9T&7CfΘHNa# 2'tɠ638B!lb_:X9sefx5{GZ@D gΜ|2?8SLLL477g2{|>ぉz*0G9T&>d#.]2gZ#f"t!BI(T'B!bu۹܉\G~:etщFvP&YV:nmm[{\Cd-멐R H$V|HWvgLig0=#_u^51Wق{ j3n}S!BHV$-_wwa۷p[XjWʁjZ: BST__h2|?ٶ6W,_thKO*z*0G9T&݇]1@;FeZ#f&(@B!$QewO^b;m-{KoW%: BrW:|8{ƍGWzzz.\ —E=XأY*C!3vgLig0Ўt +:[Pk dPp!Bkb^yxl&yc+׽s•ڽ4t>m||p ߺu+J?133S.j,q\p|@ |xQO4(GF}ȌSi) c$]Z#f&@!jTj-,sw:r];//ߗ:t8yd4}' vwwK׵hb=_wW:?+V"$A~˲(>ڳB^>P;v$ːtVقZkv|$̄"RARc9)'.לu*m5moLڥ.C>nO|v>!ZN<gXy;cijwO6:|}$u;hr"zP!V&vJ4]2D7hY}l)k_8ËϱOvVeᥗǝ+K!u@E23C2ZM픔iTeB3o'2DVé"+7/^6+z;sݾσnrSN\$S9>$Uj$NIFK]|ܞ(4|"C4k:<4ˊ33j&pu: <}$u;hr"zP!V&vJ4]2D7hY}, '[W_bYVcG?zS|yX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVS [K*nV3ᅗ`ic#MIݎ,ڧH^s}HFմI2j =?Qh Dhju8uRy~x+NҬo[8snCARc9)'.לu*m5moLڥ.C>nO|v>!ZNd_u]?=껬4؞?E2Uj$NIFK]|ܞ(4|"C4k:ygWobYvp;;_yeK>YO9qL Vii|;%e.uq{~Ќ Ѭp>$1Y_"?sڹx6 u>xE23C2ZM픔iTeB3o'2DVé@O.8O}oyX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVSOeOq滓}|yX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVSYߺO'S4ˎ|kZvu>xE23C2ZM픔iTeB3o'2DVéؔOFN ++ΰC;YyUϽ0J>YO9qL Vii|;%e.uq{~Ќ Ѭp>6puyžpGs4?;aHyX΢}ʉd5g@݇dJ[M))Өvːf<ߠOdfVS~foO'Yy+x?.]zy& w>YO9qL Vii|;%e.uq{~Ќ Ѭp>6 |nOfv-7~z˛XIݎ,ڧH^s}HFմI2j =?Qh Dhju8uh'|et ?W>YO9qL Vii|;%e.uq{~Ќ Ѭp>~Cvh'+}u'];5/uyeئnmZI[ЄDz6n'$| h܀Se2m5`{m\$P`$&^;_.{jM|t9ύB5aQk]H) g44;Cr= >;"aHO,Xjv| <B! V?&=|owԭ~Rb6B, +y52)&fgHg'6W: _m4B!27w+%t˸۹-|G]4X.B7-B^k L,*GJa`< <$itCzbW}#=(l0,@B!B4 sÞ<߾pˍ;,tZ(ր®r3Cb!LG\0'Ok,~;>҃t!BIBfG]|ο}=`{9YOyE?+J\P(G|>wVōp, +y52)&fgHg'6iů6`GzP`X!Bh㔦h(%ߵ?QϵȟܽZn!iXYY{ ƺΞ=[Tuia9ooo(E!T&v#00t 4d:@!=xZc>F6@!Z7IZȷn;vu|מVVN<!)YZZ (|gg^tÇXZk@ebaW9R +M@!1ΐ\ONmt5Aida:B!VK=*]|g=|Vxg"tIn(#Gfggoݺt:_E!T&v#00t 4d:@!=xZc>F6@!Z{U.\vD;빶ۓ~/*? ,tIn($Ff$!Bhb%Po]{8Hjtmvh4033S}z~w.Jl6NgjL'XL}f314db!N}LOwf\,SgxXHe\O3s?G!X]8;zD=jokb)Bn($644Vz^vmEQL&SSSHQ|,;j3*Ge3S&c/ ?;۬ \cvjvcX|nohn>}Μ^^^^K!B_{e?N+:uKQ~:IBfc)>bzIŋ^\TJRZk@ebaW9R ̍$j:i(Jrz|v2שkLJc7`GzxBK5#7'?G!&''?Q^Oڶq[S[4_$!9vOfggXd2dAk L,*GJacKyHLq^m(L.d5AidF"I<B!GBV'ws[m|g}›gSdqC6?㸁{}sH$Μ9+}Z2X6rg4ҶHNF ٞg5FVʄN!LҾQ|6: - w9eNjvKoEIfI3ӟ(x" +S+͔}L\TA|;G@ +uSX3J̨x`r_ҹW3OkS#8[f kK1iݻwST?v:˲LӜK&Ǐj$ pyMDQhr\lԠf 9 U˰jhv>VeFz_/ۮ7MzjL߷v|y6Qx<)z'&&7'l2ܱcݻ/\`&uL(O9~P6SjPa3qQueY*eOfbyo4G;+2n]2H7%=Y߷Aѧ?9[QQx5r|ʕ˗/_zڵk[XX0Mi7oQUaf~' +B +e3u6UgP&B]Tk/Fs R,3>+}73׿mϓzrggngeQGWg?QDڧ?W()5:2v,H2Z3|7gpbQ ٿnX/h'}QZ\DBDQhr\lԠf 9 U˰jhv>VeFb,^=ڤƙp>OHDQhr\lԠf 9 U˰jhv>VeFݺdI7goѓcԈoտ}P!Rg?QDڧ?W()5:2v,H2Z3|7gpbQ,C_.lKAmzO-}v魣[*u@:ufOD}sR3(oȂT.~5{9xwX)ubKK?og>=lmwN Zu0' +B +e3u6UgP&B]Tk/Fs R,3>X+\.m3ܨǛiݿy:3'>BLA݇EɷsdAŸVX3J̨x@mۜ驱.9Yz߬5k@ZDQhr\lԠf 9 U˰jhv>VeFڠ}o_~ܨMh{׳C_:we' +B +e3u6UgP&B]Tk/Fs R,3>`Yލwg,9m:mz-r`u>ՙO<)fJ >l&.ΠL# R _,haXf}Vc"-==yRި7t~5Z#u>3ӟ(x" +S+͔}L\TA|;G@ +uSX3J̨!կw>SO驱w_~ƍT9` wWs_&65OO-ƙ"u:OPg?QDڧ?W()5:2v,H2Z3|7gpbQeYNӓ333n;;;k׮;w~m۶NowjF*u?"x[»o]|{ޟ6"WDa (,-P/Xh".C}Ra)v&@MQVը!(=唥t*ŵV|v MeO*#\3 ;>%D"t) +0X,޾}/,,@%D!!"~p߱?G݀BOe58أtP0CeܾJNc@ Ie$+btaǧdۙhB5EXLR 硡!$w*Ȉr P@B{_}-+Zأ;Z%}Cv^B_'fkp0G9el`,݇ʸ}qB$tH&W ÎOɠ3фj:HܹS(~rTP!B%jK+=wgV8vg@C.ADoe58أtP0CeܾJNc@ Ie$+btaǧdۙhB5EQ$IyǏ;v}bb"CD!w*)^}X +]7Zv:B}s(=唥t*ŵV|v MeO*#\3 ;>%D"t("IrNPtR[[p\vVAD!T3R?{S +W%]*@Cg‰ QNY:[(A2n_\kgD ]21:ðS2L4!B($wlnn޿;A?>N?mF>_YY"z /ScN_=]=tey)糹|6O ~|\Bl8Q6{X=)Kg c9>Tk44$PTF2"Fgv|J&D>PQE䓯F^v˗/;&I2'LAog tE$s^jh4lNNN>!ԬV&R&}U +ׅCbJS/@Cĉ QNY:[(A2n_\kgD ]21:ðS2L4!B($w ,[*l <|!T.VB!m;nTt@M(=唥t*ŵV|v MeO*#\3 ;>%D"th5_wdYeܹsXtGGիW+ BH%Ax'D(x[!v'fkp0G9el`,݇ʸ}qB$tH&W ÎOɠ3фjt:}Ν>͛sssrYwvww*7n'"CG!«תfŷ;|>}]rz_B{'fkp0G9el` ~=n_\kgD ]21:ðS2L4!BeN˿:ur,Kx#B8Q6{X=)Kg c9>Tk44$PTF2"Fgv|J&D>PS4s ``B/Z~qΐH ]o}x÷*t:j:N``rBXqZ+ >;&I2'LAog Bj{{+x[|KtyА7!^SSSt ,[,C_?>MweqŽ2rfa(jAE0*=fP P+J\ڢ)]ޯ|ɷI~4Sf,2= ^0k["ݏSJ7]jZ9Kǵ.*!N_NJ#Du#DaV+z{{_744t2%K`G¤,,,9sh4zoܸqǏ 4Sf,2= ^0k["ݏSJ7]jZ9Kǵ.*!NUIogӂb v>F: DžnBC*lN5L('TzPmt?Lb*-D|vyj,f$B0d8Bv|BB&Ck)Y +U|u:9'yt@)yСϟo\ﯯ7Bm2/Y3drB ږH#*MggVΒnFq-K-d'd(4iQV^D{We _O};)is֪sq@Gnn޸'ˍF#Pl|P2? 8aI9>2~$bTA*YH<.O(В^`&; +?ΐ>ڈ'A}6u:>It:sssnž>\n4_s8FY_y^9?l3V +Ģ-]I hbH,grU}}=.Ƨ\v9WYXIQtf!_s +&_D@q]JLR(.lj*汓 t}}}rh4<0̓'OfggiY(;$jOekׯt7#<}4l?:_0u賩tO&na';9:Ǒo\,s\CCC߷Z0҉ Q9Ç/..n\P(mmm93hd-&mHEM `xO sbY6oƇQlIvWo5o逰sssIGQ D" C]](` >Ɨ\kJ_~&~~(<1x<===h4*J1 C:$e\~+@VX" cú,I(dɔ,>q:ϓ[yܬ@V WK:#$p8lZ%-//APYYI:1 +9T;4W=p;7.XY]]u:wUTPk5jK:#$$eݻ'J=zر'Oz}ؾ:A%Mo*b."u5p +<ؘphiiZxۼK>y!QQ599)}!&Q]~B2Q |HWWW{{{KKNST`̟>8tXRήvά:Y*"p$pr@G .73 $\!dD֚jd}9>y>/`qX|^Q]uH$U&>l!Qz9Av)Nq&Rqhdϖu $%ơ!LV]]]^^\nqq1a, |L6_9@<<6L~"X5/@zo\mi|Eonحj=#css$999!!?v]O#!Td"%GFFt:$SSS322vuh᡾~mm{mU*>Ԁ999BӽWC|; Gh4x$%%>4UTT6,2l/6:rs[(uMLL@H <_eeej(:X!뉥wtt8,mEc@)ͺ0Dh}p!< ~(ű^deO.766VUU.`,b +JyMŽvq}W:v^gȽF}$;u?>=z9I4LI&VfwI T:WA-Ɛ2JnW((%rwww[[ +{4Q$""ؘf۶NEEE\.`_v-;;ߏ +v[] c݃Bwfoo/=,~ee[JMNNN.w;>0GA$ONNuzzƤ 6>NDó0n*BD.NE)gyy9"P) Zy +fٻ #xE\x@ +?|tFTCҝ===Z{T*E< SRRxQ r枻f@W&!(Jii)zݱa^X a6d;".R]k@ѐb;@x: Y}gOSNZs $ܵ666F̳gP%544澐/.`l6VW6FakYq@AHL.ĪRdK!  j9J6?\:_Y vejj*44oB Vt:wcL +r%a̎r +^s`@FWk\p- 2t糳漻$I``իWU*٩kܹPG<}IDRRRrssS%***--P$u+ Oqڪjd,q򦦦bHbL#nyX +^ > pva1uzz:,QD4G{ `v@ŕ]@ aWNa"c/Nn0:h}hg7_fpu K +\POq\Ҳ:XT{GdS=ȍ'Cdgo]IRa Vf |mLLLdddPTTOTAyL7nuW|(P(~?u]qIδ!:Miɤt2=x̎رbYf_j 6b3Xl",̾ؒX1 7U_&S3t9{{ϷC + +:~8mhh ALJJNaGWvvv(|||EZVJB`ׯ_'p/NNNNj\ԫPǬz^VSFi:8;;H[QQ:<=*=L&U@5!/]tԉ >y>R啞S("/^h4af BHH#`0PbO<nݺu *E&:::88/_quuuqq,8lP P +r@CݻWXXH^!@˶Qy3*&f_/j2dȐ!CĶa-E%g>\Z;g<س8h`:Z/:j|B힞tΫ+/}ڿjgod(o{vɟz>qsrgn-{޿31}i˯[|iϻ!Cƿu:331A`@MMMf + +Yb#!S .@h48(ð6773~BB8+++3b˄ۅSSSKJJ@1k|3q=.**zWRhZ<@츟Ey..e rc;,ddd}Z^Z+No{{{ccvI kDϗNд4_Ӄ;;;o7GDpvw4nvvMv;lvvg&a7$3Ĭ, r2"W;7EUZFBʥh-`r)h OY;{is>}_{$!p8đtѢR2 0t:e2$R "tZtQnZaE.f``roΝ5j10N2ƞ|abii… lg}} r]3cA.ө8Vg.wӅ?%^]PZf5Y$H A‡ ӍG+a_;8~򻕫> s\.Xw"DžյMr}}Ns:>* J`s +aݖģ(|8!C^Ցo~۷on6Hݠ M}ithњ1Bw엳ҥK*j~~~.WsMf΋8jEjh4(_H Y {fff~~~`dCCfXzzzrss4pI5^GGGSSS!:{ //d2 jAxĄ_f#&A.)) u'W;22B%ݲ|MMMpJIfeeQqVAAA|mBEl&J^PnPȭnmmp0 >bdff'̢Pl4dedT+vwhh/%A $H9N=977'c/lw?vVލvP¿B.^T___[[[UUuuT\˯\RVVVSSV=&L~Y1(οt)R߇}.|q-87AS^\^wy66KŋA8Pf=x1_0??OE>}zs#)bjj3݇0D68q"dgg%>D!Z@rɓ'ѷnz)ÔJs񁍰; 6ֆMYfl644ڱ|UThǏťs*|@4rݻ!]n%nV`0pzT(axUKV;Z&==^WHMM`煅>gϞ> EKlbƍ!Q^)U@M&_ᐐ~!e2 I@H۷o=QP\A~Ӭ,$?8#͖M2wܙ`0FGGE + 988СC 4S,TVVbncS|>Rg*--yƁ:ʓeNguu񱱱 O<ȬDn Dʼn$H Agk+FjE3DZ~҉/] Ogk?a.?ܯ/Z+׹ |2T.˃9%So7va B5R5A/7TEEEk׮QP, +bVhhh(YAEı(t$ l [>|HLMM1iZ,G|>477,OI0-CCC0ῦu\$H A=w-&r1_,Xޥ\WWW `q*++"qee%T:ih`m:|gX(yϜ~{P#TLLwO,.uov%HxJKKJ@;M;pl~5Ų͋܈FCBW*..nbzq jiDh722!"Devvv}}=4** +d,AQaaaT(٬x[?$vݻxEOt&&&UЗ`^@_5 #*JO.unm6c /hNHHH}Lo&4o *3L_?mi_VZiUwUwۨ?tTB-IJx!‘`\!$@0!&p`pc}[/v +my?w晙b8$$2<2xcBrh˃"xS|JJJJ"\ENd2YVV8 , -'9pG>|X <l,7߸qYX%fMM Qs1KY$: !333<<<,,Lōmp#G0= A $?⺝Ӡ4?e++g^sȶƻz}ۤdwoFF/kȻJKK+**jI k7;-ţT_TNY{jc~eӽ; g nYݾvwP^(84B@!*}Q$ɅkkkDVzN@W7DDkZZZbb"B &E6VFE~GZ6`"$ ߻ߟիWd%%%zITfW(\6ָvۧHl@`ݸL1uuuOpTBRR秧w%Z233߿\p .M MAi\\\VVCxUNS~~>ojj*777!!p6B{TTt:U*e7n܀:fk  򔔔ׯ` +#7 r;qr|)TCKtt4{'2 P1`ѕgq@,oK A +f˶ZUZ^*_֖@}iWOAJCbF! .+++--%-/@2LU^^NZHV0t,{Ւ&yNuM/xd'ӼV=mxܞmwgw,A;ggg + +2HgGVTT$&&r'B!!JOB!P^TTVE“ ;DDDps#{dDӈY.ioݺ/FFFpeԫR4td&gX[XX`6O[[2˙3gǩ_tO NS&x!8.+77ZfK A ;M]䷬XO 뵉[S};ε^߾]__͛7s/\v DR/Eڶǵ5ri6p`ЙwkTm?z^Uo69aہN /sssfn uuu+++eHG###Iֶ:::boVt2'HP#G-㢣iD-IjFFdB=zm7~0Y?V,--֞8qb``/^i߽{WPCJqgg\~w0)))=YZZj41ڪT*^/Uގի0eÌvD'%%ǏΞ=K?x`SSí[_@2>>~ҥQ›C +)|BC `Xd6ncy܉q+@rrX|?duuuhhp0.Y[/Ν;>72s By=!A $?rq//kWC\Be|׷"u$S"&٫ %&rII y2wVy8o69W.ʖnQ}Ye=i^}#Lmh.@[;٠ ]ޱ QSWW[t(tZ_C\| Gqܾ};>>>++Euu5wx<f~e,X {zz/v[XXB3L?+z=ϟnll\^^}dd?0;;+v t +ohhqӝ;w ;<[[[CcHbonnҲc6^{Zby4 ^~!@<"|B ;7o[p$0ߧZlSS _ZZ688H'EhĭjZPv;~ʕ<ʬytttiibH1N=Ogt|S|k͍skʋ"Dށ 0v.f !ʫ of!!/ $!=a79lo2dyfgϓ<Jt *X___QQQ[[k4є!BT ꂂ rGп9s;HF) }@!s*dvGBXN60͡ZEQww9*4ID5_jo:uX; x܉D"(uנĭΝ;(+D gk gwQS.bfgdool(3}!EouVUUD~N-?ݠEfffcuBr}zVTTOנzmm@ pBeG}X,VNFh wwwʐ^/ h~48u:]cc u`lc )hKD"X,!ѠTKA\e4Qrҟ~ϴZ[O G/ gmCCz*ȼ! K }**Nn8OGR_:D"&MR) +L&J1 H$"$iX<O, qC}]lgW :X@?ٗK&>8_;!^4Z.Obbt"՝6+L?PWyދ?ʷ~fM۔8R]zb+++GR8./HaÇ bYZz +:t[Iwmq˪cÙy=9ĞlbY|kf9tـZTwFZ|E?JPW +71S.0  +<$AD"X,H>J$%Y{ւ/-ETs{r}f.zo/Ws _sXE)טs`$^iKN>J]~+6J@_NuxiD"0L(r8zS*bf\T*;::t:niO2, gcډcr5k +\:Vup޴Xr,Gy> +c I)N|;U䗔pGuN,L04rJB2 qTkiiQf* M&g-uܗU'Ju_~X4|PV!y0d_7l5:Wc41qoGb?延+xwd>_6%VmI.7x-9THfi=đ go?{`lXrpMaG|t_DU&[;Tf1Ju˲`pyyf=yDtvvd2X,$B@GFFf Di~iD3n?׌ݝM:ޓC% NTJ1jSo M _^u'ſJPe[)ERqMӑHϛLL&Hb1aRq\եjV+EQkO쪏3ܩ[[13O;@dVyXiߘ +&Ӕ?Oa4vCHWJ*{*J]cMIMu|˲gjjjppMP(&''nw<yFx軩 +tYCPcX=.F{n=A wRzKO9ReRZzURrǥR)aD$dG NQT8iDz] Xa:Y?^*$?8!vgn-ɥвw-Y.}޿٭ק4vf֮hEXk^fmwSA( .c]-\b@!܌IHN!ד {ıX@px~Ι7oydfz0.#5y_EME Ō}MN%l,333fYѨT*\. +y<H$===ܷ.OEQkCB)h檼iqPDWPSsBv/'/ s?L8p` ah:8=N|ɏTq7$o0\緩,N XZZzCCC V BDѡRL&L fkC%R?~8LHϴ%}'uoUxa/,7m_w/-Tz:ێտ5.&,:\gI,0 MәL0á;:: +S$ⶶ6D"Jr-a%=Z V=>{Jt*;{X̷S_Jr͂ʼnlN +%ىD%~g&mWb::si$d$qF[$|*AbL&S(Jl6?z(?]Y!3 ʼn|U-SO*ӆw=4i,8|qI?uwjau;#}J{MVX& ^:X,}}}2m3JR;)^dYѢ rsYci:Ti8XUd$7\"2$zqX8јZտɋc_Ot]zFt, EQ`n(ݭP($ BP |)jj|h4Hd2ep.7&uݰ~t#ŧ N{KuOh>G:k5Fxкd3{xat}|8V#Rz߹V:^ْsEQZ#Hx<@ PZ'u'Df3]|ƴL_P?ՍT޴]ZɎ40 L&0MkϽ^T6\YZZ4/bw DqKfbApU (^ +lj9x<m:9 vv7⊌7m4nKRܰ ndwT*mmmUp'JRR걱1Fם iY_(5&#ο]2w-սQ?p +=R5aاW'ExfkC$Ir}k.!EQrEonnniij6rNn-BaoqcwwvN^.444d2. 466NNNf2Osp8֦=ggg:&,/շ ۱bu;r; uv3U(l6 7r3$ UbMCpB7fXfi1Wh~TX?p +=XVf3ٝnft:vL6;f٩PUoժ  +ToTX.ިUlKp8>qkml~rr{53|unxȷ cvD}1HƐiD wǍFc^^^]]ċ< +7ׂ$"f0+++ mE)y 333appS V]]]PPraaacH$[]]}444`%}ʢ VTTDm}H@ Hlv8$J{K>2?ο~R/O&I ^KxY^V;;;JeGGL&J,bkkk{{F1N3 ?H$^0J&̏ͷdlf(\0M0slI+~ԭ_] +x$Jũw#b+?, STp % F7o޼x"-++p8 FeeeWu:]<OP~%8ޓݿYPx%8Za 9??B!uH$ +b1 J +kkkǀV _`۟@ bǡ0'ߴv}Xѯ_]1"/ɽmiiibbBjB!HZ[[D"xd0== ` ̏bȲ*]پc5|4cxٟ#t鋖sa +Cݼ5@ ~n\2`0X,Vss39}4nkk%bs!SmmR|bl6[ׯC$0@ tzYYbZ uxUTZDs:իWqw:p˗/K^@ bIج.-_u$q$mL&a pll |7"D"q +t?b[%Ē2@ N:#'O`h1"CE-3[Uv.7o|>P~dzyJ.\V].דp81 K&t:덍,k||ӧHQlp8CCCDΜ9׏+//</''ujj& !D08BNg} Noii +0j AO@ bGHF@=+%VWq(,"mIܿ h/37]Noc?t;:b-K`BPjИKAE Mb (`H8$+.Jݾ9s9>o2|/lP?[SS(Lե0 vf,+聇fiDWKP؛>rEH궻Wͪ ؟>bG/l6޺uK.+ +hYGGǝ;wpYWWbˉ~ŋMz[__VXQQ188zC7(jq'N gwwws\DbXF#q x@ SKR1i||<`8|6- +1dxb7Y@ Y[ :gCdppЃ2wq|+Ɏr~꽓xjv,kkkr͍ݾ}6L$UWW# kllliiU*f333˯Lvo≧tLjKz8վD$/4Ɵ0s MјTl] _]@ 'h̎jEt GT)6]ZZZVV^\\\AaaaQQu:ɉZ8?~8 F& +DrZJvq޻wm ree%.."*))bL܌riݎ +fEN'J F(xʕ+XxZZCq +R[ @ ސsIPY- 칙Aeb2wS- >_Sow[g}@3==}Nx os +7>>r^WY0__醩͓q{?>=tF2GMcjgJxP1a0>))IY֔Νɡi:8N{{ܜL&}(@ *pbqq\.G E0(/zrݨP(l6[dR`Ⲳ2 ?ԕBn2Pj-@xly!7~~YFqP]CEqP^2w8(gv7E`a)к[[[o޼ K&HjkkkjjE"R0 {4tdĥ#܃ˍQepٱm``>0pe---FL΍x>|81W_Y L/Kek#_?adh~%ī&>Ч^Tݞ꼿`w}c[}wv@ hH8?i +v+nZ QKKKkoow\#\Bv{d&'OX,.i#e?}4fDSNfL 6pRe2YSSjEzB{Pa@]l=HR.rq,۴Jth2x<~7>yiiihh/crss#Ǜf/]b***ٮ %,]WQ"H( ?եj ew AeOeHS"NuUneeeUUUbq]]b\>88 qee"Mss\2LNdn7_Bן`➞ r4Mo auu5^g|gRSS + +"nLOA[[?˝CMOA`m}\v>ٙ{`2v}#_.NMWg]kǮ[vwm̬ (^֐m +8qE 6Ry@"BC77!g{ u9o=wn&|V1 tcAE +,흝BѣG a7D99'W4W<%MTq\s+ɼ>]c}5( σ۟re_o͖24-P*++R)T4SxYPz6//p\.χePL޻wĉ. ޠ*v~4`$ fh + >|,D8))͛Y`nܸ/Zؓ۔ | &^'}~A6bDwB2G>]XX ﹹgƫWξ`A^A_8t\?n, Y&iΫ#TA8unu iPrV%ykPzf811W*q{C*ߘT>yӌO.ťK>JNJ8/&N͛=Do p9p`0j322VL&ӳ5п@5zッEAɁ~,2,!!!// ?3gθnX +(lZshBښrԩ:H$[Y*xԃ^2M|Ra}4jFOm]/[ &4v{4?)gffbo0LA%d{W}:F}G!wY;K?'2~Ffu6x) S [z@6 r$‰f׃la zlxxX׀ήٳ%%%,$L&NZ o?~2LڵkLlt ?Zg[!Fdn'2;mWدlv*vȢH5NI"ں466B1&ɦM&质7w~3Issl9$$ޤEGI5q¯ "nw̅a\8VWW,˃N`WHS$^$lN3j 2KKK~---R{)OrA DÀ_ +dXZ7ͱF@bx<ޛAdsn9'G;n~ڗ$m7ӖVb]> 05q xjj +\[[[}}=(%9NCCCSSS{{;wzzzbR%hDS9IT$DRćS%f +>RzGVώ  oP:"AքdXZk,(AK0¡09vJyVf\;{_\am%AEG0F"ttt4Ed$.J<+al׌I1J` +޶0zhT JB캺: `BP*bUl3fal }RMet*k"/h5.9*0E9焟]%[Zvk7%SN(TTN/A +|UAAd2tzE$$$X,Xc___UUUgg=|>aCyY(A-(Of¬_^W)555l6SS?봣BU\ukXw(HDŊXղv]DIB! %<HbC!H{7Ai˶<9I~9|lI~ v='r6licNEhP=˺g-'v'$^FbJɛ=9y;4?߂GDoEWA,W~~~nn䁁-..6 7qPy,k/#܀fnD|9>"J?^t &b`& "255eۍFcCCCEED"JE2kڮ.~4kU/uL;2ʹq51>ɰaYÞsNI;'~9|& 77l~~>aYΝ;M>=NGd Otn(9Ỻ X7YQ4n9=u߃?Ei&IqhX, 2L"myy9].WVV*JJVf_Fn'N^iƄd}b{S.t}(Xd>qv]|5ZX{ + ^V+jkkk?Bo#.⧞ju#k@mAE/V`uʮeqM.0uo(vTWW+ʊ +\.[$JG:p[aY^ȃ'O>ܞ3wO3M||gbaϹ;5vS .o Q~wDV$s#X\Cn#J? 537͑Xw&^4---j?WRdQYYX,j<66677x$aY8nh*s&O>|Dpy_qY3$}|#7% Y4ghhH&}{L&aLMM566 ߿_WWxb2`-zN=kw|wˉG.!^zi3D`MvPF v0 Ɨi =<<۫ +E""U*|j:bYvY'z4%oе.!I*?ͱ(RT\fύDVhp6'bi.ie'TCHƺnB]ێo?8vy%}/,I@Eщ \YY)^$]$ +Jh4&t"]V-f@5.'ٖ$}B~YCba_PW#g/k|2)ffj8ei#bxģ-=%O~ѕ2nĺ7C4zv{{{R2L_Z[[>}x菪@Rl.Lؽ/įӌY3!XMl:C_n]ہA?G`@) -Ubn.L,0t_ðaTWWR +L&+//JEr\Xq Idf06wXRQ9֏E{w&3:kHH>k8kU1lq*f[ +ԅ;JYXh "XdC2 ?Cnÿ>Pf]K\uKAޮVJT*F.?~X8F[f1wwAӋkӅ}G.[S J'$Jw)"J6`0LXb^ONrv q8Dl@EnƋ~lAZUǬr4Mcv].|$Wy<1ͦjkjjbqYY)YTYY'ju[[lv:^ 'fC=X}Lr䫢i$]B~癗q hCOMy9|ױ +*>S9kmADksyDMAlb4HH`H&&ms)R|gg|q +Zݭکgl4b KTgK!~=^[Kԯ'65o].%oIa="1r862 EQ0>>iFcccZFD,;ZP(Je{{{wwP f ΰ\f9&N?5G8aWYe_`mw5>HfE9ڒsĚ766uĥ-dY*sL~+p04r\Z$4MWWNP(9BQADZrr$IaYvJqֶZ~ֲe) ++0;|6;6$Sy:P>SڤĽOZJxf^Kfuo;(IEk]zW120T  ÔJ% "E]&D,D"P?j8<<#EQ4_ ( o=ǯ>l/K/9ףI q2n-^?˥{d(52\ 4MQsss~|||dddhhn'Ot:ZT*QŢׄ?d*JvuuFƗ e}>L8bh4/|$O + Rk Ѽ7Vam;nUm8oN#[hp<ij{É`p8|AuJD~h؈.X׮Ѹ9e9y}JYZ5? 04Mg2d2I$pxvvy<izZd""Q5ARBh4:c2vz~o.{M&mnB3sfΓ-nj%'eU؁恊fWtfh%P(n0LAX,)B^CE2L^P(Emmmj}}}v}dd/)LyLSGS7\J+MeUS؞ӖZU>N?7qqc: ispcdmmv|6& +(c:Ȗd&%eIXXFF,#۲,YcuvWrךǤL@>wlН7Bk [ɳ/g~Hn$O?r?=,fBnc}bHQT$z.bi4eBq\.c&ɤRd -C X q +D.+1 ò,qեR+aCO=i{zֺu1˶c_*.,2y.sl U1g|gi!uĵ=-bcMb|+ֲ7 "JKLu +EQHdnnnzz\. L&htZVV8.JQEDkk=?ݻgZGGG'&&|h4Jd*f4Ms"'69g?xʃg뉭5f>1rxNwk M'"t}Tb \,8h&kD b߉5~;ִlZoِvVVK]a]g͗VV +tHb( ~;66p8fN"KwDkH$8Ꞟd2t:nd XXX/JR4Md'2:#a7M|ui*Nͧ1i +6co4^>4-GͻNXqca_4<K3R3$G#u7Md:zgp{r5ٱ?!oedR:_ vvd2 * +EQP(*C2qT*dr\P(JZhZmooAz@ 'Ia*5 +-w&jj]~ r!L}i-|QU,;OXuĞ&ۛwΏt=~s)p8L&`PTH5?R*z/t:333p8NswUZS񬲎oyDu95 yfk UuV{ IܣY+3*}ikHz02uzCԆhۏwM]?q6iQÑnWQk4J +q $X,Fː2QP(Uz~pppddv|`0H$RT:f4M3 q\]|Uznu]?ֺeke39/TC'Th9L3 [txVJ`uc' +~?p'{<zp׎C77O~yErC+G +MW#LE"kPF l6x?~痖x:iX,VzA*L/dl]ݓw9՘뉿FPG8n|ļ۫cďE`h,H3nςcY:KeȥTd|2vN<4~grfOJX0jdJD# KT (O,d2BR4MOO^7CCCv}|||jj* F"B6Ep,52A*L [wꬂz*~_Gk|cŴn$<Tʊe]Et2EC czw]s+JQ.2LG*+odepnhX\.띝D"EVzOK W*l[XΙƢwuOoOs ~Uk +zbwj~u}q J?Oed2gff<2tFRTJ.eĈLJ%TG,#Ab#( H$TT/t:~qq"4](/8X,JJYs,:؁6OO4j;OXl ;tĝ__nn^7m)C[{Nzތzs&<6jc ,@HPH$A$!!!t)V2n*,- a:O0lkrCVUU4|zpO xp FҊ"EQ$Irl6NST<B~tZVN7::*H\. 4N6`2L2Q6 eh2~&ǸGz[7ǘuw<8%BXyPd>yID~w_ G[KmXMfo; LmSRߨeLU +~ .fXf99cӰ9;+-ۻ3pfc,3bbۿ,D2:?d۪y٢)w454ۛmXuimk|DiByFkvHl6KD x44$HbP(\.EQ&(CLϹ7(z {O\9]o,uGpN%1$ܫj>]I|af.)7-ݑxM^8eK_vh-ԛ7֩jU(w4/;h!ߨeyD6&IX6+t:FCP zNѣGEcP(b@ p8:bxx0p8|>_(Jg2?Af[~p-㧑mm1| +{3|-] nK/  SU(Tx l?.Zvn=ֈm/ iw4whv9Uw%K/ؽtt`-rAeǕJT* +|>s86(b1ʐ2:NJOKd2Je4^b<OәL&͖N$)Z]-YIaGG7E: +n[S.'cl1Esbƒ{A\ag{P/?8բi·5b ؖMR7ax|8p,O,ERJւBN >tNNN FT=ziY4i@ȋuiIɺlZ6chBʳKCE .ߔѐu*<d"Eo4&FQT2F8BxfX,FQժjT* +W+X,dJǝ:A15;;˕0,sc{li!c}A˷[hȃ$e)GEX45YG[ rUSvSBcN1C%Zx#wix7z`aiRId2HDErV+ *J, d32D"Je2Ykk\.W(g```|||zz(JnNKHc2>r'Zªwc5{rD~3u'6/kprfd%(<^@îp!pC>u{B#!#KMG*̿8^cwwuĩH0MMMl6ɤڤRx *M++P(Z-霟_\\L$E1+?[JQD_0qE)zð ΥWE {B˶hN.{Ә,OSI6R95Qcut?^~Ta=m.|9+_8UޖZo Qu1 CQID"E"~힘FDөjXy AP(D\T*J[h:::Fqhhn +Wqc^:vXhb;ZZůo<<WԒr:Y^/e$.|Ĕ/f@kMS_ݲ)7g2drw/9Tb:Ziŕ/o*LSx=(Am4vfE2DQ\QɤjJessP(l *ͫ3ZZZT*Uwwwf8$Σ.2f!r=& +~ޅ]܃p} }nDŽZi`6 +4D5Y.?pq.@)Srr,tYr|K8qARt0̰,a* ͍F ~iχnn1 FRIҁD"|~S ѶAEZdZN3zIEE~w؀ |-<_~JT%bE밂Ǖ+\#?{5}x hW}5hhk|s,ZM4iR|_З_NkmUlB;)/z~P(d6{zzACCÝ;w4 >mCQtpp4<}mccD"iiinW(###z~zzzvvnG p}%OaƽD/B)iWtuqV;VŊ K{#^I %PƋq=Ӷ"z5Ά.k`&MbKJU)]&xjd=Cȍ!/bbH$z^򞞞VP{#Ab "I,G_rj`2l6APDؠUG k +x]}tq&uaGPi롟eW4C#^УE_ՒW3q\%ߒ)KΒo͑*Rs;U{OJGΏ7"}$r H̭B˜l8H$Bt$aY<w/5D/6%𒟹/5m acj^e7_,wtt+ +F311a2l60ry< ifYplpQ}u\*^>^+Zx#H^,k R$S(O!WGΏ<=xh{29K%ߒ)K̐%ƧIitȌw^_1Iݷ=~y#Bt:D"n ] ¶~LFFbleMQT$:O}衤rCDf, V8,Mml +a_s9%kh7024׃@Leµfsͩ?]b8%W&ݔ.VbwslW!zќo 8jX)pҫq}0uu0 EQ$I9cCmPyp]KM!*xm +|8Ar*~تcK,EF^{ԬshZ9ߞ9PS~xBؖHΖ'e7gJ?<ㅱjA:ˮrt\A<⺴/+Zak7+cΟL8/ zTmݶbpFNADeE-1eQUIBB a!@7h(WǗv3Dɴ!ID$$շm.6*=rlGgNj~Dn5yUa}Lfn&M2N_ V|bw6Qze+n7nSȇof|0?^ٓ[+%Baꘌ<_.wTrn V|;k^} Xȱ"9W8*w'Jeor]t(zwos؞&2j^Yxx'CW3:UliCTMD&2]%h;Qc?H|)`ԵZ,% KCO=՛k}w1*]HHZ%D+%e?8[֣/?ZE_ oBl' nm;ݎ5 4[WͯJf:Qd< IRK$3$ hxW}E׬wclp5^Uw?'r3 vZ.GZ+l5R/[0Am.nt8F-;o=<_;t;F޶'շDbI"R2o* yD=ݍ|KAJTm?rS;_Ѕ(\O/-۾QEWpyx;2hn7W<~ZwDKVHDkd1򶃙J'g.zcl쪦O0hu +tQ]EQۨ"*mW2+weE\ժ%]iʾ9p~D?;-Fk#4ᩚ})$oPV|:ڳ<ಹ8Nj:'8)ixiURm!d&2gj7 qlyEV/gzswk+NtP.3xxGTfxH7D$?>vxCyY~sϏ9;XkK1P6JHJ}ȴTүܳ:4'@[pVZ٩C':>RMF%kaGT!bUpSD5퓵 +ukΐٜn^Vz~`/ܐ/~BIo$֑iud&TYI[nTÓ7R,v~ڪg*_I)Iꀸ@s)xbT{T@aZfۆiJ[V? osczR#cQ~dʏH)󥲷3w/ƚ'5ƹt/0Ĭmh¬j n%%>RU;n +ADp*DHRjc?](aX>9avώ:Z̕tn%LLJN 7U?)&=nr8r鞚zˏ&ʡCMXHRQɚ=?j.iO/滉ƞs6޻ߪ鴶?tn0Rl[(/nOZZnXZOo2+jPAzKL6&RHR'CBĪx"&ž7u[yilN7yo& eKKK?~d2Y}}ZW7!XHNV5=y1  St4>)@J}ȴd:*x1r[h΍jܳ:,~>ii]dZQ1pyQɚ*8'ED@\71/ +ʡ/gY;mܼ`٬VӧOryqq%yyyk] ^`O _2m=]ebmն +L/p86W *$JeqqqeeeUUՕ+Wt:˲k] ^i`-L))VJQD;r=Ny_ѧ75tW=p{,P|QH&(񪠥)-9ٝT2{mmի_o_Q]w=._ҵQp3i5jS{/52 #j 0-*KTQ&*2sf0,"ЙaҝXWfjgٗg8?"h~8.KєWWWwvv&5N8>(1u煮?uU3|@l!?m_@t +?$``|N9<U[3ԆٺstsKKUiEe=Ҫ[5gv}dLpP .f+?Ȃ`$yN_ )n1񦦦 6TVV<O___ww +3_Sw\jwlv&vQ_A<.kWmkwώޭM +4%=_PKjCVaY"/_]Yjz{rͭ鸤vt{wz=aOMx߄ AXy<@ 0UD4MEEjMj1 eE< &ed3G"M4"x\ȡcpڽl7]k 2RFoҧ2Ն߿zB?xc/CbH4S|KGDgZc$!O[j=Æg}i;pvwOG~oG̶;ySʰx(W_{ycKZfO;rJV>vrT t:ʦ#GܺuK?_//nY{n娻45 n{&PRǝOjNϗTҫE?"JG0txw*ļ4tD3T$x#[vrT`&Jϑbihhp,JǢH$GGG\btww}H fАsر6p:;vPԈiۋx԰%Bh4hTUu\sMIIMjm6gΜUVq(6JD4o~"+W\vm}}fO6:qիj"1 ---tFn';qZY֯_oX$I>.'rUyhh(//oYn]oookyK/4o޼s%3ٻwoJJʞ={gVTb܃8(^FjwaLJӔк.()mZ&qIBJj4D05eu%xβvgz?vys||ho `bb}}}۷ +X|>|  +esXtiAAsСEa{zzF { ֦z{{7mDՙLfrrr}}r&@ 7RRR<<<555gӛ4iҿ;q0/%%~Y[[r A!@L4<</֖MFGGgSNl62fٚ.]Bb?~뼼3g%K\xsessslpسrrrDxłzUGĨ]7z[ZZ;fii+**|R2@YYYqqիWvPX"FZ PS!5O ڳg|||N>#6c> @=x1ojhhH6`h41--ׯ]E^ |yy96d0T]ƫV +3%2kHc_z3ajt:{ɲ}RUUU///4_D>|HHH`2WWW'A @ nRRR<<LD\<1[UU%ϭuӦMpSWW}6 +W2Q200oϟ?ӧO ;gggK%%%ZZZ<==ᣥAПxGGTb 08hL ^\3L%K m+++ &Y:lVVVllldddDD~huօFGGmٲESSСCDEE۷'镎yvxxĉoݺ%c"7􍲘ٕJLooo [퍌0 ^???j$ȮRwwSp~O\)S0CKaSRR914qqq۷og Ġ^ @ j\_vm (//WWW߰aC^^ްA .\!"K㩪r8Xh55QbQEEeܸqӦMKOOW^///MM͙3gyn(ՕFn۶ GLѢC755I/_3gٳʄ355E444$urrzRkd)p<[YY F}P5@u#5e5:֦,~OOV`֮] yhf ,Xg;;ReE}}}|Cv!,;]]]ؠɓ'o޼Fİ}, M63MIc[ F@  7H")n?GNٰakiiR۰q.\k.ٿL^<Jbi;o^x1gkkklnnn.n׬U2dn@s`466Æ DfffsMLLZ]XX˗Ǐkii1>}~& +ސFwww$kQA===o߾E>[lqvv)s188`0233G?`H$ .XZZؠ7n|8(L#JvuuőɛIF퍉999n={lϞ/6`B$dCJ~NeRMecEAIa.LmJZLx蜓{>?Μ~{}g滆46:(y(E7nСW 9fW%#}pKv=***P•+W:u~z%$$p-n {]{@L +䔗/իW ҥKkAP*Hl榥d2BR~J]~ >r\DDl-$H A $HP[[{ԩI&amllt5nBn6oތ{xΘ1#)) 7R wE8p8/V%KJJ\\\RRR0hTb?ntj0֭[C 9rHbbK^/>OO&&&%Ν;޽O߿O>ollL xVyo=~z48700 ,,,׃!,,k׮ӧO'*;v,],//}Zjn۷oZ7TUU4aҥEmn]]]yTz/^xmhp^q=((s111nСׯo!gX6lnذknF!Z?:k֬ Pz\\܈#d|| +5HyyeCCüo޼7)΢E`gg'ǎ8;wh (((+++|'#gźf2'N%%%0$!}a޽{u⩛7o76뢔nnnGe/[6"P 9 䤕::y$Z~~~tXYY͟?}]W"J .\$L& +JPhɓVIMM% $H A $ubGlŀ:v_S߆ľmSiiiW#333 мMQ`rss'ڹs6."ϙ3'**ע6 !Ȕ)S,YmlrXZAz>|6Ly? ⭃CnTǛ7ozic'N)0<< 00P\ + +"TLL ^:f̘f +$"ٳ#Gtqqj $cuu… L_Z"dHuR>|3>~FV׮]Z/@Ewʕ0//Osシ͏;cee%"2dݻTƺ^xQXQT߿? +A9k֬m۶޽{yȧ}%&&j&CÈ+gHHxR6TTT r6BzJECCóglll ZblbbG?f'r9䄳FrrrRizؾ};\| W*""===]&) +je@x|mVXF +ˍ7EFFj $H A $_SB⤰o/_p ޾}ۦMggg76FfO7tЄݻw"%% v-Y733Y(,ۋ/222uW\)Zdrrrկaqzsΰ3<^|zxxDW|ĉ&>}QS$U|v\~=Ԗ#D,-Tmۆ"Erqss"r>XBFDPgeeVii)^3@[=y &''Y(,,ӫa]077uU +5RRRTTTY#ݻlvuu322оaXGGGUUU+VY.Ҟ3ZZZNLLTTTg3đ߽{҂Iloo1/whhh׮]H\###QQQh{Kcc#vijj"]]]-99O:UPPT|aYúYv -ALLl֭ⰣGfsƍsss?700())qrssM',OUuuu]]]*uHG16m%Y z$)))))iii.//nN$UUU~~~LK>}999`mm DD^ +155%h\I!b]]]by` 0`(Bh%%%M (# /^`KС?]ЪK0oooKRQNN1-- h"糳ñeb K S7Dzjjj05#v,,,̌?H-! Tdzz^ +++WHA+244!i?iflnnFd߿O+P>gnn.244%3gDVVg!PXPPkHHiǴXZZ388WZ۷prrjkkZ/@_pa +GFFbbb茌 (--}={JN$deeQDXְ1_v-..Ӌfff/_~:: 0޹s秥(#11qzzׇtDŽςnFRkmmt*/|ܲ'O"׮]Çyyyϝ;ܮ\rElL}آ"<zzz JPPPQQo>E.!ZFoo/ +ڹO{:0` 0`𷡮RBLL "񿥥رc_ƙZ j ݝ5!dK u :}5> \\\Z|riqqq9|I|EDDdjjVJJJEE:nvv>]]]k׮555}9k +g=2T-(?i@'&&𙐐 ,,788H^]]P6>!] Q -QvvΝ;F O999h+7ZaHBBBH{ZZ$۱cէOl?{ D`jB"%%%b*X#""8pK[[[ڤ$666??gffSh:7 yPho߈#,kqlrĉ/_:B`WHHܼ3D^?͛_zEXp%$$2Ѯ ###ɸYT +޽{xd%%%a <RAA]UVVXRUUaY+511=jmm]LX 0` U:񉎎vpp+777HBBBII# +w-,,<==YC9rUdggyr*w188xQWWWRPPjVuttTQQ{ӧO7 + [TT9aÆq2tVGGGRR۷577{((( Tmhh(`?i珏GM&&&>|͚ nAmn"ٳg}jjwI] ]PP$$$HKKa|~`n/++|***⳶ޞ68@ff&N]ɓ'ׯ_~@Oh4fccCj%%%?POOp@j... 'bNNN655E1-))):::(2887?WWWB###nnn<<< bee7~ @ܜ#,T]]3 t*228s Z ޸qzSSSwލw(cI lkkc]EHp^wwK/*>Dac߸Cal +)tH1uj,TF44EjeْNQ%$%Zm 1Dq>;__돳~~i63222_|VСÓX"F0@=O)FDD@. +/::4,,#% +#..Iwppرc,, r*+++eeEv + ՒZ HPGSRR rjj1d2a򭩩ۋz\MMmٌП Ǐenn5;;r+ԥmlln׮]...8 +-»{.v+++_xgggmmm-#egMf"[7n/ݥtzzzDoNOO#wwwXI{JJJW\cH + Ҝ`ƙ:#<(ׯ_wF&zUSS>7nEB놄`m!#ZKWW ϟkN╉ !" k0;;kKKKUUUɜ.T·o ʠ-iooO OU`0 Ty<I +fzMxdff߿ˆ>x {)))PH HB(V͛7qfw%$$ /^?eVV֧OFGG )d,e8EBCCQA,KKKMLLPkL~~>łX999djnnnccckkk BՒZ H4ITTT__mG-˥,h3d^|I勦1(_555bbbz… 6l@R{]tuu333h00n}} /N1q7nLMMuvv:::H]!Դe-qqqW9 pE"P`Ш:ujӦM(qrrrppu늋rTVVFh9ʂq EC}pp0&&F֨EQQo .))ںh \VV&// J.##s91١ĈJge466 /qqq***;dggCq8c-Ǐ_I@A޽;((h $U[[`0/lhFȮލݷoٳg===KJJIj yHb 5B9;;խtq~~ U EEEz{{i{xxTBB0e999%88z*}+??buttƉ pg333,"""а+EG"##$QQQ}}}=%%R!mۨQļ<}}}OOOVMM g5]d29RyssKnݺFc-TSOOˊ +EEE??cǎhhh`wffQ[[[0 ]]]hiiݻuu\@NKK 7655EDD 6@"ʾh9ʂ汲Zi@O555jЀrxyy"4\bb"L^^ۻSH Q;|<|9N>yDW@%@r۷oEEEz{{i; %% )hRR͛CBBڲe ȁ~oX,;;233͛۷5555777񡥥` ]___ $QQQ:88FezzJEEٹkrr$зjjj<==螜*..޺uٳgϚ4dp&ExϿ N\]]|JFGF50>}ZSS y "fjkllĉJJJF}U<]VVV644է?x`3-##t@%u(`|TUUEDDu𒒒uYYwgg0ytBAAϋ]O>E' +<yj %pϴBbxxxTWW/$<<\__2gRE`ܾ}~|gVTUUф|djii(AHcTEEWy0mSRB eIM4lfxeP$1CLli+"FHӴ([ fBilc Ǿ 9}x{8s}mCzqaaa++ +.] H;733CXP\J755[Wff&B6112??$$$.^Hs+/++nԿ + +B"]=55UKKz||zȑ#Aqqq{{riNLL Z8Ң //pbb"**\M{SSȼ$ ={vii մQVV^/|#77=ósNNHHQ>0700(..gEsrrPJmmm$ + ;.Gر}N1Άl |KKK|%0>>O;;;rx^^J۷|6an;7РA 4hРA {qqxY^^^k/266$h+nJ'''|̢r3gff KUTT"aihhprr + +B$I_<)zܹz0hUU.}aaa~~~CCC_PP0..PϧC***Rw333uuuMLL= AZTTÃZZZ8XZZt522#rjj*C$###OhiizׯUb]pvpp۷oq Ɂ⭩پ})s,WVV0vvvXVTT=\aI%%SN-..-l<_|A8C<*&$ϟoss3ub-,,`*ggg #АH{~~>k׮!?"p p8|0^IJ+66v޽Crrϟ_Dn߾!o_AЍ W """=|L&gGnㆯРA 4hРAP>>>>T#͛<|jnn>>>$ g2ԭO>ajՈٳg2A ̲wܡڑ𘘘%ʄӧOc⢦ 񫮮~H좂666JJJD + ۧ+**byddh@s1H汴tCNvttPcǠeggSx葎r||<==Q|j^BV#H/A+++wvv0Oi |0>( 8c@cӦMyyyd 4hРA <lmm}||Ʈ[Bpmٲs`KJJחbejj}m۶Byyy*zMKKKBB"99yCPRйݭ{…?rumm-@)))X6446]pp0! 4~"##BBB.tww",+@`CATwrnn ܺuKDDIX"WZ͛PUй/_|<ٱc0!LMMp +򭨨HOtt4T(n +^II TP0ۆgM6- `(2)c``gdqې'WTT@ hoo@!xDu:;;EtwwL8;EQ8)NEuuua?, @^(,2/~EC𳹹Y<^DpD< +҂W虯["GҥK:uuu4NX,T_4_-B177G/\pʔ)hEEUV999pPAd7o޼Y8q , mmmv/|ڳg̙36lؐ%vf\0'=o/wI68VXKutEp*v&''KMAAAAAAPFFFu#?~xpp"7mڄqqq@FAڵkΝP7ݺu%K =z6wvv3g΄ 6nx#YBÇ^Ufx5u vvvc#Z)56-.|'444"""))CR^1?rajjQld6]\\UTT޼yEyqqܹskjjF4sCCCi0#[.{ ?~A?~\UU5c455޽{1·oF +_%ݶm3f رc999<!@e |jkkf_---)LLL<<<<]nnʕ+9RWWǰ>==}hߊ/"K.a%M"r`fKMAAA'O]p8VVV#*++"JJJnkmmMHH>uꔧ3g!߿Uȅ'O:88gYcI!CO>: s~޾}"h_u\nTT`r?Xp;;;wwwVcc[@PQQlkk~uVAA-̧pv\277WPPPVVj +ۇS3fPTT\hWggԃh /r"HqXrFCCBBf6]ZZֿ|bҴJJJN@  &GT=fԣ#??2G)""ח~***JGGb655I=KkkkPP󳳳N.gϞ=   7w``GB|@ * _z{{ѷR7cR!N                    _ǟß*ʙYIoAAAAnn]dd$aݝ…ցҖ~ 555yקOF|VQQ[ꂂ= {I]rw$$$ڈT!:Ν; +{{>HړU^^.|d? z-;;+<o222N>`ѽB SKII}\Yg?˕sU;;;OOO Œ1Jbǎׯ+++[XXܹsL,aDDĒ%K'LLLҠM+nXXfqd?Z@ @PWWy]/^ 0'Olll˼X,==/ +$f7n$''D˗/wܹs{+ ~~~555)EAAմiӸ\A777%%%SSӢz|xx8;;XKK 󝜜ձk"0 8Wb>^33џ­BsڵziyyyKy捫%Va[[[1]iAeHsɓq0..V[\\:::gϞSx677'''xOׯ=ehh~:_^coo/3%00srredFBӮ}\RR"m"F́dG3N2 ޞiNMMM&EEE贀znkkoS&=igg7{px葪LJ&_ y^^_@ @#222ӳ޽ mbBBlx ݱc>ܜʌ3444.]A===3g`ŧO憄?Z[[=<},78\Ti + +c_)s8Kxʈ{;}tK.{dddZZZKK ^v#wppe}ǎ#{2JJJN8C +cu-|NLMMMȌd@΍7P &Q iiiݽ{?Ǐ\.[ f&N"##YZPPȥKzzz&q NNNjjj###L66vٳg[ZZr(dBp_A@$((hpp͛zB<-8 JΛ7a[,Lݻw7n<9P=Zx +++8 \pF]Rb`p@p0)-%˖ 2k14$ EϏx?6åa$Ȥ(+#'/ g _ӓ@oވ/MQWW߹s'hddd;88~%Xxb5kΝkmmLDnQQQpdp^_|a뷶TWW.\PAAu_j"̙30-- ~ϟ2I +߿_)j?lWAA.^q`o:Tش bjj*]ff&:&,x!9Ŀ}ЀR譪ɓ'[lYhQݢ=t˘W^ꘘn7⢦622~jlllnn~eLآ\yxxar>c۷oO :$4@ +++/aa<{,"""!!!%%KJJ*++ HFFǧ]quujNNNW^&%q"VVVVIIio߾ea@ 9#q cRfe|!3gǏ^j-{a4(o 88|C8Y8a'x~T6JHDD)tmllpkKݻwcZ6IԒ%K.\;͛u':tgIHHRZJ&ffDU" !ϒK$% v))JdzaN|X bjdddJpCCC0<8uL@ ..n޽0HBBRRRoo/N^^ަM|r]v:;;K" o|~pp0 Zll+WPٳHƫq Ztܫd99gQQ*ĴOʕ+ TTTdddb +LV06ٶmGFFЧyyÇQm]&Aq +---D_IJJUklltqqQSS^lp``jϟ?np<***:88֊7s=)))d444`d ⨬AcldttzhmmmE`TVV.--e`v{nnn۷ogVٓ6NѣGA 066!3gΰS$&&!Hkkx<GiVV8~pj3_XX/dss.455M||u)؃x||>^GG7FFFЛSgg'Uqq1vӧO___\[{iK.388K0DB̙ſe(95U))!%S͏E]#DRxyHh(QQ!Αgd0<|zafܠ.t=|ӦM ,-PbHT\tjBww7322Ph#۶m˭b`8<<<""T=E +rLX*닼 ~%,<@uuugg禦&¬a3z 066----===]]]h{{{[nڵȔ[``@ gH6GGGSSS•KJJ.D"tʠ}&322+mȸ\nUU3trr +NII9}ѣG=ȅ +Y5kV^^ڼK 0Y͛7AA>Bihh)#e6NC("tpЎ +-,,RSS( zzz >### $"#cPPP[[ưE汱1>>^KK {144E z2nJL*!!ʕ+ب)S̐ijgnܸ@o\\\NNΧO `7A){ ݝIɢx]]]~x>NILLpj|]\\vc߾}}_ y\Lqq!~^޾%==080P/{'?g>dHlFɁ$*xxwwჴ^i +ب_  ,X` ,PQQ +iv߿5 +@(iiin@JJʴiӸ\ӧ!`x񢝝ɓ')VKJJ|葽u]],9v옆&ݵk Ο?O'-//߰a9\("իWܹ~mmtZ3A0tI@HGG1~r500P LԔ*))  +HZDBtwwx<~h0UUU j6`~~>rLX*$3߾}{ 8a+ʃ!WOOGGGrN̙3XE†;wRI;;;Qv/_fAwmmm1\,-mZ2  GGG) ⢣cuud9~8v w% F;pχ3ٱc'VXXrJ]]] RSSL?"xzxˣ1"v(3w\ggg<Dd𠪪ODȮ]Y듩Soww~+Q̜̌IO'&&!99pRO$pkIL ٽ[ʊ\,o +/ |V,X` ,X`!۷ooݺu͚5奥Jjjj!!!D}/AFGGJ?UPP`mm w%Klٲƀ[[[` D t|^ٳg999o555-7oٳg4ᐐ`aaL]P{ \zx*Н-e\l2333 ;ԫ /L + y.**-JJJ!,DD"aP4\r)@ӑ#G)Kss {{{i7|dR.Ԅ/?p[&XLM4R +ԩSzzz.?yuLݻwX +(++Naد`(6a*tD|i!t脎GjvۗƈTs`Ҙvϒ$cuo=vWy߿kv~}߿g綶6 Ix@@Ecbb +L&^8vAGGGP '::>bʕ+TFGGMLL>Θ޽{.]+9\.Ye="vpptKwy?8RQQD`}`ٲHD~XDMXY_%˖I =="VYǏdYdzIUay J5r!+Wmmc䆈V  0` 5|}}I/Ѓ233!H###eZ `/^?>>KAAԊ!bB?ӂA]]"ׯ۶m...555kT|^¨qqqqvB=B(e Bzz:Ud/u|;i|ZxG `t&444@0?~<;;KeQ+HTUXX866F$ZHII/ Q})`bb?.xđzsssTѼy{?=&ݻUUUʕ 'J*)4???cccVP@:f>"',QS#D[s"؅gI@ٰAboJr,mc#Z)̮G%h9p$1%$,lLlmdBr*پÒ 0`>>>tuu| +H<-hv{!!!nnnvSB_|I +Ң\L`` hc\\@ HHH~z-]f M.tttD^`fZZڂ rss_z/\pɓ'}MM &XYYMihhx]ss3"QsVVhs,((044\jիWU<##ښFvp;(𶧧˸e˖saSz{{?|PeԄ%33422RT2R|:{,:d)<@a^"C~xHt%5)g/`-!퐇򭘙ijjjll@r͛7TgT"00޽{X1rъ () %?QS¼y +[[[SGGGϟ?ӦMHG S@uuu544:::>}ZVVVxb8 E֮]Յ˗|I hi E(PH qss]#ˢ-TjDx<^KK1PLDEEƄV033 8 BBoߎ@;v(DKKKlll>*Dq+W`sȰr}}}E,b˖-XK, + +O"""bݘ644Єh0YTEmCfeIRҬd_>,Y"yklL Uɀu|YO?a$Fhh{{h!!Iq#%M%_ss󰰰c 0`(.. 066{{{iÇ!]o޼9::L>h1VRBee%TbbbY(2ܤ$zgg_X]D*D4!5/$JhP"Dɔ(a^-S H^Cd1_M.'jޙo4ss=]o߾CN_?C¢css3hmm-##ô;;;/_Rz +@].\P[[r:444~~~`lRZZ +*ܹԶ(%Ѻ333۳gOpp0گGCC<|MM s΁ +tW8+%%ej={fbb}v<())IHHKL dcccDK]]ҥKh?1w;;;QQQ?00@a=<|AӤrP + +syAIIIUUտƁL`t--- i"''w…$6Qbs'N#}6߸q*ΞIL|􉲀,#nOqs15c 7`ӦM`=22"A,ŋT_Yf}8_??"$D*woyQP{+/ V9ONܹCqA޽# 1$>_7D45I[qsߵL\L!!!DZ` ,X`:|0m+%%)EŠ!3<<:V(OB[NVVvfmm xԩ +AAA\? P!{PQQjD!CXXϟ +hU[[[V<755edd\uuu+++???_>;;;oܸQUU5DU[[[.]4nnnPϟ?g/_бPS355x̃wR]]=/^_'YмSQqm===g5556m aVKuQ7ohczz#]ׯ_7o޼rʸ8fiii3gd,Ʊcnj& wŊʹۆ~*[oX'///3I|QLgdd PGG';;{'?###17ogKKKgƍ<[lQVV/wmll:::!-4*//?s挒ŀqqc!Eݽ{#MqAA" @֮%HVY|쭂IJ"m1gIK Z[ɑ#DYBMMFI{;ʱ` ,X`/jaaa7001 UyA$!Cw]]]Sгk֬SSS0e˖g(\AAAɡ!.111()vƌW^WC}~ +AP1g(YGDfjju9U +Wtuuˠ^edd@vqqY555߿@deea:B%dff2غu+9FFF"y}}=Rj2UGvvvxvpp̂ CBBբ___utt8WZ%//7-\PKKYyTT< ~kk+b)Ĥr["Z[[*D***^^^RRR/_aoopEYZZZ,,,ܿ,O,ȣGX9,v5t`TT>Ku޽ǏS()))**Lի_q rssQ<222={6ׯ8 K98H""' wHFyɇaLLxk.EE~=ik#nnc{`ls3yW` ,X`@ZZ 㓓SSScbbDEEO>= +7D@NB_R===CiiGSS~#ɭ[.FFF|BOODΝ;߼ySTT Ъo4 @cvww'**JGG!BBBǎؿ9(><ɓ[nE;jɒ%~~~ULL VPPѣ fP$ׇdff2@ ...555j(rqVJJO ڵkՋg)x{{ڵ+447##c 0''ɓ'Ç۶mgϞEGA/^`seaaa'TUU#""],-- r*2??:99EZ쭗m;8剝G (;;6 @AAapkΝ FpF##ұݻwia{{{@@8_RRB]k@L\vrr=uzKJJYcpPvv*...l6;99Y@)[ZZޢ)k@DZUU9744׏C͚5kű6wm``+/((Y2*] wt***Ʈ"dD 2nܸ@>eJoSS6yKҲnݺɓ']RRhcۛ>>JJJ`6l())wz~~><<`WXXtRVp̔PŮ.z133۹s'?׮];z5k׳gF3g{vtt |Ktt4Ud8L>}hh%6a[ċ-p.]\v'( \EfؤbiiN{ *z <|0۷o?zrvv^jծ]N> +^.lDn߿+O8 ߐÐ$6 t|ᨫB4pRRU{{{?}Mt26[;zɓ'QA 233%duD1#F&NTڼyГ[[[y@>1/8"44ŋ߿'a4͛1& + + + .|sEkr@~ڈ=!,&zzҒ~J12"ɎDT+ jjԔXXWI_|Wښqb9"$DhjyyM(2-ZiaÁkMK5//F_0` 0`X9(( KA!m!ݳgOKK ?---333P9ZhjjX[[K AA-srr + + +V^M>|ǎ 222ޏ?<bcc㛛ǮzyyCƞ Ŀڌǂ0K,Aiatt4fP>a>>Ȋ3g(rg{{{lKP(++C%$$(kjj޽+4| e2_...ÇGTu%Z`͛7!Hct;;ĽwTõ:q觟~B"LLLrΝ\ +qʷ,GGٳgwsbG~U;WXXwEHME +vF>`g' +?,oŽB@b\ͅwER`e%:;@>8)7 TTDDDDD] 6m%K0aBJJJbPa͚5BCCMMM(1J6ggjŋxz!Clܸ4TNU=z߫F666Ǐe#FXr%SRtƌ +رc˖- b!+)((@7TlccU<<Щ|rQ^|nҤI(KQEfΜPذaMMMQM>5ʻhqww7nBy#JQ +(vܙݏ555mٲeӦM233eYYYw,FFFo)I{,G"HRd2۷okjjƺ:b~ԨQX?ݻw +""""v +^ssw%Crʭ[^x!/zpSyy1Ⱦ}Pp[.<<Çݾ^VVviT_*{{/m333++/ys猍_z%oOt a(4BV__۷oK$6PmmL&Snooo1cN:{l''<ܭ"He:kkk^ + +sULff&(55U:# ~zrrrUU՗zbnݪ: y-5c+++Μ9]ݻwիEV7o䍸J'O?~9stuuݻ_)p>|[,Bc"uo۶T166ҥKjTǥÿb };}UQQ~ xQaboݏ?vѣG~~~)))= W٩տASr<==0E}[X,677swwTF&Ǐ~=>}ޮ[/^֧Y\]]7oJ];dKHHpssr7nܸwbo[ZZ={Io~`(n\?'#E166ȁgttt t_x"D_pǎʍqqq $H!!!"h#"""""""l/_啖&o)++;}t```}}FDDDDDDD4D'O+Wxxx$&&thDDDDDDDDN{{{bb-[SSS[[[:."""""""i#"""""""""""""""""""""""""""""""""""""""""""ocC RӕL&DbqcFFFFMM TpG333kkk/HӋrR \R\կfLܶ8W?hdFXP,ePd. CPF) eyҝ4^ss*z>4{=  ( CCC ..gEEEQQQ"̜߳glʪU݋0'"E]+   pvvv4Miij컜FNgXeE N県'&`0\D<###E +   ?3FCFvw93:bP~^]?8==fnoo܋."##E +/m!  Pi4Eeꚟt:GFF*++ C^^^MM‚{b陜4` 577 'e˗/m6ZB*;11͛lFi̸7`tlp8~ bqRVǏ?𝝝_|qs__Ӻ322|||;::jkk}թUKKKMMMX|KJJ)'^g Ă֓eIǍ .hv;vOMM~`Wׯ_y>Kj{{ \_dID&fB\Jw+q-,,D>e߾}XN,>A-$r=u  9!5F\YY;??o0H鎎~A`` 5rZ^A]Վ*Pl%[>s$djPYht,W @#sss(65cVVVTTԽ{|}}yA|j̔ +_~MĂl6Kq>,9880LaaaXPD\\G tݻw҇ʲ<66zWә4^rÇ\xA݆B &&AˋlѣfuX:Bcc + J1rkkQ""4 ~9EE"B;!ayI  ꌬh4a莌0G;--Mu٪[\\LL;==}zzϡUUUduuuԆDF?\blYQQ'RQR---QgeeQ1:88Zj~}}=hyyy&&&X vr||[ϟtjj*!!ڵkf]7 ===ZHYsssqٙ}cў'{{{}}}=== + 1ɓ',ݥqeee\RIoccC7n % [[[oݺGnll DB#7^.AAj4ʮ.֘95<<<|Cd$j4,,9Mv;vww˗/#""Tzrcp8~ E4 KKKwjR1!!!112PYҪh)))jԽ8)N9ߖu3:::**JUj8looϞ=Wqx5㿹I؝NZOt@&CCCL3W]]x$CP]>3@@@@^^ީ 5Jܶ=.[as·[܄ƙ+RjGGGB8]yONNT80]ƪ_󓓓v%""}@#p|{+&s]VSSGI@+W  :;;Qw=Kfܺ0zݹQ/pQ:H=2ԑP@:H$(!tCQI$BHay}:"]0^kl{=xwygJ!B["MLLDE/J!(Yccc־6CP'p,(QHkZޒu2$'X(q/Z>;;GȥUQQQVVf٠hvvFathB*{nnNJiE(S$H;wHV!!!aooDB>ca}-))YXXvvv#z}ZZ˗/8F`dtt6449hLJJsq9 +E6%c0|>0޺u åP(=' ao#B!$PgJ "q}}=$$DѸ\.ݻ7<<ЀІ333biZޒZ8www/NVU*a79RQQQVVf}hvvFath +=}dAH-.."/`q:rtt,իWЧH+o۷uuu^WX%%%Zr_PPDuۍYYYF`0DGG^3;;>66P(FFF<\Xqbb1Lxӱ ]orfggg·B!3Rrӧ2 *\(\U*BǨEǔ4bj+%Q=>>MNNF,\0MHH,JtB~2r4!$Z(,:ͮ.|Ri6hR4DP‚Ĝ HHFXIIIWc_ Q7==XVVuݻwz=GONN +כ7ojkk1">> +gD{gg'vc BWfbb"$$nll`h ϟ?St L&$͛7r6p + + +BbiGccFZWwB!eLLL}}=!yyy}uQpfffA0OAA\}}}b,tԮlKKK~%mPuc\FQ5-dfnn.F~vvvuG@aKJJ + "&$& h~!h{pp|$Ύ4b1..障l _`0!p744ԟhMh,**¥x2,(((55}E!/z=˰?VWW5Arݸqk;77HsEieJR2!BA*%LNN pffPWq:gWWޕi6Kn[2{gggusss>|900 -ߏST˄V>{ckk A4wvv7 !ڧhB v'O/b6!*BCC!3[ZZ4 Rz?͸\R?==C^qR#""pJ?>>(…oyQ^^]Zbd2\.W՘ybxuu5{@:==1dXkX]]ngffE7^FFxU,!ϓ}_"CW„B!B!?ɉhLNNh4׽B!B!7>>y{!B!BVB!B!{ B!B!B!B!B!BȥGqqqkkuoc~~gyyTX|>lF͋ƍbD5wYZZBHɂ,CH Hs ")GRK?Vl@Raoll6GFFb -B!Bˁι@^^^ZZUTT:; 1|zz&33vd%͠T*aFA~˅=XρS111SSS6 t_\{{{aaa 8 X +Exx\.DZ?>>X׻h4OeeZ@`wwN۷Rkkkk]tqpaŕ_g?WYS[_  |( +iӮ]vzacZrssGFFOMMI2XReXh༼|Y1`cL N{{;j#d27ߨR?ff>FRPT'Ou??q +r333m6yїPPmЃATurŷ힛jP>}{Oh4l|PTo}U~jjjju$Ij2tVj\zU$mooBr۷QģTNs, `0_4ҕ+WrrrD|4&9</9"H$&T*#d#N!^| +:MXz}uuuNNhkkSfxxo__-**`d *Jjb}8>ܹs7"љo޼rf%!ܑp}URRz3?~CCCG;;;fYZ=~t:݋/1. 뙙@t:\4P~TQQy#+,,Bb99eeePt܎'ᨼE|APDǵ54UG UUUF$ ~2vA0^1Bavvvgg___7G|R^P|---+++s)[WWT*X/ +H}_&hబ A>}D5ŠRJJJh4lX ܂Df] {{{p bi4*|>G,|'''&)//ւQ(j(x̠MSCPÃp8O??o9g{`XJJJD"ƯJzt:'Z{VVVF`c`` ~GxYYYGG:]]]]Fղ9ʁ1Md҈{uuu6 l777C0D]*bv`VZZPgn<>>.,,DhT)l>uċilf70h߀E OI~+gv%cByAAzN)a Ps\.B/555==`P<XcfCZ6551FE( Ӿ_<SwNz/ +ʔF-//;LF7|>?##b%zBfggr\RwRPAjA L&nőbQ*555V5~j%ٯ#Uo4*{jj(rQ(@Y 0o8@0K1bB̾`ۤ_97ht>Y793ôӓ bLLL477#a[[dGxT*h$>/« nZ.**"ڧ*p8USSCrd +ǃ IZZFkbݾ}C`0cpQ8Lnp訑5gggwvvb](+|Xo`foܸn!cKL1Z SPPPPPPPPPPP|5L,lɛ磊G>1[C1D?2&GF>jY2FJT77:kwqm {"*kkkblXL&MLn˗/F#:]|'''G155RzjnnN:::>DrrZӽ<<Ȯ{K ּUGZmCw%)_[HTSS*gbii $clll@-((H>߿B|hl6tbNSTg].SըT*Eԕ|xsssTyx0LJ8 l!Q}}}ggVO;. #BH$nBh$PKKK,vuu4{Nww\ _3s)T=ݱV |WvOƃ Ǯt}}[~~>V*,ؤ4Myy9La_c0X}0XlvN|[ZZeGGG__< [[ ?33~̉}9a1G~cfg_lfi]nNLL`?())z={ݍߢ"5ZMRA o[[xqqqxr0r!*lTHX,L&e||<** +<ں'Jh$!ԄZ퍧!T4%/.ǒP(@[.ˏNuu5# E$rR氙srr + |~~!ZL,Y2ƍ |||>?""D"Q2Dt{zz:yjllLCUUUT!Woo/& 3<ʊ {g`j+p[Ds99 V_Ybm=`]YYIHH&[XXRRRL&H0//Q!BN111`844ZPP0<>>9Pp8N@@ +DhTը5`15====|q}nn.އ0==-B999 +D@Qneggաdx<B?Zb#<88Hntt$R\\S!8/--_f _\ 2Xz遻I,h؛^I011hnW;V-lݾ1 X,N+Bc ae-Ը8,=ի'8p=s9?1glN-KsssRR>]..&IRA)BRAT%ceeeDHR\<<.8\C@`4p88ؾr[6I^j%`0p\OPFzqVVVEE璒yppPUU%jﰁ_  +[[[---K.Fb% + + +yyy`%@ÿOj + 1P4GimmEՐw`iZb1ޙ5 ڵk0ܹ0BHU7պfEhz`OǤb$vbx&*[ATj0f"jyF-H ň jN7v1ʢ>>V- + + + + + + + + + +P X:= +1 snnfE"& 044Ӄr\~?xZcx;iuuoU +' +@!F#T煰PA_c ;N$;4FP7/n_=ܿ;&Sϱڢ`XPjXj +¡X!uVR{zz`Rt +-I,yyy"TTUUommiOF,z}ZZfy7өP(nݺ +G ]]](u\~aɍRVVVYYI,bT*-uuurd8<<,t݅|>B }L&C>p#### .<*q4}/]|277p8 h"g䉹bxzh"JtL&1o>::4q.l.0554 + + +vvvX8K^㶍S"D|^؂z <bffY\uuuSжQ*XB{:.%%r}^MW\$?8徰q l gffzcc#$-T*x $.Zmh4(Ӷ ih#,lL&KkkkE.755o6^X+**@\722 > h2PUTP@tS7!fannG28nX@P`2'&&@/pFL={ MNN* +g1H_vn6{)((((((((((((.^ ×i4lHDVYYx +2pll pcc$͛798dee+;`ii +jr BH;NH$姧y{{ld2, >}cPdlT*ZhիW<oxxnOOz*rrrY +J%j322yB,//644r!&<==K, cގA>22x.D"v)#x!m6 Zmmmvvv``ӒZFXfffVTTc0!N!7]$ry  [ , g6-`;::zttDźw" )((((((((((((*:@[Av566NNNB]&@ݻw/P(Ip.,,@3B-\{~k(6JYb `秦BNLL|8L OCȁW 8a$,ɽ-g,hD0\]l!%cSL*"2gEh'eR6p6[w PHMMMn+==`ffϳX \j#+t9`qsstyooO"^шdݭvy~! +\wޡR\E dGGGfb$P^YP[IeV.(AǣBmmmA~f8N s}}}yyYՂKZ|S5RDh4;5GӡCƆdr\sZx||LPa#8e[ +endstream endobj 130 0 obj <>/Filter/FlateDecode/Height 590/Intent/Perceptual/Length 881/Name/X/Subtype/Image/Type/XObject/Width 1475>>stream +H +كCA_\ +endstream endobj 38 0 obj [/Indexed/DeviceRGB 225 131 0 R] endobj 129 0 obj <>/Filter/FlateDecode/Height 137/Intent/Perceptual/Length 2530/Name/X/Subtype/Image/Type/XObject/Width 1268>>stream +Hlg88KPs*ѭq4D 8g "D`L6/]ȐMFe'-\d̘dQ2Bbf&eP +I~y|O/mOs?- +K=kCU [o&Sy?:Om;~.M;˂M=U_LFyoYOϼy"ٸdc-,H:/ddgc-,#:/dS+!u0>o;NґU4 EZ:۬7UvKznٺi`CӪM;[mϽmYz/5{VϮ+za-[[mW +endstream endobj 131 0 obj <>stream +~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnmmmlllkkkjjjiiihhhgggfffeeedddcccbbbaaa```___^^^]]]\\\[[[ZZZYYYXXXWWWVVVUUUTTTSSSRRRQQQPPPOOONNNMMMLLLKKKJJJIIIHHHGGGFFFEEEDDDCCCBBBAAA@@@???>>>===<<<;;;:::999888777666555444333222111000///...---,,,+++***)))((('''&&&%%%$$$""" +endstream endobj 10 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 137 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 11 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 148 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 12 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 152 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 13 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 155 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 26 0 obj <>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/XObject<>>>/Thumb 171 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 156 0 obj <>stream +HWێ}WsvUX F"lIN`9: 9rMFSU{f28Oݎ:yO?|}0_w3Kh{kUlu"*B +ϐBd_v8jbϻp+@dz۟5|3'om웚p]hyW(^?zYl{ 9҅Rw{4Fpl%;×TAnȭ{Un0Ǝx&|cA[ߑ"}a$f)āwMv}Hs P;I*`uV b4}/}~=1h} .xzVM?,q7DX%X߅#[:^~.SRRLHlOπp/R B` Ȥl 48 mtݞ=>:1)`doEY"rٕ;GG3Ic"7jqMiSԛ#0@&HYH8xinkRa#62Z2ZUi~M +;r>QVNZ ;lx8i;)Md'12EE̸*z.YtM6*J4Z7 k涟,P׌$:e pg@~.ݢV8 c-x^r S)4YՈZȦ"Xߛ;sZ/9?X>-MIpMj/e]|L77+6ÊG.C;\9Yuhn%`n:7瓶 X,pUj;{,쑝!SCٍ=57s5FƊ+.&M(vW1Ir_QBII#˖"GIt['$"A1;F=l(*+I2/3p$h!^*^}l,-<%˲8Mzgtɣ(휬]C9 (*9q}`#@f^S۳)}q6><5S Ŵz ƢQUMNY;rh=(Dde@.>^6)#Smi!wQuIfz{,cXMl (5TWY+Rz熀iɣAdTNj2`>Kz^%ras>[AL|.# +p$X%K`ۀ~WKF~OyMjn:T95jRYmU '3cCԳ=}/#F œ/a[#e+>X~ %~n!1=\lIex]HQ6Ni/a0ڄ1H.u- + uj&=i'aW͘Lgde.~W +"l>z##I2"d-]\;rĒ:R}E$]*톣R+^H܎ᡪ /YQftԿk|EEK}LJ%"]K}x?ab_X^((A${Au*@ھ7 Zj"y8CUSҁ4f|ԾL1kd[,)EC6ry}Q o-qG>z"y|?A3wcX 7Iy˛^ $2c-M/.L)s1E`=oe8a>p7%r@@rq辿BDJ|BAEV9E-xYt˲IVVսP u=8央OGd^4_@Ħ/&o`Fg(<" yy}ϘҴo&>%)^8y N^ZK#qUʛGfbCQ>\/~ƔɳMH0M=ӗCL5@MM xIf9VN_p6?8\!EK^5MyٿK'gHdP\~:< 임h8esq)'Ž}msWVy(WXqg7{XYԅ5xL aN!MJ+;fָ)κ+]ziB^JCX!k@c[.Z +ljSNn>ᖫ:p%# cuA$%R/>)8-T~-BU^-XKr)uۺ{9-Lt{x-2UןA@T@ځ("46ܣÒ6/rCX2[N#e͸(`bNҶz㼽_BtsJnv齐cr! @g,ᧅa`\ wZ8s3B̆ Y?w3wT;^/CJI'Õߚ@qڹigLtUZcT?,=aaDԍ@xH ^h8V0Q{WWn/۾C7۫w~_ y_9ZTRnq.Kdtr ş +endstream endobj 157 0 obj <> endobj 171 0 obj <>stream +8;Z\74dOhF&6A&_pB[ptW03$[\V4B?Btq2VrU4+Q/:q;lIrCT +&2Qq/@A.D)p(6R#_@>X&+&Khip2h+UDE`/.R:GTWLT +Eict!rQl=M#0je^;'$J;Ng:Qf!=PG)mN[-u;7O@r5bC2Sa@)PRr(DUr#alb3#c)M9 +MpU);&nN,t6=_.PJQ^l)2/b]/EZoc_\aq4u/IKoCde.52c)]E5jV*pV:d'7TqDW!j +o2'c3j#7^g0U6AaDt\UG=uDPM?Ad>"""lDc@1t(Cf!`V2T6TLnqYVdL:!u*=!TDL- +%9(YoS8[7('(C`A5Wd&C=96Io5M-e7H4$1V&Qfab]U+`?VLtD(c2;ngF)/!c)k]*2 +5B+]_C3n]N[$:+Giu-iDA@PU9q0^'?$'riaR7u.K.M5s7n-gm"fV@P:MF6:9bn_ih +8#EN40.2s_iob@leua#,JD[YONNH)W/ie5\f\!="k*8$'H?]32F$pG#YeT6AFq^$4 +bg>gbfl+]Sb!tS_A$.Dq2i-0ncYD.P4M%0;:E,ZrKB&R44q3hZp#s;X*]!C#3c\t: +q"r%&:M[Z,-kSB)0QeE2a4,GIc:mE8CZ4qm7YJ.rB(NUjS'@?[&+E!//)(3r~> +endstream endobj 161 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 430.793 -113.267 17.008 re +f + +endstream endobj 162 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 412.785 -113.267 17.009 re +f + +endstream endobj 163 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 430.793 -113.267 17.008 re +f + +endstream endobj 164 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 412.785 -113.267 17.009 re +f + +endstream endobj 165 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 160.985 -113.267 17.009 re +f + +endstream endobj 166 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +297.705 142.977 -113.267 17.008 re +f + +endstream endobj 167 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 160.985 -113.267 17.009 re +f + +endstream endobj 168 0 obj <>>>/Subtype/Form>>stream +0.859 0.863 0.863 rg +/Perceptual ri +/GS0 gs +524.238 142.977 -113.267 17.008 re +f + +endstream endobj 169 0 obj <>stream +H]kq9)lbApa!e}x#Y}|JK>(х 0~QA;f+Abp!&&0ոm +DJ̴#>[?ۓ< 6説q\>Q)&ƪ~=6.9F.̱d>1R$Gжl_]q"U9) 2p=]0c1;u0GTG~o}zh'L#gӧR=M8#@}Mn&]YmW婲+JZ0ocrB㶹ٙF}_\C,&K%u|r_XIm8x;v&-˱]%ڹĮW7RF ~쒷;qr$hWQV|6Kr1Q.n.QIGVmhn̫O=HVr ,}7bccl|Hd9LF&Y[h6?Nc7بsl=q;LmKm+)&EN{"Zv'58dM9Ur\Itp `+XSv uq/"cO3r]9.na͆39NF丙)7?92Xs# n|D.7JI%t3v3xc.ϱ]EZy`q>ŕV`ϱXsyre<[1Rzﭶ9k9.^&Gg(DC0!Xs\qh$j;dnRS9ocr`N؝l>L<<>CjON>MG,AmvrSۯpxB:AGr;C&Z`B_qNT9މi2iS9VD'.[58$R/iC,106ART IG۬_nq m* +Jwj|uH>Fu +`sD] +[{MO߰jYOqU86M计#9B]$ap"Ǒ-톼Y{sSUo3l|Xe}׍sNvAM[]8LܾvP8 ̴} skyshMؘ\YWe-vn9wOUZ'mfɪ1-TuDb½ac"G'.Gb'P>o=%uQAPnpc^d:5ݼS꣫t8=/'m*% $` 0@x3@ ørC`W_F];k%-K^y>gIvPATEB݁vFU=6IKhnj׭4#Z~33kVFM5 +i|Iy܊YKڏ:#Wy=(q) NB:PQ&s p`dKU8?21 ;gjx,L;VJ0c2R^E~jGw:4~7d>}[NfYKڽYd` + |˒]|CKra yx|2R ?)i֒vOD^o/,(7jI[NaLC^q9IKx-!2u3&c< :1Y8?q/gj(O3Ale__=6SX+&0S__In8;\=izWM{<{( ]Lޠ@=,v=O/43u0,{F3GO5Skfj%cϘZ:LzXbjǞAsuzz"gP5ə끚,ub2fj cZL+#X`WBuGc"4:P_Z;VLFKcP^c4ȏ{5jI3Ƞ^A!HFҪ%.t3\^=!?P8oݏ EҪ%. +3^qXⰎUheY; j +jid1{zZ~ 3c=4$C½1䈘YF*NV-iw\2;=6 nM>{رQKڏY`235z%a'r$)jI!SkcFcdyV9OLMfj=6 k2Ux+a)S~|Xm4|f:[6e>zNfZV^nU?lj|/xR|QEXai!S?VUc ^q +@y1:d]ok; c3_q⦰1jre~z~Y{ 9S[rLC뢻twwjSc_9L1Ug+kҩ-?9'žrL[Uo~ʹ_Y^Nm!Ox2rb۰Kr5nԖԩ-9S.74NFW߯ԷCJөqq{?x;x֩sL=:m#ٶ9-s^6WoܩS[8Nmmc:5FܩS[{=mc:5.NpUf9S⎝Ml?nO/ck;gpOHvN ާc`FvFStJ˫N .5qU6ŕNxtT/Lvdgb N5C:5 |':5 oN 9~xasαә(}땥dcAbzNURsA]cܦWsz$&i]Usm'w/SUrY^%EZ;y=梏{cW"DyajiɆwist}ؤ=U;)Ɖ}רhyU#AXģ Wn~GSGRZ6T.3ke](ȳ8IM]c0X5pWfC]ݻbM6AH7Uw,/Ƹk7MsY5Jl%yyZMɅl-7FMY|2)f82l\dw`^J i,S^8F 9>3/Ws?YϱIN0y/C |IrY)(q|K] /^v 29FXF=g`,Sۜr>stream +H엽Fyq219 ! $#R f3}Όl +aI˹z-Xr)Ęa53͕HOZnO=f!^HZvjcΘT4Q9^OS5uYf VWm!0dbXYe? 2D_qB?7vΙ8fjkM&xYT"9'_g|Yq/A=k|oldWy`cx}]êrvw +WBZ8FgOJU໙SG(N*DF5"-x:^JLkAg.6y~7ue\d4dIuϲxW ~gOW(OW#=F`^GUյ3}N.D?^$]r4Ͻy6/6{]c>H3\E[=<{Pׂ4?걽aԷΎD%T:9ZmdCZ6ܽ(b \l|DRy/k`_y]mB\DGUBӤRBUx_,{2Mnc} .ocL[}QM6Hm F'7:AS97]@; 58rZXÎ",I.!8tb^C5F;7$Ebs!_^-oƔ\ŒvR?W޽쵰5j^l44Ť1#~?{^">^D1\zC(h\3*m3* +/(g:˧^>:坍R-z&fu:$kU o ~Ksz(BZ:CFos>c$"L6s:=.C13\3ν֣n +5XqzjP[3y6l,'smWE&ݚ9VGkd^oik~HuJuџ:T^x=9f.^OU`UXb 30qZx4ꜽ6,vk1 +F_{=:SU^3c^騖܇'I[{}W' [p"O3b7fnO}.ݬ}%&zNNuT\y'?ʳקV*_ENۃZV/I!l6uqɧbf֎^E0l 9+)S$Kz}?ʳ6Zh߷D|`YwE3s[ۡ]k ԩnZ[H}xXE09-DvgykY7X|p/>^h JÑf.6V{-)rӮ*-"otnV%FnkyI3?^mj;[JfA X%-B·8z)Q/6ع}}_ڦ]VwE+OUy-}hkX ΦWZͺ>x˚YJ5}6_:w:\u]p5Q>DEa.2T2yIaʾof]GdN+{?'vX-+ghv~WlZ:]s1.$*o^ՐrAO;o A.KQuٕTݧk=WUث6 ץ}mz3 H V:˩׊⁲ד|k~'ާͲVg'i&UߴQ}#L1K2i ӖvdmFe +"r8t+d,=Uo<駧}xx5Nj8sA(sokmYLGZmE~E}0n9:Vi;=k6C[g|5vD3dmÆѳOnڞmLm!y!i5 x UNiv|eb1{p{Ä-\3PU$3dI:8e74ov|97V/EV,۽tWow٭Ǒ2 +n}b{[3Ɉ+(iF #<;%2L.;鎝N2\t*v(mcu7A={`Vf.qX :8ܨX +:8tpA? kyA/lF3077Axk{0*tp {`Vf`v3Swp`T~tpA;tpfFup`Vf`^`v`ff {Q̎G~4k\ 0>= C4 OOOm p2׏u=wñT&LQu)Cl?X?sG7mkpmkp y0]kp]R:8atKkp'[Ǩ:PҐ\[H4dЍ5r å~BICV;8r 06uwfS>-bI)eYk¬l\,wpLHEݛ(Dj!~P:8azGazQYW⪊LT?T#05^K=uzaf:8r ;z4=)C;Fa vpñ>kEޚ\࿽\USfN2?I5r &ȴ˔| NLws5r F+g?66sk5a'KJ& ]WGar1IJv mӾ!;~#0J5s tpup&9 uʙZr!Yvgw]aP?\Rc\HJ.P\AQ\{Eq}M/̵\AE +YQ6;rw=O){kpQ&u=|VYDJEw=̠ U*Dky~/bk)|158jUȴuO@VGt~0+5*F5o5|c7d~u`ɠo赋eѼj˝ ˅47Ax=ž_g;!_m!Wי6y'ˏ }y? BLJkp3j?6\JmoakI৆kpY&s[huqŲ~rwձfxtsC5%ZQb{ WuZ;;r X{\ʦ(XY2\X\ʼ>]dng+\AERk,ml!t庐'>;):\r~pr .6g~r NzRٚT\AIUҼpf"7l?t kp+e{eBĆw0]WkpS2溮M>}ŅEUu]=/GOܕҥ䦞;mWkpX앬<5kp~#' +r N^73exk!?3N!\P$2m^l5*JOF:\ctX +3UqjIC5H6ir9T#vp!\|ֽ,c3wA<UUQ0\Fk"|\WkpdI*sm\yFNk'4BQeʛ2z\&r7"}uV?3e*Hwzkqbu.׷K!ahers&wp K+v{`HWk^,G-zo? isΝ4fେup ٞUb&Իb:|1ts5s.s޽TfevpVVQyJYs^5}\xm :s&OՅHz8]B?VܑkpC'k0ZWkktC5}uBp =P:!;\XuG !68=+ PuZ; !$..& +r=4\s^m oholᵢ2Jp3߾GGs,d\A0|OkW™ A@!D;xkzz,k/."i^Mo}ӾHCrrGTXg1:q˨yNR Y: ٧s6 #upPñ>V^8ueYw~Haۂ,F](!F HY"DD^>. *Iuw`Ssvı7:7 kϸÌ8an7WcZ'nz_vW4^BfE#Zvήì ~<?~L/epm *]|, +G8p<=<$+xy!zZ+S4?oh ץ:*I%w|j拟可^Z(*c yw<_m^Wx= ׮w ~m^*NL4z {G4d]Ӝ $x= ;&N9IzxwzzM&.ܩ=e$=珧gp^`^#ˤ4}YXDJk׾gM;?CuZnԟ1Z yE7x5^)Ȑu+dY|=zu𚒺 IL\W75׾dpO^#oj^Gx3EǓ nko2#afג 0꼖>͉ӳ&53`|K5"ןlfp/^ x VOl9O}+PQׂ{-oA7ߖx52fEZ3V2Kg2ڷ nkd uS![R5F qu7K,<_ރDqfnSI^)9y)pz\^ s;^p@6Jg:QQeZ 1\{^4zAIgAݗe] np쵗Ϯ.[yvC +Z; np52ݲF78Ú^2:wr起kdppqudp;Yk^㰶s_lV78ky n 8;{eR^;ޯw7G^֮ mzk3~gpa=^(e̥5vV/"gCq&yn787 28%g23}V^ vx]!;W.r7؆/~dCkt^Gn W^WON>O-II)g!q;󚱸#di{ kSRey XJޝ,,(cEbwdp6 + +l>dph ꈀ2F`*{{\NGh Ĕssldp6>ע!֣؈ֺufɇ#28{J< UMmc!r"~dpr!W/@QoB6XNHaݖAn\M}xxsϲWe@u^+dp(׽> F^ `loD7ݮ!u GQԉXPBH]"aNTDWVdKČG2JXKdJmBfWX%lVp4*ˋVwﵮjOl*TEA5I˺8WpDܪ/ȔkQ}V: EBhY7,pˬJ⼬O d%ol=ږ~ Qx´nΥEYյ;瀢7gx[RS56k$/n.˻ /^mB\'nE$<66y!%b-“2N2w+<#ESF 8W6U^XhÌ=-8:j(ͻz }뷩q}U +oVi-cpJJ*mGCyWE~߳*۵eZʢ-n>stream +J~0í¬گؽDћwХ˧j(Ȇ[LJZ‹grrs@a%^$hײ\#{V]#ίcZ"X!W!e:U!˚SP|||yrrrjjjgaaa^u[YYYUyNkIgDrD^Ao>h;e4V3T2R0P/O-M-K,K*H~ +endstream endobj 158 0 obj [/Indexed/DeviceRGB 108 181 0 R] endobj 181 0 obj <>stream +ϲ}ʭʬ~0弞í¬ෙگڂFؽؽյԹӷћwm*˧ɯɮȆ[þrs@n;^$ײ\#ήZ"X!W!e:U!ݟS ؚ˚SPۆ|||ysrrrjjjgaaa^uYYYNkIgGaDrD_D^?Z:b:a5Z4V3T0P/O-M-K,K*H~ +endstream endobj 179 0 obj <> endobj 178 0 obj <> endobj 177 0 obj <> endobj 176 0 obj <> endobj 175 0 obj <> endobj 174 0 obj <> endobj 173 0 obj <> endobj 172 0 obj <> endobj 160 0 obj <> endobj 153 0 obj <>stream +HW[}ׯs`U}R&qLˮkT_fY{ ۨUS!Kj\4zߗw|߿~cxj߃h1=8~y?|;ݾwU>C~"z|T| +x$jdO? jbG9vӷ;5h~X^ȑp$a`=iT{CãW;~Q6S`_{g!zV]qPnVdZ|b=RaIyGM2 {+[2]ȿd)RUj&miҵ1כjy(LȺ1"KN>DX+:'D,r0 CaƉS' 3y lU'D +;7 ( a،e':a{YEGNG*VM˝qr%$41 u^hw +Ý=)(v\FxޓB<Rf;Yb3j"PXO33A(ty S,T̨@|R%} !yRa|Z=q ~bp> Ȧ(uQkcc=4RʱKAo1-1lrp{fzs"aMTz[rD-٪A](-iJ63o5)v^+Y +,a +r WbQ^lVʪT_sR[8B9l˟_x^6|c5˼n&1pYBa(oخk7DP3y28S(fwgd "SP*ZӂTd;|V@i'ԐwpO|F=8OgYșrŤJ$NNjoKD9&R:wpǿ% EK&ɺmX5x bGgЩ 3qI`!5!a6*w8ئĈ.Pc7'V1 +DnИuTNjnC;E?ƞnW 'y! :/5}hհP*-RJwh!У :z`lO[k:r"}`Щ$tP66*wJ"bY-Lݳ]3o)̤{ <73 hP\fkC2 +i#Q>j#&heu|;$w# VO|tLU_#c>K׽U«Q0oA֠ObOWҚ@+)^NNgsڭGEZɒ)f4ԖJMZq6/eby_Z디v'O;"qjGef!΄0c s[j`dž'Q®~*02af +o3QD<]D 2)3d]ɂ%_%jl2}*YS}0HCX3@eLֹk!f]łsYۯGj?3B f~L.;pds,?g*x4޼Œbٟ]6-u+*q& `ޫe&UIN2,:W:|F&S@Af~q;Se{R( L?#|s6ގoyi8;E=?1f vDSt~9oa#N"QMN5ԧ7w8=UM@{߆XSJm0|:hqY" R S8 {!IZT1Xr")fYE#@]8z`*i >j=̩cԄ Ҍ3)eҝ%uH̯2e汿 +WM0qTJ_Zl=ƈym}]6a1z躥nfh{p]a3I͆7895_cB>>#<gwGRfF1ұT;5ggdFnH,Dpo26[lyٛ*C"a̓k.ܿBnmG@n0D {ޮ*|CB"C3Y.Rve"IE\ 1#>(x8o/|7:Fc?ꫤE"޿_gax ID?o)ͪ kEŝZnaSBͶ +t mNC= +X$BO:QVd3sTra"Ntfsf\H9eBOS.=#j9h\n7"{IY + +[&XU8ӌ2P~EASpr4`UM SQqyG.H<ﭭ=MEVTEZ qtPygP+)߿]FQzUƦ^F_G/"KϢםׯґ[B13Lb^kCu{Mmʷ!qlx .N3n"+ץZ⃶/%ر0O8<-e/`\l0s`;XFoc1/?ѹ|9^.2Fd`qx?<Ӡ+7ۮ>^jw;OvdEfhlv#~/vRR7sBKFhS->7k {|~E?=.YHcU9!? AWnk _KiRP;nyrعG< A bxM dc0OOT{ʛahCy4` Ov#X-PX"df~Bj-b@@*v.My z,)^H&No +.Uu.Pm +! !F'eF*2g*4I +=ͷ).= eio:B)PvI5er6KP7‘njcy}ÇlZ@Iu yu摺hpPrOr*i^a7{EÁ=a'#7:޶z< +\X*|Զg(vEh6hvhYFig}鑤cY!IY"ɛ%Hk +t'[%V'~_:Jz} +@t56cUM 9[/sgDy;'y'=d[pS$)VL|2N|F6ؾ_˷?,÷/nW}'Cv}6cѾZk?08I#dx cZݿˋWֱFlcvOے|Ϗ5 H %tbQNYf 6BH}zFۿ 'I +endstream endobj 154 0 obj <> endobj 155 0 obj <>stream +8;Z\70m81'%-;U]H]O7;]^4HpMi:=i6#Y^LOJOnXOtOti:,+ZJQ>D-]L@i0.ScdqS +QA"mA);lV$W%N>V=k-gP112t6QN1&jr,4sQU?V+mH#]do9AfVZqqkZRgs +MTQU_1`r``GZCK4pTo@Zo=EQb$qirg&p]MonPC+91%,_`BaJT +endstream endobj 149 0 obj <>stream +HWۊ$}gCeKBS ? Ƙfx6}Х*&ĉmRӺ'?~y//?<|~AMjC|H~fMQ#96,Io!\0 lC:Bq0 ?v {~Vk-/44hg54f# +n1bs3r4F׍@1JA CAIGwYE|QneȊ +snw y[TWWIfhruG.Wm=g7lhGN4ղ?z3x ̸?9xOBz&䷧ghmwp 7J}|ϧv,j{[->TNQtASƳ=Pi >6:@ +8vڰ#J$yX#Z %mcxB%h+I_gƾ@$5,u OMvCV~OͲ&eyq(}^[ljAȦHBU>*SFkARw^PRӎF:GBh{\="T ÆT =QGjb>+.R\k@#ʏJ\(%2!0%ƘhltQ+3IdWcsj^(&lUDm[䝈䒬ycRA&2j A={_k}u^`3KJN9l&ubm4B1U}2g擃GiVVe_Zς0*ms{$ vI,3d tNg:I,}q`5 oE_ORRNa?sk8D)‚q ;TPC;VPf[znh{16TLaYY3y88Pp8!t))2m`㢙=6β+ȶW.>P!=> 5`=A3rf*4^ϛCɶs!0' +&sPX A|7zvKHuǶXm H|d =B{ѳ:^>#_)z}[!XEU]ew23͜.Ys_TK苹텾 +Ȅe^9WhӉU dr4)?@ED^ ]I>g=ňHUC~Dz>I<}aN3 pq1|=,~_7͒$)18GcGi/b!9:(:)MFІ1ee5q A|9(ɇ!ś:kWK_\ڃέ@ wA;>8X[TKRdba(j͡栻#^r?qo' hat9mtx,@fG硼b0?(u`ֈBo+y4c3J"1Xb@ YRJO'LaFeSE:)Yn3:N`d!7#NLrIծ(H+)6h 2X&(+uOiZo0GuIDJ Iq6ߠ;d_ƐmgHij j @P&ؖv@t.a`zKHJ^4@LlgW@U CÄӡ%0i-6$\bI@2-"+oE׃*&;5old6O>Twrčx53;5 _ԌvE,HK@J>2-3w4Qa5 5aQق]qT#b|f5WrB&u %I7_z?;𥉉7k&N}+k0Zݾvq]ٵv]MS{Kءv#,(_*{ 2=As*J0/7D5,,^V7SIts +sCPq K7N2>y>a^qఒ3Mcj(h@.tA!u#lp614L_]~L q =)WKQgThakWR4  Gbr)D{ azkĥM&_Ô?Սv +endstream endobj 150 0 obj <> endobj 152 0 obj <>stream +8;Z\74dt+J&>b?_4b>0TD83&t$^IlBJlK:4R[bMS-EXZX!A^=`hF5_ +UZN6t\eU7/`HZ_7itW4f/"H*KgWLoLRfIVB;Fdln;),IRok2EeT\lMm49#1G4F"o7 +Xa)Bkj$a@p4VJRmIm:X>%;0H8Y7qc?9$e+D\De/T6"*$pia/shUaBBi0&!lXA(mNF@GuM +'pHt/q\jhH^cS,sK_s>k7QK]);f"4:P.UelK&!$UL%Qp/"S>QlI?IA_b(SKnYq>V# +*#8"V\3*3mJf2NDFZ&1&IQ5O-d+]dQORMA2Ia\VQ[aj$?*Ot2E<,oI5i"WNF62*rg +_rCLM(Q0I\N(q6#=MAu04ZR(AF,m[?\XnDk%Jp,Nl8dYP7`T!9(e'S5JiO,i:p2b( +D=.9injJT>P_P;ISM-5cR]*?^DHT*meG+)!'u*2>&-;DI3a<7Mm?*Ou_9)1[k%F6L +,jm'tOiABoQbDIP4QN'?/[d![^Jo$0T?5gJFb"3OuCq-:maQ&J.2^Qc- +GrQnfKJNu)ZX9(ru1~> +endstream endobj 151 0 obj <>/Filter/FlateDecode/Height 606/Intent/Perceptual/Length 64368/Name/X/SMask 182 0 R/Subtype/Image/Type/XObject/Width 593>>stream +H엋? 1-"$DэtYٳζڔ$]PY Auiݺ4\|̳gI}o{ޯ7AAAAAAAA?eH"1MXYI ʛ:|/((((((AAs ^oqKwwƍ &zxN88Ѩ\__7oޜɓ'ݎ['=!!QD| XGg㍍^xNBrOԨ 幻dw!ؾ}.eCCChEٳ]=|YE>> g\Q/WN>,,K Q7%3TRSB? +˃2F-ӆNa3˗/M' 1)1޾Ok)"d4J삧Ox=4>?ĭ(de%N ;ka!444xx̆+ ٳ]n-!!^&A7!77R۷5ڵh*==- > HyaWXX>kL{W^^1WYw/b[ìCuu5w DtOZ7PY=]<;tL)T .#"0atcbǥyhB_(2{TNO<Ԥ')1r.ao%oܸpqqb1>g;WuvzwvDA祿7oںuKp40϶m[1C٨a7a^3fte"iAL <ǰcqI@"1+,,`ל9sXsf.;P(B166FkeFykll~pLJ{Ő  6eeevZJs{;w ߽[T\|޽bsԁtԹsGOcRcnܸzEE|.ѪI5p Ξ=^pAGKkԫO?.V2#gΜN_¥Jg)F._U[[袵7B#xիW`.XXY9̄5* +}we8W ,Xf/]JD… ZZZ#*Uyت\711Q`o^f "ƷNKKH/)):mlO? ӁG𘔔d}bӧoaa; D#)7jk:#۷oqЊ8 oݺேڵkZܹׯ" ['pn5>H#.Nyp ;FFF:a7MR]VH`o?icAUU# I_فGRcٍw ;vRoĩkGA6Qd]>Z*id2".(bt*ZރǢ>ԅ*Q@DL@ $`|_@B1M~9;sn8|ɿ3/111dtaxavaȦM + + +dz-~wϚ3227o}}WAΎZ4  c#W_L``vtFGsqq123[oϟ764UTpQH݀G*"QΝA8*NBL'Wn(j6oClE1pگaÊm!9tt355<ڂ=okHNNR}Tii)|ס\Q@߸q=ZNy0_j[f5stH/rpãm߾ ˜[|uyQ6G|)å"`XÁ?WWW˹ $..'%p,\]<<\ll..p)}Ҍ̿v1pAAA唇KatT" (,,d7-ܾ}K57o^_+tuunnnºBX,_ %66OJ~)fkk#9xv<,.4PTT}_R{ܸq5Drssbd_ز͛7nn>0 V9 dfX!Ǐ;s&맟3ppjU|(H}{xTTLԡGF;;[_ߕW@i6)Euҁ}}}G[zʔXŋL,iǎ6[/_thh+ˣ&HyZҩ{ˑ˗sPhRRNDz /]QVK PXnO'뻉{DJ$#*>ԳgϠ$ K'Ox']I4>=E~oưIkGdxxX$]}]U =GA < BO Az) HyA@# RA'̅CCԨ56>; ǫeB>ަy[DDݬw)-s</##33cj䚱֭jm'lQ?nnNNt:9;;TC]jbbhjjٷ7ذx̺\\6h_x嫪*U8bwvtt5ʃ`1X, +ߴiǏ_"^99o?OyDS*T2rQTT$vs()))¾*+/(X{vFFJxiV*,,_@yuc:rVӏxS(ȉǍ7tH[''+ˇjj +h-WK&NZW{lŨ({NNc]VV|47wIbG kmmq@|޽MM \)YtR^QQ(sg!UUUH<ʫff&F9?n]  Y<1qAOH Y<5 8w򂃿#W8pٸ1':t/nmCF .YO!-m޻wҼFGV/,ς!!uNS,ӧ =gɓXoQQ^JJW57o޴;wxxLbT(4''+$$<(@D+/ʋ_/}Ey'NLyݒޡήޭS]<;8S҈./??蘦oW曈B##Åsoߎ&<|CSx_/+(΢܊1ѢSӔw\yzzw|Μܝ*UfrrNpqwÇ6j)ά^ WnҥR[SjS@K=<=GtZY t@Gs͚5+CwNLl\hё-Y%ڵ&ԄOCgnQZA6KyzN=ڑٳg1kѢTZ@v*4+^| i/IPPTݻcƌR2M(!,KKɓ)t5S3 HCmPۥKd`%H;ϔg4兇*EYEd>>s#&8B? v__gEEaúhtt/鼗m+))޲eӶm[Дd +xD*+So>G:sL쉉tJ#hT&_)uΫVEID5yeeM#̜7U~6"Gٿk׮K.E'!9姟9:h%>0(R@RvdGkkkLqE9a!G^[n ˵kW)~'xmnn>vȏ?"}%&nTרqjj!jKKK[[[>!aCi]Ӕ)tO慀P8rM_*N#:S'kN|𡇇`Ϟ]e7nL /I()22(>xZ%33#,l>`>aX.Q^^>yEHH6 uRޮ]tu(6dTrQ&rTL}3ݹs G\А!^x%S-_PN8.4ǯUb48mKK3 +c| S`@ 'Nʫ+ RK{2'iYY*qNII32Ӥ!ҥN?q/^BD*hx]>550 +3ƱA~cCyXb'% Yfq%Qޞ=un9+Wзe}l2AAmm_Gyr(p(?~??P*| +U*ptzXF)!{UUUj +-w ~yvwwuf~~B1Ox;G5h5'J…[Ƈ1PީSh_B H9rї/_mmIVVVJ+9s~477xDQޮ]qLA?@gϞ N27Jyqq\B#(4%%frKKhEE9HH2> b)ኊ +JH56ML*SS#Fy&q/i(Pt_~sVĉll, VHHpOOFNj-,&Μ{{{=߿p,,Tѡ \xvBWų9ݔ[-X.KJʧ]]]O>4WUUݾ}cFmOwrr,..\DrssE23?g:`3RDAp@_*YTYry6?$ ЌIk_Nee'_(h%fv矇2e2Z)P9=Z`FyIIՅcWؠtڴ {@^xxs׭ v9pxn.+̙ +汐p +H.P/o}揿tUƄyԩ6d 7lXOPu니P( +_˓,TSs H@++/p0+..!sg^S ŔMg}>}4ba/x >|p\|rO? `ټ9Eg' +n=yDv\tCCW'zѯM+,<G\SYC2<'ɋ/(<' +0iEEEueۀ!(U__߽{W}bcʕ8-NQQ¸wiiG]]Mp L4?zb!deo޼Id;& @|[ZZ(hJx51GwnioߺcǶhfdh|awor[(MѨ.[CDD`HyII dѥKaPu9S-zg Ct<< Fy|7##F +h4oS744X岲ӧ$OE"7YrjpeK˗/ɰc#WP^wwWPPHJ}a$XtU)"ffi:~uE)]DFndP555kÇz?~X2vu=WRUUI[&'M"Q[[ch`Nj񡄋禦Jo<;gllXSsI2RDݾ=899)r,-wttد_jݔNzJXQQa"6%k*,:A,~ڷso.RR>۹3^,11> `1!| 0 +!#c?qΎ722ų[WWrIqj M eQ q^قXu4Y~_Jy׮]7Nt߇Gyn;v xռ:˔w5[[j6)YW2fͽ{=7n8s";[~r]HH0D&Bg|ϛ>}s'Np):m|DG(mc ͦMǎMIvңPrT3ȠBZ33Sb"/VI-Bnj+((x'3lŔGlee!$5YI+ +>Cq B<噪+߼YBB\ mm=jGLt, qWT4e+,9ӵF-##7r2Lu>H/ZX899WP^s(%qh WUUӣ#l'o`HF1=}d)eX*'OH)ɷ YZZP0/II&66FX'3#GS-_R}Lfޑ+VvTonGG;T_OlD{]y==D&fC< _YY)N򂽽mHaRHq۶E6uQQ%#ސch8_;wngee)GV{[|YڦGRt,YLL 9aΜٓ^mRb:DasT&vK?[xPP (JK557eTcZ aEEe" +d1ÎmlTR$@ D6U "AeJGS`d${.s}Չ<"C"كbϞQ&w)rI')yC#>{Ɵ| pthϓ +; Cb>G%#"0\S +5%#Jpԕ Qݽ[UVvEp{CB +ܾwz{K092Gr,8"&&ԧ8#R˚"~+eElhkk% =}bnyyW +#f4 86<<k1ƍݝ_”y ]*))f>tp7J[MMUۂۿ& ++4YKII^DKkkKx%9,]\R߿òL +y7{7`XS DӃ.\ Ƀ<)Cf{zHnʏ<%7xOT%ڔy'p)BXpGOO\ AC6̹sɉm*}. x* Q)AMM t|6pKKKpeqq¾ ovacf?>>E4Aޙ3 ܈"N _W"'1YrP;(Pa vv6K y_ɱ}}}/hJ?lPAW LR': +Z]KKc.E䉾q%UcS]b}}R +ܹ+V,-[\!hhP.M;mbby G*Ɂ]]iIǏ3AK*粢kjjǮsrr޾y<;R4i |>իWccݺuCuq[`F]O> + +4qFs<"/A 9SS).VWWy1RVSQY:_ȃ='boFU**nܸtnjjBBPd6$&&@_V u=]RtɄVRR":#z3_߶p V퐔tt"{{{ S 5mm2%m444xl ا&>D>a%\}АJ!ùma>6 y CCC~4)?g_0=ٳĈȞ˗߹'QG ^v5#fooKH}cui' f !BBY^^&PZޱ y + qKp/ 2 <<ܮ^-m y\n-besEp8;wR'{.)dn1xvѼPw7ymmMH9 +C ꪪ*s2e@lppps=zuGxBoS Nj  $wt[YYwigicc-7:֭s}TTfe!b1˗.DvВvvv65=j---;ws<)==H +GZ[[P%$=r䐟/Be>|8f^T͛7[$,-7r\|"MI7GqRޭTc;"U~x5ua?Dd &e K㱣Zg:RҊQ-3Zʪ1(pHPVe 8IsFwރ~rwͦMTUUYÿ#(,`3hjŵt:v`2=B?13LOO/.*''KZQk Aޑq]B뗓sw.:yoկ8qG$yF<FAOFGDD#""`D0H"yDD$<""FI#$GDD#""`D0H"yDD$<""WFRpɒX,G-U#ǛFެY1*ʍbX,1 UUu{4L"""""""""""""""""""""""""""""""""""""""""""""""""""za׮OSSSX,Y!ggg#X,%0AVQQn<բE EDD$ϟ??qormy/\xDOyDD$z<""FI#$GDD#)}o0,OÜ*"2FӧOwr5?|4Fy󦒒mdݺUyKKK_ c_uuځ3\"c޽K&Qׯ[u;AMf]3hhHގrRj[q˗/x){QQ)}}/2Qӽ~̲eqfn޼1"bZYY۸R#q+.T*yxΣ@ֳg0ہ~l]t0v|||3~oƌiƥ;vIp~]aɓ<=' 5KXd1.8+&-yɓH4ɑ30=577*zĉZk"F^4g,L6)`Z;v|n04ty^^S3:wa;,,2uj)={ȑ#8Pj;4_nn80W11m< + +x^Yxy7".+pK?0<\x\Pxp(l`%,@I͊r$JKKDFB!)ihXϟ + DΞKFgf;y򄣣ب 煄s6t{Vd8DaNζAh@Xs KaI'y7o0.^Pw9x5+*w:8 ٿ?s]\xo`n_u:|nB׉R*H[Zj]+}D#Gىܑ98=~ܜP8?چf}KK ASg>.11AwAqwwՆ zBaښ{455\HOOja8)bJKK5Aᣏ1xhqy7ygd6 wXqgG[!)i5*9yԩS]z%wH&#y$>mqqE$77WDD;vyaːqqqKOV]]7nAp8ƒoݺ58EffÇnhT]Xn4&&֭J\ :s @*`06,,D{$ kjj iDc#ħ>66رt7xnnooǝvm"&Fzƙyy 5kۻwȳD$ݗ'/w ~n-D^kkˢE *\x6vB\j~~l]#Q3uuu^~QQQ||ɓ'[__;_BC7n>a~mmƍɇE`tLo!:nn.~rvvs #Q*fcS#566"ysmؐ|ӧO> +?,X0wu֬k׊<}jyy-G2\.Cd8992~/,5+ax#/+0F~WQQĿlL8H? NxBqq1مKN^ /Nm zG1H;CCѭDFt53:Zm693Bt~" ˆ`@kn r,x"p~85yqXp_ A.8*i$c]tVQmWErڕ$9V (AP"r)&(W5t}L{^7yXKva0W9Eff˗r iթ`U!ɰ ,qbbBmzzZ(Ƶ98|NNj%(`@yp +;L~333:00_Y5A@l9=|}nܨ{5)O={$AΝCK5t$855޲0I0(gk K ZXXz˃LLpib=G +Qvm~#"艨(۰b|R;HNNV^^NnnvP(9s1} ]ҕ+W0hggf8Wj͍EN{Mhh0'&&TGyǙL:#pk/^ k|{yys׽y(|6߷oo``@CCJF  pd}~~TERݼyrS%B99ٚ?pyuwlĥ +c0=3ځ"G% DyO8FmDWT^zYnN %Pm撀v Q^NYY)6ZXiүrWWFpr +ߵ8:gk\/"v:wBX(T2?q"_e-Qy b +]>KA0jMo"ѕOuB'a.O>:W[[|"55YO9sÃBBv:geb1bTUB .<\.d}jjJG;wdL֌]]޷Nqvv|~韣UzHB­BdV@֭3˩J \t7hLG[l) Kb '8UԔ;::D  9[pAxx+\$QX`XYYzGzw@xq: #|+*`[FFFPɣ'Dbcc1TUUB:8;;1Y⑼:-%X~;`3=SxBO>y`ll PGW3o߾UVVZUUUXǝ;NygNq-|Mkk+$`/__o??_#[ׯYNBX,$ T KK +AUU-#y 544,p*yT4I(NlęR(yhμ\"[ }CCS +l 3J&g~򡭭QPISSCHz5=l8[Q=㜷%'õ9}"3c 7$8b{!"蠒'\f%y ]###~^C wvv"ZKx +y0::F"da'9moop[Db8im=J :M3"gϮ]vp:?թ~-<ӧAšx Ys{t=goݺym۶Z@ G*(( q·Tf (y{'f ąנ&*ꢧǽwcggzJصk}} ɃJcm`? s***Noذlkks©ss;s}hh*8;5Tˬ$хb\M3AY Ҍ a,c'Owt܉RWW;Z]]]޿:8عB>~::9_<Ε ౠ1p^z gDjj#=RR(y,LYccC\ =&PoHrQ^oakfqz+**DH/Z$Gٖ-ӌ ~/-,--|%577[YYx5^s'`ohj~S$NΑxG)(0@̦<(iXXlJ].-KHH@Pάsz33#yy +e;#j YIa{#SJիWq W_ɓTXܹ)***RP۷o%=E..9:I 7B󢲹0@&(Yo,,pX)P~-DH||h9y mS I14+#ޱf$pJvvF656 KK/:;;qpbu_;7/***;xvpeU*ԐbvGG}L7%_Q%[{3yfϓ;MMwbl<=ݐ,,,;sbb}}}>iyQE쳲-ARO@!" +/LDfF ,_ oRՕ y =ٱwl混0-B R+ +e#=Wgg mm5:G`ǫT*iXW'%%2JB557\<Dd+F`)lWUULNLLw튆^,ikEFrE@lE@6ڻ76dP`9<<4D?qg|dn>S?z왆RPndV̠eJJi0;x ]cCnՑClӧ3AL EjiiVXzzz\\a(v@7DV0@bPh++v67-Շ"Cl.hPWˁ@ +Ŗ]F"ou:/ o" OQm?:u2:Ts\djpE6ݾ}kBSogVȋCc*c%P阘CdW_bx/M +!ЂzLoxN}hdf1]w=s,+Fbh{9 ® ee?ⶆ))Ɍ)c1ۃ^ձxyyzelltϞXJ˽~#ёFPoܹsGrr҅ +]xի1$Jr9 Gޓ'haloMSS蘋v(;;4wbw]m o" {{ڕivvqkk nb WW't|L&ݺu33 [T]*Ozz$ &&&ptX} EEƏ?vssƨ^ό0ȋ7|܈<!y')׳:;;KJyj@ÉfͪQD@ Z6vse˖MeСjeeWS#J%{u`,?ЧGO]]"j ottSԭVnԫ5ٵ+}r_ D"뺺qAHaR޽{Shh`#\6Fn1ES]ݞvy&+WaHKORl<4vjjBw۷onyOMOOXonVy$T)?"IWΜV'ż}{)=D"Ш{0<* *S򣁼Rswߕ/K~*$b! 3( ݰ! \'))Ʉ˓'* tԩGt(E) +U7oּڴ)]!!8f4:b.YVTT1 krx:-l53_QQ2b=DJA1q3W#)..Fpzx7<,344xZ^XoSNFFFڀEAbcĪbccp-DG7Ny@jxO>ձ_B,ׯUT\/,p-VBɅN7d >x1@ WT(b{}DG&tL%EvT}V&یg|m)^^v$.9Ry~[xƤyM!]b5dybtR:f99ɞ?Wr#GGlv3W<}O!##i%]T>v y$E + +!g2{x>dBL[z1mӦի +(9v(`AȻwB"۶m$1 ]򚛛1 +eBa%䩷l374 tr488@$ZBNХ655jBtA3vl00ЏH,AQ"K^AKݝ[Z1Cuo"&RW +޺u3>[,-- ˳}koh/ -"n'cΜ..|>v"ӄ@cT1U&aa??k~|..f8Z)ݲ%CTJ`k79¹sg\2dOOC-688j{whnFU <>];w6_>EBUWW3d0qℜ{Qkٳi/^0x*8/d.:y7[ZCyإq\߻JiRRF`4-&Qv+s88H7"#vs[G3٭sZ[ngbgWdŊ翡 ޛ[dٖp||.y:c[n O?Fc +ZK17o0<Ùm{W߃sԉ!1=z}rrzs2/:i _zaOC<|}}r9{/tjzzՉ<#9]X.//g7ץ\Z~(q#CϜJ"t\XF_롊)p\]/X2Ґk~h!mƳgeMR* +䁿/MѩS'hiuHiST͙$k?LpMf)L-w'ʞ~Ȧ76^lR{{s NS__ץP@#GWN. (*}}J477QCz^[[ximɓ_fffjB +u"P`yXAO>YLQmm,˳8܅ 88ܹiYJ1A?̝ `yXfi`v`yXfi`v`yXfi0͛7w ..ΫW )>7n[spqYc!5vM6V\>}S'CִiS&O&R(fO2m AX+J`yX+J`y-ol  mhGA4Dh¼<9LIH *?ʼn_CAP%!#AAQ(On:=ayšAAY"z Zk9B.,J`yX+J`yX99-_)W6;XP4] +ׅ]YW֤yyx#riIf!`y:fwR)L\,J)n4#DÃyCxcZ*},XjZdǃK#pBV(wiYNܙ.߄.xQx66([z I{'sN<"Bhpœ8!K8.3'CeѩV]Ej.!wFN5*["ϹPh̛:js'fHn׺n6^L{y#]]ȝ彛/iÐ%6Bޑ?#&\T)<`Y?J{ABJNo`ɰ/Bl9myפ~;va6"ɦ̹Y.̔~&Bq@7;mu +w"jt6ӅByK˛U i$6O#œNsOzUw4Rdj}K9&b0c U6zoCWEoWOaj&NM1)*zyd+ۮz5?09) o{_h+O) :16p'ۇZUU6@}=An4Qu4*yE$WõpSGq_PJ#4iԄ$ZeM -U_` yp}@0$)BdJML)!i&LhW!\ 8 p$& +(BMb%Km7l _e,۲-ْ%Yoղaʼi=>nCg6YC[[v{^`Wg6VLk-vi +o*=Uȅ1Ӛ%h56huOFw:e6KIYwIJ˸,Jn5#88"04b1 x@Ҷo1MDX+ Ζ紑| jk_SF7eзEPwX<9y{t0U=x.azW[3GSR^W>NY[hop?NO+;qqC^wEh|Rr&2hE ?D*)f筵H8.F>SI Ce`Uv6:."ۧ%=Z_@ZEy8>a'YYx<9.>`dzXnNP-ܶQǹN,&J;{B!ɯγVCB];RC LӽxX\(|f +niE7B)wHbNTk pl*,zCg)?WE M۰#6wP/BCh_yLtoBW Cw @IL9sx>dY{ģE58@ydu$g7.9&[ *{kx,I TNNB-m뇆S _Պ%={<ցX+DBBC#6?Z4dWm=^~ F/|$iBVJV^oEaf 87( +piѥ$8e=)D/z>`R$dlgwDb6 : oGl_ 9CE"!_!!-%$}^8[ߺiRDɯ2(1 B@B35IUcUԋD^A{(B~tm|4g[]vl[")rXM gūSSv5z>g4KJ Sf7Z\N';[#2^ِi6wEBIGbǑ Xy&4QBՆ\2kVږvw0V;)~ᢱtx79[z<З l$)zrª`RGPȫ@B + a2san76vBFj>BJ4zzPaOF)]PS RYS0s缝q DBɅGJk)A)Xx[vBR(7ңov5In7^dCcB(768Z{`v XDXg8?4ϘmZ%@J[vi'04|J I`mvmc&SHYfa 5Wox"[xY`[mٖdFC"l#g(}w=ҽw[xxG?2L ़ZQvtN^yp80Id2}j9 [ ںׅq '9u0lD7>'G_^4P4r(;h367޻#B` +`yP5Tzoz=G'ZD!? ky"w8&ء12)вƁ٥7]}iI2K>B0÷&6~Ms@y{.͇sx~Ø-^wDV[ wD>U}R0:=)\O0_c\%?3X"M#đþ] +,-=uKeAa7{ᘃςrpܜMOw;>ˈgrX SE 3~ky .5^qi.uAA+%K^Ġ! ZTo}SG!ezq +oY fkyqY2tlP[ CRp?lGCB<$ -/3#iU &Ke1)J/)[Ӟ\ƶ+[k.ojr9WYjG5Wi43[df3;9-%^8o qE #Cf"O򞺛ܖ5lH)q6=^J8Xs'S+X^ݔיּQ{Rbu>Qp%Y*֦CJP.a|pc iU%קo}ߣ*Vi\T e"B9X\ީxWuf̿nGީ+v^;([@$AC +}(Wѥ]*oԤiu?.K!OX ?- w[޽`@8E#DtR)f_QfR{Zpϟ֌@c-鄚3I;7"1VL-{pW[Xr Id8]zퟆDRB8> ۏڞ < Tbܜ6@%IcNLɼ',h&y&}Cק9`k(-\ơbr/$Tjx`_yMFr@VIu >I%4#(NGBk3I2B?p絼m5W=. ^_*z;- +{!]wI JU +xZ l8r?oq': +:j;D"XTAKOY0ciRFE$0yau,>=Iˡǔ/쨩O'*t^>)BC9< L"ݶշJ~_QMinE::m=sʴjujkv@@A@@ t\HEZ-QGK$DK`@yKi>ɇOyޛww>/%WMkwsp 5Ʉ"Oo3C ^SiCMM3^<2x +nyڡv윥0'؊ڡgHH]? 9ۇpFɉ<i*t&h̺/ O@S_`B5GtT\r6\_(Ȝ$`ܬEVz5NF5SA Nۇ_Mr"Ôu^EaVZRuFDw-,4Mo5ScuYh ;[yh5eXh,``3oQ[*+-i3BVbn(f뜸p GI%y +Ozv[<NSuj:סAd#]/'z#99XE.ôT6ʉu~)AihdL"`^n^Ώ0.mLk}u|#C]X=.7@*AvwɯV} @U֥y(;[-R>} v3 mvvY:w04Lc"lL"uV6*::J +kƢDA&ONqɻʮY߱ yS(ĕxsjw͢B9m^zJ%]h2J]ȇ]d=?b:T}:!@5ƒ^ ڎ=;2q`ɷ@< +ymҋF{!2׋0cY[y +]]? OfA7ZyHB\MuYXiPOmJnx 6g]i^D|^…GI%iy0l3}MNFw(i)4|Von +a-`.3AB h:I_ e4+EpȣW :F#3^LAF]y{yIS)DL"@d Qč*״N A"X;Yw9Uxk{oD,L F#*M79F$ s7({+2gl^gn[̋Z) FCsI/l?(F W},5 Põ9($hN<n"/:^pB#פ @?_|[tC'w)}+I[K/nn5t@7 Ej!y[G!"OrA{{^+]x-WƑ &j?{rԛNv!#S6>%CX3 z*Bc]"\gYei`3?KxvR /^Ή׻Z ^9vvAFx… <\JhqwY)y7792M3;ݖ'f-:ƪ w?^f(O+y 1ā MSn"u#.)N2Yl֘L|Gڹm|QhP8;N=p2˯`oZ_p"M055?5VlM<~,:**K'݁"5冼v!wy|J>FZ4aU}聾(@I?B X[gȵInx|6fÿ2.6iP(>uFߺkA?䄉jȍ\oF= {V2~,-t|: Zg1zqs+cH| ,/io;Oӗ}RzhE(v7eCpyβ!m1/j(Ve@f,ˀ:߄#ׯ GI%~#\:9_QMwڮuvcUϬ{9[ln;vQZZ]ά +֣KmPHB =B(&B 䝐&=E \ >wo|gAnHy>~9w࠰Cf޶ыEi]{~jjHה,nG{-f0ioQ}'3LDzÔ-ytI~Ȏ -MWBii_Yz̰ +v-sb':NE[NtH32¨#uu4iEE^U r70?_2r~TsS_4G~\L>Sc*u9L6 ezhm>V6r^H/T.6ƞХFeQ98_n[͐(M^{*@m1mo5j54B(A |!3vk)ٵP沣x?mu_<MVݲkJrEj$U!Y/fE] 00:XG}/IДCvu@ Tsܿ GWՂZ캀)7P$  U M<@jarGBy5MC=`HL@ HGNVpZZ !1w-nI(@y@P$Cy=.qȐo:lt+L~ds`,m]ZWy fĹ&NgnM  a@ ї:l+ӱ&EBV(T0JbR$1'# 'CɏNV4v}wn?h.zqY.Sܢmv A度FJ {0 ` ^bEQG=tu8L +l-T$r)ev4( P@y' Vr" >T5`4;ѱl&ȍK=2'6b{)ƤÉ{aR)MgsT9A0jct y ?\5֖/lDz}lFU\##bsU&?F"~wQOn_U(p8wyA{_tcӸR˘KSrP1?m)OA8^vtoS_lN\Zw|% +Z &;,s6c0NDfmon{ؒ$N&<܅GC;V4Z~Uei._a +Mq7 :),xf0hF +J{?S~w:O?5t +g2su5dw[/r93>)bXͶ_ڃ1ՕpDYTvi=$x;%VWfDd (!yvNU&O'ÅJ'o9A+]|V0KX;jrCg3v[9[;t^Z]pъΡP*OuxrFk屢uU:OPa=(aȳ\tMyZ[R +=Q9<3Bnq&҃9?GOX,?Uommg;k[GmgZgw]] !Z("ZţJAEvrW"W!J$ȱOD6ewo|y}>ϛPSڎ"˚\P@;Q&&~Si9X\Pr.9UK/s9qGpEMf}<샸 0;%byJ9N]">EAn Cy}pЕu:3.pcףk +Y{}1 ߆Kە6*Hwm("lcUQY튼[I?)Oah|_2AtWuoIp1=:Y//j)9rH^fas[v\ t*W}e7FfpDc_jTi x@Nץ,i02<6-9:( gL _}Wd9ml8`57">x6sz ()X52̱)jaz APƠK{Guvw-DW&߄T\,@m'1Vz)$Vp:E}IK &>ۗI5ZS'qR׈z,A1 CWx z&Q&P%x|TN ̃3ȴZ]kE;zKm*!`Rn )ţ<&"FdL|ֲ~pexQmGɕ{<o?"c~S8keC&1gPxf0 }z:d!㘀r%E^I>ف_xu>m~|&?t!H'Aú H(Bў*C۪t$WkSkp>As%rƨWIPm['tiQULa(^MRbw|[vS+UW6ۓ +C/f .r4+%̓N ?9qnm)o*7!QmpQR} hNv3 + U?I߅o(2^ɫ36+ *YxcPODFl1-CY{햢8k +DP;lo!Mlϰc/ǡ;Acw"(3FeG$MPQbX9+BhA=]!Ȑ}"kuƯV)o}9@)^g)r&׋φE8|PѩB3Ek畆 7o3O[opRtx uhP3܇h! i䙑Fe +{ƢXq[Es8 "&PPm;Jk#Wx (= )7XY @%X/Sʐ僒l.VE $)Mv J+"6Ѯk4N:Jy+9<esսL`cTin?0(+=7ݪkgl Ҏ a̪N5W٭8OF7TaYnhΒCM?Q+Γ,LaJ]PWmh|' DŽiH ,D(} LyDccwJuc[8FӍ\mx;9.N<ݍ$@,6*+d-}nN`lFqW,ʈw8k~;%.[zI:_k-ڇ.Svձ FVBlOfbLHwZJq) LMx=xE4 2,⭃t4)Z,WPd3yAn;.'XC/eM` mb #VN%B _<! ڣIT BOZVQ6md5-mܪT0eD5Nw6?4ub䄬(:|@nBylq&3nU ىf^ƿWjHܔ'ƫѿ/,ֺZg:j=XqљӎgޮE]dozo%fQ 2yEO4p[Kڢ~ʡDYBJN#;jMQnݖR##t7"/Y0Y#ZFZdW/OXƖh܄8 g+b!q +/ X5Uﮠ9>.S :< xAVul;XphUlZ&s} Jy%%!q]}Xdo>"2Gǧ|Ų=e{݄~ O"$O.EcuJ"K7czdӄR]>X:y5Ejl*  3AKFsY5t7O:&'12/1xЏR~0'Tێŵ%T=8SDPcua|/lyxi Ӷ4%L8`|f8<|=y Э]7GэUKqDy5ŸCTPbkV+5!gIBb"4aI9W\[TWTOocF8hꕁyMx ڥq]pzz$DxPBkmyGf +*B^vSs<2e"O{N;3\M;Ϲ\HYgpƞVҷ ݝ{0_q__;TrUf`eks#Wȴg7KO$ꌓÊr@݈}Wn?iº\|ts UbgQ6 }q!Ӂ'"Ð )"O٘8U◈2]Ӆt/ \@ iZMȑa6KSpY_KZ8"*1;+3bms3})ݤr_e! $>,jRkIώO\q;J/7[{;c0SYcɰ۵ +ds6=i pෲvf,u7-M Emե BDScxg|Q̰Q\+u:YآŚAyI;bסK)|v# =bNqJy_GXyȓ +Hf읩0Ql(UT?iQMgVա 92@+ xQ-ȋGWeGxm07/L9J^x)T\׻R<ϝFr$tNn*E Ԧ (Me:iDl(@i$~?g 1ؙ$Y/a5yw#+D򧅼a/̾D^i[ͬq1u Ndn]$9XK!?_U^r 7jx4@"3l r#auT]>Y33@4;22-SDnp6fIkWZ5ҝ8Bl[%(AՕ =F7h`G2z9՝ 3Ł }OMnN!e\7h;뙃3CۉXx$!`sF>۩!}̖5Tv!22L#]CW`E +Uy^ +p=}hn-0E+;++ B& +yl#^siBG~uEya5vX{;=g2+dREJ@i +^Ec,%7vK_)KGXX`a{vřyM ݩs}gv5Wݭ˄{8A%.9 Iy)sxR|YwtKf - +D`BMms9^؆~X[ +x +إ?xZLWBy?Ummmt|q WT4A5A +=Iy-b+cP=QӐ@Y+錰-qFZ,`8͒0eS0kT9\O Piר+;_Z7EA8S^dvHJ'V-Irqq'`;%ltg t:>`;WCC~mm3 ?8V)ϔ>tuj6*m)Mg3@up~CRS9;mL3[U"4jI8IoyNeUO7|K:Tv6y4.=|oJOWQg&h\}MߠUʃ +ڕ<8eVxH^O)g (1ij>KI9&;lǡ{\&S9%ZBB.}cOV6I0ݟGﱤ<1|v\N}= gmUsݯPAu_r5&f`LzB ZR0 +jsT㑢{FDlr:|v*qxS!Lf݅,$v; +N"s^wkSYnH鯁 .b6\'Tҫ0[ v=\oQ9Iq;&E{( 2Q`:{XӴ75SImXr]rT-\FQR9 CȬ"ItDV-b +n,c86 +̿h#v>"2> +\- +(ޏg:/DhpX(E|vCQ,t{A I/s\$C}!ql1L:bZq[x :a + a`jk)AQ4. 2E39\uw }fX'rbKIlw|ky#m K8žB` %6 vR[<0`=>UΆ4+3ߧ2P2?'pCnQ/)T6Dx";% b0+AkE a-h(` ~2hS@)6aST9_P^\}榤I?-Ir^Uz +23F$ =\tY2WTzČMt=Y%d5vڝ{/z^U6| 6DfAcXE"ȈnX:5O>7|@ӪĠc}buo. -J.E YjN ؜^ Y% +cɻ}4!pzOM){-Ɣu4h߽zcҔ6SYnmt#A0jx"(hZ`xqbU-qe*0jIPgd?)O$=.jS<)Z|.j7} R$s[w+;2)_v)ݲ|e}6YV ~c+D\}gbTvP=vFCm͌uřqiت (F*(jP(G&{րK~FF~rrwk[kjTJ2r|8fG|`R婖H.łW]׾Fd ?~.毒#7Zܺ]>KmL.7eꮾ]`S.o6UcS^!97_eoA+SKNJݍF'_wQRIcT'0 %~DL{cV7ʙj>䟺b!Ӿc9&3Bd:UXjuq9UZ\JU?Do߭Ѿn#t1.ۚLl-9Sq=!ʵȃ!^D'zyp;""< +yHD܎k,;&;6jk y"vD^+tfc}.Oȃ#˓4r1cbǎV U>Z^^~իe|ƿKY}%:ʮ7ƍ#GT^^2ӑM D' şw5G^ڵUu-.7^{;6y۰WJY=5%%zRݻm ^sbcl6]j䥤,)++ "L:*++ 6qq***FxykW#U^^Kڷ7J6X|8266mVj#;FGzwye1typfeeggMLhK=L C2\g`ĄVj#]m\ 8RX39YG$#҅8ܹ3$ĊEQgpt~ѪJd%:x͚̏_H"yDD$<""FI#$GDD#""`D0H"yDD$<""FI#$GDD#""`D0H"yDD$<""FI#$GDD#""`D#Vzy{{ դ_b2M5 JvvGzZEGGDDKT"ˀÍE%2ffF))*sP7Q3nN\`ǛyEEorD5111{mrrqFI# 1yDG$#2H<"1FAb1 #HGdyDb<"#c$F# 1yDG$#2H<"1FAbj䵵BDP9큐0 2aa!zд?r力7oݑH6fٳgredd|644xdQTTРl]O{٭ޝ}'B֖{s'Ϣyql=p`dove`Vuu;#!iF:'glggWS54]Ǐw}1Z/\rttt :8 .tww'&;8ػdݺ]\Ο?? +lyg.8rGew) it~58a߱Z__ߪU+1C$|[.Ôܷ/OS99Tm __oB4033Bxmj66&XPrrrfp/{a сdڅ% Guǥ,q*1溺[: ѿdI˚"QM&sq:vWy*>cl?<=P||y_|I<،<_Ed߿/4A + EpۿC +rswcv,#mhhioo`㺷n^P(!6js練ey۷WX|]//Ǜ@l!kx1^`eeSOÀ0ݴ) ~\QQti7nYSS <>~eYY,Ǐ$űȏ?^ObW>z3!0쑑S%]-[*XQ7o&O,Yk׮AX?Zyy֍돁E^kk3}~GxΝQ??ejW۾[[,002ۼ9uv#L;w̛7ޫW#AΞmsj)n߮sw㴴4?>#z'O6xy޾#dXȯ ###SO t~˕ *>xЈ݋-)9fp#9vxY˄‘Wivu++,F!KFZH;vdb-Eo1*0 3 fF1y╯>C }i---B5!mۊ{Q)c +ſ/='"&]$ r=I2$HC$Y!nÑKGX>x;H5k5ֻz>>_yII ?|ޔȋehQGFQ3V&&Υ>ʭu %=} Kk&[k tm&'66JJ1lO8gFvFFc/)z^ՙΝ;O*$dą5GzJeySSӂnvi݅ddlt檱޽$iQHsc _!-O>N+S?-!oNl|}DImӡCq򜝝C|İO^<:%%BL,^Pz-raa㥤$"Z}egg4q ݻ׽=گ*Űɑ-]MDƏ+@FdH +D٪&0Ǜ&MTej۷o(sryyyy]H`UTWWstNxAٚ2s̙uS~C+W.c3gNUqq1233Iiiil{Ǽx.Pn?~_y4TpW!/99GR"o^_J ] qeJKKZF#3ɥHk]f៷z+))m8 XVVv\;s$}bjUڗL;6Z[ǃCcƄC>$4tqJU[[HSey֥ sЁ11Qm@4)CMVx?Ed8ɓ#DIM]* +((? 򪪪N +Brsrr +2$`fQKy/%%7Us9ܗ/_%=>lB|~. +U^.Z .(˽ზ̊ > ̙3ߥ`z +FӍ:9w ]YyOgg'iW575I-蘗gQemyO?C:WWg/Yy .0G3յy:s<"^RRSN7UC\Tгr? +$!҆o2i$ -w%_V$zf8z7!pkKc-,ǧE}`:u +`-ZԌ9YfՃN#Y +(ױM߾ı 8N7y CCÈls;`~ݓ'=611[" +* QiI5 9H-JH"ygzdJF..lW[[М}RS14h޵kvI֎Μ9#66G(#x7Z? k'OЪ?~r3A@ +ׯ{L7bplףG+[{l5Z´+VN#;;y`8Aa.]Dh"Hryw1̍Owl-_U&ǠA>gΜG8o^2*h:3fL=2VPP)uOyedl'"<3?Gۡ!-~葚999,Z$,FĠs([q +\gX%B.jUZZ*F Sgv%kۿ!LVDގ;ġcg wޞDy0wyqq <#+"b@Dr)WM(G]&#JyJw3ǭ,DjMbQ11VyR*jYU+*̙'6"Ԉ18x'OTɓfhT.seƆ)׎ryuuWO!l+W.'mllT~B*899`VI֎<ܹý}Li $_$50tf'Jan۶__Q]IP&$ADP4*EA@4B@$'nsdQa,|J^{MwAݪ{oB >ݺuKKK ;71RxzzMCcQmW+i(؂R|?Fy*JCCΝ;-##Roo4KoArM<<4!!^fܘEv2gffLm2ͦHmmrKyin~'N) qe[7VXk%R^A9Unn牉 250mD:1KC&XP᷵r_ag̤gϞQ呠1sPG||SR,XZ|)^ee%СlOo__Ҿ?tjlOKKa( (-Z[[[E(obbuj9F)zi^ϐFy6L5hR~}ÖUU\K.$=+Gy0_ia)@bsgR45[4S:`(V ey'XX,%&T@ V + Q +ور?.4F&M)y{5μBYAmm>I "" r5Cù/2 I%S"7::34yg322as.u?E?0ʳ@NFGG=߽{׉۷SQ^vv6￉kq4<AΝ;2Ns711AJIeHn+(O"Ļ@9R!%?##{㭖&_aZZ*+%::Z,8%ZJe#HxXPژ4 v%''a~++˫sndQ.qWuuDmbb|曭\X $&& à< Y/ڴ+H9gg' Cyzz_` 5kollTF.+V-ⴄh1&A,DȢ_ft2g4X4f˖@g4`UiLrOLL` FE}SX,0H˗/es-jA eQviv`|CJ zD("#WWgggʿNzf(o:ee% ꠷iiixyy};!$mg$̴'ıeQVp.EFF*R}\8l 6^|fU(Ayo޼ ,t"PStG=44T^^F-|䔇11ѪF@V+9lh'趸/ǎ\ SEzիҖ2&&<ʥp@s55Po߾RV r_@AdQnP氰PGG;XnZ?6V$-3+ =;ktu$&Mp=WVV$+Duc$ߘ(q8O$))rsx!!؆8gOY]v677.ciddc;ZS~"hd--͋BCwCݖCT<~:/oF}NK>f58o_ ݿ߈>Mqہhɇn5i~*/)V۶?Ga*q"9TAsRDG`& ۓ.(JfX#v` ѱ!"Qd\8ƷcttT"EKx{i괷%?}N<_`ǵk0I\\\Yejt7|9=6yrDx@L 04oثVʛ%c5<}j-[/==?kyk=j:{LIP(֭_P N]d`!8W6m +eP؂-^_޴)Yx҆ d" )aaqP{! ߲e۷B$ll aBx|kkkHHJp"V"N)";1}:ut8'C7n tpu@?gv:ٵ{Tm\w4X=0U|gsF?-ro'j.f P 9χ%?2; +u<,T f钒Ǽ=))}vwr8ϟoǏAlm78JKjλwn,+/)n===]YCBY!`p "eg oDJ0{.(K/cݝ/!i$ִEL`H-]_)aZppѲ̺&y?/XaO`$Rl ,HNc_&X,Spӽ3W{wÍps.W\܏~!$1Ub7MGg!<6{Wlxܹ-9D==w.[wDaN0{P㙿|raUUU&&FRgf̎B$O>qUy^^H#"0x?Gh```6Ū<v> ٳ]pdggcd_|9&oo8F!zm*QRݸQs6>>nGVyK.Bn: +aHjXOQAtpJ,74𴶶²%yc3ŝ׬YhS\\4;b#̅86䘆( ׯ_E=%j#y;wFX19 .W͘GA@ҡg֬/7oEYDG0222֭JDCt.\ c}2m& +{ܹ]XXE+*;vlĨRr(d8-nkkJJ^II1"`G8}ĸ<8|ĚDJ/6\^Y@GEcq+M)hVV(BB6FFFKɓ'Qa.'44[,A +ͳ6m>uDEjii`lވɓoA'&˖PfLHH0:k1VQOϋGӑ #YF3eee(z{{z'B<ڵ||~vx8uwăFf+[ZZ B֭EUVC411D(`m\ ww@1^|YH3H ̙ׯ_VhOOOgggSSӋD>y򤻻{Yo߾Au'6%$ͽ._]}wB6oTIA2 %xL|Ƀ66::ZnnK~)255̙S |,,xL̈́Bx[,$y! IBN>>?r8FFn9C kCߩ!~T$y! IZbcclmW^Q]}wm{n..Ζx899,_oUIABGW^yfkGww7쬭_]]HŐ,$y,$y,$y,$y,$y,$y,$y,$y|Jqp{]ϳI^TvP8ޯNLuu5i$ƊѠFsivvcvIq_j&Cy{Cfg Q weޮٯ(4 0x!&1&*}U"(E"!hjWQˀ,r0#Oq_5tM;Y,97\oyDDDC<"" F#dGDD2#""`L0H&yDD$<"" F#dGDD2#""`L0H&yDD$<"" F#dGDD2#""`L0H&yDD$Fci}}]eebXQNTy9TJ%bXVj쿑s5+K}bX,+6%VPPq13bXW_}*D^HHJeTX,eV+J RWWWWgU*R1LzIDDdZ^xq<""2q<"" F#dGDD2#""`L0H&yDD$<"" F#dGt:]E/z~߿|QXXhIIoG2hd!:eeγ4;zBabgOOϫX-?vaa;VAA~ee1} fo)*k)D#d̙?_԰-sJG}¸ݒu /ll!ÇoCDcǎ6\Jsڛ4,,DF}$oydz<( Zz5kV]|h__7Jk;:: 200TBbSm߾J.6~7Opńwo^o{F{{ IO]]]]m0`)蚛! mmmEZ*88a͌ b棏fT.iLAgg'.I.ϞM:vva:Ǿ ~5"mݺx S'F]V+Ϙx\:FBlg#g=2<2a!qI_{ggiӦZvb/؂LyEEwmmK"LKKξfS~~>B…U.] _>k1|UG>3 &+11ٳhll())XVV<|}z41T,[掌r%[ySZF^ff&KFF[l7Ȼ{<~r'NGJ^cv1N7oNUU5d#\0B۷w,aóg;bt=t ^nkWOO77puGG;\8W<fc<2Uj +[#?xpqIBY[OB4445))/\ѣZ41`8R* #SyXp׮ seed'ǎ[+Vx;w +#[Bsd߶P^ Nt eD +66Pq#H=o MMMoOA{#SgO7|#jkG6 ? ƙM1򺻻1 F^q$cǎ;y x)Ғ?' ůZ*555g, ^^1օGDFFnNLLJ:ykrsss + +n#C1f";;;d | + FGӧOAdL< VuJIfC]]=s:T~~>qq{u͚U8^{wTLL4-X0y1._β0SHZ)F޽{EvVxf|?&7>T'>ᇺ1O:p87,(*Dؽkk׾H@r֨é+Z-7^wYd-:݌=GW?ڵ˖-7*/?:=t_纕mVg<"<"V)GOuuu%''S칩34o\ǎ,re(T'AH^4u+++E.T^GDGĊ<:l6㴵"|@EEB!S_}Uq@VmtzS#d2B"("KN~G/**,$ lL6Eql/8Gd#bʃȠ` B LJJlkks8< ^rsT T+PެY:JY]kc`8tpsQAy>U^l6ɔM@b6Fvtt w \>U ذaݚ5ϫ2ߴișׯۿg6xY&0]W*,I@?vh0'333`+ly$ȑ#Bӧ׭{N MJZm=Wy|R,YM,rT Tt6~˗?%3r56>}l11<?na;HhΝku<|7x}p/w׬ydSyDPyD:XxDan#;|[[Ҋzk+W]MM]4_~YpႂWxN+++ЖFG6Z|}6'!!?i"쟔k(!wTh[ݑRC 79BWp:,:t/ox;!H*BD!H*BD!H*BD!H*BD!H*BD!H*BDgUBP^Uמ[:Gɦ2 !P*e^yM `/_t B!D-6ԝ +endstream endobj 182 0 obj <>/Filter/FlateDecode/Height 606/Intent/Perceptual/Length 373/Name/X/Subtype/Image/Type/XObject/Width 593>>stream +H  o 0#}- +endstream endobj 138 0 obj <>stream +HWۊ}gdD@] b>,YHkKD^{z.L]ՙYq=q"ܾۧ?|{ן>o9ܾ~gͧg?p&9R6>>Z g* +5*LcK$KQgm|Ͽ=|FH=̯;Fz=a"G1?$sC9VrCX!WyԮR+ZA1Wbdp~1pGk݄+=t9׮_{O~Gd8 +c4GE77!F<,̣dn,79uesD "9 !Z>i!cZ)@& i)y 4CNCB͸.C%(n< <=;v8 紷?Pn%@ ټӐZƈrP1M(Dqȇ d +\1Yȡ#r;sH BIf' 3`p.@YϠJ0!Kcu7s +'S}./[kki&'#Ol g"mv.#0aYmnx&egzBJCzyB4]v!BZlQœz8UB%i#Yv!٪ˀ@ ?#/  d*PX`T^,Es gymB|M&du*!ж]5tp¥D-3Ma]{>6 E1PDKRHcX{y>#iL3n-np3XFVHylF]FiŸMXdPL0h/m~nCQmdpzQ=ZƍTWvAPssU)n-z];Ӝ0uxA iOQu ys2N咅g(Yat! *rZiV~t'bdWӇ5^ B5TG v@Q-Q]e` 9/a/-|l dJlΦP-*p' gZl=nRѮ1>cLUWP st55mM⪚5”( ![!iZh%)-.qtj֠$*[k6$Ž@]5tTVMj%B\WTp5Kx.-/YuhrNs-}_١FѼ! +QPM@8-Q}kSZaJB-̦j.:U}J,Me pLFJ2SeP5m ͪ{2 ('c`FGS<1C,*ӬyH)bqlOleNЦ]q?ze6γq;GLs*V +G+\gՃEoH.[-23\t+swJJ !rknMU{iu(Fh{1Ov:u|65#7|jǹM@ÆX|&ͮSpPn0^vd@wd1P&z?ϹfwGW7NP`ܡ!pv}~ $\ZEpw\]TNڣ@>{}̞TR]/c$ =]Ez}}z|}Z˜=Kd)ޕZtZw oF,U&EqӶtsM~Z5=L\r:޿Yϝc潰V{_)-}ŧVkW䙽9;f.8ci|_7Ԡ^)!>&Ǟq{5N)` (<}"k6k8}fBܺ>f  p.g>@#CӦ)\_N"^7,)1S,$;7(eЧyp/,; ìHC}̯8UxT sdބ FQAC$xU7O +Jr<)28s oy2opinTh4!}0rM~|Ȃ0U-dƒ4(^i#$R)ARiyZG%Cft P1`b EK)D[/7.A~׭㌌~`W`Vl3FE{?~9|,R QM[hxͿ+uE點!?q}3}3{QhBp : i `X3Yehba`R 6 = N Xt8"6fv +endstream endobj 139 0 obj <> endobj 148 0 obj <>stream +8;ZD/Yu\ab']h\%cEM@\g\)6q5nAXnbDXZB.,&eUh9+J5qTmDrD$(0#RFB/WFi +#*71H!5b`+IC-X<5!eeJ_XaU;X9d7 +8`nin'HqFbf_:XKUcn&1RP)O.!L?h'Dl,BB$F'2"d>'Ti?InDRbS@pC#FmVbH]hG& +rMl\C@91qUmC?u3pD2g@!U+tgkRZg>FCE^?X*2ahl"0.f=#a#:!G87BRFJ1uaZ6:?W^-g̛ǂw +h"Bd|=FKh*?2oa#̛L2BnT{p}=✌Xȗ-g̛-=^tū'~!wU:h_VX뼙f]޻#t(7K.)~/$P@*UWޮ>BwŃK.YzqjI.S;˯xJ)6Y7Zm#Y^F*V᠘EEFŒK=&BG띫НX2vn_w}S't #dڟVЛ m^%Ty|jqE;[AF{ +mlKo7/W؄-eܼ,έvHf*00cTh~ 4Cټ8'VZcv #Tn/B{=r}{Jcrޱkm~l[U/` ;Z:Ҵ6_b0k(=z's9Hs#ͳe2BK;K`ɓ:ʶ^ v7YԪ[,ZSͿ3#F^cDh56?U/ݏ>KBd|k3\rI3ݴ6^|W/$B!2oUDd"B!2o:ȼzh ""롡P̛"B!2o:ȼzh ""롡P̛ +éH!%4t:O+:4L_ uiJhN"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B"!@"D!BD B4NQ[ DTO/P"D!B! +uCdxY7=D(@֍G +uCdxY7=D(@֍G +uCdxY7= +"dB[`حI[ZrGȺoՋ3zxvĭߪ۫73tMީs;0Bmj#4[UjF +eUC>Pr뚑F +!u?D\l]q85B{v^w)iyșK}[ۛ,~/!z3q0έ1B7u-GvO+]gd%1wy6Κ<ˀuS;R s i3U[ѳvjF'Ԏ)_gțBoz#%yos)B~yz-P%P̽LL0uv_=^>@SZm~lSۼ-nȮzw7rO$y3Fq~P^rfݬwomX:] I"s/3ѳ_>{TF;837/ 2 P7=4=M=~㶌Pv9L$^ѳ_?{k`BQFIR!Bh&g莇\,"B#B*[]376|ֺڸlartm!TX+mv` #dܘX;8>ܵ^BDHQ9FΰM9薛:Y׻ !e=n<"I3>rj!)E縵QxYDYDYnNEŪN:BYrpDDȘ;apDDȘS#"BOOcpDDϟ>stream +H c6f mIڲ&nnmDX,__ ܓ˝IVB!B!B!B!~sg EI&CBKܒg$r.]lşO +!AS*.Kf>Ͳ3M]k`|zd3$SR$ cm;/17,xsM!B!B!B!B!Bz3؝N 9ŒΈ@ ČΈ@ ČΈ@ ČΈ@ ČΈ@ hgbg %D @ I$3 (PH$ + 4A23%D @ I$3 (PH$ + 4A23%D @ I$3 (PH$ + 4FH($LIXr"QL 3m\I=tgJD2A&ptSMC[?WbFqE@ (`P&HSG흫K]X"QL \jY,~i(`P&H٫mO\(`P&H_7Vsn{NM(C+1AF($^_r1DhઽKjl>d]r15RsU?o \V윃-q7.ԣh:>$QGSos'=oO}#y]T.&v=tĶGl>ӝK}p:-Tůwaߎxe6盈 Q'XM:vD)ҺNQAʘAn7^HtVo˨ @YM\vIfANJ?]KV&e\If}Ql2)}Ks%k[ pR[Ŏ竤۞pAF"[eqMKs_>r] @Y,xy]v;v✨ZQ=S\:g5UTT4m{z.wk({a'T>stream +HcӸ']h[Z|Ǎr?$YNM%!Yl?_1B#):2hӝՕDXt%J8XgXGbFDL;zy{,Cgo9{z (K% +bDX@,Q (q]Yzx5>%{K 6@l ,X'#g~O` ƞjLPPll{|] ,YF(+F +ׄO`ubnV;V謖1>5o27S1T%+ZZT6O*ݽ|]Gai38ĶɣEWH)c4};fl4tX2K/ِg̑@CA2;?蟌Tcr2ZQA+vZ~MWm Bݛ<@l{běnC!Orq |/ۊWlJJerp Bg ݡգ-ؓbqW82>aVٰ Q\W~{vOfo+έmꊋMd'<VI:{fyxr[<ݭ_''IfAFxՉ"nYjdlsf2\WΕGXYdkCbw#숭quWeρdXs[+ww*V]6!v.iYP 'ؾS\{Oc3 v+^Wӝt$UMbs͓,8j6F>%Zm2}|c럶lR;L_YшMf m;Lb"M|~=J9c4MWڈT6@P̄˻8{cq@M + |/+b?ƒqer@wPO̪bLIbF^eV؛0Zy}ǞoQSVA+z4}6]1dV-Mn6Yy^~pMԂgG챭%Vtk'dG,-K:1֊&Sq4NŬi*f.2ZQ'vZ~MWm Bݛ<@SZ;,Ċ7- +B,;*V_)*bi9X=.VxՊ.)6uE&Nf$ \\ƚxֱ@MۛŬXDssWʐ/5[79?Hf/[b=ڿb.vhUV<ƶbk6¯Bw{uG;bj'^Օ4>Ew !VJ+U&Uw2+b;^X=.Vf.^֘s9Ot"+3gLئ(Dv#^l#7~WU^>O4#zŖQι8hڔ=BT->G5/wqXiՈT/Qϣز?4e3_T(~[ ϣam&'f~;u[~kbF^e67Ãۏ|qN`=ɵ*<]w NU#vKI>7mcO[XO|, IݨbO|/ Jk.Fyk1wPb&'$eڅHea `m\rjb#+,?N.FB|>F.X%>Bi>e_b98b%\pw/u~SQ(ak?qbDX@,Q (K% +bDX,@,Q (K% +bb)5rF\؈fmχoCE= t;m @t +endstream endobj 147 0 obj <>stream +H엱Yyu% (Xh. 6tpb3N.3 O,,ϸ^U{{RtzUI1(zp `7 z `7 z `7 z `7ft78Z>2uѻb!DZ/qkNUGзR> QOzGd,ۖG(kJȽ̯.D"SڇڥQ9n3ͼАB j9ol>a{]O9E{vf+?*:OKr?QsmTJ+ekhɳƞ4(Өsr {+qDkݍ.郩6= G<:Rˏһ|xJz۞*cuCg׏ɫ5WQ&{S; "3mFq3"Ruˡ0I5jKa~O{"תfGV^=7":wKIV)j|kRW1:q|Fq><%ftˢ) +&^Bu;z'{&kZX#u9ӫZ_ + E2)wҨ\VqJ0t7 +zK1َ%O6qzLosDlꝚj[]Olt<'<̯w zzb+UAWl 5-=K^ڽz+z8P{\OIG-FzsQXnΩ}KbݪN)0'Z~mݎn)z:ޅIf3ޥ!;žw1`7o8[f:{hzOJz l0U'߁r%WOyiORstQ>Bo1Fwm>' fޫ# .>[CS8wbD /N:j9<;H Kq%A@o0 A@o0 A@o0 A@o0 A@o0 Al6C`.A@o0 A@o0 sޝPt 1ٻH!5-*eoz1=Pz7X7]Qdop w\ sD8YJ_Ð旌dwۆE#B_W˙x.COY: 5-t ֣TҁpX;ґPX+ª߿zt( 6!X~0 ~vX@){P}uۥ!&пo*|t4 V6ʗ G`}z^h_/}֤wd>?V꿋n5#r_j__2pI/ 5c_Ͼ[,k'?U~?f`@Vϔw[$kϷufh@IN~{"gMzlzߟX"pZ~gMz{I۫G`MzWwOv4 V'__9k}рX޿x}h@Igkn{//_1pI_8G_-c|~I84Ef{wuzff7H0"E+FC>aHs!F4K"T *wGnvHw{ğ^I.ss'XiP*p{N9BJC$woaYMgכ5ro}-\mkujɋכ1%KX*,T⥠mK%KX5w(lls7. Zo]ք X+K5L3PBmDa +MD2 wްY>3Ԫ=ـmN$z[Ya[1ӂpˎ3!lw"՛Gl %?9ܟHV.7T!@~u95GabOsM=Uka_~JC$8]=PHqp3̑4Dޟ ~J NzvC3/i'Bh[5GAbޟ (^!Ɵ8]a&qgflGo!@mہ5` z ;sHR)99~2 t~k䝏 +bHЛug8'g$:ׄs]4DoK~@i'?/}O~!@~Gra9IC$8mhLr4D_̋| %35G1$Lo]~/uN~*Ո&Nz”~01&Nzξ5cKT ;s 1$Rov~U$ƒ8=WQA JcHBfYw,JazT7YMg2d1gY=ׅJīi$օSmز1uΘ{XossM0pbf=m, \S1tabLhYBoW@hLr`Y5w﯂V4|41J{ʦ7{fl9N{F]u'NȻwݴe#if +[Nн*^ꪨNěÉٻ7Y͜Ul[Iy"]{Q7cBSQ}"ݪZUCuUu[j@m-],oٶ]e|CY2]eXw}:h JZ1$hٲ(I bT؃z[-CKc .e; /Y[J- Jq_o;kYfc+]ԖwօSm}05q|[u=T݈ zV/p|Gy;PމnUQ0 YcVߊAoּ"{W M,c4iO F7"Z|g|5RG].ݫ.J;"J̶ҚfVQ8z3gE=GDG.բ+8Fa4-.b5$"b1ZVkM8tw>ZG"|=9V}}>p3wZࣷ+eN~~BI7c%Ǩ`-+=yX&fSٻfUm7{<+^qPJ#CveB/GԊqdz3g]=FnL`w6m8WS- -O6Oss' 6znW7kLpz׻6|z'ˏq8 ApbԞS[W“b{_=8!sIY| 1Tt[_yq BDp[3-,-Ƭ'xjm"B2szaxo='(2#w͜'xvtY|iKeGo:)O]OL٣R~f x ،(!Is?7MDH7lv t{/b&"$?ENz~kmD$qz_x< b%"$K[N"B[s/8mr%ބ'xJ"Bmɳzf /lzٟۚQFŝ'}UIJesFTor&!?"_ d;Q$@-~ +Nkޝ=ODHw]|uHz@a7HzZ2i΄'p"B[ƇI=^=N me*N#<]V&"$ NWfdi3w$ޛNmtJ%-S6v)xO8JDHWns+ ?IDHw,LNQg߹ޔҚvv!!T%! 4FўCZ(ijDs.1Xg<]B$^{L?޽[uv%i13Rm^)GKO()ZNe 4vP 0/P F!%WI:G&eʍ+ȦJa[/fX5RaxUp ;ˉlYwNK6&H'K;yݛ,/v#7՜$-/<;:Siϲv3cUFp|䞰޽UuBY3*˻2K/u?tn\qHy[)Y)`+hc%q=eT)6)~7`3L Zn )"/5?L4Zhm"6Y{nh{eS†`m{J`_>g= =eahP)HyrȌ{J}ɳSD{?"qjº4=/}QϽ7籲 rOa5of}7JЎc`kS:xmbg9񄲚YInoZneѫ\6OwHEnt;o0|m{iuOi{wo՗;KAi촃bHX)n +{ޡ\Cy $)yݛ,e:Rz(M{y +k_QG!,;ھ2[Z +wtmš3,籲T_uO)o*=ƣ%7 ܊Hyo)U=vY7T& {J>w)MtZEmŶȼMy/!"Ro[3S&9Dc`g7ֺ-WŊbOylkN-^R9O("} [_P{b=%_ B5ؿKzxuuO*=EG1S2dS})!RwXW P8bcD##R`N C)V`81Ii~쏂M3(z`-FcDq{"6@:=%-7"= ++օt)`?:҉X,C`M@zK4r̵ 7ؿ +ܟp[0XTx4_Ҙ'>/cDb$6n @?$Rc`^9<y/7nofD؏W`|2,75n>98F~_)R`ؿ&%"}_)69*H ؿ)Rg`!_A?RςC`zãHy?/9<2)?=t#aі5oy=q Z#ٗ5Ef#wLNcؿ ~ͼ#4%BzI6ؿ_/OYϓNc'4Y?J?Ri_9޴gAM$v)~ͼ5gӎcؿ( }gH~Hy9y\`?"g`"O? C#e&`Q-"/c#E{ +/'" O#~?P| ++`iKwG?^ρ^^2om?sxy~G``2o1D?R#u*HyG ϒ! +qxHA 쟤i3zNў忴AͼUUW=h1~y{| +sO!KފD6oIgvoΥc;D&ͼ!Y$b-dޒF-)`dޒF-)`dޒF-)`dޒF-)`~? /[RzEѐFԮGO!,Jޚ x[U婇CJd6oJ}WUg { `g&lleMgG}#]ۣey_ɻ+.us?Z-q 777777777777-} j$cDw ^F%[^f{2[}+au[yf򾎼Kj}Ǟ6l޼o~򾌼Kr39Lu-|le=ޞw9n6x~G=xg>f9w}?y_Gyg5ogm]7ya%u a a a a a a a a a a a a a a˲D_pVo#o#o#o#o#o#o#o#o#o󼿢ɷB +endstream endobj 143 0 obj [/Indexed/DeviceRGB 219 183 0 R] endobj 183 0 obj <>stream +ߪߩߩߨާަޥݥݤݣݣܢܡܠܠ۟۞۞۝ڜڛٚٚٙ٘ؗؗؖؕהדד֑֒֐ՏՎՍԌԌԋԊӉӈ҇҆҆хфууЂЁЀ~}|{zyxxwvvuttsrqponmmlkkjiihgffedcbba`_^]\[[ZYXWWVUTSRQPO +endstream endobj 142 0 obj [/Indexed/DeviceRGB 86 184 0 R] endobj 184 0 obj <>stream +}X}0XX0}}}}}}0X}00xxxwwwuulhZXXXX}}X0}X0XX00RQPONNNNMMMMLLL@@@8884440}0v0X00}00X000/w/v/u-v-u,t*s*s)r)q$o$n#n###"h"hcW~%/7P +endstream endobj 141 0 obj [/Indexed/DeviceRGB 48 185 0 R] endobj 185 0 obj <>stream +}X}0XX0}}}}}}0X}00xxxwwwXXXX}}X0}X0XX00NNNMMMLLL@@@8884440}0X00}00X000###c +endstream endobj 140 0 obj [/Indexed/DeviceRGB 62 186 0 R] endobj 186 0 obj <>stream +θxxxwwwuusclhZQPONNNNMMMMLLLL@@@:~8884440v/w/v/v/u-v-u,t*s*s)r)q$o$n#n###cccW~ +endstream endobj 132 0 obj <>stream +HWk ޿>n$~Bdw !Ll'NB~s;,I%s~żaf^3ѿWx??06z55Xc~Mr4l> ^=~WUG`B=Ӛ_̯cGJ Q42u&Cb?>2p~ ~qc +q8Qr.ڍ<Ȧa;Wp[> 4(ny58C=1Ŷ="o?4S^YgG(.OOOXsYP#EȴG [? ; +I<Fl?w ;A +8zqV1Is$UpvďvՖFA5 +gm0]?3~ +x˹vb pQ-005&]=|=ctɘ9EgaG +r={sбb_lfQux! ^^-8C؜)/wNKOg_ۘCxōqFƋm*h +Lov81m?!;Dp3 Z?N'H =pӘ|OoR* NJ;(x ~0NFQ˶SׅqA9:;Ă<;3,'9v\y7 +3@rvB9?*n%'lxɩ DM..z~y!3!i"/N`g"ڙl)*l}q' szL)#(Ї;C)5`8;KtF |Rȴ@;U@R+kBǚ7wg rfDDSLd}y\E":vz [Y<!6 pAYe>gu]egn K⾉ e߲kݸH+5#j;y^$[6490*rUp/XԞEvgP %2a$_EZ@+I|lM-(;?W7 h-S4/Q-{ѯ^Z|: X^}6M@ 2J(|Xʭ?k~0O#B wTsZOEw萈REm=Sum j< ]5Q-rЄ14OLbBVv)ݓ_%+׸ ΋[чMLy1'q'e}G73UptLqUDRsH9˜G׎.ZB')t\Q_ 0tWp`Zmi~DnE_$QvA2vCAdBZ2 {3/.N =F yN"@>a,a>~ -;FAmd͘Pf5Yh]l\Ս-訌%:q_]o!eq8ծ)fuҺe]aC&˙VC {yA+uy^,;G6h@NT"! +endstream endobj 133 0 obj <> endobj 137 0 obj <>stream +8;Z\7]lKl%&8&(#rB13^2"%Qj,=&)g.Slau;@aA.Pij[eda>u^4EFNrF\[G+&s?X> +&;`RG1i';uqe>_;K`pmtlTsaFV"&3sV'dh66j$Q8q$l:a^46lUO*mF8,>DCpWo%O/ +IFq5_4P$32[cJG2dfq``+tD)`@kNkh7?o(Mgb*tE4Cf^)fPI.<'R)Kd`Va0?L<)bf +9!-r8RoSplp&8uZ=fI%opZ"k>Jncm7L%0(qL[8r`RdS1:J3WRd[TPa3T]VuegJC(W +qQblG=;2sV>$A!Z:ea-kY4fjZ:bhK2A=/aQrpE/+>P,HRcM?.jrJj1J2"?rHa_Re^ +>e]oUc>4F?]gKd(P>YnJ7F69:]C:GipWQ65F0?^C6>f/5LTYD'P_#To;2\d-ffhNC +?/#CE9UPV(8&$b:3AU_a$Xj0jW/k(mrcY,LrNds.<'@J;fd +endstream endobj 134 0 obj <>>>/Subtype/Form>>stream +0.922 0.427 0.396 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 160.5998 508.1125 cm +0 0 m +88.092 -175.92 l +-121.187 -73.838 l +h +f* +Q + +endstream endobj 135 0 obj <>>>/Subtype/Form>>stream +0.514 0.745 0.91 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 167.3349 566.5065 cm +0 0 m +315.984 -120.537 l +-46.905 -217.983 l +h +f* +Q + +endstream endobj 136 0 obj <>/Filter/FlateDecode/Height 298/Intent/Perceptual/Length 27033/Name/X/SMask 189 0 R/Subtype/Image/Type/XObject/Width 523>>stream +HyXgy}TB)*x+EE얂AmV@E(HbVND.!@p!ɐcLffsxOZ 5ϓ?w!K(`ޑ*4&+@I& zMS(;U9F4w7T]cֱ2rx/ ({N٨f;"2ڱ1Ye{HzNޯ(2bB}#G>Wp<"`SiN En^غ!ZjP̼!mK[zEǷ:8Q"s!p:_i'Kr}UdۍvN8̗@E$IQkT7:zɅ~K,~VQ~Sދ)nQ৾0۷b*D=бo?34gTP}rN )Rl3YzJbwucyu4,.%fITNI?j"Wf^joo/++Rn 64 .'ؙUUי5ML^ZX]ɭ]PyXڟcudn[q,l]sxaLv_˕.E%YYYE8{KҢƟ`!"1%6Ĥci +nd$&$&'M.Iw,69\>{H\$!Fb ч<gr t3>@h3>@h3>@h3>@h3>@h1$),,$IϬ@ +C&?GR B ]jAqssCD9A*ji ]L?v6.z($|/+DrbSسBrrA^x@ %BPSpppx|acc|ȑ$<.[qo:Lz;^rc|V_h{)#B,BDUnFBf4w@+7&.#lOTT4I" pZʫN(w3Lqj;C2>/A ŨP޲+hRuS7睿`yb%mVEhaxZ? pShwxO6 50][eg: M,|6ġ=q&??3jy9uMq2fU!듦19UTed1p&0E0C//R L;51>ugƿ3",GWh)oxK&z.T~/欍]l}ovb\7_A CQloϕp>5MN-.1,P"}8h.*cb0z^:8*EWB ]aXZzzOYhTNhnn~'|CyJTaxZy{Ya'{0l~#u \9~ŚȮii&*<˩$Fp\K NG<: ,ZΊOxxyѭCTJgf~~=u*[k=xA[Yўd(Z__ݻ|LBB9R.jҌ}E7p5y;UPr3<~5'Yt,%VҖF1=Y|IHzyXX@ h$b^9ȑF5 ˟sE1$P~[ggz7 oMOLlj@hK z${tΕ>g"qh}DӔZ\} +{%] G{E] TKSmL;jѤYEx~LjF |Vp ]]i7LIj*=p@h1$D(F>c@ @\rHP@RiuCsk[-cU|rX\*F~5uq\vlǺ~iުq-"N]twn--UV8UPL0E.X@"RQLHȕK8p|`ޜ<{sEI=/5l(B.'#LZ-Њ jET*T[NDvv/&'x+%@4E|߳a JHN4Ւ3?Iv` + EoE缵5Z~pEkoPe%F?B[ ;G  QQ@0w%:^m#Q~9w B0""bejjZR) +2L*׿ڊYoe#7mڴy/Lذa˷ׇ6lᠨ(O +l|~ǵ) KK+Ec뎆'$/W#n*{uw/sAҮV&RՑҌ+5Y;,)))gL8} + + +rrr322RSSI0<3{(.7ɓ'CM8~ÇY+BښvĺuHgxX ZE~7 BV[kDo:DVT/OytݠJÊ:j ?ZQn̠Ԗ1@`))ׯ_?zmLC;$$d̙\.e靚6e˖M wVaco 'anlOJբ/'{aiaEoe;gVs(ֹ +E4C@YmÇ +˦@sssSSAMMMQQѭ[|>N~ӈ>xข` a(u66?8񆱷 1رc{1C9C b4ٶm)uuuPQor[Je$IoJ՚ކ|ZXyl^L4x՝4Ͼ:'S]$Nq˒;(?%Z9L0PzJ%H***pX0G=e9NRRRrr2JjjjZZ>efffgg߾};''yyy + ݻ.\M>e**b1U[[ۡC=qww3ˣ)/GCoVt1&7&&&:TČ퀮 W@bFfTtS>@%{KȎ{/n5)m?sҦ$\;m@Zn.Grrl/LX +/Nપqqq:",, '6>{xxN.]rrrzm$rs3 +ǏG(>fc,8JHoA-Fcy~IW;$Izۛ*D5mPzBRY&nh +qUI" +ގJb&B룹v>D{PtSRRKKKS R)qzp3컶ҙx1RǽJ ~,hz3 b*A[tvvرhqcM0|Mll,>.dxӇYNf`1==-((-A!bBz?f>t냂&BDDDVVVyy9T*" ILwǣ2Xtdnc?.9n鲻x1zC۱rq"t& -m-T#O +EhֵPJ[o~_B~w}ߩYbANXh4`1:8]!`@X +P㰷7 *J$ڵk !e2B1lXA7SUZkKhG+,,T{/OꑻLC6V^"@a^tiΝi/TVVjM&: TuTލXBbZp0IѠwߥRO=ri X  $l;;;>|əLLLܷo_DDDLL̹Y<s9ra|>R*8ڷJ緐`nCp ܜ""EQF}"l3ǥ + + +`A餤0 + Y X tcmm-ԣ@ pQCff&X`0LNNrs1Μ.zdBkR>#"82A p@pBFFFnnnSSb:]zX#O|zN.& + +wzTVfR8$xDBGnA +A׫jB! +;۷oWaZJ..iUoz{>5x\IXQ;vIO܄":??.jJMMMCCC+[ 3TV"__~sp^(X,F6o - X! addX" _$//O uR|R ?W,`R8I#@L㏩6߂"K4}}}^x:n5\OgDHPX2-w `r{`Ѩj޽; nR(\F#w7UhMMM3>G.gמ DUNLLL T*L.pVP(///\upORZ_1`llL*K'=bpYʹu+DAV=111}Hg5DQud">ލ݊ +z|S97l@f3;A@AX$$$8q"ʉ`3(=zh}$7Y )g+e(+" i UUUbtmFU?so X^^RbMLFQQA@AXvmC +"""l6s#::oS /ܞ@P(RiÁw<7Ce}}sPoٖ aaنJH$:p@ddE'?uLASGR' , cRtwwޡn܈FF 6CH¿p_N ?~*J] x{YC.?'1!>>>2DcAV(3;.)H\N "Np:}5Ûr^7o/} 0F;{l/ bk)WeO>S之II}|.k1a%jd.j:r``vV,#U*:XR&sp0^ _8[i=Z{15X(:ƍ%%%N6˘rl2j$33~X20D?w NfKLov7c^ +P5dgg;痗wuuMLLpsٓʔXFZV\N?D d +0ƍTfxu8'[:_I{!^1/DB__BpQ5X,v$` :s~(Lfعv-:A)k|ltӧDGGPAAX 28&!77WvU ,Ԟ=TӾ**HFܻwC g>%%s"Z[wՔYd^1/Def5lM@ H1ѶmTǏ1ξsL&(5Dr2|wFL彷! ,CPO<.jSR4 @j5j~RpjA;q0'7GΞ,qˮ  +a4kkkr9ǣ ^444 5\\ttM}=40q6@?JQK ؁q0'p 7Ӯ]Kgzj igδ(u3y7q EFaAMA}74ȳhlnnf4h t: Skqj?|**ӦYڬ_)8 &:; )eYIpyſռ7,\p9[X*qqJq 6xxxX;66v$%% xV:~c˃cDNNi!bpмtE96rRdᢥۊZ`ЩQUF^b6MȊv AC^A@(A&[ìZ +}>eN:h4ADE^` +9jEK/brRdVUj @=j/p_oޖJFbbr2=!1sqt1&&&qW|C7ؙV.\NVDӛF&&¥N@ |@ikk۴i +RTTkSDr#vhoo𡍬Q\-ʧNB$AA`oB /YlvҩD+>p$Gk?:A8 Z[[ALx n +.$'5{ KT뙖Sm,ʧL1s8䔥 Z+oVnip:𕂖#~+٭L21d 򛍥/ޒ(D'_\,. 4T*1'O|`j?ĝ;A\A0Li},_|LPs h+<ѯt%NDˡUܳ^n~q»o.z#_Dv,[_/D0{Ƭʽo$e\SSS(@ 8ʜ67Ν;;W^^NɌb2AE(! Rv9ᅎpRjD"QEEo/q]~z?q}>'Xpso]l])^Z-=dB8kxne4=>Ԅ/e40m_̟3ăc0 3WRRA Eѡ!0[J|IpURNe1@"?%zjZTty`9+jG_drv[>76|wٌ̌2 Hy]'28]CؑA{dpqt{7B u:\.8RG^̙'??z, + EABQUWWU)1 R9~`xHHHhhhppȧaM`GmfZ:n@7 /?W3`EK19yM`C5<.-!!%P/  ;d2% HT |0ԩ;wC"f6 +"(x~(ZùSP]/Qy,diV0 +hG`4kkkY,SܺuKTOxk]¡[itPT$߼PcfQ^eDUwt B:RegglKt0&@%vC]XXh=}T{66^M(1ey|q)t{_ .;YƸ@ 8'$$ND"ASWgk[8z5H$V C` {gR ~ӗ&c'hR'77x!fsE:z7Fd <(/_NLj Bs#5qfpO +Yd b?b&IkkkAZ; + +l 6, YC||<6vS*m]\HHAAZ>sؿر.>pq RP( +h4ZqqL&wbKV< r9bە%FIAj岞ەZ{/ FV`0䈦&NgW+8&`u†z>33z7gL=,$A \B1k~L6}cte 40LP$''̊׮]3 T<˗mq6vڋt{CJD boަ!#=`'hx*J$h4OHH`X(R-dm=R)qhiioXϘA@j BՔvV^~lsz*ke 4SAy<Ƀ +5B/QQ6/TvQagttgke2֊>X+bWVkwG +,,>p]b$"A"o؀B K{^|{w|ΏggOZbk"=>",JZۇc3X1A ء 0c!mii)f]bky{3eA<Gs2r7[M1NX{LӮ 1͍"mLQYYj0cڶrdՁZĞ͍xlO6^W>=z_B5!WvMŘ HWd2dԀa;> D"ֶZW^%TZԞl, +ǬV֦YwAJ tfTUUpH 3pJb1kۂ,!>o4=YLŃ"7ɥ:Nj Ϟ9}&bA@ЉIII9f^c8 5׹?=ȑ VRROaDRS)A$$l$M(Z,-"ܹL"SGE+SnԪm<淛cY$O>H$\.V@0S ;8-.QpG1}3Ťws?TPAVMkO==~|wFujY$WqBzv:ě5JP"^xr|T$HFG.U[g&+6 uVsCy<^qq^}:`CB`'/77l6OMʿx1Sy>z't:.:hęsS/򯖍`,y)H.ammm/_A$ףU˩6(VdhhhoS-c*AX/ȹ"3St,C}y† +ٵ:##lL.{֭Nd:`mᐥP(&fG*@>õM81Z.N?.e A87?T*MKK_*++A_; E۩V +* +j27J*Syªnܱ?$E矓ʯ-g%6 $ѣG+`WWWGIJ57r*@Sy| \#xJrB'=Zü$`(--p8dr\Lh\𻻻XOOAfszz:YP5Ğ=L"h7?ο|W_+Ap>0 ._Ҳ*++- t̝k?`}n8%htNf&%P@H_/[Ð 1HI֩}q"c8 w3R)vkkk% ,Zd?`Z!ill$3--;ɔ JEDž>>[7PUAp.**d륧_| +; bv-uNL~c /*COIa* A]Kidzsw)`9C pDIssd 1m ؆Al6\yk8T(xqFGƌ>nqH3PaUWWs8$F1QX7KSSb_5bnn S1LmFQf R$_٭}E{B bFݻw󋋋AN~R̄l6Z%붨\u^-o5~S1]^LvScǽE*+dUg_4Z_qٓ>'ͨTܓIݺ#A\, tb !+%xiSHH$/WnO~{ P,4X}|kMO~5uq|th;ctZ3]WQX ElwAdwwE6Z$@#ᆇD 1 $y']s9?~9g롕w$!1)6bW|zƨ%)jAJ#7.{PgL?p"qG${"tDfɨ=_1zFs(r&I/*ks98m68vXN0''4PyTV+ zmV_ԏuzE;:AzkskkY%Jg4*:{,L +bҁD"Fրľq:o+Vbdԋӧ|a%Et=uW2.n)("x6X40t>yuA!uM~VU;Rw6_-|ɻ=cօʡё=.xl曣ԐLJx<^UUh$(=]kcmvdڊ +y@2LW{ɵ3gXA,++B@Qp_sC/s&y;KnZw7(k#FuENku|j4gs2n;.5jxcقt:j"ܹsQN<1pr2 vFIH̙3fyt]],o;"Ê񩨨Zu褢]w^Vj^{uảg Ka@bכP> Gۇ?,<6/p"V}A9i葟J$$CĜ6;c&dmp̂P1^:e×zme iQDVt@:R7ZUJ`dX0);GV<,???AK@xymv4ӵ4mTj[[#&gݡ54 +.eFPDΡ-mB +žQ*W^]|Âظq#t$6edNcB.3L + +1Zqw8@QĨo+ZG +AGfXༀ͛ndrr挹R(Ә@ V{ f3Ϙaݡ¨>+Gc7blc\HA!)))82t:<%E v48 a`A}}}̙5A(ns>pvS6,<᳉"5uy;lc\HAP(JKK`0U*t$ /v^b6 ϖRPl7O#$Bmc\HA\.F'fD"V ;ɳ`o7W_ŌF؁pQ)))ry ""/AZE>NfΜ*2K61. X`AzzzOO}W)ڵ~ ; N[[q5RMMMowi0ͺB(bԎ(v75J#1 P,UUUST(<[; Pjj*QNeg[w_(@4׳gOFS#8δVL +.jHNN#ÁibCp_RզWJ ECuY hY\^Yc )ƾ,K;\p|٥{%zx`vSlgXΞ[wS(Pwo +ͭiT8Ƹx 444Y .A`#yij~os` @8zN.)NӺZ]gP(D;W8:.q[61. |>ŲCii\.7]HH*2d r_̺u£_xw"ie#WXAٯqq!a{j5ǣRv @b oS`@fbbbqԩs͂((Pw^mT&W(561. l l6R K]\{Zs96dHA Vbڧ陙v4| `1 ccQ"OcG B^WxT.ki5܏MSri*f2$5a&àfX Q4QR +"0  Њ"BWyP Z^m)-`)>i/~m|Q4?)y2H[׃Aj"))ZG @q2 ^?6[W_rt իWGDD'*2ծ]v"͂PHYaZ^%k}=.+<:q\i X4;B~~> V;h4aWL&dSL"(--g喯]k i77RDa2di@wܱ}v{gť=Vۙ`A6PW)‹F#T\)ȉ3HA%׬$ЄlHddzC @|@h s-`A «t:ݜ{ʣG;{5i09;[іCe0!,00U \.H31##''RK @@}dItq&%QTZZZ?A3|#0:t`D}eSaw`OdbNMMmhhy1c0vCB~K +LDL o<)PXݸq^Vf.Q = WX=}rEcia_`mllʢ!//b:ChDdvp@/3y绻[Rp/ + a$ (_9l*+~Rh1- (*-99Zrh嗉tJd6ggd)55zkjjl zKxLJ{1If[611J<`0 .MxRDLfO+ hxTGq+((P*ozh-Zt-ͯM4ǘ,0QEReff^rZG477c5`:wOBӌڲL`Ξ| .h\.k׮I7twInxcJ l ,,+"""<<J4!!!;;[&a;`:=2d-_NrtD/ +f3l6J@6CTs\#|>; ^A(sW5 {tX9`ALX`RiAAexbddd\\\qqqKKK^cb06qZl!$B!rt$|lh}}}ZZ7oެjUAU;s3bϱ" +uÞӱϟ+lPҜU`ALCcccff&rrrb1t: fhJ-)Kr2ZLp6;;;l&&&X/cDNL? + +8=+FNsW1%0TVV&''SPRRk, d[(fb2|MA444\~z~E8ڈ!A5N˖-sYfi[kTOHHL# [*v }*WWHy#2Ú5`- '˳\\\jDu递S* |8ԢJIIimmj@7NC#FF ^юZKbbb`{n8}dQB讻m_߀\aeH;Û#JRG}qF~_*~&+G+H=gϺ{#kL&ÐO,u X ^Hcc#u-B˓Jw2x1٢/G-C @~J>/Db''x<QQQ7n=pHHHPP}YLtd䩟iǾ89NtrmwDE/ͥעsxygO^L2|goTjHѐ:s!;%q` &R˭p***LG`faaqKģhfǏX{^Yzu_{KԈm| Z;R *Qnލ2ə9rOl)vGW +UGɫ+Zۂkg}Tv).he,ѪBku\t,"V""QcR  +@ yA 80wN3"A<˥R0/ ]6qqq0쀘+D2LiTT#`mp!`Ǯ\XXH `*D"D*Sb/9dz;:rk4~ֱjitV6kVdV.gIѮyoVn7PثbZ L6p ˆ}| uU7n܆I lm_Bg'Ex}?܆I |~qqqׯ_///we",I[e jV{Y!b}#TT8a)"6N"쐔`0d2C*d2s( n"ػXXwNރ*SH۪i?>p%A3Wpo^p3X쐘(0lxD` T5TZ f3{D߆B%ls~+$29.}>6L2 +**CF‡"1r`d_~ wVz Ƽ@ i6`J$bo0d4RThjp8QQQ:;$$$+Et%`~OAf&&`hk$O~ +%<; D{B3WV$md2 B&fjIKK 9}Gxx8CFF5@LHJ@&5vMs'HHwj 2R VE)BVꨱ>?xy77eyyyh7QM ;0~5 $kC+S>FCb"|4#ަw*b?a?i *lt_0o߾Ḻb(I:Ӥ YM74Ұ 'NH$fhfG !P1/~b&$x.v z{{n (NӇ` _8n\ooq'k8a! ø\nrr/qvvF@ ܻ@@8y @|<2'h!D8aI h&CcHDtbB ȱ:Ffnm{-8a.BDPbbb#T*Vn@SYŻ'Raz:MhA(AH$b1ѭ!΂h.`勗,[񉝽 ߓpkcL\A|hc;4Rn @LpϜ;YNInm(Z=00@b ɭe^c:8ڛU_V4Ƌ4 +oVCrQYCKtPU Z6 -Ѝ)\B J1v/!!Wĉ~qH/$_b {4<?V"t:Imu())ys@9m[kaN\ +0###$4\zU׻\.M""v ?Ob}HIFï`zRJ@|_[1)YAܬT*x߿ 9z:HVR⍜ǮXhc,IL&? dwbF gG?~;sVb޽{_Z=88(\ +DQ)ns p8u(--l@*9e8^\\̯^w:@@ ,@T*~FC 3E`2fggQ/B +ATZ,eR!`Yj{{{QHB2 IW^֡dtta@X8n||;nJ !$Ij-((סh Ary4 2.H2 K }1a?yBD334P~7% D hkk/Jl6cqѤD 8{GzA~~f9C @lu3ߣ`g"= 兪@]8sJC%BZldyHgvFq/yE:ç;s=&d?=9]? +cSܲt_?c̻~6?:;h4Q TG;ǟhYSۿ{6njKk?YܓZYd2v +q||X@@bvYs gyawo~< Mmɖ'm\[۪uw'ֽQppk+9WFFF_O,(~ʺDE[=>8fto3Clc:Ԛy[ϱQw.`;5}Lqga|5^{S]a6\~lذa߾}%tA0?>[X4i:iTfʼt_i.9} WN~S%SvιϏMo}36!999'Ns){ ,[Zl$Pjh 䯘LJkp瞰LAGsNgh8leN@!ɤT*ut eND@ ,1Ǒ"EH$s$!`)(ZCe;'@" ^-dq2L +"\^SSp8PHW f/d  A64M[,JůCYYyE6č +w\>Od2~ܹHF\Hr-X󻻻H^rl6+hq֭ eE  u(*ZR +xě 1`ƍyR! 6dqx<*ZZZ8jND@ A`0۫T*idvuԃ@.!Z\Hu@xx + 6 + QX,*… ϟ}^N7110c$Zj۶mp֭[W^MJqc$by/ڲe˗8@@ b4vz4 ^ )hA bdڵ_sN%hA b,;88844d65<0ԣӆ!t@@ !Hg!t8}KY:c#-\B`Y,lv7_s[4DDs*gi6p\ڱ"K53vgt[;nӱ+޵ErAE墀T @*jAE)RE!bD \%- $pK Bn'MN/)9's~yp%p@s<^O/p|F[>H=_U˭u%\Z{`CCOK_u*6L_fg⹦R+ +a̐jkk0X/@(x<@@ PrX`.'Lb @@Jrjjb $Vj@,LǕsJݻG?'XrL__H$"U__al6@* + w$. +8rX`> cr  BA@@@fnCyyԸ +bFQ&g&&&FGGa}d2&' ^j0Hr + TO kEbɁ"yDB(G;8aE^2i $.z):%\r%~"Fƨc灳 ?2(8fZ?aĊ;n@0tfRwOLm0p5Oz3 +:{M&ݘ/PuξKFgQ `WfZ~Q럽*j e&sLhTzdfUnx xQhQ7%2+P@ N[͚@د؝awufBIfz$p`BF8aJ*K `!b{a{Qx`[1Gg`_n'pDfB[ŔmeVzgU/&C +(8wt{s4SSM_onW}NȠN*BCK2kgGY'QdzbѸ֮nӣ}"w„U 8xrv{ ȜA%S!Y;PD+a(]#>)ɩݾBaooky{7i0ͤ FθM8HKt?v  +L:I<3sEu! ZhdJ a&I ڍ2NdiyEH`qo${WV)N ӟ=۬8N-Ns`*+/Z +'H:eK9H <aanp_5>]q|հ,I[ltUSP(ʦll鯈۳ kN?VWsX놛xST2V=ң'ZM6{]PPیcߢjA-,rb_# BP_i_$T澃38ý- [$W){6+ZA?Wh3ձ IAg ;6O贪!QZg`߯>V[ék[!z׽SQ>ĬOw]Es|? u%_P(Y A]%=Tڦ`Z/̎JojT!nR +0y?>nQ9 AyEE'xGB{/)V)d鵽SPQX5y@z.*yH "fֶUѩTVd|mvל:+5 +Qѕ̨LjjK.1o5>)yg5̀pt)#=韚/h>Y$lQ3۝WPtSE~rl> †JϧQ}}u W"^]q}ZtD~4$MSHh9)X7!b7Mt  prAqJ^O`yZCTtJ؟;&,-;\'H\D9d%p(C'[UV..AMGJXХو<||? LS[ׅߚCq>10O ̎!QY|ʄ HOȪO-({󷷞h6\šV'0WvrvBk˷[`PX8f(L .-Аȕ*P1m_=> Ct:q~J1(ԉ~)J{ef+Ff̬aF=6(/gƸՒGՆq z>9 + S[?eVQ܎ ¥}SJ=n?źH +F>fM3)Wr  0g_&+k+v_P$a T#Μ};+!0Dek.Nmq9YLޘ&9C?R̪=cf<˞h/kԵJn=\AJq9i.w0EjsjA#uXlHܾ)3@NҨA$'wUa`Oisd*̦!RXLIe{׬lz*KFNVw|iqe:)HaI+O.v )4 ~ .?pyil(+-ᕤkUA2Ah[sK]LOcYN[.Ϥe&MkOj&&=v164k**wFנXM |UGڅ4+FUX%E_MƱ: Ԩ3jzp9Wa0uؠQ0S7,Z-9`t +endstream endobj 189 0 obj <>/Filter/FlateDecode/Height 298/Intent/Perceptual/Length 176/Name/X/Subtype/Image/Type/XObject/Width 523>>stream +H ]U<`8 +endstream endobj 188 0 obj <> endobj 187 0 obj <> endobj 5 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Thumb 192 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 6 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 197 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 7 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 202 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 8 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Thumb 212 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 9 0 obj <>/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>/XObject<>>>/Thumb 217 0 R/TrimBox[0.0 0.0 1190.55 841.89]/Type/Page>> endobj 213 0 obj <>stream +HWێ#I}W3RdDUTו+؝x!9{eWyě_Ûog;L<hпo~oyg8>{ɑIy֟PjgQes4,>)ß gZ+9$}b-'\]{ե^P[Զ{MLiFMu>3#xa˹vUwtLi&)]6!%3{]M#~@MɒOYNI}V0"9 1f>C,Š3B%io53bG-eK:-9& # vZ"|_oBS|)4 MB}9#}6XN')ш=; +у2zK/8/d3ȾhR\.٨(<Wd ?xIKjfU6 ./B0Pd/MڄVFx0PϚGBB Q!*? +l"fUGcWTLS018F}Ფ xk9F39\$.$8L(<3#6ԏ%zRW´m-ٹ-h'bV}-~u3mq}Lgbg˞v<y,cƆ8r\nk,1Ig8RgqhL)H\KH[Ƌ,&"1.}N\%C+4rwul-nBfނ{81E ;޲r#,kThhYsJ3/J[ kbuhC^" M%VZ/hGz"~ϋ6_(-&]և/襌t+BCv8B]-v^rBHN⦰zIyC OS߿UHRsgF)0*W5Vp??*,w=wRW黳U +趄[ci;R:O"З(Tuyog:u8RhN>/>L#L-iui!%Θe*=d +DƁjgf90&G]{"aɟ$A(VS @ww+įi8}yT9|: +O\B]{lt6!.xiB r<}|LVZV#%/J̳ݖw}ׂہҶMIQ\ʷw/I9%D_$Yac@ >Ika(&ŖԘr޵l}:A2g>](0As3|BÝ&sAͧo D ;g.lb'; Pꦀ}VV*/ r9mQCR>Iznd$c\?];VKdIrTP% +XDZv{'GXsԐz >γ8O)BJC)a=!+qYX2r~QSt'c3x?y;A,|]i1|м۔aw$Mr>*yYL=Y2yoF3KG/RwgjG;: nv,B]m4>\[[Ml)+QU 4C[Pg"6uX )b8bN 'leRK*t`G5|B.ZETq +NVC6 55J}WU݀+$TC@J~@~QﻔqUF> endobj 217 0 obj <>stream +8;ZD/4-H?m&>_:+A-^VS^l`&h+dn17$fm,bLG=S:9q:4!)`V7=@U3WX,pX`]O>+Q. +Xa+2Xa9K5$2#S#_59&^Y]9BlDf7s)At^=B\c?/@2PYf:1$ +#1KMqY$5-!reummWY_Rjep'7Vm8n21cNF5miLL77W70X/Vcc9gf?!AF,]FW>ZeV(6`#U@/89pJQMK+ +D\"$[$+aS!0;TFj;_0bZ]YZd?bR@Pi+jPp)@69QZUeD#!5095=<\I-A(a\`J.!_^N +*-3?"<\h>8nK)9'B?d>iT&qIro1k%&RWr[%d35*Pj;'.b^AV'mciR:W])?[5\YMf1=+bp/B_*m-fK9$n]>92d8G65rUPV-u&+&nZ7Ho)k +.rF,V_WF$Gq+8D\K2pN'G.0W7_;=XsSi[1>ASQAU#b=e(^Da\cQmC8@1i#Qf#%bjP +aLjIXPut;S.X/_AcPq7N#e_i-%N3o":PAkdW,]\)DZ6H2W]2~> +endstream endobj 216 0 obj <>>>/Subtype/Form>>stream +0.043 0.188 0.557 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 165.0288 513.1763 cm +0 0 m +143.396 -126.674 l +-92.73 -72.859 l +h +f* +Q + +endstream endobj 218 0 obj <> endobj 215 0 obj <> endobj 203 0 obj <>stream +HWk%I~E}:/9(.vDewUvԙU̺UUʌljwofM]/w׿=|q|G%!e 7_o * sCTlr MLsKE I'!J~)IcGۥxӯ.B )D!w|Drr . AĨoJDvB eӡCb +q[6b'|hn"ʰC?v Dx)簿xR_z۳_cy=] j]=Ս=vj7y{oZWlw&"X/^kSUǏw ?B:$;g1݇rr8 WjWxkdT h昫v)uX?9qqw]jEQFPM:WBBht伣vTX p꾈sz[SVQ7\N)%DFG`%f; JLDB>Χؠ؍ ]7*T8FG4CPOvdz z%HL@J"I9:8*jx=vw Cmd IuymuQ?(aFzEF%"sʢio<;Y2nL>Lnd6n~E=[J>^}["1R/Nu+WQJBUH.#4`u*Aڍ:k3iSLk(!9Y1?ë濫X^&piӄ!>{n),leenrM\u5YFzYwMyS n%~7t2>kSeWSN3{e5Y,n>B' I8"|XKWHB`F@V͔``̚2RfD` P*; %h4qި0qSb~$;1-L,J+@?2e!a-iv[rQ[gWW,>ft 5@.uA; {1`"w叻Xۯ]8H>8n\fqhڷ6(~-(C(/襖BZd3'(KW7QAZə!ᬂ8?:IT%:N YDZcDƪ&(%!N+ Skh*34\I)2c~7lZ%t6QvgH|ehtrp)mx_SKO#S~T/Jđ(]S_Izif.xW 7$c*B"#Y{wC6=<C½.DΧIhN=f Dp ?> +}%E1OS\.(Y7}^STUK1&~@J)KkW4<{R +PVw 'vC7F/y_ +ei(ሥpѯKMݖB\ғKI^?#9do?r׽{_A}Ӧ*,\^9$;1`OB:*~r@*6XV?Wy=j /%dC:wL>L,n\D\)zkaHNRp5!K?=]C܏Q;mm\0˷F~r݆k4A3ѝ{sȊ c8ѬsQ`sa +endstream endobj 204 0 obj <> endobj 212 0 obj <>stream +8;Z\7]5jZ#'QpshdP,\&/laamFr]6GT=V1R=-5KB^Hlf72*'5Bo^.L,4DNF44\?,_OAJ!:C\adXW55a$ +-0T'1B_g\g.fJnES;HI57UGRS:)8nS',,Q^sR4#@J3Xfdh#Mh<:;D_*P"7b)A1?b8EtOA/Bp8c:fPN +->MnHm*VsQG$\]\FA]O%:kh]0BXp7T/WanPRQ(OHM?peq%QdTNT/pEVST6.j%b8Pj +1#s#EPbD#jllGRDDcabU8`(t;(Cb3#MN#:e_olAN2p$f/j%bl +d<\ouMPE0.[;HPX>t*d6Qb/97\0o0\P]k6X4k.4Jh`[7=;JP7TI_YVoO+HQn2>ki] +kg>')"GAaL&$%)N44c$q*b/nckXfXO8%?&hWH)O+&7IK>#Z/1$6(fR-:U_i7?r?<7K2O +endstream endobj 206 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 32.1599993 663.5654297 613.0302473 cm +/Im0 Do +Q + +endstream endobj 207 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 61.1999986 663.5654297 552.5503065 cm +/Im0 Do +Q + +endstream endobj 208 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 38.1599991 663.5654297 515.1102645 cm +/Im0 Do +Q + +endstream endobj 209 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 54.2399988 663.5654297 461.5902624 cm +/Im0 Do +Q + +endstream endobj 210 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 20.1599995 663.5654297 443.1102641 cm +/Im0 Do +Q + +endstream endobj 211 0 obj <>/Filter/FlateDecode/Height 695/Intent/Perceptual/Length 95274/Name/X/Subtype/Image/Type/XObject/Width 1402>>stream +H]oFolћ~mzM 4Ͷ ^$i$~Cɶ,l.NUL>t$I:6PU@ +]88X(}I$i~?l8si"tähhU1n٧$IbW +b766ug+]lFG5ǟ$I\VâXǽb]^p,z ԈyG_}óϾQ$I'VX²Vo}jbm\)l\Ͻ04PXX3 *&Ͳ/a<nu9z$It k^Xz%0a-\]&Je{&gh=Q秗?.g}$Z:mz2a!\f\ n#`DM/~ϗn0"IqHeY  +0[2ŲVMJ~XT姗dr霛}F~( ݯݯ kaXRVq\g;'c=P"o<|6t*qIѐ&+c\v_0,aE\dXǚRb]pp&776N~LTc'<}q99k0ufMeRu2y4/lsOvoz'|eXoV%vNDS`kbiw_2a^9oRxPs@-)WNJ;׭ +w)aQ?alze;zH_]8WO~c4\n3 h\Cݚۖ;}Fm{ve۱KG|&8hԛ'b149FWrtG|}ONVİ(Jza\gp~A.4g^͗&b!|#^I4| '_xG^*Za)OG/NGnbtw|+w߄EqY_\źl.~[qwof4Gi%ҾRݽ5F:~tM$rcYyRNӑGy"پ[W2n薵ٸO_e?1,bKoqشvp~ (Njz4GFkhƕNmoLޤt߫vF5iw|LUR[ΚӑK6F_]"Eq8?Bs)Ozj?eT*2&iNίWt7M/dK蕪vxWé9< [~Cc~Xbt8 {=yG_VߵrQ?s0uHW[毱2MJ'5*U]xr˓t4ٲQ9ǽ鲧]nǍNY6ݶ(x[\g)mD/otJ7uŗێ-q}Q~Z>GsdYm|MC<KMo~7)}]Um~wxi?LNӑ~Ë_?te 3\pa߅f+Bp-qyբpk9r!Z?w|Q*8zA7)@v]oٮ88L/SO_So4tF'F#fehGwO=/g8e 3\pa-otJl/nWn˃.5`rj/M٪SN, z'oRx~c#RxC@g]cvH{ /q/ ˹0[3ʟvL@`!`2=KrM;:BT맿sFյݙL=y)ՇgV>ԵČ l!v=>yyS8ydRIEjA-!~lTbozB@ V'kȴ*·Jt1.,9OIg($D*"!06j0R?Vfj˃c2SĤ=8F~>/CJzAXdw.F//ђqqCjGë *7=H @%ud*E(vER줂֫'䤈"ilWGָ-#u}#΄>Y*|M}.VcVg{Mmj\{PǠ{S@HD%`#S)"Z:ıA5Mj2=;|v$w)*Hwgf-wK$>XRo]k uç< i&B#Bx mTboJB@ iuĿ\ /h{tϿؙg"HA N N\]ԇWO,,xTs)D~tw +8)bRhï>2C-ot;Bŗqq۾$ZS=kp7%TboB@ )(uĿc0*<5qgϒJC" 2L x'˓䤈Itq.F/ڨAtqbskL#"зe۾]qlLJW.)_Gyg)K44"@ RQ 1(suzpSٜ1AdU1 ͤeIuvOM"΄qN +tUc<fj)b"8އ}DJbS_D\_/ғt5Bb CEY]*G>NYA%! 2b\G$< kD-h=7Tv'up|tNN c6骽5q0S/LgK7bl}^ հ?Yk]*ْh84"@ RQ gQeT +ɳPs A+D&M6G^K_!9)]RrRqtUu[bX3u3}f#}h_=W3vrAv-h]:QPW/cOyG[Q% @HD1`#E$κ`t\\bt'Tǥ8 JּRZĹ1F( +|'EL7QDi&#wfQq=]'_dxΙoč^T.|'*}tqX\ WA1`&C/EAI4P$B s,"FB,LfϪ{y)1b=QM\bIGQ]KW ,2.fjf=YGn5׿˯XU¯74Ζ +c/aWM&{ @/ņ6ʕDw;"f{Z:P}Ɔ.7A`(Q\_kb<ųDm̵aWuD! E@ bhey8s˧pSw|9V +b=&0̹|'EL+%'*Nb4]\@{a ].,X*fccylN<)v~_X3,jXYe.yƚKKll6oC%gMq z+ղގJ17] ƛfMt'yOlZvUoT6X3[3j+xg=RF\]}NPXS;W }3禈 zViާx / >8"2EN?Z1 ^Ƙ&Cx|?7夈@xCMYN +lv1Y֪jJǝn+7GI˱!xjg~Nl75v(8`?2[Բjqq)WwAA *:帘.1 E@ bL:TF> + X t"s#9NzԲqR,]}`s˰K3P$B(-:TVTv &WcbM[ܧ3wRyb㡜[bExbA,,-=fÆƮ>XWKI4ɚn/IS(T6 ժx&]uccR\B?څGے +wDX_sA cnvc&@H(Fu8VuRWN"n5 3&T)lxKXMYnwR,]}<ӢwKv;2>A~'mo)y-Xhɛ͆p&`C%piAV|6gCN\.I 9A|ILțvK}/sS~.Has˰K3!@ o X*= oֵ2ZbF&4SZB%&O[+wt{'C9-*yߑBa bq5J VE<'O:YsiI6OJ*;-/ =؏0P; +`Kl {n +wDX_vA[] I aw(: jSvD&ddVjJK?6&Tw!Z*=%V-w?KW崨ݒ|G' ~T/aV@eai8?\y,0wJ`1JP``` A~;Kn +B7YRoo|h Mj9{WIۻP 쇰"ONzW;!i3b3椬(ya؝MLb hVQ&1DXnÓVuRbЕ:MnZԢɝMc.7ˍ@啔ҵݾ96r5I~3w5PWpт!Lv:=E38!Y)Ѩ81N35'7~Koy6c^vg5UUjSrYҖIHXjE Ի8V{Q^I)]kjY{]_ݝnNwq9noq8H !ṉBx|pxrY Abv2D7]l:<'w،9) x\O\fln>>I@ע\"grge,[ Ǽ0&& 1k4(^m@cҮ"},Ƀ|'V܎%ןڛ+P2H/պ,7zWRJךj֢vg[ j*?RnN)7'CS.K_*!O\ߕQVA[sRZ~ebfOB']r.VxFV'!I%-DقrV!u%[°;0@ Ѭl:FhڶH+&ՊB =*W " Ԃ-պ,7zWRJךj֢vgDܱ>ʇXeW1w5uK.B/ܫ# q&]%=}HoagflIi6/p,OS Y>opxɐC禜Q{AX°;0@ Ѭl:bjDӨv%`_XKr#Gy%tf-jo~FtwqMa2{ V_uZuW7Wsk}oYg'a^mmvt ,( S4a-mRa͊(?#6ckNJ3߭ '/VFdқi Rn- Qsjw1/ C @*fCZ|~UFܬV*bH<$ZB!wj]ro@=+)kM 5kQW}33TqJ7m/( Ỵ{:u>it|F[sR~ox.aF2}s<!ۻU}6|8-UiGW$s*E"aMcy1/ C @*f#Fa_4u<\^Iv<>:Ƀ %H6ۻ8V{Q^I)]kjY-HP~Fl֜foɺ5GN'p nd +q<$tzʩ,Hf=zЋ+9Kve[U!91/ C @*ft]<"Ơxg~AooC)q;FIH .պ,7zWRJךj֢v3*5'ћ ׫ryRq=sr#]>? IA1hCy lb@ F@cH6 =8Z@ l()^^M{{j]ro@=+)kM 5kQW |ψؚҌAup(<z =Ac_ -_oRȏF P°;0@ Ѭl:P#! 'JY 'R ƒg'?RXKr#Gy%tf-j8#B[sRn67ϟZa%6SFXg'haQ1/ C @*ƪXfԣRPu[W،9)yx|/~>?:Oz noʢn672^'gm[! Ãk/ya؝MLb hVQW.jp5ˍ@啔ҵ +gflIi]םNg|n(u,S.@{n p{ \[qvq}=@\<,?7ekDCfB߬۫r<=~>D;l}}{E}l9ysΘb +|a,FݰNgh/?gy?cn {` %B|%YELuco !WRܮ15TIMgD ;6?;l<]Wht_,[}|~_ݨL&wp9wwx3׀`ai3X-X捉158BdU99V+"{%SC4tFPψccNJ{6{N<#>oo` vhīel ok`~78ЂuWvZ:=ưPb@!WU T9V+"{%SC4tFPψccNcn {` %B|%YE)as W!DI;CFrY8sckp(1 +*d ~ÕlovZMn:#b(g߱1'%ٽ\>_]}o2~|YNF|>ļ&d}E t--[{̍aĀB$(3s W $%~N6g[vOТ)W`xڈvZMnψccNJ{ j4oKuu}|tzm j=?dr9CMx+:17=' B*d ~Õlo$~]n*~{T,-iy3f٢jm5H PxH<{%SC4.6Ɯ>jUP9SX|ȋq)q{+1߃=ưĀB"YERutUJ7zzҗЖh@9u{fzոIHu ڗAZ{!\!DUq-i^-`WRܮ15TIbӚwlI9ϴߘT٭&}a˫HyWu@7d~G5 n믁ˀO³K/ +{` B!NdeJ9V+ވz l^AThgx-!?~;xvD,[PpU\ji6{/S⺯r z`PڮJ vZMnψccNJ{Y?&u.o6/ű)\‡F$R$|wK +,8[17=!'H28:Ǫp%@y"3JPyį֋U7)*bF"BJV~ RmRybxFg~"G]h`@9qK&['@'†^IqP& jMkbpg߱1'%ٽ[y;$I4jh5 +zOQzJ +zCgܟ}:]Lr1{%SC4^__?==7j⒰ƜcLPșHLDy#A!`̙~C[4" S7g1K ?H>T5=ưĀB"YEylqNtUJ7"N\Pavl|QIRA~"Q/Vo ͲEq %%3_wamp_^t/< g 6.thp"xvw)KqbkL jҠv3No߾.x{"X}?տ)xLQ!!`3ؘG:|\6p+NgqT]4.V}j|hsckp8Bq$(s W ea)`-وNu}=T@~j0яxm^qXᐸh}j:UB(&WDK-Ht'SѐЀO8u]yp;igJ"qSC2jj.?¤S]WHȯFOnLzN^~1i1;/bٵ0/|amE{tc^1M+-7_~o;O)vg"n/cVä_*ǍgݴG@***** +*b# 27+ G +Ytrh&̃cp;{Am~HL+NFPԒ4ٚ,1;Eg6WZOo3CwI~I7u\Pv9i$mWM)W j4Κa L`>QIJ">wN|~ص]jzK=X~}J;+|].D1J{_'"M.yiy@ө>dEcү?bv:8*(ҼאXC x>7W$oԜvN3 X7\^,{Wtz1,9'kPIr +|/fWQm:E-0f)r+Pr~~&!aox%mrR;a.L#z_G9M15T/v3Fqk\G $10րMl)( .Ѡ{kTaE+)dkZ cQ +J_"c"ԶKwGlZ.?O?ؽ9M'R߀k|UƤ_*}<3u(<2PQQQQqT(VQc1@ÄFsFQHqe 3F)^^`^ON/ЗY m}5Jb$SXpV` bk4CQ;An劌p3(=lv۩&]xg|,ngQS8x^׃!ݵE"0F3hDy cիNԉ' f>9̨"w +tB#vLX x"tUF/&+s\_Z=_K'v̟R_VHVxa b jlq#?a7CB"IۂP' ZT,t7"V܋de/''S!~xݾfWv1ȩ||mZfSZ8%_ ) ~NBe>rh+7%KX! PQS8x^6ejEJK'lUQNj$Wh`1L͋W&=FFh_#'ĂK}v;(xh,[pw]  * jT=>~J;\Z!p1)=z~~}l?d lS[71<r:cj^FMf^;wy4(+P$"40YWAg'Qn@:j\·c6ppPȇ>HAR @E,`1+2{g'v̟r{gF~3nZƒ#DXaH !uSi>X7\Hw?w/FSzbSjϟgK/ b}N/b 1)_y;Nekh~QS8x^66ʢ0U$GCb_כ~5V/fz_`$=tEp!F@lWiF$pqЗ8Ӎk%xN4mV󟛍;O9{gC~3nZƒ#DHX39X_Q ^f#ĎS̰֡Q<, .JC:,>$ C& ZT®Q~~/bgbU&؉&kU$&E3:|ة6SMÏj {A\5}|+ uDnp0y_#K'v̟r{D~3nZJ*****~DPOy597r6>5ߵQ7 N%& ~/bgb% T18V WQQ19M15T/vK+vmBU`WF`/e8aÀ"%  0itL}qnA.^]77jM@ѶTՔ?U,rYuο8-zm?[A]m8)>Ƽ4{~8˴"#vd^~ӑ0I6>tO,;vgtD1Ir򪣮KMEj˝2JB]~]d8=B;}5,6YC<7?T}KsOV]5X햝_ - + ?Ԯ Wi&KN$9bGOL~ez\.ȣh$ i'#Yv%:90b@`UvaI#1˜nPtvEK;Wb WצNS;b}2esEQDb}^"ylh^?tOKYv%dFUGyϙnwFA(gUuH)tm)˒t<'y8O][`_`?NʄOkSwC>2s%EQ\/;"|3(4 Q~crj\w wR&\}z^:rL?GɔrWy|E6I64ϲc@K}Vi0s6>gQ h*Uq,6Ipzmn0#'SʹݾDтF6ˎ4_AMMz(г|ovgtD1ITs`uW~'eէ굩ӻ!GTsĎXL~h\>5MFݾVGEA4b4猱ϙnwFA(D1j\w wR&\}z^:rL?GɔUu^hi7ni4HMheG#I6ݾ8Q>gQ hO!TJyyZ1]b WצNS;b}2e>=QH}^2D]Wՙ4lHNγL; Mu:JN5nZ(2c^}5;)>=TM 9#vd|{T9I64ɲc-tZ=a4X HN3߀s۝a&:TRJTZ9ǦQE]b WצNS;b}2e>~'YvEoʷۗ49>Z0VIg̗L; Mu:JN5"˲7%L }5;)>=TM 9#vd|NE4;$ِ(&:- !|3(4 QNUue)y^?v$LhG=K#Rq75Wb WצNS;b}2esYvEmI14[lp:}zivgtD1Ir>UGJ)G,Z& əfYzw]b WצNS;b}2e>~'YvEk\>( +# ݒ 6$UvgtD1Ir>Ub92sCh(OUu$!-jHO][ij|3(4 QΤPJq|-vB[v$eId_JIWq1hVM ո +LP6uz7 +~)399d1WGl/UuLKQs,#$U՛}t3: $XGIUG+s!ziqlKR,8]ͳRʛK$vS}5,6Ipzmn0#'S> HN:;j$Uu90b@`XUF,!R*c["/=Y%٧f?k/Vq}5,6Ipzmn0#'S: |>gQ h:~]}gYB)=y}+͕R +D*ߗ}_<_{ wR&\}z^:rL?Gs ϙnwFA(_G~_WcB()Y@jDJ1]iN{j$7j|;Wbj]H~ͫl^l3ުԒug& F A>u[}%9N00j]=IqP^* ; ){ˮ0@%xבߑ>UQ9Ŀ|ͣGLߗ=~C>sgw>EZ^C;JğYTKfឤĸd(Cٔxǂ½eW@eȪħJF5?~';U ᚢ{opORb\c2סJvÎC}GlJcA^sDz+ly PGoT6 +åmX+Y`qm6 IJkL:Tn`(ؘMY؋q{ˮ0@%J~P:ɪ9*()#Ľx')11P%aG#|bc6gAlW + v 5o---QSs,P?~<4X#_7ae*̤{opORb\c2סJvCiy}A#v5ZsKy<fD*1|/~ȋTS:T ̚4HUZZ^9Xܻ $)')11P%!L1&lς4^ JUհ斲+41(3'"f|TƎ1$LSү1z 05R6a +왭9qb])[dL,K f'Zٓz͕Pf vn9ZDQDۯ\eقjBlRY2ޑPY $)p(umIRb\Y >aj,23=sHW~)}yn*bIGA eL`ʞ/% +-\څQ 2XDfeݜgMc}piycE^BP +PTӬnl$lHR`tORb\D}(a +mIցvw\ (I#J*+w*( _(L59tǒC^z/znu"/\ +K"Sy(%E`>0 EGY yI] +Jd>*Xv;IF$CkzO#_Qi S[#L9tO)r&Rnfd3,:B|wiu:xeTF*& +KU~߄M]bڵQ 0]Dq֑fԧWnDzL> $zxHIcI)b`V18F5caj.L#L6|94~jϡ;uDI8jxɳ50TF*& +pS!/C>KLیbO6IDrf}5e]Ѥo/@%Rt<(I-lP’ƏFR|P'/7<P 9͡WB&ɫh+7c-hlT,.15Ei <\YҤ#&ꦞR3)jK N^^v^éO4g(jHw^\o~seխƏFRgRm1\|/ _y6 7*;"Fk=*ם`Y^ɔ_i~r{\([QZEb"4IDWW߇nDvr!i*R7/$.T.4t9 U^Y)КvL٥Ľ&Tn-F`.QNP̀PFEDZPehXM4˷HR༲qL[_A(TYКvDWeM)_Y4K,Q0 N@J ϛd6KfqʙNݑew@Se֗B33G0lӳ3/vu_N,k_ ;h_w$^걹r$`LYsyRre"QL׬e1?vyO+5iR|]Wnc ʰ"ǻF;O ťԿޞ:y084ݙ;GGBS/S=6D1I}e`*T| 꺯_hd(/FgJ ,/eEIIϿs_E\Jt9h`Eń^OyW|;Lg0| 6Ƿ(]d?/m9/紱3]mozv&Y;g|ر6N$ɑH# sy7Lyϫy@Dڗ}7H.IcYT\p +BD\So ~ bqb'EQUe061>Nʆw>VO=YM6cBٴr&3Qr3T֚N\Ymaj3{`a7v6ڗ]&^ag8Ԓx#g|?Ii4A-(;}D!_j"&֔3+nUWs Z_h\}N{Me N"&(*ƌbIsv:CGxLL2uwݟ:;MڗMT Se!\3fwWGV+޷G5CO]3@*InMR.ŲwڵQďIRfN(:RD AjrNgu|Q6!Eƽ}X7fh_6p>]^bN,tݭf(?0Zۄ,9P_^!$[R(H"a~ [M8KgL {F"y&:i;Mli_9.Sz~T3vb@VlZgr9|AsnBV9jQ0gHyRĄRڤ(*$f޺i貳ٖ =A͇%m{2œYQ9Y;,m'x`U8?9|o"??~wdnt[g[VT<=D>?Ŀ\ t2ɓa/IQEUPD#bbOw !{1]B@DCi_-3_o7Ӿш=)(izyRNEQTeyA2J-×|ě8NyEȊib1$}CZu>~kZ sUlmReϓ"FHJ(2GS&⧆;Bf+{$}lXR +AtvÜq!BBȊd04Cq%EQUqE/YRP|e!ʵ+& 9]?.L+}d#:yٴ͋kѿxh"BVOO?).&1LSe-)(J0 GR ܿ׌к?ȭKaj_-AY7CTgV/o\Y)Kp$p s2Jd#-Kk%JfB*($\\tW(jSvCHf>yvj|hZ_o7v""R\ᛋgGmÞhu^/ Bֈb+Hwp(K9S$⇦}'e<8{&P9:om vt!N4(OӜr7otL:O09:Q@D@MK5ʛ pNP#l[B6b,(ťYkzvGmq,H8AXn0*}m7ų<ڷtPF x((Y_:2=LFˆ}X[S%#}1ՖrǞ<ڷqwjs@75!EQEQAϺi0wUo-~zѾ{^@G`QY@((* ®cȺ치0bޞ0LdڧB`CJj̰K#}t +3 bKqvo+PR*KQEQEQE-.hEt/j07Ǧ5_(e1RV;3:mۺxЮQ]zh6 ajS`.w)2USt* ܄I"6.Hn#Brg8 BYHDLKN\(ޣr(j}~>w/{\A}ٵ0}}>KM蠷#:wx Z,4N_ЍvW;LLxԧR{CkRYJc+V7v 1r&3B<}cy WۋWcu@܋绠?'UHT*KChaOOru{.+J|sYNy86:VƎIQ4k,F!TASKDZ]左?iI͝o6# ?o~zg+e13r&3B1 +V7v,/LlRanPeQ hD.Z6(ͯ,DZis^z6mKЋn=͝n`Lfcmv-/LlRq^M҄*0 +l9 @Јre~ɳXmzn|EJ?f9bk] h:[c0 +l9 @Јre~ɳXmznCJ 4V/[ٵ0)gfq}.+6[N?4\rQ~U(P=_"lfSIʲIMe\n zѭjtЌ|}?{-}IQ4=3g|7A ig@(l|U %).?s^AXUwiCoO]g=0)gf&aX1 L?,ߍƮnfXZj.~Xmbmm8o:a?r%᝭G&EtVyf&JR0 + {DcVL>F,\{'=<<>O-@UsCM.\,htI~~/G4#PBzdyaRMgg |aG3C3Q ht}"{"͙U5WoJeP?]}$?qI8ZYY^EY<;_kУLQ~˷撔,OJ 벝.#L٠6k{Uo,I^5=Іv¤(LQN؟Z>t<zA#bηZ>-Th!u]a(dy"IYDZii\X>YߋZd\-j^%{&ELfrٟIF!ah̊igѮ܇-VCVtnTjTݷ zcynibeoJqP~Dv;02->U{jDZo,/Ll:gCX1 L74:݈FtfKҼ,OKC-H^z #*y[~OSg)+[~f=¤(glnm82ƹX1 N+hz#UO)l"K%wڷ&yA;8 @_A^-ǿy)NxYFWL^nzaRyJ}7>)v쑹庬jXqhWЈɎJ 鴍f&ٞ铏or? 4@-mD@HJ-&@IVPhZ(iرN\'Nlbgwdf㱽Wgʯ{zή_}dm3ٵ((jGMccpc INU 0* K/e|警 m=Q3b+w~)vb|YF3&;ѿ/hvF±ln2>N{=5-|ώ]t ]LG%5#y9mcpF

/}v}7n=|7o)EL[s]_5X7.<܂y*zW^ڳw=Z_8I­J]ȫsse]§ҧAI:jnb]v1hz-{j]$d 5vy +=sϞ.ة8tN83t1軈C 9*> xV!\c[%37Ll<,W_ 3ܝO>öM/S]z2Uۑz +}=vЇN_\T+jIaI \ rH6Yx@ԂH{@}=?ōEH7>&p~«$P^;|Hop{%#+=i2n8w( Fl|j|'N]b#!G3@Ā\ a|.v*N+z<}uUL;nZMx`pxeՑm rK cO7u:UZ +uv;wI#Ѳ +L/nff ZBԅ (Gg/>m`H@cjJ];.n.hvůNWq=oB(4U kKzB4Y pmX}Rܭl͎dt:UwBf0|]bCK%r` OpOv1M9ba֗*u`hvȚn+gkf-FV`يB3˖tߚ:}Ă! Q!hKjǛ+Xȳ t1ߙ&CJE3 T)l_P7/؅w*zh)Ej@R8q]PAVcěYolg 0)EK:)֌( eQ;=|B݌=u<0Ħ zC 'MMy9nnq~x!̕jɹ%rn ^N~tC k7_{_L[YvԮB/j}d^ݮ} vꔢuoՕ< Aj * + + je,HXPx8ޤ@sjhi&*5?}FJb֗*1GVk' u`N)ښza u52%,Q̆6 1ƀfⳛq6}](x5@0ÃATpml#jD?y)邝:kY `3!AAAA4-Xhx8xznh2M@ƃX'ޏd)ӊi!=VYuZ$Ѩ'9%vni;^1 o%s /!X-Q݋@nBQO !r^!uՈ=DuY8Rf! n+ћM@w Blw4[H[W !챾H0"G!T#>Ã-Ƒjtǽo̍%sѯKS^zw!<{>SLNݫӻB3`z;D?@uT#$Jѽ"bÕ=:7ֽL*C-0u) Ĉ7y<|k&n:ҥDQv^ݰ!E_$XL+tIT)KILPѥ&Eh}WM^t/}p$1 76 cK?mXn ؒEW͉ O,oNRcKrB G[)~ѧ߼V5?>wt4UrfB Mr$Ilb.ι?YS}X_m\(cW*p,-UveQB!>|/|OvK|?~٣gV7icG֞;ͥ;Y޽g WEmەyinB|21vE"-KvٮB!Ʊ=+[4<i1 7![@{cdQicu2j +{WTؑWI .Vb/@beDzcۏRߢ_մ +( +!RoVn?>QN vUQmHZp΢΁mQ3o6w#g08E{uCKYbZܐL/8eIB!ԃUm]Qmc?~wЪPY!|#R5Fc +`o*@aH)==; 5k$y3l6.3^ī<{ŷ.g].BMHkO_'F%BlBۇnmH7U@-/ϽT?}x<S% C,Tj㇑yt: 0Nc{q/i^fƽ [^&ɴ&'u!BjC6+z^׈xHv=%m)@MFÇ7$pxVV/Nv#gi[)+wxj(leQ.,{I | ܋53bօB UX\__'=z|N) J6&Bhh#kbC}fC?LeҶ b )?D!m6w% >k ɅilmoYQKU!]YU4`9Ee!rxQ-#AFSA't~_12Š v?1aGvY.eG!²d߽X3E  !R""^#8T|ʢ 5(ko +B$IUZb! Sj'}%UIвU`#?ڨ,-56;j4v6^_sr1Ň(D=_p2x(A}upp^DWz}KCH)w/2%+˒BinJk%Il]UU=C,4q֠mc:F:VeiUvNv-6uJxBI:dA jdoj,Ks{_'?\_.!nʽdt/BHmP4tڼHws|P<|(mpl( Th}ۂU5TJ;+$3W8D:2-;lGYUZmܠ_Ӎ:oWN{A6[s(o5 r"SVQX$;{2)'sL ZԖ$IJ/ENJC b2pP<˯yNH$1B(1z=^N[8(%TNFj!LAg(_O0Q'cA'?Dg.-6[]tWcN(={);8s'3cZ?n~Lz-rw|'E{9{!B6J^OdqHۈP!Ra|Uv{_GtVAc~>N"I ++m[{Gb$qqw!05CsPU$7R:ê 5s`fU8?\IT?ғܘ^nx뿃 I{9{!$ȒȃПY@'k͌48:;rF6t`8< }I Ckk翲AZݫ؂-߬}J$r fsHnğ댩;6^>Zt j)]9 O=MHrNBe62<q l=ڿZ{+#wI +T殎ϵĀpT}?v~"PL[yx5E.QUd1 ǜs u~6\̻@?`n?5 yH;0a+M0i2 }$v9:ucYg/⨮uYL&^9^fQ1^DV5 4^/C|rmk`0<"Wzaa!UFz}8F@ADZt:.AZ!AW)`ag`zWҫiSeW%RB9DCz euh(sҷaKh!۸TғAtD~.ABzbh<2hw_ )9!4]r*իՖ 5#'U|!vETYMO92І`tzŒ|Ƌ%h& 0`L6nUfQt/<(Oj0^/^ =IΕy Fv6}ڰې3TQHURRFIENs))G\U|!vETY[f[{i2ladh&s$u̓I84x> )Q;&Ee`pzn3/,7J KfC#qśr-$g^ KWvB}ڰBrJUx +uԕisYX WӦDzm #@͛vC]kӫ04Eh0GS?vX6 NYTzV2^X>+s%e !4^/7~t̤$M}fj'7MQC]h׆d2)S4eh[e*CidtPHPy2e`J*TYUzGNib:ee@]OFmtx|-!VvD 2px0Ԥ}hL rmLmYdh^/^ ' ft\ Q˂O"{O0yAw6 `}ڰGec(DeUsjLLQ)el8OW\Q(-kCZ*R0ʅ$̺m$m"`&hN8D9`paMSГc^} v-Ý$xIu꫍TR"/*gvTjAs_/6aWog/Ύ-a7K@zv+̇0áY.h gv@Ĉc"Fҟ64KfþCn'WaȽm}"Gdr%噙ovr׎v_ʜP/./_"Rƞ;V]Yr%rm+IL&DzGUp䘘QLՆfBzbk0iFXYy}YRш#+Ȑz!,űol%4׆2' vkֲpY.4ԂvPUL&vŰNWۍH7g!u:ѹ%N^Xch'>=}pn=ydz15n_ Bz/^L̥1\$%}~K5ͥࢄL7t)gA}$|oMS`0KfBn' ?}\~J n_>m+WP -T>@q zG{km<"vQT]\ঀM%:P2C\p0? G#>hx8~>LYhNQ^lT/z ǝ;Q,4@3WyS/w2OS{AzQ,7`!Uɼ͛~!LiJ->>;=W8A yo=T/6PPPe,4@3ƫ֧_ ,aj>JeNOTEshzP^lT/zˠXh|gWO]Y@N/g'j{^H|}@ +B[F + +w WyF:-~!^J-E]]^׶G4NT ((ޟ(%DXh|R/_<Ӿ|EӕW($FRI>&G|\lcաRب^@AAnf-^.I j_CW+e2C.7XCfxI5^&W*ުQ^lT/g-2'-~./#bZ͛`sL E:-h[h]giLӓuRب^@A1X/`0Dzz1S] #bǣFc`z]y! . oG87|#m  +-d2rq4z AvJW/_tJWJe&A:&z6F +ꝛn^AX>VeW1S] x^oDa@34\a'$l ߎ.WgFD[K)h`0_la&Gáy.ϼϛ]iJuc|}pvz8If4yfns(:w`CP^lT/޹zA :\XV=9,/V0TO3;c6|`p@qoN^gYBzy뺎NOhB|I>`U*DU"?gOwwɄ>vi_T/v bz#dSi<#˓Gh}`Yu +jM +U rUoH~BzF5aȟn'˓G߾kk&2h#Z=BdXTyNs^zO}{э]t#/=P|el|˼pZFáy 7A1Z;;=Ѩos@q7 w$,5l:3ԗɗ4ٺ-&.R 'k 4BQoȮp# #+<ه7Fv Pi_\ZT;5`zLuVurӴxDj0e)ru7AA"m6N8tL#t (8߅D앢G׊{~Vw|Fw>@|xd̬tt:cݙ@{CDT.e)`X,IP#uL$aM3bXoZ)xZ߸}ȧ{6ؽD$ؽ%iR($M[@8̼"Y ~-@ b0rZZrʮ.$ѳ2\Ȳ9?F +Ɇs RFMflOX1 +}2S9IieHdM`Cޞ;ZtV tVH"daBC>(I_7H7(3#BH7MrK!eT)RTco_&6^(`+X yw2,e<Aq^]1 W[t2 CV dYp׹\x|.b° {'HTc3А|z~n5j O=\<|%zp)Se +m( pb4ƀjFKH 5GJۯ"Đҹd=4\ +" +&QSҺ Du*S՗C>˶%R_$Mcx<%iQ9֝j,zD[[ Clv'1Klv,aMfx5^v}q#eC[p)jW{&֛ۧ&\,LyS.6O@!a6x{"Z=љ$@ÅATnphݤXG|m#KHS;$M #*Y2ٝ{X"٩ +s/o8^ S(g +e0Ls= tI5v% G0Tq# m`WmGT[tîr;qR_W&e{%R$MX`z px!i}Z-1wKI^A$ (R:6 S ° v4S'n)]wvq%4RXFɎ+sԆn"X]{Xsp2F<X‡J|tO=p)R[TcβIYSk ̋hOX#naa?v;`X {xrlvpqN!#e$q6܁N|v LW%4RX’-gɏOOsд~Lۏ ǧ16c%F.%)G0}~6 PXZQMCR*s]]wpE4 0R[ƍ=F*ߓ[;XT#c=GI?s]>KH-R;kT&eOyL.yL=Xpk<|\8#'˲2ԡ!GG6(8v{>9 p p6+#v 8a,dp)jWaɶ^<ÐnXTj{qr+.e n`>-4VI]6ā_v6sʈ:[ +c:IƊ=y*,DY*FU7"rJ!R vEyl6^^"EjjY40ڠ@&_e7x.T6`1()tRq# +fFe{%R$MFic<iµ6O&\ j-{+3h08@N%L.B 㚗fwXxf~#&q"2Q-;IyY0XKh^$[Iô^ar=?2u]ӽlֽD.ؽR%i`L5hȁ.vN0~,˨s:rD2!A +#Ljv<:KEP3l$Xk%>Ha\KO,zlͦyZ"ec,2f+7m(ѻv{s‹&Zft9E:.PIvD58 D-N_u]ӽlֽD.ؽ%K$,4$g> >#1v:GOWZ`W3!O%o=1 kme,>fw<"ja?{ljnxDWEwpdr>"@O,zlw6'<σ?/ +q2ZW;odgxf/}exf|\4=Y6p1?~lUVV#~%c<Hn'?էTo^wp%7P(X\ۣc'_y3PuEVÃ} c]JvJd[^GgF5#rٸV^/2#c\+Oz KK/[{X=_{Z_!}{{$h|wd;緔"7y9&v;r[,v{ޓO=uBzhXb)qWnꢻMN%%yua/^ꞯXB`qR4[f,1Ɣ8+,?+´Z3+KV1&!;I?da~.N V{EQtdkI/aipmzGݩ*3cJ|^@թ/ۅgD5#ouey)HˆCm2xd:{(ʜr<%i rQwvʌ%Ƙ'_ytkATzyifV{ Odl!gk(s:2ʵ򤗐-xmzGݩ*3cJ| ^@֖Ãfs"ga~.gmY1|ĺU(ʜr<%i rQwvʌ%Ƙ'_yWhkQU|^/2#c\+Oz yڂܦwԝh!(]2c1W[r:u^zQ9cZyK<6C AzK1%Nܪp^e.2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<E2ʵ򤗐-xmzGݩ*3cJ<I9;;[1Csݥ󤗐-xmzGݩ*3H)q@++:A g]:Oz yڂܦwԝh!(]218nOM;uBPp^ecLqۙUyK<6C AzH1%Nqng' _yK<6C AzI1%Nqngw@F\OM;uBPp^ecLq#;A c\+Oz yڂܦwԝh!(^+8'' օ򤗐OQh!(^[8''x<%$SwZ +W8vIR =v/'x"C A +qn<9l[?^);P-+`]ǧݮq<%$SwZ +W^򤗐OQh!(^zɓ^B |oy/_\QOl4.J;7Vz<{Ԣ'v>SՕ:οՈUso߾ye|Ǐ߸qݻ#e?ޞgvvvWkyɓ'o7o?_wot)BSSe?Rܐ:a|!/gK:e^9+ϔ(jue+F5"cjB۸x4Gq Pl]Bͺ:LI=iAe{ 2] +C7ttAnC!,Ie۾}H3zo|m6,jZni +=xظAe86 VY(TUUbHT*5g2gY1!BF>y˗_}+W~)OΞ|_Z.?D>?|>/~@Jl+`ZEp#q_{#{ű4a„ G=m2ZGZ&B&7rz> Jٗebf݊PUlنaP(]'?}Ν(J>93!H҉[~{a!9|;VBfsXCE",#E *c,+} &L8jgѽtkkhZ 4eYlVY!3roQUUVBa] ŰErT*$v&ZF>Iŋ~[Q3}G~G~[}KS\_wܫ>P>×)EYư>h6!ByiZ?cI5LLrUDϦ I\@VE +f P/ +7ngd}t80}{1Ǿ҄ &5FvC3F^:S5t! acZ-YfeqSEUq`Ú阋%b3f2s]Ird09_.(Rҹs_~M<ϟKKi%_) G(ϔ,cXx²>p!2 VPك>q`%a4&!j۶hZM3dH\ +R"CUX0WJ&Lp  ѣ{LV0M20 jdY!ZE +2%rӳ` :ɅصF>1oOE?%)}ŏ>-ϟRSssvw^Ӑ ~>xL)2`O4:Cִu *#P ,-ڠ6aUnBHi2䶑AjξQ#*c,+} &L8j?K( nҐ܂`voG48h}m1)KD>6^:5^u]zDc&TNvJL.TIi%(}V \8VYzRCzmqmgc=lq_F#{ű4a„ GޜnQ~Q,.A2+8n=e}m{CGҙʯ1>`Ѓth `]EO?I˲-ԣ*ՠ0zDd;w/O|B6z3gNu2?3 GHQq)%PbjueV°HA8On8 nX->HYn6¸bo#ǂW0a„Fk>?{f~S҉()Ogg#o^dTۜ^סWe Mo7#!M>{BYذJD5`vL -}hIGWzl}{9Ǿ҄ &5zܙn!1² FOȬ;;Ut |}_ax&r^:50MSeAt]gBaPdY?a3 k*PhQT/#}w-J/SƟI\Ǐǽ /_Zݶ+e(Όh` @X Y#ȺЪ@sw V mH Jq_F#{ű4a„ Gnf}~x{~|67HCZ,.JGw=|}7Jj0xgx#=^:5hZD,RSa=_"ʲjh4;\*>VP(h.'_EQ +̙c ݻg(GHJ?UгfLYM u>9de.[{"dD/ܧz`3ڇuKfݲ0+"K3t)Mۀi"{űd„ 2on02|[e5BBX\a%}kȏ#q3&Kgi +eYF!Vhl~P(mfǸ_ѽO_YL%S33)'1JK҉TJOo޼{C@3#^wFQomjV묍~HmQ3ɲ˂B5d7H 0lIHR!MJhJ$TWj*HlxTRy%R!)KCʡIH2<,t¦cړ+x= {{Ϟ;''eCa{ *%Ц!=뺟^%*OhUCUDhoNEc& +cə <-/ʈxnCY0\ɳκ'2uj~QLQ@*"o[z/7_(ğ4<4tэ7H[Y^;g~D~lbaccc9=)AjBUJۻ!]hwxO?JHtOaSd{)Ͱfi Ȳl۶Բ,a,XU(\]Yg?zEq/W(ܫx`&m^a6JpH½7w'*)IJCCCg8l2Q$)MIQ>|̙^O>]ٳCv=Tg8zX4Լ깅rm+fh88aS" +< VxafSTX8FS9=8Y.Gű:~Dy}3!H^D +P"k&(tP(1ĽfV,ar9f2O|>4۶EA?hP(PJ(@D(Oge\-p;f +4w܁/^,_}uΝm%1%)IJ>00p|3>>ԩ TG=ܻ>i"ԼHIW- +\ٞLJO2Epk2pvPSd~M'''`ó\.߾};#:O:EmH!I$׍4ڕXIpALt%t`ݐR!4þ +dG 00XifH|>K,Ke )4MR0ciJ%Z$ޛ};n ~ܹsuuǎ۷o0:<<ALIi\-:~[o#7<+ڵ>q,I޽j?{ q$$Ϋ(| ߇Tr/J1#XNs6R<971iU-'8999u;käC6 (1\"'%u.ȥ~!4->d%$0  +QM0EQl,ippbdYF#KxfY:KqHUU՝*(%Z$_<s}rJ.\.lYwZfٯ(+^η'P_&NERTJ(NUc>R +vIB/%pJ`|> B1g +Mfݻۛ=t}͛7o_Za2`B0+,t\nuL۷.] +zQt1X. I׏K(/vkjj_ߵsǏ70` +07׽h-LڧD'(Jz{+G?+(uc3tYpxp0Itf.C0^TGͽȵ4%5UЭ,h,Y"ܕjx5]' h PAL@`: Bd(+L]`0𗅬h1ߦĎ=;ߒ D" X.tyE[^}ח6iZYS[rS=WwDfzŋF}wI~_ByC츯LvqtK0jgYhVIkSq(h(i +"t&{nj,|bX`i@r%]9BW-a"ĥ MpO{Qj7^~w Jsss J0eS:::Ȕ/<3xjxQFbX(,a1lCzٴ  lvs/uޱ(]󳺻&,ˠG@  +D a +AA\04Z'i;K*ٰak5mM&υN)~HAn_3 K(ݹxՅFϖ(Z!t/#V^I( Vgɲt@ +:::loo׍$766¨Ui;K&.A{Ǘ.ź:~ߵsmox4O~H~D|ks?6~nz|6F9vu35\i1gü7$]?/!.̯ ҙ_7b}Ž Ч(}KpiA€W]f쒼jiBEہ{)Z`f0:K0饇pԓk1d&sP 99"AC]I EsVIwxZ!t/#/m;dѽgg[[)_ѾWlr;R4xt+Yʅ&Ԉ_=<lkn%,y7nht8:{dl34 d~iŎ{ G(Kpin( cʰWhd"IxF ٮUW6 0)l0\WKPĜW"33 AB[nςatQHN9/,Л2NtNf{~r݋-(#{ѼX;KVPr\?`xOE=W?,}R#)Tٍs_|WjtP ɨ|әWwu3nAp"W\T%qv Jn̯Kގ{+bw[򸁻,L0|X3!I # W0j_KI5CNatDϴ)ỵٮ; l`dfVs 30vŠGf2WݼGt/#iA/Dn*/Ŏ=;ߒD"SͩtouuSMXw`O+ G%ç+F{f+}ODR/LQ|2Z6WvCq϶/(C7$]?.i3:;+mdN?6:jwC@WS3#ӂX"GcHkހYQ"1$"` mZzE&0 ++j0 &iN$0fYL X +铢p4::Ğc0z(8 ~yI^TG-Ea缃 g{$x|ƌ'=;s~? wJI鍳??ooDB+/Zz=Eǚw<7yX DWFSǩ%#3lc`2Mb}Ž #u ;! _xĿ %p͐Y`X*E k.Ixf,GB?bH<`FJH⢺[Ӛ }A OpBqUDծ !8r61ӽ`[L 8?;;KǧOz{#{}#1ifCGվ +T/vJ轰{i_Mv K]n)^ӦUkJt8:{d01@`LpZ[6c-}7׽4MK`(Q!#\ ;4H4e`HN Bjlf Je0 ,6|i4&9y V! LD{(zTw1xZ!t/#ؖ;p;Kg̨rg~Fq]yw)DPpQU~ @,EI%!-TvHKqPhyPGc{S? +]@಩Y`SN:ǝvGVsϽs=sW^ݓSSSSy39#3_iZ;ZߧWv?}a{nժU-ye8xsQ}ΟK@2XcD 0~KL+ꕞB$PdH &Ar84lʎ{+@B%B9J2>U}zPlA z{ R{E( Fxvִ7_z5_4cS9nP<~aʉ?۶SrwKB޹um fϞf͚-[\p+?~촻pY +)k1jcXQ5 jHQSWD:Gp!g1N MF4'l~_|q\^*U8$Rt d + 1 w Wȿ E2 +ۑj )\MF]m]B(D#!2:-T3УD[3:ysˬi?f"P8YSFmo7~)ˈ4䂸Qs**ʝ;w,(cvŭ'O^q=1A_/zxV'\=-P`X,y#[PIJL:y*1)\+bQ.,S$$ j:Y\={q' z]bE+TQMFGG_'0 [^榦3x4no=vߘYOc?掼!q}q뮥CP(H$xf֭UUU&|"ETT,ro#b8 ɔQct*>zll]t@D56vĎ{[RK!.Os=≳3f(E|V5%M["1IC"艑Qd(0^"&/&BOd$ga'GqThkƁ̮KHPIZ.bRNrmؘq +~JTr)i@OcK'X( }(ˈؖu#/[ĊT"ccc?ٶӦy0/r*t,N/_@4OoBwݾ}O&&Iʟ=_7z {w3UKCßg2s疆B!pkbb<Bgg$FHo8%bޞ7nܻwɓLf 倨k ,q"f(ik;t )HNr:zŊzea6IQR.mG츧-丩"Co +U`cko[7 і&z* 7nRSBYSĊݵT.D9aooG3eb88d O PRTJӗPЧ ɅT^x[C +ADI#Yi6 s绽3{/ޱ0;|invvg~3|'E}]]_ |HDDMCzoݺys=qxM&EAHfPFUeED,6 +577wJJyޙo>^y7~< uz#,@W p+6X#e0 0NP0b5:KFVyؽHLýpU,(Hᄏ煟zk< ,)x< +NÃKRRZ4r,6 ݻw'&&n~{ۑE|7l8NpxO/+-`ͱ&:d G"=leKL44t@ H$EVU~E1133#H< B*iA,6?55u͑ޞnPe*/FPrҳW['5--1H 6%LP($> c# ܋Hm '=gezb 0eZʁI}nWĽ-lG`03[FaSa^Dn[?7ɄI8;%WE,]S[SSq|ecǎ .E5J2)JBGJqGj* H$<111<i!.[R"dK-48qa ,[b2 m̖` a:ج.8.38PWWv_gݶp#27&|*(wù7o)--8]F^x +> eHfVBAOjүˋDbzzzdddxx8477C0Vnhh(/+ikz{{I\?6B<N Xm$-1H 6%Lp@0y38PWW _q3.榦1p/"}->?Lt {ꪸTwܩp8˗m߾r9ө4UGU~T!hX=)>ndGH￟rZENƳn7:%36& )Ip2A|RѦXӏhfBV)jVD JIԗdVt#JJO+64H +0tw{< +O3{}!Gb$lvff>=ޤn}Ď>| H8](>)L%a,grv{7ۿYۿVU9A:rHSS(A8u/^LA0TX{@^!V)UUMNO|/^_w=>t'Iv>daaeSqW*W]SQv^1=*}b;p8lbgb1{uy +u +قd[~_\ 3 +;B%avϼtr~\nt&W֗_^Ez Nݻ0icUӠr#CPu'N}>_*ǜgGGc 7I|T\[+4l5)ZV,( ᘍB'xiiiK*v; %G!xe9ބK|?Lv>rTVGFFl*{=po.Ԫ!x҆xVWWJn 3"lpfG7. ^;w>t@]E[}>r]ikk#ܠO^hlZZvXhZc6X<*j/pHۑE%'-[KMWXLWVV>췂 >)6A|W0FS%vƀ +333*az +Hfu[K}! IIM쐕|F=4###OqJ?z-ia}Rʚb +r8`]󨨽}<&H8D<` 6crrt/=ѽlmiu^\,eѣGOfRdzeM1o9l.yTF~0(HYF!W#& ЋT9Ğ^KMWX'X?~|,6o H \p!X4 +h"xyyQfTͬHǚ!I<~18 ucccr]%ߟJB5e͔?)AjGdzeY1o9l.yT.,{W7?`(E%'fXg^ޯ]&Iv .Ν;01XEHCFMC+SSSsss䕌jzT3k+5QDpZ/{zM2Nf}*TRCXVi͢).J;%+ˊy+p8fuaΣw!`0@{n޸Yp`+=cu"G p!4Ĭ3b/tztuvvA=Q41BHغ1<թx|f"U4 ' I k' HݠNmpXJ?wrh(k'G2jAY^YY[A1 sE xe`0DC“pu_(rt/=ѽ=翧Xe +Y{O&gϞ$(nOwwɓ^|5 `bG]YYO<>Pxu#Io̢Wg!R)H,9s v{Ukkk6YθSYW(1Ҕ?2$˟ +b +r8`](o7o\WEɲ ' ^'A&^{{3՟/jJx3y@ p$.6s F'˚1V5 S6"N奉YY)*Ś'6ħR8\={wdHt:]. l,..>5|* +"F)&[a_P,. օ9 +߈d Qop7!G 9}|9Y粭FGG]%̽uLgkkk[ZZZ˰ 9E-k}bb]IhyKQ{]zUUWS)icS奉9Tje&Yd@$b}MS)&K"EZ:, +k >QFcpd%<  9ТmCnPES7PFKC#Il6]uVcT6?Cq\1H?o߼y;ު_| +ػڈHCCÊX9>?Mt*'<9KB5>9@bO}EWi"T/閨^Hyu:au"fȲT1VEyg&C&&&!Jf$)X T9-_?ڼyÇ7nzf2HT]HW'v2sA!gRvրsIȇdpQaEQU&:B"<9KnZCϡ(H9ԉ(TTTTv3V*^-Q@{3\@  M." <I 0H$<ϛĐeYdBg-,iٳN't 81cN=w$14UHK x,bǫE@.Rz +Ҡ=uj~VF.jhhXQ5G秉j Oek 4>򪞊nbJ%K%_WjQ6fM)\EpBkx`s ? +I$rJF~^FЮ/ջ(G>trD׶{'s{\ .@#Լ~11Z51 c!Ո1(ߛ5FFN +:ٽri駏&I6GYPu'gGo5~uciHו־(U=dLJtKT/`u +ctV&EBkxA9~6@/S-yBV)KƖ̳:ZzO$v:9"cYn@aHci*!X,N' 7(hLFKGw8XЎ;veٶ6fs:W ?([,Gj“@_ 4~z)RIKeѩ|S3bDQ,9 ,,,$I,Y1 + (ZC>L^2dV}:qڇ?9}WEz?}>}ݻ@1iJd<(EQEQ10,Y0 =X}Z|q _/u]_-o>}̙@cUTETpŢh:䝤7i"΢.bҽGt*o\~-C]n`NnX8tΞ]gff%>?Mt(issE x0uyuU=dLJt3mٓ`00,˕E@hBB:ƣ N$ _XXyy#?Mq(v +n9z1u|uU=dż.X|~B%K9L0dSEx\ %$H$S<e FHn/ܙrd&k$A#Դg.ϻ>&!uї{?xF~ƶq\q|H0cV65R`~Q(@Q6|RBŶd[2嘇cgeIV얪9L\ڤHIqExo̾ou5h [n`e,'dYR).>áY$%RN0mlթ/7Ud7ghH# -϶5jD^54O?I~Fr5MR#yx_ɲx&EQwh^caaa՚}1?cJ^uUW<2| F9Afɤs\.@/(9$y6Ғן"k, +Z!Bko~Ѯ|sH OX}m[#GV!Dhfcymv+PH,t~FscBQQQ. O~G-|,qejSvn~*) պ:z<%(ʺJիz,,,ZS/懂x,~B)KB(>Ds\.l6(pfLB3daH'/1˩λ\)E6D3Nh4 CKK f5 0. ܲH;s݄P} j~8LO=1fv`}Ms a+qQ΅mlh>yBVKh!s۷_xAQEe)T[ DʿXaۡ?nzMǾA@"' ^i!zhO?;޷sN?*)dYzE{ #!ߢ&;'iY6x9Le9BU4 fx"Л c+/U거jMվ + +T/Zڪ_xGejiiq:`Ъ~!] +inn^O{DQ37X,fpBVk/ eS} ώ~Y9.lVڈ8R/L)dv6 rO?'B!E!yT[Z9X,'el3崭Q xāA/oy{w}(uſ=T߫]d/Sg^%mߦi)f p+(U>_Rzk `֍x,VK^U<E! X<,F4rbl*,L&B>`fuy{|lJzxdscw73o6.Ȑ=pd\+4"DhKBHCԮ] ,'E!j/JеxKCكW}|Cw}$sG]u jo@9w[=r(=̈́\$ [ܽ +NY+)U>_RğS`0 SGc"L^Jկy(fFc^?zWDa8M&Sfą$֮17[݄R}\Vv?rsaE DhKBHi_[H Y%RZ|T9L{1PA͍_׹iiZW'Aj>|P>frk +kr۷E7*y(U>_R_`0LŊV3y)KB&I(u6i6QKU`yt:꜐?t*eo,"R^go}Hrs\ıb\._l'jj`}vs֧(HAH?fHJewc(4|ꦏ3}C6ӓo&RE1!kv!i?5Ɖ +cǻ~uR~T6THN#J4VWe +R[J*A#EꏪI#mB,10,T*0]ά{f{;c~:s=՝sѥ𬦃">?9B6BeT`0 i# +iƸ%oVz ~~R,|p8xԭL&B!ŚbKc`nPPb|={o+gkI9)K-|e'ؿ ,fsE`W\5::arQDI*>(Y^֩t}e߽ˏ^L$"/ggg0ʄ~Ǎk*92sqQh:k5w31´W,è"0ڪ1  A1%{զx^xf|>L CGn71iZ!V55x@bQ_q(U6^tޛzjh38nBوP.Q,itc:I0Yn^zb%I,T,KRn:~(E8_<$wyWVw mEtLI1Yfq">pnǿ-ޝ^č1´W,è"0ڪ1  A1%{զx^x%ISL +P. +u\.Gt~B5MXZr8V_q( {$Scg>ݲn>:y +` +/UO!4k-{vKRQŪ(j)I~Q+Y=!wU,G7YwX٣tO'9" tdC"}ϏqbF%VE`0 eAҌq-K6,r`0S`b @ P0L8.Ky?n^9gE=&4aŪqCks@Yes3 +ovtޛ$=vvhn:y + L)͢P6N?FSCh/q?K/oذs$ʲ$IERXmǰY|A~daΆluP("/zia+aTRmU `ZFAT ג j#X`*2Jg(N(}>e +MӠVJj^/'I a"3[BP L0RB(+VuFr)Mq}ݳ&285myБ .x$D*0+ɜFǬ=;w6,!ˢ"T#5C|P4ivK< ߮b+l['ا$--]$2#!L}2J*0 AP4c\K7kH& +^(kBj|Ci9CdAP)5J~?A!\.F5#UVjqu u{$Wl9NC8(㈧P.Q*K/-elLNY&e(IEr4jOͨeY{uyݺuV dA6/_?;mSaUnLm:sIzBv|c#i#tXQIEw3G m· +Ah]Z_[T*B!h`*`0FOL 곔pF7?={o_m~0EC|(KT Lh*N>&?h6y$XJYEҔP +B__ /H&B,_vZ{;޲8h:F|\)ǜSȑn X{? =?9BBeTF[=50L۠}o? +кxd/y0&={o|m+:rd!>8%4$#oQ8y]ߊSKɲ,JHJEY.K\)u6S֮]p L'f a,uY~mo+nSP6&{_  + !L{}2J*xD m· +Ah]ZQ_[L螽7åo;m̀!BD#+E lݿ1ݻv3duffdYdYIՈ '֯_0f*qG[ ;l{鰓m e!lFG,k1´W,è"0ڪȍAD`+|Pū%{4{sf?9BNGE| qP.1[ x~L8}nۑ?t_AϜ93>>qӢX|6;=5Ŏ]oܸ{k^ Qd6[lr7:mMڧN~rc\8~wwpb;cǖv:LLZGکڱRGFQJ#V#*"HDAlA;^6#V J{h8?r=wwvvo+4Ueʮ|EO{aP| 1&<_ÊtڹDB 2pfrl;bek}MS!۳%SMԴIKkiӫ~D%KÈ؛kQvQm'Hx`1@"dɓ>} FEX%-Y`yM{'@.yT&ʀ9eDU'ID +z; ȁ*%Z+iɠF; +)S=,QU$/}Vmi;(<^ǏBrL&YڼDB 2~C0Cv{@G{u:͢-2>bekmcOr1 6Cz:y+g:E=C?Ku*rfUڨQjiKm- #6>yzڬuOW`V"e%X;L$ $rDrP]~0!ueJVeŠ5Ԏ,è  {X8I~vR/3G ! 9W7P޹ӈYOܗԻ2çB㸎i1 ƻT&Z2zA@8!|܋M;w_Zc*\&^޸^LSɫiQz}M˥PŊR@ʨu+ڑ'Tӝyԍ RIߜ $ $( X8KG\H3T_ʨگM eO@~yzll?IvQ=ʁJ6iT& j*ng`Dc L |T +"y1)o> ۳aW!;|\bU5S, ;NmǨK):^~kz]Gpϕ^ǏB*!_NhK,K@/&xQdƘ[N94jԋCvuܴq8ј<=龍&\QΔfN|69zC0CvgߘV4D|܋M5bp~Šת-kzV4CqDft;ᕿV>~ѢWf~ JIF|^ׂ7 ^x5 zPHuQԽl r*YV@:^Ǐ8C#rĐlV+f0r +!DDBy?u5ɨ=j1&jG2]B7{o+%x uq N|c#z4 C(p " =wMB?Yág&}=#4߫)j7^l!Rma0"M=q ZMLog[SaM̷\; +["k=Cn;amL^J%[#[QKf X~ siSK/&^E/d2Fԫ3VƪDѠl6lzz~Ȁ|^H5x+̌T6d|yaĉ4c +x.<2KSB̮QwYdY>8|;O)aMl| EkBsQw|4fx%hl*Z(zQ78z]K>j1@3hξ(gZsb':s-P=tp- ѽ|4!Ol;Y> &ZOH㈳Dv4쎚)L/U񗬾E ⻰D(GQC[vQ4&hA >k(>`>{}Ib*-tE׭&ifg7a{2f?{rɹ{gν'_;g=|OvWk!H}#P*QS brԈDvpL-ߊ*XKvfm{Y2M6lcJbX?g%@ +ƖduSo4|H w{ACsI/&n uJAxkn^\~s}k/\߽uvcg5C>Kx?çբO4IRz< U_hql<6h2A􈥲]2c';Sݜi9zoVt RYGY?;e=Zvvi3LOLD+֓r*aRW)eWaz ;0|ҋۂSN{@77W6xb׽۹}kq_77_Om2`ԭ^ݿ?x"JES Zl`ddg +d].y zt%7-Jm9vpV^.y +mUjuxnSIkB[]r!NU"~_trbNAwhj`!PPz<U*x ^q9=ո =#S\S<=A(^[BCLqndM(J:M:RW)yTM KQͷ\[Rʻ(~𿠼vwA=q4>mA0CP z֫>ʹYJ|&Js1D6~0)\מS71{ a]tos/%GsWj)7oU18G=OqilL= jveC/^ DJ=;4(s *ύ#_97[Ix&;>%Oz1t[)uNPBhow7xp67ݓd7S:B͔h9%alc"ȅw~-UЄemcES _VNI.ya_Qt +ˆ'=Sޮ;;w{=ٲ͛o;`Q|ҋۂHyzMW{{{w]4aܘaIy:G-dn(mTЄ%~ڪAV#<0?'J-y-u:T{''b{L\S0ޡ@>5ojg[E9r5;gf|rӹ"3E sVv\W&w%A Mn`' D +ʠԫ;Ao'ˁ#>Ő^ RHP(^ՇA&-5Nk sk5=Z2?\GVj۳K_Qt +fqd%>Ő^ RHP(^ՇA&-!NUA/}I/Bz2@>5QCzE Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP 4 bH/)w(?XPYCzH!CBz' D +ʠ+h>Ő^ RHP(^@I/Bz2@ +Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP 4 bH/)w(?XPYCzH!CBz' D +ʠ+h>Ő^ RHP(^@I/Bz2@ +Oz1;A, +W,|ҋ!@ޡ j`!P@f^ "eP jB:h{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKBj{-TOz1t[)a;4([gKtjg sj;+1]E}m5PU^[3ǢwQ +b R¦wh:j`!P^ϖ)jM'\?--/-HrngfD=<Ԉ@Hε+.!W.aw(ςP^[r/V7./{oMOz1t[)a;4([gKZt,/-۳ٟd<5f^[:3sZ)D2߭#?ɉɑwKXa%|ɻ Be4ƽ6(GՍ_t8_K޸N{,Oz1t[)a;4([gKWoW?,f +TF- *j'DjW*Ѐل4)I(-AbwaԀ?/ &%6I1qG&3nmνw=yۨCW4# re.Ao4=yUdJٟ kJ%y"ߟG g^T E{ M8ٟHܾVfʱ ٖ -ɨKz-]^m쬊t0D9taB靰GbWϖDTt.A`UTYܨnK -T2 +!V kM&9m dӆ}`&D$ׅγb[]Iu.4~ ("P=;b??b@JْHMCWt fTY++RRij}"1YC@30o]3"k Ϫ7$8o .)Im|Ƀ￿o?k+N.1sŹ,]?^:kC!N#D+gK"qP*J: 0J򪡏#1Ke3܇5V+e$>(쟄gJ f!x`$f7N$n/[+/|W.%1 h[9]K5uB 1 }%lI$`"1V }\QҸM$s%d c.A"f-UeЈ*q6 4Oދ;Dbl[qM˅$.{_iw]B' ~3>BGvrzl_[p!4M20+۶Y=ϋ2d[u](qeh+"ʫ9w]yFW(!ľ-L$ƪ+JTT@fD\!l ,gB , /<7DZ؄а9{ѿ\W77f<5x0QN/-k@Ğy:K`Yi +4qB%uk)mzb@JْHDbZ)qJ%KFE GzOG=W]׏Oλr)5)xPM98/|sKO9>rK9:}bա7饳e~mÅDvX"̟ߚ%Q`^ְ=<7B 1 }%lI$`"1`4J%qkr }\QҼTQ B%֨p`W$qpP3Jp>sWx[Ͽ>u~GSHlKz1 Vk3k6rzl_[p!>(bF?tM.47Hm-K{8 ,4m.ι$cZ%2ikChK̋(6fIC)(ň 7 +$ +  kS{,T2?>*t@A#)yaź"ũ+ ݋ah.v⺮T3,KӴ8 lcrEKdPT-:X3OߏKj%L,_ʊv]3\ƒHP AU%A ]<1x)%=Ddߥws$GOۑߛ?;q' {swocEF^_kϝC˾yq䕎A%•H} ]??dXX\1}8?̎g}V$Hm-n.eYiϨJ]ץUιx4ͶjisjQs(dOhLq4|ȘT(hP-1Zrv"]?،{_[BAP ߵ 3wu#\,==7_,B$F%bVT.g ݋h +vضeYsIZ2Md YҼ!*:'WR;CMӄ}|ȘT(^;!]?B 03\Hmuwlv_9.3+=%H{m&mVU4z\ץι?VDz,2pM5(Ky#M$O4ONhL֌(S)o<+H+菏 }L03q3RtR"\ѹؾX,HKt/ЦlseY1mcuiLNWlqi 4M]q@P]^Tt +l +x]838m+4IpE/+̥;''$Hjgg(Y^GF~E&b’=-Y3s?B .܎>'fL*NRUK]okSب^@HA!~ !Wn,*U>6RI{e&,'x2bQ +vZڀ/Iq0Y4-X,N2,ϘSrVfѱOnHte^F 3s3_˛>FB +w0  jV"ԡSӅ1W䷬*ZACcԴ=R8X,ʹ&fs7~C1iS1dg^[O-d%L1x-Y=w䁧zQ C`@B 8' DT58u=}$ONeUDQ2Zïi^xҰͅ[Wg>ťv+wCUXc 3ON^h4;Obz!;@p^!YoAdeU;MˑZ,N49 }AU̘L151]>|Լ>脧zQ C`@B 8hZN"U>uT5'XX{z S>I];8%)ι(F#*1 +Rs~Nx )[?%#`T"IX,!˪,' M S>ʻ C:u_ +}N*KR`R/T/6RFU7v?@k~;JG(+ IIJQլ{< QKX,ꍡGI&wf&e9'r̴yǯi9zS9 +bdĒŧgJl%:^lT/ _w4v +Jk5~ m0y0hZN"Uu^a~]ϓF}; }`YNuQmFx3߫bdt?ίնT/6Rޝ slvCa\8bl~l6{n%7y5!r/In?9!+iTUSZ8,2S&f]j;Obz!ūFOVݟ +tsҏS΀#ǫ^t=/nŢ!MFa^,'|o4#$}#-:?SKb dbxyq<Ջ;#z&[ۢp/v +Pk㍶l=~ҏ銧#<~k^fz1z[3&S^lT/ xh#{ZY{LlxMXح6W6[mt\H9>q^&w^T)% b|Y;^lT/ x;3:/qyK/θ9:7^_{dҏr\4''O u k`9tILb71Uf9jo{=^lT/ x\kgkKMun-ϱq##~:dL'{]pN-/k_>m#W?I +za nR^c]]lm΢(HP?5e9<7oߐ36_s?64|}w?];~No62_ܺ +ɾ/ q82{Qz@lJ).'i&\?DlkB!ͯowƅ޽o2<Ώ?~Y9K __ =NoTḱVuRGOo"t9X<œ'~~Myp7l'$ [KKp5QԆ}!3z~b=|ۿym?Yf%/x|孭Wä7zWD_/( "T1قAy2r fœ`__2[|JvnðNP .ϫ;NPn 2Xt[YEqAd7"`szyz! H'e`۝>-+ZP'@9/CEk  鱡 =<p&D9mlN/1O/d0 7F]IזaZ͗JZ5!3 [(f 裨m;NhAukhx^{tc FTb=bC %nx|OBџB$/Z 9ʾEJoQ0ВdK#Z5!3 [KKm*fPJ +^4 t1( 9yMzaS%aSNEYn'>``L;)I#$"M˗//>p}݀6Hi.R<jrVe/e6b|n#%$O*)v4T#a_p&dak)|uGy5iA3h{ǩcEo^ 9vxD1Ή"ATXnLbp)y}JDx OȻI$.]xիW>euuuccx;NZ][[n +K Y0G4&Z(Pf[Kjdi)?* Y-ujX㪔W`#\!AЄÕDQq*մLL !-I7[Rᘝn#Gs(hzC$rtt*lN/1O/dP4&y-9CQW_i/%{޿~bEO>%#_GqFO^Kbpp@oUUFx') + <-48a1qszI0j2L7M5>c["H3L#g~ \ibcvW~ +VUU (j7J y$ dt/e'|eŐτ`0²:f)Wk}}8;;;IEѢ5Tۋ/)r(--u;x1szxyL$޿x3]B1#' N>ukAE,kkkgE@ccǏ9ZYYE ,sK&'{zz{ +Y^^<==q@@~8vޜ=}4Einn&i bmo:I(FylvɜJ$|3"2NKk[]]}Zڵk4^zUU^|`5{ %-2]4^?C(_GqFA\4CQ4ðmD_XX* 644ܻw͛7xfs#O 掎C\TT55֒ɤbUӚLM_(/ c()ᗖ(dd}Nte!aƉKqzoFUdYytim06oFDEwc>^}\-s^?1>@ʲ_GqFA\tvv2 KQ`x豶jllTԩ!PωIҥ4CCCC, n:r~iP,+l4VABUAavvEQV+FJm׮5f7'.I Q3NKUպw߾39s8W߯۷XN/< HVng~ӲQܯA$+Ph׮f mÇ + E3 }(ƍZOAN:uuyX,&xxo[OAǽ^o}wʫWm嗇V|<5{I^5e5}D_+qd$].A' ?}(inI [ckkΝ R + +6%ɭ[%nnn]׫ biϣ}nO$UU+++Vu~;vʲu-ڳZ^;~Ѻ¢<5{y[}(+"%xћ7o655%-JjTjs9Z]zuϞ=lǏ u={Vl)ˍ.\8uo{=v^]TT4bx[^nj.j#kTZZoܸI%A:EwygϞ@ H.@It#6??φO!;ݞҲ/^du>kWi~Iz#ZUUKO|FGǬǧ7VTTФ(KKK_?4 Ӽ5L&w"[4 O}гh1JMNNgcMc\z@Դ8텼셗^覽mc5jz.}PrwwOUU$TR}x r <=z~&lnnvqqTii :thvv>YiC]]=UUK-Eo;\r޸{woCCCHĚ4 ̙"ú[zi>ںgJJ?r䨢(l(9ןlɆfڋ^[^x Vf_fY}M ^9ZI=*H&}}}PMMM<AQ\.AӧA/]t\;OOqk׮566twwOOOaDvikk;;;_|I+[N&&&l0<<|Ν/5772r"x?iZOO-ۗbp8| 4@}jjvuu elE1K"}$o!{.y{a£C]alJSf5Y)3l^M?VC Eں֟[]/^$xFil95ݬeT6F(J.@P(֟n08`$DTLaڣs.հYLH/TzLNϫhm`AQ\.Ph?g9[(-d/YEyf|nw/YhmoK[D:޽{w?g{nJb + -[d[T[ x 7 kov<^8lbPԏFC6ݧ_{0gi)$IR uQ5!;$T8lʩ|N]_Mo}<5m86PK$m\tZK#,C9͏f1q>|(܎: G?$I;^ gVG7F3֎O#'O3+oqmy/]}jӛ$Iڢ{#G[fF=P7XJ>}^73 g}}ޭ'fB$IC"l4c*UM3/Ͱ}o0x۱:j itOWÆC$[vEXac*MP3֎3O&`A]v3*=7G?zmb$I%¢"1◫;UOv.ݸavA>}K.z5=õ.|꽧~sV/>W$IE),Š[",+kUI4TqtzU삡OWMwNU%zw_t'_>=}s_|He { ;!r!%kɛ$N6~:fݑ0.Վ5e3V΀t}x~\;$i { B;!9q6-CLڴU4cvJxlY[9 Vv$I"/=8Kb En*ux.{}]\ya"IvզPG^#]Z)tl֧ލIϦu1 9!I- oMX&q]|v0O=/~$P-g$Igڢ3#C,Y*E1̊=xT= մnj$Iڅ~]Ѧg[l8EX|HK϶Xi6T$Ik)E]:M}HG?o.<btN I?m\y3ѦiFk=~Syti'4Ň;G$-[9 6CW,1ֶG'%6@9hH}4 CWxcy!-#G$-X7 -[P̆~+$I~֝ + 1~>F$ZySsB$[[FIt0$iwx07 +endstream endobj 232 0 obj <> endobj 234 0 obj <>stream +Hms8=ĪAJJj:^ww2sg~C0,7Bb>b-iEuwBeKZvhVM5d5Z]Mz >Ee5۶A;Tq~nG~eUGg5|X?f`Yb<]cT<%l+59%9xEj=&'씱,uLB=gMC^' X#u>`^8=U;q0gRgm~ +T{\8a<.^3Pe*բn21ZƻxY~ J{t+5}vxLAg+agXR+iHW¥gω:{>E ֯ދ#Ly yk΋wzv=Zn뤞OW墼QUJyN+z =zCOSo7z =zCOSo7z =zCOSo7z =zCOSo7z =zCOSo詷"-EegΕg!4 ޣ.Ef O B{O0J ߲z|Ʋt"ҭѫ\zj,qR`|9)0VjVp򔠻x9̬3jPB ZEYdbw'N1p.: +1P)&8<ϞѪݝ8th'*P΄1Τ^Eg4|Đ׉:>X#u>`^8=I7䄘2I6p8="BWo8 +~Ltad,ekwy=]nG~eUGNqm{XlZ0^$3Ftk.vKx&Qz΢P(lInR @Um:b5&iİa 0ܖ +endstream endobj 220 0 obj [/Indexed/DeviceRGB 63 236 0 R] endobj 235 0 obj <>/Filter/FlateDecode/Height 84/Intent/Perceptual/Length 1320/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +Hջk*yxm AQ+X; lDVATlX +* +Vj +A &dٳv  -gwlʦ&߃aB)'Kdr%ܰrD1IyrbbPi5-Q)p)J F 2$TWP^Ib;;,f=bsOPoVCP0zV c2%iuT$'IE"E#T5JvfbaEz1FoRR Gch85rIH &|X0dk@zKf+d\pAӫloUрè?xjtlw=nݬAsOl^7f5vxi{HќގÖB'޳xpq<Ÿ(?LzŚ_`zS1{uE l D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тh}s=zrv|g4rsdzҋqQL|y޳vܼ|m{^~irzg8[mWaY͆z>r~=XLvۃvz9kX{j@4[i'劦׀ ^-g~F?.7{t6_,/+Ll:to7rqۼTT}p3j)Eymz͹'O(S,p,Xmڝnv;V=J&zJᣒRR7OF^K$sIS }ORl._(n +\6QnłSO>&S[/LEx"\$X4B}[#a?;b\}c:<^ z\oԸXǤWjRopr:6YOi")$H`4̀+hHBKE߃bbPi5-Q)p=Kdr%ܰrD ?dLR!`}#) +cSU , П +endstream endobj 236 0 obj <>stream +++'$$$$$############""""""""""""!!!!!!          +endstream endobj 233 0 obj <> endobj 237 0 obj <> endobj 238 0 obj [0.0 0.0 0.0] endobj 239 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 20.1599995 663.5654297 443.1102641 cm +/Im0 Do +Q + +endstream endobj 240 0 obj <> endobj 242 0 obj <>/Filter/FlateDecode/Height 84/Intent/Perceptual/Length 1320/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +Hջk*yxm AQ+X; lDVATlX +* +Vj +A &dٳv  -gwlʦ&߃aB)'Kdr%ܰrD1IyrbbPi5-Q)p)J F 2$TWP^Ib;;,f=bsOPoVCP0zV c2%iuT$'IE"E#T5JvfbaEz1FoRR Gch85rIH &|X0dk@zKf+d\pAӫloUрè?xjtlw=nݬAsOl^7f5vxi{HќގÖB'޳xpq<Ÿ(?LzŚ_`zS1{uE l D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тhAO'Z-D z=тh}s=zrv|g4rsdzҋqQL|y޳vܼ|m{^~irzg8[mWaY͆z>r~=XLvۃvz9kX{j@4[i'劦׀ ^-g~F?.7{t6_,/+Ll:to7rqۼTT}p3j)Eymz͹'O(S,p,Xmڝnv;V=J&zJᣒRR7OF^K$sIS }ORl._(n +\6QnłSO>&S[/LEx"\$X4B}[#a?;b\}c:<^ z\oԸXǤWjRopr:6YOi")$H`4̀+hHBKE߃bbPi5-Q)p=Kdr%ܰrD ?dLR!`}#) +cSU , П +endstream endobj 241 0 obj <> endobj 243 0 obj [/ICCBased 244 0 R] endobj 244 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km +endstream endobj 229 0 obj <> endobj 231 0 obj <>stream +HnH&ᔩ2b![M&'F b\?~0v3eQ跘w~Iz"? ]*gɊvm0=jr +z9s~UoCvYxU?_@c sy=aeJľ/rҥ%zvzγPR,KRݖ2S3ӂӉ?tma(-!D%)dQwݡ?<]q-PJXמb-Svy\$-g,IG̒f=H{VZZ%5%onU~><;/-&Mqxy_{~MG7*pnXK|ʦ;=/!ODOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOlFOl/&Vktʳ~nVh7WLf=SgJKKQPRXJքԭJg\$->0X>HUVj=w-gB)a]XV eʮS}xFp7]TMI34iG-em3ܮHhmyݩط}h歷'`Ym{[39յGT -S޸Q]'0]]fI,Y]#lwO'>gY-e$sg}c)icI2ٝǟGギޜ;rcIk5f4v괞}}_ް1뻹#KZ%g_瞇 +endstream endobj 245 0 obj <>/Filter/FlateDecode/Height 226/Intent/Perceptual/Length 1695/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qW'@"Q ĭ!huk ѶZ1qii)ZEAR}n]s;} wb跡גjSU9FIAj5rO9No4$")#2z %U})茢b;6,u‡RI8cs,8]nKJyh=!"[瞟uZxq^ +nFcD—H$Fp1 +4:7ãd4Mʜ'Gf紉UZoD3ً|//0Fbh7v|+K2)Q*oo +nhqbT &sy=z]+Zתu.s]_vZMzZ c|Hrh/ⲍzԓSvk${Soڝ3)[MdOM?xgu;>_^u_[ۋdl{37{"eh̠nԊx$ ]IKNw6$ec?My?{f:AJ NO?> endobj 246 0 obj <> endobj 247 0 obj [0.0 0.0 0.0] endobj 248 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 54.2399988 663.5654297 461.5902624 cm +/Im0 Do +Q + +endstream endobj 249 0 obj <> endobj 250 0 obj <>/Filter/FlateDecode/Height 226/Intent/Perceptual/Length 1695/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qW'@"Q ĭ!huk ѶZ1qii)ZEAR}n]s;} wb跡גjSU9FIAj5rO9No4$")#2z %U})茢b;6,u‡RI8cs,8]nKJyh=!"[瞟uZxq^ +nFcD—H$Fp1 +4:7ãd4Mʜ'Gf紉UZoD3ً|//0Fbh7v|+K2)Q*oo +nhqbT &sy=z]+Zתu.s]_vZMzZ c|Hrh/ⲍzԓSvk${Soڝ3)[MdOM?xgu;>_^u_[ۋdl{37{"eh̠nԊx$ ]IKNw6$ec?My?{f:AJ NO?> endobj 228 0 obj <>stream +HnH&ᔩ*Sb![MuOLk_!M}c,J~y.뗤/`٥R{j'Уf,aa.}??_N=dIkW 4|_ް1뻹#KZ%g_=՛3p#lXZͲ=m`tЙm}]dJ-zV3geY%e$sg=ZB4KR$etmaC2=yjcSݚ a_IZWƍ28ynl$*7Qy 1ys.ZՔT'KQK颥"|xw3Fמ1X)NawwO0`T>ȟs~`٥R{jӣ翠qwNr>u`gLidw8^ +endstream endobj 251 0 obj <>/Filter/FlateDecode/Height 159/Intent/Perceptual/Length 1531/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HձK: Իδ @t! \HZhii )ZѵE'Ak(y漢ty/o𝘀 % zJ ð$eƢGSrV>=nr%'xZqYoOASS˒<iٽ$ +N~j& ;53'jp-Fւ-LQO3s?ƶwvX4Ks<ǘGsgmNQZو񄲟Ldr_IƊ$:mp& nƖO2`L$}|x[~sC#r2/B!8;JɑWtXQOosO9:^Kr(K[ {Y;β7}wفySX^/+Ft:RlT+0i2ON`,q|y{hu{Fjj^'bA5= m%+Vǧ~??=vb.lyF=-zIt=1/O}){Z~&3r>g]+2u吏GBQoo``W;r'gRZ9'/ݷzO/o`Su_ʟx%x(GZv/lcv^p-8\q짜Ai vc/9&aI2ZLKIZV0Ns/Ua , ,N+ +endstream endobj 227 0 obj <> endobj 252 0 obj <> endobj 253 0 obj [0.0 0.0 0.0] endobj 254 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 38.1599991 663.5654297 515.1102645 cm +/Im0 Do +Q + +endstream endobj 255 0 obj <> endobj 256 0 obj <>/Filter/FlateDecode/Height 159/Intent/Perceptual/Length 1531/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HձK: Իδ @t! \HZhii )ZѵE'Ak(y漢ty/o𝘀 % zJ ð$eƢGSrV>=nr%'xZqYoOASS˒<iٽ$ +N~j& ;53'jp-Fւ-LQO3s?ƶwvX4Ks<ǘGsgmNQZو񄲟Ldr_IƊ$:mp& nƖO2`L$}|x[~sC#r2/B!8;JɑWtXQOosO9:^Kr(K[ {Y;β7}wفySX^/+Ft:RlT+0i2ON`,q|y{hu{Fjj^'bA5= m%+Vǧ~??=vb.lyF=-zIt=1/O}){Z~&3r>g]+2u吏GBQoo``W;r'gRZ9'/ݷzO/o`Su_ʟx%x(GZv/lcv^p-8\q짜Ai vc/9&aI2ZLKIZV0Ns/Ua , ,N+ +endstream endobj 223 0 obj <> endobj 225 0 obj <>stream +HnH&ᔩ*Sb![MuOLk_!M}c,J~y.뗤/`٥R{j'Уf,aa.}??_N=dIkW 4|_ް1뻹#KZ%g_=՛3p#lXZͲ=m`tЙm}]dJ-zV3geY%e$sg=ZB4KR$etmaC2=yjcSݚ a_IZWƍ28ynl$*7Qy 1ys.ZՔT'KQK颥"|xw3Fמ1X)NawwO0`T>ȟs~`٥R{jӣ翠qwNr>u`gLidw3 +endstream endobj 257 0 obj <>/Filter/FlateDecode/Height 255/Intent/Perceptual/Length 1770/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qԴii H b`Pdh-B8 +-"DA szu˽>>|'&ےjUU9F} h9꧜RLAo0LScLF^>Fq2gwجsѨ>r&Eվpn)vE,NӳvǻWIJ8ӓfSՋ ._`}cs{'KJw77>¬תsfki-ُ)Hc^hme7Uhuֶ"d*}t|!eNҩd,sXEh*a "\P,IRX粇Pc1h=E^\VkDZ)_]ֽ㨧Z097"e~s{Gԯkgddc1gVs?͇VH_*=4E.wZG=Ujݔ؎WSLJt:OU>lS/wĎ +zZ>r(=qr|^^IAyS)AgOnT}^ކKp[-$vW=z=3]#%~uW-e{{dkwg}uW;=Ȟ |dObO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO{䞭/zSk=RՑz22CguW-e{N<)Uo:!)tb2/SR<=rϕQ\o~@_{v^.vVqO+M篮N癔t|:pF='Ԃor}j+Rf^ȥ7NIPOz97"e~s{Gԯkgddc17-URHjR8;={-Fj0cBl._(JDT,sÃH(=5zmEbT$CʜSXdk簊zͨZ0^d?'D"E#{%l~w!iX R͍ϵ0+?ޑT*e%`r?T%~`Ȅܵ +endstream endobj 224 0 obj <> endobj 258 0 obj <> endobj 259 0 obj [0.0 0.0 0.0] endobj 260 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 61.1999986 663.5654297 552.5503065 cm +/Im0 Do +Q + +endstream endobj 261 0 obj <> endobj 262 0 obj <>/Filter/FlateDecode/Height 255/Intent/Perceptual/Length 1770/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qԴii H b`Pdh-B8 +-"DA szu˽>>|'&ےjUU9F} h9꧜RLAo0LScLF^>Fq2gwجsѨ>r&Eվpn)vE,NӳvǻWIJ8ӓfSՋ ._`}cs{'KJw77>¬תsfki-ُ)Hc^hme7Uhuֶ"d*}t|!eNҩd,sXEh*a "\P,IRX粇Pc1h=E^\VkDZ)_]ֽ㨧Z097"e~s{Gԯkgddc1gVs?͇VH_*=4E.wZG=Ujݔ؎WSLJt:OU>lS/wĎ +zZ>r(=qr|^^IAyS)AgOnT}^ކKp[-$vW=z=3]#%~uW-e{{dkwg}uW;=Ȟ |dObO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO,bO{䞭/zSk=RՑz22CguW-e{N<)Uo:!)tb2/SR<=rϕQ\o~@_{v^.vVqO+M篮N癔t|:pF='Ԃor}j+Rf^ȥ7NIPOz97"e~s{Gԯkgddc17-URHjR8;={-Fj0cBl._(JDT,sÃH(=5zmEbT$CʜSXdk簊zͨZ0^d?'D"E#{%l~w!iX R͍ϵ0+?ޑT*e%`r?T%~`Ȅܵ +endstream endobj 219 0 obj <> endobj 222 0 obj <>stream +HosJjeW.DKW'S>{31\ewwLtY/-=oI/ʳ`rjT3MXq%Ujs[zZg-.3Єc{|O(k;Gx;,Gwq'c]tmnױQ3 7m& 5~F?;ZA2Z"\d=C0LŹ*,Lc1^pMk2=PU.cyXJhf#:;yf{bc/s1+'*8y6|̔L0^{ԛ(ጽVfw܆ˡfU +Cp{LZBVMp{<˭WL&= %حPw>=sNԩqOZf:;ltO5řL7\uzlmKKLm?<RֵGZb>QkwS%Z"_OT䮞/>Ó&xOI>/Filter/FlateDecode/Height 134/Intent/Perceptual/Length 1463/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qdX'瞙;7dA67 ^(_y~s +j0) CH4FŢp( +)c4[Yγ .E[6Llm"K₇c .Hfwl6#S(L;MK%0Xdisush&-"IRj|r|x+Gnt,v䃣˫kEr}uy~zt gf5 ťӋMqcnyg]yܓ7R}n?WJzx?&mrNls'7wNWUUvZw7'VD?x?} kAԹ_r"=cLrhu{/`sj\W +dLi3-V6c^íR-fWzr=KUV`p:PMZz}[:5OZ߆ݬv= >=AdГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'{/zӰ=lZO5fTMZ~9޳XUny{JsCO,)Tnyyu[J!4= 9_wz6{OU9/'zOJN.oZ>n.Or魈879af\/?>[vUzhkw1QYo(.^n&sۨ.Nx;;i:gk;յE9><ؕ#m]Zݔ\P,1B>'KK^c-f9-˫;R*-g]0"锴, +N{< Rd-HnQF|-$.x8gS‘hlE#P0Te`zT%`L +endstream endobj 221 0 obj <> endobj 264 0 obj <> endobj 265 0 obj [0.0 0.0 0.0] endobj 266 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +80.6399982 0 0 32.1599993 663.5654297 613.0302473 cm +/Im0 Do +Q + +endstream endobj 267 0 obj <> endobj 268 0 obj <>/Filter/FlateDecode/Height 134/Intent/Perceptual/Length 1463/Name/X/Subtype/Image/Type/XObject/Width 336>>stream +HտKr qdX'瞙;7dA67 ^(_y~s +j0) CH4FŢp( +)c4[Yγ .E[6Llm"K₇c .Hfwl6#S(L;MK%0Xdisush&-"IRj|r|x+Gnt,v䃣˫kEr}uy~zt gf5 ťӋMqcnyg]yܓ7R}n?WJzx?&mrNls'7wNWUUvZw7'VD?x?} kAԹ_r"=cLrhu{/`sj\W +dLi3-V6c^íR-fWzr=KUV`p:PMZz}[:5OZ߆ݬv= >=AdГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'-ГzBOZI =i'{/zӰ=lZO5fTMZ~9޳XUny{JsCO,)Tnyyu[J!4= 9_wz6{OU9/'zOJN.oZ>n.Or魈879af\/?>[vUzhkw1QYo(.^n&sۨ.Nx;;i:gk;յE9><ؕ#m]Zݔ\P,1B>'KK^c-f9-˫;R*-g]0"锴, +N{< Rd-HnQF|-$.x8gS‘hlE#P0Te`zT%`L +endstream endobj 205 0 obj <> endobj 198 0 obj <>stream +HWَ5}3R{|oR]˼AHyD($2}uUwUd rϹ˱]=; Uw͋/~_ .X]Q򥺻8v|Ξ}5L4F䥤r>Zs1d{' 2Q >Fr ^:k F}i$FO65{L tW݉siVbRv 秚fVT<*`R>`Y7Q^̸Y}ѐDi*>ItkI +HϊJ){1FXrd'$`T3J;MvLt  +׵Eptk -wfNȓTn"Zq7ݣ#łS%.hiiqa4[A`\gإć\Q n܇\=-Gp.7dD[FDKaqA3<h$4pSE [ +);G\:mR;ËcWsӅy#A+>[{hc xNhZ]EJf(K8MfxB|= (<l.Β2z̠MU*/x9a抠[Pm>1`(EdKH3s1B^B:*a=̺{F _,ճF^v7Wxel*gK@|>Q҂ș=A0M5SDضIAI}V{V2T1a`$0\.pFgMXƨ<g-5q_0y:d\Ӂ=ߑ7Ŗ{dsl~ uĻ{}vp4Y;c[Sh*CP4U1wNe5<ԇ(b~lұ5dT΋Y}Ϣ0*i¹+!PeHc[-m<RKid6"*l$[ܥb*ic߶r2%%M[ql"96hNJF  ffFp nS6K +l=Ů{gܝ9VEE0l+4Ǵvd#t):ZdwByzK?~9oj!mu 9=valG +Fslx+d-mhoy to2#4&ۃ`ccTRʰ9v#]Y +r5] %m~ʋZ-xJ +endstream endobj 199 0 obj <> endobj 202 0 obj <>stream +8;Z]"4cY1L%##uWI$PN!Tqn.#j:]r&-8aC&[BHos':-EFL'^VNe`O3^cNs)PhBWrV +7Qt2>Dj2-)@f:^[&5sJX&0&9e@t70j)k +Kmm!=Bfl\1EG=G?GURYOPV-HSW:./)2nWdO:CLFWmWDXok'O:0.PuLpm +@CJj$79&T(:p=C'KP)U%q)R&)RSu)[E&"LFh0sTMQ14[R;G;X11kAJYE.pVoG,*Gu +1`Cjs,&c85.uI]>We_@2YSY0C03B+eS(Dd3,mN6=[sC7@!2X1XE<~> +endstream endobj 201 0 obj <>>>/Subtype/Form>>stream +0.141 0.69 0.502 rg +/Perceptual ri +/GS0 gs +q 1 0 0 1 160.5998 508.1125 cm +0 0 m +119.431 -172.677 l +-89.847 -70.594 l +h +f* +Q + +endstream endobj 269 0 obj <> endobj 200 0 obj <> endobj 193 0 obj <>stream +HWn#E}g$7 !Ŏe}@l%_ם5NUw:U=}3w9uS7{={#G.%}.mm~{.=T0vR9{˚O/H=wm ̅|&;Wy2u9gW_H.>)d.E_2c|ҚqQ_6qaT8*b`A{ap>%]q,PKȊB:G쒏Z+nSK1bB.C9|DFv7MI=gRJ`hi\/v2, P<CG@3Q1oڝDZ>b]T*utB'lW`U>+v=J."UV{6٬r1C +RQ1*=ݱuX7q%?TګC#(lrishc-Kg+z)/6~(.)#/fiW,؆eŠK6Z7K VV +,pPǛjX e iQ&4-o| JbqbF%A&q0țb:k<yx0Zcxsu1le`{Û ˠ#u ,AB +2 (A҈VW6#PuR=! yc}@x,< E6?|_G2'^υ+69OjMdPf T:KY+裌QOO ĉH%i%XO ?ʇ$(a JCKޯc`BO0(] !Y>̹0LTrBF +ʥ^Y ^':Mg7ˢ_n/n}4!)1!xe+8)qΗc(*ˊVcXH:rh.(c{1de #/9 +*RZFYCžiyC3VDU3Cv3#.Bk4g|Lѹg> |L 藙cYfs"p{LߣcTCJ͐Guĺiv@4`>9DcG0=cQ{Gsh@ +endstream endobj 194 0 obj <> endobj 197 0 obj <>stream +8;Z\74-kIP'KsLZoPT<D<=+*R=0 +VTo[8:@f_nNk>0:2'!/!'%GIDc-s%)W_K]J%6MbO3YPJ^k)"Q*9!6Zl/TZ_j(8Xu[ +\e0j5/Z94Im`Wi8ImtCj +O8]+RP_+G\<'VginMQlZBCFBt@)dj2q4aY`EfB!6;;;0FChc7$bRJ,-IVef_%VE`n +bU]5EX,&gEig>8?s.Hpn*uL+i7EgB7`QH@@gTqAIDIRfMofoG`U8J,oaZL1_VZc;h +[b.DCbER;*7/GAFj2>\;LY:1"CU'U;!M9VIaQZ=u9^P;Ib +m8!]2bgMV8F>TkWXSh0UgiHF:oUrM(D.u[Z5T=e+I*odk:l-eH3?];K0eG]Achd[+ +#FRAf$d/83JoWaQk`fbp:\Q1mLXj8^-G99*?":#l1O"f;j%mL:\JF:K$J9\/G!mC! +Ud%;BJ$Ah)=0I*;ZArRVh>Q@]/!2,jm%5/@lrccLOf;=*\>1ar+u]kM7fFNZ#6<7YVBQ~> +endstream endobj 196 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +0.043 0.188 0.557 rg +/Perceptual ri +/GS0 gs +/C0_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 118.6989 0 0 118.6989 591.2881 698.2305 Tm +[<0026003200310037002800310037>12 <0036>]TJ +ET + +endstream endobj 270 0 obj <> endobj 195 0 obj <> endobj 190 0 obj <>stream +HWˮeG ?pw]Sʨ#ƨHY=.^^v}7ׇߔ7z_~x}_>}//{}rW5θqs}׳|0'Ɯw)m]=ƽ>c~zEw-z.w[rv|~u FXU=΅?}_dOeܽk0ޯ +cckp\o=S,Yۭ/{*okuڸ\[ĎC'Bsvz7"=V>]T\kkAJFr;|NB!cJnoZgݣ| s W]xDhp{Ր# q9AaͥLj6/& +"w*7 }#6'Y`8^`߸ZlU^a'^$5 Ҩ҅mAG!.nq vjƳ+˂ܔGU6JĻjYF^)P3SJy^f 8ͻ}t;Rv}7Nio鎲p* ߐ:4N& _Q2X%*GIllk[gPN( +1n ^!;=mvòE(Ħ %mg)Ϊ |Z98-T2R[UQg!nhT +$&πغwX>bv 6G u; +P𻵙F'Q?#m>)ߤWXX,W݀UX$*6.T)RjHud2lZdהf+*P-lD&S_$vT$8ŕ)w@^߇ ikɏwlzY0ߢًWi rUjV` C4# o6 X9W;bVXo|?!B-$=2w0@٦8XٕRϰi;|,lQk!1"s^Gzq4Յmځ0/QKڏwz}>Y!0;Ur\h2\X;#8{_`ĉ덓ſCU5Fd@Ad0HK%<<8a24(V42xv}lm(Ojڱ],hd9@(; 6<*)<6țXV@A%X$V9:1]NMET]3MhfnsqlС[7]rQK?nj2Xʨ` + =[H}}p`3b-J͈ qtվ5xifm)xqV-W^E ljtׅz7jy\*>l[l:";Kz4kC@;ͳT`Yt9c;ž]zw T=݀3ӄΤ cEoVڱs=zHJvtrZil0UA߯gԫOF]UB-a/g9t?f^][tV6ݥvT-}dI v2 9z=>l+02MeJlbazC3LXyM2ώ9{هmh3i[ZaR=97$sc1rrj*B3+a +%\> ՘s0zb*fГBI'T1v2i{97 ?4Ew}+[Ǭ66CGK[= ^J1ISeZ9Mi7; OX Ka.=VCODzLֳ<'cO5Vp"[佦^،1'jnJ+l`ą-XGVjvnK؅vז3XRŀciGDZҸ *柽NTYfR5Xq/~=kc߹ |QeNǼE{R;<zeSgRn{M>ֺ_6JET4CB扽%䚚x6yRdiUwF\+N!K2ץ'M_I5~ jP|7Sf"V̈́E7 vԤbN-Cp/+ZV!0M: +Ի:[DXꈥ(a]%ά-:*}xTc& iVE8!iׇ:dW)SX۴4tfE!WаQC٠MMf _Ŋq!!BnFXTelwUʿ2[HTدQYj5=Yd~CAXVZ=7R[ =Tdۉk. 9(hran7^"aZ8 ˧tL;UR7/jQ^ +5B$yQXSUuA߁B2pڀ!T34Iƞ3z.<,k7e^0ұMoeFgcCǴ(FUT& Yb\ZkX$ !JG_[pvBr#8.MfڑYf? \V}Į)yTjɷ0/KB(9K#Up!mX a?wj5J9;w +,HP!Ą L|:$Q gXL  G ˏ/?]C™Q4vGnf{U0xI%&BY(!Fp)GXِvi[ȵ^7u.۪TEQ԰GH~W)c*j1k-vfn p. hC+e@Jk#}S#d@嬄e!9D@!@QŻ삒do.T<,vr_b?\H+.i13Y#I_m:Ҍ&L%daufn’POrݽ_ju/?j H *Polje];]F9`V;B[ve2 `a9T6H=QDgGFvKbM^vJXYhʙIԔa"њjib sLMpIsWۦnc*QQ5ר,?ai4d&2SUUByzu oLqx@!/-@1w>lL4K?^Yf0ZEt7y~_ɇfh9:8"MD^dKV̜ nsHy36bymk] zb EĎ˥U.<^@4Z)43q+*FǏ-ܹ%y&sd's2L>dt$s_(F +M &aJF&q72:v=b3v ~;pb ddhY6T?HgSHhA@90[Pܡ,]}av,!4.ߐ9G:;FK*\C{Nʴԅ=ѶDFw܏L,Z%P +QmS4,[oq:0( +иc$bCHjpк>J~\shGC%q;>ᱝQ^|qA;d܈Bw47ȴ- i:CS*WN3 .M_Bl'sBD-6IŨ]`5vڜDٿ9@R4Ѽ'zncO1]oZmDp9sL/QJ/Kǘ|tULSqk'ۜ;kلQ:&{`Ů8$x:$ Ǧb[AXM][=S +w>'y= dGg{+;"=*8r`[>1,}aE)H%Y-P$U^-OEO DF;?ߨxq.~@OL/[x@]!R2u|}˟OD*X0$MMh}LWB]!Jʪw)]ThE.&j+cOXpcjf|e ZE+RP$0Vlj%A+P-\rLѽ&&3X,Rj^MKNrsA1 юILǥb2,̈́ʟX٦F+:2p vE~u@V@?MsW(.IfYv$kwe%; +"X)9ۧ\f78uJZȶCbU,b~Zqy +{N_~s:T}H<0U{-g% +Nn:TtCf 3::n0FrVo65Ϳj{??v*q#l+\2TMMFj}'v[@ ?C>Pobx§Ƌ`e$d +M~bwO!M\ՓOTt,UZ(ՍY@z$a מɽ΅@7f5{ˣ QQ `M+ʱ]sW%!#  ӝSxB;xsX}h=R0#K 5%G:h.yBnH[-XC}[>1ΐn毶-P%7`Ly#nI5wm '}hj + z,H15$uQ1ĪKhA(]~>0>I-ab!TY͒Cj{mPqZs%c<$gG;#P6GuYǒV-R1eZݹ#`oi w H[r4&%lBa $_y}&`Φ8EYc`%Wi^E`oT5=q+ @l/`KHMX}S{dj?&A +aY!Sv'!D VznФ8Ȃ`J գ1B9!٘d?𖹽P*@D&lM#Xu +V S{;s2wyd_8*DbDɽ`0nڲ9JE,W wfDAAtڭ)=_ՈQappZrh#N(Cn.AtQ<͏Ί^)ai9|mi訠.;~2Cf%Zb'VS=ؑɷSKwm ?O!{W"F,')ϦP C1v5-[/OAFyVg*0 YԎ^9Le:C,w:Y1O%8MG{Vu׊dVT:Lbaw*9ݼo&F }-f!ڻNL"bNN'?VҧRxJj]YhԪ(^I&P/vNV?v0sի<`UT#Vm{ tG$C/.HEAaD"=ܥ?wf.I`IT^FE iviŜ)>9TLOh%@ƻJq+O%NOV;%qF>tQ(M̈́(mзʠiYkv:Dnj@d.6}]~I_׋ce]>.?yl*uyA@ ߲[ ]_kǮGi;$XBUrSJ8}Yp8W{[E/{#,m;;LqOUټLx l>hf9cf5u+˳ߊ} l[NŨ8i\Q1[ib],G_ Yy\;O_Ŵczf"|V;e};7 }^ṫQk=|woni:['u1 +`^)j\(Y"xy]2f:+B쭬륂{$<ՄJl, +s?o{kBqxe8E'j^nn$!twoӿ樽fm>w&YjۓIaj/^&l9=[-^>qCXp_Sn{//c: +[j]UCKK $ +'#EUᒔU#L(XӧpURM[9sˤHMc͎+ks#NpuGc'd(.WEjNSRιU[A.PAO}b%~ ыҔ6LR_"]XjE& +̢J+oA&\JGSynGƃrWx+2b4NBwnE.Xۘ GS۞J 0eSP ,MmS,JcG0p +Q+y$L6Ƕoniȡ^`M7~v/s*6ÈM"_+t ! %KZ K#]UhW&]^<' L)w`ÅF #EpQn`)R{zT|zr[ I! bi<WwM}4q!;%sv_6Bih'sJ֟2hԋQi\mHCˆVM>mCwj4+#(j3R[q%PՖFA˩^2!8n+VʻF@Vl+hjr޶"$}B\(\h%?TT %GN /[I[u0I9ݣKM%:q,ҔMC8͗pv[d8eҹuZg2ruPIF=SCω({}RIcQhC1ұTIU6dCѮP <p`Uw}fP#fh3DΨ^,k7e0ұ|Ooߗ/zg\6pL@28iUEeR!婇6P K@ х Pbݽ-jΏoaCɏ%0 4ъ:# !xWy<$DŐ/KB*)*rH,\][+N?eI5|qtQ۔UMjT~.2 JTQ@ P~)3Iq5@ eF:ZyF sxٳZI ,ęmsXաnno.@5B(ך'-k*z3,^:P +\4ح*ϽkTݢl`Z% CK*a%bHfO.kV߶#UAuǘp-LYB!&Q7sI@ &f1@=Ye-,,TyvAid*,9hK晷U ~$"Tdm.:dL'e.h"BUO+LWɨKJݏ|9Bh Gdc+TȗCk9sf[UZv aeHιC)vk +WŴ ~yvD-,m?u#a95QEݶ2T *DM^Ã\W8U۾dN NTCGasFT5j󩄦Z2eDzRcl7M+NV=gK(_람', [Q' GWax8rιJsC"~4EL7 ?KpDm6͒Sj[?2yؾc >̟ǝrǭ+,KK +osKL6NX8>SItrzP*%R3L'l*B K ]1yhK%skc `OB$q= v4SJw$?C u6uvXeɰ* n{ʸ!1o.J|ߥjsQ1JR iJ؈JeirK @`eY*4ؗ"F0iꝹb_fC + u !T%>BYk519v@FmʆlH[]}3%wþytD:лoš*|e^>C: +nbÉ7>Ά鼔>.R~9oz`r +4c2φ887cʈd+hhAaQIZHIjzky1ׁռc1Gy +|{sP$HMJ 4l cӿsD-%l 9 v 4l{ja0;*Z95n7b`H"qiR> endobj 192 0 obj <>stream +8;Z]"0p7/C$q3<`iBBbNAIj3tb"Ye$78e/^V+KuOct&Wq]$AHYP7SiZgK:ega_):i +6hEjhQ41Q5Inpdq8Ck(iUG?57Jgr38(nlSI6t&bY(_s+tl,C$am'^R9Us8(7LIQN/ +T8VE49O#Yl9p8/c=%@R^c+^_VQ!OWM=o&IJOLSnY2Y9;Y;NmY!bZ):a%UH*h[DE4j +cLq.m=OpB`A"CVC%14h/*RV-qh[!8%)lGu^FeF;m5f^$6K/\:^I6khnn5o]e$`p2F +FcFKkB?$#3b23_L54;:UpUdAoc=7rNOuak?H6&=(AZ\a*4NXPViHGeX=\GCN'1fTe +?;amNkmuC/I#L?HJ*1MpZcVm'=N@K<[BAMQNEqCglKQ8Ts6rV"eD."#8*7Jg/N' +=lEFp'tmapidI,7q81B!oh+(gQ7C[TjR9H(;dk!EQNUNmH7i-sOHu.9C:b0Z$E7fj +;Z;u:8r5$S`"uG.I*k[5p)H82s: +U +endstream endobj 22 0 obj [21 0 R 20 0 R 19 0 R] endobj 271 0 obj <> endobj xref +0 272 +0000000000 65535 f +0000000016 00000 n +0000000175 00000 n +0000058814 00000 n +0000000000 00000 f +0001930001 00000 n +0001930461 00000 n +0001930969 00000 n +0001931477 00000 n +0001932064 00000 n +0001770288 00000 n +0001770839 00000 n +0001771461 00000 n +0001771977 00000 n +0001495182 00000 n +0000066473 00000 n +0001564409 00000 n +0000066610 00000 n +0001612840 00000 n +0000065908 00000 n +0000065980 00000 n +0000066055 00000 n +0002088872 00000 n +0000058881 00000 n +0000058970 00000 n +0000059064 00000 n +0001772462 00000 n +0000059179 00000 n +0000059735 00000 n +0000060217 00000 n +0000060733 00000 n +0000061227 00000 n +0000061709 00000 n +0000062191 00000 n +0000062661 00000 n +0001624433 00000 n +0001629166 00000 n +0000254766 00000 n +0001766735 00000 n +0000254653 00000 n +0001630190 00000 n +0001640645 00000 n +0001629231 00000 n +0001618539 00000 n +0001623460 00000 n +0001623525 00000 n +0001613919 00000 n +0001616974 00000 n +0001618424 00000 n +0001618047 00000 n +0001617039 00000 n +0001607292 00000 n +0001611786 00000 n +0001611851 00000 n +0001601208 00000 n +0001606268 00000 n +0001606333 00000 n +0001558661 00000 n +0001563404 00000 n +0001563469 00000 n +0001491480 00000 n +0001494450 00000 n +0001494515 00000 n +0000063119 00000 n +0000064730 00000 n +0000064795 00000 n +0000065346 00000 n +0000065394 00000 n +0000066357 00000 n +0000066388 00000 n +0000066241 00000 n +0000066272 00000 n +0000066125 00000 n +0000066156 00000 n +0000239884 00000 n +0000239909 00000 n +0000066747 00000 n +0000066772 00000 n +0000071901 00000 n +0000080989 00000 n +0000081058 00000 n +0000081341 00000 n +0000082348 00000 n +0000240793 00000 n +0000241737 00000 n +0000241806 00000 n +0000242090 00000 n +0000242359 00000 n +0000254840 00000 n +0000255492 00000 n +0000258003 00000 n +0000264373 00000 n +0000329962 00000 n +0000395551 00000 n +0000461140 00000 n +0000526729 00000 n +0000592318 00000 n +0000657907 00000 n +0000723496 00000 n +0000789085 00000 n +0000854674 00000 n +0000920264 00000 n +0000985854 00000 n +0001032350 00000 n +0001097940 00000 n +0001163530 00000 n +0001229120 00000 n +0001294710 00000 n +0001360300 00000 n +0001425890 00000 n +0001495321 00000 n +0001495348 00000 n +0001497873 00000 n +0001501743 00000 n +0001501813 00000 n +0001502099 00000 n +0001502705 00000 n +0001564548 00000 n +0001564575 00000 n +0001566192 00000 n +0001568398 00000 n +0001568468 00000 n +0001568755 00000 n +0001569206 00000 n +0001612979 00000 n +0001613006 00000 n +0001613469 00000 n +0001613849 00000 n +0001618360 00000 n +0001766784 00000 n +0001765611 00000 n +0001769558 00000 n +0001897758 00000 n +0001900524 00000 n +0001901543 00000 n +0001901855 00000 n +0001902167 00000 n +0001900590 00000 n +0001874418 00000 n +0001877104 00000 n +0001897468 00000 n +0001897220 00000 n +0001896858 00000 n +0001896096 00000 n +0001878059 00000 n +0001880833 00000 n +0001882992 00000 n +0001886087 00000 n +0001877170 00000 n +0001803179 00000 n +0001808123 00000 n +0001809180 00000 n +0001808189 00000 n +0001797461 00000 n +0001802186 00000 n +0001802252 00000 n +0001773144 00000 n +0001776914 00000 n +0001796406 00000 n +0001795983 00000 n +0001797347 00000 n +0001778041 00000 n +0001778309 00000 n +0001778577 00000 n +0001778845 00000 n +0001779113 00000 n +0001779381 00000 n +0001779649 00000 n +0001779917 00000 n +0001780185 00000 n +0001787472 00000 n +0001776980 00000 n +0001797283 00000 n +0001797219 00000 n +0001797155 00000 n +0001797091 00000 n +0001797027 00000 n +0001796963 00000 n +0001796899 00000 n +0001796835 00000 n +0001796033 00000 n +0001796456 00000 n +0001873804 00000 n +0001896146 00000 n +0001896907 00000 n +0001897269 00000 n +0001897517 00000 n +0001929937 00000 n +0001929873 00000 n +0001929456 00000 n +0002077464 00000 n +0002088024 00000 n +0002088090 00000 n +0002074432 00000 n +0002075867 00000 n +0002077340 00000 n +0002076873 00000 n +0002075933 00000 n +0002071838 00000 n +0002073215 00000 n +0002074317 00000 n +0002073941 00000 n +0002073281 00000 n +0001937469 00000 n +0001941306 00000 n +0002071723 00000 n +0001942580 00000 n +0001942933 00000 n +0001943286 00000 n +0001943639 00000 n +0001943992 00000 n +0001944345 00000 n +0001941372 00000 n +0001932584 00000 n +0001935768 00000 n +0001937345 00000 n +0001936969 00000 n +0001935834 00000 n +0001937281 00000 n +0002066249 00000 n +0002041185 00000 n +0002069411 00000 n +0002066313 00000 n +0002059854 00000 n +0002063630 00000 n +0002059918 00000 n +0002054177 00000 n +0002057474 00000 n +0002054241 00000 n +0002048007 00000 n +0002051633 00000 n +0002048071 00000 n +0002039863 00000 n +0002043039 00000 n +0002039927 00000 n +0002041234 00000 n +0002042795 00000 n +0002043155 00000 n +0002043221 00000 n +0002043252 00000 n +0002043571 00000 n +0002045207 00000 n +0002043646 00000 n +0002045320 00000 n +0002045357 00000 n +0002049696 00000 n +0002051749 00000 n +0002051815 00000 n +0002051846 00000 n +0002052165 00000 n +0002052240 00000 n +0002055701 00000 n +0002057590 00000 n +0002057656 00000 n +0002057687 00000 n +0002058006 00000 n +0002058081 00000 n +0002061618 00000 n +0002063746 00000 n +0002063812 00000 n +0002063843 00000 n +0002064162 00000 n +0002064237 00000 n +0002067706 00000 n +0002069527 00000 n +0002069593 00000 n +0002069624 00000 n +0002069943 00000 n +0002070018 00000 n +0002074253 00000 n +0002077276 00000 n +0002088911 00000 n +trailer +<]>> +startxref +2089113 +%%EOF diff --git a/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2103.pdf b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2103.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3fa59eccc234080f4023e9a585bf28370803ce7c Binary files /dev/null and b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2103.pdf differ diff --git a/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2109.pdf b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2109.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0d900bd672ad4027e4cce0f1d2e1edbb6c06c923 Binary files /dev/null and b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2109.pdf differ diff --git a/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2203.pdf b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2203.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f09b71d8a11bda2a0ce8ebd68edba96df7763fac Binary files /dev/null and b/web-ui/docs/.vuepress/public/whitepaper/openEuler-whitepaper-2203.pdf differ diff --git "a/web-ui/docs/.vuepress/public/whitepaper/ru/openEuler-21.03-\320\242\320\265\321\205\320\275\320\270\321\207\320\265\321\201\320\272\320\270\320\271-\320\270\320\275\321\204\320\276\321\200\320\274\320\260\321\206\320\270\320\276\320\275\320\275\321\213\320\271-\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202.pdf" "b/web-ui/docs/.vuepress/public/whitepaper/ru/openEuler-21.03-\320\242\320\265\321\205\320\275\320\270\321\207\320\265\321\201\320\272\320\270\320\271-\320\270\320\275\321\204\320\276\321\200\320\274\320\260\321\206\320\270\320\276\320\275\320\275\321\213\320\271-\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..78a7c1b9b1c4f7293484d4202d310941d5afe1b4 Binary files /dev/null and "b/web-ui/docs/.vuepress/public/whitepaper/ru/openEuler-21.03-\320\242\320\265\321\205\320\275\320\270\321\207\320\265\321\201\320\272\320\270\320\271-\320\270\320\275\321\204\320\276\321\200\320\274\320\260\321\206\320\270\320\276\320\275\320\275\321\213\320\271-\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202.pdf" differ diff --git "a/web-ui/docs/.vuepress/public/whitepaper/\344\270\255\345\233\275\350\275\257\344\273\266\346\240\271\346\212\200\346\234\257\345\217\221\345\261\225\347\231\275\347\232\256\344\271\246\357\274\210\345\237\272\347\241\200\350\275\257\344\273\266\347\257\207\357\274\211.pdf" "b/web-ui/docs/.vuepress/public/whitepaper/\344\270\255\345\233\275\350\275\257\344\273\266\346\240\271\346\212\200\346\234\257\345\217\221\345\261\225\347\231\275\347\232\256\344\271\246\357\274\210\345\237\272\347\241\200\350\275\257\344\273\266\347\257\207\357\274\211.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..dc49206ba1e00e8f65ef9a3f80ce71c0dbd112a6 Binary files /dev/null and "b/web-ui/docs/.vuepress/public/whitepaper/\344\270\255\345\233\275\350\275\257\344\273\266\346\240\271\346\212\200\346\234\257\345\217\221\345\261\225\347\231\275\347\232\256\344\271\246\357\274\210\345\237\272\347\241\200\350\275\257\344\273\266\347\257\207\357\274\211.pdf" differ diff --git a/web-ui/docs/.vuepress/styles/palette.styl b/web-ui/docs/.vuepress/styles/palette.styl new file mode 100644 index 0000000000000000000000000000000000000000..482a762ca840ddafad36f24d51df94c7e40f410e --- /dev/null +++ b/web-ui/docs/.vuepress/styles/palette.styl @@ -0,0 +1 @@ +$nprogressColor = #002fa7 \ No newline at end of file diff --git a/web-ui/docs/.vuepress/theme/components/CustomFooter.vue b/web-ui/docs/.vuepress/theme/components/CustomFooter.vue new file mode 100644 index 0000000000000000000000000000000000000000..e54da4662d12f1b0011e19543532cbd353044809 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/components/CustomFooter.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/web-ui/docs/.vuepress/theme/components/CustomHeader.vue b/web-ui/docs/.vuepress/theme/components/CustomHeader.vue new file mode 100644 index 0000000000000000000000000000000000000000..502ab9c7e5ba3d3548e5faf21a08000f9c7e90f3 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/components/CustomHeader.vue @@ -0,0 +1,909 @@ + + + + + diff --git a/web-ui/docs/.vuepress/theme/global-components/Badge.vue b/web-ui/docs/.vuepress/theme/global-components/Badge.vue new file mode 100644 index 0000000000000000000000000000000000000000..53951f9d505dfb5ece39c10c5656db6cfd0915d0 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/global-components/Badge.vue @@ -0,0 +1,44 @@ + + + diff --git a/web-ui/docs/.vuepress/theme/index.js b/web-ui/docs/.vuepress/theme/index.js new file mode 100644 index 0000000000000000000000000000000000000000..baaf102ba77679ad628a048ee533986f6e8bc870 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/index.js @@ -0,0 +1,59 @@ +const path = require('path') + +// Theme API. +module.exports = (options, ctx) => { + const { themeConfig, siteConfig } = ctx + + // resolve algolia + const isAlgoliaSearch = ( + themeConfig.algolia + || Object + .keys(siteConfig.locales && themeConfig.locales || {}) + .some(base => themeConfig.locales[base].algolia) + ) + + const enableSmoothScroll = themeConfig.smoothScroll === true + + return { + alias () { + return { + '@AlgoliaSearchBox': isAlgoliaSearch + ? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue') + : path.resolve(__dirname, 'noopModule.js') + } + }, + + plugins: [ + ['@vuepress/active-header-links', options.activeHeaderLinks], + '@vuepress/search', + '@vuepress/plugin-nprogress', + ['container', { + type: 'tip', + defaultTitle: { + '/': 'TIP', + '/zh/': '提示' + } + }], + ['container', { + type: 'warning', + defaultTitle: { + '/': 'WARNING', + '/zh/': '注意' + } + }], + ['container', { + type: 'danger', + defaultTitle: { + '/': 'WARNING', + '/zh/': '警告' + } + }], + ['container', { + type: 'details', + before: info => `

${info ? `${info}` : ''}\n`, + after: () => '
\n' + }], + ['smooth-scroll', enableSmoothScroll] + ] + } +} diff --git a/web-ui/docs/.vuepress/theme/layouts/404.vue b/web-ui/docs/.vuepress/theme/layouts/404.vue new file mode 100644 index 0000000000000000000000000000000000000000..1155fbd60d079ce912315c352db7186c93691bde --- /dev/null +++ b/web-ui/docs/.vuepress/theme/layouts/404.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/web-ui/docs/.vuepress/theme/layouts/Layout.vue b/web-ui/docs/.vuepress/theme/layouts/Layout.vue new file mode 100644 index 0000000000000000000000000000000000000000..1d24031c2ac3a0975f02c252554905a4f5aa8f06 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/layouts/Layout.vue @@ -0,0 +1,48 @@ + + + + diff --git a/web-ui/docs/.vuepress/theme/layouts/Post.vue b/web-ui/docs/.vuepress/theme/layouts/Post.vue new file mode 100644 index 0000000000000000000000000000000000000000..cdaed2d23e0e5d9dc4238425732eaf68cb4e6100 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/layouts/Post.vue @@ -0,0 +1,408 @@ + + + + + + \ No newline at end of file diff --git a/web-ui/docs/.vuepress/theme/noopModule.js b/web-ui/docs/.vuepress/theme/noopModule.js new file mode 100644 index 0000000000000000000000000000000000000000..b1c6ea436a540020ff61f01dea449d5b39367b27 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/noopModule.js @@ -0,0 +1 @@ +export default {} diff --git a/web-ui/docs/.vuepress/theme/styles/arrow.styl b/web-ui/docs/.vuepress/theme/styles/arrow.styl new file mode 100644 index 0000000000000000000000000000000000000000..20bffc0dc87339fa3b52d35e5ea17995d5cdb9f8 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/arrow.styl @@ -0,0 +1,22 @@ +@require './config' + +.arrow + display inline-block + width 0 + height 0 + &.up + border-left 4px solid transparent + border-right 4px solid transparent + border-bottom 6px solid $arrowBgColor + &.down + border-left 4px solid transparent + border-right 4px solid transparent + border-top 6px solid $arrowBgColor + &.right + border-top 4px solid transparent + border-bottom 4px solid transparent + border-left 6px solid $arrowBgColor + &.left + border-top 4px solid transparent + border-bottom 4px solid transparent + border-right 6px solid $arrowBgColor diff --git a/web-ui/docs/.vuepress/theme/styles/code.styl b/web-ui/docs/.vuepress/theme/styles/code.styl new file mode 100644 index 0000000000000000000000000000000000000000..9d3aa9a54130c6fef1c3b818d7e6898f4231975b --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/code.styl @@ -0,0 +1,137 @@ +{$contentClass} + code + color lighten($textColor, 20%) + padding 0.25rem 0.5rem + margin 0 + font-size 0.85em + background-color rgba(27,31,35,0.05) + border-radius 3px + .token + &.deleted + color #EC5975 + &.inserted + color $accentColor + +{$contentClass} + pre, pre[class*="language-"] + line-height 1.4 + padding 1.25rem 1.5rem + margin 0.85rem 0 + background-color $codeBgColor + border-radius 6px + overflow auto + code + color #fff + padding 0 + background-color transparent + border-radius 0 + +div[class*="language-"] + position relative + background-color $codeBgColor + border-radius 6px + .highlight-lines + user-select none + padding-top 1.3rem + position absolute + top 0 + left 0 + width 100% + line-height 1.4 + .highlighted + background-color rgba(0, 0, 0, 66%) + pre, pre[class*="language-"] + background transparent + position relative + z-index 1 + &::before + position absolute + z-index 3 + top 0.8em + right 1em + font-size 0.75rem + color rgba(255, 255, 255, 0.4) + &:not(.line-numbers-mode) + .line-numbers-wrapper + display none + &.line-numbers-mode + .highlight-lines .highlighted + position relative + &:before + content ' ' + position absolute + z-index 3 + left 0 + top 0 + display block + width $lineNumbersWrapperWidth + height 100% + background-color rgba(0, 0, 0, 66%) + pre + padding-left $lineNumbersWrapperWidth + 1 rem + vertical-align middle + .line-numbers-wrapper + position absolute + top 0 + width $lineNumbersWrapperWidth + text-align center + color rgba(255, 255, 255, 0.3) + padding 1.25rem 0 + line-height 1.4 + br + user-select none + .line-number + position relative + z-index 4 + user-select none + font-size 0.85em + &::after + content '' + position absolute + z-index 2 + top 0 + left 0 + width $lineNumbersWrapperWidth + height 100% + border-radius 6px 0 0 6px + border-right 1px solid rgba(0, 0, 0, 66%) + background-color $codeBgColor + + +for lang in $codeLang + div{'[class~="language-' + lang + '"]'} + &:before + content ('' + lang) + +div[class~="language-javascript"] + &:before + content "js" + +div[class~="language-typescript"] + &:before + content "ts" + +div[class~="language-markup"] + &:before + content "html" + +div[class~="language-markdown"] + &:before + content "md" + +div[class~="language-json"]:before + content "json" + +div[class~="language-ruby"]:before + content "rb" + +div[class~="language-python"]:before + content "py" + +div[class~="language-bash"]:before + content "sh" + +div[class~="language-php"]:before + content "php" + +@import '~prismjs/themes/prism-tomorrow.css' diff --git a/web-ui/docs/.vuepress/theme/styles/config.styl b/web-ui/docs/.vuepress/theme/styles/config.styl new file mode 100644 index 0000000000000000000000000000000000000000..9e403210fd385f823fbf9796fd51b4fc4f1843aa --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/config.styl @@ -0,0 +1 @@ +$contentClass = '.theme-default-content' diff --git a/web-ui/docs/.vuepress/theme/styles/custom-blocks.styl b/web-ui/docs/.vuepress/theme/styles/custom-blocks.styl new file mode 100644 index 0000000000000000000000000000000000000000..5b868166a434c112c09b5b2d525521f6de2c8d81 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/custom-blocks.styl @@ -0,0 +1,44 @@ +.custom-block + .custom-block-title + font-weight 600 + margin-bottom -0.4rem + &.tip, &.warning, &.danger + padding .1rem 1.5rem + border-left-width .5rem + border-left-style solid + margin 1rem 0 + &.tip + background-color #f3f5f7 + border-color #42b983 + &.warning + background-color rgba(255,229,100,.3) + border-color darken(#ffe564, 35%) + color darken(#ffe564, 70%) + .custom-block-title + color darken(#ffe564, 50%) + a + color $textColor + &.danger + background-color #ffe6e6 + border-color darken(red, 20%) + color darken(red, 70%) + .custom-block-title + color darken(red, 40%) + a + color $textColor + &.details + display block + position relative + border-radius 2px + margin 1.6em 0 + padding 1.6em + background-color #eee + h4 + margin-top 0 + figure, p + &:last-child + margin-bottom 0 + padding-bottom 0 + summary + outline none + cursor pointer diff --git a/web-ui/docs/.vuepress/theme/styles/index.styl b/web-ui/docs/.vuepress/theme/styles/index.styl new file mode 100644 index 0000000000000000000000000000000000000000..2ed3c90ee0db6d14f7ac923b33332ba47af9291c --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/index.styl @@ -0,0 +1 @@ +@require './code' \ No newline at end of file diff --git a/web-ui/docs/.vuepress/theme/styles/mobile.styl b/web-ui/docs/.vuepress/theme/styles/mobile.styl new file mode 100644 index 0000000000000000000000000000000000000000..f5bd32739d774a8d69a60ae282630eaf2ac2b72f --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/mobile.styl @@ -0,0 +1,37 @@ +@require './config' + +$mobileSidebarWidth = $sidebarWidth * 0.82 + +// narrow desktop / iPad +@media (max-width: $MQNarrow) + .sidebar + font-size 15px + width $mobileSidebarWidth + .page + padding-left $mobileSidebarWidth + +// wide mobile +@media (max-width: $MQMobile) + .sidebar + top 0 + padding-top $navbarHeight + transform translateX(-100%) + transition transform .2s ease + .page + padding-left 0 + .theme-container + &.sidebar-open + .sidebar + transform translateX(0) + &.no-navbar + .sidebar + padding-top: 0 + +// narrow mobile +@media (max-width: $MQMobileNarrow) + h1 + font-size 1.9rem + {$contentClass} + div[class*="language-"] + margin 0.85rem -1.5rem + border-radius 0 diff --git a/web-ui/docs/.vuepress/theme/styles/toc.styl b/web-ui/docs/.vuepress/theme/styles/toc.styl new file mode 100644 index 0000000000000000000000000000000000000000..d3e71069ba79f12ab46681be457be98e88156184 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/toc.styl @@ -0,0 +1,3 @@ +.table-of-contents + .badge + vertical-align middle diff --git a/web-ui/docs/.vuepress/theme/styles/wrapper.styl b/web-ui/docs/.vuepress/theme/styles/wrapper.styl new file mode 100644 index 0000000000000000000000000000000000000000..a99262c71ab374f473eeccd01c1cd970c3ccf89c --- /dev/null +++ b/web-ui/docs/.vuepress/theme/styles/wrapper.styl @@ -0,0 +1,9 @@ +$wrapper + max-width $contentWidth + margin 0 auto + padding 2rem 2.5rem + @media (max-width: $MQNarrow) + padding 2rem + @media (max-width: $MQMobileNarrow) + padding 1.5rem + diff --git a/web-ui/docs/.vuepress/theme/util/index.js b/web-ui/docs/.vuepress/theme/util/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4433bb3c5fad61ec8a51d1cbe6ba485e92847802 --- /dev/null +++ b/web-ui/docs/.vuepress/theme/util/index.js @@ -0,0 +1,243 @@ +export const hashRE = /#.*$/ +export const extRE = /\.(md|html)$/ +export const endingSlashRE = /\/$/ +export const outboundRE = /^[a-z]+:/i + +export function normalize (path) { + return decodeURI(path) + .replace(hashRE, '') + .replace(extRE, '') +} + +export function getHash (path) { + const match = path.match(hashRE) + if (match) { + return match[0] + } +} + +export function isExternal (path) { + return outboundRE.test(path) +} + +export function isMailto (path) { + return /^mailto:/.test(path) +} + +export function isTel (path) { + return /^tel:/.test(path) +} + +export function ensureExt (path) { + if (isExternal(path)) { + return path + } + const hashMatch = path.match(hashRE) + const hash = hashMatch ? hashMatch[0] : '' + const normalized = normalize(path) + + if (endingSlashRE.test(normalized)) { + return path + } + return normalized + '.html' + hash +} + +export function isActive (route, path) { + const routeHash = decodeURIComponent(route.hash) + const linkHash = getHash(path) + if (linkHash && routeHash !== linkHash) { + return false + } + const routePath = normalize(route.path) + const pagePath = normalize(path) + return routePath === pagePath +} + +export function resolvePage (pages, rawPath, base) { + if (isExternal(rawPath)) { + return { + type: 'external', + path: rawPath + } + } + if (base) { + rawPath = resolvePath(rawPath, base) + } + const path = normalize(rawPath) + for (let i = 0; i < pages.length; i++) { + if (normalize(pages[i].regularPath) === path) { + return Object.assign({}, pages[i], { + type: 'page', + path: ensureExt(pages[i].path) + }) + } + } + console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`) + return {} +} + +function resolvePath (relative, base, append) { + const firstChar = relative.charAt(0) + if (firstChar === '/') { + return relative + } + + if (firstChar === '?' || firstChar === '#') { + return base + relative + } + + const stack = base.split('/') + + // remove trailing segment if: + // - not appending + // - appending to trailing slash (last segment is empty) + if (!append || !stack[stack.length - 1]) { + stack.pop() + } + + // resolve relative path + const segments = relative.replace(/^\//, '').split('/') + for (let i = 0; i < segments.length; i++) { + const segment = segments[i] + if (segment === '..') { + stack.pop() + } else if (segment !== '.') { + stack.push(segment) + } + } + + // ensure leading slash + if (stack[0] !== '') { + stack.unshift('') + } + + return stack.join('/') +} + +/** + * @param { Page } page + * @param { string } regularPath + * @param { SiteData } site + * @param { string } localePath + * @returns { SidebarGroup } + */ +export function resolveSidebarItems (page, regularPath, site, localePath) { + const { pages, themeConfig } = site + + const localeConfig = localePath && themeConfig.locales + ? themeConfig.locales[localePath] || themeConfig + : themeConfig + + const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar + if (pageSidebarConfig === 'auto') { + return resolveHeaders(page) + } + + const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar + if (!sidebarConfig) { + return [] + } else { + const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig) + if (config === 'auto') { + return resolveHeaders(page) + } + return config + ? config.map(item => resolveItem(item, pages, base)) + : [] + } +} + +/** + * @param { Page } page + * @returns { SidebarGroup } + */ +function resolveHeaders (page) { + const headers = groupHeaders(page.headers || []) + return [{ + type: 'group', + collapsable: false, + title: page.title, + path: null, + children: headers.map(h => ({ + type: 'auto', + title: h.title, + basePath: page.path, + path: page.path + '#' + h.slug, + children: h.children || [] + })) + }] +} + +export function groupHeaders (headers) { + // group h3s under h2 + headers = headers.map(h => Object.assign({}, h)) + let lastH2 + headers.forEach(h => { + if (h.level === 2) { + lastH2 = h + } else if (lastH2) { + (lastH2.children || (lastH2.children = [])).push(h) + } + }) + return headers.filter(h => h.level === 2) +} + +export function resolveNavLinkItem (linkItem) { + return Object.assign(linkItem, { + type: linkItem.items && linkItem.items.length ? 'links' : 'link' + }) +} + +/** + * @param { Route } route + * @param { Array | Array | [link: string]: SidebarConfig } config + * @returns { base: string, config: SidebarConfig } + */ +export function resolveMatchingConfig (regularPath, config) { + if (Array.isArray(config)) { + return { + base: '/', + config: config + } + } + for (const base in config) { + if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) { + return { + base, + config: config[base] + } + } + } + return {} +} + +function ensureEndingSlash (path) { + return /(\.html|\/)$/.test(path) + ? path + : path + '/' +} + +function resolveItem (item, pages, base, groupDepth = 1) { + if (typeof item === 'string') { + return resolvePage(pages, item, base) + } else if (Array.isArray(item)) { + return Object.assign(resolvePage(pages, item[0], base), { + title: item[1] + }) + } else { + const children = item.children || [] + if (children.length === 0 && item.path) { + return Object.assign(resolvePage(pages, item.path, base), { + title: item.title + }) + } + return { + type: 'group', + path: item.path, + title: item.title, + sidebarDepth: item.sidebarDepth, + children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)), + collapsable: item.collapsable !== false + } + } +} diff --git a/web-ui/docs/en/README.md b/web-ui/docs/en/README.md new file mode 100644 index 0000000000000000000000000000000000000000..24a93d05aa59be040ef844b52e1b025a7a6b4c3f --- /dev/null +++ b/web-ui/docs/en/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/activities/README.md b/web-ui/docs/en/activities/README.md new file mode 100644 index 0000000000000000000000000000000000000000..edd773e9947ca675129adb59c6e0420df9550b67 --- /dev/null +++ b/web-ui/docs/en/activities/README.md @@ -0,0 +1,7 @@ +--- +title: "Summer Activities" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/blog/Benshuai5D/Build a BiSheng JDK RPM Package.md b/web-ui/docs/en/blog/Benshuai5D/Build a BiSheng JDK RPM Package.md new file mode 100644 index 0000000000000000000000000000000000000000..a8cd986c56609d53b109e6ba4cb2da6afe26aabc --- /dev/null +++ b/web-ui/docs/en/blog/Benshuai5D/Build a BiSheng JDK RPM Package.md @@ -0,0 +1,517 @@ +--- +title: Build a BiSheng JDK RPM Package +date: 2021-06-06 +tags: + - BiSheng JDK + - build RPM package +archives: 2021-06 +author: Benshuai5D +summary: Just about everything you need to build a BiSheng JDK RPM package +--- + +# Start from Scratch: Building a BiSheng JDK RPM Package (on openEuler and Raspberry Pi) + +BiSheng JDK is the open source version of Huawei JDK customized for Huawei internal OpenJDK. It is a high-performance OpenJDK distribution that can be used in production environments. Huawei JDK runs on more than 500 Huawei products, and its development team has accumulated rich development experience, resolved countless issues encountered in actual service running, and improved the JDK performance on the ARM architecture. Therefore, BiSheng JDK can achieve better performance in big data scenarios. + +Red Hat Package Manager (RPM) is a software package management system running on Red Hat Enterprise Linux, CentOS, and Fedora. It can easily distribute, manage, and update software created for Red Hat Enterprise Linux, CentOS, and Fedora. Packaging software into RPM packages includes: (re)installing, deleting, upgrading, and verifying the software packages; packaging original software sources into source and binary packages; adding the software packages to Yum repositories; and signing digital signatures. + +This document analyzes the RPM package build process of OpenJDK-1.8.0 on a VM and on a Raspberry Pi, both with openEuler installed. + +## Build Process of openEuler-based BiSheng JDK RPM Packages + +### 1. openEuler Installation + +#### Downloading the openEuler Image File + +openEuler, an open source OS, is designed based on the Linux kernel and developed by global open source contributors. It supports Kunpeng and other processors and can fully unleash the potential of computing chips. It has become essential for database, big data, cloud computing, and artificial intelligence (AI) scenarios. In addition, openEuler provides entry to the open source OS community, where global developers can collaborate to build an innovative, unified, and open OS that supports the multi-processor architecture, to advance the hardware/software applications. + +Visit the [official openEuler website](https://www.openeuler.org/en/download/) and download the required version. In this example, select openEuler 20.03 LTS. openEuler 20.03 LTS is a standard distribution, whose lifecycle is four years. It meets the requirements of open solutions. + +image-openEuler-version + +Click **Download** on the card of the selected version. On the **Download** page, select **ISO/** to download the image CD-ROM file. You can use the burning software to directly burn the ISO file into a system CD-ROM that can be installed. The ISO file name extension is .iso. + +image-openEuler-20.03-LTS + +In the **ISO/** index, select the system to be downloaded. The ISO download list of openEuler 20.03 LTS provides the AArch64 ISO, x86_64 ISO, and openEuler source code ISO. Here, we use the x86_64 ISO. + +image-openEuler-ISO + +In the **/openEuler-20.3-LTS/ISO/x86_64/** index, download the required ISO file. Here, we download **openEuler-20.03-LTS-x86_64-dvd.iso**. + +image-openEuler-x86_64 + +#### Creating a VM + +Use the VMware Workstation or Oracle VM software to create a VM, with the downloaded ISO image file **openEuler-20.03-LTS-x86_64-dvd.iso**. + +On the openEuler **INSTALLATION SUMMARY** page, set the installation parameters, such as the **Keyboard**, **Language Support**, **Time & Date**, and **Installation Destination**. + +image-INSTALLATION SUMMARY + +On the **INSTALLATION SUMMARY** page, select **Installation Destination** and set the installation disk and partition of the OS. + +image-INSTALLATION Destination + +Set the password for the **root** user of the VM. A **root** account is used to run administration tasks of key systems. It is not recommended during daily work or system access. + +image-CONFIGURATION + +image-reroot + +#### Creating a User Account + +``` +useradd zhangsan // Create an individual user account. +passwd zhangsan // Change the personal password. +su - zhangsan // Switch to the individual user account. +``` + +image-newuser + +The password of the **root** user and the password of the new user must meet the password complexity requirements; otherwise, the password configuration or user creation will fail. Password complexity requirements: Each password must contain at least eight characters, including at least three types of the following characters: uppercase letters, lowercase letters, digits, and special characters. +Note: The password cannot be the same as the account and cannot be a password in the weak password dictionary. + +#### MobaXterm: Remote Network Access Tool + +MobaXterm is a toolbox for remote computing. Its intuitive user interface allows you to access remote servers through different networks or systems. After a VM is created and configured, you can access it using MobaXterm. The IP address of the VM is allocated after the VM is created. + +image-MobaXterm + +Remotely access the openEuler VM using the corresponding IP address, username, and password. + +image-MobaXterm-SSH + +### 2. Dependency Installation and Source File Download + +#### Installing the RPM Build Toolkit + +`yum install rpm-build rpm-devel rpmdevtools` + +image-rpmbuildtools + +Check the utilities for RPM packaging provided by the software package: `rpm -ql rpmdevtools | grep bin` `rpm -ql rpm-devel | grep bin` `rpm -ql rpm-build | grep bin` + +image-rpm -ql rpm-devel + +**rpmdev-setuptree** creates the directory layout for constructing the RPM packaging space. +**rpmdev-newspec** creates an empty SPEC file. +**rpmbuild** creates an actual RPM software package from the SPEC file. +**rpmspec** queries the parsed output of specifications. + +#### Generating the rpmbuild Directory and Related Subdirectories + +Go to the personal folder and run `rpmdev-setuptree` to automatically create the rpmbuild directory and related subdirectories. + +image-rpmdev-setuptree + +The following figure shows the generated rpmbuild directory and its subdirectories. +**BUILD**: During package build, `%buildroot` creates various directories here. If the log output does not provide sufficient information, it is useful to investigate failed builds. + **RPMS**: Binary RPMs are created in its subdirectories of different architectures (for example, `x86_64` and `noarch`). + **SOURCES**: This folder stores the compressed source code archives and patches. The `rpmbuild` command can be found here. + **SPECS**: This folder stores SPECS files. + **SRPMS**: If `rpmbuild` is used to build SRPM instead of binary RPM, the result SRPM is created here. + +image-rpmdev-setuptree-filelist + +#### Preparing the Source Package and SPEC File + +In the **/rpmbuild/SOURCES/** directory, download the jdkSource file for building the RPM package by running `git clone https://gitee.com/src-openeuler/openjdk-1.8.0.git`. The URL of the openJDK is [https://gitee.com/src-openeuler/openjdk-1.8.0](https://gitee.com/src-openeuler/openjdk-1.8.0). If you want to build the JDK of another version, replace the URL. + +.image-git clone jdk source + +Move the SPEC file in the downloaded JDK package to the **SPECS** folder. +`mv ./openjdk-1.8.0/*spec ../SPECS/` + +image-spec-preapare + +image-spec-preaparelist + +Move other files in the JDK package to the **SOURCE** folder. +`mv ./openjdk-1.8.0/* ./` + +image-source-prepare + +image-source-preparelist + +#### Installing and Configuring JDK 8 + +You can use `yum list | grep openjdk` to check the JDK version that can be installed in the Yum source of openEuler and install the JDK. If the required JDK is not available, install it or update the Yum source. + +image-yum list grep openjdk + +Installation command: `yum install java-1.8.0-openjdk.x86_64` + +Check whether the JDK is installed successfully. +`java -version` + +image-java -version + +The following lists the versions provided by each OpenJDK Yum source. + +[https://repo.openeuler.org/openEuler-20.03-LTS/OS/x86_64/Packages/](https://repo.openeuler.org/openEuler-20.03-LTS/OS/x86_64/Packages/) + +image-openEuler-21.03-os + +[https://repo.openeuler.org/openEuler-20.03-LTS/everything/x86_64/Packages/](https://repo.openeuler.org/openEuler-20.03-LTS/everything/x86_64/Packages/) + +image-openEuler-everything + +[https://repo.openeuler.org/openEuler-21.03/everything/x86_64/Packages/](https://repo.openeuler.org/openEuler-21.03/everything/x86_64/Packages/) + +image-openEuler-everything-jdk11 + +#### Installing the Dependencies + + `yum install alsa-lib-devel cups-devel elfutils-devel fontconfig-devel freetype-devel giflib-devel harfbuzz-devel lcms2-devel nss-devel` + +image-reliant package + +To install other required dependencies, run the `yum install package` command. + +### 3. RPM Package Build + +Go to the **SPECS** folder and enter the corresponding command as required to start the build. + +``` +rpmbuild -bi java-1.8.0-openjdk.spec // Execute script in the install phase. +rpmbuild -bb java-1.8.0-openjdk.spec // Generate the RPM binary package. +rpmbuild -bs java-1.8.0-openjdk.spec // Generate the RPM source package. +rpmbuild -ba java-1.8.0-openjdk.spec // Generate the RPM binary package and source package. +``` + + The RPM package build complete. + +image-successful result + +File list + +tree + +### 4. Common Errors and Solutions + +#### Error: There are no enabled repositories in "/etc/yum.repos.d" + +image-there are no enabled repositories + +Solution: + +`cd /etc/yum.repos.d` + +`vi openEuler_x86_64.repo` (or `vi openEuler_aarch64.repo` for AArch64 OSs) + +Content to be added: + +``` +#generic-repos is licensed under the Mulan PSL v2. +#You can use this software according to the terms and conditions of the Mulan PSL v2. +#You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +#THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +#PURPOSE. +#See the Mulan PSL v2 for more details. + +[OS] +name=OS +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler + +[everything] +name=everything +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/everything/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/everything/$basearch/RPM-GPG-KEY-openEuler + +[EPOL] +name=EPOL +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/EPOL/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler + +[debuginfo] +name=debuginfo +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/debuginfo/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/debuginfo/$basearch/RPM-GPG-KEY-openEuler + +[source] +name=source +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/source/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/source/RPM-GPG-KEY-openEuler + +[update] +name=update +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/update/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler +``` + +The Yum source is from Gitee. The link is [https://gitee.com/src-openeuler/openEuler-repos/blob/openEuler-20.03-LTS/generic.repo#](https://gitee.com/src-openeuler/openEuler-repos/blob/openEuler-20.03-LTS/generic.repo#). + +#### Error: Failed build dependencies: packages is needed by java-1.8.0-openjdk-1:1.8.0.282.b08-17.x86_64 + +image-packages is needed by java-1.8.0-openjdk + +Cause: Packages required for RPM package build are not installed in the SPECS file. + +Solution: Run the `yum install packages` command to install the packages. + +`yum install gdb java-1.8.0-openjdk-devel libX11-devel libXext-devel libXi-devel libXinerama-devel libXrender-devel libXt-devel libXtst-devel libjpeg-devel openssl-devel` + +image-yum install packages + +#### Error: java-8-openjdk-devel is is needed by xxx + +Cause: openjdk-devel is required in **BuildRequires** in the SPEC file, but the current OpenJDK version does not meet the requirement. + +Solution: If you are sure that the installed OpenJDK version meets the build requirements, comment out the line or modify the version requirements. If you are not sure whether the current version meets the build requirements, install and configure the OpenJDK version as required. + +image-java-8-openjdk-devel is needed by xxx + +#### Error :tzdate-java>=2020a is needed by xxx + +Cause: The tzdate-java version is specified in **BuildRequires** in the SPEC file, but the installed version does not meet the requirement. + +Solution: If you are sure that the installed tzdate-java version meets the build requirements, comment out the line or modify the version requirements. If you are not sure whether the current version meets the build requirements, install and configure the tzdate-java version as required. + +image-tzdate-java + +#### Error: Bad exit status from /var/tmp/rpm-tem.f4PLQX(%build) + +Cause: JDK 8 has been configured in the system, but the downloaded SPEC file has not been modified. You need to access the SPEC file and change the JDK path to the local JDK 8 path. + +`vim /root/rpmbuild/SPECS/java-1.8.0-openjdk.spec?configure` + +Find the **configure** location and change the JDK path to the local JDK 8 path. + +image-Bad exit status from + +### 5. RPM Package Build for Other JDK Versions + +For other JDK versions, such as JDK 11 and JDK 15, if you want to build RPM packages, you only need to download the JDK source package of the corresponding version, replace the corresponding URL, and change the JDK path to the corresponding local JDK path. The build process is the same as that of JDK 8. If an error message is displayed, refer to solutions provided in this section. + +## Build Process of openEuler-based Raspberry Pi RPM Packages + +### 1. Installation of the openEuler ISO Image + +#### Installation Requirements + +The Raspberry Pi where you want to install the openEuler OS must meet the following hardware compatibility and minimum hardware requirements: Raspberry Pi versions 3B, 3B+, and 4B; Memory: at least 4 GB for better application experience; Drive: at least 8 GB for better application experience. The Raspberry Pi official website is [https://www.raspberrypi.org/](https://www.raspberrypi.org/), and the openEuler community website is [https://www.openeuler.org/en/download/](https://www.openeuler.org/en/download/). + +#### Obtaining the Installation Source + +Obtain the Raspberry Pi image and its verification file released by openEuler. Log in to the [openEuler community](https://www.openeuler.org/en/download/) and click **Download** on the **openEuler 20.03 LTS SP1** card. + +image-get iso + +Click **raspi_img**. The Raspberry Pi image download list is displayed. + +image-get rasp_img + +Click **openEuler-20.03-LTS-SP1-raspi-aarch64.img.xz** to download the Raspberry Pi image released by openEuler to your local PC. + +image-get img + +#### Formatting the SD Card + +Download and install an SD card formatting tool. The following uses the DiskGenius disk formatting tool as an example. + +Select the drive letter of the SD card to be formatted, delete its content, and save the file. + +Select the disk whose content has just been deleted, create a partition, set the file system type to FAT32, and save and format the disk. + +#### Writing the Image File to the SD Card + +Download and install an image writing tool. The following uses Win32 Disk Imager as an example. + +Select the **openEuler-20.03-LTS-SP1-raspi-aarch64.img** image file in the image file download path, select the drive letter of the SD card as the device, and click **Write**. + +>Note: After the image file is written, the disk capacity of the SD card decreases because the ext file system cannot be identified in Windows. This is normal. + +#### Starting the System + +Insert the SD card after image writing into the Raspberry Pi and power it on. + +#### Logging In to the System + +You can log in to the Raspberry Pi in either of the following ways: local login and SSH remote login. + +Local login: After the Raspberry Pi is connected with the monitor, keyboard, and mouse, start the Raspberry Pi and you can view the Raspberry Pi startup logs on the monitor. After the Raspberry Pi is started, enter the username (**root**) and password (**openeuler**) to log in. + +SSH remote login: If the Raspberry Pi is connected to a known router, you can log in to the router to view the new IP address (that is, the Raspberry Pi IP address). Alternatively, you can use an IP address scanning tool to scan the Raspberry Pi IP address. The following uses advanced_ip_scanner as an example. + +image-log in system + +For example, if the IP address of the Raspberry Pi is 192.168.1.9, you can use the remote network access tool MobaXterm to access the Raspberry Pi. + +image-use the moba log + +If the remote access is successful, enter the username (**root**) and password (**openeuler**) to log in. The following figure shows the window for using MobaXterm to access the openEuler system on the Raspberry Pi. + +image-the success of log + +### 2. Installing Yum on Raspberry Pi openEuler + +Log in to the system and run **yum** to install packages and dependencies. The message `-bash: yum: command not found` is displayed. + +image-yum command not found + +You need to manually install `yum-4.2.23-3.oe1.noarch.rpm` and upload it. + +URL: [https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm). Run `rpm -ivh --force --nodeps yum-4.2.23-3.oe1.noarch.rpm` in the same directory. + +image-yum rpm + +### 3. Dependency Installation and Source File Download + +#### Installing the RPM Build Toolkit + +`yum install rpm-build rpm-devel rpmdevtools` + +image-rpmbuildtools + +#### Generating the rpmbuild Directory and Related Subdirectories + +Go to the personal folder and run `rpmdev-setuptree` to automatically create the rpmbuild directory and related subdirectories. + +image-repdev-setuptree + +The following figure shows the generated rpmbuild directory and its subdirectories. +**BUILD**: During package build, `%buildroot` creates various directories here. If the log output does not provide sufficient information, it is useful to investigate failed builds. + **RPMS**: Binary RPMs are created in its subdirectories of different architectures (for example, `x86_64` and `noarch`). +**SOURCES**: This folder stores the compressed source code archives and patches. The `rpmbuild` command can be found here. +**SPECS**: This folder stores SPECS files. +**SRPMS**: If `rpmbuild` is used to build SRPM instead of binary RPM, the result SRPM is created here. + +image-success of setuptree + +#### Preparing the Source Package and SPEC File + +In the **/rpmbuild/SOURCES/** directory, download the jdkSource file for building the RPM package by running `git clone https://gitee.com/src-openeuler/openjdk-1.8.0.git`. The URL of the openJDK is https://gitee.com/src-openeuler/openjdk-1.8.0. If you want to build the JDK of another version, replace the URL. + +image-prepare the src package + +Move the SPEC file in the downloaded JDK package to the **SPECS** folder. +`mv ./openjdk-1.8.0/*spec ../SPECS/` + +image-the first of command + +image-the result of move the spec + +Move other files in the JDK package to the **SOURCE** folder. +`mv ./openjdk-1.8.0/* ./` + +image-the result of move the everything + +#### Installing and Configuring JDK 8 + +You can use `yum list | grep openjdk` to check the JDK version that can be installed in the Yum source of openEuler and install the JDK. If the required JDK is not available, install it or update the Yum source. + +yum openjdk rasp + +Installation command: `yum install java-1.8.0-openjdk.aarch64` + +Check whether the JDK is installed successfully. +`java -version` + +#### Installing the Dependencies + +`yum install alsa-lib-devel cups-devel elfutils-devel fontconfig-devel freetype-devel giflib-devel harfbuzz-devel lcms2-devel` + +image-yum install reliant package + +To install other required dependencies, run the `yum install package` command. + +### 4. RPM Package Build + +Go to the **SPECS** folder and enter the corresponding command as required to start the build. + +`rpmbuild -bi java-1.8.0-openjdk.spec ` Execute the script in the install phase. +`rpmbuild -bb java-1.8.0-openjdk.spec` Generate the RPM binary package. +`rpmbuild -bs java-1.8.0-openjdk.spec ` Generate the RPM source package. +`rpmbuild -ba java-1.8.0-openjdk.spec ` Generate the RPM binary package and source package. + +The following figure shows a built RPM package. + +raspberry success + +The file list is as follows: + +tree + +### 5. Errors and Solutions + +#### Error: The Raspberry Pi cannot be remotely accessed. + +For the SSH connection, you need to: (1). Confirm that the Raspberry Pi is connected to the network. (2). Confirm that the IP address, username, and password are correct. (3). Check whether the SSH is enabled. If the Raspberry Pi is connected to the network and the IP address, username, and password are correct, but the remote access still fails, the SSH is disabled. + +Solution: If an external monitor is used and the system monitor interface is connected, run the `rpm -qa|grep openssh` command to check whether the SSH server software package has been installed during system installation. If the command output contains `openssh-server-`, the SSH server has been installed. In this case, run the `service iptables start` command to start the SSHD service. + +images-openssh + +If no external monitor is available and the system monitor interface can be connected, create an SSH file (without the file name extension) in the SD card to enable remote access. + +.image-ssh + +#### Error: bash: yum: command not found + +When you run the **yum** command, the message `-bash: yum: command not found` is displayed. + +yum command not found + +You need to manually install `yum-4.2.23-3.oe1.noarch.rpm` and upload it. + +URL: [https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm). Run `rpm -ivh --force --nodeps yum-4.2.23-3.oe1.noarch.rpm` in the same directory. + +yum rpm + +#### Error: Failed build dependencies: xxx is needed by java-1.8.0-openjdk-1:1.8.0.282.b08-17.aarch64 + +failed build dependencied + +Cause: Packages required for RPM package build are not installed in the SPECS file. + +Solution: Run the `yum install xxx` command to install the package. + +`yum install gdb java-1.8.0-openjdk-devel libX11-devel libXext-devel libXi-devel libXinerama-devel libXrender-devel libXt-devel libXtst-devel libjpeg-devel openssl-devel` + +#### Error: java-8-openjdk-devel is needed by xxx + +Cause: openjdk-devel is required in **BuildRequires** in the SPEC file, but the current OpenJDK version does not meet the requirement. + +Solution: If you are sure that the installed OpenJDK version meets the build requirements, comment out the line or modify the version requirements. If you are not sure whether the current version meets the build requirements, install and configure the required OpenJDK version. + +image-java-8-openjdk-devel is needed by xxx + +#### Error: Bad exit status from /var/tmp/rpm-tem.f4PLQX(%build) + +Cause: JDK 8 has been configured in the system, but the downloaded SPEC file has not been modified. You need to access the SPEC file and change the JDK path to the local JDK 8 path. + +`vim /root/rpmbuild/SPECS/java-1.8.0-openjdk.spec?configure` + +Find the **configure** location and change the JDK path to the local JDK 8 path. + +image-Bad exit status from + +### 6. RPM Package Build for Other JDK Versions + +For other JDK versions, such as JDK 11 and JDK 15, if you want to build RPM packages, you only need to download the JDK source package of the corresponding version, replace the corresponding URL, and change the JDK path to the corresponding local JDK path. The build process is the same as that of JDK 8. If an error message is displayed, refer to solutions provided in this section. + +## References + +How to create an RPM package: [https://fedoraproject.org/wiki/How_to_create_an_RPM_package?rd=How_to_create_an_RPM_package/en](https://fedoraproject.org/wiki/How_to_create_an_RPM_package?rd=How_to_create_an_RPM_package/en) + +RPM Packaging Guide: [https://rpm-packaging-guide.github.io/](https://rpm-packaging-guide.github.io/) + +BiSheng JDK 8 User Guide: [https://gitee.com/openeuler/bishengjdk-8/wikis/Home?sort_id=2879418](https://gitee.com/openeuler/bishengjdk-8/wikis/Home?sort_id=2879418) + +Raspberry Pi: [https://www.raspberrypi.org/](https://www.raspberrypi.org/) diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.1.png b/web-ui/docs/en/blog/Benshuai5D/image/1.1.png new file mode 100644 index 0000000000000000000000000000000000000000..667ad6ad917f863e588492336d2aae71b455d927 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.1.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.10.png b/web-ui/docs/en/blog/Benshuai5D/image/1.10.png new file mode 100644 index 0000000000000000000000000000000000000000..413b57f39fb3ad5131c15f6029cd30f8fed4932d Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.10.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.11.png b/web-ui/docs/en/blog/Benshuai5D/image/1.11.png new file mode 100644 index 0000000000000000000000000000000000000000..992ea79a7c4a51f11609c3808e8b01f46fd6c106 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.11.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.12.png b/web-ui/docs/en/blog/Benshuai5D/image/1.12.png new file mode 100644 index 0000000000000000000000000000000000000000..10e147ab64d85238a2f687f968fa050220814123 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.12.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.13.png b/web-ui/docs/en/blog/Benshuai5D/image/1.13.png new file mode 100644 index 0000000000000000000000000000000000000000..46861335a21b8b6df56aa01a3ea7b6c6e3f2907c Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.13.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.14.png b/web-ui/docs/en/blog/Benshuai5D/image/1.14.png new file mode 100644 index 0000000000000000000000000000000000000000..877c6a632a082d736016469ff84c92745d33cfc0 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.14.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.15.png b/web-ui/docs/en/blog/Benshuai5D/image/1.15.png new file mode 100644 index 0000000000000000000000000000000000000000..3dfb7d4b7727900c12eb3eedb9d70ae1333fb5f5 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.15.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.16.png b/web-ui/docs/en/blog/Benshuai5D/image/1.16.png new file mode 100644 index 0000000000000000000000000000000000000000..f20489059a82c6277289b750175a8447b1c7dfe0 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.16.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.17.png b/web-ui/docs/en/blog/Benshuai5D/image/1.17.png new file mode 100644 index 0000000000000000000000000000000000000000..815e1ef75ec9c529f7936100c403298ec25cb46b Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.17.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.18.png b/web-ui/docs/en/blog/Benshuai5D/image/1.18.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fc541a5b18b96698c56a3bbd3a01d1135466ec Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.18.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.19.png b/web-ui/docs/en/blog/Benshuai5D/image/1.19.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6acb32853e3f135b764388feecdd1e34b8f677 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.19.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.2.png b/web-ui/docs/en/blog/Benshuai5D/image/1.2.png new file mode 100644 index 0000000000000000000000000000000000000000..6855b0fc972765056cef22b4aa25750f44ad201c Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.2.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.20.png b/web-ui/docs/en/blog/Benshuai5D/image/1.20.png new file mode 100644 index 0000000000000000000000000000000000000000..e36730395d7754c72a9cc8b64920affe062fb62f Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.20.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.21.png b/web-ui/docs/en/blog/Benshuai5D/image/1.21.png new file mode 100644 index 0000000000000000000000000000000000000000..bac4ad1e99c41c70a2892222ef9e0f2a109ae039 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.21.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.22.png b/web-ui/docs/en/blog/Benshuai5D/image/1.22.png new file mode 100644 index 0000000000000000000000000000000000000000..d7f637289e29fd7f1c4fc41b7684b0b7266970fd Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.22.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.23.png b/web-ui/docs/en/blog/Benshuai5D/image/1.23.png new file mode 100644 index 0000000000000000000000000000000000000000..30ae54b7df09c2712de11f56c03283c095b7b651 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.23.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.24.png b/web-ui/docs/en/blog/Benshuai5D/image/1.24.png new file mode 100644 index 0000000000000000000000000000000000000000..ed86288812897b1e2be9c07cfae5503d12774407 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.24.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.25.png b/web-ui/docs/en/blog/Benshuai5D/image/1.25.png new file mode 100644 index 0000000000000000000000000000000000000000..67174e7f8b03ccc8fba99ccfe463d24a6c6d0269 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.25.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.26.png b/web-ui/docs/en/blog/Benshuai5D/image/1.26.png new file mode 100644 index 0000000000000000000000000000000000000000..0a91822baf4959fcec1bf77a3b2abd370ef745be Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.26.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.27.png b/web-ui/docs/en/blog/Benshuai5D/image/1.27.png new file mode 100644 index 0000000000000000000000000000000000000000..703ab90c90f5ab30c3324fadf8f43bae8bef4a9e Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.27.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.3.png b/web-ui/docs/en/blog/Benshuai5D/image/1.3.png new file mode 100644 index 0000000000000000000000000000000000000000..ca43efdf55e87a75bfd0d2bcb121bc212e174410 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.3.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.4.png b/web-ui/docs/en/blog/Benshuai5D/image/1.4.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb864430b1ba266f8f82d4534d95662fdd000e7 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.4.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.6.png b/web-ui/docs/en/blog/Benshuai5D/image/1.6.png new file mode 100644 index 0000000000000000000000000000000000000000..fbed0d417fba7e05178428fa5dd5ea85ee78af86 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.6.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.7.png b/web-ui/docs/en/blog/Benshuai5D/image/1.7.png new file mode 100644 index 0000000000000000000000000000000000000000..b29e2aff8032ecc13386f11c7a17750372faac25 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.7.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.8.png b/web-ui/docs/en/blog/Benshuai5D/image/1.8.png new file mode 100644 index 0000000000000000000000000000000000000000..343b6021363c67adb39726ca5345ec804c8f7bfe Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.8.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/1.9.png b/web-ui/docs/en/blog/Benshuai5D/image/1.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fc2d950552333b1cbc2ef9df7a129be788303d82 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/1.9.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.1.png b/web-ui/docs/en/blog/Benshuai5D/image/2.1.png new file mode 100644 index 0000000000000000000000000000000000000000..e33005ff34151f79faccf233208d8d9f8557a561 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.1.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.10.png b/web-ui/docs/en/blog/Benshuai5D/image/2.10.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d55a106be8d98faa9f3029ab6a23fd9c58d154 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.10.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.11.png b/web-ui/docs/en/blog/Benshuai5D/image/2.11.png new file mode 100644 index 0000000000000000000000000000000000000000..0d13f545ee8c33959aa0e8d45bf98e480aa2567a Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.11.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.12.png b/web-ui/docs/en/blog/Benshuai5D/image/2.12.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc846123fb5ebabfd3f1190a378e8b5d9174277 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.12.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.13.png b/web-ui/docs/en/blog/Benshuai5D/image/2.13.png new file mode 100644 index 0000000000000000000000000000000000000000..8dfc945f734345f0ce50d0074ee6b0f6ee9826e0 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.13.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.14.png b/web-ui/docs/en/blog/Benshuai5D/image/2.14.png new file mode 100644 index 0000000000000000000000000000000000000000..2a2ee909dc2b88860721bd9ba43e4180b7246be9 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.14.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.15.png b/web-ui/docs/en/blog/Benshuai5D/image/2.15.png new file mode 100644 index 0000000000000000000000000000000000000000..596bd39002ae788d255f5521ef27d159d900171c Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.15.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.16.png b/web-ui/docs/en/blog/Benshuai5D/image/2.16.png new file mode 100644 index 0000000000000000000000000000000000000000..c16ce518b5a0d5c8d24fb7b2be611c6513697c51 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.16.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.17.png b/web-ui/docs/en/blog/Benshuai5D/image/2.17.png new file mode 100644 index 0000000000000000000000000000000000000000..105c01e8ff06c929303a429c60fd744c3e98fa16 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.17.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.18.png b/web-ui/docs/en/blog/Benshuai5D/image/2.18.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c5967fc8a7e44512cd85376440e71c7efac03d Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.18.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.19.png b/web-ui/docs/en/blog/Benshuai5D/image/2.19.png new file mode 100644 index 0000000000000000000000000000000000000000..50f4b02523b2769aa0f5d057eef9978248ed5d38 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.19.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.2.png b/web-ui/docs/en/blog/Benshuai5D/image/2.2.png new file mode 100644 index 0000000000000000000000000000000000000000..fdeb5e66f5f7a382329c98c921a37ffd3e745877 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.2.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.20.png b/web-ui/docs/en/blog/Benshuai5D/image/2.20.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d2e694e03419e8bd842bc3d6e961e454584a40 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.20.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.21.png b/web-ui/docs/en/blog/Benshuai5D/image/2.21.png new file mode 100644 index 0000000000000000000000000000000000000000..4252a54f55427c9ebe84389c8c24648541a7f6cc Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.21.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.22.png b/web-ui/docs/en/blog/Benshuai5D/image/2.22.png new file mode 100644 index 0000000000000000000000000000000000000000..c09dd71307f987e3c945c322fe44dcb090187986 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.22.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.23.png b/web-ui/docs/en/blog/Benshuai5D/image/2.23.png new file mode 100644 index 0000000000000000000000000000000000000000..c123fb6153d8604b2a7446dc653e4685a1588c1b Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.23.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.24.png b/web-ui/docs/en/blog/Benshuai5D/image/2.24.png new file mode 100644 index 0000000000000000000000000000000000000000..30b8185bf9c7d25dd5dc394a3859091366140fb4 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.24.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.25.png b/web-ui/docs/en/blog/Benshuai5D/image/2.25.png new file mode 100644 index 0000000000000000000000000000000000000000..08ea41b739b6bf269319009371fb3c4118f74202 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.25.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.26.png b/web-ui/docs/en/blog/Benshuai5D/image/2.26.png new file mode 100644 index 0000000000000000000000000000000000000000..35d46cd6dbe50fcaa948b35954ec331cdd0d120a Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.26.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.27.png b/web-ui/docs/en/blog/Benshuai5D/image/2.27.png new file mode 100644 index 0000000000000000000000000000000000000000..d4b10d248d4c59310cb651ffb2274f50a6fec981 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.27.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.28.png b/web-ui/docs/en/blog/Benshuai5D/image/2.28.png new file mode 100644 index 0000000000000000000000000000000000000000..40634a45ca9dbf7312803d818f1a5caabce287fe Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.28.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.29.png b/web-ui/docs/en/blog/Benshuai5D/image/2.29.png new file mode 100644 index 0000000000000000000000000000000000000000..4252a54f55427c9ebe84389c8c24648541a7f6cc Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.29.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.3.png b/web-ui/docs/en/blog/Benshuai5D/image/2.3.png new file mode 100644 index 0000000000000000000000000000000000000000..099a25fb18d057ab0a0585c0a9a5d2258f2aff34 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.3.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.30.png b/web-ui/docs/en/blog/Benshuai5D/image/2.30.png new file mode 100644 index 0000000000000000000000000000000000000000..c33ffef0eb38743411bdab42824ce462d54dcabe Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.30.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.31.png b/web-ui/docs/en/blog/Benshuai5D/image/2.31.png new file mode 100644 index 0000000000000000000000000000000000000000..f1510842fa5124ea602d640677f9404a3c17c4e2 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.31.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.32.png b/web-ui/docs/en/blog/Benshuai5D/image/2.32.png new file mode 100644 index 0000000000000000000000000000000000000000..8e791255cc612216e1ffac6f74fd336828c756b2 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.32.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.33.png b/web-ui/docs/en/blog/Benshuai5D/image/2.33.png new file mode 100644 index 0000000000000000000000000000000000000000..a0daf52d16492d79380d4bebf6d20372e43f934a Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.33.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.34.png b/web-ui/docs/en/blog/Benshuai5D/image/2.34.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe317e3d3a743416b57cfbfef5fd77682f1a466 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.34.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.35.png b/web-ui/docs/en/blog/Benshuai5D/image/2.35.png new file mode 100644 index 0000000000000000000000000000000000000000..0d13f545ee8c33959aa0e8d45bf98e480aa2567a Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.35.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.36.png b/web-ui/docs/en/blog/Benshuai5D/image/2.36.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc846123fb5ebabfd3f1190a378e8b5d9174277 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.36.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.37.png b/web-ui/docs/en/blog/Benshuai5D/image/2.37.png new file mode 100644 index 0000000000000000000000000000000000000000..d2063c545f4f1b6dd9cf5c5486f2fde5d4f9eff8 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.37.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.38.png b/web-ui/docs/en/blog/Benshuai5D/image/2.38.png new file mode 100644 index 0000000000000000000000000000000000000000..d812efca4b3a196cfb56fd92a83e4ccefc21787f Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.38.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.4.png b/web-ui/docs/en/blog/Benshuai5D/image/2.4.png new file mode 100644 index 0000000000000000000000000000000000000000..596afb8c93d837374762450632ef4e8526607513 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.4.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.5.png b/web-ui/docs/en/blog/Benshuai5D/image/2.5.png new file mode 100644 index 0000000000000000000000000000000000000000..11599fcda5430204ff8597cae625391d29b51c4b Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.5.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.6.png b/web-ui/docs/en/blog/Benshuai5D/image/2.6.png new file mode 100644 index 0000000000000000000000000000000000000000..31f06e172d27300f405c8e5209320dcefab81dd4 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.6.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.7.png b/web-ui/docs/en/blog/Benshuai5D/image/2.7.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4f73f1af8f0b6ea5f0d3993516396c711195ca Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.7.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.8.png b/web-ui/docs/en/blog/Benshuai5D/image/2.8.png new file mode 100644 index 0000000000000000000000000000000000000000..a61895105572e354e7036916dbdc0aaa826471b5 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.8.png differ diff --git a/web-ui/docs/en/blog/Benshuai5D/image/2.9.png b/web-ui/docs/en/blog/Benshuai5D/image/2.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1f79f9d93373ad0336cbebbdff2441642cad51a1 Binary files /dev/null and b/web-ui/docs/en/blog/Benshuai5D/image/2.9.png differ diff --git a/web-ui/docs/en/blog/bluesky1213/2020-06-30-The-Future-of-Cloud-in-a-COVID-19-Era.md b/web-ui/docs/en/blog/bluesky1213/2020-06-30-The-Future-of-Cloud-in-a-COVID-19-Era.md new file mode 100644 index 0000000000000000000000000000000000000000..043af9c0bedfe8c114b199996b9aa29e4f689bab --- /dev/null +++ b/web-ui/docs/en/blog/bluesky1213/2020-06-30-The-Future-of-Cloud-in-a-COVID-19-Era.md @@ -0,0 +1,115 @@ +--- +title: The Future of Cloud in a COVID-19 Era +date: 2020-06-24 +tags: + - Cloud + - COVID-19 + - Open Hardware +archives: 2020-06 +author: ByBryan Che +summary: How was Huawei Cloud able to grow so quickly over such a short time? One of the things that distinguishes Huawei is that we believe in the power of open innovation. + +--- + +# The Future of Cloud in a COVID-19 Era + + + + +## **Three Years of Astonishing Cloud Growth** + +Almost exactly three years ago in June 2017, Huawei launched its public cloud business, [Huawei Cloud](https://www.huaweicloud.com/en-us/), in China. At the time, China’s public cloud market had just exceeded **US$1 billion in the 1H 2017**. + +The top vendors in the space were: + +Source: [China Internet Watch](https://www.chinainternetwatch.com/22936/public-cloud-market-share-h1-2017/) **Public Cloud Market Share in H1 2017 (IaaS)** + +Three years later, and Canalys has just released its latest figures for the China public cloud market, as of June 2020: + + + +Several things are noteworthy from a comparison between 2017 and 2020: + +- Over 3 years, China’s public cloud infrastructure market has grown about 800%, from $1B over 6 months in H1 2017 to US$3.9 billion over 3 months in Q1 2020. +- China’s public cloud market is coalescing around its larger technology leaders, BAT and Huawei. +- During these 3 years, Huawei Cloud grew and gained share the fastest, going from non-existent to now the #2 public cloud in China. + +On this 3-year anniversary of Huawei Cloud, I’d like to take the opportunity to reflect on a few key trends in cloud computing: the effects of COVID-19 on cloud, the evolution of global cloud industries, and the importance of being open. + +## **COVID-19 and the Acceleration of Digital Trends** + +COVID-19 has been a terrible blight upon the world, inflicting both human suffering and economic hardship. As people have been staying at home and moving interactions online, the use of digital services and connections has spiked dramatically. + +From events to meetings to media to shopping, everything that can be online is moving online. Of course, in China, many of these activities had already moved online and onto smartphones years ago—and at much higher adoption rates than in other countries. Ubiquitous app-based food delivery, restaurants with QR-code-based menus, cashless spending, and many other digital services are so normal here, they are the rule rather than the exception. + +Even with all these digital services, though, China’s total spending on public cloud infrastructure is still relatively small both for its economy size and also when compared with other markets. **So, it is remarkable that even in China, COVID-19 has brought such a dramatic increase in spending on cloud computing services**. + +
+ +
+ +As evidenced by a 67% increase in Q1 cloud spending against a massive global slowdown, COVID-19 has demonstrated to Chinese companies that in times of abrupt need, only cloud can truly deliver the necessary scale, agility, and depth of services required. Thus, even after this COVID-19 crisis has passed, the acceleration towards cloud in China will continue. + +## **The Evolution of Global Cloud Industries** + +As China and the world accelerate their adoption of cloud, what will this look like? Different regions will evolve differently, but they will share many similar characteristics. For example, consider both China and Europe. + +## **China and New Infrastructure** + +To help address the economic fallout from COVID-19, the Chinese government recently announced to accelerate a multi-trillion yuan investment plan towards **New Infrastructure**, the goal of which is to provide ubiquitous and high quality connectivity and computing. Target technologies and industries for New Infrastructure spending include cloud, AI, 5G, blockchain, and industrial internet. + + + +So, not only did COVID-19 bring a spike in cloud consumption in China while everyone stayed home, it is also leading to a massive new investment across the country in digital technologies. This in turn will only further accelerate the adoption of cloud services in China. + +# Europe and Digital Sovereignty + +Like China, the European Commission has recently introduced a massive €750 billion stimulus plan to deal with the COVID-19 fallout, *Next Generation EU*. And, like with China’s New Infrastructure, Europe’s **Next Generation EU** calls for spending heavily on projects towards strengthening for the digital age: + + +- Investing in more and better connectivity, especially in the rapid deployment of 5G networks. +- A stronger industrial and technological presence in strategic sectors, including artificial intelligence, cybersecurity, supercomputing and cloud. +- Building a real data economy as a motor for innovation and job creation. +- Increased cyber resilience. + +In addition, though, as Europe invests in these technologies, it is also doing so with an eye towards digital sovereignty. And so, also this past month, [GAIA-X](https://www.data-infrastructure.eu/GAIAX/Navigation/EN/Home/home.html), a project to build a federated digital infrastructure for Europe, officially announced their new European foundation: + +> *With GAIA-X, representatives from politics, business and science from France and Germany, together with other European partners, create a proposal for the next generation of a data infrastructure for Europe: a secure, federated system that meets the highest standards of digital sovereignty while promoting innovation. This project is the cradle of an open, transparent digital ecosystem, where data and services can be made available, collated and shared in an environment of trust.* +> +> [Data Infrastructure EU, GAIA-X](https://www.data-infrastructure.eu/GAIAX/Navigation/EN/Home/home.html) + +According to a recent Gartner study, the adoption rate of public cloud for many European countries is similar to that of China and also lags many other markets: + + + +With projects like Next Generation EU and GAIA-X, however, European adoption of cloud and digital technologies should rapidly accelerate over the next few years. And just as in China and around the world, we look forward to sharing our experience and expertise and to working together openly and securely to build out this next generation of digital services. + +# **The Importance of Being Open** + +How was Huawei Cloud able to grow so quickly over such a short time? One of the things that distinguishes Huawei is that we believe in the power of open innovation. + +This is how we view our Huawei Cloud business: + + + +## **Open Hardware** + +First, Huawei believes that as we move towards next generation cloud services, AI, energy efficiency, edge computing, and many additional factors are going to drive cloud towards heterogeneous architectures. To support that, Huawei offers a variety of advanced chipsets optimized for different types of use cases, including x86 CPU, Arm CPU, GPU, NPU etc. + +Unlike other cloud providers, though, we share our hardware and chipsets openly with other vendors to implement their own systems and clouds. We do not restrict them only to Huawei Cloud. + +## **Open Source Software** + +Huawei Cloud is built on open source software. From OpenStack at the IaaS layer to Kubernetes and other CNCF projects at the container and PaaS layer to projects like our own open source AI framework [MindSpore](https://www.mindspore.cn/) for innovative services, Huawei Cloud is arguably the most open cloud in the industry. + +## **Open, Collaborative Innovation** + +Huawei is not just consuming open source software, though. Indeed, we are a top-level member and top contributor across all the major open source foundations and projects, including Linux Foundation, CNCF, OpenStack Foundation, Apache Foundation, and Eclipse Foundation. It is by deeply participating in the open source ecosystem that we are able to bring such fast innovation to market and grow at such a high rate. + +It’s not just in open source communities that we collaborate with others. This is why we have such a big partner focus at Huawei Cloud and look to enable them to be successful as well. When they do well, our customers do well, and we all do well together. + +# **To Shared Recovery and Triumph** + +I hope that during this period of deep trouble, a spirit of open, collaborative innovation can help us all work together for our shared recovery. Cloud computing works because it shares resources across many different users. Huawei Cloud has succeeded because we share in the open development and benefits of cloud. + +Europe, China, and the world will all have different paths forward out of our current situation. But, may the next three years and beyond bring for everyone a hopeful and triumphant future. \ No newline at end of file diff --git a/web-ui/docs/en/blog/cascades/Learning About libFuzzer.md b/web-ui/docs/en/blog/cascades/Learning About libFuzzer.md new file mode 100644 index 0000000000000000000000000000000000000000..29d3edd085515a944a8d84a698099c91de5c96f3 --- /dev/null +++ b/web-ui/docs/en/blog/cascades/Learning About libFuzzer.md @@ -0,0 +1,262 @@ +--- +title: "[Open Source Promotion Plan] Learning About libFuzzer" +date: 2021-08-14 +tags: + - Fuzzing + - Peng Cheng Laboratory + - summer2021 +archives: 2021-08 +author: cascades +summary: libFuzzer is an in-process, coverage-guided, evolutionary fuzzing engine for library functions. It is included in the LLVM project. +--- + +# Learning About libFuzzer + +This article was first published in the openEuler community [Open Source Promotion Plan](https://summer.iscas.ac.cn/). +Project Name: [No. 112 Improving QEMU Fuzzing](https://gitee.com/openeuler-competition/summer2021-112) + +## About This Document + +libFuzzer is an `in-process`, `coverage-guided`, and `evolutionary` fuzzing engine that is a part of the LLVM project. It provides the fuzzing input for the to-be-tested library and related functions through a specific entry point. During the test, libFuzzer constantly mutates the input and measures code coverage and crashes. + +* [Project location](https://www.llvm.org/docs/LibFuzzer.html) +* [Code path](https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/fuzzer) + +## Using libFuzzer + +### Experiment Environment + +The cloud host of the Peng Cheng Laboratory running openEuler is used. + +```bash= +[root@host-10-0-0-94 libFuzzer]# lscpu +Architecture: aarch64 +CPU op-mode(s): 64-bit +Byte Order: Little Endian +CPU(s): 4 + +[root@host-10-0-0-94 libFuzzer]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +``` + +### Using libFuzzer in Simple Mode + +[libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) + +1. Install LLVM and Clang. + * [Source code build](https://clang.llvm.org/get_started.html#build): The requirements on the host are strict (8 GB memory and 15 GB to 20 GB drives), and the build commands need to be optimized. In addition, install [`compile-rt`](https://compiler-rt.llvm.org) on which libFuzzer depends. + ```bash= + git clone https://gitee.com/mirrors/LLVM.git + cd LLVM ; mkdir build ; cd build + cmake -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;compiler-rt" -DCMAKE_BUILD_TYPE="Release" -DLLVM_TARGETS_TO_BUILD="host" -G "Unix Makefiles" ../llvm + make -j4 + ``` + + * [Binary installation](https://github.com/llvm/llvm-project/releases): Download the binary files of various versions to facilitate version switching. Add soft links to environment variables for ease of use. + * [Package manager installation](https://www.rootusers.com/how-to-install-dnf-package-manager-in-centosrhel/): The package manager version is old and contains libFuzzer. + ```bash= + # Run the sudo apt/dnf search xxx command to view the software contained in the package manager and the version. + sudo apt/dnf install clang llvm compiler-rt + ``` + +2. Build the binary file to be tested and add the libFuzzer build option. + + ```cpp= + // The function interface provided by libFuzzer is implemented in the source code fuzz_me.cc to be tested. + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + DoSomethingInterestingWithMyAPI(Data, Size); + return 0; // Non-zero return values are reserved for future use. + } + ``` + + ```bash= + # Clang searches for the static link libraries of libclang_rt.xxx.a, that is, sanitizers. + # In addition to ASAN, other sanitizers such as UBSAN and TSAN can be added. + clang -fsantize=address,fuzzer -g fuzz_me.c -o fuzz_me + ``` + +If the build command fails to be executed, the installation in the previous step fails. In this case, check the location of the compile-rt library or reinstall the library. + +3. Run the binary file and check the output. + ```bash= + ./fuzz_me + grep ERROR ./*.log | sort -k 3 + ``` +If a sanitizer detects an abnormal behavior of the program, fuzzing output (a crash) is generated. In addition to the crash, the fuzzer also records parameters during fuzzing, such as code coverage (in the unit of basic block) and seed mutation. + +4. Reproduce the input to locate the vulnerability. + ```bash= + ./fuzz_me crash-xxx + ./fuzz_me -seed=xxx # xxx is the SHA-1 hash value of the crash. + gdb fuzz_me + ``` +The sanitizer provides the vulnerability type and the environment where the vulnerability is triggered. Check the crash details, then reproduce the vulnerability, or use the GDB for debugging. + +![](https://img-blog.csdnimg.cn/img_convert/585afb1d9b9b3892943e01d85abc25de.png) + + +### Helpful Utilities +For large-scale software, some build options need to be enabled to improve fuzzing efficiency. +* `-jobs`: number of jobs. Each job triggers a crash. Jobs run in the worker processes. One worker can manage multiple jobs. If **-jobs** is set to **1000**, simple bugs of the program can be bypassed. +* `-workers`: number of processes. A maximum of half of the CPU cores can be used. +* `-forks`: Replace `-jobs = N` and `-workers = N` with `-fork = N`. +* `-dict`: dictionary, which is necessary for fuzzing files in a specific format. +* `CORPUS`: corpus, which is used to save the input for triggering new paths in fuzzing. +* `-max-len`: maximum input length, which is defined based on the size of the corpus file. +* `-run`: Reduce the crash producer. The unit is the number of mutations in each iteration. +* `-shrink`: Reduce the corpus size to improve code coverage. + + +### Project Practice +* Course: The [`libFuzzer workshop`](https://github.com/Dor1s/libfuzzer-workshop/) includes common methods for using libFuzzer. +* Open source project CVE practice: libFuzzer has discovered [many vulnerabilities](https://www.llvm.org/docs/LibFuzzer.html#trophies) in open source software, including the Heartbleed vulnerability in OpenSSL. Find a piece of open source software with vulnerabilities in Google [`fuzzer-test-suite`](https://github.com/google/fuzzer-test-suite) and reproduce the vulnerabilities using libFuzzer. +* Comparison with other tools: see [Related links](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md#related-links) in the libFuzzer tutorial. + +## libFuzzer Principles + +### Mutation Algorithms +Mutation is a key step in modern fuzzers because it generates new inputs that can cover more basic blocks. libFuzzer contains a series of built-in simple mutation algorithms, most of which are bit-level inversion. It also supports user-defined mutation algorithms for targeted fuzzing. + +#### Existing Mutation Algorithms +By observing the [`Stderr Output`](https://www.llvm.org/docs/LibFuzzer.html#output) of libFuzzer, you can find the mutation algorithms used by the current input in the MS field. See the following figure: + +![](https://img-blog.csdnimg.cn/img_convert/cac0122be891840a29113c2a1136c681.png) + +libFuzzer has 12 built-in mutation algorithms, which are member functions of the `MutationDispatcher` class. The class definition code is as follows: + +```cpp= +// Code path: LLVM/compiler-rt/lib/fuzzer/FuzzerMutate.cpp + +MutationDispatcher::MutationDispatcher(Random &Rand, const FuzzingOptions &Options) : Rand(Rand), Options(Options) { + DefaultMutators.insert( + DefaultMutators.begin(), + { + {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_InsertRepeatedBytes, "InsertRepeatedBytes"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, + {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, + {&MutationDispatcher::Mutate_AddWordFromManualDictionary, "ManualDict"}, + {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, "PersAutoDict"}, + }); + // Implementation of the preceding functions + } +``` + +The names of most mutation algorithms reflect their implementation methods. For example, `EraseBytes` calls the `memmove` function to overwrite some bits, and `InsertBytes` calls the `memmove` function to add a bit. It should be noted that in these built-in mutation algorithms, the mutation point and the mutation value are generated using a random function of the `Rand` series. + + +#### Adding a Mutation Algorithm + +libFuzzer and AFL are `coverage-guided` fuzzing tools. When fuzzing specific objects, they may be filtered out at the early stage of program running because the mutation algorithms do not contain semantic information. Compared with generation-based fuzzing tools, libFuzzer and AFL are inefficient. Therefore, Google proposed [`structure-aware fuzzing`](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md), a `libFuzzer plugin` that allows users to add mutation algorithms. This section describes how to add a plugin and lists some officially implemented plugins. + +The following code shows how to add a plugin. Implement a user-defined `LLVMFuzzerCustomMutator` function, add a specific mutation algorithm, and call `LLVMFuzzerMutate` in the function to implement common mutation. + +When implementing code, use the conditional compilation instructions `ifdef CUSTOM_MUTATOR` and `clang -DCUSTOM_MUTATOR` to enable or disable the user-defined plugin. + +```cpp= +// Optional user-provided custom mutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +// Given the same Seed produces the same mutation. +size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed); + +// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); +``` + +To add your own plugins, refer to the [related links](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#related-links) or the topic [`"Structure-aware fuzzing for Clang and LLVM with libprotobuf-mutator"`](https://www.youtube.com/watch?v=U60hC16HEDY) at the 2017 LLVM Developers' Meeting. + +### Coverage Statistics + +Analyze code coverage from the following two perspectives: + +* **Statistical precision**: From rough to precise, code coverage are classified into three levels: + * `Function level`: Collects statistics on called functions. Statistics on the internal code of the functions are ignored. + * `Basic block level`: Collects statistics on basic blocks, which can be queried in the **cov** field of [`Stderr Output`](https://www.llvm.org/docs/LibFuzzer.html#output) in libFuzzer. + * `Edge level`: Collects statistics on not only basic blocks, but also virtual blocks created between basic blocks and the execution information. + +![](https://img-blog.csdnimg.cn/img_convert/f3d19dfa66d44924b3386cd6860505c5.png) + +* **Analysis object**: The basic statistics method is instrumentation by adding count variables. There are three levels: + * `Source code`: Provides coverage statistics modes in build options. + * `Intermediate representation`: Specifies statistics collection mode, for example, `llvm pass`. + * `Binary`: Use binary instrumentation tools such as `Pin` and `DynamoRIO` to collect statistics on hooks. + +In short, libFuzzer uses [`SanitizerCoverage`](https://clang.llvm.org/docs/SanitizerCoverage.html) in the LLVM framework to collect source code–level coverage statistics. You can run the following command to specify the level. By default, the `edge` level is used. + +```bash= +# xxx=edge,bb,func,trace-pc-guard,inline-8bit-counters,inline-bool-flag,pc-table,trace-pc +clang -fsanitize-coverage=xxx fuzz_me.c +``` + +In addition, you can develop analysis tools using `SanitizerCoverage`. The sanitizer provides a coverage callback interface that allows you to dump the coverage statistics result to a `.sancov` file when the fuzzing process is stopped. The LLVM framework provides the `Sancov Tool` to generate source code–level coverage reports. + +### Error Check + +#### Common Errors + +As mentioned, the mission of each `job` in the libFuzzer process is to complete the check task. It does not stop until a crash occurs or it times out. In this case, the libFuzzer daemon process captures the error code. If the error code is **77**, a timeout occurs (the default timeout interval is 1,200 seconds) or the libFuzzer program is abnormal. If the error code is **crash**, the result and the input that causes the crash are recorded. + +#### Sanitizers + +Crash detection does not cover all fuzzing error check scenarios. For example, memory leakage and data races may not cause crashes, but they are serious errors. In such cases, memory detection tools such as `Valgrind` can be used. libFuzzer uses a series of [`sanitizers`](https://github.com/google/sanitizers) in the LLVM framework. These tools are provided by Google and can be used to detect runtime exceptions of C/C++. Common sanitizers are as follows: +* `AddressSanitizer (ASAN)`: Captures stack overflow and UAF vulnerabilities. +* `ThreadSanitizer (TSAN)`: Captures data races and supports C/C++ and Go. +* `UndefinedBehaviorSanitizer (UBSAN)`: Captures abnormal behaviors such as integer overflow and null pointer dereference. + +ASAN is used as an example to analyze the principles of these error check tools. For details, see [`USENIX ATC 2021`](http://research.google.com/pubs/pub37752.html). + +1. During compilation, ASAN performs instrumentation before and after LLVM IR-level memory access operations (load, store, and alloca). Due to the 8-byte alignment requirement of memory, some memory is in unused status. Set it to `shadow memory` in memory mapping mode to show the read and write status. +2. Hook the malloc function during running and set the `Redzone` area before and after the function, which is similar to the stack canary method. Set the shadow memory in the Redzone to unwritable to avoid overflow. +3. Perform hook operations on the free function during running. Instead of releasing memory immediately, set the shadow memory to a negative value. That is, the shadow memory cannot be read or written, and is placed in the isolation area for observation. If UAF or wild pointer dereference occurs, it will be captured. + +![](https://img-blog.csdnimg.cn/img_convert/e70c15eb1734af0179d9745801a3e88d.png) + + +## Other Fuzzers + +* Academia: As a hot academic topic in recent years, fuzzing-related papers were presented at top international conferences for fields such as system security, network security, software analysis, and programming language. For details, see the [`FuzzingPaper`](https://github.com/wcventure/FuzzingPaper) project. Most of these papers propose a fuzzer for a specific object (software, hardware, OS kernel, programming language, etc.) or a specific vulnerability type (race condition, buffer overflow, etc.), and use methods such as concolic fuzzing and deep learning to improve fuzzing efficiency. + +* Industry: Many tools are developed on GitHub based on AFL and libFuzzer, and subsequently many companies developing fuzzing technologies have emerged. Google developed a series of fuzzing tools and the `FuzzBench` platform to evaluate fuzzer performance in a unified manner. + +In short, the research on fuzzing in academia and industry is closely related. Most fuzzing technologies are implemented based on the LLVM framework and are highly scalable. The academic research is conducted based on the existing tools in the industry, and the achievements with good performance are released on GitHub. The following lists some fuzzers. For more fuzzers, visit [`Awesome-Fuzzing`](https://github.com/secfigo/Awesome-Fuzzing). +* Generic fuzzers + * [`libFuzzer-gv`](https://github.com/guidovranken/libfuzzer-gv): enhanced edition of libFuzzer + + * [`AFL++`](https://aflplus.plus/): enhanced edition of AFL + + * [`OSS-Fuzz`](https://google.github.io/oss-fuzz/) + [ClusterFuzz](https://google.github.io/clusterfuzz): large-scale distributed fuzzer implemented through cooperation between the frontend and backend + + * [`boofuzz`](https://boofuzz.readthedocs.io/en/stable/): enhanced edition of the Sulley framework + + * [`phuzzer`](https://github.com/angr/phuzzer): Python framework for interacting with AFL + +* Safety + * [`Honggfuzz`](https://honggfuzz.dev/): fuzzer targeting at software security vulnerabilities + + +* Network protocol + * [`AFLNet`](https://github.com/aflnet/aflnet): gray-box fuzzer for network protocols + +* Kernel + * [`Syzkaller`](https://github.com/google/syzkaller): unsupervised Linux kernel fuzzer + +* Programming language + * [Fuzzers implemented using Rust](https://github.com/rust-fuzz): AFL, libFuzzer, and Honggfuzz + * [`PolyGlot`](https://github.com/s3team/Polyglot): fuzzer for programming language interpreters + +* IoT + * [`FirmAFL`](https://github.com/zyw-200/FirmAFL): gray-box fuzzer for IoT firmware + * [`DIANE`](https://github.com/ucsb-seclab/diane): fuzzer for IoT applications on mobile phones + * [`Frankenstein`](https://github.com/seemoo-lab/frankenstein): fuzzer for wireless IoT devices + +If there are any errors, please contact [cascades-sjtu](https://cascadeschen.cn). diff --git a/web-ui/docs/en/blog/cascades/Learning about the QEMU Fuzzer.md b/web-ui/docs/en/blog/cascades/Learning about the QEMU Fuzzer.md new file mode 100644 index 0000000000000000000000000000000000000000..f0cf5cb048be6414473f94d8e1c1e8c7f30fc940 --- /dev/null +++ b/web-ui/docs/en/blog/cascades/Learning about the QEMU Fuzzer.md @@ -0,0 +1,416 @@ +--- +title: "[Open Source Promotion Plan] Learning about the QEMU Fuzzer" +date: 2021-08-15 +tags: + - Qemu + - Virtio + - summer2021 +archives: 2021-08 +author: cascades +summary: QEMU Fuzzer is a framework that uses libqtest and libFuzzer to perform fuzz testing on the process of reading and writing devices by the guest OS. QEMU Fuzzer is included in QEMU 5.0 and later versions. +--- + +# Learning about the QEMU Fuzzer + +This article was first published in the openEuler community [Open Source Promotion Plan](https://summer.iscas.ac.cn/). +Project Name: [No. 112 Improving QEMU Fuzzing](https://gitee.com/openeuler-competition/summer2021-112) + +## About This Document +Common QEMU + Fuzzing implementations include the qemu-afl mode and various tools that use virtualization technologies to fuzz IoT devices. + +This article describes the fuzzing framework for QEMU that performs fuzzing on Hypervisor. It adopts the Qtest framework to emulate the guest OS's read and write operations on devices and uses the heuristic algorithms of libFuzzer to collect massive amounts of data. This framework originates from the [`Google Summer of Code 2019`](https://summerofcode.withgoogle.com/archive/2019/projects/6200259867312128/) project and is added to the master branch in QEMU 5.0.0 and later versions. + +## QEMU Emulation Principles + +[`QEMU`](https://www.qemu.org/) is an open-source virtualization and emulation tool implemented by [`Fabrice Bellard`](https://bellard.org/). It supports two emulation modes: + +* `Full-system`: provides KVM and Hyper-V acceleration modes for CPU, memory, and peripheral emulation. +* `User-mode`: runs binary programs of another CPU architecture through instruction translation. + +Virtualization is to use a user-mode program to process the access of a device emulator to the memory and other special hardware when only the user-mode memory is used. To emulate devices with different architectures and instruction sets, QEMU adopts object-oriented programming and implements the `QEMU Object Model` to describe device models. + +* Device model: Each emulated device corresponds to a TypeInfo object, which is uniquely identified by a device name and stored in the hash table. +* Device startup: Device registration, device model initialization, and device instantiation are required before starting a device. +* Instruction translation: QEMU uses the software Tiny Code Generator (TCG) or kernel-based virtual machines (KVM) to receive instructions from the device emulator and translates the instructions to physical devices. Despite the performance overheads, the hardware virtualization overheads are relatively lower than those software virtualization overheads. +* Memory emulation: QEMU provides memory mappings for the client. When the client accesses the memory to write data to a drive, QEMU captures the access and sends the request to the IDE controller device model of QEMU. The model parses the I/O request and emulates an instruction via the system call of the host. Then, the memory of the client is copied to the drive of the host. + +In short, the guest OS considers that it can directly communicate with hardware devices on the host OS. Actually, QEMU acts as an intermediary as follows: + +```asciidoc= ++----------+ +----------+ +----------+ +----------+ +----------+ +| UserSpace| | UserSpace| | UserSpace| | UserSpace| | UserSpace| ++----------+ +----------+ +----------+ +----------+ +----------+ +| Linux | | Mac OS | | Windows | | Linux | | Solaris | ++----------+ +----------+ +----------+ +----------+ +----------+ +| Drivers | | Drivers | | Drivers | | Drivers | | Drivers | ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+ +----------+ +----------+ +----------+ +----------+ +| QEMU x86 | | QEMU x86 | | QEMU ARM | | QEMU PPC | | QEMU MIPS| ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+-+----------+-+----------+-+----------+-+----------+ +| Host System:Linux,Mac OS,Windows | ++--------------------------------------------------------------+ ++--------------------------------------------------------------+ +| Hardware:CPU,memory,disk,networking,USB,etc | ++--------------------------------------------------------------+ +``` + +For details about QEMU emulation, see [`User Documentation`](LLVMFuzzerTestOneInput). +For details about QEMU devices, see [`Understanding QEMU devices`](https://www.qemu.org/2018/02/09/understanding-qemu-devices/). +For details about QEMU, see [`QEMU, a Fast and Portable Dynamic Translator`](https://www.usenix.org/legacy/event/usenix05/tech/freenix/full_papers/bellard/bellard.pdf#:~:text=We%20present%20the%20internals%20of%20QEMU%2C%20a%20fast,one%20target%20CPU%20can%20be%20runon%20another%20CPU.). + +## Using the QEMU Fuzzer + +See the [official documentation](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html). + +### Test Environment + +For this experiment, we use the Docker environment on the local Windows Subsystem for Linux (WSL). + +```bash= +root@31b23c4c00b7:~/qemu# lscpu +Architecture: x86_64 +CPU op-mode(s): 32-bit, 64-bit +Byte Order: Little Endian +CPU(s): 16 +root@31b23c4c00b7:~/qemu# cat /etc/os-release +NAME="Ubuntu" +VERSION="20.04.2 LTS (Focal Fossa)" +``` + +#### Problem with the Environment + +* Description: The QEMU Fuzzer has not adapted to the AArch64 architecture. Although the compilation is successful, an error is reported during the running. + +![](https://img-blog.csdnimg.cn/img_convert/2161923b370fbd9f89318104b70fad11.png) + +* Solution: Adapting QEMU Fuzzer to AArch64 is the goal of this project. Currently, the x86 environment is used. + +#### Wrong Version + +* Description: The example on the official website uses Clang 8. However, the latest Clang version is Clang 14. If a version later than Clang 8 is used, an error is reported in the compile phase because **-Werror** is enabled. + +* Solution + * (Recommended) Use the package manager (apt/dnf) to install Clang. + * Run the **git checkout** command to match LLVM 8 to 10. + * Go to the [official release page](https://releases.llvm.org/) and download the LLVM source code whose version is between 8 and 10. + +```bash= +# Run the sudo apt/dnf search xxx command to view the software contained in the package manager and the corresponding version. The default version is Clang 10. +sudo apt/dnf install clang llvm compiler-rt +``` + +#### Packaging Docker + +To facilitate deployment, Docker is used to configure the experiment environment: [image path](https://hub.docker.com/repository/docker/cascadessjtu/qemu_fuzz) + +### Using the Fuzzer in Simple Mode + +After configuring the environment, run the following commands to compile and run the fuzzing program. The libFuzzer output is displayed. + +```bash= +CC=clang-10 CXX=clang++-10 ./configure --enable-sanitizers --enable-fuzzing +# qemu-fuzz-isa isa indicates the architecture of the device emulator. +make qemu-fuzz-i386 qemu-fuzz-aarch64 +# View available fuzzing objects. +build/qemu-fuzz-i386 --fuzz-target=FUZZ_NAME +``` + +The QEMU Fuzzer also supports libFuzzer compilation instructions, which can be viewed by running the `-help=1` command. + +To view fuzzing results, run [`Clang Sanitizer`](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html#generating-coverage-reports), a tool that uses the CORPUS parameter and modifies compilation instructions. After fuzzing is complete, run the `llvm-cov` command to convert the generated `default.profraw` file into an `.html` file. + +### Adding a User-Defined Fuzzer + +To add a new fuzzer, perform the following: +1. Compile the fuzzer source file `foo-device-fuzz.c` and save it in the `tests/qtest/fuzz` directory. +2. Refer to the existing fuzzer and use APIs in libqos and libqtest to communicate with the device emulator. +3. Register the fuzzer in the `tests/qtest/fuzz/meson.build` file. + +### Using the Fuzzer in Generic Mode + +Writing fuzzers for specific device models is time-consuming and laborious, especially for device drivers that are not included in libqos. QEMU provides the `generic-fuzz` option to perform preliminary fuzzing on all devices, including PIO, MMIO, and DMA. To enable generic-fuzz, set the following environment variables: +* `QEMU_FUZZ_ARGS=`: parameters required for configuring a device, such as the NIC and user name. +* `QEMU_FUZZ_OBJECTS`=: matching character strings to specify the memory area for fuzzing. Use `./qemu-fuzz-i386 --fuzz-target=generic-fuzz -runs=0` to check the matched memory area. More matched memory areas create a larger `input-space` for fuzzing. This makes it more difficult to identify the input that causes the device crash. Therefore, `MemoryRegion` must be set to a proper value. + +### Integrating OSS-Fuzz +OSS-Fuzz is an integrated fuzzing tool that fuzzes all objects by default. The official [`Dockerfile`](https://github.com/google/oss-fuzz/blob/master/projects/qemu/Dockerfile) for environment setup is provided, and the startup of the generic fuzzer requires additional settings of environment variables. Therefore, QEMU defines some device models in the `tests/qtest/fuzz/generic_fuzz_configs.h` file for OSS-Fuzz. In addition, developers can add new device models to the file. + +### Crash Reproduction Tool + +When you reproduce a crash, the QEMU that does not contain a fuzzer is required to filter out false alarms and enhance the debugging function. You can use the OSS-Fuzz script to create a `one-line reproducer`. + +### Fuzzer Lifespan + +The QEMU Fuzzer provides two entry points for libFuzzer, which are called after the main function of libFuzzer is called. +* `LLVMFuzzerInitialize`: called before fuzzing starts to initialize the environment. +* `LLVMFuzzerTestOneInput`: called when each fuzzing task is running to provide input and reset the status after fuzzing is complete. + +The Fuzzer process is reset after each fuzzing operation. In addition, the QEMU status needs to be reset. The following are two methods to reset the QEMU status. +* `Reboot`: Restart the guest OS after each fuzzing operation is complete. +* `Fork`: Run **test case** in subprocesses, which is similar to the `fork-server` mode of AFL. + +## Dependencies of the QEMU Fuzzer + +The implementation of the QEMU Fuzzer depends on the libqtest and libqos libraries. For details, see [`Testing QEMU emulated devices using qtest`](https://www.linux-kvm.org/images/4/43/03x09-TestingQEMU.pdf). This document describes the basic principles of Qtest, APIs, and methods of adding test cases. + +### libqtest + +* [Code path](https://github.com/qemu/qemu/tree/master/tests/qtest/libqtest.c) +* [Documentation](https://qemu.readthedocs.io/en/latest/devel/qtest.html) + +Qtest is a framework used to perform unit tests on hardware devices emulated by QEMU. It consists of the `Qtest Client` and `Qtest Server`. The two communicate with each other through UNIX Socket and support instructions such as PIO, MMIO, interrupt, and QMP. + +* `Qtest Client`: A driver program compiled for a device. It is encapsulated from bottom to top and depends on the glib unit test framework, libqtest, libqos, and qgraph. To add a new test program, perform the following: + + 1. Compile new test code `tests/qtest/foo-test.c` in the Qtest directory. + 2. Add compilation instructions to **Makefile.include**. + 3. Perform compilation: `make tests/qtest/foo-test.c` + 4. Run the test program. + ```bash= + QTEST_LOG=1 QTEST_QEMU_BINARY=i386-softmmu/qemu-system-i386 tests/qtest/foo-test` + ``` +* `Qtest Server`: Similar to the TCG and KVM, the `Qtest Server` is an accelerator and is registered by running `-machine accel=qtest`. In common scenarios, the vCPU directly interacts with virtual hardware. In test scenarios, the Qtest directly interacts with virtual hardware and acts as an intermediary between the Qtest client and virtual hardware. Qtest is used to check whether the device behavior is correct, and the guest OS is not started. + +During running, `libqtest.c` starts QEMU as a subprocess. The main function for starting QEMU is in `vl.c`. In the test scenario, the `qtest_init()` function of `qtest.c` is called to initialize the Qtest server. + +The following shows the relationship between the Qtest client and Qtest server. +```asciidoc= ++----------------+ socket +----------------+----------------------+ +| Qtest Client +----------> Qtest Server | | ++----------------+ +-------+--------+ | ++----------------+ | | Qemu | +| Qgraph | PIO|MMIO | | ++----------------+ | | | ++----------------+ +-------v--------+----------------------+ +| libqos | | Hardware Emulation | ++----------------+ +---------------------------------------+ ++----------------+ +| libqtest | ++----------------+ ++----------------+ +| glib test | ++----------------+ +``` + +### libqos + +* [Code path](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/libqos.c) +* [Documentation](https://qemu.readthedocs.io/en/latest/devel/qtest.html?highlight=libqos) + +libqos is a device driver framework used to compile qtest cases and provides APIs related to `memory`, `PCI`, and `virtio`. It provides the following functions: +* Acts as the wrapper of the bus and implements specific functions for each type of bus. +* Unifies the device access model and simplifies developers' work. + +## QEMU Fuzzer Process + +* [Code path](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz) +* [Documentation](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html) + +The preceding two dependencies are designed for QEMU function tests and depend on the test input. Fuzzing improves the test input quality by adding randomness and mutation algorithms to the input. In this way, libFuzzer can be used to hook the Qtest input to improve the test efficiency. The following shows the overall structure of the QEMU Fuzzer. + +![](https://img-blog.csdnimg.cn/img_convert/f269d3ace4fe504117d7fe4e2a253375.png) + +In the source code: +* `fuzz.h` defines the interface and data structure for implementing a fuzzing target and the interaction with libFuzzer. +* `fork_fuzz.h` defines the shared memory between concurrent fuzzers. +* `qos_fuzz.h` defines the encapsulated interfaces of libqos on Qtest. +* `generic_fuzz_configs.h` defines generic fuzzer settings. +* `virtio_xxx_fuzz.h` implements the fuzzing target of virtio devices (net, blk, and scsi). + +## QEMU Fuzzer Case Analysis + +The QEMU [`developer documentation`](https://wiki.qemu.org/Documentation/GettingStartedDevelopers) writes: + +QEMU does not have a high level design description document - only the source code tells the full story. + +Therefore, it is essential for QEMU developers to learn about the source code. This section uses the virtio-net device as an example to analyze the QEMU fuzzing process. The code path is [`tests/qtest/fuzz/virto_net_fuzz.c`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/virtio_net_fuzz.c). Virtio is a paravirtualization technology. It requires the host OS to emulate devices and the guest OS to drive devices. The following shows the working process. + +![](https://img-blog.csdnimg.cn/img_convert/8cbe7f371f062202bb88928900b3a481.png) + +The following describes the top-down implementation logic. +* First, implement the registration function `register_virtio_net_fuzz_targets()`. The `fuzz_add_qos_target()` function is provided by libqos to add three fuzzing objects and is the wrapper of `fuzz_add_target()` function by libqos. The prototype is as follows: + +```cpp= +void fuzz_add_qos_target( + FuzzTarget *fuzz_opts, + const char *interface, + QOSGraphTestOptions *opts + ); +``` + +* Finally, modify the [`meson.build`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c) file and add conditional compilation options. + +The following uses `virtio-net-socket` as the major fuzzing target to analyze the parameters and the functions involved in the parameters. + +* `virtio-net-socket`: +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket", + .description = "Fuzz the virtio-net virtual queues. Fuzz incoming " + "traffic using the socket backend", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +The first parameter is the pointer that points to the temporary object of FuzzTarget. This object is defined by [`fuzz.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c) and contains identification information and many callback functions related to fuzzing. It is described as follows: +```asciidoc= ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| Field | Declaration | Description | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| name | const char *name | target identifier (passed to --fuzz-target=) | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| description | const char *description | help text | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| pre_fuzz | void(*pre_fuzz)(QTestState *) | will run once, after QEMU has been initialized, prior to the fuzz-loop. | +| | | eg: detect the memory map | +| | | Can be NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| fuzz | void(*fuzz)(QTestState *, const unsigned char *, size_t); | accepts and executes an input from LibFuzzer. | +| | | this is repeatedly executed during the fuzzing loop. | +| | | It should handle setup, input execution and cleanup. | +| | | Cannot be NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +``` + +`virtio_net_pre_fuzz` initializes the shared memory used by **qos path** and **fork fuzz**. `virtio_net_fork_fuzz` forks the child process and calls the `virtio_net_fuzz_multi` function. This function uses the user-defined `vq_action` to manage random data, adds data packets to `virtioqueue` based on the arrival of data packets, and kicks out the data packets. The main loop is then run. + +The second parameter indicates the name of the used device. In this example, the value is **virtio-net**. + +The third parameter is the structure about the test options provided by [`qgraph.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/qgraph.h). The `before` parameter accepts functions whose prototype is `QOSBeforeTest`. The `virtio_net_test_setup_socket` function specifies the backend of the QEMU network device as **socket**. It facilitates communication with the virtual device and sends the data packets of the virtual device to the host network. + +* `virtio-net-socket-check-use` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket-check-used", + .description = "Fuzz the virtio-net virtual queues. Wait for the " + "descriptors to be used. Timeout may indicate improperly handled " + "input", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz_check_used,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +`virtio_net_fork_fuzz_check_used` is similar to `virtio_net_fork_fuzz`. The difference is that `true` is used when the `virtio_net_fuzz_multi` function is called. + +* `cirtio-net-slirp` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-slirp", + .description = "Fuzz the virtio-net virtual queues with the slirp " + " backend. Warning: May result in network traffic emitted from the " + " process. Run in an isolated network environment.", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_user} + ); +``` + +`virtio_net_test_setup_user` specifies the network backend as **user**. + +## QEMU Fuzzer Case CVE-2017-12809 + +This part briefly analyzes a [CVE vulnerability](https://unit42.paloaltonetworks.com/unit42-palo-alto-networks-discovers-new-qemu-vulnerability/) on QEMU discovered by libFuzzer. +* Vulnerability description: This vulnerability is a denial of service vulnerability. When an IDE drive and CD/DVD-ROM emulator are used to build the guest OS, privileged users in the guest OS can clear an empty CD-ROM device driver, causing null pointer dereference. As a result, the QEMU process breaks down. +* Vulnerability code: Before calling the `blk_aio_flush()` function in the `hw/ide/core.c` file, the system does not check whether `s->blk` is empty. +```asciidoc= +--- + hw/ide/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index 0b48b64d3a..bea39536b0 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s) + s->status |= BUSY_STAT; + ide_set_retry(s); + block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH); +- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ ++ if (blk_bs(s->blk)) { ++ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ } else { ++ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this ++ * temporary workaround when blk_aio_*() functions handle NULL blk_bs. ++ */ ++ ide_flush_cb(s, 0); ++ } + } + + static void ide_cfata_metadata_inquiry(IDEState *s) +-- +``` +* [Vulnerability troubleshooting](https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg01989.html): Add a condition judgment to where the vulnerability occurs and test code to `tests/ide-test.c`. + +```asciidoc= +--- + tests/ide-test.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/tests/ide-test.c b/tests/ide-test.c +index bfd79ddbdc..aa9de065fc 100644 +--- a/tests/ide-test.c ++++ b/tests/ide-test.c +@@ -689,6 +689,24 @@ static void test_flush_nodev(void) + ide_test_quit(); + } + ++static void test_flush_empty_drive(void) ++{ ++ QPCIDevice *dev; ++ QPCIBar bmdma_bar, ide_bar; ++ ++ ide_test_start("-device ide-cd,bus=ide.0"); ++ dev = get_pci_device(&bmdma_bar, &ide_bar); ++ ++ /* FLUSH CACHE command on device 0 */ ++ qpci_io_writeb(dev, ide_bar, reg_device, 0); ++ qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE); ++ ++ /* Just testing that qemu doesn't crash... */ ++ ++ free_pci_device(dev); ++ ide_test_quit(); ++} ++ + static void test_pci_retry_flush(void) + { + test_retry_flush("pc"); +@@ -954,6 +972,7 @@ int main(int argc, char **argv) + + qtest_add_func("/ide/flush", test_flush); + qtest_a + cd qemu + git checkout stable-2.10dd_func("/ide/flush/nodev", test_flush_nodev); ++ qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive); + qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush); + qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush); + +-- +``` + +* Vulnerability reproduction: Find the commit version before the patch is installed, add the test cases in the new test, and run the Qtest program. +```bash= +# The corresponding version cannot be obtained by running the **wget** command because all affected versions have been fixed. +git clone https://gitlab.com/qemu-project/qemu.git;cd qemu +git checkout stable-2.10 +# Obtain the author of the patch from the mailing list and find the corresponding commit. +git log --author=Hajnoczi +git reset --hard=4da97120d51a4383aa96d741a2b837f8c4bbcd0b +# Start building. +mkdir build;cd build;../configure ----disable-werror +make qtest +``` + +The QEMU VM escape vulnerability has been common in Capture the Flag (CTF) competitions and Common Vulnerabilities and Exposures (CVE), for example, [CVE-2020-14364](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14364). + +If there is any error, please contact [cascades-sjtu](https://cascadeschen.cn). diff --git a/web-ui/docs/en/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md b/web-ui/docs/en/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md new file mode 100644 index 0000000000000000000000000000000000000000..205196bdc4e4dca90c74a91b7753a976f771be99 --- /dev/null +++ b/web-ui/docs/en/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md @@ -0,0 +1,156 @@ +--- +title: Installing GNOME 3.38 on openEuler 21.09 +date: 2021-10-12 +tags: + - GNOME +archives: 2021-10 +author: dwl301 +summary: Just about how to install GNOME 3.38 on openEuler 21.09 and resolve known issues. +--- + +# Installing GNOME 3.38 on openEuler 21.09 + +GNOME is a desktop environment for Unix-like operating systems. It is the official desktop of GNU Project, providing a comprehensive, easy-to-use, and user-friendly environment for developing and using applications. + +This document describes how to install a complete GNOME desktop environment on openEuler 21.09. + +## 1. Downloading the openEuler 21.09 Image + +``` +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso.sha256sum +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso +# sha256sum -c openEuler-21.09-x86_64-dvd.iso.sha256sum +openEuler-21.09-x86_64-dvd.iso: OK +``` + +## 2. Making an OS Installation Medium +Assume that the following **sdb** is a USB storage device. In this case, run the **lsblk** command to confirm the device. + +``` +# dd if=./openEuler-21.09-x86_64-dvd.iso of=/dev/sdb +# sync +``` + +## 3. Installing the OS +Boot the OS from your USB device and install the OS in the minimum installation mode. +Then ensure a minimum 5 GB available space for the root partition to install GNOME 3.38. + +## 4. Configuring the OS and Installing GNOME 3.38 +Set the system Yum source. +Ensure that the following addresses are included in your **/etc/yum.repos.d/openEuler.repo** file: + +``` +baseurl=http://repo.openeuler.org/openEuler-21.09/everything/x86_64/ +baseurl=http://repo.openeuler.org/openEuler-21.09/EPOL/main/x86_64/ +``` + +Refresh the Yum cache. +``` +# yum clean all +# yum makecache +``` + +Install font packages. +``` +# yum install -y dejavu-fonts liberation-fonts gnu-*-fonts wqy-*-fonts cjkuni-ukai-fonts +``` +If you use a high-speed network, add **google-\*-fonts** in the preceding command to install the large Google font packages; otherwise, do not add **google-\*-fonts**. + +Install X Server dependencies. +``` +# yum install -y xorg-* +``` + +Install GNOME 3.38 dependencies. +``` +# yum install -y adwaita-icon-theme atk atkmm at-spi2-atk at-spi2-core baobab abattis-cantarell-fonts cheese clutter clutter-gst3 clutter-gtk cogl dconf dconf-editor devhelp eog epiphany evince evolution-data-server file-roller folks gcab gcr gdk-pixbuf2 gdm gedit geocode-glib gfbgraph gjs glib2 glibmm24 glib-networking gmime30 gnome-autoar gnome-backgrounds gnome-bluetooth gnome-boxes gnome-builder gnome-calculator gnome-calendar gnome-characters gnome-clocks gnome-color-manager gnome-contacts gnome-control-center gnome-desktop3 gnome-disk-utility gnome-font-viewer gnome-getting-started-docs gnome-initial-setup gnome-keyring gnome-logs gnome-menus gnome-music gnome-online-accounts gnome-online-miners gnome-photos gnome-remote-desktop gnome-screenshot gnome-session gnome-settings-daemon gnome-shell gnome-shell-extensions gnome-software gnome-system-monitor gnome-terminal gnome-tour gnome-user-docs gnome-user-share gnome-video-effects gnome-weather gobject-introspection gom grilo grilo-plugins gsettings-desktop-schemas gsound gspell gssdp gtk3 gtk4 gtk-doc gtkmm30 gtksourceview4 gtk-vnc2 gupnp gupnp-av gupnp-dlna gvfs json-glib libchamplain libdazzle libgdata libgee libgnomekbd libgsf libgtop2 libgweather libgxps libhandy libmediaart libnma libnotify libpeas librsvg2 libsecret libsigc++20 libsoup mm-common mutter nautilus orca pango pangomm libphodav python3-pyatspi python3-gobject rest rygel simple-scan sushi sysprof tepl totem totem-pl-parser tracker3 tracker3-miners vala vte291 yelp yelp-tools yelp-xsl zenity +``` + +Start GNOME 3.38 using the GNOME Display Manager. +``` +# systemctl start gdm +``` + +Enable the default desktop login upon system start. +``` +# systemctl enable gdm +# systemctl set-default graphical.target +``` + +## 5. Fixing Known Issues +### 5.1 Failed to Play Videos +The decoder is missing. Manually compile and install the decoder. +``` +# yum install rpm-build git ffmpeg-devel +# git clone https://gitee.com/src-openeuler/gstreamer1-libav.git +# mkdir -p ~/rpmbuild/SOURCES +# cp gstreamer1-libav/* /root/rpmbuild/SOURCES/ +# rpmbuild -ba /root/rpmbuild/SOURCES/gstreamer1-libav.spec +# yum install -y /root/rpmbuild/RPMS/x86_64/gstreamer1-libav-1.18.4-1.x86_64.rpm +``` +Ensure that each command is executed properly and no error is reported. + +### 5.2 Failed to Create a VM by GNOME Boxes Using a Local ISO File +The CPU type of the VM running in the default QEMU version is incorrect. Upgrade GNOME Boxes to the following version: + +``` +# rpm -Uvh http://119.3.219.20:82/openEuler:/Mainline/standard_x86_64/x86_64/gnome-boxes-3.38.2-3.oe1.x86_64.rpm +``` + +Recompile QEMU. The smartcard option is disabled for the QEMU version installed by default. Add the `--enable-smartcard ` option to the **configure** command and recompile QEMU. +``` +# wget https://repo.openeuler.org/openEuler-21.09/source/Packages/qemu-4.1.0-82.oe1.src.rpm +# rpm -ivh qemu-4.1.0-82.oe1.src.rpm + +Modify the ~/rpmbuild/SPECS/qemu.spec file as follows: +# diff -Nur ~/rpmbuild/SPECS/qemu.spec.bak ~/rpmbuild/SPECS/qemu.spec +--- /root/rpmbuild/SPECS/qemu.spec.bak 2021-10-12 14:30:30.300362506 +0800 ++++ /root/rpmbuild/SPECS/qemu.spec 2021-10-12 14:37:14.140967049 +0800 +@@ -1,6 +1,6 @@ + Name: qemu + Version: 4.1.0 +-Release: 82 ++Release: 83 + Epoch: 2 + Summary: QEMU is a generic and open source machine emulator and virtualizer + License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 +@@ -750,7 +750,7 @@ + --disable-parallels \ + --disable-sheepdog \ + --disable-capstone \ +- --disable-smartcard \ ++ --enable-smartcard \ + --enable-zstd + + make %{?_smp_mflags} $buildldflags V=1 +@@ -963,6 +963,9 @@ + %endif + + %changelog ++* Tue Oct 12 2021 Wenlong Ding ++- Open build option: --enable-smartcard ++ + * Sun Sep 26 2021 Chen Qun + - virtio-net: fix use after unmap/free for sg + +``` + +Install the QEMU compilation dependencies, and recompile and upgrade QEMU. +``` +# yum install -y bison brlapi-devel chrpath device-mapper-multipath-devel flex gnutls-devel libaio-devel libattr-devel libcap-devel libcap-ng-devel libcurl-devel libiscsi-devel librbd-devel libseccomp-devel libssh-devel libtasn1-devel lzo-devel ncurses-devel numactl-devel pam-devel python-sphinx python3-devel rdma-core-devel snappy-devel spice-server-devel texinfo zstd-devel +# rpmbuild -ba /root/rpmbuild/SPECS/qemu.spec +# rpm -Uvh ~/rpmbuild/RPMS/x86_64/qemu-*.rpm +``` +After the upgrade is complete, restart the host. After logging in to the host again, you can create and run VMs using gnome-boxes. + +### 5.3 Inefficiency for Common Users to Run VMs Using GNOME Boxes +Common users are not automatically added to the `kvm` and `libvirt` groups, and VMs can only run as QEMU emulators. This makes it inefficient for common users to run VMs using GNOME Boxes. +Run the following commands to add common users to the two groups so that VMs can run in KVM paravirtualization mode to improve the VM running efficiency. +``` +# usermod -aG kvm test +# usermod -aG libvirt test +# id test +uid=1000(test) gid=1000(test) groups=1000(test),10(wheel),36(kvm),985(libvirt) +``` + +After a common user is added to the `kvm` and `libvirt` groups, restart the system for the configuration to take effect. diff --git a/web-ui/docs/en/blog/fred_li/2020-03-03-license-update.md b/web-ui/docs/en/blog/fred_li/2020-03-03-license-update.md new file mode 100644 index 0000000000000000000000000000000000000000..674d13de3390e86305f84bb7a0b8d88856205063 --- /dev/null +++ b/web-ui/docs/en/blog/fred_li/2020-03-03-license-update.md @@ -0,0 +1,43 @@ +--- +title: Notice to upgrade license from Mulan PSL v1 to v2 +date: 2020-03-04 +tags: + - License + - Mulan PSL v2 +archives: 2020-03 +author: Fred Li +summary: Mulan Permissive Software License v2 has got accepted by OSI, thus openEuler community is planning to upgrade the license from Mulan PSL v1 to v2. +--- + +## Notice to upgrade openEuler software license from Mulan PSL v1 to v2 + +Now openEuler community uses [Mulan PSL v1](https://license.coscl.org.cn/MulanPSL/index.html). + +_At the Board meeting of February 14, 2020, the Board of the Open Source Initiative approved the Mulan PSL License v2._ You can find the email + +As [Mulan PSL v2](https://license.coscl.org.cn/MulanPSL2/index.html) is approved by [OSI](https://opensource.org/), openEuler community would like to update Mulan PSL from v1 to v2. + +## Your opinion matters + +All openEuler community members' opinion matters, thus this notice is published. + +If you have different opinion on this, please send email to by March 19th, 2020. + +The license updating will not be valid until March 19th, 2020. + +## The difference between Mulan PSL v1 and v2 + +|Comparation| Mulan PSL v1 | Mulan PSL v2 | +|:--------|:-------|:--------| +| Definition of "Affiliates" | Affiliates means entities that control, or are controlled by, or are under common control with a party to this License | Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License | +| The clause of "Grant of Patent License" | excluding of any patent claims solely be infringed by your or others’ modification or other combinations. If you or your Affiliates directly or indirectly (including through an agent, patent licensee or assignee), institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.|The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.| +|"Language" clause|no|This license is written in both chinese and english, and the chinese version and english version shall have the same legal effect. in the case of divergence between the chinese and english versions, the chinese version shall prevail.| +|Disclaimer of Warranty|Using Lowercase letters|Using Uppercase letters| + +You can find the Mulan PSL V1 and V2 below: + +Mulan PSL v2: + +Mulan PSL v1: + + diff --git a/web-ui/docs/en/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md b/web-ui/docs/en/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md new file mode 100644 index 0000000000000000000000000000000000000000..000259defc436bdc88f577fc978fa2bbc054eea9 --- /dev/null +++ b/web-ui/docs/en/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md @@ -0,0 +1,122 @@ +--- +title: Apply for VMs from Peng Cheng Laboratory +date: 2020-03-25 +tags: + - Virtual Machine + - Test + - Peng Cheng Laboratory + - PCL +archives: 2020-03 +author: openEuler Infrastructure +summary: This article is to guide you apply for virtual machines from Peng Cheng Laboratory. +--- + + +### The procedure to apply for VMs from Peng Cheng Liboratory for openEuler development {#1} + + +#### Introduction. + +In order to facilitate the development or test of developers in the openEuler community, [Peng Cheng Liboratory](https://dw.pcl.ac.cn/) provides some virtual machines. This article introduces the application steps for openEuler community developers to apply for Arm virtual machine in Peng Cheng Laboratory. + +**Note**: The resource is for developers who contribute in the openEuler community, including code development, testing, document development, and any other ways of contribution. + +#### Application Procedures + +##### Submit application in openEuler community and get approval + +1. Log in openEuler Issue on Gitee and create the application + +The link is + +2. Create an issue + +- Type:需求 + +- Title:Starting with "[VM Application in PCL]" + +- Content template: + +``` +- PCL ID:(Apply at https://dw.pcl.ac.cn/cloud/login) + +- Purpose: + +- The links related with the purpose(one or more): + - Issue link: + - Pull Request link: + - SIG link: + - Project link: + +- Duration(days): (<=30 days) + +- How many VMs: + +``` + +3. Wait for openEuler Infrastructure team to review and approve + +The following will review and approve: +@freesky-edward +@imjoey +@TommyLike +@zerodefect + + +4. After it is approved, please write down the issue url. + + +##### Apply in Peng Cheng Laboratory (sorry for only Chinese interface) + +1. login + +2. Click `需求申请` to start the application + +3. Page 1 + +- 项目名称:openEuler Development + +- 项目信息:其他--openEuler + +- 项目简介:openEuler项目是位于openeuler.org的开源项目,旨在通过社区合作,打造创新平台,构建支持多处理器架构、统一和开放的操作系统,推动软硬件应用生态繁荣发展。 + +- 领域信息:其他--openEuler操作系统 + +- 领域概述:openEuler操作系统,是基于Linux Kernel的Linux发行版。 + +4. Page 2 + +- 产品名称:openEuler + +- 产品信息:测试/研发类产品 + +- 产品概述:openEuler项目是位于openeuler.org的开源项目,旨在通过社区合作,打造创新平台,构建支持多处理器架构、统一和开放的操作系统,推动软硬件应用生态繁荣发展。 + +- 云服务用途:your usage + +- 用途概述:Used for openEuler project development and the issue link is issue url + +5. Page 3: fill it according to your usage + +6. Page 4:fill it according to your needs + +7. End + +##### Release the VMs + +There are 2 ways to release the resource. + +1. Release at + +2. Once it expires, it will be released. Please **back up your work**. + +#### Help + +1. If you have any questions, please + +- Contact + +- Submit an issue in , with the title staring with "[VM Application in PCL]" + + + diff --git a/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png b/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png new file mode 100644 index 0000000000000000000000000000000000000000..0566afa288ea5917fba2656e76c5e01cde59ff8f Binary files /dev/null and b/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png differ diff --git a/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png b/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png new file mode 100644 index 0000000000000000000000000000000000000000..18fcfcac6df8b0763fe8f5031a94322ee7bdd679 Binary files /dev/null and b/web-ui/docs/en/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png differ diff --git a/web-ui/docs/en/blog/gaohuatao/Analysis of the Implementation Solution of the Container Exit Monitoring Mechanism in Kata Shim V2.md b/web-ui/docs/en/blog/gaohuatao/Analysis of the Implementation Solution of the Container Exit Monitoring Mechanism in Kata Shim V2.md new file mode 100644 index 0000000000000000000000000000000000000000..f3c2f19ac2fa912dbf7233f03f54f2de2c6f035a --- /dev/null +++ b/web-ui/docs/en/blog/gaohuatao/Analysis of the Implementation Solution of the Container Exit Monitoring Mechanism in Kata Shim V2.md @@ -0,0 +1,294 @@ +--- +title: Analysis of the Implementation Solution of the Container Exit Monitoring Mechanism in Kata Shim V2 +date: 2021-04-09 +tags: + - iSulad + - Container + - shim v2 +archives: 2021-04 +author: Gao Huatao +summary: As the runtime of the kata container, containerd-shim-kata-v2 reduces the number of components and shortens the call chain compared with shim v1. +--- + +Currently, shim is available in two architectures: shim v1 and shim v2. As the traditional shim solution, shim v1 acts as the intermediate layer between the container engine and runtime to forward I/Os and signals. The new shim v2 integrates the runtime, shortening the call chain for creating containers and effectively reducing memory overheads. This document uses [containerd-shim-kata-v2](https://github.com/kata-containers/runtime/tree/master/containerd-shim-v2) to analyze how iSulad and containerd monitor the exit of the pause and service containers. + +### Introduction to Shim V2 + +In the shim v1 architecture, the startup of a secure container involves the kata-shim, kata-runtime, kata-proxy, kata-agent, and QEMU used to create VMs. In the shim v2 architecture, shim, proxy, and runtime are integrated into a binary file. When the pause container and service containers in the pause container are started, only one containerd-shim-kata-v2 process and one qemu-kvm process run in the host OS, that is, the pause container and its service containers share the same containerd-shim-kata-v2 process and VM. + +The following figure shows [comparison between the shim v2 and shim v1 architectures](https://github.com/kata-containers/documentation/blob/master/design/architecture.md). In the single pause + multiple service containers scenario of shim v1, each time a pause or service container is started, a containerd-shim or isulad-shim process and a kata-shim process are started. The pause and service containers share the kata-proxy (not VSOCK) and VM processes (2N+1). However, in the same scenario of shim v2, the host OS has only one containerd-shim-kata-v2 process and one qemu-kvm process. The call chain is shorter and the overall memory overhead is lower. This is particularly noticeable with increased service containers in the pause container, as it is more advantageous to have low memory overheads. + +![](./2021-04-09-isulad-shimv2-arch-1.png) + +### Relationship Between iSulad and Shim V1 and Shim V2 + +1. Implementation of Shim V1 in iSulad + + The isulad-shim component is the implementation solution of shim v1 in iSulad. Its code is stored in the iSulad repository so it is compiled and installed together with iSulad. The component can be used to connect to different OCI runtimes, such as runc and kata-runtime. + +2. Implementation of Shim V2 in iSulad + + Currently, the interconnection between iSulad and shim v2 is still being debugged. Shim v2 is implemented in two modes: containerd-shim-kata-v2 and containerd-shim-runc-v2. This document uses containerd-shim-kata-v2 to analyze how shim v2 monitors the exit of a secure container. + +3. The following figure shows the differences between shimv1 and shim v2. + +![shimv-shimv2-diff](./2021-04-09-isulad-shimv2-shimv2-differences.png) + + +### Container Exit Monitoring in iSulad + +iSulad uses the epoll mechanism to confirm the exit_fifo file descriptor opened in each isulad-shim process is closed. When detecting that a container exits, isulad-shim writes its exit code into the FIFO file, and then reads and sets the container exit status in iSulad. Both the service container and pause container open an exit_fifo file descriptor and start an isulad-shim process, respectively. + +iSulad | <==> isulad-shim <==> container init + +iSulad | <==> isulad-shim <==> pause init + +The code for opening the exit_fifo file descriptor and enabling epoll monitoring during the container startup process in iSulad is as follows: + +```c +int do_start_container(container_t *cont, const char *console_fifos[], bool reset_rm, pid_ppid_info_t *pid_info) +{ + runtime_start(); + do_post_start_on_success() { + container_supervisor_add_exit_monitor() { + supervisor_handler_lock(); + epoll_loop_add_handler(); + } + } +} +``` + + + +### Container Exit Monitoring in containerd + +When starting a container and monitoring its exit status, containerd uses the wait method in RPC instead of the FIFO file. When starting a pause container or service container and invoking the exec command of the container, containerd starts a coroutine to obtain the exit status. After containerd is restarted, the connect method rebuilds the wait methods of all containers. + +- Process of monitoring the start sandbox and start container + +Code file: containerd/vendor/github.com/containerd/cri/pkg/server/events.go + +```go +// eventMonitor monitors containerd event and updates internal state correspondingly. +// TODO(random-liu): Handle event for each container in a separate goroutine. +type eventMonitor struct { + c *criService + ch <-chan *events.Envelope + // exitCh receives container/sandbox exit events from exit monitors. + exitCh chan *eventtypes.TaskExit + errCh <-chan error + ctx context.Context + cancel context.CancelFunc + backOff *backOff +} +//container monitors exits. +func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (retRes *runtime.StartContainerResponse, retErr error) { + // wait is a long running background request, no timeout needed. + //ght container for listening + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + + // start the monitor after updating container state, this ensures that + // event monitor receives the TaskExit event and update container state + // after this. + c.eventMonitor.startExitMonitor(context.Background(), id, task.Pid(), exitCh) +} + +// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure +// the sandbox is in ready state. +func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) { + // wait is a long running background request, no timeout needed. + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + // start the monitor after adding sandbox into the store, this ensures + // that sandbox is in the store, when event monitor receives the TaskExit event. + // + // TaskOOM from containerd may come before sandbox is added to store, + // but we don't care about sandbox TaskOOM right now, so it is fine. + c.eventMonitor.startExitMonitor(context.Background(), id, task.Pid(), exitCh) +} +``` + +containerd/process.go + +```go +// containerd/process.go monitors the exit of processes such as container exec. +func (p *process) Wait(ctx context.Context) (<-chan ExitStatus, error) { + c := make(chan ExitStatus, 1) + go func() { + defer close(c) + r, err := p.task.client.TaskService().Wait(ctx, &tasks.WaitRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + c <- ExitStatus{ + code: UnknownExitStatus, + err: err, + } + return + } + c <- ExitStatus{ + code: r.ExitStatus, + exitedAt: r.ExitedAt, + } + }() + return c, nil +} +``` + +- containerd obtains the shim PID again. Different from shim v1, the shim PID is not used as the PPID of the container. Therefore, if the container process cannot be killed, you cannot kill the shim PID to forcibly exit the container. + +```go +func (m *TaskManager) loadTasks(ctx context.Context) error {} + func loadShim() + func (s *shim) Connect(ctx context.Context) error { + response, err := s.task.Connect(ctx, &task.ConnectRequest{ + ID: s.ID(), + }) + if err != nil { + return err + } + s.taskPid = int(response.TaskPid) // Obtain the PID of shim. + return nil +} + +``` + + + +### containerd-kata-shim-v2 Code Analysis + +1. Entry of the ttrpc Server + +The **containerd-shim-v2/service.go** file defines the entry function for containerd-kata-shim-v2 to serve as the ttrpc server, allowing shim v2 to listen to the ttrpc calls from the container engine and implement operations such as container exit monitoring, I/O and signal forwarding. + +```go +// service is the shim implementation of a remote shim over GRPC +type service struct { + mu sync.Mutex + eventSendMu sync.Mutex + + // pid Since this shimv2 cannot get the container processes pid from VM, + // thus for the returned values needed pid, just return this shim's + // pid directly. + pid uint32 + + ctx context.Context + sandbox vc.VCSandbox + containers map[string]*container // Stores all pause and containers in this map. + config *oci.RuntimeConfig + events chan interface{}// publish uses the 128K buffer. + monitor chan error // Monitors the status of the sandbox, that is, the VM. + + cancel func() // ctx cancel + + ec chan exit // Stores information such as the container exit code and PID. + id string// io.containerd.kata.v2 +} +``` + +- The service provides interfaces for managing the ttrpc server and shim. + +```go +type TaskService interface { + State(ctx context.Context, req *StateRequest) (*StateResponse, error) + Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) + Start(ctx context.Context, req *StartRequest) (*StartResponse, error) + Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) + Pids(ctx context.Context, req *PidsRequest) (*PidsResponse, error) + Pause(ctx context.Context, req *PauseRequest) (*google_protobuf1.Empty, error) + Resume(ctx context.Context, req *ResumeRequest) (*google_protobuf1.Empty, error) + Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) + Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) + Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) + ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) + CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) + Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) + // Obtains the container exit status. + Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) + Stats(ctx context.Context, req *StatsRequest) (*StatsResponse, error) + // Obtains the shim pid. + Connect(ctx context.Context, req *ConnectRequest) (*ConnectResponse, error) + // Cancels all context subtasks and stops the containerd-shim-kata-v2 process. + Shutdown(ctx context.Context, req *ShutdownRequest) (*google_protobuf1.Empty, error) +} +// Shim server interface +type Shim interface { + shimapi.TaskService + Cleanup(ctx context.Context) (*shimapi.DeleteResponse, error) + StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) +} +``` + + + +### Using containerd-shim-kata-v2 to Run Containers on iSulad + +- Start the pause container. + +```bash +isula run -tid --runtime io.containerd.kata.v2 --network none --annotation io.kubernetes.docker.type=podsandbox +``` + +Obtain sandbox-id of the pod. + +- Create a service container and add it to the pod. + +```bash +isula run -tid --runtime io.containerd.kata.v2 --network none --annotation io.kubernetes.docker.type=container --annotation io.kubernetes.sandbox.id= busybox +``` + + + +### Using containerd-shim-kata-v2 to Run Containers on containerd + +Install cri-tools. In this document, the master branch of the cri-tools Github repository is used for compilation and installation. + +- containerd configuration: + +Add the following information to the containerd configuration file **/etc/containerd/config.toml** to configure the kata parameters: + +```toml +[plugins."io.containerd.grpc.v1.cri".containerd.runtimes] +// + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] + runtime_type = "io.containerd.kata.v2" + pod_annotations = ["com.github.containers.virtcontainers.sandbox_cpu", "com.github.containers.virtcontainers.sandbox_mem", "com.github.containers.virtcontainers.static_devices", "com.github.containers.virtcontainers.sandbox_drivers", "com.github.containers.virtcontainers.boot_cgroup"] + container_annotations = ["com.github.containers.virtcontainers.storage_spec"] +// + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + base_runtime_spec = "" + +``` + +- Install the CNI plug-in. + +Install the plugin by using the following script: + +``` +https://github.com/containerd/containerd/blob/master/script/setup/install-cni +``` + +- Specify the runtime to run the pod. + +```bash +$ crictl -i unix:///var/run/containerd/containerd.sock -r unix:///var/run/containerd/containerd.sock runp --runtime kata sandbox-config.json +$ cat sandbox-config.json +{ + "metadata": { + "name": "nginx-sandbox", + "namespace": "default", + "attempt": 1, + "uid": "hdishd83djaidwnduwk28bcsb" + }, + "image": { + "image": "docker.io/library/busybox:latest" + }, + "linux": { + } +} + +``` + +---- + +Author: Gao Huatao diff --git a/web-ui/docs/en/blog/georgecao/openEuler_SIG_Member_Management.md b/web-ui/docs/en/blog/georgecao/openEuler_SIG_Member_Management.md new file mode 100644 index 0000000000000000000000000000000000000000..783a585dbbe1f56b72000775854254d414d2e970 --- /dev/null +++ b/web-ui/docs/en/blog/georgecao/openEuler_SIG_Member_Management.md @@ -0,0 +1,155 @@ +--- +title: SIG Member Management Solution for the openEuler Community +date: 2022-04-26 +tags: + - openEuler + - SIG Member Management +archives: 2022-04 +author: georgecao +summary: Details about the SIG member management solution for the openEuler community. +--- + +# SIG Member Management Solution for the openEuler Community +## Roles of Community SIG Members +Following discussion with multiple SIGs and the Technical Committee, the roles of openEuler community SIG members are divided as follows: +| Role| Responsibility | +|--|--| +| Maintainer | SIG planner who is responsible for driving the vision of the SIG, regularly organizing SIG meetings, and presenting the SIG status to the community on behalf of the SIG.| +| Committer| Principal owner of a SIG repository. Committers are also reserve forces for maintainers in the SIG.| +|Contributor|Contributor to a SIG repository, who is responsible for fixing repository issues and developing code and is a backup for committers.| +|Developer|Contributor to the community. Those who have made long-term contributions to the community can recommend themselves or be recommended as repository contributors or even committers.| +|RepoAdmin|Some self-developed code repositories of the community require the git push permission, and therefore the Admin permission is set for these repositories. In most cases, the SIG maintainer assumes this role and is responsible for the full code incorporation of these repositories.| + +## Division of Rights and Responsibilities of SIG Members +Different roles have different rights and responsibilities in the community (especially on the Gitee platform). +|SIG Member Role|Record sig_info.yaml| Submit Code|Comment "/approve" to Merge PRs|Merge git push| +|--|--|--|--|--| +| Maintainer | ✔️ | ✔️ [All repositories] | ✔️ |❌| +| Committer| ✔️ |✔️ | ✔️ [Some repositories]| ❌ | +| Contributor| ✔️ |✔️ |❌ |❌ | +| Developer| ❌ | ✔️ | ❌ | ❌| +| RepoAdmin | ✔️ | ✔️ | ✔️ [Some repositories]| ✔️ [Some repositories] | + +## Member Management Solution + + 1. A **sig_info.yaml** file is added to each SIG for managing community members. + + 2. The **sig_info.yaml** file takes effect only after the OWNER file in the current SIG directory is deleted. If the OWNER file exists, the original member relationship and permission control functions are retained. + 3. (Mandatory) The **sig_info.yaml** file must be assigned with a global maintainer who has the merge permission on all repositories in the SIG (inheriting the original maintainer logic). + 4. (Optional) Specific committers can be added to some repositories. These committers only have merge permission on these repositories. + 5. (Optional) Contributors without merge permission can be added to some repositories. + 6. (Optional) Admins with administrator permission can be added to some repositories. These users can use the git push function to merge code. + 7. The access control group creates **sig_info.yam**l for each SIG based on the OWNER file and repository information. + + +## How to Compile the sig_info.yaml File +### Manually Compiling the sig_info.yaml File + +The **sig_info.yaml** file contains the following basic elements: +| **Field**| Type| Description| +|--|--|--| +| name | String| (Mandatory) SIG name| +| description | String| (Mandatory) SIG description| +| created_on| String| (Mandatory) SIG creation time| +| mailing_list | String| (Optional) Email list address for the SIG discussion| +| meeting_url | String| (Optional) URL of SIG regular meeting minutes| +| mentors | List| (Optional) List of current SIG mentors | +| maintainers | List| List of all maintainers in the SIG| +| repositories| List| Information about the Gitee repositories managed by the SIG| + +Each record in the **mentors** list and **maintainers** list represents the personal information of a mentor and a maintainer, respectively. Each record contains the following elements: +| **Field**| Type| Description| +|--|--|--| +| gitee_id | String| (Mandatory) Gitee ID| +| name | String| (Mandatory) Name (or nickname)| +| organization| String| (Optional) Organization| +| email| String| (Optional) Personal email address| + +The **repositories** field is a list. Each element in the list represents the information about a group of repositories managed by the SIG, including the following four fields: +| **Field**| Type| Description| +|--|--|--| +| repo | List| (Mandatory) Array consisting of names of repositories managed by the SIG | +| committers| List| (Optional) Common committers of the repositories | +| contributors| List| (Optional) Common contributors of the repositories | +| repo_admin| List| (Optional) Common repo admins of the repositories | + +**repo** is an array of repository names, and **committers**/**contributors**/**repo_admin** are member arrays. Each element indicates a piece of personal information, which is the same as the maintainer information. + +| **Field**| Type| Description| +|--|--|--| +| gitee_id | String| (Mandatory) Gitee ID| +| name | String| (Mandatory) Name (or nickname)| +| organization| String| (Optional) Organization| +| email| String| (Optional) Personal email address| + +Committers have the permission to review the code of all repositories in the corresponding repo group, while contributors are the main contributors of all repositories in the repo group. + +#### sig_info.yaml example: +``` +name: Infrastructure +description: This is a sample sig. Please copy it over and modify it accordingly. +created_on: '1970-01-01' +mailing_list: infra@openeuler.org +meeting_url: NA +mature_level: startup +mentors: +- gitee_id: batMan + name: Wayne + email: aaaaaaa@openeuler.org +maintainers: +- gitee_id: Joe + name: JoeDou + organization: RealT + email: yyyyyyy@qq.com +- gitee_id: Jane + name: JaneDou + email: xxxxxxx@gmail.com +repositories: +- repo: + - openeuler/infrastructure + - openeuler/website + - openeuler/website-v2 + committers: + - gitee_id: Bob + name: BobMa + email: zzzzzzz@yahoo.com + contributors: + - gitee_id: infra_superman + name: Clark_Ken + orgnization: Justice_L + email: zzzzzzz@openeuler.org +- repo: + - openeuler/cve-manager + - openeuler/tool-collections + - openeuler/go-gitee + - openeuler/gitbook-theme-hugo + - cve-manager + committers: + - gitee_id: tommyliu + name: Tommy + email: zzzzzzzhh@163.com + repo_admin: + - gitee_id: lisa993 + name: LisaLi + email: lililisa@qq.com +``` +### Filling Out the **sig_info.yaml** Template +The infrastructure provides an automation script to quickly generate the configuration management file **sig_info.yaml** of the related SIG. +The gitee_id of the maintainer comes from the OWNER file, and the repository information in repositories comes from all repository configurations in the **sig** directory. Other information exists on a formatted template and needs to be completed manually. + +#### Using Commands to Submit the sig_info.yaml Template + - Obtain the community repository code. + +**git clone https://gitee.com/openeuler/community.git** + + - Go to the SIG management directory. + +**cd community/sig/** + + - Create a **sig_info.yaml** file template in the corresponding SIG folder. + +**python3 create_sig_info_template.py** *xxx* (*xxx* indicates the SIG name, such as Infrastructure or A-Tune) + + - Go to the corresponding SIG folder and modify the **sig_info.yaml** template. + + - Submit the modified **sig_info.yaml** file. diff --git a/web-ui/docs/en/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md b/web-ui/docs/en/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md new file mode 100644 index 0000000000000000000000000000000000000000..7314ab2d7a6836eb570b3ba84785cb6f8f44f8a7 --- /dev/null +++ b/web-ui/docs/en/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md @@ -0,0 +1,332 @@ +--- +title: Guide for Uploading a Software Package to the openEuler Community +date: 2021-12-20 +tags: + - openEuler + - software + - guidebook +archives: 2021-12 +author: gitee-cmd +summary: Guidebook for openEuler community software upload +--- + + +# Guide for Uploading a Software Package to the openEuler Community + +This guide describes how to upload a software package to the openEuler community for contributors, so as to improve efficiency and ensure the package to be uploaded to meet certain requirements. + +## 1. Checklist + +Before submitting a pull request (PR), check whether the software package and related dependencies meet the admission rules of the openEuler community. The following table displays the checklist items. + + + +| Item | Description | +| ---------------------------- | ------------------------------------------------------------ | +| Normalization | ● In most cases, a piece of software is uploaded to src-openeuler only once. | +| Source | ● Open-source software must be downloaded from its official website or the code hosting address specified by the official website. | +| Software Name | ● The software name must be the same as that on the official website or in the community.
● It is not allowed to use a sub-module in the software package as the software name.
● If the software is the development library of a language, prefixes such as python- and perl-can be added for name standardization management. | +| Community Status | You are not advised to upload the following software:
● software released by a well-known community or organization but no longer maintained;
● software released by individuals or a small-sized community/organization and has no new version uploads within two years;
● software whose community operating status is unclear;
● software whose issues have not been addressed in the most recent six months. | +| Official Website (Mandatory) | ● Use the official website provided by the software vendor. If there is no official website, use the project website on mainstream code hosting platforms, such as GitHub.
● Do not use websites of the following hosting platforms as the software official websites: Maven, MvnRepository, or SpringSource. | +| Software Package Information | ● Use the official download address of the source package for source tracing.
● If a binary package is required, the official download address of the binary package must be provided. | +| License | ● Check whether the software to be uploaded has a license.
● Check whether the entered license is the same as that on the official website and in the software package.
● Exercise caution when uploading open source software with a high-risk license. | +| Copyright | ● Provide the copyright information contained in the official website, community, code hosting platform, source package, and release package. | + + + +**Note:** + +1. Normalization: Before uploading multiple versions of a software package, such as MySQL and MySQL5, contact the technical committee and SIG.。 +2. For details about the license check and copyright trustlist and blocklist, see the [SPDX License List](https://spdx.org/licenses/). + + + +## 2. Analysis of Software Package Dependencies + +You are advised to analyze the software package dependencies before submitting a PR to upload the software. The following provides several methods for dependency analysis. + +### 2.1. Using pkgship + +pkgship is a package management tool developed by the openEuler team for software management in the openEuler community. It can be used to analyze dependencies of various openEuler versions and Fedora software packages, and query binary and source packages. You can download pkgship from [pkgship](https://pkgmanage.openeuler.org/). + +#### 2.1.1. Online analysis + +pkgship supports four types of dependency analysis: **Install Depend**, **Build Depend**, **Self Depend**, and **Bedepend**. Before uploading the software package, use pkgship to perform dependency online analysis to view excels of the installation dependency and compilation dependency. + +![guide](./images/pkgship.png) + + + +**Selecting an analysis type:** + +On the **Package Management** page, click **Depend Info**, select a proper dependency analysis type, enter the package name, and click **click here** to select a repository. + +![guide](./images/pkg_repo_select.png) + +**Selecting a branch and an upstream community:** + +On the page that is displayed, select the desired branch and upstream community and click **OK**. + +![guide](./images/branch_select.png) + + + +**Querying results:** + +Click the magnifier icon, and pkgship automatically performs dependency analysis based on the user-defined settings. + +![guide](./images/fed_pkg.png) + + + +**Analyzing dependency query results:** + +View the **Source Package List**. The source packages whose **Database** is displayed as **fedora33** are the packages to be uploaded. + +![guide](./images/need_introduce.png) + + + +#### 2.1.2. Local Dependency Analysis + +pkgship also supports local deployment and dependency analysis of user-defined sources. For details, visit https://gitee.com/src-openeuler/pkgship. + +**Note:** +If you find any problems when using pkgship, provide your feedback in the [pkgship repository](https://gitee.com/openeuler/pkgship/issues). + + +### 2.2. Analyzing Dependencies in the Upstream Community + +For the software packages whose dependencies cannot be analyzed based on pkgship, you need to manually analyze their dependencies. + +#### 2.2.1. Compilation Dependency + +**Using the SPEC file provided by the upstream community**: + +Query the compilation dependency of the package to be uploaded based on the dependency package name in the **BuildRequires** field in the SPEC file. + +**Using the language management tool and dependency management file**: + +If the upstream community does not provide the SPEC file, perform the analysis using the language management tool or specific dependency file. The following table lists the package manager and dependency management file types of some languages. + +| Language | Package Manager | File Type | +| -------- | --------------- | ------------------------- | +| C++ | CMake | Makefile | +| java | maven pom | pom.xml | +| go | go modules | go.mod | +| rust | cargo | Cargo.toml | +| ruby | RubyGems | *.gemspec | +| python | pip | requirements.txt/setup.py | +| Node.js | npm/yarn | | + +**Tools to generate the SPEC file:** + +- For Python packages: [PyPorter](https://gitee.com/openeuler/pyporter) + +- For Ruby packages: [RubyPorter](https://gitee.com/openeuler/rubyporter) + +- For Node.js packages: [nodejsporter](https://gitee.com/openeuler/nodejsporter) + +- For perlporter packages: [perlporter](https://gitee.com/openeuler/pyporter) + + **Note:** After the tool is generated, check the following information: + + - Check whether the description of the software is properly provided. (The description cannot be left blank, or contain only the package name.) + - Check whether each part in SPEC is properly separated by empty lines to ensure the standardization and aesthetics. For example, empty lines should be added to the front of **%prep** and **%description**. + + + +#### 2.2.2. Installing and Running Dependencies + +**Using the SPEC file provided by the upstream community**: + +Search for the installation dependency of the package to be uploaded based on the dependency package name in the **Requires** field in the SPEC file. + +**Using the rpmbuild tool for analysis:** + +```bash +rpm -a requires [package_name] # Check the installation dependency +``` + + + +## 3. Software Package Self-Verification + +Perform dependency analysis and self-verification on the software package before submitting a PR. + +### 3.1. SPEC Modification + +#### 3.1.1. Format Rectification and Static Check + +- Modify the keyword sequence. +- Modify **changelog**. **changelog** in the SPEC file of the new software package only contains package **init**. +- Exclude sensitive words and retain non-sensitive patch comments. Generally, openEuler does not accept contents of the Fedora and RHEL upstream communities. +- Modify the **release** field. Set the **release** field of the new software package to **1**, and increase the value by 1 each time the SPEC file is modified. +- Compare the license list to ensure that no software packages with risky licenses are uploaded. + +#### 3.1.2. Code Source Tracking + +- Ensure that the official website URL in the SPEC file is valid and can be accessed by the browser. + +- Ensure that download address of the source package (**source0**) in the SPEC file is valid, and the source link package is consistent with the source package of the software. + + - If the downloaded source package is different from the built-in source package, use the downloaded source package for verification. + + - ```bash + md5sum package name 1 package name2   # Check whether the two character strings are the same. + ``` + ![guide](./images/md5.png) + + - If the download link of **source0** is unavailable, search for the download link that can be used by the version maintained by an upstream community (similar to GitHub) for re-verification. (You can find clues from the comments of the original SPEC file.). + +### 3.2 rpmbuild + +Use rpmbuild to verify local compilation. + +```bash +rpmbuild -ba [spec file] # Use the -ba parameter to build a binary package and a source package based on the SPEC file. +``` + + + +### 3.3. [OBS](https://117.78.1.88/) Compilation Verification + +Although rpmbuild can be used for local compilation verification, the OBS compilation result may be different from the local compilation result because the OBS environment is different from the local environment. Therefore, before submitting a PR, find the corresponding branch from OBS and perform compilation verification. + +#### 3.3.1. OSC Environment Configuration + +Create the **.oscrc** file in the **/root/** directory to configure the OSC client. The OSC configuration methods are as follows: + +- Specify the IP address in the configuration file. + + ![guide](./images/osc_config1.png) + +- Use the domain name in the configuration file and add the mapping between the IP address and the domain name in **/etc/hosts**. + + ![guide](./images/osc_config2.png) + + ![guide](./images/etc_host.png) + +#### 3.3.2. OBS Development and Verification + +- **Branch pulling** + + 1. Find a software package in the branch. + + ![guide](./images/obs_branch.png) + + 2. Create a new software package in the branch. + + ![guide](./images/obs_create_pkg.png) + +3. Create a local branch. + +- **OSC Compilation** + + 1. Run the following command to download the online repository to the local host. + + ```bash + osc co home:xxxxx:branches:openEuler:Mainline software_package_name + ``` + + 2. Go to your own branch: **home:xxxxx:branches:openEuler:Mainline/*software package name*** + + 3. Move the SPEC file and TAR package corresponding to the software to your own branch. (Patches and configuration files may also need to be uploaded.) + + 4. Due to limited OBS resources, you are advised to run the **osc build** command to perform local compilation verification before uploading the package to OBS for online compilation. This prevents repeated uploads and compilation. + + ```bash + osc build + ``` + + 5. Run the **osc** command to upload the local file to your online OBS branch. + + ```bash + osc add * + osc ci + ``` + + 6. View the compilation results online in your OBS branch. + + ![guide](./images/osb.png) + + + +### 3.4. Verification for Software Package Installation and Uninstallation + +- + Ensure that the package of another version does not exist in the environment. + + ```bash + rpm -e `rpm -qa | grep $fileName` + ``` + +- Install the software package. + + ```bash + rpm –ivh xxx-2.0.1-2.aarch64.rpm + ``` + ​ The **rpm** command cannot automatically search for dependencies. Therefore, install the dependency packages in advance for verification. + +- Check whether the software package can be uninstalled. + + ```bash + rpm –e xxx-2.0.1-2.aarch64.rpm + ``` + + + +### 3.5. Verification for Basic Functions of the Software Package + +**Software package with command lines:** + +```bash +rpm –qpl xxx.rpm # Query the command and run the command to check whether the verification function can be used properly. (The new command is placed in the /usr/bin/ directory.) +``` + +**Service software package:** + +```bash +systemctl start [service.name] +``` + + + + + +## 4. YAML File Compilation + +openEuler-Advisor aims to provide automatic inspection and suggestions on routine work of openEuler artifact repositories. To support automatic running of openEuler-Advisor, configure the YAML file in the repository by referring to **[YAML File Specifications](https://gitee.com/openeuler/openEuler-Advisor/blob/master/README.en.md)**. + +1. Create a YAML file. The YAML file name must be the same as the SPEC file name. + +2. Edit the YAML file and add the following field content. + + - **version_control**: version control protocol of the upstream repository. Currently, the value can be **svn**, **git**, **hg**, **github**, **gnome**, **metacpan**, and **pypi**. For other version control protocols, enter **NA**. + + - **src_repo:** actual address of the upstream repository. You can use **version_control** and **src_repo** to download the corresponding code. + + - **tag_prefix:** version prefix in the tag of the upstream repository. If the git protocol is used, you can run the **git tag** command to display all tags. If the tag provided by the upstream is v1*0*1, **tag_prefix** must be set to **^v**. The correct version information can be obtained by matching **tag_prefix**. If the tag format is modified, use the latest tag format. + + For some special cases, use wildcard (*) as follows: + + ![guide](./images/special_yaml.png) + + Example: + + ```bash + "selenium-(.*?)-alpha-(.*?)" + ``` + + - **separator:** version separator in the tag. If the tag is v1*0*1 and **separator** is set to **_**, the correct version number 1.0.1 can be obtained by parsing the code. + + ![guide](./images/yaml_content.png) + + + +## References + +[openEuler-Advisor](https://gitee.com/openeuler/openEuler-Advisor/blob/master/README.en.md) + +[Gitee DisNight Repository](https://gitee.com/disnight) + diff --git a/web-ui/docs/en/blog/gitee-cmd/images/branch_select.png b/web-ui/docs/en/blog/gitee-cmd/images/branch_select.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3f88dd6c75f04bcf9f9845c5d2176467368752 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/branch_select.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/etc_host.png b/web-ui/docs/en/blog/gitee-cmd/images/etc_host.png new file mode 100644 index 0000000000000000000000000000000000000000..19c51a5628c73cfbf8869ced8750f012edd1a041 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/etc_host.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/fed_pkg.png b/web-ui/docs/en/blog/gitee-cmd/images/fed_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..e55fd3d183d962cf4620a525e0465653a0748632 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/fed_pkg.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/md5.png b/web-ui/docs/en/blog/gitee-cmd/images/md5.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0e221071f14668e2f63c15c20cd762fc0c1a46 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/md5.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/moban.png b/web-ui/docs/en/blog/gitee-cmd/images/moban.png new file mode 100644 index 0000000000000000000000000000000000000000..03aeb294357923f19c0722a0805b4617cbb0de7a Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/moban.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/need_introduce.png b/web-ui/docs/en/blog/gitee-cmd/images/need_introduce.png new file mode 100644 index 0000000000000000000000000000000000000000..10c7d21d7cfd5651177c2a9e9e82113c58d51816 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/need_introduce.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/obs_branch.png b/web-ui/docs/en/blog/gitee-cmd/images/obs_branch.png new file mode 100644 index 0000000000000000000000000000000000000000..dd51ea6e7c223d8407187a7b80abdcab8cbb365e Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/obs_branch.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/obs_branch_accept.png b/web-ui/docs/en/blog/gitee-cmd/images/obs_branch_accept.png new file mode 100644 index 0000000000000000000000000000000000000000..6b90b6152711453613fc5e765aba9af082297c75 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/obs_branch_accept.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/obs_create_pkg.png b/web-ui/docs/en/blog/gitee-cmd/images/obs_create_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..c90f2748f3f1d92930cc08c8fecc534ec8f1b714 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/obs_create_pkg.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/osb.png b/web-ui/docs/en/blog/gitee-cmd/images/osb.png new file mode 100644 index 0000000000000000000000000000000000000000..16d1e3bb9997a0913b3d658037f3fa4260d03be7 Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/osb.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/osc_config1.png b/web-ui/docs/en/blog/gitee-cmd/images/osc_config1.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2e7a1298594c1d3efb74f838fa10145187114c Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/osc_config1.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/osc_config2.png b/web-ui/docs/en/blog/gitee-cmd/images/osc_config2.png new file mode 100644 index 0000000000000000000000000000000000000000..dc809fcb24c44b25b463dd5cbca322b0c40132ef Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/osc_config2.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/pkg_repo_select.png b/web-ui/docs/en/blog/gitee-cmd/images/pkg_repo_select.png new file mode 100644 index 0000000000000000000000000000000000000000..b852280ea8fc77807366a10449a6bc37d60731eb Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/pkg_repo_select.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/pkgship.png b/web-ui/docs/en/blog/gitee-cmd/images/pkgship.png new file mode 100644 index 0000000000000000000000000000000000000000..c2174d66958f75b6f5012ea37aa32cca2443926c Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/pkgship.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/sample.png b/web-ui/docs/en/blog/gitee-cmd/images/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..28e1a7ab2ab82a4ee20328a2fdd0ca26301e2b9b Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/sample.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/special_yaml.png b/web-ui/docs/en/blog/gitee-cmd/images/special_yaml.png new file mode 100644 index 0000000000000000000000000000000000000000..fccacdc0c24ca3c441ae3ff0595208f62038476c Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/special_yaml.png differ diff --git a/web-ui/docs/en/blog/gitee-cmd/images/yaml_content.png b/web-ui/docs/en/blog/gitee-cmd/images/yaml_content.png new file mode 100644 index 0000000000000000000000000000000000000000..8d756634862798f0786500d4c48d0d335c57316c Binary files /dev/null and b/web-ui/docs/en/blog/gitee-cmd/images/yaml_content.png differ diff --git a/web-ui/docs/en/blog/judithsq/.keep b/web-ui/docs/en/blog/judithsq/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/web-ui/docs/en/blog/judithsq/2022-02-15-get-started-with-openEuler-community.md b/web-ui/docs/en/blog/judithsq/2022-02-15-get-started-with-openEuler-community.md new file mode 100644 index 0000000000000000000000000000000000000000..20694dbdba12841265d3e7c4afd7b3d74b0a1bcb --- /dev/null +++ b/web-ui/docs/en/blog/judithsq/2022-02-15-get-started-with-openEuler-community.md @@ -0,0 +1,48 @@ +--- +title: Get Started with openEuler Community +date: 2022-02-15 +tags: + - get started + - openEuler + - community +sig: G11N +archives: 2022-02 +author: Gomico & Judith +summary: This blog provides information you need to get started with the openEuler community quickly. +--- + + + + + +# openEuler community +openEuler is an open source, free Linux distribution. It offers huge improvements in performance and useful tools, such as A-Tune, an AI-based system tuning software, and iSulad, a lightweight container runtime daemon for IoT and cloud infrastructure. + +Our community is the core behind the development of openEuler. Until now, 95 SIGs, comprising 8,000 contributors, have helped develop the OS for 400 thousand users. We want to leverage SIGs to drive our innovations. In addition, 11 OS vendors have released commercial editions based on openEuler. +# opeEuler website +Now, whether you are interested in openEuler, want to contribute to the OS, or you are already an openEuler user who wants to simply learn more about the system, you should check out the community website. The community website provides useful information and assets for beginner or expert developers. + +If you are new to openEuler and want to try it out, simply click Download and choose an ISO. openEuler releases include innovative and Long-term Support (LTS) versions for different application scenarios. Documentation includes installation and other detailed guides covering system usage, management, and software development. For example, the Desktop Environment User Guide can help Linux beginners install a desktop environment and use the system; whereas developers can set up their development environments in openEuler based on the Application Development Guide. + +In addition to technical documentation, you can also find useful insights in the blog posts written by our community members. Other information about our news, live streams, meetups, and summits can be found on the Connect pages. + +For openEuler users who intend to use the OS for development or production, the Discovery pages are home to practical components and tools that help you build a secure and high-performance environment or product. What's more, all of these original projects are open source. In addition to the aforementioned A-Tune and iSulad, openEuler provides Java developers with BiSheng JDK, a stable, reliable, and easy-to-debug JDK. Likewise, secure application developers may want to check out secGear, a confidential computing development suite that delivers a unified development framework for various hardware devices, while tools like Pkgship and Compliance will help you solve compatibility and compliance issues. + +A major concern in the openEuler community is the system security and stability. To see how we handle the security vulnerabilities related to the community version of openEuler, visit the Support pages. Here you can find the security advisories and Common Vulnerabilities and Exposures (or CVEs), and obtain information about the compatibility of openEuler in different hardware and software environments. +# Join us +On your first time to the community, the Community pages will guide you through the participation and contribution process. You can participate in the openEuler community in different ways. Our public meetings, meetups, live streams, and summits are open to everyone, regardless if you are an expert developer or a common user. If you are a developer seeking to engage in community contributions, you may want to find your perfect SIG, which is organized into one or more specific technical topics. The SIG list allows you to find the SIGs you want to join. After joining a SIG, you can contribute in a number of ways: by submitting and addressing issues, contributing and reviewing code, participating in original open source projects - you name it. + +If no SIG suits your interest, you can always start a new SIG by visiting the Application page and Roles page. They will help you understand the SIG application process and SIG roles. + +Maybe you don't want to write code – that's OK! Our community welcomes all users to help us build the community through non-code contributions, such as function testing, project management, document writing, and translation. Any contribution, big or small, is valued. +# Grow with the community +The last step in your contribution journey is a never-ending one - growing together with the community. You will grow as you become more experienced, and gain influence through contributions. Our openEuler certification recognizes those who want to prove their development, technical support, and O&M capabilities. + +Working in openEuler's open source community is about trust and sharing. It's a joyful journey, full of accomplishment. Countless innovative possibilities are available every step of the way. We simply insist on our original work to establish the openEuler community as one of the most energetic communities in the world. + +So if you believe in collaboration and sharing, then we hope to see you soon in the openEuler community. + + diff --git a/web-ui/docs/en/blog/lingff/Using A-Tune on openEuler.md b/web-ui/docs/en/blog/lingff/Using A-Tune on openEuler.md new file mode 100644 index 0000000000000000000000000000000000000000..38cf6724af7d6cbacf9652c4f53769ee926e5493 --- /dev/null +++ b/web-ui/docs/en/blog/lingff/Using A-Tune on openEuler.md @@ -0,0 +1,179 @@ +--- +title: Using A-Tune on openEuler +date: 2021-04-18 +tags: + - A-Tune + - Tuning + - Intelligence +archives: 2021-04 +author: lingff PKU +summary: This document describes how to install and use A-Tune on openEuler and the offline dynamic tuning process of A-Tune. +--- +# What Is A-Tune +A-Tune is an AI-based OS performance tuning engine. It leverages AI technologies to enable the OS to understand services, simplify IT system tuning, and deliver excellent performance for applications. +This project helps developers get familiar with the A-Tune offline dynamic tuning process to tune an application. + +# Installing A-Tune +openEuler 20.03 LTS SP1 is used to install A-Tune from source code as follows: +1. Install the dependent system software packages. + +```bash +yum install -y golang-bin python3 perf sysstat hwloc-gui +``` +2. Install the Python dependencies. + +```bash +# Dependencies of the A-Tune service +yum install -y python3-dict2xml python3-flask-restful python3-pandas python3-scikit-optimize python3-xgboost python3-pyyaml +# Database dependencies +yum install -y python3-sqlalchemy python3-cryptography +yum install -y python3-psycopg2 +``` +3. Download and compile the A-Tune source code, and then install A-Tune. + +```bash +git clone https://gitee.com/openeuler/A-Tune.git +cd A-Tune +make models +make +make collector-install +make install +``` +# Using A-Tune +## Configuring the A-Tune Service +Change the values of **network** and **disk** in the **/etc/atuned/atuned.cnf** file to the specified network adapter and disk. +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417193945263.png) +## Managing the A-Tune Service +Load and start the atuned and atune-engine services. + +```bash +systemctl daemon-reload +systemctl start atuned +systemctl start atune-engine +``` +> NOTE: It takes some time to run the three commands, and no output is displayed. If the system is restarted, restart the services. + +Check the status of the atuned and atune-engine services. + +```bash +systemctl status atuned +systemctl status atune-engine +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417194614472.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +![](https://img-blog.csdnimg.cn/20210417194522940.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +## Using the atune-adm CLI +1. The **list** command is used to list the profiles supported by the system and the profiles in the active status. +For example: +```bash +atune-adm list +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417194836656.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) + +2. The **profile** command is used to activate a profile. +For example: + +```bash +atune-adm profile web-nginx-http-long-connection +``` +The preceding command activates the profile configuration of web-nginx-http-long-connection. + +3. The **analysis** command is used for online static tuning. It collects system information in real time, identifies load types, and automatically optimizes them. +Interface syntax: + +```bash +atune-adm analysis [OPTIONS] +``` + +4. The **tuning** command is used for offline dynamic tuning. It uses the specified project file to search the dynamic space for the selected parameters to find the optimal solution under the current environment configuration. +Interface syntax: + +```bash +atune-adm tuning [OPTIONS] +``` +Offline dynamic tuning is the focus of this project. + +# A-Tune Offline Tuning Case +The following describes how to optimize the GCC compiler. This case can be found in the **A-Tune/examples/tuning** directory. + +```bash +cd /examples/tuning/gcc_compile +``` +1. Set up the environment. + +```bash +sh prepare.sh +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418133402328.png) + +2. Download stream.c, a memory bandwidth test program. + +```bash +wget http://www.cs.virginia.edu/stream/FTP/Code/stream.c +``` +3. Tune the GCC compiler. + +```bash +atune-adm tuning --project gcc_compile --detail gcc_compile_client.yaml +``` +Tuning result: +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418133945119.png) + +The memory bandwidth is increased by 121%, and the size of the executable file after compilation is reduced by 17%. + +4. Save the result. + +```bash +atune-adm tuning --restore --project gcc_compile +``` +There is no output. +# Performing A-Tune Offline Tuning +Offline dynamic tuning involves three input files: **client.yaml**, **server.yaml**, and **benchmark**. + - **client.yaml**: file stored on the client, including tuning evaluation indicators. + - **server.yaml**: file stored on the server, including adjustable parameters for tuning. + - **benchmark**: file stored on the client. You can run this file to obtain the benchmark values of the evaluation indicators. + +The following uses GCC offline dynamic tuning as an example to describe the three files. +## client.yaml + +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418211719224.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) + +The parameters in the preceding picture are as follows: +- Tuning algorithm (line 2) +- Number of iterations (line 3) +- Number of random iterations (line 4) +- Benchmark execution command (line 6) +- Information about evaluation indicator 1 (lines 8 to 13) +- Information about evaluation indicator 2 (lines 14 - end) + +In addition, you can add **parameter selection** to the **client.yaml** file. + +Parameter selection is performed before offline dynamic tuning to reduce the parameter space. It selects the parameters that have the greatest impact on performance from the provided parameter space for tuning. + +To implement parameter selection, add the following parameters to the **client.yaml** file: + +- **feature_filter_engine**: parameter selection algorithm +- **feature_filter_cycle**: number of parameter selection cycles +- **feature_filter_iters**: number of parameter selection iterations +- **feature_filter_count**: parameter(s) selected in each cycle +- **split_count**: number of parameters evenly selected from the value range of tuning parameters + + +## server.yaml +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418212213431.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +- Application startup command (line 3) +- Command for stopping the application (line 4) +- Adjustable parameters (lines 5 - end) +## Benchmark File +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418212600100.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) + +The benchmark file is used to execute the commands provided in the **client.yaml** file during performance tuning. + +## Tuning and Result Saving +Perform tuning: +```bash +atune-adm tuning --project --detail +``` +Save the result: +```bash +atune-adm tuning --restore --project +``` diff --git a/web-ui/docs/en/blog/liujingang09/2020-6-24-announce-cna.md b/web-ui/docs/en/blog/liujingang09/2020-6-24-announce-cna.md new file mode 100644 index 0000000000000000000000000000000000000000..e6cebf89261590ec7ae97c10a6016e6d08307a12 --- /dev/null +++ b/web-ui/docs/en/blog/liujingang09/2020-6-24-announce-cna.md @@ -0,0 +1,41 @@ +--- +title: openEuler Becomes a Member of the CNA Program +date: 2020-06-24 +tags: + - CVE + - CNA + - Security +archives: 2020-06-24 +author: liujingang09, openEuler Security Committee +summary: openEuler Becomes a Member of the CNA Program +--- + +### openEuler Becomes a Member of the CNA Program + +The openEuler community attaches great importance to the community version security. To quickly respond to and handle security issues related to the openEuler, the community has developed a complete vulnerability management policy. On June 24, 2020, openEuler joins the CVE Numbering Authority (CNA) Program. Currently, openEuler is entitled to assign and manage CVEs related to the openEuler community. By joining the CNA Program, openEuler applies mature vulnerability management standards in the industry to promote the community cyber security. + +The security committee of openEuler community is responsible for building community security engineering and improving vulnerability response capabilities. We hope that security experts and enthusiasts who are interested in openEuler can join our hands to enhance the openEuler community security. + +#### Vulnerability management policy: + https://www.openeuler.org/en/security.html +#### What is CVE? ++ CVE is an international, community-based effort that maintains a community-driven, open data registry of vulnerabilities. ++ The CVE IDs assigned through the registry enable program stakeholders to rapidly discover and correlate vulnerability information used to protect systems against attacks. ++ The CVE List is built by CVE Numbering Authorities (CNAs). Every CVE Entry added to the list is assigned by a CNA. ++ The CVE List feeds the U.S. National Vulnerability Database (NVD). + +#### CVE Value: ++ CVE enables two or more people or tools to refer to a vulnerability and know they are talking about the same thing, resulting in significant time and cost savings. + +#### CVE is Community Driven: ++ The CVE Program relies on the community (vendors, end users, researchers, and more) to discover and register vulnerabilities. ++ CVE IDs are assigned by CVE Numbering Authorities (CNAs), which are operated on a voluntary basis by participating organizations. ++ The CVE Board, which drives the direction of the CVE Program, consists of industry, academic, and government representatives from around the world. ++ CVE Working Groups develop the program’s policies (approved by the CVE Board) and are open to the community. + +#### Sponsored by: ++ [The CVE Program](https://cve.mitre.org/) is sponsored by the Cybersecurity and Infrastructure Security Agency (CISA, [https://www.cisa.gov/](https://www.cisa.gov/)of the U.S. Department of Homeland Security (DHS) and is operated by [the MITRE Corporation](https://www.mitre.org/) in close collaboration with international industry, academic, and government stakeholders + +#### What are CNAs (CVE Numbering Authorities) ++ CNAs are organizations authorized by the CVE Program to assign CVE IDs to vulnerabilities affecting products within their distinct, agreed-upon scope. + diff --git a/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png new file mode 100644 index 0000000000000000000000000000000000000000..faf84c12a81260aeb0be4520b6f582a5c25d45bb Binary files /dev/null and b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png differ diff --git a/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b820312a2603b934c5464ae8106ee29ccb80c2 Binary files /dev/null and b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png differ diff --git a/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png new file mode 100644 index 0000000000000000000000000000000000000000..d85295011c695c359fb04ec3838b85eeb83cd502 Binary files /dev/null and b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png differ diff --git a/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png new file mode 100644 index 0000000000000000000000000000000000000000..bed0c5029d8d63667cd3179b8ad2e855dc8be39f Binary files /dev/null and b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png differ diff --git a/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png new file mode 100644 index 0000000000000000000000000000000000000000..b83fae4c4a29df46066ec83e88b67a6d89b2ae1d Binary files /dev/null and b/web-ui/docs/en/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png differ diff --git a/web-ui/docs/en/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md b/web-ui/docs/en/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md new file mode 100644 index 0000000000000000000000000000000000000000..f2b14232224a4255db9ea31b93f600ab9bab06a1 --- /dev/null +++ b/web-ui/docs/en/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md @@ -0,0 +1,43 @@ +--- +title: How to Unsubscribe from a Mailing List of the openEuler Community +date: 2021-11-23 +tags: + - openEuler + - Mailing List + - Unsubscribe +sig: sig-Gatekeeper +archives: 2021-11 +author: liuqi<469227928@qq.com> +summary: This blog describes two methods to unsubscribe from an openEuler mailing list. + +--- +# How to Unsubscribe from a Mailing List of the openEuler Community +The openEuler infrastructure team has received some inquiries from community maintainers and contributors about how to unsubscribe from openEuler mailing lists. Here are two methods: + +### 1. Unsubscribe through email + +Unsubscribe by email in either of two methods. In an email with an unsubscription footer, click the unsubscription icon in the email footer to create and send an unsubscription email. Alternatively, send an email to `**-leave@openeuler.org`. The following describes how to unsubscribe from test@openeuler.org. + +- + For emails containing an unsubscribe footer, click test-leave@openeuler.org to create and send unsubscription emails. You do not need to include a specific email title or include any content. + 通过邮件页脚退订 + + After you send the email, you will receive an email from test-bounces informing you that you have successfully unsubscribed from the mailing list. + 退订成功 + +- + You can also send an email to tc-leave@openeuler.org from your registered mailbox. You do not need to include a specific email title or include any content. + 发送退订邮件 + + After you send the email, you will receive an email from tc-bounces informing you that you have successfully unsubscribed. + 退订成功 + + +### 2. Unsubscribe on WebUI +If you are a registered user of the openEuler mailing list (the registration interface is unavailable currently), log in to [**Postorius**](https://mailweb.openeuler.org/postorius/lists/), go to the related mailing list, and click **Unsubscribe**. + +Web UI退订 + +### More Related Issues +Visit [**Mailweb List FAQ**](https://osinfra.cn/faq/mailinglist.html) for more questions about the community mailing list. + diff --git "a/web-ui/docs/en/blog/ouyanghaitao/Open Source Internship Report\342\200\224Porting openEuler to Windows WSL.md" "b/web-ui/docs/en/blog/ouyanghaitao/Open Source Internship Report\342\200\224Porting openEuler to Windows WSL.md" new file mode 100644 index 0000000000000000000000000000000000000000..e5f4dd8a29f7ab81dd4b634a77fd3c9f7364e2cb --- /dev/null +++ "b/web-ui/docs/en/blog/ouyanghaitao/Open Source Internship Report\342\200\224Porting openEuler to Windows WSL.md" @@ -0,0 +1,89 @@ +--- +title: Open Source Community Internship—Porting openEuler to Windows WSL +date: 2021-07-28 +tags: + - WSL + - Porting +archives: 2021-07 +author: ouyanghaitao +summary: Porting openEuler to Windows Subsystem for Linux (WSL) +--- + +# Open Source Internship Report—Porting openEuler to Windows WSL + + +## Joining Huawei and Determining My Objective + +My name is Wang Haitao, a third-year student in computer science of Harbin Institute of Technology (Shenzhen). + +To prepare for the Computer System Capability Challenge 2021, my supervisor suggested I first participate in RISC-V contests to gain experience writing a kernel from scratch. So, during the 2020 winter vacation, I participated in the openEuler 2020 College Developer Competition with the topic "Add the Grub boot mode for openEuler-RISC-V". This task required me to install openEuler, register a Gitee account, use QEMU to emulate RISC-V, and understand the ins and outs of Grub, giving me invaluable knowledge of the OS boot process. More importantly, I met contributors of the openEuler open source community, which helped me integrate myself with core members. + +With curiosity about the openEuler community and longing for an internship in Huawei, I sent my resume to Huawei's Open Source Development & Operations Dept., the branch responsible for running Huawei's four open source communities. After three months of waiting, I finally received an internship offer from Huawei with an opportunity to work on the back-end of the openEuler community. + +After just a few days, I discovered that the Windows Subsystem for Linux (WSL), a native virtualization solution of Microsoft commonly used in schools, did not support openEuler. WSL can run different mainstream Linux distros with faster speed and fewer drives on Windows, so I was surprised to see the lack of compatibility. + + +The thought came to me—I can solve this problem. I told my supervisors, and they were very encouraging. This conversation signaled the start of my first internship task—porting an openEuler distro to WSL. + +## Creating the Installation Package + +After reading the WSL documentation, I was confident that any Linux distro can be imported into WSL, meaning there are no restrictions on openEuler. + +First, I needed to import the root file system of the Linux distro using the WSL commands. Microsoft recommends that users use the official Docker image of the Linux distro and run the docker export command after starting the container to export the snapshot of the container image as the required root file system. + +On the download section of the official openEuler website, each openEuler distro has a corresponding Docker image. I downloaded the Docker image of [openEuler 20.03 LTS SP1](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/docker_img/x86_64/) and performed operations recorded in the WSL document. The next day, I started openEuler on WSL. + +It took me a few days to successfully compile the installation package. Normally, I just need to double-click the installation package to install the WSL version of openEuler in Windows. + +But when I tried to upload the project code to the openEuler community for archiving, I found the code needed to be mounted to a SIG. + +That brings us to the first problem—there was no SIG related to WSL. To set up a SIG on openEuler, I needed to submit an application through the email list of the technical committee (TC). So I sent an email to the open source TC and asked how to create a WSL SIG, who replied there was no need to create a WSL SIG, and suggested I join the OS-builder SIG. Later, I attended the OS-builder SIG's biweekly meeting, presented the porting work and problems, and with help from other members, successfully created the WSL repository under OS-builder. + +There was an interesting episode. After I sent the application email, I received an email from Mr. Yuan, the maintainer of SIG-minzuchess and contributor to the popularization of Raspberry Pi for middle schools. He asked me if I could accept an interview about the WSL project. I was flattered at that time and excited. In the interview, I first introduced the progress of porting openEuler to WSL and some basic Linux knowledge. Then, I shared my experience and lessons learned from the college entrance examination to Harbin Institute of Technology (Shenzhen) and colorful college life ([Interview link](https://gitee.com/yuandj/siger/blob/master/%E7%AC%AC10%E6%9C%9F%20%E5%8D%97%E5%BE%81%E5%8C%97%E6%88%98%EF%BC%88%E4%B8%8A12%EF%BC%89.md#%E4%B8%80%E5%B0%81%E9%9D%A2%E6%95%85%E4%BA%8B%E9%98%B3%E5%85%89%E6%B5%B7%E6%B6%9B)). + +My code needed to be tested before being submitted. But I was unsure how to do it. To address this, I participated in the regular meetings of the Quality Assurance (QA) and release-management SIGs, who suggested I use the latest mugen test framework and integration-test scripts to test the system. This helped me find another issue – a bug in the script. The test allowed me to fix a bug in the test script by adding a space between the grep command and the file name, before I submitted a PR. It was not a major bug, but still, I was excited about this small achievement. + +The test result shows that all test cases in the os-basic folder pass the test, but half of the overall test cases fail. The error logs show that WSL does not have certain native Linux functions, preventing many functions from being enabled and causing related tests to fail. For example, WSL does not support systemctl, and most test scripts need to use systemctl to enable system functions before testing, meaning WSL cannot pass these tests. Despite the failed tests, no problems were found after the ported openEuler is used for a while, indicating that the normal use of the openEuler is not affected. + +When I waited for the PR of my tested code, submitted to the WSL repository, to be incorporated, I considered submitting the installation package to the Microsoft Store. + +## Seeking Help + +Before releasing the openEuler installation package on Microsoft Store, I needed to solve some non-technical problems. The community is the best place to seek help. + +Although the installation package is complete, the logo displayed on the start menu is not as good as that of Ubuntu. The openEuler logo consists of the blue letter E and the black character openEuler at the bottom. Two problems: one, the icon with text is small in the Microsoft start menu; and two, the black text is not clear in the background when the Windows dark mode is enabled. + +A simple solution was to delete the text on the logo and then zoom in on the logo. But a colleague reminded me that the logo without the text may be illegal. I confirmed this with a lawyer from Huawei's legal affairs department, who said it was not a violation of the official standard and gave me a screenshot of the trademark search report. Every time I think of this logo, it reminds me that I must consider compliance when developing anything for the open source community. + +After the logo problem was solved, my project was ready for release. It was mentioned in the WSL document that I had to send an email to the WSL team for testing before releasing the project on the Microsoft Store, which I did. + +After two weeks of not hearing from the WSL, I sent another email. When the WSL team finally replied to me, they told me Microsoft was very busy holding meetings recently and they did not have the time to see the email. More importantly, they informed me WSL can be directly submitted after being ported without testing. + +The document says that to release the software package on Microsoft Store, one must first register a company or a personal account at Microsoft Partner Center. The former needs official certificates of the company and will be verified by Microsoft, while the latter is not verified by Microsoft. I intended to create a company account that allows more users to log in and release apps with specific functions, even though openEuler is not a company. To do so, I found the maintainer of the community infrastructure SIG, who helped me set up an openEuler email address to register a Microsoft account. Once this was verified, the Microsoft Partner Center displays a verification error message. I needed to provide the related certificates to show the domain name openeuler.io is registered by the community. So, I asked for proof materials from the community infrastructure SIG, who sent me screenshots of the administrator interface, which were submitted to Microsoft. + +Microsoft did not reply for two weeks. In the forum of the Microsoft Partner Center, I found that, like me, several people were also stuck in the same verification phase, but with a key difference - after they posted their issues, Microsoft administrators followed up to help solve the verification problem. So I posted a support request in the discussion section, hoping that the customer service personnel can help me with the verification. + +A few days later, I received a call from the United States. Although we talked about it all afternoon, the staff member was unable to solve my problem. Later, I found that my question category was incorrect. The reason was that there were several account-related questions, which were similar to each other. + +This taught me a key lesson. I learned that if partners do not reply, I should proactively communicate with them, such as posting on forums, contacting customer service personnel, and sending emails to related teams. + +## Releasing openEuler on Microsoft Store + +Because customer service could not solve my problem, I had to wait for my proof materials to be verified by Microsoft. Fortunately, about a week later, Microsoft sent me an email, asking me to provide the official PDF certificate of the company in addition to screenshots. This was problematic as openEuler is an open source community, rather than a commercial company, so there is no official certificate. Community members suggested I register a personal account instead to release the version. + +So I used another openEuler email address to create a Microsoft personal account, bypassing verification, allowing me to successfully submit the required application information. During the release, I cannot submit the installation package and the system displayed a message indicating that the signature is incorrect. When I checked the introduction to the Microsoft software release on YouTube and the related question on Stack Overflow, I found that the Windows publisher ID of the developer account, that is, a string of numbers starting with CN, must be provided. This number is used as the Publisher common name of the Visual Studio–signed installation package, and the signed installation package can be successfully identified by the Microsoft Partner Center. I did not find any relevant content about this release tip in Microsoft development documentation. + +Surprisingly, three days later, I received a suggestion from Microsoft, who told me to change the privacy link, add the statement that openEuler does not support Windows 10 S, and submit the upload request again. I thought it would take a long time to release the application, but I was wrong. Never in my wildest dreams did I expect that openEuler would be released on the Microsoft Store within just a few days. + +The preceding figure is a screenshot of openEuler in the Microsoft Store. You can get it at [Link 1](https://www.microsoft.com/zh-cn/p/openeuler/9ngf0q0xp03d?rtc=1&activetab=pivot:overviewtab). Note: you need to enable the WSL function before installing any release of the WSL. For details, see [Link 2](https://gitee.com/openeuler/wsl). + +During the three-month internship, I conversed with Microsoft and with the open source community. It was the first time I communicated with community members about openEuler, and it made me feel that I part of the openEuler family. + +This experience made me realize how Huawei provides a positive working environment for its colleagues, who are willing to help each other. So I decided to extend my internship from July to the end of September. I hope that I can learn more and contribute more to openEuler in the next three months. + +I attached the technical document about porting openEuler to WSL at https://gitee.com/openeuler/wsl. This document describes how to install openEuler on WSL. +If you have any questions, please create an issue in the WSL repository of the openEuler community at https://gitee.com/openeuler/wsl/issues. + +If you want to participate in openEuler development, search for the mini-program "openEuler" in WeChat. The program contains more than 80 SIG‘s meeting schedules, topics, and online and offline meetups of openEuler. You can select topics that you are interested in to participate in regular meetings, communicate with community members in detail during meetings, or participate in Meetup activities on site. + +We hope to see you soon in the openEuler community. diff --git a/web-ui/docs/en/blog/randy1568/Apache 2.4.39 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Apache 2.4.39 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..e2984ad2dc611e282c2dd99f5815591f2304d375 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Apache 2.4.39 Porting Guide.md @@ -0,0 +1,135 @@ +--- +title: Apache 2.4.39 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Apache + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Apache 2.4.39 +--- + +# Apache 2.4.39 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Apache Overview + +Apache HTTP Server (Apache for short) is an open-source web server of the Apache Software Foundation. It can run on numerous operating systems (OSs) and is widely used due to its high security and compatibility with multiple platforms. It is fast and reliable, and can be extended using simple APIs to compile interpreters such as Perl and Python to the server. + +Programming language: C + +Brief description: web server + +## Recommended Version + +Apache httpd 2.4.39 or later + +# Environment Requirements + +## Hardware + +The following table lists hardware requirements. + +Item| Description +----- | ----- +Server| TaiShan 200 server (model 2280) +CPU | Kunpeng 920 5250 +Drive partition| No requirements + +## Operating Systems + +The following table lists OS requirements. + +Item| Version +----- | ----- +openEuler | 20.03 SP1 AArch64 +Kernel | 4.19 + +NOTE: + +When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". Otherwise, lots of software packages need to be installed manually. + +# Configuring the Compilation Environment + +1. Install the development package. + + ``` + yum update + yum install gcc gcc-c++ + ``` + +2. Install dependencies. + + ``` + yum install apr-devel.aarch64 apr-util-devel.aarch64 pcre-devel.aarch64 -y + ``` + +3. Obtain the source code. + + Download address: http://archive.apache.org/dist/httpd/httpd-2.4.39.tar.gz + +## Preparing the Installation Package + + tar xzvf httpd-2.4.39.tar.gz + +## Modifying the Source Code + + cd httpd-2.4.39 + vi ./build/config.sub + + In the following two lines, add aarch64: + + | x86 | xc16x | xstormy16 | xtensa \ + => + | x86 | aarch64 | xc16x | xstormy16 | xtensa \ + + + | x86-* | x86_64-* | xc16x-* | xps100-* \ + => + | x86-* | aarch64-* | x86_64-* | xc16x-* | xps100-* \ + +## Compiling and Installing Apache + + ./configure --host=aarch64 --build=aarch64 + make -j4 + make install + +# Configuring Parameters + +## Modifying httpd.conf + + vi /usr/local/apache2/conf/httpd.conf + + Delete the comment tag in line 89. + LoadModule socache_shmcb_module modules/mod_socache_shmcb.so + + Delete the comment tag in line 196 and change the value to the IP address of the current server. + #ServerName www.example.com:80 + => + ServerName local_server_ip:80 + + Delete the comment tag in line 461. + Include conf/extra/httpd-mpm.conf + + Delete the comment tag in line 488. + Include conf/extra/httpd-default.conf + +## Modifying httpd-default.conf + + vi /usr/local/apache2/conf/extra/httpd-default.conf + + Change the value in line 23 to 0. + MaxKeepAliveRequests 0 + +# Verifying Apache + + Run the following command to start Apache: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start + + Run the following command to stop Apache: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k stop + + Run the following command to check the service process: + ps -ef |grep httpd diff --git a/web-ui/docs/en/blog/randy1568/Dubbo-2.6.8-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/Dubbo-2.6.8-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..539755c5a0354e262c9c83953241c155e58c3ac5 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Dubbo-2.6.8-Porting-Guide.md @@ -0,0 +1,225 @@ +--- +title: Dubbo 2.6.8 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Dubbo 2.6.8 +--- + +# Dubbo 2.6.8 Porting Guide (openEuler 20.03 LTS SP1) + +## Introduction + +### Overview + +Dubbo is a high-performance open-source service framework provided by Alibaba, which enables applications to implement service output and input via high-performance remote procedure calls (RPC), and can be seamlessly integrated with the Spring framework. In short, Dubbo is a Spring-based RPC framework that implements remote calling and management of services. + + + +### Recommended Version + +Dubbo 2.6.8 + + + +## Environment Requirements + + + +### Hardware + +[Table 1](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html) lists the hardware requirements. + +| Item| Description | +| ---- | ------------- | +| CPU | Kunpeng 920 processor| +| Network| Accessible to the Internet | +| Storage| No requirements | +| Memory| No requirements | + + + +### Operating Systems + +[Table 2](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html) lists the OS requirements. + +| Item | Version | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64| +| Kernel | 4.19.90 | + + + +## Configuring the Compilation Environment + +### Configuring a DNS server + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + + + +### Installing Dependencies + +1. Download and install dependencies. + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + + + +2. Query the Java version. + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + + + +### Installing Maven + + + +1. Download the Maven installation package. + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + + + +2. Decompress the installation package to a specified directory. + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + + + +3. Configure the Maven environment variables. + +a. Add the Maven path to the end of the **/etc/profile** file. + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo "export PATH=$MAVEN_HOME/bin:$PATH" >> /etc/profile +``` + + + +b. Make the modified environment variables take effect. + +``` +source /etc/profile +``` + + + +4. Check whether the configuration has taken effect. + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + + + +5. Modify the local repository, remote repository, and proxy in the Maven configuration file. + +Configuration file path: **/opt/apache-maven-3.6.3/conf/settings.xml** + +Configure the network proxy. Change the values of **host**, **port**, **username**, and **password** as required. + +``` + + + my-proxy + true + https + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + + my-proxy1 + true + http + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + +``` + +Configure the remote repository. + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + + + +## Compiling Dubbo 2.6.8 + + + +### Obtaining the Source Code + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.6.8.tar.gz +&& tar -xvf dubbo-2.6.8.tar.gz +``` + + + +### Compiling the dubbo-rpc-redis Module + +``` +mvn install +``` + +If **BUILD SUCCESS** is displayed, it means that the dubbo-rpc-redis module has been successfully compiled. + + + +### Compiling Dubbo 2.6.8 + + Add the following content to the end of line 552 in the **/home/Dubbo/dubbo-dubbo-2.6.8/pom.xml** file: + + + + +If **BUILD SUCCESS** is displayed, it means that Dubbo 2.6.8 has been successfully compiled. + + + + + +The **dubbo-2.6.8.jar** package generated after the compilation is stored in the **all/target** directory. diff --git a/web-ui/docs/en/blog/randy1568/Dubbo-2.7.5-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/Dubbo-2.7.5-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..72318bd79fb1c522d4895e0d6806e229a50cac9b --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Dubbo-2.7.5-Porting-Guide.md @@ -0,0 +1,437 @@ +--- +title: Dubbo 2.7.5 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Dubbo 2.7.5 +--- + +# Dubbo 2.7.5 Porting Guide (openEuler 20.03 LTS SP1) + + + +## Introduction + +### Overview + +Dubbo is a high-performance open-source service framework provided by Alibaba, which enables applications to implement service output and input via high-performance remote procedure calls (RPC), and can be seamlessly integrated with the Spring framework. In short, Dubbo is a Spring-based RPC framework that implements remote calling and management of services. + + + +### Recommended Version + +Dubbo 2.7.5 + + + +## Environment Requirements + + + +### Hardware + +[Table 1](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html) lists the hardware requirements. + +| Item| Description | +| ---- | ------------- | +| CPU | Kunpeng 920 processor| +| Network| Accessible to the Internet | +| Storage| No requirements | +| Memory| No requirements | + + + +### Operating Systems + +[Table 2](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html) lists the OS requirements. + +| Item | Version | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64| +| Kernel | 4.19.90 | + + + +## Configuring the Compilation Environment + +### Configuring a DNS server + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + + + +### Installing Dependencies + +1. Download and install dependencies. + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + + + +2. Query the Java version. + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + + + +### Installing Maven + + + +1. Download the Maven installation package. + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + + + +2. Decompress the installation package to a specified directory. + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + + + +3. Configure the Maven environment variables. + +a. Add the Maven path to the end of the **/etc/profile** file. + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> /etc/profile +``` + + + +b. Make the modified environment variables take effect. + +``` +source /etc/profile +``` + + + +4. Check whether the configuration has taken effect. + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + + + +5. Modify the local repository, remote repository, and proxy in the Maven configuration file. + +Configuration file path: **/opt/apache-maven-3.6.3/conf/settings.xml** + +Configure the network proxy. Change the values of **host**, **port**, **username**, and **password** as required. + +``` + + + my-proxy + true + https + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + + my-proxy1 + true + http + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + +``` + +Configure the remote repository. + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + + + +## Compilation + + + +### Obtaining the Source Code + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.7.5.tar.gz +&& tar -xvf dubbo-2.7.5.tar.gz +``` + + + +### Compiling the dubbo-common Module + + + +### Compiling the dubbo-remoting-netty Module + + + +1. Modify the **NettyClientTest.java** file. + + + + a. Open the file and change **6000** in line 76 to **9000**. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/NettyClientTest.java ` + + + + + + b. Compile the dubbo-remoting-netty module. + + ``` + cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty && mvn install + ``` + + + + + +If **BUILD SUCCESS** is displayed, it means that the dubbo-remoting-netty module has been successfully compiled. + + + +### Compiling the dubbo-rpc-redis Module + +1. Obtain the **embedded-redis-0.6.jar** package that supports AArch64. + +``` + mkdir -p /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar -O /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar +``` + + + +2. Compile the dubbo-rpc-redis module. + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-rpc/dubbo-rpc-redis/ && mvn install +``` + + + +If **BUILD SUCCESS** is displayed, it means that the dubbo-rpc-redis module has been successfully compiled. + +### Compiling the dubbo-remoting-etcd3 Module + +1. Install Docker. + +``` +yum -y install docker +``` + +2. Configure environment variables. + +``` +echo "export TESTCONTAINERS_RYUK_DISABLED=true" >> /etc/profile && source /etc/profile +``` + +3. Modify the **/root/.testcontainers.properties** file. + +``` +echo "checks.disable=true" >> /root/.testcontainers.properties +``` + +4. Replace the **jetcd-launcher-0.3.0.jar** package with the one that supports the ARM64 image. + +``` +wget https://mirrors.huaweicloud.com/kunpeng/maven/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar -O /root/.m2/repository/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar +``` + + + +5. Compile the dubbo-remoting-etcd3 module. + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-etcd3/ && mvn install +``` + + + +If **BUILD SUCCESS** is displayed, it means that the dubbo-remoting-etcd3 module has been successfully compiled. + +### Compiling the dubbo- registry-consul Module + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-registry/dubbo-registry-consul/ && mvn install + +``` + +If the error message "EmbeddedConsul Could not start Consul process in..." is displayed during the compilation, store the **consul_1.1.0_linux_arm64.zip** package of the ARM64 version to the **local /tmp/embedded-consul-1.1.0** directory. + +``` +wget https://releases.hashicorp.com/consul/1.1.0/consul_1.1.0_linux_arm64.zip && unzip consul_1.1.0_linux_arm64.zip && mv consul /tmp/embedded-consul-1.1.0/consul +``` + + + +Then recompile the module. + + + +If **BUILD SUCCESS** is displayed, it means that the dubbo-registry-consul module has been successfully compiled. + + + +### Modifying Other Configuration Files + +1. Replace the **netty-all-4.1.25.Final.jar** package in the local repository. + + + + ``` + mkdir -p /root/.m2/repository/io/netty/netty-all/4.1.25.Final/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar -O /root/.m2/repository/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar + ``` + + + + + +2. Modify the **/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml** file. + + + + 1. Open the **pom.xml** file. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml ` + + 2. Add the following code. Save the file and exit. + + - Add the following code to line 31: + + ``` + true + ``` + + + + + + - Add the following code to line 206: + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + + + + + +3. Modify the **/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml** file. + + + + 1. Open the **pom.xml** file. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml ` + + 2. Add the following code. Save the file and exit. + + - Add the following code to line 30: + + ``` + + true + + ``` + + + + + + - Add the following code to line 110: + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + + + + + +### Compiling Dubbo 2.7.5 + + Add the following content to the end of line 592 in the **/home/Dubbo/dubbo-dubbo-2.7.5/pom.xml** file: + +``` + + true + +``` + + + + + + + +If **BUILD SUCCESS** is displayed, it means that Dubbo 2.7.5 has been successfully compiled. + +The **dubbo-2.7.5.jar** package generated after the compilation is stored in the **dubbo-all/target** directory. diff --git a/web-ui/docs/en/blog/randy1568/Flask 1.1.2 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Flask 1.1.2 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..ceece7d8092af4a6f1f765d07c93dab2820c8823 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Flask 1.1.2 Porting Guide.md @@ -0,0 +1,195 @@ +--- +title: Flask 1.1.2 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Flask + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything of the Flask 1.1.2 Porting Case +--- + +# Flask 1.1.2 Porting Guide (OpenEuler 20.03 LTS SP1) + + + +## Introduction + +### Overview + +Flask is a lightweight web framework written in Python. Flask is based on the Werkzeug, WSGI toolkit and the Jinja2 template engine. +In this case, x86_64 VMs and the evaluation tool x2openEuler are used to evaluate the compatibility of Flask 1.1.2 to be ported to the openEuler OS and complete the porting based on the evaluation result. + +Programming language: Python + +Open source license: BSD + +### Recommended Version + +The recommended version is Flask 1.1.2. + +NOTE: This document applies to Flask 1.1.2. You can also refer to this document when porting other Flask versions. + +## Environment Requirements + +### OS Requirements + +| OS | Version | +| :-------- | :------------ | +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +### Installing the OS + +When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". Otherwise, lots of software packages need to be installed manually. +For details about how to install the openEuler OS, see https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html.(https://bbs.huaweicloud.com/forum/thread-116157-1-1.html#) + +## Compatibility Evaluation + +### Obtaining Flask RPM Package + +``` +wget https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-flask-1.1.2-4.el7.noarch.rpm +``` + +#### Downloading x2openEuler + +``` +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/contrib/x2openEuler/x86_64/Packages/ + +User guide: +https://gitee.com/openeuler/docs/blob/stable2-20.03_LTS_SP1/docs/en/docs/thirdparty_migration/x2openEuleruserguide.md +``` + +#### Deploying x2openEuler + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +Note: +You need to install the RPM package as the root user. Currently, the network is required for downloading and installing dependencies. +Install dependencies such as bzip2-devel as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Enter the following information about the Redis database in sequence. +IP address: 127.0.0.1 +Port: 6379 +Database index (0-16): 0 +Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +Note: After x2openEuler is installed using an RPM package, the default resource package (**source_centos7.6-openEuler20.03-LTS-SP1.tar.gz**) is generated in the /opt/x2openEuler directory. +To support the evaluation of hardware compatibility from CentOS 8.2 to openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run `x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz` to import the package. Replace the package with the actual one. + +#### Scanning Flask + +``` +x2openEuler scan python36-flask-1.1.2-4.el7.noarch.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## Viewing Evaluation Results + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the call of other software packages, dynamic libraries, or system interfaces during the software running. If the interface compatibility is not 100%, an exception may be triggered when some function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + + + +Result: The report shows that the external interface compatibility is 100%. A manual review confirmed that the dependency package is missing. Since the software package is a Python package, you are advised to use pip3 to install the dependency and Python Flask of the corresponding version. + +## Installing Flask + +### Installing the Flask RPM Package + +The compatibility report shows that the dependency package is missing. So you can install the downloaded RPM package for verification. + +``` +[root@localhost test]# yum install -y python36-flask-1.1.2-4.el7.noarch.rpm +Last metadata expiration check: 1:39:08 ago on Mon 22 Mar 2021 10:35:29 AM CST. +Error: + Problem: conflicting requests + - nothing provides python36-setuptools needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python(abi) = 3.6 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-click >= 5.1 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-itsdangerous >= 0.24 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-jinja2 >= 2.10.1 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-werkzeug >= 0.15 needed by python36-flask-1.1.2-4.el7.noarch +(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages) +``` + +Flask failed to be installed due to dependency missing. + +### Installing Flask Using PIP + +Install Flask of the same version using pip3. + +``` +[root@localhost ~]# pip3 install flask +WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead. +Collecting flask + Using cached Flask-1.1.2-py2.py3-none-any.whl (94 kB) +Requirement already satisfied: itsdangerous>=0.24 in /usr/lib/python3.7/site-packages (from flask) (1.1.0) +Requirement already satisfied: Werkzeug>=0.15 in /usr/local/lib/python3.7/site-packages (from flask) (1.0.1) +Requirement already satisfied: click>=5.1 in /usr/local/lib/python3.7/site-packages (from flask) (7.1.2) +Requirement already satisfied: Jinja2>=2.10.1 in /usr/lib/python3.7/site-packages (from flask) (2.11.2) +Requirement already satisfied: MarkupSafe>=0.23 in /usr/lib64/python3.7/site-packages (from Jinja2>=2.10.1->flask) (1.1.1) +Installing collected packages: flask +Successfully installed flask-1.1.2 +``` + +## Running and Verifying Flask + +### Checking the Version + +``` +[root@localhost ~]# python3 +Python 3.7.9 (default, Dec 16 2020, 03:16:57) +[GCC 7.3.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> import flask +>>> flask.__version__ +'1.1.2' +``` + +### Running Flask + +The starter program is provided on the Flask official website ([https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application](https://bbs.huaweicloud.com/forum/thread-115817-1-1.html#)) + +``` +vim hello.py +``` + +Edit the following content: + +``` +from flask import Flask +app = Flask(__name__) + +@app.route('/') +def hello_world(): + return 'Hello, World!' +``` + +Save the file and exit. Run the following command on the terminal: + +``` +[root@localhost ~]# export FLASK_APP=hello.py +[root@localhost ~]# python3 -m flask run + * Serving Flask app "hello.py" + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: off + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + +The running is successful. diff --git a/web-ui/docs/en/blog/randy1568/HAProxy-1.9.0-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/HAProxy-1.9.0-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..ca4445884d826d972ca4e086938765dc2be08ec1 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/HAProxy-1.9.0-Porting-Guide.md @@ -0,0 +1,200 @@ +--- +title: HAProxy 1.9.0 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - HAProxy + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port HAProxy 1.9.0 +--- + +# HAProxy 1.9.0 Porting Guide (openEuler 20.03 LTS SP1) + +## Introduction + +#### Overview + +HAProxy is a free and open-source software program written in C. It provides a high availability load balancer and proxy server for TCP and HTTP-based applications, supports virtual hosts, and has a reputation for being fast and reliable. +Programming language: C + +Brief description: web load balancer + +#### Recommended Software Version + +HAProxy 1.9.0 + +Notes: + +This document applies to HAProxy 1.9.0. However, you can refer to this document when porting other HAProxy versions. + +## Environment Requirements + +#### Hardware + +| Item | Description | +| -------- | ----------------------------- | +| Server | TaiShan 200 server (model 2280)| +| CPU | Kunpeng 920 5250 processor | +| Drive partition| No requirements | + +#### OS + +| Item | Version | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64| +| Kernel | 4.19 | + +Check the current system information. + +```bash +cat /etc/os-release +``` + + + +For details about how to install the openEuler OS, see https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html. +Notes: +You are advised to select the "Server with GUI" installation mode. + +## Installing HAProxy Using the RPM Package Obtained from a Mirror Site + +If your server can access the network, run the "wget https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm" command to download the RPM package. Otherwise, visit https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm to download the package and copy it to the **/home** directory on the server. + +Notes: +The RPM packages in the mirror site are compiled and packaged using open-source code, and then uploaded to the mirror site. + +The following describes how to download the RPM package to the local PC and then upload it to the server. + +1. Install HAProxy. + + ```bash + rpm -ivh haproxy-1.9.0-1.el7.aarch64.rpm + ``` + + + +2. View the installation directory. + + ```bash + ls /usr/local/haproxy + ``` + + + +## Operation and Verification + +- Configure parameters. + + a. Open the **option-http_proxy.cfg** file. + + ```bash + vi /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + + b. Modify the file as follows, and save and close the file: + + ```bash + global + maxconn 20000 + log 127.0.0.1 local0 info + uid 0 + gid 0 + chroot /usr/local/haproxy + nbproc 4 + daemon + defaults + mode http + retries 3 + timeout connect 10s + timeout client 20s + timeout server 30s + timeout check 2s + frontend test-proxy + bind *:80 + mode http + log global + default_backend test-proxy-srv + backend test-proxy-srv + balance roundrobin + option http-server-close + option httpchk GET /index.html + http-check expect status 200 + server web1 IP1:PORT1 weight 3 + server web2 IP2:PORT2 weight 3 + ``` + + For details about the parameters in the configuration file, see the [following table](https://support.huaweicloud.com/prtg-kunpengwebs/kunpenghaproxy_02_0011.html#kunpenghaproxy_02_0011__table177828478439). + + + +| Parameter | Description | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| global | - | +| maxconn 20000 | Specifies the maximum number of connections. | +| log 127.0.0.1 local0 info | Specifies the log output device. info indicates the log severity level. | +| uid 0 | Specifies the ID of the user who runs HAProxy. | +| gid 0 | Specifies the ID of the user group to which the user running HAProxy belongs. | +| chroot /usr/local/haproxy | Specifies the chroot running path. | +| nbproc 4 | Specifies the number of processes. | +| daemon | Runs HAProxy in the background. | +| defaults | - | +| mode http | Specifies the processed type (layer 7 uses HTTP, and layer 4 uses TCP). | +| retries 3 | Specifies the maximum number of retries for connecting to the backend server. If the number of retries exceeds the specified value, the backend server is unavailable.| +| timeout connect 10s | Specifies the maximum time allowed before the connection between HAProxy and the backend server is set up. | +| timeout client 20s | Specifies the timeout period for keeping an idle connection with the client. | +| timeout server 30s | Specifies the timeout period for keeping an idle connection with the server. | +| timeout check 2s | Specifies the timeout period for checking the server. | +| frontend test-proxy | - | +| bind *:80 | Specifies one or more listening sockets. The asterisk (*) indicates all IPv4 addresses. | +| mode http | Specifies the processed type (layer 7 uses HTTP, and layer 4 uses TCP). | +| log global | Inherits the definition of log in the global section. | +| default_backend test-proxy-srv | Specifies the default backend server pool. | +| backend test-proxy-srv | - | +| balance roundrobin | Specifies the load balancing algorithm round robin, which is a weight-based polling algorithm and applies to scenarios where servers have roughly identical performance.| +| option http-server- | This parameter must be enabled when the persistent connection is enabled. | +| option httpchk GET /index.htmlhttp-check expect status 200 | Enables HTTP service status check (health check) and checks the returned status code. If "200" is not returned, no request is sent to backend servers.| +| server web1IP1:PORT1 weight 3 server web2 IP2:PORT2 weight 3 | Defines multiple backend servers. Format: server :[port] [param*]** (Note: **IP1:PORT1 and IP2:PORT2 indicate the IP address and port number of a backend server.)| + +- Start HAProxy. + + ```bash + taskset -c 0-3 /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + +- Verify HAProxy. + + ```bash + ps -ef | grep haproxy + ``` + + The HAProxy process is displayed. + + Open the browser, enter http://*HAProxy IP address*:80 in the address box, and press **Enter**. The WebUI page of the backend server is displayed, indicating that HAProxy is running properly. Refresh the page. The page switches between backend servers. + + Notes: + + - (Optional) Stop HAProxy. Do not run this command when services are running. + + ```bash + pkill haproxy + ``` + + - (Optional) Uninstall HAProxy and query the result. + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rpm -e --nodeps haproxy-1.9.0 + ``` + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rm -rf /usr/local/haproxy + ``` diff --git a/web-ui/docs/en/blog/randy1568/Memcached 1.5.12 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Memcached 1.5.12 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..28c31829c4f93e1d3351402a058ceb3400fd4747 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Memcached 1.5.12 Porting Guide.md @@ -0,0 +1,218 @@ +--- +title: Memcached 1.5.12 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Memcached + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Memcached 1.5.12 +--- + +# Memcached 1.5.12 Porting Guide + +## Introduction + +#### Overview + +Memcached is a high-performance, distributed memory object caching server, developed by Brad Fitzpatric from Danga Interactive, a subsidiary of LiveJournal. It is used to cache database query results and reduce database access times to improve the speed and scalability of dynamic web applications. + +Official Memcached website: https://memcached.org/ + +Programming language: C + +Brief description: distributed memory object caching system + +## Environmental Requirements + +### Hardware + +The following table lists the hardware requirements. + +| Item | Description | +| -------- | ----------------------------- | +| Server | TaiShan 200 server (model 2280)| +| CPU | Kunpeng 920 5250 processor | +| Drive partition| No requirements | + +### Operating Systems + +The following table lists the requirements for the operating system. + +| Item | Version | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64| +| Kernel | 4.19 | + +Check the current OS version. + +``` +cat /etc/os-release +``` + + + + + +For details about installing the openEuler OS, see https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html. +Note: +You are advised to select the "Server with GUI" installation mode. + +## Configuring the Compilation Environment + +To compile Memcached, you need to prepare the C compiler, GNU, make, automake, libevent, and libevent-devel. + +1. Install the GNU Compiler Collection (GCC). If GCC has been installed, skip this step. + + ```bash + yum -y install gcc gcc-c++ kernel-devel + ``` + +2. Install GNU make, Automake, unzip, and Telnet. If they have been installed, skip this step. + + ```bash + yum -y install make automake unzip telnet + ``` + +3. Install libevent and libevent-devel. + + ```bash + yum -y install libevent libevent-devel + ``` + +## Obtaining Source Code + +If your server can access the network, run the "wget https://github.com/memcached/memcached/archive/1.5.12.zip" command to download the source code. Otherwise, visit https://github.com/memcached/memcached/archive/1.5.12.zip to download the source code and copy it to the /home directory on the server. + +## Compiling and Installing Memcached + +The following uses the source code downloaded to the local PC and then uploaded to the server as an example for describing compilation and installation operations. + +1. Decompress the source package. + + ```bash + cd /home + ``` + + ```bash + unzip 1.5.12.zip + ``` + +2. Go to the **memcached-1.5.12** directory. + + ```bash + cd memcached-1.5.12 + ``` + +3. Configure Memcached. + + ```bash + sh autogen.sh + ``` + + ```bash + ./configure --prefix=/opt/memcached + ``` + + You can specify the Memcached installation directory, for example, **/opt/memcached**, in this step. + +4. Perform compilation. + + ```bash + make -j60 + ``` + + **-j60** leverages the multi-core CPUs to speed up compilation. + +5. Perform installation. + + ```bash + make install + ``` + +6. Switch to the Memcached installation directory **/opt/memcached**. If the generated bin directory contains the Memcached executable file, installation is successful. + +7. Set environment variables. + + a. Add the following command to the **/etc/profile** file: + + ```bash + export PATH=/opt/memcached/bin/:$PATH + ``` + + b. Make the environment variable effective. + + ```bash + source /etc/profile + ``` + +## Running and Verifying Memcached + +- Start Memcached. + + ```bash + memcached -t 24 -p 11211 -u root -m 49152 -c 10240 + ``` + + The following table describes the parameters in the startup command. + +| Parameter| Description | Default Value | +| -------- | ------------------------------------- | -------------------------- | +| -t | Thread count | 4 | +| -p | TCP listening port | 11211 | +| -u | User who starts the process | The default user cannot be root.| +| -m | Memory size (in MB) allocated to Memcached | 64M | +| -c | Maximum number of concurrent connections | 1024 | +| -d | Starts a daemon in the background. | - | + +- Start another shell window to connect to Memcached. + + ```bash + telnet 127.0.0.1 11211 + ``` + +- After creating a connection, run the stats command to obtain the statistics of the Memcached server. + + ```bash + stats + ``` + + + + +The [following table](https://support.huaweicloud.com/intl/en-us/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table1896316817714) lists the common stats commands. + + + +| Command | Description | +| --------------- | ------------------------------------------------------------ | +| stats | Displays the overall status of Memcached, including the startup time, amount of data stored, cache hit ratio, and number of current connections.| +| stats items | Outputs the item information of each slab. | +| stats slabs | Outputs more details about slabs. | +| stats sizes | Displays the size and number of all items. | +| stats cachedump | Outputs certain pieces of data in a slab. If the input is 0, all data in the slab is output. | +| stats detail | Sets (on/off) or displays (dump) detailed operation records, such as the get/set operation. | +| flush_all | Invalidates all items in the memory. This operation does not suspend the server because no free memory is released and the existing items are marked as invalid. | + + Note: + To exit the Telnet connection, run the **quit** command. + + ```bash + quit + ``` + +In addition to connecting to the Memcached service using Telnet to obtain data, the source code provides some tool scripts, such as memcached-tool, in the scripts directory of the source code. + +For details about how to use the memcached-tool, see the [following table](https://support.huaweicloud.com/intl/en-us/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table15821759181818). + + + +| Command | Description | +| -------------------------------------------- | ------------------------ | +| ./memcached-tool localhost display | Displays slabs information. | +| ./memcached-tool 10.0.0.5:11211 display | Displays slabs information. | +| ./memcached-tool 10.0.0.5:11211 stats | Displays memcached statistics. | +| ./memcached-tool 10.0.0.5:11211 settings | Displays memcached settings. | +| ./memcached-tool 10.0.0.5:11211 sizes | Displays the size and number of all items. | +| ./memcached-tool 10.0.0.5:11211 dump [limit] | Outputs keys and values from the cache.| diff --git a/web-ui/docs/en/blog/randy1568/MySQL-5.7.21-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/MySQL-5.7.21-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..58531c41165bfaede9964a394efb13ce71af3a42 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/MySQL-5.7.21-Porting-Guide.md @@ -0,0 +1,272 @@ +--- +title: MySQL 5.7.21 Porting Guide (openEuler 20.03 LTS SP1) +date: 2022-01-05 +tags: + - MySQL + - Porting Case +sig: sig-Compatibility-Infra +archives: 2022-01 +author: xielihao +summary: Just everything about the MySQL 5.7.21 porting cases +--- + +# MySQL 5.7.21 Porting Guide (openEuler 20.03 LTS SP1) + + +## 1. Introduction + +This document describes how to deploy the MySQL database on openEuler 20.03 SP1. + +MySQL is a secure, cross-platform, and efficient database system that works closely with mainstream programming languages such as PHP and Java. +In this document, x86_64 VMs are used. The x2openEuler tool is used to evaluate the compatibility between MySQL 5.7.21 and openEuler before data migration. + +MySQL 5.7.21 is recommended. + +> NOTE: +> This document applies to MySQL 5.7.21. However, you can refer to this document when porting other MySQL versions. + +## 2. Environment + +Hardware +| Item | Description | +| -------- | ----------------- | +| Server | TaiShan 200 server| +| CPU | Kunpeng 920 processor| +| RAID controller card | SAS3508 | +| NIC | Mellanox SP333 | +| | TM210 | +| | TM280 | +| Drive | 500 GB or more | + +Operating systems +| Software| Version | Remarks | +| ---- | ------------------- | ------------------- | +| OS | CentOS 7.6.1810 | Current MySQL cluster server| +| OS | openEuler 20.03 SP1 | Target server | + +Software packages +| Software | Version | +| --------------------- | ------ | +| mysql5 | 5.7.21 | +| mysql5-common | 5.7.21 | +| mysql5-embedded | 5.7.21 | +| mysql5-embedded-devel | 5.7.21 | +| mysql5-errmsg | 5.7.21 | +| mysql5-libs | 5.7.21 | +| mysql5-server | 5.7.21 | +| mysql5-test | 5.7.21 | + +## 3. Software Compatibility Assessment + +The openEuler community provides [x2openEuler](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/) to evaluate software packages and interfaces of compiled binary programs, and determine whether application software needs to be adapted and whether any dependencies are needed. In addition, the tool checks whether prototypes of interfaces called by the software are different between the two OSs. + +Note: It is difficult to ensure that the binary program is completely compatible with the target OS once it has been compiled and therefore memory risks may occur. Since it is difficult to identify this problem through verification, it is therefore important to perform software compatibility evaluation prior to porting. + +#### 3.1 Obtain the MySQL RPM package and decompress it to the /opt/mysql directory. + +``` +wget -P /opt https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar +``` +``` +cd /opt/ +mkdir mysql +tar -xf mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar -C mysql +``` + +#### 3.2 Download x2openEuler to the /opt/mysql directory. + +``` +cd /opt/mysql +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm +``` +#### 3.3 Deploy the tool. + +``` +cd /opt/mysql +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> Note: You need to install the RPM package as the root user. Currently, a network connection is required for downloading and installing the dependencies. +> Note: Install dependencies such as **bzip2-devel** as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` +> Enter the following information about the Redis database in sequential order. +> IP address: 127.0.0.1 +> Port: 6379 +> Database index (0-16): 0 +> Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Note: After x2openEuler is installed using an RPM package, the default resource package (source_centos7.6-openEuler20.03-LTS-SP1.tar.gz) is generated in the **/opt/x2openEuler** directory. +> To support the evaluation of hardware compatibility between CentOS 8.2 and openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run **x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz** to import the package. + +#### 3.4 Scan MySQL. + +``` +x2openEuler scan /opt/mysql/ +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` +## 4. Evaluation Result Analysis + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the calling of other software packages, dynamic libraries, or system interfaces during the running of the software. If the interface compatibility is not 100%, an exception may be triggered when a certain function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + +#### 4.1 Report Analysis + +``` +Open and view the HTML report line by line. In the example below, the report shows that using the CentOS MySQL package on openEuler may cause the following risk: +One to-be-confirmed interface indicates that the MySQL series packages call libaio.so.1.0.1, and that the number of function parameters changes from 4 to 5. When the function is called, an exception may be triggered. + +In addition, the report shows that three dependencies need to be confirmed. Manual confirmation confirms that they are self-closed-loop dependencies of the MySQL series packages. Therefore, the software installation is not affected. +``` + + + + + +#### 4.2 Suggestion + +``` +Suggestion: To avoid function call risks, you are advised to use the MySQL 5.7.21 series software packages that have been compiled and released on the openEuler community. +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mariadb-common-10.3.9-9.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-common-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-server-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-errmsg-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mecab-0.996-2.oe1.x86_64.rpm +``` + +## 5. MySQL Database Installation + +#### 5.1 Installing MySQL and Configuring the Password + +**(1) Install MariaDB and MySQL services.** + +rpm -ivh mysql5-5.7.21-3.oe1.x86_64.rpm mariadb-common-10.3.9-9.oe1.x86_64.rpm mysql5-common-5.7.21-3.oe1.x86_64.rpm mysql5-server-5.7.21-3.oe1.x86_64.rpm mecab-0.996-2.oe1.x86_64.rpm mysql5-errmsg-5.7.21-3.oe1.x86_64.rpm + +**(2) Start MySQL.** + +systemctl start mysqld + +**(3) Query the MySQL status.** + +systemctl status mysqld + +If the service status is running, the MySQL service starts successfully. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 ~# systemctl status mysqld + +● mysqld.service - MySQL 5.7 database server + + Loaded: loaded (/usr/lib/systemd/system/mysqld.service; disabled; vendor preset: disabled) + + Active: active (running) since Thu 2021-09-09 10:23:25 CST; 1 day 4h ago + + Process: 103715 ExecStartPre=/usr/libexec/mysql-check-socket (code=exited, status=0/SUCCESS) + + Process: 103738 ExecStartPre=/usr/libexec/mysql-prepare-db-dir mysqld.service (code=exited, sta> + + Process: 103773 ExecStart=/usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld> + + Process: 103803 ExecStartPost=/usr/libexec/mysql-check-upgrade (code=exited, status=0/SUCCESS) + + Main PID: 103775 (mysqld) + + Tasks: 37 + + Memory: 188.4M + + CGroup: /system.slice/mysqld.service + +​ └─103775 /usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld/mysqld. +``` + +**(4) Log in to the database and change the default password.** + +mysql -uroot -p + +a. By default, there is no password. Press **Enter** to log in. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 2 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +mysql> +``` + +b. Set the password. + +alter user 'user'@'localhost' identified by 'passward'; + +``` +mysql> alter user 'root'@'localhost' identified by '123456'; + +Query OK, 0 rows affected (0.00 sec) + +mysql> flush privileges; + +Query OK, 0 rows affected (0.00 sec) + +mysql> +``` + +> You need to run the **flush privileges** command to make the settings take effect. + +**(5) Verify the password.** + +Log out and then log in to MySQL again to check whether the password is changed successfully. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 3 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + + +mysql> +``` diff --git a/web-ui/docs/en/blog/randy1568/Nginx 1.14.2 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Nginx 1.14.2 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..d0beef22164b5f11c2ea11515ac86ea5973db8a8 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Nginx 1.14.2 Porting Guide.md @@ -0,0 +1,553 @@ +--- +title: Nginx 1.14.2 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Nginx + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Nginx 1.14.2 +--- + +# Nginx 1.14.2 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Nginx Overview +Nginx is a lightweight web server that can act as a reverse proxy or mail (IMAP/POP3) proxy. It provides high concurrency with a low memory footprint, and supports FastCGI, SSL, virtual hosts, URL rewriting, gzip, and extension of many third-party modules. + +Programming language: C + +Brief description: a web server, reverse proxy server, or mail (IMAP/POP3) proxy server +## Recommended Version +Nginx 1.14.2 + >NOTE: + >This document applies to Nginx 1.14.2. However, you can refer to this document when porting other Nginx versions. + + +# Environment Requirements +## Hardware +Table 1 lists the hardware requirements. +Table 1 Hardware requirements + +|Item |Description | +|---------|--------------------------| +|Server |TaiShan 200 server (model 2280)| +|CPU |Kunpeng 920 5250 processor | +|Drive partition |No requirements | + +## Operating Systems +Table 2 lists the OS requirements. +Table 2 OS requirements + +|Item |Version |Command Used to Query the Version | +|------------|---------|---------------------------------| +|openEuler |20.03 LTS SP1 |```cat /etc/openEuler-release``` | +|Kernel |4.19.90 |``` uname -r``` | + +# Configuring the Compilation Environment +## Configuring the Yum Repository +NOTE: +Configure the local source if the server cannot obtain dependencies from the Internet using **yum** commands. + +1. Copy the OS image file **openEuler-20.03-LTS-everything-aarch64-dvd.iso** to the **/root** directory on each server. +2. Mount the image file. Mount the openEuler .iso file in the **/root** directory to the **/mnt** directory. + + ```mount /root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt``` + + NOTE: + This operation takes effect only once and becomes invalid after the OS is restarted. (Optional) To configure automatic image mounting on boot, perform the following steps: + + (1) Open the **fstab** file. + ```vi /etc/fstab``` + + (2) Add the following content to the end of the **fstab** file: + ```/root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt iso9660 loop 0 0``` + + (3) Save and then exit the **fstab** file. +3. Add a local source file. + + (1) Go to the **/etc/yum.repos.d** directory. + + ```cd /etc/yum.repos.d``` + + NOTE: + It is recommended that you move the *.repo file in this directory to any other backup directory. + + (2) Create a **local.repo** file. + + ​ a. Open the **local.repo** file. + ```vi local.repo``` + + ​ b. Add the following content to the **local.repo** file: + + ``` + [local] + name=local.repo + baseurl=file:///mnt + enabled=1 + gpgcheck=0 + ``` + NOTE: + The file path in **baseurl** is the image-mounting path, which corresponds to image file mounting directory **/mnt**. + + ​ c. Save and exit the **local.repo** file. + + ​ d. Make sure the local source is used. + + ``` + yum clean all + yum makecache + yum list + ``` + +## Installing Dependencies +Download and install dependencies. + +``` +yum -y install gcc gcc-c++ make libtool zlib zlib-devel pcre pcre-devel pcre2-devel perl-devel perl-ExtUtils-Embed openssl openssl-devel +``` + +# Obtaining the Source Code +This document uses the source code for compilation and installation. You will also need to obtain the Nginx source code. + +Run the following commands to download the Nginx source code: + +``` cd /home``` + +```wget https://nginx.org/download/nginx-1.14.2.tar.gz --no-check-certificate``` + +NOTE: +You can also download the source code using a local browser and upload it to the **/home** directory on the server. +Download address: [https://nginx.org/download/nginx-1.14.2.tar.gz](https://nginx.org/download/nginx-1.14.2.tar.gz) + +NOTE: +If you need to configure a proxy to access the Internet, perform the following operations. +1. Open the **profile** file. +```vi /etc/profile``` +2. Add the following code, and then save the file and exit. +The user name, password, IP address, and port number of the proxy server must be configured based on the site requirements. +``` +export http_proxy="http://Proxy server user name:password@IP address:port" +export http_proxy=$http_proxy +export no_proxy=127.0.0.1,.huawei.com,localhost,local,.local +``` +3. Ensure the proxy is used. +```source /etc/profile``` +4. View the proxy information in the environment variables. +```env``` +5. Verify whether the proxy function is configured successfully. +```curl www.baidu.com``` + +If Baidu, for example, can be parsed, the configuration is successful. + +# Compiling and Installing Nginx +1. Decompress the Nginx installation package. +```tar -xvf nginx-1.14.2.tar.gz``` + +2. Go to the **nginx-1.14.2** directory. +```cd /home/nginx-1.14.2/``` + +3. Configure Nginx. +```./configure --prefix=/usr/local/nginx --with-http_ssl_module``` +NOTE: +- **--prefix=*PATH*** specifies the Nginx installation directory. The default installation directory is **/usr/local/nginx**. +- **with-http_stub_status_module** does not need to be configured because this module affects the performance of Nginx. +4. Compile and install Nginx. + +```make -j96 && make -j96 install``` + + NOTE: + In the command, -j96 leverages the multi-core feature of the CPUs to accelerate compilation. + You can run the **lscpu** command to query the number of CPU cores. + +5. Check the installation directory. + +```ls /usr/local/nginx``` + + +# Running and Verifying Nginx +## Generating a Certificate +1. Go to the **/usr/local/nginx directory** and generate a key in the directory. +```cd /usr/local/nginx``` +```openssl genrsa -des3 -out server_2048.key 2048``` + +Enter a password twice. The **server_2048.key** file is generated. +``` +[root@localhost nginx]# openssl genrsa -des3 -out server_2048.key 2048 +Generating RSA private key, 2048 bit long modulus (2 primes) +..................................................................................+++++ +................+++++ +e is 65537 (0x010001) +Enter pass phrase for server_2048.key: +Verifying - Enter pass phrase for server_2048.key: +``` + + NOTE: + You can run the following command to use the file without needing a password: + ```openssl rsa -in server_2048.key -out -server_2048.key``` + + ``` + [root@localhost nginx]# openssl rsa -in server_2048.key -out -server_2048.key + Enter pass phrase for server_2048.key + writing RSA key + ``` + +2. Create a certificate signing request (CSR). +``` +openssl req -new -key server_2048.key -out server_2048.csr +``` + +``` +[root@localhost nginx]# openssl req -new -key server_2048.key -out server_2048.csr +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []: +Organization Name (eg, company) [Internet Widgits Pty Ltd]: +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []: +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +Enter the password set in 1. Set **Country Name** to **CN**, for example, and leave other parameters blank. +3. Rewrite the key. +```openssl rsa -in server_2048.key -out server_2048.key``` +``` +[root@localhost nginx]# openssl rsa -in server_2048.key -out server_2048.key +writing RSA key +``` +4. Generate a certificate. +```openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt``` +``` +[root@localhost nginx]# openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt +Signature ok +subject=C = CN, ST = Some-State, O = Internet Widgits Pty Ltd +Getting Private key +``` +Enter the password set in 1. If password-free access is set for the file, you do not need to enter the password. + +## Configuring Functions +### Configuring Nginx HTTPS +1. Open the **nginx.conf** file. +```vi /usr/local/nginx/conf/nginx.conf``` +2. Modify the following configurations in the **nginx.conf** file, save the file, and exit (by pressing **Esc** + **:wq**). + - Set the user permission for running Nginx to **root**. + - Change the listen port number to **20000**. You can also use the default port number. + - Specify the **ssl_certificate** and **ssl_certificate_key** files. + +#### Default content: +``` +#user nobody; +... + # HTTPS server + # + #server { + # listen 443 ssl; + # server_name localhost; + + # ssl_certificate cert.pem; + # ssl_certificate_key cert.key; + + # ssl_session_cache shared:SSL:1m; + # ssl_session_timeout 5m; + + # ssl_ciphers HIGH:!aNULL:!MD5; + # ssl_prefer_server_ciphers on; + + # location / { + # root html; + # index index.html index.htm; + # } + #} +``` + +#### Content after the modification: +``` +user root; + ... + HTTPS server + + server { + listen 20000 ssl; + server_name localhost; + + ssl_certificate /usr/local/nginx/server_2048.crt; + ssl_certificate_key /usr/local/nginx/server_2048.key; + + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location / { + root html; + index index.html index.htm; + } + } + +``` + + +### Configuring Nginx HTTP + +1. Open the **nginx.conf** file. +```vi /usr/local/nginx/conf/nginx.conf``` +2. Modify the following configurations in the **nginx.conf** file, save the file, and exit (by pressing **Esc** + **:wq**). + - Set the user permission for running Nginx to **root**. + - Change the listen port number to **10000**. You can also use the default port number. + +#### Default content: +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 80; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +#### Content after the modification: +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 10000; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +## Running Nginx +1. Start Nginx in either of the following ways: + + - Start the Nginx service. You need to add Nginx to the service list, and then start the service using a command. + + (1) Modify the **/etc/init.d/nginx** file. + + a. Delete the original **nginx** file. + ```rm -rf /etc/init.d/nginx``` + + b. Create a new **nginx** file. + ```vi /etc/init.d/nginx``` + + c. Add the following content to the file, and then save the file and exit. +``` + #!/bin/bash + # chkconfig: 2345 10 90 + # description: nginx + case "$1" in + 'start') + /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf + echo "$0_start"; + ;; + 'stop') + /usr/local/nginx/sbin/nginx -s quit + echo "$0_stop"; + ;; + esac +``` + +(2) Modify the permission on the **/etc/init.d/nginx** file. + +​ ``` chmod 777 /etc/init.d/nginx``` + +​ (3) Add Nginx to the **chkconfig** management list. +​ ``` chkconfig --add /etc/init.d/nginx``` + +​ (4) Enable Nginx to automatically start upon OS startup. +​ ```chkconfig nginx on``` + +​ (5) Start Nginx. +​ ```service nginx start``` + + - Start Nginx by running a script. + +```/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf``` + +2. Check the Nginx process. +```ps -ef | grep nginx``` +``` +[root@localhost nginx]# ps -ef | grep nginx +root 9463 1 0 18:22 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf +root 9464 9463 0 18:22 ? 00:00:00 nginx: worker process +root 9466 1352 0 18:23 ttyAMA0 00:00:00 grep --color=auto nginx +``` + NOTE: + You can run any of the following commands to disable Nginx. Do not run the commands when the service is running. + - Stop the Nginx service. + + ```service nginx stop``` + - Stop Nginx by running a script. + + ```/usr/local/nginx/sbin/nginx -s quit``` + - Stop the Nginx process. + + ```pkill nginx``` + +``` +[root@localhost nginx]# pkill nginx +[root@localhost nginx]# ps -ef | grep nginx +root 9469 1352 0 18:27 ttyAMA0 00:00:00 grep --color=auto nginx +``` + +## Verifying Nginx +1. Check the Nginx monitoring port (10000 for the HTTP monitoring port and 20000 for the HTTPS monitoring port). +```netstat -anp | grep 10000``` +```netstat -anp | grep 20000``` +```netstat -anpt``` + +``` +[root@localhost nginx]# netstat -anp | grep 10000 +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anp | grep 20000 +tcp 0 0 0.0.0.0:20000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anpt +Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 775/sshd: /usr/sbin +``` +2. Query the directory where the HTML files of the Nginx are located. +```ll -h /usr/local/nginx/html/``` +``` +[root@localhost nginx]# ll -h /usr/local/nginx/html/ +total 8.0K +-rw-r--r--. 1 root root 537 Mar 20 16:46 50x.html +-rw-r--r--. 1 root root 612 Mar 20 16:46 index.html +``` +3. Verify the HTTPS function. +Access the Nginx HTML page using cURL. +```curl -k https://127.0.0.1:20000/index.html``` + +``` +[root@localhost nginx]# curl -k https://127.0.0.1:20000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +
nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` +4. Verify the HTTP function. +Access the Nginx HTML page using cURL. +```curl http://127.0.0.1:10000/index.html``` + +``` +[root@localhost nginx]# curl http://127.0.0.1:10000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` + +# Uninstalling Nginx +1. Delete the installation directory. +```rm -rf /usr/local/nginx``` diff --git a/web-ui/docs/en/blog/randy1568/Squid 4.8 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Squid 4.8 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..e5e5343e22e9f34f7bc6ffe69e594c11bbe857ee --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Squid 4.8 Porting Guide.md @@ -0,0 +1,111 @@ +--- +title: Squid 4.8 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Squid + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Squid 4.8 +--- + +# Squid 4.8 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +#### Squid Overview + +Squid cache, or Squid for short, is a popular open-source proxy server and web cache server that runs on Unix systems, and released under GNU General Public License (GPL). Squid caches related requests as the frontend cache server of a web server to improve the speed of the web server, caches the World Wide Web, DNS, and other network searches for a group of people to share network resources, filters traffic to help ensure network security, and provides proxy access for a local area network. It has a long history of development and, with a rich function portfolio, can fit a wide scope of industry scenarios. In addition, it supports HTTP, FTP, and HTTPS, and IPv6 in the test version 3.0. + +Programming language: C++ + +Brief description: web proxy service and web cache server + +#### Recommended Version + +Squid 4.8 + +Note: This document applies to Squid 4.8. You can also refer to this document when porting other Squid versions. + +# Environment Requirements + +#### Hardware + +| Item | Description | +| -------- | ----------------------------- | +| Server | TaiShan 200 server (model 2280)| +| CPU | Kunpeng 920 5250 processor | +| Memory | 8 GB or more | +| Drive partition| No requirements | + +#### Operating System + +| Item | Version | +| --------- | --------------------------------- | +| openEuler | openEuler 20.03 LTS SP1 AArch64 | +| Kernel | 4.19.90-2003.4.0.0036.oe1.aarch64 | + +#### OS Installation + +For details, see [openEuler 20.03 LTS SP1 Installation Guide](https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html). + + +#### Checking the Current System Information + +```bash +[root@localhost ~]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +ID="openEuler" +VERSION_ID="20.03" +PRETTY_NAME="openEuler 20.03 (LTS-SP1)" +ANSI_COLOR="0;31" +``` + +> Note: +> When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". Otherwise, you will need to install multiple software packages manually. + +# Installing Squid + +## Configuring the DNS Resolution File + +```bash +[root@localhost ~]# echo "nameserver 114.114.114.114" >> /etc/resolv.conf +``` + +## Installing Dependencies + +```bash +[root@localhost ~]# yum install gcc libxml2-devel libcap-devel libtool-ltdl-devel perl* -y +``` + +## Compiling Source Code to Install Squid + +### Obtain the Squid 4.8 source package. + +```bash +[root@localhost ~]# cd /home +[root@localhost home]# wget http://www.squid-cache.org/Versions/v4/squid-4.8.tar.gz +``` + +### Install Squid 4.8. + +```bash +[root@localhost home]# tar -xf squid-4.8.tar.gz +[root@localhost home]# cd squid-4.8 +[root@localhost squid-4.8]# ./configure +[root@localhost squid-4.8]# make -j 64 && make install +[root@localhost squid-4.8]# chmod 777 /usr/local/squid/var/logs/ +``` + +# Running and Verifying Squid + +```bash +[root@localhost squid-4.8]# /usr/local/squid/sbin/squid +[root@localhost squid-4.8]# ps -ef |grep squid +root 79023 1 0 19:40 ? 00:00:00 /usr/local/squid/sbin/squid +nobody 79025 79023 0 19:40 ? 00:00:00 (squid-1) --kid squid-1 +nobody 79026 79025 0 19:40 ? 00:00:00 (logfile-daemon) /usr/local/squid/var/logs/access.log +root 79028 1405 0 19:40 pts/0 00:00:00 grep --color=auto squid +``` diff --git a/web-ui/docs/en/blog/randy1568/Tengine 2.2.2 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Tengine 2.2.2 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..ef2735f56c12bd248ac61a72e3d980a8b3f88aea --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Tengine 2.2.2 Porting Guide.md @@ -0,0 +1,264 @@ +--- +title: Tengine 2.2.2 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Tengine + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Tengine 2.2.2. +--- + +# Tengine 2.2.2 Porting Guide + +# Introduction + +#### Overview + +Tengine is a web server project initiated by Taobao. Tengine provides many advanced functions and features based on Nginx to meet the requirements of websites with large access traffic. It aims to build an efficient and secure web platform. + +Programming language: C + +Brief description: lightweight web server + + +#### Recommended Version + +Tengine 2.2.2 + +NOTE: This document applies to Tengine 2.2.2. However, you can refer to this document when porting other Tengine versions. + +# Environment Requirements + +#### Hardware + +| Item | Description | +| -------- | ----------------------------- | +| Server | TaiShan 200 server (model 2280)| +| CPU | Kunpeng 920 5250 processor | +| Drive partition| No requirements | + +#### Operating System + +| Item | Version: | +| --------- | --------------------------------- | +| openEuler | openEuler 20.03 LTS SP1 AArch64 | +| Kernel | 4.19.90-2003.4.0.0036.oe1.aarch64 | + +#### Installing the OS + +For details, see [openEuler 20.03 LTS SP1 Installation Guide](https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html). + +#### Checking the Current System Information + +```bash +[root@localhost ~]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +ID="openEuler" +VERSION_ID="20.03" +PRETTY_NAME="openEuler 20.03 (LTS-SP1)" +ANSI_COLOR="0;31" +``` + +> NOTE: +> When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". Otherwise, lots of software packages need to be installed manually. + +# Installing Tengine + +## Configuring the DNS Resolution File + +```bash +[root@localhost ~]# echo "nameserver 114.114.114.114" >> /etc/resolv.conf +``` + +## Installing Dependencies + +```bash +[root@localhost ~]# yum install gcc gcc-c++ make libtool zlib zlib-devel pcre pcre-devel perl-devel perl-ExtUtils-Embed wget vim -y +``` + +## Obtaining Tengine RPM from the Mirror Site + +> Note: +> The RPM packages in the mirror site are compiled and packaged using open-source code, and then uploaded to the mirror site. + +### Obtaining the RPM Package of Tengine 2.2.2. + +```bash +[root@localhost ~]# cd /home +[root@localhost home]# wget https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +``` + +### Evaluating Compatibility + +#### Downloading the Tool + +``` +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm + +User guide: +https://gitee.com/openeuler/docs/blob/stable2-20.03_LTS_SP1/docs/zh/docs/thirdparty_migration/x2openEuleruseguide.md +``` + +#### Deploying the Tool + +``` +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> NOTE: Install the RPM package as the root user. Currently, the network is required for downloading and installing dependencies. +> NOTE: Install dependencies such as **bzip2-devel** as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> Enter the following information about the Redis database in sequence. +> IP address: 127.0.0.1 +> Port: 6379 +> Database index (0-16): 0 +> Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Note: After x2openEuler is installed using an RPM package, the default resource package (source_centos7.6-openEuler20.03-LTS-SP1.tar.gz) is generated in the **/opt/x2openEuler** directory. +> To support the evaluation of hardware compatibility between CentOS 8.2 and openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run **x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz** to import the package. + +#### Scanning the Software + +``` +x2openEuler scan tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## Viewing Evaluation Results + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the calling of other software packages, dynamic libraries, or system interfaces during the running of the software. If the interface compatibility is not 100%, an exception may be triggered when a certain function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + + + +Result: The report shows that the external interface compatibility is 100%. The dependency package compatibility passes the manual review. The Tengine 2.2.2 software package is compatible with the openEuler 20.03 LTS SP1. + +### Installing Tengine + +```bash +[root@localhost home]# rpm -ivh tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +Verifying... ################################# [100%] +Preparing... ################################# [100%] +Updating / installing... + 1:tengine-1:2.2.2-1.el7_4.ngx ################################# [100%] +``` + + +### Viewing the Installation Directory + +```bash +[root@localhost home]# cd /usr/local/tengine-nginx/ +[root@localhost tengine-nginx]# ls +conf html include logs modules sbin +``` + + +# Running and Verifying Tengine + +## Configuring HTTPS + +### Generating a Certificate + +```bash +[root@localhost tengine-nginx]# openssl genrsa -des3 -out server_2048.key 2048 +Generating RSA private key, 2048 bit long modulus (2 primes) +...................................+++++ +..................+++++ +e is 65537 (0x010001) +Enter pass phrase for server_2048.key: +Verifying - Enter pass phrase for server_2048.key: +[root@localhost tengine-nginx]# openssl rsa -in server_2048.key -out server_2048.key +Enter pass phrase for server_2048.key: +writing RSA key +[root@localhost tengine-nginx]# openssl req -new -key server_2048.key -out server_2048.csr +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []: +Organization Name (eg, company) [Internet Widgits Pty Ltd]: +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []: +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +[root@localhost tengine-nginx]# openssl rsa -in server_2048.key -out server_2048.key +writing RSA key +[root@localhost tengine-nginx]# openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt +Signature ok +subject=C = CN, ST = Some-State, O = Internet Widgits Pty Ltd +Getting Private key +[root@localhost tengine-nginx]# ls +conf html include logs modules sbin server_2048.crt server_2048.csr server_2048.key +``` + +## Configuring Tengine + +```bash +vim /usr/local/tengine-nginx/conf/nginx.conf +``` + +Modify the following contents: + +``` + # HTTPS server + # + #server { + # listen 443 ssl; + # server_name localhost; + + # + # ssl_certificate /usr/local/tengine-nginx/server_2048.crt; + # ssl_certificate_key /usr/local/tengine-nginx/server_2048.key; + + # ssl_session_cache shared:SSL:1m; + # ssl_session_timeout 5m; +``` + + +## Running Tengine + +```bash +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# ps -ef | grep nginx +root 5710 1 0 17:25 ? 00:00:00 nginx: master process /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nobody 5711 5710 0 17:25 ? 00:00:00 nginx: worker process +root 5713 1407 0 17:25 pts/0 00:00:00 grep --color=auto nginx +``` + +Hints: + +- The `http upstream check_shm_size is too small` error is reported. + +```bash +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nginx: [crit] ngx_slab_alloc() failed: no memory +nginx: [emerg] http upstream check_shm_size is too small, you should specify a larger size. +[root@localhost tengine-nginx]# +[root@localhost tengine-nginx]# sed -i "/http {/a\check_shm_size 50m;" /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# ps -ef | grep nginx +root 5710 1 0 17:25 ? 00:00:00 nginx: master process /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nobody 5711 5710 0 17:25 ? 00:00:00 nginx: worker process +root 5713 1407 0 17:25 pts/0 00:00:00 grep --color=auto nginx +``` diff --git a/web-ui/docs/en/blog/randy1568/Tornado 4.2.1 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Tornado 4.2.1 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..2e5a457222b1ae995b3fe617157f93ee16e0967f --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Tornado 4.2.1 Porting Guide.md @@ -0,0 +1,236 @@ +--- +title: Tornado 4.2.1 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Tornado + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Tornado 4.2.1 +--- + +# Tornado 4.2.1 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Tornado Overview + +Tornado is a Python web framework and asynchronous networking library that was originally developed by FriendFeed. It uses non-blocking network I/O to scale to tens of thousands of open connections, making it ideal for long polling, WebSockets, and other apps that require a persistent connection to each user. +This document uses x86_64 VMs and the x2openEuler tool to evaluate the compatibility of Tornado 4.2.1 with openEuler. You can port the software based on the evaluation result. + +Programing languages: C++/Python + +Brief description: A Python web framework and asynchronous networking library + +Open-source license: Apache + +## Recommended Version + +Tornado 4.2.1 + +Note: This document applies to Tornado 4.2.1. However, you can refer to this document when porting other Tornado versions. + +# Environment Requirements + +## OS Requirements + +| OS | Version | +| :-------- | :------------ | +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +## Installing the OS + +When installing the OS for the first time, select **Server with GUI** instead of **Minimal Install**. Otherwise, lots of software packages need to be installed manually. +For details about how to install the openEuler OS, see [https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html](https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html). + +# Compatibility Evaluation + +## Obtaining the Tornado RPM Package + +``` +wget http://mirror.centos.org/centos/7/os/x86_64/Packages/python-tornado-4.2.1-5.el7.x86_64.rpm +``` + +#### Downloading x2openEuler + +``` +Download address: https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/contrib/x2openEuler/ +``` + +#### Deploying the Tool + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +Note: +You need to install the RPM package as the root user. Currently, a network connection is required for downloading and installing dependencies. +Install dependencies such as **bzip2-devel** as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Enter the following information about the Redis database in sequential order. +IP address: 127.0.0.1 +Port: 6379 +Database index (0-16): 0 +Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +Note: After x2openEuler is installed using an RPM package, the default resource package **source_centos7.6-openEuler20.03-LTS-SP1.tar.gz** is generated in the **/opt/x2openEuler** directory. +To support the evaluation of software compatibility between CentOS 8.2 and openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run `x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz` to import the package. Replace the package with the actual one. + +#### Scanning the Software + +``` +x2openEuler scan python-tornado-4.2.1-5.el7.x86_64.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the **/opt/x2openEuler/output** directory. +``` + +## Viewing Evaluation Results + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the calling of other software packages, dynamic libraries, or system interfaces during the running of the software. If the interface compatibility is not 100%, an exception may be triggered when a certain function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + + + +Result: The report shows that the external interface compatibility is 100%, and the dependency compatibility passes the manual review. It is confirmed that the Tornado 4.2.1 software package is compatible with the openEuler 20.03 LTS SP1 system. You can install the software package on openEuler 20.03 LTS SP1 and then verify the software. + +# Installing Tornado + +## Installing Tornado using an RPM package + +The compatibility report shows that the software is compatible with openEuler. Use the downloaded RPM package to install the software. + +``` +[root@localhost ~]# yum install python-tornado-4.2.1-5.el7.x86_64.rpm -y +Last metadata expiration check: 0:11:53 ago on Mon 22 Mar 2021 01:25:06 PM CST. +Dependencies resolved. +================================================================================ + Package Arch Version Repository Size +================================================================================ +Installing: + python-tornado x86_64 4.2.1-5.el7 @commandline 641 k +Installing dependencies: + python2-backports x86_64 1.0-17.oe1 everything 9.2 k + python2-backports-ssl_match_hostname noarch 3.7.0.1-2.oe1 everything 16 k + python2-ipaddress noarch 1.0.23-1.oe1 everything 41 k + python3-pycurl x86_64 7.43.0.3-1.oe1 OS 65 k + +Transaction Summary +================================================================================ +Install 5 Packages + +Total size: 772 k +Total download size: 131 k +Installed size: 4.1 M +Downloading Packages: +(1/4): python2-backports-1.0-17.oe1.x86_64.rpm 53 kB/s | 9.2 kB 00:00 +(2/4): python2-backports-ssl_match_hostname-3.7 63 kB/s | 16 kB 00:00 +(3/4): python2-ipaddress-1.0.23-1.oe1.noarch.rp 126 kB/s | 41 kB 00:00 +(4/4): python3-pycurl-7.43.0.3-1.oe1.x86_64.rpm 113 kB/s | 65 kB 00:00 +-------------------------------------------------------------------------------- +Total 226 kB/s | 131 kB 00:00 +warning: /var/cache/dnf/OS-fcb43ce6e8cef091/packages/python3-pycurl-7.43.0.3-1.oe1.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID b25e7f66: NOKEY +OS 14 kB/s | 2.1 kB 00:00 +Importing GPG key 0xB25E7F66: + Userid : "private OBS (key without passphrase) " + Fingerprint: 12EA 74AC 9DF4 8D46 C69C A0BE D557 065E B25E 7F66 + From : http://repo.openeuler.org/openEuler-20.03-LTS-SP1/OS/x86_64/RPM-GPG-KEY-openEuler +Key imported successfully +Running transaction check +Transaction check succeeded. +Running transaction test +Transaction test succeeded. +Running transaction + Preparing : 1/1 + Installing : python2-ipaddress-1.0.23-1.oe1.noarch 1/5 + Installing : python2-backports-1.0-17.oe1.x86_64 2/5 + Installing : python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.n 3/5 + Installing : python3-pycurl-7.43.0.3-1.oe1.x86_64 4/5 + Installing : python-tornado-4.2.1-5.el7.x86_64 5/5 + Running scriptlet: python-tornado-4.2.1-5.el7.x86_64 5/5 + Verifying : python3-pycurl-7.43.0.3-1.oe1.x86_64 1/5 + Verifying : python2-backports-1.0-17.oe1.x86_64 2/5 + Verifying : python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.n 3/5 + Verifying : python2-ipaddress-1.0.23-1.oe1.noarch 4/5 + Verifying : python-tornado-4.2.1-5.el7.x86_64 5/5 +Installed: + python-tornado-4.2.1-5.el7.x86_64 + python2-backports-1.0-17.oe1.x86_64 + python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.noarch + python2-ipaddress-1.0.23-1.oe1.noarch + python3-pycurl-7.43.0.3-1.oe1.x86_64 + +Complete! +``` + +The installation is successful. + +# Running and Verifying Tornado + +## Checking the Version + +``` +[root@localhost ~]# python +Python 2.7.18 (default, Dec 8 2020, 03:37:36) +[GCC 7.3.0] on linux2 +Type "help", "copyright", "credits" or "license" for more information. +>>> import tornado +>>> tornado.version +'4.2.1' +``` + +## Using Tornado + +Write a handler to respond to a standard HTTP request. The code is obtained from the [Tornado official website](https://www.tornadoweb.org/en/stable/). + +``` +vim hello.py +``` + +Edit the following content: + +``` +import tornado.ioloop +import tornado.web + +class MainHandler(tornado.web.RequestHandler): + def get(self): + self.write("Hello, world") + +def make_app(): + return tornado.web.Application([ + (r"/", MainHandler), + ]) + +if __name__ == "__main__": + app = make_app() + app.listen(8888) + tornado.ioloop.IOLoop.current().start() +``` + +Save the file and exit. Run the following command on the terminal: + +``` +python hello.py +``` + +Open another terminal and run the following command: + +``` +curl http://localhost:8888 +``` + +The following output indicates that Tornado is successfully installed: + +``` +Hello, world +``` diff --git a/web-ui/docs/en/blog/randy1568/Varnish 6.2.0 Porting Guide.md b/web-ui/docs/en/blog/randy1568/Varnish 6.2.0 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..dbc0b0382a4cb4bb45b8be241a900d2be2e696e7 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/Varnish 6.2.0 Porting Guide.md @@ -0,0 +1,236 @@ +--- +title: Varnish 6.2.0 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Varnish + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port Varnish 6.2.0 +--- + +# Varnish 6.2.0 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Varnish Overview +Varnish is a high-performance and open-source reverse proxy server and HTTP accelerator. Compared with traditional cache servers, Varnish offers higher performance, faster speeds, and easier management. Many large-scale websites have adopted Varnish to replace Squid, contributing to the rapid development of Varnish. + +Programming language: C++ + +Brief description: reverse proxy server and HTTP accelerator + +## Recommended Version +Varnish 6.2.0 + +# Environment Requirements +## Hardware Requirements +Table 1 lists the hardware requirements. +Table 1 Hardware requirements + +|Item| Description | +|------|----------------------------| +|Server| TaiShan 200 server (model 2280)| +|CPU| Kunpeng 920 5250 processor| +|Drive partition|No requirements| + +## OS Requirements +Table 2 lists the OS requirements. +Table 2 OS requirements + +|Item| Version| Command Used to Query the Version| +|----------|--------|-------| +|openEuler| 20.03 LTS SP1| `cat /etc/openEuler-release`| +|Kernel| 4.19.90| uname -r| + +# Configuring the Compilation Environment +## Configuring the Yum Repository + Note: + Configure the local source if the server cannot obtain dependencies from the Internet using **yum** commands. +1. Copy the OS image file **openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso** to the **/root** directory on each server. + +2. Mount the image file. + (1) Mount the openEuler image file in the **/root** directory to the **/mnt** directory. + `mount /root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt` + Note: This operation takes effect only once and becomes invalid after the OS restarts. (Optional) To configure automatic image mounting upon boot, perform the following steps: + + a. Open the **fstab** file. + ` vi /etc/fstab` + + b. Add the following content to the end of the **fstab** file: + `/root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt iso9660 loop 0 0` + + c. Save and exit the **fstab** file. + +3. Add a local source file. + (1) Go to the **/etc/yum.repos.d** directory. + `cd /etc/yum.repos.d` + Note: It is recommended that you move the *.repo file in this directory to any other backup directory. + (2) Create a **local.repo** file. + + a. Open the **local.repo** file. + `vi local.repo` + + b. Add the following content to the **local.repo** file: + + ``` + [local] + name=local.repo + baseurl=file:///mnt + enabled=1 + gpgcheck=0 + ``` + Note: + The file path in **baseurl** is the image mounting path, which corresponds to image file mounting directory **/mnt**. + + c. Save and exit the **local.repo** file. + +4. Make the local source take effect. +``` +yum clean all +yum makecache +yum list +``` + +## Installing Dependencies +Download and install dependencies. +1. Install the required dependencies. +``` +yum install -y autoconf automake jemalloc-devel libedit-devel libtool ncurses-devel pcre-devel pkgconfig python-docutils python-sphinx graphviz httpd +``` +2. View the Python3 version. + ``` + [root@localhost]# python3 --version + Python 3.7.9 + ``` + +# Installation +## Installation Mode +This document describes how to install Varnish by compiling source code. + +## Installing Varnish by Compiling Source Code +### Obtaining Source Code +1. Download the Varnish source package using a local browser. +URL: [https://varnish-cache.org/_downloads/varnish-6.2.0.tgz](https://varnish-cache.org/_downloads/varnish-6.2.0.tgz) +2. Copy the source package to the **/home** directory on the server. +Note: If the server is connected to the Internet, run the **wget** command on the server to download the source code. + +### Performing Compilation and Installation +1. Go to the **/home** directory. +`cd /home/` +2. Decompress the source package. +`tar -zxvf varnish-6.2.0.tgz` +3. Go to the **varnish-6.2.0** directory. +`cd /home/varnish-6.2.0/` +4. Perform automatic compilation. +`sh autogen.sh` +5. Check dependencies. +`./configure --prefix=/usr/local/varnish` +``` +[root@localhost varnish-6.2.0]# ./configure --prefix=/usr/local/varnish +checking for gcc... gcc +checking whether the C compiler works... yes +checking for C compiler default output file name... a.out +checking for suffix of executables... +checking whether we are cross compiling... no +checking for suffix of files... o +checking whether we are using the GNU C compiler... yes +checking whether gcc accepts -g... yes +``` +Note: **--prefix=PATH** specifies the Varnish installation directory. + +6. Compile and install Varnish. +`make && make install` +``` +[root@localhost varnish-6.2.0]# make && make install +make all-recursive +make[1]: Entering directory '/home/varnish-6.2.0' +Making all in include +make[2]: Entering directory '/home/varnish-6.2.0/include' +make all-am +make[3]: Entering directory '/home/varnish-6.2.0/include' +``` + +### Configuration Files +1. Create a folder in the Varnish installation path for storing configuration files. +`cd /usr/local/varnish && mkdir config` +2. Copy the configuration files to the **config** directory. +`cp /usr/local/varnish/share/doc/varnish/example.vcl /usr/local/varnish/config/default.vcl` + +# Running and Verifying Varnish +The following describes how to run and verify Varnish when the local host is used as a backend object. +1. Modify the backend IP address and port number for the reverse proxy test. +If the cache policy needs to be configured, obtain the latest Varnish Book from the official website. In this example, the local host is configured as the backend object. The default port number is 80. + + a. Open the configuration file. + `vi /usr/local/varnish/config/default.vcl` + + b. Modify the file as follows, and save the change and exit. + ``` + vcl 4.0; + # Default backend definition. Set this to point to your content server. + backend default { + .host = "127.0.0.1"; + .port = "80"; + } + + sub vcl_recv { + } + sub vcl_backend_response { + } + sub vcl_deliver { + } + ``` + +2. Start the HTTP service of the backend object. +`systemctl start httpd` +3. Start Varnish. +`/usr/local/varnish/sbin/varnishd -a :12345 -T 127.0.0.1:6082 -s malloc,10GB -f /usr/local/varnish/config/default.vcl` +``` +[root@localhost ~]# /usr/local/varnish/sbin/varnishd -a :12345 -T 127.0.0.1:6082 -s malloc,10GB -f /usr/local/varnish/config/default.vcl +Debug: Version: varnish-6.2.0 revision b14a3d38dbe918ad50d3838b11aa596f42179b54 +Debug: Platform: Linux,4.19.90-2012.4.0.0053.oe1.aarch64,aarch64,-jnone,-smalloc,-sdefault,-hcritbit +Debug: Child (30634) Started +``` +The following describes the Varnish startup parameters. +Parameter description + + -a address:port: IP address and port number for Varnish to monitor the HTTP service. The IP address is the IP address of the local host by default. + + -T address:port: IP address and port number for Varnish to manage Telnet. + + -s: specifies the cache storage mode for Varnish. In this example, malloc is used. A total of 10 GB memory space is allocated. + + -f: specifies the location of the Varnish configuration file. + +4. Access the local host to view the test page on the backend. + `curl http://localhost:80` + + ``` + ... + + This page is used to test the proper operation of the Apache HTTP server after it has been installed. If you can read this page, it means that the Apache HTTP server installed at this site is working properly. + + + + + +

If you are a member of the general public:

+ + The fact that you are seeing this page indicates that the website you just visited is either experiencing problems, or is undergoing routine maintenance. + + If you would like to let the administrators of this website know that you've seen this page instead of the page you expected, you should send them e-mail. In general, mail sent to the name "webmaster" and directed to the website's domain should reach the appropriate person. + + For example, if you experienced problems while visiting www.example.com, you should send e-mail to "webmaster@example.com". + + For information on openEuler Linux, please visit the openEuler, Inc. website. The ation for openEuler Linux is available on the openEuler, Inc. website. + + ... + ``` + Note: + - To stop Varnish, run the following command (do not run this command during service running): + `pkill varnish` + - To uninstall Varnish and query the result: + Uninstall Varnish that is installed by compiling source code. + `rm -rf /usr/local/varnish/` diff --git a/web-ui/docs/en/blog/randy1568/enca 1.19 Porting Guide.md b/web-ui/docs/en/blog/randy1568/enca 1.19 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..7f00731cbf8765b955a0af17f48a3fc0de55c0e1 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/enca 1.19 Porting Guide.md @@ -0,0 +1,134 @@ +--- +title: enca 1.19 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - enca + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port enca 1.19 +--- + +# enca 1.19 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Overview + +enca is a practical code conversion tool. In this case, x86_64 VMs and the evaluation tool x2openEuler are used to evaluate the compatibility of enca 1.19 to be ported to the openEuler OS, and complete the porting based on the evaluation result. + +Programming language: C + +## Recommended Version + +The recommended version is enca 1.19.1. + +NOTE: +This document applies to enca 1.19.1. You can also refer to this document when porting other enca versions. + +# Environment Requirements + +## OS Requirements +| OS| Version | +|---|---| +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +## Installing the OS + +When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". Otherwise, lots of software packages need to be installed manually. +For details about how to install the openEuler OS, see [https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html](https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html). + +# Compatibility Evaluation + +Tool: x2openEuler +Environment: CentOS 7.6 + +#### Downloading x2openEuler + +``` +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/contrib/x2openEuler/x86_64/Packages/ + +User guide: +https://gitee.com/openeuler/docs/blob/stable2-20.03_LTS_SP1/docs/en/docs/thirdparty_migration/x2openEuleruserguide.md +``` + +#### Deploying x2openEuler + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +Note: +You need to install the RPM package as the root user. Currently, the network is required for downloading and installing dependencies. +Install dependencies such as bzip2-devel as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Enter the following information about the Redis database in sequence. +IP address: 127.0.0.1 +Port: 6379 +Database index (0-16): 0 +Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +Note: After x2openEuler is installed using an RPM package, the default resource package (**source_centos7.6-openEuler20.03-LTS-SP1.tar.gz**) is generated in the **/opt/x2openEuler** directory. +To support the evaluation of hardware compatibility from CentOS 8.2 to openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,** run `x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz` to import the package. Replace the package with the actual one. + +#### Scanning enca + +``` +wget http://rpmfind.net/linux/epel/7/x86_64/Packages/e/enca-1.19-1.el7.x86_64.rpm +x2openEuler scan enca-1.19-1.el7.x86_64.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## Viewing Evaluation Results + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the call of other software packages, dynamic libraries, or system interfaces during the software running. If the interface compatibility is not 100%, an exception may be triggered when some function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + + + +Result: The report shows that the external interface compatibility is 100%. The dependency package compatibility passes the manual review. enca 1.19 is compatible with the openEuler 20.03 LTS SP1. + +# Installing enca RPM + +1. Download the RPM package: [http://rpmfind.net/linux/epel/7/x86_64/Packages/e/enca-1.19-1.el7.x86_64.rpm](http://rpmfind.net/linux/epel/7/x86_64/Packages/e/enca-1.19-1.el7.x86_64.rpm). +2. Upload the package to the openEuler server. + > Note: + > If the server is connected to the Internet, you can run the **wget** command on the server to download the source package. + +3. Install enca. +```shell + rpm -ivh enca-1.19-1.el7.x86_64.rpm +``` + +# Running and Verifying enca + +1. Check whether enca has been installed. +```shell + enca --version +``` +2. enca was successfully installed if the following information is displayed: +```shell + enca 1.19 + + Features: -librecode-interface +iconv-interface +external-converter +language-detection +locale-alias+ + target-charset-auto +ENCAOPT + + Copyright (C) 2000-2005 David Necas (Yeti) (<yeti@physics.muni.cz>), + 2005 Zuxy Meng (<zuxy.meng@gmail.com>). + + Enca is free software; it can be copied and/or modified under the terms of + version 2 of GNU General Public License, run `enca --license' to see the full + license text. There is NO WARRANTY; not even for MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. +``` diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-1.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-1.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-10.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-10.png new file mode 100644 index 0000000000000000000000000000000000000000..36a9f77639b1141cb7e1fdb460b6261caa751e08 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-10.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-11.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-11.png new file mode 100644 index 0000000000000000000000000000000000000000..70466f513236b842a5528197751f0e286ea75cfa Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-11.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-12.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-12.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-12.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-13.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-13.png new file mode 100644 index 0000000000000000000000000000000000000000..02873d6b02031ccfe7762298e1ad5b8b7a81a16e Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-13.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-2.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ea89b334d288854dfc4403570f7892dd7749f1a3 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-2.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-3.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9518a15004dec9da4856bcc6c6e2bb22942941e1 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-3.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-4.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-4.png new file mode 100644 index 0000000000000000000000000000000000000000..429f02e0e97e1c7d556fd80f11b4a9cf1a5a5c3e Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-4.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-5.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-5.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fe8ad56cb34ab2788458dd77e555af08ef315e Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-5.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-6.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-6.png new file mode 100644 index 0000000000000000000000000000000000000000..9b1b2903df4caec60872d48556e4914446cd4a50 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-6.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-7.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-7.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3dead21a92ced874dadbcd904e387a30882b86 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-7.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-8.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-8.png new file mode 100644 index 0000000000000000000000000000000000000000..f43d97c66f49b4dfd37c12dc13a19d9efd7151d0 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-8.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Dubbo-9.png b/web-ui/docs/en/blog/randy1568/image/Dubbo-9.png new file mode 100644 index 0000000000000000000000000000000000000000..188b4cb375fc3cecef034a70c61613f7cc429b38 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Dubbo-9.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/HAProxy-1.jpeg b/web-ui/docs/en/blog/randy1568/image/HAProxy-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/HAProxy-1.jpeg differ diff --git a/web-ui/docs/en/blog/randy1568/image/HAProxy-2.png b/web-ui/docs/en/blog/randy1568/image/HAProxy-2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd0dc9e9f6e82c49274a7cba090fe3bf11e0e5cd Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/HAProxy-2.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/HAProxy-3.png b/web-ui/docs/en/blog/randy1568/image/HAProxy-3.png new file mode 100644 index 0000000000000000000000000000000000000000..41ec8fc71a9ee5c151bcdd08ecb5adf9256fb90d Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/HAProxy-3.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Memcached-1.jpeg b/web-ui/docs/en/blog/randy1568/image/Memcached-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Memcached-1.jpeg differ diff --git a/web-ui/docs/en/blog/randy1568/image/Memcached-2.jpeg b/web-ui/docs/en/blog/randy1568/image/Memcached-2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7ada68ee64f6cd59bbb77ca65990f0be66277060 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Memcached-2.jpeg differ diff --git a/web-ui/docs/en/blog/randy1568/image/Mysql-3.png b/web-ui/docs/en/blog/randy1568/image/Mysql-3.png new file mode 100644 index 0000000000000000000000000000000000000000..8a2ddfc7dba89f8bc9c0d5c54828d38a1a663af8 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Mysql-3.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/Mysql-4.png b/web-ui/docs/en/blog/randy1568/image/Mysql-4.png new file mode 100644 index 0000000000000000000000000000000000000000..4a92cded1ed5a4e3884271e014389d4b24f73221 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/Mysql-4.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/enca-1.png b/web-ui/docs/en/blog/randy1568/image/enca-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6816b39778d01c1255f53d2b597386e9f7660062 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/enca-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/flask.png b/web-ui/docs/en/blog/randy1568/image/flask.png new file mode 100644 index 0000000000000000000000000000000000000000..ea5e04c8689710fd3323362ad96db46be75f881f Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/flask.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/hardware-1.png b/web-ui/docs/en/blog/randy1568/image/hardware-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1422647a6f4b26bf47b28bb513e3e041a0a5219a Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/hardware-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/hardware-5.png b/web-ui/docs/en/blog/randy1568/image/hardware-5.png new file mode 100644 index 0000000000000000000000000000000000000000..c67151a571663a93b681750c1d17d1d90ec70910 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/hardware-5.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/iok-1.png b/web-ui/docs/en/blog/randy1568/image/iok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..23edd3b09d0c2eb05c0b56690c44b28d32914989 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/iok-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/lok-1.png b/web-ui/docs/en/blog/randy1568/image/lok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..19b4f36ba04958bf7bd113adeb02fac4b3e42976 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/lok-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/lok-2.png b/web-ui/docs/en/blog/randy1568/image/lok-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6acd3eb0204d2d2f06a6394c97cb622aecd81a26 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/lok-2.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/tengine-1.png b/web-ui/docs/en/blog/randy1568/image/tengine-1.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf3d66d7747dab6a29d00393a20d90d1b2eeb49 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/tengine-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/image/tornado-1.png b/web-ui/docs/en/blog/randy1568/image/tornado-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f4502460b411ccc4b28c8ef450c53b175762d78 Binary files /dev/null and b/web-ui/docs/en/blog/randy1568/image/tornado-1.png differ diff --git a/web-ui/docs/en/blog/randy1568/iok-2.1.3-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/iok-2.1.3-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..4e7309989d7a52d2e65f746313ed0d78cffa4ddb --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/iok-2.1.3-Porting-Guide.md @@ -0,0 +1,146 @@ +--- +title: iok 2.1.3 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - lok + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port iok 2.1.3 +--- + +# iok 2.1.3 Porting Guide (openEuler 20.03 LTS SP1) + +## Introduction + +iok is a keyboard mapping application that displays Indian languages. + +### Selected Version + +2.1.3 + +### Installation Guide + +https://docs.openeuler.org/en/docs/20.03_LTS_SP1/docs/Installation/Installation.html + +### Checking OS Version + +```shell +cat /etc/os-release +``` + + + +### Checking Compatibility + +#### Download iok-2.1.3 SRPM. + +``` +wget http://mirror.centos.org/centos/7/os/x86_64/Packages/iok-2.1.3-6.el7.x86_64.rpm +``` + +#### Download x2openEuler. + +``` +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm + +User guide: +https://gitee.com/openeuler/docs/blob/stable2-20.03_LTS_SP1/docs/en/docs/thirdparty_migration/x2openEuleruseguide.md +``` + +#### Deploy x2openEuler. + +``` +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +Note: You need to install the RPM package as the root user. Currently, a network connection is required for downloading and installing dependencies. +Install dependencies such as **bzip2-devel** as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Enter the following information about the Redis database in sequential order. +IP address: 127.0.0.1 +Port: 6379 +Database index (0-16): 0 +Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +Note: After x2openEuler is installed using an RPM package, the default resource package (source_centos7.6-openEuler20.03-LTS-SP1.tar.gz) is generated in the **/opt/x2openEuler** directory. +To support the evaluation of hardware compatibility between CentOS 8.2 and openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run **x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz** to import the package. + +#### Scan the software. + +``` +x2openEuler scan iok-2.1.3-6.el7.x86_64.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## Viewing Evaluation Results + +The software compatibility evaluation report consists of three parts: dependency compatibility, C/C++ interface compatibility, and Java interface compatibility. Dependency compatibility reflects the required direct dependencies during software installation. If the dependency compatibility is not 100%, the installation fails. Interface compatibility reflects the calling of other software packages, dynamic libraries, or system interfaces during the running of the software. If the interface compatibility is not 100%, an exception may be triggered when a certain function is called. Manual confirmation is recommended for some results. The priority of software packages is as follows: packages that have been ported to openEuler > manually recompiled packages for openEuler > packages for CentOS. + + + + + +Result: According to the dependency report, the unique3 dependency issue needs to be resolved before porting iok to openEuler 20.03 LTS SP1. + +## Including Dependencies + +- Create an issue from the [openEuler/oec-application repository](https://gitee.com/openeuler/oec-application). + + + +- Track the issue until the missing dependency package is included in the YUM repository of openEuler 20.03 LTS SP1. + +## Build Process + +After the missing dependency package is included, you can perform the following operations: + +- Obtain the CentOS 7.6.1810 SRPM package for iok. +- Build the binary package on openEuler 20.03 LTS SP1. + +###Build the binary package. + +```shell +yum install -y rpm-build +``` + +- Install the SRPM package over the network. + +```shell +rpm -i https://vault.centos.org/7.6.1810/os/Source/SPackages/iok-2.1.3-6.el7.src.rpm +``` + +- Install the dependency. + +```shell +yum-builddep -y ~/rpmbuild/SPECS/iok.spec +``` + +- Build the binary package. + +```shell +rpmbuild -bb ~/rpmbuild/SPECS/iok.spec +``` + +- Install the binary package. + +``` +rpm -i ~/rpmbuild/RPMS/x86_64/*.rpm +``` + +- View the binary file. + +``` +which iok +``` diff --git a/web-ui/docs/en/blog/randy1568/lighttpd 1.4.53 Porting Guide.md b/web-ui/docs/en/blog/randy1568/lighttpd 1.4.53 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..95d7898368ede36599ce790388e32ccd4ceb5c2b --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/lighttpd 1.4.53 Porting Guide.md @@ -0,0 +1,211 @@ +--- +title: lighttpd 1.4.53 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Lighttpd + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port lighttpd 1.4.53 +--- + +# lighttpd 1.4.53 Porting Guide (openEuler 20.03 LTS SP1) + +# Introduction + +## Overview + +lighttpd is an excellent open source lightweight software, whose fundamental purpose is to provide a secure, fast, compatible, and flexible web server environment for high-performance websites. It has a low memory footprint, is loaded with a small CPU, and delivers good performance and abundant modules. + +Programming language: C + +Brief description: web server + +## Recommended Version + +lighttpd 1.4.53 + +# Environmental Requirements + +## Hardware + +The following table lists the hardware requirements. + +|Item|Description| +|-----|-----| +|Server|TaiShan 200 server (model 2280)| +|CPU|Kunpeng 920 5250 processor| +|Drive partition|No requirements| + +## Operating Systems + +The following table lists the requirements for the operating system. + +Item| Version +----- | ----- +openEuler | 20.03 SP1 AArch64 +Kernel | 4.19 + +Note: +When installing the OS for the first time, select "Server with GUI" instead of "Minimal Install". This will bypass the need to manually install lots of software packages. + +# Configuring the Compilation Environment + +1. Install dependencies. + + yum -y install gcc gcc-c++ glib2-devel pcre-devel bzip2-devel zlib-devel gamin-devel + +2. Obtain the source code. + + URL: https://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.53.tar.gz + +## Preparing the Installation Package + +``` +cp lighttpd-1.4.53.tar.gz $HOME && cd $HOME +tar xzvf lighttpd-1.4.53.tar.gz +``` + +## Compiling and Installing lighttpd + +``` +cd lighttpd-1.4.53 +./configure --prefix=/usr/local/lighttpd --with-fam +make -j60 && make install +``` + +Note: + + **--prefix=PATH** specifies the lighttpd installation directory. + **--with-fam** reduces the number of times that **stat()** is called. + + +# Configuring Parameters + +## Creating a Software Directory + +``` +cd /usr/local/lighttpd/ +mkdir log webpages cache config +``` + +## Copying the Configuration File or Directory + +``` +cp $HOME/lighttpd-1.4.53/doc/config/lighttpd.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/modules.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/conf.d /usr/local/lighttpd/config/ -r +``` + +Note: + + When lighttpd is installed, only three folders **lib**, **sbin**, and **share** exist in the installation directory. Other files need to be copied and created. + +## Modifying the lighttpd.conf File + +``` +vi /usr/local/lighttpd/config/lighttpd.conf + +``` + +Modify lines 16 to 20 as follows: + +``` +var.log_root = "/usr/local/lighttpd/log" +var.server_root = "/usr/local/lighttpd" +var.state_dir = "/usr/local/lighttpd" +var.home_dir = "/usr/local/lighttpd" +var.conf_dir = "/usr/local/lighttpd/config" +``` + +Modify line 61 as follows: + +``` +var.cache_dir = "/usr/local/lighttpd/cache" +``` + +Add the following comment to line 93: + +``` +#server.use-ipv6 = "enable" +``` + +Modify lines 104 to 105 as follows: (This item is about the operation permission. You are not advised to use the **root** user.) + +``` +server.username = "lighttpd1" +server.groupname = "lighttpd" +``` + +Modify line 115 (path for storing the access page) as follows: + +``` +server.document-root = server_root + "webpages" +``` + +Modify line 246 (cache mode) as follows: (The default value is **simple**. According to the official explanation, **fam** is better than **simple**.) + +``` +server.stat-cache-engine = "fam" +``` + +Add the following content to line 182. (This configuration item is used to configure the multi-process mode. The lighttpd process is a single process by default. You can change the value based on the site requirements.) + +``` +server.max-worker = 4 +``` + +## Creating a User Group + +``` +groupadd lighttpd +useradd -g lighttpd lighttpd1 +``` + +## Modifying Permissions + +``` +chown lighttpd1 /usr/local/lighttpd/log +``` + +## Adding a Test Page + + cd /usr/local/lighttpd/webpages + vi index.html + +``` + <html> + <head> + <title>lighttpd test</title> + </head> + <body> + <p>this is a testing</p> + </body> + </html> +``` + +# Testing the Service + +Start lighttpd. + +``` +/usr/local/lighttpd/sbin/lighttpd -f /usr/local/lighttpd/config/lighttpd.conf +``` + +Check the program process. + + +``` +ps -ef |grep lighttpd +``` + +Stop lighttpd. + +``` +pkill lighttpd +``` + +Test web page: + + http://{{ server_ip }}:80/index.html diff --git a/web-ui/docs/en/blog/randy1568/pkgship 2.1.0 Porting Guide.md b/web-ui/docs/en/blog/randy1568/pkgship 2.1.0 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..90e1d4dff389597a4d963dc03e2866307f59e651 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/pkgship 2.1.0 Porting Guide.md @@ -0,0 +1,203 @@ +--- +title: pkgship 2.1.0 Porting Guide (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - pkgship + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you need to port pkgship 2.1.0 +--- + +# pkgship 2.1.0 Porting Guide (openEuler 20.03 LTS SP1) + +## Introduction + +pkgship is a query tool used to manage the dependency of OS software packages and provide a complete dependency graph. It provides functions such as software package dependency query, lifecycle management, and patch query. + +### Selected Version + +2.1.0 + +## OS Information + +```shell +cat /etc/os-release +``` +## Compatibility Check + +Use x2openEuler to analyze the pkgship-2.1.0 RPM package in the tool directory. + +```shell +x2openEuler scan pkgship-2.1.0-7.oe1.noarch.rpm +``` + +Based on the check report, dependency issues caused by different Python versions need to be resolved before porting pkgship to openEuler 20.03 LTS SP1. + +# Installation from the Source Package + +## Installation Procedure + +- Install dependencies. +- Configure the Yum repository. +- Obtain the pkgship source package **pkgship-2.1.0.tar.gz**. +- Decompress the source package. +- Modify the source code to ensure pkgship is compatible with Python 3.7. +- Use the installation script **setup.py** to install pkgship. +- The installation is successful. + +## Installing pkgship + +- Install dependencies. + +```shell +[root@master ~]# yum install -y libffi-devel + + +[root@master ~]# vim requirements.txt + +prettytable==0.7.2 +Flask_RESTful==0.3.8 +Flask_Session==0.3.1 +Flask_Script==2.0.6 +Flask_Limiter==1.4 +Flask==1.1.2 +marshmallow==3.5.1 +PyYAML==5.3.1 +gevent==20.12.1 +requests==2.21.0 +uwsgi==2.0.18 +elasticsearch==7.10.1 +redis==3.5.3 +retrying==1.3.3 + +[root@master ~]# pip3 install -r requirements.txt +``` + + +- Configure the Yum repository. + +```shell +[root@master ~]# cd /etc/yum.repos.d/ +[root@master yum.repos.d]# vim openEuler.repo +[openeuler] +name=openEuler-21.03 +baseurl=http://119.3.219.20:82/openEuler:/21.03/standard_aarch64/ +enabled=1 +gpgcheck=0 + + +[fedora] +name=fedora +baseurl=https://mirrors.huaweicloud.com/fedora/releases/30/Everything/aarch64/os/ +enabled=0 +gpgcheck=0 + +[elasticsearch] +name=Elasticsearch repository for 7.x packages +baseurl=https://artifacts.elastic.co/packages/7.x/yum +gpgcheck=1 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md + +``` + +- Obtain the source package. + +> Obtain the **pkgship-2.1.0.tar.gz** package from https://gitee.com/src-openeuler/pkgship?_from=gitee_search. + +- Decompress the source package. + +```shell +tar -xzvf pkgship-2.1.0.tar.gz +``` + +- Modify the source code files. + +> In the generated source code directory, modify the following files in the source code path: +```shell +./packageship/application/query/pkg.py +./packageship/application/query/depend.py +``` + +Set the value of **monkey.patch_all()** in the 19th line of the two files to **monkey.patch_all(thread=False,ssl=False)**. + +In the **packageship** directory of the source code directory, create a **version.yaml** file and then add the following content to the file: + +```shell +Version: 2.1.0 +Release: 7.oe1 +``` +This operation avoids the following error caused by lack of the file during the installation. + +```shell +installing package data to build/bdist.linux-x86_64/egg +running install_data +creating /etc/pkgship +copying packageship/package.ini -> /etc/pkgship/ +copying conf.yaml -> /etc/pkgship/ +copying packageship/auto_install_pkgship_requires.sh -> /etc/pkgship/ +copying packageship/uwsgi_logrotate.sh -> /etc/pkgship/ +copying packageship/pkgshipd -> /usr/bin +copying packageship/pkgship -> /usr/bin +copying packageship/pkgship.service -> /lib/systemd/system/ +copying packageship/application/common/rsp/mapping.xml -> build/bdist.linux-x86_64/egg/packageship/application/common/rsp +error: can't copy 'packageship/version.yaml': doesn't exist or not a regular file +``` + + +- Install pkgship. + +In the main directory of pkgship, run the **setup.py** script to install pkgship. + +```shell +[root@localhost ~]# python3 --version +Python 3.7.9 +[root@localhost ~]# python3 setup.py install +``` + + +- The following content indicates that the installation is successful. + +```shell +Processing packageship-2.1.0-py3.7.egg +creating /usr/local/lib/python3.7/site-packages/packageship-2.1.0-py3.7.egg +Extracting packageship-2.1.0-py3.7.egg to /usr/local/lib/python3.7/site-packages +Adding packageship 2.1.0 to easy-install.pth file + +Installed /usr/local/lib/python3.7/site-packages/packageship-2.1.0-py3.7.egg +Processing dependencies for packageship==2.1.0 +Finished processing dependencies for packageship==2.1.0 + +[root@localhost pkgship-2.1.0]# pip3 list | grep packageship +packageship 2.1.0 +[root@localhost pkgship-2.1.0]# pkgship +usage: pkgship [-h] [-v] [-remote] + {init,list,builddep,installdep,selfdepend,bedepend,pkginfo,dbs} + ... + +package related dependency management + +positional arguments: + {init,list,builddep,installdep,selfdepend,bedepend,pkginfo,dbs} + package related dependency management + init initialization of the database + list get all package data + builddep query the compilation dependencies of the specified + package + installdep query the installation dependencies of the specified + package + selfdepend query the self-compiled dependencies of the specified + package + bedepend dependency query for the specified package + pkginfo query the information of a single package + dbs Get all data bases + +optional arguments: + -h, --help show this help message and exit + -v Get version information + -remote The address of the remote service +``` diff --git a/web-ui/docs/en/blog/randy1568/x86-Hardware-Compatibility-Assessment-and-Porting-Guide.md b/web-ui/docs/en/blog/randy1568/x86-Hardware-Compatibility-Assessment-and-Porting-Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..b93bfdf44eaa0089ba6ecf535247ad90d07d9373 --- /dev/null +++ b/web-ui/docs/en/blog/randy1568/x86-Hardware-Compatibility-Assessment-and-Porting-Guide.md @@ -0,0 +1,119 @@ +--- +title: x86 Hardware Compatibility Assessment and Porting Guide (openEuler 20.03 LTS SP1) +date: 2022-01-07 +tags: + - x86 hardware compatibility evaluation + - CX5 & 3108 RAID + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2022-01 +author: randy1568 +summary: Just about everything you need to evaluate the compatibility of x86 hardware (Hi1822 NIC & 3108 RAID controller card) +--- + +# x86 Hardware Compatibility Assessment and Porting Guide (openEuler 20.03 LTS SP1) + + +# Environment + +## Hardware + +The following table lists the hardware. + +Hardware| Description +----- | ----- +Server| 2288H V5 +CPU | Intel(R) Xeon(R) Gold 6266C CPU @ 3.00 GHz +NIC| Mellanox ConnectX-5 +RAID controller card| Huawei LSI SAS3108 + +## Operating System + +The following table lists the OSs. + +OS| Description +----- | ----- +CentOS Linux| 7.9.2009 (Core) +Kernel | 3.10.0 x86_64 + +Check the current system information. +cat /etc/os-release + + + +# Running x2openEuler and Evaluating Hardware Compatibility + +The openEuler community provides [x2openEuler](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/), which can be used to evaluate hardware, software, and system configuration. In terms of hardware, the compatibility between openEuler and boards that run properly on CentOS is evaluated. The tool collects board information and generates reports in HTML format, displaying hardware compatibility visually. + +## Downloading x2openEuler + +``` +cd /opt/ +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm +``` + +## Deploying x2openEuler + +``` +cd /opt/ +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> Note: You need to install the RPM package as the root user. Currently, a network connection is required for downloading and installing dependencies. +> Note: Install dependencies such as **bzip2-devel** as prompted. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> Enter the following information about the Redis database in sequential order. +> IP address: 127.0.0.1 +> Port: 6379 +> Database index (0-16): 0 +> Password (encrypted by the tool): If the Redis password is not set or is empty, press **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Note: After x2openEuler is installed using an RPM package, the default resource package (source_centos7.6-openEuler20.03-LTS-SP1.tar.gz) is generated in the **/opt/x2openEuler** directory. +> To support the evaluation of hardware compatibility between CentOS 8.2 and openEuler 20.03 LTS SP1, you need to obtain and import the corresponding static resource package. For example, if the resource package is **source_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, run **x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz** to import the package. + +## Analyzing Hardware Compatibility + + x2openEuler hardware-analyse + ‏The command output is as follows: + 2021-11-30 09:41:20,865 - INFO - Log save directory: /var/log/x2openEuler + 2021-11-30 09:41:20,887 - INFO - x2openEuler hardware-analyse + 2021-11-30 09:41:20,888 INFO manager/get_param_config/179: Parameter configuration file loaded. + 2021-11-30 09:41:20,905 INFO manager/get_regex_config/218: Regex pattern compiled. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/233: All builtin parsers loaded. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/236: All custom parsers loaded. + 2021-11-30 09:41:21,254 INFO time_utils/wrapper/21: 0.35s taken for running function [get_data] + 2021-11-30 09:41:21,269 WARNING list/parse_content/47: no data in ls_dev + 2021-11-30 09:41:21,377 INFO time_utils/wrapper/21: 0.12s taken for running function [get_parsed_content] + 2021-11-30 09:41:21,377 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_startup_param.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/syscall_interface.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/path.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/port.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/device_interface.json. + 2021-11-30 09:41:21,380 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/linux_command.json. + 2021-11-30 09:41:21,387 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/hardware_configure.json. + 2021-11-30 09:41:21,396 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/proc.json. + 2021-11-30 09:41:21,404 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_configure.json. + 2021-11-30 09:41:21,408 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_service.json. + 2021-11-30 09:41:21,412 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_configure.json. + 2021-11-30 09:41:21,426 - INFO - Producing report... + 2021-11-30 09:41:21,427 - INFO - Generate Success! The results are saved: /opt/x2openEuler/output/hw_compat_report-20211130094121.html + In the command output, /opt/x2openEuler/output/hw_compat_report-20211130094121.html is the evaluation report. + +# Analyzing Hardware Evaluation Results + +The hardware compatibility evaluation report directly shows whether each board and the device as a whole are compatible with openEuler. If any item is not in the compatibility list, adaptation is required. + + + + +The four tuples (VID, DID, SVID, and SSID) uniquely identify a board. As shown in the preceding figure, each board can be queried in the southbound compatibility list. Therefore, in this example the hardware server can be ported from CentOS to openEuler 20.03 LTS SP1. + diff --git a/web-ui/docs/en/blog/rosinL/2022-01-30-Ceph Community News (2021-12-13 to 2022-01-16).md b/web-ui/docs/en/blog/rosinL/2022-01-30-Ceph Community News (2021-12-13 to 2022-01-16).md new file mode 100644 index 0000000000000000000000000000000000000000..c22eac66ea5ff1b7e192f24b629bb64d1971009f --- /dev/null +++ b/web-ui/docs/en/blog/rosinL/2022-01-30-Ceph Community News (2021-12-13 to 2022-01-16).md @@ -0,0 +1,48 @@ +--- +title: Ceph Community News (2021-12-13 to 2022-01-16) +date: 2022-01-30 +tags: + - Ceph + - News + - Pacific +sig: ceph-sig +archives: 2022-1 +author: rosinL +summary: Ceph Community News +--- +# Ceph Community News (2021-12-13 to 2022-01-16) +## Quincy Version Under Feature Freeze and to Be Released in March 2022 +The Quincy version has been under feature freeze since January 15, 2022, and is currently in the testing phase. In addition to regular tests, more scaling tests are performed this time. The test scale reaches 1000+ OSDs. +## Recently Merged PRs +- common: Optimized the PriorityCache. The cache is organized by time and priorities are much finer-grained. However, performance tests are showing little gain. [pr#43299](https://github.com/ceph/ceph/pull/43299) +- bluestore: Optimized the writing process. Zeros from the bufferlist are checked and skipped without writing. A new counter can be used to track this process. [pr#43337](https://github.com/ceph/ceph/pull/43337) +- bluestore: Reduced memory consumption for fsck during the startup. [pr#43667](https://github.com/ceph/ceph/pull/43667) +- bluestore: Optimized BlueFS locking at a finer granularity. [pr#43794](https://github.com/ceph/ceph/pull/43794) +- bluestore: Used the huge page–based read buffer, which is disabled by default. [pr#43691](https://github.com/ceph/ceph/pull/43691) +- mon: Added the --bulk flag when a pool is created so the pg autoscaler can adjust the initial number of PGs of the pool to the maximum value. By default, the pg autoscaler adjusts the initial number of PGs of the pool to the minimum value and dynamically changes the value. [pr#44241](https://github.com/ceph/ceph/pull/44241) +- mgr: Added the commands for enabling and disabling pg_autoscaler globally. [pr#43716](https://github.com/ceph/ceph/pull/43716) +- mgr: Implemented TTL cache to store cluster information and reduce the interaction with the cluster. [pr#44088](https://github.com/ceph/ceph/pull/44088) +- mgr: Optimized the balancer and refactored calc_pg_upmaps ([pr#44002](https://github.com/ceph/ceph/pull/44002)). The primary balancer is to be implemented in the Quincy version to balance the capacity and load. +- cephdeduptool: Added chunk (offset and length) and object dedupe commands, facilitating the use of the deduplication function. [pr#43686](https://github.com/ceph/ceph/pull/43686) +- rgw/s3select: Added arrow/parquet ([pr#40802](https://github.com/ceph/ceph/pull/40802)). Due to the dependency problem, this function is disabled by default during compilation. [pr#44603](https://github.com/ceph/ceph/pull/44603) +- rgw: Added the user/bucket-level rate limit. [pr#42891](https://github.com/ceph/ceph/pull/42891) +- rgw: Reduced unnecessary bucket stats load. [pr#44538](https://github.com/ceph/ceph/pull/44538) +- rgw: Added the max_header_size option to adjust the parse buffer size of the beast. The default size is 16 KB, and the maximum size is 64 KB. A larger buffer size can reduce the number of socket reads ([pr#44029](https://github.com/ceph/ceph/pull/44029)). The size is increased to static 64 KB in [pr#29776](https://github.com/ceph/ceph/pull/29776), improving flexibility. +## Recent Ceph Developer News +Each module of the Ceph community holds regular meetings to discuss and align the development progress. Meeting videos are uploaded to [YouTube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos). The major meetings are as follows: +|Meeting|Description|Frequency| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & SeaStore development|Weekly| +|Ceph Orchestration Meeting|Ceph management module (mgr)|Weekly| +|Ceph DocUBetter Meeting |Document optimization|Biweekly| +|Ceph Performance Meeting|Ceph performance optimization|Biweekly| +|Ceph Developer Monthly|Ceph developers|Monthly| +|Ceph Testing Meeting|Version verification and release|Monthly| +|Ceph Science User Group Meeting|Ceph scientific computing|Irregularly| +|Ceph Leadership Team Meeting|Ceph leadership team|Weekly| + +Recently, the focus is on performance. The following topics are discussed at the meetings: +- The performance test of the Quincy version needs to be compared with that of the Pacific version. The NVMe performance test is based on MAKO (AMD EPYC 7742) and 120 OSDs. The test covers single and multiple nodes (copy and EC). The test tools include fio(rbd cephfs), hsbench (rgw), tcmu-runner (iscsi/nbd), and omapbench(mds). +- The recovery testing may be added for the Quincy version. +- According to the Pacific version test, perf cycles/op monitoring reduces the performance by up to 15%. +- The memory usage in the Ceph is not transparent because the memory of many modules cannot be tracked. Therefore, more memory optimization may be required. diff --git a/web-ui/docs/en/blog/rosinL/2022-02-23-Ceph Community News (2021-01-17 to 2022-02-16).md b/web-ui/docs/en/blog/rosinL/2022-02-23-Ceph Community News (2021-01-17 to 2022-02-16).md new file mode 100644 index 0000000000000000000000000000000000000000..9442d321ec83980bdd358fa69ff4536685b1f7c6 --- /dev/null +++ b/web-ui/docs/en/blog/rosinL/2022-02-23-Ceph Community News (2021-01-17 to 2022-02-16).md @@ -0,0 +1,88 @@ +--- +title: Ceph Community News (2022-01-17 to 2022-02-16) +date: 2022-02-23 +tags: + - Ceph + - News + - Pacific +sig: ceph-sig +archives: 2022-2 +author: rosinL +summary: Ceph Community News +--- +# Ceph Community News (2022-01-17 to 2022-02-16) +## Cephalocon 2022 Postponed +Due to the COVID-19 pandemic, Cephalocon 2022, originally scheduled for April 5-7 (April 6-8, Beijing Time), has been postponed. The new time is yet to be determined. The topics of the conference have been released and are listed below. For more details, see [Cephalocon 2022 schedule](https://ceph2022.sched.com/). +|Category|Topic|Speaker|Institution| +|----|-------|----|----| +|RGW, Performance|[Optimizing RGW Object Storage Mixed Media through Storage Classes and Lua Scripting](https://sched.co/w9FL)|Curt Bruns & Anthony D'Atri|Intel| +|RGW|[RGW: Sync What? Sync Info Provider: Early Peek](https://sched.co/w9Fm)|Yehuda Sadeh-Weinraub|Red Hat| +|RGW|[RGW – An Ultimate S3 Frontend for MultipleBackends: An Implementation Story](https://sched.co/w9GJ)|Gregory Touretsky & Andriy Tkachuk|Seagate| +|RGW, S3select|[S3select: Computational Storage in S3](https://sched.co/w9GY)|Gal Salomon & Girjesh Rajoria|Red Hat| +|RGW|[Testing S3 Implementations: RGW & Beyond](https://sched.co/w9Gh)|Robin Hugh Johnson|DigitalOcean| +|RGW|[Introduction to Container Object Storage Interface aka COSI for ceph RGW](https://sched.co/w9Fs)|Jiffin Tony Thottan|Red Hat| +|RGW|[RGW Zipper](https://sched.co/w9GD)|Daniel Gryniewicz & Soumya Koduri|Red Hat| +|Cephadm|[Lightning Talk: Introduction to Cephadm](https://sched.co/w9EW)|Melissa Li|Red Hat| +|Dashboard|[Dashboard: Exploring Centralized Logging with Ceph Storage](https://sched.co/w9GP)|Gaurav Sitlani & Aashish Sharma|Red Hat| +|Dashboard|[Operating Ceph from the Ceph Dashboard: Past, Present and Future](https://sched.co/w9F0)|Ernesto Puerta|Red Hat| +|Ceph, QoS, mClock|[Ceph QoS Refinements for Background Operations using mClock](https://sched.co/w9Fv)|Sridhar Seshasayee|Red Hat| +|Ceph, PG|[pgremapper: CRUSHing Cluster OperationaComplexity](https://sched.co/w9EZ)|Joshua Baergen|DigitalOcean| +|Ceph, PG|[New Workload Balancer in Ceph](https://sched.co/w9Eo)|Josh Salomon & Laura Flores|Red Hat| +|Ceph, DPDK|[Lightning Talk: Ceph Messenger DPDkstack Development and Debugging](https://sched.co/w9FO)|Chunsong Feng|Huawei| +|Ceph, Windows|[Ceph on Windows](https://sched.co/w9Ei)|Alessandro Pilotti|Cloudbase Solutions| +|Seastore|[What's New with Crimson and Seastore?](https://sched.co/w9FI)|Samuel Just|Red Hat| +|Seastore, Crimson|[Lightning Talk: Introduction to Crimson from a Newbie](https://sched.co/w9FF)|Joseph Sawaya|Red Hat| +|Seastore|[Understanding SeaStore Through Profiling](https://sched.co/w9ET)|Yingxin Cheng & Tushar Gohad|Intel| +|Bluestore|[Accelerating PMEM Device Operations in BlueStore with Hardware Based Memory Offloading Technique](https://sched.co/w9F9)|Ziye Yang|Intel| +|Bluestore|[Revealing BlueStore Corruption Bugs in Containerized Ceph Clusters](https://sched.co/w9Fj)|Satoru Takeuchi|Cybozu| +|Dev|[Chasing Bad Checksums: A Journey through Ceph, TCMalloc, and the Linux kernel](https://sched.co/w9Fd)|Mauricio Faria de Oliveira & Dan Hill|Canonical| +|Dev|[Lightning Talk: Improving Ceph Build and Backport Automations Using Github Actions](https://sched.co/w9Gt)|Deepika Upadhyay|Red Hat| +|Dev|[Ceph Crash Telemetry Observability in Action](https://sched.co/w9Ec)|Yaarit Hatuka|Red Hat| +|Performance|[DisTRaC: Accelerating High-Performance Compute Processing for Temporary Data Storage](https://sched.co/w9Ef)|Gabryel Mason-Williams|Rosalind Franklin Institute| +|Performance|[Putting the Compute in your Storage](https://sched.co/w9Fg)|Federico Lucifredi & Brad Hubbard|Red Hat| +|Performance|[Modifying Ceph for Better HPC Performance](https://sched.co/w9Gb)|Darren Soothill|CROIT| +|Performance|[Over A Billion Requests Served Per Day: Ensuring Everyone is Happy with Our Ceph Clusters' Performance](https://sched.co/w9FR)|Jane Zhu & Matthew Leonard|Bloomberg LP| +|Performance|[Lessons Learned from Hardware Acceleration Initiatives for Ceph-specific Workloads](https://sched.co/w9G4)|Harry Richardson & Lionel Corbet|SoftIron| +|Performance|[The Effort to Exploit Modern SSDs on Ceph](https://sched.co/w9GG)|Myoungwon Oh|Samsung Electronics| +|Performance|[NVMe-over-Fabrics Support for Ceph](https://sched.co/w9GS)|Jonas Pfefferle, IBM & Scott Peterson|Intel| +|Security|[Introducing the New RBD Image Encryption Feature](https://sched.co/w9F3)|Or Ozeri & Danny Harnik|IBM| +|Security|[CephFS At-Rest Encryption with fscrypt](https://sched.co/w9Eu)|Jeffrey Layton|Red Hat| +|Security|[Secure Token Service in Ceph](https://sched.co/w9Ex)|Pritha Srivastava|Red Hat| +|Security|[Data Security and Storage Hardening in Rook and Ceph](https://sched.co/w9Fp)|Federico Lucifred & Michael Hackett|Red Hat| +|Ceph application|[Improved Business Continuity for an Existing Large Scale Ceph Infrastructure: A Story from Practical Experience](https://sched.co/w9G7)|Enrico Bocch & Arthur Outhenin-Chalandre|CERN| +|Ceph application|[How we Operate Ceph at Scale](https://sched.co/w9Fy)|Matt Vandermeulen|Digital Ocean| +|Ceph application|[BoF Session: Ceph in Scientific Computing and Large Clusters](https://sched.co/w9FC)|Kevin Hrpcek|Space Science & Engineering Center, University of Wisconsin - Madison| +|Ceph application|[Aquarium: An Easy to Use Ceph Appliance](https://sched.co/w9Ge)|Joao Eduardo Luis & Alexandra Settle|SUSE| +|Ceph application|[Stretch Clusters in Ceph: Algorithms, Use Cases, and Improvements](https://sched.co/w9Gn)|Gregory Farnum|Red Hat| +|Ceph application|[We Added 6 Petabytes of Ceph Storage and No Clients Noticed! Here's How We Did It.](https://sched.co/w9FX)|Joseph Mundackal & Matthew Leonard|Bloomberg LP| +|Ceph application|[Why We Built A "Message-Driven Telemetry System At Scale" Ceph Cluster](https://sched.co/w9FU)|Xiaolin Lin & Matthew Leonard|Bloomberg LP| +|Ceph application|[Lightning Talk: Ceph and 6G: Are We Ready for zettabytes?](https://sched.co/w9Gk)|Babar Khan|Technical University Darmstadt| +|Ceph application|[Bringing emails@ceph Into the Field](https://sched.co/w9G1)|Danny Al-Gaaf|Deutsche Telekom AG| +|Ceph application|[Lightning Talk: Ceph and QCOW2 a Match Made in Heaven: From Live Migration to Differential Snapshots](https://sched.co/w9F6)|Effi Ofer|IBM| +|Ceph application|[Lightning Talk: Installing Ceph on Kubernetes Using the Rook Operator and Helm](https://sched.co/w9GM)|Mike Petersen|Platform9| +|Benchmark|[Connecting The Dots: Benchmarking Ceph at Scale](https://sched.co/w9GA)|Shon Paz & Ido Pal|Red Hat| +|Benchmark|[Introducing Sibench: A New Open Source Benchmarking Optimized for Ceph](https://sched.co/w9GV)|Danny Abukalam|SoftIron| +## Recently Merged PRs +Recently, PRs have mainly focused on bug fixing. The following describes notable changes: +- mgr: Disabled the pg recovery by default when OSD is in or out. You can manually enable it as required to reduce the impact on the service cluster. [pr#44588](https://github.com/ceph/ceph/pull/44588) +- osd: Added the dump_blocked_ops_count option to ceph daemon perf dump to quickly obtain the number of blocked ops, reducing the overhead caused by the dump_blocked_ops operation. [pr#44780](https://github.com/ceph/ceph/pull/44780) +- rgw: Added support for the conditional copy by the rgw s3 CopyObject interface. [pr#44678](https://github.com/ceph/ceph/pull/44678) +- rgw: Fixed the issue that a large amount of memory is used during the radosgw-admin bucket chown process. [pr#44357](https://github.com/ceph/ceph/pull/44357) +- rbd: Introduced the rxbounce option to krbd to solve the problem of CRC errors and performance deterioration when images are used as block devices of the Windows system. [pr#44842](https://github.com/ceph/ceph/pull/44842) +## Recent Ceph Developer News +Each module of the Ceph community holds regular meetings to discuss and align the development progress. Meeting videos are uploaded to [YouTube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos). The major meetings are as follows: +|Meeting|Description|Frequency| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & SeaStore development|Weekly| +|Ceph Orchestration Meeting|Ceph management module (mgr) development|Weekly| +|Ceph DocUBetter Meeting |Document optimization|Biweekly| +|Ceph Performance Meeting|Ceph performance optimization|Biweekly| +|Ceph Developer Monthly|Ceph developers|Monthly| +|Ceph Testing Meeting|Version verification and release|Monthly| +|Ceph Science User Group Meeting|Ceph scientific computing|Irregularly| +|Ceph Leadership Team Meeting|Ceph leadership team|Weekly| + +Recently, the community focuses on the freeze test and verification of the Quincy version. The following topics are discussed at the meetings: +- In the Quincy version test, the read performance meets the expectation, but the write performance deteriorates in some scenarios. It can be determined that 4k min_alloc_size and bluestore allocator can improve the performance. +- As the omap scale increases, the omap_iterator efficiency causes a large number of slow_ops or even no response. The [issue](https://tracker.ceph.com/issues/53926) records the test results of the two compaction modes. If the compaction is manually triggered, the latency cannot be restored to the previous level. To resolve this issue, Rocksdb provides [periodic and TTL compaction](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide#periodic-and-ttl-compaction). After this function is enabled, the latency can be restored to the previous level. +- A large number of PRs are merged for the Ceph Benchmark Tool (CBT) with a focus on the control of memory resources during the large-scale OSD test and the multi-client concurrent test cases. diff --git a/web-ui/docs/en/blog/rosinL/Ceph Community News (2022-02-17 to 2022-03-13).md b/web-ui/docs/en/blog/rosinL/Ceph Community News (2022-02-17 to 2022-03-13).md new file mode 100644 index 0000000000000000000000000000000000000000..1541ceeddbf4ba85b14ae9eea03360c9226ad5f0 --- /dev/null +++ b/web-ui/docs/en/blog/rosinL/Ceph Community News (2022-02-17 to 2022-03-13).md @@ -0,0 +1,53 @@ +--- +title: Ceph Community News (2022-02-17 to 2022-03-13) +date: 2022-3-31 +tags: + - Ceph + - News + - Pacific +sig: ceph-sig +archives: 2022-3 +author: rosinL +summary: Ceph Community News +--- +# Ceph Community News (2022-02-17 to 2022-03-13) +## Cephalocon 2022 Postponed to July 11-13 +Cephalocon 2022 has been rescheduled to July 11-13. The schedule is now available at [Cephalocon 2022 sched](https://ceph2022.sched.com/). +## [Ceph Octopus v15.2.16](https://ceph.com/en/news/blog/2022/v15-2-16-octopus-released/) Released +Notable Changes +- Fix in the read lease logic to prevent PGs from going into WAIT state after OSD restart. +- Several bug fixes in BlueStore, including a fix for object listing bug, which could cause stat mismatch scrub errors. + +## Recently Merged PRs +Recently, the PR mainly focuses on bug fixing. The following describes notable changes: +- cephfs-top: Added average read/write/metadata latency. [pr#41397](https://github.com/ceph/ceph/pull/41397) +- rbd: Added rbd_default_map_options to be set and used at the image and pool level. [pr#44904](https://github.com/ceph/ceph/pull/44904) +- common: Used thread-local pointer variables to save the shard location required. [pr#44479](https://github.com/ceph/ceph/pull/44479) +## Recent Ceph Developer News +Each module of the Ceph community holds regular meetings to discuss and align the development progress. Meeting videos are uploaded to [YouTube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos). The major meetings are as follows: +|Meeting|Description|Frequency| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & SeaStore development|Weekly| +|Ceph Orchestration Meeting|Ceph management module (mgr)|Weekly| +|Ceph DocUBetter Meeting |Document optimization|Biweekly| +|Ceph Performance Meeting|Ceph performance optimization|Biweekly| +|Ceph Developer Monthly|Ceph developer|Monthly| +|Ceph Testing Meeting|Version verification and release|Monthly| +|Ceph Science User Group Meeting|Ceph scientific computing|Irregularly| +|Ceph Leadership Team Meeting|Ceph leadership team|Weekly| +|Ceph Tech talks|Discussion on Ceph community technologies|Monthly| + +### Performance Meeting +- At [performance weekly](https://www.youtube.com/watch?v=syq_LTg25T4) on March 3, Intel's Michal Wysoczanski introduced openCAS versions and applications, as well as features of Ceph-based application deployment. However, he did not mention Ceph-based performance optimization. It is expected that the information can be provided in the future. +- At [performance weekly](https://www.youtube.com/watch?v=RFYA-0k6QEk) on March 15, the following performance-related issues were discussed: + - PGLog optimization + - Crimson cyanstore performance testing + - rocksdb iterator performance +### [Ceph Talks](https://ceph.io/en/community/tech-talks/) +The Ceph community discusses technology-related topics monthly. The topic discussed in March is as follows: +- 2022-3-24, Ceph Tech Talk: How Teuthology Works with Kamoltat (Junior) Sirivadhna +## Ceph Community Newsletter +[Ceph Community Newsletter March 2022 Edition](https://ceph.com/en/news/blog/2022/newsletter-march/) is published. +This edition covers the following contents: + +- The Ceph Quincy Release Canadidate v17.1.0 is available. diff --git a/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png new file mode 100644 index 0000000000000000000000000000000000000000..57118696975c312eabf9ac6c80d9fd8a36d92503 Binary files /dev/null and b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png differ diff --git a/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png new file mode 100644 index 0000000000000000000000000000000000000000..46406e0975abdab87d6c69badd9fbe54664896f0 Binary files /dev/null and b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png differ diff --git a/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png new file mode 100644 index 0000000000000000000000000000000000000000..62fde4d9d9c5452b3ea0c1c8dbf4d45eefc19c2f Binary files /dev/null and b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png differ diff --git a/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md new file mode 100644 index 0000000000000000000000000000000000000000..f87b82b6ae205214b7824a77de0704a38410739d --- /dev/null +++ b/web-ui/docs/en/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md @@ -0,0 +1,269 @@ +--- +title: Introduction to cgroup v2 Functions and Principles in iSulad +date: 2021-04-19 +tags: + - iSulad +archives: 2021-04 +author: wangfengtu +summary: Just about how iSulad uses and implements cgroup v2. + +--- + +cgroup is used to restrict process group resources in Linux. It has two versions: cgroup v1 and cgroup v2, the latter of which is designed to replace its predecessor. However, for compatibility purposes, cgroup v1 is not deleted from the kernel and there is a high probability that cgroup v1 will exist for a long time. iSulad supports pure cgroup v2, which is still an experimental function now. + + + +## Changes in cgroup v2 Compared with cgroup v1 + +cgroup v2 yields the following differences over cgroup v1: + +1. While v1 mounts each subsystem (controller) to its own directory, all subsystems of v2 are mounted to the same directory. +2. Processes can be bound only to the **/** directory and leaf nodes of a cgroup and cannot be bound to intermediate nodes. +3. To use the functions of a controller in the subdirectory, enable it in **cgroup.subtree_control**. +4. In v2, the **tasks** file used in v1 is deleted, and **cgroup.clone_children** in the CPU is removed. +5. The notification mechanism in v2 changes to the **cgroup.events** file. +6. Certain APIs are deleted. For details, see the function comparison between v2 and v1 supported by iSulad. In addition, some APIs implemented through cgroup are implemented in eBPF mode. The implementation principle of eBPF will be described later. + + + +The following are major differences when used with iSulad. + +1. In cgroup v1, each subsystem is implemented and mounted independently as follows: + +``` +root@wft-pc:~# ls /sys/fs/cgroup/ +blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event rdma unified +cpu cpu,cpuacct devices hugetlb net_cls net_prio pids systemd +root@wft-pc:~# +``` + +In cgroup v2, implementation of each subsystem is planned in a unified manner (for example, almost all values range from **1** to **10000**), and all subsystems are mounted to the same directory. The following is an example: + +``` +root@wft-pc:/sys/fs/cgroup/isulad# ls +cgroup.controllers cpu.max cpu.weight hugetlb.2MB.events.local memory.events.local memory.swap.high +cgroup.events cpu.pressure cpu.weight.nice hugetlb.2MB.max memory.high memory.swap.max +cgroup.freeze cpuset.cpus hugetlb.1GB.current hugetlb.2MB.rsvd.current memory.low pids.current +cgroup.max.depth cpuset.cpus.effective hugetlb.1GB.events hugetlb.2MB.rsvd.max memory.max pids.events +cgroup.max.descendants cpuset.cpus.partition hugetlb.1GB.events.local io.max memory.min pids.max +cgroup.procs cpuset.mems hugetlb.1GB.max io.pressure memory.oom.group rdma.current +cgroup.stat cpuset.mems.effective hugetlb.1GB.rsvd.current io.stat memory.pressure rdma.max +cgroup.subtree_control cpu.stat hugetlb.1GB.rsvd.max io.weight memory.stat +cgroup.threads cpu.uclamp.max hugetlb.2MB.current memory.current memory.swap.current +cgroup.type cpu.uclamp.min hugetlb.2MB.events memory.events memory.swap.events +root@wft-pc:/sys/fs/cgroup/isulad# +``` + +2. In cgroup v1, a mounted controller can be directly used. By contrast, in cgroup v2, a mounted controller can be used only after being enabled. The cgroup directory contains the **cgroup.controllers** and **cgroup.subtree_control** files. + +​ **cgroup.controllers**: lists the available controllers in the current directory. It is a read-only file whose content is determined by **cgroup.subtree_control** in the upper-level folder. + +​ **cgroup.subtree_control**: lists the available controllers in the subdirectory. To enable a controller, add it to this file. Then, you can use the controller in the subdirectory. + +The **echo +memory > cgroup.subtree_control** command enables the memory controller in the subdirectoty. **+memory** can be changed to any controller supported by **cgroup.controllers**. In the following example, no memory-related controller is set in the **test** directory. After you enable the memory controller, you can see it in the **test** directory. + +``` +root@wft-pc:/sys/fs/cgroup/test# cat cgroup.controllers +cpuset cpu io memory hugetlb pids rdma +root@wft-pc:/sys/fs/cgroup/test# cat cgroup.subtree_control +root@wft-pc:/sys/fs/cgroup/test# mkdir test +root@wft-pc:/sys/fs/cgroup/test# ls test +cgroup.controllers cgroup.freeze cgroup.max.descendants cgroup.stat cgroup.threads cpu.pressure io.pressure +cgroup.events cgroup.max.depth cgroup.procs cgroup.subtree_control cgroup.type cpu.stat memory.pressure +root@wft-pc:/sys/fs/cgroup/test# echo +memory > cgroup.subtree_control +root@wft-pc:/sys/fs/cgroup/test# ls test +cgroup.controllers cgroup.max.descendants cgroup.threads io.pressure memory.high memory.oom.group memory.swap.events +cgroup.events cgroup.procs cgroup.type memory.current memory.low memory.pressure memory.swap.high +cgroup.freeze cgroup.stat cpu.pressure memory.events memory.max memory.stat memory.swap.max +cgroup.max.depth cgroup.subtree_control cpu.stat memory.events.local memory.min memory.swap.current +root@wft-pc:/sys/fs/cgroup/test# +``` + + + +## Configuring iSulad to Support cgroup v2 + +Although the kernel supports cgroup v2 since version 4.5, not all related functions are supported. It is recommended that the kernel of the latest version be used to support more cgroup subsystems. To validate the cgroup v2 functions supported by iSulad, you are advised to use kernel 5.8 or later (run the **uname -r** command to query the kernel version). For example, in practice the openEuler 21.03 uses kernel 5.10. iSulad automatically checks the current cgroup version. If the system supports only cgroup v2 and automatically mounts cgroup v2 to the **/sys/fs/cgroup** directory, iSulad uses cgroup v2 to restrict container resources. You can configure **cgroup_no_v1=all** in the system startup command line to disable all cgroups of v1. In this way, when the system starts, only cgroup v2 is enabled and the cgroup v2 subsystems are mounted to the **/sys/fs/cgroup** directory. After system restart, run the **mount | grep cgroup** command. If cgroup v2 is mounted to **/sys/fs/cgroup**, the environment that supports cgroup v2 has been successfully configured. + +``` +root@wft-pc:~# mount | grep cgroup +cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime) +root@wft-pc:~# +``` + + + +## iSulad Using cgroup v2 to Restrict Resources + +### Examples: + +1. To restrict the memory usage threshold for a single container to 10 MB, add the **-m 10m** option when running the container. + + ``` + root@wft-pc:~# isula run -tid -m 10m busybox sh + dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + root@wft-pc:~# + ``` + + -**m 10m** indicates that a maximum of 10 MB memory can be used in a container. You can run the **isula stats** command to view the resource restrictions. + + ``` + root@wft-pc:~# isula stats --no-stream dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + CONTAINER CPU % MEM USAGE / LIMIT MEM % BLOCK I / O PIDS + dcea83315b7b 0.00 300.00 KiB / 10.00 MiB 2.93 0.00 B / 0.00 B 1 + root@wft-pc:~# + ``` + + You can configure the resource threshold as needed. + + ``` + root@wft-pc:~# isula update -m 20m dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + root@wft-pc:~# isula stats --no-stream dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + CONTAINER CPU % MEM USAGE / LIMIT MEM % BLOCK I / O PIDS + dcea83315b7b 0.00 300.00 KiB / 20.00 MiB 1.46 0.00 B / 0.00 B 1 + root@wft-pc:~# + ``` + +2. Assume that you want to mount the **/dev/nvme0n1** device to the container as **/dev/sdx** and restrict it as a read-only device. The configuration is as follows: + + ``` + root@wft-pc:~# isula run -ti --rm --device=/dev/nvme0n1:/dev/sdx:wm busybox fdisk /dev/sdx + fdisk: can't open '/dev/sdx' + root@wft-pc:~# + ``` + + The syntax for mounting a device to a container is **--device=$host:$container:rwm**. + Where + **$host** specifies the absolute path of the device on the host; **$container** specifies the absolute path of the device in the container; **r** indicates that the device can be read; **w** indicates that the device can be written; and **m** indicates that nodes can be created. + In the preceding command, the **r** parameter is missing. That means, the nodes can be written and created but cannot be read (read-only). + +### More resource restrictions: + +iSulad provides the same APIs for both cgroup v1 and v2. However, some functions supported by cgroup v1 are removed from cgroup v2 or the implementation modes are different. Therefore, some APIs are unavailable or their meanings are changed in cgroup v2. iSulad can restrict the following resources: + +| Resource | Function | Difference from cgroup v1 | +| ---------- | ---------------------------------------------- | ------------------------------------------------------------ | +| devices | Restricts access to a device in a container.| The **devices** subsystem uses the eBPF mode instead of writing values to the cgroup file to restrict resources.| +| memory | Restricts the memory resources of a container. | Swappiness, kmem parameters, and **oom_control** are not supported. | +| cpu/cpuset | Restricts the CPU resources of a container. | **rt_***-related (real-time threads) restrictions are not supported. | +| blkio/io | Restricts the block device I/Os of a container. | Both block device I/Os and buffer I/Os are restricted. | +| hugetlb | Restricts the use of huge page memory. | No difference. | +| pids | Restricts the PIDs used by a container. | No difference. | +| files | Restrict the FDs used by a container. | No difference. | +| freeze | Suspends a container. | No difference. | + +To view the script for the preceding example, visit the following link: + +[https://gitee.com/openeuler/iSulad/blob/master/CI/test_cases/manual_cases/cgroupv2.sh](https://gitee.com/openeuler/iSulad/blob/master/CI/test_cases/manual_cases/cgroupv2.sh) + + + +## Implementation Principle of cgroup v2 in iSulad + + + + + +The preceding figure shows the iSulad resource restriction process. iSulad verifies the validity of parameters; lcr generates configurations that can be identified by lxc in the **lxc.conf** file; and lxc parses parameters in the **lxc.conf** file and configures the parameters to the cgroup API file corresponding to the container or uses the eBPF mode to implement corresponding functions. + +lcr determines whether cgroup v1 or cgroup v2 is used based on the **magic** value of the **/sys/fs/cgroup** file system. + +``` +int lcr_util_get_cgroup_version() +{ + struct statfs fs = {0}; + + if (statfs(CGROUP_MOUNTPOINT, &fs) != 0) { + ERROR("failed to statfs %s: %s", CGROUP_MOUNTPOINT, strerror(errno)); + return -1; + } + + if (fs.f_type == CGROUP2_SUPER_MAGIC) { + return CGROUP_VERSION_2; + } else { + return CGROUP_VERSION_1; + } +} +``` + +If cgroup v2 is used, the configuration of cgroup v2 is generated. Otherwise, the configuration of cgroup v1 is generated. + +``` +static struct lcr_list *trans_oci_resources(const defs_resources *res) +{ + int cgroup_version = 0; + + cgroup_version = lcr_util_get_cgroup_version(); + if (cgroup_version < 0) { + return NULL; + } + + if (cgroup_version == CGROUP_VERSION_2) { + return trans_oci_resources_v2(res); + } else { + return trans_oci_resources_v1(res); + } +} +``` + +The configuration of cgroup v2 generated by lcr is as follows: + +``` +root@wft-pc:/var/lib/isulad/engines/lcr/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat config | grep cgroup2 +lxc.cgroup2.devices.deny = a *:* rwm +lxc.cgroup2.devices.allow = c *:* m +lxc.cgroup2.devices.allow = b *:* m +lxc.cgroup2.devices.allow = c 1:3 rwm +lxc.cgroup2.devices.allow = c 1:5 rwm +lxc.cgroup2.devices.allow = c 1:7 rwm +lxc.cgroup2.devices.allow = c 5:0 rwm +lxc.cgroup2.devices.allow = c 5:1 rwm +lxc.cgroup2.devices.allow = c 5:2 rwm +lxc.cgroup2.devices.allow = c 1:8 rwm +lxc.cgroup2.devices.allow = c 1:9 rwm +lxc.cgroup2.devices.allow = c 136:* rwm +lxc.cgroup2.devices.allow = c 10:200 rwm +lxc.cgroup2.devices.deny = c 10:229 rwm +lxc.cgroup2.memory.max = 10485760 +lxc.cgroup2.memory.swap.max = 10485760 +root@wft-pc:/var/lib/isulad/engines/lcr/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# +``` + +**lxc.cgroup2.memory.max = 10485760** and **lxc.cgroup2.memory.swap.max = 10485760** (if **swap** is not configured, its default value is the same as that for memory restriction) are generated based on the **-m 10m** configuration. Other parameters related to **lxc.cgroup2.devices** are the default **devices** parameters configured by lcr for the container. + +### Restricting Resources Using cgroup v2 File + +Using the **lxc.conf** file, lxc writes most configurations to the corresponding files in the cgroup directory of a container to restrict resources. + +``` +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# pwd +/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat memory.max +10485760 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat memory.swap.max +10485760 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# +``` + +Note that the cgroup directory of the container is **/sys/fs/cgroup/isulad/$container_id**, and the file is the value of a configuration without the prefix **lxc.cgroup2** in the **lxc.conf** configuration file. For example, the file corresponding to **lxc.cgroup2.memory.max** is **memory.max**. + +Then, the kernel restricts the resources by following the cgroup configuration. + +### Using eBPF to Restrict Devices in cgroup v2 + +As mentioned above, some cgroup v2 resource restrictions are implemented through eBPF. Among the resources used by iSulad, restrictions of devices, that is, the configurations starting with **lxc.cgroup2.devices.**, are implemented through eBPF. The following describes how to restrict devices resources in eBPF mode. + + + +eBPF can dynamically load a segment of bytecode to the kernel for execution without recompiling the kernel or loading the kernel module. In this way, the kernel data can be used for data observation or restriction. Different from the Linux kernel module (LKM), eBPF cannot access kernel resources without restrictions. Instead, it uses a mechanism similar to a VM to execute code in an isolated environment. The eBPF execution process is as follows: + +1. Compile an eBPF program, usually a small segment of assembly code used to implement a user-defined function, for example, observing kernel data or filtering a control permission. A small assembly program compiled in the lxc code is used to implement the filtering function of the devices of cgroup v2. + +2. Before eBPF is loaded, the validator strictly validates the eBPF program. The validator generates a directed acyclic graph (DAG) based on the code to confirm that the program is valid. A valid program does not have the recursion, control cycle, or unreachable instruction. The number of instructions is within the allowed range, and the instructions do not exceed the program boundary. In addition to basic validation, the validator analyzes each instruction executed by the program for pre-execution. After the validation is successful, the eBPF program is compiled into machine code for execution. + +3. During loading of the eBPF program, specify an execution point, which is determined by the eBPF program type. The eBPF program is mounted to a specified kernel event based on the specified type. In this case, when a corresponding kernel event is generated, the eBPF machine code is executed. The type of the eBPF program for the devices function of cgroup v2 is **BPF_PROG_TYPE_CGROUP_DEVICE**, and the loading point is **/sys/fs/cgroup/isulad/$container_id**. + +4. When creating a container, lxc generates the eBPF program based on the **lxc.cgroup2.devices.*** configuration in the **lxc.conf** file and attaches the program to the cgroup root folder of the container to filter device permissions in the container. lxc uninstalls the eBFP program when destroying the container. + + diff --git a/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/Introduction to NuttX tmpfs.md b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/Introduction to NuttX tmpfs.md new file mode 100644 index 0000000000000000000000000000000000000000..cf93ce882aacd14d12d9f99e7ccdeabee2554be3 --- /dev/null +++ b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/Introduction to NuttX tmpfs.md @@ -0,0 +1,1995 @@ +--- +title: File System-Introduction to NuttX tmpfs +date: 2021-05-18 +tags: + - File system + - tmpfs + - nuttx +archives: 2021-05 +author: wangshuo +summary: Introduction to the NuttX tmpfs based on the NuttX source code +--- +# About This Document +The temporary file system, or tmpfs, is an independent file system that can be used immediately after being mounted. It is similar to a virtual drive (RAM drive), but the drawback of a RAM drive is that it serves as a block device and can be used only after being formatted by commands such as **mkfs**. This document uses tmpfs of NuttX-10.0.1 as an example to introduce its basic data structures and interface implementation. +
+ +# Data Structures +The tmpfs source code is stored in the **fs/tmpfs** directory of NuttX, and there is only one C file. The following describes the key data structures of tmpfs. +
+ +## object +In the following figure, the **object** structure can be regarded as the abstraction of the **file** and **directory** structures for unifying interfaces. From the object-oriented perspective, **object** is the parent structure of **file** and **directory**. +``` +/* The generic form of a TMPFS memory object */ + +struct tmpfs_object_s +{ + FAR struct tmpfs_dirent_s *to_dirent; + struct tmpfs_sem_s to_exclsem; + + size_t to_alloc; /* Allocated size of the memory object */ + uint8_t to_type; /* See enum tmpfs_objtype_e */ + uint8_t to_refs; /* Reference count */ +}; +``` +

+ +
+

+ +## dirent +**dirent** represents a directory entry matching the corresponding object. On the source code, **dirent** adds the object name after the **object** structure. + +``` +/* The form of one directory entry */ + +struct tmpfs_dirent_s +{ + FAR struct tmpfs_object_s *tde_object; + FAR char *tde_name; +}; +``` +
+ +## directory +A **directory** structure contains one or more **dirent** structures that point to files and subdirectories. Files and directories (including the root directory) are interleaved to form a tmpfs tree. +``` +/* The form of a directory memory object */ + +struct tmpfs_directory_s +{ + /* First fields must match common TMPFS object layout */ + + FAR struct tmpfs_dirent_s *tdo_dirent; + struct tmpfs_sem_s tdo_exclsem; + + size_t tdo_alloc; /* Allocated size of the directory object */ + uint8_t tdo_type; /* See enum tmpfs_objtype_e */ + uint8_t tdo_refs; /* Reference count */ + + /* Remaining fields are unique to a directory object */ + + uint16_t tdo_nentries; /* Number of directory entries */ + struct tmpfs_dirent_s tdo_entry[1]; +}; +``` +
+ +## file +A file is a sequential stream of bytes. Each file has a readable name. You can read, write, create, and delete a file with a specified name. +``` +/* The form of a regular file memory object + * + * NOTE that in this very simplified implementation, there is no per-open + * state. The file memory object also serves as the open file object, + * saving an allocation. This has the negative side effect that no per- + * open state can be retained (such as open flags). + */ + +struct tmpfs_file_s +{ + /* First fields must match common TMPFS object layout */ + + FAR struct tmpfs_dirent_s *tfo_dirent; + struct tmpfs_sem_s tfo_exclsem; + + size_t tfo_alloc; /* Allocated size of the file object */ + uint8_t tfo_type; /* See enum tmpfs_objtype_e */ + uint8_t tfo_refs; /* Reference count */ + + /* Remaining fields are unique to a directory object */ + + uint8_t tfo_flags; /* See TFO_FLAG_* definitions */ + size_t tfo_size; /* Valid file size */ + uint8_t tfo_data[1]; /* File data starts here */ +}; +``` +
+ +## tmpfs_s +The **tmpfs_s** structure represents an instance of tmpfs. The member **tfs_root** points to the root directory of tmpfs. +``` +/* This structure represents one instance of a TMPFS file system */ + +struct tmpfs_s +{ + /* The root directory */ + + FAR struct tmpfs_dirent_s tfs_root; + struct tmpfs_sem_s tfs_exclsem; +}; +``` +
+ + +## Structure Relationship +The following figure shows the relationships between the preceding structures. +
+

+ +# Main Internal Interfaces +Key internal interfaces are classified into the following types based on the operation type. +

+ +## dirent Operations +### tmpfs_add_dirent +As mentioned, **dirent** is the simplified encapsulation of the **object** structure and the object name, and **object** is the abstraction of **directory** and **file**. Therefore, the **tmpfs_add_dirent** function is used to add files and directories. The source code is as follows. +**tmpfs_add_dirent** reallocates the current **tdo** directory by adding a **tdo** entry, and assigns the new object (that is, **to**) and name to the new **tdo** entry. + +``` +/**************************************************************************** + * Name: tmpfs_add_dirent + ****************************************************************************/ + +static int tmpfs_add_dirent(FAR struct tmpfs_directory_s **tdo, + FAR struct tmpfs_object_s *to, + FAR const char *name) +{ + FAR struct tmpfs_directory_s *oldtdo; + FAR struct tmpfs_directory_s *newtdo; + FAR struct tmpfs_dirent_s *tde; + FAR char *newname; + unsigned int nentries; + int index; + + /* Copy the name string so that it will persist as long as the + * directory entry. + */ + + newname = strdup(name); + if (newname == NULL) + { + return -ENOMEM; + } + + /* Get the new number of entries */ + + oldtdo = *tdo; + nentries = oldtdo->tdo_nentries + 1; + + /* Reallocate the directory object (if necessary) */ + + index = tmpfs_realloc_directory(tdo, nentries); + if (index < 0) + { + kmm_free(newname); + return index; + } + + /* Save the new object info in the new directory entry */ + + newtdo = *tdo; + tde = &newtdo->tdo_entry[index]; + tde->tde_object = to; + tde->tde_name = newname; + + /* Add backward link to the directory entry to the object */ + + to->to_dirent = tde; + return OK; +} +``` +
+
+ +### tmpfs_find_dirent +The **tmpfs_find_dirent** function is used to search for a **dirent** with a specified name in a directory, for example, **tdo**. The source code is as follows. It is implemented through traversal search. +``` +/**************************************************************************** + * Name: tmpfs_find_dirent + ****************************************************************************/ + +static int tmpfs_find_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name) +{ + int i; + + /* Search the list of directory entries for a match */ + + for (i = 0; + i < tdo->tdo_nentries && + strcmp(tdo->tdo_entry[i].tde_name, name) != 0; + i++); + + /* Return what we found, if anything */ + + return i < tdo->tdo_nentries ? i : -ENOENT; +} +``` +

+ +### tmpfs_remove_dirent +The **tmpfs_remove_dirent** function is used to delete a **dirent** with a specified name from a directory, for example, **tdo**. Its source code is presented below. This function releases the strdup name in the **tmpfs_add_dirent** function and then checks whether the deleted **dirent** is the final one. If so, the function stops; otherwise, it overwrites the to-be-deleted **dirent** with the final **dirent** to release the final **dirent** for future use and avoid frequent reallocation. +``` +/**************************************************************************** + * Name: tmpfs_remove_dirent + ****************************************************************************/ + +static int tmpfs_remove_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name) +{ + int index; + int last; + + /* Search the list of directory entries for a match */ + + index = tmpfs_find_dirent(tdo, name); + if (index < 0) + { + return index; + } + + /* Free the object name */ + + if (tdo->tdo_entry[index].tde_name != NULL) + { + kmm_free(tdo->tdo_entry[index].tde_name); + } + + /* Remove by replacing this entry with the final directory entry */ + + last = tdo->tdo_nentries - 1; + if (index != last) + { + FAR struct tmpfs_dirent_s *newtde; + FAR struct tmpfs_dirent_s *oldtde; + FAR struct tmpfs_object_s *to; + + /* Move the directory entry */ + + newtde = &tdo->tdo_entry[index]; + oldtde = &tdo->tdo_entry[last]; + to = oldtde->tde_object; + + newtde->tde_object = to; + newtde->tde_name = oldtde->tde_name; + + /* Reset the backward link to the directory entry */ + + to->to_dirent = newtde; + } + + /* And decrement the count of directory entries */ + + tdo->tdo_nentries = last; + return OK; +} +``` +

+ +## Object Operation +### tmpfs_find_object +As mentioned, **object** is the abstraction of **directory** and **file**. Therefore, the **tmpfs_find_object** function is used to find files and directories. The source code is as follows. +Although the source code contains about 150 lines, it is relatively simple. In the input parameters, **relpath** is an absolute path. The **tmpfs_find_object** function searches from the root directory of tmpfs, and the **tmpfs_find_dirent** function is used to search in a specific directory. If the object cannot be found, an error code is returned. If the object is found, the target object and its directory are locked, and the values of **to_refs** and **tdo_refs** increase by 1. + +``` +/**************************************************************************** + * Name: tmpfs_find_object + ****************************************************************************/ + +static int tmpfs_find_object(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_object_s **object, + FAR struct tmpfs_directory_s **parent) +{ + FAR struct tmpfs_object_s *to = NULL; + FAR struct tmpfs_directory_s *tdo = NULL; + FAR struct tmpfs_directory_s *next_tdo; + FAR char *segment; + FAR char *next_segment; + FAR char *tkptr; + FAR char *copy; + int index; + int ret; + + /* Make a copy of the path (so that we can modify it via strtok) */ + + copy = strdup(relpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Traverse the file system for any object with the matching name */ + + to = fs->tfs_root.tde_object; + next_tdo = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + for (segment = strtok_r(copy, "/", &tkptr); + segment != NULL; + segment = next_segment) + { + /* Get the next segment after the one we are currently working on. + * This will be NULL is we are working on the final segment of the + * relpath. + */ + + next_segment = strtok_r(NULL, "/", &tkptr); + + /* Search the next directory. */ + + tdo = next_tdo; + + /* Find the TMPFS object with the next segment name in the current + * directory. + */ + + index = tmpfs_find_dirent(tdo, segment); + if (index < 0) + { + /* No object with this name exists in the directory. */ + + kmm_free(copy); + return index; + } + + to = tdo->tdo_entry[index].tde_object; + + /* Is this object another directory? */ + + if (to->to_type != TMPFS_DIRECTORY) + { + /* No. Was this the final segment in the path? */ + + if (next_segment == NULL) + { + /* Then we can break out of the loop now */ + + break; + } + + /* No, this was not the final segment of the relpath. + * We cannot continue the search if any of the intermediate + * segments do no correspond to directories. + */ + + kmm_free(copy); + return -ENOTDIR; + } + + /* Search this directory for the next segment. If we + * exit the loop, tdo will still refer to the parent + * directory of to. + */ + + next_tdo = (FAR struct tmpfs_directory_s *)to; + } + + /* When we exit this loop (successfully), to will point to the TMPFS + * object associated with the terminal segment of the relpath. + * Increment the reference count on the located object. + */ + + /* Free the dup'ed string */ + + kmm_free(copy); + + /* Return what we found */ + + if (parent) + { + if (tdo != NULL) + { + /* Get exclusive access to the parent and increment the reference + * count on the object. + */ + + ret = tmpfs_lock_directory(tdo); + if (ret < 0) + { + return ret; + } + + tdo->tdo_refs++; + } + + *parent = tdo; + } + + if (object) + { + if (to != NULL) + { + /* Get exclusive access to the object and increment the reference + * count on the object. + */ + + ret = tmpfs_lock_object(to); + if (ret < 0) + { + return ret; + } + + to->to_refs++; + } + + *object = to; + } + + return OK; +} +``` +

+ + +## File Operations +### tmpfs_alloc_file +The **tmpfs_alloc_file** function is used to allocate space for new files. The source code is as follows. It requests memory and initializes the structure. +``` +/**************************************************************************** + * Name: tmpfs_alloc_file + ****************************************************************************/ + +static FAR struct tmpfs_file_s *tmpfs_alloc_file(void) +{ + FAR struct tmpfs_file_s *tfo; + size_t allocsize; + + /* Create a new zero length file object */ + + allocsize = SIZEOF_TMPFS_FILE(CONFIG_FS_TMPFS_FILE_ALLOCGUARD); + tfo = (FAR struct tmpfs_file_s *)kmm_malloc(allocsize); + if (tfo == NULL) + { + return NULL; + } + + /* Initialize the new file object. NOTE that the initial state is + * locked with one reference count. + */ + + tfo->tfo_alloc = allocsize; + tfo->tfo_type = TMPFS_REGULAR; + tfo->tfo_refs = 1; + tfo->tfo_flags = 0; + tfo->tfo_size = 0; + + tfo->tfo_exclsem.ts_holder = getpid(); + tfo->tfo_exclsem.ts_count = 1; + nxsem_init(&tfo->tfo_exclsem.ts_sem, 0, 0); + + return tfo; +} +``` +

+ +### tmpfs_create_file +The **tmpfs_create_file** function is used to create a file. The source code is presented below. The function determines whether to create a file in the root directory. If yes, the **parent** variable is the root directory; otherwise, the **tmpfs_find_directory** function is used to find the upper-level directory of the file to be created. Then, the **tmpfs_find_dirent** function is used to check whether the current file exists in the directory. If it exists, an error code is returned and the function stops. If not, the **tmpfs_alloc_file** function is called to allocate space for the new file and the **tmpfs_add_dirent** function is called to allocate a directory entry in the directory where the new file is located. +``` +/**************************************************************************** + * Name: tmpfs_create_file + ****************************************************************************/ + +static int tmpfs_create_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_file_s **tfo) +{ + FAR struct tmpfs_directory_s *parent; + FAR struct tmpfs_file_s *newtfo; + FAR char *copy; + FAR char *name; + int ret; + + /* Duplicate the path variable so that we can modify it */ + + copy = strdup(relpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Separate the path into the file name and the path to the parent + * directory. + */ + + name = strrchr(copy, '/'); + if (name == NULL) + { + /* No subdirectories... use the root directory */ + + name = copy; + parent = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + /* Lock the root directory to emulate the behavior of + * tmpfs_find_directory() + */ + + ret = tmpfs_lock_directory(parent); + if (ret < 0) + { + kmm_free(copy); + return ret; + } + + parent->tdo_refs++; + } + else + { + /* Terminate the parent directory path */ + + *name++ = '\0'; + + /* Locate the parent directory that should contain this name. + * On success, tmpfs_find_directory() will lock the parent + * directory and increment the reference count. + */ + + ret = tmpfs_find_directory(fs, copy, &parent, NULL); + if (ret < 0) + { + goto errout_with_copy; + } + } + + /* Verify that no object of this name already exists in the directory */ + + ret = tmpfs_find_dirent(parent, name); + if (ret != -ENOENT) + { + /* Something with this name already exists in the directory. + * OR perhaps some fatal error occurred. + */ + + if (ret >= 0) + { + ret = -EEXIST; + } + + goto errout_with_parent; + } + + /* Allocate an empty file. The initial state of the file is locked with + * one reference count. + */ + + newtfo = tmpfs_alloc_file(); + if (newtfo == NULL) + { + ret = -ENOMEM; + goto errout_with_parent; + } + + /* Then add the new, empty file to the directory */ + + ret = tmpfs_add_dirent(&parent, (FAR struct tmpfs_object_s *)newtfo, name); + if (ret < 0) + { + goto errout_with_file; + } + + /* Release the reference and lock on the parent directory */ + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + + /* Free the copy of the relpath and return success */ + + kmm_free(copy); + *tfo = newtfo; + return OK; + + /* Error exits */ + +errout_with_file: + nxsem_destroy(&newtfo->tfo_exclsem.ts_sem); + kmm_free(newtfo); + +errout_with_parent: + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + +errout_with_copy: + kmm_free(copy); + return ret; +} + +``` +

+ +### tmpfs_find_file +The **tmpfs_find_file** function (source code below) is used to search for a target file from a specified absolute path. It calls the **tmpfs_find_object** function and adds a judgment. If the attribute (to_type) of the found object is not **FILE**, an error code is returned and the function stops. +``` +/**************************************************************************** + * Name: tmpfs_find_file + ****************************************************************************/ + +static int tmpfs_find_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_file_s **tfo, + FAR struct tmpfs_directory_s **parent) +{ + FAR struct tmpfs_object_s *to; + int ret; + + /* Find the object at this path. If successful, tmpfs_find_object() will + * lock both the object and the parent directory and will increment the + * reference count on both. + */ + + ret = tmpfs_find_object(fs, relpath, &to, parent); + if (ret >= 0) + { + /* We found it... but is it a regular file? */ + + if (to->to_type != TMPFS_REGULAR) + { + /* No... unlock the object and its parent and return an error */ + + tmpfs_release_lockedobject(to); + + if (parent) + { + FAR struct tmpfs_directory_s *tdo = *parent; + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + } + + ret = -EISDIR; + } + + /* Return the verified file object */ + + *tfo = (FAR struct tmpfs_file_s *)to; + } + + return ret; +} +``` +

+ + +### tmpfs_realloc_file +The **tmpfs_realloc_file** function (source code below) is used to expand the space of the current file. The **tfo_alloc** member in the **tmpfs_file_s** structure records the actual size of the current file and pre-allocates some space to a newly created file. If the size to be expanded does not exceed the actual size of the file, change the value of **tfo_size**. Otherwise, use the **kmm_realloc** function to expand the space and then update the structure. +``` +/**************************************************************************** + * Name: tmpfs_realloc_file + ****************************************************************************/ + +static int tmpfs_realloc_file(FAR struct tmpfs_file_s **tfo, + size_t newsize) +{ + FAR struct tmpfs_file_s *oldtfo = *tfo; + FAR struct tmpfs_file_s *newtfo; + size_t objsize; + size_t allocsize; + size_t delta; + + /* Check if the current allocation is sufficient */ + + objsize = SIZEOF_TMPFS_FILE(newsize); + + /* Are we growing or shrinking the object? */ + + if (objsize <= oldtfo->tfo_alloc) + { + /* Shrinking ... Shrink unconditionally if the size is shrinking to + * zero. + */ + + if (newsize > 0) + { + /* Otherwise, don't realloc unless the object has shrunk by a + * lot. + */ + + delta = oldtfo->tfo_alloc - objsize; + if (delta <= CONFIG_FS_TMPFS_FILE_FREEGUARD) + { + /* Hasn't shrunk enough.. Return doing nothing for now */ + + oldtfo->tfo_size = newsize; + return OK; + } + } + } + + /* Added some additional amount to the new size to account frequent + * reallocations. + */ + + allocsize = objsize + CONFIG_FS_TMPFS_FILE_ALLOCGUARD; + + /* Realloc the file object */ + + newtfo = (FAR struct tmpfs_file_s *)kmm_realloc(oldtfo, allocsize); + if (newtfo == NULL) + { + return -ENOMEM; + } + + /* Adjust the reference in the parent directory entry */ + + DEBUGASSERT(newtfo->tfo_dirent); + newtfo->tfo_dirent->tde_object = (FAR struct tmpfs_object_s *)newtfo; + + /* Return the new address of the reallocated file object */ + + newtfo->tfo_alloc = allocsize; + newtfo->tfo_size = newsize; + *tfo = newtfo; + return OK; +} +``` +

+ +## Directory Operations +### tmpfs_alloc_directory +The **tmpfs_alloc_directory** function is used to allocate space to a new directory. Similar to the **tmpfs_alloc_file** function, it requests memory and initializes the structure. +

+ +### tmpfs_create_directory +The **tmpfs_create_directory** function is used to create a directory, which is similar to the **tmpfs_create_file** function. +

+ +### tmpfs_find_directory +Similar to the **tmpfs_find_file** function, the **tmpfs_find_directory** function is used to search for a target directory from a specified absolute path. It also calls the **tmpfs_find_object** function and adds a judgment. If the attribute (to_type) of the found object is not **DIRECTORY**, an error code is returned and the function stops. +

+ + +### tmpfs_realloc_directory +The **tmpfs_realloc_directory** function is used to add a directory entry for a specified directory, for example, **tdo**. The source code is presented below. Different from the **tmpfs_realloc_file** function, the input parameter of **tmpfs_realloc_directory** is the expected total number of directory entries after reallocation. As mentioned, tmpfs does not delete a **dirent** immediately but reserves the final one. Therefore, if the reserved **dirent** in the current directory meets the requirements, you only need to update **tdo_nentries**. Otherwise, **kmm_realloc** is called to expand space and update related structures. +``` +/**************************************************************************** + * Name: tmpfs_realloc_directory + ****************************************************************************/ + +static int tmpfs_realloc_directory(FAR struct tmpfs_directory_s **tdo, + unsigned int nentries) +{ + FAR struct tmpfs_directory_s *oldtdo = *tdo; + FAR struct tmpfs_directory_s *newtdo; + size_t objsize; + int ret = oldtdo->tdo_nentries; + + /* Get the new object size */ + + objsize = SIZEOF_TMPFS_DIRECTORY(nentries); + if (objsize <= oldtdo->tdo_alloc) + { + /* Already big enough. + * REVISIT: Missing logic to shrink directory objects. + */ + + oldtdo->tdo_nentries = nentries; + return ret; + } + + /* Added some additional amount to the new size to account frequent + * reallocations. + */ + + objsize += CONFIG_FS_TMPFS_DIRECTORY_ALLOCGUARD; + + /* Realloc the directory object */ + + newtdo = (FAR struct tmpfs_directory_s *)kmm_realloc(oldtdo, objsize); + if (newtdo == NULL) + { + return -ENOMEM; + } + + /* Adjust the reference in the parent directory entry */ + + DEBUGASSERT(newtdo->tdo_dirent); + newtdo->tdo_dirent->tde_object = (FAR struct tmpfs_object_s *)newtdo; + + /* Return the new address of the reallocated directory object */ + + newtdo->tdo_alloc = objsize; + newtdo->tdo_nentries = nentries; + *tdo = newtdo; + + /* Return the index to the first, newly allocated directory entry */ + + return ret; +} +``` +

+ + +# Interfaces +Like common file systems, tmpfs provides standard interfaces that serve as the final implementation of system calls. This section describes several common interfaces. + +## bind +### Description +Creates a tmpfs root file system instance in the initialization phase. +

+ +### Source Code Analysis +In the source code, the **bind** interface requests memory for and initializes the **tmpfs_s** structure. The involved interfaces are described in the preceding sections and are not described here. +``` +/**************************************************************************** + * Name: tmpfs_bind + ****************************************************************************/ + +static int tmpfs_bind(FAR struct inode *blkdriver, FAR const void *data, + FAR void **handle) +{ + FAR struct tmpfs_directory_s *tdo; + FAR struct tmpfs_s *fs; + + finfo("blkdriver: %p data: %p handle: %p\n", blkdriver, data, handle); + DEBUGASSERT(blkdriver == NULL && handle != NULL); + + /* Create an instance of the tmpfs file system */ + + fs = (FAR struct tmpfs_s *)kmm_zalloc(sizeof(struct tmpfs_s)); + if (fs == NULL) + { + return -ENOMEM; + } + + /* Create a root file system. This is like a single directory entry in + * the file system structure. + */ + + tdo = tmpfs_alloc_directory(); + if (tdo == NULL) + { + kmm_free(fs); + return -ENOMEM; + } + + fs->tfs_root.tde_object = (FAR struct tmpfs_object_s *)tdo; + fs->tfs_root.tde_name = ""; + + /* Set up the backward link (to support reallocation) */ + + tdo->tdo_dirent = &fs->tfs_root; + + /* Initialize the file system state */ + + fs->tfs_exclsem.ts_holder = TMPFS_NO_HOLDER; + fs->tfs_exclsem.ts_count = 0; + nxsem_init(&fs->tfs_exclsem.ts_sem, 0, 1); + + /* Return the new file system handle */ + + *handle = (FAR void *)fs; + return OK; +} +``` +

+ +## unbind +### Description +Releases the tmpfs file system. +

+ +### Source Code Analysis +The core of the **unbind** interface is the **tmpfs_foreach** function that releases the content in tmpfs through traversal, and then tmpfs releases the root file system. +``` +/**************************************************************************** + * Name: tmpfs_unbind + ****************************************************************************/ + +static int tmpfs_unbind(FAR void *handle, FAR struct inode **blkdriver, + unsigned int flags) +{ + FAR struct tmpfs_s *fs = (FAR struct tmpfs_s *)handle; + FAR struct tmpfs_directory_s *tdo; + int ret; + + finfo("handle: %p blkdriver: %p flags: %02x\n", + handle, blkdriver, flags); + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Lock the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Traverse all directory entries (recursively), freeing all resources. */ + + tdo = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + ret = tmpfs_foreach(tdo, tmpfs_free_callout, NULL); + + /* Now we can destroy the root file system and the file system itself. */ + + nxsem_destroy(&tdo->tdo_exclsem.ts_sem); + kmm_free(tdo); + + nxsem_destroy(&fs->tfs_exclsem.ts_sem); + kmm_free(fs); + return ret; +} +``` +

+ +## open +### Description +Opens a file, which is similar to using the **open** system call in user mode. +

+ +### Source Code Analysis + +The source code contains about 150 lines and the involved interfaces have been described in preceding sections. The **tmpfs_find_file** function is used to search for a file. If the file is not found, the **tmpfs_create_file** function is called to determine whether to create a file or report an error and stop based on the flag transferred in user mode. If the file is found, the **tmpfs_find_file** function determines whether to return the EEXIST error code or clear up the file based on the flag transferred in user mode. +``` +/**************************************************************************** + * Name: tmpfs_open + ****************************************************************************/ + +static int tmpfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct inode *inode; + FAR struct tmpfs_s *fs; + FAR struct tmpfs_file_s *tfo; + off_t offset; + int ret; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL); + + /* Get the mountpoint inode reference from the file structure and the + * mountpoint private data from the inode structure + */ + + inode = filep->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Skip over any leading directory separators (shouldn't be any) */ + + for (; *relpath == '/'; relpath++); + + /* Find the file object associated with this relative path. + * If successful, this action will lock both the parent directory and + * the file object, adding one to the reference count of both. + * In the event that -ENOENT, there will still be a reference and + * lock on the returned directory. + */ + + ret = tmpfs_find_file(fs, relpath, &tfo, NULL); + if (ret >= 0) + { + /* The file exists. We hold the lock and one reference count + * on the file object. + * + * It would be an error if we are asked to create it exclusively + */ + + if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + /* Already exists -- can't create it exclusively */ + + ret = -EEXIST; + goto errout_with_filelock; + } + + /* Check if the caller has sufficient privileges to open the file. + * REVISIT: No file protection implemented + */ + + /* If O_TRUNC is specified and the file is opened for writing, + * then truncate the file. This operation requires that the file is + * writeable, but we have already checked that. O_TRUNC without write + * access is ignored. + */ + + if ((oflags & (O_TRUNC | O_WRONLY)) == (O_TRUNC | O_WRONLY)) + { + /* Truncate the file to zero length (if it is not already + * zero length) + */ + + if (tfo->tfo_size > 0) + { + ret = tmpfs_realloc_file(&tfo, 0); + if (ret < 0) + { + goto errout_with_filelock; + } + } + } + } + + /* ENOENT would be returned by tmpfs_find_file() if the full directory + * path was found, but the file was not found in the final directory. + */ + + else if (ret == -ENOENT) + { + /* The file does not exist. Were we asked to create it? */ + + if ((oflags & O_CREAT) == 0) + { + /* No.. then we fail with -ENOENT */ + + ret = -ENOENT; + goto errout_with_fslock; + } + + /* Yes.. create the file object. There will be a reference and a lock + * on the new file object. + */ + + ret = tmpfs_create_file(fs, relpath, &tfo); + if (ret < 0) + { + goto errout_with_fslock; + } + } + + /* Some other error occurred */ + + else + { + goto errout_with_fslock; + } + + /* Save the struct tmpfs_file_s instance as the file private data */ + + filep->f_priv = tfo; + + /* In write/append mode, we need to set the file pointer to the end of the + * file. + */ + + offset = 0; + if ((oflags & (O_APPEND | O_WRONLY)) == (O_APPEND | O_WRONLY)) + { + offset = tfo->tfo_size; + } + + filep->f_pos = offset; + + /* Unlock the file file object, but retain the reference count */ + + tmpfs_unlock_file(tfo); + tmpfs_unlock(fs); + return OK; + + /* Error exits */ + +errout_with_filelock: + tmpfs_release_lockedfile(tfo); + +errout_with_fslock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ + +## close +### Description +Closes a file, which is similar to using the **close** system call in user mode. +

+ +### Source Code Analysis +The core of the **close** interface is to operate **tfo_refs**. The source code is as follows. +``` +/**************************************************************************** + * Name: tmpfs_close + ****************************************************************************/ + +static int tmpfs_close(FAR struct file *filep) +{ + FAR struct tmpfs_file_s *tfo; + int ret; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Decrement the reference count on the file */ + + DEBUGASSERT(tfo->tfo_refs > 0); + if (tfo->tfo_refs > 0) + { + tfo->tfo_refs--; + } + + filep->f_priv = NULL; + + /* If the reference count decremented to zero and the file has been + * unlinked, then free the file allocation now. + */ + + if (tfo->tfo_refs == 0 && (tfo->tfo_flags & TFO_FLAG_UNLINKED) != 0) + { + /* Free the file object while we hold the lock? Weird but this + * should be safe because the object is unlinked and could not + * have any other references. + */ + + kmm_free(tfo); + return OK; + } + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return OK; +} +``` +

+ +## read +### Description +Reads content from a file to a specified buffer, which is similar to using the **read** system call in user mode. +

+ +### Source Code Analysis +The source code of the **read** interface is as follows. It calls **memcpy** to copy the content in a specified position of the file to the provided user buffer. +``` +/**************************************************************************** + * Name: tmpfs_read + ****************************************************************************/ + +static ssize_t tmpfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct tmpfs_file_s *tfo; + ssize_t nread; + off_t startpos; + off_t endpos; + int ret; + + finfo("filep: %p buffer: %p buflen: %lu\n", + filep, buffer, (unsigned long)buflen); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Handle attempts to read beyond the end of the file. */ + + startpos = filep->f_pos; + nread = buflen; + endpos = startpos + buflen; + + if (endpos > tfo->tfo_size) + { + endpos = tfo->tfo_size; + nread = endpos - startpos; + } + + /* Copy data from the memory object to the user buffer */ + + memcpy(buffer, &tfo->tfo_data[startpos], nread); + filep->f_pos += nread; + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return nread; +} +``` +

+ +## write +### Description +Writes the content in a specified buffer to a file, which is similar to using the **write** system call in user mode. +

+ +### Source Code Analysis +This interface calls **memcpy** to copy the content in the user buffer to a specified position of the file. If the file space is insufficient, the **tmpfs_realloc_file** function is called to expand the capacity first. The source code of the **write** interface is as follows: +``` +/**************************************************************************** + * Name: tmpfs_write + ****************************************************************************/ + +static ssize_t tmpfs_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct tmpfs_file_s *tfo; + ssize_t nwritten; + off_t startpos; + off_t endpos; + int ret; + + finfo("filep: %p buffer: %p buflen: %lu\n", + filep, buffer, (unsigned long)buflen); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Handle attempts to write beyond the end of the file */ + + startpos = filep->f_pos; + nwritten = buflen; + endpos = startpos + buflen; + + if (endpos > tfo->tfo_size) + { + /* Reallocate the file to handle the write past the end of the file. */ + + ret = tmpfs_realloc_file(&tfo, (size_t)endpos); + if (ret < 0) + { + goto errout_with_lock; + } + + filep->f_priv = tfo; + } + + /* Copy data from the memory object to the user buffer */ + + memcpy(&tfo->tfo_data[startpos], buffer, nwritten); + filep->f_pos += nwritten; + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return nwritten; + +errout_with_lock: + tmpfs_unlock_file(tfo); + return (ssize_t)ret; +} +``` +

+ +## seek +### Description +Obtains or moves the position of a file pointer, which is similar to using the **lseek** system call in user mode. +

+ +### Source Code Analysis +In tmpfs, the **f_pos** member indicates the position of the current file pointer. When the file is opened, **f_pos** is cleared or added to the end of the file as required. The source code of the **seek** interface is as follows: +``` +/**************************************************************************** + * Name: tmpfs_seek + ****************************************************************************/ + +static off_t tmpfs_seek(FAR struct file *filep, off_t offset, int whence) +{ + FAR struct tmpfs_file_s *tfo; + off_t position; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Map the offset according to the whence option */ + + switch (whence) + { + case SEEK_SET: /* The offset is set to offset bytes. */ + position = offset; + break; + + case SEEK_CUR: /* The offset is set to its current location plus + * offset bytes. */ + position = offset + filep->f_pos; + break; + + case SEEK_END: /* The offset is set to the size of the file plus + * offset bytes. */ + position = offset + tfo->tfo_size; + break; + + default: + return -EINVAL; + } + + /* Attempts to set the position beyond the end of file will + * work if the file is open for write access. + * + * REVISIT: This simple implementation has no per-open storage that + * would be needed to retain the open flags. + */ + +#if 0 + if (position > tfo->tfo_size && (tfo->tfo_oflags & O_WROK) == 0) + { + /* Otherwise, the position is limited to the file size */ + + position = tfo->tfo_size; + } +#endif + + /* Save the new file position */ + + filep->f_pos = position; + return position; +} +``` +

+ +## mkdir +### Description +Creates a directory, which is similar to using the **mkdir** system call in user mode. +

+ +### Source Code Analysis +The source code of the **write** interface is as follows. It calls **tmpfs_create_directory** to create a directory. Its implementation has been described in preceding sections. +``` +/**************************************************************************** + * Name: tmpfs_mkdir + ****************************************************************************/ + +static int tmpfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, + mode_t mode) +{ + FAR struct tmpfs_s *fs; + int ret; + + finfo("mountpt: %p relpath: %s mode: %04x\n", mountpt, relpath, mode); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Create the directory. */ + + ret = tmpfs_create_directory(fs, relpath, NULL); + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## opendir +### Description +Opens a directory, which is similar to using the **opendir** system call in user mode. +

+ +### Source Code Analysis +The source code of the **opendir** interface is as follows. By calling **tmpfs_find_directory**, it finds a specified directory, returns the directory structure to the upper level that calls **opendir**, and returns the processed directory structure to the user. +``` +/**************************************************************************** + * Name: tmpfs_opendir + ****************************************************************************/ + +static int tmpfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *tdo; + int ret; + + finfo("mountpt: %p relpath: %s dir: %p\n", + mountpt, relpath, dir); + DEBUGASSERT(mountpt != NULL && relpath != NULL && dir != NULL); + + /* Get the mountpoint private data from the inode structure */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Skip over any leading directory separators (shouldn't be any) */ + + for (; *relpath == '/'; relpath++); + + /* Find the directory object associated with this relative path. + * If successful, this action will lock both the parent directory and + * the file object, adding one to the reference count of both. + * In the event that -ENOENT, there will still be a reference and + * lock on the returned directory. + */ + + ret = tmpfs_find_directory(fs, relpath, &tdo, NULL); + if (ret >= 0) + { + dir->u.tmpfs.tf_tdo = tdo; + dir->u.tmpfs.tf_index = tdo->tdo_nentries; + + tmpfs_unlock_directory(tdo); + } + + /* Release the lock on the file system and return the result */ + + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## closedir +### Description +Closes a directory opened using **opendir**, which is similar to using the **closedir** system call in user mode. +

+ +### Source Code Analysis +The source code of the **closedir** interface is as follows. It subtracts the value of **tdo_refs** that increases when **tmpfs_find_object** is called during the **opendir** operation. +``` +/**************************************************************************** + * Name: tmpfs_closedir + ****************************************************************************/ + +static int tmpfs_closedir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_directory_s *tdo; + + finfo("mountpt: %p dir: %p\n", mountpt, dir); + DEBUGASSERT(mountpt != NULL && dir != NULL); + + /* Get the directory structure from the dir argument */ + + tdo = dir->u.tmpfs.tf_tdo; + DEBUGASSERT(tdo != NULL); + + /* Decrement the reference count on the directory object */ + + tmpfs_lock_directory(tdo); + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + return OK; +} +``` +

+ +## readdir +### Description +Reads a directory opened using **opendir**, which is similar to using the **readdir** system call in user mode. +

+ +### Source Code Analysis +The source code of the **readdir** interface is as follows. It uses **tf_index** obtained during the **opendir** operation to access the **dirent** in the target directory from back to front, and then the index decreases automatically. +``` +/**************************************************************************** + * Name: tmpfs_readdir + ****************************************************************************/ + +static int tmpfs_readdir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_directory_s *tdo; + unsigned int index; + int ret; + + finfo("mountpt: %p dir: %p\n", mountpt, dir); + DEBUGASSERT(mountpt != NULL && dir != NULL); + + /* Get the directory structure from the dir argument and lock it */ + + tdo = dir->u.tmpfs.tf_tdo; + DEBUGASSERT(tdo != NULL); + + tmpfs_lock_directory(tdo); + + /* Have we reached the end of the directory? */ + + index = dir->u.tmpfs.tf_index; + if (index-- == 0) + { + /* We signal the end of the directory by returning the special error: + * -ENOENT + */ + + finfo("End of directory\n"); + ret = -ENOENT; + } + else + { + FAR struct tmpfs_dirent_s *tde; + FAR struct tmpfs_object_s *to; + + /* Does this entry refer to a file or a directory object? */ + + tde = &tdo->tdo_entry[index]; + to = tde->tde_object; + DEBUGASSERT(to != NULL); + + if (to->to_type == TMPFS_DIRECTORY) + { + /* A directory */ + + dir->fd_dir.d_type = DTYPE_DIRECTORY; + } + else /* to->to_type == TMPFS_REGULAR) */ + { + /* A regular file */ + + dir->fd_dir.d_type = DTYPE_FILE; + } + + /* Copy the entry name */ + + strncpy(dir->fd_dir.d_name, tde->tde_name, NAME_MAX); + + /* Save the index for next time */ + + dir->u.tmpfs.tf_index = index; + ret = OK; + } + + tmpfs_unlock_directory(tdo); + return ret; +} +``` +

+ +## unlink +### Description +Deletes a file, which is similar to using the **unlink** system call in user mode. +

+ +### Source Code Analysis +The source code of the **unlink** interface is as follows. It calls **tmpfs_find_file** to find the target file and its directory, and then calls **tmpfs_remove_dirent** to delete the **dirent** of the target file from the directory. Then, it checks the value of **tfo_refs** of the file. If the value is less than or equal to **1**, **kmm_free** is called to release the memory occupied by the target file. +``` +/**************************************************************************** + * Name: tmpfs_unlink + ****************************************************************************/ + +static int tmpfs_unlink(FAR struct inode *mountpt, FAR const char *relpath) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *tdo; + FAR struct tmpfs_file_s *tfo = NULL; + FAR const char *name; + int ret; + + finfo("mountpt: %p relpath: %s\n", mountpt, relpath); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Find the file object and parent directory associated with this relative + * path. If successful, tmpfs_find_file will lock both the file object + * and the parent directory and take one reference count on each. + */ + + ret = tmpfs_find_file(fs, relpath, &tfo, &tdo); + if (ret < 0) + { + goto errout_with_lock; + } + + DEBUGASSERT(tfo != NULL); + + /* Get the file name from the relative path */ + + name = strrchr(relpath, '/'); + if (name != NULL) + { + /* Skip over the file '/' character */ + + name++; + } + else + { + /* The name must lie in the root directory */ + + name = relpath; + } + + /* Remove the file from parent directory */ + + ret = tmpfs_remove_dirent(tdo, name); + if (ret < 0) + { + goto errout_with_objects; + } + + /* If the reference count is not one, then just mark the file as + * unlinked + */ + + if (tfo->tfo_refs > 1) + { + /* Make the file object as unlinked */ + + tfo->tfo_flags |= TFO_FLAG_UNLINKED; + + /* Release the reference count on the file object */ + + tfo->tfo_refs--; + tmpfs_unlock_file(tfo); + } + + /* Otherwise we can free the object now */ + + else + { + nxsem_destroy(&tfo->tfo_exclsem.ts_sem); + kmm_free(tfo); + } + + /* Release the reference and lock on the parent directory */ + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + tmpfs_unlock(fs); + + return OK; + +errout_with_objects: + tmpfs_release_lockedfile(tfo); + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + +errout_with_lock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## rmdir +### Description +Deletes a directory, which is similar to using the **rmdir** system call in user mode. +

+ +### Source Code Analysis +The source code of the **rmdir** interface is as follows. It calls **tmpfs_find_directory** to search for a target directory. If there are files in the target directory or the target directory is opened by another process, it returns an error code and stops. The rest procedures are similar to those of **unlink**. +``` +/**************************************************************************** + * Name: tmpfs_rmdir + ****************************************************************************/ + +static int tmpfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *parent; + FAR struct tmpfs_directory_s *tdo; + FAR const char *name; + int ret; + + finfo("mountpt: %p relpath: %s\n", mountpt, relpath); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Find the directory object and parent directory associated with this + * relative path. If successful, tmpfs_find_file will lock both the + * directory object and the parent directory and take one reference count + * on each. + */ + + ret = tmpfs_find_directory(fs, relpath, &tdo, &parent); + if (ret < 0) + { + goto errout_with_lock; + } + + /* Is the directory empty? We cannot remove directories that still + * contain references to file system objects. No can we remove the + * directory if there are outstanding references on it (other than + * our reference). + */ + + if (tdo->tdo_nentries > 0 || tdo->tdo_refs > 1) + { + ret = -EBUSY; + goto errout_with_objects; + } + + /* Get the directory name from the relative path */ + + name = strrchr(relpath, '/'); + if (name != NULL) + { + /* Skip over the fidirectoryle '/' character */ + + name++; + } + else + { + /* The name must lie in the root directory */ + + name = relpath; + } + + /* Remove the directory from parent directory */ + + ret = tmpfs_remove_dirent(parent, name); + if (ret < 0) + { + goto errout_with_objects; + } + + /* Free the directory object */ + + nxsem_destroy(&tdo->tdo_exclsem.ts_sem); + kmm_free(tdo); + + /* Release the reference and lock on the parent directory */ + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + tmpfs_unlock(fs); + + return OK; + +errout_with_objects: + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + +errout_with_lock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## rename +### Description +Renames a file or directory, which is similar to using the **rename** system call in user mode. +

+ +### Source Code Analysis +The source code of the **rename** interface is as follows. **oldrelpath** and **newrelpath** transferred by **tmpfs_rename** are processed absolute paths. The interface first checks that **newrelpath** is in the root directory, and then the parent directory is the root file system. Otherwise, it calls the **tmpfs_find_directory** function to search for the new parent directory corresponding to the new file name, and then calls the **tmpfs_find_dirent** function to check whether the new file exists in the new parent directory. If the file exists, an error code is returned; otherwise, it searches for the parent directory corresponding to the old file name and the structure of the file and deletes the **dirent** corresponding to the old file name from the old parent directory. After that, it associates the **dirent** corresponding to the new file name with the file structure and adds the **dirent** to the new parent directory. In this way, the **rename** operation is complete. +``` +/**************************************************************************** + * Name: tmpfs_rename + ****************************************************************************/ + +static int tmpfs_rename(FAR struct inode *mountpt, + FAR const char *oldrelpath, + FAR const char *newrelpath) +{ + FAR struct tmpfs_directory_s *oldparent; + FAR struct tmpfs_directory_s *newparent; + FAR struct tmpfs_object_s *to; + FAR struct tmpfs_s *fs; + FAR const char *oldname; + FAR char *newname; + FAR char *copy; + int ret; + + finfo("mountpt: %p oldrelpath: %s newrelpath: %s\n", + mountpt, oldrelpath, newrelpath); + DEBUGASSERT(mountpt != NULL && oldrelpath != NULL && newrelpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Duplicate the newpath variable so that we can modify it */ + + copy = strdup(newrelpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + kmm_free(copy); + return ret; + } + + /* Separate the new path into the new file name and the path to the new + * parent directory. + */ + + newname = strrchr(copy, '/'); + if (newname == NULL) + { + /* No subdirectories... use the root directory */ + + newname = copy; + newparent = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + tmpfs_lock_directory(newparent); + newparent->tdo_refs++; + } + else + { + /* Terminate the parent directory path */ + + *newname++ = '\0'; + + /* Locate the parent directory that should contain this name. + * On success, tmpfs_find_directory() will lockthe parent + * directory and increment the reference count. + */ + + ret = tmpfs_find_directory(fs, copy, &newparent, NULL); + if (ret < 0) + { + goto errout_with_lock; + } + } + + /* Verify that no object of this name already exists in the destination + * directory. + */ + + ret = tmpfs_find_dirent(newparent, newname); + if (ret != -ENOENT) + { + /* Something with this name already exists in the directory. + * OR perhaps some fatal error occurred. + */ + + if (ret >= 0) + { + ret = -EEXIST; + } + + goto errout_with_newparent; + } + + /* Find the old object at oldpath. If successful, tmpfs_find_object() + * will lock both the object and the parent directory and will increment + * the reference count on both. + */ + + ret = tmpfs_find_object(fs, oldrelpath, &to, &oldparent); + if (ret < 0) + { + goto errout_with_newparent; + } + + /* Get the old file name from the relative path */ + + oldname = strrchr(oldrelpath, '/'); + if (oldname != NULL) + { + /* Skip over the file '/' character */ + + oldname++; + } + else + { + /* The name must lie in the root directory */ + + oldname = oldrelpath; + } + + /* Remove the entry from the parent directory */ + + ret = tmpfs_remove_dirent(oldparent, oldname); + if (ret < 0) + { + goto errout_with_oldparent; + } + + /* Add an entry to the new parent directory. */ + + ret = tmpfs_add_dirent(&newparent, to, newname); + +errout_with_oldparent: + oldparent->tdo_refs--; + tmpfs_unlock_directory(oldparent); + + tmpfs_release_lockedobject(to); + +errout_with_newparent: + newparent->tdo_refs--; + tmpfs_unlock_directory(newparent); + +errout_with_lock: + tmpfs_unlock(fs); + kmm_free(copy); + return ret; +} +``` +

+ + +# Summary +This document introduces basic data structures of tmpfs and several common system calls based on their NuttX source code. The content of NuttX tmpfs is simple, and with its complete functions, it can be used as a reference for learning complex file systems in Linux. +
+ +# Recommended Articles +**glibc malloc series articles** +    Principle analysis: +     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90.html
+    Data structure: +     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90.html
+    malloc: +     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%BA%8C).html
+    free: +     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%B8%89).html
+
+ +**Articles about glibc fault locating and analysis** +    Analysis of the VM performance deterioration when running memcpy to copy 1,000 bytes in the x86_64 environment: +     https://www.openeuler.org/zh/blog/wangshuo/memcpy_1k%E5%AD%97%E8%8A%82x86_64%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%88%86%E6%9E%90.html
+    Call stack fault analysis: +     https://www.openeuler.org/zh/blog/wangshuo/glibc%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D--%E6%8E%A8%E6%A0%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html
+ +    glibc locale usage: +     https://www.openeuler.org/zh/blog/wangshuo/glibc%20locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90/glibc+locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90.html
\ No newline at end of file diff --git a/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/nuttx.jpg b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/nuttx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff6bde1a1d1693a0c6fabb8c03a874d78582cdf0 Binary files /dev/null and b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/nuttx.jpg differ diff --git a/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/tmpfs.jpg b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/tmpfs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1fd30102b027343730b7e0508c0ee4a9772d14fd Binary files /dev/null and b/web-ui/docs/en/blog/wangshuo/Introduction to NuttX tmpfs/tmpfs.jpg differ diff --git a/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/Linux_Futex_Principle_Analysis.md b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/Linux_Futex_Principle_Analysis.md new file mode 100644 index 0000000000000000000000000000000000000000..80b6a3e7431f9bd0b1d3f5050e9c23bcec023ce5 --- /dev/null +++ b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/Linux_Futex_Principle_Analysis.md @@ -0,0 +1,313 @@ +--- +title: Linux Futex Principle Analysis +date: 2021-06-1 +tags: + - linux + - kernel + - futex +archives: 2021-06 +author: wangshuo +Summary: Introduction to the basic functions of futex based on the source code. +--- +# Overview +Fast userspace mutexes, or futex, is a concept that adds atomic check in user mode to determine whether to enter the kernel for waiting. This document describes the basic functions of the futex based on the Linux source code. +
+ +The software information is as follows: +| Item | Version | +| :------------------------------------:| :--------------------------------------------------------------: | +| OS | openEuler 20.03 (LTS) | +| Kernel | 4.19.90-2003.4.0.0036.oe1.aarch64 | +| glibc | 2.28 | +| gcc | 7.3.0 | +

+ + +# Principles +Futex is a synchronization mechanism that combines user and kernel modes to synchronize lock operations between threads in a process and between processes. Threads share virtual memory space so the virtual address can uniquely identify the futex variable, that is, threads use the same virtual address to access the futex variable. Because processes have independent virtual memory space, the futex variable is used only when MMAP () allows processes to share an address space. + +During process synchronization, a piece of memory is shared between synchronized processes through mmap. The futex variable is located in this shared memory and the operation is atomic. When the process tries to enter or exit the mutex area, it checks the futex variable in the shared memory. If there is no competition, only the futex is modified, and no system calls are executed; otherwise, you must execute a system call to complete the corresponding processing. + +futex_wait is called when a task is made to wait, while futex_wake is called when the task needs to wake up. The two functions implement the basic futex mechanism. The simplified definition is as follows: + +``` +//Uaddr points to an address, and val represents the expected value of the address. When *uaddr==val, wait occurs. +int futex_wait(int *uaddr, int val); + +//Wake up n pending processes on lock variables pointed to by uaddr +int futex_wake(int *uaddr, int n); +``` +
+ +# Data Structures +As mentioned above, the futex variable is created in the user space and shared between processes or threads. When a process or thread wants to enter the critical section, the futex variable is checked. If the futex variable meets the required conditions, the process or thread enters the critical section; otherwise, the process or thread is blocked on the futex variable. When the process or thread is about to exit the critical section, other processes or threads that are blocked on the futex variable are woken up. In the kernel, a futex variable is associated with a suspended process (thread) by using the struct futex_q structure. The definition and functions of key members are as follows: +``` +struct futex_q { + struct plist_node list; // Linked list node + struct task_struct *task; // Suspended process (thread) associated with the futex variable + spinlock_t *lock_ptr; // Spin lock, which controls the access to the linked list + union futex_key key; // Flag of the futex variable address + + //The following three items are related to priority inheritance and are not described here. + struct futex_pi_state *pi_state; + struct rt_mutex_waiter *rt_waiter; + union futex_key *requeue_pi_key; + + u32 bitset; // Mask matching +}; +``` +
+ +In the kernel, a global hash table is used to maintain all processes (threads) that are suspended on the futex variable. A futex variable calculates a hash key based on the address identifier and locates a bucket, and all suspended/blocked processes and threads that are on the same futex variable correspond to the same bucket. The data structure is as follows: +``` +//bucket +struct futex_hash_bucket { + // Number of waiters in the current spin waiting hash bucket + atomic_t waiters; + + // Spin lock, which is used to control chain access, + // lock_ptr in struct futex_q is the spin lock that references the bucket where the lock is located. + spinlock_t lock; + + // Priority chain. Different from the traditional waiting queue, the futex uses the priority linked list to implement the waiting queue. + //The purpose is to implement priority inheritance and solve the priority inversion problem. + struct plist_head chain; +} ____cacheline_aligned_in_smp; + +// Global hash table +static struct { + struct futex_hash_bucket *queues; + unsigned long hashsize; +} __futex_data __read_mostly __aligned(2*sizeof(long)); +#define futex_queues (__futex_data.queues) +#define futex_hashsize (__futex_data.hashsize) +``` +
+ +The bucket corresponding to the process (thread) is the value of the global hash table. The key of the hash table is as follows: +``` +union futex_key { + struct { + u64 i_seq; + unsigned long pgoff; + unsigned int offset; + } shared; // Different processes share the futex variable through file sharing, indicating the location of the variable in the file. + + struct { + union { + struct mm_struct *mm; + u64 __tmp; + }; + unsigned long address; + unsigned int offset; + } private; // Different threads of the same process share the futex variable, indicating the position of the variable in the process address space. + + struct { + u64 ptr; + unsigned long word; + unsigned int offset; + } both; +}; +``` +
+futex_key is a structure of the union type and can be used by processes and threads. The futex fills in the futex_key based on the user-mode uaddr and process (thread) information, calculates a global hash table index using the jhash, and maps the index to a bucket. Processes/threads that attempt to obtain the same futex are mapped to the same bucket, and other processes/threads in the bucket linked list are found based on the value of futex_key. + +The following figure shows the relationships between the structures. + +
+

+ +# Source Code Analysis +## Pre-Futex Operations +The source code for futex initialization is as follows. Initialization is complete upon kernel startup. The initialization content is simple. A fixed number of buckets are applied for and managed by the global hash table__futex_data, and then the spin lock of the linked list of each bucket is initialized. +``` +static int __init futex_init(void) +{ + + ... + +#if CONFIG_BASE_SMALL + futex_hashsize = 16; +#else + futex_hashsize = roundup_pow_of_two(256 * num_possible_cpus()); +#endif + + futex_queues = alloc_large_system_hash("futex", sizeof(*futex_queues), + futex_hashsize, 0, + futex_hashsize < 256 ? HASH_SMALL : 0, + &futex_shift, NULL, + futex_hashsize, futex_hashsize); + futex_hashsize = 1UL << futex_shift; + + futex_detect_cmpxchg(); + + for (i = 0; i < futex_hashsize; i++) { + atomic_set(&futex_queues[i].waiters, 0); + plist_head_init(&futex_queues[i].chain); + spin_lock_init(&futex_queues[i].lock); + } + + return 0; +} +core_initcall(futex_init); +``` +
+ +After the futex system call enters the kernel, it calls do_futex first. The source code is as follows: in user mode, input parameters (such as the number of input parameters and specific operations) need to be determined. The kernel determines operations to be performed based on the input parameters. This document is an introductory post of futex and only introduces futex_wait and futex_wake. +``` +long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, + u32 __user *uaddr2, u32 val2, u32 val3) +{ + int cmd = op & FUTEX_CMD_MASK; + unsigned int flags = 0; + + ... + + switch (cmd) { + case FUTEX_WAIT: + val3 = FUTEX_BITSET_MATCH_ANY; + fallthrough; + case FUTEX_WAIT_BITSET: + return futex_wait(uaddr, flags, val, timeout, val3); + case FUTEX_WAKE: + val3 = FUTEX_BITSET_MATCH_ANY; + fallthrough; + case FUTEX_WAKE_BITSET: + return futex_wake(uaddr, flags, val, val3); + case FUTEX_REQUEUE: + return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0); + case FUTEX_CMP_REQUEUE: + return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0); + case FUTEX_WAKE_OP: + return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3); + case FUTEX_LOCK_PI: + return futex_lock_pi(uaddr, flags, timeout, 0); + case FUTEX_UNLOCK_PI: + return futex_unlock_pi(uaddr, flags); + case FUTEX_TRYLOCK_PI: + return futex_lock_pi(uaddr, flags, NULL, 1); + case FUTEX_WAIT_REQUEUE_PI: + val3 = FUTEX_BITSET_MATCH_ANY; + return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3, + uaddr2); + case FUTEX_CMP_REQUEUE_PI: + return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1); + } + return -ENOSYS; +} +``` +

+ +## futex_wait Analysis +The following figure shows the execution process of the futex. +
+

+Below shows the futex source code, which we can analyze based on the preceding flowchart. In timeout scenarios, futex_wait sets the timer using futex_setup_timer, and then invokes the futex_wait_setup function, which obtains the key of the global hash table based on the input parameter to find the related bucket and obtain the spin lock. It also checks whether the uaddr value is the expected value before the task enters the queue. If uaddr is updated to an unexpected value, futex _wait returns to the user mode to obtain the lock. Otherwise, futex_wait invokes futex_wait_queue_me to insert the current task into the waiting queue, start the scheduled task, and trigger rescheduling. When the task can be executed, the task determines how it is woken up and releases the hrtimer to exit. + +``` +static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, + ktime_t *abs_time, u32 bitset) +{ + + ... + + to = futex_setup_timer(abs_time, &timeout, flags, + current->timer_slack_ns); +retry: + /* + * Prepare to wait on uaddr. On success, holds hb lock and increments + * q.key refs. + */ + ret = futex_wait_setup(uaddr, val, flags, &q, &hb); + if (ret) + goto out; + + /* queue_me and wait for wakeup, timeout, or a signal. */ + futex_wait_queue_me(hb, &q, to); + + /* If we were woken (and unqueued), we succeeded, whatever. */ + ret = 0; + /* unqueue_me() drops q.key ref */ + if (!unqueue_me(&q)) + goto out; + ret = -ETIMEDOUT; + if (to && !to->task) + goto out; + + /* + * We expect signal_pending(current), but we might be the + * victim of a spurious wakeup as well. + */ + if (!signal_pending(current)) + goto retry; + + ret = -ERESTARTSYS; + if (!abs_time) + goto out; + + ... + +out: + if (to) { + hrtimer_cancel(&to->timer); + destroy_hrtimer_on_stack(&to->timer); + } + return ret; +} +``` +

+ +## futex_wake Analysis +The futex_wake process is as follows: +
+

+ +The futex_wake source code is as follows. It uses get_futex_key to generate the key of the global hash table and uses hash_futex to find the corresponding bucket (same as futex_wait_setup). Then, futex_wake traverses the bucket, finds the task waiting in the current futex based on the key, and obtains the task from the bucket and places it in the temporary queue wake_q. Then, it releases the spin lock of the bucket and wakes up tasks in wake_q one by one. +``` +static int +futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) +{ + + ... + + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ); + if (unlikely(ret != 0)) + return ret; + + hb = hash_futex(&key); + + /* Make sure we really have tasks to wakeup */ + if (!hb_waiters_pending(hb)) + return ret; + + spin_lock(&hb->lock); + + plist_for_each_entry_safe(this, next, &hb->chain, list) { + if (match_futex (&this->key, &key)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + break; + } + + /* Check if one of the bits is set in both bitsets */ + if (!(this->bitset & bitset)) + continue; + + mark_wake_futex(&wake_q, this); + if (++ret >= nr_wake) + break; + } + } + + spin_unlock(&hb->lock); + wake_up_q(&wake_q); + return ret; +} +``` +

+ +# Summary +Based on the source code of futex in Linux, this document briefly describes two basic functions of futex: futex_wait and futex_wake. Other implementations related to futex will be introduced later. +

+ + diff --git a/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex.jpg b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99c94f57a596c0fc686b02a8a5cc4a7e77ef42e0 Binary files /dev/null and b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex.jpg differ diff --git a/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wait.jpg b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wait.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5acaa0ee0916b5c2f6ee22715428d7f7ed86cd6 Binary files /dev/null and b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wait.jpg differ diff --git a/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wake.jpg b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wake.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6c080f69f484c5ff422a32cd576bd998d83cb0f Binary files /dev/null and b/web-ui/docs/en/blog/wangshuo/Linux_Futex_Principle_Analysis/futex_wake.jpg differ diff --git a/web-ui/docs/en/blog/wangshuo/glibc Bugs - Fault Analysis of malloc Call Stack.md b/web-ui/docs/en/blog/wangshuo/glibc Bugs - Fault Analysis of malloc Call Stack.md new file mode 100644 index 0000000000000000000000000000000000000000..3eee994c0818395ebe983b77cc742a1534830efe --- /dev/null +++ b/web-ui/docs/en/blog/wangshuo/glibc Bugs - Fault Analysis of malloc Call Stack.md @@ -0,0 +1,383 @@ +--- +title: glibc Bugs - Fault Analysis of malloc Call Stack +date: 2021-03-13 +tags: + - glibc +archives: 2021-03 +author: wangshuo +summary: Uses a case to describe the glibc community bugs and fixing policy, and introduces the push-to-stack functionality in the AArch64 architecture. +--- + +# 1 Overview +Assume the malloc function is used by GDB to obtain the call stack, but the call stack information is not displayed due to a community bug. A modification solution is submitted to the community, and the bug is fixed in version 2.28-50. The following describes the cause and solution of this bug. +The software information is as follows: +|
Software
|
Version
| +| :------------------------------------:| :--------------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1.aarch64
| +|
glibc
|
2.28
| +|
GCC
|
7.3.0
| +

+ +# 2. Issue Description +In a service scenario, when the malloc function runs in the call stack, the stack information at the application layer is lost. However, this is not caused by the **-fomit-frame-pointer** option because the debuginfo package is installed and the unwinding algorithms are used. +``` +(gdb) b malloc +Breakpoint 2 at 0xfffff7e0d198: malloc. (2 locations) +(gdb) c +Continuing. + +Thread 2 "xxxxxxx" hit Breakpoint 2, __GI___libc_malloc (bytes=10532) at malloc.c:3039 +3039 = atomic_forced_read (__malloc_hook); +(gdb) bt +#0 __GI___libc_malloc (bytes=10532) at malloc.c:3039 +#1 0x0000fffff7fce484 in allocate_dtv_entry (size=, alignment=64) + at dl-tls.c:594 +#2 allocate_and_init (map=0x4212c0) at dl-tls.c:607 +#3 tls_get_addr_tail (ti=0x424050, dtv=0x425200, the_map=0x4212c0) at dl-tls.c:787 +#4 0x0000fffff7fd2e90 in _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:214 +#5 0x0000fffff6dfab44 in OurFunction (threadId=10532) + at /home/test/test_function.c:30 +#6 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +``` +
+ +According to the preceding information, the malloc function is not directly invoked, but indirectly invoked by **dltlsdesc_dynamic** provided by glibc when a value is assigned to the thread variable. After referring to some documentation and service requirements, we found that the initialization of thread local storage (TLS) is involved during the process. The probable cause is **dltlsdesc_dynamic** instead of the malloc function. +We then ran this specific scenario as a demo and reproduced the problem, and confirmed that the problem is caused by **_dl_tlsdesc_dynamic** under **sysdeps/aarch64/dl-tlsdesc.S.** Specifically, the push-to-stack fails after **_dl_tlsdesc_dynamic** is invoked. But there are two exceptions. The first exception is as follows: + +``` +Thread 2 "xxxxxxx" hit Breakpoint 1, _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +149 stp x1, x2, [sp, #-32]! +Missing separate debuginfos, use: dnf debuginfo-install libgcc-7.3.0-20190804.h24.aarch64 +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +150 stp x3, x4, [sp, #16] +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +157 mrs x4, tpidr_el0 +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +``` +But the call stack information is restored after line 150 is executed. The second exception is as follows: +``` +Thread 2 "xxxxxxx" hit Breakpoint 1, _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +149 stp x1, x2, [sp, #-32]! +Missing separate debuginfos, use: dnf debuginfo-install libgcc-7.3.0-20190804.h24.aarch64 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +150 stp x3, x4, [sp, #16] +(gdb) +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +157 mrs x4, tpidr_el0 +(gdb) +158 ldr PTR_REG (1), [x0,#TLSDESC_ARG] +(gdb) +159 ldr PTR_REG (0), [x4,#TCBHEAD_DTV] +(gdb) +160 ldr PTR_REG (3), [x1,#TLSDESC_GEN_COUNT] +(gdb) +161 ldr PTR_REG (2), [x0,#DTV_COUNTER] +(gdb) +162 cmp PTR_REG (3), PTR_REG (2) +(gdb) +163 b.hi 2f +(gdb) +165 ldp PTR_REG (2), PTR_REG (3), [x1,#TLSDESC_MODID] +(gdb) +166 add PTR_REG (0), PTR_REG (0), PTR_REG (2), lsl #(PTR_LOG_SIZE + 1) +(gdb) +167 ldr PTR_REG (0), [x0] /* Load val member of DTV entry. */ +(gdb) +168 cmp PTR_REG (0), #TLS_DTV_UNALLOCATED +(gdb) +169 b.eq 2f +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:169 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=4294967295) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:184 +184 stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]! +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:184 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=4294967295) + at /home/test/test_function.c:30 +#2 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +``` +From line 184, the call stack information cannot be printed until **_dl_tlsdesc_dynamic** exits. + + +# 3. Function Calling Process +The following describes the calling process of **_dl_tlsdesc_dynamic**. The exceptions occur in the **sysdeps/aarch64/dl-tlsdesc.S** directory, and are related to the **_dl_tlsdesc_dynamic** architecture and subsequent assembly language. And the developers related comments of C++ language during code writing. See the following: +``` + /* Handler for dynamic TLS symbols. + Prototype: + _dl_tlsdesc_dynamic (tlsdesc *) ; + + The second word of the descriptor points to a + tlsdesc_dynamic_arg structure. + + Returns the offset between the thread pointer and the + object referenced by the argument. + + ptrdiff_t + __attribute__ ((__regparm__ (1))) + _dl_tlsdesc_dynamic (struct tlsdesc *tdp) + { + struct tlsdesc_dynamic_arg *td = tdp->arg; + dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + TCBHEAD_DTV); + if (__builtin_expect (td->gen_count <= dtv[0].counter + && (dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED), + 1)) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset + - __thread_pointer; + + return ___tls_get_addr (&td->tlsinfo) - __thread_pointer; + } + */ +``` +
+ +From the preceding information, this function is used to return the offset between the thread pointer and the referenced parameter object through the **fast path** or **slow path**. If the generated count variable exceeds the maximum and TLS initialization is complete, the **fast path** is used. Otherwise, **slow path** is used, which leads to the aforementioned issues. Specifically, the first exception occurs when **_dl_tlsdesc_dynamic** is invoked, and the second exception occurs when the script attempts to run **slow path**. In addition, we tried to compile demos that do not depend on the service scenario to reproduce the slow path logic, but failed. We would be grateful if you could provide any suggestions or feedback. + + +# 4 Introduction to the Call Stack +This problem is related to the push-to-stack operation in the ARM architecture, which is why we briefly introduce the basic principles in the following section. +## 4.1 Register and Assembly Instruction +Take AArch64 as an example. AArch64 has 31 general-purpose registers, which are named **X*n*** in 64-bit system and **W*n*** in 32-bit system. The registers are classified into parameter (X0 to X7), temporary (X9 to X15), callee-saved (X19 to X29), and special-purpose registers (X8, X16 to X18, X29, and X30), based on the subsequent functions. The following uses special-purpose registers as examples: +    X8: indirect result register, which is used to store the return address of the subprogram. +    X16 and X17: temporary registers invoked in the program +    X18: platform register, which is reserved for the platform +    X29: frame pointer register (FP) +    X30: link register (LR) +    X31: stack pointer register (SP) or zero register (ZXR) +
+ +## 4.2 Push-to-Stack Principle +The following shows the call stack when the main function calls **func1**. Each function has its own stack space called a stack frame. It is created when the function is called and destroyed after the function is returned. During the process, four registers (PC, LR, SP, and FP) are involved. Note that the values of PC, LR, SP, and FP registers in each stack frame are historical values, not the current ones. +``` + ________________ /_________________ + | | \ | + memory: | PC | | +high address |________________| | + /|\ | | | + | | LR | | + | |________________| | + | | | | + | | SP | | + | |________________| | + | | | | + | | FP | | + | |________________| | + | | | | + | main | main:argc | | + | |________________| | + | | | | + | | main:argv | | + | |________________| | + | | | | + | | main:val:i | | + | |________________| | + | | | | + | | main:val:j | | + | |________________| | + | | | | + | | func1 param | | + | ________\ |________________| /________ | + | / | | \ | | + | | PC | | | + | |________________| | | + | | | | | + | | LR | | | + | |________________| | | + | func1 | | _________| | + | | SP | | + | |________________| | + | | | _________________| + | | FP | + | |________________| + | | | + | | func1 val:p1 | + | |________________| + | | | + memory: | func1 val:p2 | +low address |________________| + | | + | func1 val:p3 | + |________________| + Top of Stack +``` +
+Both the PC and LR registers point to a code segment. PC indicates where the current code points, and LR indicates indicates the location to be executed after the function is returned. The SP and FP registers are used to maintain the stack space of the function, where SP points to the stack top, and FP points to the stack top of a previous function stack frame. If the function is ready to invoke another function, the parameters of the function to be invoked must be saved in the temporary variable area beforehand. The FP register, mainly used for stack trace, is used to locate the stack bottom of the next FP register to obtain the PC pointer for offset fixing, helping to trace an early PC pointer. In this way, the entire running process of the function can be traced. + + +# 5 Solution Overview +## 5.1 Conclusion +After fault locating and analysis, we determined that this problem is a community defect. We have submitted patches (commit IDs: cd62740 and f5082c7) to the community. For details, see the following links: +https://sourceware.org/pipermail/libc-alpha/2021-January/121272.html
+https://sourceware.org/pipermail/libc-alpha/2021-January/121330.html

+ +## 5.2 Analysis +The aforementioned exceptions are caused by two bugs after fault locating. The following describes the two bugs. +The first exception occurs when the script calls **_dl_tlsdesc_dynamic**. The involved code is as follows: +``` +144 _dl_tlsdesc_dynamic: +145 DELOUSE (0) +146 +147 /* Save just enough registers to support fast path, if we fall +148 into slow path we will save additional registers. */ +149 stp x1, x2, [sp, #-32]! +150 stp x3, x4, [sp, #16] +151 cfi_adjust_cfa_offset (32) +152 cfi_rel_offset (x1, 0) +153 cfi_rel_offset (x2, 8) +``` +Specifically, when line 150 is executed, the push-to-stack operation fails. After the execution is complete, the push-to-stack can be performed normally. Note that line 151 is actually a CFI macro, which is not executed. It is used to notify the debugger of the compilation of the current canonical frame address (CFA) and the base CFA of the invoked function. (CFA can be also referred to the stack pointer of the upper-level caller.) +Before line 151 is executed, the STP operations are performed twice. Line 149 indicates that the values of the X1 and X2 registers are saved to the SP with a 32-bit offset. Equally, the SP is also offset. Because the stack is expanded from a high to a low address, the value of SP is **–32**. In line 150, the values of the X3 and X4 registers are added to the stack, but SP is not updated. SP is updated at line 149, but the original code does not notify the debugger of the change as needed. As a result, the push-to-stack at line 150 fails. To solve the first exception, declarations are made after line 150 is executed, ensuring the subsequent push-to-stack can be performed normally by adjusting the position of the CFI macro. + +When locating the second exception, we found that it occurred after the jump ends. The corresponding code is as follows: +``` +169 b.eq 2f +170 sub PTR_REG (3), PTR_REG (3), PTR_REG (4) +171 add PTR_REG (0), PTR_REG (0), PTR_REG (3) +172 1: +173 ldp x3, x4, [sp, #16] +174 ldp x1, x2, [sp], #32 +175 cfi_adjust_cfa_offset (-32) +176 RET +177 2: +178 /* This is the slow path. We need to call __tls_get_addr() which +179 means we need to save and restore all the register that the +180 callee will trash. */ +181 +182 /* Save the remaining registers that we must treat as caller save. */ +183 # define NSAVEXREGPAIRS 8 +184 stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]! +185 cfi_adjust_cfa_offset (16*NSAVEXREGPAIRS) +186 cfi_rel_offset (x29, 0) +187 cfi_rel_offset (x30, 8) +``` +Specifically, when line 169 jumps to line 184, the push-to-stack cannot be normally performed until the function exists. Another file with similar functions is found in the same directory. Its source code is as follows: +``` +sysdeps/aarch64/dl-trampoline.S + +219 bge 1f +220 cfi_remember_state +221 +222 /* Save the return. */ +223 mov ip0, x0 +224 +225 /* Get arguments and return address back. */ +226 ldp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0] +227 ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] +228 ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] +229 ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +230 ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +231 ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +232 ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +233 ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] +234 +235 cfi_def_cfa_register (sp) +236 ldp x29, x30, [x29, #0] +237 cfi_restore(x29) +238 cfi_restore(x30) +239 +240 add sp, sp, SF_SIZE + 16 +241 cfi_adjust_cfa_offset (- SF_SIZE - 16) +242 +243 /* Jump to the newly found address. */ +244 br ip0 +245 +246 cfi_restore_state +247 1: +248 /* The new frame size is in ip0. */ +``` +
+ +In the code, the **cfi_remember_state** and **cfi_restore_state** macros are used in lines 220 and 246. According to the descriptions of the two macros provided at the binutils official website, if push-to-stack is required in the AArch64 architecture, **cfi_remember_state** is used to save the status of the registers to be used before the jump, and then **cfi_restore_state** is used to restore status after the jump. The second exception can be resolved after adding these two macros. +``` +7.11.20 .cfi_remember_state and .cfi_restore_state +.cfi_remember_state pushes the set of rules for every register onto an implicit stack, while .cfi_restore_state pops them off the stack and places them in the current row. This is useful for situations where you have multiple .cfi_* directives that need to be undone due to the control flow of the program. For example, we could have something like this (assuming the CFA is the value of rbp): + + je label + popq %rbx + .cfi_restore %rbx + popq %r12 + .cfi_restore %r12 + popq %rbp + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 + ret +label: + /* Do something else */ +Here, we want the .cfi directives to affect only the rows corresponding to the instructions before label. This means we'd have to add multiple .cfi directives after label to recreate the original save locations of the registers, as well as setting the CFA back to the value of rbp. This would be clumsy, and result in a larger binary size. Instead, we can write: + + je label + popq %rbx + .cfi_remember_state + .cfi_restore %rbx + popq %r12 + .cfi_restore %r12 + popq %rbp + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 + ret +label: + .cfi_restore_state + /* Do something else */ +That way, the rules for the instructions after label will be the same as before the first .cfi_restore without having to use multiple .cfi directives. +``` +
+ +# 6. Summary +This problem is unprecedented as the bugs are found in the code submitted to the community. With this cause, we were able to solve problems by referring to the logic of the normal code and related materials. This method is also applicable to other uncommon problems. + +# References +binutils official description: https://sourceware.org/binutils/docs/as/CFI-directives.html +ARMv8-AArch64 registers and instruction sets: https://winddoing.github.io/post/7190.html +Analysis and implementation of backtrace on ARM: https://cloud.tencent.com/developer/article/1599605 +Unwinding stack trace: https://blog.csdn.net/pwl999/article/details/107569603 +
+ +# Recommended Articles Related to glibc +**glibc malloc series articles**: +     Principle Description: https://cutt.ly/NzcDUEd +    Data Structure: https://cutt.ly/JzcSBfB. +    malloc: https://cutt.ly/TzcSjUX +    free: https://cutt.ly/QzcSy5G +
+ +**Articles about glibc fault locating and analysis**: +    Analysis of the VM performance deterioration when running memcpy to copy 1,000 bytes in the x86_64 environment: https://cutt.ly/8zcDyPi +
+ +Usage of glibc locale: https://cutt.ly/wxoH9OG +
diff --git "a/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces.md" "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces.md" new file mode 100644 index 0000000000000000000000000000000000000000..1d1c55da67bad032912adcd7225b87a1a8cf512b --- /dev/null +++ "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces.md" @@ -0,0 +1,380 @@ +--- +title: 'musl Source Code Analysis: Introduction to fopen Series Interfaces' +date: 2021-05-19 +tags: + - musl + - fopen +archives: 2021-05 +author: wangshuo +summary: Introduction to the principles of the fopen series interfaces based on the musl source code +--- +# About This Document +musl is a C standard library intended for OSs built on the Linux kernel. It contains the interfaces defined in POSIX and mainstream extensions. Compared with glibc, musl is faster, simpler, and more lightweight and protocol-friendly. This document uses the fopen series interfaces of musl to describe basic operations on files based on musl source code. + +# Data Structures +The following shows the key data structure of a file involving musl. The structure is FILE. This document focuses on four function pointers (close, read, write, and seek) and five position pointers (rpos and rend for read and wend, wpos, and wbase for write.) +``` +struct _IO_FILE { + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE *); + unsigned char *wend, *wpos; + unsigned char *mustbezero_1; + unsigned char *wbase; + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + unsigned char *buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long lockcount; + int mode; + volatile int lock; + int lbf; + void *cookie; + off_t off; + char *getln_buf; + void *mustbezero_2; + unsigned char *shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + struct __locale_struct *locale; +}; +``` + + +# Interfaces +## fopen +The fopen source code is as follows. This interface first determines the file opening mode and uses the open system call to obtain a file descriptor (FD) from the kernel. Then, it encapsulates the FD into a FILE using the __fdopen function before mounting the default functions on the four function pointers (close, read, write, and seek). +The following figure shows the initial status of the FILE structure. The first part is the main body of FILE; the second part is a reserved area **UNGET** for non-buffering scenarios (8 bytes by default); and the third displays the buffer reserved by musl (1024 bytes by default). + +``` +FILE *fopen(const char *restrict filename, const char *restrict mode) +{ + FILE *f; + int fd; + int flags; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + /* Compute the flags to pass to open() */ + flags = __fmodeflags(mode); + + fd = sys_open(filename, flags, 0666); + if (fd < 0) return 0; + if (flags & O_CLOEXEC) + __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + f = __fdopen(fd, mode); + if (f) return f; + + __syscall(SYS_close, fd); + return 0; +} + +... + +FILE *__fdopen(int fd, const char *mode) +{ + ... + + /* Allocate FILE+buffer or fail */ + if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return 0; + + /* Zero-fill only the struct, not the buffer */ + memset(f, 0, sizeof *f); + + ... + + f->fd = fd; + f->buf = (unsigned char *)f + sizeof *f + UNGET; + f->buf_size = BUFSIZ; + + ... + + /* Initialize op ptrs. No problem if some are unneeded. */ + f->read = __stdio_read; + f->write = __stdio_write; + f->seek = __stdio_seek; + f->close = __stdio_close; + + ... + +} +``` +

+ +
+

+ +## fclose +The fclose source code is as follows (only key steps are presented). This interface flushes data from the write buffer to the file and calls the close function __stdio_close using **f->close(f)**. It then closes the file corresponding to the FD by using system calls before releasing externally encapsulated data structures. +``` +int fclose(FILE *f) +{ + int r; + + FLOCK(f); + r = fflush(f); + r |= f->close(f); + FUNLOCK(f); + + ... + + free(f->getln_buf); + free(f); + + return r; +} + +... + +int __stdio_close(FILE *f) +{ + return syscall(SYS_close, __aio_close(f->fd)); +} +``` + + +## fread +The fread interface calls the read pointer function (a member in _IO_FILE) that is initialized during the fopen phase. The source code of this function is as follows. This process is used to read data whose length is *len* to the user buffer and preread a part of the data to the FILE buffer. +Based on the initialization of the iov structure array, the first element is the user buffer, and the second is the FILE buffer. That is, the data is read to the user buffer first and then to the FILE buffer. The data that is read to the FILE buffer is less than or equal to 1023 bytes by default. +The reason it is not 1024 bytes is because the start address length of the first element of the iov structure array is subtracted by 1. That is, iov reads a maximum of *len* – 1 elements. The last element is placed in iov[1] and reassigned to buf[len – 1] at the end. In this way, the rpos pointer is offset by one byte, indicating that there is preread data in the FILE buffer. The following figure shows the pointers after the preread operation (the three pointers related to the write operation are null). + +
+

+ +``` +size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) +{ + struct iovec iov[2] = { + { .iov_base = buf, .iov_len = len - !!f->buf_size }, + { .iov_base = f->buf, .iov_len = f->buf_size } + }; + ssize_t cnt; + + cnt = iov[0].iov_len ? syscall(SYS_readv, f->fd, iov, 2) + : syscall(SYS_read, f->fd, iov[1].iov_base, iov[1].iov_len); + if (cnt <= 0) { + f->flags |= cnt ? F_ERR : F_EOF; + return 0; + } + if (cnt <= iov[0].iov_len) return cnt; + cnt -= iov[0].iov_len; + f->rpos = f->buf; + f->rend = f->buf + cnt; + if (f->buf_size) buf[len-1] = *f->rpos++; + return len; +} +``` + + +The source code of the fread interface is as follows. As mentioned, the __stdio_read function prereads data. fread reads data from the FILE buffer by calling the memcpy function first. If insufficient, it then calls __stdio_read to read data from the file. +``` +size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) +{ + unsigned char *dest = destv; + size_t len = size*nmemb, l = len, k; + if (!size) nmemb = 0; + + FLOCK(f); + + f->mode |= f->mode-1; + + if (f->rpos != f->rend) { + /* First exhaust the buffer. */ + k = MIN(f->rend - f->rpos, l); + memcpy(dest, f->rpos, k); + f->rpos += k; + dest += k; + l -= k; + } + + /* Read the remainder directly */ + for (; l; l-=k, dest+=k) { + k = __toread(f) ? 0 : f->read(f, dest, l); + if (!k) { + FUNLOCK(f); + return (len-l)/size; + } + } + + FUNLOCK(f); + return nmemb; +} +``` + +fread calls the __toread function before calling __stdio_read. The following shows the source code of __toread. This function serves as the switch between the read and write modes. Because the read and write operations share the same buffer, if the previous operation is write, data in the write buffer needs to be flushed to the file and the three write-related pointers need to be cleared before the read operation is performed. In addition, the __toread function is used to check whether the file is readable. +``` +int __toread(FILE *f) +{ + f->mode |= f->mode-1; + if (f->wpos != f->wbase) f->write(f, 0, 0); + f->wpos = f->wbase = f->wend = 0; + if (f->flags & F_NORD) { + f->flags |= F_ERR; + return EOF; + } + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; +} +``` + +## fwrite +This section analyzes the source code of the __stdio_write function, which is used to write data in the user buffer to the FILE buffer. After the FILE buffer is full, the data is written to the file. Compared with __stdio_read, __stdio_write is simpler. The following figure shows the positions of the FILE pointers when an __stdio_write operation is complete and the FILE buffer is not full. +``` +size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) +{ + struct iovec iovs[2] = { + { .iov_base = f->wbase, .iov_len = f->wpos-f->wbase }, + { .iov_base = (void *)buf, .iov_len = len } + }; + struct iovec *iov = iovs; + size_t rem = iov[0].iov_len + iov[1].iov_len; + int iovcnt = 2; + ssize_t cnt; + for (;;) { + cnt = syscall(SYS_writev, f->fd, iov, iovcnt); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; + return len; + } + if (cnt < 0) { + f->wpos = f->wbase = f->wend = 0; + f->flags |= F_ERR; + return iovcnt == 2 ? 0 : len-iov[0].iov_len; + } + rem -= cnt; + if (cnt > iov[0].iov_len) { + cnt -= iov[0].iov_len; + iov++; iovcnt--; + } + iov[0].iov_base = (char *)iov[0].iov_base + cnt; + iov[0].iov_len -= cnt; + } +} +``` +

+ +
+

+Next shows the source code of the fwrite interface. __towrite can also be used to switch between the read and write modes. If the remaining space of the write buffer is insufficient, fwrite calls the __stdio_write function. If the buffer space is sufficient, data is directly written to the buffer by calling memcpy. + +``` +size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) +{ + size_t i=0; + + if (!f->wend && __towrite(f)) return 0; + + if (l > f->wend - f->wpos) return f->write(f, s, l); + + if (f->lbf >= 0) { + /* Match /^(.*\n|)/ */ + for (i=l; i && s[i-1] != '\n'; i--); + if (i) { + size_t n = f->write(f, s, i); + if (n < i) return n; + s += i; + l -= i; + } + } + + memcpy(f->wpos, s, l); + f->wpos += l; + return l+i; +} + +size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) +{ + size_t k, l = size*nmemb; + if (!size) nmemb = 0; + FLOCK(f); + k = __fwritex(src, l, f); + FUNLOCK(f); + return k==l ? nmemb : k/size; +} +``` + +Conversely, __towrite is used to switch to the write operation. The source code is as follows. The following includes a bug, which will be described in detail in the following section. +``` +int __towrite(FILE *f) +{ + f->mode |= f->mode-1; + if (f->flags & F_NOWR) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} +``` + +# Weaknesses +By comparing the source code of __towrite and __toread, you can see that they are not symmetric. Specifically, __toread flushes data in the write buffer to the file through **f->write(f, 0, 0)** before switching to the read mode. However, __towrite clears read-related pointers (rpos and rend) before switching to the write mode. To note the differences, let's see the following operations: + +|
Step
|
Action
|
Expected Position
|
Actual Position
| +|:------------------------------------:|:--------------------------------------:|:--------------------------------------:|:--------------------------------------:| +|
1
|
Write 30 bytes.
|
30
|
30
| +|
2
|
Return to the beginning.
|
0
|
0
| +|
3
|
Read 15 bytes.
|
15
|
15
| +|
4
|
Write 15 bytes.
|
30
|
45
| + + +If you use fgetpos to obtain the position of the current file pointer after step 4 is complete, you can see that the actual position is **45** instead of the expected position **30**. The last 15 bytes of the file are expected to be overwritten in step 4. However, 15 bytes are directly added, and the actual position becomes **45**. Why? +As mentioned, the fread interface prereads some data. Therefore, when reading 15 bytes of data in step 3, it actually reads 30 bytes, that is, the entire file. The following code shows why the result of step 3 is correct: + +``` +off_t __ftello_unlocked(FILE *f) +{ + off_t pos = f->seek(f, 0, + (f->flags & F_APP) && f->wpos != f->wbase + ? SEEK_END : SEEK_CUR); + if (pos < 0) return pos; + + /* Adjust for data in buffer. */ + if (f->rend) + pos += f->rpos - f->rend; + else if (f->wbase) + pos += f->wpos - f->wbase; + return pos; +} +``` + +fgetpos calls the __ftello_unlocked function to obtain the file's real position from the kernel through system calls, and then performs correction. Specifically, the read operation is performed in step 3, and therefore the rend pointer is not null. ftello_unlocked subtracts data that is preread. Therefore, no error occurs in step 3. However, in step 4, the towrite function clears the read pointers, and the 15 bytes of data is directly placed in the FILE buffer. During the next read operation, the 15 bytes of data is directly added to the end of the file. +To solve this problem, move back to the position before the preread phase and before __towrite clears the read pointers. + +# Summary +This document analyzes the implementation of fopen series interfaces based on the musl source code. Compared with glibc, musl source code is simpler, but still contains imperfections. For more information, see the following recommended articles. + +# Recommended Articles +**glibc malloc series articles** +Principle analysis: +[https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90.html](https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90.html) +Data structure: +[https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90.html](https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90.html) +malloc: +[https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%BA%8C).html](https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%BA%8C).html) +free: +[https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%B8%89).html](https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%B8%89).html) + +**Articles about glibc fault locating and analysis** +Analysis of the VM performance deterioration when running memcpy to copy 1,000 bytes in the x86_64 environment: +[https://www.openeuler.org/zh/blog/wangshuo/memcpy_1k%E5%AD%97%E8%8A%82x86_64%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%88%86%E6%9E%90.html](https://www.openeuler.org/zh/blog/wangshuo/memcpy_1k%E5%AD%97%E8%8A%82x86_64%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%88%86%E6%9E%90.html) +Call stack fault analysis: +[https://www.openeuler.org/zh/blog/wangshuo/glibc%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D--%E6%8E%A8%E6%A0%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html](https://www.openeuler.org/zh/blog/wangshuo/glibc%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D--%E6%8E%A8%E6%A0%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html) +glibc locale usage: +[https://www.openeuler.org/zh/blog/wangshuo/glibc%20locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90/glibc+locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90.html](https://www.openeuler.org/zh/blog/wangshuo/glibc%20locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90/glibc+locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90.html) \ No newline at end of file diff --git "a/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/original.jpg" "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/original.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..38c93ef47b5c67c0b9cc102dbfc1b6095b428bbc Binary files /dev/null and "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/original.jpg" differ diff --git "a/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/read.jpg" "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/read.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..37d548976990ad0c67e656fb66569daeacc6d635 Binary files /dev/null and "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/read.jpg" differ diff --git "a/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/write.jpg" "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/write.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..050f03f7f8ac5b1c816e3afa1e1967806a6f5e93 Binary files /dev/null and "b/web-ui/docs/en/blog/wangshuo/musl Source Code Analysis \342\200\224 Introduction to fopen Series Interfaces/write.jpg" differ diff --git a/web-ui/docs/en/blog/wangxun/2020-03-25-lifecycle-02.png b/web-ui/docs/en/blog/wangxun/2020-03-25-lifecycle-02.png new file mode 100644 index 0000000000000000000000000000000000000000..74212ce828c419501d83d0b59a22db1c20fc17be Binary files /dev/null and b/web-ui/docs/en/blog/wangxun/2020-03-25-lifecycle-02.png differ diff --git a/web-ui/docs/en/blog/wangxun/openeuler-lifecycle.md b/web-ui/docs/en/blog/wangxun/openeuler-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..5486b0967f1202c14c72c7764c13334f5d4126b4 --- /dev/null +++ b/web-ui/docs/en/blog/wangxun/openeuler-lifecycle.md @@ -0,0 +1,28 @@ +--- +title: openEuler community release rule and life cycle management +date: 2020-03-25 +tags: + - Release + - Lifecycle +archives: 2020-03 +author: WangXun, Technical Committee +summary: openEuler lifecycle. +--- + +# openEuler community release rule and life cycle management + + + +* 社区版本按按照交付年份和月份进行版本号命名。例如,openEuler 20.09于2020年09月发布。 +* openEuler release is named based on the delivery year and month. For example, openEuler 20.09 will be released in September 2020. +* 社区版本分为长期支持版本和创新版本。 +* We have two kinds of release: long-term support release and innovation release. +* 长期支持版本:发布间隔周期定为2年,提供4年社区支持。社区首个LTS版本openEuler 20.03 将于20年3月正式发布。 +* Long-term support release: The release interval is set to two years, and four-year-community-support is provided. OpenEuler 20.03-the first LTS will be officially released in March 2020. +* 社区创新版本:LTS版本之间每隔6个月openEuler会发布一个社区创新版本,提供6个月社区支持。 +* Innovation release: openEuler publishes an innovation version every six months between LTS versions and provides six-month community support. +* 欢迎社区开发者和用户提出宝贵建议,以上规则将根据反馈意见以及社区实施情况不断完善。 +* Developers and users are welcome to provide your valuable suggestions. The rule will be updated based on feedback and implementation. + + + diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-01.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-01.png new file mode 100644 index 0000000000000000000000000000000000000000..8a894a848fb2b1590d5c27bb5a95ce6d1034c5a8 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-01.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-02.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-02.png new file mode 100644 index 0000000000000000000000000000000000000000..15f2c1f344927d4878c3b9c23a816c164c6514ae Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-02.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-03.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-03.png new file mode 100644 index 0000000000000000000000000000000000000000..82856947b3d257b455e26a53dd87561f61071c18 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-03.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-04.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-04.png new file mode 100644 index 0000000000000000000000000000000000000000..37e1d572a5cba29fe3c61abd5d14ea7e14b4ad54 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-04.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-05.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-05.png new file mode 100644 index 0000000000000000000000000000000000000000..2e09265e6a71ef394862250ad6d4c26b0912c6c6 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-05.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-06.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-06.png new file mode 100644 index 0000000000000000000000000000000000000000..ffee25ccf4ef86e6af314b8acd34795790d62d73 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-06.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-07.png b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-07.png new file mode 100644 index 0000000000000000000000000000000000000000..1b6986fb2d2ae470cc6ec7efe489607024668220 Binary files /dev/null and b/web-ui/docs/en/blog/zhengyaohui/2022-03-21-ci_guild-07.png differ diff --git a/web-ui/docs/en/blog/zhengyaohui/Access Control Function Guide.md b/web-ui/docs/en/blog/zhengyaohui/Access Control Function Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..910a3c70c8baa47218049d2959e90725d7c3f347 --- /dev/null +++ b/web-ui/docs/en/blog/zhengyaohui/Access Control Function Guide.md @@ -0,0 +1,202 @@ +--- +title: Access Control Function Guide +date: 2022-03-21 +tags: + - Access control + - openEuler + - src-openEuler +sig: sig-Gatekeeper +archives: 2022-03 +author: zhengyaohui +summary: This document describes the openEuler access control function, helping openEuler community contributors submit their code efficiently. +--- +# 1 Introduction to the Access Control Function + +## 1.1 Access Control + +The code of the openEuler community is hosted on Gitee. To ensure the code quality, when you submit a pull request (PR) on Gitee, the access control system is automatically triggered to check the coding specifications and build, installation, and interface changes. Then, the access control check result is returned to the PR comment, helping you locate problems and maintainers review code. + +For the open-source access control code, visit https://gitee.com/openeuler/openeuler-jenkins. + +## 1.2 src-openEuler Access Control Check Items + +### 1.2.1 Access Control Triggering Conditions + +Submit a PR for the first time, leave a comment, or retest. + + + +### 1.2.2 Access Control Notification + + + +Click the links to view real-time access control building logs. + +### 1.2.3 Access Control Check Results + +Basic check items + + + + + +Interface change check items + + + + +Table 1 lists the six basic check items of the access control system. Interface change check items are separately displayed because there are many sub-items. + +### 1.2.4 Corresponding Code Locations of the Access Control Check Items + +| Check Item | Function Description | Code Location | +| ----------------------- | ------------------------ | ------------------------------------------------------------ | +| check_binary_file | Binary file check | [check_binary_file.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/binary/check_binary_file.py) | +| check_package_license | License validity check | [check_spec.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/spec/check_spec.py), [Licenses.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_license/config/Licenses.yaml)| +| check_package_yaml_file | YAML file format check | [check_yaml.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_yaml/check_yaml.py), [check_repo.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_yaml/check_repo.py)| +| check_spec_file | SPEC file format check | [check_spec.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/spec/check_spec.py) | +| check_build | Package build check | [osc_build_k8s.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/osc_build_k8s.py)| +| check_install | Checks whether the package after being built can be installed. | [extra_work.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/extra_work.py) | +| compare_package | Checks interface changes in the 64-bit x86 environment. | [compare_package.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/utils/compare_package.py) | + +In addition, the access control system supports the optional configuration of check items (check_code_style, check_package_license, check_package_yaml_file, and check_spec_file). The configuration file is stored in [ac.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/framework/ac.yaml). Code related to the PR output of each check item is stored in [gitee_comment.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/gitee_comment.py). + +### 1.2.5 Basic Check Items and the Functions + +| Check Item | Function | SUCCESS | FAILED | WARNING | +| ----------------------- | ---------------------------- | ------------------------------------------------------------ | ------------------- | ----------------------------------------------- | +| check_binary_file | Checks whether binary files exist in the repository. | The repository does not contain .pyc, .jar, .ko, or .o file (including files in compressed packages but excluding files provided by the upstream community in the form of links). | The SUCCESS condition is not met.| N/A | +| check_package_license | Checks the license validity. | All licenses are in the trustlist, and the source code is consistent with that of the licenses listed in the SPEC file. | A license in the blocklist is found. | All licenses are in the trustlist, but the source code is inconsistent with that of the licenses listed in the SPEC file.| +| check_package_yaml_file | Checks the YAML file format. | The **version_control**, **src_repo**, **tag_prefix** and **separator** fields are complete, and the content of the **version_control** field is the same as the domain name specified in the **url** field in the SPEC file.| The SUCCESS condition is not met.| N/A | +| check_spec_file | Checks the validity of the SPEC file. | If the version number remains unchanged, the release number must be incremented; if the version number changes, the release number must be set to 1. All patches must be used during compilation, and the **changelog** format must be correct.| The SUCCESS condition is not met.| N/A | +| check_build | Verifies the build result. | The RPM package is successfully built. | The SUCCESS condition is not met.| N/A | +| check_install | Verifies the installation. | The RPM package is successfully installed. | The SUCCESS condition is not met.| N/A | + +### 1.2.6 Interface Change Check Items and Functions + +| Check Item | Function | SUCCESS | FAILED | WARNING | +| ------------ | ------------------------------------------- | ------------------------------------------------------------ | ------------------- | ------- | +| add_rpms | Checks whether RPM packages are added in the PR. | Compared with the last successfully merged PR in the same branch, no RPM package is added in the PR. | The SUCCESS condition is not met.| N/A | +| delete_rpms | Checks whether the RPM package is deleted in the PR. | Compared with the last successfully merged PR in the same branch, no RPM package is deleted in the PR. | The SUCCESS condition is not met.| N/A | +| rpm_files | Checks whether files are added to or deleted from RPM packages generated in the PR. | Compared with the last successfully merged PR in the same branch, the file list of each RPM package remains unchanged. (File contents are not checked.) | The SUCCESS condition is not met.| N/A | +| rpm_provides | Checks whether the components in RPM packages generated in the PR change. | Compared with the last successfully merged PR in the same branch, the component names in each RPM package remain unchanged. | The SUCCESS condition is not met.| N/A | +| rpm_requires | Checks whether the dependencies of the RPM package generated in the PR change. | Compared with the last successfully merged PR in the same branch, the dependency names of each RPM package remain unchanged. | The SUCCESS condition is not met.| N/A | +| check_abi | Checks whether the binary interfaces (C++) of the RPM package generated in the PR change. | Compared with the last successfully merged PR in the same branch, the binary interfaces of each RPM package remain unchanged. | The SUCCESS condition is not met.| N/A | +| check_jabi | Checks whether the binary interfaces (Java) of the RPM package generated in the PR change. | Compared with the last successfully merged PR in the same branch, the binary interfaces of each RPM package remain unchanged. | The SUCCESS condition is not met.| N/A | +| check_kabi | Checks whether the binary interfaces (kernel) of the RPM package generated in the PR change. | Compared with the last successfully merged PR in the same branch, the binary interfaces of each RPM package remain unchanged. | The SUCCESS condition is not met.| N/A | + +## 1.3 openEuler Access Control Check Items + +### 1.3.1 Access Control Check Results + + + +### 1.3.2 Access Control Code Locations Corresponding to the Check Items + +| Check Item | Function Description | Code Location | +| -------------- | ------------------------------- | ------------------------------------------------------------ | +| check_code | Coding specification check | [check_code.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/openlibing/check_code.py) | +| check_sca | Code snippet scan | [check_sca.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/sca/check_sca.py) | +| x86-64/*repository_name* | Package build check in the 64-bit x86 environment | Implemented by maintainers and does not belong to the access control code. | +| aarch64/*repository_name*| Package build check in the AArch64 environment| Implemented by maintainers and does not belong to the access control code. | + +In addition, the access control system supports the optional configuration of check items (check_openlibing and check_sca). The configuration file is stored in [ac.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/framework/ac.yaml). Code related to the PR output of each check item is stored in [gitee_comment.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/gitee_comment.py). + +Currently, check_openlibing is implemented by calling the remote service (https://majun.osinfra.cn:8384/api/openlibing/codecheck), and check_sca is implemented by calling the remote service (https://sca-beta.osinafra.cn). + +# 2 FAQs and False Alarm Feedback + +## 2.1 Division of Access Control Responsibilities + +| Responsibility | Owner | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| General contact person for access control | [Zheng Yaohui](https://gitee.com/open_euler/dashboard/members/zhengyaohui) | +| Maintainers of the community repository | [Cao Zhi](https://gitee.com/open_euler/dashboard/members/georgecao), [Liu Qi](https://gitee.com/open_euler/dashboard/members/liuqi469227928), [Zhao Chunjiang](https://e.gitee.com/open_euler/members/trend/dakang_siji) | +| Maintenance personnel of the obs_meta repository | [Dong Jie](https://e.gitee.com/open_euler/members/trend/dongjie110) | +| Maintenance personnel of the release_management repository | [Dong Jie](https://e.gitee.com/open_euler/members/trend/dongjie110) | +| Maintenance personnel of single-repository access control for software packages | [Wang Huan](https://e.gitee.com/open_euler/members/trend/wanghuan158), [Cheng Shaowei](https://e.gitee.com/open_euler/members/trend/MementoMoriCheng), [Zheng Yaohui](https://gitee.com/open_euler/dashboard/members/zhengyaohui) | +| Infrastructure maintenance personnel (including OBS, Gitee, Jenkins basic services, hardware, and network) | [Cao Zhi](https://gitee.com/open_euler/dashboard/members/georgecao), [Liu Qi](https://gitee.com/open_euler/dashboard/members/liuqi469227928), [Zhao Chunjiang](https://e.gitee.com/open_euler/members/trend/dakang_siji) | +| OBS project maintenance personnel | [Wang Chong](https://gitee.com/open_euler/dashboard/members/wangchong1995924), [Xia Senlin](https://e.gitee.com/open_euler/members/trend/small_leek), [Zhou Xiaxiang](https://e.gitee.com/open_euler/members/trend/zhouxiaxiang) | +| Majun platform maintenance personnel | Zhang Yaxiong | + +Note: +1. The code snippet scan (check_sca) and coding specification check (check_code) in the software package single-repository access control check are implemented by calling the Majun platform service. + +2. The maintenance personnel responsible for single-repository access control of software packages are the contact persons of corresponding problems on the openEuler and src-openEuler platforms. For OBS or infrastructure service problems, contact the corresponding maintenance personnel. For common problems and solutions, see [Access Control Troubleshooting Manual](https://gitee.com/openeuler/openeuler-jenkins/blob/master/doc/%E9%97%A8%E7%A6%81%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%89%8B%E5%86%8C.md). + +## 2.2 Access Control Result Feedback + +If you have any doubts about access control results, contact the related owner. We will solve the problem as soon as possible. If the problem cannot be solved quickly, you can submit an issue to the access control repository ([https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins)) to track the progress. After that, you can provide feedback on false alarms through PR comments. The statistics help us do better in the future. + +Format of comments for marking false alarms: **/ci_unmistake build_no** or **/ci_mistake build_no **. + +Note: + +1. **ci_mistake** is used to mark a false alarm, and **ci_unmistake** is used to withdraw the mark. Either **ci_mistake** or **ci_unmistake** must be specified. +2. **build_no** indicates the build number of a trigger project. When the access control starts, the access control task link and build number are printed in the comment. One PR can have multiple build results. Therefore, the build numbers are used to distinguish the build results. This parameter is mandatory. +3. **mistake_type** indicates the false alarm type. This parameter is optional. You can select **ci** (access control), **obs**, or **infra** (infrastructure) or leave it blank. +4. **ci_mistake_stage** indicates the phase in which the false alarm is generated. This parameter is optional. You can select one or more items from check_binary_file, check_package_license, check_package_yaml_file, check_spec_file, check_build, check_install, compare_package, and build_exception, or leave it blank. All items except build_exception correspond to access control check items. build_exception indicates that the access control system runs abnormally (for example, the access control result is not returned). +5. The sequence of **mistake_type** and **ci_mistake_stage** can be changed. + +# 3 Access Control Code Rollout Process + +Perform the three steps in sequence: 1. Submit a PR to the access control code repository and contact a maintainer for merging; 2. Generate a tag for the submission (contact the maintainer); 3. Update the container image (contact access control personnel [Wang Huan](https://e.gitee.com/open_euler/members/trend/wanghuan158), [Wei Shaowei](https://e.gitee.com/open_euler/members/trend/MementoMoriCheng), [Zheng Yaohui](https://gitee.com/open_euler/dashboard/members/zhengyaohui)). In a few cases, the access control personnel need to modify the Jenkins configuration. + +## 3.1 Submitting and Merging a PR + +The access control code is stored in [https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins). Contact a maintainer to integrate the code. + +## 3.2 Generating a Tag + +Theoretically, a tag can be generated for each commit. However, because not all PRs need to be merged and rolled out immediately, you do not need to generate a tag for each commit. + + + +## 3.3 Generate a container image. + +Currently, the access control environment is included in the container image. Therefore, each time you update the access control code, you must update the container image code as well. The image version is distinguished by tags. + +# 4 Running Node Customization + +## 4.1 Current Node/Image List + + + +The following table lists the nodes related to access control. + +| Node | Project | +| ------------------------------------------------------------ | -------------------------------------- | +| k8s-x86-soe and k8s-aarch64-soe | All access control projects in src-openEuler | +| k8s-x86-oe | The trigger and comment projects in openEuler | +| **k8s-x86-openeuler, k8s-x86-openeuler-20.03-lts, k8s-x86-openeuler-20.03-lts-sp1, k8s-x86-openeuler-20.03-lts-sp2, k8s-x86-openeuler-20.03-lts-sp3, k8s-x86-openeuler-20.09, k8s-x86-openeuler-21.03, k8s-aarch64-openeuler, k8s-aarch64-openeuler-20.03-lts, k8s-aarch64-openeuler-20.03-lts-sp1, k8s-aarch64-openeuler-20.03-lts-sp2, k8s-aarch64-openeuler-20.03-lts-sp3, k8s-aarch64-openeuler-20.09, k8s-aarch64-openeuler-21.03**| **x86-64 and aarch64 build projects in openEuler**| + +Note: +1. All projects in src-openEuler and the trigger and comment projects in openEuler are configured on the access control side and use the same environment. Therefore, the nodes are fixed. + +2. The code executed by the x86-64 and AArch64 build projects in openEuler is managed by the related SIGs and used in different environments. You can select the nodes listed **in bold**. To avoid impacting other Jenkins tasks, do not use other nodes. + + +## 4.2 Node Customization + +You may need to customize access control nodes for some tasks. + +### 4.2.1 The base image lacks dependencies, and the dependency installation is time-consuming. + +Dependencies can be installed during the running of the container environment provided by the access control system. Therefore, you are advised to run the **sudo yum install -y xxx** command in the running script to install a few dependencies. If you need to install a large number of dependencies, submit a dockerfile to the access control repository [https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins). The access control side reviews and integrates the dockerfile, creates an image, and then creates a running node. + +For details about the dockerfile format, visit https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/dockerfile/release-tools-dockerfile. Generally, you only need to modify the first two statements. + +``` +FROM swr.cn-north-4.myhuaweicloud.com/openeuler/openjdk/OPENJDK:TAG +RUN set -eux; \ + yum install -y python3-pip cpio bsdtar expect openssh sudo vim git strace python-jenkins python3-requests python-concurrent-log-handler python3-gevent python3-marshmallow python3-pyyaml python-pandas python-xlrd python-retrying python-esdk-obs-python git +``` + +### 4.2.2 The base image version is not openEuler. + +In addition to compiling the dockerfile, you need to provide the base image of the corresponding version. + +### 4.2.3 The server architecture does not meet requirements. + +In addition to the preceding two requirements, you need to deploy a server of the corresponding architecture, and then perform steps 4.2.1 and 4.2.2. In this case, the access control code needs to be modified. + diff --git a/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-01.png b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-01.png new file mode 100644 index 0000000000000000000000000000000000000000..5749faba4fd48805b22b2fb6c78737f88b7254d9 Binary files /dev/null and b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-01.png differ diff --git a/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-02.png b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-02.png new file mode 100644 index 0000000000000000000000000000000000000000..393ee7ca904b05623e250ea193db836aee7576ca Binary files /dev/null and b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level-02.png differ diff --git a/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level.md b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level.md new file mode 100644 index 0000000000000000000000000000000000000000..740a3c05e5cb4d25895ffe19e1218bf52fd2ba5c --- /dev/null +++ b/web-ui/docs/en/blog/zhongjun/2021-09-15-developer-level.md @@ -0,0 +1,59 @@ +--- +title: Open source community operation metric design exploration +date: 2021-09-15 +tags: + - Infrastructure + - Operation Metric + - Funnel model +archives: 2021-09 +author: openEuler Infrastructure +summary: Open source community operation metric design exploration. +--- + +### Open source community operation metric design exploration + + +#### Preface + +The developer operation process of the open source community is a process of expanding the community user and developer of open source projects. +How to determine the changes in the developer community and how to determine the conversion rate of contributors is the key information we have always hoped to obtain from digital operations. Based on the actual operating experience of openEuler, this article defines the contributors of the open source community hierarchically, hoping to provide a new dimension to observe the health of the community through the data. + +#### Introduction-funnel model + +The operational perspective usually divides the developers whose code hosting platform (github.com or gitee.com) leaves a digital footprint on the project based on their contribution to the open source project, and implements different operating strategies for different developers. +Due to the particularity of the operating system open source community, during the practice of the openEuler project, it was found that developers from the openEuler official website, developers who download and install the operating system, and developers who update software packages on a daily basis do not need an account during the above operations. The inability to confirm the identity results in the inability to track, and during the operation process, only data statistics are performed for this part of the developers. Therefore, developers in the openEuler community are currently limited to developers who have interacted with the openEuler code repository on the code hosting platform, that is, developers who have entered the code repository. + +The openEuler community divides developers into three levels: + +1. **Code contributors (D2)**: narrow contributors, only merged PR (Pull Request) +2. **Contributor (D1)**: A contributor in a broad sense, a developer who merged a PR (Pull Request), submits an Issue, or comments on an issue or PR +3. **Developer (D0)**: Reach contributors, submit PR (Pull Request), submit Issue or comment on issue or PR, Star, Watch, or Fork the code repository + +According to the above classification, the three levels of developers form an inclusive relationship from D0 to D2, thus forming a funnel model. + +**Funnel chart**: showing the conversion rate of each layer +**Active**: Display the number of active developers at each level of the time series according to the time distribution +**By organization**: Display the number of people invested by each organization according to the distribution of the organization + + + + +#### Application-Operated for developers + +Every developer participating in the community is a living individual rather than a cold number in the platform or KPI. Some students operating in the open source community are obsessed with digital operations and ignore the personality of the developer. Every developer is a customer of an operator, and needs to treat each developer's demands with a service mentality, and operate for developers rather than KPI operations. + +**Code contributors (D2)**: Focus on the community growth path and career path of developers, and cultivate maintainer or Evangelist for the project-cultivate developer's **loyalty** to the community +**Contributor (D1)**: Pay attention to the developers' demands for the project's functions, assist the developers to use the project in actual production; solve the developer's communication with the community during the project's technical route and use process-enhance the developer's **trust** in the community +**Developer (D0)**: Belongs to the followers of the project. The focus of operation is to disseminate key information such as the technical characteristics of the project, landing cases and other key information to D0 developers, attracting them to conduct in-depth trials of the project-to capture the developer's **attention** to the community + +At the same time, the changes in the community can also be observed based on the data of the funnel model combined with other operational data: + +Developers participate in cycle changes in open source projects. The developers of open source projects are not stable. They are more like "hard-fought soldiers"-Where new contributors come from and where core contributors are lost, it is also the operator’s changes to the community situation +Observe whether the deep-seated culture and conflict of interest in the community will lead to changes in the role of the open source community, and which characteristics of developers are more likely to grow into the backbone of the community-the identification of key developers is the key for operators to improve operational efficiency + + +#### Summarize + +The operation of the open source community requires complete data support. How to sort out the key model of developers in front of a large amount of data and improve operational efficiency is what openEuler has been exploring in depth. However, any model must conform to the technical characteristics and life cycle of the open source project itself. It is hoped that this model has certain reference significance for the operation of other open source projects. + + diff --git a/web-ui/docs/en/building/README.md b/web-ui/docs/en/building/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f14b76a1efc2719e262f7df6fed2ec51d8db4e0e --- /dev/null +++ b/web-ui/docs/en/building/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/en/community/certification-services/README.md b/web-ui/docs/en/community/certification-services/README.md new file mode 100644 index 0000000000000000000000000000000000000000..57ef1d65d62cc272b0cd28c192b4ed82a94fb75f --- /dev/null +++ b/web-ui/docs/en/community/certification-services/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/en/community/certification-services/down.md b/web-ui/docs/en/community/certification-services/down.md new file mode 100644 index 0000000000000000000000000000000000000000..aff1dd4f4e03e625656105802aef2c2b6114f8e1 --- /dev/null +++ b/web-ui/docs/en/community/certification-services/down.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/en/community/certification-services/search.md b/web-ui/docs/en/community/certification-services/search.md new file mode 100644 index 0000000000000000000000000000000000000000..584078cba784f885ec509e091b66f6b5725569e0 --- /dev/null +++ b/web-ui/docs/en/community/certification-services/search.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/en/community/conduct/README.md b/web-ui/docs/en/community/conduct/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6e4794e96828b8f32426080a1156ba907767eb79 --- /dev/null +++ b/web-ui/docs/en/community/conduct/README.md @@ -0,0 +1,60 @@ +--- +title: "Convention" + +--- + + + +
+ + +The openEuelr community complies with the code of conduct specified in the open source community V1.4. For details, visit the following website: + +If you need to report insults, harassment, or other unacceptable behavior, you can send an email to to contact the openEuler Technical Committee. + +## Commitment of Contributors +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards +Examples of behavior that contributes to creating a positive environment include: + ++ Using welcoming and inclusive language + ++ Being respectful of differing viewpoints and experiences + ++ Gracefully accepting constructive criticism + ++ Focusing on what is best for the community + ++ Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + ++ Use of sexualized language or imagery and unwelcome sexual attention or advances + ++ Trolling, insulting/derogatory comments, and personal or political attacks + ++ Public or private harassment + ++ Publishing others' private information, such as a physical or electronic address, without explicit permission + ++ Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Obligations + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Applicable to + +This Code of Covenant applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces.
+Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
+Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +You can send an e-mail to report abuse, harassment, and misconduct to the project team.
+All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The community team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Project maintainers who do not follow or enforce the Covenant in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +
\ No newline at end of file diff --git a/web-ui/docs/en/community/contribution/README.md b/web-ui/docs/en/community/contribution/README.md new file mode 100644 index 0000000000000000000000000000000000000000..60e6741e88c7499cc190457fdd12dd563b935241 --- /dev/null +++ b/web-ui/docs/en/community/contribution/README.md @@ -0,0 +1,7 @@ +--- +title: "Contribution" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/community/contribution/detail.md b/web-ui/docs/en/community/contribution/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..0ce3bb509e49f35f51f5f96db5bc480f1cc78e4a --- /dev/null +++ b/web-ui/docs/en/community/contribution/detail.md @@ -0,0 +1,145 @@ +--- +title: "Contribution" +--- + + + + +
+ +Welcome to openEuler! + +## 1. Experience openEuler +### 1.1 Experience the openEuler OS + +Experience the openEuler OS in any of the following ways: + +- [Public cloud](https://huaweicloud.com/intl/en-us/product/ecs.html) +- [Virtual machine](https://docs.openeuler.org/en/docs/20.03_LTS/docs/Virtualization/virtualization.html) +- [Hardware](https://docs.openeuler.org/en/docs/20.03_LTS/docs/Installation/Installation.html) +- [Raspberry Pi](https://gitee.com/openeuler/raspberrypi/blob/master/README.en.md) + +### 1.2 Experience Original Open Source Projects + +Experience a range of original open source projects in the openEuler community. + +- [StratoVirt](https://www.openeuler.org/en/other/projects/stratovirt/):An enterprise-grade virtualization platform intended for cloud data centers. +- [A-Tune](https://www.openeuler.org/en/other/projects/atune/):An AI-based intelligent tuning engine. +- [iSula](https://www.openeuler.org/en/other/projects/isula/): A lightweight container solution. +- [secGear](https://www.openeuler.org/en/other/projects/secgear/):A confidential computing security application development suite for the computing industry. +- [pkgship](https://pkgmanage.openeuler.org/):A query tool that manages OS software package dependencies and provides detailed dependency graphs. +- [BiSheng JDK](https://www.openeuler.org/en/other/projects/bishengjdk/):The open source version of Huawei JDK that is developed on the OpenJDK framework. It is a high-performance OpenJDK release that can be used in production environments. +- [Compass-CI](https://compass-ci.openeuler.org/): An open source software platform for sustainable integration, building an open and complete test system. + +## 2. Sign the CLA + +Sign the openEuler community Contributor License Agreement (CLA) before starting community contributions. +Choose an individual CLA, employee CLA, or corporation CLA based on your participation status (click [here](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)) + +- Individual CLA: Join the community as an individual. +- Corporation CLA: Join the community as a corporation. +- Employee CLA: Join the community as an enterprise employee. + +## 3. Join the openEuler Community +### 3.1 Participate in Community Activities + +Learn about and participate in a variety of community activities. + +- [Meeting](https://www.openeuler.org/en/#meeting):View the public meeting schedule of Special Interest Groups (SIGs) on the openEuler homepage and join the meetings you are interested in. +- [Meetups](https://www.openeuler.org/en/interaction/salon-list/) +- [Live](https://www.openeuler.org/en/interaction/live-list/) +- [Summit](https://www.openeuler.org/en/interaction/summit-list/summit2021/) + +### 3.2 Find the SIGs to Participate In +#### 3.2.1 Learn About SIGs and Find the SIGs You Are Interested In +The openEuler community is organized into SIGs to better manage the work processes. SIGs are open to anyone, and finding your perfect SIG is the first step to contributing to community affairs. +Currently, the openEuler community has more than 70 SIGs. View the openEuler [SIG list](https://www.openeuler.org/en/sig/sig-list/) to find the SIG you want to join. +If you cannot find the SIG that you are interested in, send an email to [community@openeuler.org](mailto:community@openeuler.org) It is recommended that you use "[Development Process Issue]" as the heading of the mail and describe the SIGs or projects you are looking for. + +#### 3.2.2 Start a New SIG + +If you fail to find the SIGs you are interested in and want to start a new SIG for maintenance and development in the openEuler community, refer to [Application Process](https://www.openeuler.org/en/sig/sig-guidance/). + +### 3.3 Engage in Community Contributions + +Once you sign the [CLA](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=) and join a [SIG](https://www.openeuler.org/en/sig/sig-list/) you can start your contribution journey. Any contribution, big or small, are welcomed and valued by the community. +##### 1.Submit and Address Issues + +- Find the issue list. + On the Gitee homepage of the SIG project you are interested in, click Issues(for example, the issues of the [Community](https://gitee.com/openeuler/community/issues)) project. +- Submit an issue. + If you want to report bugs, submit requests, or contribute your comments or suggestions to the openEuler community, submit an issue in the corresponding repository of the openEuler community. + For details about how to submit an issue, see the [Issue Submission Guide](https://gitee.com/openeuler/community/blob/master/en/contributors/issue-submit.md). To attract more attention, you can also attach the issue link in an email and send it to everyone through the [Mailing Lists](https://www.openeuler.org/en/community/mailing-list/). +- Participate in the discussion on an issue. + There are discussions among participants under each issue. If you are interested in an issue, you can also post your comments in the comment box. +- Find the issues that you want to address. + If you want to work on one of those issues, you can assign it to yourself. Type /assign or /assign @your_account_name in the comment box. The system will assign the issue to you and your name will appear in the owner list. + +##### 2.Contribute Code + +- Prepare the openEuler development environment. + Prepare an openEuler development environment before contributing code. For details, see [Preparing the Development Environment](https://gitee.com/openeuler/community/blob/master/en/contributors/prepare-environment.md). +- Understand the development precautions of the SIG and the project. + The coding languages, development environments, and coding conventions used by projects of each SIG may vary. If you want to learn about and contribute code, find the project's contributor guide for developers – which is generally available as a CONTRIBUTING.md file on the SIG's homepage, or just in README.md of the project. +- Download code and pull a branch. + Before contributing code, learn how to download code from Gitee and merge code through pull requests (PRs). openEuler code is hosted on the Gitee platform. For details, see [Gitee Workflow](https://gitee.com/openeuler/community/blob/master/en/contributors/Gitee-workflow.md). Gitee is similar to GitHub. If you have used GitHub before, skip this section. +- Perform modification, building, and local validation. + After the modification is complete on the local branch, build and verify the local branch by referring to [Software Package Building](https://gitee.com/openeuler/community/blob/master/en/contributors/package-install.md). +- Create a PR. + Creating a PR means that you are contributing code to the community. For details, see [Creating a Pull Request.](https://gitee.com/openeuler/community/blob/master/en/contributors/pull-requests.md) + To make your PR easier to be accepted, you need to: + - Follow the coding conventions (if any) of the SIG. + - Write good commit messages. + - If you want to commit a large amount of code at a time, it is recommended that you divide the code into a series of smaller pieces, which will make it easier for reviewers to understand your ideas. + - Mark the PR with appropriate SIG and monitor tags. The CI Bot will walk you through the PR process. + +  Note: If your PR does not attract enough attention, you can ask for help through the SIG mailing list or + [dev@openeuler.org](mailto:dev@openeuler.org). + +##### 3.Contribute a Package +If you find that openEuler is missing any software package, you can contribute the software package to the openEuler community. Contributing software packages enhances openEuler functionalities, making openEuler a software ecosystem with anything you need. When a software package is added to openEuler on Gitee, a repository with the same name will be created in openEuler:Factory of OBS. When code is committed to the created Gitee repository, the code compilation is automatically checked. For details, see [Adding a New Software Package](https://gitee.com/openeuler/community/blob/master/en/contributors/create-package.md). +##### 4.Contribute Original Open Source Projects +If you want to contribute your original open source project to the openEuler community and make it a part of the openEuler release, you can use either of the following methods: +- Method 1: Develop a project in another community and integrate it into openEuler. + Assuming that you already have your own projects on GitHub, GitLab, or Gitee, simply add the software to the src-openeuler repository by referring to [Adding a New Software Package](https://gitee.com/openeuler/community/blob/master/en/contributors/create-package.md). +- Method 2: Develop and integrate a project in openEuler. + Creating original projects directly at [https://gitee.com/openeuler](https://gitee.com/openeuler) is similar to "hosting" projects to the openEuler community, such as iSula and A-Tune. + If you have a great idea that you want to implement in the openEuler community, follow the procedure below to get deeply involved in the openEuler community. + 1.Apply for an open source project in [regular meetings of the Technical Committee (TC)](https://www.openeuler.org/en/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org). + 2.If the TC evaluates that it is a good idea and deserves to be promoted, you can set up a repository at [https://gitee.com/openeuler](https://gitee.com/openeuler). + 3.The project will be continuously developed and incubated in openEuler until it matures. Then create a repository in src-openeuler to provide relevant spec files for the project and create an RPM file. + 4.Eventually, your original open source project will be used by people around the world with openEuler releases. + +##### 5.Review Code +openEuler is an open community and everyone involved is expected to be active reviewers. When you are a committer or maintainer of a SIG, you have the responsibility and permission to review code. +Everyone in the community is encouraged to pursue excellence and promote collaboration on the ground of the [Code of Conduct](https://gitee.com/openeuler/community/blob/master/code-of-conduct.md) and mutual respect.[ The Gentle Art Of Patch Review ](https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/) lists a series of review highlights. Code review activities are expected to promote the active participation of new contributors without causing the contributors to be overwhelmed by minor errors at the beginning. Therefore, during the review, focus on the following: + +  1.Whether the idea behind the contribution is reasonable. + +  2.Whether the contribution architecture is correct. + +  3.Whether the contribution is complete. + +##### 6.Test +Testing is the responsibility of all contributors. For the community version, [sig-qa group](https://gitee.com/openeuler/QA) is the official community organization responsible for testing activities. If you want to test on your own infrastructure, refer to [Introduction to the Community Test System](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md) . +To successfully release a community version, you need to complete multiple test activities. The location of the test code varies according to the test activity, so do the details of the environment required for successful test running. For details, see [Test Contribution Guide for Community Developers](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E5%BC%80%E5%8F%91%E8%80%85%E6%B5%8B%E8%AF%95%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97.md). +##### 7.Package Community Components +You can also participate in community component packaging. For details, see [openEuler Packaging Guide](https://gitee.com/openeuler/community/blob/master/en/contributors/packaging.md). +##### 8.Participate in Non-Code Contributions +If your interest is not in writing code, you can find work of interest in the [ Non-Code Contributions](https://gitee.com/openeuler/community/blob/master/en/contributors/non-code-contributions.md). +##### 9.Community Security Issues +[Security Issue Handling Process](https://gitee.com/openeuler/security-committee/blob/master/%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.jpg) briefly describes the process of handling security issues. +[Security Disclosure](https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md) describes how to report a security vulnerability. + +## 4. Grow with the Community +### 4.1 Community Roles + +Everyone in the community plays an important part. Roles differ in terms of responsibilities and permissions. Grow, accumulate experience, and gain influence by contributing to the community. For details about roles, responsibilities, and permissions, see [Community Membership](https://gitee.com/openeuler/community/blob/master/community-membership.md). + +### 4.2 Technical Committee + +The openEuler Technical Committee (TC) is the technical decision-making body of the openEuler community. It is responsible for technical decision-making and coordination of technical resources in the openEuler community. +
+For details, see the introduction to the [openEuler Technical Committee](https://www.openeuler.org/en/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org). + +
\ No newline at end of file diff --git a/web-ui/docs/en/community/mailing-list/README.md b/web-ui/docs/en/community/mailing-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..09432be3e4fc9ef15ddf82cf3b60af3e02b82de5 --- /dev/null +++ b/web-ui/docs/en/community/mailing-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Mail lists" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/compatibility/README.md b/web-ui/docs/en/compatibility/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7620c171b4783007a6447126569755231627f9c8 --- /dev/null +++ b/web-ui/docs/en/compatibility/README.md @@ -0,0 +1,7 @@ +--- +title: "Compatibility" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/compatibility/hardware-info/README.md b/web-ui/docs/en/compatibility/hardware-info/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af845b8f47b801a22fcdcd66528f1173db870534 --- /dev/null +++ b/web-ui/docs/en/compatibility/hardware-info/README.md @@ -0,0 +1,7 @@ +--- +title: "HardwareInfo" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/compatibility/hardware/README.md b/web-ui/docs/en/compatibility/hardware/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7d8b33fb2d5f45ddfae96413aad95f0615ca0793 --- /dev/null +++ b/web-ui/docs/en/compatibility/hardware/README.md @@ -0,0 +1,7 @@ +--- +title: "Hardware" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/download/README.md b/web-ui/docs/en/download/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d17a2aa9e3b538f2cbe93feb5e37e36decadab0 --- /dev/null +++ b/web-ui/docs/en/download/README.md @@ -0,0 +1,7 @@ +--- +title: "Download" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/blog-list/README.md b/web-ui/docs/en/interaction/blog-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f9d1e14dc33b36d6278a769b303b2f6763924dcc --- /dev/null +++ b/web-ui/docs/en/interaction/blog-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Blog" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/live-list/README.md b/web-ui/docs/en/interaction/live-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af1866debde384429a772fac86e87e0d199e6fb2 --- /dev/null +++ b/web-ui/docs/en/interaction/live-list/README.md @@ -0,0 +1,6 @@ +--- +title: "Live" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/news-list/README.md b/web-ui/docs/en/interaction/news-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a43f525d5a83ae0834fb5692ad3ce4c16481e30d --- /dev/null +++ b/web-ui/docs/en/interaction/news-list/README.md @@ -0,0 +1,7 @@ +--- +title: "News" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/post-blog/README.md b/web-ui/docs/en/interaction/post-blog/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0eaa04e90634f7830c36292fd86ea3c3eef60359 --- /dev/null +++ b/web-ui/docs/en/interaction/post-blog/README.md @@ -0,0 +1,172 @@ +--- +title: "Guidance to Post a Blog" + +--- + + + + +
+ +## Preparation + +1. Refer to to register Gitee account. + +2. Set your primary mail box in gitee settings . + +3. Sign your CLA in . + +4. Prepare your git environment refering to . + +## Understand blog format + +The openEuler blog is written in markdown format. +You can read to get understand how the blog is designed. + +The head includes the following information: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: sig-xxx +archives: 2020-03 +author: openEuler Blog Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your blog. +``` + +Tips: you can copy https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post.md to your folder and edit it. + +## Post your blog + +The blog posting follows the pull request of [Gitee](gitee.com). + +1. Fork openEuler blog project to your own gitee. Refer to for detailed guidance. + +2. Clone the code to your local environment. + +``` +git clone https://gitee.com//website-v2 +``` + +3. Create a branch + +``` +git checkout -b +``` + +4. Create a folder in the website floder +If you are going to post a blog in English, the web-ui/docs/en/blog is your work path. + +And if you are going to post a blog in Chinese, the web-ui/docs/zh/blog is your work path. + +Assume that you are preparing a English blog. + +``` +cd web-ui/docs/en/blog +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +And You can put the resources in the same folder as your text file's, and name the resources as +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +Where the YEAR, MONTH, DAY, and title are the same as your blog file, and NN is the serial number of the pictures, like 01, 02 and so on. The MARKUP is the file extension, and for pictures it is recommended to use png. +The following are one example. +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` + +1. Commit your post + +``` +git add +git commit -m "" +git push origin : +``` + +2. Refer to to submit your Pull Request + +3. Wait for reviewing and merging. + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/post-blog/blog_design/README.md b/web-ui/docs/en/interaction/post-blog/blog_design/README.md new file mode 100644 index 0000000000000000000000000000000000000000..df5f3e46b86f70f24ddedbfc90c948984f39e3d9 --- /dev/null +++ b/web-ui/docs/en/interaction/post-blog/blog_design/README.md @@ -0,0 +1,101 @@ +# Posts +This file is to explain in which way the content of the blogs are stored and read by the blog system. + +## What is supported in the blog +A blog can include many formats of information, like text, pictures, videos, animations or others. + +openEuler Blog is designed to support the following formats: + +1. text +2. static picture +3. links +4. animation + +## Folder design +The content of blogs are under + +``` +|__ web-ui/docs/en/interaction/post-blog/blog_example --list the some blog examples +|__ web-ui/docs/zh/blog/guidance --house the guidance to post and maintain the blogs in Chinese +|__ web-ui/docs/en/blog/guidance --house the guidance to post and maintain the blogs in English +|__ web-ui/docs/zh/blog --house all the final posts in Chinese + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID +|__ web-ui/docs/en/blog --house all the final posts in English + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID + +``` + +## Post content design +### Choose languange +If you are going to post a blog in English, the web-ui/docs/en/blog is your work path. + +And if you are going to post a blog in Chinese, the web-ui/docs/zh/blog is your work path. + +### File name (Assuming to write a post in Enlgish) +To create a post, add a file to your web-ui/docs/en/blog/author_1/_ directory with the following format: + +``` +YEAR-MONTH-DAY-title.MARKUP +``` +Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers, and MARKUP is the file extension representing the format used in the file. For example, the following are examples of valid post filenames: +``` +2020-01-01-new-years-is-coming.md +2020-02-15-how-to-write-a-blog.md +``` + +### File headers +Functionally, the post should support categories, archives, title, date, brief description, thus the file headers should be as below. +``` +--- +title: ... +date: yyyy-mm-dd +tags: + - aaaa + - bbbb + - cccc +archives: yyyy-mm +author: name of author +summary: ... +--- +``` + +### Including resources + +At some point, you’ll want to include images, downloads, or other digital assets along with your text content. + +You can put the resources in the same folder as your text file's, and name the resources as +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +Where the YEAR, MONTH, DAY, and title are the same as your blog file, and NN is the serial number of the pictures, like 01, 02 and so on. The MARKUP is the file extension, and for pictures it is recommended to use png. +The following are one example. +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +Then, from within any post, they can be linked to using the site’s root as the path for the asset to include. Here are some simple examples in Markdown: + +Including images in a post: +``` +...Use the html tag,and enter relative path of the image as src attribute. + +``` + +Linking to a PDF for readers to download: +``` +... +Use the html tag,and enter relative path of the file as href attribute. +The file will be downloaded once the link is clicked. +get the PDF. +``` +Linking to a url for readers to visit: +``` +... you can [read more](). +``` + +## Thanks +The content above refered to . diff --git a/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post.md b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post.md new file mode 100644 index 0000000000000000000000000000000000000000..a52989d0004def71a4b37219e8acc568a43267b1 --- /dev/null +++ b/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post.md @@ -0,0 +1,85 @@ +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: sig-xxx +archives: 2020-03 +author: openEuler Blog Maintainer +summary: Just about everything you'll need to style in the theme: headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +## HTML Elements + +Below is just about everything you'll need to style in the blog. + +# Heading 1 + +## Heading 2 + +### Heading 3 + +#### Heading 4 + +##### Heading 5 + +### Body text + +This blog is about bla bla. **This is strong**. + +![openEuler is open](./2020-03-03-sample-post-01.png) + +### Quotation + +> The sites that have been chosen are listed and described next to each work, with encapsulating quotes or pieces of text narrating central themes for the groups. + +## List Types + +### Ordered Lists + +1. Item one + 1. sub item one + 2. sub item two + 3. sub item three +2. Item two + +### Unordered Lists + +* Item one +* Item two +* Item three + +## Tables + +| Header1 | Header2 | Header3 | +|:--------|:-------:|--------:| +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|---- +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|===== +| Foot1 | Foot2 | Foot3 +{: rules="groups"} + +## Code + +``` +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; +``` + +## Attachment + +Download the file here download: +[get the PNG](![The architecture]() +) directly. \ No newline at end of file diff --git a/web-ui/docs/en/interaction/post-news/README.md b/web-ui/docs/en/interaction/post-news/README.md new file mode 100644 index 0000000000000000000000000000000000000000..57a0807a6fda3a34462f5f95f0aa4e1a1d0d212b --- /dev/null +++ b/web-ui/docs/en/interaction/post-news/README.md @@ -0,0 +1,172 @@ +--- +title: "Guidance to Post a News" + +--- + + + + +
+ +## 准备 + +1. 参考 http://git.mydoc.io/?t=179267 注册Gitee账号。 + +2. 在Gitee个人设置中设置主邮箱地址,在此https://gitee.com/profile/emails。 + +3. 签署贡献者协议,https://www.openeuler.org/zh/other/cla。 + +4. 参考http://git.mydoc.io/?t=180692准备你的git环境 + +## 理解新闻格式 + +openEuler是用markdown格式写新闻的。 +请阅读该文章 来理解openEuler新闻是如何设计的。 + +文件头需要包含如下信息: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - theme +banner: img/banners/banner-2020hdc.png +author: openEuler +sig: sig-xxx +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your news. +``` + +小提示:你可以复制 https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post.md 到你的工作路径下然后继续编辑。 + +## 提交新闻 + +新闻的提交利用了Gitee的PR(Pull Request)。 + +1. Fork openEuler 新闻项目 到你自己的Gitee上。如果需要具体指导请参考 。 + +2. Clone代码 + +``` +git clone https://gitee.com//website-v2 +``` + +3. 创建分支 + +``` +git checkout -b +``` + +4. 创建工作路径 + +如果你发表中文新闻,工作路径是 web-ui/docs/zh/news 。 +假设你要写一个英文新闻: + +``` +cd web-ui/docs/en/news +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +你可以以你的md文档名来命名你的资源文件,方便使用。例如: +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +其中,YEAR, MONTH, DAY, 和 title 和你的新闻md文件名一致。NN 是01、02、03这样的序号。MARKUP文件扩展名。如下例子: +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +使用HTML \ 标签嵌入图片, 但你的图片资源需要放入当前目录下(即your-gitee-id目录下),输入图片名称作为 src 值: +``` + +``` + +1. Commit 你的新闻 + +``` +git add +git commit -m "" +git push origin : +``` + +2. 参考 提交你的PR + +3. 等待评审和合入。 + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01.png b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post.md b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1bb635ce0f8af793b1ce09b57d8a5d5e597aa0 --- /dev/null +++ b/web-ui/docs/en/interaction/post-news/news_example/2020-03-03-sample-post.md @@ -0,0 +1,85 @@ +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: A-Tune +banner: img/news/20201225/poster.png +archives: 2020-03 +author: openEuler news Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +## HTML Elements + +Below is just about everything you'll need to style in the news. + +# Heading 1 + +## Heading 2 + +### Heading 3 + +#### Heading 4 + +##### Heading 5 + +### Body text + +This news is about bla bla. **This is strong**. + +![openEuler is open](./2020-03-03-sample-post-01.png) +### Quotation + +> The sites that have been chosen are listed and described next to each work, with encapsulating quotes or pieces of text narrating central themes for the groups. + +## List Types + +### Ordered Lists + +1. Item one + 1. sub item one + 2. sub item two + 3. sub item three +2. Item two + +### Unordered Lists + +* Item one +* Item two +* Item three + +## Tables + +| Header1 | Header2 | Header3 | +|:--------|:-------:|--------:| +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|---- +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|===== +| Foot1 | Foot2 | Foot3 +{: rules="groups"} + +## Code + +``` +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; +``` + +## Attachment + +Download the file here download: +[get the PNG](![The architecture]() +) directly. diff --git a/web-ui/docs/en/interaction/salon-list/README.md b/web-ui/docs/en/interaction/salon-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d826600c5257ca41f9769b47d378c19853e3a58f --- /dev/null +++ b/web-ui/docs/en/interaction/salon-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Meetups" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/salon-list/detail/README.md b/web-ui/docs/en/interaction/salon-list/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fc36b9f0e7dce00d89b87a7dc17f843278c916e2 --- /dev/null +++ b/web-ui/docs/en/interaction/salon-list/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "Meetups Detail" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/summit-list/README.md b/web-ui/docs/en/interaction/summit-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c5d85b441cd90d98a5aac70716adbafaef0467e2 --- /dev/null +++ b/web-ui/docs/en/interaction/summit-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Summit" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/summit-list/devday2021/README.md b/web-ui/docs/en/interaction/summit-list/devday2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..93d427f5b35f2fc44b4292eb01114e745fe2262c --- /dev/null +++ b/web-ui/docs/en/interaction/summit-list/devday2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/summit-list/devday2022/README.md b/web-ui/docs/en/interaction/summit-list/devday2022/README.md new file mode 100644 index 0000000000000000000000000000000000000000..88d19760d9da30c24fd47848003074ed59de4e27 --- /dev/null +++ b/web-ui/docs/en/interaction/summit-list/devday2022/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2022" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/summit-list/list/README.md b/web-ui/docs/en/interaction/summit-list/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9e1512acf1c53de938f1c3b196f841b576801f5d --- /dev/null +++ b/web-ui/docs/en/interaction/summit-list/list/README.md @@ -0,0 +1,7 @@ +--- +title: "Summit" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/interaction/summit-list/summit2021/README.md b/web-ui/docs/en/interaction/summit-list/summit2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1d9d1ad9ef1d5c6d03167f760be3cb6cdebe4e9a --- /dev/null +++ b/web-ui/docs/en/interaction/summit-list/summit2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Summit 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/learn/mooc/README.md b/web-ui/docs/en/learn/mooc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e446ad7dfdd641398ae9052e8a9fcf12dd0971e5 --- /dev/null +++ b/web-ui/docs/en/learn/mooc/README.md @@ -0,0 +1,6 @@ +--- +title: "MOOC" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/learn/mooc/detail/README.md b/web-ui/docs/en/learn/mooc/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d5f74fa3cdff427d8ff7db85db063f243f11e9af --- /dev/null +++ b/web-ui/docs/en/learn/mooc/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "MOOC" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/mirror/list/README.md b/web-ui/docs/en/mirror/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9b6cacc7c347a78d0464260e5e1800518b5551ac --- /dev/null +++ b/web-ui/docs/en/mirror/list/README.md @@ -0,0 +1,6 @@ +--- +title: "Mirrors" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/mirror/select/README.md b/web-ui/docs/en/mirror/select/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8512551d387279e2417c5bb8c19993ffc04aff93 --- /dev/null +++ b/web-ui/docs/en/mirror/select/README.md @@ -0,0 +1,6 @@ +--- +title: "Selected Mirrors" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/news/20200101.md b/web-ui/docs/en/news/20200101.md new file mode 100644 index 0000000000000000000000000000000000000000..2e79a06dc721b7ffa4a6b1d3d72e2c3278b36415 --- /dev/null +++ b/web-ui/docs/en/news/20200101.md @@ -0,0 +1,39 @@ +--- +title: "openEuler Community Infrastructure Is Launched" +date: "2020-01-01" +tags: + - theme +banner: "img/banners/banner-20200101.png" +author: "openEuler Infrastructure Team" +summary: "After more than 3 months' preparation, the openEuler community infrastructure was officially launched." +--- + + + + + +
+ +openEuler Community Infrastructure is Launched +Since September 17, 2019, when openEuler was announced to be open source at the end of the year, the openEuler infrastructure team has been preparing the infrastructure. After more than 3 months' preparation, the openEuler community infrastructure was officially launched. + +On the evening of December 31, 2019, openEuler infrastructure team mentioned: "We are very excited at this moment. It was hard to imagine that we will manage thousands of repositories. And to ensure that they can be compiled successfully, we would like to thank all those who participated in contributing". The biggest challenge in building this community is managing so many code repositories. Such an amount of repositories puts a lot of load on the entire infrastructure system. + +As shown by Gitee, openEuler includes two organizations, one for source code and the other for packages sources. Currently it shows that there are 20+ repositories in the source code organization. I would hight recommend 2 projects, iSulad and A-Tune. iSulad is a lightweight gRPC service-based container runtime. Compared to runc, iSulad is written in C but all interfaces are compatible with OCI. And A-Tune is a system software to auto-optimize the system adaptively to multiple scenarios with embedded AI-engine. In addition, you will also see several infrastructure-supported projects that set up the community's operating systems. According to the submission records of these projects, these systems are built on the Huawei Cloud through script automation. + +The other organization is src-openeuler, which is used to store software packages. These packages are to be built to the ISO and installation packages of the openEuler operating system. According to Gitee statistics, there are currently about 1,000 software packages stored here, each one The software package provides both ARM64 and X86 architecture versions, so the amount of engineering is beyond anyone's imagination. And the amount of these packages will continue to increase. + +According to Gitee statistics, there are currently more than 50 contributors in the community and nearly 600 commits. About 20 SIGs (project groups) are in openEuler community. + +The openEuler community is currently in the preparatory stage. If you are interested, please contact infra@openeuler.org to join the infrastructure team. + +At this important moment, please join me to say thanks to the following contributors: + + - dogsheng + - freesky-edward + - imjoey + - tommyhusheng (husheng) + - xiangxinyong + - zerodefect (Fred_Li) + +
diff --git a/web-ui/docs/en/other/brand/README.md b/web-ui/docs/en/other/brand/README.md new file mode 100644 index 0000000000000000000000000000000000000000..22626af5dcddefcd8c30fac62f9c201dc3b622c3 --- /dev/null +++ b/web-ui/docs/en/other/brand/README.md @@ -0,0 +1,7 @@ +--- +title: "TradeMark" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/legal/README.md b/web-ui/docs/en/other/legal/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8ea6c3dd757f888ae8048665a821a7609543d75d --- /dev/null +++ b/web-ui/docs/en/other/legal/README.md @@ -0,0 +1,85 @@ +--- +title: "Legal" +--- + + + +
+ +This legal notice contains legal policies for the openEuler community. These policies govern this site and project releases hosted by openEuler community. + +## Terms and Conditions for Accessing the openEuler Community Website + + is operated by openEuler community. The following rules apply to all visitors to this website. openEuler community may, without notice to you and at any time, revise these terms according to laws, regulations, and market changes. The right to access this website is granted by openEuler community according to the terms specified in this Notice. If you do not agree to these terms, please do not use this website. By accessing, browsing, or using this website and the services provided herein, you acknowledge that you agree with all contents of this Notice. In the event of any violation of these terms and conditions, openEuler community reserves the right to seek all remedies available by law and in equity against such violations. +## Protection of Personal Information + +The openEuler community respects personal information of any individual who accesses this website. When you visit this website, you may be asked to provide basic personal information (such as your name, email address, and contact information). You can choose whether to provide such information. The personal information you provide will be kept confidential in accordance with the applicable laws of the People's Republic of China (PRC). The information will not be provided or disclosed to any third party in any way, except in any of the following cases: + +(1) Sharing with your explicit consent. After notifying you of the third party's name, contact information, processing purpose, processing method, and personal information type, and obtaining your explicit consent, the openEuler community will share the information within the scope of your authorization to the third party. + +(2) Sharing under legal circumstances. Your personal information is required to be shared according to applicable laws and regulations, legal procedures, litigation/arbitration, government's compulsory orders, and regulatory requirements. + +(3) To the extent required or permitted by law, it is necessary to provide your personal information to third parties to protect your or the public's interests, property, or security from being damaged. + +(4) To protect national security or public security of the PRC, or the legitimate rights and interests of you and other individuals, it is necessary to share your personal information. + +(5) Your personal information is made public by yourself or has been legally made public. + +## General Disclaimer + +Although openEuler community has attempted to provide accurate information on this website, +including but not limited to text, pictures, data, opinions, advice, web pages, and links, +openEuler community assumes no responsibility for the accuracy, completeness, adequacy, and reliability of such information, +or incorrectness or loss of such information. +openEuler community disclaims all warranties, expressed or implied, including, without limitation, +those of ownership, proprietorship, quality, and the absence of viruses. +openEuler community may change the information on this website at any time without notice. +To obtain the latest version information, you shall periodically visit this website. +The mention of non- openEuler community products or services is for information purposes only and constitutes neither an endorsement nor a recommendation. +openEuler community does not provide any statement, guarantee or authorization for any of the products or services appearing on the website. +The BBS service on this website, including but not limited to the user names, company names, contacts, pictures, and other information, +is provided by the community members, who shall assume full responsibility for such information. +Any entity or individual who suspects that the content on this website (including but not limited to the commodity information posted by community members on this website) infringes upon legal rights or interests shall notify openEuler community in written form and provide the identity, +ownership certification, associated link (URL), and proof of infringement. openEuler community will remove the content related to the alleged infringement by law upon receiving the foregoing legal documents. + +## Copyright Statement + +All materials and contents on this website are protected by law. +Unless otherwise indicated, all copyrights belong to openEuler community. +Without the prior written consent of openEuler community or other parties hereto, no individual shall replicate, distribute, copy, +or broadcast any portion of such information, or connect to or transmit such information through hyperlinks, +upload it to any other servers, store it in any information retrieval systems, +or use it for any other purposes by any means, except the downloading or printing of it by users for non-commercial purposes (provided that the preceding downloaded or printed information is not modified, +and the notification of copyrights or any other proprietary rights contained in such information is reserved). + +## Trademark + +All logos and trademarks used on this website are the properties of openEuler community or other third parties as stated if applicable. +No content provided on the openEuler community website shall be deemed as granting approval or the right to use any trademark or logo aforesaid by implication, +lack of objection, or other means without the prior written consent of openEuler community or any third party which may own the mark. +No individual shall use the name, trademark, or logo of openEuler community by any means without the prior written consent of openEuler community. + +## Links to Third-Party Websites + +This website may contain links to third-party websites. +Access to any other website linked to on this website is at the user's own risk and openEuler community is not responsible for the accuracy, +completeness, adequacy, and reliability of any information, data, opinion, picture, advice, or statement on these websites. +openEuler community provides these links merely as a convenience and the inclusion of such links does not imply an endorsement, +recommendation, promotion, or advertisement. + +## Website Updates and Changes + +The contents on this website are provided for your convenience only. The openEuler community has the right to change or update the contents on this website at any time without notifying you or any third party. You acknowledge and accept the above changes or updates. You are advised to visit this website regularly to obtain information about updates or changes in a timely manner. + +## Applicable Law and Dispute Resolution + +Access and all related activities on or through this website shall be governed by, construed, +and interpreted in accordance with the laws of the People's Republic of China. +You agree that any dispute between the parties arising out of or in connection with this legal notice or your access and all related activities on or through this website shall be governed by a court with jurisdiction in Shenzhen, Guangdong Province of the People's Republic of China. + +
\ No newline at end of file diff --git a/web-ui/docs/en/other/lifecycle/README.md b/web-ui/docs/en/other/lifecycle/README.md new file mode 100644 index 0000000000000000000000000000000000000000..85451f198d29344c4433f13cba62dafdfcd52d93 --- /dev/null +++ b/web-ui/docs/en/other/lifecycle/README.md @@ -0,0 +1,19 @@ +--- +title : "openEuler releases lifecycle" +--- + +
+ +## lifecycle + +openEuler releases are named by the edition number according to the year and month when to release. For example, openEuler 20.09 is released in September 2020. + +The community version is divided into an LTS (long-term support) release and an innovative release. + +- **LTS release**: released every 2 years, and community support is provided for 4 years starting the release date. The community's first LTS version, openEuler 20.03 LTS, was officially released in March 20th. + +- **Community Innovation release**: released every 6 months between 2 LTS releases and 6 months' support is provided.The next version will be released in September 2021. + +![](./lifecycle.png) + +
\ No newline at end of file diff --git a/web-ui/docs/en/other/lifecycle/lifecycle.png b/web-ui/docs/en/other/lifecycle/lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..cb0a0b6dc24dc4546dd285a15e9e1fd881b0ed3a Binary files /dev/null and b/web-ui/docs/en/other/lifecycle/lifecycle.png differ diff --git a/web-ui/docs/en/other/privacy/README.md b/web-ui/docs/en/other/privacy/README.md new file mode 100644 index 0000000000000000000000000000000000000000..20fae4838cd2727fad00333333162cd05bac0ff0 --- /dev/null +++ b/web-ui/docs/en/other/privacy/README.md @@ -0,0 +1,78 @@ +--- +title: "Privacy" +--- + + + +
+ +The openEuler Community understands the importance of your privacy and fully respects it. **Please read this openEuler Community Privacy Statement ("Statement") carefully before you submit your personal data to us.** If you have any questions about how we process your personal data, please feel free to contact us. Unless otherwise specified, "we" and "us" in this Statement refers to the openEuler Community. + +## 1.How We Collect and Process Your Personal Data +**We generally do not require your personal data if you only browse the general content of the openEuler Community ("Community"). We will collect your personal data accordingly in the following circumstances:**
+(a) **Mail Subscription**. When you use our mail subscription service, we will collect your **email address and name (optional)**. We will provide you with the email subscription service through this email address to facilitate your participation in discussions in the community.
+(b) **Service Optimization**. To continuously understand the operating status of the openEuler Community and provide better services for you, we will deploy a third-party plugin in this program. The third-party plugin will collect and record information on your browser, computer, and mobile device, including but not limited to your **IP address, access source, number of visits to the community, stay duration, access timestamp, browser type, and server type and version**, etc. This will form the basis of our analysis, which helps us to better understand the openEuler Community operation.
+(c) **Contributor License Agreement Signing**. When you participate in code contribution through the Contributor License Agreement ("CLA") signing system (click [here](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=) to learn more), you need to submit your relevant personal data to the CLA signing system. We will obtain such personal data to verify whether you have signed the CLA, and to conduct relevant statistical analysis to understand how the community is operating. + +We may also collect your personal information from third parties, including other platforms or communities, within the scope of your authorization and consent, or obtain your personal information from other legal and public channels. We promise to process your personal information in strict accordance with applicable laws and regulations. Please read the privacy policies and user agreements of the third parties carefully. If your personal information provided by a third party is required when you use the openEuler community, but you refuse to allow the third party to collect, use, transfer, or share your personal information when the third party provides services, you may not be able to use related services of the openEuler community. For example, when you use an authorized third-party account to log in to the openEuler community, we will obtain your personal information from the third party with your consent. + +## 2.How We Use Cookies and Similar Technologies + +(a) To ensure our website works properly, we may at times place cookies on your computer or mobile device. A cookie is a small data file placed on your computer or mobile device when you access a website. The content of a cookie can be retrieved or read only by the server that creates the cookie. Cookies serve different purposes. For example, they help us understand how the website is used, help you efficiently browse pages, remember your preferences, and improve your browsing experience.
+(b) We use two types of cookies:
+  (1)Strict and necessary cookies: used for login and verification. When you log in to the website with your HUAWEI ID, cookies improve your Web browsing experience.
+  (2)Statistical analysis cookies: We collect information about your use of our services, including your single or multiple visits, which help us understand how the services are running and used. We use the statistical analysis plugin provided by Baidu.
+Many services require cookies. If you do not allow cookies related to these services, you may not be able to use these services or some functions of these services.
+(c) **Do Not Track**. Many Web browsers provide the **Do Not Track** function, which can be used to send **Do Not Track** requests to websites. Currently, major Internet standardization organizations have not established policies to specify how websites should handle these requests. If you enable **Do Not Track** or other similar functions that your browser may provide, we will not change the way your data is collected and used as described in this Statement. However, we reserve the right to respond to your **Do Not Track** request and stop collecting your data without prior notice.
+(d) **Your Choice**. Most browsers allow you to delete or reject cookies. To do this, follow the instructions in the browser settings. By default, many browsers accept cookies until you change your settings. + +## 3.How We Share Your Personal Data + +Sharing means providing third parties with your personal data. The third parties and we would handle the personal data independently. We do not share your personal data with third parties without your consent, except in the following circumstances or as described in this Statement:
+(a) **Sharing under your instruction**. We may share your personal data with your consent and under your instruction to the third parties indicated by you.
+(b) **For compliance, fraud prevention and safety**. We may share your personal data for the purposes of compliance, fraud prevention, and safety.
+(c) **Affiliates**. We may share your personal data with our affiliates, for the purposes of transaction support, service support, or security support.
+(d) **Partners**. We may share your personal data with our partners. However, we will share your personal data only for legitimate, justified, necessary, specified, and explicit purposes, and share only the personal data necessary for providing our services. Our partners may include:
+  (1) **Developers, platforms, and social media networks**. Some products or services may be directly provided to you by third parties. In this case, we need to provide them with the transaction information. If you associate our services or products with third-party platforms or social media networks (for example, direct login through a third-party website, virtual login, or associated login), we may disclose your personal data with your authorization. We do not control the third party's use of your personal data.
+  (2) **Service suppliers or professional service providers**. We may share your personal data with third-party companies and individuals that provide services on our behalf or help us operate the website and services (such as supply, infrastructure, hosting, customer support, marketing and analytics, and data processing services). We share such data only for purposes consistent with this Statement or under your authorization. We may disclose your personal data to professional advisors, such as auditors, insurers, bankers, and lawyers, where necessary in the course of the professional services that they render to us.
+When we share your personal data with associated companies or partners, their responsibilities and obligations will be governed by contracts and we will require them to take appropriate measures to ensure the safety of the personal data processed. + +## 4.How Long We Retain Your Personal Data For +We will retain your personal data for no longer than is necessary for the purposes set out in this Statement, unless otherwise required by laws or requested by you.
+Generally, we will store or retain your personal data within the retention period according to applicable laws or service agreements from the date when you obtain your personal data in the openEuler Community. If your personal data has exceeded the retention period and no law requires us to continue processing your specific personal data, we will delete your personal data or anonymize it according to applicable laws. + +## 5.How We Protect Your Personal Data +We take the security of your personal data seriously. We take appropriate physical, organizational, and technical measures to protect your personal data. For example, we use encryption technologies to ensure the confidentiality of data; we implement protection mechanisms to protect data from attacks. We deploy access control mechanisms to ensure that only authorized personnel can access your personal data. In addition, we hold security and privacy protection training. **In a word, we are committed to protecting your personal data. Nevertheless, no security measure is perfect and no product, service, website, data transfer, computing system, or network connection is absolutely secure.** + +## 6.How We Access or Control Your Personal Data +In accordance with applicable laws and regulations, you may have the following rights regarding your personal data:
+(a) Access the personal data we hold about you and obtain copies thereof;
+(b) Request us to update or correct your personal data;
+(c) Request us to erase your personal data;
+(d) Object to our processing of your personal data;
+(e) Restrict our processing of your personal data;
+(f) File a complaint with the competent data protection authority.
+Please note that these rights are not absolute and may be restricted in accordance with applicable laws. If you need our assistance in exercising the requests or rights above, please contact us as set out in the "How to Contact Us" section below.
+**Generally, we will respond to you within one month, unless otherwise required by applicable laws. Depending on the complexity of your requests, we may extend the period by two further months. In this case, we will inform you of the extension and its reasons within one month of receiving your request.** Please note that under some circumstances, for example where we cannot verify your identity, or your claim exceeds your rights under applicable laws, we may refuse your request. In this case, we will inform you in written form that your request is refused together with the reasons for our refusal.
+You can change the scope of your authorization for us to collect your personal data or withdraw your authorization. However, your decision to withdraw your consent or authorization does not affect any previous processing of personal information based on your authorization. + +## 7.Personal Data Storage Location +We provide products and services for you through our global resources and servers. Your personal data collected by us may be stored in the countries or regions where we, our affiliates, service providers, and subcontractors are located. This means that your personal data may be transferred to other jurisdictions outside the country or region where the product or service you use is located, or may be accessed from these jurisdictions.
+Jurisdictions where such personal data is stored may have laws that protect personal information to varying degrees or may not have personal data protection laws. We will ensure that your personal data is protected by applicable laws and regulations as well as this Statement. + +## 8.How This Statement Is Updated + +We may update or modify this Statement from time to time according to changes of our services or data processing. If we update this Statement, we will publish the latest version of the Statement on the website, and it will take effect immediately upon its release. You are advised to review this Statement periodically for any changes. If we make any substantial changes to this Statement (any change of personal data we collect or we use for), we will notify you through appropriate channels and obtain your consent. + +## 9.How to Contact Us +If you want to contact us or exercise your rights, please contact us at . + + +Last updated: March, 2022 + +
\ No newline at end of file diff --git a/web-ui/docs/en/other/projects/atune/README.md b/web-ui/docs/en/other/projects/atune/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b32c575cb8fd67bb4926ac5466282876a9dff191 --- /dev/null +++ b/web-ui/docs/en/other/projects/atune/README.md @@ -0,0 +1,6 @@ +--- +title: "A-Tune" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/projects/bishengjdk/README.md b/web-ui/docs/en/other/projects/bishengjdk/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ac9151010fea5cd78348ed154baf3a4728cc3231 --- /dev/null +++ b/web-ui/docs/en/other/projects/bishengjdk/README.md @@ -0,0 +1,6 @@ +--- +title: "BiSheng JDK" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/projects/bishengjdk/tck-affidavit/README.md b/web-ui/docs/en/other/projects/bishengjdk/tck-affidavit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8f741c9dca1db6a218ff7bc5baedb52bd7f28f92 --- /dev/null +++ b/web-ui/docs/en/other/projects/bishengjdk/tck-affidavit/README.md @@ -0,0 +1,22 @@ +--- +title: "BiSheng JDK" +--- + +
+ +# Huawei BiSheng Statement of Java SE Compatibility + + All Huawei BiSheng(JDK 8) binaries available from have passed all requirements of the then-current Java SE 8 Compatibility test suite(JCK tests), and are compliant and compatible implementations. + +
+ + \ No newline at end of file diff --git a/web-ui/docs/en/other/projects/isula/README.md b/web-ui/docs/en/other/projects/isula/README.md new file mode 100644 index 0000000000000000000000000000000000000000..303f5a64312ea876a3987aa89b03919aec2880f8 --- /dev/null +++ b/web-ui/docs/en/other/projects/isula/README.md @@ -0,0 +1,6 @@ +--- +title: "iSula" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/projects/secgear/README.md b/web-ui/docs/en/other/projects/secgear/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6f9ac611eacf3a1010fc5dfa5a8fe67c6075c721 --- /dev/null +++ b/web-ui/docs/en/other/projects/secgear/README.md @@ -0,0 +1,6 @@ +--- +title: "secgear" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/projects/stratovirt/README.md b/web-ui/docs/en/other/projects/stratovirt/README.md new file mode 100644 index 0000000000000000000000000000000000000000..13e1c7f3bd30f84aa90386a77a123de3ae8deade --- /dev/null +++ b/web-ui/docs/en/other/projects/stratovirt/README.md @@ -0,0 +1,6 @@ +--- +title: "StratoVirt" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/other/search/README.md b/web-ui/docs/en/other/search/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a95664566b6ec3822223f0ee81b3800b8b880c3e --- /dev/null +++ b/web-ui/docs/en/other/search/README.md @@ -0,0 +1,6 @@ +--- +title: "Search" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/security/cve/README.md b/web-ui/docs/en/security/cve/README.md new file mode 100644 index 0000000000000000000000000000000000000000..101def4754bd28297bf62f40542b3ec4de6ac4fe --- /dev/null +++ b/web-ui/docs/en/security/cve/README.md @@ -0,0 +1,7 @@ +--- +title: "CVE" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/security/cve/detail.md b/web-ui/docs/en/security/cve/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..607af6015c823fceecf8c2e0dea2c348448b6faa --- /dev/null +++ b/web-ui/docs/en/security/cve/detail.md @@ -0,0 +1,7 @@ +--- +title: "Security-cveDetail" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/security/safety-bulletin/README.md b/web-ui/docs/en/security/safety-bulletin/README.md new file mode 100644 index 0000000000000000000000000000000000000000..06fe465a3b3308a5c2a27d8a9b5c007892630941 --- /dev/null +++ b/web-ui/docs/en/security/safety-bulletin/README.md @@ -0,0 +1,7 @@ +--- +title: "Security advisories" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/security/safety-bulletin/detail.md b/web-ui/docs/en/security/safety-bulletin/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..7d2187467ade7b46d5866b3ec5d44ac67f3a74f7 --- /dev/null +++ b/web-ui/docs/en/security/safety-bulletin/detail.md @@ -0,0 +1,7 @@ +--- +title: "Security-bulletinDetail" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/security/vulnerability-reporting/README.md b/web-ui/docs/en/security/vulnerability-reporting/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f60fd67bf15f58c24b6ba34df788193fed4a05df --- /dev/null +++ b/web-ui/docs/en/security/vulnerability-reporting/README.md @@ -0,0 +1,134 @@ +--- +title: "Vulnerability management" + +--- + + + +
+ +## Vulnerability Response +The openEuler community attaches great importance to the community version security. The security committee of openEuler community is responsible for receiving, investigating, and disclosing security vulnerabilities related to the community. Researchers and industry organizations working on vulnerability prevention are encouraged to report the potential security vulnerabilities in the openEuler community to the security committee. The reported security issues or vulnerabilities will be quickly analyzed and resolved by the committee. + +## Versions Supported +The vulnerability response process supports the LTS distribution of the openEuler community and its branch versions. + +## Vulnerability Handling Process +Each security vulnerability is tracked and handled by a designated person. This person is a member of the security committee of openEuler community, who is responsible for tracking, resolving, and disclosing the vulnerability. The following flowchart shows the E2E vulnerability handling process. + + + + + + + + +## Vulnerability Reporting +We hope that you can report the potential vulnerability of an openEuler product to the openEuler community and work with us to resolve and disclose the vulnerability. + + +### Reporting Channel +You can send the potential security vulnerabilities of an openEuler product to the e-mail of the openEuler security team (). Given that the vulnerability information is sensitive, you are advised to use the public PGP key of the security team to encrypt the e-mail. +The information of the security team members is described as follows: + ++ Liu Jingang [@liujingang09], , public PGP key ++ Yang Li [@yangli69393], ++ Yan Xiaobing [@yanxiaobing2020], , public PGP key ++ Zhu Jianwei [@zhujianwei001], , public PGP key ++ Wei Gang [@gwei3], <11015100@qq.com>, public PGP key + +### Reporting Content +To quickly identify and verify suspected vulnerabilities, the reporting e-mail should include but is not limited to the following content: + ++ Basic information: including the modules affected by the vulnerability, triggering conditions of the vulnerability, and impact on the system after the vulnerability is exploited. ++ Technical details: including system configuration, fault locating method, description of exploit, POC, and method and procedure of fault reproduction. ++ Suggestions on resolving the vulnerability. ++ Organization and contact information of the vulnerability reporter. ++ Reporter's possible plan for vulnerability disclosure. + +### E-mail Response +We will respond to the reporting of suspected security vulnerabilities through e-mail within 48 hours and keep the reporter informed of the vulnerability handling progress. + + +## Vulnerability Severity Assessment +The Common Vulnerability Scoring System (CYSS) is widely used in the industry to assess vulnerability severity. Currently openEuler is using CVSS v3 to assess vulnerabilities, and such assessment focuses on the impact caused by the vulnerability in a preset attack scenario. The vulnerability severity assessment covers factors such as the exploit difficulty and the impact of vulnerability exploit on the confidentiality, integrity, and availability of the product. A score will be given after these factors are assessed. + +### Assessment Criteria +The CVSS v3 adopted by the openEuler community assesses the impact of a vulnerability based on the following variables: + ++ Attack vector (AV): indicating the remoteness of an attack and how to exploit this vulnerability. ++ Attack complexity (AC): describing the difficulty in executing an attack and the conditions for a successful attack. ++ User interaction (UI): determining whether the attack requires users' participation. ++ Permission required (PR): recording the level of user authorization required for a successful attack. ++ Scope (S): determining whether an attack can affect components of different permission levels. ++ Confidentiality (C): measuring the impact of unauthorized information disclosure. ++ Integrity (I): measuring the impact of information tampering. ++ Availability (A): measuring the impact on data access or services for users affected by the vulnerability. + +### Assessment Principles ++ The severity of a vulnerability is assessed, not the risk of the vulnerability. ++ The assessment must be based on an attack scenario where the system confidentiality, integrity, and availability are affected by a successful attack. ++ When a security vulnerability has multiple attack scenarios, the attack scenario with the highest CVSS score (that is, with the greatest impact) shall prevail in the assessment. ++ When a library that is embedded or invoked has vulnerabilities, the assessment on its vulnerability severity should be based on an attack scenario, which is determined by the usage of the library in the product. ++ When a security defect does not trigger or affect the confidentiality/integrity/availability (CIA), the CVSS score is 0. + +### Assessment Procedure +Perform this procedure to assess a vulnerability: + ++ Set a possible attack scenario and score based on this attack scenario. ++ Identify vulnerable components and affected components. ++ Select the value of the basic assessment indicator, and perform the vulnerability impact assessment based on the exploitable indicators (attack vector, attack complexity, permission required, user interaction, and scope) and affected indicators (confidentiality, integrity, and availability). + +### Severity Rating + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Severity RatingScore
Critical9.0 - 10.0
High7.0 - 8.9
Medium4.0 - 6.9
Low0.1 - 3.9
None0.0
+ +### Scoring Difference Between National Vulnerability Database (NVD) and CVSS +The CVSS scoring is determined by a series of factors, including the version number of an affected component and how it is provided and used, as well as the platform and software compilation mode. The NVD scoring takes into account all scenarios where vulnerabilities are exploited. This assessment mode is not suitable for the open source openEuler, which is built based on the upstream community and mainly applies to server scenarios. As a result, openEuler will score all common vulnerabilities and exposures (CVEs) based on their specific impact. For the same CVE, the scoring by openEuler may be different from that by NVD. + +## Vulnerability Disclosure +For the security of openEuler users, the openEuler community will not discuss, confirm, or disclose the security issues of an openEuler product until the vulnerability is investigated and resolved and the security announcement is issued. After a security vulnerability is resolved, the openEuler community will release a security announcement, with information including the technical details, CVE identifier, CVSS security score, and severity level of the vulnerability, as well as the affected and fixed versions. You can subscribe to security announcements of the openEuler community on the sa-announce.We also provide security announcements in CVRF format, which can be obtained at [CVRF Documentation](https://repo.openeuler.org/security/data/cvrf/). + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/en/security/vulnerability-reporting/procedure(en)-mobile.png b/web-ui/docs/en/security/vulnerability-reporting/procedure(en)-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..6f805db481139acdb3fa2d8f11f2696babc87f71 Binary files /dev/null and b/web-ui/docs/en/security/vulnerability-reporting/procedure(en)-mobile.png differ diff --git a/web-ui/docs/en/security/vulnerability-reporting/procedure(en).png b/web-ui/docs/en/security/vulnerability-reporting/procedure(en).png new file mode 100644 index 0000000000000000000000000000000000000000..c8784fa687aa34ab835a7de514520f46f8099595 Binary files /dev/null and b/web-ui/docs/en/security/vulnerability-reporting/procedure(en).png differ diff --git a/web-ui/docs/en/sig/role-description/README.md b/web-ui/docs/en/sig/role-description/README.md new file mode 100644 index 0000000000000000000000000000000000000000..db37e3d47ac5748c00458fc96c531b0d824c5ace --- /dev/null +++ b/web-ui/docs/en/sig/role-description/README.md @@ -0,0 +1,108 @@ +--- +title: "Characters" + +--- + + + +
+ + +*Description*:The permissions of Maintainer and Committer are the same on Gitee, and the difference lies in the scope of SIG governance. The detailed informationes are described below. + +## New Contributor + +Welcome to join the community. Start contributing by referring to [contribution guidience](/en/contributors/README.md). + + +## Existing Community Member + + +Existing community members should follow the principles in this article and be familiar with SIG's organization, roles, policies, software, and etc. At the same time, they should have corresponding technical and writing skills. The detailed informatione of responsibilities and requirements of the community member are described below. + + +## Contributor +Contributors are people who frequently contribute to the community. They take part in SIG group activities, resolve questions, review PR, and complete tests before submitting the PR. + + +### Requirement + ++ Registered member on Gitee ++ Contribute to SIG or community in many ways, including but not limited to: + + Submitting or reviewing PR(Pull Request) on Gitee + + Documenting or commenting issues on Gitee + + Participating in SIG or community discussions ++ Read [Contribution Guideline](/en/contributors/README.md) ++ Join one or more SIGs + +### Responsibility and Power + ++ Respond to assigned issues and PR(Pull Request) ++ Contributed code should satisfy the criteria described below + + Well tested + + Passing the test correctly and completely + + Resolving subsequent errors or problems ++ Agree PR by executing '/ lgtm' ++ Assign issue or PR, ask memebers to comment by execting`/assign @username` ++ Run PR test automatically. `/ok-to-test` is not necessary ++ Operate the PR with `needs-ok-to-test` label by execting `/ok-to-test` and close PR by execting `/close`. + +**Note**: Contributors should actively take part in code review and if they'd like to help more, strive to be a *Committer* of SIG. + +## Committer + +Committers can review the quality and correctness of code in SIG or some parts of SIG. Committers should have a good knowledge of code repository and software engineering principles. + +**Definition**:*developer* entry in the OWNERS file owned by each SIG. + +### Requirement + ++ Have worked in openEuler for At least 3 months as contributors ++ Participated in at least 6 PR reviews as the main reviewer ++ Review or merge at least 30 PR into the code repo ++ Being Familiar with code repo ++ Can be self-nominated or nominated by the committers or maintainer of the SIG + +### Responsibility and Privilege + ++ **Review PR**:Review the PR submitted by contributor. The review can refer to [编程建议]() and [安全编程规范](). ++ **Distribute and deal with problems**:Please refer to [问题处理流程]() . ++ **Tracking dependency issues**:In the development branch, software package's dependencies in the SIG may be broken due to the software package updates in other SIG. At this time, the Committer will receive an alert. Then, the committer should try to rebuild the software package. Because dependency problem may prevent users from updating the system, the build team will also participates in rebuilding packages that have dependency issues, but the Maintainer should not rely on these works. ++ **Notify SIG that may be affected due to interface changes**:Because other SIGs or projects rely on software package of this SIG, changes to the package interface may affect them. Maintainer should review the dependency impact caused by decision changes. Then Maintainer should announce and send alert emails of API or ABI changes. +Those work should be completed at least one week before the change occurs, and all SIGs that may be affected should be notified. For detailed informationes please refer to [接口变更通知流程](). ++ **Update and maintain package version**:Follow the startegy of [软件包更新质量控制策略]() and complete the package update. ++ **Collaborate with upstream community**, including: + + Push all changes to upstream community + + Participate in upstream community mailing list + + Get the account of the Bug Tracker of the upstream community, and track the important bugs of the upstream community + + Push serious errors to upstream community for help + For further information, please refer to [上游社区软件包管理建议]() ++ **Collaborate with test team** including: + + When you submit the software packages, the information how to debug and classify the packages should be provided to QA for problem classification + + Provide basic functional test cases for regression testing + + When you update the software package, the test cases related to fixed problems in the update package should be provided to QA + + +## Maintainer + +Maintainer is the leader of SIG group or member of management Committee, and also the maintainer of software package. They can review and approve code like committers. The key of code review is the code quality and correctness, while the approvals focus on overall acceptance of contributions. **Maintainer has all the responsibility and privilege of Committer** . In addition, Maintainer is also need to work out technical roadmap and undertake coordination within and outside the team. + +**Definition**:*developer* entry in the OWNERS file owned by openEuler SIG. + +### Requirement + ++ At least 3 months as committer ++ Participated in at least 12 PR reviews as the main reviewer ++ Review or merge at least 30 basic PR into the code repo ++ Being familiar with code repo ++ Could be self-nominated or nominated by sub-project Maintainer, and there is no objection from other sub-project Maintainers. + +### Responsibility and Power + +- **Work out technical roadmap for SIG project**:Including planning the SIG technical direction, roadmap, solution of software architecture evolution +- **Prepare release plan for SIG project**: Make key requirements and release plans for project;Participate in community PM activities and coordinate SIG initiatives to match community release milestone schedules +- **Participate in community coordination activities**:As a representative of SIG, Maintainer should attend the meetings and activites organized by Technical committee or the Community Council +- **Organize SIG meetings**:Regularly organize SIG meetings and make decisions on contentious issues within SIG + +
+ diff --git a/web-ui/docs/en/sig/sig-guidance/README.md b/web-ui/docs/en/sig/sig-guidance/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fcf4877417591c45b3ce174430dfbf7d22114967 --- /dev/null +++ b/web-ui/docs/en/sig/sig-guidance/README.md @@ -0,0 +1,7 @@ +--- +title: "Application" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/sig/sig-list/README.md b/web-ui/docs/en/sig/sig-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7852c258b8d968ec1e5d748de0e1025c94165d93 --- /dev/null +++ b/web-ui/docs/en/sig/sig-list/README.md @@ -0,0 +1,7 @@ +--- +title: "SIG lists" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/en/sig/sig-list/sig-detail.md b/web-ui/docs/en/sig/sig-list/sig-detail.md new file mode 100644 index 0000000000000000000000000000000000000000..d706bb14e38b653641aad73351ded41bb631c791 --- /dev/null +++ b/web-ui/docs/en/sig/sig-list/sig-detail.md @@ -0,0 +1,7 @@ +--- +title: "SIG" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/README.md b/web-ui/docs/ru/README.md new file mode 100644 index 0000000000000000000000000000000000000000..24a93d05aa59be040ef844b52e1b025a7a6b4c3f --- /dev/null +++ b/web-ui/docs/ru/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/activities/README.md b/web-ui/docs/ru/activities/README.md new file mode 100644 index 0000000000000000000000000000000000000000..edd773e9947ca675129adb59c6e0420df9550b67 --- /dev/null +++ b/web-ui/docs/ru/activities/README.md @@ -0,0 +1,7 @@ +--- +title: "Summer Activities" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/blog/cascades/Learning about the QEMU Fuzzer.md b/web-ui/docs/ru/blog/cascades/Learning about the QEMU Fuzzer.md new file mode 100644 index 0000000000000000000000000000000000000000..477aff4ef6675b54bacc5292f702dd7dbe72d64e --- /dev/null +++ b/web-ui/docs/ru/blog/cascades/Learning about the QEMU Fuzzer.md @@ -0,0 +1,433 @@ +--- +title: \[Open Source Promotion Plan] Инструмент фаззинга QEMU Fuzzer +date: 2021-08-15 +tags: + - Qemu + - Virtio + - summer2021 +archives: 2021-08 +author: cascades +summary: QEMU Fuzzer — это фреймворк, который тестирует запускаемые в гостевой ОС процессы чтения и записи на устройствах методом фаззинга, используя для этого инструменты libqtest и libFuzzer. QEMU Fuzzer включен в эмулятор QEMU, начиная с версии 5.0 и выше. +--- +# Инструмент фаззинга QEMU Fuzzer + +Данная статья впервые опубликована сообществом openEuler в рамках программы продвижения программного обеспечения с открытым исходным кодом [Open Source Promotion Plan](https://summer.iscas.ac.cn/). Название проекта: [No. 112 Improving QEMU Fuzzing](https://gitee.com/openeuler-competition/summer2021-112). + +## О документе + +В общих реализациях QEMU + Fuzzing применены режим qemu-afl и различные инструменты, которые тестируют устройства Интернета вещей методом фаззинга с использованием технологий виртуализации. + +В данной статье описывается фреймворк фаззинга для эмулятора QEMU, выполняющий фаззинг-тестирование в гипервизоре. Для эмуляции операций чтения и записи, выполняемых на устройствах с гостевой ОС, применяется фреймворк Qtest, а для сбора большого объема данных применяются эвристические алгоритмы libFuzzer. Данный фреймворк, созданный в рамках проекта [`Google Summer of Code 2019`](https://summerofcode.withgoogle.com/archive/2019/projects/6200259867312128/), добавлен к основной ветке эмулятора QEMU 5.0.0 и более поздних версий. + +## Принципы эмуляции QEMU + +[`QEMU`](https://www.qemu.org/) — это инструмент эмуляции и виртуализации с открытым исходным кодом, реализованный силами [`Fabrice Bellard`](https://bellard.org/). Инструмент поддерживает два режима эмуляции: + +* `Full-system`: обеспечивает ускорение центрального процессора (ЦП), памяти и периферийных устройств с помощью KVM и Hyper-V. +* `User-mode`: запускает бинарный код в другой архитектуре ЦП посредством трансляции инструкций. + +Виртуализация позволяет обрабатывать операции доступа к памяти и другому специальному оборудованию с эмулятора устройств с использованием программы в пользовательском режиме при условии, что память используется только в пользовательском режиме. Устройства с другими архитектурами и наборами инструкций в QEMU эмулируются с помощью объектно-ориентированного программирования. Для описания моделей устройств в эмуляторе реализована объектная модель `QEMU Object Model`. + +* Модель устройства: каждое эмулируемое устройство соответствует объекту TypeInfo, который однозначно определяется по имени устройства и хранится в хэш-таблице. +* Запуск устройства: перед запуском необходимо зарегистрировать устройство, инициализировать его модель и создать его экземпляр. +* Трансляция инструкций: для получения инструкций от эмулятора устройств и перевода их на физические устройства в QEMU используется компонент Tiny Code Generator (TCG) или Kernel-based Virtual Machine (KVM). Несмотря на некоторые потери в производительности, ресурсов на аппаратную виртуализацию затрачивается относительно меньше, чем на программную виртуализацию. +* Эмуляция памяти: QEMU обеспечивает для клиента возможность размещать объект в оперативной памяти. Когда клиент пытается получить доступ к памяти для записи данных на диск, QEMU перехватывает запрос на доступ и посылает его в модель устройства контроллера IDE. Данная модель выполняет синтаксический анализ запроса на операцию ввода-вывода и эмулирует инструкцию посредством вызова хост-системы. Далее память клиента копируется на диск хоста. + +То есть в хост-ОС гостевая ОС считает, что напрямую взаимодействует с физическими устройствами. Фактически QEMU выполняет роль посредника и выглядит это следующим образом: + +```asciidoc= ++----------+ +----------+ +----------+ +----------+ +----------+ +|Польз.прос| |Польз.прос| |Польз.прос| |Польз.прос| |Польз.прос| ++----------+ +----------+ +----------+ +----------+ +----------+ +| Linux | | Mac OS | | Windows | | Linux | | Solaris | ++----------+ +----------+ +----------+ +----------+ +----------+ +| Драйверы| | Драйверы | | Драйверы | |Драйверы | | Драйверы | ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+ +----------+ +----------+ +----------+ +----------+ +| QEMU x86 | | QEMU x86 | | QEMU ARM | | QEMU PPC | | QEMU MIPS| ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+-+----------+-+----------+-+----------+-+----------+ +| Хост-система:Linux,Mac OS,Windows | ++--------------------------------------------------------------+ ++--------------------------------------------------------------+ +|Аппаратное обеспеч:ЦП,память,диск,сетевое устройство,USB и др.| ++--------------------------------------------------------------+ +``` + +Подробнее об эмуляции QEMU см. [`Документация для пользователей`](LLVMFuzzerTestOneInput). +Подробнее об устройствах QEMU см. [`Об устройствах QEMU`](https://www.qemu.org/2018/02/09/understanding-qemu-devices/). +Подробнее о QEMU см. [`QEMU: быстрый и легкий динамический транслятор`](https://www.usenix.org/legacy/event/usenix05/tech/freenix/full_papers/bellard/bellard.pdf#:~:text=We%20present%20the%20internals%20of%20QEMU%2C%20a%20fast,one%20target%20CPU%20can%20be%20runon%20another%20CPU.). + +## Использование QEMU Fuzzer + +См. описание в [официальной документации](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html). + +### Среда тестирования + +Для данного эксперимента использована среда Docker в локальной подсистеме Windows Subsystem for Linux (WSL). + +```bash= +root@31b23c4c00b7:~/qemu# lscpu +Architecture: x86_64 +CPU op-mode(s): 32-bit, 64-bit +Byte Order: Little Endian +CPU(s): 16 +root@31b23c4c00b7:~/qemu# cat /etc/os-release +NAME="Ubuntu" +VERSION="20.04.2 LTS (Focal Fossa)" +``` + +#### Проблема при работе в данной среде + +* Описание. Инструмент QEMU Fuzzer не адаптирован к архитектуре AArch64. Несмотря на успешное завершение компиляции, во время прогона возникает ошибка. + +![](https://img-blog.csdnimg.cn/img_convert/2161923b370fbd9f89318104b70fad11.png) + +* Решение. Цель данного проекта заключается в адаптации QEMU Fuzzer к архитектуре AArch64. В настоящее время используется среда x86. + +#### Неверная версия + +* Описание. В примере на официальном веб-сайте использована версия Clang 8. Но есть уже версия Clang 14. При использовании версий, более поздних, чем Clang 8, на этапе компиляции появляется ошибка, что связано с включением **-Werror**. + +* Решение + + * (Рекомендуется) Установите Clang, используя менеджер пакетов (apt/dnf). + * Выполните команду **git checkout**, которая переключает между ветками LLVM — с 8 на 10. + * Перейдите на [официальную страницу релизов](https://releases.llvm.org/) и загрузите исходный код LLVM версии с 8 по 10. + * Выполните команду sudo apt/dnf search xxx, чтобы проверить программное обеспечение, включенное в менеджер пакетов, и соответствующую версию. Версией по умолчанию является Clang 10. + +```bash= +# sudo apt/dnf install clang llvm compiler-rt +``` + +#### Упаковка с помощью Docker + +Для развертывания используется Docker, который конфигурирует экспериментальную среду: [путь к образу.](https://hub.docker.com/repository/docker/cascadessjtu/qemu_fuzz) + +### Использование инструмента фаззинга в простом режиме + +Настроив среду, скомпилируйте и запустите программу фаззинга следующими командами. Появится результат выполнения libFuzzer. + +```bash= +CC=clang-10 CXX=clang++-10 ./configure --enable-sanitizers --enable-fuzzing +# qemu-fuzz-isa isa indicates the architecture of the device emulator. +make qemu-fuzz-i386 qemu-fuzz-aarch64 +# View available fuzzing objects. +build/qemu-fuzz-i386 --fuzz-target=FUZZ_NAME +``` + +QEMU Fuzzer также поддерживает инструкции по компиляции libFuzzer, которые можно просмотреть, выполнив команду `-help=1`. + +Для просмотра результатов фаззинга запустите инструмент [`Clang Sanitizer`](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html#generating-coverage-reports), который использует параметр CORPUS и изменяет инструкции компиляции. По завершении фаззинга выполните команду `llvm-cov` для конвертации сгенерированного файла `default.profraw` в файл `.html`. + +### Добавление пользовательского инструмента фаззинга + +Для добавления нового инструмента фаззинга выполните следующие действия: + +1. Скомпилируйте файл исходного кода `foo-device-fuzz.c` инструмента и сохраните его в каталоге `tests/qtest/fuzz`. +2. Для взаимодействия с эмулятором устройств используйте существующий инструмент фаззинга и API в libqos и libqtest. +3. Зарегистрируйте инструмент фаззинга в файле `tests/qtest/fuzz/meson.build`. + +### Использование инструмента фаззинга в универсальном режиме + +Написание инструментов для фаззинга, ориентированных на определенные модели устройств, занимает много времени и ресурсов, особенно если драйверы устройств не включены в libqos. В QEMU предусмотрена опция `generic-fuzz`, которая запускает подготовительное фаззинг-тестирование на всех устройствах, в том числе PIO, MMIO и DMA. Для включения опции generic-fuzz установите следующие переменные среды: + +* `QEMU_FUZZ_ARGS=`: параметры, которые необходимы для настройки устройства, например NIC и имя пользователя. +* `QEMU_FUZZ_OBJECTS`=: строки символов, которые задают область памяти, выделенную под фаззинг. Для определения подходящей области памяти используйте `./qemu-fuzz-i386 --fuzz-target=generic-fuzz -runs=0`. Чем больше областей памяти, тем больше пространство для ввода данных (`input-space`) для проведения фаззинг-тестирования. Однако в этом случае сложнее выявить, какие введенные данные привели к сбою устройства. Поэтому параметру `MemoryRegion` необходимо задать корректное значение. + +### Интеграция OSS-Fuzz + +OSS-Fuzz — это интегрированный инструмент фаззинга, который выполняет фаззинг-тест по умолчанию на всех объектах. Для настройки среды доступен официальный файл [`Dockerfile`](https://github.com/google/oss-fuzz/blob/master/projects/qemu/Dockerfile), а для запуска фаззинга в универсальном режиме (generic fuzzer) требуется сделать дополнительные настройки переменных среды. В эмуляторе QEMU в файле `tests/qtest/fuzz/generic_fuzz_configs.h` для OSS-Fuzz определен ряд моделей устройств. Также в данный файл разработчики могут добавлять новые модели устройств. + +### Инструмент воспроизведения сбоя + +При моделировании сбоя необходимо добиться, чтобы эмулятор QEMU, не имеющий компонента для фаззинга, отфильтровывал ложные ошибки и улучшил функцию отладки. Для создания инструмента воспроизведения `one-line reproducer` можно воспользоваться скриптом OSS-Fuzz. + +### Продолжительность процесса фаззинга + +Во фреймворке QEMU Fuzzer доступны две точки входа для libFuzzer, вызов которых осуществляется после вызова главной функции libFuzzer. + +* `LLVMFuzzerInitialize`: вызов осуществляется до того, как фаззинг-инструмент запустит процесс инициализации среды. +* `LLVMFuzzerTestOneInput`: вызов осуществляется для ввода данных во время выполнения задачи фаззинга и сброса статуса после завершения фаззинга. + +Процесс Fuzzer сбрасывается после каждой операции фаззинга. Также требуется сброс статуса самого эмулятора QEMU. Сбросить статус QEMU можно двумя способами. + +* `Reboot`: гостевая ОС перезапускается после завершения выполнения каждой операции фаззинга. +* `Fork`: выполняется **test case** в подпроцессах. Эта операция схожа с режимом `fork-server` AFL. + +## Зависимости QEMU Fuzzer + +Реализация QEMU Fuzzer зависит от библиотек libqtest и libqos. Подробнее см. [`Тестирование устройств, эмулированных в QEMU с помощью qtest`](https://www.linux-kvm.org/images/4/43/03x09-TestingQEMU.pdf). В данном документе описаны основные принципы Qtest, API и методы добавления сценариев тестирования. + +### libqtest + +* [Путь к исходному коду](https://github.com/qemu/qemu/tree/master/tests/qtest/libqtest.c) +* [Документация](https://qemu.readthedocs.io/en/latest/devel/qtest.html) + +Qtest — это фреймворк, используемый для выполнения модульных тестов на физических устройствах, эмулированных с помощью QEMU. В состав фреймворка входят компоненты `Qtest Client` и `Qtest Server`. Компоненты взаимодействуют друг с другом через UNIX Socket и поддерживают следующие инструкции: PIO, MMIO, interrupt, QMP. + +* `Qtest Client`: драйвер, компилируемый для устройства. Драйвер инкапсулируется снизу вверх и зависит от фреймворка модульных тестов glib, libqtest, libqos и qgraph. Для добавления нового теста выполните следующие действия: + + 1. Скомпилируйте код нового теста `tests/qtest/foo-test.c` в каталоге Qtest. + 2. Добавьте инструкции по компиляции в **Makefile.include**. + 3. Выполните операцию компиляции: `make tests/qtest/foo-test.c` + 4. Запустите тест. + + ```bash= + QTEST_LOG=1 QTEST_QEMU_BINARY=i386-softmmu/qemu-system-i386 tests/qtest/foo-test` + ``` + +* `Qtest Server`: подобно TCG и KVM, компонент `Qtest Server` выполняет роль ускорителя и регистрируется запуском `-machine accel=qtest`. В стандартных сценариях vCPU напрямую взаимодействует с виртуальным устройством. В сценариях тестирования Qtest напрямую взаимодействует с виртуальным устройством и выполняет роль посредника между клиентом Qtest и виртуальным устройством. Qtest — используется для проверки корректности работы устройства, а также, чтобы удостовериться, что гостевая ОС не запущена. + +Во время работы компонента `libqtest.c` запускает QEMU как подпроцесс. Основной целью запуска QEMU является выполнение главной функции `vl.c`. В сценарии тестирования осуществляется вызов функции `qtest_init()` `qtest.c` для инициализации сервера Qtest. + +На следующей схеме показана взаимосвязь между клиентом и сервером Qtest. + +```asciidoc= ++----------------+ сокет +----------------+----------------------+ +| Клиент Qtest +----------> Сервер Qtest | | ++----------------+ +-------+--------+ | ++----------------+ | | Qemu | +| Qgraph | PIO|MMIO | | ++----------------+ | | | ++----------------+ +-------v--------+----------------------+ +| libqos | | Эмуляция физического устройства | ++----------------+ +---------------------------------------+ ++----------------+ +| libqtest | ++----------------+ ++----------------+ +| glib test | ++----------------+ +``` + +### libqos + +* [Путь к исходному коду](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/libqos.c) +* [Документация](https://qemu.readthedocs.io/en/latest/devel/qtest.html?highlight=libqos) + +libqos — это фреймворк драйверов, который используется для компиляции сценариев qtest и предоставляет API, связанные с `memory`, `PCI` и `virtio`. Функции фреймворка: + +* Фреймворк выполняет роль обертки (wrapper) шины и функции, специфичные для каждого типа шин. +* Унифицирует модель доступа к устройству, облегчая задачу разработчику. + +## Процесс QEMU Fuzzer + +* [Путь к исходному коду](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz) +* [Документация](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html) + +Упомянутые выше две зависимости разработаны для проведения тестов функций QEMU и зависят от вводимых тестовых данных. Фаззинг повышает качество вводимых тестовых данных за счет использования алгоритмов генерирования случайных данных и мутации существующих данных. В этом случае libFuzzer можно использовать для фильтрации входных данных Qtest и повышения эффективности теста. Далее показана общая структура QEMU Fuzzer. + +![](https://img-blog.csdnimg.cn/img_convert/f269d3ace4fe504117d7fe4e2a253375.png) + +В данном исходном коде: + +* `fuzz.h`: интерфейс и структура данных для реализации целевого объекта фаззинга и взаимодействия с libFuzzer. +* `fork_fuzz.h`: общая память, параллельно используемая разными инструментами фаззинга. +* `qos_fuzz.h`: инкапсулированные интерфейсы libqos фреймворка Qtest. +* `generic_fuzz_configs.h`: задает настройки фаззинга в стандартном режиме. +* `virtio_xxx_fuzz.h` реализует фаззинг устройств virtio (net, blk и scsi). + +## Анализ сценариев QEMU Fuzzer + +В [`документации для разработчиков`](https://wiki.qemu.org/Documentation/GettingStartedDevelopers) QEMU упоминается следующее: + +> К эмулятору QEMU нет документации с описанием архитектуры высокого уровня. Все необходимое есть в исходном коде. + +Поэтому разработчикам QEMU крайне важно изучить исходный код. В данном разделе проанализирован процесс фаззинга QEMU на примере устройства virtio-net. Путь к исходному коду: [`tests/qtest/fuzz/virto_net_fuzz.c`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/virtio_net_fuzz.c). Virtio называют технологией паравиртуализации. В этом случае эмуляцию устройств выполняет хост-ОС, а гостевая ОС управляет устройствами. На следующей схеме представлен рабочий процесс. + +![](https://img-blog.csdnimg.cn/img_convert/8cbe7f371f062202bb88928900b3a481.png) + +Описание логики реализации сверху вниз. + +* В первую очередь реализуется функция регистрации `register_virtio_net_fuzz_targets()`. Функция `fuzz_add_qos_target()` в libqos добавляет три объекта фаззинга и служит оберткой функции `fuzz_add_target()` данного фреймворка. Прототип: + +```cpp= +void fuzz_add_qos_target( + FuzzTarget *fuzz_opts, + const char *interface, + QOSGraphTestOptions *opts + ); +``` + +* В завершении необходимо изменить файл [`meson.build`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c) и добавить опции условной компиляции. + +`virtio-net-socket` использован здесь как главный объект фаззинга для анализа параметров и функций, содержащихся в данных параметрах. + +* `virtio-net-socket`: + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket", + .description = "Fuzz the virtio-net virtual queues. Fuzz incoming " + "traffic using the socket backend", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +Первый параметр — это указатель, который отмечает временный объект FuzzTarget. Данный объект определяется с помощью [`fuzz.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c) и содержит идентификационную информацию и ряд функций обратного вызова, связанных с фаззингом. Описание объекта: + +```asciidoc= ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| Поле | Выражение | Описание | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| name | const char *name | идентификатор объекта (passed to --fuzz-target=) | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| description | const char *description | справ. текст | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| pre_fuzz | void(*pre_fuzz)(QTestState *) | запускается после инициализации QEMU перед fuzz-loop. | +| | | eg: detect the memory map | +| | | Может иметь значение NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| fuzz | void(*fuzz)(QTestState *, const unsigned char *, size_t); | принимает и исполняет команды, введенные с LibFuzzer. | +| | |повторно исполняется в течение цикла фаззинга. | +| | | Цикл состоит из установки, исполнения и сброса. | +| | | Не может иметь значение NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +``` + +`virtio_net_pre_fuzz` инициализирует общую память, используемую **qos path** и **fork fuzz**. `virtio_net_fork_fuzz` порождает дочерний процесс и вызывает функцию `virtio_net_fuzz_multi`. Данная функция управляет случайными данными с помощью определяемой пользователем операции `vq_action`, добавляет поступающие пакеты данных в `virtioqueue` и отбрасывает пакеты данных. Затем запускается основной цикл. + +Второй параметр задает имя пользовательского устройства. В приведенном примере используется значение **virtio-net**. + +Третий параметр задает структуру тестовых опций, предоставляемых [`qgraph.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/qgraph.h). Параметр `before` принимает к исполнению функции, прототипом которых является `QOSBeforeTest`. Функция `virtio_net_test_setup_socket` определяет серверную часть (backend) сетевого устройства QEMU в качестве **socket**, что обеспечивает связь с виртуальным устройством и отправку его пакетов данных в сеть хоста. + +* `virtio-net-socket-check-use` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket-check-used", + .description = "Fuzz the virtio-net virtual queues. Wait for the " + "descriptors to be used. Timeout may indicate improperly handled " + "input", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz_check_used,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +Функция `virtio_net_fork_fuzz_check_used` схожа с `virtio_net_fork_fuzz`. Разница заключается в значении `true`, которое используется при вызове функции `virtio_net_fuzz_multi`. + +* `cirtio-net-slirp` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-slirp", + .description = "Fuzz the virtio-net virtual queues with the slirp " + " backend. Warning: May result in network traffic emitted from the " + " process. Run in an isolated network environment.", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_user} + ); +``` + +`virtio_net_test_setup_user` определяет серверную часть сетевого устройства в качестве **user**. + +## Сценарий QEMU Fuzzer: CVE-2017-12809 + +В данном разделе представлен краткий анализ [уязвимости, включенной в базу данных CVE,](https://unit42.paloaltonetworks.com/unit42-palo-alto-networks-discovers-new-qemu-vulnerability/) которая была обнаружена в эмуляторе QEMU инструментом libFuzzer. + +* Описание уязвимости: данная уязвимость классифицируется как отказ в обслуживании. Когда для сборки гостевой ОС используется эмулятор дисков IDE, CD или DVD-ROM, привилегированные пользователи гостевой ОС могут удалить пустой драйвер устройства CD-ROM, что приведет к разыменованию нулевого указателя. В результате будет нарушен процесс QEMU. +* Код уязвимости: перед вызовом функции `blk_aio_flush()` в файле `hw/ide/core.c` система не проверяет, пустой или не пустой `s->blk`. + +```asciidoc= hw/ide/core.c | 10 +++++++++- +--- + hw/ide/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index 0b48b64d3a..bea39536b0 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s) + s->status |= BUSY_STAT; + ide_set_retry(s); + block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH); +- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ ++ if (blk_bs(s->blk)) { ++ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ } else { ++ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this ++ * temporary workaround when blk_aio_*() functions handle NULL blk_bs. ++ */ ++ ide_flush_cb(s, 0); ++ } + } + + static void ide_cfata_metadata_inquiry(IDEState *s) +-- +``` + +[Устранение уязвимости](https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg01989.html): добавьте условное суждение в часть, в которой возникает данная уязвимость, и код теста к `tests/ide-test.c`. + +``` +--- + tests/ide-test.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/tests/ide-test.c b/tests/ide-test.c +index bfd79ddbdc..aa9de065fc 100644 +--- a/tests/ide-test.c ++++ b/tests/ide-test.c +@@ -689,6 +689,24 @@ static void test_flush_nodev(void) + ide_test_quit(); + } + ++static void test_flush_empty_drive(void) ++{ ++ QPCIDevice *dev; ++ QPCIBar bmdma_bar, ide_bar; ++ ++ ide_test_start("-device ide-cd,bus=ide.0"); ++ dev = get_pci_device(&bmdma_bar, &ide_bar); ++ ++ /* FLUSH CACHE command on device 0 */ ++ qpci_io_writeb(dev, ide_bar, reg_device, 0); ++ qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE); ++ ++ /* Just testing that qemu doesn't crash... */ ++ ++ free_pci_device(dev); ++ ide_test_quit(); ++} ++ + static void test_pci_retry_flush(void) + { + test_retry_flush("pc"); +@@ -954,6 +972,7 @@ int main(int argc, char **argv) + + qtest_add_func("/ide/flush", test_flush); + qtest_a + cd qemu + git checkout stable-2.10dd_func("/ide/flush/nodev", test_flush_nodev); ++ qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive); + qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush); + qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush); + +-- +``` + +* Воспроизведение сценария уязвимости: перед установкой патча найдите версию с подтвержденными изменениями, добавьте тестовые сценарии в новый тест и запустите программу Qtest. + +```bash= +# The corresponding version cannot be obtained by running the **wget** command because all affected versions have been fixed. +git clone https://gitlab.com/qemu-project/qemu.git;cd qemu +git checkout stable-2.10 +# Obtain the author of the patch from the mailing list and find the corresponding commit. +git log --author=Hajnoczi +git reset --hard=4da97120d51a4383aa96d741a2b837f8c4bbcd0b +# Start building. +mkdir build;cd build;../configure ----disable-werror +make qtest +``` + +Найденная в QEMU уязвимость VM escape включена в список стандартных уязвимостей, проработанных на соревнованиях в области информационной безопасности Capture the Flag (CTF), и базу данных общеизвестных уязвимостей информационной безопасности CVE ([CVE-2020-14364)](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14364). + +> Если вы заметили ошибку, напишите об этом здесь [cascades-sjtu](https://cascadeschen.cn). \ No newline at end of file diff --git a/web-ui/docs/ru/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md b/web-ui/docs/ru/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md new file mode 100644 index 0000000000000000000000000000000000000000..3f1ea20fd7c8307a2f6a966db5e1b27ba6ae3fba --- /dev/null +++ b/web-ui/docs/ru/blog/dwl301/Installing GNOME 3.38 on openEuler 21.09.md @@ -0,0 +1,175 @@ +--- +title: Установка GNOME 3.38 на ОС openEuler 21.09 +date: 2021-10-12 +tags: + - GNOME +archives: 2021-10 +author: dwl301 +summary: Принципы установки релиза GNOME 3.38 на операционной системе openEuler 21.09 и методы решения известных проблем. +--- + + + +# Установка GNOME 3.38 на ОС openEuler 21.09 + +GNOME — это среда рабочего стола для операционных систем подобных UNIX. Это официальная версия рабочего стола GNU Project, которая предоставляет универсальную, удобную и простую в использовании среду для разработки и использования приложений. + +В данном документе описывается метод установки среды рабочего стола GNOME как полного законченного решения на операционной системе openEuler 21.09. + +1\. Загрузка образа openEuler 21.09 + +``` +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso.sha256sum +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso +# sha256sum -c openEuler-21.09-x86_64-dvd.iso.sha256sum +openEuler-21.09-x86_64-dvd.iso: OK +``` + +2\. Создание установочного носителя для ОС + +Предположим, нижеприведенный носитель **sdb** является устройством хранения USB. В этом случае необходимо выполнить команду **lsblk**, чтобы подтвердить данное устройство. + +``` +# dd if=./openEuler-21.09-x86_64-dvd.iso of=/dev/sdb +# sync +``` + +3\. Установка ОС + +Выполните загрузку операционной системы с устройства USB и установите ее в минимальном режиме. Убедитесь, что для установки GNOME 3.38 в корневом разделе доступно не менее 5 ГБ свободного места. + +4\. Конфигурирование ОС и установка GNOME 3.38 + +Установите источник Yum системы. Убедитесь, что в ваш файл **/etc/yum.repos.d/openEuler.repo** включены следующие адреса: + +``` +baseurl=http://repo.openeuler.org/openEuler-21.09/everything/x86_64/ +baseurl=http://repo.openeuler.org/openEuler-21.09/EPOL/main/x86_64/ +``` + +Обновите кэш Yum. + +``` +# yum clean all +# yum makecache +``` + +Установите пакеты со шрифтами. + +``` +# yum install -y dejavu-fonts liberation-fonts gnu-*-fonts wqy-*-fonts cjkuni-ukai-fonts +``` + +Если используется высокоскоростное сетевое соединение, добавьте в вышеприведенную команду **google-\*-fonts**, чтобы установить тяжелые пакеты со шрифтами Google. В противном случае добавлять **google-\*-fonts** не нужно. + +Установите зависимости X Server. + +``` +# yum install -y xorg-* +``` + +Установите зависимости GNOME 3.38. + +``` +# yum install -y adwaita-icon-theme atk atkmm at-spi2-atk at-spi2-core baobab abattis-cantarell-fonts cheese clutter clutter-gst3 clutter-gtk cogl dconf dconf-editor devhelp eog epiphany evince evolution-data-server file-roller folks gcab gcr gdk-pixbuf2 gdm gedit geocode-glib gfbgraph gjs glib2 glibmm24 glib-networking gmime30 gnome-autoar gnome-backgrounds gnome-bluetooth gnome-boxes gnome-builder gnome-calculator gnome-calendar gnome-characters gnome-clocks gnome-color-manager gnome-contacts gnome-control-center gnome-desktop3 gnome-disk-utility gnome-font-viewer gnome-getting-started-docs gnome-initial-setup gnome-keyring gnome-logs gnome-menus gnome-music gnome-online-accounts gnome-online-miners gnome-photos gnome-remote-desktop gnome-screenshot gnome-session gnome-settings-daemon gnome-shell gnome-shell-extensions gnome-software gnome-system-monitor gnome-terminal gnome-tour gnome-user-docs gnome-user-share gnome-video-effects gnome-weather gobject-introspection gom grilo grilo-plugins gsettings-desktop-schemas gsound gspell gssdp gtk3 gtk4 gtk-doc gtkmm30 gtksourceview4 gtk-vnc2 gupnp gupnp-av gupnp-dlna gvfs json-glib libchamplain libdazzle libgdata libgee libgnomekbd libgsf libgtop2 libgweather libgxps libhandy libmediaart libnma libnotify libpeas librsvg2 libsecret libsigc++20 libsoup mm-common mutter nautilus orca pango pangomm libphodav python3-pyatspi python3-gobject rest rygel simple-scan sushi sysprof tepl totem totem-pl-parser tracker3 tracker3-miners vala vte291 yelp yelp-tools yelp-xsl zenity +``` + +Запустите GNOME 3.38 с помощью экранного менеджера GNOME Display Manager. + +``` +# systemctl start gdm +``` + +Активируйте окно входа на рабочий стол по умолчанию при запуске системы. + +``` +# systemctl enable gdm +# systemctl set-default graphical.target +``` + +5\. Исправление известных проблем + +5.1 Сбой воспроизведения видео + +Нет декодера. Вручную скомпилируйте и установите декодер. + +``` +# yum install rpm-build git ffmpeg-devel +# git clone https://gitee.com/src-openeuler/gstreamer1-libav.git +# mkdir -p ~/rpmbuild/SOURCES +# cp gstreamer1-libav/* /root/rpmbuild/SOURCES/ +# rpmbuild -ba /root/rpmbuild/SOURCES/gstreamer1-libav.spec +# yum install -y /root/rpmbuild/RPMS/x86_64/gstreamer1-libav-1.18.4-1.x86_64.rpm +``` + +Убедитесь, что каждая команда выполняется корректно, ошибки не возникают. + +5.2 Сбой создания ВМ в среде GNOME с помощью локального файла ISO + +Некорректный тип центрального процессора виртуальной машины, работающей в версии QEMU, которая установлена по умолчанию. Обновите GNOME Boxes до версии: + +``` +# rpm -Uvh http://119.3.219.20:82/openEuler:/Mainline/standard_x86_64/x86_64/gnome-boxes-3.38.2-3.oe1.x86_64.rpm +``` + +Повторно скомпилируйте QEMU. В установленной по умолчанию версии QEMU отключена опция smartcard. Добавьте опцию `--enable-smartcard` в команду **configure** и повторно скомпилируйте QEMU. + +``` +# wget https://repo.openeuler.org/openEuler-21.09/source/Packages/qemu-4.1.0-82.oe1.src.rpm +# rpm -ivh qemu-4.1.0-82.oe1.src.rpm + +Modify the ~/rpmbuild/SPECS/qemu.spec file as follows: +# diff -Nur ~/rpmbuild/SPECS/qemu.spec.bak ~/rpmbuild/SPECS/qemu.spec +--- /root/rpmbuild/SPECS/qemu.spec.bak 2021-10-12 14:30:30.300362506 +0800 ++++ /root/rpmbuild/SPECS/qemu.spec 2021-10-12 14:37:14.140967049 +0800 +@@ -1,6 +1,6 @@ + Name: qemu + Version: 4.1.0 +-Release: 82 ++Release: 83 + Epoch: 2 + Summary: QEMU is a generic and open source machine emulator and virtualizer + License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 +@@ -750,7 +750,7 @@ + --disable-parallels \ + --disable-sheepdog \ + --disable-capstone \ +- --disable-smartcard \ ++ --enable-smartcard \ + --enable-zstd + + make %{?_smp_mflags} $buildldflags V=1 +@@ -963,6 +963,9 @@ + %endif + + %changelog ++* Tue Oct 12 2021 Wenlong Ding ++- Open build option: --enable-smartcard ++ + * Sun Sep 26 2021 Chen Qun + - virtio-net: fix use after unmap/free for sg + +``` + +Установите зависимости для компиляции QEMU, повторно скомпилируйте и обновите QEMU. + +``` +# yum install -y bison brlapi-devel chrpath device-mapper-multipath-devel flex gnutls-devel libaio-devel libattr-devel libcap-devel libcap-ng-devel libcurl-devel libiscsi-devel librbd-devel libseccomp-devel libssh-devel libtasn1-devel lzo-devel ncurses-devel numactl-devel pam-devel python-sphinx python3-devel rdma-core-devel snappy-devel spice-server-devel texinfo zstd-devel +# rpmbuild -ba /root/rpmbuild/SPECS/qemu.spec +# rpm -Uvh ~/rpmbuild/RPMS/x86_64/qemu-*.rpm +``` + +Завершив обновление, перезапустите хост-систему. После повторного входа на хост будут доступны операции создания и запуска виртуальных машин с помощью gnome-boxes. + +5.3 Сбой запуска ВМ с помощью GNOME Boxes обычными пользователями + +Пользователи с обычным набором прав не добавлены автоматически в группы `kvm` и `libvirt`, поэтому виртуальные машины могут работать только как эмуляторы QEMU. По этой причине такие пользователи не могут запускать виртуальные машины, используя GNOME Boxes. Для добавления обычных пользователей к упомянутым группам выполните следующие команды, после чего ВМ смогут работать в режиме паравиртуализации KVM, который повышает эффективность. + +``` +# usermod -aG kvm test +# usermod -aG libvirt test +# id test +uid=1000(test) gid=1000(test) groups=1000(test),10(wheel),36(kvm),985(libvirt) +``` + +Добавив обычных пользователей к группам `kvm` и `libvirt`, перезапустите систему, чтобы настройки вступили в силу. \ No newline at end of file diff --git a/web-ui/docs/ru/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md b/web-ui/docs/ru/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md new file mode 100644 index 0000000000000000000000000000000000000000..f002b196e3e577baec7e91b94aa155abc820450c --- /dev/null +++ b/web-ui/docs/ru/blog/gitee-cmd/Guide for Uploading a Software Package to the openEuler Community.md @@ -0,0 +1,313 @@ +--- +title: Руководство по выгрузке программного пакета в сообщество openEuler +date: 2021-12-20 +tags: + - openEuler + - программное обеспечение + - руководство +archives: 2021-12 +author: gitee-cmd +summary: Руководство по выгрузке программного обеспечения в сообщество openEuler +--- + +--- + +# Руководство по выгрузке программного пакета в сообщество openEuler + +В данном руководстве описан метод выгрузки программного пакета на ресурс сообщества openEuler. Участникам проекта необходимо следовать данным инструкциям для обеспечения успешной выгрузки и эффективной работы сообщества. + +## 1\. Контрольный список требований + +Прежде чем отправить запрос на принятие изменений кода (Pull Request; PR), убедитесь, что пакет программного обеспечения и соответствующие зависимости отвечают правилам приема, принятым в сообществе openEuler. В следующей таблице перечислен контрольный список требований. + +| Требование | Описание | +| ------------------------------------------------ | ------------------------------------------------------------ | +| Нормализация | ● В большинстве случаев фрагмент кода выгружается на src-openeuler только один раз. | +| Источник | ● Исходный код необходимо загружать только с официального веб-сайта или хоста, адрес которого указывается на официальном веб-сайте. | +| Название программного обеспечения | ● Название программного обеспечения должно совпадать с названием, приведенным на официальном веб-сайте или странице сообщества.
● В качестве названия запрещается использовать подмодуль, содержащийся в программного пакете.
● Если программное обеспечение представляет собой библиотеку для разработки на каком-либо языке программирования, можно добавить префиксы python- и perl- в целях стандартизации названий. | +| Статус сообщества | Не рекомендуется выгружать следующее программное обеспечение:
● программное обеспечение, выпущенное известным сообществом или организацией, обслуживание которого больше не осуществляется;
● программное обеспечение, выпущенное отдельными пользователями или небольшим сообществом или организацией, у которого за последние два года нет новых выгруженных версий;
● программное обеспечение, выпущенное сообществом, текущий статус которого неясен;
● программное обеспечение, у которого проблемы не решались в течение последних шести месяцев. | +| Официальный веб-сайт (обязательное к выполнению) | ● Необходимо использовать официальный веб-сайт поставщика программного обеспечения. В отсутствии официального веб-сайта можно использовать веб-сайт проекта на основных платформах размещения исходного кода, например GitHub.
● Запрещается использовать в качестве официального веб-сайта следующие хостинговые платформы: Maven, MvnRepository, SpringSource. | +| Информация о пакете программного обеспечения | ● Для отслеживания исходного кода необходимо использовать официальный адрес загрузки пакета с кодом.
● Если требуется бинарный пакет, необходимо предоставить официальный адрес загрузки такого пакета. | +| Лицензия | ● Убедитесь, что на выгружаемое программное обеспечение есть лицензия.
● Убедитесь, что указанная лицензия совпадает с лицензией, содержащейся на официальном веб-сайте и в программном пакете.
● Соблюдайте осторожность, выгружая фрагмент открытого программного обеспечения, лицензия на которое относится к высокому риску. | +| Авторские права | ● Предоставьте информацию об авторских правах, содержащуюся на официальном веб-сайте, ресурсе сообщества, хостинговой платформе размещения исходного кода, пакете с исходным кодом и пакете релиза. | + +**Примечание.** + +1. Нормализация: прежде чем выгрузить разные версии одного программного пакета, например MySQL и MySQL5, свяжитесь с техническим комитетом и SIG. +2. Подробнее о проверке лицензий, а также о белом и черном списках для защиты авторского права см. \[[Список лицензий](https://spdx.org/licenses/) [SPDX](https://spdx.org/licenses/)]. + +## 2\. Анализ зависимостей программного пакета + +Прежде чем отправить PR-запрос для выгрузки программного обеспечения, рекомендуется проанализировать зависимости программного пакета. Далее предложены несколько методов анализа. + +### 2.1. Использование pkgship + +pkgship — это инструмент, разработанный командой openEuler для управления программными пакетами в сообществе openEuler. С помощью данного инструмента можно проанализировать зависимости разных версий ОС openEuler и программных пакетов Fedora, а также запросить бинарные пакеты и пакеты с исходным кодом. Загрузить pkgship можно здесь [pkgship](https://pkgmanage.openeuler.org/). + +#### 2.1.1. Онлайн-анализ + +pkgship поддерживает четыре типа анализа зависимостей: **Install Depend**, **Build Depend**, **Self Depend**, **Bedepend**. Перед выгрузкой пакета программного обеспечения выполните анализ зависимостей в онлайн, используя инструмент pkgship, который позволит просмотреть зависимости установки и компиляции в формате Excel. + +![guide](./images/pkgship.png) + +**Выбор типа анализа:** + +На странице **Package Management** нажмите **Depend Info**, выберите корректный тип анализа зависимостей, введите имя пакета и выберите репозиторий, нажав **click here**. + +![guide](./images/pkg_repo_select.png) + +**Выбор ветки и исходного сообщества:** + +На открывшейся странице выберите нужную ветку и исходное сообщество и нажмите **OK**. + +![guide](./images/branch_select.png) + +**Запрос результатов:** + +Нажмите значок лупы, инструмент pkgship автоматически проанализирует зависимости в соответствии с заданными пользователем настройками. + +![guide](./images/fed_pkg.png) + +**Анализ результатов запроса зависимостей:** + +Просмотрите список пакетов с исходным кодом в разделе **Source Package List**. Выгрузить необходимо те пакеты, у которых в пункте **Database** стоит значение **fedora33**. + +![guide](./images/need_introduce.png) + +#### 2.1.2. Анализ зависимостей в локальном режиме + +Инструмент pkgship также поддерживает локальный режим развертывания и анализа зависимостей источников, задаваемых пользователями. Подробнее см. на странице https://gitee.com/src-openeuler/pkgship. + +**Примечание.** + +В случае возникновения любой проблемы с использованием инструмента pkgship оставьте свой отзыв в [репозитории pkgship](https://gitee.com/openeuler/pkgship/issues). + +### 2.2. Анализ зависимостей в исходном сообществе + +В тех программных пакетах, в которых проанализировать зависимости с помощью инструмента pkgship нельзя, необходимо выполнить ручной анализ. + +#### 2.2.1. Компиляционные зависимости + +**Использование файла SPEC, предоставляемого исходным сообществом:** + +Найдите компиляционные зависимости выгружаемого пакета по имени пакета с зависимостями, которое можно найти в поле **BuildRequires** в файле SPEC. + +**Использование** **инструмента управления языками программирования и файла управления зависимостями:** + +Если исходное сообщество не предоставляет файл SPEC, выполните анализ с помощью инструмента управления языками программирования и конкретного файла управления зависимостями. В следующей таблице перечислены типы файлов управления зависимостями для ряда языков программирования и соответствующие им менеджеры управления пакетами. + +| Язык | Менеджер управления пакетами | Тип файла | +| ------- | ---------------------------- | ------------------------- | +| C++ | CMake | Makefile | +| java | maven pom | pom.xml | +| go | go modules | go.mod | +| rust | cargo | Cargo.toml | +| ruby | RubyGems | *.gemspec | +| python | pip | requirements.txt/setup.py | +| Node.js | npm/yarn | | + +**Инструменты для генерации файла SPEC:** + +- Для пакетов на языке Python: [PyPorter](https://gitee.com/openeuler/pyporter) + +- Для пакетов на языке Ruby: [RubyPorter](https://gitee.com/openeuler/rubyporter) + +- Для пакетов Node.js: [nodejsporter](https://gitee.com/openeuler/nodejsporter) + +- Для пакетов на языке perlporter: [perlporter](https://gitee.com/openeuler/pyporter) + +**Примечание.** Сгенерировав файл, проверьте следующую информацию: + +- Проверьте корректность описания программного обеспечения. (Поле для описания не должно быть пустым или содержать только имя пакета.) +- Убедитесь, что соблюдены требования к стандартному оформлению, в частности, каждая часть в файле SPEC отделена пустыми строками. К примеру, пустые строки должны быть добавлены перед выражениями **%prep** и **%description**. + +#### 2.2.2. Установка и запуск зависимостей + +**Использование файла SPEC, предоставляемого исходным сообществом:** + +Найдите инсталляционные зависимости выгружаемого пакета по имени пакета с зависимостями, которое можно найти в поле **Requires** в файле SPEC. + +**Использование инструмента rpmbuild для анализа:** + +```bash +rpm -a requires [package_name] +``` + +Проверьте инсталляционные зависимости. + + + +## 3\. Самопроверка программного пакета + +Анализ зависимостей и самопроверку программного пакета необходимо выполнять перед отправкой PR-запроса. + +### 3.1. Изменение файла SPEC + +#### 3.1.1. Правка формата и статическая проверка + +- Измените последовательность ключевых слов. +- Измените **changelog**. **changelog** в файле SPEC нового программного пакета содержит только пакет **init**. +- Исключите деликатные слова и сохраните комментарии к патчу, не содержащие деликатных слов. Как правило, сообщество openEuler не принимает контент от исходных сообществ Fedora и RHEL. +- Измените поле **release**. Установите в поле **release** нового программного пакета значение **1** и при каждом последующем изменении файла SPEC изменяйте это значение на 1. +- Проверьте список лицензий и убедитесь, что не выгружаете программные пакеты с лицензиями, несущими риски. + +#### 3.1.2. Отслеживание источника получения кода + +- Убедитесь, что URL-адрес официального веб-сайта, содержащийся в файле SPEC, рабочий, и к нему можно получить доступ через браузер. + +- Убедитесь, что адрес загрузки пакета с исходным кодом (**source0**), содержащийся в файле SPEC, действительный, и пакет с ссылкой на источник совпадает с пакетом с исходным кодом данного программного обеспечения. + + - Если загруженный пакет с исходным кодом отличается от собранного пакета с исходным кодом, используйте для проверки загруженный пакет. + + - ```bash + md5sum package name 1 package name 2   + ``` + + ![guide](./images/md5.png) + + Убедитесь, что данные две последовательности символов совпадают. + + - Если ссылка на загрузку пакета **source0** не работает, найдите ссылку, которую можно использовать для версии, поддерживаемой исходным сообществом (подобным GitHub), для повторной проверки. (Можно найти в комментариях к исходному файлу SPEC.) + +### **3.2 rpmbuild** + +Для проверки локальной компиляции воспользуйтесь инструментом rpmbuild. + +```bash +rpmbuild -ba [spec file] +``` + +Используйте параметр -ba для сборки бинарного пакета и пакета с исходным кодом в соответствии с файлом SPEC. + +### 3.3. Проверка компиляции [OBS](https://117.78.1.88/) + +Несмотря на то, что для проверки локальной компиляции можно использовать инструмент rpmbuild, результаты такой проверки могут отличаться от результатов проверки компиляции OBS, поскольку среда OBS отлична от локальной среды. Поэтому прежде чем отправить запрос PR, найдите соответствующую ветвь от OBS и проверьте компиляцию. + +#### 3.3.1. Конфигурирование среды OSC + +Для настройки клиента OSC создайте файл **.oscrc** в каталоге **/root/**. Методы настройки OSC: + +- Укажите IP-адрес в конфигурационном файле. + + ![guide](./images/osc_config1.png) + +- Используйте доменное имя в конфигурационном файле и добавьте соответствие между IP-адресом и доменным именем в **/etc/hosts**. + + ![guide](./images/osc_config2.png) + + ![guide](./images/etc_host.png) + +#### 3.3.2. Разработка и проверка OBS + +- **Получение изменений и обновление локальной ветви** + +1. В нужной ветви выберите пакет программного обеспечения. + + ![guide](./images/obs_branch.png) + +2. В этой же ветви создайте новый пакет программного обеспечения. + + ![guide](./images/obs_create_pkg.png) + +3. Создайте локальную ветвь. + +- **Компиляция OSC** + + 1. Выполните следующую команду, чтобы загрузить сетевой репозиторий на локальный хост. + + ```bash + osc co home:xxxxx:branches:openEuler:Mainline software_package_name + ``` + + 2. Перейдите на свою ветвь: **home:xxxxx:branches:openEuler:Mainline/*название пакета программного обеспечения*** + + 3. Переместите файл SPEC и пакет TAR, соответствующий данному программному обеспечению, в свою ветвь. (Также необходимо выгрузить патчи и конфигурационные файлы.) + + 4. В связи с ограниченностью ресурсов OBS рекомендуется выполнить команду **osc build** для проверки локальной компиляции, прежде чем выгружать пакет в среду OBS для онлайн-компиляции. Эта операция позволит избежать повторной выгрузки и компиляции. + + ```bash + osc build + ``` + + 5. Выполните команду **osc** для выгрузки локального файла в свою сетевую ветвь OBS. + + ```bash + osc add * + osc ci + ``` + + 6. Просмотрите результаты компиляции онлайн в своей ветви OBS. + + ![guide](./images/osb.png) + +### 3.4. Проверка установки и удаления пакета программного обеспечения + +- Убедитесь, что в данной среде не существует пакета другой версии. + + ```bash + rpm -e `rpm -qa | grep $fileName` + ``` + +- Установите пакет программного обеспечения. + + ```bash + rpm –ivh xxx-2.0.1-2.aarch64.rpm + ``` + + Команда **rpm** не выполняет автоматический поиск зависимостей. Поэтому установите заранее пакеты зависимостей для проверки. + +- Убедитесь, что данный пакет программного обеспечения можно удалить. + + ```bash + rpm –e xxx-2.0.1-2.aarch64.rpm + ``` + +### 3.5. **Проверка базовых функций пакета программного обеспечения** + +**Пакет программного обеспечения с командными строками:** + +```bash +rpm –qpl xxx.rpm +``` + +Запросите команду и выполните ее, чтобы убедиться, что функция проверки работает корректно. (Новая команда помещается в каталог /usr/bin/.) + +**Сервисный пакет программного обеспечения:** + +```bash +systemctl start [service.name] +``` + +## 4\. Компиляция файла YAML + +openEuler-Advisor предназначен для автоматической проверки и составления рекомендаций по рутинным операциям с репозиториями артефактов сообщества openEuler. Чтобы инструмент openEuler-Advisor запускался автоматически, сконфигурируйте файл YAML в репозитории в соответствии с **[требованиями к файлам YAML](https://gitee.com/openeuler/openEuler-Advisor/blob/master/README.en.md)**. + +1. Создайте файл YAML. Имя файла YAML должно совпадать с именем файла SPEC. + +2. Отредактируйте файл YAML и добавьте информацию в следующие поля. + + - **version\_control**: протокол управления версиями исходного репозитория. В настоящее время доступны значения **svn**, **git**, **hg**, **github**, **gnome**, **metacpan**, **pypi**. Если нужного протокола нет среди доступных значений, введите **NA**. + + - **src\_repo:** фактический адрес исходного репозитория. Для загрузки соответствующего кода можно использовать **version\_control** и **src\_repo**. + + - **tag\_prefix**: префикс версии в теге исходного репозитория. Если используется протокол git, командой **git tag** можно вывести все теги. Если тег с исходного репозитория — v1*0*1, параметру **tag\_prefix** необходимо задать значение **^v**. Информацию по корректной версии можно получить, сравнив **tag\_prefix**. Если формат тега изменен, используйте последний вариант формата. + + В особых случаях используйте знак подстановки (\*) следующим образом: + + ![guide](./images/special_yaml.png) + + Пример. + + ```bash + "selenium-(.*?)-alpha-(.*?)" + ``` + +- **separator:** разделитель версий в теге. Если тег — v1*0*1, а параметр **separator** имеет значение **\_**, корректную версию 1.0.1 можно узнать, проанализировав код парсингом. + +![guide](./images/yaml_content.png) + +## Справочная информация + +[openEuler-Advisor](https://gitee.com/openeuler/openEuler-Advisor/blob/master/README.en.md) + +[Репозиторий Gitee DisNight](https://gitee.com/disnight) \ No newline at end of file diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/branch_select.png b/web-ui/docs/ru/blog/gitee-cmd/images/branch_select.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3f88dd6c75f04bcf9f9845c5d2176467368752 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/branch_select.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/etc_host.png b/web-ui/docs/ru/blog/gitee-cmd/images/etc_host.png new file mode 100644 index 0000000000000000000000000000000000000000..19c51a5628c73cfbf8869ced8750f012edd1a041 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/etc_host.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/fed_pkg.png b/web-ui/docs/ru/blog/gitee-cmd/images/fed_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..e55fd3d183d962cf4620a525e0465653a0748632 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/fed_pkg.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/md5.png b/web-ui/docs/ru/blog/gitee-cmd/images/md5.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0e221071f14668e2f63c15c20cd762fc0c1a46 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/md5.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/moban.png b/web-ui/docs/ru/blog/gitee-cmd/images/moban.png new file mode 100644 index 0000000000000000000000000000000000000000..03aeb294357923f19c0722a0805b4617cbb0de7a Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/moban.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/need_introduce.png b/web-ui/docs/ru/blog/gitee-cmd/images/need_introduce.png new file mode 100644 index 0000000000000000000000000000000000000000..10c7d21d7cfd5651177c2a9e9e82113c58d51816 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/need_introduce.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch.png b/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch.png new file mode 100644 index 0000000000000000000000000000000000000000..dd51ea6e7c223d8407187a7b80abdcab8cbb365e Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch_accept.png b/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch_accept.png new file mode 100644 index 0000000000000000000000000000000000000000..6b90b6152711453613fc5e765aba9af082297c75 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/obs_branch_accept.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/obs_create_pkg.png b/web-ui/docs/ru/blog/gitee-cmd/images/obs_create_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..c90f2748f3f1d92930cc08c8fecc534ec8f1b714 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/obs_create_pkg.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/osb.png b/web-ui/docs/ru/blog/gitee-cmd/images/osb.png new file mode 100644 index 0000000000000000000000000000000000000000..16d1e3bb9997a0913b3d658037f3fa4260d03be7 Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/osb.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/osc_config1.png b/web-ui/docs/ru/blog/gitee-cmd/images/osc_config1.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2e7a1298594c1d3efb74f838fa10145187114c Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/osc_config1.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/osc_config2.png b/web-ui/docs/ru/blog/gitee-cmd/images/osc_config2.png new file mode 100644 index 0000000000000000000000000000000000000000..dc809fcb24c44b25b463dd5cbca322b0c40132ef Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/osc_config2.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/pkg_repo_select.png b/web-ui/docs/ru/blog/gitee-cmd/images/pkg_repo_select.png new file mode 100644 index 0000000000000000000000000000000000000000..b852280ea8fc77807366a10449a6bc37d60731eb Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/pkg_repo_select.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/pkgship.png b/web-ui/docs/ru/blog/gitee-cmd/images/pkgship.png new file mode 100644 index 0000000000000000000000000000000000000000..c2174d66958f75b6f5012ea37aa32cca2443926c Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/pkgship.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/sample.png b/web-ui/docs/ru/blog/gitee-cmd/images/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..28e1a7ab2ab82a4ee20328a2fdd0ca26301e2b9b Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/sample.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/special_yaml.png b/web-ui/docs/ru/blog/gitee-cmd/images/special_yaml.png new file mode 100644 index 0000000000000000000000000000000000000000..fccacdc0c24ca3c441ae3ff0595208f62038476c Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/special_yaml.png differ diff --git a/web-ui/docs/ru/blog/gitee-cmd/images/yaml_content.png b/web-ui/docs/ru/blog/gitee-cmd/images/yaml_content.png new file mode 100644 index 0000000000000000000000000000000000000000..8d756634862798f0786500d4c48d0d335c57316c Binary files /dev/null and b/web-ui/docs/ru/blog/gitee-cmd/images/yaml_content.png differ diff --git a/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png new file mode 100644 index 0000000000000000000000000000000000000000..faf84c12a81260aeb0be4520b6f582a5c25d45bb Binary files /dev/null and b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png differ diff --git a/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b820312a2603b934c5464ae8106ee29ccb80c2 Binary files /dev/null and b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png differ diff --git a/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png new file mode 100644 index 0000000000000000000000000000000000000000..d85295011c695c359fb04ec3838b85eeb83cd502 Binary files /dev/null and b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png differ diff --git a/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png new file mode 100644 index 0000000000000000000000000000000000000000..bed0c5029d8d63667cd3179b8ad2e855dc8be39f Binary files /dev/null and b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png differ diff --git a/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png new file mode 100644 index 0000000000000000000000000000000000000000..b83fae4c4a29df46066ec83e88b67a6d89b2ae1d Binary files /dev/null and b/web-ui/docs/ru/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png differ diff --git a/web-ui/docs/ru/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md b/web-ui/docs/ru/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md new file mode 100644 index 0000000000000000000000000000000000000000..5a0489a7602275b5a757732130f5ed0cffe678eb --- /dev/null +++ b/web-ui/docs/ru/blog/liuqi/How to Unsubscribe from a Mailing List of the openEuler Community.md @@ -0,0 +1,46 @@ +--- +title: Как отписаться от рассылки сообщества openEuler +date: 2021-11-23 +tags: + - openEuler + - Рассылка + - Отмена подписки на рассылку +sig: sig-Gatekeeper +archives: 2021-11 +author: liuqi<469227928@qq.com> +summary: В данном блоге описаны два метода отмены подписки на рассылку сообщества openEuler. + +--- + + +Специалисты из группы поддержки сообщества openEuler получают от участников и специалистов по обслуживанию вопросы об отказе от рассылки openEuler. Здесь приведены два способа отмены подписки. + +### 1\. Отмена подписки на рассылку по электронной почте + +Отмените подписку по электронной почте одним из двух методов. В нижней части электронного письма найдите и щелкните значок отмены подписки. В результате данной операции будет создано и отправлено электронное письмо с отказом от подписки. Другой вариант: отправьте письмо по адресу `**-leave@openeuler.org`. Далее описывается процедура отмены подписки от рассылки с адреса test@openeuler.org. + +\- Если в электронном письме есть нижний колонтитул с ссылкой на отказ от рассылки, нажмите +test-leave@openeuler.org, будет создано и отправлено письмо с отказом от рассылки. Здесь не требуется добавлять заголовок письма или какое-либо содержание. + +通过邮件页脚退订 + +После этого в ответ придет автоматически созданное электронное письмо, информирующее об успешной отмене подписки на рассылку. + +退订成功 + +\- Другой вариант: отправьте электронное письмо по адресу tc-leave@openeuler.org с вашего зарегистрированного почтового ящика. Здесь не требуется добавлять заголовок письма или какое-либо содержание. + +发送退订邮件 + +После этого в ответ придет автоматически созданное электронное письмо, информирующее об успешной отмене подписки на рассылку. + +退订成功 + +### 2\. Отмена подписки на рассылку через веб-интерфейс + +Если вы являетесь зарегистрированным пользователем, включенным в список рассылки openEuler (в настоящее время интерфейс регистрации недоступен), войдите в [**Postorius**](https://mailweb.openeuler.org/postorius/lists/), перейдите к списку рассылки и нажмите **Unsubscribe**. + +Web UI退订 +### Другие проблемы + +Если остались без ответа какие-либо вопросы, связанные с рассылкой сообщества, перейдите на ресурс [**Часто задаваемые вопросы по рассылке**](https://osinfra.cn/faq/mailinglist.html). \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Apache 2.4.39 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Apache 2.4.39 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..16e83a33bcd27ea61b9ed0522fcf93d65d8e7ac7 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Apache 2.4.39 Porting Guide.md @@ -0,0 +1,136 @@ +--- +title: Руководство по портированию Apache 2.4.39 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Apache + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования Apache 2.4.39. +--- + +# Руководство по портированию Apache 2.4.39 (openEuler 20.03 LTS SP1) + +# Введение + +## Обзорная информация об Apache + +Apache HTTP Server (сокращенно Apache) — это веб-сервер с открытым исходным кодом, разработанный при поддержке фонда разработчиков Apache Software Foundation. Сервер, работающий на разных операционных системах, широко используется благодаря высокой безопасности и совместимости с различными платформами. Это надежное и быстродействующее программное обеспечение можно расширять с помощью простых API-интерфейсов, которые позволяют компилировать на сервер интерпретаторы таких языков, как Perl и Python. + +Язык программирования: C. + +Краткое описание: веб-сервер. + +## Рекомендуемая версия + +Apache httpd 2.4.39 или более поздние версии. + +# Требования к среде + +## Аппаратное обеспечение + +В следующей таблице приведены требования к аппаратному обеспечению. + +| Параметр | Описание | +| --------------------- | -------------------------------- | +| Сервер | Сервер TaiShan 200 (модель 2280) | +| Центральный процессор | Процессор Kunpeng 920 5250 | +| Раздел диска | Нет требований | + +## Операционная система + +В следующей таблице приведены требования к операционной системе. + +| Параметр | Версия | +| --------- | ----------------- | +| openEuler | 20.03 SP1 AArch64 | +| Ядро | 4.19 | + +ПРИМЕЧАНИЕ: + +Если операционная система устанавливается впервые, выберите режим установки «Server with GUI» вместо «Minimal Install». Иначе придется вручную устанавливать много программных пакетов. + +# Конфигурирование среды компиляции + +1. Установите пакет для разработки. + +``` +yum update +yum install gcc gcc-c++ +``` + +2. Установите зависимости. + +``` +yum install apr-devel.aarch64 apr-util-devel.aarch64 pcre-devel.aarch64 -y +``` + +3. Получите исходный код. + + Адрес загрузки: http://archive.apache.org/dist/httpd/httpd-2.4.39.tar.gz. + +## Подготовка инсталляционного пакета + + tar xzvf httpd-2.4.39.tar.gz + +## Изменение исходного кода + + cd httpd-2.4.39 + vi ./build/config.sub + + In the following two lines, add aarch64: + + | x86 | xc16x | xstormy16 | xtensa \ + => + | x86 | aarch64 | xc16x | xstormy16 | xtensa \ + + + | x86-* | x86_64-* | xc16x-* | xps100-* \ + => + | x86-* | aarch64-* | x86_64-* | xc16x-* | xps100-* \ + + +## Компиляция и установка Apache + + ./configure --host=aarch64 --build=aarch64 + make -j4 + make install + +# Настройка параметров + +## Изменение httpd.conf + + vi /usr/local/apache2/conf/httpd.conf + + Delete the comment tag in line 89. + LoadModule socache_shmcb_module modules/mod_socache_shmcb.so + + Delete the comment tag in line 196 and change the value to the IP address of the current server. + #ServerName www.example.com:80 + => + ServerName local_server_ip:80 + + Delete the comment tag in line 461. + Include conf/extra/httpd-mpm.conf + + Delete the comment tag in line 488. + Include conf/extra/httpd-default.conf + +## Изменение httpd-default.conf + + vi /usr/local/apache2/conf/extra/httpd-default.conf + + Change the value in line 23 to 0. + MaxKeepAliveRequests 0 + +# Верификация Apache + + Run the following command to start Apache: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start + + Run the following command to stop Apache: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k stop + + Run the following command to check the service process: + ps -ef |grep httpd \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Dubbo 2.6.8 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Dubbo 2.6.8 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..f2286b5a7812bef8da5e4ad617f0005d1576428c --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Dubbo 2.6.8 Porting Guide.md @@ -0,0 +1,192 @@ +--- +title: Руководство по портированию Dubbo 2.6.8 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования Dubbo 2.6.8. +--- + +# Руководство по портированию Dubbo 2.6.8 (openEuler 20.03 LTS SP1) + +## Введение + +### Обзор + +Dubbo — это высокопроизводительный сервисный фреймворк с открытым исходным кодом, предоставляемый компанией Alibaba, с помощью которого приложения выполняют ввод и вывод сервисных запросов через удаленный вызов процедур (RPC). Данный фреймворк легко интегрируется с фреймворком Spring. Фактически Dubbo представляет собой фреймворк RPC, основанный на Spring, который реализует удаленный вызов и управление сервисами. + + + +### Рекомендуемая версия + +Dubbo 2.6.8 + + + +## Требования к среде + +### Аппаратное обеспечение + +Требования к аппаратному обеспечению перечислены в [Табл. 1](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html). + +| Параметр | Описание | +| --------------------- | -------------------------- | +| Центральный процессор | Процессор Kunpeng 920 | +| Сеть | Наличие доступа к Интернет | +| СХД | Нет требований | +| Память | Нет требований | + +### Операционная система + +Требования к операционной системе перечислены в [Табл. 2](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html). + +| Параметр | Версия | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64 | +| Ядро | 4.19.90 | + + + +## Конфигурирование среды компиляции + +### Конфигурирование сервера DNS + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + +### Установка зависимостей + +1. Загрузите и установите зависимости. + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + +2. Запросите версию Java. + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + +### Установка Maven + +1. Загрузите инсталляционный пакет Maven. + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + +2. Разархивируйте инсталляционный пакет в указанный каталог. + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + +3. Сконфигурируйте переменные среды Maven. + +a. Добавьте путь к Maven в конце файла **/etc/profile**. + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo "export PATH=$MAVEN_HOME/bin:$PATH" >> /etc/profile +``` + +b. Выполните операцию, чтобы измененные переменные среды вступили в силу. + +``` +source /etc/profile +``` + +4. Убедитесь, что конфигурация вступила в силу. + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + +5. В конфигурационном файле Maven измените локальный репозиторий, удаленный репозиторий и прокси. + +Путь к конфигурационному файлу: **/opt/apache-maven-3.6.3/conf/settings.xml**. + +Сконфигурируйте сетевой прокси. Введите желаемые значения параметров **host**, **port**, **username** и **password**. + +``` + + + my-proxy + true + https + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + + my-proxy1 + true + http + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + +``` + +Сконфигурируйте удаленный репозиторий. + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + +## Компиляция Dubbo 2.6.8 + +### Получение исходного кода + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.6.8.tar.gz +&& tar -xvf dubbo-2.6.8.tar.gz +``` + +### Компиляция модуля dubbo-rpc-redis + +``` +mvn install +``` + +Если на экране появится сообщение **BUILD SUCCESS**, значит модуль dubbo-rpc-redis скомпилирован. + +### Компиляция Dubbo 2.6.8 + +В конец строки 552 файла **/home/Dubbo/dubbo-dubbo-2.6.8/pom.xml** добавьте следующее содержание: + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит Dubbo 2.6.8 скомпилирован. + + + +Созданный после компиляции пакет **dubbo-2.6.8.jar** сохраняется в каталоге **all/target**. \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Dubbo 2.7.5 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Dubbo 2.7.5 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..99ca2ae2ec834a9c891b1b55fe658b9a54de15d6 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Dubbo 2.7.5 Porting Guide.md @@ -0,0 +1,366 @@ +--- +title: Руководство по портированию Dubbo 2.7.5 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования Dubbo 2.7.5. +--- + +# Руководство по портированию Dubbo 2.7.5 (openEuler 20.03 LTS SP1) + + + +## Введение + +### Обзор + +Dubbo — это высокопроизводительный сервисный фреймворк с открытым исходным кодом, предоставляемый компанией Alibaba, с помощью которого приложения выполняют ввод и вывод сервисных запросов через удаленный вызов процедур (RPC). Данный фреймворк легко интегрируется с фреймворком Spring. Фактически Dubbo представляет собой фреймворк RPC, основанный на Spring, который реализует удаленный вызов и управление сервисами. + + + +### Рекомендуемая версия + +Dubbo 2.7.5 + + + +## Требования к среде + +### Аппаратное обеспечение + +Требования к аппаратному обеспечению перечислены в [Табл. 1](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html). + +| Параметр | Описание | +| --------------------- | -------------------------- | +| Центральный процессор | Процессор Kunpeng 920 | +| Сеть | Наличие доступа к Интернет | +| СХД | Нет требований | +| Память | Нет требований | + +### Операционная система + +Требования к операционной системе перечислены в [Табл. 2](https://support.huaweicloud.com/intl/en-us/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html). + +| Параметр | Версия | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64 | +| Ядро | 4.19.90 | + + + +## Конфигурирование среды компиляции + +### Конфигурирование сервера DNS + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + +### Установка зависимостей + +1. Загрузите и установите зависимости. + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + +2. Запросите версию Java. + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + +### Установка Maven + +1. Загрузите инсталляционный пакет Maven. + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + +2. Разархивируйте инсталляционный пакет в указанный каталог. + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + +3. Сконфигурируйте переменные среды Maven. + +a. Добавьте путь к Maven в конце файла **/etc/profile**. + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> /etc/profile +``` + +b. Выполните операцию, чтобы измененные переменные среды вступили в силу. + +``` +source /etc/profile +``` + +4. Убедитесь, что конфигурация вступила в силу. + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + +5. В конфигурационном файле Maven измените локальный репозиторий, удаленный репозиторий и прокси. + +Путь к конфигурационному файлу: **/opt/apache-maven-3.6.3/conf/settings.xml** + +Сконфигурируйте сетевой прокси. Введите желаемые значения параметров **host**, **port**, **username** и **password**. + +``` + + + my-proxy + true + https + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + + my-proxy1 + true + http + Proxy server URL + Proxy server port + User name + Password + local.net|some.host.com + + +``` + +Сконфигурируйте удаленный репозиторий. + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + +## Компиляция + +### Получение исходного кода + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.7.5.tar.gz +&& tar -xvf dubbo-2.7.5.tar.gz +``` + +### Компиляция модуля dubbo-common + +### Компиляция модуля dubbo-remoting-netty + +1. Измените файл **NettyClientTest.java**. + + a. Откройте файл и замените значение **6000** в строке 76 значением **9000**. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/NettyClientTest.java` + + + b. Скомпилируйте модуль dubbo-remoting-netty. + + ``` + cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty && mvn install + ``` + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит модуль dubbo-remoting-netty скомпилирован. + + + +### Компиляция модуля dubbo-rpc-redis + +1. Получите пакет **embedded-redis-0.6.jar**, поддерживающий AArch64. + +``` + mkdir -p /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar -O /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar +``` + +2. Скомпилируйте модуль dubbo-rpc-redis. + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-rpc/dubbo-rpc-redis/ && mvn install +``` + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит модуль dubbo-rpc-redis скомпилирован. + +### Компиляция модуля dubbo-remoting-etcd3 + +1. Установите Docker. + +``` +yum -y install docker +``` + +2. Настройте переменные среды. + +``` +echo "export TESTCONTAINERS_RYUK_DISABLED=true" >> /etc/profile && source /etc/profile +``` + +3. Измените файл **/root/.testcontainers.properties**. + +``` +echo "checks.disable=true" >> /root/.testcontainers.properties +``` + +4. Замените пакет **jetcd-launcher-0.3.0.jar** пакетом, поддерживающим образ ARM64. + +``` +wget https://mirrors.huaweicloud.com/kunpeng/maven/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar -O /root/.m2/repository/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar +``` + +5. Скомпилируйте модуль dubbo-remoting-etcd3. + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-etcd3/ && mvn install +``` + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит модуль dubbo-remoting- etcd3 скомпилирован. + +### Компиляция модуля dubbo-registry-consul + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-registry/dubbo-registry-consul/ && mvn install + +``` + +Если во время компиляции появится сообщение «EmbeddedConsul Could not start Consul process in...», сохраните пакет **consul\_1.1.0\_linux\_arm64.zip** версии ARM64 в каталоге **local /tmp/embedded-consul-1.1.0**. + +``` +wget https://releases.hashicorp.com/consul/1.1.0/consul_1.1.0_linux_arm64.zip && unzip consul_1.1.0_linux_arm64.zip && mv consul /tmp/embedded-consul-1.1.0/consul +``` + +Затем повторно скомпилируйте модуль. + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит модуль dubbo-registry-consul скомпилирован. + +### Изменение остальных конфигурационных файлов + +1. Замените пакет **netty-all-4.1.25.Final.jar** в локальном репозитории. + + ``` + mkdir -p /root/.m2/repository/io/netty/netty-all/4.1.25.Final/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar -O /root/.m2/repository/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar + ``` + +2. Измените файл **/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml**. + + 1. Откройте файл **pom.xml**. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml` + + 2. Добавьте следующий код. Сохраните файл и выйдите. + + - Добавьте следующий код в строку 31: + + ``` + true + ``` + + + + - Добавьте следующий код в строку 206: + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + +3. Измените файл **/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml**. + + 1. Откройте файл **pom.xml**. + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml` + + 2. Добавьте следующий код. Сохраните файл и выйдите. + + - Добавьте следующий код в строку 30: + + ``` + + true + + ``` + + + + - Добавьте следующий код в строку 110: + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + + +### Компиляция Dubbo 2.7.5 + +В конец строки 592 файла **/home/Dubbo/dubbo-dubbo-2.7.5/pom.xml** добавьте следующее содержание: + +``` + + true + +``` + + + + +Если на экране появится сообщение **BUILD SUCCESS**, значит Dubbo 2.7.5 скомпилирован. + +Созданный после компиляции пакет **dubbo-2.7.5.jar** сохраняется в каталоге **dubbo-all/target**. \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/HAProxy 1.9.0 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/HAProxy 1.9.0 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..3f4cbb6f5b76ab0ed8f3bdc686bc7436440191cd --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/HAProxy 1.9.0 Porting Guide.md @@ -0,0 +1,203 @@ +--- +title: Руководство по портированию HAProxy 1.9.0 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - HAProxy + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования HAProxy 1.9.0 +--- + +# Руководство по портированию HAProxy 1.9.0 (openEuler 20.03 LTS SP1) + +## Введение + +#### Обзор + +HAProxy — это свободное программное обеспечение с открытым исходным кодом, написанное на языке C. Выполняя роль балансировщика нагрузки высокой доступности и прокси-сервера для приложений TCP и HTTP, программа поддерживает виртуальные хосты, отличается быстродействием и надежностью. + +Язык программирования: C + +Краткое описание: веб-балансировщик нагрузки + +#### Рекомендуемая версия программного обеспечения + +HAProxy 1.9.0 + +Примечание. + +Данный документ адресован версии HAProxy 1.9.0. Также этот документ можно использовать для справки при портировании других версий HAProxy. + +## Требования к среде + +#### Аппаратное обеспечение + +| Параметр | Описание | +| --------------------- | -------------------------------- | +| Сервер | Сервер TaiShan 200 (модель 2280) | +| Центральный процессор | Процессор Kunpeng 920 5250 | +| Раздел диска | Нет требований | + +#### Операционная система + +| Параметр | Версия | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64 | +| Ядро | 4.19 | + +Проверьте актуальную информацию о системе. + +```bash +cat /etc/os-release +``` + + + +Подробную информацию об установке ОС openEuler см. в документе https://docs.openeuler.org/en/docs/20.03\_LTS\_SP1/docs/Installation/Installation.html. + +Примечание. + +Рекомендуется выбрать режим установки «Server with GUI». + +## Установка HAProxy с использованием пакета RPM, полученного с зеркального узла + +Если с сервера есть доступ к сети, загрузите пакет RPM, выполнив команду «wget https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm». Если доступа нет, перейдите на страницу https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm, загрузите пакет и скопируйте его в каталог **/home** на сервере. + +Примечание. + +Пакеты RPM с зеркального узла компилируются и собираются с помощью открытого исходного кода и затем выгружаются на этот зеркальный узел. + +Далее описана процедура загрузки пакета RPM на локальный ПК с последующей выгрузкой его на сервер. + +1. Установите HAProxy. + + ```bash + rpm -ivh haproxy-1.9.0-1.el7.aarch64.rpm + ``` + + + +2. Просмотрите инсталляционный каталог. + + ```bash + ls /usr/local/haproxy + ``` + + + + +## Выполнение операций и верификация + +- Сконфигурируйте параметры. + + a. Откройте файл **option-http\_proxy.cfg**. + + ```bash + vi /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + + b. Измените файл, как приведено далее, сохраните изменения и закройте файл: + + ```bash + global + maxconn 20000 + log 127.0.0.1 local0 info + uid 0 + gid 0 + chroot /usr/local/haproxy + nbproc 4 + daemon + defaults + mode http + retries 3 + timeout connect 10s + timeout client 20s + timeout server 30s + timeout check 2s + frontend test-proxy + bind *:80 + mode http + log global + default_backend test-proxy-srv + backend test-proxy-srv + balance roundrobin + option http-server-close + option httpchk GET /index.html + http-check expect status 200 + server web1 IP1:PORT1 weight 3 + server web2 IP2:PORT2 weight 3 + ``` + + Подробную информацию о параметрах, содержащихся в конфигурационном файле, см. в [следующей таблице](https://support.huaweicloud.com/prtg-kunpengwebs/kunpenghaproxy_02_0011.html#kunpenghaproxy_02_0011__table177828478439). + +| Параметр | Описание | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| global | \- | +| maxconn 20000 | Максимальное количество соединений. | +| log 127.0.0.1 local0 info | Параметр задает устройство вывода журнала. Информация содержит уровень серьезности журнала. | +| uid 0 | Идентификатор пользователя, запускающего в работу HAProxy. | +| gid 0 | Идентификатор группы, в которую входит пользователь, запускающий в работу HAProxy. | +| chroot /usr/local/haproxy | Путь запуска chroot. | +| nbproc 4 | Количество процессов. | +| daemon | Параметр запускает выполнение HAProxy в фоновом режиме. | +| defaults | \- | +| mode http | Тип обработки (на уровне 7 используется HTTP, на уровне 4 — TCP). | +| retries 3 | Максимальное количество попыток подключения к backend-серверу. В случае превышения заданного значения, то есть после исчерпания всех попыток, backend-сервер будет недоступен. | +| timeout connect 10s | Максимальное время ожидания установления соединения между HAProxy и backend-сервером. | +| timeout client 20s | Время удержания соединения с клиентом на ожидании. | +| timeout server 30s | Время удержания соединения с сервером на ожидании. | +| timeout check 2s | Время ожидания проверки сервера. | +| frontend test-proxy | \- | +| bind \*:80 | Данным параметром задается один или более прослушивающих сокетов. Значком звездочки (\*) задаются все IPv4-адреса. | +| mode http | Тип обработки (на уровне 7 используется HTTP, на уровне 4 — TCP). | +| log global | Параметр устанавливает наследование определения журнала в глобальном разделе. | +| default\_backend test-proxy-srv | Параметр задает пул backend-сервера, используемый по умолчанию. | +| backend test-proxy-srv | \- | +| balance roundrobin | Параметр устанавливает циклический алгоритм балансировки нагрузки, который представляет собой алгоритм взвешенного опроса и применяется в сценариях, в которых серверы обладают примерно одинаковой производительностью. | +| option http-server- | Данный параметр необходимо включить в условиях включенного постоянного соединения. | +| option httpchk GET /index.htmlhttp-check expect status 200 | Параметр включает проверку статуса службы HTTP (проверка работоспособности), в процессе которой проверяется возвращаемый код со статусом. Если код «200» не возвращается, запросы на backend-серверы не отправляются. | +| server web1IP1:PORT1 weight 3 server web2 IP2:PORT2 weight 3 | Параметр определяет несколько backend-серверов. Формат: server :\[port] \[param\*]\*\* (Примечание: \*\*IP1:PORT1 и IP2:PORT2 — это IP-адреса и номера портов backend-серверов.) | + +- Запустите HAProxy. + + ```bash + taskset -c 0-3 /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + +- Проверьте HAProxy. + + ```bash + ps -ef | grep haproxy + ``` + + На экране отобразится процесс HAProxy. + + Откройте браузер, введите в адресной строке http:*//IP-адрес* *HAProxy*:80 и нажмите **Enter**. Появится страница веб-интерфейса backend-сервера, что означает корректный запуск HAProxy. Обновите страницу. Данная страница переключает между backend-серверами. + + Примечание. + + - (Опционально) Остановите HAProxy. Не выполняйте данную команду, если какие-либо службы в данный момент работают. + + ```bash + pkill haproxy + ``` + + - (Опционально) Удалите HAProxy и запросите результат. + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rpm -e --nodeps haproxy-1.9.0 + ``` + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rm -rf /usr/local/haproxy + ``` \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Iok 2.1.3 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Iok 2.1.3 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..b992fea81ea9a6f8de5ad217999532703c5bac10 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Iok 2.1.3 Porting Guide.md @@ -0,0 +1,143 @@ +--- +title: Руководство по портированию iok 2.1.3 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - lok + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования iok 2.1.3 +--- + +# Руководство по портированию iok 2.1.3 (openEuler 20.03 LTS SP1) + +## Введение + +> iok — это утилита для переназначения клавиш клавиатуры и отображения текста на языках Индии. + +### Версия + +> 2.1.3 + +### Руководство по установке + +> [https://docs.openeuler.org/en/docs/20.03\_LTS\_SP1/docs/Installation/Installation.html](https://docs.openeuler.org/en/docs/20.03\_LTS\_SP1/docs/Installation/Installation.html) + +### Проверка версии ОС + +```shell +cat /etc/os-release +``` + + + +### Проверка совместимости + +#### Загрузите iok-2.1.3 SRPM. + +``` +wget http://mirror.centos.org/centos/7/os/x86_64/Packages/iok-2.1.3-6.el7.x86_64.rpm +``` + +#### Загрузите x2openEuler. + +``` +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm + +User guide: +https://gitee.com/openeuler/docs/blob/stable2-20.03_LTS_SP1/docs/en/docs/thirdparty_migration/x2openEuleruseguide.md +``` + +#### Установите x2openEuler. + +``` +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> Примечание. Пакет RPM может установить пользователь с правами администратора (**root)**. Для загрузки и установки зависимостей необходимо сетевое соединение. +> +> Примечание. Установите зависимости, например **bzip2-devel,** следуя инструкциям. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> Последовательно введите следующую информацию о базе данных Redis. +> +> IP-адрес: 127.0.0.1 +> Порт: 6379 +> Индекс базы данных (0-16): 0 +> Пароль (шифруется инструментом): если пароль Redis не установлен или не заполнен, нажмите **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Примечание. После установки x2openEuler с помощью пакета RPM в каталоге **/opt/x2openEuler** создается пакет с ресурсами по умолчанию (source\_centos7.6-openEuler20.03-LTS-SP1.tar.gz). Для поддержки оценки совместимости аппаратного обеспечения с операционными системами CentOS 8.2 и openEuler 20.03 LTS SP1 необходимо получить и импортировать соответствующий пакет со статическими ресурсами. Например, если пакетом ресурсов является **source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, выполните команду **x2openEuler init source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, чтобы импортировать пакет. + +#### Выполните сканирование программы. + +``` +x2openEuler scan iok-2.1.3-6.el7.x86_64.rpm +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## Просмотр результатов оценки + +Отчет с результатами оценки совместимости программного обеспечения состоит из трех частей: совместимость зависимостей, совместимость с интерфейсом C/C++ и совместимость с интерфейсом Java. Результат совместимости зависимостей показывает, какие прямые зависимости требуются во время установки программного обеспечения. Если совместимость зависимостей не 100%, установка не будет выполнена. Результат совместимости с интерфейсом показывает, к каким программным пакетам, динамическим библиотекам или интерфейсам системы идет обращение во время работы программы. Если совместимость с интерфейсом не 100%, вызов определенной функции может инициировать исключение. Некоторые результаты рекомендуется подтверждать вручную. Приоритет программных пакетов: пакеты, портированные в openEuler > пакеты, повторно вручную скомпилированные для openEuler > пакеты для CentOS. + + +> Результат: согласно отчету о зависимостях, прежде чем портировать iok в ОС openEuler 20.03 LTS SP1, необходимо устранить проблему с зависимостью unique3. + +## Добавление зависимостей + +- Создайте задачу по проблеме в репозитории [openEuler/oec-application repository](https://gitee.com/openeuler/oec-application). + + +- Отслеживайте задачу, пока отсутствующий пакет с зависимостью не будет включен в репозиторий YUM операционной системы openEuler 20.03 LTS SP1. + +## Процесс компоновки + +> После добавления отсутствующего пакета с зависимостью можно приступать к следующим операциям: + +- Получите пакет CentOS 7.6.1810 SRPM для iok. +- Скомпонуйте бинарный пакет в openEuler 20.03 LTS SP1. + +###Скомпонуйте бинарный пакет. + +```shell +yum install -y rpm-build +``` + +- Установите пакет SRPM по сети. + +```shell +rpm -i https://vault.centos.org/7.6.1810/os/Source/SPackages/iok-2.1.3-6.el7.src.rpm +``` + +- Установите зависимость. + +```shell +yum-builddep -y ~/rpmbuild/SPECS/iok.spec +``` + +- Скомпонуйте бинарный пакет. + +```shell +rpmbuild -bb ~/rpmbuild/SPECS/iok.spec +``` + +- Установите бинарный пакет. + +``` +rpm -i ~/rpmbuild/RPMS/x86_64/*.rpm +``` + +- Просмотрите бинарный пакет. + +``` +which iok +``` \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Memcached 1.5.12 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Memcached 1.5.12 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..7421936bec3c7b7d4a5c45681ffe3f0873e5eec4 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Memcached 1.5.12 Porting Guide.md @@ -0,0 +1,217 @@ +--- +title: Руководство по портированию Memcached 1.5.12 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Memcached + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования Memcached 1.5.12 +--- + +# Руководство по портированию Memcached 1.5.12 + +## Введение + +#### Обзор + +Memcached — это высокопроизводительный сервер кэширования объектов в оперативной памяти, разработанный основателем компании Danga Interactive и блог-платформы «Живой Журнал» Брэдом Фицпатриком (Brad Fitzpatric). Сервер используется для кэширования результатов запроса базы данных и сокращения времени доступа к базе данных, что повышает быстродействие и масштабируемость динамических веб-приложений. + +Официальный веб-сайт Memcached: https://memcached.org/ + +Язык программирования: C. + +Краткое описание: распределенная система кэширования объектов в оперативной памяти. + +## Требования к среде + +### Аппаратное обеспечение + +В следующей таблице приведены требования к аппаратному обеспечению. + +| Параметр | Описание | +| --------------------- | -------------------------------- | +| Сервер | Сервер TaiShan 200 (модель 2280) | +| Центральный процессор | Процессор Kunpeng 920 5250 | +| Раздел диска | Нет требований | + +### Операционная система + +В следующей таблице перечислены требования к операционной системе. + +| Параметр | Версия | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 AArch64 | +| Ядро | 4.19 | + +Проверьте текущую версию ОС. + +``` +cat /etc/os-release +``` + + + +Подробную информацию об установке ОС openEuler см. в документе https://docs.openeuler.org/en/docs/20.03[\_LTS\_SP1/docs/Installation/Installation.html](). + +Примечание: + +Рекомендуется выбрать режим установки «Server with GUI». + +## Конфигурирование среды компиляции + +Для компиляции Memcached необходимо подготовить следующие инструменты: компилятор на языке C, GNU, make, automake, libevent и libevent-devel. + +1. Установите набор компиляторов GNU Compiler Collection (GCC). Если GCC уже установлен, пропустите этот шаг. + + ```bash + yum -y install gcc gcc-c++ kernel-devel + ``` + +2. Установите GNU make, Automake, unzip и Telnet. Если данные инструменты уже установлены, пропустите этот шаг. + + ```bash + yum -y install make automake unzip telnet + ``` + +3. Установите libevent и libevent-devel. + + ```bash + yum -y install libevent libevent-devel + ``` + +## Получение исходного кода + +Если с сервера есть доступ к сети, загрузите пакет с исходным кодом, выполнив команду +«wget https://github.com/memcached/memcached/archive/1.5.12.zip». Если доступа нет, перейдите на страницу https://github.com/memcached/memcached/archive/1.5.12.zip, загрузите пакет с исходным кодом и скопируйте его в каталог **/home** на сервере. + +## Компиляция и установка Memcached + +В приведенной процедуре компиляции и установки использован исходный код, загруженный на локальный ПК и затем выгруженный на сервер. + +1. Распакуйте пакет с исходным кодом. + + ```bash + cd /home + ``` + + ```bash + unzip 1.5.12.zip + ``` + +2. Перейдите в каталог **memcached-1.5.12**. + + ```bash + cd memcached-1.5.12 + ``` + +3. Сконфигурируйте Memcached. + + ```bash + sh autogen.sh + ``` + + ```bash + ./configure --prefix=/opt/memcached + ``` + + На этом шаге можно указать каталог установки Memcached, например **/opt/memcached**. + +4. Выполните операцию компиляции. + + ```bash + make -j60 + ``` + + Для ускорения процесса компиляции **-j60** использует преимущества многоядерных процессоров. + +5. Выполните установку. + + ```bash + make install + ``` + +6. Перейдите в каталог установки Memcached — **/opt/memcached**. Если созданный каталог bin содержит исполняемый файл Memcached, установка успешно выполнена. + +7. Настройте переменные среды. + + a. Добавьте к файлу **/etc/profile** следующую команду: + + ```bash + export PATH=/opt/memcached/bin/:$PATH + ``` + + b. Выполните операцию, чтобы переменные среды вступили в силу. + + ```bash + source /etc/profile + ``` + +## Запуск и верификация Memcached + +- Запустите Memcached. + + ```bash + memcached -t 24 -p 11211 -u root -m 49152 -c 10240 + ``` + + В следующей таблице перечислены параметры команды запуска. + +| Параметр | Описание | Значение по умолчанию | +| -------- | --------------------------------------------------------- | ------------------------------------------------------------ | +| -t | Счетчик потоков | 4 | +| -p | Порт прослушивания TCP | 11211 | +| -u | Пользователь, запускающий данный процесс | По умолчанию пользователь не имеет прав администратора (root). | +| -m | Размер памяти (в МБ), выделенный под Memcached | 64M | +| -c | Максимальное количество параллельных соединений | 1024 | +| -d | Данный параметр запускает процесс daemon в фоновом режиме | \- | + +- Для подключения к Memcached запустите другое окно оболочки. + + ```bash + telnet 127.0.0.1 11211 + ``` + +- Подключившись, выполните команду stats для получения статистики по серверу Memcached. + + ```bash + stats + ``` + + + + +В [следующей таблице](https://support.huaweicloud.com/intl/en-us/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table1896316817714) перечислены часто используемые команды stats. + +| Команда | Описание | +| --------------- | ------------------------------------------------------------ | +| stats | Команда выводит общую информацию Memcached, в том числе время запуска, объем сохраненных данных, коэффициент попадания в кэш и количество текущих соединений. | +| stats items | Команда выводит информацию об элементах каждого слоя памяти (slab). | +| stats slabs | Команда выводит детальную информацию о слоях памяти (slab). | +| stats sizes | Размер и количество всех элементов. | +| stats cachedump | Команда выводит фрагменты данных в одном слое. Если вводится 0, выводятся все данные в слое. | +| stats detail | Команда включает и отключает операции (on/off) либо выводит (dump) подробные записи об операциях, таких как операции получения и настройки. | +| flush\_all | Команда делает недействительными все элементы в памяти. Эта операция не приостанавливает работу сервера, поскольку память не освобождается, а существующие элементы помечаются как недействительные. | + +Примечание: + +Чтобы выйти из сеанса Telnet, выполните команду **quit**. + +```bash +quit +``` + +Помимо функции подключения к Memcached через сеанс Telnet и получения данных, в пакете с исходным кодом имеется ряд инструментальных скриптов, например memcached-tool, которые помещены в каталог скриптов. + +Подробную информацию об использовании memcached-tool см. в [следующей таблице](https://support.huaweicloud.com/intl/en-us/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table15821759181818). + +| Команда | Описание | +| --------------------------------------------- | -------------------------------------------------- | +| ./memcached-tool localhost display | Вывод информации о слоях памяти (slab). | +| ./memcached-tool 10.0.0.5:11211 display | Вывод информации о слоях памяти (slab). | +| ./memcached-tool 10.0.0.5:11211 stats | Вывод статистики кэширования в оперативной памяти. | +| ./memcached-tool 10.0.0.5:11211 settings | Вывод настроек сервиса memcached. | +| ./memcached-tool 10.0.0.5:11211 sizes | Размер и количество всех элементов. | +| ./memcached-tool 10.0.0.5:11211 dump \[limit] | Ключи со значениями, полученные от каждого кэша. | + diff --git a/web-ui/docs/ru/blog/randy1568/MySQL 5.7.21 Porting Guide (openEuler 20.03 LTS SP1).md b/web-ui/docs/ru/blog/randy1568/MySQL 5.7.21 Porting Guide (openEuler 20.03 LTS SP1).md new file mode 100644 index 0000000000000000000000000000000000000000..9c3dc1f4fadfc673affcf15e20359471082edfd8 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/MySQL 5.7.21 Porting Guide (openEuler 20.03 LTS SP1).md @@ -0,0 +1,277 @@ +--- +title: Руководство по портированию базы данных MySQL 5.7.21 (openEuler 20.03 LTS SP1) +date: 2022.01.05 +tags: + - MySQL + - Пример портирования +sig: sig-Compatibility-Infra +archives: 2022.01 +author: xielihao +summary: принципы и примеры портирования базы данных MySQL 5.7.21 +--- + +# Руководство по портированию базы данных MySQL 5.7.21 (openEuler 20.03 LTS SP1) + +## 1\. Введение + +В данном документе описывается метод развертывания базы данных MySQL в операционной системе openEuler 20.03 SP1. + +MySQL — это защищенная, межплатформенная эффективная система базы данных, работающая с основными языками программирования, такими как PHP и Java. В данном документе используются виртуальные машины x86\_64. Для оценки совместимости MySQL 5.7.21 с ОС openEuler перед миграцией данных применяется инструмент x2openEuler. + +Рекомендуется использовать версию MySQL 5.7.21. + +> ПРИМЕЧАНИЕ. Данный документ составлен для версии MySQL 5.7.21. Однако его можно использовать для справки при портировании баз данных MySQL других версий. + +## 2\. Среда + +Аппаратное обеспечение + +| Компонент | Описание | +| ---------------------- | --------------------- | +| Сервер | Сервер TaiShan 200 | +| Центральный процессор | Процессор Kunpeng 920 | +| Карта RAID-контроллера | SAS3508 | +| NIC | Mellanox SP333 | +| | TM210 | +| | TM280 | +| Диск | 500 ГБ и больше | + +Операционные системы + +| Программное обеспечение | Версия | Примечания | +| ----------------------- | ------------------- | -------------------------------- | +| ОС | CentOS 7.6.1810 | Актуальный сервер кластера MySQL | +| ОС | openEuler 20.03 SP1 | Целевой сервер | + +Программные пакеты + +| Программное обеспечение | Версия | +| ----------------------- | ------ | +| mysql5 | 5.7.21 | +| mysql5-common | 5.7.21 | +| mysql5-embedded | 5.7.21 | +| mysql5-embedded-devel | 5.7.21 | +| mysql5-errmsg | 5.7.21 | +| mysql5-libs | 5.7.21 | +| mysql5-server | 5.7.21 | +| mysql5-test | 5.7.21 | + + + +## 3\. Оценка совместимости программного обеспечения + +Для оценки программных пакетов и интерфейсов скомпилированных бинарных программных модулей сообщество openEuler предлагает использовать инструмент [x2openEuler](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/), который определяет необходимость адаптации прикладной программы и установку каких-либо зависимостей. Также инструмент выявляет, имеются ли какие-либо отличия между прототипами интерфейсов, к которым обращается программа, двух операционных систем. + +Примечание. Получить скомпилированную бинарную программу, полностью совместимую с целевой ОС, довольно проблематично, поэтому всегда есть риск с работой памяти. И поскольку выявить эту проблему с помощью обычной верификации сложно, оценка совместимости программного обеспечения становится важной процедурой, которую необходимо выполнить перед портированием. + +#### 3.1 Получите RPM-пакет MySQL и распакуйте его в каталог /opt/mysql. + +``` +wget -P /opt https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar +``` + +``` +cd /opt/ +mkdir mysql +tar -xf mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar -C mysql +``` + +#### 3.2 Загрузите инструмент x2openEuler в каталог /opt/mysql. + +``` +cd /opt/mysql +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm +``` + +#### 3.3 Установите инструмент. + +``` +cd /opt/mysql +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> Примечание. Пакет RPM может установить пользователь с правами администратора (**root)**. Для загрузки и установки зависимостей необходимо сетевое соединение. +> +> Примечание. Установите зависимости, например **bzip2-devel,** следуя инструкциям. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Последовательно введите следующую информацию о базе данных Redis. + +IP-адрес: 127.0.0.1 +Порт: 6379 +Индекс базы данных (0-16): 0 +Пароль (пароль шифруется инструментом): если пароль Redis не установлен или не заполнен, нажмите **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Примечание. После установки x2openEuler с помощью пакета RPM в каталоге **/opt/x2openEuler** создается пакет с ресурсами по умолчанию (source\_centos7.6-openEuler20.03-LTS-SP1.tar.gz). Для поддержки оценки совместимости аппаратного обеспечения с операционными системами CentOS 8.2 и openEuler 20.03 LTS SP1 необходимо получить и импортировать соответствующий пакет со статическими ресурсами. Например, если пакетом ресурсов является **source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, выполните команду **x2openEuler init source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, чтобы импортировать пакет. + +#### 3.4 Выполните сканирование MySQL. + +``` +x2openEuler scan /opt/mysql/ +The x2openEuler user must have the read permission on the file to be analyzed. +After the scan is complete, an HTML report is generated in the /opt/x2openEuler/output directory. +``` + +## 4\. Анализ результатов оценки + +Отчет с результатами оценки совместимости программного обеспечения состоит из трех частей: совместимость зависимостей, совместимость с интерфейсом C/C++ и совместимость с интерфейсом Java. Результат совместимости зависимостей показывает, какие прямые зависимости требуются во время установки программного обеспечения. Если совместимость зависимостей не 100%, установка не будет выполнена. Результат совместимости с интерфейсом показывает, к каким программным пакетам, динамическим библиотекам или интерфейсам системы идет обращение во время работы программы. Если совместимость с интерфейсом не 100%, вызов определенной функции может инициировать исключение. Некоторые результаты рекомендуется подтверждать вручную. Приоритет программных пакетов: пакеты, портированные в openEuler > пакеты, повторно вручную скомпилированные для openEuler > пакеты для CentOS. + +#### 4.1 Анализ отчета + +``` +Open and view the HTML report line by line. In the example below, the report shows that using the CentOS MySQL package on openEuler may cause the following risk: +One to-be-confirmed interface indicates that the MySQL series packages call libaio.so.1.0.1, and that the number of function parameters changes from 4 to 5. When the function is called, an exception may be triggered. + +In addition, the report shows that three dependencies need to be confirmed. Manual confirmation confirms that they are self-closed-loop dependencies of the MySQL series packages. Therefore, the software installation is not affected. +``` + + + +#### 4.2 Рекомендации + +``` +Suggestion: To avoid function call risks, you are advised to use the MySQL 5.7.21 series software packages that have been compiled and released on the openEuler community. +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mariadb-common-10.3.9-9.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-common-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-server-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-errmsg-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mecab-0.996-2.oe1.x86_64.rpm +``` + +## 5\. Установка базы данных MySQL + +#### 5.1 Установка MySQL и настройка пароля + +**(1) Установите службы MariaDB и MySQL.** + +rpm -ivh mysql5-5.7.21-3.oe1.x86\_64.rpm mariadb-common-10.3.9-9.oe1.x86\_64.rpm mysql5-common-5.7.21-3.oe1.x86\_64.rpm mysql5-server-5.7.21-3.oe1.x86\_64.rpm mecab-0.996-2.oe1.x86\_64.rpm mysql5-errmsg-5.7.21-3.oe1.x86\_64.rpm + +**(2) Запустите MySQL.** + +systemctl start mysqld + +**(3) Запросите статус MySQL.** + +systemctl status mysqld + +Если статус — Running, служба MySQL успешно запущена в работу. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 ~# systemctl status mysqld + +● mysqld.service - MySQL 5.7 database server + + Loaded: loaded (/usr/lib/systemd/system/mysqld.service; disabled; vendor preset: disabled) + + Active: active (running) since Thu 2021-09-09 10:23:25 CST; 1 day 4h ago + + Process: 103715 ExecStartPre=/usr/libexec/mysql-check-socket (code=exited, status=0/SUCCESS) + + Process: 103738 ExecStartPre=/usr/libexec/mysql-prepare-db-dir mysqld.service (code=exited, sta> + + Process: 103773 ExecStart=/usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld> + + Process: 103803 ExecStartPost=/usr/libexec/mysql-check-upgrade (code=exited, status=0/SUCCESS) + + Main PID: 103775 (mysqld) + + Tasks: 37 + + Memory: 188.4M + + CGroup: /system.slice/mysqld.service + +​ └─103775 /usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld/mysqld. +``` + +**(4) Войдите в базу данных и измените пароль по умолчанию.** + +mysql -uroot -p + +a. По умолчанию пароль не задан. Нажмите **Enter**, чтобы войти. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 2 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +mysql> +``` + +b. Задайте пароль. + +Измените пользователя 'user'@'localhost', определяемого по 'passward'; + +``` +mysql> alter user 'root'@'localhost' identified by '123456'; + +Query OK, 0 rows affected (0.00 sec) + +mysql> flush privileges; + +Query OK, 0 rows affected (0.00 sec) + +mysql> +``` + +> Чтобы настройки вступили в силу, необходимо выполнить команду **flush privileges**. + +**(5) Проверьте пароль.** + +Выйдите и снова войдите в службу MySQL, чтобы удостовериться в успешном изменении пароля. + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 3 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + + +mysql> +``` \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/Nginx 1.14.2 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/Nginx 1.14.2 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..7d63e62504a2dc64ee06c0134b740995ca53cfcb --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/Nginx 1.14.2 Porting Guide.md @@ -0,0 +1,636 @@ +--- + +title: Руководство по портированию Nginx 1.14.2 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Nginx + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования Nginx 1.14.2. +--- + +# Руководство по портированию Nginx 1.14.2 (openEuler 20.03 LTS SP1) + +# Введение + +## Сведения о Nginx + +Nginx — это облегченная версия веб-сервера, который выполняет роль обратного прокси-сервера и прокси-сервера электронной почты (IMAP/POP3). Сервер выделяется высокой степенью параллелизма, занимает мало ресурсов памяти и поддерживает FastCGI, SSL, виртуальные хосты, перезапись URL, сжатие в формате gzip и расширение многих сторонних модулей. + +Язык программирования: C. + +Краткое описание: веб-сервер, обратный прокси-сервер или прокси-сервер электронной почты (IMAP/POP3). + +## Рекомендуемая версия + +Nginx 1.14.2 + +ПРИМЕЧАНИЕ: + +Данный документ адресован версии Nginx 1.14.2. Также этот документ можно использовать для справки при портировании других версий Nginx. + +# Требования к среде + +## Аппаратное обеспечение + +Требования к аппаратному обеспечению перечислены в Табл. 1. + +Табл. 1 Требования к аппаратному обеспечению + +| Параметр | Описание | +| --------------------- | -------------------------------- | +| Сервер | Сервер TaiShan 200 (модель 2280) | +| Центральный процессор | Процессор Kunpeng 920 5250 | +| Раздел диска | Нет требований | + +## Операционная система + +Требования к операционной системе перечислены в Табл. 2. + +Табл. 2 Требования к операционной системе + +| Параметр | Версия | Команда, используемая для запроса версии | +| --------- | ------------- | ---------------------------------------- | +| openEuler | 20.03 LTS SP1 | `cat /etc/openEuler-release` | +| Ядро | 4.19.90 | `uname -r` | + +# Конфигурирование среды компиляции + +## Конфигурирование репозитория Yum + +ПРИМЕЧАНИЕ: + +Если сервер не может получить зависимости из сети Интернет командой **yum**, сконфигурируйте локальный источник. + +1. Скопируйте файл с образом **openEuler-20.03-LTS-everything-aarch64-dvd.iso** в каталог **/root** на каждом сервере. + +2. Смонтируйте файл с образом. Файл openEuler.iso из каталога **/root** монтируется в каталог **/mnt**. + ```mount /root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt``` + + ПРИМЕЧАНИЕ: + + Данная операция будет действительна только до перезапуска операционной системы. (Опционально) Для настройки автоматического монтирования образа при загрузке, выполните следующие операции: + + (1) Откройте файл **fstab**. + + `vi /etc/fstab` + + (2) В конце файла **fstab** добавьте следующее содержание: + + `/root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt iso9660 loop 0 0` + + (3) Сохраните файл **fstab** и выйдите. + +3. Добавьте файл локального источника. + + (1) Перейдите в каталог **/etc/yum.repos.d**. + + `cd /etc/yum.repos.d` + + ПРИМЕЧАНИЕ: + + Рекомендуется перенести расположенный в данном каталоге файл \*.repo в любой другой резервный каталог. + + (2) Создайте файл **local.repo**. + + ​ a. Откройте файл **local.repo**. + + ​ `vi local.repo` + + ​ b. Добавьте следующую информацию в файл **local.repo**: + + ``` + [local] + name=local.repo + baseurl=file:///mnt + enabled=1 + gpgcheck=0 + ``` + + ПРИМЕЧАНИЕ: + + Путем к файлу в **baseurl** является путь, по которому смонтирован образ, то есть это каталог, в который смонтирован файл с образом – **/mnt**. + + ​ c. Сохраните файл **local.repo** и выйдите. + + ​ d. Убедитесь, что используется локальный источник. + + ``` + yum clean all + yum makecache + yum list + ``` + +## Установка зависимостей + +Загрузите и установите зависимости. + +``` +yum -y install gcc gcc-c++ make libtool zlib zlib-devel pcre pcre-devel pcre2-devel perl-devel perl-ExtUtils-Embed openssl openssl-devel +``` + +# Получение исходного кода + +В описанной в данном документе процедуре компиляции и установки использован исходный код. Вам также необходимо получить исходный код Nginx. + +Чтобы загрузить исходный код Nginx, выполните следующие команды: + +``` cd /home``` +```wget https://nginx.org/download/nginx-1.14.2.tar.gz --no-check-certificate``` + +ПРИМЕЧАНИЕ: + +Исходный код также можно загрузить через локальный браузер и выгрузить его в каталог **/home** на сервер. Адрес загрузки: https://nginx.org/download/nginx-1.14.2.tar.gz. + +ПРИМЕЧАНИЕ: + +Чтобы сконфигурировать прокси для доступа к Интернет, выполните следующие операции: + +1. Откройте файл **profile**. + + `vi /etc/profile` + +2. Добавьте следующий код, сохраните файл и выйдите. Необходимо настроить имя пользователя, пароль, IP-адрес и номер порта прокси-сервера в соответствии с требованиями сайта. + +``` +export http_proxy="http://Proxy server user name:password@IP address:port" +export http_proxy=$http_proxy +export no_proxy=127.0.0.1,.huawei.com,localhost,local,.local +``` + +3. Убедитесь, что используется прокси. + + `source /etc/profile` + +4. Проверьте информацию о прокси в переменных среды. + + `env` + +5. Убедитесь в успешном завершении настройки функции прокси. + + `curl www.baidu.com` + + Например, можно проверить следующим образом: если Baidu анализируется, значит настройка завершена. + +# Компиляция и установка Nginx + +1. Разархивируйте инсталляционный пакет Nginx. + + `tar -xvf nginx-1.14.2.tar.gz` + +2. Перейдите в каталог **nginx-1.14.2**. + + `cd /home/nginx-1.14.2/` + +3. Сконфигурируйте Nginx. + + `./configure --prefix=/usr/local/nginx --with-http_ssl_module` + + ПРИМЕЧАНИЕ: + +- **--prefix=*PATH*** — это каталог для установки Nginx. Каталогом для установки по умолчанию является **/usr/local/nginx**. +- Модуль **with-http\_stub\_status\_module** конфигурировать не требуется, поскольку он влияет на производительность Nginx. + +4. Скомпилируйте и установите Nginx. + + `make -j96 && make -j96 install` + + ПРИМЕЧАНИЕ: + + В данной команде для ускорения процесса компиляции -j96 использует преимущества многоядерных процессоров. Запрос количества ядер осуществляется командой **lscpu**. + +5. Проверьте каталог установки. + + `ls /usr/local/nginx` + +# Запуск и верификация Nginx + +## Создание сертификата + +1. Перейдите в каталог **/usr/local/nginx directory** и сгенерируйте в каталоге ключ. + + `cd /usr/local/nginx` `openssl genrsa -des3 -out server_2048.key 2048` + + Дважды введите пароль. Сгенерируется файл **server\_2048.key**. + +``` +[root@localhost nginx]# openssl genrsa -des3 -out server_2048.key 2048 +Generating RSA private key, 2048 bit long modulus (2 primes) +..................................................................................+++++ +................+++++ +e is 65537 (0x010001) +Enter pass phrase for server_2048.key: +Verifying - Enter pass phrase for server_2048.key: +``` + +ПРИМЕЧАНИЕ: + +Для использования файла без пароля выполните следующую команду: + + ```openssl rsa -in server_2048.key -out -server_2048.key``` + +``` +[root@localhost nginx]# openssl rsa -in server_2048.key -out -server_2048.key +Enter pass phrase for server_2048.key +writing RSA key +``` + +2. Создайте запрос на подпись сертификата (CSR). + +``` +openssl req -new -key server_2048.key -out server_2048.csr +``` + +``` +[root@localhost nginx]# openssl req -new -key server_2048.key -out server_2048.csr +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []: +Organization Name (eg, company) [Internet Widgits Pty Ltd]: +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []: +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +Введите пароль, установленный на шаге 1. Задайте параметру **Country Name** значение **CN**, остальные параметры не настраивайте. + + 3\. Перезапишите ключ. + +`openssl rsa -in server_2048.key -out server_2048.key` + +``` +[root@localhost nginx]# openssl rsa -in server_2048.key -out server_2048.key +writing RSA key +``` + +4. Сгенерируйте сертификат. + + `openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt` + +``` +[root@localhost nginx]# openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt +Signature ok +subject=C = CN, ST = Some-State, O = Internet Widgits Pty Ltd +Getting Private key +``` + +Введите пароль, установленный на шаге 1. Если для этого файла настроен доступ без пароля, вводить пароль не требуется. + +## Настройка функций + +### Настройка Nginx HTTPS + +1. Откройте файл **nginx.conf**. + + `vi /usr/local/nginx/conf/nginx.conf` + +2. В файле **nginx.conf** измените следующие настройки, затем сохраните файл и выйдите (нажав комбинацию **Esc** + **:wq**). + - Для запуска Nginx необходимо установить права пользователя **root**. + - Задайте номер порта прослушивания — **20000**. Можно также использовать номер порта по умолчанию. + - Укажите файлы **ssl\_certificate** и **ssl\_certificate\_key**. + +#### Настройки по умолчанию: + +``` +#user nobody; +... + # HTTPS server + # + #server { + # listen 443 ssl; + # server_name localhost; + + # ssl_certificate cert.pem; + # ssl_certificate_key cert.key; + + # ssl_session_cache shared:SSL:1m; + # ssl_session_timeout 5m; + + # ssl_ciphers HIGH:!aNULL:!MD5; + # ssl_prefer_server_ciphers on; + + # location / { + # root html; + # index index.html index.htm; + # } + #} +``` + +#### Настройки после изменения: + +``` +user root; + ... + HTTPS server + + server { + listen 20000 ssl; + server_name localhost; + + ssl_certificate /usr/local/nginx/server_2048.crt; + ssl_certificate_key /usr/local/nginx/server_2048.key; + + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location / { + root html; + index index.html index.htm; + } + } + +``` + +### Настройка Nginx HTTP + +1. Откройте файл **nginx.conf**. + + `vi /usr/local/nginx/conf/nginx.conf` + +2. В файле **nginx.conf** измените следующие настройки, затем сохраните файл и выйдите (нажав комбинацию **Esc** + **:wq**). + - Для запуска Nginx необходимо установить права пользователя **root**. + - Задайте номер порта прослушивания — **10000**. Можно также использовать номер порта по умолчанию. + +#### Настройки по умолчанию: + +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 80; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +#### Настройки после изменения: + +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 10000; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +## Запуск Nginx + +1. Запустите Nginx любым из приведенных способов: + + - Запустите службу Nginx. Необходимо добавить Nginx в список служб и затем запустить службу командой. + + (1) Измените файл **/etc/init.d/nginx**. + + ​ a. Удалите исходный файл **nginx**. + + `rm -rf /etc/init.d/nginx` + + ​ b. Создайте новый файл **nginx**. + + `vi /etc/init.d/nginx` + + ​ c. Добавьте в файл следующую информацию, сохраните файл и выйдите. + +``` + #!/bin/bash + # chkconfig: 2345 10 90 + # description: nginx + case "$1" in + 'start') + /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf + echo "$0_start"; + ;; + 'stop') + /usr/local/nginx/sbin/nginx -s quit + echo "$0_stop"; + ;; + esac +``` + +​ (2) Измените права в файле **/etc/init.d/nginx**. + +​ ``` chmod 777 /etc/init.d/nginx``` + +​ (3) Добавьте Nginx в список администрирования **chkconfig**. + + ​ ` chkconfig --add /etc/init.d/nginx` + +​ (4) Включите опцию автоматического запуска службы Nginx во время запуска ОС. ​ + +​ ```chkconfig nginx on``` + +​ (5) Запустите Nginx. ​ + +​ ```service nginx start``` + +- Запустите Nginx методом выполнения скрипта. + +`/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf` + +2. Проверьте состояние процесса Nginx. + + `ps -ef | grep nginx` + +``` +[root@localhost nginx]# ps -ef | grep nginx +root 9463 1 0 18:22 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf +root 9464 9463 0 18:22 ? 00:00:00 nginx: worker process +root 9466 1352 0 18:23 ttyAMA0 00:00:00 grep --color=auto nginx +``` + +ПРИМЕЧАНИЕ: + +Отключить Nginx можно любой из следующих команд. Не выполняйте данные команды, если в данный момент работает какая-либо служба. + +- Остановите службу Nginx. + + `service nginx stop` + +- Остановите службу Nginx методом выполнения скрипта. + + `/usr/local/nginx/sbin/nginx -s quit` + +- Остановите процесс Nginx. + + ```pkill nginx``` + +``` +[root@localhost nginx]# pkill nginx +[root@localhost nginx]# ps -ef | grep nginx +root 9469 1352 0 18:27 ttyAMA0 00:00:00 grep --color=auto nginx +``` + +## Верификация Nginx + +1. Проверьте порт мониторинга Nginx (10000 — номер порта мониторинга службы HTTP, а 20000 — службы HTTPS). + + `netstat -anp | grep 10000` + `netstat -anp | grep 20000` + `netstat -anpt` + +``` +[root@localhost nginx]# netstat -anp | grep 10000 +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anp | grep 20000 +tcp 0 0 0.0.0.0:20000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anpt +Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 775/sshd: /usr/sbin +``` + +2. Запросите каталог, в котором размещены файлы HTML службы Nginx. + + `ll -h /usr/local/nginx/html/` + +``` +[root@localhost nginx]# ll -h /usr/local/nginx/html/ +total 8.0K +-rw-r--r--. 1 root root 537 Mar 20 16:46 50x.html +-rw-r--r--. 1 root root 612 Mar 20 16:46 index.html +``` + +3. Проверьте функцию HTTPS. Войдите на HTML-страницу Nginx с помощью cURL. + + `curl -k https://127.0.0.1:20000/index.html` + +``` +[root@localhost nginx]# curl -k https://127.0.0.1:20000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` + +4. Проверьте функцию HTTP. Войдите на HTML-страницу Nginx с помощью cURL. + + `curl http://127.0.0.1:10000/index.html` + +``` +[root@localhost nginx]# curl http://127.0.0.1:10000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` + +# Удаление Nginx + +1. Удалите каталог установки. + + `rm -rf /usr/local/nginx` \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-1.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-1.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-1.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-10.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-10.png new file mode 100644 index 0000000000000000000000000000000000000000..36a9f77639b1141cb7e1fdb460b6261caa751e08 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-10.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-11.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-11.png new file mode 100644 index 0000000000000000000000000000000000000000..70466f513236b842a5528197751f0e286ea75cfa Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-11.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-12.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-12.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-12.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-13.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-13.png new file mode 100644 index 0000000000000000000000000000000000000000..02873d6b02031ccfe7762298e1ad5b8b7a81a16e Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-13.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-2.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ea89b334d288854dfc4403570f7892dd7749f1a3 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-2.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-3.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9518a15004dec9da4856bcc6c6e2bb22942941e1 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-3.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-4.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-4.png new file mode 100644 index 0000000000000000000000000000000000000000..429f02e0e97e1c7d556fd80f11b4a9cf1a5a5c3e Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-4.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-5.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-5.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fe8ad56cb34ab2788458dd77e555af08ef315e Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-5.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-6.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-6.png new file mode 100644 index 0000000000000000000000000000000000000000..9b1b2903df4caec60872d48556e4914446cd4a50 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-6.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-7.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-7.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3dead21a92ced874dadbcd904e387a30882b86 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-7.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-8.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-8.png new file mode 100644 index 0000000000000000000000000000000000000000..f43d97c66f49b4dfd37c12dc13a19d9efd7151d0 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-8.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Dubbo-9.png b/web-ui/docs/ru/blog/randy1568/image/Dubbo-9.png new file mode 100644 index 0000000000000000000000000000000000000000..188b4cb375fc3cecef034a70c61613f7cc429b38 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Dubbo-9.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/HAProxy-1.jpeg b/web-ui/docs/ru/blog/randy1568/image/HAProxy-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/HAProxy-1.jpeg differ diff --git a/web-ui/docs/ru/blog/randy1568/image/HAProxy-2.png b/web-ui/docs/ru/blog/randy1568/image/HAProxy-2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd0dc9e9f6e82c49274a7cba090fe3bf11e0e5cd Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/HAProxy-2.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/HAProxy-3.png b/web-ui/docs/ru/blog/randy1568/image/HAProxy-3.png new file mode 100644 index 0000000000000000000000000000000000000000..41ec8fc71a9ee5c151bcdd08ecb5adf9256fb90d Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/HAProxy-3.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Memcached-1.jpeg b/web-ui/docs/ru/blog/randy1568/image/Memcached-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Memcached-1.jpeg differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Memcached-2.jpeg b/web-ui/docs/ru/blog/randy1568/image/Memcached-2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7ada68ee64f6cd59bbb77ca65990f0be66277060 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Memcached-2.jpeg differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Mysql-3.png b/web-ui/docs/ru/blog/randy1568/image/Mysql-3.png new file mode 100644 index 0000000000000000000000000000000000000000..8a2ddfc7dba89f8bc9c0d5c54828d38a1a663af8 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Mysql-3.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/Mysql-4.png b/web-ui/docs/ru/blog/randy1568/image/Mysql-4.png new file mode 100644 index 0000000000000000000000000000000000000000..4a92cded1ed5a4e3884271e014389d4b24f73221 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/Mysql-4.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/hardware-1.png b/web-ui/docs/ru/blog/randy1568/image/hardware-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1422647a6f4b26bf47b28bb513e3e041a0a5219a Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/hardware-1.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/hardware-5.png b/web-ui/docs/ru/blog/randy1568/image/hardware-5.png new file mode 100644 index 0000000000000000000000000000000000000000..c67151a571663a93b681750c1d17d1d90ec70910 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/hardware-5.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/iok-1.png b/web-ui/docs/ru/blog/randy1568/image/iok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..23edd3b09d0c2eb05c0b56690c44b28d32914989 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/iok-1.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/lok-1.png b/web-ui/docs/ru/blog/randy1568/image/lok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..19b4f36ba04958bf7bd113adeb02fac4b3e42976 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/lok-1.png differ diff --git a/web-ui/docs/ru/blog/randy1568/image/lok-2.png b/web-ui/docs/ru/blog/randy1568/image/lok-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6acd3eb0204d2d2f06a6394c97cb622aecd81a26 Binary files /dev/null and b/web-ui/docs/ru/blog/randy1568/image/lok-2.png differ diff --git a/web-ui/docs/ru/blog/randy1568/lighttpd 1.4.53 Porting Guide.md b/web-ui/docs/ru/blog/randy1568/lighttpd 1.4.53 Porting Guide.md new file mode 100644 index 0000000000000000000000000000000000000000..ac6fc77fc014ba875d1ca10ae0aaf9cb28bc9c92 --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/lighttpd 1.4.53 Porting Guide.md @@ -0,0 +1,211 @@ +--- +title: Руководство по портированию lighttpd 1.4.53 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Lighttpd + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Принципы портирования lighttpd 1.4.53. +--- + +# Руководство по портированию lighttpd 1.4.53 (openEuler 20.03 LTS SP1) + +# Введение + +## Обзор + +lighttpd — это отлично зарекомендовавшее себя облегченное программное обеспечение с открытым исходным кодом, основной целью которого является предоставление безопасной, быстродействующей, совместимой гибкой среды веб-сервера для обеспечения работы высокопроизводительных веб-сайтов. lighttpd занимает мало ресурсов памяти, для его загрузки требуется процессор небольшой мощности, но при этом он отличается хорошей производительностью и многообразием модулей. + +Язык программирования: C. + +Краткое описание: веб-сервер. + +## Рекомендуемая версия + +lighttpd 1.4.53 + +# Требования к среде + +## Аппаратное обеспечение + +В следующей таблице перечислены требования к аппаратному обеспечению. + +| Параметр | Описание | +| --------------------- | -------------------------------- | +| Сервер | Сервер TaiShan 200 (модель 2280) | +| Центральный процессор | Процессор Kunpeng 920 5250 | +| Раздел диска | Нет требований | + +## Операционная система + +В следующей таблице перечислены требования к операционной системе. + +| Параметр | Версия | +| --------- | ----------------- | +| openEuler | 20.03 SP1 AArch64 | +| Ядро | 4.19 | + +Примечание: + +Если операционная система устанавливается впервые, выберите режим установки «Server with GUI» вместо «Minimal Install». Иначе придется вручную устанавливать много программных пакетов. + +# Конфигурирование среды компиляции + +1. Установите зависимости. + +`yum -y install gcc gcc-c++ glib2-devel pcre-devel bzip2-devel zlib-devel gamin-devel` + +2. Получите исходный код. + +URL: https://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.53.tar.gz + +## Подготовка инсталляционного пакета + +``` +cp lighttpd-1.4.53.tar.gz $HOME && cd $HOME +tar xzvf lighttpd-1.4.53.tar.gz +``` + +## Компиляция и установка lighttpd + +``` +cd lighttpd-1.4.53 +./configure --prefix=/usr/local/lighttpd --with-fam +make -j60 && make install +``` + +Примечание: + +\-**-prefix=PATH** — это каталог для установки lighttpd. + +**--with-fam** уменьшает количество вызовов **stat()**. + +# Настройка параметров + +## Создание каталога хранения программных файлов + +``` +cd /usr/local/lighttpd/ +mkdir log webpages cache config +``` + +## Копирование конфигурационного файла или каталога + +``` +cp $HOME/lighttpd-1.4.53/doc/config/lighttpd.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/modules.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/conf.d /usr/local/lighttpd/config/ -r +``` + +Примечание: + +При установке lighttpd в инсталляционном каталоге создаются только три папки: **lib**, **sbin**, **share**. Остальные файлы необходимо скопировать и создать. + +## Изменение файла lighttpd.conf + +``` +vi /usr/local/lighttpd/config/lighttpd.conf + +``` + +Измените строки 16–20 следующим образом: + +``` +var.log_root = "/usr/local/lighttpd/log" +var.server_root = "/usr/local/lighttpd" +var.state_dir = "/usr/local/lighttpd" +var.home_dir = "/usr/local/lighttpd" +var.conf_dir = "/usr/local/lighttpd/config" +``` + +Измените строку 61 следующим образом: + +``` +var.cache_dir = "/usr/local/lighttpd/cache" +``` + +Добавьте следующий комментарий к строке 93: + +``` +#server.use-ipv6 = "enable" +``` + +Измените строки 104–105 следующим образом (данная команда связана с правами на выполнение операций, поэтому не рекомендуется использовать пользователя **root)**: + +``` +server.username = "lighttpd1" +server.groupname = "lighttpd" +``` + +Измените строку 115 (путь для сохранения страницы доступа) следующим образом: + +``` +server.document-root = server_root + "webpages" +``` + +Измените строку 246 (режим кэширования) следующим образом (значение по умолчанию — **simple**, и согласно официальному описанию режим **fam** лучше, чем **simple**): + +``` +server.stat-cache-engine = "fam" +``` + +Добавьте следующую информацию к строке 182. (Данный элемент конфигурации используется для настройки многопроцессного режима. Процесс lighttpd по умолчанию используется в однопроцессном режиме. Изменить значение можно в соответствии с требованиями к площадке.) + +``` +server.max-worker = 4 +``` + +## Создание группы пользователей + +``` +groupadd lighttpd +useradd -g lighttpd lighttpd1 +``` + +## Изменение прав + +``` +chown lighttpd1 /usr/local/lighttpd/log +``` + +## Добавление тестовой страницы + +cd /usr/local/lighttpd/webpages +vi index.html + +``` + <html> + <head> + <title>lighttpd test</title> + </head> + <body> + <p>this is a testing</p> + </body> + </html> +``` + +# Тестирование службы + +Запустите lighttpd. + +``` +/usr/local/lighttpd/sbin/lighttpd -f /usr/local/lighttpd/config/lighttpd.conf +``` + +Проверьте процесс программы. + +``` +ps -ef |grep lighttpd +``` + +Остановите lighttpd. + +``` +pkill lighttpd +``` + +Тестовая веб-страница: + +http://{{ server\_ip }}:80/index.html \ No newline at end of file diff --git a/web-ui/docs/ru/blog/randy1568/x86 Hardware Compatibility Assessment and Porting Guide (openEuler 20.03 LTS SP1).md b/web-ui/docs/ru/blog/randy1568/x86 Hardware Compatibility Assessment and Porting Guide (openEuler 20.03 LTS SP1).md new file mode 100644 index 0000000000000000000000000000000000000000..35b403181098b21a2ee92ebe2cae6cd52a9b361b --- /dev/null +++ b/web-ui/docs/ru/blog/randy1568/x86 Hardware Compatibility Assessment and Porting Guide (openEuler 20.03 LTS SP1).md @@ -0,0 +1,117 @@ +--- +title: Руководство по оценке совместимости аппаратного обеспечения x86 и портированию (openEuler 20.03 LTS SP1) +date: 2022.01.07 +tags: + - оценка совместимости аппаратного обеспечения x86 + - CX5 и 3108 RAID + - Руководство по портированию +sig: sig-Compatibility-Infra +archives: 2022.01 +author: randy1568 +summary: принципы оценки аппаратного обеспечения x86 (Hi1822 NIC и карта RAID-контроллера 3108) +--- + +# Руководство по оценке совместимости аппаратного обеспечения x86 и портированию (openEuler 20.03 LTS SP1) + + +# Среда + +## Аппаратное обеспечение + +В следующей таблице приведено описание аппаратного обеспечения. + +| Аппаратное обеспечение | Описание | +| ---------------------- | ----------------------------------------------- | +| Сервер | 2288H V5 | +| Центральный процессор | Процессор Intel(R) Xeon(R) Gold 6266C, 3,00 ГГц | +| NIC | Mellanox ConnectX-5 | +| Карта RAID-контроллера | Huawei LSI SAS3108 | + +## Операционная система + +В следующей таблице приведено описание операционных систем. + +| ОС | Описание | +| ------------ | --------------- | +| CentOS Linux | 7.9.2009 (Core) | +| Kernel | 3.10.0 x86_64 | + +Проверьте информацию о текущей системе. +cat /etc/os-release + + + +# Запуск инструмента x2openEuler и оценка совместимости аппаратного обеспечения + +Для оценки аппаратного и программного обеспечения, а также конфигурации системы сообщество openEuler предлагает использовать инструмент [x2openEuler](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/). При оценке аппаратного обеспечения проверяется совместимость плат, корректно работающих на ОС CentOS, с операционной системой openEuler. Инструмент собирает информацию о платах и создает отчеты в формате HTML, в которых выводятся данные о совместимости аппаратного обеспечения. + +## Загрузка x2openEuler + +``` +cd /opt/ +wget https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/x2openEuler-1.0-1.noarch.rpm +``` + +## Установка x2openEuler + +``` +cd /opt/ +rpm -ivh x2openEuler-1.0-1.noarch.rpm +``` + +> Примечание. Пакет RPM может установить пользователь с правами администратора (**root)**. Для загрузки и установки зависимостей необходимо сетевое соединение. +> +> Примечание. Установите зависимости, например **bzip2-devel,** следуя инструкциям. + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +Последовательно введите следующую информацию о базе данных Redis. + +IP-адрес: 127.0.0.1 +Порт: 6379 +Индекс базы данных (0-16): 0 +Пароль (шифруется инструментом): если пароль Redis не установлен или не заполнен, нажмите **Enter**. + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> Примечание. После установки x2openEuler с помощью пакета RPM в каталоге **/opt/x2openEuler** создается пакет с ресурсами по умолчанию (source\_centos7.6-openEuler20.03-LTS-SP1.tar.gz). Для поддержки оценки совместимости аппаратного обеспечения с операционными системами CentOS 8.2 и openEuler 20.03 LTS SP1 необходимо получить и импортировать соответствующий пакет со статическими ресурсами. Например, если пакетом ресурсов является **source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, выполните команду **x2openEuler init source\_centos8.2-openEuler20.03-LTS-SP1.tar.gz**, чтобы импортировать пакет. + +## Анализ совместимости аппаратных средств + + x2openEuler hardware-analyse + ‏The command output is as follows: + 2021-11-30 09:41:20,865 - INFO - Log save directory: /var/log/x2openEuler + 2021-11-30 09:41:20,887 - INFO - x2openEuler hardware-analyse + 2021-11-30 09:41:20,888 INFO manager/get_param_config/179: Parameter configuration file loaded. + 2021-11-30 09:41:20,905 INFO manager/get_regex_config/218: Regex pattern compiled. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/233: All builtin parsers loaded. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/236: All custom parsers loaded. + 2021-11-30 09:41:21,254 INFO time_utils/wrapper/21: 0.35s taken for running function [get_data] + 2021-11-30 09:41:21,269 WARNING list/parse_content/47: no data in ls_dev + 2021-11-30 09:41:21,377 INFO time_utils/wrapper/21: 0.12s taken for running function [get_parsed_content] + 2021-11-30 09:41:21,377 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_startup_param.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/syscall_interface.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/path.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/port.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/device_interface.json. + 2021-11-30 09:41:21,380 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/linux_command.json. + 2021-11-30 09:41:21,387 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/hardware_configure.json. + 2021-11-30 09:41:21,396 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/proc.json. + 2021-11-30 09:41:21,404 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_configure.json. + 2021-11-30 09:41:21,408 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_service.json. + 2021-11-30 09:41:21,412 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_configure.json. + 2021-11-30 09:41:21,426 - INFO - Producing report... + 2021-11-30 09:41:21,427 - INFO - Generate Success! The results are saved: /opt/x2openEuler/output/hw_compat_report-20211130094121.html + In the command output, /opt/x2openEuler/output/hw_compat_report-20211130094121.html is the evaluation report. + +# Анализ результатов оценки аппаратных средств + +В отчете с результатами оценки аппаратных средств выводится информация о том, насколько каждая плата и устройство в целом совместимы с ОС openEuler. Если какого-либо компонента нет в списке совместимых компонентов, требуется адаптация. + + +Каждая плата уникально определяется посредством четырех кортежей (VID, DID, SVID и SSID). Как видно из приведенного рисунка, по каждой плате можно сделать запрос по списку совместимых нижестоящих компонентов. Таким образом, в данном примере аппаратный сервер можно портировать с ОС CentOS на ОС openEuler 20.03 LTS SP1. \ No newline at end of file diff --git a/web-ui/docs/ru/blog/rosinL/2022-01-30 Ceph Community News (2021-12-13 to 2022-01-16).md b/web-ui/docs/ru/blog/rosinL/2022-01-30 Ceph Community News (2021-12-13 to 2022-01-16).md new file mode 100644 index 0000000000000000000000000000000000000000..7822530c8f1670612dc1290063756a6a2f643b55 --- /dev/null +++ b/web-ui/docs/ru/blog/rosinL/2022-01-30 Ceph Community News (2021-12-13 to 2022-01-16).md @@ -0,0 +1,57 @@ +--- +title: Новости сообщества Ceph (в период с 13.12.2021 по 16.01.2022) +date: 2022.01.30 +tags: + - Ceph + - Новости + - Pacific +sig: ceph-sig +archives: 2022.01 +author: rosinL +summary: новости сообщества Ceph +--- + +# Новости сообщества Ceph (в период с 13.12.2021 по 16.01.2022) + +## Планирование выпуска версии Quincy, функции в которую уже не добавляются, в марте 2022 г. + +Новые функции в версию Quincy не добавляются с 15 января 2022 года, и в настоящее время она находится в стадии тестирования. Помимо стандартных тестов, в настоящий момент проводятся более масштабные тесты. В таких тестах задействуются более 1000 OSD. + +## Слияние PR + +- common: оптимизирован PriorityCache. Ресурсы кэш-памяти распределяются по времени, реализована более точная установка приоритетов. Однако тесты на производительность показывают незначительное увеличение. [pr#43299](https://github.com/ceph/ceph/pull/43299) +- bluestore: оптимизирован процесс записи. Поток bufferlist проверяется на наличие нулей. Найденные нули пропускаются во время записи. Для отслеживания данного процесса используется новый счетчик. [pr#43337](https://github.com/ceph/ceph/pull/43337) +- bluestore: уменьшен объем ресурсов памяти, необходимых для fsck во время запуска. [pr#43667](https://github.com/ceph/ceph/pull/43667) +- bluestore: оптимизирована блокировка BlueFS с повышением детализации. [pr#43794](https://github.com/ceph/ceph/pull/43794) +- bluestore: используется буфер чтения с выделением огромных страниц памяти, который по умолчанию отключен. [pr#43691](https://github.com/ceph/ceph/pull/43691) +- mon: при создании пула добавляется флаг --bulk, в результате компонент pg autoscaler регулирует исходное число PG пула, вплоть до увеличения его до максимального значения. По умолчанию pg autoscaler настраивает минимальное значение количества PG пула и далее динамически изменяет это значение. [pr#44241](https://github.com/ceph/ceph/pull/44241) +- mgr: добавлены команды для глобального включения и отключения pg\_autoscaler. [pr#43716](https://github.com/ceph/ceph/pull/43716) +- mgr: реализована кэш-память TTL, которая хранит информацию о кластере и уменьшает операции по взаимодействию с кластером. [pr#44088](https://github.com/ceph/ceph/pull/44088) +- mgr: оптимизирован балансировщик и реорганизована структура calc\_pg\_upmaps ([pr#44002](https://github.com/ceph/ceph/pull/44002)). Балансировщик будет реализован в версии Quincy для балансировки емкости и нагрузки. +- cephdeduptool: добавлены команды chunk (offset и length) и object dedupe, которые облегчают использование функции дедупликации. [pr#43686](https://github.com/ceph/ceph/pull/43686) +- rgw/s3select: добавлены arrow/parquet ([pr#40802](https://github.com/ceph/ceph/pull/40802)). Из-за проблемы, связанной с зависимостями, данная функция во время компиляции по умолчанию отключена. [pr#44603](https://github.com/ceph/ceph/pull/44603) +- rgw: добавлены ограничения скорости по пользователю/сегменту памяти. [pr#42891](https://github.com/ceph/ceph/pull/42891) +- rgw: уменьшена ненужная нагрузка, связанная со статистикой сегмента памяти. [pr#44538](https://github.com/ceph/ceph/pull/44538) +- rgw: добавлена опция max\_header\_size, которая регулирует размер буфера синтаксического анализа фронтенда beast. По умолчанию устанавливается размер 16 КБ, максимальный размер — 64 КБ. Буфер большего размера позволяет уменьшить число операций чтения из сокета ([pr#44029](https://github.com/ceph/ceph/pull/44029)). В [pr#29776](https://github.com/ceph/ceph/pull/29776) размер увеличен до статической величины 64 КБ, что повысило гибкость. + +## Свежие новости от разработчиков Ceph + +Каждый модуль сообщества Ceph проводит регулярные совещания, на которых обсуждаются и решаются вопросы, связанные с текущим прогрессом разработки. Видео совещаний выгружаются на [YouTube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos). Наиболее важные совещания: + +| Совещание | Описание | Частота | +| ------------------------------------------------------------ | ----------------------------------- | ----------------- | +| Еженедельное совещание по вопросам Crimson SeaStore OSD | Разработка Crimson и SeaStore | Еженедельно | +| Совещание по вопросам оркестрации Ceph | Управляющий модуль Ceph (mgr) | Еженедельно | +| Совещание по вопросам Ceph DocUBetter | Оптимизация документов | Каждые две недели | +| Совещание по вопросам производительности Ceph | Оптимизация производительности Ceph | Каждые две недели | +| Ежемесячное совещание разработчиков Ceph | Разработчики Ceph | Ежемесячно | +| Совещание по вопросам тестирования Ceph | Верификация и выпуск версий | Ежемесячно | +| Совещание группы пользователей Ceph, ведущих научную деятельность | Научные вычисления Ceph | Нерегулярно | +| Совещание руководящей группы Ceph | Руководящий состав Ceph | Еженедельно | + +В последнее время большое внимание уделяется вопросам производительности. На совещаниях обсуждаются следующие темы: + +- Необходимость сравнения теста на производительность версии Quincy с тестом версии Pacific. Тест на производительность NVMe основан на MAKO (AMD EPYC 7742) и 120 OSD. Тестируются отдельные узлы или множество узлов (копированием и EC). Инструменты тестирования: fio(rbd cephfs), hsbench (rgw), tcmu-runner (iscsi/nbd), omapbench(mds). +- В версию Quincy можно добавить тест на восстановление. +- Согласно тесту версии Pacific, perf cycles/op monitoring уменьшает производительность максимум на 15%. +- Информация о занятой памяти Ceph не является прозрачной в связи с невозможностью отследить состояние памяти множества модулей. Поэтому может потребоваться дальнейшая оптимизация памяти. \ No newline at end of file diff --git a/web-ui/docs/ru/blog/rosinL/2022-02-23 Ceph Community News (2021-01-17 to 2022-02-16).md b/web-ui/docs/ru/blog/rosinL/2022-02-23 Ceph Community News (2021-01-17 to 2022-02-16).md new file mode 100644 index 0000000000000000000000000000000000000000..d4a2d5ba7b30841e65da3d255badb56b4752a62e --- /dev/null +++ b/web-ui/docs/ru/blog/rosinL/2022-02-23 Ceph Community News (2021-01-17 to 2022-02-16).md @@ -0,0 +1,101 @@ +--- +title: Новости сообщества Ceph (в период с 17.01.2022 по 16.02.2022) +date: 2022.02.23 +tags: + - Ceph + - Новости + - Pacific +sig: ceph-sig +archives: 2022.02 +author: rosinL +summary: новости сообщества Ceph +--- + +# Новости сообщества Ceph (в период с 17.01.2022 по 16.02.2022) + +## Отложенная конференция Cephalocon 2022 + +Конференция Cephalocon 2022, которая изначально планировалась на 5–7 апреля (6–8 апреля по пекинскому времени), отложена в связи с пандемией COVID-19. Новая дата мероприятия еще не объявлена. Доклады к конференции подготовлены и собраны в приведенной далее таблице. Подробную информацию см. в разделе [Расписание Cephalocon 2022](https://ceph2022.sched.com/). + +| Категория | Тема доклада | Докладчик | Организация | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------- | ------------------------------------------------------------ | +| RGW, производительность | [Оптимизация объектного хранилища RGW для рабочих нагрузок смешанного типа с помощью классификации памяти и разработки скрипта Lua](https://sched.co/w9FL) | Курт Брунс и Энтони Д'Атри | Intel | +| RGW | [RGW:](https://sched.co/w9Fm)[ ](https://sched.co/w9Fm)[Что синхронизируем?](https://sched.co/w9Fm)[ ](https://sched.co/w9Fm)[Sync Info Provider:](https://sched.co/w9Fm)[ ](https://sched.co/w9Fm)[беглый обзор]() | Иегуда Садех-Вайнрауб | Red Hat | +| RGW | [RGW – непревзойденный фронтенд S3 для нескольких бэкендов:](https://sched.co/w9GJ)[ ](https://sched.co/w9GJ)[история реализации](https://sched.co/w9GJ) | Григорий Турецкий и Андрей Ткачук | Seagate | +| RGW, S3select | [S3select:](https://sched.co/w9GY)[ ](https://sched.co/w9GY)[Вычислительное хранилище в S3](https://sched.co/w9GY) | Галь Саломон и Гирджеш Рахория | Red Hat | +| RGW | [Тестирование реализаций S3:](https://sched.co/w9Gh)[ ](https://sched.co/w9Gh)[RGW и не только](https://sched.co/w9Gh) | Робин Хью Джонсон | DigitalOcean | +| RGW | [Введение в интерфейс объектного хранилища контейнера (COSI) для ceph RGW](https://sched.co/w9Fs) | Джиффин Тони Тоттан | Red Hat | +| RGW | [RGW Zipper](https://sched.co/w9GD) | Даниэль Гриневич и Сумья Кодури | Red Hat | +| Cephadm | [Блиц-доклад:](https://sched.co/w9EW)[ ](https://sched.co/w9EW)[введение в Cephadm](https://sched.co/w9EW) | Мелисса Ли | Red Hat | +| Dashboard | [Dashboard:](https://sched.co/w9GP)[ ](https://sched.co/w9GP)[исследования в области централизованного ведения журнала в системе хранения данных Ceph Storage](https://sched.co/w9GP) | Гаурав Ситлани и Аашиш Шарма | Red Hat | +| Dashboard | [Эксплуатация системы хранения Ceph через панель управления Ceph Dashboard:](https://sched.co/w9F0)[ ](https://sched.co/w9F0)[вчера, сегодня и завтра]() | Эрнесто Пуэрта | Red Hat | +| Ceph, QoS, mClock | [Оптимизация QoS в системе хранения Ceph для фоновых операций с помощью mClock](https://sched.co/w9Fv) | Шридхар Сешасайи | Red Hat | +| Ceph, PG | [pgremapper:](https://sched.co/w9EZ)[ ](https://sched.co/w9EZ)[Сложности работы с кластером CRUSHing](https://sched.co/w9EZ) | Джошуа Баерген | DigitalOcean | +| Ceph, PG | [Новый балансировщик рабочих нагрузок в Ceph](https://sched.co/w9Eo) | Джош Саломон и Лора Флорес | Red Hat | +| Ceph, DPDK | [Блиц-доклад:](https://sched.co/w9FO)[ ](https://sched.co/w9FO)[Разработка и отладка Ceph Messenger DPDkstack](https://sched.co/w9FO) | Чунсун Фэн | Huawei | +| Ceph, Windows | [Ceph на ОС Windows](https://sched.co/w9Ei) | Алессандро Пилотти | Cloudbase Solutions | +| Seastore | [Что нового у Crimson и Seastore?](https://sched.co/w9FI) | Самюэль Джаст | Red Hat | +| Seastore, Crimson | [[Блиц-доклад]:](https://sched.co/w9FF)[ ](https://sched.co/w9FF)[Crimson глазами новичка](https://sched.co/w9FF) | Джозеф Савайя | Red Hat | +| Seastore | [Интерпретация SeaStore путем профилирования производительности](https://sched.co/w9ET) | Инсинь Чэн и Тушар Гохад | Intel | +| Bluestore | [Ускорение операций устройства PMEM в BlueStore аппаратными методами разгрузки памяти](https://sched.co/w9F9) | Цзие Ян | Intel | +| Bluestore | [Выявление ошибок, связанных с повреждением данных в BlueStore, в контейнерных кластерах Ceph](https://sched.co/w9Fj) | Сатору Такэути | Cybozu | +| Dev | [Отслеживаем неправильные контрольные суммы:](https://sched.co/w9Fd)[ ](https://sched.co/w9Fd)[турне по Ceph, TCMalloc и ядру Linux](https://sched.co/w9Fd) | Маурисио Фариа де Оливейра и Дэн Хилл | Canonical | +| Dev | [Блиц-доклад:](https://sched.co/w9Gt)[ ](https://sched.co/w9Gt)[оптимизация компоновки Ceph и автоматизация бэкпортирования с помощью Github Actions](https://sched.co/w9Gt) | Дипика Упадхьяй | Red Hat | +| Dev | [Контроль фатальных сбоев Ceph посредством телеметрии в действии](https://sched.co/w9Ec) | Яарит Хатука | Red Hat | +| Производительность | [DisTRaC:](https://sched.co/w9Ef)[ ](https://sched.co/w9Ef)[ускорение высокопроизводительных вычислений в системах хранения временных данных](https://sched.co/w9Ef) | Габриэль Мейсон-Уильямс | Rosalind Franklin Institute | +| Производительность | [Закладываем вычислительные мощности в вашу СХД](https://sched.co/w9Fg) | Федерико Люцифреди и Брэд Хаббард | Red Hat | +| Производительность | [Модификация Ceph для повышения производительности HPC](https://sched.co/w9Gb) | Даррен Сутхилл | CROIT | +| Производительность | [Обработка более миллиарда запросов в день:](https://sched.co/w9FR)[ ](https://sched.co/w9FR)[производительностью кластера Ceph останется довольным каждый](https://sched.co/w9FR) | Джейн Чжу и Мэтью Леонард | Bloomberg LP | +| Производительность | [Извлечение уроков из проектов аппаратного ускорения работы приложений под Ceph](https://sched.co/w9G4) | Гарри Ричардсон и Лайонел Корбет | SoftIron | +| Производительность | [Актуальные разработки передовых SSD под Ceph](https://sched.co/w9GG) | Мёнвон О | Samsung Electronics | +| Производительность | [Поддержка интерфейса NVMe-over-Fabrics для Ceph](https://sched.co/w9GS) | Йонас Пфефферле, IBM и Скотт Петерсон | Intel | +| Безопасность | [Знакомство с новой функцией шифрования образов RBD](https://sched.co/w9F3) | Ор Озери и Дэнни Харник | IBM | +| Безопасность | [Шифрование данных во время хранения в CephFS с помощью fscrypt](https://sched.co/w9Eu) | Джеффри Лейтон | Red Hat | +| Безопасность | [Служба](https://ceph2022.sched.com/) [Secure Token Service в Ceph](https://sched.co/w9Ex) | Притха Шривастава | Red Hat | +| Безопасность | [Безопасность данных и усиление защиты хранения в Rook и Ceph](https://sched.co/w9Fp) | Федерико Люцифред и Майкл Хакетт | Red Hat | +| Применение Ceph | [Оптимизация существующей крупной инфраструктуры Ceph с точки зрения непрерывности бизнеса:](https://sched.co/w9G7)[ ](https://sched.co/w9G7)[пример из практики](https://sched.co/w9G7) | Энрико Боч и Артур Оутенин-Шаландр | CERN | +| Применение Ceph | [Как мы эксплуатируем Ceph в нужном масштабе](https://sched.co/w9Fy) | Мэтт Вандермюлен | Digital Ocean | +| Применение Ceph | [Семинар по BoF:](https://sched.co/w9FC)[ ](https://sched.co/w9FC)[Ceph в научных вычислениях и крупных кластерах](https://sched.co/w9FC) | Кевин Хрпчек | Space Science \& Engineering Center, University of Wisconsin - Madison | +| Применение Ceph | [Aquarium:](https://sched.co/w9Ge)[ ](https://sched.co/w9Ge)[как легко использовать устройства Ceph](https://sched.co/w9Ge) | Жоао Эдуардо Луис и Александра Сеттл | SUSE | +| Применение Ceph | [Расширение кластеров в Ceph:](https://sched.co/w9Gn)[ ](https://sched.co/w9Gn)[алгоритмы, примеры использования и улучшения](https://sched.co/w9Gn) | Грегори Фарнум | Red Hat | +| Применение Ceph | [Как мы добавили к СХД Ceph 6 петабайт емкости и ни один пользователь не заметил...](https://sched.co/w9FX)[ ](https://sched.co/w9FX) | Джозеф Мундакал и Мэтью Леонард | Bloomberg LP | +| Применение Ceph | [Для чего мы построили систему телеметрии и сбора сообщений о работе всего кластера Ceph?](https://sched.co/w9FU) | Сяолинь Линь и Мэтью Леонард | Bloomberg LP | +| Применение Ceph | [Блиц-доклад.]()[ ](https://sched.co/w9Gk)[Ceph и 6G:](https://sched.co/w9Gk)[ ](https://sched.co/w9Gk)[а мы готовы к объемам данных, измеряемых в зеттабайтах?](https://sched.co/w9Gk) | Бабар Хан | Technical University Darmstadt | +| Применение Ceph | [emails@ceph: хранение почтовых сообщений в кластере Ceph]() | Дэнни Аль-Гааф | Deutsche Telekom AG | +| Применение Ceph | [Блиц-доклад.]()[ ](https://sched.co/w9F6)[Ceph и QCOW2 — идеальный союз.](https://sched.co/w9F6)[ ](https://sched.co/w9F6)[Переходим от миграции в реальном времени к дифференцированным мгновенным снимкам](https://sched.co/w9F6) | Эффи Офер | IBM | +| Применение Ceph | [Блиц-доклад](https://sched.co/w9Gk)[:](https://sched.co/w9GM)[ ](https://sched.co/w9GM)[установка Ceph на Kubernetes с использованием Rook Operator и Helm](https://sched.co/w9GM) | Майк Петерсен | Platform9 | +| Эталонное тестирование | [Делая выводы:](https://sched.co/w9GA)[ ](https://sched.co/w9GA)[эталонное тестирование Ceph в нужном масштабе](https://sched.co/w9GA) | Шон Пас и Идо Пал | Red Hat | +| Эталонное тестирование | [Знакомимся с Sibench:](https://sched.co/w9GV)[ ](https://sched.co/w9GV)[новый инструмент эталонного тестирования](https://sched.co/w9GA)[ с открытым исходным кодом, оптимизированный под Ceph](https://sched.co/w9GV) | Дэнни Абукалам | SoftIron | + + + +## Слияние PR + +В последнее время PR ориентированы на исправление ошибок. Далее приведены наиболее значительные изменения: + +- mgr: отключено восстановление pg по умолчанию при вводе и выводе OSD. Функцию по необходимости можно включить вручную, чтобы уменьшить влияние на сервисный кластер. [pr#44588](https://github.com/ceph/ceph/pull/44588) +- osd: в дамп производительности демона ceph добавлена опция dump\_blocked\_ops\_count, которая позволяет быстро получить число заблокированных операций, уменьшая затраты ресурсов на операцию dump\_blocked\_ops. [pr#44780](https://github.com/ceph/ceph/pull/44780) +- rgw: добавлена ​​поддержка условного копирования с помощью интерфейса rgw s3 CopyObject. [pr#44678](https://github.com/ceph/ceph/pull/44678) +- rgw: исправлена ​​проблема, связанная с занятием большого объема памяти во время процесса radosgw-admin bucket chown. [pr#44357](https://github.com/ceph/ceph/pull/44357) +- rbd: к krbd добавлена ​​опция rxbounce, которая решает проблемы с ошибками CRC и ухудшением производительности при использовании образов в качестве блочных устройств системы Windows. [pr#44842](https://github.com/ceph/ceph/pull/44842) + +## Свежие новости от разработчиков Ceph + +Каждый модуль сообщества Ceph проводит регулярные совещания, на которых обсуждаются и решаются вопросы, связанные с текущим прогрессом разработки. Видео совещаний выгружаются на [YouTube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos). Наиболее важные совещания: + +| Совещание | Описание | Частота | +| ------------------------------------------------------------ | ----------------------------------------- | ----------------- | +| Еженедельное совещание по вопросам Crimson SeaStore OSD | Разработка Crimson и SeaStore | Еженедельно | +| Совещание по вопросам оркестрации Ceph | Разработка управляющего модуля Ceph (mgr) | Еженедельно | +| Совещание по вопросам Ceph DocUBetter | Оптимизация документов | Каждые две недели | +| Совещание по вопросам производительности Ceph | Оптимизация производительности Ceph | Каждые две недели | +| Ежемесячное совещание разработчиков Ceph | Разработчики Ceph | Ежемесячно | +| Совещание по вопросам тестирования Ceph | Верификация и выпуск версий | Ежемесячно | +| Совещание группы пользователей Ceph, ведущие научную деятельность | Научные вычисления Ceph | Нерегулярно | +| Совещание руководящей группы Ceph | Руководящий состав Ceph | Еженедельно | + +В последнее время сообщество уделяет большое внимание приостановленным тестам и верификации версии Quincy. На совещаниях обсуждаются следующие темы: + +- В тесте версии Quincy производительность чтения соответствует ожиданиям, однако производительность записи в некоторых сценариях ухудшается. Производительность могут улучшить 4k min\_alloc\_size и bluestore allocator. +- По мере увеличения масштаба omap производительность итератора omap\_iterator приводит к большому числу операций slow\_ops или даже к отсутствию ответа. В раздел [проблемы](https://tracker.ceph.com/issues/53926) вносятся результаты испытаний двух режимов сжатия. Если сжатие запускается вручную, восстановить задержку до прежнего уровня невозможно. Для решение этой проблемы в Rocksdb предлагается функция [периодического сжатия и TTL](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide#periodic-and-ttl-compaction). После ее включения задержку можно будет восстановить до прежнего уровня. +- Для эталонного инструмента Ceph Benchmark Tool (CBT) выполнено слияние большого числа PR с упором на управление ресурсами памяти в сценариях тестирования OSD в крупномасштабной среде и параллельного тестирования в многоклиентской среде. \ No newline at end of file diff --git a/web-ui/docs/ru/building/README.md b/web-ui/docs/ru/building/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f14b76a1efc2719e262f7df6fed2ec51d8db4e0e --- /dev/null +++ b/web-ui/docs/ru/building/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/ru/community/certification-services/README.md b/web-ui/docs/ru/community/certification-services/README.md new file mode 100644 index 0000000000000000000000000000000000000000..57ef1d65d62cc272b0cd28c192b4ed82a94fb75f --- /dev/null +++ b/web-ui/docs/ru/community/certification-services/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/ru/community/certification-services/down.md b/web-ui/docs/ru/community/certification-services/down.md new file mode 100644 index 0000000000000000000000000000000000000000..aff1dd4f4e03e625656105802aef2c2b6114f8e1 --- /dev/null +++ b/web-ui/docs/ru/community/certification-services/down.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/ru/community/certification-services/search.md b/web-ui/docs/ru/community/certification-services/search.md new file mode 100644 index 0000000000000000000000000000000000000000..584078cba784f885ec509e091b66f6b5725569e0 --- /dev/null +++ b/web-ui/docs/ru/community/certification-services/search.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/ru/community/conduct/README.md b/web-ui/docs/ru/community/conduct/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6804d6f0ba721ea7fd83b5527404f4174dbd493f --- /dev/null +++ b/web-ui/docs/ru/community/conduct/README.md @@ -0,0 +1,60 @@ +--- + + +title: "Кодекс" + +--- + + + + + +
+Сообщество openEuler соблюдает Кодекс поведения разработчиков Contributor Covenant Code of Conduct V1.4, составленный сообществом разработчиков программного обеспечения с открытым исходным кодом. + +Если вы хотите сообщить о случаях оскорбления, домогательства или другом недопустимом поведении, свяжитесь с Техническим комитетом openEuler, отправив электронное письмо по адресу . + + +## Обязательства разработчиков + +В интересах создания открытой благоприятной среды разработчики и специалисты по сопровождению обязуются, участвуя в проекте openEuler и будучи участниками сообщества openEuler, не предпринимать действий оскорбительного характера к кому-бы то ни было по возрастному признаку, различиям в телосложении, наличию инвалидности, этнической принадлежности, сексуальной ориентации и гендерному самовыражению, уровню опыта, образованию, социально-экономическому положению, национальности, внешности, расовым признаками, религиозному выбору. + +## Стандарты openEuler + +Поведение, которое способствует формированию позитивной атмосферы: + ++ Доброжелательная недискриминационная лексика + ++ Уважительное отношение к разным точкам зрения и разному опыту + ++ Адекватная реакция на конструктивную критику + ++ Акцент на оптимальные для общества условия + ++ Проявление сочувствия к другим участникам сообщества + +Недопустимое поведение участников: + ++ Использование сексуально окрашенных выражений или образов, нежелательных сексуальных жестов или знаков внимания + ++ Травля, комментарии оскорбительного или неуважительного характера, переход на личности или политические выпады + ++ Преследования отдельной личности или широкого круга общественности + ++ Разглашение частной информации посторонних лиц, например физического или электронного адреса, без явного на то разрешения + ++ Другое поведение, которое можно считать неуместным в профессиональной среде + +## Обязательства сообщества + +Специалисты по сопровождению проекта несут ответственность за разъяснение стандартов приемлемого поведения и в случае любого недопустимого поведения обязаны принять надлежащие и справедливые корректирующие меры.
Специалисты по сопровождению проекта вправе и обязаны удалять, редактировать или отклонять комментарии, подтверждения операций и команд, правки вики-страниц, замечания и другой контент, который не соответствует данному Кодексу поведения, или временно либо навсегда запретить любому разработчику совершать другие действия, которые они считают неуместными, угрожающими, оскорбительными или оказывающими тлетворное влияние. + +## Область применения + +Данный Кодекс поведения применяется во всех проектах, а также в тех случаях, когда какое-либо лицо представляет проект или его сообщество в публичных пространствах.
К таким случаям относятся использование официального электронного адреса проекта, размещение информации в социальных сетях через официальный аккаунт или выполнение функций назначенного представителя на традиционном или онлайн-мероприятии.
Специалисты по сопровождению проекта могут дополнительно определить и уточнить область, охватываемую термином представления проекта. + +## Контроль соблюдения Кодекса + +Чтобы сообщить о случаях оскорбления, домогательства или другом недопустимом поведении проектной группе, отправьте электронное письмо по адресу .
Все жалобы подлежат рассмотрению и изучению, после чего отправляется ответ, который будет сочтен необходимым и целесообразным в данных обстоятельствах. Группа сообщества обязана соблюдать конфиденциальность в отношении лица, сообщившего об инциденте. Более подробная информация о конкретных мерах контроля соблюдения Кодекса поведения может быть размещена отдельно.
В отношении специалистов по сопровождению проекта, которые не соблюдают Кодекс или недобросовестно относятся к выполнению своих обязательств, могут быть приняты временные или постоянные меры, определенные другими руководителями проекта. + +
diff --git a/web-ui/docs/ru/community/contribution/README.md b/web-ui/docs/ru/community/contribution/README.md new file mode 100644 index 0000000000000000000000000000000000000000..60e6741e88c7499cc190457fdd12dd563b935241 --- /dev/null +++ b/web-ui/docs/ru/community/contribution/README.md @@ -0,0 +1,7 @@ +--- +title: "Contribution" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/community/contribution/detail.md b/web-ui/docs/ru/community/contribution/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..9e1445320bf297c65d1aacec07afc093e1abe239 --- /dev/null +++ b/web-ui/docs/ru/community/contribution/detail.md @@ -0,0 +1,140 @@ +--- +title: "Contribution" +--- + + + + +
+ +欢迎来到openEuler! + +## 1. 体验openEuler +### 1.1 体验openEuler操作系统 + +您可以通过以下四种方式体验openEuler操作系统: + +- [公有云](https://huaweicloud.com/product/ecs.html) +- [虚拟机](https://www.openeuler.org/ru/docs/20.03_LTS/docs/Virtualization/virtualization.html) +- [硬件](https://www.openeuler.org/ru/docs/20.03_LTS/docs/Installation/installation.html) +- [树莓派](https://gitee.com/openeuler/raspberrypi) + +### 1.2 体验原创开源项目 + +您可以体验openEuler社区里的以下原创开源项目: + +- [StratoVirt](https://www.openeuler.org/ru/other/projects/stratovirt/):面向云数据中心的企业级虚拟化平台 +- [A-Tune](https://www.openeuler.org/ru/other/projects/atune/):一款基于AI开发的智能优化引擎 +- [iSula](https://www.openeuler.org/ru/other/projects/isula/):轻量级容器解决方案 +- [secGear](https://www.openeuler.org/ru/other/projects/secgear/):面向计算产业的机密计算安全应用开发套件 +- [pkgship](https://pkgmanage.openeuler.org/):管理OS软件包依赖关系,提供依赖和被依赖关系完整图谱的查询工具 +- [BiSheng JDK](https://www.openeuler.org/ru/other/projects/bishengjdk/): OpenJDK定制版Huawei JDK的开源版本,是一个高性能、可用于生产环境的OpenJDK发行版 +- [Compass-CI](https://compass-ci.openeuler.org/): 可持续集成的开源软件平台, 构建一个开放、完整的测试系统 + +## 2. 签署CLA + +在参与社区贡献前,您需要签署openEuler社区贡献者许可协议(CLA)。 +根据您的参与身份,选择签署个人CLA、员工CLA或企业CLA,请点击[这里](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)签署 + +- 个人CLA:以个人身份参与社区,请签署个人CLA +- 企业CLA: 以企业身份参与社区,请签署企业CLA +- 员工CLA: 以企业员工的身份参与社区,请签署员工CLA + +## 3. 参与openEuler社区 +### 3.1 参与社区活动 + +您可以了解并参与丰富多彩的社区活动: + +- [Meeting](/zh/#meeting):查看官网首页SIG公开例会日程安排,可参与你感兴趣的会议 +- [Meetups](https://www.openeuler.org/ru/interaction/salon-list/) +- [直播](https://www.openeuler.org/ru/interaction/live-list/) +- [峰会](https://www.openeuler.org/ru/interaction/summit-list/summit2021/) + +### 3.2 找到您想参与的SIG +#### 3.2.1 了解SIG并找到您感兴趣的SIG +SIG就是Special Interest Group的缩写,openEuler社区按照不同的SIG来组织,以便于更好的管理和改善工作流程。因此参与社区事务正确的起始姿势是先找到您感兴趣的SIG, SIG组均是开放的,欢迎任何人来参与。 +目前openEuler社区已有70+ SIG组,可查看 [openEuler SIG 列表](https://www.openeuler.org/ru/sig/sig-list/) 找到您感兴趣的SIG。 +如果定位不到您感兴趣的SIG,您可以向[community@openeuler.org](mailto:community@openeuler.org)发求助邮件。建议您在邮件列表内用“【开发过程疑问】”作为标题,在内容中写出你寻找的SIG或项目的特征,我们会为您提供帮助。 + +#### 3.2.2 成立新的SIG + +如果在已有的SIG组列表里面没有找到您感兴趣的SIG,而您对某个方向有浓厚的兴趣,希望在openEuler社区成立一个新的相关SIG进行维护和发展,那您可以参考 [申请新SIG流程指南](https://www.openeuler.org/ru/sig/sig-guidance/) 来申请创建新的SIG. + +### 3.3 参与社区贡献 + +在签署了[CLA协议](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)、找到了你想参与的[SIG组](https://www.openeuler.org/ru/sig/sig-list/)之后,就可以开始你的社区贡献之旅啦!社区贡献的方式有很多种,每一种贡献都将受到社区的欢迎和重视。 +##### 1.提交Issue/处理issue任务 + +- 找到Issue列表: + 在您感兴趣的SIG项目Gitee主页内,点击“Issues”,您可以找到其Issue列表(如[Community团队的Issue列表](https://gitee.com/openeuler/community/issues)) +- 提交Issue + 如果您准备向社区上报Bug或者提交需求,或者为openEuler社区贡献自己的意见或建议,请在openEuler社区对应的仓库上提交Issue。 + 提交Issue请参考 [Issue提交指南](https://gitee.com/openeuler/community/blob/master/zh/contributors/issue-submit.md)。为了吸引更广泛的注意,您也可以把Issue的链接附在邮件内,通过[邮件列表](https://www.openeuler.org/ru/community/mailing-list/)发送给所有人。 +- 参与Issue内的讨论 + 每个Issue下面可能已经有参与者们的交流和讨论,如果您感兴趣,也可以在评论框中发表自己的意见。 +- 找到愿意处理的Issue + 如果您愿意处理其中的一个issue,可以将它分配给自己。只需要在评论框内输入 /assign或 /assign @yourself,机器人就会将问题分配给您,您的名字将显示在负责人列表里。 + +##### 2.贡献编码 + +- 准备openEuler的开发环境 + 如果您想参与编码贡献,需要准备openEuler的开发环境,请参考[开发环境准备](https://gitee.com/openeuler/community/blob/master/zh/contributors/prepare-environment.md)。 +- 了解SIG和项目内的开发注意事项 + 每个SIG内的项目使用的编码语言、开发环境、编码约定等都可能存在差异的。如果您想了解并参与到编码类贡献,可以先找到该项目给开发者提供的贡献者指南——这个指南一般是在该SIG的首页地址内,以CONTRIBUTING.md文件的形式提供,或者就直接在该项目的README.md内。 +- 下载代码和拉分支 + 如果要参与代码贡献,您还需要了解如何在Gitee下载代码,通过PR合入代码等。openEuler使用Gitee代码托管平台,想了解具体的指导,请参考[Gitee Workflow Guide](https://gitee.com/openeuler/community/blob/master/zh/contributors/Gitee-workflow.md)。该托管平台的使用方法类似GitHub,如果您以前使用过GitHub,本节的内容您可以大致了解甚至跳过。 +- 修改、构建和本地验证 + 在本地分支上完成修改后,进行构建和本地验证,请参考[构建软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/package-install.md)。 +- 提交一个Pull-Request + 当你提交一个PR的时候,就意味您已经开始给社区贡献代码了。请参考 openEuler社区PR提交指导。 + 为了使您的提交更容易被接受,您需要: + - 遵循SIG组的编码约定,如果有的话 + - 准备完善的提交信息 + - 如果一次提交的代码量较大,建议将大型的内容分解成一系列逻辑上较小的内容,分别进行提交会更便于检视者理解您的想法 + - 使用适当的SIG组和监视者标签去标记PR:社区机器人会发送给您消息,以方便您更好的完成整个PR的过程 + + 注意:如果您的PR请求没有引起足够的关注,可以在SIG的邮件列表或dev@openeuler.org求助。 + +##### 3.贡献软件包 +如果你发现openEuler缺失了一个软件包,可以帮openEuler把这个软件包补上。实际上贡献软件包的过程就是帮助openEuler提供更丰富功能的过程。希望随着大家的参与,openEuler能够成为一个“无所不有”的软件生态系统。openEuler支持在gitee新增软件包的同时自动在obs的openEuler:Fctory上创建同名仓库。这样在向已创建的gitee仓库提交代码时,会自动对代码编译进行检测。具体流程可参考 [如何新增软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/create-package.md)。 +##### 4.贡献原创开源项目 +如果你想将自己原创的开源项目贡献到openEuler社区,成为openEuler发行版本中的一份子,那么可参考以下两种方式: +- 方式一:在其它社区开发,集成到openEuler中 + 假定你已经在github,gitlab或者gitee上拥有了自己的项目,那么只需要按照以上提到的 [如何新增软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/create-package.md) 那样,将软件加入到src-openeuler这个repo仓就可以了。 +- 方式二:在openEuler社区中开发,在openEuler中集成 + 直接在https://gitee.com/openeuler中建立原创项目,类似将项目“托管”到openEuler社区,比如现在社区中的iSula和A-Tune就是这样的模式。 + 如果你有了一个很棒的idea想要在openEuler社区里实现,那么他可以依照下面的过程来深度参与到openEuler中。 + 1.在[TC委员会的例会](https://www.openeuler.org/ru/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org)中申请一个开源项目; + 2.如果TC委员会认为这是一个很好的idea,并且认为值得去推进,那么我们会在[https://gitee.com/openeuler](https://gitee.com/openeuler)中建立一个repo; + 3.这个项目在openeuler中持续开发和孵化,直到项目逐渐成熟,那么就可以在src-openeuler中建立一个仓,为该项目提供相关的spec文件,制作成为一个rpm; + 4.最终这个原创的开源项目会随着openEuler的发布版本走遍全世界,为世界人民所使用。 + +##### 5.检视代码 +openEuler是一个开放的社区,我们希望所有参与社区的人都能成为活跃的检视者。当成为SIG组的committer或maintainer角色时,便拥有审核代码的责任与权利。 +强烈建议本着[行为准则](https://gitee.com/openeuler/community/blob/master/code-of-conduct.md),超越自我,相互尊重和促进协作。[《补丁审核的柔和艺术》](https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/)一文中提出了一系列检视的重点,说明代码检视的活动也希望能够促进新的贡献者积极参与,而不会使贡献者一开始就被细微的错误淹没,所以检视的时候,可以重点关注包括: +  1.贡献背后的想法是否合理 +  2.贡献的架构是否正确 +  3.贡献是否完善 + +##### 6.测试 +测试——是所有贡献者的责任,对于社区版本来说,[sig-qa](https://gitee.com/openeuler/QA)组是负责测试活动的社区官方组织。如果您希望在自己的基础架构上开展测试活动,可以参考:[社区测试体系介绍](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md) 。 +为了成功发行一个社区版本,需要完成多种测试活动。不同的测试活动,测试代码的位置也有所不同,成功运行测试所需的环境的细节也会有差异,有关的信息可以参考:[社区开发者测试贡献指南](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E5%BC%80%E5%8F%91%E8%80%85%E6%B5%8B%E8%AF%95%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97.md)。 +##### 7.选择社区组件打包 +您也可以参与社区组件打包,请参考 [如何打包](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md)。 +##### 8.参与非代码类贡献 +如果您的兴趣不在编写代码方面,可以在[ 非代码贡献指南 ](https://gitee.com/openeuler/community/blob/master/zh/contributors/non-code-contributions.md)中找到感兴趣的工作。 +##### 9.社区安全问题披露 +[安全处理流程](https://gitee.com/openeuler/security-committee/blob/master/%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.jpg)——简要描述了处理安全问题的过程。 +[安全披露信息](https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md)——如果您希望报告安全漏洞,请参考此页面。 + +## 4. 和社区一起成长 +### 4.1 社区角色说明 + +社区不同角色对应不同的责任与权利,每种角色都是社区不可或缺的一部分,您可以通过积极贡献不断积累经验和影响力,并获得角色上的成长。更详细角色说明与责任权利描述请查看 [角色说明](https://gitee.com/openeuler/community/blob/master/community-membership_cn.md)。 + +### 4.2 技术委员会 + +openEuler技术委员会(Technical Committee,简称TC)是openEuler社区的技术决策机构,负责社区技术决策和技术资源的协调。 +详情请查看 [openEuler技术委员会介绍](https://www.openeuler.org/ru/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org) + +
\ No newline at end of file diff --git a/web-ui/docs/ru/community/mailing-list/README.md b/web-ui/docs/ru/community/mailing-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..09432be3e4fc9ef15ddf82cf3b60af3e02b82de5 --- /dev/null +++ b/web-ui/docs/ru/community/mailing-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Mail lists" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/compatibility/README.md b/web-ui/docs/ru/compatibility/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7620c171b4783007a6447126569755231627f9c8 --- /dev/null +++ b/web-ui/docs/ru/compatibility/README.md @@ -0,0 +1,7 @@ +--- +title: "Compatibility" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/compatibility/hardware-info/README.md b/web-ui/docs/ru/compatibility/hardware-info/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af845b8f47b801a22fcdcd66528f1173db870534 --- /dev/null +++ b/web-ui/docs/ru/compatibility/hardware-info/README.md @@ -0,0 +1,7 @@ +--- +title: "HardwareInfo" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/compatibility/hardware/README.md b/web-ui/docs/ru/compatibility/hardware/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7d8b33fb2d5f45ddfae96413aad95f0615ca0793 --- /dev/null +++ b/web-ui/docs/ru/compatibility/hardware/README.md @@ -0,0 +1,7 @@ +--- +title: "Hardware" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/download/README.md b/web-ui/docs/ru/download/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d17a2aa9e3b538f2cbe93feb5e37e36decadab0 --- /dev/null +++ b/web-ui/docs/ru/download/README.md @@ -0,0 +1,7 @@ +--- +title: "Download" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/blog-list/README.md b/web-ui/docs/ru/interaction/blog-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f9d1e14dc33b36d6278a769b303b2f6763924dcc --- /dev/null +++ b/web-ui/docs/ru/interaction/blog-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Blog" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/live-list/README.md b/web-ui/docs/ru/interaction/live-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0c22aa239ca62887cc5200a75bfb031a1f25f93b --- /dev/null +++ b/web-ui/docs/ru/interaction/live-list/README.md @@ -0,0 +1,6 @@ +--- +title: "Live" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/news-list/README.md b/web-ui/docs/ru/interaction/news-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a43f525d5a83ae0834fb5692ad3ce4c16481e30d --- /dev/null +++ b/web-ui/docs/ru/interaction/news-list/README.md @@ -0,0 +1,7 @@ +--- +title: "News" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/post-blog/README.md b/web-ui/docs/ru/interaction/post-blog/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0eaa04e90634f7830c36292fd86ea3c3eef60359 --- /dev/null +++ b/web-ui/docs/ru/interaction/post-blog/README.md @@ -0,0 +1,172 @@ +--- +title: "Guidance to Post a Blog" + +--- + + + + +
+ +## Preparation + +1. Refer to to register Gitee account. + +2. Set your primary mail box in gitee settings . + +3. Sign your CLA in . + +4. Prepare your git environment refering to . + +## Understand blog format + +The openEuler blog is written in markdown format. +You can read to get understand how the blog is designed. + +The head includes the following information: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: sig-xxx +archives: 2020-03 +author: openEuler Blog Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your blog. +``` + +Tips: you can copy https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/en/interaction/post-blog/blog_example/2020-03-03-sample-post.md to your folder and edit it. + +## Post your blog + +The blog posting follows the pull request of [Gitee](gitee.com). + +1. Fork openEuler blog project to your own gitee. Refer to for detailed guidance. + +2. Clone the code to your local environment. + +``` +git clone https://gitee.com//website-v2 +``` + +3. Create a branch + +``` +git checkout -b +``` + +4. Create a folder in the website floder +If you are going to post a blog in English, the web-ui/docs/en/blog is your work path. + +And if you are going to post a blog in Chinese, the web-ui/docs/zh/blog is your work path. + +Assume that you are preparing a English blog. + +``` +cd web-ui/docs/en/blog +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +And You can put the resources in the same folder as your text file's, and name the resources as +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +Where the YEAR, MONTH, DAY, and title are the same as your blog file, and NN is the serial number of the pictures, like 01, 02 and so on. The MARKUP is the file extension, and for pictures it is recommended to use png. +The following are one example. +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` + +1. Commit your post + +``` +git add +git commit -m "" +git push origin : +``` + +2. Refer to to submit your Pull Request + +3. Wait for reviewing and merging. + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/post-blog/blog_design/README.md b/web-ui/docs/ru/interaction/post-blog/blog_design/README.md new file mode 100644 index 0000000000000000000000000000000000000000..df5f3e46b86f70f24ddedbfc90c948984f39e3d9 --- /dev/null +++ b/web-ui/docs/ru/interaction/post-blog/blog_design/README.md @@ -0,0 +1,101 @@ +# Posts +This file is to explain in which way the content of the blogs are stored and read by the blog system. + +## What is supported in the blog +A blog can include many formats of information, like text, pictures, videos, animations or others. + +openEuler Blog is designed to support the following formats: + +1. text +2. static picture +3. links +4. animation + +## Folder design +The content of blogs are under + +``` +|__ web-ui/docs/en/interaction/post-blog/blog_example --list the some blog examples +|__ web-ui/docs/zh/blog/guidance --house the guidance to post and maintain the blogs in Chinese +|__ web-ui/docs/en/blog/guidance --house the guidance to post and maintain the blogs in English +|__ web-ui/docs/zh/blog --house all the final posts in Chinese + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID +|__ web-ui/docs/en/blog --house all the final posts in English + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID + +``` + +## Post content design +### Choose languange +If you are going to post a blog in English, the web-ui/docs/en/blog is your work path. + +And if you are going to post a blog in Chinese, the web-ui/docs/zh/blog is your work path. + +### File name (Assuming to write a post in Enlgish) +To create a post, add a file to your web-ui/docs/en/blog/author_1/_ directory with the following format: + +``` +YEAR-MONTH-DAY-title.MARKUP +``` +Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers, and MARKUP is the file extension representing the format used in the file. For example, the following are examples of valid post filenames: +``` +2020-01-01-new-years-is-coming.md +2020-02-15-how-to-write-a-blog.md +``` + +### File headers +Functionally, the post should support categories, archives, title, date, brief description, thus the file headers should be as below. +``` +--- +title: ... +date: yyyy-mm-dd +tags: + - aaaa + - bbbb + - cccc +archives: yyyy-mm +author: name of author +summary: ... +--- +``` + +### Including resources + +At some point, you’ll want to include images, downloads, or other digital assets along with your text content. + +You can put the resources in the same folder as your text file's, and name the resources as +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +Where the YEAR, MONTH, DAY, and title are the same as your blog file, and NN is the serial number of the pictures, like 01, 02 and so on. The MARKUP is the file extension, and for pictures it is recommended to use png. +The following are one example. +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +Then, from within any post, they can be linked to using the site’s root as the path for the asset to include. Here are some simple examples in Markdown: + +Including images in a post: +``` +...Use the html tag,and enter relative path of the image as src attribute. + +``` + +Linking to a PDF for readers to download: +``` +... +Use the html tag,and enter relative path of the file as href attribute. +The file will be downloaded once the link is clicked. +get the PDF. +``` +Linking to a url for readers to visit: +``` +... you can [read more](). +``` + +## Thanks +The content above refered to . diff --git a/web-ui/docs/ru/interaction/post-news/README.md b/web-ui/docs/ru/interaction/post-news/README.md new file mode 100644 index 0000000000000000000000000000000000000000..caef4a12876a9c9f791a1c2106da80efd5be5ce5 --- /dev/null +++ b/web-ui/docs/ru/interaction/post-news/README.md @@ -0,0 +1,172 @@ +--- +title: "Guidance to Post a News" + +--- + + + + +
+ +## 准备 + +1. 参考 http://git.mydoc.io/?t=179267 注册Gitee账号。 + +2. 在Gitee个人设置中设置主邮箱地址,在此https://gitee.com/profile/emails。 + +3. 签署贡献者协议,https://www.openeuler.org/zh/other/cla。 + +4. 参考http://git.mydoc.io/?t=180692准备你的git环境 + +## 理解新闻格式 + +openEuler是用markdown格式写新闻的。 +请阅读该文章 来理解openEuler新闻是如何设计的。 + +文件头需要包含如下信息: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - theme +banner: img/banners/banner-2020hdc.png +author: openEuler +sig: sig-xxx +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your news. +``` + +小提示:你可以复制 https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post.md 到你的工作路径下然后继续编辑。 + +## 提交新闻 + +新闻的提交利用了Gitee的PR(Pull Request)。 + +1. Fork openEuler 新闻项目 到你自己的Gitee上。如果需要具体指导请参考 。 + +2. Clone代码 + +``` +git clone https://gitee.com//website-v2 +``` + +3. 创建分支 + +``` +git checkout -b +``` + +4. 创建工作路径 + +如果你发表中文新闻,工作路径是 web-ui/docs/zh/news 。 +假设你要写一个英文新闻: + +``` +cd web-ui/docs/en/news +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +你可以以你的md文档名来命名你的资源文件,方便使用。例如: +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +其中,YEAR, MONTH, DAY, 和 title 和你的新闻md文件名一致。NN 是01、02、03这样的序号。MARKUP文件扩展名。如下例子: +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +使用HTML \ 标签嵌入图片, 但你的图片资源需要放入当前目录下(即your-gitee-id目录下),输入图片名称作为 src 值: +``` + +``` + +1. Commit 你的新闻 + +``` +git add +git commit -m "" +git push origin : +``` + +2. 参考 提交你的PR + +3. 等待评审和合入。 + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01.png b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post.md b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1bb635ce0f8af793b1ce09b57d8a5d5e597aa0 --- /dev/null +++ b/web-ui/docs/ru/interaction/post-news/news_example/2020-03-03-sample-post.md @@ -0,0 +1,85 @@ +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: A-Tune +banner: img/news/20201225/poster.png +archives: 2020-03 +author: openEuler news Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +## HTML Elements + +Below is just about everything you'll need to style in the news. + +# Heading 1 + +## Heading 2 + +### Heading 3 + +#### Heading 4 + +##### Heading 5 + +### Body text + +This news is about bla bla. **This is strong**. + +![openEuler is open](./2020-03-03-sample-post-01.png) +### Quotation + +> The sites that have been chosen are listed and described next to each work, with encapsulating quotes or pieces of text narrating central themes for the groups. + +## List Types + +### Ordered Lists + +1. Item one + 1. sub item one + 2. sub item two + 3. sub item three +2. Item two + +### Unordered Lists + +* Item one +* Item two +* Item three + +## Tables + +| Header1 | Header2 | Header3 | +|:--------|:-------:|--------:| +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|---- +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|===== +| Foot1 | Foot2 | Foot3 +{: rules="groups"} + +## Code + +``` +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; +``` + +## Attachment + +Download the file here download: +[get the PNG](![The architecture]() +) directly. diff --git a/web-ui/docs/ru/interaction/salon-list/README.md b/web-ui/docs/ru/interaction/salon-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ba505246ebde63970ef1b9f25a487c6667d08788 --- /dev/null +++ b/web-ui/docs/ru/interaction/salon-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Meetups" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/salon-list/detail/README.md b/web-ui/docs/ru/interaction/salon-list/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fc36b9f0e7dce00d89b87a7dc17f843278c916e2 --- /dev/null +++ b/web-ui/docs/ru/interaction/salon-list/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "Meetups Detail" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/summit-list/README.md b/web-ui/docs/ru/interaction/summit-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8a8f7713d70486758874d0149d3341978f2f512a --- /dev/null +++ b/web-ui/docs/ru/interaction/summit-list/README.md @@ -0,0 +1,7 @@ +--- +title: "Summit" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/summit-list/devday2021/README.md b/web-ui/docs/ru/interaction/summit-list/devday2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..93d427f5b35f2fc44b4292eb01114e745fe2262c --- /dev/null +++ b/web-ui/docs/ru/interaction/summit-list/devday2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/summit-list/devday2022/README.md b/web-ui/docs/ru/interaction/summit-list/devday2022/README.md new file mode 100644 index 0000000000000000000000000000000000000000..88d19760d9da30c24fd47848003074ed59de4e27 --- /dev/null +++ b/web-ui/docs/ru/interaction/summit-list/devday2022/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2022" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/summit-list/list/README.md b/web-ui/docs/ru/interaction/summit-list/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d9216617de0f393d37fe302bc23e414917993e3d --- /dev/null +++ b/web-ui/docs/ru/interaction/summit-list/list/README.md @@ -0,0 +1,7 @@ +--- +title: "Summit" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/interaction/summit-list/summit2021/README.md b/web-ui/docs/ru/interaction/summit-list/summit2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1d9d1ad9ef1d5c6d03167f760be3cb6cdebe4e9a --- /dev/null +++ b/web-ui/docs/ru/interaction/summit-list/summit2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Summit 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/learn/mooc/README.md b/web-ui/docs/ru/learn/mooc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..de3d35ce616771cfa39d30740dca6663fa00c1ae --- /dev/null +++ b/web-ui/docs/ru/learn/mooc/README.md @@ -0,0 +1,6 @@ +--- +title: "МООК" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/learn/mooc/detail/README.md b/web-ui/docs/ru/learn/mooc/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..80a5e254bb1942479635af4027922bc78e3cc63b --- /dev/null +++ b/web-ui/docs/ru/learn/mooc/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "МООК" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/mirror/list/README.md b/web-ui/docs/ru/mirror/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9b6cacc7c347a78d0464260e5e1800518b5551ac --- /dev/null +++ b/web-ui/docs/ru/mirror/list/README.md @@ -0,0 +1,6 @@ +--- +title: "Mirrors" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/mirror/select/README.md b/web-ui/docs/ru/mirror/select/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8512551d387279e2417c5bb8c19993ffc04aff93 --- /dev/null +++ b/web-ui/docs/ru/mirror/select/README.md @@ -0,0 +1,6 @@ +--- +title: "Selected Mirrors" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/brand/README.md b/web-ui/docs/ru/other/brand/README.md new file mode 100644 index 0000000000000000000000000000000000000000..22626af5dcddefcd8c30fac62f9c201dc3b622c3 --- /dev/null +++ b/web-ui/docs/ru/other/brand/README.md @@ -0,0 +1,7 @@ +--- +title: "TradeMark" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/legal/README.md b/web-ui/docs/ru/other/legal/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c740f2949739c99bdafa7669415b574fc34fc65a --- /dev/null +++ b/web-ui/docs/ru/other/legal/README.md @@ -0,0 +1,40 @@ +--- +title: "Правовое уведомление" +--- + + + +
+ +В этом правовом уведомлении собраны правовые политики, применимые в отношении сообщества openEuler. Данные политики регулируют размещаемые сообществом openEuler рабочие версии и контент данного веб-сайта. + +## Условия доступа к веб-сайту сообщества openEuler + + управляется сообществом openEuler. Следующие правила применяются ко всем посетителям данного веб-сайта. Сообщество openEuler имеет право в любое время без предварительного уведомления пересмотреть данные условия в соответствии с законами, нормативами и изменениями на рынке. Сообщество openEuler предоставляет доступ к данному веб-сайту в соответствии с условиями, приведенными в настоящем Уведомлении. Если вы не примете данные условия, вы не сможете использовать данный веб-сайт. Посещая, просматривая данный веб-сайт или используя его и предлагаемые на нем услуги, вы подтверждаете, что принимаете все условия, содержащиеся в данном Уведомлении. В случае любого нарушения этих условий сообщество openEuler оставляет за собой право изыскать любые доступные по закону и в соответствии с нормами справедливости средства правовой защиты против таких нарушений. + +## Заявление об отсутствии гарантий + +Несмотря на то, что сообщество openEuler прилагает усилия, чтобы предоставляемая на этом веб-сайте информация, включая, в том числе, текст, фотографии, данные, мнения, рекомендации, адреса веб-страниц и ссылок, была точной, сообщество openEuler не несет ответственности за точность, полноту, компетентность и надежность такой информации, а также ее некорректность или потерю. Сообщество openEuler отказывается от всех явно выраженных или подразумеваемых гарантий, включая, помимо прочего, гарантии обладания правом собственности на информацию, гарантии ее качества и отсутствия вирусов на веб-сайте. Сообщество openEuler может изменять размещаемую на данном веб-сайте информацию в любое время без предварительного уведомления. Для получения актуальной информации о версиях вы должны периодически посещать этот веб-сайт. Упоминание продуктов или услуг других сообществ, не имеющих отношение к openEuler, носит исключительно информационный характер и не является рекомендацией или положительным заключением в пользу их приобретения. Сообщество openEuler не предоставляет никаких заявлений и гарантий на любые продукты или услуги, информация о которых появляется на веб-сайте, или утвердительных решений в их отношении. Сервис BBS на этом веб-сайте, в том числе, помимо прочего, имена пользователей, названия компаний, контактные данные, фотографии и другая информация предоставляются участниками сообщества, которые несут полную ответственность за такую информацию. Располагая сведениями о том, что контент данного веб-сайта (в том числе, помимо прочего, информация о товарах, размещенная на этом веб-сайте участниками сообщества) нарушает законные права или интересы, любая организация или любое физическое лицо должны уведомить об этом сообщество openEuler в письменной форме, отправив по адресу идентификационные данные, свидетельство о праве собственности, соответствующую ссылку (URL-адрес) и доказательства нарушения. Получив вышеуказанную законную информацию, сообщество openEuler удалит контент, связанный с предполагаемым нарушением закона. + +## Заявление об авторском праве + +Все содержащиеся на данном веб-сайте материалы и контент защищены законом. В отсутствии иных указаний все авторские права принадлежат сообществу openEuler. Без предварительного письменного согласия сообщества openEuler или других сторон настоящего Уведомления запрещается тиражировать, распространять, копировать или рассылать любую часть такой информации, получать доступ к ней или передавать ее через гиперссылки, выгружать на любые другие серверы, хранить в любых информационных поисковых системах или использовать, применяя любые средства по любым другим причинам, кроме загрузки и распечатки пользователями в некоммерческих целях (при условии, что упомянутая загруженная или распечатанная информация не будет изменена, и будет сохранено упоминание об авторских или любых других имущественных правах). + +## Товарный знак + +Все используемые на этом веб-сайте логотипы и товарные знаки являются собственностью сообщества openEuler или других указанных третьих лиц, если это применимо. Размещенные на веб-сайте сообщества openEuler материалы не должны рассматриваться как предоставленное разрешение или право использовать любой такой товарный знак или логотип косвенным путем, в силу отсутствия возражений или по другой причине без предварительного письменного согласия сообщества openEuler или любого третьего лица, которое может владеть данным товарным знаком. Запрещается кому-либо использовать название, товарный знак или логотип сообщества openEuler без предварительного письменного согласия последнего. + +## Ссылки на сторонние веб-сайты + +Данный веб-сайт может содержать ссылки на сторонние веб-сайты. Риск, связанный с доступом к любому другому веб-сайту, ссылка на который имеется на данном веб-сайте, лежит на пользователе, и сообщество openEuler не несет ответственности за точность, полноту, компетентность и надежность любой информации, данных, мнений, изображений, рекомендаций или заявлений, содержащихся на таких веб-сайтах. Сообщество openEuler приводит эти ссылки исключительно ради удобства и их включение в контент не рассматривается как рекомендация или положительное мнение в отношении содержащейся по этим ссылкам информации, а также не означает, что сообщество продвигает или рекламирует соответствующие товары и услуги. + +## Применимое законодательство и урегулирование споров + +Доступ к данному веб-сайту и все совершаемые на нем или посредством него действия регулируются и толкуются в соответствии с законодательством Китайской Народной Республики. Вы соглашаетесь с тем, что любой спор между сторонами, который может возникнуть в связи с данным правовым уведомлением или в связи с вашим доступом к данному веб-сайту и всеми совершаемыми на нем или посредством него действиями, регулируется судом Шэньчжэня провинции Гуандун, Китайская Народная Республика. + +
diff --git a/web-ui/docs/ru/other/lifecycle/README.md b/web-ui/docs/ru/other/lifecycle/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c76a0cee75994e604e7bce0271c729bf4f92d896 --- /dev/null +++ b/web-ui/docs/ru/other/lifecycle/README.md @@ -0,0 +1,20 @@ +--- +title : "Жизненный цикл релизов openEuler" +--- + +
+ +## Жизненный цикл + + +Релизам openEuler присваиваются имена по номеру издания в соответствии с годом и месяцем выпуска. Например, релиз openEuler 20.09 был выпущен в сентябре 2020 года. + +Релизы сообщества классифицируются на релиз с долгосрочной поддержкой (LTS) и инновационный релиз. + +- **Релиз LTS**. Данный релиз выпускается каждые 2 года, а поддержку сообщество предоставляет в течение 4 лет, начиная с даты выпуска. Первый релиз LTS сообщества openEuler 20.03 был официально выпущен в марте 2020 года. + +- **Инновационный релиз сообщества.** Данный релиз выпускается каждые 6 месяцев между двумя релизами LTS, а поддержку сообщество предоставляет в течение 6 месяцев, начиная с даты выпуска. Следующий релиз будет выпущен в сентябрь 2021 года. + +![](./lifecycle.png) + +
\ No newline at end of file diff --git a/web-ui/docs/ru/other/lifecycle/lifecycle.png b/web-ui/docs/ru/other/lifecycle/lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..fc528e96e4a1c77584f931b270901fe3c0a124f2 Binary files /dev/null and b/web-ui/docs/ru/other/lifecycle/lifecycle.png differ diff --git a/web-ui/docs/ru/other/privacy/README.md b/web-ui/docs/ru/other/privacy/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9e17e19932b1d01b534fab57db032b163adfbd18 --- /dev/null +++ b/web-ui/docs/ru/other/privacy/README.md @@ -0,0 +1,74 @@ +--- +title: "Конфиденциальность" +--- + + + +
+ +Сообщество openEuler понимает важность сохранения конфиденциальности ваших данных и соблюдает ее. **Внимательно прочтите настоящее Уведомление о конфиденциальности сообщества openEuler («Уведомление»), прежде чем отправите нам свои персональные данные.**Если у вас возникли вопросы о том, как мы обрабатываем ваши персональные данные, свяжитесь с нами. Если не указано иное, «мы» и «наш» в настоящем Уведомлении относятся к сообществу openEuler. + +## 1.Использование файлов cookie и похожих технологий + +**a)** Для обеспечения надлежащей работы веб-сайта мы иногда можем разместить файлы cookie на вашем компьютере или мобильном устройстве. Файл cookie — это небольшой массив данных, размещаемый на вашем компьютере или мобильном устройстве при доступе к веб-сайту. Содержимое файла cookie может извлечь и прочитать только сервер, создавший этот файл cookie. Файлы cookie служат различным целям. Например, они помогают нам понять, как используется веб-сайт, помогают вам эффективно просматривать страницы, помнят ваши предпочтения и улучшают опыт просмотра веб-сайта.
+**b)** Мы используем два типа файлов cookie:
+**  1)** Обязательные файлы cookie: используются для входа и верификации. Когда вы выполняете вход на веб-сайт с помощью вашего аккаунта HUAWEI, файлы cookie улучшают ваш опыт просмотра веб-сайта.
+**  2)** Файлы cookie для статистического анализа: мы собираем информацию об использовании наших сервисов, включая единичные или повторные посещения, которые помогут нам понять, как работают и используются сервисы. Мы используем плагин для статистического анализа, предоставляемый Baidu.
+  Многие сервисы требуют использования файлов cookie. Если вы не разрешите использование файлов cookie, относящихся к этим сервисам, вы не сможете использовать эти сервисы или некоторые функции этих сервисов.
+**c)** Функция «Не отслеживать». У большинства веб-браузеров есть функция «Не отслеживать», которая отправляет сигналы «Не отслеживать» на веб-сайты. В настоящее время участники ведущих организаций по стандартизации Интернета не пришли к согласию по поводу того, какие действия должны предпринимать веб-сайты, когда получают такие сигналы. Если вы активируете функцию Не отслеживать или другие аналогичные функции в вашем браузере, мы не изменим способы сбора и использования ваших данных, описанные в настоящем Уведомлении. Однако мы оставляем за собой право ответить на ваш запрос Не отслеживать и прекратить сбор ваших данных без предварительного уведомления.
+**d)** (d)Ваш выбор. Большинство браузеров позволяют удалить или отклонить файлы cookie. Для этого следуйте инструкциям в настройках браузера. По умолчанию многие браузеры принимают файлы cookie, пока вы не измените свои настройки. + +## 2.Передача ваших персональных данных + +Передача означает предоставление третьим лицам ваших персональных данных. Третьи лица и мы будем обрабатывать персональные данные независимо. Мы не передаем ваши персональные данные третьим лицам без вашего согласия, за исключением следующих обстоятельств или согласно положениям настоящего Уведомления:
+**a) Передача по вашему требованию**. Мы можем передать ваши персональные данные с вашего согласия и по вашему требованию третьим сторонам, указанным вами.
+**b) В целях соблюдения требований, предотвращения мошенничества и обеспечения безопасности**. Мы можем передавать ваши персональные данные в целях соблюдения требований, предотвращения мошенничества и обеспечения безопасности.
+**c) Аффилированные лица**Мы можем передать ваши персональные данные своим аффилированным лицам для поддержки проведения транзакций, работы сервисов или безопасности.
+**d) Партнеры**. Мы можем передавать ваши персональные данные своим партнерам. Однако мы будем передавать ваши персональные данные только в законных, оправданных, необходимых, указанных и явно выраженных целях, а также передавать персональные данные только в объеме, необходимом для предоставления наших сервисов. В число наших партнеров могут входить следующие лица:
+**  1) Разработчики, платформы и социальные сети**. Некоторые продукты или сервисы могут напрямую предоставляться вам третьими лицами. В этом случае мы должны предоставить им информацию о транзакциях. Если вы связываете наши сервисы или продукты со сторонними платформами или социальными сетями (например, выполняете прямой вход через веб-сайт третьего лица, виртуальный вход или связанный вход), мы можем раскрывать ваши персональные данные с вашего разрешения. Мы не контролируем использование ваших персональных данных третьим лицом.
+**  2) Поставщики услуг или профессиональные обслуживающие организации**(2). Мы можем передавать ваши персональные данные сторонним компаниям и физическим лицам, которые предоставляют сервисы от нашего имени или помогают нам управлять веб-сайтом и сервисами (такие как поставки, инфраструктура, хостинг, поддержка клиентов, маркетинг и аналитика, а также сервисы обработки данных). Мы передаем такие данные только в целях, соответствующих настоящему Уведомлению, или при вашем разрешении. Мы можем раскрывать ваши персональные данные профессиональным консультантам, например аудиторам, страховщикам, банковским сотрудникам и юристам, где это необходимо при оказании нам профессиональных услуг.
+Когда мы передаем ваши персональные данные связанным компаниям или партнерам, их обязанности будут регулироваться договорами, и мы потребуем от них принять соответствующие меры для обеспечения безопасности обработанных персональных данных. + +## 3.Срок хранения ваших персональных данных + +Мы будем хранить ваши персональные данные не дольше, чем это необходимо, в целях, изложенных в настоящем Уведомлении, если иное не требуется законом или вашим запросом. +Мы будем хранить ваши персональные данные в течение периода хранения в соответствии с применимыми законами или сервисными соглашениями с даты получения ваших персональных данных в сообществе openEuler. Если срок хранения ваших персональных данных превысил лимит и ни один закон не требует от нас продолжать обработку ваших конкретных персональных данных, мы удалим или анонимизируем их в соответствии с применимыми законами. + +## 4.Защита ваших персональных данных + +Мы серьезно относимся к безопасности ваших личных данных. Мы принимаем соответствующие физические, организационные и технические меры для защиты ваших персональных данных. Например, мы используем технологии шифрования для обеспечения конфиденциальности данных, а также внедряем механизмы для защиты данных от атак. Мы используем механизмы контроля посещений, которые предоставляют доступ к персональным данным только авторизованному персоналу. Кроме того, мы проводим тренинги по вопросам безопасности и защиты конфиденциальности.** Таким образом, мы привержены защите ваших персональных данных. Несмотря на это, никакая защита не может быть идеальной, никакие продукты, услуги, веб-сайты, вычислительные системы, механизмы передачи данных и сети не могут быть надежными на 100%.** + +## 5.Доступ и контроль ваших персональных данных + +В соответствии с применимыми законами и правилами у вас есть следующие права в отношении ваших персональных данных:
+**a)** Получать доступ к персональным данным, которые есть у нас о вас, и получать их копии; 
+**b)** Запрашивать обновление или исправление ваших персональных данных;
+**c)** Запрашивать удаление ваших персональных данных;
+**d)** Возражать против обработки ваших персональных данных;
+**e)** Запретить обработку ваших персональных данных;
+**f)** Подать жалобу в компетентный орган по защите данных.
+Обратите внимание, что эти права не являются абсолютными и могут быть ограничены в соответствии с применимыми законами. Если вам нужна наша помощь в выполнении вышеупомянутых запросов или осуществлении прав, свяжитесь с нами согласно информации в разделе «Контакты» ниже.
+**Как правило, мы отвечаем в течение одного месяца, если иное не требуется применимым законодательством. В зависимости от сложности ваших запросов мы можем продлить срок еще на два месяца. В этом случае мы сообщим вам о продлении и причинах в течение одного месяца с момента получения вашего запроса.**Обратите внимание, что при некоторых обстоятельствах, например, если мы не можем подтвердить вашу личность или ваша заявка выходит за рамки ваших прав согласно применимому законодательству, мы можем отказать в выполнении вашей заявки. В этом случае мы сообщим вам в письменной форме, что ваша заявка отклонена, и укажем причины отклонения.
+Вы можете изменить объем разрешения на сбор ваших персональных данных или отозвать ваше разрешение. Однако ваше решение отозвать свое согласие или разрешение не влияет на предыдущую обработку персональных данных, выполненную на основании вашего разрешения. + +## 6.Место хранения персональных данных + +Мы предоставляем вам продукты и сервисы через наши глобальные ресурсы и серверы. Ваши персональные данные, собранные нами, могут храниться в странах или регионах, в которых расположены мы, наши аффилированные лица, поставщики услуг и субподрядчики. Это означает, что ваши персональные данные могут быть переданы другим юрисдикциям за пределами страны или региона, где находится продукт или сервис, которые вы используете, или к ним может быть получен доступ из этих юрисдикций.
+Юрисдикции, в которых хранятся такие персональные данные, могут иметь законы, которые защищают персональную информацию в различной степени, или могут не иметь законов о защите персональных данных. Мы обеспечим, чтобы ваши персональные данные были защищены применимыми законами и правилами, а также положениями настоящего Уведомления. + +## 7.Обновления текста Уведомления + +Мы можем время от времени обновлять или изменять настоящее Уведомление в соответствии с изменениями в наших сервисах или обработке данных. Если мы обновим настоящее Уведомление, мы опубликуем его последнюю версию на веб-сайте, и оно вступит в силу сразу же после его публикации. Рекомендуем вам периодически проверять настоящее Уведомление на предмет изменений. Если мы внесем существенные изменения в настоящее Уведомление (любые изменения в отношении персональных данных, которые мы собираем или используем), мы уведомим вас по соответствующим каналам связи и получим ваше согласие. + +## 8.Контакты + +Если вы хотите связаться с нами или осуществить свои права, свяжитесь с нами по ****. + +

Обновлено: июнь 2021 г. + +
\ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/atune/README.md b/web-ui/docs/ru/other/projects/atune/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b32c575cb8fd67bb4926ac5466282876a9dff191 --- /dev/null +++ b/web-ui/docs/ru/other/projects/atune/README.md @@ -0,0 +1,6 @@ +--- +title: "A-Tune" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/bishengjdk/README.md b/web-ui/docs/ru/other/projects/bishengjdk/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ac9151010fea5cd78348ed154baf3a4728cc3231 --- /dev/null +++ b/web-ui/docs/ru/other/projects/bishengjdk/README.md @@ -0,0 +1,6 @@ +--- +title: "BiSheng JDK" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/bishengjdk/tck-affidavit/README.md b/web-ui/docs/ru/other/projects/bishengjdk/tck-affidavit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8f741c9dca1db6a218ff7bc5baedb52bd7f28f92 --- /dev/null +++ b/web-ui/docs/ru/other/projects/bishengjdk/tck-affidavit/README.md @@ -0,0 +1,22 @@ +--- +title: "BiSheng JDK" +--- + +
+ +# Huawei BiSheng Statement of Java SE Compatibility + + All Huawei BiSheng(JDK 8) binaries available from have passed all requirements of the then-current Java SE 8 Compatibility test suite(JCK tests), and are compliant and compatible implementations. + +
+ + \ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/isula/README.md b/web-ui/docs/ru/other/projects/isula/README.md new file mode 100644 index 0000000000000000000000000000000000000000..303f5a64312ea876a3987aa89b03919aec2880f8 --- /dev/null +++ b/web-ui/docs/ru/other/projects/isula/README.md @@ -0,0 +1,6 @@ +--- +title: "iSula" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/secgear/README.md b/web-ui/docs/ru/other/projects/secgear/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6f9ac611eacf3a1010fc5dfa5a8fe67c6075c721 --- /dev/null +++ b/web-ui/docs/ru/other/projects/secgear/README.md @@ -0,0 +1,6 @@ +--- +title: "secgear" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/projects/stratovirt/README.md b/web-ui/docs/ru/other/projects/stratovirt/README.md new file mode 100644 index 0000000000000000000000000000000000000000..13e1c7f3bd30f84aa90386a77a123de3ae8deade --- /dev/null +++ b/web-ui/docs/ru/other/projects/stratovirt/README.md @@ -0,0 +1,6 @@ +--- +title: "StratoVirt" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/other/search/README.md b/web-ui/docs/ru/other/search/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a95664566b6ec3822223f0ee81b3800b8b880c3e --- /dev/null +++ b/web-ui/docs/ru/other/search/README.md @@ -0,0 +1,6 @@ +--- +title: "Search" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/security/cve/README.md b/web-ui/docs/ru/security/cve/README.md new file mode 100644 index 0000000000000000000000000000000000000000..101def4754bd28297bf62f40542b3ec4de6ac4fe --- /dev/null +++ b/web-ui/docs/ru/security/cve/README.md @@ -0,0 +1,7 @@ +--- +title: "CVE" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/security/cve/detail.md b/web-ui/docs/ru/security/cve/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..607af6015c823fceecf8c2e0dea2c348448b6faa --- /dev/null +++ b/web-ui/docs/ru/security/cve/detail.md @@ -0,0 +1,7 @@ +--- +title: "Security-cveDetail" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/security/safety-bulletin/README.md b/web-ui/docs/ru/security/safety-bulletin/README.md new file mode 100644 index 0000000000000000000000000000000000000000..06fe465a3b3308a5c2a27d8a9b5c007892630941 --- /dev/null +++ b/web-ui/docs/ru/security/safety-bulletin/README.md @@ -0,0 +1,7 @@ +--- +title: "Security advisories" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/security/safety-bulletin/detail.md b/web-ui/docs/ru/security/safety-bulletin/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..7d2187467ade7b46d5866b3ec5d44ac67f3a74f7 --- /dev/null +++ b/web-ui/docs/ru/security/safety-bulletin/detail.md @@ -0,0 +1,7 @@ +--- +title: "Security-bulletinDetail" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/security/vulnerability-reporting/README.md b/web-ui/docs/ru/security/vulnerability-reporting/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fdc61e68a942f2d7508617ad682623d064497a32 --- /dev/null +++ b/web-ui/docs/ru/security/vulnerability-reporting/README.md @@ -0,0 +1,144 @@ +--- +title: "Управление уязвимостями" + +--- + + + + +
+ +## Меры по устранению уязвимостей +Сообщество openEuler придает большое значение вопросу безопасности выпускаемых версий. Комитет по безопасности openEuler выполняет функции приема информации о уязвимостях в системе безопасности сообщества, их изучения и раскрытия данной информации. Разработчикам и отраслевым организациям, занимающимся выявлением и устранением уязвимостей, рекомендуется сообщать о потенциальных проблемах в системе безопасности openEuler в комитет по безопасности. Комитет оперативно проанализирует и решит проблемы безопасности и устранит возникшие уязвимости. + +## Поддерживаемые версии + +Процесс принятия мер в ответ на уязвимости предусматривает использованием LTS-дистрибутивов сообщества openEuler и его веток. + +## Процесс обнаружения и устранения уязвимостей + +За отслеживание и устранение каждой уязвимости в системе безопасности отвечает отдельно назначенное лицо. Являясь членом комитета по безопасности сообщества openEuler, данный специалист отслеживает возникающие уязвимости, принимает меры для их устранения и передает информацию остальным участникам. На следующей блок-схеме показан комплексный процесс обнаружения и устранения уязвимостей. + + + + + + + + +## Сообщение об уязвимостях + +Сообщество openEuler полагается на вашу готовность сообщать о потенциальных уязвимостях, обнаруженных в продукте openEuler, а также вашу помощь сообществу в их устранении и раскрытии информации. + +### Способ передачи отчета об уязвимостях + +Вы можете отправлять информацию о потенциальных уязвимостях, найденных в продукте openEuler, по электронной почте группы специалистов по безопасности openEuler (). Учитывая, что информация об уязвимостях является конфиденциальной, рекомендуется для шифрования электронных сообщений использовать открытый PGP-ключ данной группы. Информация о включенных в группу безопасности сотрудниках: + ++ Лю Цзиньган (Liu Jingang) \[@liujingang09], , открытый PGP-ключ ++ Ян Ли (Yang Li) \[@yangli69393], ++ Янь Сяобин (Yan Xiaobing) \[@yanxiaobing2020], , открытый PGP-ключ ++ Чжу Цзяньвэй (Zhu Jianwei) \[@zhujianwei001], , открытый PGP-ключ ++ Вэй Ган (Wei Gang) \[@gwei3], <11015100@qq.com>, открытый PGP-ключ ++ Го Сяоци (Guo Xiaoqi) \[@guoxiaoqi], , открытый PGP-ключ ++ Ян Лицзинь (Yang Lijin) \[@jinjin], + +### Содержание отчетов + +Для оперативного выявления и проверки потенциальных уязвимостей отправляемый по электронной почте отчет должен содержать в том числе следующую информацию: + ++ Основная информация: модули, подверженные влиянию уязвимости, условия ее возникновения и масштаб влияния на систему после ее использования. ++ Технические детали: конфигурация системы, метод обнаружения проблемы, описание эксплойта, POC-код, а также метод и процедура воспроизведения сценария проблемы. ++ Предложения по устранению уязвимости. ++ Организация и контактная информация лица, сообщившего об уязвимости. ++ Возможный план по раскрытию информации об уязвимости, предложенный сообщившим лицом. + +### Ответ по электронной почте + +Сообщество обязуется ответить на сообщения о потенциальных уязвимостях в системе безопасности по электронной почте в течение 48 часов и в дальнейшем информировать сообщившее лицо о ходе выполнения работ по устранению уязвимостей. + +## Оценка степени серьезности уязвимости + +Для оценки степени уязвимости в отрасли широко применяется система общей оценки уязвимости (Common Vulnerability Scoring System; CVSS). В настоящее время для оценки уязвимостей openEuler использует CVSS версии v3, и получаемая таким образом оценка акцентируется на степени влияния, которое оказывает уязвимость в спланированном сценарии атаки. Оценка степени уязвимости охватывает такие факторы, как сложность вредоносного кода и последствия его влияния на конфиденциальность, целостность и доступность продукта. Балл подсчитывается после оценки этих факторов. + +### Критерии оценки + +В системе CVSS версии v3, принятой сообществом openEuler, оцениваются последствия уязвимости на основе следующих переменных: + ++ Вектор атаки (Attack vector; AV): определяет удаленность атаки и способ применения данной уязвимости. ++ Сложность атаки (Attack complexity; АС): описывает сложность атаки и условия для успешного ее применения. ++ Взаимодействие с пользователем (User interaction; UI): данный критерий определяет вовлечение пользователей в атаку. ++ Требуемые полномочия (Permission required; PR): уровень полномочий пользователя, необходимый для успешной атаки. ++ Область действия (Scope; S): данный критерий определяет вероятность воздействия атаки на компоненты с различными уровнями разрешений. ++ Конфиденциальность (Confidentiality; С): данный критерий измеряет степень влияния несанкционированного раскрытия информации. ++ Целостность (Integrity; I): данный критерий измеряет степень влияния незаконного искажения информации. ++ Доступность (Availability; A): данный критерий измеряет степень влияния уязвимости на доступ к данным или предоставляемые пользователям услуги. + +### Принципы оценки + ++ Принцип заключается в оценке степени серьезности уязвимости, а не риска ее возникновения. ++ Оценка должна учитывать сценарий, в котором атака затрагивает конфиденциальность, целостность и доступность системы. ++ Если уязвимость в системе безопасности реализуется посредством нескольких сценариев, то в оценке будет превалировать сценарий атаки с наивысшим баллом CVSS (т.е. с наибольшей степенью влияния). ++ Если во встроенной или вызванной библиотеке есть уязвимости, оценка степени серьезности уязвимости должна основываться на сценарии атаки, который определяется уровнем загруженности библиотеки в продукте. ++ Если уязвимость в системе безопасности не инициирует процедуру устранения и не влияет на конфиденциальность, целостность и доступность (confidentiality/integrity/availability; CIA), то балл по CVSS-системе равен 0. + +### Процедура оценки + +Для оценки уязвимости необходимо выполнить следующую процедуру: + ++ Определите возможный сценарий выполнения атаки и подсчитайте балл на его основе. ++ Определите уязвимые компоненты и затронутые проблемой компоненты. ++ Выберите значение базового индикатора оценки и проведите оценку степени влияния уязвимости на основе критериев масштаба ее распространения (вектор атаки, сложность атаки, требуемые полномочия, взаимодействие с пользователем и область действия) и показателей масштаба затронутых областей (конфиденциальность, целостность и доступность). + +### Оценка степени серьезности + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Severity RatingScore
Critical9.0 - 10.0
High7.0 - 8.9
Medium4.0 - 6.9
Low0.1 - 3.9
None0.0
+### Оценка различий между Национальной базой данных уязвимостей и CVSS + +Оценка CVSS определяется рядом факторов, включая номер версии затронутого компонента и способ его предоставления и использования, а также метод компиляции платформы и программного обеспечения. При оценке посредством Национальной базы данных уязвимостей (NVD) учитываются все сценарии, в которых применяются вредоносные коды. Этот способ оценки не подходит сообществу openEuler разработчиков ПО с открытым исходным кодом, деятельность которого построена на деятельности вышестоящего сообщества, и применяется, в основном, в серверных сценариях. В результате, openEuler оценивает все общеизвестные уязвимости информационной безопасности (Common Vulnerabilities and Exposures; CVE) на основе степени их воздействия. Баллы, полученные в результате оценки openEuler и методом NVD, могут отличаться. + +## Раскрытие информации об уязвимостях + +В целях обеспечения безопасности пользователей продуктов openEuler сообщество openEuler не будет обсуждать и подтверждать проблемы с безопасностью любого продукта openEuler, а также раскрывать информацию о таких проблемах, пока данная уязвимость не будет изучена и устранена и пока не будет опубликовано соответствующее уведомление о безопасности. Устранив уязвимость, сообщество openEuler выпустит уведомление о безопасности, которое будет содержать в том числе такую информацию, как технические детали, идентификатор CVE, оценку безопасности CVSS и уровень серьезности уязвимости, а также версии, затронутые уязвимостью, и исправленные версии. Вы можете подписаться на получение уведомлений о безопасности от сообщества openEuler на странице sa-announce.Предоставляем также уведомления о безопасности в формате CVRF, которые можно получить по ссылке [Документация CVRF](https://repo.openeuler.org/security/data/cvrf/). + +
+ diff --git a/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru)-mobile.png b/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru)-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..567bad7fe404d07c1e7ef3cfee5c68a88a339e8f Binary files /dev/null and b/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru)-mobile.png differ diff --git a/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru).png b/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru).png new file mode 100644 index 0000000000000000000000000000000000000000..257ee7e9383572a26cd69b7e0366494e354acfc0 Binary files /dev/null and b/web-ui/docs/ru/security/vulnerability-reporting/procedure(ru).png differ diff --git a/web-ui/docs/ru/sig/role-description/README.md b/web-ui/docs/ru/sig/role-description/README.md new file mode 100644 index 0000000000000000000000000000000000000000..db37e3d47ac5748c00458fc96c531b0d824c5ace --- /dev/null +++ b/web-ui/docs/ru/sig/role-description/README.md @@ -0,0 +1,108 @@ +--- +title: "Characters" + +--- + + + +
+ + +*Description*:The permissions of Maintainer and Committer are the same on Gitee, and the difference lies in the scope of SIG governance. The detailed informationes are described below. + +## New Contributor + +Welcome to join the community. Start contributing by referring to [contribution guidience](/en/contributors/README.md). + + +## Existing Community Member + + +Existing community members should follow the principles in this article and be familiar with SIG's organization, roles, policies, software, and etc. At the same time, they should have corresponding technical and writing skills. The detailed informatione of responsibilities and requirements of the community member are described below. + + +## Contributor +Contributors are people who frequently contribute to the community. They take part in SIG group activities, resolve questions, review PR, and complete tests before submitting the PR. + + +### Requirement + ++ Registered member on Gitee ++ Contribute to SIG or community in many ways, including but not limited to: + + Submitting or reviewing PR(Pull Request) on Gitee + + Documenting or commenting issues on Gitee + + Participating in SIG or community discussions ++ Read [Contribution Guideline](/en/contributors/README.md) ++ Join one or more SIGs + +### Responsibility and Power + ++ Respond to assigned issues and PR(Pull Request) ++ Contributed code should satisfy the criteria described below + + Well tested + + Passing the test correctly and completely + + Resolving subsequent errors or problems ++ Agree PR by executing '/ lgtm' ++ Assign issue or PR, ask memebers to comment by execting`/assign @username` ++ Run PR test automatically. `/ok-to-test` is not necessary ++ Operate the PR with `needs-ok-to-test` label by execting `/ok-to-test` and close PR by execting `/close`. + +**Note**: Contributors should actively take part in code review and if they'd like to help more, strive to be a *Committer* of SIG. + +## Committer + +Committers can review the quality and correctness of code in SIG or some parts of SIG. Committers should have a good knowledge of code repository and software engineering principles. + +**Definition**:*developer* entry in the OWNERS file owned by each SIG. + +### Requirement + ++ Have worked in openEuler for At least 3 months as contributors ++ Participated in at least 6 PR reviews as the main reviewer ++ Review or merge at least 30 PR into the code repo ++ Being Familiar with code repo ++ Can be self-nominated or nominated by the committers or maintainer of the SIG + +### Responsibility and Privilege + ++ **Review PR**:Review the PR submitted by contributor. The review can refer to [编程建议]() and [安全编程规范](). ++ **Distribute and deal with problems**:Please refer to [问题处理流程]() . ++ **Tracking dependency issues**:In the development branch, software package's dependencies in the SIG may be broken due to the software package updates in other SIG. At this time, the Committer will receive an alert. Then, the committer should try to rebuild the software package. Because dependency problem may prevent users from updating the system, the build team will also participates in rebuilding packages that have dependency issues, but the Maintainer should not rely on these works. ++ **Notify SIG that may be affected due to interface changes**:Because other SIGs or projects rely on software package of this SIG, changes to the package interface may affect them. Maintainer should review the dependency impact caused by decision changes. Then Maintainer should announce and send alert emails of API or ABI changes. +Those work should be completed at least one week before the change occurs, and all SIGs that may be affected should be notified. For detailed informationes please refer to [接口变更通知流程](). ++ **Update and maintain package version**:Follow the startegy of [软件包更新质量控制策略]() and complete the package update. ++ **Collaborate with upstream community**, including: + + Push all changes to upstream community + + Participate in upstream community mailing list + + Get the account of the Bug Tracker of the upstream community, and track the important bugs of the upstream community + + Push serious errors to upstream community for help + For further information, please refer to [上游社区软件包管理建议]() ++ **Collaborate with test team** including: + + When you submit the software packages, the information how to debug and classify the packages should be provided to QA for problem classification + + Provide basic functional test cases for regression testing + + When you update the software package, the test cases related to fixed problems in the update package should be provided to QA + + +## Maintainer + +Maintainer is the leader of SIG group or member of management Committee, and also the maintainer of software package. They can review and approve code like committers. The key of code review is the code quality and correctness, while the approvals focus on overall acceptance of contributions. **Maintainer has all the responsibility and privilege of Committer** . In addition, Maintainer is also need to work out technical roadmap and undertake coordination within and outside the team. + +**Definition**:*developer* entry in the OWNERS file owned by openEuler SIG. + +### Requirement + ++ At least 3 months as committer ++ Participated in at least 12 PR reviews as the main reviewer ++ Review or merge at least 30 basic PR into the code repo ++ Being familiar with code repo ++ Could be self-nominated or nominated by sub-project Maintainer, and there is no objection from other sub-project Maintainers. + +### Responsibility and Power + +- **Work out technical roadmap for SIG project**:Including planning the SIG technical direction, roadmap, solution of software architecture evolution +- **Prepare release plan for SIG project**: Make key requirements and release plans for project;Participate in community PM activities and coordinate SIG initiatives to match community release milestone schedules +- **Participate in community coordination activities**:As a representative of SIG, Maintainer should attend the meetings and activites organized by Technical committee or the Community Council +- **Organize SIG meetings**:Regularly organize SIG meetings and make decisions on contentious issues within SIG + +
+ diff --git a/web-ui/docs/ru/sig/sig-guidance/README.md b/web-ui/docs/ru/sig/sig-guidance/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fcf4877417591c45b3ce174430dfbf7d22114967 --- /dev/null +++ b/web-ui/docs/ru/sig/sig-guidance/README.md @@ -0,0 +1,7 @@ +--- +title: "Application" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/sig/sig-list/README.md b/web-ui/docs/ru/sig/sig-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7852c258b8d968ec1e5d748de0e1025c94165d93 --- /dev/null +++ b/web-ui/docs/ru/sig/sig-list/README.md @@ -0,0 +1,7 @@ +--- +title: "SIG lists" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/ru/sig/sig-list/sig-detail.md b/web-ui/docs/ru/sig/sig-list/sig-detail.md new file mode 100644 index 0000000000000000000000000000000000000000..d706bb14e38b653641aad73351ded41bb631c791 --- /dev/null +++ b/web-ui/docs/ru/sig/sig-list/sig-detail.md @@ -0,0 +1,7 @@ +--- +title: "SIG" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/README.md b/web-ui/docs/zh/README.md new file mode 100644 index 0000000000000000000000000000000000000000..bd15820edc6145843ece16e68ad11eeed612095c --- /dev/null +++ b/web-ui/docs/zh/README.md @@ -0,0 +1,6 @@ +--- +title: "openEuler" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/activities/README.md b/web-ui/docs/zh/activities/README.md new file mode 100644 index 0000000000000000000000000000000000000000..edd773e9947ca675129adb59c6e0420df9550b67 --- /dev/null +++ b/web-ui/docs/zh/activities/README.md @@ -0,0 +1,7 @@ +--- +title: "Summer Activities" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/activities/happynewyear2022/README.md b/web-ui/docs/zh/activities/happynewyear2022/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e799ebbe9f339556228b5524630653b01d422928 --- /dev/null +++ b/web-ui/docs/zh/activities/happynewyear2022/README.md @@ -0,0 +1,12 @@ +--- +title: "happynewyear2022" +--- + + + + \ No newline at end of file diff --git a/web-ui/docs/zh/approve/README.md b/web-ui/docs/zh/approve/README.md new file mode 100644 index 0000000000000000000000000000000000000000..61ca8981e3e743f702eb540730e4dd6ea04ac547 --- /dev/null +++ b/web-ui/docs/zh/approve/README.md @@ -0,0 +1,6 @@ +--- +title: "Approve" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/approve/approve-info/README.md b/web-ui/docs/zh/approve/approve-info/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d9ac6061265886d498c9f4b45c2b832fa93328df --- /dev/null +++ b/web-ui/docs/zh/approve/approve-info/README.md @@ -0,0 +1,6 @@ +--- +title: "ApproveInfo" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/approve/approve-step/README.md b/web-ui/docs/zh/approve/approve-step/README.md new file mode 100644 index 0000000000000000000000000000000000000000..bf7e05edb6a25519d91efe2769b0bc5799a17edc --- /dev/null +++ b/web-ui/docs/zh/approve/approve-step/README.md @@ -0,0 +1,6 @@ +--- +title: "ApproveStep" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/blog/Benshuai5D/2021-06-10-build-bishengJDK-rpm-package.md b/web-ui/docs/zh/blog/Benshuai5D/2021-06-10-build-bishengJDK-rpm-package.md new file mode 100644 index 0000000000000000000000000000000000000000..36e8b909ad5d76a2eb834d7455c7dbea79a7688e --- /dev/null +++ b/web-ui/docs/zh/blog/Benshuai5D/2021-06-10-build-bishengJDK-rpm-package.md @@ -0,0 +1,507 @@ +--- +title: Build bishengJDK-rpm package +date: 2021-06-06 +tags: + - bishengJDK + - build rpm package +archives: 2021-06 +author: Benshuai5D +summary: Just about everything you'll need to build bishengJDK-rpm package +--- + +# 从0到1构建bishengJDK-rpm包(基于openeuler和树莓派) + +bishengJDK是Huawei内部OpenJDK定制版Huawei JDK的开源版本,是一个高性能、可用于生产环境的OpenJDK发行版。HuaweiJDK运行在华为内部500多个产品上,HuaweiJDK团队积累了丰富的开发经验,解决了业务实际运行中遇到的多个问题,并在ARM架构上进行了性能优化,毕昇JDK运行在大数据等场景下可以获得更好的性能。 + +RPM软件包管理器(RPM)是在Red Hat Enterprise Linux,CentOS和Fedora上运行的软件包管理系统,RPM可以更轻松地分发,管理和更新为Red Hat Enterprise Linux,CentOS和Fedora创建的软件。将软件打包到RPM软件包中有如下优点:安装、重新安装、删除、升级和验证软件包、将原始软件源打包为源包和二进制包、将软件包添加到Yum repositories、对packages进行数字签名等 + +本文通过两部分,分别在装有openEuler系统的虚拟机及装有openEuler系统的树莓派中对openjdk-1.8.0对rpm包构建过程进行解析。 + +## 一、基于openEuler的bishengJDK-rpm包构建过程解析 + +### 1、openEuler系统安装 + +#### openEuler系统镜像文件下载 + +openEuler是一款开源操作系统。当前openEuler内核源于Linux,支持鲲鹏及其它多种处理器,能够充分释放计算芯片的潜能,是由全球开源贡献者构建的高效、稳定、安全的开源操作系统,适用于数据库、大数据、云计算、人工智能等应用场景。同时,openEuler是一个面向全球的操作系统开源社区,通过社区合作,打造创新平台,构建支持多处理器架构、统一和开放的操作系统,推动软硬件应用生态繁荣发展。 + +进入openeuler官网选择所需版本进行下载,这里选择openEuler 20.03 LTS,openEuler 20.03 LTS版的生命周期为四年,是一种标准发行版,可以满足开放方案的要求 + +image-openEuler-version + +选择好对应版本后点击Download,在版本Download界面选择ISO/进行镜像文件的下载,ISO文件为光盘的镜像文件,刻录软件可以直接把ISO文件刻录成可安装的系统光盘,ISO文件一般以iso为扩展名 + +image-openEuler-20.03-LTS + +在ISO/界面选择版本的所要下载的系统,openEuler 20.03 LTS的ISO下载列表有提供AArch64架构的ISO、x86_64架构的ISO及openEuler源码ISO,这里选择x86_64架构的ISO + +image-openEuler-ISO + +在/openEuler-20.3-LTS/ISO/x86_64/界面按照需求下载对应的ISO文件,这里下载openEuler-20.03-LTS-x86_64-dvd.iso + +image-openEuler-x86_64 + +#### 新建虚拟机 + +通过VMware Workstation软件或者Oracle VM软件新建虚拟机,使用的ISO映像文件为下载的openEuler-20.03-LTS-x86_64-dvd.iso文件 + +image-VMware + +可在 openEuler INSTALLATION SUMMARY界面按需进行相关安装设置,如Keyboard、Language Support、Time&Date、Installation Destination等 + +image-INSTALLATION SUMMARY + +在“INSTALLATION SUMMARY”页面中选择“Installation Destination”,按需设置操作系统的安装磁盘及分区 + +image-INSTALLATION Destination + +对虚拟机的Root用户Password进行设置,root帐户是尝用来执行关键系统管理任务,不建议在日常工作及系统访问时使用root帐户 + +image-CONFIGURATION + +image-reroot + +#### 创建用户 + +``` +useradd zhangsan //创建个人用户 +passwd zhangsan //修改个人密码 +su - zhangsan //切换至个人用户 +``` + +image-newuser + +用户设置的root用户密码或新创建用户的密码均需要满足密码复杂度要求,否则会导致密码设置或用户创建失败。设置密码的复杂度的要求如下:口令长度至少8个字符、口令至少包含大写字母、小写字母、数字和特殊字符中的任意3种、口令不能和账号一样、口令不能使用字典词汇 + +#### 连接远程网络工具MobaXterm + +MobaXterm是进行远程计算的工具箱,MobaXterm专注于一个简单的目标:提供一个直观的用户界面,可以通过不同的网络或系统有效地访问远程服务器,虚拟机创建配置完成后,就可通过远程网络工具MobaXterm进行完成连接,虚拟机的IP地址由创建虚拟机后分配产生 + +image-MobaXterm + +通过IP地址及用户名密码对openEuler虚拟机进行远程连接 + +image-MobaXterm-SSH + +### 2、安装依赖及源文件下载 + +#### rpm构建工具包安装 + +`yum install rpm-build rpm-devel rpmdevtools` + +image-rpmbuildtools + +查看软件包所提供的打包RPM的实用程序:`rpm -ql rpmdevtools | grep bin` `rpm -ql rpm-devel | grep bin` `rpm -ql rpm-build | grep bin` + +image-rpm -ql rpm-devel + +其中rpmdev-setuptree:创建构造rpm打包空间的目录布局、rpmdev-newspec:创建一个未填充的SPEC文件、rpmbuild:从SPEC文件创建实际的rpm软件包、rpmspec:用于规格查询已解析输出的新命令 + +#### 生成rpmbuild目录及相关子目录 + +进入个人文件夹下执行`rpmdev-setuptree`自动生成rpmbuild目录及相关子目录 + +image-rpmdev-setuptree + +生成的rpmbuild目录及相关子目录如下图,BUILD目录:构建软件包时,`%buildroot`将在此处创建各种目录。如果日志输出未提供足够的信息,这对于调查失败的构建很有用,RPMS目录:在不同体系结构的子目录中创建二进制RPM,例如在子目录`x86_64`和中`noarch`,SOURCES:在这里放置压缩的源代码存档和补丁,该`rpmbuild`命令在此处查找,SPECS:存放SPECS文件,SRPMS:当`rpmbuild`用于构建SRPM而不是二进制RPM时,将在此处创建结果SRPM + +image-rpmdev-setuptree-filelist + +#### 源码包及spec文件准备 + +在/rpmbuild/SOURCES/文件夹下,进行需要构建rpm包的jdkSource文件下载`git clone https://gitee.com/src-openeuler/openjdk-1.8.0.git ` (若要构建其他版本jdk,则更换url即可),该openjdk的url:https://gitee.com/src-openeuler/openjdk-1.8.0 + +.image-git clone jdk source + +将下载的jdk文件中的.spec文件移动到SPECS目录下`mv ./openjdk-1.8.0/*spec ../SPECS/` + +image-spec-preapare + +image-spec-preaparelist + +将余下的jdk文件中的其他文件移动至SOURCE文件夹下`mv ./openjdk-1.8.0/* ./` + +image-source-prepare + +image-source-preparelist + +#### jdk8安装及配置 + +可通过`yum list | grep openjdk`查看openEuler附带的yum源内可安装的jdk版本,并进行安装,若没有所需jdk,则需要另行安装或者更新yum源 + +image-yum list grep openjdk + +安装命令:`yum install java-1.8.0-openjdk.x86_64` + +检查jdk是否安装成功`java -version` + +image-java -version + +Openjdk各个yum源所提供的版本如下: + +https://repo.openeuler.org/openEuler-20.03-LTS/OS/x86_64/Packages/ + +image-openEuler-21.03-os + +https://repo.openeuler.org/openEuler-20.03-LTS/everything/x86_64/Packages/ + +image-openEuler-everything + +https://repo.openeuler.org/openEuler-21.03/everything/x86_64/Packages/ + +image-openEuler-everything-jdk11 + +#### 安装依赖 + + `yum install alsa-lib-devel cups-devel elfutils-devel fontconfig-devel freetype-devel giflib-devel harfbuzz-devel lcms2-devel nss-devel` + +image-reliant package + +若后续还存在其他依赖未安装,则使用`yum install package`进行安装即可 + +### 3、rpm包构建 + +进入SPECS文件夹下,按需输入对应指令即可进行构建 + +``` +rpmbuild -bi java-1.8.0-openjdk.spec //执行到install阶段 +rpmbuild -bb java-1.8.0-openjdk.spec //生成rpm二进制包 +rpmbuild -bs java-1.8.0-openjdk.spec //生成rpm源码包 +rpmbuild -ba java-1.8.0-openjdk.spec //生成rpm二进制包和源码包 +``` + +完成rpm包构建 + +image-successful result + +文件列表 + +tree + +### 4、常见报错及解决方案 + +#### There are no enabled repositories in "/etc/yum.repos.d" + +image-there are no enabled repositories + +解决方法: + +`cd /etc/yum.repos.d` + +`vi openEuler_x86_64.repo` (若为arrch64系统则为`vi openEuler_aarch64.repo`) + +添加内容: + +``` +#generic-repos is licensed under the Mulan PSL v2. +#You can use this software according to the terms and conditions of the Mulan PSL v2. +#You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +#THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +#PURPOSE. +#See the Mulan PSL v2 for more details. + +[OS] +name=OS +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler + +[everything] +name=everything +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/everything/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/everything/$basearch/RPM-GPG-KEY-openEuler + +[EPOL] +name=EPOL +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/EPOL/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler + +[debuginfo] +name=debuginfo +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/debuginfo/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/debuginfo/$basearch/RPM-GPG-KEY-openEuler + +[source] +name=source +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/source/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/source/RPM-GPG-KEY-openEuler + +[update] +name=update +baseurl=http://repo.openeuler.org/openEuler-20.03-LTS/update/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=http://repo.openeuler.org/openEuler-20.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler +``` + +该yum源来自于码云,链接如下: + +#### Failed build dependencies: packages is needed by java-1.8.0-openjdk-1:1.8.0.282.b08-17.x86_64 + +image-packages is needed by java-1.8.0-openjdk + +问题原因:specs文件中构建rpm包所需相应包未进行安装 + +解决方法:通过`yum install packages`对对应包进行安装 + +`yum install gdb java-1.8.0-openjdk-devel libX11-devel libXext-devel libXi-devel libXinerama-devel libXrender-devel libXt-devel libXtst-devel libjpeg-devel openssl-devel` + +image-yum install packages + +#### error:java-8-openjdk-devel is is needed by xxx + +报错原因:spec文件中BuildRequires要求了openjdk-devel,当前安装的openjdk版本未满足要求 + +解决方法:若确定安装openjdk版本可以满足构建需求,则可将该行要求注释掉或者修改版本要求,若不确定当前版本是否满足构建需求,则可安装配置其要求的openjdk版本 + +image-java-8-openjdk-devel is needed by xxx + +#### error:tzdate-java>=2020a is needed by xxx + +报错原因:spec文件中BuildRequires要求了tzdate-java的版本,当前安装的版本未满足要求 + +解决办法:若确定安装tzdate-java版本可以满足构建需求,则可将该行要求注释掉或者修改版本要求,若不确定当前版本是否满足构建需求,则可安装配置其要求的版本 + +image-tzdate-java + +#### error:Bad exit status from /var/tmp/rpm-tem.f4PLQX(%build) + +原因:jdk8已经在系统配置完成,但是下载的spec文件还未进行修改,需进入spec文件把jdk的路径修改为本地jdk-8的路径 + +`vim /root/rpmbuild/SPECS/java-1.8.0-openjdk.spec` +`?configure` 找到configure配置位置,将jdk的路径改为自己本地安装的jdk8的路径 + +image-Bad exit status from + +### 5、其他jdk版本rpm包构建 + +其他jdk版本,如果jdk11、jdk15等rpm包构建仅需要在源码包处下载对应版本的jdk源码包,更换对应的url,后续的jdk路径改成相应的jdk路径即可,其他构建过程与jdk8的rpm包构建相同,如有报错等信息都可参考jdk8的rpm包的构建过程 + +## 二、openEuler系统树莓派rpm包构建过程解析 + +### 1、openEuler系统iso镜像安装 + +#### 安装要求 + +在树莓派环境上安装 openEuler 操作系统,则树莓派需要满足如下的硬件兼容性和最小硬件要求:树莓派版本3B、3B+、4B,内存:为了获得更好的应用体验,建议至少 4GB,硬盘:为了获得更好的应用体验,建议至少8GB,树莓派官网https://www.raspberrypi.org/,openEuler社区网站https://www.openeuler.org/en/download/ + +#### 获取安装源 + +获取openEuler 发布的树莓派镜像及其校验文件,登陆openEuler社区网站https://www.openeuler.org/en/download/,单击卡片 openEuler 20.03 LTS SP1 上的“download”按钮 + +image-get iso + +单击“raspi_img”,进入树莓派镜像的下载列表 + +image-get rasp_img + +单击“openEuler-20.03-LTS-SP1-raspi-aarch64.img.xz”,将 openEuler 发布的树莓派镜像下载到本地 + +image-get img + +#### 格式化SD卡 + +下载并安装格式化SD卡工具,以下操作以DiskGenius磁盘格式化工具为例 + +选中需要格式化的SD卡的对应盘符,删除内容并保存 + +image-formatting SD card + +选中刚刚删除内容并保存的磁盘,建立新分区,文件系统类型选择FAT32,并保存格式化 + +image-save the formatting + +格式化后的磁盘如图所示 + +image-the success of formatting + +#### 镜像文件写入SD卡 + +下载并安装刷写镜像的工具,以下操作以 Win32 Disk Imager 工具为例 + +镜像文件选择镜像文件下载路径下的openEuler-20.03-LTS-SP1-raspi-aarch64.img,设备选择SD卡的盘符后点击写入即可 + +image-write iso in SD card + +说明:镜像文件写入后,会显示SD卡的磁盘容量减少,原因为Windows下认不出ext文件系统,为正常现象 + +#### 启动系统 + +将写入镜像后的 SD 卡插入树莓派,通电启用 + +#### 登陆系统 + +登录树莓派有以下两种方式:本地登陆和ssh远程登陆 + +本地登陆:树莓派连接显示器、键盘、鼠标后,启动树莓派,可以看到树莓派启动日志输出到显示器上。待树莓派启动成功,输入用户名(root)和密码(openeuler)登录 + +ssh远程登陆:如果树莓派连接已知路由器,可登录路由器查看,新增的 IP 即为树莓派 IP,或者通过IP扫描工具来将树莓派IP进行扫描获取,这里以advanced_ip_scanner为例 + +image-log in system + +例如,树莓派对应 IP 为:192.168.1.9,则可以使用远程网络工具MobaXterm进行访问,MobaXterm专注于一个简单的目标:提供一个直观的用户界面,可以通过不同的网络或系统有效地访问远程服务器 + +image-use the moba log + +远程访问成功,输入用户名(root)和密码(openeuler)登录,通过MobaXterm远程网络访问工具访问树莓派openEuler系统界面如下 + +image-the success of log + +### 2、树莓派openEuler安装yum + +进入系统,进行yum进行包及依赖安装,会提示`-bash:yum:command not found` + +image-yum command not found + +需要自动手动安装下载`yum-4.2.23-3.oe1.noarch.rpm`并上传 + +URL:https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm,在同目录下执行`rpm -ivh --force --nodeps yum-4.2.23-3.oe1.noarch.rpm` + +image-yum rpm + +### 3、安装依赖及源文件下载 + +#### rpm构建工具包安装 + +`yum install rpm-build rpm-devel rpmdevtools` + +image-rpmbuildtools + +#### 生成rpmbuild目录及相关子目录 + +进入个人文件夹下执行`rpmdev-setuptree`自动生成rpmbuild目录及相关子目录 + +image-repdev-setuptree + +生成的rpmbuild目录及相关子目录如下图,BUILD目录:构建软件包时,`%buildroot`将在此处创建各种目录。如果日志输出未提供足够的信息,这对于调查失败的构建很有用,RPMS目录:在不同体系结构的子目录中创建二进制RPM,例如在子目录`x86_64`和中`noarch`,SOURCES:在这里放置压缩的源代码存档和补丁,该`rpmbuild`命令在此处查找,SPECS:存放SPECS文件,SRPMS:当`rpmbuild`用于构建SRPM而不是二进制RPM时,将在此处创建结果SRPM + +image-success of setuptree + +#### 源码包及spec文件准备 + +在/rpmbuild/SOURCES/文件夹下,进行需要构建rpm包的jdkSource文件下载`git clone https://gitee.com/src-openeuler/openjdk-1.8.0.git ` (若要构建其他版本jdk,则更换url即可),该openjdk的url:https://gitee.com/src-openeuler/openjdk-1.8.0 + +image-prepare the src package + +将下载的jdk文件中的.spec文件移动到SPECS目录下`mv ./openjdk-1.8.0/*spec ../SPECS/` + +image-the first of command + +image-the result of move the spec + +将余下的jdk文件中的其他文件移动至SOURCE文件夹下`mv ./openjdk-1.8.0/* ./` + +image-the result of move the everything + +#### jdk8安装及配置 + +可通过`yum list | grep openjdk`查看openEuler附带的yum源内可安装的jdk版本,并进行安装,若没有所需jdk,则需要另行安装或者更新yum源 + +yum openjdk rasp + +安装命令:`yum install java-1.8.0-openjdk.aarch64` + +检查jdk是否安装成功`java -version` + +#### 安装依赖 + +`yum install alsa-lib-devel cups-devel elfutils-devel fontconfig-devel freetype-devel giflib-devel harfbuzz-devel lcms2-devel` + +image-yum install reliant package + +若后续还存在其他依赖未安装,则使用`yum install package`进行安装即可 + +### 4、rpm包构建 + +进入SPECS文件夹下,按需输入对应指令即可进行构建 + +`rpmbuild -bi java-1.8.0-openjdk.spec `执行到install阶段 +`rpmbuild -bb java-1.8.0-openjdk.spec`生成rpm二进制包 +`rpmbuild -bs java-1.8.0-openjdk.spec `生成rpm源码包 +`rpmbuild -ba java-1.8.0-openjdk.spec `生成rpm二进制包和源码包 + +完成rpm包构建图如下 + +raspberry success + +文件列表如下: + +tree + +### 5、常见问题及解决方案 + +#### 树莓派无法使用远程连接: + +SSH连接,需要确认的是:①树莓派有没有连接网络、②使用软件时,填写的IP、用户名和密码是否正确、③有没有打开SSH,若确认已经连接到网络并且ip用户名和密码都正确,依旧无法正确使用远程连接,则为SSH未开启 + +解决方案:外界显示器情况下,可连接到系统显示界面情况下:检查安装系统时是否已经安装SSH服务端软件包`rpm -qa|grep openssh`若显示结果中包含`openssh-server-`,则说明已经安装,直接启动sshd服务就可以了`service iptables start` + +images-openssh + +未外界显示器,无法连接到系统显示界面:SD卡内,新建ssh文件(无后缀),即可开启远程访问 + +.image-ssh + +#### -bash:yum:command not found + +使用yum指令,会提示`-bash:yum:command not found` + +yum command not found + +需要自动手动安装下载`yum-4.2.23-3.oe1.noarch.rpm`并上传 + +URL:https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/aarch64/Packages/yum-4.2.23-3.oe1.noarch.rpm,在同目录下执行`rpm -ivh --force --nodeps yum-4.2.23-3.oe1.noarch.rpm` + +yum rpm + +#### Failed build dependencies: xxx is needed by java-1.8.0-openjdk-1:1.8.0.282.b08-17.aarch64 + +failed build dependencied + +问题原因:specs文件中构建rpm包所需相应包未进行安装 + +解决方法:通过`yum install xxx`对对应包进行安装 + +`yum install gdb java-1.8.0-openjdk-devel libX11-devel libXext-devel libXi-devel libXinerama-devel libXrender-devel libXt-devel libXtst-devel libjpeg-devel openssl-devel` + +#### error:java-8-openjdk-devel is needed by xxx + +报错原因:spec文件中BuildRequires要求了openjdk-devel,当前安装的openjdk版本未满足要求 + +解决方法:若确定安装openjdk版本可以满足构建需求,则可将该行要求注释掉或者修改版本要求,若不确定当前版本是否满足构建需求,则可安装配置其要求的openjdk版本 + +image-java-8-openjdk-devel is needed by xxx + +#### error:Bad exit status from /var/tmp/rpm-tem.f4PLQX(%build) + +原因:jdk8已经在系统配置完成,但是下载的.spec文件还未进行修改,需进入.spec文件把jdk的路径修改为本地jdk-8的路径 + +`vim /root/rpmbuild/SPECS/java-1.8.0-openjdk.spec` +`?configure` 找到configure配置位置,将jdk的路径改为自己本地安装的jdk8的路径 + +image-Bad exit status from + +### 5、其他jdk版本rpm包构建 + +其他jdk版本,如果jdk11、jdk15等rpm包构建仅需要在源码包处下载对应版本的jdk源码包,更换对应的url,后续的jdk路径改成相应的jdk路径即可,其他构建过程与jdk8的rpm包构建相同,如有报错等信息都可参考jdk8的rpm包的构建过程 + +## References + +How to create an RPM package:https://fedoraproject.org/wiki/How_to_create_an_RPM_package/zh-cn#.25files_.E9.83.A8.E5.88.86 + +RPM Packaging Guide:https://rpm-packaging-guide.github.io/ + +bishengJDK 8 user guide:https://gitee.com/openeuler/bishengjdk-8/wikis/Home?sort_id=2879418 + +Raspberry pi:https://www.raspberrypi.org/ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.1.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.1.png new file mode 100644 index 0000000000000000000000000000000000000000..667ad6ad917f863e588492336d2aae71b455d927 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.1.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.10.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.10.png new file mode 100644 index 0000000000000000000000000000000000000000..413b57f39fb3ad5131c15f6029cd30f8fed4932d Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.10.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.11.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.11.png new file mode 100644 index 0000000000000000000000000000000000000000..992ea79a7c4a51f11609c3808e8b01f46fd6c106 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.11.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.12.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.12.png new file mode 100644 index 0000000000000000000000000000000000000000..10e147ab64d85238a2f687f968fa050220814123 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.12.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.13.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.13.png new file mode 100644 index 0000000000000000000000000000000000000000..46861335a21b8b6df56aa01a3ea7b6c6e3f2907c Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.13.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.14.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.14.png new file mode 100644 index 0000000000000000000000000000000000000000..877c6a632a082d736016469ff84c92745d33cfc0 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.14.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.15.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.15.png new file mode 100644 index 0000000000000000000000000000000000000000..3dfb7d4b7727900c12eb3eedb9d70ae1333fb5f5 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.15.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.16.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.16.png new file mode 100644 index 0000000000000000000000000000000000000000..f20489059a82c6277289b750175a8447b1c7dfe0 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.16.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.17.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.17.png new file mode 100644 index 0000000000000000000000000000000000000000..815e1ef75ec9c529f7936100c403298ec25cb46b Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.17.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.18.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.18.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fc541a5b18b96698c56a3bbd3a01d1135466ec Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.18.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.19.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.19.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6acb32853e3f135b764388feecdd1e34b8f677 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.19.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.2.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.2.png new file mode 100644 index 0000000000000000000000000000000000000000..6855b0fc972765056cef22b4aa25750f44ad201c Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.2.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.20.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.20.png new file mode 100644 index 0000000000000000000000000000000000000000..e36730395d7754c72a9cc8b64920affe062fb62f Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.20.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.21.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.21.png new file mode 100644 index 0000000000000000000000000000000000000000..bac4ad1e99c41c70a2892222ef9e0f2a109ae039 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.21.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.22.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.22.png new file mode 100644 index 0000000000000000000000000000000000000000..d7f637289e29fd7f1c4fc41b7684b0b7266970fd Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.22.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.23.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.23.png new file mode 100644 index 0000000000000000000000000000000000000000..30ae54b7df09c2712de11f56c03283c095b7b651 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.23.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.24.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.24.png new file mode 100644 index 0000000000000000000000000000000000000000..ed86288812897b1e2be9c07cfae5503d12774407 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.24.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.25.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.25.png new file mode 100644 index 0000000000000000000000000000000000000000..67174e7f8b03ccc8fba99ccfe463d24a6c6d0269 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.25.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.26.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.26.png new file mode 100644 index 0000000000000000000000000000000000000000..0a91822baf4959fcec1bf77a3b2abd370ef745be Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.26.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.27.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.27.png new file mode 100644 index 0000000000000000000000000000000000000000..703ab90c90f5ab30c3324fadf8f43bae8bef4a9e Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.27.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.3.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.3.png new file mode 100644 index 0000000000000000000000000000000000000000..ca43efdf55e87a75bfd0d2bcb121bc212e174410 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.3.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.4.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.4.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb864430b1ba266f8f82d4534d95662fdd000e7 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.4.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.5.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a6ea83ab393bebf9c7f702d8644a50f6e44e3b Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.5.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.6.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.6.png new file mode 100644 index 0000000000000000000000000000000000000000..eb29fe944eca2d206cbf3993497b21f20451ff9a Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.6.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.7.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.7.png new file mode 100644 index 0000000000000000000000000000000000000000..ca70446a31250eb14e11e7f553e48848dfc8e1d9 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.7.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.8.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.8.png new file mode 100644 index 0000000000000000000000000000000000000000..7627a618e1f07b655ced1701ff73f0e20bd568e8 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.8.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/1.9.png b/web-ui/docs/zh/blog/Benshuai5D/image/1.9.png new file mode 100644 index 0000000000000000000000000000000000000000..969306ad3ed75434c1f4499961af2a6b517648fe Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/1.9.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.1.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.1.png new file mode 100644 index 0000000000000000000000000000000000000000..e33005ff34151f79faccf233208d8d9f8557a561 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.1.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.10.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.10.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d55a106be8d98faa9f3029ab6a23fd9c58d154 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.10.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.11.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.11.png new file mode 100644 index 0000000000000000000000000000000000000000..0d13f545ee8c33959aa0e8d45bf98e480aa2567a Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.11.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.12.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.12.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc846123fb5ebabfd3f1190a378e8b5d9174277 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.12.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.13.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.13.png new file mode 100644 index 0000000000000000000000000000000000000000..8dfc945f734345f0ce50d0074ee6b0f6ee9826e0 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.13.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.14.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.14.png new file mode 100644 index 0000000000000000000000000000000000000000..2a2ee909dc2b88860721bd9ba43e4180b7246be9 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.14.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.15.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.15.png new file mode 100644 index 0000000000000000000000000000000000000000..596bd39002ae788d255f5521ef27d159d900171c Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.15.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.16.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.16.png new file mode 100644 index 0000000000000000000000000000000000000000..c16ce518b5a0d5c8d24fb7b2be611c6513697c51 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.16.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.17.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.17.png new file mode 100644 index 0000000000000000000000000000000000000000..105c01e8ff06c929303a429c60fd744c3e98fa16 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.17.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.18.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.18.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c5967fc8a7e44512cd85376440e71c7efac03d Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.18.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.19.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.19.png new file mode 100644 index 0000000000000000000000000000000000000000..50f4b02523b2769aa0f5d057eef9978248ed5d38 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.19.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.2.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.2.png new file mode 100644 index 0000000000000000000000000000000000000000..fdeb5e66f5f7a382329c98c921a37ffd3e745877 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.2.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.20.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.20.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d2e694e03419e8bd842bc3d6e961e454584a40 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.20.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.21.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.21.png new file mode 100644 index 0000000000000000000000000000000000000000..4252a54f55427c9ebe84389c8c24648541a7f6cc Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.21.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.22.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.22.png new file mode 100644 index 0000000000000000000000000000000000000000..c09dd71307f987e3c945c322fe44dcb090187986 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.22.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.23.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.23.png new file mode 100644 index 0000000000000000000000000000000000000000..c123fb6153d8604b2a7446dc653e4685a1588c1b Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.23.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.24.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.24.png new file mode 100644 index 0000000000000000000000000000000000000000..30b8185bf9c7d25dd5dc394a3859091366140fb4 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.24.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.25.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.25.png new file mode 100644 index 0000000000000000000000000000000000000000..08ea41b739b6bf269319009371fb3c4118f74202 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.25.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.26.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.26.png new file mode 100644 index 0000000000000000000000000000000000000000..35d46cd6dbe50fcaa948b35954ec331cdd0d120a Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.26.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.27.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.27.png new file mode 100644 index 0000000000000000000000000000000000000000..d4b10d248d4c59310cb651ffb2274f50a6fec981 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.27.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.28.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.28.png new file mode 100644 index 0000000000000000000000000000000000000000..40634a45ca9dbf7312803d818f1a5caabce287fe Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.28.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.29.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.29.png new file mode 100644 index 0000000000000000000000000000000000000000..4252a54f55427c9ebe84389c8c24648541a7f6cc Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.29.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.3.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.3.png new file mode 100644 index 0000000000000000000000000000000000000000..099a25fb18d057ab0a0585c0a9a5d2258f2aff34 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.3.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.30.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.30.png new file mode 100644 index 0000000000000000000000000000000000000000..f6cd4db5d952d6698b6e49abb2c48fa7e3c04934 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.30.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.31.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.31.png new file mode 100644 index 0000000000000000000000000000000000000000..f1510842fa5124ea602d640677f9404a3c17c4e2 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.31.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.32.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.32.png new file mode 100644 index 0000000000000000000000000000000000000000..8e791255cc612216e1ffac6f74fd336828c756b2 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.32.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.33.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.33.png new file mode 100644 index 0000000000000000000000000000000000000000..a0daf52d16492d79380d4bebf6d20372e43f934a Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.33.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.34.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.34.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe317e3d3a743416b57cfbfef5fd77682f1a466 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.34.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.35.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.35.png new file mode 100644 index 0000000000000000000000000000000000000000..0d13f545ee8c33959aa0e8d45bf98e480aa2567a Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.35.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.36.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.36.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc846123fb5ebabfd3f1190a378e8b5d9174277 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.36.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.37.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.37.png new file mode 100644 index 0000000000000000000000000000000000000000..d2063c545f4f1b6dd9cf5c5486f2fde5d4f9eff8 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.37.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.38.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.38.png new file mode 100644 index 0000000000000000000000000000000000000000..d812efca4b3a196cfb56fd92a83e4ccefc21787f Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.38.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.4.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.4.png new file mode 100644 index 0000000000000000000000000000000000000000..596afb8c93d837374762450632ef4e8526607513 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.4.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.5.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.5.png new file mode 100644 index 0000000000000000000000000000000000000000..11599fcda5430204ff8597cae625391d29b51c4b Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.5.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.6.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.6.png new file mode 100644 index 0000000000000000000000000000000000000000..31f06e172d27300f405c8e5209320dcefab81dd4 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.6.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.7.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.7.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4f73f1af8f0b6ea5f0d3993516396c711195ca Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.7.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.8.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.8.png new file mode 100644 index 0000000000000000000000000000000000000000..a61895105572e354e7036916dbdc0aaa826471b5 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.8.png differ diff --git a/web-ui/docs/zh/blog/Benshuai5D/image/2.9.png b/web-ui/docs/zh/blog/Benshuai5D/image/2.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1f79f9d93373ad0336cbebbdff2441642cad51a1 Binary files /dev/null and b/web-ui/docs/zh/blog/Benshuai5D/image/2.9.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-cli-main.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-cli-main.png new file mode 100644 index 0000000000000000000000000000000000000000..bc184dbf816ddfdf7824da9e475f7274892d0da7 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-cli-main.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-code-overview.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-code-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..23cae1615e2b0c1961e257572c0aeabb46a60ddc Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-code-overview.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-core.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-core.png new file mode 100644 index 0000000000000000000000000000000000000000..099bdfacb3d2bb66502f436a2de349a65b9cb840 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-core.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-daemon-main.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-daemon-main.png new file mode 100644 index 0000000000000000000000000000000000000000..e8376ee609fa92215e2b0370fbcb75328d67eb1a Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-daemon-main.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-folder-overview.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-folder-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..7562f45458d27a6392812552d6240aab5f9e5ee2 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-folder-overview.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-help-info.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-help-info.png new file mode 100644 index 0000000000000000000000000000000000000000..57f55db79c998940cdb5595da4b7f698a68e7ac4 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-help-info.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-isula-logo.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-isula-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a971e1365b25d7fe95f63f5c80111afa4edbca95 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-isula-logo.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-join-us.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-join-us.png new file mode 100644 index 0000000000000000000000000000000000000000..5f03e9b8c884c766a4b4016bd211e2bfbafd8167 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-join-us.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-make.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-make.png new file mode 100644 index 0000000000000000000000000000000000000000..21f576312f3ef1e3a0da21ff8b2a6d93d0ba4873 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-make.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-makefile.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-makefile.png new file mode 100644 index 0000000000000000000000000000000000000000..824f291b6f1b9ff599d3062d9b7492490f11a151 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-makefile.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-release.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-release.png new file mode 100644 index 0000000000000000000000000000000000000000..35718d9d241aa5bbfb95dc18c51267bf6a9fd361 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-release.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-struct-overview.png b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-struct-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..745986b5354b5038adabd85965891b263a2cac87 Binary files /dev/null and b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration-struct-overview.png differ diff --git a/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration.md b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration.md new file mode 100644 index 0000000000000000000000000000000000000000..128bff1cff0ce7d991e26f0a981dd7df213b30f7 --- /dev/null +++ b/web-ui/docs/zh/blog/DCCooper/2020-09-15-isula-build-code-exploration.md @@ -0,0 +1,152 @@ +--- +title: isula-build 源码剖析 +date: 2020-09-15 +tags: + - iSulad + - 容器 + - 镜像构建 +archives: 2020-09 +author: 李翔 +summary: 作为iSulad软件生态的一员,isula-build承载了镜像构建、管理、分发等多项功能 +--- + +在观看了前几期[容器镜像构建工具的使用和介绍](https://www.bilibili.com/video/BV1Gp4y1i7Rs)之后,你或许想去研究下这个工具的内部逻辑,或者想去给这个初生的小工具提一些建议或者改进,那么,你需要一个快速入手`isula-build`开源项目的方法,本期文章就来带你一起走进`isula-build`容器镜像构建工具的内部([视频链接](https://www.bilibili.com/video/BV1Ca4y177te))。话不多说,一起来看看吧。 + +## isula-build代码剖析 + +本期文章目标 + +1. 介绍isula-build是什么 + +2. 深入代码,搞懂你敲下的指令在做什么 + +3. 社区发布流程、如何参与isula-build社区 + +### isula-build 是什么 + +说起isula-build,就不得不提及`iSulad` + +![isula_build_code_exploration_isula_logo](./2020-09-15-isula-build-code-exploration-isula-logo.png) + +`iSulad`是华为自主研发的通用容器引擎,旨在统一的架构设计来满足 CT 和 IT 领域的不同需求。相比 Golang 编写的 Docker,轻量级容器具有**轻、灵、巧、快**的特点,不受硬件规格和架构的限制,底噪开销更小,可应用领域更为广泛。目前**已开源**(开源地址:https://gitee.com/openeuler/iSulad)。 + +作为`iSulad`生态的一员,`isula-build` 承载了镜像构建、管理、分发等功能。 + +### isula-build 能做什么 + +- 安全快速构建容器镜像、管理镜像 +- 与isulad、docker均可快速集成,部署方便 +- 镜像管理增删改查功能,麻雀虽小五脏俱全 +- 构成容器全栈解决方案 + +### isula-build 架构全景图 + +`isula-build`采用经典的 C-S 架构,分为客户端`isula-build`和服务端`isula-builder`,客户端和服务端使用`GRPC`通信。用户可通过`isula-build`命令行与服务端`isula-builder`进行交互,发起镜像构建、镜像管理等请求。 + +![isula_build_code_exploration_struct_overview](./2020-09-15-isula-build-code-exploration-struct-overview.png) + +### isula-build 代码全景图 + +isula-build使用`golang`作为开发语言,目前自研代码行数超过2w+ + +```bash +-------------------------------------------------------------------------------- +Language files blank comment code +-------------------------------------------------------------------------------- +Go 134 3293 2676 25038 +Markdown 9 486 0 1098 +Bourne Shell 15 95 225 499 +XML 9 0 0 419 +Protocol Buffers 2 41 97 193 +make 1 18 1 89 +Dockerfile 6 14 0 68 +Bourne Again Shell 1 8 4 31 +TOML 3 37 255 15 +JSON 1 0 0 8 +-------------------------------------------------------------------------------- +SUM: 181 3992 3258 27458 +-------------------------------------------------------------------------------- +``` + +进入isula-build项目,我们可以看到有一系列文件夹,分别承载了不同的功能和设计 + +![isula_build_code_exploration_code_overview](./2020-09-15-isula-build-code-exploration-code-overview.png) + +下图为一些文件夹的主要功能概述 + +![isula_build_code_exploration_folder_overview](./2020-09-15-isula-build-code-exploration-folder-overview.png) + +看到这里你可能已经懵逼了,如何快速的了解代码呢? + +### isula-build 代码解析 --- 编译 + +首先在我看来,如何最快了解一个项目的最快方法就是不要一开始就钻进代码里,而是先去`编译和运行`这个软件,然后通过将外在表象和内在逻辑一一对应的方法,来熟悉整个项目。 + +那么,如何运行isula-build?如果我们没有安装rpm包,那么就需要我们去手动编译二进制了,那目标就是找到`Makefile`,在其中查找蛛丝马迹。 + +我们看到了项目里有Makefile,那么里面肯定写了如何编译这个项目。我们打开文件,找到isula-build和isula-builder这两个二进制是在哪里编译的,就能找到代码最开始的地方,也就是我们即将进入的程序入口。 + +![isula_build_code_exploration_makefile](./2020-09-15-isula-build-code-exploration-makefile.png) + +那么,我们尝试着去编译一下,看看会发生什么 + +![isula_build_code_exploration_make](./2020-09-15-isula-build-code-exploration-make.png) + +我们发现,在isula-build/bin目录下,生成了两个二进制,那这两个二进制就是我们的成品啦,试着去运行下吧~ + +### isula-build 代码解析 --- 命令行入口 + +学过go语言的朋友都知道,每个二进制都是由`main.go`文件生成的,那么我们根据之前的isula-build代码全景图可以知道,`isula-build`的入口就在`cmd/cli/main.go`里面,而`isula-builder`的入口也就在对应的`cmd/daemon/main.go`里面啦。 + +![isula_build_code_exploration_cli_main](./2020-09-15-isula-build-code-exploration-cli-main.png)![isula_build_code_exploration_daemon_main](./2020-09-15-isula-build-code-exploration-daemon-main.png) + +试着敲敲`isula-build -h`和`isula-builder -h`帮助信息,看看都有什么吧! + +![isula_build_code_exploration_help_info](./2020-09-15-isula-build-code-exploration-help-info.png) + +### isula-build 代码解析 --- 外在表现和内部逻辑 + +那么,知道了程序入口,我们就好比拿到了开启宝藏的钥匙,那么,我们就以一条`构建容器镜像并将其保存为本地tar包`的命令来讲述代码的流程: + +> 例子:isula-build ctr-img build –f Dockerfile –o docker-archive:busybox.tar:busybox:latest . + + +![isula_build_code_exploration_core](./2020-09-15-isula-build-code-exploration-core.png) + +限于篇幅,上图为大家准备了小抄,可以方便快速的找到整个构建流程的每一处关键点位,大家可以参考上图的`S`形,按图索骥,找到对应的代码,并加以扩展 + +> 考考你:到目前为止,isula-build 有多少个二级子命令? + +### isula-build 社区开发 + +那么,在熟悉了isula-build代码框架之后,你是否已经跃跃欲试,想给我们的小工具提点建议或者改进的方向。那么,如何参与到开源社区的开发中呢? + +首先不得不说下我们代码开发和发布的流程 + +![isula_build_code_exploration_release](./2020-09-15-isula-build-code-exploration-release.png) + +上图概述了开发的整个流程。 + +如图所示,首先作为用户或者开发者的你会拿到我们发布的isula-build `rpm`包或者源码。在你的使用过程中,你会有一些问题不明白或者你想参与改进,你就需要去我们的[源码仓](https://gitee.com/openeuler/isula-build) `提交issue`。 + +那比如我发现,哦哟,小伙子不错哦,还真是个好的改进点,办它!那你的issue就进入了`issue accepted `阶段。我们会根据问题的紧急、难易程度等要素进行排期。 + +接下来,有热心群众就会去认领该issue并开始码代码,也就进入了`coding`阶段。本地代码写完之后,功能也测试完毕,你兴奋的点击了提交按钮。那么你的提交就会来到了代码仓的pull request中。这里存放着大家的奇思妙想~ + +那是不是就意味着你的代码可以直接合入了呢?当然不能啦!所有人提交的代码要经过严格的审核,这里包括大佬们(maintainer)肉眼的review和机器人(ci bot)无情的自动化用例检查,确保每一次合入都是OK的~ 经过了一系列的审查,大家都觉得你提交的代码又短小又精悍(#手动狗头),那么你的代码进可以合入`源码仓`啦。至此,所有在源码仓中的活动也就告一段落了。 + +你以为这就完了?你写的代码是如何变成一个rpm包让你使用简单的`yum install isula-build`就能装在你的电脑中并运行的呢?这里就涉及到我们的另一个仓库,[制品仓](https://gitee.com/src-openeuler/isula-build)。 + +制品仓中的isula-build代码会以tar包的形式存在,也就是`源码打包`,并伴随有相应的spec文件,进行`rpm 包构建`,最终集成到我们openEuler的`发布件`中一起发布。当然,你也可以单独获取我们的[rpm包](https://build.openeuler.org/package/show/openEuler:Mainline/isula-build) + +到这里,我们整体的isula-build代码架构和流程剖析就告一段落了,接下来,我们唯一需要的,就是屏幕前观看文章的你,加入我们,一起收获更多! + +![isula_build_code_exploration_join_us](./2020-09-15-isula-build-code-exploration-join-us.png) + +> isula-build 源码仓:https://gitee.com/openeuler/isula-build +> +> isula-build 制品仓:https://gitee.com/src-openeuler/isula-build +> +> isula-build obs地址:https://build.openeuler.org/package/show/openEuler:Mainline/isula-build + + diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-01.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-01.png new file mode 100644 index 0000000000000000000000000000000000000000..cf5d8b23d2e2844f6690d8ee52acb5c45716f76c Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-01.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-02.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-02.png new file mode 100644 index 0000000000000000000000000000000000000000..6f03b482efbd3d180fbf0ee2ff84b5c53a69f2bd Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-02.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-03.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-03.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfe1c4ea309f39f6ab3bcffb677e9a08041dbf Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-03.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-04.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-04.png new file mode 100644 index 0000000000000000000000000000000000000000..3243e108d1cd04c3b1b325367c6322491e3149de Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-04.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-05.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-05.png new file mode 100644 index 0000000000000000000000000000000000000000..38248c68774281023fc287d13f37a45c29f1d958 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-05.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-06.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-06.png new file mode 100644 index 0000000000000000000000000000000000000000..af7afbfdb1f61712d6710646241ff191041e81c4 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-06.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-07.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-07.png new file mode 100644 index 0000000000000000000000000000000000000000..32c920069f3d98cfaa46413f9fb1645ded4bb528 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-07.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-08.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-08.png new file mode 100644 index 0000000000000000000000000000000000000000..622a44d40ef9fb176ce333f8092c8f1fa4ddf4de Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-08.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-09.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-09.png new file mode 100644 index 0000000000000000000000000000000000000000..4cdd9bff1522539969a8d3686db3b8fd8e33291d Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-09.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-10.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-10.png new file mode 100644 index 0000000000000000000000000000000000000000..83c5bdc0a206e090178a9230ea8572e5fc06d2bb Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-10.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-11.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-11.png new file mode 100644 index 0000000000000000000000000000000000000000..dde73ad476349967abf36501ec7164ddfafdab3a Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-11.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-12.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-12.png new file mode 100644 index 0000000000000000000000000000000000000000..33cf025dd929602bf6d28cd5077f45d621b2a4ad Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-12.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-13.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-13.png new file mode 100644 index 0000000000000000000000000000000000000000..d78e763a58b93988a2e718d53386faa7c00f0cba Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-13.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-14.png b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-14.png new file mode 100644 index 0000000000000000000000000000000000000000..e87176eb0be1dfc036bbc2aa0f095d311c99e7b9 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis-14.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis.md b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis.md new file mode 100644 index 0000000000000000000000000000000000000000..e7f9363cc30af516d900529f6abec4aa922231e7 --- /dev/null +++ b/web-ui/docs/zh/blog/MrRlu/2020-12-04-cloud-native-network-dp-analysis.md @@ -0,0 +1,349 @@ +--- +title: 云原生网络数据面加速方案浅析 +date: 2020-12-04 +tags: + - 云原生网络 + - eBPF + - DPDK + - 数据面提速 +archives: 2020-12 +author: luzhihao +summary: 站在云原生网络角度分析网络数据面各阶段的性能瓶颈以及可能的优化手段. +--- + +# 云原生网络数据面加速方案浅析 + +## 背景 + +云原生网络数据面性能直接决定整个系统的吞吐量、服务响应时间等关键性能指标。数据面提速是系统提速的重要手段。 + +云原生网络包括CNI、ServiceMesh、Ingress、数据中心网络,其中大部分都是虚拟网络,除数据中心网络以外。数据面提速聚焦在这些虚拟网络内。 + + + +## 总体概要 + +CNI:PoD内通信路径、PoD间通信路径(Nod内)、网络策略、访问Service路径、PoD通信后端(Node间通信) + +ServiceMesh:Side-car通信路径 + +Ingress:Ingress加速 + +### PoD内通信加速 + +PoD内主要数据路径集中在内核协议栈,内核协议栈本身一直在研究并持续的性能优化,但是其性能还是远不如DPDK、AF_XDP这类用户态协议栈。 + +#### 提速方案 + +PoD内引入数据多平面,当PoD内存在Legacy/IO intensive APP并存时,后者可以走高性能数据面,提速的同时可以避免对其他APP的影响。 + + + +#### 小结 + +方案名称:**用户态CNI**(openEuler高性能网络sig已经在设计/开发这款软件:**Gazelle CNI**) + +用户态CNI可以基于DPDK、AF_XDP两种技术实现,两种技术各有优劣,互补关系,所以需要考虑同时支持DPDK、AF_XDP两种技术。 + +在控制面/数据面分离、Legacy/IO intensive APP并存、多租户隔离等场景,用户态CNI存在应用价值。 + +### PoD间通信加速 + +PoD间的通信通常取决于容器网络模型,网络模型通常有:Bridge(缺省模式)、Host、Container、None。参见下图: + + + + + +Bridge模式:给每个PoD启动一个eth0,通过veth pair将其接入一个Bridge(缺省命名cni0),然后与Node eth0通信。 + +Host模式:直接与Node共享Namespace,所以PoD能够看到Node上的eth0(当然也包括其他接口)。 + +Container模式:与其他容器共享Namespace,这样目标容器的接口就能够被其识别并使用。 + +None模式:没有接口。(没有不代表真的就没有,实际就是给开发者留了自定义空间,无代表有,少即是多) + +这里我们重点分析Bridge、None两种模式(其他两种没有分析价值)。None模式中,常见的自定义模式中,经常用Router来解决通信问题。所以我们分析Bridge、Router两者数据路径的加速。 + +#### 提速方案 + +缺省情况下,Bridge/Router分别位于内核协议栈链路层、IP层,数据路径经过内核协议栈处理后,才能到达目的PoD。 + +提速方案是使用XDP over veth,在XDP Prog中通过help函数查询内核FIB信息,完成类似Bridge、Router + +的转发动作,但是整个转发路径无需进入内核协议栈,只需在Driver层处理完成。 + + + +#### 小结 + +方案名称:**VNF powered by XDP** + +这个场景里面的VNF是Bridge, Router。这种方案与应用场景不耦合,所以很容易复制应用到其他场景,适合基础软件供应商提供。 + +### Node间通信加速 + +由于我们聚焦虚拟网络的加速,所以Node特指VM。 + +VM间通信主流方案有Open vSwitch,VMware virtual switch,Cisco Nexus 1000V,huawei 1800v,huawei evs等。其中大部分采用了DPDK技术提速。 + + + + + +#### 提速方案 + +从性能角度看,现有成熟方案已经是性能最优方案。但是如果从硬件可获得角度看,可以改用AF_XDP代替DPDK,性能上略有差距,但可以弥补硬件不可获得的缺陷。 + +可以参考:https://events19.linuxfoundation.cn/wp-content/uploads/2017/11/Accelerating-VM-Networking-through-XDP_Jason-Wang.pdf + +#### 小结 + +方案名称:**VNF powered by DPDK** + +裸机上针对VM间通信加速,DPDK基本处于垄断地位,留给AF_XDP的空间很小,针对这种场景的性能改进工作,想象空间很小。 + + + +### K8S网络策略加速 + +K8S缺省定义了一些网络策略spec(各种CNI插件方案会重定义自己的网络策略spec),从下面示例可以看出网络策略定义能力非常灵活,可以针对IP/Port、Namespace、Pod等几种维度定义,可以单一使用,也可以混合使用。 + +``` +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: test-network-policy + namespace: default +spec: + podSelector: + matchLabels: + role: db + policyTypes: + - Ingress + - Egress + ingress: + - from: + - ipBlock: # 基于网络地址定义网络策略 + cidr: 172.17.0.0/16 + except: + - 172.17.1.0/24 + - namespaceSelector: # 基于namespace定义网络策略 + matchLabels: + project: myproject + - podSelector: # 基于PoD标签定义网络策略 + matchLabels: + role: frontend + ports: + - protocol: TCP + port: 6379 + egress: + - to: + - ipBlock: + cidr: 10.0.0.0/24 + ports: + - protocol: TCP + port: 5978 +``` + + 这些网络策略定义后,控制面会转换成linux iptables规则下发至linux网络数据面实现网络访问控制。 + +``` +#控制面会通过侦听环境运行状态,填入合适的网络地址信息 +iptables -A INPUT -s X.X.X.X -d X.X.X.X -j ACCEPT +iptables -A INPUT -s X.X.X.X -d X.X.X.X -j ACCEPT +… +iptables -A OUTPUT -s X.X.X.X -d X.X.X.X -j ACCEPT +iptables -A OUTPUT -s X.X.X.X -d X.X.X.X -j ACCEPT +…. +``` + +数据面执行iptables规则时: + +1. Iptables基于网络位置标识进行访问控制。 +2. 网络位置标识随PoD生命周期变化而变化,处于不稳定状态,网络访问规则总是在刷新。 +3. 网络位置与PoD数量(集群规模)成正比增长,且是非线性增长,网络访问规则剧增。 +4. Iptables固有缺陷: + +- 时延性能低:iptables线性匹配规则,随着集群规模扩大,规则数量剧增,匹配的时间复杂度是O(N)。 +- 扩展性差:无法增量更新规则,由于规则数量庞大,更新提交时,内核会执行kernel lock,这个过程只能等待。 +- 可用性差:服务扩缩容时,iptables规则刷新会导致协议链接断开,服务不可用。 + + + +#### 提速方案1 + +数据面、控制面视角存在差异,前者视角是从网络地址(IP/Port)执行访问策略,后者是从K8S Deployment信息定义访问策略,期间的Gap就是导致性能劣化的原因。 + +如果将K8S Deployment翻译成一个集群唯一的identify,将其加入网络负载中,数据面基于identify进行访问控制,统一两者的视角。 + +具体方案如下: + +1. 使用eBPF自定义网络策略控制逻辑,基于K8S deployment(映射成集群唯一identify)访问控制。 +2. K8S deployment不会随PoD生命周期变化而变化。 +3. K8S deployment属于业务视角抽象信息相比较IP/Port这类物理位置信息,能够起到聚合效果,有效降低规则数量。 +4. eBPF控制更灵活,执行性能优于iptables。 + +``` +#举例说明聚合效果 +#K8S定义访问控制策略如下 +Ingress: + from: + podSelector: + matchLabels: + role: frontend +#上述策略如果翻译成iptables这类基于网络地址进行访问控制的规则可能存在数十条(取决于后端PoD实例数量) +#翻译成基于identify访问控制策略只有2条 +#1 allow pod-label=frontend +#2 deny all +``` + + + +#### 提速方案2 + +方案1性能固然比较好,但是其依赖CNI ISV完全重新设计CNI解决方案,并且由于增加了隧道封装,降低了传输效率。从方案适用性角度看,方案1并不被看好,这也是众多CNI解决方案里面,只有cilium采用此方案。 + +大部分CNI解决方案是改进数据面后端,用eBPF技术重新打造iptables。 + +例如: + +- Calico cni 插件式管理数据面,可以支持多种数据面组件,包括eBPF打造的高性能数据面。(参考:https://docs.projectcalico.org/about/about-calico) +- 兼容iptables前端,eBPF技术重新实现iptables后端。(参考:https://github.com/mbertrone/bpf-iptables) + +#### 小结 + +方案1名称:**Network Policy base by K8S identify** + +方案2名称:**iptables power by eBPF** + +- 方案1更适合CNI ISV厂商,从整体出发,将管理面、数据面充分融合在一起。 +- 方案2更适合基础软件供应商,比如兼容iptables前端,替换后端实现。 + + + +### 服务网格加速 + +服务网格(比如常见的istio)在云原生系统中应用比较普遍,它为集群管理带来服务治理能力。 + + + +istio会在每个PoD内部署一个Proxy组件(通常称其为side-car),该组件会接管PoD所有对外通信请求,同时为PoD带来L7层负载分担、API流量可视、拓扑管理等能力。但是所有数据流量都会经过Proxy处理,无意将数据路径加长,如下图所示: + + + +#### 提速方案 + +通过eBPF实现socket map方案,将PoD 内Container 与 side-car之间TCP链接的一对socket进行映射,两个socket收发数据时,eBPF提前将数据丢到另一个socket内,并唤醒其所属线程,避免其进入完整的内核协议栈。 + +如下图所示: + + + +#### 小结 + +方案名称:**SocketMap** + +SocketMap加速方案除了应用在ServiceMesh场景,也可以快速复制到其他场景,比如相同Namespace APP之间的通信加速。这种提速方案容易被复制到其他应用场景,所以适合基础软件供应商提供。 + +### 访问Service加速 + +背景: Kubernetes为了提升可用性,提出service的概念,将应用程序提供的服务抽象成一个endpoint,并为其分配IP/Port,而该service则由多个backend实例提供服务,通过这种服务、程序实例分离,并程序多实例部署的方式,实现服务的高可用性。 + +集群内访问Service时,需要根据实际的Backend实例进行地址转换,将请求LB到具体的PoD实例内。这个过程时由kubernetes组件kube-proxy控制,它会监听Service/Backend的匹配关系,并将其形成LB数据信息写入数据面。现有kube-proxy支持两种数据面:iptables、ipvs。后者性能优于前者。 + +举例Service之间互访数据流: + + + + + +iptables存在诸多限制(参考前面章节介绍),ipvs相对而言性能更优,请参考如下性能测试数据: + +- [ ] **时延性能比较** + + + +- 增加 Iptables 规则的时延,随着规则数的增加呈“指数”级上升; +- 当集群中的 Service 达到 2 万个时,新增规则的时延从 50us 变成了 5 小时; +- 而增加 IPVS 规则的时延始终保持在 100us 以内,几乎不受规则基数影响。 + +- [ ] **带宽性能比较** + + + +- iptables模式下,随着service数量增加,first/last service的带宽直线下降,在25000个service时,基本已经不可用。 +- ipvs模式下,随着service数量增加,first/last service的带宽略有下降,并且first/last service之间的带宽差别不大。 + +- [ ] **CPU usage比较** + + + +很明显,IPVS 在 CPU/内存两个维度的指标都要远远低于 Iptables。 + +备注:以上数据来源 https://zhuanlan.zhihu.com/p/37230013 + + + +#### 提速方案1 + +目前kube-proxy仍然将iptables设置为缺省模式,isula平台可以在安装阶段将kube-proxy设置为ipvs模式。 + + + +#### 提速方案2 + +ipvs性能明显好于iptables,但是kube-proxy仍然默认采用iptables,背后的原因是什么? + +一方面存在兼容性问题,另一方面是ipvs在数据路径中的处理阶段与iptables不同,在有些场景下如果两者并存可能会存在一些兼容性问题。 + +所以有些CNI ISV厂商(比如 cilium)干脆替换kube-proxy组件,CNI软件采取eBPF技术实现Service寻址Backend的过程(暂定命名为:LB power by eBPF)。 + +但是这种方案适合个别CNI,对于大部分CNI而言不具备这种能力,为了让LB power by eBPF覆盖场景更广,可以沿用iptables power by eBPF的技术思路。 + +#### 小结 + +方案1名称:**ipvs** + +方案2名称:**iptables power by eBPF** + +- 提速方案1应该慎重采纳,兼容性问题并不容易发现及解决。 +- 提速方案2中 eBPF改造iptables的方案更适合基础软件供应商。 + + + +### Ingress加速 + +背景: Kubernetes cluster有时需要向集群外暴露service,一般有三种方案,具体如下: + +1. NodePort方案:在K8S节点上开放一个特定端口,该端口对外暴露,所以该端口流量都被转发到特定Service。(缺点:1)每个Service占用一个端口;2)如果Node IP发生变更直接影响入口流量) +2. LoadBalancer方案:集群外部署一个LB节点,该LB地址需要暴露出去,基于L4层完成流量转发,直接将流量转发到Service Backend实例上。(缺点:每类Service均需要在internet上暴露一个独立LB IP,并支付费用) +3. Ingress方案:集群内部署一个ingress节点,ingress基于L7层负载分担,并由ingress controller兼容集群内service的变化,实时更新ingress规则。由于其采用L7层解析分担方式,所以其可以一个ingress节点支持负载分担多种Service。 + + + +#### 提速方案 + +ingress是主流方案,ingress可以采用多种ingress软件,包括HA Proxy、Nginx等。其中Nginx是最常见的ingress方案。 + +openEuler已经完成针对nginx的性能优化,在一些场景优化超过50%。(详细优化方案可以参考《Innovation Drivers the Feature of openEuler》) + +#### 小结 + +方案名称:nginx性能优化 + +## 总结 + +我们总结下各场景的性能优化方案以及适合提供这类技术方案的软件厂商。 + +| 场景 | 加速方案 | 适合的软件供应商 | 关键技术 | +| --------------- | ----------------------------------- | ---------------- | -------- | +| PoD内通信加速 | 用户态CNI | OS及基础软件 | AF_XDP | +| PoD间通信加速 | VNF powered by XDP | OS及基础软件 | XDP | +| Node间通信加速 | VNF powered by DPDK | ISV | DPDK | +| K8S网络策略加速 | Network Policy base by K8S identify | ISV | CNI | +| | iptables power by eBPF | OS及基础软件 | eBPF | +| 服务网格加速 | SocketMap | OS及基础软件 | eBPF | +| Service访问加速 | ipvs | 不推荐该方案 | | +| | iptables power by eBPF | OS及基础软件 | eBPF | +| Ingress加速 | nginx性能优化 | OS及基础软件 | nginx | diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-01.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-01.png new file mode 100644 index 0000000000000000000000000000000000000000..8c5712630c0d6be13ffcebc6046086773b9b3df9 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-01.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-02.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-02.png new file mode 100644 index 0000000000000000000000000000000000000000..a601a05e197f7d37bdcdc9973061f009005acc61 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-02.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-03.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-03.png new file mode 100644 index 0000000000000000000000000000000000000000..c020eb9a574ac8870543f787e0b8c56b0d47eff3 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-03.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-04.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-04.png new file mode 100644 index 0000000000000000000000000000000000000000..e4119a800d59d636d18430722861dedd4711a28e Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-04.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-05.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-05.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c0b38ae99c30c407c1a13cc606fca650aceee3 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-05.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-06.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-06.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd61a472e881930b47ed732750471d59a90ec77 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-06.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-07.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-07.png new file mode 100644 index 0000000000000000000000000000000000000000..f024e5172d61d0c8687fd988b40cb667b23cc961 Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-07.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-08.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-08.png new file mode 100644 index 0000000000000000000000000000000000000000..f9ce16ceda0b1e14a0bc758be5a6978d67b6adfd Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-08.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-09.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-09.png new file mode 100644 index 0000000000000000000000000000000000000000..06206aa48a4580ca4824e233cc1900d9a360b87c Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-09.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-10.png b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-10.png new file mode 100644 index 0000000000000000000000000000000000000000..751461530ab23599d46864916a554248b89d09aa Binary files /dev/null and b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce-10.png differ diff --git a/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce.md b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce.md new file mode 100644 index 0000000000000000000000000000000000000000..8b3573583443b4ea23f57f0bf0963ea1c64dbfcd --- /dev/null +++ b/web-ui/docs/zh/blog/MrRlu/2021-01-04-openEuler eBPF introduce.md @@ -0,0 +1,239 @@ +--- +title: eBPF introduce +date: 2021-01-04 +tags: + - kernel + - eBPF +archives: 2021-01 +author: luzhihao +summary: 介绍BPF技术以及相应的使用场景以及openEuler上eBPF技术落地情况. +--- + +# eBPF introduce + +## eBPF 发展历程 + +- 1992年:BPF全称Berkeley Packet Filter,诞生初衷提供一种内核中自定义报文过滤的手段(类汇编),提升抓包效率。(tcpdump) +- 2011年:linux kernel 3.2版本对BPF进行重大改进,引入BPF JIT,使其性能得到大幅提升。 +- 2014年: linux kernel 3.15版本,BPF扩展成eBPF,其功能范畴扩展至:内核跟踪、性能调优、协议栈QoS等方面。与之配套改进包括:扩展BPF ISA指令集、提供高级语言(C)编程手段、提供MAP机制、提供Help机制、引入Verifier机制等。 +- 2016年:linux kernel 4.8版本,eBPF支持XDP,进一步拓展该技术在网络领域的应用。随后Netronome公司提出eBPF硬件卸载方案。 +- 2018年:linux kernel 4.18版本,引入BTF,将内核中BPF对象(Prog/Map)由字节码转换成统一结构对象,这有利于eBPF对象与Kernel版本的配套管理,为eBPF的发展奠定基础。 +- 2018年:从kernel 4.20版本开始,eBPF成为内核最活跃的项目之一,新增特性包括:sysctrl hook、flow dissector、struct_ops、lsm hook、ring buffer等。场景范围覆盖容器、安全、网络、跟踪等。 + + + +## eBPF原理及功能介绍 + +### 宏观视角 + +从宏观视角看eBPF,我们将其与kernel进行对比看,便于我们更粗粒度的理解eBPF原理: + +- 内核的本质是事件驱动机制,事件由系统调用/系统中断产生。 +- eBPF也是事件驱动机制,其采用sandbox技术,与内核隔离。从原理上两者相近,只是能力不同而已。 + + + + + +### 微观视角 + +归纳其软件架构特点: + +- 采用sandbox技术,旁挂于内核,与用户态应用软件、内核、内核模块(网卡驱动)、Device编程、Host加速等均有交互。 +- 通过Helper/hook机制,eBPF与内核可以交换数据/逻辑;通过Map/eBPF Prog机制,eBPF可以与应用程序交换数据/逻辑。最终效果:应用可以通过eBPF改变内核数据/逻辑,或者说用户程序将运行在内核态。 +- 用户编程接口:有限能力的高级语言(c/go/rust)编写eBPF Prog。 +- 编译方式:通过Clang将其编译成eBPF定义的ISA指令,再由Host/Device JIT翻译成机器指令。 + + + + + +### eBPF主要功能介绍 + +| **特性** | **引入版本** | **功能介绍** | **应用场景** | +| -------------------- | ------------ | ------------------------------------------------------------ | ------------- | +| Tc-bpf | 4.1 | eBPF重构内核流分类 | 网络 | +| XDP | 4.8 | 网络数据面编程技术(主要面向L2/L3层业务) | 网络 | +| Cgroup socket | 4.10 | Cgroup内socket支持eBPF扩展逻辑 | 容器 | +| AF_XDP | 4.18 | 网络原始报文直送用户态(类似DPDK) | 网络 | +| Sockmap | 4.20 | 支持socket短接 | 容器 | +| Device JIT | 4.20 | JIT/ISA解耦,host可以编译指定device形态的ISA指令 | 异构编程 | +| Cgroup sysctl | 5.2 | Cgroup内支持控制系统调用权限 | 容器 | +| Struct ops Prog ext | 5.3 | 内核逻辑可动态替换 eBPF Prog可动态替换 | 框架基础 | +| Bpf trampoline | 5.5 | 三种用途: 1.内核中代替K(ret)probe,性能更优 2.eBPF Prog中使用,解决eBPF Prog调试问题 3.实现eBPF Prog动态链接功能(未来功能) | 性能跟踪 | +| KRSI(lsm + eBPF) | 5.7 | 内核运行时安全策略可定制 | 安全 | +| Ring buffer | 5.8 | 提供CPU间共享的环形buffer,并能实现跨CPU的事件保序记录。用以代替perf/ftrace等buffer。 | 跟踪/性能分析 | + +备注:BPF社区还在快速发展中,众多高级特性可以参考kernel社区。 + + + +## eBPF应用场景介绍 + +### 网络场景 + +在网络加速场景中,DPDK技术大行其道,在某些场景DPDK成了唯一选择。XDP的出现为厂商提供了一种新的选择,借助于kernel eBPF社区的蓬勃发展,为网络加速场景注入了一股清流。下面我们总结下两种差异: + +- [ ] DPDK优势/价值:优势(性能、生态)、价值(带动硬件销售) + **性能**:总体上XDP性能全面弱于DPDK(但是差距不大),注意:只是比较DPDK/XDP自身性能 + **生态**:DPDK历经多年发展,生态体现在:驱动支持丰富、基础库丰富(无锁队列、大页内存、多核调度、性能分析工具等)、协议支持丰富(社区强大,例如VPP,支持众多协议ARP/VLAN/IP/MPLS等) + **价值**:将网络类专有硬件的工作转嫁给软件实现,进而拓展硬件厂商市场范围。 +- [ ] XDP优势:可编程、内核协同工作 + **可编程**:在网络硬件智能化趋势下,可编程可以适用多种场景。 + **内核协同**:XDP并不是完全bypass kernel,所以在必要的时候可以与内核协同工作,利于网络统一管理、部署。 +- [ ] DPDK一些固有缺陷: + **独占Device**:设备利用率低。 + **部署复杂**:由于独占Device,网络部署需要与OS协议栈协同部署。 + **开发困难**:DPDK定位就是网络数据面开发包,所以它对使用者要求具备专业网络知识、专业硬件知识,所以入门门槛高。 + **端到端性能不高**:DPDK只是提供数据包从NIC到用户态软件的零拷贝,但是用户态传输协议依然需要CPU参与。所以端到端性能不高。 + + + +#### Polycube项目介绍 + +- [ ] Polycube项目目标是: + 重构网络数据面,通过XDP技术实现bypass内核的网络数据面。 + 北向提供可编程接口,实现网络可编程的事实标准,可被不同解决方案集成(包括网络安全场景、容器场景、虚拟网络场景等)。 + 南向可以逐步实现硬件offload,便于适配各种智能网卡。 +- [ ] Polycube使用场景包括: + VNF场景 + 容器网络数据面 + 通用网络基础设施(包括iptables、lvs、nat等等) + … + + + + + +VNF场景示例: + + + +### 容器场景 + +背景:云原生场景中容器比虚拟化技术有着更好的低底噪、轻便、易管理等优点,基本已经成为云原生应用的事实标准。容器场景对网络需求实际是应用对网络的需求,即面向应用的网络服务。 + +- [ ] 云原生应用特点以及对网络的诉求: + 生命周期短:要求提供基于PoD静态身份信息实施的网络安全策略。(不能基于IP/Port) + 租户间隔离:要求提供API级别的网络隔离策略。 + ServiceMesh拓扑管理:要求提供side-car加速。 + 服务入口位置透明:要求提供跨集群Ingress服务能力。 + 安全策略跨集群:要求网络安全策略能够在集群间共享、继承。 + 服务实例冗余保证高可用性:要求提供L3/4层LB能力。 + +#### Cilium项目介绍 + +Cilium 是一个纯开源软件,该软件用于透明地保护使用 Linux 容器管理平台(如 Docker 和 Kubernetes)部署的应用程序服务之间的网络连接。 + +Cilium 以eBPF作为其技术基础,为容器场景带来高性能、灵活、安全的容器网络解决方案。举例说明其功能: + +功能1:使用K8S label代替IP/Port作为容器微隔离的标签 + + + + + +功能2:使用sockmap技术代替loopback环回通信,进而加速side-car + + + +### 云原生运维场景 + +背景:容器场景的维测要求与内核提供的维测手段存在相当GAP,虽然内核维测手段种类繁多,但是诸多技术均是站在内核视角提供维测数据,无法支撑容器场景的维测需。 +解决方案:采用eBPF技术实现微服务视角的数据采集,实现容器平台的运维功能。行业里面比较成熟的项目sysdig/hubble。 + + + +### 内核逻辑自定义(定制TCP拥塞算法) + +参考:https://lwn.net/Articles/811631/ + +从表现上看,就是BPF可以“任意”重定义内核中struct xxx_ops结构体,5.6版本目前已经支持TCP拥塞算法的定制。 + +如果使用? +1. C or rust 语言定义TCP拥塞算法,参考bpf_cubic.c + +2. clang编译拥塞算法成elf文件 + +3. bpftool加载elf文件(参考代码struct_ops.c) + + ~ bpftool struct_ops register \ + +价值:TCP拥塞算法在CDN这类场景存在大量定制诉求。衍生下,比如file ops,也可以由BPF自定义访问策略。 + +“Linux内核正在迈向 BPF runtime 微内核方向发展” -- Toke Høiland-Jørgensen + + + +### 安全场景 + +背景:Linux系统的运行安全始终是在动态平衡中,系统安全性通常要评估两方面的契合度:signals(系统中一些异常活动迹象)、mitigation(针对signals的一些补救措施)。内核中的signal/mitigation设置散布在多个地方,配置时费时费力。 +解决方案:引入eBPF,提供一些eBPF Helper实现“unified policy API”,由API来统一配置signal和mitigation。 + + + + + +## eBPF趋势及其背后动机 + +### 应用场景归纳 + +- Bypass内核:比如网络数据路径的bypass、系统调用bypass。 +- 内核逻辑定制:比如安全逻辑的定制、容器安全控制、网络TC定制等 +- 内核状态窥探:比如结合特定业务领域运维功能(包括容器、AI、大数据等) +- 改造内核基础设施:比如改造内核协议栈iptables、lvs等 +- 性能监控:分布式系统的性能分析等。 +- … + + + +### 发展趋势 + +- [ ] eBPF技术朝着几个方向发展: + eBPF虚机的能力逐渐增强:支持有限循环、支持批量报文处理、支持批量MAP操作能力、支持更多指令数量、支持更大的stack、支持更多种类指令。 + 开发界面逐渐友好:支持runtime debuging、支持Compile-Once Run-Everywhere、支持更多高级语言lib库。 + 内核向eBPF开放的窗口逐渐放大:最早支持单向互动kernel->eBPF;后来支持双向互动kernel<->eBPF;最新可以支持重定义内核逻辑。 +- [ ] eBPF的应用场景趋势: + 网络方面:广泛应用在TC、协议栈加速、安全、硬件offload、虚拟化/容器网络。 + 系统运维:可生产环境部署的运维系统、可视化运维系统。 + 其他:文件系统、安全等领域。 +- [ ] 行业正在发生的: + Intel提出高性能XDP概念,通过网卡预处理携带meta-data,提升XDP性能。 + Google提出弹性TrafficShaping概念,使用eBPF技术重新打造高性能网络QoS,旨在解决TC root lock、逐包QoS等固有问题。 + CloudFlare提出可编程socket的概念,通过eBPF技术旨在解决百万级链接场景socket操作性能耗时大的问题。 + Redhat提出bpfilter项目,通过eBPF技术旨在重新实现iptables,使用户无感知的替换iptables。 + VMWare提出ovs-ebpf项目,通过eBPF技术加速OVS。 + + + +### 发展背后动机 + +- 原因1:内核的设计做了太多的抽象(解决用户态API稳定、硬件差异兼容的问题),而抽象的代价是性能开销大。在硬件性能大幅提升后,这个问题就凸显出来。 +- 原因2:内核经过长期发展,代码规模已经超过3千万,代码复杂度高,带来的问题是不易扩展新功能。 +- 原因3:内核属于社区开源代码,其发展路径并不受商业公司约束。带来的问题是商业公司在内核上的投入被社区绑定。(google曾经评估重新打造一个内核的代价,旨在代替linux内核) +- eBPF特点:内核逻辑可定制、用户态开发代码、内核状态可窥探正是上述原因的发展结果。 + 社区活跃厂商: + Facebook + Cilium + Netronome + Redhat + Google + … + + + +### 总结 + +我们就用2句话总结吧~ + +"BPF is eating the world.”-- Marek Majkowski +Let’s change the world! -- openEuler and all Geeks + +## openEuler eBPF落地情况 + +openEuler LTS版本 kernel 4.19 ,openEuler 创新版本 kernel 5.4。 + +除了上游社区eBPF特性/Bugfix回合openEuler社区之外,openEuler致力于基于eBPF技术打造开放式高性能数据数据面底座,为下游厂商提供更便捷的业务创新方式。 + +具体情况请移步openEuler [高性能网络sig](https://gitee.com/openeuler/community/tree/master/sig/sig-high-performance-network)交流。 + diff --git a/web-ui/docs/zh/blog/Shinwell_Hu/2020-03-16-A-Status-Update-of-Early-Spring.md b/web-ui/docs/zh/blog/Shinwell_Hu/2020-03-16-A-Status-Update-of-Early-Spring.md new file mode 100644 index 0000000000000000000000000000000000000000..6b7e57a688e35c3b28c6e14ea3d7f40d5b88b42e --- /dev/null +++ b/web-ui/docs/zh/blog/Shinwell_Hu/2020-03-16-A-Status-Update-of-Early-Spring.md @@ -0,0 +1,57 @@ +--- +title: A Status Update of Early Spring +date: 2020-03-16 +tags: + - TC + - StatusUpdate +archives: 2020-03 +author: Shinwell Hu, Technical Committee +summary: A summary of TC status update。 +--- + +# 技术委员会运作二月总结 + +由于openEuler是个全新的社区,本届技术委员会的所有成员都由Board任命而来,计划任期一年。 +我们希望用着一年时间看护好社区的运作,同时期待社区活跃者的涌现,来年的技术委员会中,更多 +出现社区活跃开发者的身影。 + +在开始正文之前,简单介绍下自己。我的gitee账号是Shinwell_Hu,当前在华为公司2012实验室工作。 +我从1999年开始接触Linux操作系统,一度沉迷于国内各个BBS上和Linux以及相关技术的版面,不可自 +拔。后来因为各种原因和社区活动渐行渐远。这是将近20年多年第一次重新在论坛上发帖。是初见,也 +是久别重逢。 + +我本届是技术委员会的主席。本届技术委员会的成员后续都将陆续在博客中出现,对他们的介绍,留给 +他们自己。 + +## 运作情况的总结 + +技术委员会从2月5日开始,已经召开了4次会议。除了第一次会议是采用irc的方式,后续几次都采用 +zoom系统。每次会议的接入方式都会提前1~2天在 tc@openeuler.org 上通知。欢迎对技术委员会运作 +感兴趣的朋友们围观。 + +技术委员会会议的议题,是通过 tc@openeuler.org 邮件列表收集的。我们会在邮件列表上确定需 +要上会讨论的议题,可以是委员提议,也可以是其他任何人提出并得到至少一个委员的认可。 + +每次会议的纪要,我们都通过邮件列表归档,这里就不在赘述了。 + +## 值得关注的技术动向预告 + +- CS2C的开发者提案在 openEuler 中创建了 oVirt 这个 SIG。 oVirt 是一个免费的虚拟化解决方案, + 如果成功引入到 openEuler 中,可以填补 openEuler 社区的一大空白。虽然当前这个 SIG 还没有提交代码, + 但我们对此还是拭目以待。 + +- 普华的开发者提案在 openEuler 中创建了 mate-desktop 这个SIG。Mate 桌面环境是 gnome3 项目启动后 + 爱好者们对 gnome2 的延续。相对于 gnome3 和 KDE 来说,Mate 桌面的优势在于轻量而直观,对硬件环境要 + 求更低。这个工作对 openEuler 当前非常欠缺的桌面环境是个很好的补充。也请对此感兴趣的朋友们关注试用。 + +- 吴峰光提案在 openEuler 中对上游软件社区提供测试服务,目标是通过全自动的bisect-report-fix-verify + 闭环来简化上游软件社区的测试过程,进一步提升开源软件的质量。提案已经在技术委员会例会上讨论通过,近期 + 将以 PR 的方式提交社区。之前峰光针对内核的自动化测试工程获得了极大的成功,相信这次在 openEuler 更进 + 一步,对整个开源社区也会有很大的推动和促进。 + +## 总结 + +虽然 openEuler 从1月发布还不过短短2个月的时间,技术委员会正式运作的时间更短。但我们还是被国内的技术氛 +热情所鼓舞,不论是来自其他厂商的,还是来自华为公司内部其他团队的。 + +在这个特殊的春天里,我们开始对年底共同的收获有所期待。 diff --git a/web-ui/docs/zh/blog/ZihaoChang/2020-11-29-qemu-qmp.md b/web-ui/docs/zh/blog/ZihaoChang/2020-11-29-qemu-qmp.md new file mode 100644 index 0000000000000000000000000000000000000000..d4613fb15c10bd71ac316917df53a62bf123f220 --- /dev/null +++ b/web-ui/docs/zh/blog/ZihaoChang/2020-11-29-qemu-qmp.md @@ -0,0 +1,203 @@ +--- +title: 'QEMU QMP机制' +date: 2020-11-29 +tags: + - QEMU + - QMP + - HMP +archives: 2020-11 +author: Zihao Chang +summary: QEMU QMP 使用和开发详解 +--- + + +### QMP简介 +QMP的全称是QEMU Machine Protocol,是一种以json格式为基础的协议,允许用户通过该接口查询、配置QEMU实例。 + +QEMU官方文档中对QMP的解释是: +* Lightweight, text-based, easy to parse data format +* Asynchronous messages support (events) +* Capabilities negotiation +* API/ABI stability guarantees + +很多基于QEMU的应用都使用了QMP接口,比如著名的虚拟化中间件libvirt,对QEMU实例的操作就是使用了QMP接口。此外,还可以通过telnet、qmp-shell script等方式使用QMP接口,QEMU的官方文档进行了[详细介绍](https://wiki.qemu.org/Documentation/QMP)。本博客主要使用libvirt来展示QMP相关接口,通过libvirt提供的virsh工具可以直接调用QMP接口。 + + +### 1 环境准备 +* 支持虚拟化的Server,装有QEMU、libvirt等相关虚拟化组件 +* 虚拟机,可以通过virsh与其交互 + +### 2 相关命令使用 +#### 2.1 通过`virsh list`查看虚拟机状态是否正常 + +``` +Linux:~ # virsh list + Id Name State +------------------------ + 1 ubuntu running +``` +#### 2.2 查看`qemu-monitor-command`子命令 +``` +Linux:~ # virsh qemu-monitor-command --help + NAME + qemu-monitor-command - QEMU Monitor Command + + SYNOPSIS + qemu-monitor-command [--hmp] [--pretty] [--return-value] {[--cmd] }... + + DESCRIPTION + QEMU Monitor Command + + OPTIONS + [--domain] domain name, id or uuid + --hmp command is in human monitor protocol + --pretty pretty-print any qemu monitor protocol output + --return-value extract the value of the 'return' key from the returned string + [--cmd] command +``` + +`qemu-monitor-command`子命令是`virsh`调用QMP的接口,通过帮助文档我们可以看到其基本用法。 +其中 **--pretty** 可以格式化相关json输出, **--hmp** 是将复杂的QMP接口简化成了便于手动执行的接口,**--return-value**仅输出返回内部,忽略状态码等信息。 + +#### 2.3 调用示例 + +1. virsh qemu-monitor-command ubuntu '{"execute":"query-commands"}' + +``` +Linux:~ # virsh qemu-monitor-command ubuntu '{"execute":"query-commands"}' +{"return":[{"name":"netdev_add"},{"name":"device_add"},{"name":"query-QMP-schema"}, +{"name":"query-memory-size-summary"},{"name":"closefd"},{"name":"getfd"}, +{"name":"set_link"},{"name":"query-uuid"},{"name":"query-kvm"},{"name":"query-name"}, + ··· + 忽略部分输出 + ··· +{"name":"add_client"},{"name":"query-commands"},{"name":"query-version"},{"name":"QMP_capabilities"}],"id":"libvirt-21"} +``` +可以看到QMP提供了非常多的接口供使用,包括`query-commands`、`query-qmp-schema`、`query-kvm`等查询类接口,`add_client`、`set_link`等修改设置的接口。 + +2. virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-memory-size-summary"}' +``` +Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-memory-size-summary"}' +{ + "return": { + "base-memory": 4294967296, + "plugged-memory": 0 + }, + "id": "libvirt-30" +} + +``` +加入 **--pretty**参数后,输出被格式化。 + +#### 2.4 HMP格式 +上面提到`qemu-monitor-command`子命令支持 **--hmp**参数,是对QMP命令的简化,大大降低了使用QMP命令的复杂度,并且部分HMP就是对QMP命令进行了封装,底层实际只用的还是QMP命令。但是通过QEMU的官方说明看,HMP是QEMU上的简单交互式监视器,主要为调试和简单的人类使用而设计,更高级别的工具应该连接到QMP , QMP才能提供一个稳定的JSON接口,以便于进行可靠的解析。 +以查询虚拟机内存为例,使用HMP可以简化命令的输入和输出: +``` +Linux:~ # virsh qemu-monitor-command ubuntu --HMP info memory_size_summary +base memory: 4294967296 +plugged memory: 0 +``` + +### 3 编写新的QMP命令 +下面将展示如何向QEMU中增加一个hello world接口。 + +#### 3.1 QEMU源码编译安装 +这里仅展示了基础步骤,还要根据不同的平台和机器安装对应的依赖。 +``` +git clone https://git.qemu.org/git/qemu.git +cd qemu +git submodule init +git submodule update --recursive +./configure +make +``` + +#### 3.2 编写QMP接口源码 + +##### 3.2.3 增加QMP接口 +QEMU提供了一套QMP接口实现框架,在QEMU的源码的qapa路径下有多个***.json, 这些都是不同分类的QMP接口的定义。这里选择在qapi/misc.json文件,增加一个hell world接口声明。 +``` +## +# @hello-world: +# Print a client provided string to the standard output stream. +# +# @message: string to be printed +# +# Returns: Nothing on success. +# +# Notes: if @message is not provided, the "Hello, world" string will +# be printed instead +# Since: +## +{ 'command': 'hello-world', 'data': { '*message': 'str' } } +``` + +##### 3.2.3 实现QMP函数 +在monitor/qmp-cmds.c添加函数实现 +``` +void qmp_hello_world(bool has_message, const char *message, Error **errp) +{ + if (has_message) { + printf("%s\n", message); + } else { + printf("Hello, world\n"); + } +} + +``` + +##### 3.2.4 实现HMP命令 +在hmp-commands.hx添加接口 +``` + { + .name = "hello-world", + .args_type = "message:s?", + .params = "hello-world [message]", + .help = "Print message to the standard output", + .cmd = hmp_hello_world, + }, +``` +在include/monitor/hmp.h添加函数声明 +``` +void hmp_hello_world(Monitor *mon, const QDict *qdict); +``` + +在monitor/hmp-cmds.c添加函数实现 +``` +void hmp_hello_world(Monitor *mon, const QDict *qdict) +{ + const char *message = qdict_get_try_str(qdict, "message"); + Error *err = NULL; + + qmp_hello_world(!!message, message, &err); + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + error_free(err); + return; + } +} +``` +##### 3.2.5 验证QMP命令实现 +编写完成上述代码后,重现编译安装,修改虚拟机xml中的标签,使用自定义的QEMU启动虚拟机,验证新的QMP命令。 +1. 查看QMP命令是否存在 +``` +Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-commands"}' | grep hello + "name": "hello-world" +``` + +2. 调用QMP命令 +``` +Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }' +{ + "return": { + + }, + "id": "libvirt-17" +} +``` +3. 查看HMP命令是否存在 +``` +Linux:~ # virsh qemu-monitor-command ubuntu --hmp help | grep hello +hello-world hello-world [message] -- Print message to the standard output + +``` \ No newline at end of file diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/1.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/1.png new file mode 100644 index 0000000000000000000000000000000000000000..571d862930b90a8c469bc932efe120745664e697 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/1.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/2.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/2.png new file mode 100644 index 0000000000000000000000000000000000000000..edea7590d9a2d4a239aee455c0692c853df8fef3 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/2.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/3.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/3.png new file mode 100644 index 0000000000000000000000000000000000000000..525663f71cc416532c97bdae24161110786fa4f4 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/3.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/4.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/4.png new file mode 100644 index 0000000000000000000000000000000000000000..af084464c4173e1ccd07a87ae8fb5924d8f63c89 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/4.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/5.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/5.png new file mode 100644 index 0000000000000000000000000000000000000000..c7a72485ca43fcbafa7adcba709efff178d074df Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/5.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/6.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/6.png new file mode 100644 index 0000000000000000000000000000000000000000..5dca66dda2d9398bd69d677710b1cd7063375164 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/6.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/7.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/7.png new file mode 100644 index 0000000000000000000000000000000000000000..6b493276937b9305f2facec217f2c80d284dd614 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/7.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/8.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/8.png new file mode 100644 index 0000000000000000000000000000000000000000..3de064b1fec1f19462d9f946bdf2a223234bfeff Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/8.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/9.png b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/9.png new file mode 100644 index 0000000000000000000000000000000000000000..8b16d8d4e32df8ec28c101f3ac27848c9675aa51 Binary files /dev/null and b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker-images/9.png differ diff --git a/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker.md b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker.md new file mode 100644 index 0000000000000000000000000000000000000000..d7b603ccb3ccbd09b6ac62f309dc48d081b187b1 --- /dev/null +++ b/web-ui/docs/zh/blog/bestlenavo/2020-06-18-docker.md @@ -0,0 +1,87 @@ +--- +title: windows下使用Docker安装openEuler +date: 2020-07-13 +tags: + - 安装openEuler +archives: 2020-07 +author: bestlenavo +summary: windows下使用Docker安装openEuler +--- + +### 【背景】 +很多小伙伴基本上都是在使用windows,windows下面跑linux有很多方法,下面就来介绍其中一种——使用容器Docker + +### 【环境准备】 + +- Windows10 64位 +- Docker Desktop Installer +- openEuler开源社区下载:[openEuler-docker.aarch64.tar.xz](https://repo.openeuler.org/openEuler-20.03-LTS/docker_img/aarch64/) (aarch64) + + + +### 【安装步骤】 + +##### 一、下载安装Docker + +在[Docker官网](https://www.docker.com/get-started) 选择Download for Windows + + + +安装直接默认选择,点击OK; + + + +安装成功之后,点击Close关闭;有的小伙伴可能是第一次配置Hyper-V,所以需要重启电脑; + + + +##### 二、导入openEuler + +双击打开桌面上的Docker Desktop,等待Docker图标从Docker is starting变成Docker is running + + + + +第一次打开Docker Desktop的时候,我们选择跳过教程,之后不用去管界面了 + + + +运行CMD,进入**openEuler-docker.aarch64.tar.xz**的存放目录,执行命令 +``` +docker load < openEuler-docker.aarch64.tar.xz +``` + +等待加载完毕之后,执行命令 +``` +docker run -p 10000:22 --privileged -td openeuler-20.03-lts /usr/sbin/init +``` + +容器运行起来之后,执行命令查看CONTAINER_ID +``` +docker ps -a +``` + +执行命令,把CONTAINER_ID替换成你自己的容器ID +``` +docker exec -it CONTAINER_ID /bin/bash +``` + + + +##### 三、配置openEuler +现在我们已经进入到openEuler系统中,但我们会发现在的系统连yum,vim等基本工具都无法使用,所以接下来我们来安装这些工具 + +让我们配置repo源,依次执行下面的命令 +``` +cd /etc/yum.repos.d +touch local.repo +echo -e '[basiclocal]\nname=basiclocal\nbaseurl=http://repo.openeuler.org/openEuler-20.03-LTS/OS/aarch64/\nenabled=1\ngpgcheck=0\n' >> local.repo +yum update +``` + + + +更新完成之后,就可以使用yum来安装软件包了 + +到这里Docker安装openEuler就完成了,谢谢大家 +最后谢谢 @Yikun @hao 的指导,https://gitee.com/openeuler/community/issues/I1K1BG#note_2665664 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/bzhaoopenstack/2020-04-23-Running-Mysql-On-ARM-Does-It-work.md b/web-ui/docs/zh/blog/bzhaoopenstack/2020-04-23-Running-Mysql-On-ARM-Does-It-work.md new file mode 100644 index 0000000000000000000000000000000000000000..928f9fcd9ffc2256ca973b0667f08ceda78cbfc9 --- /dev/null +++ b/web-ui/docs/zh/blog/bzhaoopenstack/2020-04-23-Running-Mysql-On-ARM-Does-It-work.md @@ -0,0 +1,71 @@ +--- +title: ARM上跑Mysql, 能行吗? +date: 2020-04-23 +tags: + - Database + - Mysql + - arm64 +archives: 2020-04 +author: bzhaoopenstack +summary: 本文介绍Mysql对于ARM平台的支持情况。 +--- +译者:[bzhaoopenstack](https://github.com/bzhaoopenstack) + +作者: [Krunal Bauskar](https://github.com/mysqlonarm) + +原文链接: https://mysqlonarm.github.io/Running-MySQL-on-ARM/ + +我相信在座的大多数都会有这个问题。事实上,在我开始主动开始#mysqlonarm 相关工作之前,我也有过同样的经历。在ARM上运行MySQL需要什么?真的有用吗?包依赖关系呢?它有什么样的表现?支持什么功能呢?社区支持这么玩吗?还有很多悬而未决的问题。。 + +让我们试着用简单的问答形式来回答这些问题。 + +#### Q: Mysql支持ARM架构吗? + +A:支持,Mysql官方支持ARM。可以从mysql.com站点下载可用的软件包。 + +#### Q: 支持啥OS? + +A: 目前支持RHEL-7 & 8/Oracle-Linux- 7 & 8,还没有发现发布其他OS的包。 + +#### Q: 我们能在ARM架构下从源代码在OS上(如ubuntu)构建Mysql吗? + +A: 可以,能玩。我一直在源码构建二进制包,使用的是当前mysql的release tag mysql-8.0.19。同样也可以在CentOS上玩。这也意味着所有需要的包依赖性问题都得到了解决,或已经可用。 + +#### Q: ARM上的工具链可用吗? + +A: 因为软件包是可用的,而且我能够从源代码构建它,所以默认的应用程序工具,如mysql shell/mysqladmin/mysqlslap/mysqldump/etc...,以及大量其他的默认程序都随二进制文件一起发布了。如果你关心某个特定的工具,告诉我,我会检查它们。现在,我尝试了一些我认为比较重要的工具,它们工作正常。 + +#### Q: MariaDB和Percona在ARM上是否支持各自的服务器规格? + +A: MariaDB Community Server软件包(来自MariaDB公司)在ARM (CentOS7/Ubuntu-16.04/18.04)上可用,MariaDB服务器工具在ARM上暂未正式发布。 Percona尚未正式支持ARM ,但我能够从源代码构建它( MyRocks / TokuDB不可用)。 + +#### Q: 如果工具不可用。这能阻止我在ARM上尝试MySQL(或其衍生软件)吗? + +A: 不会,因为大多数工具都是符合mysql标准的,不是所谓的强绑定特定平台。所以你当然既可以把它们安装在X86,同时安装在ARM上(除非工具还没有移植到ARM上)。 + +#### Q: 社区支持这么玩吗? + +A: MySQL on ARM 已经有一段时间了。ARM、高通、华为等多家厂商积极贡献,Mysql社区发展迅速。在对Mysql ARM优化方面,社区呈现很大的兴趣,非常多的开发者想参与其中。挑战极具吸引力,然而最麻烦的是ARM硬件资源短缺。如果你有兴趣参与,和我聊聊(给我发一封电子邮件)。 + +#### Q: 看起来都还行。性能咋样? + +A: 这是一个大话题,所以我会在未来几天内发布多个关于这个话题的博文,但把它在一定范围内的表现是可比的。另一方面,ARM实例提供更好的价格比。 + +#### Q:可以从哪里获取帮助? + +由于软件包可以从MySQL官方下载,我假定他们的服务提供也应涵盖ARM。和MariaDB一样。当然,除了官方支持之外,还有普通团体和独立开发者。 + +#### Command to build MySQL on ARM + +``` +cmake .. -DWITH_NUMA=1 -DDOWNLOAD_BOOST=1 -DWITH_BOOST= -DCMAKE_INSTALL_PREFIX= +make -j +``` + +因此,在ARM上构建Mysql不需要什么特殊的flag。(假设你已经安装了标准依赖). 它会默认使用"CMAKE_BUILD_TYPE=RelWithDebInfo"来编译。 + +## 结论 + +MySQL on ARM已为事实,并且得到了日益增长的生态系统/社区来支持。可以来试试。当你不考虑性能或功能时,它可以成为你节约成本这个大目标的必选项。 + +*如果你还有问题/疑问,请告诉我。我会尝试回答* diff --git "a/web-ui/docs/zh/blog/cascades/2021-8-14-LibFuzzer\345\255\246\344\271\240.md" "b/web-ui/docs/zh/blog/cascades/2021-8-14-LibFuzzer\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..75d7d0721bb10213e775bbe63bd142d2f5e2a0aa --- /dev/null +++ "b/web-ui/docs/zh/blog/cascades/2021-8-14-LibFuzzer\345\255\246\344\271\240.md" @@ -0,0 +1,262 @@ +--- +title: 【开源软件供应链点亮计划】LibFuzzer学习 +date: 2021-08-14 +tags: + - Fuzzing + - 鹏程实验室 + - summer2021 +archives: 2021-08 +author: cascades +summary: LibFuzzer是一个in-process, coverage-guided, evolutionary的针对库函数的模糊测试引擎,包含在LLVM项目中。 +--- + +# LibFuzzer学习 + +> 本文章来自于[开源软件供应链点亮计划](https://summer.iscas.ac.cn/)的openEuler社区项目 +> 项目名称:[No.112 qemu设备fuzz测试完善](https://gitee.com/openeuler-competition/summer2021-112) + +## 前言 + +LibFuzzer是一个`in-process`,`coverage-based`,`evolutionary`的模糊测试引擎,是LLVM项目的一部分。它与被测库链接,通过特定的入口点将模糊测试的输入提供给被测函数。在测试过程中不断变异输入,并统计代码覆盖率和崩溃情况。 + +* [项目地址](https://www.llvm.org/docs/LibFuzzer.html) +* [代码路径](https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/fuzzer) + +## LibFuzzer 使用方法 + +### 实验环境 + +采用了鹏程实验室的云主机,操作系统为openEuler + +```bash= +[root@host-10-0-0-94 libFuzzer]# lscpu +Architecture: aarch64 +CPU op-mode(s): 64-bit +Byte Order: Little Endian +CPU(s): 4 + +[root@host-10-0-0-94 libFuzzer]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +``` + +### 简单使用 + +[入门教学](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) + +1. 安装llvm和clang + * [源码编译](https://clang.llvm.org/get_started.html#build):对于机器性能尤其是内存(8GB)和硬盘(15-20GB)的要求比较高,需要对编译命令进行一些[优化](https://blog.csdn.net/qq_40323844/article/details/103191029)。需要额外安装LibFuzzer依赖的[`compile-rt`](https://compiler-rt.llvm.org)。 + ```bash= + git clone https://gitee.com/mirrors/LLVM.git + cd LLVM ; mkdir build ; cd build + cmake -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;compiler-rt" -DCMAKE_BUILD_TYPE="Release" -DLLVM_TARGETS_TO_BUILD="host" -G "Unix Makefiles" ../llvm + make -j4 + ``` + + * [二进制安装](https://github.com/llvm/llvm-project/releases):下载对应版本的二进制文件,方便在不同版本间切换。可以使用软链接添加到环境变量中方便使用。 + * [包管理器安装](https://www.rootusers.com/how-to-install-dnf-package-manager-in-centosrhel/),版本较低,自带了libFuzzer。 + ```bash= + # sudo apt/dnf search xxx 可以查看包管理器中包含的软件以及对应版本 + sudo apt/dnf install clang llvm compiler-rt + ``` + +2. 编译被测二进制文件,加入LibFuzzer的编译选项 + + ```cpp= + // LibFuzzer提供的函数接口,在被测源代码fuzz_me.cc中实现 + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + DoSomethingInterestingWithMyAPI(Data, Size); + return 0; // Non-zero return values are reserved for future use. + } + ``` + + ```bash= + # clang会去寻找libclang_rt.xxx.a的静态链接库,即sanitizers + # 除了ASAN,还可以添加UBSAN,TSAN等其他sanitizers + clang -fsantize=address,fuzzer -g fuzz_me.c -o fuzz_me + ``` + +如果使用该编译命令失败,说明上一步安装不成功,需要检查compile-rt库的位置或重新安装。 + +3. 运行二进制文件,观察输出 + ```bash= + ./fuzz_me + grep ERROR ./*.log | sort -k 3 + ``` +如果程序的异常行为被sanitizer检测到,会产生Fuzzing output,即crash。除了crash,Fuzzer还会记录Fuzzing过程中的参数,例如代码覆盖率(以基本块为单位),种子变异情况等等。 + +4. 复现该输入,定位漏洞 + ```bash= + ./fuzz_me crash-xxx + ./fuzz_me -seed=xxx # xxx为crash的SHA-1哈希值 + gdb fuzz_me + ``` +sanitizer给出了漏洞类型和漏洞触发的环境。可以重新观察crash,复现漏洞,或放入gdb调试。 + +![](https://img-blog.csdnimg.cn/img_convert/585afb1d9b9b3892943e01d85abc25de.png) + + +### 一些有用的utils +面对大型软件时,还需要开启一些编译选项,来提高Fuzzing的效率: +* `-jobs`:任务数,每个job的目的就是触发crash,job在workers进程中运行,一个worker可以管理多个job。如果将jobs设置为1000,可以绕过程序的简单bug +* `-workers`:进程数,最多可使用一半的CPU核心数 +* `-forks`:将`-jobs = N`和`-workers = N`替换为`-fork = N` +* `-dict`:字典,在Fuzzing特定格式的文件时非常必要 +* `CORPUS`:语料库,用于保存Fuzzing中触发新路径的输入 +* `-max-len`:设置最大输入长度,根据语料库文件大小来定义 +* `-run`:减少crash producer,单位为每次迭代中的变异次数 +* `-shrink`:减小语料库大小,可能可以提高代码覆盖率 + + +### 项目实践 +* 课程:[`libfuzzer-workshop`](https://github.com/Dor1s/libfuzzer-workshop/)包括了LibFuzzer一些常见的使用方法,[此处为课程笔记](https://www.secpulse.com/archives/71898.html)。 +* 开源项目CVE实战:LibFuzzer发现了[许多开源软件中的漏洞](https://www.llvm.org/docs/LibFuzzer.html#trophies),包括OpenSSL中的Heartbleed漏洞,可以在Google的[`fuzzer-test-suite`](https://github.com/google/fuzzer-test-suite)中找到有漏洞的开源软件,并通过LibFuzzer进行复现。 +* 与其他工具的对比:LibFuzzerTutorial给出的[参考链接](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md#related-links)。 + +## LibFuzzer 原理 + +### 变异算法 +变异(Mutation)是现代Fuzzer中的关键步骤,用于产生新的且能够覆盖更多基本块的输入。LibFuzzer包含了一系列内置的简单的变异算法,大多为bit级反转。LibFuzzer同时也接受用户自定义变异算法,用于定向Fuzzing。 + +#### 已有变异算法 +通过观察LibFuzzer的[`Stderr Output`](https://www.llvm.org/docs/LibFuzzer.html#output),可以在MS字段发现当前输入使用的变异算法,如图所示。 + +![](https://img-blog.csdnimg.cn/img_convert/cac0122be891840a29113c2a1136c681.png) + +LibFuzzer一共内置了12种变异算法,属于`MutationDispatcher`类的成员函数,类定义代码如下: + +```cpp= +// 代码路径:LLVM/compiler-rt/lib/fuzzer/FuzzerMutate.cpp + +MutationDispatcher::MutationDispatcher(Random &Rand, const FuzzingOptions &Options) : Rand(Rand), Options(Options) { + DefaultMutators.insert( + DefaultMutators.begin(), + { + {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_InsertRepeatedBytes, "InsertRepeatedBytes"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, + {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, + {&MutationDispatcher::Mutate_AddWordFromManualDictionary, "ManualDict"}, + {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, "PersAutoDict"}, + }); + // 以上函数的具体实现 + } +``` + +大部分变异算法从名称就可以看出实现方法。比如`EraseBytes`即调用`memmove`函数覆盖掉部分比特位;`InsertBytes`即调用`memmove`函数添加一个比特位。值得注意的是,在这些内置的变异算法中,变异的位置的和变异的值都是采用`Rand`系列的随机函数生成。 + + +#### 如何添加新的变异算法 + +LibFuzzer和AFL属于`coverage-guided`的Fuzzing工具,在Fuzz具体的对象时,可能由于变异算法不包含语义信息而导致在程序运行的初期就被过滤掉,相对于generation-based的Fuzzing工具效率低下。Google由此提出了[`structure-aware-fuzzing`](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md)的高级概念,可以让用户自行添加变异算法,即`LibFuzzer Plugin`,文中也介绍了如何添加Plugin,并列举了一系列官方实现的Plugin。 + +添加Plugin的方法如下面代码所示。首先需要实现一个自定义的`LLVMFuzzerCustomMutator`函数,加入特定的变异算法,然后在该函数中调用`LLVMFuzzerMutate`来实现普通的变异。 + +在具体的代码实现中,可以通过条件编译指令`ifdef CUSTOM_MUTATOR`和`clang -DCUSTOM_MUTATOR`来开启或关闭自定义的Plugin。 + +```cpp= +// Optional user-provided custom mutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +// Given the same Seed produces the same mutation. +size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed); + +// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); +``` + +对于添加自己的Plugin感兴趣的同学,可以参考该文章中给出的[参考链接](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#related-links),也可以参考2017年LLVM开发者大会上的议题[`"Structure-aware fuzzing for Clang and LLVM with libprotobuf-mutator"`](https://www.youtube.com/watch?v=U60hC16HEDY) + +### 覆盖率统计 + +代码覆盖率统计方法需要从两个维度分析: + +* **统计精度**:从粗糙到精细,代码覆盖率(Coverage)的统计大致分为三个层次 + * `function level`:统计调用的函数,忽略对函数内部代码的统计 + * `basic block level`:统计标准块,可以在LibFuzzer的[`Stderr Output`](https://www.llvm.org/docs/LibFuzzer.html#output)的cov字段查找到 + * `edge level`:edge不仅包含了基本块信息,还在基本块之间建立虚拟块,以包含执行信息 + +![](https://img-blog.csdnimg.cn/img_convert/f3d19dfa66d44924b3386cd6860505c5.png) + +* **分析对象**:统计的基本方法是插桩(instrumentation),加入计数变量,大致分为三个级别 + * `source code`:在编译选项中提供覆盖率统计方式 + * `intermediate representation`:用`llvm pass`等方式统计 + * `binary`:使用`Pin`,`DynamoRIO`等二进制插桩工具去hook统计 + +综上所述,LibFuzzer使用了LLVM框架中的[`SanitizerCoverage`](https://clang.llvm.org/docs/SanitizerCoverage.html)来实现源代码级别的覆盖率统计,可以通过如下命令指定,默认使用`edge`级别。 + +```bash= +# xxx=edge,bb,func,trace-pc-guard,inline-8bit-counters,inline-bool-flag,pc-table,trace-pc +clang -fsanitize-coverage=xxx fuzz_me.c +``` + +此外,还可以在`SanitizerCoverage`的基础上开发分析工具。Sanitizer提供了覆盖率的回调接口,用户可以在Fuzzing进程关闭时将覆盖率统计的结果转储为`.sancov`文件。LLVM框架提供了`Sancov Tool`工具来生成源代码级别的覆盖率报告。 + +### 错误检查 + +#### 常见错误 + +前文提到,LibFuzzer进程中的每个`job`的使命就是完成检查任务。它直到遇到crash或者运行超时后才会停止。这时,LibFuzzer的守护进程会捕获错误码。如果错误码为77,则为超时(默认超时时间为1200秒)或者LibFuzzer本身程序异常;如果为crash,则将crash结果以及造成crash的输入记录下来。 + +#### Sanitizers + +而仅仅检测出crash并不够覆盖所有Fuzzing的检测场景,比如内存泄漏,竞态等情况虽然可能不会造成crash,但也是非常严重的一类错误。针对这些非crash的错误,有像`Valgrind`这样的重量级内存检测工具。而LibFuzzer使用的是LLVM框架中的一系列[`Sanitizers`](https://github.com/google/sanitizers)。这些工具由Google提出,可以用于检测C/C++语言的各类运行时异常,比较常用的Sanitizers列举如下: +* `AddressSanitizer(ASAN)`:捕获堆栈溢出,UAF等漏洞 +* `ThreadSanitizer(TSAN)`:捕获data race,支持C/C++和Go +* `UndefinedBehaviorSanitizer(UBSAN)`:捕获整数溢出,空指针解引用等异常行为 + +以ASAN为例来分析这些错误检查工具的原理,详细介绍可以看[`USENIX ATC 2021`](http://research.google.com/pubs/pub37752.html)。 + +1. 在编译时,ASAN在LLVM IR级别的访问内存操作(load,store,alloca)的前后插桩。由于内存有8字节对齐的要求,所以部分内存处于unused状态,可以使用内存映射的方式将其设置为`shadow memory`,来指示其读写情况。 +2. 在运行时对malloc函数进行HOOK,并在前后设置`Redzone`区域,类似于Stack Canary的做法。将Redzone区域的shadow memory设置为不可写,即可避免溢出问题。 +3. 在运行时对free函数进行HOOK,不立即释放该内存,而是将shadow memory设置为负数,即不可读写的状态,并放入隔离区观察。如果发生UAF或者野指针解引用的情况,则会被捕获。 + +![](https://img-blog.csdnimg.cn/img_convert/e70c15eb1734af0179d9745801a3e88d.png) + + +## 其他 Fuzzer + +* 学术界:Fuzzing作为学术热点,近年来在系统安全,网络安全,软件分析,程序语言等领域的国际顶级会议上都有许多相关论文,可以查看[`FuzzingPaper`](https://github.com/wcventure/FuzzingPaper)项目。这些论文大多是提出一种针对某一特定对象(软件,OS内核,硬件,程序语言等等)或者特定漏洞类型(竞态条件,缓冲区溢出)的Fuzzer,并结合符号执行(Concolic Fuzzing),深度学习等方法提高Fuzzing效率。 + +* 工业界:在AFL,LibFuzzer这样的工具诞生之后,Github上陆续有许多在此基础上开发的工具,也有许多主打模糊测试技术的公司兴起。其中比较著名的是Google提出的一系列Fuzzing工具,包括其维护的`Fuzzbench`平台,可以对Fuzzer性能进行统一评估。 + +总体来说,学术界和工业界在Fuzzing的研究上还是非常相关的。因为大部分Fuzzing技术基于LLVM框架实现,所以可扩展性很强。学术界的工作基于工业界的已有的工具扩展开发,而学术界性能较好的成果,也会发布到Github上。以下列举一些我在学习Fuzzing过程中收藏的Fuzzer,更完整的版本可以查看[`Awesome-Fuzzing`](https://github.com/secfigo/Awesome-Fuzzing) +* 通用 + * [`LibFuzzer-gv`](https://github.com/guidovranken/libfuzzer-gv):LibFuzzer增强版 + + * [`AFL++`](https://aflplus.plus/):AFL增强版 + + * [`OSS-Fuzz`](https://google.github.io/oss-fuzz/)+[ClusterFuzz](https://google.github.io/clusterfuzz):前后端配合实现的大规模分布式Fuzzer + + * [`boofuzz`](https://boofuzz.readthedocs.io/en/stable/):Sulley框架增强版 + + * [`phuzzer`](https://github.com/angr/phuzzer):和AFL交互的python框架 + +* 安全 + * [`Honggfuzz`](https://honggfuzz.dev/):更加针对于软件安全漏洞的Fuzzer + + +* 网络协议 + * [`AFLNet`](https://github.com/aflnet/aflnet):针对网络协议的灰盒Fuzzer + +* 内核 + * [`Syzkaller`](https://github.com/google/syzkaller):无监督的linux内核Fuzzer + +* 编程语言 + * [使用Rust实现的一系列Fuzzer](https://github.com/rust-fuzz):包括AFL,LibFuzzer,Honggfuzz + * [`PolyGlot`](https://github.com/s3team/Polyglot):针对程序语言解释器的Fuzzer + +* IoT + * [`FirmAFL`](https://github.com/zyw-200/FirmAFL):针对IoT固件的灰盒Fuzzer + * [`DIANE`](https://github.com/ucsb-seclab/diane):针对IoT配套的手机APP的Fuzzer + * [`Frankenstein`](https://github.com/seemoo-lab/frankenstein):Fuzz无线物联网设备 + +> 有错误之处请批评指正,作者联系方式:[cascades-sjtu](https://cascadeschen.cn) diff --git "a/web-ui/docs/zh/blog/cascades/2021-8-14-QemuFuzzer\345\255\246\344\271\240.md" "b/web-ui/docs/zh/blog/cascades/2021-8-14-QemuFuzzer\345\255\246\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..e7f8f5e4ab9f170247a93a3e24f34ec9d54ff038 --- /dev/null +++ "b/web-ui/docs/zh/blog/cascades/2021-8-14-QemuFuzzer\345\255\246\344\271\240.md" @@ -0,0 +1,415 @@ +--- +title: 【开源软件供应链点亮计划】Qemu Fuzzer学习 +date: 2021-08-15 +tags: + - Qemu + - Virtio + - summer2021 +archives: 2021-08 +author: cascades +summary: Qemu Fuzzer是一个借助libqtest和LibFuzzer,对GusetOS读写设备的过程进行模糊测试的框架,包含在Qemu 5.0以后的版本中。 +--- + +# Qemu Fuzzer学习 + +> 本文章来自于[开源软件供应链点亮计划](https://summer.iscas.ac.cn/)的openEuler社区项目 +> 项目名称:[No.112 qemu设备fuzz测试完善](https://gitee.com/openeuler-competition/summer2021-112) + +## 前言 +一提到 Qemu + Fuzz 的组合,我首先想起的是AFL的Qemu模式,或者是各种使用虚拟化技术对IoT设备进行Fuzzing的工具。 + +而本文学习的是Qemu自身的Fuzzing框架,即对Hypervisor的Fuzzing。它借助Qtest框架模拟Guest OS对设备的读写,并使用LibFuzzer的启发式算法提供数据驱动。该框架最早源于[`Google Summer of Code 2019`](https://summerofcode.withgoogle.com/archive/2019/projects/6200259867312128/)项目,在Qemu5.0.0版本后被加入到master分支中。 + +## Qemu 设备模拟原理 + +[`Qemu`](https://www.qemu.org/)是一款开源的虚拟化和仿真工具,由[`Fabrice Bellard`](https://bellard.org/)实现。Qemu支持两种模式的仿真: +* `system mode`:对于CPU,内存以及外设的全系统仿真,提供KVM,Hyper-V等加速方式 +* `user mode`:通过指令翻译在一种架构的CPU上运行另一种CPU架构的二进制程序 + +首先需要理解虚拟化的本质在于:使用一个用户态的程序,在只使用用户态内存的情况下,来处理模拟设备对内存以及其他特殊硬件的访问。由于Qemu需要仿真不同架构,不同指令集的设备,所以其采用了OOP的编程思想,实现了`Qemu Object Model`来描述设备模型。 + +* 设备模型:每个模拟出来的设备都对应一个TypeInfo对象,由设备名唯一标识,并存储在hash table中 +* 设备启动:启动设备需要经过设备注册,设备类型初始化,设备实例化等步骤, +* 指令翻译:真正运行时,Qemu通过TCG(软件)或者KVM(硬件)等方式,接受模拟设备的指令,并翻译到物理设备上执行。这样会带来性能开销,相比起来硬件虚拟化带来的开销更低 +* 内存模拟:Qemu负责提供内存映射给客户机。当客户机访问这部分内存以便写磁盘时,Qemu会捕获访问,并且将请求传送给qemu的IDE控制器设备模型,模型会解析I/O请求并且通过宿主机的系统调用来模拟指令。最终将客户机的内存拷贝至宿主机的磁盘中。 + +总之,在Guest OS中,它认为自己可以直接和Host OS上的硬件设备打交道,Qemu充当了中间人的角色,可以用下图来概括: + +```asciidoc= ++----------+ +----------+ +----------+ +----------+ +----------+ +| UserSpace| | UserSpace| | UserSpace| | UserSpace| | UserSpace| ++----------+ +----------+ +----------+ +----------+ +----------+ +| Linux | | Mac OS | | Windows | | Linux | | Solaris | ++----------+ +----------+ +----------+ +----------+ +----------+ +| Drivers | | Drivers | | Drivers | | Drivers | | Drivers | ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+ +----------+ +----------+ +----------+ +----------+ +| QEMU x86 | | QEMU x86 | | QEMU ARM | | QEMU PPC | | QEMU MIPS| ++----------+ +----------+ +----------+ +----------+ +----------+ ++----------+-+----------+-+----------+-+----------+-+----------+ +| Host System:Linux,Mac OS,Windows | ++--------------------------------------------------------------+ ++--------------------------------------------------------------+ +| Hardware:CPU,memory,disk,networking,USB,etc | ++--------------------------------------------------------------+ +``` + +> 关于Qemu设备模拟的方法,可以参考[`User Documentation`](LLVMFuzzerTestOneInput) +> 关于Qemu设备模拟的理解,可以参考[`understanding Qemu devices`](https://www.qemu.org/2018/02/09/understanding-qemu-devices/) +> Qemu作者的论文:[`QEMU, a Fast and Portable Dynamic Translator`](https://www.usenix.org/legacy/event/usenix05/tech/freenix/full_papers/bellard/bellard.pdf#:~:text=We%20present%20the%20internals%20of%20QEMU%2C%20a%20fast,one%20target%20CPU%20can%20be%20runon%20another%20CPU.) + +## Qemu Fuzzer 的使用方法 + +[文档说明](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html) + +### 实验环境 + +采用了本机的WSL上的Docker环境 + +```bash= +root@31b23c4c00b7:~/qemu# lscpu +Architecture: x86_64 +CPU op-mode(s): 32-bit, 64-bit +Byte Order: Little Endian +CPU(s): 16 +root@31b23c4c00b7:~/qemu# cat /etc/os-release +NAME="Ubuntu" +VERSION="20.04.2 LTS (Focal Fossa)" +``` + +#### 环境问题 + +* 描述:Qemu的Fuzzing还没有适配AArch64架构,虽然编译成功,但运行报错。 + +![](https://img-blog.csdnimg.cn/img_convert/2161923b370fbd9f89318104b70fad11.png) + +* 解决方案:适配AArch64下的Qemu Fuzzing正是本项目要做的内容,但在学习阶段,还是采用x86环境来运行。 + +#### 版本问题 + +* 描述:官网给出的示例使用的是clang-8,而最新的clang版本已经来到了clang-14,如果采用较新的版本,则会在编译阶段报错(原因为开启了Werror)。 + +* 解决方案: + * (推荐)直接采用包管理器(apt/dnf)安装clang + * git checkout到LLVM8-10之间的版本 + * 到[官方Release页面](https://releases.llvm.org/)下载LLVM8-10之间版本的源代码 + +```bash= +# sudo apt/dnf search xxx 可以查看包管理器中包含的软件以及对应版本,默认为clang-10 +sudo apt/dnf install clang llvm compiler-rt +``` + +#### Docker打包 + +为了方便部署,采用了docker的形式来配置实验环境:[镜像地址](https://hub.docker.com/repository/docker/cascadessjtu/qemu_fuzz)。 + +### 简单使用 + +配置好环境后,通过如下命令编译运行Fuzzing程序,即显示LibFuzzer的输出。 + +```bash= +CC=clang-10 CXX=clang++-10 ./configure --enable-sanitizers --enable-fuzzing +# qemu-fuzz-isa isa为模拟设备的架构 +make qemu-fuzz-i386 qemu-fuzz-aarch64 +# 查看可用的Fuzzing对象 +build/qemu-fuzz-i386 --fuzz-target=FUZZ_NAME +``` + +除了上述命令外,Qemu Fuzzer还支持LibFuzzer的编译指令,可以通过`-help=1`来查看 + +对于Fuzzing的结果,可以考虑采用[`Clang Sanitizer`](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html#generating-coverage-reports)查看。该工具需要使用CORPUS参数,并对编译指令进行一定的修改。在Fuzzing结束后,通过`llvm-cov`命令将生成的`default.profraw`文件转化为`.html`的可视化文件。 + +### 添加自定义Fuzzer + +添加一个新的Fuzzer需要以下三个步骤: +1. 编写Fuzzer源文件`foo-device-fuzz.c`,放在`tests/qtest/fuzz`目录下 +2. 参考已有的Fuzzer,使用libqos和libqtest中的API与模拟设备通信 +3. 在`tests/qtest/fuzz/meson.build`文件中注册该Fuzzer + +### 通用Fuzzer + +为某些特定的设备类型写Fuzzer是非常费时费力的事情,尤其是那些libqos并没有包含的设备驱动。Qemu提供了`generic-fuzz`的选项,用于对所有设备进行初步的Fuzzing,包括设备的PIO,MMIO和DMA。如果要启用generic-fuzz,至少需要设置以下两个环境变量: +* `QEMU_FUZZ_ARGS=`:配置设备所需要的参数,比如网卡,用户名 +* `QEMU_FUZZ_OBJECTS`=:采用字符串匹配的方式来指定Fuzzing的内存区域。可以用`./qemu-fuzz-i386 --fuzz-target=generic-fuzz -runs=0`来检查匹配到的内存区域。如果匹配到的内存区域越多,Fuzzing的`input-space`就越大,越难发现导致该设备crash的输入,所以`MemoryRegion`的选取要适度。 + +### 集成OSS-Fuzz +OSS-Fuzz是集成式的Fuzzing工具,它默认对所有的对象进行Fuzz。由于通用Fuzzer的启动需要额外对环境变量进行设置,所以Qemu在`tests/qtest/fuzz/generic_fuzz_configs.h`文件中自定义了一些设备类型,用于OSS-Fuzz。开发者可以在该文件中添加新的设备类型,官方也提供了用于搭建环境的[`Dockerfile`](https://github.com/google/oss-fuzz/blob/master/projects/qemu/Dockerfile)。 + +### crash复现工具 + +当复现crash的时候,需要不包含Fuzzer的Qemu,这样可以过滤调误报,并增强调试功能。可以使用OSS-Fuzz的脚本来创建一个`one-line reproducer`。 + +### Fuzzer生命周期 + +Qemu Fuzzer为LibFuzzer提供了两处入口点,在LibFuzzer自己的main函数之后调用: +* `LLVMFuzzerInitialize`:Fuzzing开始前调用,初始化环境 +* `LLVMFuzzerTestOneInput`:每个Fuzzing任务运行时调用,提供输入并在Fuzzing结束后重置状态 + +因为Fuzzer的进程会在每次Fuzzing运行后被重置(reset),所以Qemu的状态也需要重置,有两种方法来实现重置,各有优劣。 +* `Reboot`:在每次运行之间重启Guest OS +* `Fork`:在子进程中运行test case,和AFL的`fork-server`模式很相似 + +## Qemu Fuzzer的依赖库 + +Qemu Fuzzer实现主要依赖的是libqtest和libqos两个库,它们的关系可以参考[`Testing QEMU emulated devices using qtest`](https://www.linux-kvm.org/images/4/43/03x09-TestingQEMU.pdf),这篇文章介绍了qtest的基本原理,提供的API函数,并给出了添加testcase的方法。 + +### libqtest + +* [代码路径](https://github.com/qemu/qemu/tree/master/tests/qtest/libqtest.c) +* [文档说明](https://qemu.readthedocs.io/en/latest/devel/qtest.html) + +Qtest是一个用于对Qemu模拟出的硬件设备做单元测试的框架,它由`Qtest Client`,`Qtest Server`两部分组成。两者之间通过UNIX Socket通信,支持PIO,MMIO,中断,QMP等指令。 + +* `Qtest Client`:它是为某个设备编写的驱动程序,按照自底向上的封装顺序,它依赖于glib单元测试框架,libqtest,libqos和qgraph。如果需要添加新的测试程序,需要如下四个步骤: + 1. 在Qtest目录下编写新的测试代码`tests/qtest/foo-test.c` + 2. 在Makefile.include中添加编译指令 + 3. 编译:`make tests/qtest/foo-test.c` + 4. 运行: + ```bash= + QTEST_LOG=1 QTEST_QEMU_BINARY=i386-softmmu/qemu-system-i386 tests/qtest/foo-test` + ``` +* `Qtest Server`:它和TCG,KVM的功能类似,是一种加速器(accelerator),通过编译指令`-machine accel=qtest`注册。在普通的使用场景中,VCPU直接和虚拟硬件交互;而测试场景中,Qtest直接和虚拟硬件交互,充当了Qtest Client和虚拟硬件的中间角色。Qtest用于验证设备的行为是否正确,实际上并没有启动Guest OS。 + +运行时,`libqtest.c`将启动Qemu为子进程。Qemu的启动主函数在`vl.c`中,在测试场景中,调用`qtest.c`的`qtest_init()`函数,初始化Qtest Server。 + +两者的关系可以用下图表示: +```asciidoc= ++----------------+ socket +----------------+----------------------+ +| Qtest Client +----------> Qtest Server | | ++----------------+ +-------+--------+ | ++----------------+ | | Qemu | +| Qgraph | PIO|MMIO | | ++----------------+ | | | ++----------------+ +-------v--------+----------------------+ +| libqos | | Hardware Emulation | ++----------------+ +---------------------------------------+ ++----------------+ +| libqtest | ++----------------+ ++----------------+ +| glib test | ++----------------+ +``` + +### libqos + +* [代码路径](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/libqos.c) +* [文档说明](https://qemu.readthedocs.io/en/latest/devel/qtest.html?highlight=libqos) + +libqos是用于编写qtest case的设备驱动框架,提供了关于`memory`,`PCI`,`virtio`的API函数。它的功能主要有以下两个: +* 相当于总线的wrapper,为每类总线都实现了特定的函数 +* 统一了设备访问的模型,简化了开发者的工作 + +## Qemu Fuzzer 的整体流程 + +* [代码路径](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz) +* [文档说明](https://qemu.readthedocs.io/en/latest/devel/fuzzing.html) + +以上的两个依赖库都是为Qemu的功能性测试设计,依赖于测试输入的选取。而Fuzzing正是通过对输入增加随机性和变异算法来提高测试输入的质量。从而可以使用LibFuzzer对Qtest的输入进行HOOK,提高Qtest的测试效率。综上所述,Qemu Fuzzer的整体结构如图所示。 + +![](https://img-blog.csdnimg.cn/img_convert/f269d3ace4fe504117d7fe4e2a253375.png) + +从源代码的角度来看: +* `fuzz.h`:定义了实现一个Fuzz Target用到的接口和数据结构,以及与LibFuzzer之间的交互 +* `fork_fuzz.h`:定义了并发Fuzzer之间的共享内存 +* `qos_fuzz.h`:定义了libqos在qtest上的进一步封装的接口 +* `generic_fuzz_configs.h`:定义了通用的Fuzzer设置 +* `virtio_xxx_fuzz.h`:实现了virtio设备(net,blk,scsi)的Fuzz Target + +## Qemu Fuzzer 的用例分析 + +Qemu的[`Developer documentation`](https://wiki.qemu.org/Documentation/GettingStartedDevelopers)中写道: + +> QEMU does not have a high level design description document - only the source code tells the full story. + +所以作为Qemu的开发者,阅读源码非常关键。本节以virtio-net设备为例,分析Qemu Fuzzing的流程,代码路径为[`tests/qtest/fuzz/virto_net_fuzz.c`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/virtio_net_fuzz.c)。virtio是一种半虚拟化的技术,需要Host OS提供对设备的emulation,Guest OS负责对设备的驱动。工作模式如下图所示: + +![](https://img-blog.csdnimg.cn/img_convert/8cbe7f371f062202bb88928900b3a481.png) + +实现方面,以自顶向下的逻辑进行说明: +* 首先,实现注册函数`register_virtio_net_fuzz_targets()`。使用libqos提供的`fuzz_add_qos_target()`函数添加了三个Fuzzing对象。该函数是libqos对于`fuzz_add_target()`函数的wrapper,其原型如下: + +```cpp= +void fuzz_add_qos_target( + FuzzTarget *fuzz_opts, + const char *interface, + QOSGraphTestOptions *opts + ); +``` + +* 最后,修改[`meson.build`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c)文件,添加条件编译选项。 + +接下来,以`virtio-net-socket`为主,对Fuzzing对象的参数以及参数中涉及到的函数进行分析 + +* `virtio-net-socket`: +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket", + .description = "Fuzz the virtio-net virtual queues. Fuzz incoming " + "traffic using the socket backend", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +第一个参数为指向FuzzTarget的临时对象的指针。该对象由[`fuzz.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/fuzz/fuzz.c)定义,含标识信息和许多与Fuzzing特性相关的回调函数。介绍如下: +```asciidoc= ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| Field | Declaration | Description | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| name | const char *name | target identifier (passed to --fuzz-target=) | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| description | const char *description | help text | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| pre_fuzz | void(*pre_fuzz)(QTestState *) | will run once, after QEMU has been initialized, prior to the fuzz-loop. | +| | | eg: detect the memory map | +| | | Can be NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| fuzz | void(*fuzz)(QTestState *, const unsigned char *, size_t); | accepts and executes an input from LibFuzzer. | +| | | this is repeatedly executed during the fuzzing loop. | +| | | Its should handle setup, input execution and cleanup. | +| | | Cannot be NULL | ++-------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +``` + +其中,`virtio_net_pre_fuzz`初始化了qos path和fork fuzz用到的共享内存。`virtio_net_fork_fuzz`首先fork出子进程,并调用`virtio_net_fuzz_multi`函数。该函数用自定义的`vq_action`来管理随机数据,根据数据包到来情况,将其加入`virtioqueue`中,并kick out出去。随后运行主循环。 + +第二个参数表示使用的设备接口名称,这里统一为virtio-net。 + +第三个参数为[`qgraph.h`](https://github.com/qemu/qemu/tree/master/tests/qtest/libqos/qgraph.h)提供的关于测试选项的结构体。其中`before`参数接受原型为`QOSBeforeTest`的函数。`virtio_net_test_setup_socket`函数指定了Qemu网络设备的后端为socket。它负责和虚拟设备通信,并将虚拟设备的数据包发送到宿主机的网络设备中。 + +* `virtio-net-socket-check-use` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-socket-check-used", + .description = "Fuzz the virtio-net virtual queues. Wait for the " + "descriptors to be used. Timeout may indicate improperly handled " + "input", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz_check_used,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} + ); +``` + +`virtio_net_fork_fuzz_check_used`和`virtio_net_fork_fuzz`非常相似,不同之处在于调用`virtio_net_fuzz_multi`函数的时候使用了`true`。 + +* `cirtio-net-slirp` + +```cpp= +fuzz_add_qos_target(&(FuzzTarget){ + .name = "virtio-net-slirp", + .description = "Fuzz the virtio-net virtual queues with the slirp " + " backend. Warning: May result in network traffic emitted from the " + " process. Run in an isolated network environment.", + .pre_fuzz = &virtio_net_pre_fuzz, + .fuzz = virtio_net_fork_fuzz,}, + "virtio-net", + &(QOSGraphTestOptions){.before = virtio_net_test_setup_user} + ); +``` + +`virtio_net_test_setup_user`指定了网络后端的类型为user + +## Qemu Fuzzer 案例 CVE-2017-12809 + +最后,简要分析一个[由LibFuzzer发现](https://unit42.paloaltonetworks.com/unit42-palo-alto-networks-discovers-new-qemu-vulnerability/)的Qemu上的CVE漏洞。 +* 漏洞描述:该漏洞属于拒绝服务类。当通过IDE硬盘和CD/DVD-ROM模拟器来构建Guest OS时,Guest OS中的特权用户可以通过清除一个空的CDROM设备驱动,造成空指针解引用,进而导致Qemu进程崩溃。 +* 漏洞代码: 在`hw/ide/core.c`文件中调用`blk_aio_flush()`函数前没有检查`s->blk`是否为空 +```asciidoc= +--- + hw/ide/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index 0b48b64d3a..bea39536b0 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s) + s->status |= BUSY_STAT; + ide_set_retry(s); + block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH); +- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ ++ if (blk_bs(s->blk)) { ++ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); ++ } else { ++ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this ++ * temporary workaround when blk_aio_*() functions handle NULL blk_bs. ++ */ ++ ide_flush_cb(s, 0); ++ } + } + + static void ide_cfata_metadata_inquiry(IDEState *s) +-- +``` +* [漏洞修复](https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg01989.html):除了在漏洞发生部分增加条件判断以外,还在`tests/ide-test.c`中增加了测试代码 + +```asciidoc= +--- + tests/ide-test.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/tests/ide-test.c b/tests/ide-test.c +index bfd79ddbdc..aa9de065fc 100644 +--- a/tests/ide-test.c ++++ b/tests/ide-test.c +@@ -689,6 +689,24 @@ static void test_flush_nodev(void) + ide_test_quit(); + } + ++static void test_flush_empty_drive(void) ++{ ++ QPCIDevice *dev; ++ QPCIBar bmdma_bar, ide_bar; ++ ++ ide_test_start("-device ide-cd,bus=ide.0"); ++ dev = get_pci_device(&bmdma_bar, &ide_bar); ++ ++ /* FLUSH CACHE command on device 0 */ ++ qpci_io_writeb(dev, ide_bar, reg_device, 0); ++ qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE); ++ ++ /* Just testing that qemu doesn't crash... */ ++ ++ free_pci_device(dev); ++ ide_test_quit(); ++} ++ + static void test_pci_retry_flush(void) + { + test_retry_flush("pc"); +@@ -954,6 +972,7 @@ int main(int argc, char **argv) + + qtest_add_func("/ide/flush", test_flush); + qtest_a + cd qemu + git checkout stable-2.10dd_func("/ide/flush/nodev", test_flush_nodev); ++ qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive); + qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush); + qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush); + +-- +``` + +* 漏洞复现:找到patch前的commit版本,加上新增test中的测试用例,运行qtest程序: +```bash= +# 不能直接wget对应的release版本,因为受影响的版本都被修复了 +git clone https://gitlab.com/qemu-project/qemu.git;cd qemu +git checkout stable-2.10 +# 从mailing list中获取patch的作者,找对应的commit +git log --author=Hajnoczi +git reset --hard=4da97120d51a4383aa96d741a2b837f8c4bbcd0b +# 构建 +mkdir build;cd build;../configure ----disable-werror +make qtest +``` + +其实Qemu虚拟机逃逸漏洞已经常见于CTF比赛和CVE中了,比如知名的[CVE-2020-14364](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14364) + +> 有错误之处请批评指正,作者联系方式:[cascades-sjtu](https://cascadeschen.cn) + diff --git a/web-ui/docs/zh/blog/compile_success/2021-01-23-dnspooq.md b/web-ui/docs/zh/blog/compile_success/2021-01-23-dnspooq.md new file mode 100644 index 0000000000000000000000000000000000000000..09ddcc263520c5f297f4105db06777f86c896a81 --- /dev/null +++ b/web-ui/docs/zh/blog/compile_success/2021-01-23-dnspooq.md @@ -0,0 +1,61 @@ +--- +title: DNSpooq漏洞分析 +date: 2021-01-23 +tags: + - CVE + - 漏洞分析 +archives: 2021-01 +author: compile_success +summary: DNSpooq漏洞分析 +--- + +### 1.1 概述 +Dnsmasq是一个开源的轻量级DNS转发软件,为小型网络提供DNS和DHCP等网络基础服务,被广泛地用于智能手机和IoT设备。近期JSOF披露了七个Dnsmasq漏洞(CVE-2020-25681、CVE-2020-25682、CVE-2020-25683、CVE-2020-25684、CVE-2020-25685、CVE-2020-25686和CVE-2020-25687),这些漏洞被统称为DNSpooq,攻击者可以利用这些漏洞发起DNS缓存投毒、远程执行代码和拒绝服务攻击。 + +### 1.2 漏洞详情 + + + +1)缓冲区溢出漏洞:CVE-2020-25681、CVE-2020-25682、CVE-2020-25683、CVE-2020-25687 +当dnsmasq被配置为使用DNSSEC时,攻击者成功利用这些漏洞,可以导致远程执行任意代码或者dnsmasq服务崩溃。这4个CVE主要涉及两个函数: +static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx, + unsigned char **rrset, char *buff1, char *buff2) +static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen, unsigned char **p, u16 **desc) + +sort_rrset中的代码: + + + 当get_rdata返回0时,表示RDATA中的剩余数据被复制到buff1中。由于buff1的大小为MAXDNAME * 2(2050)字节,同时由于dnsmasq支持使用UDP进行数据传输,而UDP允许的最大报文长度为4096字节,由于代码中缺少长度校验,所以攻击者可以发送超过2050字节的RRset报文,触发系统缓冲区溢出。 + +2)DNS缓存投毒:CVE-2020-25684 CVE-2020-25685 CVE-2020-25686 +DNS缓存投毒攻击(也称为DNS欺骗)。DNS缓存投毒是一种攻击方法,攻击者利用该方法可以篡改设备上的DNS记录,将恶意DNS注入到设备中,从而将用户重定向到攻击者指定的恶意服务器。 + +### 1.3 影响性分析 + +影响范围 dnsmasq< 2.83的版本源代码之中均存在该漏洞,openEuler使用的是2.82版本。 + +### 1.4 缓解措施 + +1、缓冲区溢出漏洞:CVE-2020-25681、CVE-2020-25682、CVE-2020-25683、CVE-2020-25687 +在升级漏洞修复版本之前,暂时禁用DNSSEC验证选项。 + +2、DNS缓存投毒:CVE-2020-25684 CVE-2020-25685 CVE-2020-25686 +禁用dnsmasq缓存:在/etc/dnsmasq.conf配置文件中添加cache-size=0配置。 +说明:禁用dnsmasq缓存后,所有DNS查询都转发到上游服务器,所以影响DNS的响应速度,在应用之前,请评估缓解措施是否适合系统的环境。 + +### 1.5 漏洞修复方法 + +• 下载openEuler发布最新的dnsmasq软件包: + 漏洞SA:https://www.openeuler.org/zh/security/safety-bulletin/detail.html?id=openEuler-SA-2021-1001 + 20.03-LTS: + [aach64架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/aarch64/Packages) + [x86架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/x86_64/Packages) + 20.03-LTS-SP1: + [aach64架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/update/aarch64/Packages/) + [x86架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/update/x86_64/Packages/) +• 升级dnsmasq软件包 + rpm -Uvh dnsmasq-*.rpm +• 升级完成之后查看dnsmasq软件包是否升级成功。 + rpm -qi dnsmasq + 20.03-LTS修复版本:dnsmasq-2.82-4。 + 20.03-LTS-SP1修复版本:dnsmasq-2.82-5。 diff --git a/web-ui/docs/zh/blog/compile_success/2021-01-23-images/1.png b/web-ui/docs/zh/blog/compile_success/2021-01-23-images/1.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6bbc027a481d3db70d6038aafd1276e46b9d08 Binary files /dev/null and b/web-ui/docs/zh/blog/compile_success/2021-01-23-images/1.png differ diff --git a/web-ui/docs/zh/blog/compile_success/2021-01-23-images/2.png b/web-ui/docs/zh/blog/compile_success/2021-01-23-images/2.png new file mode 100644 index 0000000000000000000000000000000000000000..83b5f23037bb29eb203471772dbd2f40867c43ba Binary files /dev/null and b/web-ui/docs/zh/blog/compile_success/2021-01-23-images/2.png differ diff --git a/web-ui/docs/zh/blog/dwl301/2021-10-12-openEuler-21.09_Installing_GNOME3.38.md b/web-ui/docs/zh/blog/dwl301/2021-10-12-openEuler-21.09_Installing_GNOME3.38.md new file mode 100644 index 0000000000000000000000000000000000000000..ff76aa01fef4f50790f96630220bda5a4550b46d --- /dev/null +++ b/web-ui/docs/zh/blog/dwl301/2021-10-12-openEuler-21.09_Installing_GNOME3.38.md @@ -0,0 +1,152 @@ +--- +title: 在 openEuler-21.09 上安装 GNOME-3.38 +date: 2021-10-12 +tags: + - GNOME +archives: 2021-10 +author: dwl301 +summary: 如何在openEuler-21.09上安装GNOME-3.38,以及如何解决已知问题 +--- + +# 在 openEuler-21.09 上安装 GNOME-3.38 + +GNOME是运行在类Unix操作系统中最常用桌面环境。是一个功能完善、操作简单,界面友好,集使用和开发为一身的桌面环境,是GNU计划的正式桌面。 + +参照本文在 openEuler-21.09 上安装一个完整的GNOME桌面环境。 + +##1. 下载 openEuler-21.09 镜像 +``` +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso.sha256sum +# wget https://repo.openeuler.org/openEuler-21.09/ISO/x86_64/openEuler-21.09-x86_64-dvd.iso +# sha256sum -c openEuler-21.09-x86_64-dvd.iso.sha256sum +openEuler-21.09-x86_64-dvd.iso: OK +``` + +##2. 制作系统安装介质 +假设下面的 sdb 是 USB 存储设备,可以通过 lsblk 确认你的设备。 +``` +# dd if=./openEuler-21.09-x86_64-dvd.iso of=/dev/sdb +# sync +``` + +##3. 安装系统 +从你的 USB 设备启动,选择最小化安装系统即可。 +系统安装完根分区至少应保留5G左右的剩余空间安装 GNOME-3.38。 + +##4. 配置系统并安装GNOME-3.38 +设置系统 yum 源 +确定以下地址在你的 /etc/yum.repos.d/openEuler.repo 中正常启用: +``` +baseurl=http://repo.openeuler.org/openEuler-21.09/everything/x86_64/ +baseurl=http://repo.openeuler.org/openEuler-21.09/EPOL/main/x86_64/ +``` + +刷新 yum 缓存 +``` +# yum clean all +# yum makecache +``` + +安装字体相关包 +``` +# yum install -y dejavu-fonts liberation-fonts gnu-*-fonts wqy-*-fonts cjkuni-ukai-fonts +``` +如果网络不错可以顺带安装 google-\*-fonts,有几个google的字体包特别大,网速慢可以选择不安装。 + +安装 XServer 相关包 +``` +# yum install -y xorg-* +``` + +安装 GNOME-3.38 相关包 +``` +# yum install -y adwaita-icon-theme atk atkmm at-spi2-atk at-spi2-core baobab abattis-cantarell-fonts cheese clutter clutter-gst3 clutter-gtk cogl dconf dconf-editor devhelp eog epiphany evince evolution-data-server file-roller folks gcab gcr gdk-pixbuf2 gdm gedit geocode-glib gfbgraph gjs glib2 glibmm24 glib-networking gmime30 gnome-autoar gnome-backgrounds gnome-bluetooth gnome-boxes gnome-builder gnome-calculator gnome-calendar gnome-characters gnome-clocks gnome-color-manager gnome-contacts gnome-control-center gnome-desktop3 gnome-disk-utility gnome-font-viewer gnome-getting-started-docs gnome-initial-setup gnome-keyring gnome-logs gnome-menus gnome-music gnome-online-accounts gnome-online-miners gnome-photos gnome-remote-desktop gnome-screenshot gnome-session gnome-settings-daemon gnome-shell gnome-shell-extensions gnome-software gnome-system-monitor gnome-terminal gnome-tour gnome-user-docs gnome-user-share gnome-video-effects gnome-weather gobject-introspection gom grilo grilo-plugins gsettings-desktop-schemas gsound gspell gssdp gtk3 gtk4 gtk-doc gtkmm30 gtksourceview4 gtk-vnc2 gupnp gupnp-av gupnp-dlna gvfs json-glib libchamplain libdazzle libgdata libgee libgnomekbd libgsf libgtop2 libgweather libgxps libhandy libmediaart libnma libnotify libpeas librsvg2 libsecret libsigc++20 libsoup mm-common mutter nautilus orca pango pangomm libphodav python3-pyatspi python3-gobject rest rygel simple-scan sushi sysprof tepl totem totem-pl-parser tracker3 tracker3-miners vala vte291 yelp yelp-tools yelp-xsl zenity +``` + +使用登录管理器 gdm 启动 GNOME-3.38 +``` +# systemctl start gdm +``` + +设置开机默认启动桌面登录 +``` +# systemctl enable gdm +# systemctl set-default graphical.target +``` + +##5. 已知问题解决 +###5.1 视频无法播放 +缺少解码器,手动编译安装解码器: +``` +# yum install rpm-build git ffmpeg-devel +# git clone https://gitee.com/src-openeuler/gstreamer1-libav.git +# mkdir -p ~/rpmbuild/SOURCES +# cp gstreamer1-libav/* /root/rpmbuild/SOURCES/ +# rpmbuild -ba /root/rpmbuild/SOURCES/gstreamer1-libav.spec +# yum install -y /root/rpmbuild/RPMS/x86_64/gstreamer1-libav-1.18.4-1.x86_64.rpm +``` +请确保每一步命令正常执行没有报错。 + +###5.2 gnome-boxes 无法使用本地 iso 创建虚拟机 +升级 gnome-boxes。默认版本 qemu 模式下运行虚拟机设置 CPU 类型错误,升级使用下面版本: +``` +# rpm -Uvh http://119.3.219.20:82/openEuler:/Mainline/standard_x86_64/x86_64/gnome-boxes-3.38.2-3.oe1.x86_64.rpm +``` + +重新编译 qemu。默认安装的 qemu 关闭了 smartcard 支持选项,需要在 configure 命令中添加 `--enable-smartcard ` 选项重新编译: +``` +# wget https://repo.openeuler.org/openEuler-21.09/source/Packages/qemu-4.1.0-82.oe1.src.rpm +# rpm -ivh qemu-4.1.0-82.oe1.src.rpm + +修改 ~/rpmbuild/SPECS/qemu.spec 文件,修改内容如下: +# diff -Nur ~/rpmbuild/SPECS/qemu.spec.bak ~/rpmbuild/SPECS/qemu.spec +--- /root/rpmbuild/SPECS/qemu.spec.bak 2021-10-12 14:30:30.300362506 +0800 ++++ /root/rpmbuild/SPECS/qemu.spec 2021-10-12 14:37:14.140967049 +0800 +@@ -1,6 +1,6 @@ + Name: qemu + Version: 4.1.0 +-Release: 82 ++Release: 83 + Epoch: 2 + Summary: QEMU is a generic and open source machine emulator and virtualizer + License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 +@@ -750,7 +750,7 @@ + --disable-parallels \ + --disable-sheepdog \ + --disable-capstone \ +- --disable-smartcard \ ++ --enable-smartcard \ + --enable-zstd + + make %{?_smp_mflags} $buildldflags V=1 +@@ -963,6 +963,9 @@ + %endif + + %changelog ++* Tue Oct 12 2021 Wenlong Ding ++- Open build option: --enable-smartcard ++ + * Sun Sep 26 2021 Chen Qun + - virtio-net: fix use after unmap/free for sg + +``` + +安装 qemu 的编译依赖并重新编译、升级 +``` +# yum install -y bison brlapi-devel chrpath device-mapper-multipath-devel flex gnutls-devel libaio-devel libattr-devel libcap-devel libcap-ng-devel libcurl-devel libiscsi-devel librbd-devel libseccomp-devel libssh-devel libtasn1-devel lzo-devel ncurses-devel numactl-devel pam-devel python-sphinx python3-devel rdma-core-devel snappy-devel spice-server-devel texinfo zstd-devel +# rpmbuild -ba /root/rpmbuild/SPECS/qemu.spec +# rpm -Uvh ~/rpmbuild/RPMS/x86_64/qemu-*.rpm +``` +升级完成后重启机器,用户重新登录后即可通过 gnome-boxes 创建、运行虚拟机。 + +###5.3 普通用户使用 gnome-boxes 运行虚拟机效率低 +普通用户由于没有自动加入 `kvm` 和 `libvirt` 组,虚拟机只能以 qemu 模拟器的方式运行,所以效率比较低。 +通过下面命令将普通过户加入这两个组,可以使虚拟机运行在 kvm 半虚拟化模式下,虚拟机的运行效率会有大幅度提高。 +``` +# usermod -aG kvm test +# usermod -aG libvirt test +# id test +uid=1000(test) gid=1000(test) groups=1000(test),10(wheel),36(kvm),985(libvirt) +``` + +普通用户加入 `kvm` 和 `libvirt` 组后重启系统生效。 diff --git a/web-ui/docs/zh/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md b/web-ui/docs/zh/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md new file mode 100644 index 0000000000000000000000000000000000000000..8c371ea4fa7dbd76c77dd6fb7ab9dd3ab193679f --- /dev/null +++ b/web-ui/docs/zh/blog/fred_li/2020-03-25-apply-for-vm-from-pcl.md @@ -0,0 +1,117 @@ +--- +title: 如何在鹏城实验室申请虚拟机 +date: 2020-03-25 +tags: + - 虚拟机 + - 鹏城实验室 +archives: 2020-03 +author: openEuler Infrastructure +summary: 本文章介绍如何在鹏城实验室申请虚拟机。 +--- + + +### 向鹏城实验室申请Arm虚拟机进行openEuler测试流程 + +#### 简介 + +为了方便openEuler社区的开发者开发,[鹏城实验室](https://dw.pcl.ac.cn/)为openEuler社区的开发者提供了一些虚拟机,用于开发调测。本文介绍为openEuler社区开发者介绍在鹏城实验室申请Arm虚拟机的申请步骤。 + +**说明**:该资源面向在openEuler社区进行贡献的开发者,包括代码开发、软件测试、文档开发等不同形式的贡献。 + +#### 申请步骤 + +##### 在openEuler社区提交申请并得到批准 + +1. 登陆Gitee上的openEuler公共Issue,准备创建申请 + +链接在此 + +2. 创建Issue + +- 类型:需求 + +- 标题:以"[鹏城实验室VM申请]"开头 + +- 内容模板: + +``` +- 鹏城生态门户开发者云ID:(在https://dw.pcl.ac.cn/cloud/login申请) + +- 申请目的: + +- 与该目的对应的openEuler社区链接(一个或多个): + - Issue链接: + - Pull Request链接: + - SIG组链接: + - Project链接: + +- 使用时长(天): 不超过30天 + +- VM数量: + +``` + +3. 提交Issue后,等待openEuler Infrastructure组的批准 + +如下人员可以审批: +@freesky-edward +@imjoey +@TommyLike +@zerodefect + + +4. 审批通过后,记录该issue的url。 + + +##### 到鹏城实验室进行正式申请 + +1. 登陆,如果没有账号请注册 + +2. 点击`需求申请`申请VM + +3. 第一页填写内容 + +- 项目名称:openEuler Development + +- 项目信息:其他--openEuler + +- 项目简介:openEuler项目是位于openeuler.org的开源项目,旨在通过社区合作,打造创新平台,构建支持多处理器架构、统一和开放的操作系统,推动软硬件应用生态繁荣发展。 + +- 领域信息:其他--openEuler操作系统 + +- 领域概述:openEuler操作系统,是基于Linux Kernel的Linux发行版。 + +4. 第二页填写内容 + +- 产品名称:openEuler + +- 产品信息:测试/研发类产品 + +- 产品概述:openEuler项目是位于openeuler.org的开源项目,旨在通过社区合作,打造创新平台,构建支持多处理器架构、统一和开放的操作系统,推动软硬件应用生态繁荣发展。 + +- 云服务用途:根据实际用途 + +- 用途概述:openEuler开源社区开发测试试用,审批单号:issue url + +5. 第三页:根据实际情况填写 + +6. 第四页:根据实际情况填写,与issue申请单内容一致 + +7. 完成申请 + +##### 释放资源 + +使用完成后,有两种方式可以释放资源。 + +1. 在释放资源。 + +2. 申请时间到期后自动释放,提醒**做好备份**。 + +#### 帮助 + +1. 在资源申请过程中,如果有疑问,可以 + +- 发邮件给咨询 + +- 在中提交问题,标题以`[鹏城实验室VM申请]`开头 + diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-OBS\344\273\223\345\272\223.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-OBS\344\273\223\345\272\223.png" new file mode 100644 index 0000000000000000000000000000000000000000..2b813cd7dc1289876e5b74b2b3d77a9b03c13936 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-OBS\344\273\223\345\272\223.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-Webhook\351\241\265.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-Webhook\351\241\265.png" new file mode 100644 index 0000000000000000000000000000000000000000..46561824bf36dad802f6e59e07527dfa36910de6 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-Webhook\351\241\265.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-gitee\344\273\223\345\272\223.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-gitee\344\273\223\345\272\223.png" new file mode 100644 index 0000000000000000000000000000000000000000..0919a5e397ae347cae2a53a2035043f1cf9f1b72 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-gitee\344\273\223\345\272\223.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223.png" new file mode 100644 index 0000000000000000000000000000000000000000..e1733999eaf15b54de412e3dd333fe28680fe273 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223\351\241\265.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223\351\241\265.png" new file mode 100644 index 0000000000000000000000000000000000000000..f853300eb86f996a8f24ddef0b795016daa78cd5 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-git\344\273\223\345\272\223\351\241\265.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-service\350\277\220\350\241\214\344\270\255.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-service\350\277\220\350\241\214\344\270\255.png" new file mode 100644 index 0000000000000000000000000000000000000000..e56c7d0858e200d5b8cac00d39562d6b2f55875b Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-service\350\277\220\350\241\214\344\270\255.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\226\260\345\273\272Webhook.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\226\260\345\273\272Webhook.png" new file mode 100644 index 0000000000000000000000000000000000000000..b62249b4336d8962d56632b8e020e5d690f82775 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\226\260\345\273\272Webhook.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\267\273\345\212\240.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\267\273\345\212\240.png" new file mode 100644 index 0000000000000000000000000000000000000000..f5ea50e502a2944384d43c5482dedd90bd5af3a0 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\346\267\273\345\212\240.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\216\257\345\242\203\346\240\207\347\255\276.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\216\257\345\242\203\346\240\207\347\255\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..e923c6b35508c9730b4ed7624060bca49abc10d8 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\216\257\345\242\203\346\240\207\347\255\276.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\251\272Package.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\251\272Package.png" new file mode 100644 index 0000000000000000000000000000000000000000..a850d3a399e7a26456828dbe6eb6e4c07a64abd7 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git-\347\251\272Package.png" differ diff --git a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git.md b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git.md new file mode 100644 index 0000000000000000000000000000000000000000..8ac5d5ae3ef10d296b172a0db8327e1e2d2bcf00 --- /dev/null +++ b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-OBS-with-Git.md @@ -0,0 +1,247 @@ +--- +title: 如何使用 openEuler OBS - (二)与gitee的联动 +date: 2020-03-26 +tags: + - OBS +archives: 2020-03 +author: Changjie Fu +summary: OBS系统如何借助Source Services自动获取git仓库中的代码。 +--- + +## 概要 + +本文分为两部分: + + - 利用Source Services(下称源服务)直接获取git源码并编译成包 + - 利用webhook 使源服务在git仓库push时触发,从而实现OBS始终跟进git仓库最新版本源码的效果 + +> 此文章的全部步骤使用[openEuler OBS](http://openeuler-build.huawei.com/)完成,使用其他服务器时可能出现工具不全的情况。 + +## 利用源服务直接获取git源码并编译成包 + +### Source Services 相关 + +> Source Services 是用于以可靠方式验证,生成或修改源的工具。它们被设计为最小的工具,并且可以按照经典UNIX设计的强大思想进行组合。 + +源服务就像是系统中的函数,我们可以通过运行脚本调用它;而脚本就是Package中的_service文件。 + + +### 创建使用源服务的Package + +1. 通过命令行工具或者网页新建一个空的Package + + + +2. 进入Package目录并创建_service: + + * 网页端点击*Add file* ,点击*Choose a file*,并选择本地建好的_service文件。 + * 命令行则在Package目录中新建_service文件并上传之服务器。 + +3. 准备编辑_service文件 + +### 编辑_service文件 + +最基础的_service文件将会如下所示: + +```powershell + + + git + git://github.com/cs2c-fu/hi.git + + + xz + *.tar + + + +``` + +最外层为``标记,在``内则为一个个``函数,而``则为``函数的参数。 + +为了实现“**利用源服务直接获取git源码并编译成包**”这个目标, + +我们的_service应该类似于这样(以下格式请根据具体情况选择合适的顺序): + +```xml + + + + git + helloworld + git://github.com/cs2c-fu/hi.git + VERSION.git + + + + *.* + */*.spec */*.patch + + + + xz + *.tar + + + + + +``` + +下面将对所需的服务逐一进行介绍: + +**第一个服务:[tar_scm](https://github.com/openSUSE/obs-service-tar_scm)** + +**tar_scm** 会将链接 url 中的仓库下载下来并打包为 tar 文件,文件包命名格式为: + +> [Name]-[Version].[commit_timestamp].tar + +其中,[commit_timestamp]为 commit 十六进制时间戳。 + +可选参数: + + - **filename** 定义打包后文件的 Name,默认为git仓库名。 + - **versionprefix** 定以打包后文件的 Version 格式,默认为当前十进制时间戳。 + + +在OBS官方服务器中, **tar_scm** 服务由于在空间利用率上表现不佳, 已被 **obs_scm**、**tar** 服务取代,但openEuler的外网OBS暂时还不支持**obs_scm**,所以这里选择 **tar_scm** 。 + +> 详见:[链接](https://openbuildservice.org/2016/04/08/new_git_in_27/) + +**第二个服务:[extract_file](https://github.com/openSUSE/obs-service-extract_file)** + +**extract_file** 可以从tar包中提取文件, 具体需要提取什么文件取决于git仓库中的文件格式。 + + +一般来说我们可以将打包需要的内容分为四大类: + + - **源码** : 参与编译过程的文件 + - **spec文件** : 指导如何打包的规范文件 + - **patch文件** : 修改源码的差异文件 + - **源文件** : 不参与编译但需要打包的文件 + +对于**git仓库**来说,一般会将所有文件放到仓库的根目录。 + + + +此时我们需要将**spec文件、patch文件、源文件**提取出来, **源码**则留在tar包中等待之后的服务将其压缩打包。 + +对于**OBS仓库**来说,为了方便OBS系统使用,人们已经对源码进行压缩打包。 + + + +此时我们需要将**所有文件**提取出来并省略之后的压缩打包环节。 + +参数: + + - **archive** 定义提取来源文件格式 + - **files** 定义提取文件类型 _注意:存在一个顶层目录,其名称未知,因此文件名应以 “*/” 开头_ + +**第三个服务:[recompress](https://github.com/openSUSE/obs-service-recompress)** + +**recompress** 会对指定文件进行压缩 + +参数: + + - **compression** 压缩格式,可选:none、gz、bz2、xz + - **file** 压缩内容 + +**第四个服务:[set_version](https://github.com/openSUSE/obs-service-set_version)** + +会将spec文件中的Version替换为obs_scm时的 + +`[Version].[commit_timestamp]` + +spec文件中可以以 + +`helloworld-%{version}.tar.xz` + +格式定位源码包。 + +### 等待编译完成 + +由于使用源服务获取源码,所以编译时需要额外过程与时间。 + + + +当状态显示为 **blocked** 时, 表明源服务正在运行。当源服务运行完毕时会正常开始打包过程。 + +我的参考案例:[链接](http://openeuler-build.huawei.com/package/show/home:changjie_fu/hi) + +### Source Services 在实际场景中的应用 + +在[oVirt-SIG](http://openeuler-build.huawei.com/project/show/oVirt-SIG)组中,我们应用了源服务实现代码由git到OBS的同步。 + +首先,我们在git仓库中以:**spec文件、patch文件、 **源码tar包** 的格式上传并管理源码。 + + + +在OBS系统中建立对应包并以一下格式定义_service文件: + +```xml + + + git + ioprocess + https://gitee.com/openkylin/ioprocess.git + + + *.* + */* + + +``` + +由于我们已经很好的在git仓库中设置了存储格式, 此时我们只需将所有文件下载并提取即可。 + +在这之后,OBS系统会帮助我们完成编译与打包的环节。 + +## 利用 webhook 使源服务在git仓库push时触发 + +在写此文时,OBS系统还不支持gitee格式的webhook,所以以下内容为使用github仓库实现。 + +> obs可以创建令牌(token),当令牌被触发时,OBS会运行源服务。 +> +> 将网址与令牌添加到git仓库的webhook列表中,就可以在git仓库中实现触发源服务,进而更新OBS中的包版本。 +> +> +> **具体步骤:** +> +> 创建专属包的OBS Token(OBS令牌): +> ``` +> osc token --create +> ``` +> +> 命令将生成仅对Project/Package生效的token。 +> +> - 使用命令 `osc token` 可以查看当前生效的令牌列表。 +> +> - 使用命令`osc token --delete ` 可以删除令牌 +> +> +> 打开git仓库网址(以github为例): +> +> +> +> 打开仓库 -> Setting -> Webhooks +> + +> +> 点击左上方的 Add webhook 。 +> +> + +> +> 在 Payload URL中以: +> +> ` http://openeuler-build.huawei.com/trigger/webhook?id=<令牌ID>` +> +> 为格式填入。 +> +> 在 Secret 中填入令牌秘匙,按需求选择trigger类型, 保证Webhook为Active状态。 +> +> 之后点击 Add webhook 即成功实现。 +> +> 可尝试触发trigger以验证成果。 + + diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-AFD\351\241\265.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-AFD\351\241\265.png" new file mode 100644 index 0000000000000000000000000000000000000000..e993718a7cc0bfc723d4c94a88926879e60a4303 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-AFD\351\241\265.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-commit\344\273\213\347\273\215.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-commit\344\273\213\347\273\215.png" new file mode 100644 index 0000000000000000000000000000000000000000..c37a24c31068aac714dcfd3a93bae5fe5f1c6b64 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-commit\344\273\213\347\273\215.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-meta\351\205\215\347\275\256.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-meta\351\205\215\347\275\256.png" new file mode 100644 index 0000000000000000000000000000000000000000..5dd788cb66e8e188c8571074c075e740cfbb3177 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-meta\351\205\215\347\275\256.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\211\347\247\215\345\257\206\347\240\201\344\277\235\345\255\230\346\226\271\345\274\217.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\211\347\247\215\345\257\206\347\240\201\344\277\235\345\255\230\346\226\271\345\274\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..bfca95365ab3d3b4956a623cf7e749c8ea73b5e7 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\211\347\247\215\345\257\206\347\240\201\344\277\235\345\255\230\346\226\271\345\274\217.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\273\351\241\265\345\217\263\344\270\212\350\247\222.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\273\351\241\265\345\217\263\344\270\212\350\247\222.png" new file mode 100644 index 0000000000000000000000000000000000000000..99233c5de6b377b66aeae4914b0d9a5e43281b68 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\344\270\273\351\241\265\345\217\263\344\270\212\350\247\222.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\345\233\276\347\211\2071.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\345\233\276\347\211\2071.png" new file mode 100644 index 0000000000000000000000000000000000000000..6ee834f2a22bb34f4931ebca88704cd20756a7a6 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\345\233\276\347\211\2071.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\216\257\345\242\203\346\240\207\347\255\276.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\216\257\345\242\203\346\240\207\347\255\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..d9b447d68d2bc31cfce581a2d640c08125677736 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\216\257\345\242\203\346\240\207\347\255\276.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\231\273\351\231\206OBS.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\231\273\351\231\206OBS.png" new file mode 100644 index 0000000000000000000000000000000000000000..c80bbccdac6b96473fe7944191944584c9599a9b Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\231\273\351\231\206OBS.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\233\256\345\275\225\346\240\274\345\274\217.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\233\256\345\275\225\346\240\274\345\274\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..5bc97635dbcc79958b0ed19b63deb310a4c13ed7 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\233\256\345\275\225\346\240\274\345\274\217.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\263\273\347\273\237\347\273\223\346\236\204.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\263\273\347\273\237\347\273\223\346\236\204.png" new file mode 100644 index 0000000000000000000000000000000000000000..f548773a7050f0de25027aeafde7ff4cae12e483 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\263\273\347\273\237\347\273\223\346\236\204.png" differ diff --git "a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\274\226\350\257\221\347\212\266\346\200\201.png" "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\274\226\350\257\221\347\212\266\346\200\201.png" new file mode 100644 index 0000000000000000000000000000000000000000..c1d00f35e08a99e33ff2d2ba4445f9b739879e51 Binary files /dev/null and "b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS-\347\274\226\350\257\221\347\212\266\346\200\201.png" differ diff --git a/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS.md b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS.md new file mode 100644 index 0000000000000000000000000000000000000000..cbc73e54ee57a4189fc2e07ef18295144634ceb5 --- /dev/null +++ b/web-ui/docs/zh/blog/fuchangjie/2020-03-26-how-to-OBS.md @@ -0,0 +1,200 @@ +--- +title: 如何使用 openEuler OBS - (一)介绍 +date: 2020-03-26 +tags: + - OBS +archives: 2020-03 +author: Changjie Fu +summary: OBS系统的介绍及openEuler OBS 的简单应用。 +--- + + +## OBS是什么 + +OBS是Open Build Service 的简写(官方网址:[https://openbuildservice.org/](https://openbuildservice.org/)), + +原本是作为发行版openSUSE专用的rpm打包的平台,后续扩展为面向多发行版、多架构、多格式的打包发布平台。 + + + +## 与koji的不同 + +- 管理范围 + +与koji只管理包(包括源码包与二进制包)仓库不同,OBS同时管理着源码与包两个仓库。koji是从一个包编译完成后开始接手,根据包的NVR(Name-Version-Release)确定包的位置,在编译验证后入库保存。而OBS是从源码阶段开始管理,它拥有自己的包版本标记与changelog日志。OBS可以像git一样保存源码的历史版本,对源码进行分支管理。并生成各版本的二进制包与源码包。 + +换句话说,OBS可以同时实现koji和git的功能。 +> OBS接受源码的格式与git普遍的保存格式并不相同,所以OBS无法完全取代git。 + +- 适用格式 + +OBS可以生成rpm、deb等格式的包,而koji只适用于rpm格式。 + + +## OBS使用 + +### 安装osc + +osc是OBS的命令行程序,您可以在[这里](https://download.opensuse.org/repositories/openSUSE:/Tools/) ,选择自己的系统版本,添加软件源到自身包管理器中。 + +这里以Fedora30为例: + +1. 添加软件源 + +将文件`http://download.opensuse.org/repositories/openSUSE:/Tools/Fedora_30/openSUSE:Tools.repo`另存到/etc/yum.repo.d/中。 +> 需要root权限。 + +2. 安装osc + +执行 `dnf install osc` 命令安装osc。 + +### 配置openEuler的OBS + +有很多方法可以将osc链接至openEuler外网的OBS: + +1. 最基础的方法为在每次执行 `osc` 命令时添加参数: `-A http://openeuler-build.huawei.com/` +2. 使用alias:`alias iosc="osc -A http://openeuler-build.huawei.com/"` +3. 修改位于`home`目录下的osc配置文件:`vi ~/.oscrc`,并写入以下内容: + +``` +[general] +apiurl = http://openeuler-build.huawei.com/ + +[http://openeuler-build.huawei.com/] + +``` + +### 注册OBS账号 + +打开 [http://openeuler-build.huawei.com/](http://openeuler-build.huawei.com/),点击右上角“Sign Up”,注册自己喜欢的帐号。 + +注册完成后,重新回到上面网址。点击右上角的“Login”,用新账户登录。系统会在注册时自动创建一个以“home:用户名”为格式命名的Home Project。 + +### 创建本地目录 + +创建obs工作目录: +`mkdir ~/obs` + +进入obs工作目录: +`cd ~/obs` + +将远程obs库同步到本地: +`osc checkout home:用户名` + +输入网页用户名与密码 + + + +第一次登陆时会询问本地密码保存方式,三种方式分别是: + +1. 明文保存 +2. 加密保存 +3. 不保存(需要每次输入) + + + +这里推荐选择2。同步结束后可以看到当前目录下有以Project名命名的文件夹。 + +### 配置Project + +两种方法:网页操作、命令行操作 + +- 网页操作: + +在obs主页点击右上角 + + + +依次进入 Home Project -> Repositories -> Add from a Distribution 。 + + + +按上图所示填写基础配置,并在Name栏填写喜欢的名字。 + +在选择后后退至Repositories界面,可以看到如下图所示的环境: + + + + 1. 第一个为编辑按钮,可以选择当前发行版编译架构 + 2. 第二个为添加按钮,可在发行版标准环境上额外添加单独的包(例如其他私人编译的依赖包) + 3. 第三个为下载,点击后转到当前环境的仓库 + 4. 第四个为删除 + + +- 命令行操作: + +执行命令: `osc meta prj -e [project名]` ,会看到类似如下文本: + + + +其中, + 1. repository标签为仓库标签, 可添加此项添加编译时的基础环境 + 2. Path标签为可用包路径标签, 需手动添加发行版包路径。如需要额外依赖, 也可以单独添加。 + 3. Arch标签为编译架构, 可同时添加多个。 + +例如: + + ```xml + + + //此为额外添加依赖 + aarch64 + armv7l //此为多架构选项 + + ``` + +### 新建包 + +进入Project目录: + `cd [project名]` + +新建Package: +`osc mkpac [package名]` + +进入Package目录并将下载源码以【tar包、所有patch、spec文件、其他source文件】格式放置: + +! + + +向新创建的package中添加以上文件: +`osc add * ` + + + +将更改上传至服务器: +`osc commit` + + + +在这里可以注明本次上传的简短介绍,用`:wq`保存并退出 + +之后就可以在网页上等待编译并查看结果了。 + + +### 查看包状态与下载包 + +您可以在Project与Package主页右侧看到当前编译状态 + + + + +- `finished ` 表示在某个系统平台执行编译链接、安装检查的过程结束 +- `succeeded ` 状态为编译成功 +- `failed ` 为编译失败,您可以点击查看日志 + +您可以点击*编译平台 -> Go to download repository* 到达编译仓库,获得此Project的repo源与所有编译成功的package。 + +### 更新包 + +进入project文件夹: +`cd [project名]` + +更新本地代码为最新代码: +`osc up ` + +进入package目录,使用 `osc add` 命令将新文件添加到package,修改spec文件后使用`osc commit`命令上传新版本。 + + +## 参考资料 +- [openSUSE Wiki](https://en.opensuse.org/openSUSE:Build_Service_Concept_SourceService) +- [OBS官网文档](https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.source_service.html) diff --git a/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv1-shimv2-diff.md b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv1-shimv2-diff.md new file mode 100644 index 0000000000000000000000000000000000000000..727b48aad7cbc11132baf8eb49f39e46bd00de3f --- /dev/null +++ b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv1-shimv2-diff.md @@ -0,0 +1,291 @@ +--- +title: kata shimV2中监控容器退出机制的实现方案分析 +date: 2021-04-09 +tags: + - iSulad + - 容器 + - shimv2 +archives: 2021-04 +author: 高华涛 +summary: containerd-shim-kata-v2作为kata容器的runtime,相较于shimv1, 其减少了组件数量、缩短了调用链 +--- + +当前shim有shimV1和shimV2两种实现架构,shimV1作为传统shim的实现方案,主要被用作容器引擎和runtime的中间层,实现io、signals等的转发;最新版本的shimV2,在shimV1的基础上集成了runtime的功能,缩短了容器创建的调用链, 在某些场景能够有效降低底噪开销。在本文中的shimV2 默认使用的是[containerd-shim-kata-v2](),以此为分析对象,分别分析了iSulad和containerd中对pause和container(业务容器)两种类型的容器退出监控流程的实现方式。 + +### shimV2介绍 + +在shimV1架构中,安全容器的启动涉及kata-shim、 kata-runtime、 kata-proxy、kata-agent组件以及用于创建虚机的qemu组件。在shimV2架构中,将shim、proxy和runtime集成到一个二进制中,当启动pause容器和在pause中启动业务容器时,host os中只存在一个containerd-shim-kata-v2进程和qemu-kvm进程,也就是说pause容器和其中的业务容器共用同一个containerd-shim-kata-v2进程和虚拟机。[shimV2和shimV1架构对比]()如下。shimV1在单pause+多业务容器场景,每启动一个pause或者业务容器都有一个containerd-shim或者isulad-shim、kata-shim进程被拉起,pause和其中的业务容器共用kata-proxy(非vsock)进程和虚机进程(2N+1)。然而, shimV2在单pause+多业务容器场景中,host os中只有一个containerd-shim-kata-v2进程和qemu-kvm进程,调用链更短, 总体底噪更低,特别是当pause中业务容器数量增加时,低底噪优势将更加明显。 + +![](./2021-04-09-isulad-shimv2-arch-1.png) + +### iSulad与shimV1和shimV2关系 + +1. iSulad中shimv1的实现 + + isulad-shim组件作为iSulad中shimv1的实现方案,代码在iSulad仓库中,随iSulad一起编译安装;可用于对接不同的OCI Runtime, 如runc、kata-runtime. + +2. iSulad中shimv2的实现 + + 当前iSulad对接shimv2仍处于调试阶段,shimV2分为containerd-shim-kata-v2和containerd-shim-runc-v2两种实现,本文以containerd-shim-kata-v2作为对象,分析在shimv2场景下,安全容器的退出监控实现机制。 + +3. shimv1和shimv2的区别如下图所示 + +![shimv-shimv2-diff](./2021-04-09-isulad-shimv2-shimv2-differences.png) + + +### iSulad中容器退出监控剖析 + +以isulad-shim为例,iSulad中通过epoll机制监控每个isulad-shim进程中开启的exit_fifo fd是否关闭,isulad-shim在监控到容器退出后将其退出码写入此fifo, 在iSulad中读取并设置容器退出状态,业务容器和pause容器均会打开一个exit_fifo fd。对于pause容器和业务容器这两种CRI流程的容器会分别拉起独立的isulad-shim进程。 + +iSulad | <==> isulad-shim <==> container init + +iSulad | <==> isulad-shim <==> pause init + +iSulad中在start 容器流程中开启exit_fifo的读端fd并加入epoll监控, 关键代码如下: + +```c +int do_start_container(container_t *cont, const char *console_fifos[], bool reset_rm, pid_ppid_info_t *pid_info) +{ + runtime_start(); + do_post_start_on_success() { + container_supervisor_add_exit_monitor() { + supervisor_handler_lock(); + epoll_loop_add_handler(); + } + } +} +``` + + + +### containerd中容器退出监控 + +containerd在启动容器并监控其退出状态时不再使用fifo来实现而是使用rpc调用中的Wait方法, 启动pause容器、业务容器以及调用容器exec命令时,均会在containerd中开启一个协程来获取其退出状态。containerd重启后,connect方法实现将全部容器的wait方法进行重建。 + +- start sandbox和start container监控流程 + +代码文件:containerd/vendor/github.com/containerd/cri/pkg/server/events.go + +```go +// eventMonitor monitors containerd event and updates internal state correspondingly. +// TODO(random-liu): Handle event for each container in a separate goroutine. +type eventMonitor struct { + c *criService + ch <-chan *events.Envelope + // exitCh receives container/sandbox exit events from exit monitors. + exitCh chan *eventtypes.TaskExit + errCh <-chan error + ctx context.Context + cancel context.CancelFunc + backOff *backOff +} +// container 监控退出 +func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (retRes *runtime.StartContainerResponse, retErr error) { + // wait is a long running background request, no timeout needed. //ght container这里监听 + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + + // start the monitor after updating container state, this ensures that + // event monitor receives the TaskExit event and update container state + // after this. + c.eventMonitor.startExitMonitor(context.Background(), id, task.Pid(), exitCh) +} + +// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure +// the sandbox is in ready state. +func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) { + // wait is a long running background request, no timeout needed. + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + // start the monitor after adding sandbox into the store, this ensures + // that sandbox is in the store, when event monitor receives the TaskExit event. + // + // TaskOOM from containerd may come before sandbox is added to store, + // but we don't care about sandbox TaskOOM right now, so it is fine. + c.eventMonitor.startExitMonitor(context.Background(), id, task.Pid(), exitCh) +} +``` + +containerd/process.go + +```go +// containerd/process.go 监控container exec等进程退出 +func (p *process) Wait(ctx context.Context) (<-chan ExitStatus, error) { + c := make(chan ExitStatus, 1) + go func() { + defer close(c) + r, err := p.task.client.TaskService().Wait(ctx, &tasks.WaitRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + c <- ExitStatus{ + code: UnknownExitStatus, + err: err, + } + return + } + c <- ExitStatus{ + code: r.ExitStatus, + exitedAt: r.ExitedAt, + } + }() + return c, nil +} +``` + +- containerd重新获取shim pid,与shimV1不同的是这里的shim pid并不是作为容器的ppid, 因此在容器进程无法正常kill时,不能通过kill shim pid来强制容器退出。 + +```go +func (m *TaskManager) loadTasks(ctx context.Context) error {} + func loadShim() + func (s *shim) Connect(ctx context.Context) error { + response, err := s.task.Connect(ctx, &task.ConnectRequest{ + ID: s.ID(), + }) + if err != nil { + return err + } + s.taskPid = int(response.TaskPid) // 获取shim的pid + return nil +} + +``` + + + +### containerd-kata-shim-v2代码分析 + +1. ttrpc 服务端入口: + +文件containerd-shim-v2/service.go中定义了containerd-kata-shim-v2作为ttrpc服务端监听来自容器引擎的ttrpc调用的入口函数并实现了容器退出状态的监控、io和信号转发等操作。 + +```go +// service is the shim implementation of a remote shim over GRPC +type service struct { + mu sync.Mutex + eventSendMu sync.Mutex + + // pid Since this shimv2 cannot get the container processes pid from VM, + // thus for the returned values needed pid, just return this shim's + // pid directly. + pid uint32 + + ctx context.Context + sandbox vc.VCSandbox + containers map[string]*container // pause和container容器全部保存在这里 + config *oci.RuntimeConfig + events chan interface{}// publish使用 128缓冲 + monitor chan error // 监控sandbox即虚机的状态 + + cancel func() // ctx cancel + + ec chan exit // 保存了容器推出码 pid等信息, 32缓冲, shim中协程检查进程写入events,向上publish + id string// io.containerd.kata.v2 +} +``` + +- service 实现了ttrpc server和shim管理的接口 + +```go +type TaskService interface { + State(ctx context.Context, req *StateRequest) (*StateResponse, error) + Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) + Start(ctx context.Context, req *StartRequest) (*StartResponse, error) + Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) + Pids(ctx context.Context, req *PidsRequest) (*PidsResponse, error) + Pause(ctx context.Context, req *PauseRequest) (*google_protobuf1.Empty, error) + Resume(ctx context.Context, req *ResumeRequest) (*google_protobuf1.Empty, error) + Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) + Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) + Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) + ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) + CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) + Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) + // 获取容器退出状态 + Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) + Stats(ctx context.Context, req *StatsRequest) (*StatsResponse, error) + // 获取shim pid + Connect(ctx context.Context, req *ConnectRequest) (*ConnectResponse, error) + // 取消全部context子任务并停止containerd-shim-kata-v2进程 + Shutdown(ctx context.Context, req *ShutdownRequest) (*google_protobuf1.Empty, error) +} +// Shim server interface +type Shim interface { + shimapi.TaskService + Cleanup(ctx context.Context) (*shimapi.DeleteResponse, error) + StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) +} +``` + + + +### iSulad通过containerd-shim-kata-v2运行容器 + +- 启动pause容器。 + +```bash +isula run -tid --runtime io.containerd.kata.v2 --network none --annotation io.kubernetes.docker.type=podsandbox +``` + +此处获取pod的sandbox-id。 + +- 创建业务容器并加入到这个pod中 + +```bash +isula run -tid --runtime io.containerd.kata.v2 --network none --annotation io.kubernetes.docker.type=container --annotation io.kubernetes.sandbox.id= busybox +``` + + + +### containerd通过containerd-shim-kata-v2运行容器 + +自行安装cri-tools工具,本文使用github.com上master分支编译安装。 + +- containerd配置: + +containerd配置文件/etc/containerd/config.toml中增加如下一段用来配置kata参数 + +```toml +[plugins."io.containerd.grpc.v1.cri".containerd.runtimes] +// + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] + runtime_type = "io.containerd.kata.v2" + pod_annotations = ["com.github.containers.virtcontainers.sandbox_cpu", "com.github.containers.virtcontainers.sandbox_mem", "com.github.containers.virtcontainers.static_devices", "com.github.containers.virtcontainers.sandbox_drivers", "com.github.containers.virtcontainers.boot_cgroup"] + container_annotations = ["com.github.containers.virtcontainers.storage_spec"] +// + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + base_runtime_spec = "" + +``` + +- 安装cni插件: + +参考如下教程,自行编译plugins + +``` +https://github.com/containerd/containerd/blob/master/script/setup/install-cni +``` + +- 指定runtime运行pod: + +```bash +$ crictl -i unix:///var/run/containerd/containerd.sock -r unix:///var/run/containerd/containerd.sock runp --runtime kata sandbox-config.json +$ cat sandbox-config.json +{ + "metadata": { + "name": "nginx-sandbox", + "namespace": "default", + "attempt": 1, + "uid": "hdishd83djaidwnduwk28bcsb" + }, + "image": { + "image": "docker.io/library/busybox:latest" + }, + "linux": { + } +} + +``` + +---- + +Author:高华涛 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png new file mode 100644 index 0000000000000000000000000000000000000000..0566afa288ea5917fba2656e76c5e01cde59ff8f Binary files /dev/null and b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-arch-1.png differ diff --git a/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png new file mode 100644 index 0000000000000000000000000000000000000000..18fcfcac6df8b0763fe8f5031a94322ee7bdd679 Binary files /dev/null and b/web-ui/docs/zh/blog/gaohuatao/2021-04-09-isulad-shimv2-shimv2-differences.png differ diff --git a/web-ui/docs/zh/blog/genedna/summer-2020-openeuler-tasks.md b/web-ui/docs/zh/blog/genedna/summer-2020-openeuler-tasks.md new file mode 100644 index 0000000000000000000000000000000000000000..a47347a6fd48e12ab6cde0e53acb1b09d370c4a0 --- /dev/null +++ b/web-ui/docs/zh/blog/genedna/summer-2020-openeuler-tasks.md @@ -0,0 +1,361 @@ +--- +title: openEuler 社区暑期 2020任务详解分类 +date: 2020-06-03 +tags: + - openEuler 社区 + - 暑期 2020献 +archives: 2020-06 +author: genedna +summary: openEuler 社区参与暑期 2020 的 102 个任务具体分析。 +--- + + +## openEuler 社区 [暑期 2020](https://isrc.iscas.ac.cn/summer2020) 任务详解分类 + +[openEuler](https://www.openeuler.org) 社区在 [暑期 2020](https://isrc.iscas.ac.cn/summer2020) 活动中共发布了 [102](https://gitee.com/openeuler/marketing/blob/master/events/summer2020/tasks.md) 个任务,涵盖了 Linux 、容器、云计算和编程语言等多个技术栈。参与暑期 2020 活动的同学可以通过阅读本文的深度解析,找到感兴趣和符合自身技术栈的任务,这样可以在申请任务的过程中提高成功率。同时,openEuler 社区在 June 7th, 2020 、June 8th, 2020 和 June 9th, 2020 三天点晚间 19:00 ~ 20:00 间在[ Bilibili ](https://live.bilibili.com/22290444) 进行直播,由相关任务的社区 Maintainer 为大家更为详细的讲解技术点、具体要求等,现场回答同学们的问题。 + +更多问题可以和本文作者 邮件/Twitter/Telegram 联系: + +- 邮件:eli@patch.sh +- Twitter: https://twitter.com/genedna +- Telegram: genedna + +相关问题: + +- 任务是必须在 aarch64 架构上完成么? + + 在任务的要求中写明需要在 aarch64 架构下完成的,都需要在 [openEuler](https://www.openeuler.org) 的 aarch64 架构上验证通过才可以;没有写此要求的任务,由申请者和任务导师协商,以协商结果为准。 + +- 在哪里找到 aarch64 的环境? + + 可以在树莓派上进行开发,相关内容请参考 https://www.openeuler.org/zh/blog/2020/05/25/2020-05-25-raspberrypi-userguide.html 。华为公司为针对 aarch64 架构的任务赞助华为公有云的鲲鹏计算资源,可使用 openEuler 的镜像用于完成任务开发。在学生申请任务成功后,会由活动组织方统一发放。 + +- 任务验收标准不清晰? + + 验收标准可以和导师进行沟通,导师会根据沟通情况,提出具体的验收标准。 + +关于直播活动请大家加入到暑期 2020 学生的微信群,关注微信群的时间通知。 + + + +### B 站直播计划,房间地址 https://live.bilibili.com/22290444 + +June 7th, 2020 19:00 ~ 20:00 方亚芬讲解 + +* 暑期 2020 团体任务 - [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) +* [No.1 - 为 openEuler 添加 Xfce 桌面环境并能够运行在树莓派 4B 上](https://gitee.com/openeuler/marketing/issues/I1H8G3) +* [No.2 - 精简 openEuler 的树莓派 4B 镜像体积小于 500 MiB](https://gitee.com/openeuler/marketing/issues/I1H8H9) +* [No.3 - 为 openEuler 树莓派 4B 镜像提供 UEFI 启动支持](https://gitee.com/openeuler/marketing/issues/I1H8HV) + +June 8th, 2020 19:00 ~ 20:00 何晓文讲解 + +* 暑期 2020 团体任务 [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) +* [No.49 - 基于 openEuler 的 ABI 检查工具](https://gitee.com/openeuler/marketing/issues/I1HQSE) +* [No.47 - 开发 openEuler bootstrap 工具](https://gitee.com/openeuler/marketing/issues/I1HAXJ) + +June 9th, 2020 19:00 ~ 20:00 蔡灏旻讲解容器技术相关任务 + +* [No.7 - 构建可运行 iSulad 点容器镜像,并推送到 Docker Hub 镜像仓库](https://gitee.com/openeuler/marketing/issues/I1HVZF) +* [No.9 - iSula 相关项目支持编译 Debian 包](https://gitee.com/openeuler/marketing/issues/I1HWDZ) +* [No.10 - iSula 项目内存池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX3G) +* [No.11 - iSula 项目线程池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX5Y) +* [No.12 - iSula-kits 支持在多个 OS 发型版上运行](https://gitee.com/openeuler/marketing/issues/I1HXE7) +* [No.13 - iSula 容器镜像构建工具支持多存储驱动](https://gitee.com/openeuler/marketing/issues/I1HXS9)- +* [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1HXS9) + +June 15th, 2020 20:00 ~ 21:00 虚拟化相关任务讲解 + +* [No.52 - openEuler 虚拟化调度性能评估工具及方法构建](https://gitee.com/openeuler/marketing/issues/I1I9XJ) +* [No.6 - 虚拟化场景下的类似 top 点调测工具 virttop](https://gitee.com/openeuler/marketing/issues/I1HVM7) +* [No.66 - QEMU 中集成 virtio-fuzz 能力以支持模拟设备的模糊测试](https://gitee.com/openeuler/marketing/issues/I1IHCJ) +* [No.62 - QEMU 用户态进程热补丁框架](https://gitee.com/openeuler/marketing/issues/I1IG8E) + +June 16th, 2020 20:00 ~ 21:00 测试相关任务讲解 + +* [No.69 - api-sanity-checker 与 oss-fuzz 测试结合的误报优化](https://gitee.com/openeuler/marketing/issues/I1IHNM) +* [No.34 - 对 openEuler 社区发布包 keepalived 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CG) +* [No.35 - 对 openEuler 社区发布包 kmod-kvdo 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CY) +* [No.36 - 对 openEuler 社区发布包 OpenVPN 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6D6) +* [No.37 - 对 openEuler 社区发布包 lrzsz 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6EO) +* [No.38 - 对 openEuler 社区发布包 ipvsadm 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6F2) +* [No.39 - 对 openEuler 社区发布包 MongoDB 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GM) +* [No.40 - 对 openEuler 社区发布包 Redis 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GW) +* [No.41 - 对 openEuler 社区发布包 sssd 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IK) +* [No.42 - 对 openEuler 社区发布包 MySQL 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IN) +* [No.43 - 对 openEuler 社区发布包 rpcbind 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JE) +* [No.44 - 对 openEuler 社区发布包 haproxy 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JI) +* [No.29 - 对openEuler社区发布包osc和obs-build进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I5WZ) + +June 17th, 2020 20:00 ~ 21:00 openEuler 社区之旅参与介绍 + +* 介绍如何在 openEuler 社区贡献 + +### 任务分类 + +1. [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) 团体项目 - **建议申请此任务的团队需要有一定的 Linux 操作系统实战能力,掌握 Linux 内核及硬件驱动相关知识,熟悉掌握操作系统引导与启动机制。** + + [openEuler](https://www.openeuler.org) 社区致力于把 [openEuler](https://www.openeuler.org) 发行版移植到多种设备上,目前已经能在 [Raspberry Pi](https://www.raspberrypi.org) 4B Model 上顺利运行。这次团体任务的目标是把 [openEuler](https://www.openeuler.org) 20.03 LTS 版本移植到瑞芯微推出的 RK3399 芯片上运行,社区建议参与此任务团队在 Firefly 出品的 [4GB 内存/16GB 闪存](https://item.jd.com/23958924426.html) 版本的开发板进行移植任务。 + + 任务地址 https://gitee.com/openeuler/marketing/issues/I1IJ4B + +2. Raspberry Pi 树莓派相关任务 - **建议申请此任务的同学需要有一定的 Linux 操作系统实战能力,掌握 Linux DNF/RPM 管理方案,熟悉 Linux 桌面系统的同学申请此类任务** + + [openEuler](https://www.openeuler.org) 社区致力于把 [openEuler](https://www.openeuler.org) 发行版移植到多种设备上,目前已经能在 [Raspberry Pi](https://www.raspberrypi.org) 4B Model 上顺利运行。为了让 [openEuler](https://www.openeuler.org) 项目更好的运行在树莓派上, [openEuler](https://www.openeuler.org) 社区 [Raspberry Pi SIG](https://gitee.com/openeuler/community/tree/master/sig/sig-RaspberryPi) 的 Maintainer 方亚芬([yafen@iscas.ac.cn](mailto:yafen@iscas.ac.cn)) 发起了 3 个优化运行效果的任务。 + + - [No.2 - 精简 openEuler 的树莓派 4B 镜像体积小于 500 MiB](https://gitee.com/openeuler/marketing/issues/I1H8H9) 任务地址 https://gitee.com/openeuler/marketing/issues/I1H8H9 + - [No.1 - 为 openEuler 添加 Xfce 桌面环境并能够运行在树莓派 4B 上](https://gitee.com/openeuler/marketing/issues/I1H8G3) 任务地址 https://gitee.com/openeuler/marketing/issues/I1H8G3 + - [No.3 - 为 openEuler 树莓派 4B 镜像提供 UEFI 启动支持](https://gitee.com/openeuler/marketing/issues/I1H8HV) 任务地址 https://gitee.com/openeuler/marketing/issues/I1H8HV + +3. Linux 桌面相关任务 - **建议申请此任务的同学掌握 Linux DNF/RPM 管理方案,熟悉 Linux 桌面系统的同学申请此类任务** + + 由于历史原因,目前 [openEuler](https://www.openeuler.org) 还没有正式提供桌面环境,所以在这次活动中 [sig-UKUI](https://gitee.com/openeuler/community/tree/master/sig/sig-UKUI) 的 Maintainer [douyan@kylinos.cn](mailto:douyan@kylinos.cn) 和 [jianfengli@ubuntukylin.com](mailto:jianfengli@ubuntukylin.com) 发起了移植 [UKUI](https://www.ukui.org) 到 [openEuler](https://www.openeuler.org) 的任务。在 [No.1](https://gitee.com/openeuler/marketing/issues/I1H8G3) 任务则是把轻量级桌面系统 [Xfce](https://www.xfce.org) 移植到 [openEuler](https://www.openeuler.org) 系统中。 + + [UKUI](https://www.ukui.org) 是麒麟软件桌面研发团队开发的基于 Linux 发行版的轻量级桌面环境,其设计紧贴普通用户需求,特别是针对有一定 Windows 系统使用习惯的用户,减少其使用 Linux 系统的学习成本。2019年,麒麟软件全面启动 UKUI 3.0 的设计和研发工作,全新的 UKUI 3.0 使用 QT 开发,秉承 “友好易用,简单轻松” 的设计理念,将为用户提供更愉快的交互体验。 + + - [No.100 - 将 UKUI 移植到 openEuler,并支持生物识别](https://gitee.com/openeuler/marketing/issues/I1IRJ3) 任务地址 https://gitee.com/openeuler/marketing/issues/I1IRJ3 + +4. Linux 容器引擎相关任务 - **建议熟悉 Linux 容器引擎技术实现(如 Docker )的同学申请此类任务** + + [openEuler](https://www.openeuler.org) 在兼容主流的容器引擎同时,孵化自己的容器引擎项目 [iSula](https://gitee.com/openeuler/iSulad),它在支持 Docker 镜像的同时支持 OCI 格式的镜像和规范。 [iSulad SIG](https://gitee.com/openeuler/community/tree/master/sig/iSulad) 的 Maintainers 为同学带来了多个任务。更多 [iSula](https://gitee.com/openeuler/iSulad) 的任务请访问它的官方[文档](https://www.openeuler.org/zh/docs/20.03_LTS/docs/Container/container.html) + + Linux 容器相关知识可以参考: + + - Docker 相关文档 https://docs.docker.com + - [Open Container Initiative](https://opencontainers.org) 基金会对 Linux Container 定义可以在其 Github 网站 https://github.com/opencontainers + - https://riscv.org + + 任务列表: + + - [No.7 - 构建可运行 iSulad 点容器镜像,并推送到 Docker Hub 镜像仓库](https://gitee.com/openeuler/marketing/issues/I1HVZF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HVZF + - [No.9 - iSula 相关项目支持编译 Debian 包](https://gitee.com/openeuler/marketing/issues/I1HWDZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HWDZ + - [No.10 - iSula 项目内存池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX3G) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HX3G + - [No.11 - iSula 项目线程池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX5Y) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HX5Y + - [No.12 - iSula-kits 支持在多个 OS 发型版上运行](https://gitee.com/openeuler/marketing/issues/I1HXE7) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXE7 + - [No.13 - iSula 容器镜像构建工具支持多存储驱动](https://gitee.com/openeuler/marketing/issues/I1HXS9) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXS9 + - [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1HXS9) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXS9 + - [No.8 - C 语言 JSON 解析转换代码生成框架](https://gitee.com/openeuler/marketing/issues/I1HWB3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HWB3 + +5. Kubernetes 相关任务 - **建议熟悉 Kubernetes 编排调度技术的同学申请此类任务** + + [openEuler](https://www.openeuler.org) 当然不会缺席当前业界最热的开源项目 [Kubernetes](https://kubernetes.io) ,多个 SIG 组的 Maintainer 推出了相关的任务,从相对简单的集成任务到有一定难度的开发任务。[Kubernetes](https://kubernetes.io) 的资料很多,这里就不一一列举。 + + 相关资料: + + - https://kubernetes-csi.github.io/docs + - https://goharbor.io + - https://www.cs.nmsu.edu/~pfeiffer/fuse-tutorial + - https://github.com/libfuse/libfuse + - https://www.kernel.org/doc/html/latest/filesystems/fuse.html + + 任务列表: + + - [No61. - openEuler 集成 Kubernetes 相关软件包](https://gitee.com/openeuler/marketing/issues/I1IF4R) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IF4R + - [No.91 - 用 RUST 实现基于 FUSE 的 Kubernetes CSI 接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No. 14 - openEuler 集成 Harbor 项目](https://gitee.com/openeuler/marketing/issues/I1HXBE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXBE + +6. 虚拟化、云相关任务 - **建议熟悉 QEMU 等虚拟化技术的同学申请此类任务** + + [QEMU](https://www.qemu.org) 可以说是云计算的基石技术,在很多云计算的架构中是配合 KVM 来完成虚拟化工作。因为 KVM 是硬件辅助的虚拟化技术,主要负责比较繁琐的 CPU 和内存虚拟化,而 QEMU 则负责 I/O 虚拟化,两者合作各自发挥自身的优势相得益彰。 + + 相关资料: + + - https://www.qemu.org + - https://www.youtube.com/watch?v=dk6SUD8ovXw + + 任务列表: + + - [No.56 - 以 openEuler LTS 为基础生成公有云镜像](https://gitee.com/openeuler/marketing/issues/I1ICCJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICCJ + - [No.52 - openEuler 虚拟化调度性能评估工具及方法构建](https://gitee.com/openeuler/marketing/issues/I1I9XJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I9XJ + - [No.6 - 虚拟化场景下的类似 top 点调测工具 virttop](https://gitee.com/openeuler/marketing/issues/I1HVM7) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HVM7 + - [No.66 - QEMU 中集成 virtio-fuzz 能力以支持模拟设备的模糊测试](https://gitee.com/openeuler/marketing/issues/I1IHCJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHCJ + - [No.62 - QEMU 用户态进程热补丁框架](https://gitee.com/openeuler/marketing/issues/I1IG8E) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IG8E + +7. Golang 相关任务 - **建议熟悉 Golang 语言、对 aarch64 架构和算法有一定程度了解等的同学申请此类任务** + + [Golang](https://golang.org) 随着容器技术和 [Kubernetes](https://kubernetes.io) 的逐渐被开发者接受。[openEuler](https://www.openeuler.org) 社区提出的 [Golang](https://golang.org) 大多是基于 ARM64 的优化任务。需要对 ARM 的指令集和 Golang 语言编译器等有一定的了解才能顺利完成任务 + + 相关资料: + + - https://community.arm.com/developer/tools-software/oss-platforms/b/android-blog/posts/arm-neon-programming-quick-reference + - https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf + - https://static.docs.arm.com/ddi0487/a/DDI0487A_j_armv8_arm.pdf + - https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf + - https://courses.cs.washington.edu/courses/cse469/18wi/Materials/arm64.pdf + + 任务列表: + + - [No.81 - 优化 Golang 同步包中锁或原子操作在 ARM64 上的实现,提升安全并发的性能](https://gitee.com/openeuler/marketing/issues/I1IJ86) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ86 + - [No.80 - 增强 Golang 编译器基于 ARM64 的智能化编译](https://gitee.com/openeuler/marketing/issues/I1IJ5W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5W + - [No.79 - Golang 编解码算法性能优化](https://gitee.com/openeuler/marketing/issues/I1IJ5T) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5T + - [No.78 - 基于 ARM 的硬件加速能力软硬件协同调优 Golang 数学库函数](https://gitee.com/openeuler/marketing/issues/I1IJ4X) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4X + - [No.76 - 优化 Golang 压缩库的压缩率或压缩性能](https://gitee.com/openeuler/marketing/issues/I1IJ4M) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4M + - [No.74 - 优化 Golang 图像库功能和性能](https://gitee.com/openeuler/marketing/issues/I1IJ24) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ24 + - [No.73 - 增强 Golang 运行时库在 ARM 上的性能和安全性](https://gitee.com/openeuler/marketing/issues/I1IJ0J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ0J + - [No.72 - 针对 Golang 加解密库进行 ARM64 相关的优化](https://gitee.com/openeuler/marketing/issues/I1IIW6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IIW6 + +8. Rust 相关任务 - **建议熟悉 Rust 语言、具有一定存储知识(部分任务需要)的同学申请此类任务** + + [Rust](https://www.rust-lang.org) 是近几年崛起的系统级编程语言,也在 TIOBE 的排名上进入了前 20 名。越来越多的项目在使用 [Rust](https://www.rust-lang.org) 来开发。 + + 相关资料: + + - https://www.rust-lang.org + - https://coolshell.cn/articles/9606.html + - https://coolshell.cn/articles/9703.html + - https://coolshell.cn/articles/8239.html + + 任务列表: + + - [No.93 - 用 Rust 实现无锁 HashMap](https://gitee.com/openeuler/marketing/issues/I1IMNX) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMNX + - [No.92 - 用 Rust 实现无锁 LRU 缓存](https://gitee.com/openeuler/marketing/issues/I1IMNR) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMNR + - [No.91 - 用 RUST 实现基于 FUSE 的 Kubernetes CSI 接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No.89 - 基于 Rust 实现 HDFS 的用户态 FUSE 驱动](https://gitee.com/openeuler/marketing/issues/I1IMGW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMGW + - [no.87 - 基于 Rust 高性能 HTTP 库 Hyper 或 Tide 实现 S3 服务端](https://gitee.com/openeuler/marketing/issues/I1IMFO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMFO + +9. 存储相关任务 - **建议熟悉 Linux 存储知识的同学申请此类任务** + + [FUSE] 是用户态的文件系统,目前业界都在探索把存储前置到用户态,提升效率和管控的能力。[openEuler](https://www.openeuler.org) 提出的存储业务大部分都跟此方向相关。 + + 相关资料: + + - https://hadoop.apache.org/docs/r3.2.1/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html + - https://www.ibm.com/analytics/hadoop/hdfs + - https://en.wikipedia.org/wiki/Apache_Hadoop + - https://en.wikipedia.org/wiki/Filesystem_in_Userspace + - https://spdk.io + - https://lwn.net/Articles/740157 + - http://www.tcpdump.org/papers/bpf-usenix93.pdf + - https://lwn.net/Articles/599755 + - http://blog.memsql.com/bpf-linux-performance + + 任务列表: + + - [No.91 - 用 RUST 实现基于 FUSE 的 Kubernetes CSI 接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No.89 - 基于 Rust 实现 HDFS 的用户态 FUSE 驱动](https://gitee.com/openeuler/marketing/issues/I1IMGW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMGW + - [No.82 - 基于 SPDK 的高性能用户态用户态文件系统](https://gitee.com/openeuler/marketing/issues/I1IKCX) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKCX + - [No.90 - 基于 Perf 或 eBPF 对 FUSE 进行 Tracing 分析](https://gitee.com/openeuler/marketing/issues/I1IMIA) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMIA + +10. ARM64 相关任务 - **建议熟悉 aarch64 架构,算法有一定能力的同学申请此类任务** + + [openEuler](https://www.openeuler.org) 提出的 ARM64 相关任务都是优化类型,此部分参考资料参见第 7 类 [Golang](https://golang.org) 的相关资料。 + + 任务列表: + + - [No.16 - 为 ARM 平台优化开源软件的 CRC 实现](https://gitee.com/openeuler/marketing/issues/I1HYCD) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HYCD + - [No.81 - 优化Go同步包中锁或原子操作在 ARM64 上的实现,提升安全并发的性能](https://gitee.com/openeuler/marketing/issues/I1IJ86) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ86 + - [No.80 - 增强 Golang 编译器基于ARM64的智能化编译](https://gitee.com/openeuler/marketing/issues/I1IJ5W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5W + - [No.78 - 基于ARM的硬件加速能力软硬件协同调优go数学库函数](https://gitee.com/openeuler/marketing/issues/I1IJ4X) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4X + - [No.77 - 在Eigen社区中提供ARM的CI环境](https://gitee.com/openeuler/marketing/issues/I1IJ4N) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4N + - [No.75 - Numpy 在 ARM 平台的优化](https://gitee.com/openeuler/marketing/issues/I1IJ3H) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ3H + - [No.73 - 增强Golang运行时库在ARM上的性能和安全性](https://gitee.com/openeuler/marketing/issues/I1IJ0J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ0J + - [No.72 - 针对Go加解密库进行ARM64相关的优化](https://gitee.com/openeuler/marketing/issues/I1IIW6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IIW6 + - [No.65 - adler32算法在ARM平台的优化](https://gitee.com/openeuler/marketing/issues/I1IGXZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IGXZ + +11. RISC-V 相关任务 - **建议熟悉 RISC-V 架构的同学申请此类任务** + + [RISC-V](https://riscv.org) 是一种是一个基于精简指令集(RISC)原则的开源指令集架构(ISA),[openEuler](https://www.openeuler.org) 的 [RISC-V](https://gitee.com/openeuler/community/tree/master/sig/sig-RISC-V) SIG 的 Maintainer 正在致力于移植工作。 + + 相关资料: + + - https://riscv.org + + 任务列表: + + - [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1IKQO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKQO + - [No.83 - 在 RISC-V 架构openEuler平台上提供golang支持](https://gitee.com/openeuler/marketing/issues/I1IKOI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKOI + - [No.21 - 为openEuler - RISC-V 添加grub的引导启动方式](https://gitee.com/openeuler/marketing/issues/I1I1TS) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1TS + +12. 安全相关任务 - **建议熟悉 Linux 安全的同学申请此类任务** + + 安全是业界永恒的话题,[openEuler](http://openeuler.org) 从第一天开始就重视安全问题,除了 CVE 漏洞披露以外,也在 openEuler 中加入各种安全特性。 + + 相关资料: + + - https://www.open-scap.org + - https://www.redhat.com/en/topics/linux/what-is-selinux + - https://wiki.ubuntu.com/AppArmor + - https://www.op-tee.org + + 任务列表: + + - [No.50 - 提供 openEuler 满足 openscap 标准的安全配置基线](https://gitee.com/openeuler/marketing/issues/I1I7JW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I7JW + - [No.46 - SELinux 策略应用指导](https://gitee.com/openeuler/marketing/issues/I1I7H3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I7H3 + - [No.45 - 移植 libapparmor 到 openEuler 社区](https://gitee.com/openeuler/marketing/issues/I1I77C) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I77C + - [No.51 - optee 移植到 openEuler](https://gitee.com/openeuler/marketing/issues/I1I8IS) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I8IS + +13. 测试相关任务 - **建议测试专业的同学申请此类任务** + + 测试类的任务难度较低,只要熟悉要测试的软件包,对 Linux 的基本操作比较熟悉就可报名参与。 + + 主要工作: + + - 分析软件包提供的功能/具体用户使用场景/发布命令及参数/提供服务/包使用资源消耗等方面 + - 进行相应的测试设计活动,如功能类/性能类/可靠性类等 + - 根据测试设计编写相应的测试代码和调试 + + 相关任务: + + - [No.69 - api-sanity-checker 与 oss-fuzz 测试结合的误报优化](https://gitee.com/openeuler/marketing/issues/I1IHNM) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHNM + - [No.34 - 对 openEuler 社区发布包 keepalived 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CG) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6CG + - [No.35 - 对 openEuler 社区发布包 kmod-kvdo 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6CY + - [No.36 - 对 openEuler 社区发布包 OpenVPN 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6D6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6D6 + - [No.37 - 对 openEuler 社区发布包 lrzsz 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6EO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6EO + - [No.38 - 对 openEuler 社区发布包 ipvsadm 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6F2) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6F2 + - [No.39 - 对 openEuler 社区发布包 MongoDB 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GM) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6GM + - [No.40 - 对 openEuler 社区发布包 Redis 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6GW + - [No.41 - 对 openEuler 社区发布包 sssd 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6IK + - [No.42 - 对 openEuler 社区发布包 MySQL 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IN) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6IN + - [No.43 - 对 openEuler 社区发布包 rpcbind 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6JE + - [No.44 - 对 openEuler 社区发布包 haproxy 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6JI + - [No.29 - 对openEuler社区发布包osc和obs-build进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I5WZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I5WZ + + 14. AI、大数据相关任务 - **建议熟悉 AI 、大数据框架的同学申请此类任务** + + AI、大数据类的相关任务同测试相关任务类似,只要熟悉相关的软件,具有一定的 Linux 知识就可报名参与。 + + 任务列表: + + - [No.5 - 在 openEuler aarch64 架构上完成 PyTorch 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1HR9C) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HR9C + - [No.4 -在 openEuler aarch64 架构上完成 Tensorflow 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1HR7W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HR7W + - [No.23 - 在 openEuler aarch64 架构上完成 Hadoop WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I290) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I290 + - [No.22 - 在 openEuler aarch64 架构上完成 mlpack 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1I281) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I281 + - [No. 24 - 在 openEuler aarch64 架构上完成 Spark WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I29G) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I29G + - [No.25 - 在 openEuler aarch64 架构上完成 Flink WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I2A0) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I2A0 + +15. Linux 系统相关任务 - **建议熟悉 Linux 系统的同学申请此类任务** + + Linux 系统相关任务涉及到 Linux 的方方面面,无法在此进行详解。需要申请的同学对 Linux 特定领域有深入的了解,同时具有一定的开发能力。 + + 任务列表: + + - [No.67 - 基于需求覆盖度判断的用例筛选方法(RBC,requirement-based coverage)探索及工程构建](https://gitee.com/openeuler/marketing/issues/I1IHGJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHGJ + - [No.98 - 众核场景下OS基础设施机制线性度探索](https://gitee.com/openeuler/marketing/issues/I1IO7D) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IO7D + - [No.97 - 优化glibc内存管理框架内容空洞导致内存占用不断增加的问题](https://gitee.com/openeuler/marketing/issues/I1IO19) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IO19 + - [No.96 - 优化nfs-utils锁以解决并发性能差问题](https://gitee.com/openeuler/marketing/issues/I1INR1) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INR1 + - [No.95 - openEuler CPU 故障隔离](https://gitee.com/openeuler/marketing/issues/I1INPO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INPO + - [No.102 - 内核态CR(Checkpoint and Restore )用户态应用程序](https://gitee.com/openeuler/marketing/issues/I1INPF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INPF + - [No.94 - 实现API识别软件包依赖的功能](https://gitee.com/openeuler/marketing/issues/I1IMTI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMTI + - [No.90 - 基于Perf或eBPF对FUSE进行tracing分析](https://gitee.com/openeuler/marketing/issues/I1IMIA) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMIA + - [No.57 - 内核数据竞争检测工具](https://gitee.com/openeuler/marketing/issues/I1ICGN) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICGN + - [No.71 - openEuler 不同系统间源码包成分信息比较](https://gitee.com/openeuler/marketing/issues/I1IHVG) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHVG + - [No.70 - openEuler 源码包成分提取、归档](https://gitee.com/openeuler/marketing/issues/I1IHUT) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHUT + - [No. 20 - LUTF - Linux Userspace Task Framework](https://gitee.com/openeuler/marketing/issues/I1I1RK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1RK + - [No.60 - everything tool on openEuler](https://gitee.com/openeuler/marketing/issues/I1IELF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IELF + - [No. 19 - LSCA - Linux 系统调用代理](https://gitee.com/openeuler/marketing/issues/I1I1JR) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1JR + - [No. 18 - SVA (Share Virtual Address)引擎](https://gitee.com/openeuler/marketing/issues/I1I1D1) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1D1 + - [No.17 - 库函数行为收集器](https://gitee.com/openeuler/marketing/issues/I1I06J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I06J + - [No.15 - 改进 openEuler-Advisor 来支持 openEuler 快速滚动升级](https://gitee.com/openeuler/marketing/issues/I1HXMV) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXMV + - [No.49 - 基于 openEuler 的 ABI 检查工具](https://gitee.com/openeuler/marketing/issues/I1HQSE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HQSE + - [No.47 - 开发 openEuler bootstrap 工具](https://gitee.com/openeuler/marketing/issues/I1HAXJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HAXJ + - [No.33 - 基于 Posix 接口的协程框架](https://gitee.com/openeuler/marketing/issues/I1I66U) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I66U + - [No.32 - 系统资源负载预测框架](https://gitee.com/openeuler/marketing/issues/I1I64J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I64J + - [No.31 - Linux 内核 Crash 问题自动定位工具](https://gitee.com/openeuler/marketing/issues/I1I632) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I632 + +16. 开源基础设施相关任务 - **建议具有基本开发能力的同学申请此类任务** + + 本类任务需要社区内的同学具有基本的开发能力,对于开源过程中开发者体验有自己的想法和见解。 + + - [No.53 - 为 openEuler 创建用户轨迹运营看板](https://gitee.com/openeuler/marketing/issues/I1IAOD) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IAOD + - [No.58 - 为 openEuler 提供 PR Preview 功能](https://gitee.com/openeuler/marketing/issues/I1ICRB) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICRB + - [No.59 - 开源基础设施智能自检自愈系统](https://gitee.com/openeuler/marketing/issues/I1ICRK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICRK + \ No newline at end of file diff --git a/web-ui/docs/zh/blog/genedna/xsky-ceph-sig.md b/web-ui/docs/zh/blog/genedna/xsky-ceph-sig.md new file mode 100644 index 0000000000000000000000000000000000000000..a2ca4ee16673a98a236ea5165cce344d2ff7a01d --- /dev/null +++ b/web-ui/docs/zh/blog/genedna/xsky-ceph-sig.md @@ -0,0 +1,27 @@ +--- +title: openEuler 社区成立 Ceph SIG +date: 2020-06-16 +tags: + - openEuler 社区 + - XSKY + - Ceph +archives: 2020-06 +author: genedna +summary: openEuler 社区正式成立Ceph SIG。 +--- + +## openEuler 社区成立 Ceph SIG + +openEuler 开源社区(以下简称“openEuler社区”)正式成立 Ceph SIG(Special Interest Group 特别兴趣小组),完善 openEuler 操作系统在分布式存储场景的适配。 openEuler 社区参与者和用户可获得由专业存储团队维护的稳定的 Ceph 版本构建分布式存储系统,并通过 openEuler 社区获得技术支持。 + +Ceph 是一个具备高性能、可靠性和可扩展性的分布式存储解决方案,可以同时提供块、文件和对象三种服务。 目前,Ceph 已经成为最主流的开源分布式存储系统。为了进一步丰富 openEuler 环境下的存储解决方案,经过 openEuler 技术委员会讨论,正式成立 Ceph SIG, 当前 Ceph SIG 的第一位 Maintainer 为软件定义存储厂商 XSKY 。XSKY 将会把 Ceph 集成到 openEuler 的发行版本,使得 openEuler 具备分布式存储场景的适配能力。根据计划,在今年Q3前,openEuler 社区将完成 Ceph 最新主流发行版本的所有适配工作,并适时启动自动化 QA 框架的搭建。 + +XSKY 公司作为全球领先的 Ceph 开源社区推动者之一,源代码贡献居全球前列。一直以来,XSKY 主导并维护了 Ceph 社区的多个模块,也是 Ceph 基金会的全球创始顶级会员。 + +openEuler 社区技术委员会委员熊伟表示:“成立 Ceph SIG 将进一步增强 openEuler 面向存储场景的适配能力。XSKY 公司作为项目组的 Maintainer ,能够加速 Ceph 在 openEuler 的落地,并提供更加快速的版本迭代计划和问题修复能力,结合 openEuler 和 Ceph 版本发布计划为社区提供最新发行版本。 + +XSKY公司资深架构师池信泽表示:“openEuler 致力于提供一个开放、多元和架构包容的软件生态系统,帮助用户快速构建 5G、边缘、云场景等多元化的应用环境。我们非常高兴能够成为 openEuler 社区 Ceph SIG 的 Maintainer,有机会推动Ceph和openEuler两个社区的连接。未来,我们将和众多开发者一起为 openEuler 社区提供存储领域丰富的企业特性。” + +### 关于XSKY + +[XSKY](https://www.xsky.com) 是中国软件定义存储的领导厂商,致力于以中国技术力量影响开放平台生态系统,创建自主可控的底层设施,以主流的、先进的技术和产品为客户创造价值。 IDC 将 XSKY 定义为“2019 中国软件定义存储创新者”。2020 年,XSKY 入选 《Gartner Peer Insights‘Voice of the Customer’:Distributed File Systems and Object Storage》 报告,并位列第二象限。 根据 IDC 《2019Q4 China SDS Market Overview》显示:截至2019年,在中国软件定义存储(SDS)整体市场份额排名中,XSKY 位居第四;其中对象存储细分市场排名第一(22.2%),已连续11个季度占据国内市场第一位,块存储细分市场排名第三(14.1%)。 diff --git a/web-ui/docs/zh/blog/georgecao/openEuler-sig-member-management.md b/web-ui/docs/zh/blog/georgecao/openEuler-sig-member-management.md new file mode 100644 index 0000000000000000000000000000000000000000..8724401445109058ddd4a0e97809274f3ac06121 --- /dev/null +++ b/web-ui/docs/zh/blog/georgecao/openEuler-sig-member-management.md @@ -0,0 +1,143 @@ +--- +title: openEuler社区SIG组成员管理方案 +date: 2022-04-26 +tags: + - openEuler + - SIG组成员管理 +archives: 2022-04 +author: georgecao +summary: openEuler 社区SIG组成员管理方案细节。 +--- + +# openEuler社区SIG组成员管理方案 +## 社区SIG成员角色划分 +通过和多个sig组讨论,并报TC确认,openEuler社区SIG组成员角色做如下划分: +| 角色 | 定位 | +|--|--| +| Maintainer | 定位是SIG组的牵引者、规划者,努力做好SIG组的发展和演进;负责定期组织SIG组会议、并代表SIG组向社区展示SIG组情况;| +| Committer| SIG组部分仓库的看护者;作为这部分仓库的第一责任人; Committer也是SIG组Maintainer的后备力量;| +|Contributor|SIG组部分仓库的重要贡献者,也是这部分仓库Committer的后备力量;通常也是这部分代码仓库问题主要修复者和代码开发者;| +|Developer|社区最广泛的代码贡献者;在社区长期贡献可自荐或被推荐为仓库Contributor,甚至Committer;| +|RepoAdmin|1.社区部分自研代码仓库需要git push权限,会对这些仓库设置Admin权限;通常是SIG组maintainer兼任,对这部分仓库的代码合入全量负责;| + +## SIG组成员权责划分 +根据不同角色,在社区(特别是在gitee代码托管平台)承担不同的权责: +|SIG成员角色|sig_info.yaml记录| 代码提交 |评论/approve合入|git push合入 | +|--|--|--|--|--| +| Maintainer | ✔️ | ✔️ [全部仓库] | ✔️ |❌| +| Committer| ✔️ |✔️ | ✔️ [部分仓库] | ❌ | +| Contributor| ✔️ |✔️ |❌ |❌ | +| Developer| ❌ | ✔️ | ❌ | ❌| +| Repo_Admin| ✔️ | ✔️ | ✔️ [部分仓库] | ✔️[部分仓库] | + +## 成员管理方案 + + 1. 每个SIG组新增sig_info.yaml文件作为社区成员管理载体; + + 2. 只有当前SIG目录下OWNER文件被删除后,sig_info.yaml信息才会生效;OWNER文件存在时继续保持原成员关系和权限管控功能; + 3. sig_info.yaml中需要有全局的Maintainer,对sig组所有仓库都有合入权限(继承原Maintainer逻辑);——必选项 + 4. 可以在部分仓库下添加这些仓库特有的Committer,仅有这一部分仓库的合入权限;——可选项 + 5. 部分仓库下可新增Contributor字段,无代码合入权限;作为仓库的主要贡献者列出;——可选项 + 6. 部分仓库下新增Admin字段, 对这部分仓库具有管理员权限,可通过git push合入代码;——可选项; + 7. 为缓解各sig组提交sig_info.yaml的困难,门禁组会按照当前OWNER文件信息和仓库信息,自动为 sig组创建sig_info.yaml + + +## 如何编写sig_info.yaml文件 +### 手动编写sig-info.yaml 文件 + +sig-info.yaml 文件为yaml格式承载,包含如下基本元素: +| 字段 | 类型 | 说明 | +|--|--|--| +| name | 字符串 | SIG组名称 ,必填| +| description | 字符串 | SIG组描述信息,必填 | +| created_on| 字符串 | SIG组创建时间,选填 | +| mailing_list | 字符串 | SIG组讨论邮件列表地址,选填 | +| meeting_url | 字符串 | SIG例会纪要URL,选填 | +| mentors | 列表 | SIG组当前导师名单,选填 | +| maintainers | 列表 | SIG组所有maintainer名单 | +| repositories| 列表 | SIG组所管辖的码云仓库信息 | + +其中 mentors 列表中每一条记录代表一位 mentor 的个人信息,maintainers 列表中每一条记录代表一位 maintainer 的个人信息。每一条个人信息记录包含如下元素: +| 字段 | 类型 | 说明 | +|--|--|--| +| gitee_id | 字符串 | gitee ID, 必填 | +| name | 字符串 | 姓名(或者网名), 必填 | +| organization| 字符串 | 所在组织或单位, 选填 | +| email| 字符串 | 个人邮箱地址, 选填 | + +其中 repositories 字段为列表,其中每一个列表元素为SIG所管理的一组仓库信息,包括以下四个字段: +| 字段 | 类型 | 说明 | +|--|--|--| +| repo | 列表 | 该SIG管理的一组仓库名称组成的数组,必填 | +| committers| 列表 | 这一组仓库共同的committer成员们,选填 | +| contributors| 列表 | 这一组仓库共同的contributors成员们,选填 | +| repo_admin| 列表 | 这一组仓库共同的repo admin成员们,选填 | + +以上信息中repo为仓库名称数组,其余committers/contributors/repo_admin都是成员数组,其中单个元素表示一条个人信息,同上文maintainer信息: +| 字段 | 类型 | 说明 | +|--|--|--| +| gitee_id | 字符串 | gitee ID, 必填 | +| name | 字符串 | 姓名(或者网名), 必填 | +| organization| 字符串 | 所在组织或单位, 选填 | +| email| 字符串 | 个人邮箱地址, 选填 | + +其中committers拥有对应repo组下所有仓库的代码审核权限,contributors是该repo组下所有仓库的主要贡献者。 + +#### sig-info.yaml 样例: +``` +name: Infrastructure +description: This is a sample sig. Please copy it over and modify it accordingly. +created_on: '1970-01-01' +mailing_list: infra@openeuler.org +meeting_url: NA +mature_level: startup +mentors: +- gitee_id: batMan + name: Wayne + email: aaaaaaa@openeuler.org +maintainers: +- gitee_id: Joe + name: JoeDou + organization: RealT + email: yyyyyyy@qq.com +- gitee_id: Jane + name: JaneDou + email: xxxxxxx@gmail.com +repositories: +- repo: + - openeuler/infrastructure + - openeuler/website + - openeuler/website-v2 + committers: + - gitee_id: Bob + name: BobMa + email: zzzzzzz@yahoo.com + contributors: + - gitee_id: infra_superman + name: Clark_Ken + orgnization: Justice_L + email: zzzzzzz@openeuler.org +- repo: + - openeuler/cve-manager + - openeuler/tool-collections + - openeuler/go-gitee + - openeuler/gitbook-theme-hugo + - cve-manager + committers: + - gitee_id: tommyliu + name: Tommy + email: zzzzzzzhh@163.com + repo_admin: + - gitee_id: lisa993 + name: LisaLi + email: lililisa@qq.com +``` +### 自动生成sig_info.yaml样板后手动补充 +基础设施提供自动化脚本可以快速生成相关SIG组的配置管理文件sig_info.yaml。 +其中maintainer信息的gitee_id来源与owner文件,repositories中仓库信息来源于sig目录下所有仓库配置信息。其余信息只是格式化模板,需要用户自行完善; +#### 命令使用方法: + - git clone https://gitee.com/openeuler/community.git 获取community仓库代码 + - cd community/sig/ 跳转到sig管理目录 + - python3 create_sig_info_template.py xxx 在对应SIG组文件夹内创建sig_info.yaml文件模板,其中 xxx 为SIG组名称,如Infrastructure,A-Tune等 + - 进入对应SIG组文件夹,修改sig_info.yaml模板中相关内容 + - 提交sig_info.yaml修改 diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/branch_select.png b/web-ui/docs/zh/blog/gitee-cmd/images/branch_select.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3f88dd6c75f04bcf9f9845c5d2176467368752 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/branch_select.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/etc_host.png b/web-ui/docs/zh/blog/gitee-cmd/images/etc_host.png new file mode 100644 index 0000000000000000000000000000000000000000..19c51a5628c73cfbf8869ced8750f012edd1a041 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/etc_host.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/fed_pkg.png b/web-ui/docs/zh/blog/gitee-cmd/images/fed_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..e55fd3d183d962cf4620a525e0465653a0748632 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/fed_pkg.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/md5.png b/web-ui/docs/zh/blog/gitee-cmd/images/md5.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0e221071f14668e2f63c15c20cd762fc0c1a46 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/md5.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/moban.png b/web-ui/docs/zh/blog/gitee-cmd/images/moban.png new file mode 100644 index 0000000000000000000000000000000000000000..03aeb294357923f19c0722a0805b4617cbb0de7a Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/moban.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/need_introduce.png b/web-ui/docs/zh/blog/gitee-cmd/images/need_introduce.png new file mode 100644 index 0000000000000000000000000000000000000000..10c7d21d7cfd5651177c2a9e9e82113c58d51816 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/need_introduce.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch.png b/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch.png new file mode 100644 index 0000000000000000000000000000000000000000..dd51ea6e7c223d8407187a7b80abdcab8cbb365e Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch_accept.png b/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch_accept.png new file mode 100644 index 0000000000000000000000000000000000000000..6b90b6152711453613fc5e765aba9af082297c75 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/obs_branch_accept.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/obs_create_pkg.png b/web-ui/docs/zh/blog/gitee-cmd/images/obs_create_pkg.png new file mode 100644 index 0000000000000000000000000000000000000000..c90f2748f3f1d92930cc08c8fecc534ec8f1b714 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/obs_create_pkg.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/osb.png b/web-ui/docs/zh/blog/gitee-cmd/images/osb.png new file mode 100644 index 0000000000000000000000000000000000000000..16d1e3bb9997a0913b3d658037f3fa4260d03be7 Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/osb.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/osc_config1.png b/web-ui/docs/zh/blog/gitee-cmd/images/osc_config1.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2e7a1298594c1d3efb74f838fa10145187114c Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/osc_config1.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/osc_config2.png b/web-ui/docs/zh/blog/gitee-cmd/images/osc_config2.png new file mode 100644 index 0000000000000000000000000000000000000000..dc809fcb24c44b25b463dd5cbca322b0c40132ef Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/osc_config2.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/pkg_repo_select.png b/web-ui/docs/zh/blog/gitee-cmd/images/pkg_repo_select.png new file mode 100644 index 0000000000000000000000000000000000000000..ac414b3a0bde43cf4be1a751fd54c4f54d24631c Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/pkg_repo_select.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/pkgship.png b/web-ui/docs/zh/blog/gitee-cmd/images/pkgship.png new file mode 100644 index 0000000000000000000000000000000000000000..c2174d66958f75b6f5012ea37aa32cca2443926c Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/pkgship.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/sample.png b/web-ui/docs/zh/blog/gitee-cmd/images/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..28e1a7ab2ab82a4ee20328a2fdd0ca26301e2b9b Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/sample.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/special_yaml.png b/web-ui/docs/zh/blog/gitee-cmd/images/special_yaml.png new file mode 100644 index 0000000000000000000000000000000000000000..fccacdc0c24ca3c441ae3ff0595208f62038476c Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/special_yaml.png differ diff --git a/web-ui/docs/zh/blog/gitee-cmd/images/yaml_content.png b/web-ui/docs/zh/blog/gitee-cmd/images/yaml_content.png new file mode 100644 index 0000000000000000000000000000000000000000..8d756634862798f0786500d4c48d0d335c57316c Binary files /dev/null and b/web-ui/docs/zh/blog/gitee-cmd/images/yaml_content.png differ diff --git "a/web-ui/docs/zh/blog/gitee-cmd/openEuler\347\244\276\345\214\272\350\275\257\344\273\266\345\214\205\345\274\225\345\205\245\345\210\206\346\236\220\346\214\207\345\215\227.md" "b/web-ui/docs/zh/blog/gitee-cmd/openEuler\347\244\276\345\214\272\350\275\257\344\273\266\345\214\205\345\274\225\345\205\245\345\210\206\346\236\220\346\214\207\345\215\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..90ef7e7b422e9ea618a455f768f8130ed4a0c911 --- /dev/null +++ "b/web-ui/docs/zh/blog/gitee-cmd/openEuler\347\244\276\345\214\272\350\275\257\344\273\266\345\214\205\345\274\225\345\205\245\345\210\206\346\236\220\346\214\207\345\215\227.md" @@ -0,0 +1,332 @@ +--- +title: openEuler 社区软件包引入分析指南 +date: 2021-12-20 +tags: + - openEuler + - software + - guidebook +archives: 2021-12 +author: gitee-cmd +summary: Guidebook for openEuler community software Introduction +--- + + +# openEuler社区软件包引入分析指南 + +为提升软件包引入效率,保证软件包引入质量,发布本指南指导社区贡献者进行软件包引入的分析工作。 + +## 1. 软件包准入checklist + +软件包引入提交PR前需待引入软件包以及依赖进行软件包引入检查,根据[软件包引入前检查checklist](https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/software-management.md#%E8%BD%AF%E4%BB%B6%E9%80%89%E5%9E%8B%E5%8F%8A%E5%BC%95%E5%85%A5%E5%89%8D%E6%A3%80%E6%9F%A5)逐个分析带引入软件包及其依赖是否符合openEuler社区准入规则。openEuler软件包引入原则如下: + + + +| 检查点 | 说明 | +| ---------------- | ------------------------------------------------------------ | +| 归一化 | 1、原则上一款软件只在src-openeuler中引入一次。 | +| 来源可靠 | 1、开源软件都应该从开源软件官网获取或官网指定的代码托管地址获取。 | +| 规范化软件名称 | 1、 软件名称必须和官网/社区保持一致,不可随意命名, 2、 不允许以软件包中的子模块作为软件名, 3、 当软件是某个语言的开发库时,我们允许追加python-、perl-等前缀予以规范化管理。 | +| 社区运营状态检查 | 1、软件来自知名社区或组织,社区或组织通过发布公告、修改软件仓库状态、将仓库放到特定目录下等方式告知停止维护的,不建议引入, 2、软件来自个人、小型社区或组织,两年内未发布版本(含正式版本与测试版本),无明确版本计划,社区提交了有效的Bug或PR,但是半年以上未响应的,不建议引入, 3、社区运营状态不明确,通过Issue 或者邮件等方式询问社区是否继续维护,半年以上未响应或者答复停止维护的,不建议引入。 | +| 官网必填 | 1、软件官方网址填写规范,使用软件供应商提供的网址,或者无单独正式官网的情况下,提供主流代码托管商上面对应的项目网址如github 2、不能使用maven、mvnrepository、springsource等托管库作为官方网址 | +| 软件包信息提供 | 1、必须提供官方提供的源代码包的下载地址,以达到可溯源 2、如果有需要二进制包,需要提供官方的二进制包下载地址 | +| license检查 | 1、待引入软件是否有license 2、入库时填写的license是否和官网保持一致;是否和软件包中license保持一致;高风险license的开源软件谨慎引入 | +| copyright检查 | 1、通过官网、社区、代码托管网站、源码包、发布件中等地方获取并提供copyright信息 | + + + +**注意事项:** + +1. 归一化:检验时应注意多版本软件包的检查,例如mysql和mysql5,引入多版本请先与技术委员会和SIG发起沟通。 +2. License检查和copyright白黑名单参见[许可证名单筛查](https://spdx.org/licenses/) + + + +## 2. 软件包依赖分析 + +软件包引入原则上在提交PR前完成相关软件包依赖分析工作,可通过如下几种方式对软件包依赖进行分析。 + +### 2.1. Pkgship工具依赖分析 + +Pkgship是由openEuler开发团队针对openEuler社区软件管理开发的包管理工具,可对openEuler各个版本以及fedora源中软件包进行依赖分析以及二进制包、源码包查询,现已部署在openEuler官方网站:[Pkgship](https://pkgmanage.openeuler.org/)。 + +#### 2.1.1. Pkgship在线依赖分析 + +Pkgship依赖分析支持安装依赖、构建依赖、自安装依赖、被依赖共四个场景的包依赖分析。软件包引入主要关注编译依赖和安装依赖部分,通过在Pkgship在线依赖分析,用户可以得到待引入软件包的安装依赖和编译依赖的表单。 + +![guide](./images/pkgship.png) + + + +**选择依赖分析类型:** + +Package Management 界面选择Depend Info并选择合适的依赖分析类型,填写包名称后,点击click here选择仓库。 + +![guide](./images/pkg_repo_select.png) + +**选择分支和上游社区:** + +在弹出页面选择待引入的分支和上游社区并点击OK确认。 + +![guide](./images/branch_select.png) + + + +**结果查询:** + +点击放大镜查询,Pkgship将自动根据用户设置进行依赖分析。 + +![guide](./images/fed_pkg.png) + + + +**依赖查询结果分析:** + +查看 Source Package List 列表,其中 Database列中显示为 fedora33 的软件包即为待引入源码包。 + +![guide](./images/need_introduce.png) + + + +#### 2.1.2. Pkgship本地依赖分析 + +另外,Pkgship支持本地部署,自定义源进行依赖分析,详细见:[Pkgship用户部署](https://gitee.com/src-openeuler/pkgship) + +**注意:** +如果在使用过程中发现问题,欢迎在[pkgship仓库下反馈](https://gitee.com/openeuler/pkgship/issues) + + +### 2.2. 上游社区依赖分析 + +对于不能根据Pkgship进行依赖分析的软件包,则需要对软件包依赖进行人工分析。 + +#### 2.2.1. 构建依赖 + +**使用上游社区自带spec分析**: + +根据 spec文件中BuildRequires字段下依赖包名称,查询待引入包的构建依赖。 + +**根据各个语言管理工具和依赖管理文件分析**: + +若上游社区未提供spec,根据语言管理工具或特定依赖文件进行分析,下面是部分语言的包管理工具和依赖管理文件类型: + +| 语言 | 包管理工具 | 文件类型 | +| ------- | ---------- | ------------------------- | +| C++ | CMake | Makefile | +| java | maven pom | pom.xml | +| go | go modules | go.mod | +| rust | cargo | Cargo.toml | +| ruby | RubyGems | *.gemspec | +| python | pip | requirements.txt/setup.py | +| Node.js | npm/yarn | | + +**根据openEuler提供的spec生成工具:** + +- [pyporter](https://gitee.com/openeuler/pyporter): python软件包的spec推荐使用[pyporter工具](https://gitee.com/openeuler/pyporter)自动生成 +- [rubyporter](https://gitee.com/openeuler/rubyporter): Ruby软件包的spec可使用[rubyporter工具](https://gitee.com/openeuler/rubyporter)自动生成。 +- [nodejsporter](https://gitee.com/openeuler/nodejsporter): nodejs软件包的spec可使用[nodejsporter工具](https://gitee.com/openeuler/nodejsporter)自动生成。 +- [perlporter](https://gitee.com/openeuler/pyporter): perlporter软件包的spec可使用[perlporter工具](https://gitee.com/openeuler/pyporter)自动生成。 +- **注意:** 工具生成后还需要人工审视的点, + - description是否合理地给出了软件的描述信息(不是单单列出了包名或者为空) + - spec中各部分应有合理的空行分割保证SPEC的规范和美观(如%prep,%description等的前面)等。 + + + +#### 2.2.2. 安装依赖和运行依赖 + +**使用上游社区自带spec分析**: + +根据 spec文件中Requires字段下依赖包名称,查询待引入包的安装依赖。 + +**使用rpmbuild工具分析:** + +```bash +rpm -a requires [package_name] # 查看安装依赖 +``` + + + +## 3. 软件包自验证 + +原则上任何引入openEuler社区的软件包在提交PR前均需要对其进行完整的依赖分析和自验证。 + +### **3.1. SPEC整改** + +#### 3.1.1. 格式整改和静态检查 + +- 关键字顺序整改 +- changelog整改:新软件包的spec文件changelog只需要package init的日志 +- 敏感词排除,patch非敏感注释保留: openEuler原则上不接受fedora 和 rhel 上游社区 +- Release 版本修改:新软件包引入Release 设置为1,每次对spec文件修改都应该对Release +1 +- License 名单对比:不应引入有风险的license的软件包。 + +#### 3.1.2. 代码溯源检查 + +- spec中的官网url的有效性,确认浏览器能够访问 + +- spec中源码包的下载地址source0的有效性,链接源码包与软件包的源码包的一致性 + + - 如果下载源码包与自带源码包不一致,使用下载的源码包进行后续验证。 + + - ```bash + md5sum 压缩包名1 压缩包名2   # 看执行后的两个字符串是否一样 + ``` + ![guide](./images/md5.png) + + - 如果source0下载链接不可用,则搜索上游社区(类似github)维护的版本可使用的下载链接进行重新验证(可从原spec的注释中寻找线索)。 + +### **3.2 rpmbuild** + +使用rpmbuild进行本地编译构建验证 + +```bash +rpmbuild -ba [spec file] # 使用 -ba 参数,根据spec文件构建二进制包和源代码包。 +``` + + + +### **3.3. [OBS](https://117.78.1.88/)编译构建验证** + +实践中虽然可以使用rpmbuild进行本地构建验证,但由于obs环境与本地开发者有所差异可能会导致obs构建结果与本地不同,故提交PR前应在obs拉取相应分支进行编译构建验证。 + +#### 3.3.1. osc 环境配置 + +在~(/root/)用户目录下创建.oscrc文件设置osc客户端配置。 osc配置选项有如下两种方式: + +- 直接在配置文件中指定ip地址 + + ![guide](./images/osc_config1.png) + +- 在配置文件中使用域名,在/etc/hosts中加上ip与域名的映射 + + ![guide](./images/osc_config2.png) + + ![guide](./images/etc_host.png) + +#### 3.3.2. OBS开发验证 + +- **拉取分支** + + 1. 拉取分支已有的软件包 + + ![guide](./images/obs_branch.png) + + 2. 在分支新建没有的软件包 + + ![guide](./images/obs_create_pkg.png) + +3、本地 新建分支 + +- **OSC编译** + + 1. 执行osc命令下载在线仓库到本地 + + ```bash + osc co home:xxxxx:branches:openEuler:Mainline 软件包名称 + ``` + + 2. 进入到个人分支 home:xxxxx:branches:openEuler:Mainline/软件包名称 + + 3. 将包对应的spec文件和tar包(还可能需要上传patch或配置文件) 移动到个人分支目录中 + + 4. 本地编译,因OBS构建资源有限,建议在上传到OBS在线编译之前使用osc build先进行本地构建验证,避免反复上传构建浪费时间。 + + ```bash + osc build + ``` + + 5. 移动到个人分支目录中,执行osc命令将本地文件上传至OBS在线个人分支 + + ```bash + osc add * + osc ci + ``` + + 6. 在线查看OBS个人分支的编译构建结果 + + ![guide](./images/osb.png) + + + + + +### 3.4. 软件包安装卸载验证 + +- + 确认环境中没有别的版本的该包 + + ```bash + rpm -e `rpm -qa | grep $fileName` + ``` + +- 安装软件包 + + ```bash + rpm –ivh xxx-2.0.1-2.aarch64.rpm + ``` + 由于rpm不能自动搜索依赖,需要将依赖包提前安装好以便验证。 + +- 能否成功卸载 + + ```bash + rpm –e xxx-2.0.1-2.aarch64.rpm + ``` + + + +### 3.5. **软件包基础功能验证** + +**带有命令行的软件包功能验证:** + +```bash +rpm –qpl xxx.rpm # 查看命令(/usr/bin/目录下的即为新增命令),运行相关的指令验证功能是否可以正常使用。 +``` + +**服务类软件包功能验证:** + +```bash +systemctl start [service.name] +``` + + + + + +## 4. 编写yaml文件 + +openEuler-Advisor 的目标是为 openEuler 制品仓的日常工作提供自动化的巡检和建议。为支持openEuler-Advisor自动化运行,应参考openEuler社区发布的[openEuler-Advisor yaml文件命名规范](https://gitee.com/openeuler/openEuler-Advisor#31yaml-%E6%96%87%E4%BB%B6%E8%A7%84%E8%8C%83),在仓库下配置yaml文件。 + +1. 创建yaml文件,yaml文件名应与spec文件名称保持一致。 + +2. 编辑yaml文件,添加相应字段内容 + + - **version_control**: 上游仓库的版本控制协议,目前支持svn, git, hg, github, gnome, metacpan, pypi。 + + 未包含的版本控制协议填写NA。 + + - **src_repo:** 上游仓库的实际地址,通过version_control 和 src_repo 可以工具可以下载对应的代码。 + + - **tag_prefix:**上游仓库的tag 中version 前缀,如果是 git 协议,通过 git tag 命令即可显示所有tag。如果上游给的tag 是 v1_0_1, 那么tag_prefix 应该配置为"^v",我们通过匹配tag_prefix即可取出正确的版本信息得到 1_0_1。若存在tag格式修改的状况,已最新的tag格式为准。 + + 如存在特殊情况如下: + + ![guide](./images/special_yaml.png) + + 可使用如下通配符 + + ```bash + "selenium-(.*?)-alpha-(.*?)" + ``` + + - **separator:** tag中版本的间隔符,如果 tag是 v1_0_1,然后配置separator 为"_",我们通过代码解析可以得到正确的版本号"1.0.1"。 + + ![guide](./images/yaml_content.png) + + + +## 参阅 + +openEuler 技术委员会:[《openEuler 软件包管理策略原则》](https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/software-management.md) + +openEuler《软件包引入流程v1.0》----- [**disnight **](https://gitee.com/disnight) + +openEuler 《[openEuler-Advisor](https://gitee.com/openeuler/openEuler-Advisor#31yaml-%E6%96%87%E4%BB%B6%E8%A7%84%E8%8C%83)》 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/gwei3/2020-12-01-announce-vpp-zh.md b/web-ui/docs/zh/blog/gwei3/2020-12-01-announce-vpp-zh.md new file mode 100644 index 0000000000000000000000000000000000000000..810e18050a7427d726c0755828bd952175575bd8 --- /dev/null +++ b/web-ui/docs/zh/blog/gwei3/2020-12-01-announce-vpp-zh.md @@ -0,0 +1,51 @@ +--- +title: openEuler漏洞奖励计划上线试运行 +date: 2020-12-01 +tags: + - 漏洞报告 + - 漏洞评分 + - 漏洞奖励 +archives: 2020-12 +author: gwei3, openEuler Security Committee +summary: openEuler漏洞奖励计划上线漏洞盒子平台试运行。 +--- + +### openEuler漏洞奖励计划上线试运行 +今日(12月1日)openEuler漏洞奖励计划上线漏洞盒子试运行。openEuler安全团队希望能与白帽子携手共同维护和提升openEuler社区的整体安全水平。对于保护用户利益、帮助openEuler社区安全提升的白帽子,我们将予以感谢和回馈。每一位报告者反馈的问题都有专人进行跟进、分析和处理,并及时予以答复。 + +#### 漏洞接收方式 +加密邮件发送至openeuler-security@openeuler.org + +#### 漏洞接收范围 +a) 发行版本: openEuler-20.03-LTS + +b) 运行平台:x86_64或arm64 + +c) 项目:iSulad、 A-Tune + +#### 漏洞奖励规则 +严重安全问题:¥15000/个 + +高危安全问题:¥8000/个 + +中危安全问题:¥2000/个 + +低危安全问题:¥500/个 + +**推广期额外奖励(不区分漏洞级别):** +a) 第一个漏洞奖金翻倍 +b) 前十个漏洞额外奖励¥2000/个 + +#### 详见漏洞奖励计划主页: +https://openeulersrc.vulbox.com/ + +#### 漏洞管理策略 +openEuler非常重视社区版本的安全性,制定了一套完整的漏洞管理策略,快速的响应和处理openEuler相关的安全问题。 +https://www.openeuler.org/zh/security/vulnerability-reporting/ + +#### 严正声明 +1.在漏洞未修复前,请您避免任何公开和传播。我们承诺:对每一份报告,都会有专门的安全人员进行评审、跟进并及时反馈最新的处理结果,并且我们会按照“漏洞奖励方案”对您的付出表示感谢。未经openEuler书面许可,如您以任何形式公开已提交的漏洞,我们将扣除已确认奖励,并保留追究您违约或侵权行为的权利。 + +2.我们鼓励采用合法合规的方式测试漏洞。利用漏洞损害用户利益、影响业务运营、盗取用户数据、恶意传播漏洞或数据等涉嫌违反法律、行政法规规定或违反openEuler社区管理规定、网站协议等的行为,openEuler社区均保留追究法律责任的权利。 + +3.openEuler社区委托漏洞盒子平台开展漏洞奖励计划,openEuler社区不会接触、获取研究者个人信息。openEuler安全委员会通过邮件与报告者确认漏洞有效性,级别和奖金数额后,由漏洞盒子负责后续奖金支付流程。 diff --git a/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-benchmark.md b/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-benchmark.md new file mode 100644 index 0000000000000000000000000000000000000000..6ca8913b465937311bc54261a9ce0ec6146e440e --- /dev/null +++ b/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-benchmark.md @@ -0,0 +1,435 @@ +--- +title: iSula性能测试 +date: 2020-09-09 +tags: + - iSulad + - performance +archives: 2020-09 +author: haozi007 +summary: iSula容器引擎具有很多优点:轻、快等等。那么,如何呈现这些优点呢?这篇文章我们主要关注iSula容器引擎的“快”。 +--- + +iSula容器引擎具有很多优点:轻、快等等。那么,如何呈现这些优点呢?这篇文章我们主要关注iSula容器引擎的“快”。为了证明“快”,那就需要有参照物进行对比。环视业内,我们发现几个能打的;容器引擎鼻祖Docker、红帽的Podman以及CRI-O。 + +目标确定了,我们开始明确对比范围了。 + +## 测试范围 + +容器引擎的使用模式主要是: + +- 客户端使用模式:多见于个人开发、测试以及部分生产场景; +- PAAS通过CRI接口使用模式:云计算的经典场景,通过CRI接口调用容器引擎能力,管理pod集群; + +为了尽量覆盖应用场景,因此我们需要覆盖上述两种场景,对客户端模式和CRI模式分别进行测试对比。 + +### 客户端模式 + +由于CRI-O不具备客户端功能,所以我们选择的测试对象是: + +- Docker +- Podman +- iSula + +### CRI模式 + +CRI接口,需要通过`cri-tools`工具进行测试。 + +为了对比的观赏性,我们在CRI模式下也选择三个测试对象: + +- Docker +- CRI-O +- iSula + +## 环境准备 + +### 机器环境 + +#### X86 + +| 配置项 | 配置信息 | +| ------ | ---------------------------------------- | +| OS | Fedora32 X86_64 | +| 内核 | linux 5.7.10-201.fc32.x86_64 | +| CPU | 48核,Intel Xeon CPU E5-2695 v2 @ 2.4GHZ | +| 内存 | 132 GB | + +#### ARM + +| 配置项 | 配置信息 | +| ------ | ------------- | +| OS | Euleros | +| 内核 | linux 4.19.90 | +| CPU | 64核 | +| 内存 | 196 GB | + +### 安装iSulad + +参考[官方文档](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md)安装即可。 + +```bash +$ isula version + +Client: + Version: 2.0.3 + Git commit: 3bb24761f07cc0ac399e1cb783053db8b33b263d + Built: 2020-08-01T09:40:06.568848951+08:00 + +Server: + Version: 2.0.3 + Git commit: 3bb24761f07cc0ac399e1cb783053db8b33b263d + Built: 2020-08-01T09:40:06.568848951+08:00 + +OCI config: + Version: 1.0.1 + Default file: /etc/default/isulad/config.json +``` + +### 安装cri-tools + +CRI测试,使用统一的客户端工具进行测试,选择K8S对应的`V1.15.0`版本即可。 + +```bash +$ git clone https://github.com/kubernetes-sigs/cri-tools +$ cd cri-tools +$ git checkout v1.15.0 +$ make +$ export PATH=$PATH:$GOPATH/bin +``` + +### 安装docker + +根据[官方文档](https://docs.docker.com/engine/install/fedora/)安装即可。 + +```bash +$ docker version + +Client: + Version: 19.03.11 + API version: 1.40 + Go version: go1.14.3 + Git commit: 42e35e6 + Built: Sun Jun 7 21:16:58 2020 + OS/Arch: linux/amd64 + Experimental: false + +Server: Docker Engine - Community + Engine: + Version: 19.03.11 + API version: 1.40 (minimum version 1.12) + Go version: go1.14.3 + Git commit: 42e35e6 + Built: Sun Jun 7 00:00:00 2020 + OS/Arch: linux/amd64 + Experimental: false + containerd: + Version: 1.3.3 + GitCommit: + runc: + Version: 1.0.0-rc10+dev + GitCommit: fbdbaf85ecbc0e077f336c03062710435607dbf1 + docker-init: + Version: 0.18.0 + GitCommit: +``` + +### 安装kubelet + +我们选择`V1.15.0`版本作为测试版本,下载源码`https://github.com/kubernetes/kubernetes.git`。 + +#### 准备源码 + +如果下载失败或者太慢,可以配置代理: + +```bash +# 设置国内代理 +go env -w GOPROXY=https://goproxy.cn,direct +# 设置私有仓库地址 +go env -w GOPRIVATE=.gitlab.com,.gitee.com +# 设置sum验证服务地址 +go env -w GOSUMDB="sum.golang.google.cn" +``` + +开始下载源码: + +```bash +$ cd $GOPATH/src/k8s.io +$ git clone https://github.com/kubernetes/kubernetes.git +$ cd kubernetes +$ git checkout v1.15.0 +$ go mod tidy +``` + +#### 编译 + +```bash +$ make all WHAT=cmd/kubelet +``` + +注意: + +- **K8S的版本对go的版本有要求,例如`V1.15.0`需要go 1.12版本** +- 可以使用`go mod tidy`,测试依赖代码下载,如果存在鉴权失败的仓库,可以使用`go get -v -insecure`下载 + +#### 安装 + +```bash +$ cp _output/bin/kubelet /usr/local/bin/kubelet +$ kubelet --version + Kubernetes v1.15.0 +``` + +#### 启动kubelet + +```bash +$ kubelet --network-plugin=cni --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice --cgroup-driver="systemd" --fail-swap-on=false -v 5 --enable-controller-attach-detach=false --experimental-dockershim +``` + +注:cgroup由systemd管理 + +### 安装CRI-O + +由于直接通过`dnf`安装`CRI-O`的`v1.15.4`版本有问题,所以需要源码编译安装。 + +```bash +$ dnf install glib-2.0 glibc-devel glibc-static container-common +$ git clone https://github.com/cri-o/cri-o.git +$ cd crio +$ make +$ make install +$ mkdir -p /etc/crio && cp crio.conf /etc/crio/ +``` + +### 安装podman + +直接使用`dnf`的源安装即可: + +```bash +$ dnf install -y podman + +$ podman --version + podman version 2.0.3 +``` + +## 测试方案 + +本文档主要关注容器引擎的容器生命周期的性能,所以测试方案如下: + +- 单容器的create、start、stop、rm和run等操作的性能; +- 100个容器并发create、start、stop、rm和run等操作的性能; +- 单pod的runp、stopp和rmp等操作的性能; +- 单pod包含单容器的run、stop和rm等操作的性能; +- 100个pod并发runp、stopp和rmp等操作的性能; +- 100个包含单容器的pod并发run、stop和rm等操作的性能; + +注:pod的配置,必须指定linux,不然docker会给pod创建一个默认的网卡,导致cni插件执行失败。 + +```json +{ + "metadata": { + "name": "nginx-sandbox", + "namespace": "default", + "attempt": 1, + "uid": "hdishd83djaidwnduwk28bcsb" + }, + // linux字段必须存在 + "linux": { + } +} + +``` + +### 方案详细设计 + +单次测试和并发测试虽然是两种测试场景,但是单次可以看成并发的特例。因此,设计测试用例的时候,通过控制并发数量来实现两种场景的区分。具体设计如下图: + +```mermaid +graph TD + classDef notestyle fill:#98A092,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5, 5; + classDef parallelstyle fill:#C969A3,stroke:#666,stroke-width:1px,color:#ffa,stroke-dasharray: 5, 5; + subgraph pretest; + A[download images] --> B[do clean] + end + subgraph dotest + C[foreach 1->10] + D{{runtest}} + E(remove max and min cases) + X(calculate avg of residual case) + C --> D + D --> E + E --> X + end + B --> C + subgraph runtest + R(begin test) + F>t1: get begin time point] + G(parallel run all cases) + H[wait all cases finish] + I>t2: get end time point] + R --> F + F --> G + F --> H + H -. wait .-> G + H --> I + end + R -. implements .-> D + subgraph posttest + Z[do clean] + end + X --> Z + class R notestyle; + class G parallelstyle; +``` + +### 客户端模式 + +#### X86环境测试结果 + +单容器操作性能对比 + +| 操作耗时 (ms) | Docker (avg) | Podman (avg) | iSula (avg) | VS Docker | VS Podman | +| ------------- | ------------- | ------------ | ----------- | --------- | --------- | +| create | 287 | 180 | 131 | -54.36% | -27.22% | +| start | 675 | 916 | 315 | -53.33% | -65.61% | +| stop | 349 | 513 | 274 | -21.49% | -46.59% | +| rm | 72 | 187 | 60 | -16.67% | -67.91% | +| run | 866 | 454 | 359 | -58.55% | -20.93% | + +100容器并发操作性能对比 + +| 操作耗时 (ms) | Docker (avg) | Podman (avg) | iSula (avg) | VS Docker | VS Podman | +| ------------- | ------------- | ------------ | ----------- | --------- | --------- | +| 100 * create | 4995 | 3993 | 1911 | -61.74% | -52.14% | +| 100 * start | 10126 | 5537 | 3861 | -61.87% | -30.27% | +| 100 * stop | 8066 | 11100 | 4268 | -47.09% | -61.55% | +| 100 * rm | 3220 | 4319 | 1967 | -38.91% | -54.46% | +| 100 * run | 9822 | 5979 | 4392 | -55.28% | -26.54% | + +#### ARM环境测试结果 + +单容器操作性能对比 + +| 操作耗时 (ms) | Docker (avg) | Podman (avg) | iSula (avg) | VS Docker | VS Podman | +| ------------- | ------------- | ------------ | ----------- | --------- | --------- | +| create | 401 | 361 | 177 | -55.86% | -50.97% | +| start | 1160 | 1143 | 523 | -54.91% | -54.24% | +| stop | 634 | 576 | 395 | -37.70% | -31.42% | +| rm | 105 | 398 | 89 | -15.24% | -77.64% | +| run | 1261 | 1071 | 634 | -49.72% | -40.80% | + +100容器并发操作性能对比 + +| 操作耗时 (ms) | Docker (avg) | Podman (avg) | iSula (avg) | VS Docker | VS Podman | +| ------------- | ------------- | ------------ | ----------- | --------- | --------- | +| 100 * create | 14563 | 12081 | 4172 | -71.35% | -65.47% | +| 100 * start | 23420 | 15370 | 5294 | -77.40% | -65.56% | +| 100 * stop | 22234 | 16973 | 8619 | -61.24% | -49.22% | +| 100 * rm | 937 | 10943 | 926 | -1.17% | -92.33% | +| 100 * run | 28091 | 16280 | 9015 | -67.91% | -44.63% | + +### CRI模式 + +#### X86环境测试结果 + +单pod操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| runp | 681 | 321 | 239 | -64.90% | -25.55% | +| stopp | 400 | 356 | 272 | -32.00% | -23.60% | + +单pod单容器操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| run | 1249 | 525 | 382 | -69.42% | -27.24% | +| stop | 554 | 759 | 564 | +1.81% | -25.69% | + +100并发pod操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| 100 * runp | 13998 | 4946 | 3887 | -72.23% | -21.41% | +| 100 * stopp | 8402 | 4834 | 4631 | -44.88% | -4.20% | +| 100 * rmp | 2076 | 1388 | 1073 | -48.31% | -22.69% | + +100并发pod容器操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| 100 * run | 28158 | 9077 | 5630 | -80.01% | -37.98% | +| 100 * stop | 9395 | 8443 | 8196 | -12.76% | -2.93% | +| 100 * rm | 4415 | 3739 | 1524 | -65.48% | -59.24% | + +#### ARM环境测试结果 + +单pod操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| runp | 1339 | 2366 | 536 | -59.97% | -77.35% | +| stopp | 443 | 419 | 255 | -42.44% | -39.14% | + +单pod单容器操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| run | 2069 | 3039 | 338 | -83.66% | -88.88% | +| stop | 684 | 688 | 214 | -68.71% | -68.90% | + +100并发pod操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| 100 * runp | 27802 | 29197 | 9827 | -64.65% | -66.34% | +| 100 * stopp | 14429 | 11173 | 6394 | -55.69% | -42.77% | +| 100 * rmp | 771 | 9007 | 1790 | +132.17% | -80.13% | + +100并发pod容器操作 + +| 操作耗时 (ms) | Docker (avg) | CRIO (avg) | iSula (avg) | VS Docker | VS CRIO | +| ------------- | ------------- | ---------- | ----------- | --------- | ------- | +| 100 * run | 54087 | 43521 | 5284 | -90.23% | -87.86% | +| 100 * stop | 18317 | 19108 | 2641 | -85.58% | -86.18% | +| 100 * rm | 1592 | 18390 | 2162 | +35.80% | -88.24% | + +## 总结分析 + +从测试数据来看,在容器的生命周期的操作和并发操作上面,我们iSulad都是优于其他容器引擎的。尤其是在ARM上的表现尤为出色,并发性能已经接近于X86的性能了;而其他容器引擎在ARM上面的表现不尽如人意,甚至出现性能下降1倍以上。 + +那么,我们iSulad为什么有这么大的优势呢?我觉得,主要是从下面几个方面来看。 + +- 首先,iSulad是用C/C++语言写的,而Docker/Podman/CRI-O都是用golang写的;C/C++在速度方面本身就有优势; +- 架构设计上面,相对于Docker,iSulad架构更加简单,调用链更短;而Podman是serverless模式,并发更加不具备优势; +- 在容器创建流程中,减小锁粒度、消减容器的依赖(例如镜像管理模块),从而提高了并发的性能; + +### 架构对比 + +iSulad架构设计如下: + +![arch](https://gitee.com/openeuler/iSulad/raw/master/docs/design/arch.jpg) + +Docker官网给的架构图如下: + +![Docker架构图](https://docs.docker.com/engine/images/engine-components-flow.png) + +但是,docker daemon里面还涉及到containerd和runc的流程没有描述,大体结构如下: + +```mermaid +graph LR + A(docker daemon) + B(containerd) + C(runc) + A -. grpc .-> B + B -. fork/exec .-> C +``` + +从架构来看,docker的容器生命周期流程涉及:客户端到docker daemon的restful通信;daemon到containerd的GRPC通信;然后fork执行runc。而iSulad的流程:客户端到服务端的GRPC通信,然后fork执行lxc-start。 + +## 参考文档 + +- https://stackoverflow.com/questions/46726216/kubelet-fails-to-get-cgroup-stats-for-docker-and-kubelet-services +- https://developer.aliyun.com/article/630682 +- https://blog.csdn.net/bingshiwuyu/article/details/107333259 +- https://github.com/cri-o/cri-o +- https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md + diff --git a/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-json-parse.md b/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-json-parse.md new file mode 100644 index 0000000000000000000000000000000000000000..cad8f45709a691558c786867aba1b11257613d14 --- /dev/null +++ b/web-ui/docs/zh/blog/haozi007/2020-09-09-isulad-json-parse.md @@ -0,0 +1,609 @@ +--- +title: iSula与JSON的斗争 +date: 2020-09-09 +tags: + - iSulad + - JSON +archives: 2020-09 +author: haozi007 +summary: iSulad是如何处理JSON的呢? +--- + +对于各位习惯各种高级语言的伙伴们来说,JSON的解析和生成是如呼吸般简单自然的事情。但是对于C语言,JSON的解析和生成就麻烦了。根本原因是由于C语言不支持反射,没办法对JSON作动态解析和生成。但是,容器引擎中涉及大量的JSON解析和生成。那么,我们为了更好的和JSON进行和谐相处,做了那些努力呢? + +大体上,iSula经历了几个阶段,为了更好的感受这几个阶段的差距;我觉得通过武器的不同时代来感受一下。 + +## 冷兵器时代 + +C语言还是有一些JSON解析的库的,例如`yajl`,`cjson`等等;这些库提供了把JSON字符串解析为tree结构的元素集合,然后通过遍历书可以快速的找到JSON的`key/value`的对应关系和值。而且也能自己构建对应的元素结合tree,然后生成JSON字符串。那么,如何通过这些库来做JSON和C结构体直接的相互转换呢? + +### 用法 + +以`yajl`为例,实现一个`isula_version`结构体的marshal和unmarshal. + +```c +#include +#include +#include +#include +#include + +struct isula_version { + int large; + int middle; + int small; + char *version; +}; + +void free_isula_version(struct isula_version *ptr) +{ + if (ptr == NULL) { + return; + } + free(ptr->version); + ptr->version = NULL; + free(ptr); +} + +static inline yajl_val get_val(yajl_val tree, const char *name, yajl_type type) { + const char *path[] = { name, NULL }; + return yajl_tree_get(tree, path, type); +} + +struct isula_version *unmarshal(const char *json_str) +{ + char buf[1024]; + yajl_val tree; + struct isula_version *result = NULL; + + if (json_str == NULL) { + return NULL; + } + result = calloc(1, sizeof(struct isula_version)); + if (result == NULL) { + return NULL; + } + tree = yajl_tree_parse(json_str, buf, sizeof(buf)); + if (tree == NULL) { + printf("Invalid json string: %s\n", json_str); + goto err_out; + } + { + yajl_val val = get_val(tree, "Large", yajl_t_number); + if (val != NULL) { + result->large = YAJL_GET_INTEGER(val); + } + } + { + yajl_val val = get_val(tree, "Small", yajl_t_number); + if (val != NULL) { + result->small = YAJL_GET_INTEGER(val); + } + } + { + yajl_val val = get_val(tree, "Middle", yajl_t_number); + if (val != NULL) { + result->middle = YAJL_GET_INTEGER(val); + } + } + { + yajl_val val = get_val(tree, "Version", yajl_t_string); + if (val != NULL) { + char *str = YAJL_GET_STRING(val); + result->version = strdup(str); + } + } + + goto out; +err_out: + free_isula_version(result); + result = NULL; +out: + yajl_tree_free(tree); + return result; +} + +char *marshal(struct isula_version *ptr) +{ + char *result = NULL; + const unsigned char *gen_buf = NULL; + size_t gen_len = 0; + + if (ptr == NULL) { + return NULL; + } + + yajl_gen g = yajl_gen_alloc(NULL); + yajl_gen_status stat = yajl_gen_status_ok; + + stat = yajl_gen_map_open((yajl_gen)g); + if (stat != yajl_gen_status_ok) { + goto free_out; + } + /* gen struct items */ + if (ptr->version != NULL) { + stat = yajl_gen_string((yajl_gen)g, (const unsigned char *)("Version"), strlen("Version")); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + stat = yajl_gen_string((yajl_gen)g, (const unsigned char *)ptr->version, strlen(ptr->version)); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + } + + stat = yajl_gen_string((yajl_gen)g, (const unsigned char *)("Large"), strlen("Large")); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_integer((yajl_gen)g, (long long int)ptr->large); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_string((yajl_gen)g, (const unsigned char *)("Middle"), strlen("Middle")); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_integer((yajl_gen)g, (long long int)ptr->middle); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_string((yajl_gen)g, (const unsigned char *)("Small"), strlen("Small")); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_integer((yajl_gen)g, (long long int)ptr->small); + if (yajl_gen_status_ok != stat) { + goto free_out; + } + + stat = yajl_gen_map_close((yajl_gen)g); + if (stat != yajl_gen_status_ok) { + goto free_out; + } + + yajl_gen_get_buf(g, &gen_buf, &gen_len); + if (gen_buf == NULL) { + printf("gen buf failed\n"); + goto free_out; + } + + result = calloc(gen_len + 1, sizeof(char)); + if (result == NULL) { + printf("out of memory\n"); + goto free_out; + } + (void)memcpy(result, gen_buf, gen_len); + +free_out: + yajl_gen_clear(g); + yajl_gen_free(g); + return result; +} + +void show_isula_version(const struct isula_version *ptr) +{ + printf("iSula version: \n"); + if (ptr == NULL) { + return; + } + printf("large: %d\nmiddle: %d\nsmall: %d\n", ptr->large, ptr->middle, ptr->small); + printf("version: %s\n", ptr->version); +} + +int main() +{ + const char *json_str = "{\"Version\":\"1.0.0\", \"Large\": 1, \"Middle\": 0, \"Small\": 0}"; + struct isula_version *ptr = NULL; + char *marshaled = NULL; + + // step 1: unmarshal json string + ptr = unmarshal(json_str); + if (ptr == NULL) { + printf("unmarshal failed\n"); + return -1; + } + show_isula_version(ptr); + + // step 2: marshal isula version + free(ptr->version); + ptr->version = strdup("2.0.0"); + ptr->large = 2; + ptr->middle = 1; + ptr->small = 1; + marshaled = marshal(ptr); + printf("marshal isula version:\n\t%s\n", marshaled); + + free(marshaled); + free_isula_version(ptr); +} +``` + +执行效果如下: + +```bash +$ ./a.out +iSula version: +large: 1 +middle: 0 +small: 0 +version: 1.0.0 +marshal isula version: + {"Version":"2.0.0","Large":2,"Middle":1,"Small":1} +``` + +这种方式虽然没法和支持动态解析的语言一样高效简单,但是也算完成了任务。如果动态解析是热兵器,这个勉强能算是长矛了。 + +### 缺陷 + +从示例来看,完成一个结构体和JSON的映射大概需要160行左右的代码。而上面只是一个简单的结构体,而且有的项目有很多这种结构体需要做映射。这种原始的方式在大型项目中很难保证参与人员代码质量可控;而且效率低下。主要的缺陷总结如下: + +- 映射工作量较大; +- 对每种结构体需要单独适配代码,无法实现自动化; +- 效率低下; +- 代码质量不可控; + +## 伪热兵器时代 + +由于C不支持反射,没法做到动态解析。但是可以通过其他途径简化解析流程、提高效率、实现自动化以及实现代码质量可控。为了避免重复造论子,17年的时候发现了[libocispec项目](https://github.com/containers/libocispec),提供了一个解决C语言JSON映射的思路: + +- 通过[json schema](http://json-schema.org/)描述JSON字符串的结构信息; +- 通过python解析`json schema`信息; +- 根据`json schema`信息自动生成C结构体和JSON的映射代码; + +这种方式,可以解决上面的上一章节的几个缺陷: + +- 工作量大大减小,这需要写好`json schema`文件即可; +- 自动化解析代码工作; +- 效率很高; +- 代码质量可控,取决于于生成框架的质量; + +**注:libocispec早期只能用于解析oci spec的json,在我们发现之后,多个开发人员参与社区,提供了大量的功能升级,才有了今天的强大能力。** + +### iSula集成libocispec结构 + +iSula当前把JSON映射相关的代码,统一放到`lcr`项目中进行管理,通过一个动态库和头文件提供相应功能。 + +生成代码的开源python框架结构如下: + +```bash +$ tree third_party/libocispec/ +third_party/libocispec/ +├── CMakeLists.txt +├── common_c.py +├── common_h.py +├── generate.py +├── headers.py +├── helpers.py +├── read_file.c +├── read_file.h +└── sources.py +``` + +`json schema`文件存放结构(由于iSula涉及的所有JSON结构都在该目录下,所以存在大量的schema文件)如下: + +```bash +$ tree -d 1 src/json/schema/ +src/json/schema/ +├── cni +│   └── network +├── container +├── cri +├── docker +│   ├── image +│   └── types +├── embedded +├── host +├── image +├── imagetool +├── logger +├── oci +│   ├── image +│   └── runtime +├── plugin +├── registry +├── shim +│   └── client +└── storage +``` + +然后在`cmake`的时候,会触发python框架,根据schema目录下面所有的schema来生成对应的映射代码。会看到如下提示信息: + +```bash +$ mkdir build +$ cd build +$ cmake ../ +...... +Reflection: isulad-daemon-configs.json Success +Reflection: timestamp.json Success +Reflection: web-signature.json Success +Reflection: host-config.json Success +Reflection: defs.json Success +Reflection: config.json Success +Reflection: manifest.json Success +Reflection: layers.json Success +...... +``` + +### 用法 + +那么,现在我们如果需要对一个新的结构体和JSON进行映射,需要做的事情就是在`json schema`目录下面新增一个对应的schema文件即可。这里以上一章节的`isula_version`为例。 + +新增schema文件`isula_version.json`: + +```bash +$ cat ../src/json/schema/isula_version.json +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "Version": { + "type": "string" + }, + "Large": { + "type": "int32" + }, + "Middle": { + "type": "int32" + }, + "Small": { + "type": "int32" + } + } +} +``` + +重新`cmake`,可以看到新生成了两个文件: + +```bash +$ ls build/json/isula_version.* +build/json/isula_version.c build/json/isula_version.h +``` + +生成的代码对外的接口如下: + +```c +$ cat build/json/isula_version.h +// Generated from isula_version.json. Do not edit! +#ifndef ISULA_VERSION_SCHEMA_H +#define ISULA_VERSION_SCHEMA_H + +#include +#include +#include "json_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *version; + + int32_t large; + + int32_t middle; + + int32_t small; +} +isula_version; + +void free_isula_version(isula_version *ptr); + +isula_version *make_isula_version(yajl_val tree, const struct parser_context *ctx, parser_error *err); + +yajl_gen_status gen_isula_version(yajl_gen g, const isula_version *ptr, const struct parser_context *ctx, parser_error *err); + +isula_version *isula_version_parse_file(const char *filename, const struct parser_context *ctx, parser_error *err); + +isula_version *isula_version_parse_file_stream(FILE *stream, const struct parser_context *ctx, parser_error *err); + +isula_version *isula_version_parse_data(const char *jsondata, const struct parser_context *ctx, parser_error *err); + +char *isula_version_generate_json(const isula_version *ptr, const struct parser_context *ctx, parser_error *err); + +#ifdef __cplusplus +} +#endif + +#endif + +``` + +测试用例: + +```c +$ cat test.c +#include "isula_version.h" +#include + +void show_isula_version(const isula_version *ptr) +{ + printf("iSula version: \n"); + if (ptr == NULL) { + return; + } + printf("large: %d\nmiddle: %d\nsmall: %d\n", ptr->large, ptr->middle, ptr->small); + printf("version: %s\n", ptr->version); +} + +int main() +{ + const char *json_str = "{\"Version\":\"1.0.0\", \"Large\": 1, \"Middle\": 0, \"Small\": 0}"; + isula_version *ptr = NULL; + parser_error err = NULL; + char *marshaled = NULL; + + // step 1: unmarshal + ptr = isula_version_parse_data(json_str, NULL, &err); + if (ptr == NULL) { + return -1; + } + show_isula_version(ptr); + + // step 2: marshal + free(ptr->version); + ptr->version = strdup("2.0.0"); + ptr->large = 2; + ptr->middle = 1; + ptr->small = 1; + marshaled = isula_version_generate_json(ptr, NULL, &err); + if (ptr == NULL) { + goto out; + } + printf("marshal isula version:\n\t%s\n", marshaled); + +out: + free(marshaled); + free_isula_version(ptr); + return 0; +} +``` + +执行结果如下: + +```bash +$ ./a.out +iSula version: +large: 1 +middle: 0 +small: 0 +version: 1.0.0 +marshal isula version: + { + "Version": "2.0.0", + "Large": 2, + "Middle": 1, + "Small": 1 +} +``` + +### 缺陷 + +通过libocispec可以实现接近于高级语言的`marshal`和`unmarshal`了,只需要简单编写schema文件即可,极大的提高了效率,并且依托开源社区可以提高代码质量。但是,还是存在一些缺陷。 + +例如`golang`中,marshal之后的结构体可以通过map[string]interface保存,可以完整的记录JSON字符串中的信息。而我们当前的实现,只能根据schema来解析JSON字符串,因此,存在信息丢失的情况。有些场景,规范只规定了主体的JSON结构,并且支持拓展配置,例如CNI规范。 + +## 近乎热兵器时代 + +为了解决信息丢失的问题,我们通过在结构体中记录原始的元素集合tree的方案,unmarshal的时候不会丢失原始信息,marshal的时候解析记录的元素信息,从而实现原始数据完整的传递。 + +具体解决方案见官方PR:https://github.com/containers/libocispec/pull/56 + +### 用法 + +使用方式和上面的基本一致,差异主要包括以下几部分: + +1. 生成的代码有部分差异(_residual); + + ```c + $ cat isula_version.h + ... .... + typedef struct { + char *version; + + int32_t large; + + int32_t middle; + + int32_t small; + + yajl_val _residual; + } + isula_version; + ... .... + ``` + +2. 解析是需要指定`struct parser_context`参数为`OPT_PARSE_FULLKEY`; + + ```c + $ cat test.c + #include "isula_version.h" + #include + + void show_isula_version(const isula_version *ptr) + { + printf("iSula version: \n"); + if (ptr == NULL) { + return; + } + printf("large: %d\nmiddle: %d\nsmall: %d\n", ptr->large, ptr->middle, ptr->small); + printf("version: %s\n", ptr->version); + } + + int main() + { + const char *json_str = "{\"Version\":\"1.0.0\", \"Large\": 1, \"Middle\": 0, \"Small\": 0, \"resi_int\": 1, \"resi_str\": \"test\"}"; + isula_version *ptr = NULL; + parser_error err = NULL; + char *marshaled = NULL; + struct parser_context ctx; + ctx.options = OPT_PARSE_FULLKEY; + + // step 1: unmarshal + ptr = isula_version_parse_data(json_str, &ctx, &err); + if (ptr == NULL) { + return -1; + } + show_isula_version(ptr); + + // step 2: marshal + free(ptr->version); + ptr->version = strdup("2.0.0"); + ptr->large = 2; + ptr->middle = 1; + ptr->small = 1; + marshaled = isula_version_generate_json(ptr, &ctx, &err); + if (ptr == NULL) { + goto out; + } + printf("marshal isula version:\n\t%s\n", marshaled); + + out: + free(marshaled); + free_isula_version(ptr); + return 0; + } + ``` + +3. 效果如下 + + ```bash + $ ./a.out + iSula version: + large: 1 + middle: 0 + small: 0 + version: 1.0.0 + marshal isula version: + { + "Version": "2.0.0", + "Large": 2, + "Middle": 1, + "Small": 1, + "resi_int": 1, + "resi_str": "test" + } + ``` + +可以看到拓展的信息,完整的传递下去了。**通过这种方式完美的解决了CNI的拓展配置的支持,从而解决了iSulad动态支持多种插件的技术瓶颈。** + +### 缺陷 + +上面的方案已经基本和支持反射的语言实现的功能相近了,但是,还是存在部分缺陷的。例如,动态修改JSON结构的数据会比较麻烦,需要对底层的解析库比较了解,而且比较麻烦。 + +## 总结 + +虽然当前的框架还有一些缺陷,但是,我们的目标并不是实现一个完美的JSON和C结构体的映射框架,而是解决容器引擎使用JSON的问题。而上面的方案,已经完全满足iSula当前的需求。 + +因此,目前没有进一步优化的需求。如果后续使用场景或者其他用户有需求,可以到[libocispec的社区](https://github.com/containers/libocispec)进行进一步的优化。 + +# 参考文章 + +- https://github.com/containers/libocispec +- http://json-schema.org/ +- https://github.com/lloyd/yajl/tree/master/example diff --git a/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-01.png b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-01.png new file mode 100644 index 0000000000000000000000000000000000000000..9bde17d35bfcda939f59104053b7440b8aad2502 Binary files /dev/null and b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-01.png differ diff --git a/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-02.png b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-02.png new file mode 100644 index 0000000000000000000000000000000000000000..54e95c980a0e6334e5c3caa19a20f887edd6e107 Binary files /dev/null and b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-02.png differ diff --git a/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-03.png b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-03.png new file mode 100644 index 0000000000000000000000000000000000000000..e5f39681ca27110e6258aebb203b265fa015346a Binary files /dev/null and b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1-03.png differ diff --git a/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1.md b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1.md new file mode 100644 index 0000000000000000000000000000000000000000..c9509575570a417850585780b7f2e175b3164e68 --- /dev/null +++ b/web-ui/docs/zh/blog/ivye/2020-05-06-os-metrics-1.md @@ -0,0 +1,69 @@ +--- +title: 浅谈openEuler开源社区运营度量及分析 +date: 2020-05-06 +tags: + - 社区运营 + - 度量 +archives: 2020-05 +author: Ivye +summary: 浅谈openEuler开源社区运营度量及分析,属于系列博客的第一篇。 +--- + + +# 浅谈openEuler开源社区运营度量及分析 + +伴随openEuler社区的运转,如何评估开源社区运营状态以改进社区运营成为一个关键问题。那么,我们需要哪些指标、哪些数据并开展什么样的分析呢?经过一段时间的摸索,对于社区运营的目标、独立指标、度量可视化及数据分析有初步的思考和沉淀,本博客记录下来,欢迎大家一起探讨。 + + +## 一、 度量的诉求 + +好的开源社区,应该是人们愿意使用、贡献、并主动宣传的人气社区,并且有完善的用户生态、贡献者生态、技术生态和伙伴生态。社区成员也会希望通过数据统计及分析,来帮助了解社区状态、识别运营诉求、开展运营改进,支撑社区更健康的发展。 + +## 二、 度量指标框架 + +带着对好的开源社区的理解及度量诉求,构想以终为始,围绕“人、组织、技术生态和商业”,辅以“项目运营健康度”为支撑,构建开源社区度量指标框架。 + + + + +## 三、 必要的基础数据定义 + +任何能够获取数据的地方,都可以收集并跟踪。但需要哪些数据?怎么定义?于是,围绕角色(初级用户、贡献者、Committer及Mentor),基于行为趋势,定义了相关的基础数据。 +(说明,在进行指标梳理和定义时,参考了。) + + + +## 四、 第一期度量指标 + +我认为不同的项目、不同有阶段有其独特的健康度衡量,所需的指标及分析也会随项目的诉求而变化。 +第一期列出了面向开发者从感知到贡献的一些指标,当前这仅仅是支撑后续深入分析的初始阶段。 + + + + +## 五、运营系统搭建 + +基于第一期指标集,我们团队正在开展运营系统的搭建,可以期待一下接下来的分享哦~~ + + +### 参与指南 + +开源社区运营度量讨论目前都是在openEuler开源社区进行的,欢迎大家贡献思路和建议。 + +**1、Mail List:** + + + +**2、Issues:** + +[[1]](https://gitee.com/openeuler/community/issues/I1BAO0)为主任务,主要为度量框架讨论,详细内容在文档[[3]](https://docs.qq.com/doc/DRmlaYnZSbEViRm5G); + +[[2]](https://gitee.com/openeuler/community/issues/I1BSJ4)是第一批的度量指标项,详细内容在文档 [[4]](https://docs.qq.com/doc/DUG1jWGptQ2xSc0xw)。 + +[1] https://gitee.com/openeuler/community/issues/I1BAO0 + +[2] https://gitee.com/openeuler/community/issues/I1BSJ4 + +[3] https://docs.qq.com/doc/DRmlaYnZSbEViRm5G + +[4] https://docs.qq.com/doc/DUG1jWGptQ2xSc0xw diff --git a/web-ui/docs/zh/blog/jzy0/2020-08-20-run-qemu-in-nonroot-mode.md b/web-ui/docs/zh/blog/jzy0/2020-08-20-run-qemu-in-nonroot-mode.md new file mode 100644 index 0000000000000000000000000000000000000000..c855665172339d09915421761b943f5d1ed32c33 --- /dev/null +++ b/web-ui/docs/zh/blog/jzy0/2020-08-20-run-qemu-in-nonroot-mode.md @@ -0,0 +1,81 @@ +--- +title: 非root用户起qemu虚拟机:规避权限问题 +date: 2020-08-20 +tags: + - qemu + - 权限 + - root用户 + - libvirt +archives: 2020-08 +author: Zeyu Jin +summary: 本文小结了非root用户起qemu虚拟机的步骤,规避可能出现的权限问题导致其虚拟机失败。 +--- + +### 背景 +在多人使用虚拟机的场景中,每人对应一个非root用户。当某一个非root用户想要使用virsh命令起qemu虚拟机的时候,等待他的可能是一段小坑不断的试错之路。 + +非root用户起虚拟机最常遇到的是权限问题,比如运行`virsh start`的时候,出现下列报错: +``` +error: Failed to start domain jzy-lts +error: internal error: qemu unexpectedly closed the monitor: 2020-07-14T13:29:11.323694Z qemu-kvm: -drive file=/home/jzy/kvm/openEuler-20.03-LTS.aarch64.qcow2,format=qcow2,if=none,id=drive-scsi0-0-0-0,cache=none,aio=native: Could not open '/home/jzy/kvm/openEuler-20.03-LTS.aarch64.qcow2': Permission denied +``` + +有些朋友遇到类似问题会怀疑是qemu本身有bug,其实不然,很有可能操作不当才是原因。 +下面是本人总结的非root用户起qemu虚拟机的步骤,规避可能出现的权限问题。 + +### 步骤 + +从创建用户到起虚拟机: +1. 创建一个用户并添加进kvm组 +``` +[root] useradd -m jzy +[root] gpasswd -a jzy kvm +``` +2. 配置 `/etc/libvirt/qemu.conf` +``` +# user = "root" +后面加 +user = "jzy" +``` +``` +# group = "root" +后面加 +group = "jzy" +``` +3. 重启libvirtd +``` +[root] service libvirtd restart +或者 +[root] systemctl restart libvirtd.service +``` +4. 允许jzy使用sudo +``` +[root] vim /etc/sudoers +``` +增加 `jzy ALL=(ALL) ALL` +然后 `wq!` + +5. 切用户,到/home/jzy 准备好相关的文件 +保证文件和目录都是755的权限, 比如 +``` +[jzy@localhost ~]$ pwd +/home/jzy + +[jzy@localhost ~]$ ll +total 4.0K +drwxr-xr-x 2 jzy jzy 4.0K Jul 23 11:29 kvm + +[jzy@localhost ~]$ ll kvm +total 7.2G +-rwxr-xr-x 1 jzy jzy 1.6K Jul 23 11:29 openE_jzy.xml +-rwxr-xr-x 1 jzy jzy 4.4G Jul 23 11:25 openEuler-20.03-LTS-aarch64-dvd.iso +-rwxr-xr-x 1 root root 2.9G Jul 23 11:32 openEuler-image.qcow2 +``` +6. 就可以起虚拟机了 +``` +[jzy@localhost ~]$ sudo virsh create kvm/openE_jzy.xml +Domain openEulerVM created from kvm/openE_jzy.xml +``` + +特别注意: +文件的owner 和 group 不要搞错! diff --git a/web-ui/docs/zh/blog/kezhiming/2021-01-20-virttest-avocado-vt.md b/web-ui/docs/zh/blog/kezhiming/2021-01-20-virttest-avocado-vt.md new file mode 100644 index 0000000000000000000000000000000000000000..7d2aefd90e8eaa90b339d8a150f4942ccb18edac --- /dev/null +++ b/web-ui/docs/zh/blog/kezhiming/2021-01-20-virttest-avocado-vt.md @@ -0,0 +1,192 @@ +--- +title: 玩转虚拟化测试框架avocado-vt之安装部署 +date: 2021-01-20 +tags: + - virttest + - avocado-vt +archives: 2021-01 +author: kezhiming +summary: 介绍openEuler上虚拟化测试avocado-vt测试框架安装部署、测试执行、结果分析等 +--- + +# 简介 + + 本文以openeuler版本为例,介绍虚拟化框架avocado-vt的部署及应用,指导用户开展虚拟化组件测试。 + + 为了更好地理解整个应用过程,我们需要首先了解以下基本概念: + +- Avocado:Avocado是一套帮助自动化测试的工具和库,源于autotest,最主要的优势包括可以多种形式的结果呈现、提供了多个实用的程序模块、可通过插件扩展等; + + 更多信息可参见官方指导[https://avocado-framework.readthedocs.io/en/latest/index.html](https://avocado-framework.readthedocs.io/en/latest/index.html) + +- Avocado-VT:Avocado-VT是一个虚拟化测试插件,提供与虚拟化测试相关的原子,并提供Avocado提供的所有便利; + + 更多信息可参见官方指导[https://avocado-vt.readthedocs.io/en/latest/index.html](https://avocado-vt.readthedocs.io/en/latest/index.html) + +- Tp(test-providers):主要是提供组件测试用例集,当前openEuler上已有tp-libvirt/tp-qemu; + + +# 测试部署环境准备 + +- 基础rpm包安装 + + 虚拟化组件包安装,qemu、libvirt、edk2等 + + 框架依赖包,git、gcc、python3-pip、python3-devel、tcpdump、nc、diffutils、iputils等 + +- pip3源配置 + + avocado/avocado-vt部署时,需要通过pip3安装python第三方库,如果不配置,则通过pip3从python官方库获取第三方库。基于用户实际网络情况,选择配置pip3,可一定程度上提升下载的速率及稳定性。 + + 使用如下命令可配置,如配置tsinghua的源 + + ``` + pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple + ``` + +- 其他配置 + + 基于用户的实际网络环境,如果测试环境有做相关的网络隔离,根据实际情况选择是否配置代理,包括git配置http/https代理、网络配置http/https代理 + +# 测试安装部署 + +- 源码下载 + + 依次下载框架及用例集代码并切换到对应分支,其中branch当前支持openEuler-20.03 + + ``` + git clone $url + git checkout -f $branch + ``` + + 包含以下几个仓库: + + [https://gitee.com/src-openeuler/avocado](https://gitee.com/src-openeuler/avocado) + + [https://gitee.com/openeuler/avocado-vt](https://gitee.com/openeuler/avocado-vt) + + [https://gitee.com/openeuler/tp-libvirt](https://gitee.com/openeuler/tp-libvirt) + + [https://gitee.com/openeuler/tp-qemu](https://gitee.com/openeuler/tp-qemu) + +- avocado安装 + + 依赖包安装:pip3 install -r requirements-selftests.txt + + avocado框架安装: python3 setup.py install + +- avacado-vt安装 + + 配置test-providers:配置libvirt、qemu + + 依赖包安装:pip3 install -r requirements.txt + + avocado-vt插件安装: python3 setup.py install + +- 用例集引导 + + 引导tp-libvirt、tp-qemu用例集 + + ``` + avocado vt-bootstrap --vt-type qemu --vt-skip-verify-download-assets --yes-to-all + avocado vt-bootstrap --vt-type libvirt --vt-skip-verify-download-assets --yes-to-all + ``` + +以上的部署过程总结成如下代码: +``` +install_virttest() { + local branch=$1 + + cd "$srcdir/tp-qemu" + git checkout -f "$branch" + + cd "$srcdir/tp-libvirt" + git checkout -f "$branch" + + cd "$srcdir/avocado" + git checkout -f "$branch" + sed -i "s/^libvirt-python/#&/" requirements-selftests.txt + pip3 install -r requirements-selftests.txt + python3 setup.py install + + cd "$srcdir/avocado-vt" + git checkout -f "$branch" + sed -i "/^branch: /d" test-providers.d/io-github-autotest-qemu.ini + sed -i "/^uri: /c uri: $srcdir/tp-qemu" test-providers.d/io-github-autotest-qemu.ini + sed -i "/^uri: /a branch: $branch" test-providers.d/io-github-autotest-qemu.ini + sed -i "/^branch: /d" test-providers.d/io-github-autotest-libvirt.ini + sed -i "/^uri: /c uri: $srcdir/tp-libvirt" test-providers.d/io-github-autotest-libvirt.ini + sed -i "/^uri: /a branch: $branch" test-providers.d/io-github-autotest-libvirt.ini + rm -f test-providers.d/io-github-spiceqa-spice.ini + pip3 install -r requirements.txt + python3 setup.py install + + avocado vt-bootstrap --vt-type qemu --vt-skip-verify-download-assets --yes-to-all + avocado vt-bootstrap --vt-type libvirt --vt-skip-verify-download-assets --yes-to-all +} +``` + +# 测试执行准备 + +- 虚拟机xml + + 需要提前准备好libvirt的xml,并在执行tp-libvirt相关用例前先define + +- 测试虚拟机镜像准备 + + 镜像的命名要求、支持镜像的范围,可参见配置/var/lib/avocado/data/avocado-vt/backends/libvirt/cfg/guestos-os.cfg + + 镜像存放路径为/var/lib/avocado/data/avocado-vt/images/,所在磁盘分区空间需要足够大,在用例执行过程中会先备份一下镜像,故此空间至少是镜像大小两倍以上。多机场景的用例,会通过virt-clone等方式克隆多份镜像,尤其需要注意镜像所在磁盘分区空间的大小 + +- libvirt配置 + + 设置/etc/libvirt/qemu.conf下user/group字段,配置为root + +- 测试框架的base配置 + + 基础配置,包含了虚拟机名称、镜像名称、镜像登录用户密码等。如果涉及迁移双机场景,需要配置迁移环境的配置信息。 + + ``` + /var/lib/avocado/data/avocado-vt/backends/libvirt/cfg/base.cfg + /var/lib/avocado/data/avocado-vt/backends/libvirt/cfg/guest-os.cfg + ``` + +# 测试执行及结果分析 + +- 用例查看 + + 在用例执行之前,先通过avocado list查看对应模块的用例,可同时用于检测框架部署的正确性。 + + 如下几条命令,分别可查看qemu、libvirt以及通过多个条件组合过滤后的qemu_img模块的用例集。如果不做过滤用例集较大,命令执行稍微耗时多点(1分钟内) + + ``` + avocado list --vt-type qemu --vt-machine-type arm64-pci + avocado list --vt-type libvirt --vt-machine-type arm64-pci + avocado list qemu_img --vt-type qemu --vt-no-filter non-preallocated --vt-only-filter cluster_size_default --vt-machine-type arm64-pci + ``` + +- qemu用例执行 + + qemu用例可直接执行,不依赖libvirt的配置以及使用libvirt事先define一个虚拟机 + + 示例: + + ``` + avocado run type_specific.io-github-autotest-qemu.qemu_img.create.preallocated.cluster_size_default --vt-type qemu --vt-guest-os Guest.Linux.openEuler.20.03 --vt-machine-type arm64-pci + ``` + ![run-qemu-test-20210120](./run-qemu-test-20210120.png) + +- libvirt用例执行 + + libvirt用例执行之前,确保libvirt服务启动状态,同时需要基于前一章节中准备的虚拟机xml和镜像define一个测试虚拟机 + + 示例: + ``` + avocado list virsh.reset --vt-type libvirt --vt-no-filter acl_test --vt-only-filter uuid_options --vt-machine-type arm64-pci + ``` + +- 结果定位 + + 框架执行的每个用例的日志,都会归档在logs_dir = ~/avocado/job-results下(具体可配置avocado.conf中logs_dir字段)。 + + 参考前面qemu用例的执行示例图,可以看到日志的归档,关注JOB LOG文件 ,可以基于此开展失败分析定位。 diff --git a/web-ui/docs/zh/blog/kezhiming/run-qemu-test-20210120.png b/web-ui/docs/zh/blog/kezhiming/run-qemu-test-20210120.png new file mode 100644 index 0000000000000000000000000000000000000000..5a3e124e3a2b628d2d7e5c31220f29614af8f271 Binary files /dev/null and b/web-ui/docs/zh/blog/kezhiming/run-qemu-test-20210120.png differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-1.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b209b5b40601a5bcbce091e25d01bddf833c2aae Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-1.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-10.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5407a342054b47003b548254ff7f3102ab9fb172 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-10.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-11.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3dce48cc19844cd75bfedd8f04a2794ab3109cd6 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-11.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-12.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-12.jpg new file mode 100644 index 0000000000000000000000000000000000000000..186fc480b874cd858554ac973882d8f65de970ae Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-12.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-13.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-13.jpg new file mode 100644 index 0000000000000000000000000000000000000000..29203904f425c808fa2613209574bd4a8421187e Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-13.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-14.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-14.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34d49a5995788cd97c8d15105154df4692118c65 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-14.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-15.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-15.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a3c7e8f6fa1afa09af0f43bd95517e4adf6f608 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-15.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-2.png b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-2.png new file mode 100644 index 0000000000000000000000000000000000000000..52add787a198fa47f8d843ce5352eafecede2f37 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-2.png differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-3.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..91fbe524660aa8ed98fbb5d1b4e5f6cbd2252ebd Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-3.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-4.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abfc68461956196b4aaa301b1bee4c44b8002150 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-4.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-5.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24565c5536ed70e36d84c7660c07a85050d28753 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-5.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-6.png b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-6.png new file mode 100644 index 0000000000000000000000000000000000000000..7642def7568aa7a881cfd8d37578acf9c6eefeec Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-6.png differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-7.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0483983ff932f812730a7b05d1169bcd21a2728 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-7.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-8.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d06c6dd18ce65307808338e6f046aaf18210f473 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-8.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-9.jpg b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72c16070f2645628d130db5da31b077ea992a651 Binary files /dev/null and b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF-9.jpg differ diff --git a/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF.md b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF.md new file mode 100644 index 0000000000000000000000000000000000000000..bfe9470b9aab45b3d610ae6918a4abd774083b45 --- /dev/null +++ b/web-ui/docs/zh/blog/leikeke/summit 2020/BPF/BPF.md @@ -0,0 +1,226 @@ +--- +title: 基于BPF实现容器运行时安全 +date: 2021-01-15 +tags: + - BPF + - 容器 + - 安全性 +archives: 2021-01 +author: 范彬 +summary: 从BPF技术由来、架构演变、BPF跟踪、以及容器安全面对新挑战,如何基于BPF技术实现容器运行时安全等方面进行介绍。 +--- + + + _作者:范彬,中国电信股份有限公司云计算分公司_ + +# 1 前言 + +随着容器技术的发展,越来越多业务甚至核心业务开始采用这一轻量级虚拟化方案。作为一项依然处于发展阶段的新技术,容器的安全性在不断提高,也在不断地受到挑战。天翼云云容器引擎于去年11月底上线,目前已经在22个自研资源池部署上线。天翼云云容器引擎使用 ebpf 技术实现了细粒度容器安全,对主机和容器异常行为进行检测,对有问题的节点和容器进行自动隔离,保证了多租户容器平台容器运行时安全。 + + + +BPF 是一项革命性的技术,可在无需编译内核或加载内核模块的情况下,安全地高效地附加到内核的各种事件上,对内核事件进行监控、跟踪和可观测性。BPF 可用于多种用途,如:开发性能分析工具、软件定义网络和安全等。我很荣幸获得 openEuler Summit 2020大会的演讲资格,做 BPF 技术知识和实践经验的分享。本文将作为技术分享,从 BPF 技术由来、架构演变、BPF 跟踪、以及容器安全面对新挑战,如何基于 BPF 技术实现容器运行时安全等方面进行介绍。 + +# 2 初出茅庐:BPF 只是一种数据包过滤技术 + +BPF 全称是「Berkeley Packet Filter」,中文翻译为「伯克利包过滤器」。它源于 1992 年伯克利实验室,Steven McCanne 和 Van Jacobson 写得一篇名为《The BSD Packet Filter: A New Architecture for User-level Packet Capture》的论文。该论文描述是在 BSD 系统上设计了一种新的用户级的数据包过滤架构。在性能上,新的架构比当时基于栈过滤器的 CSPF 快20倍,比之前 Unix 的数据包过滤器,例如:SunOS 的 NIT(The Network Interface Tap )快100倍。 + + + +BPF 在数据包过滤上引入了两大革新来提高性能: + +● BPF 是基于寄存器的过滤器,可以有效地工作在基于寄存器结构的 CPU 之上。 + +● BPF 使用简单无共享的缓存模型。数据包会先经过 BPF 过滤再拷贝到缓存,缓存不会拷贝所有数据包数据,这样可以最大程度地减少了处理的数据量从而提高性能。 + + + +# 3 Linux 超能力终于到来了:eBPF 架构演变 + +## 3.1 eBPF 介绍 + +2013 年 BPF 技术沉默了 20 年之后,Alexei Starovoitov 提出了对 BPF 进行重大改写。2013 年 9月 Alexei 发布了补丁,名为「extended BPF」。eBPF 实现的最初目标是针对现代硬件进行优化。eBPF 增加了寄存器数量,将原有的 2 个 32 位寄存器增加到 10 个 64 位寄存器。由于寄存器数量和宽度的增加,函数参数可以交换更多的信息,编写更复杂的程序。eBPF 生成的指令集比旧的 BPF 解释器生成的机器码执行速度提高了 4 倍。 + + + +当时 BPF 程序仍然限于内核空间使用,只有少数用户空间程序可以编写内核的 BPF 过滤器,例如:tcpdump 和 seccomp 。2014 年 3 月, 经过 Alexei Starovoitov 和 Daniel Borkmann 的进一步开发, Daniel 将 eBPF 提交到 Linux 内核中。2014年 6月 BPF JIT 组件提交到 Linux 3.15 中。2014 年 12 月 系统调用bpf 提交到 Linux 3.18 中。随后,Linux 4.x 加入了 BPF 对 kprobes、uprobe、tracepoints 和 perf_evnets 支持。至此,eBPF 完成了架构演变,eBPF 扩展到用户空间成为了 BPF 技术的转折点。 正如 Alexei 在提交补丁的注释中写到:“这个补丁展示了 eBPF 的潜力”。当前eBPF 不再局限于网络栈,成为内核顶级的子系统。 + + + +后来,Alexei将 eBPF改为 BPF。原来的 BPF 就被称为cBPF「classic BPF」。现在 cBPF 已经基本废弃,Linux 内核只运行 eBPF,内核会将加载的 cBPF 字节码透明地转换成 eBPF 再执行。 + + + +下面是cBPF和eBPF的对比: + + + +接下来,让我们来看看演变后的BPF架构。 + +## 3.2 eBPF 架构演变 + +BPF 是一个通用执行引擎,能够高效地安全地执行基于系统事件的特定代码。BPF 内部由字节码指令,存储对象和帮助函数组成。从某种意义上看,BPF和Java虚拟机功能类似。对于Java 开发人员而言,可以使用 javac 将高级编程语言编译成机器代码,Java虚拟机是运行该机器代码的专用程序。相应地,BPF 开发人员可以使用编译器 LLVM 将 C 代码编译成 BPF 字节码,字节码指令在内核执行前必须通过 BPF 验证器进行验证,同时使用内核中的 BPF JIT 模块,将字节码指令直接转成内核可执行的本地指令。编译后的程序附加到内核的各种事件上,以便在 Linux 内核中运行该 BPF 程序。 + + + +BPF 使内核具有可编程性。BPF 程序是运行在各种内核事件上的小型程序。这与JavaScript 程序有一些相似之处:JavaScript 是允许在浏览器事件,例如:鼠标单击上运行的微型 Web 程序。BPF 是允许内核在系统和应用程序事件,例如:磁盘 I/O 上运行的微型程序。内核运行 BPF 程序之前,需要知道程序附加的执行点。程序执行点是由BPF程序类型确定。通过查看/kernel-src/sample/bpf/bpf_load.c 可以查看 BPF 程序类型。下面是定义在 bpf 头文件中的 bpf 程序类型: + + + +BPF 映射提供了内核和用户空间双向数据共享,允许用户从内核和用户空间读取和写入数据。BPF 映射的数据结构类型可以从简单数组、哈希映射到自定义类型映射。下面是定义在 bpf 头文件中的 bpf 映射类型: + + + +下图是 BPF 架构图: + + + +## 3.3.BPF 与传统 Linux 内核模块的对比 + +BPF 看上去更像内核模块,所以总是会拿来与 Linux 内核模块方式进行对比,但 BPF 与内核模块不同。BPF 在安全性、入门门槛上及高性能上比内核模块都有优势。 + + + +传统 Linux 内核模块开发,内核开发工程师通过直接修改内核代码,每次功能的更新都需要重新编译打包内核代码。内核工程师可以开发即时加载的内核模块,在运行时加载到 Linux 内核中,从而实现扩展内核功能的目的。然而每次内核版本的官方更新,可能会引起内核 API 的变化,因此你编写的内核模块可能会随着每一个内核版本的发布而不可用,这样就必须得为每次的内核版本更新调整你的模块代码,并且,错误的代码会造成内核直接崩溃。 + + + +BPF 具有强安全性。BPF 程序不需要重新编译内核,并且 BPF 验证器会保证每个程序能够安全运行,确保内核本身不会崩溃。BPF 虚拟机会使用 BPF JIT 编译器将 BPF 字节码生成本地机器字节码,从而能获得本地编译后的程序运行速度。 + + + +下面是 BPF 与 Linux 内核模块的对比: + + + +# 4 BPF 实践中的第一公民:BPF 跟踪 + +BPF跟踪是 Linux 可观测性的新方法。在BPF 技术的众多应用场景中,BPF 跟踪是应用最广泛的。2013 年 12 月 Alexei 已将 eBPF 用于跟踪。BPF 跟踪支持的各种内核事件包括:kprobes、uprobes、tracepoint 、USDT 和 perf_events: + +❏ kprobes:实现内核动态跟踪。 kprobes 可以跟踪到 Linux 内核中的函数入口或返回点,但是不是稳定 ABI 接口,可能会因为内核版本变化导致,导致跟踪失效。 + +❏ uprobes:用户级别的动态跟踪。与 kprobes 类似,只是跟踪的函数为用户程序中的函数。 + +❏ tracepoints:内核静态跟踪。tracepoints 是内核开发人员维护的跟踪点,能够提供稳定的 ABI 接口,但是由于是研发人员维护,数量和场景可能受限。 + +❏ USDT:为用户空间的应用程序提供了静态跟踪点。 + +❏ perf_events:定时采样和 PMC。 + + + +# 5 容器安全 + +## 5.1 容器生态链带来新挑战 + +虚拟机(VM)是一个物理硬件层抽象,用于将一台服务器变成多台服务器。管理程序允许多个VM在一台机器上运行。每个VM都包含一整套操作系统、一个或多个应用、必要的二进制文件和库资源,因此占用大量空间。VM启动也较慢。 + + + +容器是一种应用层抽象,用于将代码和依赖资源打包在一起。多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行。与虚拟机相比,容器占用的空间比较少(容器镜像大小通常只有几十兆),瞬间就能完成启动。 + + + +容器技术面临的新挑战: + +❏ 容器共享宿主机内核,隔离性相对较弱! + +❏ 有 root 权限的用户可以访问所有容器资源!某容器提权后可能影响全局! + +❏ 容器在主机网络之上构建了一层Overlay 网络,使容器间的互访避开了传统网络安全的防护! + +❏ 容器的弹性伸缩性,使有些容器只是短暂运行,短暂运行的容器行为异常不容易被发现! + +❏ 容器和容器编排给系统增加了新的元素,带来新的风险! + +## 5.2 容器安全事故:容器逃逸 + +在容器安全问题中,容器逃逸是最为严重,它直接影响到了承载容器的底层基础设施的保密性、完整性和可用性。下面的情况会导致容器逃逸: + +❏ 危险配置导致容器逃逸。在这些年的迭代中,容器社区一直在努力将「纵深防御」、「最小权限」等理念和原则落地。例如,Docker已经将容器运行时的Capabilities黑名单机制改为如今的默认禁止所有Capabilities,再以白名单方式赋予容器运行所需的最小权限。如果容器启动,配置危险能力,或特权模式容器,或容器以root用户权限运行都会导致容器逃逸。下面是容器运行时默认的最小权限。 + + + +❏ 危险挂载导致容器逃逸。Docker Socket 是 Docker 守护进程监听的 Unix 域套接字,用来与守护进程通信——查询信息或下发命令。如果在攻击者可控的容器内挂载了该套接字文件(/var/run/docker.sock),容器逃逸就相当容易了,除非有进一步的权限限制。 + + + +下面通过一个小实验来展示这种逃逸可能性: + +1.准备dockertest镜像,该镜像是基于ubuntu镜像安装docker,通过docker commit生成 + +2.创建一个容器并挂载/var/run/docker.sock + +docker run -itd --name with_docker_sock -v /var/run/docker.sock:/var/run/docker.sock dockertest + +3.接着使用该客户端通过Docker Socket与Docker守护进程通信,发送命令创建并运行一个新的容器,将宿主机的根目录挂载到新创建的容器内部; + +docker exec -it /bin/bash + +docker ps + +docker run -it -v /:/host dockertest /bin/bash + + + +❏ 相关程序漏洞导致容器逃逸,例如:runc漏洞CVE-2019-5736 导致容器逃逸。 + +❏ 内核漏洞导致容器逃逸,例如:Copy_on_Write脏牛漏洞,向vDSO内写入shellcode并劫持正常函数的调用过程,导致容器逃逸。 + + + +下面是2019年排名最高的容器安全事故列表: + + + +# 6 容器安全主控引擎 + +## 6.1 主机和容器异常活动的检测 + +确保容器运行时安全的关键点: + +❏ 降低容器的攻击面,每个容器以最小权限运行,包括容器挂载的文件系统、网络控制、运行命令等。 + +❏ 确保每个用户对不同的容器拥有合适的权限。 + +❏ 使用安全容器控制容器之间的访问。当前,Linux的Docker容器技术隔离技术采用Namespace 和 Cgroups 无法阻止提权攻击或打破沙箱的攻击。 + +❏ 使用ebpf跟踪技术自动生成容器访问控制权限。包括:容器对文件的可疑访问,容器对系统的可疑调用,容器之间的可疑互访,检测容器的异常进程,对可疑行为进行取证。例如: + +❏ 检测容器运行时是否创建其他进程。 + +❏ 检测容器运行时是否存在文件系统读取和写入的异常行为,例如在运行的容器中安装了新软件包或者更新配置。 + +❏ 检测容器运行时是否打开了新的监听端口或者建立意外连接的异常网络活动。 + +检测容器中用户操作及可疑的shell脚本的执行。 + + + +## 6.2 隔离有问题的容器和节点 + +如果检测到有问题的容器或节点,可以将节点设置为维护状态,或使用网络策略隔离有问题的容器,或将deployment的副本数设置为0,删除有问题的容器。同时,使用sidecar WAF,进行虚拟补丁等进行容器应用安全防范。 + + + +## 6.3 大型公有云容器平台安全主控引擎 + +下面是天翼云云容器引擎产品为了保证容器运行时安全实现的安全主控引擎: + + + +❏ Pod 通过 sidecar 注入 WAF组件对容器进行深度攻击防御。 + +❏ 容器安全代理 Sage 组件以Daemonset形式部署在各个节点上,用来收集容器和主机异常行为,并通过自己的 sidecar 推送到消息队列中。 + +❏ 安全主控引擎组件 jasmine 从消息队列中拉取事件,对数据进行分析,对有故障的容器和主机进行隔离。并将事件推送给SIEM安全信息事件管理平台进行管理。 + + + +参考资料: + +1. 【云原生攻防研究】容器逃逸技术概览:https://mp.weixin.qq.com/s/_GwGS0cVRmuWEetwMesauQ +2. GKE security using Falco,Pub/Sub,and Cloud Functions:https://sysdig.com/blog/gke-security-using-falco/ +3. Kubernetes Security monitoring at scale with Sysdig Falco:https://medium.com/@SkyscannerEng/kubernetes-security-monitoring-at-scale-with-sysdig-falco-a60cfdb0f67a +4. 开源项目falco:https://sysdig.com/opensource/falco/ +5. 容器逃逸成真:从CTF解题到CVE-2019-5736漏洞挖掘分析:https://mp.weixin.qq.com/s/UZ7VdGSUGSvoo-6GVl53qg \ No newline at end of file diff --git a/web-ui/docs/zh/blog/leofang94/2020-12-01-version-rec-auto-upgrade-of-openEuler-Advisor.md b/web-ui/docs/zh/blog/leofang94/2020-12-01-version-rec-auto-upgrade-of-openEuler-Advisor.md new file mode 100644 index 0000000000000000000000000000000000000000..29307605df3bc7109c078d6b5297b48ee31462ee --- /dev/null +++ b/web-ui/docs/zh/blog/leofang94/2020-12-01-version-rec-auto-upgrade-of-openEuler-Advisor.md @@ -0,0 +1,161 @@ +--- +title: openEuler-Advisor版本推荐与自动升级介绍 +date: 2020-12-01 +tags: + - version recommend + - auto-upgrade +archives: 2020-12 +author: Leo Fang +summary: version recommend and auto-upgrade features of openEuler-Advisor +--- + +## 目录 + +- openEuler-Advisor功能与定位 + +- 为什么会有openEuler-Advisor项目 + +- openEuler-Advisor基本组成 + +- 基本配置与安装 + +- 版本推荐与自动升级使用方法 +--- + +## openEuler-Advisor功能与定位 + +openEuler-Advisor, 为社区提供日常辅助功能或提供相关建议的功能集合, [主页](https://gitee.com/openeuler/openEuler-Advisor)描述为: + +Collection of automation tools for easily maintaining openEuler(用于便捷维护openEuler的自动化工具集) + +因此,该软件的定位是用于自动化维护(查询、巡检、升级、提示等)openEuler软件仓库的一套功能集合 + +## 为什么会有openEuler-Advisor项目 + +openEuler发行版集成了上游社区的软件,每个软件从被集成到持续维护,都需要一定工作量。而对一个发行版来说,基础数量已经以千为单位,为了考虑生态,更是以万为单位(参考业界社区fedora/ubuntu/openSUSE),因此总工作量巨大。 + +这种情况下,社区需要一套可以减少总工作量的工具,不但要减少贡献者、维护者的工作量,而且要减少校验者的工作量,因此openEuler-Advisor应运而生。 + +## openEuler-Advisor基本组成 + +openEuler-Advisor核心模块在advisors目录下,主要提供软件包上游信息查询、版本推荐、软件仓巡检(文件检查、重复软件包检查、软件source地址检查、衰退软件检查等)、自动创建软件仓、软件包自动升级、软件仓自动化review等功能。下面将对各组成模块功能进行简单介绍: + +
+ +![](./advisors-compose.png) + +
+ +- simple_update_robot: 用于src-openeuler仓库内软件包的自动升级工作,能够自动fork软件仓,下载要升级的源码包,修改spec文件(自动匹配上游社区已合入的补丁),本地obs编译,自动创建PR(包含差异分析报告)及issue等; + +
+ +![](./auto-upgrade.png) + +
+ +- oa_upgradable: 用于查询软件包上游发布信息及版本推荐等,能够获取软件包当前社区有效的release tags,并通过版本推荐算法,推荐出软件包的最新版本和维护版本,如果需要,可判断当前软件包版本是否需要升级,并创建相关issue; + +- check_missing_file: 用于检查src-openeuler中各个软件仓进行检查,是否有文件缺失,如果存在,则自动在对应的仓库下创建任务,提示Maintainer进行补充; + +- check_repeated_repo: 用于检查src-openeuler中是否存在可能重复的软件仓,针对upstream地址相同,软件仓名不同的情况,进行提示,由Maintainer进行审视,确保软件仓整洁及唯一; + +- check_source_url: 用于检查各个软件包的source地址是否有效,即能否通过source地址下载到有效的源码包,如果不能,则自动为对应的软件仓创建任务,提示Maintainer进行确认与修改; + +- create_repo/create_repo_with_srpm: 这两个模块提供了批量创建代码仓的功能,后者可以根据rpm包自动获取其Name、Summary、description及upstream等信息; + +- psrtool: 用于查询软件包归属SIG及某个SIG下所管理的软件包列表信息; + +- review_tool: 该模块作为代码自动检视工具,可为指定软件仓PR生成代码审视清单,规范PR审视过程,能够自动完成部分检查项的检查工作,为Commiter减轻工作量,保证检视质量; + +- tc_reminder: 用于自动为TC成员创建相关提示信息,比如社区TC成员列表,PR状态信息等,方便整个社区自动化管理; + +- which_archived: 用于检查软件包上游社区是否已经处于归档状态,即软件包是否停止维护,从而方便维护团队及时调整维护策略; + +## 基本配置与安装 + +- 安装软件包依赖: + +``` +pip3 install python-rpm-spec (ver>=0.10) +pip3 install PyYAML (ver>=5,3.1) +pip3 install requests (ver>=2.24.0) +yum install rpmdevtools (ver>=8.3) +pip3 install beautifulsoup4 (ver>=4.9.3) +``` + +- json文件配置: + + 创建json文件: root/.gitee_presonal_token.json + + json文件格式: {"user":"gitee用户名", "access_token": "token密码"} + + gitee token密码设置入口: https://gitee.com/profile/personal_access_tokens + +- gitee ssh配置: + + 如果未配置,请参考: https://gitee.com/help/articles/4181 + +- obs配置: + + 如果未配置,请参考: https://openeuler.org/zh/docs/20.09/docs/ApplicationDev/%E6%9E%84%E5%BB%BARPM%E5%8C%85.html + +- python环境配置: + + 如果处于开发态,直接使用该工具,首先需要配置Python环境路径: source ./develop_env.sh + +## 版本推荐与自动升级使用方法 + +这里主要介绍软件包版本信息查询和推荐,以及软件包自动升级功能的使用: + +- oa_upgradable: + + **查询软件包上游社区信息及版本推荐**: python3 oa_upgradable.py pkg_name [-d default_yaml_path] [-p] + + 参数说明: -d指定默认查询所需的yaml地址,yaml配置了软件包基本上游信息,详情可到openEuler-Advisor官网进行了解; -p表示若查询结果显示该软件包可以升级,会自动向软件仓创建issue + + 例如: python3 oa_upgradable.py glibc + +- simple_update_robot: + + **单软件包手动升级**: python3 simple_update_robot.py pkg_name branch_name [-fc] [-d] [-s] [-n new_version] [-b] [-p] + + 参数说明: -fc表示fork clone软件仓到本地; -d表示下载要升级的源码包; -s表示修改spec进行升级; -n表示要升级的版本; -b表示进行本地编译; -p表示本地验证ok后提交升级PR并创建相应的issue + + 例如: python3 simple_update_robot.py snappy openEuler-20.03-LTS -fc -d -s -b -n 1.8.1 + + **单软件包自动升级**: python3 simple_update_robot.py -u pkg pkg_name branch_name [-n new_version] + + 参数说明: -u pkg表示单软件包升级; -n用于指定要升级的版本,若不指定系统自动推荐合适版本 + + 例如: python3 simple_update_robot.py -u pkg snappy master + + **多软件包自动升级**: python3 simple_update_robot.py -u repo repo_name branch_name + + 参数说明: -u repo表示多软件包升级,repo_name表示要升级的集合/仓库名,默认先从本地读取同名yaml,若没有则尝试从community中进行读取 + + 例如: python3 simple_update_robot.py -u repo src-openeuler master + +用户可以在本地工作目录下配置要升级的repo列表,yaml格式如下: + +比如: upgrade-example.yaml + +``` +repositories: +- name: A-Tune +- name: python-py +- name: python-ply +``` + +如果想为某些软件包指定升级版本,可以配置为: + +``` +repositories: +- name: A-Tune + u_ver: x.y.z +- name: python-py +- name: python-ply +``` + +然后通过工具自动升级: python3 simple_update_robot.py -u repo upgrade-example master + diff --git a/web-ui/docs/zh/blog/leofang94/advisors-compose.png b/web-ui/docs/zh/blog/leofang94/advisors-compose.png new file mode 100644 index 0000000000000000000000000000000000000000..e928959f590eec6ea65d19a6e2b505bcd073dfdf Binary files /dev/null and b/web-ui/docs/zh/blog/leofang94/advisors-compose.png differ diff --git a/web-ui/docs/zh/blog/leofang94/auto-upgrade.png b/web-ui/docs/zh/blog/leofang94/auto-upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..12f59e9256e7333abb6f4f4831aabfcdbb796123 Binary files /dev/null and b/web-ui/docs/zh/blog/leofang94/auto-upgrade.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-01.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-01.png new file mode 100644 index 0000000000000000000000000000000000000000..883546c928aa00a026a622da20a74d123e401d77 Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-01.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-02.jpg b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f9129755d7780af13e4b528fc4b17ced49ee402 Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-02.jpg differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-03.jpg b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c37a0fb574d39a3718cd665f4ecc471bea8d4518 Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-03.jpg differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-04.jpg b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36afde5dfa37d44a1b2342686c71951ea1c561fe Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-04.jpg differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-05.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-05.png new file mode 100644 index 0000000000000000000000000000000000000000..40328959d8993fc1272c5d0b7f3d36b5e7bd78f8 Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-05.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-06.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-06.png new file mode 100644 index 0000000000000000000000000000000000000000..82a1663932f8706ddebd2cd0a1eee80e47acafbe Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-06.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-07.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-07.png new file mode 100644 index 0000000000000000000000000000000000000000..99a47739c4c2467782c412e4283d0f469d45e50a Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-07.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-08.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-08.png new file mode 100644 index 0000000000000000000000000000000000000000..b860eda5251f48cc44d05980fe27b6d0e99852fc Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-08.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-09.png b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-09.png new file mode 100644 index 0000000000000000000000000000000000000000..3d660ce8e0ea9b9cf1057f39125077fb45a3e585 Binary files /dev/null and b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture-09.png differ diff --git a/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture.md b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture.md new file mode 100644 index 0000000000000000000000000000000000000000..caf1ae7f2a264e9dea61bb4dc541752e068e5d3b --- /dev/null +++ b/web-ui/docs/zh/blog/lifeng2221dd1/2020-09-14-isulad-architecture.md @@ -0,0 +1,745 @@ +--- +title: iSulad 轻量级容器引擎功能介绍以及代码架构解析 +date: 2020-09-14 +tags: + - iSulad +archives: 2020-09 +author: lifeng2221dd1 +summary: iSulad架构解析 +--- + +_作者简介:李峰, 具有多年容器、操作系统软件开发经验,对容器引擎、runtime 等领域有比较深入的研究与理解。深度参与 lxc、containers 等开源容器社区。现在担任 openeuler 轻量级容器引擎 iSulad 社区 maintainer。_ + +iSulad 是一种由 C/C++编程语言编写的容器引擎,当前已经在 openeuler 社区开源(https://gitee.com/openeuler/iSulad)。 当前主流的容器引擎 docker、containerd、cri-o 等均是由 GO 语言编写。随着边缘计算、物联网等嵌入式设备场景的不断兴起,在资源受限环境下,业务容器化的需求越来越强烈。由高级语言编写的容器引擎在底噪占用上的劣势越来越凸显。另外由于容器引擎对外接口的标准化,因此用 C/C++重写一个容器引擎成为了可能。iSulad 整体架构如下图所示。 + +iSulad + +iSulad 对外提供命令行以及基于 gRPC 的 CRI 两种对外接口,其中核心功能根据业务分为镜像管理和容器管理。 + +通过下图可以理解 iSulad 在生态中的定位。 + + iSulad + +本文介绍 iSulad 的功能特性以及对整体架构进行介绍。 + +## iSulad 功能特性介绍 + +### 提供客户端命令行进行容器、镜像操作 + +iSulad 是典型的 CS 架构模式。iSulad 作为 daemon 服务端,同时也提供了单独的客户端命令 isula,供用户使用。 + +iSula 提供的命令参数覆盖了常用的大部分的应用场景。包含容器的操作接口,如运行、停止、删除、pause 等操作,也包含了镜像相关的操作,如下载、导入、删除等。 + +``` +$ sudo isula --help +USAGE: + isula [args...] + +COMMANDS: + attach Attach to a running container + cp Copy files/folders between a container and the local filesystem + create Create a new container + events Get real time events from the server + exec Run a command in a running container + export export container + images List images + import Import the contents from a tarball to create a filesystem image + info Display system-wide information + inspect Return low-level information on a container or image + kill Kill one or more running containers + load load an image from a tar archive + login Log in to a Docker registry + logout Log out from a Docker registry + logs Fetch the logs of a container + pause Pause all processes within one or more containers + ps List containers + pull Pull an image or a repository from a registry + rename Rename a container + restart Restart one or more containers + rm Remove one or more containers + rmi Remove one or more images + run Run a command in a new container + start Start one or more stopped containers + stats Display a live stream of container(s) resource usage statistics + stop Stop one or more containers + tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE + top Display the running processes of a container + unpause Unpause all processes within one or more containers + update Update configuration of one or more containers + version Display information about isula + wait Block until one or more containers stop, then print their exit codes +``` + +### 使用举例 + +假设您使用的为openeuler发行版本,可以采用以下方式使用iSulad。 + +#### 使用yum命令安装isulad + +``` +[root@openeuler ~]# yum install -y iSulad +``` + +#### 安装完成后,查看服务运行状态 + +``` +[root@openeuler ~]# systemctl status isulad +● isulad.service - iSulad Application Container Engine + Loaded: loaded (/usr/lib/systemd/system/isulad.service; enabled; vendor preset: disabled) + Active: active (running) since Mon 2020-09-14 15:53:43 CST; 4h 35min ago + Main PID: 1248 (isulad) + Tasks: 25 + Memory: 88.3M + CGroup: /system.slice/isulad.service + ├─1248 /usr/bin/isulad +``` + +#### 修改isulad的配置文件,添加镜像仓库地址 + +``` +[root@openeuler iSula]# vi /etc/isulad/daemon.json +{ + ....... + "registry-mirrors": [ + "hub.oepkgs.net" + ], + ....... +``` + +#### 重启isulad服务 + +``` +[root@openeuler iSula]# systemctl restart isulad +``` + +#### 基于openeuler:20.09镜像运行容器 + +创建容器: + +``` +[root@openeuler iSula]# isula create -it openeuler/openeuler:20.09 +Unable to find image 'openeuler/openeuler:20.09' locally +Image "openeuler/openeuler:20.09" pulling +Image "8c788f4bfb7290e434b2384340a5f9811db6ed302f9247c5fc095d6ec4fc8f32" pulled +e91e5359be653f534312bc2b4703dcc6c4ca0436ac7819e09e1ff0e75ee1d733 +``` + +由于没有运行容器,所以利用isula ps命令无法找到刚刚创建的容器: + +``` +[root@openeuler iSula]# isula ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +``` + +可以使用isula pa –a命令可以找到刚刚创建的容器: + +``` +[root@ecs-cdf3 ~]# isula ps -a +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +e91e5359be65 openeuler/openeuler:20.09 "/bin/bash" 8 seconds ago Created e91e5359be653f534312bc2b4703dcc6c4ca0436ac7819e09e1ff0e75ee1d733 +``` + +启动容器: + +``` +[root@openeuler iSula]# isula start e91e5359be65 +``` + +由于已经运行容器,可以利用isula ps命令查找运行中的容器 + +``` +[root@openeuler iSula]# isula ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +e91e5359be65 openeuler/openeuler:20.09 "/bin/bash" 30 seconds ago Up 4 seconds e91e5359be653f534312bc2b4703dcc6c4ca0436ac7819e09e1ff0e75ee1d733 +``` + +执行命令输出容器系统版本信息: + +``` +[root@ecs-cdf3 ~]# isula exec e91e5359be65 cat /etc/os-release +NAME="openEuler" +VERSION="20.09" +ID="openEuler" +VERSION_ID="20.09" +PRETTY_NAME="openEuler 20.09" +ANSI_COLOR="0;31" +``` + +可以看到我们在openeuler 20.03系统上成功运行openeuler 20.09容器。 + +暂停/恢复一个容器 + +``` +[root@openeuler iSula]# isula pause e91e5359be65 +e91e5359be65 +[root@openeuler iSula]# isula unpause e91e5359be65 +e91e5359be65 +``` + +强制删除运行中的容器 + +``` +[root@openeuler iSula]# isula rm -f 6c1d81467d33 +6c1d81467d3367a90dd6e388a16c80411d4ba76316d86b6f56463699306e1394 +``` + +删除镜像 + +``` +[root@openeuler iSula]# isula rmi openeuler/openeuler:20.09 +Image " openeuler/openeuler:20.09" removed +``` + +### 支持 CRI 标准协议 + +CRI(Container Runtime Interface)是由 K8S 定义的容器引擎需要向 k8S 对外提供的容器和镜像的服务的接口,供容器引擎接入 K8S。 + +CRI 接口基于 gRPC 实现。iSulad 遵循 CRI 接口规范,实现 CRI gRPC Server,包括 Runtime Service 和 Image Service 分别用来提供容器运行时接口和镜像操作接口。iSulad 的 gRPC Server 需要监听本地的 Unix socket,而 K8S 的组件 kubelet 则作为 gRPC Client 运行。 + +iSulad + +### 支持 CNI 网络标准协议 + +CNI(Container Network Interface) 是 google 和 CoreOS 主导制定的容器网络标准协议。通过 CNI 协议,iSulad 通过 JSON 格式的文件与具体网络插件进行通信,进而实现容器的网络功能。容器网络具体的功能均由网络插件来实现。iSulad 中使用 C 语言实现了 clibcni 接口模块,用来实现对应功能。 + +iSulad + +### 遵循 OCI 标准 + +OCI 包含两个标准规范 **容器运行时标准 (runtime spec)和 容器镜像标准(image spec)**。 + +#### 支持 OCI 标准镜像格式 + +首先介绍下,什么是容器镜像。容器运行所需的 rootfs 以及一些资源配置等信息被打包成特定的数据结构,称为容器镜像。基于容器镜像可以方便地运行容器。由于运行环境和应用被一起打包到了容器镜像中,这样就解决了应用部署时的环境依赖问题。每个容器镜像由一个或多个层数据、以及一个 config.json 配置文件组成。多个层之间有依赖关系,这种依赖关系称为父子关系(被依赖的层为父层)。运行容器之前,所有层的数据会合并挂载成一个 rootfs 供容器使用,称为容器层。合并后的数据如果有冲突,则子层的数据会覆盖父层中路径名称都相同的数据,镜像组织结构如下图所示: + +iSulad-img-single + +镜像的分层是为了解决空间占用问题。如果本层及其所有递归依赖的父层具有相同的数据,这些数据就可以复用,以减少空间占用。下图描述的是具有相同 layer0 层和 layer1 层的两个容器镜像的数据复用结构: + +iSulad-img-dual + +iSulad 支持 OCI 标准镜像格式以及与 docker 兼容的镜像格式。能够 支持从 docker hub 等镜像仓库下载容器镜像,或者导入由 docker 导出的镜像文件来启动容器使用。 + +#### 支持 OCI 标准 runtime + +iSulad 支持标准 OCI runtime 操作接口,可以进行容器生命周期管理。iSulad 不仅支持当前主流的容器 runtime 如 runc、kata,而且针对低底噪的需求,将 C 语言编写的 lxc 进行了适配修改,使其能够作为支持 OCI 标准协议的 C 语言 runtime,进一步降低了容器引擎基础设施底噪开销。 +​ 下面使用 iSulad 来运行一个新的容器,通过查看运行过程中产生的进程以及持久化的配置,理解运行新容器的过程。 + +运行容器,首先需要下载镜像,我们使用 前文中提到的 openeuler/openeuler:20.09 来作为容器镜像。 + +调用 isula 客户端命令下载镜像。 + +```bash +$ sudo isula pull openeuler/openeuler:20.09 +Image "openeuler/openeuler:20.09" pulling +Image "c7c37e472d31c1685b48f7004fd6a64361c95965587a951692c5f298c6685998" pulled +``` + +运行容器指创建一个新的容器,并启动它。 + +```bash +$ sudo isula run -itd openeuler/openeuler:20.09 +42fc2595f876b5a18f7729dfb10d0def29789fb73fe0f1327e0277e6d85189a1 +``` + +运行容器后,可以通过本地文件查看持久化的容器配置文件。 + +```bash +# cd /var/lib/isulad/engines/lcr/42fc2595f876b5a18f7729dfb10d0def29789fb73fe0f1327e0277e6d85189a1 +# ls -al +total 92 +drwxr-x--- 3 root root 4096 7月 27 16:25 . +drwxr-x--- 3 root root 4096 7月 27 16:25 .. +-rw-r----- 1 root root 4045 7月 27 16:25 config +-rw-r----- 1 root root 23878 7月 27 16:25 config.json +-rw-r----- 1 root root 2314 7月 27 16:25 config.v2.json +-rw-r----- 1 root root 0 7月 27 16:25 console.log +-rw-r----- 1 root root 101 7月 27 16:25 hostconfig.json +-rw-r--r-- 1 root root 10 7月 27 16:25 hostname +-rw-r--r-- 1 root root 183 7月 27 16:25 hosts +drwx------ 3 root root 4096 7月 27 16:25 mounts +-rw-r----- 1 root root 5 7月 27 16:25 ocihooks.json +-rw-r--r-- 1 root root 707 7月 27 16:25 resolv.conf +-rw-r----- 1 root root 26140 7月 27 16:25 seccomp +``` + +其中 config.json 文件为符合 OCI 标准协议的容器配置文件,内容包括启动容器所需的配置信息。 + +```bash +# cat config.json +{ + "ociVersion": "1.0.1", + "hooks": { + + }, + "hostname": "localhost", + "mounts": [ + { + "source": "tmpfs", + "destination": "/dev", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ], + "type": "tmpfs" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "type": "mqueue" + }, + ... +``` + +config.v2.json 为 iSulad 维护管理容器持久化的一些信息,包括容器的基础配置,以及创建时间,启动时间,容器的 PID、运行启动时间等信息。 + +```bash +# cat config.v2.json +{ + "CommonConfig": { + "Path": "sh", + "Config": { + "Hostname": "localhost", + "User": "", + "Tty": true, + "OpenStdin": true, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "sh" + ], + "WorkingDir": "", + "LogDriver": "json-file" + }, + "Created": "2020-07-27T16:25:16.170149428+08:00", + "Image": "openeuler/openeuler:20.09", + "ImageType": "oci", + "Name": "42fc2595f876b5a18f7729dfb10d0def29789fb73fe0f1327e0277e6d85189a1", + "id": "42fc2595f876b5a18f7729dfb10d0def29789fb73fe0f1327e0277e6d85189a1" + }, + "Image": "sha256:c7c37e472d31c1685b48f7004fd6a64361c95965587a951692c5f298c6685998", + "State": { + "FinishedAt": "0001-01-01T00:00:00Z", + "Pid": 19232, + "PPid": 19229, + "StartTime": 2731408, + "PStartTime": 2731402, + "Running": true, + "StartedAt": "2020-07-27T16:25:16.286812971+08:00" + } +} +``` + +## 性能表现 + +### 与其他容器引擎性能比较 + +#### 测试环境 + +| Configuration | Information | +| ------------- | -------------------------------------------- | +| OS | Fedora32 X86_64 | +| kernel | linux 5.7.10-201.fc32.x86_64 | +| CPU | 48 cores,Intel Xeon CPU E5-2695 v2 @ 2.4GHZ | +| memory | 132 GB | + +#### 测试版本 + +| Name | Version | +| --------- | --------------------------------------------------------------------- | +| iSulad | Version: 2.0.3 , Git commit: 3bb24761f07cc0ac399e1cb783053db8b33b263d | +| docker | Version: 19.03.11, Git commit: 42e35e6 | +| podman | version 2.0.3 | +| CRI-O | v1.15.4 | +| kubelet | v1.15.0 | +| cri-tools | v1.15.0 | + +#### 单容器操作 + +使用客户端 + +| operator (ms) | Docker | Podman | iSulad | vs Docker | vs Podman | +| ------------- | ------ | ------ | ------ | --------- | --------- | +| create | 287 | 180 | 87 | -69.69% | -51.67% | +| start | 675 | 916 | 154 | -77.19% | -83.19% | +| stop | 349 | 513 | 274 | -21.49% | -46.59% | +| rm | 72 | 187 | 60 | -16.67% | -67.91% | +| run | 866 | 454 | 195 | -77.48% | -57.05% | + +使用 CRI 接口 + +| operator (ms) | Docker | CRIO | iSulad | vs Docker | vs Podman | +| ------------- | ------ | ---- | ------ | --------- | --------- | +| runp | 681 | 321 | 186 | -72.69% | -42.06% | +| stopp | 400 | 356 | 169 | -57.75% | -52.53% | + +#### 并发 100 容器操作 + +使用客户端 + +| operator (ms) | Docker | Podman | iSulad | vs Docker | vs Podman | +| ------------- | ------ | ------ | ------ | --------- | --------- | +| 100 \* create | 4995 | 3993 | 829 | -83.40% | -79.24% | +| 100 \* start | 10126 | 5537 | 1425 | -85.93% | -74.26% | +| 100 \* stop | 8066 | 11100 | 2273 | -71.82% | -79.52% | +| 100 \* rm | 3220 | 4319 | 438 | -86.40% | -89.86% | +| 100 \* run | 9822 | 5979 | 2117 | -78.45% | -64.59% | + +使用 CRI 接口 + +| operator (ms) | Docker | CRIO | iSulad | vs Docker | vs Podman | +| ------------- | ------ | ---- | ------ | --------- | --------- | +| 100 \* runp | 13998 | 4946 | 2825 | -79.82% | -42.88% | +| 100 \* stopp | 8402 | 4834 | 4543 | -45.93% | -6.02% | + +## iSulad 代码架构介绍 + +前面介绍了 iSulad 的主要的功能特性,现在让我们深入到 iSulad 的代码中,了解下 iSulad 的代码组织架构。 + +### **DDD 分层架构设计** + +iSulad 采用 DDD(Domain Driven Design,领域驱动设计)的思想进行架构分层组织,层次划分如下: + +ddd + +各逻辑分层划分以及对应的职责如下: + +| **层次** | **职责划分** | +| ---------- | -------------------------------------------------------------------------------------- | +| 用户界面 | 负责向用户展现信息以及解释用户命令 | +| 接口层 | 客户端服务端通信接口、CRI 接口的定义与实现 | +| 应用层 | 调用领域层的接口,实现对应的业务应用 | +| 领域层 | 本层包含关于领域的信息,这是 iSulad 软件的核心所在。包含多种模块,业务逻辑实际的执行层 | +| 基础设施层 | 本层作为其他层的支撑库。它提供各种工具函数供其他层次调用使用 | + +根据上述逻辑分层的设计思想,iSulad 对应源码目录架构设计为: + +iSulad-img-single + +其中 api 目录中定义了 iSulad 对外提供的 gRPC 服务的 proto 文件,在编译时会使用 grpc 生成对应客户端、服务端代码。 + +### 各层代码组织结构 + +#### 用户界面层 + +用户界面层的代码位于 src/cmd 目录下,在该目录下,提供了 iSulad 对外的命令行接口。在 cmd 目录下,提供了 isula 客户端、isulad 服务端、isulad-shim 三个命令行相关的命令行解析、参数显示。代码组织结构如下: + +```bash +├── CMakeLists.txt +├── command_parser.c +├── command_parser.h +├── isula # 客户端命令行以及子命令的定义 +│   ├── base # 容器操作基础命令,如创建、启动、删除等命令 +│   ├── client_arguments.c +│   ├── client_arguments.h +│   ├── CMakeLists.txt +│   ├── extend # 容器操作扩展命令,如update更新容器资源、events查看容器事件日志 +│   ├── images # 镜像相关操作命令,如下载、导入、删除等操作 +│   ├── information # 查询容器信息操作命令,如inspect、info等操作 +│   ├── isula_commands.c +│   ├── isula_commands.h +│   ├── main.c +│   └── stream # 长连接命令,如cp、attach、exec等需要与服务端进行长连接操作的命令 +├── isulad # 服务端命令行以及参数的定义 +│   ├── CMakeLists.txt +│   ├── isulad_commands.c +│   ├── isulad_commands.h +│   └── main.c +└── isulad-shim # isulad-shim命令行以及参数的定义 +│   ├── CMakeLists.txt +│   ├── common.c +│   ├── common.h +│   ├── main.c +│   ├── process.c +│   ├── process.h +│   ├── terminal.c +│   └── terminal.h +└── options # 通用的参数解析方法 +│   ├── CMakeLists.txt +│   ├── opt_log.c +│   ├── opt_log.h +│   ├── opt_ulimit.c +│   └── opt_ulimit.h + + +``` + +#### 接口层 + +iSulad 的接口层代码位于 src/daemon/entry 目录,其中提供了客户端服务端通信接口、CRI 接口的定义。 + +用以处理客户端接口的请求以及 CRI 接口请求。 + +其中 CRI 接口处理中,可以从文件名中看到,iSulad 分别实现了 image 和 runtime 的两种 service。 + +```bash +├── CMakeLists.txt +├── connect # 处理客户端请求 +│   ├── CMakeLists.txt +│   ├── grpc # grpc 请求接口处理 +│   ├── rest # restful 请求接口处理 +│   ├── service_common.c +│   └── service_common.h +└── cri # 处理CRI接口请求 + ├── checkpoint_handler.cc + ├── checkpoint_handler.h + ├── CMakeLists.txt + ├── cni_network_plugin.cc + ├── cni_network_plugin.h + ├── cri_container.cc # cri接口中容器相关操作请求接口处理 + ├── cri_container.h + ├── cri_image_service.cc # cri接口中image相关操作请求接口处理 + ├── cri_image_service.h + ├── cri_runtime_service.cc # cri接口中runtime相关操作请求接口处理 + ├── cri_runtime_service.h + ├── cri_sandbox.cc # cri接口中pod相关操作请求接口处理 + ├── cri_sandbox.h + ├── cri_security_context.cc # cri接口中安全配置处理 + ├── cri_security_context.h + └── websocket # 使用websocket服务处理CRI 流式服务请求 +``` + +#### 应用层 + +iSulad 的应用层代码位于 src/daemon/executor 目录,其作用为调用领域层的接口,实现对应的业务应用,属于业务调度层。可以从文件夹的命名中看到,应用层分别实现了 image 和 runtime 的两种业务模块。 + +```bash +├── callback.c +├── callback.h +├── CMakeLists.txt +├── container_cb # 容器业务模块 +│   ├── CMakeLists.txt +│   ├── execution.c +│   ├── execution_create.c +│   ├── execution_create.h +│   ├── execution_extend.c +│   ├── execution_extend.h +│   ├── execution.h +│   ├── execution_information.c +│   ├── execution_information.h +│   ├── execution_network.c +│   ├── execution_network.h +│   ├── execution_stream.c +│   ├── execution_stream.h +│   ├── list.c +│   └── list.h +└── image_cb # 镜像业务模块 + ├── CMakeLists.txt + ├── image_cb.c + └── image_cb.h +``` + +#### 领域层 + +领域层包含领域的信息,这是 iSulad 软件的核心所在。其中包含各个业务模块,是业务逻辑实际的执行层。领域层代码位于 src/daemon/modules。 + +```bash +├── api # 领域层统一对外提供的头文件,供应用层调用 +│   ├── CMakeLists.txt +│   ├── container_api.h +│   ├── events_collector_api.h +│   ├── events_sender_api.h +│   ├── event_type.h +│   ├── image_api.h +│   ├── io_handler.h +│   ├── log_gather_api.h +│   ├── plugin_api.h +│   ├── runtime_api.h +│   ├── service_container_api.h +│   ├── service_image_api.h +│   └── specs_api.h +├── CMakeLists.txt +├── container # 容器模块,维护容器全生命周期,维护容器状态 +│   ├── CMakeLists.txt +│   ├── container_events_handler.c +│   ├── container_events_handler.h +│   ├── container_gc +│   ├── containers_store.c +│   ├── containers_store.h +│   ├── container_state.c +│   ├── container_state.h +│   ├── container_unix.c +│   ├── container_unix.h +│   ├── health_check +│   ├── restart_manager +│   ├── restore +│   └── supervisor +├── events # 事件收集模块,负责收集iSulad运行过程中产生的容器、镜像事件 +│   ├── CMakeLists.txt +│   ├── collector.c +│   ├── monitord.c +│   └── monitord.h +├── events_sender # 事件发送模块,该接口提供向事件收集模块发送事件的接口 +│   ├── CMakeLists.txt +│   └── event_sender.c +├── image # 镜像管理模块 +│   ├── CMakeLists.txt +│   ├── embedded # embedded格式镜像管理 +│   ├── external # external格式镜像管理 +│   ├── image.c +│   ├── image_rootfs_handler.c +│   ├── image_rootfs_handler.h +│   └── oci # oci格式镜像管理 +├── log # 日志收集模块 +│   ├── CMakeLists.txt +│   └── log_gather.c +├── plugin # 插件机制模块 +│   ├── CMakeLists.txt +│   ├── plugin.c +│   ├── pspec.c +│   └── pspec.h +├── runtime # 容器运行时模块 +│   ├── CMakeLists.txt +│   ├── engines # 基于lxc的轻量级runtime对接接口 +│   ├── isula # oci 标准runtime对接接口 +│   └── runtime.c +├── service # 服务模块,包含多个模块协同调用的实现 +│   ├── CMakeLists.txt +│   ├── io_handler.c +│   ├── service_container.c # 容器服务操作接口 +│   └── service_image.c # 镜像服务操作接口 +└── spec # oci规范配置模块,对外提供OCI spec合并、校验等功能接口 + ├── CMakeLists.txt + ├── specs.c + ├── specs_extend.c + ├── specs_extend.h + ├── specs_mount.c + ├── specs_mount.h + ├── specs_namespace.c + ├── specs_namespace.h + ├── specs_security.c + ├── specs_security.h + ├── verify.c # 配置校验功能接口 + └── verify.h +``` + +#### 基础设施层 + +基础设施层位于 src/utils 目录下,本层作为其他层的支撑库。它提供各种工具函数供其他层次调用使用: + +```bash +├── buffer # buffer 工具函数 +│   ├── buffer.c +│   ├── buffer.h +│   └── CMakeLists.txt +├── CMakeLists.txt +├── console # IO 终端处理工具函数 +│   ├── CMakeLists.txt +│   ├── console.c +│   └── console.h +├── cpputils # C++ 使用到的工具函数,包含基础字符串处理、url、线程工具 +│   ├── CMakeLists.txt +│   ├── cxxutils.cc +│   ├── cxxutils.h +│   ├── stoppable_thread.cc +│   ├── stoppable_thread.h +│   ├── url.cc +│   └── url.h +├── cutils # C使用到的工具函数,包含基础字符串处理、数据类型转换、文件处理、正则表达式等工具函数 +│   ├── CMakeLists.txt +│   ├── util_atomic.c +│   ├── util_atomic.h +│   ├── utils_aes.c +│   ├── utils_aes.h +│   ├── utils_array.c +│   ├── utils_array.h +│   ├── utils_base64.c +│   ├── utils_base64.h +│   ├── utils.c +│ .... +├── http # http 处理工具函数,包含http请求、解析、认证等工具 +│   ├── certificate.c +│   ├── certificate.h +│   ├── CMakeLists.txt +│   ├── http.c +│   ├── http.h +│   ├── mediatype.h +│   ├── parser.c +│   ├── parser.h +│   ├── rest_common.c +│   └── rest_common.h +├── sha256 # sha256 工具函数,用来计算sha256 +│   ├── CMakeLists.txt +│   ├── sha256.c +│   └── sha256.h +└── tar # 压缩、解压工具函数,用来压缩、解压文件 + ├── CMakeLists.txt + ├── isulad_tar.c + ├── isulad_tar.h + ├── util_archive.c + ├── util_archive.h + ├── util_gzip.c + └── util_gzip.h +``` + +### 调用流程 + +可以借助**Structure101** 代码分析工具,梳理出 iSulad 各个代码目录之前的调用依赖关系。 + +iSulad + +首先,用户界面层(cmd)作为上层,仅会调用其他模块的接口,不会被其他模块所依赖。cmd 会调用 client 目录中的函数,与 daemon 端进行通信。由于 cmd 目录中存在 iSulad daemon 的命令行接口,因此会依赖 daemon 目录下的函数定义。 + +daemon 目录作为服务端代码的顶层目录,其中包含接口层(entry)、应用层(executor)、领域层(modules)的代码。接口层作为调用 daemon 服务的入口,需要调用其他层中的函数进行业务调度处理,而不会被其他层次所依赖。应用层需要调用领域层(modules)中各个模块的接口来实现具体的业务。 + +modules 目录作为 iSulad 的核心领域层代码,包含各个子功能模块的具体实现。以 image 模块为例,首先在 src/daemon/modules/api 中提供了 image_api.h,屏蔽了各种不同镜像格式的差异,对外提供统一的 image 操作函数接口。 + +```c +int image_module_init(const isulad_daemon_configs *args); + +void image_module_exit(); + +int im_list_images(const im_list_request *request, im_list_response **response); + +int im_rm_image(const im_rmi_request *request, im_remove_response **response); + +int im_tag_image(const im_tag_request *request, im_tag_response **response); + +int im_inspect_image(const im_inspect_request *request, im_inspect_response **response); + +int im_import_image(const im_import_request *request, char **id); + +int im_load_image(const im_load_request *request, im_load_response **response); + +int im_pull_image(const im_pull_request *request, im_pull_response **response); + +char *im_get_image_type(const char *image, const char *external_rootfs); + +bool im_config_image_exist(const char *image_name); + +int im_login(const im_login_request *request, im_login_response **response); + +int im_logout(const im_logout_request *request, im_logout_response **response); + +int im_container_export(const im_export_request *request); + +void free_im_export_request(im_export_request *ptr); + +``` + +在镜像管理模块内部,对不同格式的镜像操作进行区分。 + +```c +static const struct bim_type g_bims[] = { +#ifdef ENABLE_OCI_IMAGE + { + .image_type = IMAGE_TYPE_OCI, + .ops = &g_oci_ops, + }, +#endif + { .image_type = IMAGE_TYPE_EXTERNAL, .ops = &g_ext_ops }, +#ifdef ENABLE_EMBEDDED_IMAGE + { .image_type = IMAGE_TYPE_EMBEDDED, .ops = &g_embedded_ops }, +#endif +}; +``` + +其他模块也都是类似的设计,具体深入到不同模块的详细解析,在后续的博客中会一一进行分析。 diff --git a/web-ui/docs/zh/blog/lijiajie128/2020-09-01-CVE-2020-14364-QEMU-USB-array-out-of-range.md b/web-ui/docs/zh/blog/lijiajie128/2020-09-01-CVE-2020-14364-QEMU-USB-array-out-of-range.md new file mode 100644 index 0000000000000000000000000000000000000000..d80edaa5b23a141af1b02fffb475180a167f749b --- /dev/null +++ b/web-ui/docs/zh/blog/lijiajie128/2020-09-01-CVE-2020-14364-QEMU-USB-array-out-of-range.md @@ -0,0 +1,182 @@ +--- +title: CVE-2020-14364 QEMU USB数组越界读写问题 +date: 2020-09-01 +tags: + - Qemu + - CVE + - USB + - Buffer overflow + - Patch +archives: 2020-09 +author: Jiajie Li +summary: 关于CVE-2020-14364的漏洞描述、分析以及针对性的解决方案 +--- + + +# CVE-2020-14364 QEMU USB数组越界读写问题 + +漏洞描述 +==== +QEMU(quick emulator)是一款由Fabrice Bellard等人编写的免费的可执行硬件虚拟化的开源托管虚拟机。其与Bochs,PearPC类似,但拥有高速(配合KVM),跨平台的特性。QEMU通过动态的二进制转换,模拟CPU,并且提供一组设备模型,使其能够运行多种未修改的客户机OS。通过QEMU与KVM一起使用,可以实现以接近本地速度来运行虚拟机,被广泛应用到虚拟化和云计算场景中。 + +近日360公司发现QEMU USB控制器模拟源代码hw/usb/core.c之中存在数组越界读写的问题,攻击者可以利用该漏洞获得qemu用户的执行权限进而实现**完整的QEMU虚拟机逃逸**。(CVE-2020-14364) + + +漏洞分析 +==== +* 经过分析,该漏洞存在于USB控制器模拟代码usb_process_one中,s->setup_len未经验证就赋值可能会引入的数组越界读写的风险 。由于libvirt启动的虚拟机默认会有配置有usb设备,而任何usb控制器(如uhci,ehci,xhci)与usb设备(如usb-tablet,usb-mouse等)之间交互都会经过core.c文件中的usb_process_one函数,因此理论上只要虚拟机有使用usb设备都存在漏洞攻击的风险。 此外,usb_process_one函数中可能进入的两个分支do_parameter和do_token_setup均存在该问题,即:**在检查最终需要使用的数组长度前已经提前设置了该数组长度(s->setup_len)**。 +* 该漏洞的影响后果**非常严重**,因为攻击者可以利用该漏洞实现任意地址读取和写入,从而获得qemu进程的所有权限从而实现**虚拟机逃逸**,实现恶意代码执行攻击。此外,如果qemu进程处于root用户组那么攻击者就可以完整获得操作系统的控制权进而执行任意linux系统命令! + +代码分析 +---- + +```c++ +static void do_token_setup(USBDevice *s, USBPacket *p) +{ + int request, value, index; + + if (p->iov.size != 8) { + p->status = USB_RET_STALL; + return; + } + + usb_packet_copy(p, s->setup_buf, p->iov.size); + s->setup_index = 0; + p->actual_length = 0; + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; //先对s->setup_len赋值 + if (s->setup_len > sizeof(s->data_buf)) { // 后对setup_len进行合法性校验 + fprintf(stderr, + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; + return; + } +``` + +```c++ +static void do_parameter(USBDevice *s, USBPacket *p) +{ + int i, request, value, index; + + for (i = 0; i < 8; i++) { + s->setup_buf[i] = p->parameter >> (i*8); + } + + s->setup_state = SETUP_STATE_PARAM; + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; //先对s->setup_len赋值 + s->setup_index = 0; + + request = (s->setup_buf[0] << 8) | s->setup_buf[1]; + value = (s->setup_buf[3] << 8) | s->setup_buf[2]; + index = (s->setup_buf[5] << 8) | s->setup_buf[4]; + + if (s->setup_len > sizeof(s->data_buf)) { // 后对setup_len进行合法性校验 + fprintf(stderr, + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; + return; + } +``` + +通过代码可以看到:do_token_setup以及do_parameter两个函数中,都在对s->setup_len做检查之前就设置了具体内容,并且当s->setup_len超出预定buffer大小之后,也没有对其进行更改,这使得其中被污染的数据依旧可以完成之后的越界读写功能。 + +影响性分析 +---- +1. 影响范围 + QEMU 1.x 至今的QEMU的版本源代码之中均存在该漏洞,其中也包括了openEuler社区之前所使用的QEMU的代码。 +2. 触发条件 + 触发该漏洞需要虚拟机至少连接有一个usb设备,而多数情况下libvirt会默认为虚拟机配置USB设备。 + +漏洞修复方法 +---- + +根据360给出的修复方案,当检测到setup_len非法之后,将s->setup_len清零表示丢弃buffer中的USB请求,同时将USB的状态设置为SETUP_STATE_ACK,重新开始接受其他请求。补丁内容为: + +```c +Subject: [PATCH] hw/usb/core.c fix buffer overflow + +Store calculated setup_len in a local variable, verify it, + and only write it to the struct (USBDevice->setup_len) in case it passed the + sanity checks. + +This prevents other code (do_token_{in,out} function specifically) +from working with invalid USBDevice->setup_len values and overruning +the USBDevice->setup_buf[] buffer. +Store +Fixes: CVE-2020-14364 +Signed-off-by: Gred Hoffman +--- + hw/usb/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 5abd128b..12342f13 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -144,6 +144,8 @@ static void do_token_setup(USBDevice *s, USBPacket *p) + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; ++ s->setup_len = 0; ++ s->setup_state = SETUP_STATE_ACK; + return; + } + +@@ -277,6 +279,8 @@ static void do_parameter(USBDevice *s, USBPacket *p) + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; ++ s->setup_len = 0; ++ s->setup_state = SETUP_STATE_ACK; + return; + } + +-- +``` + + + + +## 解决方案 + +* 下载openEuler发布最新的qemu软件包: + * [漏洞SA](https://cve.openeuler.org/#/infoDetails/openEuler-SA-2020-1061) + * [aach64架构qemu软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/aarch64/Packages) + * [x86架构qemu软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/x86_64/Packages) +* 升级qemu软件包 + + * rpm -Uvh qemu-*.rpm +* 升级完成之后查看qemu软件包的release号码,当release号大于17表示漏洞修复成功。 + + * rpm -qi qemu-4.1.0 + + ``` + Name : qemu + Epoch : 2 + Version : 4.1.0 + Release : 18.oe1 + Architecture: aarch64 + Install Date: Mon 10 Aug 2020 04:53:20 PM CST + Group : Unspecified + Size : 19468602 + License : GPLv2 and BSD and MIT and CC-BY + Signature : RSA/SHA1, Thu 09 Jul 2020 11:52:58 AM CST, Key ID d557065eb25e7f66 + Source RPM : qemu-4.1.0-14.oe1.src.rpm + Build Date : Thu 09 Jul 2020 11:44:23 AM CST + Build Host : obs-worker-004 + Packager : http://openeuler.org + Vendor : http://openeuler.org + URL : http://www.qemu.org + ``` + + + +FAQ +==== +1. OpenEuler社区对此漏洞采取了什么措施? + 社区相关人员得知漏洞之后,立刻制作出了相对应的补丁,并且第一时间将补丁合入社区相关分支之中。 +2. 如何获取该漏洞的具体复现场景? + 可以参考360在ISC2020第八届互联网安全大会上的分享: + * https://isc.360.com/2020/detail.html?vid=108 + * https://www.anquanke.com/post/id/215405 diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-1.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-1.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..fc75cfa0853e44c4058642c0bf36d9f0e183543d Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-1.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-10.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-10.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..242aa4049fe845792482628182b7460eb5c00401 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-10.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-11.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-11.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1f402689d79f9784cc3a8d41a99c49a2c595e7fb Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-11.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-12.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-12.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..e309e58bda3320248d1e2cf8240686e526ab6ad2 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-12.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-13.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-13.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..8134f335e705f1ff2800221908ead449ba25a25c Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-13.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-2.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-2.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..8aa50cc47c5e5e412bc14ae7a9b352f04ed741fe Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-2.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-3.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-3.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..cb66c5f3047d716a35a7c4d1917b8466bed44522 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-3.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-4.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-4.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..87a25cc2e31bf564039058b22a1ee00a9348aaa4 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-4.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-5.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-5.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..cb2a67f92641b9704f5fa2c066c82e075a50f2b5 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-5.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-6.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-6.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2ba9afce32f9d393da9f2175759e625b74efb27d Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-6.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-7.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-7.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a7cf0b9b4baf6ced67aae68d38d55f233c724bc2 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-7.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-8.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-8.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ee2194ac991b1a04aefe753d3c270d8684977f0c Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-8.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-9.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-9.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ce9a5f435179b6415f2bb3e57a5126f5b69f0689 Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220-9.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220.md" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..cfab60d82e33f098d60aa84fd49b491bb25c0ec2 --- /dev/null +++ "b/web-ui/docs/zh/blog/lijiajie128/2020-11-03-ELF\346\226\207\344\273\266\346\240\274\345\274\217\350\247\243\346\236\220.md" @@ -0,0 +1,157 @@ +--- +title: ELF文件格式解析 +date: 2020-11-02 +tags: + - ELF + - 可执行文件格式 +archives: 2020-11 +author: Jiajie Li +summary: 讲解ELF文件格式 +--- + +# ELF文件格式解析 +编译器编译源代码之后生成的文件叫做**目标文件**。目标文件从结构上来说,和可执行文件已经没有区别了,只是其还没有经过链接过程,其中的部分符号和地址还没有被调整。 + +**可执行文件格式**涵盖了程序的编译、链接、装载和执行的方方面面,了解可执行文件格式对于认识操作系统、了解程序运行背后的机理很有帮助。 + +目前Linux平台上可执行文件格式是ELF(Executable and Linkable Format,类似Windows平台上的exe文件格式),本文就对ELF文件的格式进行讲解。 + + +示例程序 +==== +为了方便大家理解入门,这里以一个简单的C语言程序为例,来逐一对应ELF中的各部分: +```c +#include + +void say_hello(char *who) +{ + printf("hello, %s!\n", who); +} + +char *my_name = "wb"; + +int main() +{ + say_hello(my_name); + return 0; +} +``` +我们将其编译生成名为app的可执行程序并运行: +```shell +linux-XqAfQZ:~/tmp_analyze_elf # gcc -o app main.c +linux-XqAfQZ:~/tmp_analyze_elf # ./app +hello, wb! +``` + +ELF整体布局 +==== +ELF格式可以表达四种类型的二进制对象文件(object files): + 1. 可重定位文件(relocatable file,就是大家平常见到的.o文件) + 2. 可执行文件(executable file, 例上述示例代码生成的app文件) + 3. 共享库文件(shared object file,就是.so文件,用来做动态链接) + 4. 核心转储文件(core dump file,就是core dump文件) + +可重定位文件用在编译和链接阶段;可执行文件用在程序运行阶段;共享库则同时用在编译链接和运行阶段。在不同阶段,我们可以用不同视角来理解ELF文件,整体布局如下图所示: + + + +从上图可见,ELF格式文件整体可分为四大部分: + * ELF Header, ELF头部,定义全局性信息 + * Program Header Table, 描述段(Segment)信息的数组,每个元素对应一个段;通常包含在可执行文件中,可重定文件中可选(通常不包含) + * Segment and Section,段(Segment)由若干区(Section)组成;段在运行时被加载到进程地址空间中,包含在可执行文件中;区是段的组成单元,包含在可执行文件和可重定位文件中 + * Section Header Table,描述区(Section)信息的数组,每个元素对应一个区;通常包含在可重定位文件中,可执行文件中为可选(通常包含) + + + +ELFHeader实例解析 +==== +ELF规范中对ELF Header中各字段的定义如下所示: + + + +接下来我们通过readelf -h命令来看看示例程序app中的ELF Header内容,显示结果如下图: + + + + * **e_ident**含前16个字节,又可细分成class、data、version等字段,具体含义不用太关心,只需知道前4个字节点包含”ELF”关键字,这样可以判断当前文件是否是ELF格式; + * **e_type**表示具体ELF类型,可重定位文件/可执行文件/共享库文件,显然这里是一个可执行文件;e_machine表示执行的机器平台,这里是x86_64; + * **e_version**表示文件版本号,这里的1表示初始版本号; + * **e_entry**对应”Entry point address”,程序入口函数地址,通过进程虚拟地址空间地址(0x400440)表达; + * **e_phoff**对应“Start of program headers”,表示program header table在文件内的偏移位置,这里是从第64号字节(假设初始为0号字节)开始; + * **e_shoff**对应”Start of section headers”,表示section header table在文件内的偏移位置,这里是从第4472号字节开始,靠近文件尾部; + * **e_flags**表示与CPU处理器架构相关的信息,这里为零; + * **e_ehsize**对应”Size of this header”,表示本ELF header自身的长度,这里为64个字节,回看前面的e_phoff为64,说明ELF header后紧跟着program header table; + * **e_phentsize**对应“Size of program headers”,表示program header table中每个元素的大小,这里为56个字节; + * **e_phnum**对应”Number of program headers”,表示program header table中元素个数,这里为9个; + * **e_shentsize**对应”Size of section headers”,表示section header table中每个元素的大小,这里为64个字节; + * **e_shnum**对应”Number of section headers”,表示section header table中元素的个数,这里为30个; + * **e_shstrndx**对应”Section header string table index”,表示描述各section字符名称的string table在section header table中的下标,详见后文对string table的介绍。 + +Program Header Table实例解析 +==== +Program Header Table是一个数组,每个元素叫Program Header,规范对其结构定义如下: + + + +同样我们用readelf -l命令查看示例程序的program header table: + + + +上图截取了readelf命令返回的上半部,我们重点看下前面几项: + * **PHDR**,此类型header元素描述了program header table自身的信息。从这里的内容看出,示例程序的program header table在文件中的偏移(Offset)为0x40,即64号字节处;该段映射到进程空间的虚拟地址(VirtAddr)为0x400040;PhysAddr暂时不用,其保持和VirtAddr一致;该段占用的文件大小FileSiz为00x1f8;运行时占用进程空间内存大小MemSiz也为0x1f8;Flags标记表示该段的读写权限,这里”R E”表示可读可执行,说明本段属于代码段;Align对齐为8,表明本段按8字节对齐。 + * **INTERP**,此类型header元素描述了一个特殊内存段,该段内存记录了动态加载解析器的访问路径字符串。示例程序中,该段内存位于文件偏移0x238处,即紧跟program header table;映射的进程虚拟地址空间地址为0x400238;文件长度和内存映射长度均为0x1c,即28个字符,具体内容为”/lib64/ld-linux-x86-64.so.2”;段属性为只读,并按字节对齐; + * **LOAD**,此类型header元素描述了可加载到进程空间的代码段或数据段:第三项为代码段,文件内偏移为0,映射到进程地址0x400000处,代码段长度为0x764个字节,属性为只读可执行,段地址按2M边界对齐;第四段为数据段,文件内偏移为0xe10,映射到进程地址为0x600e10处(按2M对齐移动),文件大小为0x230,内存大小为0x238(因为其内部包含了8字节的bss段,即未初始化数据段,该段内容不占文件空间,但在运行时需要为其分配空间并清零),属性为读写,段地址也按2M边界对齐。 + * **DYNAMIC**,此类型header元素描述了动态加载段,其内部通常包含了一个名为”.dynamic”的动态加载区;这也是一个数组,每个元素描述了与动态加载相关的各方面信息,我们将在动态加载中介绍。该段是从文件偏移0xe28处开始,长度为0x1d0,并映射到进程的0x600e28;可见该段和上一个数据段是有重叠的。 + +readelf命令返回内容的下半部分给出了各段(segment)和各区(section)之间的包含关系,如下图所示。INTERP段只包含了”.interp”区;代码段包含”.interp”、”.plt”、”.text”等区;数据段包含”.dynamic”、”.data”、”.bss”等区;DYNAMIC段包含”.dynamic”区。从这里可以看出,有些区被包含在多个段中。 + + + +Section Header Table实例解析 +==== +针对各区的描述信息由Section Header Table提供,该数组中每个元素的定义如下: + + + +下面我们再通过readelf -S命令看看示例程序中section header table的内容,如下图所示。示例程序共生成30个区,Name表示每个区的名字,Type表示每个区的功能,Address表示每个区的进程映射地址,Offset表示文件内偏移,Size表示区的大小,EntSize表示区中每个元素的大小(如果该区为一个数组的话,否则该值为0),Flags表示每个区的属性(参见图中最后的说明),Link和Info记录不同类型区的相关信息(不同类型含义不同,具体参见规范),Align表示区的对齐单位。 + + + +String Table实例解析 +==== +从上述Section Header Table示例中,我们看到有一种类型为STRTAB的区(在Section Header Table中的下标为6,27,29)。此类区叫做String Table,其作用是集中记录字符串信息,其它区在需要使用字符串的时候,只需要记录字符串起始地址在该String Table表中的偏移即可,而无需包含整个字符串内容。 + +我们使用readelf -x读出下标27区的详细内容观察: + + + +红框内为该区实际内容,左侧为区内偏移地址,后侧为对应内容的字符表示。我们可以发现,这里其实是一堆字符串,这些字符串对应的就是各个区的名字。因此section header table中每个元素的Name字段其实是这个string table的索引。再回头看看ELF header中的e_shstrndx,它的值正好就是27,指向了当前的string table。 + +同理再来看下29区的内容,如下图所示。这里我们看到了”main”、”say_hello”字符串,这些是我们在示例中源码中定义的符号,由此可以29区是应用自身的String Table,记录了应用使用的字符串。 + + + +Symbol Table实例解析 +==== +Section Header Table中,还有一类SYMTAB(DYNSYM)区,该区叫符号表。符号表中的每个元素对应一个符号,记录了每个符号对应的实际数值信息,通常用在重定位过程中或问题定位过程中,进程执行阶段并不加载符号表。符号表中每个元素定义如下:name表示符号对应的源码字符串,为对应String Table中的索引;value表示符号对应的数值;size表示符号对应数值的空间占用大小;info表示符号的相关信息,如符号类型(变量符号、函数符号);shndx表示与该符号相关的区的索引,例如函数符号与对应的代码区相关。 + + + +我们用readelf -s读出示例程序中的符号表,如下图所示。如红框中内容所示,我们示例程序定义的main函数符号对应的数值为0x400554,其类型为FUNC,大小为26字节,对应的代码区在Section Header Table中的索引为13;say_hello函数符号对应数值为0x400530,其类型为FUNC,大小为36字节,对应的代码区也为13。 + + + +代码段实例解析 +==== +在理解了String Table和Symbol Table的作用后,我们通过objdump反汇编来理解一下.text代码段: + + + +这里截取了与示例程序相关部分,我们看到0x400530和0x400554两处各定义一个函数,其符号分别为say_hello和main,这部分信息实际是通过符号表解析而来的;在涉及到内存地址的指令中,除了对数据段地址的引用是通过绝对地址进行的之外,对于代码段地址的引用都是以相对地址的方式进行的,这样做的好处是在二进制文件的重定位过程中,我们不用修改指令的访问地址(因为相对地址保持不变);最后,我们看到对于库函数printf的访问指向了代码段地址0x400410,那么这个地址处放的是printf函数么?要回答这个问题就涉及**动态链接**,我们将在下文专题分析。 + +总结 +==== +通过以上的定义以及示例讲解,相信大家已经对ELF的文件格式有所了解了,如果想要继续深挖ELF文件的细节,大家可以参考以下这些资料。 +1. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +2. https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/ +3. https://refspecs.linuxfoundation.org/elf/elf.pdf diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-1.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-1.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ba41717707865351758d3456584614df18b8ddfd Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-1.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-2.jpg" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-2.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..e76c66b009899459835d5d174f80f0f01a7c894a Binary files /dev/null and "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245-2.jpg" differ diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245.md" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245.md" new file mode 100644 index 0000000000000000000000000000000000000000..e7154eb630ff7beaa388927e0d0cb0de43642227 --- /dev/null +++ "b/web-ui/docs/zh/blog/lijiajie128/2020-11-09-\351\235\231\346\200\201\351\223\276\346\216\245\344\270\216\345\212\250\346\200\201\351\223\276\346\216\245.md" @@ -0,0 +1,142 @@ +--- +title: 静态链接与动态链接 +date: 2020-11-09 +tags: + - 静态链接 + - 动态链接 + - 知识图谱 +archives: 2020-11 +author: Jiajie Li +summary: 讲解静态链接与动态链接的大致流程 +--- +# 静态链接与动态链接 +自顶向下的思考逻辑 +---- +通过之前的《ELF文件格式解析》,我们对ELF目标文件有了大致的印象和了解。那么接下来的问题就是:**我们如何将编译得到的多个目标文件链接形成一个可执行文件?** + +因为可执行文件中的每一条指令都需要一个明确的地址,因此链接的任务就是为可执行文件确定这些地址。从这个角度出发,我们不难发现链接器的主要任务就是以下三者: + + 1. 为多个目标文件分配地址空间 + 2. 明确每个符号的定义以及引用 + 3. 修改需要更新地址的指令 + +以上三个步骤其实就对应了链接过程中的**地址空间分配**、**符号解析**与**符号重定位**。这其中的符号解析与符号重定位通常都是在一起完成的,因此这套处理逻辑也被称为**两步链接(Two-pass Linking)**。 + + +根据为目标文件分配地址空间方式的不同,我们可以将链接方式分为静态链接和动态链接。接下来就仔细讲解这两者的相关细节。 + +静态链接 +---- +静态链接就是在程序运行前,链接器通过对象文件中包含的重定位表,完成所有重定位操作,并最终形成一个在运行时不需要再次进行依赖库的加载和重定位操作(因为所有的依赖库在运行前都被链接到程序中了)。 + +以下面的图来简单说明一下由静态链接得到可执行文件的过程。根据在源文件中包含的头文件和程序中使用到的库函数,如stdio.h中定义的printf()函数,在libc.a中找到目标文件printf.o(这里暂且不考虑printf()函数的依赖关系),然后将这个目标文件和我们hello.o这个文件进行静态链接得到我们的可执行文件。 + + + +静态链接使得不同的程序开发者以及团队之间可以相对独立地进行自己程序模块的开发和测试,从某种意义上来说这极大地促进了程序开发的效率;并且由于静态链接使得可执行程序已经具备了程序执行的所有条件,可执行文件在执行时的运行速度很快。 + +但是静态链接对于计算机的内存和磁盘空间浪费极其严重。大家可以思考一下,对于多进程的操作系统来说,每个进程都会使用到很多公有静态库的函数,例如printf()函数、scanf()函数。静态链接就会导致系统内存以及磁盘空间之中都存在多份重复的公有库函数目标文件,空间浪费极大。 + +此外静态链接的另一个问题就在于程序更新升级困难。因为一个可执行文件所需要的目标文件更新之后,我们就需要重新链接整个可执行文件,这对于用户来说是非常不方便的。 + +要解决以上两个问题,最简单的办法就是将程序所需的各个模块分割开来,等到程序真正运行的时候才进行链接。这就是动态链接的基本思想。 + +动态链接 +---- +动态链接指的是主程序对动态共享库或对象中符号的引用,是等到程序运行后再加载并进行重定位操作。程序的主体部分也称为主程序还是静态链接的,这部分链接是不会将依赖的动态共享库或对象链接进主程序的。 + +由于动态链接涉及到了运行时链接以及多个文件的装载,这些步骤都必须要操作系统支持。而目前主流的操作系统都支持动态链接,在Linux系统中,ELF动态链接文件被称为动态共享对象(DSO,Dynamic Shared Objects),文件名一般都是以“.so”结尾;而在Window系统中,动态链接文件被称为动态共享库(Dynamic Linking Library),文件名一般都是以“.dll”结尾。 + +我们可以通过一个简单的例子来说明Linux上动态链接的大致流程。我们需要用到三个源文件:hello.c、lib.c、lib.h + +```c++ +/* hello.c file */ +#include "lib.h" +int main(){ + printInLib(1); + return 0; +} +``` + +```c++ +/* lib.c file */ +#include +void printInLib(int i){ + printf("Hello from lib %d\n", i); + return 0; +} +``` + +```c++ +/* lib.h file */ +#inndef LIB_H +#define LIB_H + +void printInLib(int i); + +#endif +``` + +演示程序很简单,hello.c调用lib.c中的printInLib函数,打印传进去的一个数字。我们首先使用以下命令将lib.c和lib.h编译成DSO。 + +```shell +gcc -fPic -shared -o Lib.so lib.c +``` + +此时我们得到一个Lib.so文件,然后我们进一步来编译hello.c文件,命令如下: +```shell +gcc -o hello hello.c ./Lib.so +``` + +这样我们就得到了一个可执行文件hello,整个编译以及链接的过程如下图所示: + + + +我们可以发现,当hello.c被编译为hello.o的时候,链接器需要明确printInLib的地址。因此链接器需要Lib.so作为输入,为hello提供完整的符号信息。 + +这里需要注意一点:此处所说的链接器指的是静态链接器,而非程序运行时所需的动态链接器。 + +通过这个简单的例子,我们基本了解了动态链接的概念,但是我们立马就会遇到一个问题:目标程序运行时,我们该如何确定动态共享对象的地址呢? + +早期的操作系统采用了一种称之为“静态共享库(Static Shared Library)”的方式,也就是将所有程序的共享库交由操作系统来管理,由操作系统在某个特定地址划分出一块地址,然后根据这些地址来进行符号重定位。 + +但是这种方法会带来一个严重的问题:地址冲突。假设一个程序A需要用到共享库1和共享库2,而程序B需要用到共享库1和共享库3,但是操作系统依旧会为共享库1、2、3分配地址,而这就意味着程序A不能使用共享库3所占用的那块地址,程序B不能使用共享库2所占用的地址。这种情况会随着程序以及共享库的增多变得越来越严重,合理分配的可行性几乎为零。 + +为了解决这个问题,我们就需要思考如何实现动态共享对象在任意地址加载?此时我们就可以参考静态链接中的重定位操作:对所有绝对地址的引用都不做重定位操作,当目标程序装载完成之后,再进行绝对地址的修改。静态链接时的重定位就被称之为链接时重定位,此时的重定位被称为**装载时重定位**。 + +装载重定位可以很好地解决地址冲突的问题,但是其存在一个很大的缺点:DSO中一部分需要修改的指令无法在多个进程之间共享,这就失去了动态链接节约内存的优势。为了解决这个问题,出现了一种被称为**地址无关代码(PIC/Position Independent Code)**的解决办法。 + +PIC的核心思想就是将DSO中需要修改的那部分指令分离出来,和数据部分放在一起;不需要修改的指令保持不变,需要修改的指令和数据可以在每个进程中拥有一个副本。怎么做到这一点呢?模块内的变量以及函数访问很简单,我们可以采用相对地址访问以及相对跳转来解决问题。 + +但是对于模块间的变量以及函数访问,该怎么办呢?此时我们可以想到计算机界的那句名言“任何问题都可以通过添加一个中间层来解决”,我们可以为这些变量以及函数创建一个全局偏移量表(GOT/Global Offset Table),通过GOT表来跳转,从而实现地址无关代码。到这一步之后,动态链接已经基本实现了我们当初所期望的优势:可以更加灵活、节约内存以及磁盘空间、更有利于升级维护。 + +总结 +---- +编译是将用编程语言所写的源文件通过词法分析、语法分析、语义分析、源代码优化、目标代码生成、目标代码优化这6个步骤生成得到汇编语言所对应的目标文件。 + +链接器则是综合了各个目标文件的符号信息,进行了地址空间分配、符号解析、符号重定位操作,最终生成得到可执行程序。根据链接过程的不同处理办法,链接可以被分为静态链接和动态链接。 + ++ 静态链接优点 + + 代码装载速度快,执行速度略比动态链接快。 + + 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱问题。 ++ 静态链接缺点 + + 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成内存以及磁盘空间浪费。 + ++ 动态链接优点 + + 更加节省内存并减少页面交换。 + + DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性。 + + 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数。 + + 适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。 ++ 动态链接缺点 + + 可执行文件的运行速度比静态链接略慢。 + + 使用动态链接库的应用程序不是自完备的,如果可执行文件所需的动态库不存在,程序就无法正确执行。 + +参考资料 +---- +1. 《程序员的自我修养——链接、装载与库》 +2. https://en.wikipedia.org/wiki/Static_library +3. https://en.wikipedia.org/wiki/Dynamic-link_library + + + + diff --git "a/web-ui/docs/zh/blog/lijiajie128/2020-11-10-\345\212\250\346\200\201\351\223\276\346\216\245\344\270\255\347\232\204PLT\344\270\216GOT.md" "b/web-ui/docs/zh/blog/lijiajie128/2020-11-10-\345\212\250\346\200\201\351\223\276\346\216\245\344\270\255\347\232\204PLT\344\270\216GOT.md" new file mode 100644 index 0000000000000000000000000000000000000000..4bc2bf9e6478158d27f4b9e5fc554f524ce3e0f7 --- /dev/null +++ "b/web-ui/docs/zh/blog/lijiajie128/2020-11-10-\345\212\250\346\200\201\351\223\276\346\216\245\344\270\255\347\232\204PLT\344\270\216GOT.md" @@ -0,0 +1,141 @@ +--- +title: 动态链接中PLT与GOT工作流程 +date: 2020-11-10 +tags: + - 动态链接 + - PLT + - 延迟绑定 + - 知识图谱 +archives: 2020-11 +author: Jiajie Li +summary: 讲解动态链接中PLT与GOT工作流程 +--- +# 动态链接中PLT与GOT工作流程 +前言 +---- +在之前的《静态链接与动态链接》中,我们介绍了这两者的优缺点:动态链接的缺点主要就是动态链接的程序执行速度会比静态链接的程度略慢一些。 + +原因就在于动态链接的可执行程序对于模块间的变量以及函数访问,都需要通过GOT表进行间接跳转。如此一来,程序的运行速度肯定会有所减慢。 + +另一个很重要的原因就是动态链接的链接工作是在程序运行时来完成的,即程序开始执行前动态链接器会去寻找并且装载程序所需的动态共享对象,然后完成一系列的符号重定位操作。这部分动作肯定会减慢程序的启动速度 + +针对这种情况,一种称为“**延迟绑定(Lazy Binding)**”的解决办法出现了。延迟绑定的核心思想就是在程序启动时并不完成所有模块间函数调用的符号重定位操作,只有当目标程序需要调用某个模块外函数时才进行地址绑定(即符号查找、符号重定位)。 + +要实现以上的目标,ELF文件采用了**PLT(PProcedure Linkage Table)**的结构,这种结构内包含了一些很精妙的指令序列,这也是本文接下来所要讲解的内容。 + +大体逻辑思考 +---- +在讲解PLT具体细节之前,我们可以从自顶向下的角度来思考一下如何完成这一项工作。假设目标程序需要调用某个动态共享对象liba.so内的函数foo(),那么第一次调用该函数的时候,动态链接器就需要一个寻找foo函数地址的查找函数来完成绑定的工作。 + +那么这个查找函数需要哪些信息呢?首先要知道绑定行为发生在哪个模块内(目标程序主模块内),其次我们要知道具体要绑定哪个函数(foo()函数)。在Glibc中,这个查找函数的名字就叫做_dl_runtime_resolve()。把这个过程用伪代码描述出来,就如以下所示: + +```c++ + void DSOFunction@plt() + { + if (DSOFunction@got[index] != RELOCATED) { + //如果该函数是第一次调用,GOT表内还没有该函数的地址 + 让查找函数根据模块ID和被调用函数的ID来获取被调用函数的地址 + 并且填入GOT的对应表项之中 + DSOFunction@got[index] = RELOCATED; + } + else{ + //GOT表内已经有了该函数地址,直接跳转到该函数地址 + jmp *DSOFunction@got[index]; + } + } +``` + +这一段伪代码就是PLT结构之中的模块外函数的对应表项。将伪代码整理一下,我们就可以得到汇编语言级别的PLT表项的内容,如下所示: + +```asm + foo@plt + jmp *(foo@got) + push n + push moduleID + jmp _dl_runtime_resolve +``` + +第一条指令就是跳转到foo()函数所对应的GOT表项,如果该GOT表项已经被绑定好了,那就可以直接跳转到正确的函数地址。如果是第一次调用该函数,其GOT表项内的内容是第二条指令“push n”的地址,这一步就实现伪代码中的if判断。 + +第二条指令就是将foo()函数所对应的函数ID压入栈内,这个ID是foo函数在重定位表中的下标。第三条指令就是将该模块的ID压入栈中,第四条指令就是跳转到我们上文所说的查找函数_dl_runtime_resolve()。_dl_runtime_resolve()进行一系列查找之后,会将foo()函数的绝对地址填入GOT的对应表项中,然后将控制流转到foo()函数上。 + +一旦foo()函数地址被成功绑定,之后再次调用foo在PLT的表项,就是直接通过GOT表项跳转到正确的地址上。以上就是GOT和PLT出现的大体逻辑。接下来讲解具体的工作流程。 + + +具体工作流程 +---- +ELF文件将GOT分为两部分,分别是.GOT和.GOT.PLT,前者用于储存全局变量,后者用于保存DSO中的函数引用地址。这里要说明一点:PLT位于可执行程序的代码段,是可读不可写的;而GOT位于可执行程序的数据段,是可读可写的。另外.GOT.PLT还有一个特别之处在于它的前三项都是有特定含义的,含义分别如下所示: + +1. 第一项保存了.dynamic段的地址,这其中描述了本模块动态链接的相关信息 +2. 第二项保存本模块的ID +3. 第三项保存了_dl_runtime_resolve的地址 + +以上几项的特殊含义就是链接器的**精妙之处**了:它将各个plt表项中的公共部分抽取出来,形成了一个可复用的公共指令序列。 + +因此实际上PLT的汇编代码结构是下面这样的: +```asm + plt[0] + push *got[1] + push *got[2] + + ··· + + foo@plt + jmp *(foo@got) + push n + jmp plt[0] +``` + +明白了大体逻辑之后,我们就来看看实际例子来看看。以下是一个简单的helloworld可执行文件的.PLT以及.GOT。 + +```asm + Disassembly of section .plt: + + 00000000004003f0 <.plt>: + 4003f0: ff 35 12 0c 20 00 pushq 0x200c12(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> + 4003f6: ff 25 14 0c 20 00 jmpq *0x200c14(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> + 4003fc: 0f 1f 40 00 nopl 0x0(%rax) + + 0000000000400400 : + 400400: ff 25 12 0c 20 00 jmpq *0x200c12(%rip) # 601018 + 400406: 68 00 00 00 00 pushq $0x0 + 40040b: e9 e0 ff ff ff jmpq 4003f0 <.plt> + + 0000000000400410 <__libc_start_main@plt>: + 400410: ff 25 0a 0c 20 00 jmpq *0x200c0a(%rip) # 601020 <__libc_start_main@GLIBC_2.2.5> + 400416: 68 01 00 00 00 pushq $0x1 + 40041b: e9 d0 ff ff ff jmpq 4003f0 <.plt> + ... + + + Disassembly of section .got: + + 0000000000600ff8 <.got>: + ... + + + Disassembly of section .got.plt: + + 0000000000601000 <_GLOBAL_OFFSET_TABLE_>: + ... +``` + +参考以上反汇编得到的代码,我们不难发现.plt有三个表项: + +1. 也就是.plt[0],首先将GOT表的第二项,即.GOT.PLT[1]压栈,然后跳转到.GOT.PLT[2],最后一条nop指令啥也不干 +2. 也就是.plt[1],首先跳转到.GOT.PLT[3],然后将0x0压栈,最后跳转回到.plt[0] +3. 也就是.plt[2],首先跳转到.GOT.PLT[4],然后将0x1压栈,最后跳转回到.plt[0] + +可以看到,以上指令的逻辑和我们在上文所分析是完全一致的。相关函数执行完之后,会将被调用函数的地址填入GOT表内,并且将程序执行流转给被调用函数,使程序继续执行下去。 + +总结 +---- +最后我们来总结一下PLT以及GOT的具体流程: + +1. 首先可执行程度在编译时就会做“编译重定位”,将模块外的函数的引用指向其对应的PLT表项之中,并且用PLT表项第二条指令的地址来初始化其对应的GOT表项。 +2. 当程序被启动时,动态链接器会从内核接过权限,更新GOT表中本模块ID以及_dl_runtime_resolve的地址。 +3. 当模块外函数被调用时,程序就会跳转到其对应的PLT表项,PLT表项进一步跳转到GOT表项中 +4. 如果GOT表项是函数地址,那就是直接调用该函数,程序控制流转移给被调用函数 +5. 如果GOT表项是第一次被调用,那就跳转到PLT表项的第二条指令,然后将函数ID以及模块ID压栈,作为参数传给_dl_runtime_resolve,_dl_runtime_resolve执行完成之后,将调用函数的地址填入对应的GOT表项之中,然后将程序控制流转移给被调用函数 + +动态链接通过延迟绑定和PLT结构将程序的启动速度提升了一些,使得动态链接的可执行程序运行速度可以有所改善。以上就是PLT和GOT的大体逻辑以及工作流程,希望对大家的理解有所帮助! \ No newline at end of file diff --git "a/web-ui/docs/zh/blog/likejun/2020-11-30-perf\344\272\213\344\273\266\347\233\221\346\216\247\347\273\223\346\236\234-02.jpg" "b/web-ui/docs/zh/blog/likejun/2020-11-30-perf\344\272\213\344\273\266\347\233\221\346\216\247\347\273\223\346\236\234-02.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a21613f48d879cae474c36dbf73253c7bea3a1c4 Binary files /dev/null and "b/web-ui/docs/zh/blog/likejun/2020-11-30-perf\344\272\213\344\273\266\347\233\221\346\216\247\347\273\223\346\236\234-02.jpg" differ diff --git "a/web-ui/docs/zh/blog/likejun/2020-11-30-perf\345\267\245\344\275\234\346\250\241\345\274\217-01.jpg" "b/web-ui/docs/zh/blog/likejun/2020-11-30-perf\345\267\245\344\275\234\346\250\241\345\274\217-01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2864b8203a6b574fe743a529f50e7a6a12c2a6b0 Binary files /dev/null and "b/web-ui/docs/zh/blog/likejun/2020-11-30-perf\345\267\245\344\275\234\346\250\241\345\274\217-01.jpg" differ diff --git "a/web-ui/docs/zh/blog/likejun/2020-11-30-\347\201\253\347\204\260\345\233\276\345\256\236\344\276\213-03.jpg" "b/web-ui/docs/zh/blog/likejun/2020-11-30-\347\201\253\347\204\260\345\233\276\345\256\236\344\276\213-03.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..328c9c14720fcb2840729b0fba0c1bb059ea8884 Binary files /dev/null and "b/web-ui/docs/zh/blog/likejun/2020-11-30-\347\201\253\347\204\260\345\233\276\345\256\236\344\276\213-03.jpg" differ diff --git "a/web-ui/docs/zh/blog/likejun/2020-11-30-\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\350\260\203\344\274\230\345\267\245\345\205\267.md" "b/web-ui/docs/zh/blog/likejun/2020-11-30-\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\350\260\203\344\274\230\345\267\245\345\205\267.md" new file mode 100644 index 0000000000000000000000000000000000000000..2e93488940055b2e10bf0632d25064deb64bee2e --- /dev/null +++ "b/web-ui/docs/zh/blog/likejun/2020-11-30-\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\350\260\203\344\274\230\345\267\245\345\205\267.md" @@ -0,0 +1,269 @@ +--- +title: 虚拟机性能调优工具 +date: 2020-11-30 +tags: + - trace工具 + - perf工具 + - 火焰图 + - Linux常用的性能检测工具 +archives: 2020-11 +author: 李柯俊 +summary: 常见的虚拟机性能调优工具trace, perf和火焰图的使用方法,以及常见的Linux系统性能检测命令的使用参数介绍。 +--- + +## 虚拟机性能调优工具 + +# 1 trace工具 + +## 1.1 简介 + +顾名思义,trace即为追踪的意思,源码位于\kernel\trace\trace.c。该工具主要用来跟踪和记录系统内核相关信息,包括内核信息,内核拓展信息,用户程序等等,尤其是对系统调用,内核服务和中断处理有着详细记录。 + +该命令有三种工作模式:默认模式、单一模式和循环模式: + +1. 默认模式:该模式默认将trace的数据写入磁盘。 +2. 单一模式:该模式先将数据写入内存的缓冲区,待trace终止后写回磁盘;当缓冲区满了trace会自动停止。 +3. 循环模式:该模式也会将数据先写入内存,不同点是缓冲区满了之后会被循环利用覆盖之前的区域,直到输入“trcstop”命令才会停止trace,写到磁盘。 + +## 1.2 获取Trace数据 + +最常用的收集trace的命令作为例子:trace -a -l -T2000000 -L4000000 -o trace.out (2000000 和 4000000 只是一个例子) + +-a : 表示trace进程在后台运行(异步运行) +-l :表示trace工作在循环模式 +-o :指定trace输出文件的目录和文件名,默认的输出文件名为 /var/adm/ras/trcfile +-T :表示缓冲区的大小,单位为byte,默认值为128KB。 +-L :表示写到磁盘上的trace输出文件的大小,单位为byte,默认值为1MB。 + +# 2 perf工具 + +## 2.1 简介 + +perf (performance 的缩写),是 Linux 系统原生提供的性能分析工具,会返回 CPU 正在执行的函数名以及调用栈(stack)。 + +它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析,常用于性能瓶颈的查找与热点代码的定位。 + +CPU周期(cpu-cycles)是默认的性能事件,所谓的CPU周期是指CPU所能识别的最小时间单元,通常为亿分之几秒,是CPU执行最简单的指令时所需要的时间,例如读取寄存器中的内容,也叫做clock tick。 + +perf的具体原理是这样的:每隔一个固定的时间,就在CPU上(每个核上都有)产生一个中断,在中断上看看,当前是哪个pid,哪个函数,然后给对应的pid和函数加一个统计值,这样,我们就知道CPU有百分几的时间在某个pid,或者某个函数上了。工作模式类似下图: + + + +这是一种采样的模式,我们预期,运行时间越多的函数,被时钟中断击中的机会越大,从而推测,那个函数(或者pid等)的CPU占用率就越高。 + +## 2.2 常用子工具 + ++ perf-list + + Perf-list用来查看perf所支持的性能事件,主要分为三类: + + 1. Hardware Event 是由 PMU 硬件产生的事件,比如 cache 命中,当您需要了解程序对硬件特性的使用情况时,便需要对这些事件进行采样。 + + 2. Software Event 是内核软件产生的事件,比如进程切换,tick 数等。 + + 3. Tracepoint event 是内核中的静态 tracepoint 所触发的事件,这些 tracepoint 用来判断程序运行期间内核的行为细节,比如 slab 分配器的分配次数等。 + + hw/cache/pmu都是硬件相关的;tracepoint基于内核的ftrace;sw实际上是内核计数器。 + + > 使用方法:perf list [hw | sw | cache | tracepoint | event_glob] + ++ perf-stat + + 面对一个性能问题的时候,最好采用自顶向下的策略。先整体看看该程序运行时各种统计事件的大概,再针对某些方向深入细节。 + + 整体监测代码性能就需要使用perf stat这个工具,该工具主要是从全局上监控,可以看到程序导致性能瓶颈主要是什么原因。perf stat通过概括精简的方式提供被调试程序运行的整体情况和汇总数据。 + + 在默认情况下,perf stat会统计cycles、instructions、cache-misses、context-switches等对系统或软件性能影响最大的几个硬件和软件事件。通过这些统计情况,基本上就能了解软件的运行效率是受CPU影响较大还是IO影响较大,是受运算指令数影响较大还是内存访问影响较大。通过指令数、缓存访问数等统计还能大致判断软件性能是否符合对应的功能设计,是否有代码级优化的可能。 + + > 使用方法: + > + > perf stat [-e | --event=EVENT] [-a] + > + > perf stat [-e | --event=EVENT] [-a] - [] + + 即perf stat + 程序,程序运行完之后,然后使用**ctrl+c**来终止程序(若程序自动终止则不用),之后,perf便会打印出监控事件结果,类似如下所示: + + + + 1. 102.97 task-clock是指程序运行期间占用了xx的任务时钟周期,该值高,说明程序的多数时间花费在CPU计算上而非IO操作。 + + 2. 6 context-switches是指程序运行期间发生了xx次上下文切换,记录了程序运行过程中发生了多少次进程切换,频繁的进程切换是应该避免的。(有进程进程间频繁切换,或者内核态与用户态频繁切换) + + 3. 0 cpu-migrations 是指程序运行期间发生了xx次CPU迁移,即用户程序原本在一个CPU上运行,后来迁移到另一个CPU + + 4. 617 page-faults 是指程序发生了xx次页错误 + + 5. 其他可以监控的譬如分支预测、cache命中等 + ++ perf-top + + perf top可以用于观察系统和软件内性能开销最大的函数列表。通过观察不同事件的函数列表可以分析出不同函数的性能开销情况和特点,判断其优化方向。 + + 例如如果某个函数在perf top -e instructions中排名靠后,却在perf top -e cache-misses和perf top -e cycles中排名靠前,说明函数中存在大量cache-miss造成CPU资源占用较多,就可以考虑优化该函数中的内存访问次数和策略,来减少内存访问和cache-miss次数,从而降低CPU开销。 + + > 使用方法:perf top [-e | --event=EVENT] [] + > + > > 常用参数: + > > + > > -e :指明要分析的性能事件。 + > > + > > -p :Profile events on existing Process ID (comma sperated list). 仅分析目标进程及其创建的线程。 + > > + > > -k :Path to vmlinux. Required for annotation functionality. 带符号表的内核映像所在的路径。 + > > + > > -K:不显示属于内核或模块的符号。 + > > + > > -U:不显示属于用户态程序的符号。 + > > + > > -d :界面的刷新周期,默认为2s,因为perf top默认每2s从mmap的内存区域读取一次性能数据。 + > > + > > -g:得到函数的调用关系图。 + ++ perf-record/perf-report + + 收集采样信息,并将其记录在数据文件中。随后可以通过其它工具(perf-report)对数据文件进行分析,结果类似于perf-top。 + + > 使用方法:首先perf record记录并生成data文件,然后通过perf report显示。 + +# 3 火焰图 + +## 3.1 简介 + +整个图形看起来就像一团跳动的火焰,这也正是其名字的由来。燃烧在火苗尖部的就是 CPU 正在执行的操作,不过需要说明的是颜色是随机的,本身并没有特殊的含义,纵向表示调用栈的深度,横向表示消耗的时间。因为调用栈在横向会按照字母排序,并且同样的调用栈会做合并,所以一个格子的宽度越大越说明其可能是瓶颈。综上所述,主要就是看那些比较宽大的火苗,特别留意那些类似平顶山的火苗。 + +CPU火焰图中的每一个方框是一个函数,方框的长度,代表了它的执行时间,所以越宽的函数,执行越久。火焰图的楼层每高一层,就是更深一级的函数被调用,最顶层的函数,是叶子函数。 + +## 3.2 使用方法 + +1、Flame Graph项目位于GitHub上:https://github.com/brendangregg/FlameGraph + +2、可以用git将其clone下来:git clone https://github.com/brendangregg/FlameGraph.git + +我们以perf为例,看一下flamegraph的使用方法: + +1、第一步 + +> perf record -e cpu-clock -g -p `pidof xxx` + +Ctrl+C结束执行后,在当前目录下会生成采样数据perf.data. + +2、第二步 + +用perf script工具对perf.data进行解析 + +> perf script -i perf.data &> perf.unfold + +3、第三步(进入FlameGraph目录) + +将perf.unfold中的符号进行折叠: + +> ./stackcollapse-perf.pl perf.unfold &> perf.folded + +4、最后生成svg图: + +> ./flamegraph.pl perf.folded > perf.svg + + + +## 3.3 解析火焰图 + +火焰图是基于 stack 信息生成的 SVG 图片,用来展示 CPU 的调用栈。 + +y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数. + +x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的. + +火焰图就是看顶层的哪个函数占据的宽度最大。只要有 “平顶”(plateaus),就表示该函数可能存在性能问题。即火焰图就是看函数占据的宽度,宽度越大越可能存在性能问题。 + +# 4 Linux常用的性能检测工具 + +| 工具 | 功能描述 | +| ----------- | ---------------------- | +| uptime | 系统平均负载率 | +| dmesg | 硬件/系统信息 | +| top | 进程进行状态 | +| iostat | CPU和磁盘平均使用率 | +| vmstat | 系统运行状态 | +| sar | 实时收集系统使用状态 | +| free | 内存使用率 | +| traffic-vis | 网络监控(只有SUSE有) | +| pmap | 进程内存占用率 | +| strace | 追踪程序运行状态 | +| ulimit | 系统资源使用限制 | +| mpstat | 多处理器使用率 | + +* ### top + + **命令功能:** + + 显示当前系统正在执行的进程的相关信息,包括进程ID、内存占用率、CPU占用率等 + + **命令参数:** + + -b 批处理 + + -c 显示完整的治命令 + + -I 忽略失效过程 + + -s 保密模式 + + -S 累积模式 + + -i<时间> 设置间隔时间 + + -u<用户名> 指定用户名 + + -p<进程号> 指定进程 + + -n<次数> 循环显示的次数 + +* ### free + + **命令功能:** + + 显示系统已用及空余物理内存量、交换分区使用情况(swap memory)、内核占用的缓存、及共享内存。 + + **命令参数:** + + -b, –bytes, 以Byte为单位显示内存使用情况 + + -k, –kilo, 以KB为单位, 这也是默认值 + + -m, –mega, 以MB为单位显示内容使用情况 + + -g, –giga, 以GB为单位显示内存使用情况 + + -h, –human, 自动将数值转换为人类易读形式 + + -c, –count, 展示结果count次,需与-s配合使用 + + -s, –seconds, 动态刷新内存使用情况的间隔 + ++ ### iostat + + **命令功能:** + + 查看CPU、网卡、tty设备、磁盘、CD-ROM 等等设备的活动情况,负载信息。 + + **命令参数:** + + -C 显示CPU使用情况 + + -d 显示磁盘使用情况 + + -m 以 M 为单位显示 + + -k 以 KB 为单位显示 + + -N 显示磁盘阵列(LVM) 信息 + + -n 显示NFS 使用情况 + + -p[磁盘] 显示磁盘和分区的情况 + + -t 显示终端和CPU的信息 + + -x 显示详细信息 + + -V 显示版本信息 \ No newline at end of file diff --git "a/web-ui/docs/zh/blog/lingff/2021-04-18-OpenEuler\344\270\212A-Tune\347\232\204\347\256\200\345\215\225\344\275\277\347\224\250.md" "b/web-ui/docs/zh/blog/lingff/2021-04-18-OpenEuler\344\270\212A-Tune\347\232\204\347\256\200\345\215\225\344\275\277\347\224\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..9e736ee440e63418d599ea6a64fdda35bd634190 --- /dev/null +++ "b/web-ui/docs/zh/blog/lingff/2021-04-18-OpenEuler\344\270\212A-Tune\347\232\204\347\256\200\345\215\225\344\275\277\347\224\250.md" @@ -0,0 +1,176 @@ +--- +title: OpenEuler上A-Tune的简单使用 +date: 2021-04-18 +tags: + - A-Tune + - 调优 + - 智能 +archives: 2021-04 +author: lingff PKU +summary: OpenEuler上A-Tune的安装和简单使用,介绍A-Tune离线动态调优的流程。 +--- +# A-Tune是什么? +A-Tune是一款基于AI的操作系统性能调优引擎。A-Tune利用AI技术,使操作系统“懂”业务,简化IT系统调优工作的同时,让应用程序发挥出色性能。 +本次项目,主要尝试熟悉A-Tune离线动态调优的流程,目的是为一款应用实现调优。 +# 一、安装A-Tune +OS: openEuler 20.03 LTS SP1,从仓库源码安装: +1. 安装依赖系统软件包 + +```bash +yum install -y golang-bin python3 perf sysstat hwloc-gui +``` +2. 安装python依赖包 + +```bash +# A-Tune服务的依赖包 +yum install -y python3-dict2xml python3-flask-restful python3-pandas python3-scikit-optimize python3-xgboost python3-pyyaml +# 数据库依赖包 +yum install -y python3-sqlalchemy python3-cryptography +yum install -y python3-psycopg2 +``` +3. 下载源码、编译、安装 + +```bash +git clone https://gitee.com/openeuler/A-Tune.git +cd A-Tune +make models +make +make collector-install +make install +``` +# 二、开始使用 +## 配置A-Tune服务 +修改/etc/atuned/atuned.cnf中的network和disk配置选项为对应的指定网卡和磁盘。 +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417193945263.png) +## 管理A-Tune服务 +加载并启动atuned和atune-engine服务: + +```bash +systemctl daemon-reload +systemctl start atuned +systemctl start atune-engine +``` +> 注意:这三条命令执行需要一定时间,且不会有任何输出显示。重启后需要重新启动服务。 + +查看atuned或atune-engine服务状态: + +```bash +systemctl status atuned +systemctl status atune-engine +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417194614472.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +![](https://img-blog.csdnimg.cn/20210417194522940.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +## atune-adm命令行工具 +1. list命令 - 列出系统当前支持的profile,以及当前处于active状态的profile。 +例: +```bash +atune-adm list +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210417194836656.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) + +2. profile命令 - 激活profile,使其处于active状态。 +例: + +```bash +atune-adm profile web-nginx-http-long-connection +``` +激活web-nginx-http-long-connection对应的profile配置。 + +3. analysis命令 - 在线静态调优。实时采集系统的信息进行负载类型的识别,并自动执行对应的优化。 +接口语法: + +```bash +atune-adm analysis [OPTIONS] +``` + +4. tuning命令 - 离线动态调优。使用指定的项目文件对所选参数进行动态空间的搜索,找到当前环境配置下的最优解。 +接口语法: + +```bash +atune-adm tuning [OPTIONS] +``` +离线动态调优是本次任务的重点。 + +# 三、A-Tune离线调优示例 +示例位于A-Tune/examples/tuning目录,这里以对gcc编译器的优化为例。 + +```bash +cd /examples/tuning/gcc_compile +``` +1. 准备环境 + +```bash +sh prepare.sh +``` +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418133402328.png) + +2. 下载stream.c(内存带宽测试程序) + +```bash +wget http://www.cs.virginia.edu/stream/FTP/Code/stream.c +``` +3. 开始调优 + +```bash +atune-adm tuning --project gcc_compile --detail gcc_compile_client.yaml +``` +调优结果: +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418133945119.png) +内存带宽提升121%,编译后的可以执行文件大小减小17%。 + +4. 保存结果 + +```bash +atune-adm tuning --restore --project gcc_compile +``` +无输出。 +# 四、A-Tune离线调优应用 +离线动态调优包含三个输入文件:client.yaml、server.yaml和benchmark。 + - client.yaml: 存放在客户端的文件,包含调优的评价指标等信息。 + - server.yaml: 存放在服务端的文件,包含调优的可调节参数等信息。 + - benchmark: 存放在客户端的文件,通过运行该文件以获取评价指标的具体数值。 + +这里以gcc离线动态调优为例,说明这三个文件。 +## client.yaml +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418211719224.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +其中包含: +- 调优算法选择(line 2) +- 迭代次数(line 3) +- 随机迭代次数(line 4) +- benchmark执行命令(line 6) +- 评价指标1相关信息(line 8 - 13) +- 评价指标2相关信息(line 14 - end) + +另外,还可以在client.yaml中添加**参数选择**: + +参数选择是在进行离线动态调优前执行的步骤,其目的是在进行离线动态调优前缩减参数空间,在给出的参数空间中选择出对性能影响最大的参数并进行调优。 + +实现方法是在client.yaml中添加如下参数: + +- feature_filter_engine: 参数选择算法 +- feature_filter_cycle: 参数选择轮数 +- feature_filter_iters: 参数选择的迭代次数 +- feature_filter_count: 每轮选择出的参数 +- split_count: 调优参数取值范围中均匀选取的参数个数 + + +## server.yaml +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418212213431.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) +- 应用启动命令(line 3) +- 应用停止命令(line 4) +- 可调参数等内容(line 5 - end) +## benchmark文件 +![在这里插入图片描述](https://img-blog.csdnimg.cn/20210418212600100.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxNDQwOA==,size_16,color_FFFFFF,t_70) + +benchmark文件用于在调优执行时,会根据client.yaml中提供的命令执行此文件。 + +## 执行优化并保存结果 +执行优化: +```bash +atune-adm tuning --project --detail +``` +保存结果: +```bash +atune-adm tuning --restore --project +``` + diff --git a/web-ui/docs/zh/blog/liqunsheng/2020-11-26-swap.md b/web-ui/docs/zh/blog/liqunsheng/2020-11-26-swap.md new file mode 100644 index 0000000000000000000000000000000000000000..02d50d52e828cb23869c4efbbe0460e06c438983 --- /dev/null +++ b/web-ui/docs/zh/blog/liqunsheng/2020-11-26-swap.md @@ -0,0 +1,257 @@ +--- +title: Linux下的内存交换 +date: 2020-11-24 +tags: + - 内存交换 + - Linux + - KVM +archives: 2020-11 +author: 李群圣 +summary: 内存交换可以用于缓解系统的内存压力;KVM进行内存交换时,需要系统额外的进行通知,否则会出现不可预知的访问错误。 +--- + + +# Linux下的内存交换 + +### 摘要: +  内存交换是减缓内存使用压力常用的一种技术手段,KVM等hypervisor可以显式地通知宿主机系统是否允许进行内存交换,从而平衡运行时的效率和内存大小。本文的目的是通过概括内存交换的原理,介绍KVM中的内存交换机制,进而深化对内存管理的理解。 +## 1. 内存交换 +  内存交换是指当系统内存使用压力较大时,内核可以将一部分暂时不能运行(如受到阻塞)的进程内存页换出到外存中,释放这部分内存,供系统分配给新的进程或是将部分外存中的进程页换入。当程序需要访问被换出的内存时,内核又再次将换出的页重新载入,确保不会发生访问错误。内存页的换入与换出的时间较长,实际上是在以时间换空间。 + +  内存交换所换出的内存页分为两种,文件映射页(file-backed page)和匿名页(anonymous page)。在交换时,文件映射页直接通过文件进行读写,而匿名页包含了堆、栈、数据段等,不以文件的形式存在,无法与磁盘文件直接交换, 需要硬盘划分出额外的交换分区进行读写。 + +## 2. KVM中通知机制 +  为了在虚拟机中实现内存交换,宿主机系统(Linux)需要有一套通知机制(notifier)来通知KVM哪一块内存进行了换入换出。 + +  在硬件辅助的虚拟化中,hypervisor将直接通过EPT页表进行虚拟机物理地址到宿主机物理地址的转换,而不需要经过宿主机的虚拟地址。以qemu为例,qemu本身具有自己的宿主机虚拟地址空间,其运行的虚拟机则有自己的物理地址空间,而Linux系统进行内存交换时,改变的是宿主机物理地址上的页面。因此,qemu本身的页面被换出时,再次访问该内存,Linux可以根据pte的内容,知道这个地址被换出到了外存,进而执行相应的换入操作;当虚拟机物理地址对应的宿主机物理地址所在的页面被换出时,再次访问该页面,将经由KVM通过EPT页表直接查询宿主机物理地址,不经Linux系统,即使是该内存被换出,KVM也会直接访问EPT中保存的原有地址空间。 + +  作为扩展,2008年Linux引入了MMU通知程序,本质上是通过回调函数的方式获取Linux系统的通知,当Linux系统中发生某些特定的事情时,就会调用这些回调函数。以Linux4.19中的KVM模块代码为例,它们定义在如下的结构中,其中release是当相关的mm_struct消失时,对KVM的最后一次回调: +```c +static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { + + .flags = MMU_INVALIDATE_DOES_NOT_BLOCK, + .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, + .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, + .clear_flush_young = kvm_mmu_notifier_clear_flush_young, + .clear_young = kvm_mmu_notifier_clear_young, + .test_young = kvm_mmu_notifier_test_young, + .change_pte = kvm_mmu_notifier_change_pte, + .release = kvm_mmu_notifier_release, + +}; +``` +  KVM可以通过如下代码来通知Linux系统,将其notifier注册到Linux系统中: +```c +static int kvm_init_mmu_notifier(struct kvm *kvm) +{ + kvm->mmu_notifier.ops = &kvm_mmu_notifier_ops; + return mmu_notifier_register(&kvm->mmu_notifier, current->mm); +} +``` +  注册函数如下所示,参数mm是与给定的地址空间相关联的mm_struct结构,只有当这些地址空间发生变化时,Linux才会通知KVM,而与KVM无关的地址空间则没有必要进行统治,以此来提高notifier的效率。 +```c +int mmu_notifier_register(struct mmu_notifier *mn, struct mm_struct *mm) +{ + return do_mmu_notifier_register(mn, mm, 1); +} +``` + +## 3. 内存交换的实现 +#### 3.1 换出的时机 +  内存换出的时机有两个: +1. 内核唤醒kswapd内核线程进行慢速回收,并进行水位标记(watermark)控制(watermark)。 + +  以内存剩余量为水位的大小,内核中存在三个水位标记 + +  1) high:内存剩余较多,使用压力不大; + +  2) low:当剩余内存减少到low水位时,表示当前内存压力较大,内核唤醒kswapd内核线程进行回收,直到再次上升到high水位; + +  3)min:最小水位,内存减少到min水位时,内存严重不足,面临很大的使用压力,内核将会阻塞当前进程,并进行内存回收;小于min的内存非特殊情况不会被使用。 + +1. 通过drop_cache进行回收;慢速回收需要内存不足时开始换出,drop_cache则可以主动发起回收。 + +#### 3.2 swap cache + +  内存与硬盘之间存在着swap cache,但是与cpu与内存之间的cache不同。swap cache一方面通过缓存的方式将交换过程与文件系统相关联,使得我们可以通过文件系统抽象接口完成交换;另一方面成为换入换出过程中的共享资源,在换出过程中,其page frame是在swap cache中供进程访问,通过锁机制可以达到同步效果,防止某一进程进行换出,而另一个进程进行换入的情况。 + +#### 3.3 内存的换出 + +  以匿名页的换出为例,文件映射页类似,换出过程如下: + +  1)首先检查匿名页是否在Swap cache中,如果不在Swap cache中,将该页加入到Swap cache中; + +  2)内核通过反向映射,找到该匿名页对应的所有PTE页表,并解除映射关系,与Swap分区中的新页面重新建立映射关系; + +  3)映射完成之后,如果脏页已经回刷完成,则内核将匿名页从Swap cache中删除,该页的引用数量降为0,可以被内核回收利用,至此完成了从内存到硬盘的页面交换。 + +```c +/* + * shrink_page_list() returns the number of reclaimed pages + */ +static unsigned long shrink_page_list(struct list_head *page_list, + struct pglist_data *pgdat, + struct scan_control *sc, + enum ttu_flags ttu_flags, + struct reclaim_stat *stat, + bool force_reclaim) +{ + ... + while (!list_empty(page_list)) { + ... + + /* + * 是匿名页但不在swap cache中,将该页加入到swap cache中 + */ + if (PageAnon(page) && PageSwapBacked(page)) { + if (!PageSwapCache(page)) { + ... + + // add_to_swap()为匿名页分配swap空间,并将该页添加到swap cache中 + if (!add_to_swap(page)) { + ... + } + + may_enter_fs = 1; + + /* Adding to swap updated mapping */ + mapping = page_mapping(page); + } + } else if (unlikely(PageTransHuge(page))) { + ... + } + + /* + * 尝试解除所有映射,try_to_unmap通过反向映射查找该页的所有PTE并解除映射 + */ + if (page_mapped(page)) { + enum ttu_flags flags = ttu_flags | TTU_BATCH_FLUSH; + + if (unlikely(PageTransHuge(page))) + flags |= TTU_SPLIT_HUGE_PMD; + if (!try_to_unmap(page, flags)) { + nr_unmap_fail++; + goto activate_locked; + } + } + + if (PageDirty(page)) { + ... + // pageout函数将该页写回交换分区 + + switch (pageout(page, mapping, sc)) { + ... + case PAGE_SUCCESS: + ... + mapping = page_mapping(page); + case PAGE_CLEAN: + ; /* try to free the page below */ + } + } + ... + + if (PageAnon(page) && !PageSwapBacked(page)) { + ... + } else if (!mapping || !__remove_mapping(mapping, page, true)) // 调用__remove_mapping将page->_count清0,加入到free_page中,释放该页 + goto keep_locked; + ... + return nr_reclaimed; +} +``` + + +#### 3.4 内存的换入 +  当被换出的页面再次被访问时,触发page fault异常处理,内核通过在换出时写入的页表内容,将换出的内存页重新换入。在linux中,调用do_swap_page函数完成页面换入操作。 + +  换入的过程如下: + +  1)查找swap cache中是否存在所查找的页面,如果存在,则根据swap cache引用的内存页,重新映射并更新页表;如果不存在,则分配新的内存页,并添加到swap cache的引用中,更新内存页内容完成后,更新页表。 + +  2)换入操作结束后,对应swap area的页引用减一,当减少到0时,代表没有任何进程引用了该页,可以进行回收。 + +```c +linux-4.19/mm/memory.c + +/* + * We enter with non-exclusive mmap_sem (to exclude vma changes, + * but allow concurrent faults), and pte mapped but not yet locked. + * We return with pte unmapped and unlocked. + * + * We return with the mmap_sem locked or unlocked in the same cases + * as does filemap_fault(). + */ +vm_fault_t do_swap_page(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct page *page = NULL, *swapcache; + struct mem_cgroup *memcg; + swp_entry_t entry; + pte_t pte; + int locked; + int exclusive = 0; + vm_fault_t ret = 0; + + if (!pte_unmap_same(vma->vm_mm, vmf->pmd, vmf->pte, vmf->orig_pte)) + goto out; + + entry = pte_to_swp_entry(vmf->orig_pte); //根据pte返回swap空间的入口entry + + ... + + page = lookup_swap_cache(entry, vma, vmf->address); // 在swap cache中寻找entry对应的page + swapcache = page; + + if (!page) { + struct swap_info_struct *si = swp_swap_info(entry); + + if (si->flags & SWP_SYNCHRONOUS_IO && + ... + } + } else { + /* + * 如果在cache中找不到page,则在swap area中查找,分配新的内存页并从swap area中读入; + */ + page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, + vmf); + swapcache = page; + } + ... + + ret = VM_FAULT_MAJOR; + count_vm_event(PGMAJFAULT); + count_memcg_event_mm(vma->vm_mm, PGMAJFAULT); + } else if (PageHWPoison(page)) { + ... + } + + locked = lock_page_or_retry(page, vma->vm_mm, vmf->flags); // 给page加锁 + + ... + + vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->address, + &vmf->ptl); // 获取一个pte的entry,重新建立映射 + + ... + + pte = mk_pte(page, vma->vm_page_prot); + + ... + + /* ksm created a completely new copy */ + if (unlikely(page != swapcache && swapcache)) { + page_add_new_anon_rmap(page, vma, vmf->address, false); + mem_cgroup_commit_charge(page, memcg, false, false); + lru_cache_add_active_or_unevictable(page, vma); + } else { + do_page_add_anon_rmap(page, vma, vmf->address, exclusive); + mem_cgroup_commit_charge(page, memcg, true, false); + activate_page(page); + } + ... + swap_free(entry); // 减少该swap area的entry上的引用计数 + ... + return ret; +} + +``` + diff --git a/web-ui/docs/zh/blog/liujingang09/2020-6-24-announce-cna-zh.md b/web-ui/docs/zh/blog/liujingang09/2020-6-24-announce-cna-zh.md new file mode 100644 index 0000000000000000000000000000000000000000..305cc59037ffbd46a12a381dd73848a03d29453a --- /dev/null +++ b/web-ui/docs/zh/blog/liujingang09/2020-6-24-announce-cna-zh.md @@ -0,0 +1,25 @@ +--- +title: openEuler正式成为CNA,获得CVE颁发资质 +date: 2020-06-24 +tags: + - CVE + - CNA + - Security +archives: 2020-06-24 +author: liujingang09, openEuler Security Committee +summary: openEuler正式成为CNA,获得CVE颁发资质。 +--- + +### openEuler正式成为CNA,获得CVE颁发资质 +openEuler非常重视社区版本的安全性,制定了一套完整的漏洞管理策略,快速的响应和处理openEuler相关的安全问题。2020年6月24日openEuler顺利通过CNA(CVE Numbering Authorities)加入程序,成为CVE编号授权机构,openEuler同时也拥有颁发和管理openEuler社区相关CVE编号的资质。openEuler通过加入CNA,遵循业界成熟的漏洞管理标准,以促进openEuler社区安全的持续发展。 + +openEuler安全委员会一直致力于提升社区安全和隐私保护能力,欢迎关注openEuler的安全专家和爱好者加入openEuler安全委员会,与我们一起构建openEuler社区安全。 + +#### openEuler漏洞管理策略: +https://www.openeuler.org/zh/security.html + +### 关于CVE +全称是 Common Vulnerabilities & Exposures 通用漏洞披露,建立于 1999年9月。 CVE是一个漏洞字典表,每个漏洞都拥有一个唯一的CVE编码。用户可以通过唯一的CVE编码在漏洞数据库或安全工具中快速的找到漏洞影响范围和修补信息,以便快速的确认系统受漏洞影响情况和获取解决方案。 + +### 关于CNA +全称是 CVE Numbering Authority,即“CVE编号授权机构”,CNA包括供应商、开源项目、漏洞研究人员、国家/行业CERT等,成为CNA将可以在授权范围内分配和管理CVE编号。 diff --git a/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code1.png b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code1.png new file mode 100644 index 0000000000000000000000000000000000000000..020bec502ef8c8eb1a171aa0e56871f3bdece198 Binary files /dev/null and b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code1.png differ diff --git a/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code2.png b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code2.png new file mode 100644 index 0000000000000000000000000000000000000000..6574f6127184747ff4cfc7ae7520504fa6b1b115 Binary files /dev/null and b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code2.png differ diff --git a/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code3.png b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code3.png new file mode 100644 index 0000000000000000000000000000000000000000..477178a3485d7e0dff00bafd3d601ca23e16e9d4 Binary files /dev/null and b/web-ui/docs/zh/blog/liujingang09/2021-01-29-images/code3.png differ diff --git a/web-ui/docs/zh/blog/liujingang09/2021-01-29-sudo-cve-2021-3156.md b/web-ui/docs/zh/blog/liujingang09/2021-01-29-sudo-cve-2021-3156.md new file mode 100644 index 0000000000000000000000000000000000000000..5c64aad18a611ded5724947cabb3806aadad49fa --- /dev/null +++ b/web-ui/docs/zh/blog/liujingang09/2021-01-29-sudo-cve-2021-3156.md @@ -0,0 +1,82 @@ +--- +title: sudo堆溢出漏洞(CVE-2021-3156)分析 +date: 2021-01-29 +tags: + - CVE + - 漏洞分析 + - sudo +archives: 2021-01 +author: liujingang09 +summary: sudo堆溢出漏洞(CVE-2021-3156)分析 +--- +### 1.1 概述 +近日,国外研究团队Qualys披露出sudo堆溢出漏洞(CVE-2021-3156), 攻击者可以通过“sudoedit -s”和以单个反斜杠字符结尾的命令行参数将特权提升到 root 用户。 +### 1.2 漏洞详情 +1)技术分析 +在sudo解析命令行参数的方式中发现了基于堆的缓冲区溢出。任何本地用户(普通用户和系统用户,sudoers和非sudoers)都可以利用此漏洞,从而无需进行身份验证就能从普通账号权限提升获取到root权限。此漏洞带来的最大威胁是对数据机密性和完整性以及系统可用性的威胁。 +该漏洞在2011年7月被引入(commit 8255ed69),当执行sudoedit –s / 时,sudo的src/parse_args.c文件的parse_args函数会把字符“/” 设置为"\"。 + + +漏洞代码位于plugins/sudoers/sudoers.c文件的set_cmnd函数中,关键代码如下: + + +如果参数以单个反斜杠字符结尾 ("sudoedit –s /"会执行这段代码逻辑),则情况如下: +1) 在905行,"from[0]"是\ , "from[1]"是空的终止符 (不是空格字符) +2) 在906行,"from"指针加1并指向空的终止符 +3)在907行,空的终止符被拷贝到"user_args"缓冲区中,"from"指针再次加1,并指向空的终止符的下一个字符(此时已越界)。 +4)再次进行906-908行的while循环,并把已越界的字符拷贝到"user_args"缓冲区中。 + +2)漏洞修复方法: +修复在user_args中转义反斜杠时的缓冲区溢出问题;并且除非在"运行模式并且通过shell命令执行"的情况下,不要尝试转义反斜杠。同时拒绝不安全的-H和-P参数:执行sudoedit –H或sudoedit –P,会输出"usage:"开头的错误信息。 + + +3)排查方法: +以非root用户登录系统并执行命令: sudoedit -s / +- 如果输出以"sudoedit:"开头的错误信息,表明存在漏洞。 +- 如果输出以"usage:"开头的错误信息,表明补丁已生效。 + +### 1.3 影响性分析 +受影响版本:从1.8.2到1.8.31p2的所有版本 + 从1.9.0到1.9.5p1的所有稳定版本 +openEuler使用的是1.9.2版本。 +### 1.4 缓解措施 +使用 systemtap 进行临时缓解,使sudoedit命令不可用: +首先,安装所需的 systemtap 软件包、依赖包以及sudo的debuginfo软件包。 +yum install systemtap kernel-devel-"$(uname -r)" +debuginfo-install sudo +然后,创建以下 systemtap 脚本,并将文件命名为 sudoedit-block.stap: +probe process("/usr/bin/sudo").function("main") { + command = cmdline_args(0,0,""); + if (strpos(command, "edit") >= 0) { + raise(9); + } +} + +最终,使用root权限执行以下脚本: +nohup stap -g sudoedit-block.stap & + +该脚本将使易受攻击的sudoedit二进制文件停止工作。sudo命令仍将照常工作。上述更改在重启后失效,每次重启后必须重新执行。 +一旦安装了补丁,就可以通过取消systemtap进程来删除systemtap脚本, 使sudoedit重新可用。 + 例如使用:# kill -s SIGTERM 26285 (其中26285是systemtap进程的PID) + +### 1.5 漏洞修复方法 +• 下载openEuler发布最新的sudo软件包: + 漏洞SA:https://www.openeuler.org/zh/security/safety-bulletin/detail.html?id=openEuler-SA-2021-1002 + 20.03-LTS: + [aach64架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/aarch64/Packages) + [x86架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS/update/x86_64/Packages) + 20.03-LTS-SP1: + [aach64架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/update/aarch64/Packages/) + [x86架构软件包](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/update/x86_64/Packages/) + +• 升级sudo软件包 + rpm -Uvh sudo-*.rpm + +• 升级完成之后查看sudo软件包是否升级成功。 + rpm -qi sudo + 20.03-LTS在:sudo-1.9.2-2版本修复。 + 20.03-LTS-SP1在:sudo-1.9.2-3版本修复。 + +### 1.6 接口变更 +不再支持sudoedit -H,sudoedit –P命令。 +执行sudoedit –H 和sudoedit –P命令,都会输出"usage:"开头的错误信息。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png new file mode 100644 index 0000000000000000000000000000000000000000..faf84c12a81260aeb0be4520b6f582a5c25d45bb Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-01.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b820312a2603b934c5464ae8106ee29ccb80c2 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-02.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png new file mode 100644 index 0000000000000000000000000000000000000000..d85295011c695c359fb04ec3838b85eeb83cd502 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-03.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png new file mode 100644 index 0000000000000000000000000000000000000000..bed0c5029d8d63667cd3179b8ad2e855dc8be39f Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-04.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png new file mode 100644 index 0000000000000000000000000000000000000000..b83fae4c4a29df46066ec83e88b67a6d89b2ae1d Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list-05.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list.md b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list.md new file mode 100644 index 0000000000000000000000000000000000000000..97873159fa22f6a984bff9ff039b823e4e7dad36 --- /dev/null +++ b/web-ui/docs/zh/blog/liuqi/2021-10-14-unsubscribe-mailing-list.md @@ -0,0 +1,42 @@ +--- +title: 如何退订openEuler的邮件列表 +date: 2021-11-23 +tags: + - openEuler + - 邮件列表 + - 退订 +sig: sig-Gatekeeper +archives: 2021-11 +author: liuqi<469227928@qq.com> +summary: 本博客介绍了两种退订openEuler邮件列表的方式 + +--- +最近openEuler基础设施团队收到一些社区维护者与贡献者的反馈,不清楚如何退订openEuler的邮件列表。下面具体介绍两种退订方式,一种是发送邮件退订,一种是用户界面退订。 + +### 一、发送邮件退订 + +发送邮件退订有两种场景。一种是在有退订指引页脚的邮件中,可直接点击邮件页脚的退订标识编辑发送邮件退订。另一种是直接编辑邮件发送给`**-leave@openeuler.org`退订。接下来以退订test@openeuler.org(已订阅)为例具体说明。 + +- + 部分邮件带有退订指引的页脚,点击页脚的`test-leave@openeuler.org`即可编辑发送退订邮件, 邮件的标题和内容不限 + 通过邮件页脚退订 + + 随后,你会收到一封test-bounces发送的退订成功告知邮件 + 退订成功 + +- + 你也可以使用订阅邮箱给test-leave@openeuler.org发送一封邮件,标题和内容不限 + 发送退订邮件 + + 随后,你会收到一封test-bounces发送的退订成功告知邮件 + 退订成功 + + +### 二、用户界面退订 +如果你已是openEuler邮件列表的注册用户(当前注册接口未开放),可直接登录[**postorius**](https://mailweb.openeuler.org/postorius/lists/), +进入需要退订的邮件列表,点击**Unsubscribe**即可 + +Web UI退订 + +### 更多 +更多社区邮件列表相关问题可参考[**Mailweb List FAQ**](https://osinfra.cn/faq/mailinglist.html) diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-01.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-01.png new file mode 100644 index 0000000000000000000000000000000000000000..056c6a1dd8f0e25d983c82929383a1d02e6e748e Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-01.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-02.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-02.png new file mode 100644 index 0000000000000000000000000000000000000000..d6795559d0c3c4e1ef22aa48df969da6f33c0ec6 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-02.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-03.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-03.png new file mode 100644 index 0000000000000000000000000000000000000000..4adff80ec42f6d4b43b8684310b96bc729b7f519 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-03.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-04.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-04.png new file mode 100644 index 0000000000000000000000000000000000000000..e69ca96ba1a3607bcae10e538a6edf5ee8ca7d0b Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-04.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-05.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-05.png new file mode 100644 index 0000000000000000000000000000000000000000..a177921ae09fcf43edc6fbcc5c79cb11708ec5e3 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-05.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-06.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-06.png new file mode 100644 index 0000000000000000000000000000000000000000..cca5761ff69ebf20b8cc2e12e6c7c8976f5d3ad7 Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-06.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-07.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-07.png new file mode 100644 index 0000000000000000000000000000000000000000..40e2db14e1d737258a3c9cb7d1b67385f7bb78bb Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-07.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-08.png b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-08.png new file mode 100644 index 0000000000000000000000000000000000000000..535300a08bb5e6f67470031007bca7e81678668d Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook-08.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook.md b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook.md new file mode 100644 index 0000000000000000000000000000000000000000..4655d7ee94557c940611b52c85167e4d321f2b42 --- /dev/null +++ b/web-ui/docs/zh/blog/liuqi/2021-11-25-jenkins-gitee-webhook.md @@ -0,0 +1,55 @@ +--- +title: 如何在Jenkins上关联Gitee的Webhook +date: 2021-11-25 +tags: + - Jenkins + - Gitee + - Webhook +sig: sig-Gatekeeper +archives: 2021-11 +author: liuqi +summary: 本博客介绍了如何在Jenkins上关联Gitee的Webhook + +--- +本文通过Jenkins项目的创建和配置与Gitee webhook的配置介绍了如何添加一个关联Jenkins项目的Gitee webhook + +### 创建Jenkins项目 + +- 在指定目录下选择`新建Item` + + 新建项目 + +- 输入项目名称,选择`构建一个自由风格的软件项目`并确定,一个Jenkins自定义项目就创建好了,接下来进行设置 + + 选择项目类型 + + + +### Jenkins项目配置 + +- 创建项目后默认进入设置,在**构建触发器**下勾选`Gitee webhook 触发构建`,此处的URL作为新增Gitee webhook的URL + + 编辑构建触发器 + +- 按照下图所示配置,并点击生成 Gitee Webhook 密码,作为新增Gitee webhook的密码 + + 生成webhook密码 + +### 在Gitee仓库配置Webhooks + +- 进入将要配置Webhooks的Gitee仓库,从管理项进入**Webhooks**,点击`添加 webHook` + + Gitee Webhooks + +- 输入Jenkins项目设置中的**Gitee webhook URL**和**Gitee Webhook 密码**,勾选选择事件的`Pull Request`和`评论`,添加webhook + + 添加Webhooks + +- 如图新增了一个webhook,点击`测试`,看到测试成功的弹窗后,点击`查看更多` + + 测试Webhooks + +- 在请求历史可查看webhook的每个请求,当请求返回的状态码为200时,说明Jenkins已经接收到了Gitee发出的请求,那么webhook也就配好了 + + 查看Webhooks历史 + diff --git a/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-01.png b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-01.png new file mode 100644 index 0000000000000000000000000000000000000000..4e01433d6e71daf6f37b43ffa928b5c940aa4b2a Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-01.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-02.png b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-02.png new file mode 100644 index 0000000000000000000000000000000000000000..add0db449203cb0126997b5a8203c8fe768ca49f Binary files /dev/null and b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share-02.png differ diff --git a/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share.md b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share.md new file mode 100644 index 0000000000000000000000000000000000000000..712d631839b9977b1df3b1c9dc3061746da1ec51 --- /dev/null +++ b/web-ui/docs/zh/blog/liuqi/2022-03-22-community-ci-share.md @@ -0,0 +1,36 @@ +# openEuler 社区门禁工程分享 + + +### openEuler社区的PR合入流程 + +openeuler-ci-bot(后面统称ci-bot)是openEuler社区的机器人,在检测到新建PR后,ci-bot会评论一条欢迎信息。ci-bot还会检查PR提交者是否已签署了CLA(Contributor License Agreement),如果你尚未签署CLA,ci-bot会在PR中打上`openeuler-cla/no`的标签,并在评论中指引你完成CLA的签署。完成CLA签署后,可评论/check-cla刷新PR中CLA标签的状态。 + +新建PR或强制推送还会触发社区门禁的构建以及生成PR审视要求清单。 + +- 门禁检查结果 +当门禁在进行中时,ci-bot会给PR打上`ci_processing`标签;如果门禁结果为 success,说明PR已经通过了门禁检查,ci-bot会给PR打上`ci_successful`标签;如果是failed的话,具体错误则需要点击Build Details下对应的地址去jenkins的门禁构建console中定位,同时,ci-bot会给PR打上`ci_failed`标签。下图是一个失败的门禁检查结构。 + +
门禁检查结果
+ +- PR审视清单 +审视清单列出了PR需要审视的内容与描述,在审视者确认无误,修改审视结果为符合要求后,审视完成。 +
审视清单
+ + 当一条可合入的PR拥有`openeuler-cla/yes`,`ci_successful`,`lgtm`,`approved`等标签,ci-bot会自动将该PR合入;对处于开启状态的PR,可通过评论/check-pr检查PR的标签是否已满足合入条件,满足的话会合入PR。 + + 如果一条新增仓库的PR被合入,ci-bot在检测到PR合入后创建仓库,并根据仓库所属sig的OWNERS文件为仓库配置开发者。如果新增的是src-openeuler的仓库,ci-bot还会自动为该项目生成_service文件,推到https://gitee.com/src-openeuler/obs_meta的master/openEuler:Factory ,同时会在Jenkins上为该项目创建一系列门禁的工程(trigger,x86-64,aarch64,comment)。 + +### openEuler社区门禁 + +openEuelr社区门禁的构建托管在Jenkins,地址为 https://openeulerjenkins.osinfra.cn/job/Infra/job/community_check_v2/ ,新建PR或强制推送会触发门禁检查,检查项具体为以下几项: +- conflict check +- sanity check +- branch check + +conflict check会检查目标PR是否存在冲突,sanity check会对提交的健全性做一系列检查,branch check则会对仓库的分支变更做检查。 + +sanity check的检查逻辑可参考源代码 https://gitee.com/openeuler/community/blob/master/ci-scripts/sanity_check.py + +branch check的检查逻辑可参考源代码 https://gitee.com/openeuler/community/blob/master/ci-scripts/check_branch.py + +branch check的配置文件为 https://gitee.com/openeuler/release-management/blob/master/valid_release_branches.yaml diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF01.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF01.png new file mode 100644 index 0000000000000000000000000000000000000000..9892bfd3bd263cb50fae216d2e04594dd42ae7d6 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF01.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF02.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF02.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccfdfd34f2c61098fba01d339486fa1623f3d68 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF02.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF03.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF03.png new file mode 100644 index 0000000000000000000000000000000000000000..c8481dc0ef929ef83772202088adf92ece13273f Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF03.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF04.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF04.png new file mode 100644 index 0000000000000000000000000000000000000000..800fb7b442294ed2a84b87a6b91ee96e12daee41 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF04.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF05.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF05.png new file mode 100644 index 0000000000000000000000000000000000000000..9af9a2f46ca2a4a6c52f3aae70f8581dcc94740a Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF05.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF06.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF06.png new file mode 100644 index 0000000000000000000000000000000000000000..2b057f5d1106cdce7b76aba96365089e8f1c4308 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF06.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF07.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF07.png new file mode 100644 index 0000000000000000000000000000000000000000..d43ce228d49e10610769559c8ac02ccfd79ac6b1 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF07.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF08.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF08.png new file mode 100644 index 0000000000000000000000000000000000000000..94c72330c1e414fa2c80e18e7e812d09da6b5afe Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF08.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF09.png b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF09.png new file mode 100644 index 0000000000000000000000000000000000000000..b880b6265a88154ca5217bfc95a2de1e9b496f57 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/OEKF09.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/openEuler-community-development-process.md b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/openEuler-community-development-process.md new file mode 100644 index 0000000000000000000000000000000000000000..74d4335c3c281450612b5b5f3e9460d64483e9f6 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/000openEuler-community-development-process/openEuler-community-development-process.md @@ -0,0 +1,132 @@ +--- +title: openEuler开源社区开发流程 +date: 2020-07-31 +tags: + - 开源社区 + - git +archives: 2020-07 +author: 罗宇哲 +summary: openEuler开源社区开发流程,介绍如何使用git提交PR。 +--- + +### 使用git提交PR + +一、环境准备 + +1. 注册码云账号,地址: +2. 加入openEuler社区,地址:https://www.openeuler.org/zh/ +3. 安装git + +> 3.1 windows安装:https://git-scm.com/download/win + +> 3.2 linux安装: + +``` +openEuler: dnf install git + +centOS: yum install git + +ubuntu: apt-get install git +``` + +4. git配置 + +> 4.1 全局配置用户名和邮箱 + +``` +git config --global user.name "Your Name" + +git config --global user.email +``` + +> 4.2 链接远程仓库 + +> 1)生成SSH密匙 + +``` +ssh-keygen -t rsa -C "youremail\@example.com" + +cat \~/.ssh/id_rsa.pub +``` + +> 2)登录远程仓库网站Gitee账户并添加密匙 + + + + + +二、提交PR + +1. 进入要修改的仓库,点击右上角的Forked,将其fork到自己的仓库,如下图所示。 + + + +2. Fork成功之后会自动进入Fork的仓库目录,点击克隆/下载-\>选择复制任一链接。见下图。 + + + +3. 将仓库clone到本地,并进入仓库目录。以上图perl-Text-ParseWords仓库为例。 + +``` +git clone .git + +cd perl-Text-ParseWords +``` + +4. 可以通过git remote –v查看所有远程库的url,见下图。 + + + +> 发现没有原作者的项目地址,使用git remote add upstream +> https://gitee.com/openeuler/perl-Text-ParseWords.git添加,再次执行git remote +> –v。如下图所示。 + + + +> 使用git remote set-url --push upstream +> no_push,设置不直接将改变推送到上游openEuler里面的仓库,而是只推送到自己Fork的gitee仓库下。见下图。 + + + +> 4.1 git fetch +> upstream与上游openEuler社区保持同步;如果是已提交过一次代码以后再做代码修改操作,可以跳过2.3/2.4两个步骤。 + +> 4.2 切换到master分支,并且把最新的代码同步下来。 + +``` +git checkout master + +git rebase upstream/master +``` + +5. 建立并进入分支进行代码开发、改动。 + +> git checkout –b \*\*\* // \*\*\*为自己定义的分支名,这里取名test_ci + +> 5.1 cd指令进入软件包路径,修改代码; 如果是对已提交过的代码再进行修改,则追加git +> pull(从初次操作的clone变为pull)。 + +> 5.2 git add . + +> git commit –m “modify” //其中modify为进行改变的标题,自行定义 + +6. 将代码提交到远端,\*\*\*为步骤2.6建立的分支名称。git push -f origin + \*\*\*。结果见下图。 + +注: + +git config --global credential.helper store + +> 输入上述命令以后用户名密码就会被git记住,之后在这个目录下都不需要再输入用户名密码了 + + + +7. 进入改动过代码的自己的仓库,选择下图小标1,或者点击小标2后接着进入新建Pull Requests。 + + + +8. 例子中2.6步建立的分支为test_ci,在新建Pull Requests之后,如下图所示 + + + +> 填写标题和说明即可创建Pull Request。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/001Auto-build-vm-enviroment.md b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/001Auto-build-vm-enviroment.md new file mode 100644 index 0000000000000000000000000000000000000000..381bfeef7aee8a40b2dd34ad029c1d8379b6339e --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/001Auto-build-vm-enviroment.md @@ -0,0 +1,217 @@ +--- +title: 第一期自动搭建openEuler虚拟机运行QEMU运行环境 +date: 2020-07-31 +tags: + - openEuler + - 虚拟机 + - QEMU运行环境 +archives: 2020-07 +author: 罗宇哲 +summary: 自动搭建openEuler虚拟机运行QEMU运行环境 +--- + + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +本文介绍了一个自动搭建openEuler虚拟机QEMU运行环境的脚本使用方法,本脚本能下载并安装各种依赖项,自动下载并编译安装QEMU4.1.1和busybox 1.25.1,下载并安装对Linux 4.19.1进行ARM64交叉编译并用gdb进行调试的环境,该环境能帮助我们理解openEuler内核的运行,以及下载和QEMU环境下安装openEuler1.0版。本脚本参考了前辈[1]在ARM32位环境下对Linux Kernel的交叉编译脚本,特此感谢!我们修改了QEMU、busybox和Linux kernel的版本和根文件系统搭建的方法,增加了依赖项,并将ARM交叉编译环境和gdb改为了64位,而且增加了openEuler的相关内容。 + +## 一、openEuler虚拟机运行环境搭建 + +环境准备:在VMware 15.1.0 或VirtualBox 6.10上搭建Ubuntu 18.04虚拟机,建议分配硬盘大小120G,内存大小2G以上。 + +自动搭建脚本码云地址:https://gitee.com/luo_yu_zhe/openEulerInstallation + +**运行脚本之间请手动更改下载源为国内源!否则下载较慢,更改源的方式参考[3]。** + +###### 脚本运行流程 + +1. sudo ./prepare.sh +2. source \~/.bashrc +3. sudo ./build.sh, 做完这一步ARM64交叉编译环境、linux kernel 4.19.1、busybox和QEMU以及依赖项应该都装好了。 +4. sudo ./start-qemu.sh进行无gdb调试linux kernel 4.19.1 或者sudo./start-qemu-gdb.sh之后另开一个窗口, aarch64-linux-gnu-gdb进入gdb界面,再输入 target remote localhost:1234进入调试阶段,在gdb窗口输入c就可以切换到qemu窗口运行。 + +sudo ./start-qemu.sh后: + + + +开启gdb运行后: + + + +###### Prepare.sh 脚本功能介绍 + +该脚本用于下载并解压64位ARM交叉编译工具、QEMU-4.1.1和openEuler镜像,此外,它还会通过apt install 安装依赖项。该脚本会检查压缩包是否存在,若存在不会重复下载解压。 + +下载openEuler镜像: + + + +下载并解压交叉编译gcc,设置环境变量: + + + +安装依赖项: + + + +下载并安装QEMU-4.1.1: + + + +下载QEMU UEFI启动固件并生成img文件,大小可以分配: + + + +###### Build.sh脚本功能介绍 + +下载并编译linux kernel 4.19.1,下载并编译busybox +1.25.1,制作根文件系统。架构和版本可以通过文件开头的参数进行设置。 + +下载并编译Linux内核4.19.1版: + + + +把编译好的Image文件copy到目标文件夹: + + + +下载并解压busybox: + + + +编译安装busybox: + + + +制作根文件系统: + + + +###### qemu启动脚本介绍 + +start-qemu.sh: qemu普通启动。 + + + +start-qemu-gdb.sh:带gdb 启动。 + + + +start-euleros.sh :用qemu启动euleros镜像。 + + + +采用gdb模式启动的时候首先运行sudo./start-qemu-gdb.sh命令,然后重新启动一个terminal,运行aarch64-linux-gnu-gdb,输入端口号然后按c。 + +qemu常见选项[2]: + +\-hda file、-hdb file、-hdc file和-hdd file。 + +把文件当成hard disk 0、hard disk 1、hard disk 2和hard disk 3。 + +  + +\-append cmdline + +将cmdline作为kernel command line,所谓kernel command line就是在kernel启动的时候,用cmdline对内核进行配置。比如"root=/dev/hda",将/dev/hda设置成根文件系统。 + +\-M machine + +选择模拟的机器(我们可以输入-M?提到一个模拟的机器列表) + +\-fda file/-fdb file + +使用file作为软盘镜像.我们也可以通过将/dev/fd0作为文件名来使用主机软盘。 + +\-cdrom file + +使用文件作为CD-ROM镜像(但是我们不可以同时使用'-hdc'和'-cdrom').我们可以通过使用'/dev/cdrom'作为文件名来使用主机的CD-ROM。 + +\-boot [a\|c\|d] + +由软盘(a),硬盘(c)或是CD-ROM(d).在默认的情况下由硬盘启动. + +\-snapshot + +写入临时文件而不是写入磁盘镜像文件.在这样的情况下,并没有写回我们所使用的磁盘镜像文件.然而我们却可以通过按下C-a s来强制写回磁盘镜像文件。 + +\-m megs + +设置虚拟内存尺寸为megs M字节.在默认的情况下为128M。 + +\-smp n + +模拟一个有n个CPU的SMP系统.为PC机为目标,最多可以支持255个CPU。 + +\-nographic + +在通常情况下,Qemu使用SDL来显示VGA输出。使用这个选项,我们可以禁止所有的图形输出,这样Qemu只是一个简单的命令行程序。模拟的串口将会重定向到命令行。所以,我们仍然可以在Qemu平台上使用串口命令来调试Linux内核。 + +## 二、openEuler 系统安装说明 + +##### 1.QEMU安装openEuler镜像 + +运行完sudo ./prepare.sh后,运行sudo./start_euleros.sh,运行该脚本会执行一下命令: + +qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 1024 -bios ./QEMU_EFI.fd +-cdrom openEuler-1.0-aarch64-dvd.iso -hda ./qemu_Euler.img -serial stdio + +QEMU会读入openEuler的镜像文件然后进入安装流程。选择安装openEuler后,选择安装模式(**选择test media选项**),之后分别配置每个前面有”[!]”这个标记的选项,主要有installation destination, root password和user password等,注意选择的时候是先输入选项对应的数字,确定之后按回车,然后再按c(continue)继续安装。以下是一个选择的流程,选项前面有[x]代表选中了该选项: + +###### A.选择 Use text mode 选项 + + + +###### B.选择Root password选项并配置 + + + +配置完之后我们可以发现大部分之前有[!]的选项之前都变成了[x]。 + +###### 配置安装目的地 + +选择大小: + + + +选择使用空间: + +VMware: + + + +VirtualBox: + + + +选择Partition方式: + +VMware: + + + +VirtualBox: + + + +###### 配置用户账户,输入b完成配置 + + + +###### E.安装完成 + +到这一步需要按一下回车然后输入之前设定的用户名和密码才行。 + + + + + +然后就和linux的操作基本一样了\~有一个问题是每次运行都要安装一次,所以装好之后最好能保存一个虚拟机快照。 + +## 参考文献 + +[1]https://github.com/xianjimli/qemu-arm-linux.git + +[2]https://blog.csdn.net/ustc_dylan/article/details/5385691 + +[3]https://blog.csdn.net/qq_35451572/article/details/79516563 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU1.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU1.png new file mode 100644 index 0000000000000000000000000000000000000000..55abec4930b21984151466512d92f0d940083554 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU1.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU10.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU10.png new file mode 100644 index 0000000000000000000000000000000000000000..8bff5137e1fd1a83c02dffc7e72ecf5f26104a77 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU10.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU11.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU11.png new file mode 100644 index 0000000000000000000000000000000000000000..d2af495e94028bee9b8a08b22a4f66543f9be22c Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU11.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU12.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU12.png new file mode 100644 index 0000000000000000000000000000000000000000..ef390b5ef04cebf07557a0d69bb87a09425e749a Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU12.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU13.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU13.png new file mode 100644 index 0000000000000000000000000000000000000000..a02f9c5c45f5c5fb93bf61fe0baf17d2765f50aa Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU13.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU14.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU14.png new file mode 100644 index 0000000000000000000000000000000000000000..e560af02008d6abb599e64ad7402ed3a65219126 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU14.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU15.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU15.png new file mode 100644 index 0000000000000000000000000000000000000000..6971f70492e1089c2649c987b68e2e4056e9a452 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU15.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU16.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU16.png new file mode 100644 index 0000000000000000000000000000000000000000..bf863bd82b95b0a7cc366d7b3a4296864e120231 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU16.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU17.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU17.png new file mode 100644 index 0000000000000000000000000000000000000000..78b379a79efd8666a41fed6b3717d72d53c91caa Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU17.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU18.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU18.png new file mode 100644 index 0000000000000000000000000000000000000000..2c6531fa4a6dccb5b7bbe79518c03f7e1eba4ffe Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU18.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU19.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU19.png new file mode 100644 index 0000000000000000000000000000000000000000..44baf3e092fb59563092a6b82cf4bae252575714 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU19.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU2.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU2.png new file mode 100644 index 0000000000000000000000000000000000000000..54c5cc9c37c2ae8aae35b343cd649c99f788f05a Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU2.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU20.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU20.png new file mode 100644 index 0000000000000000000000000000000000000000..8df9a72a8bbc8dcc1dc43c5a1e8c5dca8ce880c8 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU20.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU21.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU21.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c2e7161084bef58401ce2c7028ec6109081fa1 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU21.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU22.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU22.png new file mode 100644 index 0000000000000000000000000000000000000000..5f37512e1243b284adcd7fa2600bd366ae9cc433 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU22.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU23.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU23.png new file mode 100644 index 0000000000000000000000000000000000000000..bc23c96017f469470a09f86d25f8b1b5b06d041c Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU23.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU24.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU24.png new file mode 100644 index 0000000000000000000000000000000000000000..c642c6ae46309910f96a3d1432cf67419a037a10 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU24.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU25.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU25.png new file mode 100644 index 0000000000000000000000000000000000000000..3d7746df91dbc4d3faded8f4d330ecbe0cb5eaac Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU25.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU3.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU3.png new file mode 100644 index 0000000000000000000000000000000000000000..718f3dd942461a58e75ade8a3bcb029ca4dc5488 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU3.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU4.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU4.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad1c1b92c3b87ee4ee6098cfc90dec32298759d Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU4.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU5.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU5.png new file mode 100644 index 0000000000000000000000000000000000000000..75f91b0d581832eaa2096b15efddba9c1c60e36d Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU5.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU6.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU6.png new file mode 100644 index 0000000000000000000000000000000000000000..bef15b7a988c680c55a01ee857c8cabf79213a10 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU6.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU7.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU7.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2dc17046caa7ebe71f4bb458f8e59ee5e170b7 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU7.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU8.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU8.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c149d4a7a32aade0a106bbb489c9a6c3ec67ec Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU8.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU9.png b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU9.png new file mode 100644 index 0000000000000000000000000000000000000000..5baf240cd1e0f53c69a7fc588c959eea5010658f Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/001Auto-build-vm-enviroment/QEMU9.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/002History-of-Linux-kernel-1.md b/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/002History-of-Linux-kernel-1.md new file mode 100644 index 0000000000000000000000000000000000000000..4fe1eee45d51bc6d283e5821d3f41c6e69ca3682 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/002History-of-Linux-kernel-1.md @@ -0,0 +1,150 @@ +--- +title: 第二期Linux内核发展史-1 +date: 2020-08-06 +tags: + - Linux + - 内核 + - 发展史 +archives: 2020-08 +author: 罗宇哲 +summary: Linux内核发展史-1 +--- + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +openEuler是基于Linux 内核的企业级Linux服务器操作系统平台的开源社区发行版。openEuler支持鲲鹏架构,可运行在TaiShan服务器上。本技术连载将会从理论基础、源码分析和实操方法三个方面来比较全面地介绍内核编程与应用编程的基础知识,到2020年8月之前主要介绍内核编程部分。通过本连载的介绍,您将对openEuler内核编程和应用编程的理论和实践知识有一个基本的了解。本小节将从Linux内核发展史出发,带您走进openEuler的世界,一起学习操作系统的基础知识和openEuler内核的技术细节。 + +### 一、Linux内核发展简史 + +1991年,刚刚过完21岁生日的芬兰赫尔辛基大学计算机系单身狗Linus负债DIY了一台性能彪悍的计算机。他准备用这台计算机运行在操作系统课上学会的Minix操作系统并黑进学校性能更加强大的计算机系统来上网或者看新闻[1]。然而,Minix系统的价格让Linus望而却步,且当时Minix系统的协议只支持教学用途,于是这个小伙子决定开发一套自己的操作系统[2]。有三分之一的国土在北极圈内的芬兰冬季严寒而漫长,这给了Linus充分的时间构建自己的系统。在独自开发操作系统的漫长的日子里,只有学校每周三晚上的party给Linus的生活带来一点亮色,但他很快因为没有女伴而放弃了party并沉迷OS无法自拔。1991年9月17日,Linux内核(当时叫Freax)的0.01版被上传至FTP服务器,从此拉开了一个传奇的序幕…… + +从0.01版的内核开始,Linux内核经过不断迭代成熟,从最初的一万行左右的代码成长至今天千万行级的巨无霸。第一个版本只是一个内核。为了有一个工作系统,还需要一个shell、编译器、库等等。这些全部来自其他GNU软件。一年后的1992年,第一个Linux发行版诞生了。到今天为止,著名的发行版包括Debian、Ubuntu、RedHat Enterprise Linux和Fedora等。下表简要列出了迄今为止各版本内核的一些更新情况和发行日期[4]: + +| 内核版本号 | 时间 | 内核发展情况 | +| ------------ | ---------- | ------------------------------------------------------------ | +| 0.00 | 1991.2-4 | 两个进程分别显示AAABBB | +| 0.01 | 1991.9 | 第一个正式向外公布的Linux内核版本 | +| 0.02 | 1991.10.5 | LinusTorvalds将当时最初的0.02内核版本发布到了Minix新闻组,很快就得到了反应。LinusTorvalds在这种简单的任务切换机制上进行扩展,并在很多热心支持者的帮助下开发和推出了Linux的第一个稳定的工作版本。 | +| 0.03 | 1991.10.5 | | +| 0.10 | 1991.10 | Linux0.10版本内核发布,0.11版本随后在1991年12月推出,当时它被发布在Internet上,供人们免费使用。 | +| 0.11 | 1991.12.8 | 基本可以正常运行的内核版本 | +| 0.12 | 1992.1.15 | 主要加入对数学协处理器的软件模拟程序 | +| 0.95(0.13) | 1992.3.8 | 开始加入虚拟文件系统思想的内核版本 | +| 0.96 | 1992.5.12 | 开始加入网络支持和虚拟文件系统 | +| 0.97 | 1992.8.1 | | +| 0.98 | 1992.9.29 | | +| 0.99 | 1992.12.13 | | +| 1.0 | 1994.3.14 | Linux1.0版本内核发布,使用它的用户越来越多,而且Linux系统的核心开发队伍也建起来了。 | +| 1.2 | 1995.3.7 | | +| 2.0 | 1996.2.9 | | +| 2.2 | 1999.1.26 | | +| 2.4 | 2001.1.4 | Linux 2.4.0版本内核发布。 | +| 2.6 | 2003.12.17 | Linux 2.6版本内核发布,与2.4内核版本相比,它在很多方面进行了改进,如支持多处理器配置和64位计算,它还支持实现高效率线和处理的本机POSIX线程库(NPTL)。实际上,性能、安全性和驱动程序的改进是整个2.6.x内核的关键。 | +| 2.6.15 | 2006 | Linux 2.6.15版本内核发布。它对IPv6的支持在这个内核中有了很大的改进。 | +| 2.6.30 | 2009.6 | 改善了文件系统、加入了完整性检验补丁、TOMOYOLinux安全模块、可靠的数据报套接字(datagramsocket)协议支持、对象存储设备支持、FS-Cache文件系统缓存层、nilfs文件系统、线程中断处理支持等等。 | +| 2.6.32 | 2009.12 | 增添了虚拟化内存de-duplication、重写了writeback代码、 改进了Btrfs文件系统、添加了ATIR600/R7003D和KMS支持、CFQ低传输延迟时间模式、perftimechart工具、内存控制器支持softlimits、支持S+Core架构、支持IntelMoorestown及其新的固件接口、支持运行时电源管理、以及新的驱动。 | +| 2.6.34 | 2010.5 | 添加了Ceph和LogFS两个新的文件系统,其中前者为分布式的文件系统,后者是适用于Flash设备的文件系统。Linux Kernel 2.6.34的其他特性包括新的Vhostnet、改进了Btrfs文件系统、对Kprobesjump进行了优化、新的perf功能、RCUlockdep、GeneralizedTTLSecurityMechanism(RFC5082)及privateVLANproxyarp(RFC3069)支持、asynchronous挂起恢复等等。 | +| 2.6.36 | 2010.10 | Tilera处理器架构支持、新的文件通知接口fanotify、Intel显卡上实现KMS和KDB的整合、并行管理工作队列、Inteli3/5平台上内置显卡和CPU的智能电源管理、CIFS文件系统本地缓存、改善虚拟内存的层级结构,提升桌面操作响应速度、改善虚拟内存溢出终结器的算法、整合了AppArmor安全模型(注:与SELinux基于文件的标注不同,AppArmor是基于路径的)。 | +| 2.6.37 | 2011.1.4 | Linux2.6.37包含了对Ext4和XFS的几个SMP可伸缩性改进,一个在禁用大内核锁的情况下编译内核的选项,对每个cgroup IO限制的支持,一个基于Ceph集群文件系统的网络设备,几个Btrfs改进,更有效的静态探测,对探测模块的性能支持和可访问列表本地和全局变量、使用LZO压缩的图像休眠、IPv4支持的PPP、一些网络微优化和许多其他小的更改、改进和新的驱动程序。 | +| 2.6.38 | 2011.3.14 | 此版本增加了对自动进程分组(在新闻中称为“wonder patch”)的支持、VFS的显著可扩展性改进、Btrfs LZO压缩和只读快照、对B.a.T.M.a.N.mesh协议(有助于在发生自然灾害、军事冲突或互联网审查时提供网络连接,)、透明的大页面支持(不使用hugetblfs)、在多个cpu上自动传播即将到来的网络流量、支持AMD Fusion apu、许多驱动程序和其他更改。 | +| 2.6.39 | 2011.5.18 | EXT4 SMP的可伸缩性改进,初始TCP拥塞窗口的增加,一种称为Unicore-32的新架构,一种允许创建称为IPset的网络资源组的功能,Btrfs更新,一种允许将崩溃信息存储在固件中的功能,以便在重新引导后恢复它,通过handle syscalls打开,perf更新,以及许多其他的小变化和新的驱动。 | +| 3.0 | 2011.7.21 | 除了一个新的版本编号方案,Linux3.0还有几个新的特性:Btrfs数据清理和自动碎片整理,XenDOM0支持,ECHO中没有特权的ICMP,WakeonWLAN,Berkeley包过滤器JIT过滤,一个类似memcached的页面缓存系统,一个对sendmsg()调用和setns()进行批处理的sendmsg()系统调用,一个系统调用允许更好地处理轻量级虚拟化系统,如容器。增加了新的硬件支持:例如,Microsoft Kinect、AMD Llano Fusion APU、Intel iwlwifi 105和135、Intel C600串行连接scsi控制器、Ralink RT5370 USB、多个Realtek RTL81xx设备或Apple iSight网络摄像头。增加了许多其他驱动和小的改进。 | +| 3.1 | 2011.10.24 | 支持OpenRISC 开源 CPU,对写回限制的性能改进,slab分配器中的一些加速,新的iSCSI实现,支持用于移动支付的近场通信芯片,通用软件RAID层中的坏块管理,一个新的用于电源管理的“cpupowerutils”用户空间实用程序、默认情况下在ext3中启用的文件系统屏障、Wii遥控器支持和新的驱动程序以及许多小的改进。 | +| 3.2 | 2012.1.4 | 此版本包括对大于4KB和小于1MB的ext4块的支持,这将提高大文件的性能;btrfs已更新为更快的清理、关键文件系统元数据的自动备份和用于手动检查文件系统的工具;进程调度器添加了对设置CPU时间上限的支持;在大量写操作的情况下,桌面的响应能力得到了改进,TCP被更新为包括一个算法,该算法可以在丢失数据包后加快连接的恢复;分析工具“perf-top”增加了对任务和库的实时检查的支持,并可以看到带注释的程序集代码;设备映射器增加了对任务和库的支持对于存储的“精简配置”,我们增加了一个新的架构:高通公司的Hexagon DSP处理器。在这个版本中还提供了其他驱动程序以及一些小的改进和修复。 | +| 3.3 | 2012.3.18 | 这个版本最重要的特点是合并了Android项目的内核代码。但是,它还包括对新体系结构(TI C6X)的支持、大大改进的平衡和Btrfs中不同RAID配置文件之间的重排能力,以及一些网络改进:为虚拟化场景设计的虚拟交换机实现(Open vSwitch),一种比“绑定”驱动程序更快、更可扩展的替代方案,对网络设备的传输队列进行可配置的限制,以抵抗缓冲区膨胀,网络优先级控制组和每个cgroup的TCP缓冲区限制。也有许多小功能和新的驱动程序和修复程序也可用。 | +| 3.4 | 2012.5.20 | 此版本包括几个Btrfs更新:支持大于4KB的元数据块,大大提高了元数据性能,更好的错误处理和更好的恢复工具;还有一个新的X32 ABI,它允许在64位模式下运行带有32位指针的程序;对GPU驱动程序的几项更新:Nvidia GeForce 600“开普勒”的早期模式设置,AMD Radeon 7xxx和AMD Trinity APU系列的支持,以及Intel Medfield graphics的支持;还支持x86 CPU驱动程序自动robing,一个设备映射器目标,它存储块的加密散列以检查入侵,另一个目标是使用外部只读设备作为精简配置的LVM卷的源,一些性能改进,如GTK2报表GUI和新的“Yama”安全模块。也有许多小功能和新的驱动程序和修复程序也可用。 | +| 3.5 | 2012.7.21 | 此版本包括对Ext4中的元数据校验和的支持,使用诸如StaseTAP或PERP之类的工具进行性能分析的用户空间探针,沙盘机制允许过滤SysCurts,设计了一种新的网络队列管理算法,用于打击Buffer-BuLAT,支持检查点和恢复TCP连接,支持TCP早期重传(RFC 5827)、支持Android风格的机会挂起、btrfs I/O故障统计以及通过Firewire和USB的SCSI。许多小功能和新的驱动程序和修复程序也可用。 | +| 3.6 | 2012.9.30 | 这个Linux版本在Btrfs中包含了一些新特性:子卷配额、配额组和快照差异(也称为“发送/接收”)。它还包括支持同时挂起到磁盘和内存、TCP“快速打开”模式、“TCP小队列”功能以防止缓冲区膨胀;支持通过NFS/NBD进行安全交换、更好的Ext4配额支持、支持PCIe D3cold电源状态;以及VFIO,允许从客户机驱动程序安全访问裸机主机设备。许多小功能和新的驱动程序和修复程序也可用。 | +| 3.7 | 2012.12.10 | 此Linux版本包括对ARM 64位体系结构的支持,ARM支持使用同一内核引导到不同系统,签名的内核模块,Btrfs支持使用chattr和faster fsync()在每个文件的基础上禁用写时拷贝,这是一个模仿strace的新“perf trace”工具,支持服务器端的TCP快速打开功能、实验性的SMBv2协议支持、稳定的NFS4.1和并行的NFS支持、允许通过UDP传输第2层以太网数据包的新隧道协议,以及支持Intel“管理器模式访问保护”(SMAP)安全功能。许多小功能和新的驱动程序和修复程序也可用。 | +| 3.8 | 2013.2.18 | 这个Linux版本在Ext4中支持在inode中嵌入非常小的文件,这大大提高了这些文件的性能并节省了一些磁盘空间。还有一个新的Btrfs特性,允许快速替换磁盘,一个为ssd优化的新文件系统F2FS,支持文件系统挂载,UTS,IPC,PIDs,以及为没有特权的用户提供的网络堆栈名称空间,内存资源控制器中的内核内存,XFS中的日志校验和,改进的NUMA策略重新设计和取消了对386处理器的支持。许多小功能和新的驱动程序和修复程序也可用。 | +| 3.9 | 2013.4.28 | 这个Linux版本包括对实验性RAID5/6模式的支持,以及对Btrfs中快照共享的文件进行更好的碎片整理;对Android SDK使用的“金鱼”模拟器的支持,能够将固态硬盘存储作为缓存设备;两个新的架构端口:Synopsys ARC 700和Meta Imagination处理器;ARM中的KVM虚拟化支持体系结构,一个Intel驱动程序,它“注入”空闲状态以提高每瓦特的性能,支持Chrome OS笔记本电脑,一个新的挂起电源状态,并删除过时的配置实验配置选项。许多小功能和新的驱动程序和修复程序也可用。 | +| 3.10 | 2013.6.30 | 此版本增加了对bcache的支持,它允许使用SSD设备缓存来自其他块设备的数据;Btrfs格式的改进,使专用于存储数据块信息的树小30-35%;支持XFS元数据校验和自描述元数据、无时钟多任务、SysV IPC,rwlock和mutex可伸缩性改进,减少短事务尾部延迟的TCP尾部丢失探测算法,MIPS体系结构中的KVM虚拟化支持,混合不同类型cpu的ARM big.LITTLE体系结构,跟踪快照,新驱动程序和许多小改进。 | +| 3.11 | 2013.9.2 | 此版本增加了对一个新的O_TMPFILE open(2)标志的支持,该标志允许轻松创建安全的临时文件,自r600以来所有Radeon GPU的实验性动态电源管理,对NFS4.2和标记为NFS的SELinux的初步支持,对Lustre分布式文件系统的实验性支持,对程序写入的页的详细跟踪,ARM对ARM64的巨大页面支持和KVM/Xen支持,SYSV IPC消息队列可伸缩性改进,低延迟网络轮询机制,压缩交换缓存,新驱动程序和许多小改进。 | +| 3.12 | 2013.11.2 | 此版本增加了对Btrfs中离线重复数据消除的支持,双GPU笔记本电脑中的自动GPU切换,对AMD Radeon图形的性能提升,更好的RAID-5多核性能,改进了对内存不足情况的处理,改进了VFS路径名分辨率的可扩展性,改进了无时间多任务模式,在图形DRM层中独立的模式设置和渲染设备节点,改进了虚拟化客户机的锁定性能,XFS目录递归可伸缩性改进,IPC可伸缩性改进,tty层锁定改进,新驱动程序和许多小的改进。 | +| 3.13 | 2014.1.19 | 此版本包括nftables,iptables的后续产品,为高性能固态硬盘设计的块层的改进,英特尔RAPL设备功耗上限框架,改进的squashfs性能,默认启用的AMD Radeon电源管理和自动Radeon GPU交换,改进的NUMA性能,改进的性能与庞大的网页工作负载,TCP快速开放默认启用,支持NFC支付,支持高可用性无缝冗余协议,新的驱动程序和许多其他小的改进。 | +| 3.14 | 2014.5.30 | 此版本包括实时任务的截止时间任务调度策略、内存压缩机制现在被认为是稳定的、锁定验证器到用户空间的端口、存储属性(如Btrfs中每个inode的压缩)的能力、对跟踪事件的触发器支持、对用户空间探测的改进,内核地址空间随机化,TCP自动合并某些类型的连接,一个新的网络包调度程序来对抗缓冲区膨胀,新的驱动程序和许多其他小的改进。 | +| 3.15 | 2014.6.8 | 这个版本在有硬盘的系统中恢复得更快,它增加了对原子交叉重命名两个文件的支持,它增加了新的fallocate(2)模式,允许删除一个文件的范围或将其设置为零,它增加了一个新的文件锁定API,内存管理更好地适应工作集大小的变化,它提高了FUSE写性能,它还增加了支持zram中的LZ4算法,允许从32位EFI固件加载64位内核,增加了对即将加入英特尔CPU的AVX-512矢量指令的支持,增加了新的驱动程序和许多其他小改进。 | +| 3.16 | 2014.8.3 | 此版本通过支持动态切换Nvidia卡上的时钟频率来提高性能,它还支持将用户空间内存映射到Intel设备上的GPU,XFS有一个免费的inode btree用于更快的inode分配,ARM64内核可以用作EFI存根,IPv6支持TCP Fast Open,一些radeon设备有更好的性能得益于改进的电源管理支持,支持Intel Cherryview图形,控制组获得了可选的统一层次结构模式,还添加了新的驱动程序和许多其他小的改进。 | +| 3.17 | 2014.10.5 | 此版本增加了对IP上USB设备共享的支持,对Xbox One控制器的支持,对Apple的thunderbolt的支持,一个新的sealing API,它限制了对共享内存文件描述符的操作,使开发人员可以更容易地进行共享内存编程,支持perf trace中的页面故障跟踪,在kexec中只支持使用有符号的内核、getrandom()系统调用以生成更安全的随机数以及图形“渲染节点”不再是实验性的。也有新的驱动和许多其他小的改进。 | +| 3.18 | 2014.12.7 | 此版本增加了对overlayfs的支持,它允许在单个装载点组合两个文件系统;支持将用户空间内存映射到Radeon设备上的GPU,一个bpf()系统调用,它允许上载可附加到事件的类似bpf的程序;一个为数据中心优化的TCP拥塞算法;Geneve虚拟化封装,支持在UDP上嵌入IP协议,通过批处理套接字缓冲区提高网络性能,以及可选的多队列SCSI支持。也有新的驱动和许多其他小的改进。 | +| 3.19 | 2015.2.8 | 此版本增加了对Btrfs清理和用RAID 5和6快速替换设备的支持,对帮助阻止缓冲区溢出的Intel内存保护扩展的支持,对AMD HSA体系结构的支持,对调试ARM Coresight子系统的支持,对Altera Nios II CPU体系结构的支持,用于路由和交换卸载的网络基础设施、有助于支持Beaglebone或Raspberry Pi等消费者开发板上的扩展总线的设备树覆盖、NFSv4.2中对穿孔和预分配的支持,以及Android活页夹已从暂存区移到稳定区。也有新的驱动和许多其他小的改进。 | +| 4.0 | 2015.4.12 | 此版本增加了对内核代码进行实况补丁的支持,主要目的是在不重启的情况下修复安全更新;DAX,当文件系统在具有持久内存存储的系统上运行时,避免使用内核缓存的方法;KASAN,一种动态内存错误检测器,允许在空闲和越界bug之后找到使用;lazytime,relatime的一种替代方法,它只会在缓存中进行访问、修改和更改时间更新,并有机会写入磁盘;允许overlayfs具有多个较低层,支持并行NFS服务器体系结构;以及dm-crypt CPU可伸缩性的改进。也有新的驱动和许多其他小的改进。 | +| 4.1 | 2015.6.21 | 此版本增加了对Ext4加密的支持,对管理群集raid阵列的实验性支持,一个记录所有对设备的写入并允许重放它们的新设备映射器目标,一个在块设备中打开持久性内存系统中的内存的驱动程序,对禁用多用户支持的支持,支持基于路径标签而不是长网络地址路由数据包的多协议标签交换,允许将BPF程序附加到kprobes以进行更好的探测,ACPI支持ARM64体系结构,以及允许改进软件rasterizer的虚拟GEM驱动程序。也有新的驱动和许多其他小的改进。 | +| 4.2 | 2015.8.30 | 此版本为现代AMD Radeon硬件添加了一个新的amdgpu驱动程序,一个使用客户机内部主机GPU功能的virtio GPU驱动程序,新的原子模式设置图形API已声明稳定,支持堆叠安全模块,更快和更可扩展的自旋锁实现,cgroup写回支持,以及重新引入H8/300架构。也有新的驱动程序和许多其他小的改进。 | +| 4.3 | 2015.11.1 | 此版本删除ext3文件系统,并保留Ext4作为主Ext文件系统,Ext4还可以挂载ext3文件系统;它还添加了userfaultfd(),一个用于处理用户空间中的页面错误的系统调用;membarrier(),一个用于在一组线程上发出内存屏障的系统调用;一个用于限制cgroup中的PID数量的PID控制器,更易于使用的“环境”功能;空闲页跟踪,更精确地跟踪应用程序使用的内存;支持IPv6标识符定位器寻址;网络轻量级通道、虚拟路由和转发精简版支持,以及许多其他改进和新驱动程序。 | +| 4.4 | 2016.1.10 | 此版本增加了对虚拟GPU驱动程序中3D支持的支持,该驱动程序允许虚拟化客户机中的3D硬件加速图形;对直接I/O和异步I/O的循环设备支持,该支持节省内存并提高性能;对开放通道ssd的支持,该设备共享Flash转换层的职责在操作系统中,TCP侦听器处理是完全无锁的,允许更快和更可扩展的TCP服务器;MD层中的日志RAID5修复了RAID写入漏洞;eBPF程序现在可以由没有特权的用户运行,它们可以被持久化,perf还增加了对eBPF程序的支持;一个新的mlock2()系统调用,允许用户请求在页面错误时锁定内存;并阻止轮询支持,以提高高端存储设备的性能。也有新的驱动和许多其他小的改进。 | +| 4.5 | 2016.3.13 | 此版本添加了一个新的copy*file*range(2)系统调用,允许在不通过用户空间传输数据的情况下复制文件;现代Radeon GPU的实验性Powerplay电源管理;Btrfs可用空间处理的可扩展性改进;支持GCC的未定义行为Sanitizer(-fsanitize=Undefined);设备映射器的verity目标中的转发错误更正支持;在madvise()中支持MADVFREE标志;新的cgroup统一层次结构被认为是稳定的;*SO*REUSEPORT UDP套接字的可伸缩性改进;epoll的可伸缩性改进,以及内存控制器中套接字的更好的内存计算。也有新的驱动和许多其他小的改进。 | +| 4.6 | 2016.5.15 | 此版本增加了对USB 3.1 SuperSpeedPlus(10 Gbps)的支持、新的分布式文件系统OrangeFS、更可靠的内存不足处理、对Intel内存保护密钥的支持、使应用层协议实现更简单和更快的功能、对802.1AE MAC级加密(MACsec)的支持、对V版的支持BATMAN协议的一个OCFS2在线inode检查器,支持cgroup名称空间,支持pNFS SCSI布局,以及许多其他改进和新的驱动程序。 | +| 4.7 | 2016.7.24 | 此版本增加了对最近RADON RX 480 GPU的支持,支持同一目录中的并行路径名查找,一个新的实验“SeeDuuls'频率调速器,它应该比现有的管理者更快和更精确,支持EFI 'Capsule'升级固件的机制,支持USB/IP中的虚拟USB设备,使模拟的手机像真正的USB设备一样工作;新的安全模块“LoadPin”,确保所有内核模块都从同一个文件系统加载;在ftrace接口中创建事件直方图的接口;支持将BPF程序附加到内核跟踪点;支持调用链perf trace实用程序中的事件,对Android的sync_文件围栏机制的稳定支持,以及许多其他改进和新的驱动程序。 | +| 4.8 | 2016.10.2 | 此版本增加了对在页面缓存中使用透明的大页面的支持,对eXpress Data Path的支持,这是一个高性能、可编程的网络数据路径;对XFS反向映射的支持,它是几个即将推出的功能的构建块;使用强化的usercopy对内存副本进行更严格的检查;支持IPv6安全标签(CALIPSO,RFC 5570);GCC插件支持;virtio vsocks,以方便客户/主机通信;新的Vegas TCP拥塞控制算法;文档已移动到reStructuredText格式,以及许多其他改进和新驱动程序。 | +| 4.9 | 2016.12.11 | 这个版本增加了对共享扩展数据块(cp——reflink支持)和XFS上的写时拷贝支持;虚拟映射的内核栈使内核更加可靠和安全;一个更高效的BPF分析器,使Linux部分地支持Dtrace;基于带宽测量而非数据包丢失的新的可选BBR-TCP拥塞控制算法;使用保护密钥硬件功能的系统调用;对Ara项目中的Greybus总线的支持;用于检测固件引起的延迟的硬件延迟跟踪程序,以及许多其他改进和新的驱动程序。 | +| 4.10 | 2017.2.19 | 此版本增加了对虚拟化GPU的支持,一个用于NUMA系统中缓存行冲突分析的新“perf c2c”工具,一个用于任务调度详细历史记录的新“perf sched timehist”命令,改进的写回管理应该使系统在重写负载下更具响应性,一个新的混合块轮询方法使用更少CPU比纯轮询,支持ARM设备,如Nexus5&6或Allwinner A64,允许将eBPF程序附加到cGroup的功能,一个实验性的MD RAID5写回缓存,支持Intel缓存分配技术,以及许多其他改进和新驱动程序。 | +| 4.11 | 2017.4.30 | 此版本增加了对多队列块层中可插入IO调度程序框架的支持,在关闭write hole的MD RAID5实现中的日志支持,对在SSD中放置的交换进行更可扩展的交换实现,一个新的STATx()系统调用,解决了stat()的缺陷,作为ftrace接口前端的新perf ftrace工具,对实现OPAL存储规范的驱动器的支持,对RFC7609中定义的共享内存通信RDMA协议的支持,所有VGA控制台的持久滚动缓冲区,以及许多新的驱动程序和其他改进。 | +| 4.12 | 2017.7.2 | 此版本包括一个新的BFQ I/O调度程序,它提供了更好的交互体验;它还包括对Radeon RX Vega图形卡的初步支持和对USB Type-C连接器的支持;对实时内核修补功能的改进,对允许关闭RAID5 write hole的Intel IMSM部分奇偶校验日志的支持;支持将OpenChannel ssd公开为设备块,并支持另一个I/O调度程序Kybe,它允许为读写配置延迟目标 | +| 4.13 | 2017.9.3 | 这个版本增加了Ext4对大量目录项的支持,Ext4对64k以下扩展属性的支持,异步I/O的改进,后台写入的错误处理的改进,块层的错误处理的改进,内核TLS加速,以及许多其他改进。 | +| 4.14 | 2017.11.12 | 此版本包括支持x86硬件中更大的内存限制(128PiB虚拟地址空间,4PiB物理地址空间);支持AMD安全内存加密;提供更好内核跟踪和更小内核大小的新放卷机;一种cgroup“线程模式”,允许在一组进程的线程之间分配资源;对zstd压缩算法的支持已添加到Btrfs和Squashfs中;支持从用户内存到套接字的数据零拷贝;更好的异步缓冲I/O支持;支持未来GPU所需的异构内存管理;在某些情况下更好的cpufreq行为;使用PCID CPU特性的更长生命周期的TLB条目;异步非阻塞缓冲读取;以及许多新的驱动程序和其他改进。 | +| 4.15 | 2018.1.28 | 除了处理Meltdown/Spectre的最新代码外,此版本还包括amdgpu驱动程序的模式设置和高级显示功能;改进了对具有SATA积极链路电源管理的系统的电源管理支持;开放RISC-V cpu的端口;对AMD cpu中虚拟内存加密的初始支持;对Intel的支持用户模式指令预防功能;cgroups v2中对CPU控制器的支持;允许直接写入由文件系统管理的持久内存的新mmap(2)标志;以及许多新的驱动程序和其他改进。 | +| 4.16 | 2018.4.1 | 除了处理CPU安全漏洞的最新代码外,此版本还宣布反向映射和reflink功能稳定,membarrier(2)添加了快速支持,SMB3 Direct(RDMA)支持,添加了x86 jailhouse hypervisor,它能够静态地将多核系统划分为多个所谓的单元,支持PowerPC内存保护密钥、AMD安全加密虚拟化的管理程序部分,以及许多新的驱动程序和其他改进。 | +| 4.17 | 2018.6.3 | 此版本增加了对AMD Radeon Vega 12的支持,并在支持的AMD Radeon GPU中默认启用“显示代码”;还添加了内核TLS接收路径;更有效的空闲循环,防止CPU在shallow idle states下花费太多时间;删除了八个未维护的体系结构,另一个,添加了Andes NDS32体系结构;XFS获得了lazytime支持;修改了CPU负载估计;支持Intel Cannonlake gpu并添加了内核内存一致性模型;以及许多新的驱动程序和其他改进。 | +| 4.18 | 2018.8.12 | 此版本包括新的“可重新启动序列”系统调用,它使编写可扩展的用户空间代码变得更容易;对未授权的装载的支持;旨在使用BPF提供netfilter功能的bpfilter项目的开始;零拷贝TCP接收API;对高性能网络的新AF-XDP地址系列的支持;对高通Snapdragon 845 SoC的支持;以及许多新驱动程序和其他改进的支持。 | +| 4.19 | 2018.10.22 | 此版本还增加了:CAKE network queue management用于对抗bufferbloat,其设计初衷是为了从最慢的ISP链路和路由器中挤出最大的带宽和延迟;支持保证cGroup的最小I/O延迟目标;对未来Wi-Fi 6(802.11ax-drafts)的实验性支持;overlayfs用户的内存使用得到了改进;一个实验性的、为只读使用而优化的EROFS文件系统;一个新的异步I/O轮询接口;支持避免对攻击者控制的FIFO或世界上可写的粘性目录中的常规文件的无意写入;支持一个Intel特性,它将部分CPU缓存锁定为一个应用程序;以及许多新的驱动程序和其他改进。 | +| 4.20 | 2018.12.23 | 此版本包括对测量系统负载的新方法的支持;它增加了对未来AMD Radeon Picasso和Raven2的支持,并启用了对Radeon Vega20的非实验性支持;它增加了对C-SKY CPU体系结构和x86 Hygon Dhyana CPU的支持;TLB微优化在某些工作负载中带来了小的性能优势;TCP已经切换到“提前离开时间”模式;一种将memfd区域转换为dma buf的机制允许qemu改进虚拟化图形性能;它还包括针对CPU安全漏洞的最新一轮修复;它还添加了许多新的驱动程序和其他改进。 | +| 5.0 | 2019.3.3 | 此版本包括对energy-aware调度的支持,该调度将任务唤醒到phone中更节能的CPU;它还包括对低功耗设备的adiantum文件系统加密;它增加了对amdgpu驱动程序中AMD Freesync(可变刷新率)的支持;它增加了对UDP中接收卸载和MSG_ZEROCOPY支持的支持;它增加了对ARM指针认证的支持;它增加了对cgroupv2中的cpuset资源控制器(它可以约束任务的CPU和内存节点位置)的支持;它增加了对binderfs的命名空间支持,它允许运行多个android实例;它增加了对btrfs中交换文件的支持;它还增加了许多新的驱动因素和其他改进。 | +| 5.1 | 2019.5.5 | 此版本包括用于异步I/O的高性能接口io_uring;它还增加了fanotify的改进,以提供在大型文件系统上监视更改的可伸缩方式;它增加了一种方法,允许在PID重用的情况下安全地传递信号;持久内存现在可以用作热插拔RAM;Zstd压缩级别可以在Btrfs中配置;它还添加了一个新的cpuidle调控器,比菜单调控器做出更好的电源管理决策;所有32位体系结构都添加了处理y2038问题所需的系统调用;现在可以在没有initramfs的情况下引导到设备映射器设备;而实时补丁增加了对创建累积补丁的支持。一如既往,还有许多其他新的驱动因素和改进。 | +| 5.2 | 2019.7.7 | 此版本包括Sound Open Firmware,这是一个将开源固件引入到DSP音频设备的项目;还包括许多英特尔产品的开放固件。此版本还改进了Pressure Stall Information资源监控,使其可供Android使用;通过新的系统调用重新设计了mount API;BFQ I/O调度程序获得了一些性能改进;新的CLONE*PI*DFD标志允许CLONE(2)返回*PIDFD*send_signal(2)可用的pidfs;Ext4已经获得了对不区分大小写的名称查找的支持;还有一个新的设备映射器目标,它模拟有失败扇区和/或读取失败的设备;已经添加了ARM Mali t4xx和更新的6xx/7xx的开源驱动程序。一如既往,有最新的CPU错误(MDS)和许多其他新的驱动程序和改进。 | +| 5.3 | 2019.9.15 | 此版本包括对AMD Navi gpu的支持;对umwait x86指令的支持,该指令允许进程在短时间内等待而无需spinning loops;一种“利用率限制”机制,用于增强手机中使用的功率不对称cpu的交互性;一个新的PIDFDXOPEN(2)系统调用,完成了让用户处理PID重用问题的工作;在0.0.0.0/8范围内提供了16百万个新的IPv4地址;支持Zaxin x86 CPU;支持英特尔速度选择,以便在Xeon服务器中更容易地进行电源选择;以及支持轻量级管理程序ACRN,这是为嵌入式物联网设备构建的。一如既往,还有许多其他新的驱动和改进。 | +| 5.4 | 2019.11.24 | 此版本包括kernel lockdown mode,旨在加强UID 0和内核之间的边界;virtio fs,一个高性能virtio驱动程序,它允许一个虚拟化的客户机去装载已导出到主机上的目录;fs-verity,用于检测文件篡改,如dm-verity,但是可以在文件上工作,而不是在块设备上工作;dm-clone允许对dm目标进行实时克隆;两个新的madvise()标志用于改进Android上的应用程序内存管理,支持新的Intel/AMD gpu,支持exfat文件系统,并删除EROFS文件系统的实验状态;一个新的haltpoll cpuidle驱动程序和调控器,大大提高了虚拟化客户机在空闲循环中进行客户机端轮询的性能;blk-iocost,一个I/O cgroup控制器,试图更准确地计算I/O的成本。一如既往,还有许多其他新的驱动和改进。 | + +由此可见Linux内核不断支持新的功能,不断变得更加的复杂。 + +### 二、openEuler 特性 + +华为服务器操作系统内部代号为 EulerOS,有近10年的技术积累,已广泛用于华为内部产品配套。同时,华为基于对鲲鹏处理器的深刻理解,在性能、可靠性、安全性等方面对 EulerOS 进行了深度优化。为促进多样性计算产业发展及生态建设,华为将把服务器领域的技术积累进行开源。2019年1月7日华为正式推出了鲲鹏920处理器,并开始着力构建鲲鹏生态。华为开发了基于鲲鹏处理器的TaiShan服务器,并开源了其内部代号为EulerOS的服务器操作系统[8],社区开源版被命名为“openEuler”。openEuler是一款开源操作系统。当前openEuler内核源于Linux,支持鲲鹏及其它多种处理器,能够充分释放计算芯片的潜能,是由全球开源贡献者构建的高效、稳定、安全的开源操作系统,适用于数据库、大数据、云计算、人工智能等应用场景。 + +在之后的连载过程中,我们会逐步分析openEuler对ARM架构的支持、进程机制、内存管理机制、文件系统、网络通信、虚拟化与容器技术、系统安全技术、设备驱动程序以及初始化过程,整个连载预计192期,通过本连载的持续学习,您将对openEuler的内核有一个较为细致的了解。为了为读者提供一些实践的机会,本连载在每章之后会有一些对本章知识应用方法的介绍,帮助大家能把知识运用于实际。 + +### 三、巨人的肩膀 + +其实,除了之前提到的Minix系统外,Linux系统本身也是站在巨人的肩膀上,在它发布之前操作系统就已经经过了长期的发展,下表展现了Linux更深的渊源[7]: + +| 时间 | 事件 | +| ---------------- | ------------------------------------------------------------ | +| **20世纪60年代** | MIT开发分时操作系统(Compatible TIme-Sharing System),支持30台终端访问主机;主机负责运算,而终端负责输入输出。 | +| **1965年** | Bell实验室、MIT、GE(通用电气公司)准备开发Multics系统,为了同时支持300个终端访问主机,但是1969年失败了。刚开始并没有鼠标、键盘,输入设备只有卡片机,因此如果要测试某个程序,则需要将读卡纸插入卡片机,如果有错误,还需要重新来过。(Multics:Multiplexed Information and Computing Service) | +| **1969年** | Ken Thompson(C语言之父)利用汇编语言开发了FIle Server System(Unics,即Unix的原型。因为汇编语言对于硬件的依赖性,因此只能针对特定硬件。这么做只是为了移植一款“太空旅游”的游戏。 | +| **1973年** | Dennis Ritchie和Ken Thompson发明了C语言,而后写出了Unix的内核 。其中90%的代码是C语言写的,10%的代码用汇编写的,因此移植时只要修改那10%的代码即可。 | +| **1977年** | Berkeley大学的Bill Joy针对他的机器修改Unix源码,称为BSD(Berkeley Software Distribution),Bill Joy是Sun公司的创始人。 | +| **1979年** | Unix发布System V,用于个人计算机。 | +| **1984年** | 因为Unix规定:“不能对学生提供源码”,Tanenbaum老师自己编写兼容于Unix的Minix,用于教学。 | +| **1984年** | Stallman开始GNU(GNU’s Not Unix)项目,创办FSF(Free Software Foundation)基金会。自由软件指用户可以对软件做任何修改,甚至再发行,但是始终要挂着GPL的版权。产品:GCC、Emacs、Bash Shell、GLIBC。 | +| **1985年** | 为了避免GNU开发的自由软件被其他人用作专利软件,因此创建GPL(General Public License)版权声明。 | +| **1988年** | MIT为了开发GUI,成立了XFree86的组织。 | +| **1991年** | 芬兰赫尔辛基大学的研究生Linus Torvalds基于gcc、bash开发了针对386机器的Lniux内核。 | +| **1994年** | Torvalds发布Linux-v1.0。 | +| **1996年** | Torvalds发布Linux-v2.0,确定了Linux的吉祥物:企鹅。 | + +在上面这张表中,有两个重要的项目对Linux的诞生产生了重要的影响,它们是Unix系统和GNU项目。在下面两篇连载中,我们将简要介绍Unix系统和GNU项目。下图展示了与Linux有关的操作系统发展史: + + + +### 四、结语 + +本小节中我们简要回顾了Linux内核的发展历史。Linux的成功不但让Linus还清了其DIY个人计算机的欠款,而且还让他收获了爱情——一位叫朵芙(Tove)的姑娘向他发来邮件,邀请他去约会。不知道Linus赴约的时候是否知道,邀请他的这个女生曾六次获得芬兰空手道冠军。“朵芙是第一个通过互联网方式接近我的女人,而我干脆就把她娶回了家。”多年以后,Linus回忆这一段经历,十分得意[1]。最后献上一句Linus的话与大家共勉[2]:“做自己喜欢的、并对其他人也有帮助的事情很重要。” + +参考文献 + +[1]http://tech.sina.com.cn/csj/2019-07-26/doc-ihytcitm4728357.shtml?cre=tianyi&mod=pchp&loc=4&r=0&rfunc=43&tj=none&tr=12 + +[2]https://www.sohu.com/a/251078953_355140 + +[3]https://baijiahao.baidu.com/s?id=1611958048582090280&wfr=spider&for=pc + +[4]https://blog.csdn.net/xiebingsuccess/article/details/91861871 + +[5]https://www.oschina.net/news/101070/linux-kernel-4-19-released + +[6]https://kernelnewbies.org/Linux_4.19 + +[7]https://www.cnblogs.com/alantu2018/p/8991158.html + +[8]http://baijiahao.baidu.com/s?id=1645207733241546990&wfr=spider&for=pc \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/Linux-OS-history.jpg b/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/Linux-OS-history.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1150f32f8963f7eb4a61a504f06442e4dc311832 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/002History-of-Linux-kernel-1/Linux-OS-history.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/003History-of-Linux-kernel-2.md b/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/003History-of-Linux-kernel-2.md new file mode 100644 index 0000000000000000000000000000000000000000..0b0774a25174913e44433cabd290006c909c43b5 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/003History-of-Linux-kernel-2.md @@ -0,0 +1,64 @@ +--- +title: 第三期Linux内核发展史-2 +date: 2020-08-06 +tags: + - Linur + - 内核 + - 发展史 +archives: 2020-08 +author: 罗宇哲 +summary: Linux内核发展史-2 +--- + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +Linux是由赫尔辛基大学的Linus Torvalds开发的,在系统开发期间得到了因特网上广大UNIX程序员的帮助。它最初只是受Andy Tanenbaum教授的Minix(—个小型的类UNIX系统)启发而开发的一个程序,纯属个人爱好,但后来它逐步发展成为一个完整的系统。Linux的成功来源于其之前操作系统和应用软件的已有工作,主要是UNIX和GNU。本小结我们将介绍一下UNIX的发展简史。 + +### 一、UNIX操作系统发展历史 + +UNIX操作系统最初是由贝尔实验室开发的,当时的贝尔实验室是电信业巨头AT&T(美国电报电话公司)旗下的一员。UNIX是在20世纪70年代为DEC(数字设备公司)的PDP系列计算机设计的,它现在已成为一种非常流行的多用户、多任务操作系统。UNIX操作系统可以运行在大量不同种类的硬件平台上,其适用范围从PC工作站一直到多处理器服务器和超级计算机。 + +UNIX系统的主要特点有[1]: + +1.简单性:许多很有用的UNIX工具是非常简单的,因此也是很小并易于理解的。 + +2.集中性:在UNIX中,当用户出现新的需求时,我们通常是把小工具组合起来以完成更复杂的任务,而不是试图将一个用户期望的所有功能放在一个大程序里。 + +3.可重用组件:将应用程序的核心实现为库。具有简单而灵活的编程接口、文档齐备的库可以常助其他人开发出同类程序,或者把这些技术应用到新的应用领域。 + +4.过滤器:许多UNIX应用程序可用作过滤器。也就是说,它们对输入进行转换并产生输出。 + +5.开放的文件格式:比较成功并流行的UNIX程序都使用纯ASCII码的文本文件或XML文件作为配置文件和数据文件。 + +6.灵活性:你不能期待用户都能非常正确地使用你的程序。所以,你在編程时应尽景考虑到灵活性,尽量避免随意限制字段长度或记录数目。 + +最初的Unix是用汇编语言编写的,一些应用是由叫做B语言的解释型语言和汇编语言混合编写的。B语言在进行系统编程时不够强大,所以汤普逊和里奇对其进行了改造,并与1971年共同发明了C语言。1973年汤普逊和里奇用C语言重写了Unix。在当时,为了实现最高效率,系统程序都是由汇编语言编写,所以汤普逊和里奇此举是极具大胆创新和革命意义的。用C语言编写的UNIX代码简洁紧凑、易移植、易读、易修改,为此后UNIX的发展奠定了坚实基础。 + +1974年,汤普逊和里奇合作在ACM通信上发表了一篇关于UNIX的文章,这是UNIX第一次出现在贝尔实验室以外。此后UNIX被政府机关,研究机构,企业和大学注意到,并逐渐流行开来。 + +1975年,UNIX发布了4、5、6三个版本。1978年,已经有大约600台计算机在运行UNIX。1979年,版本7发布,这是最后一个广泛发布的研究型UNIX版本。20世纪80年代相继发布的8、9、10版本只授权给了少数大学。此后这个方向上的研究导致了九号计划的出现,这是一个新的分布式操作系统。 + +1982年,AT&T基于版本7开发了UNIX System Ⅲ的第一个版本,这是一个商业版本仅供出售。为了解决混乱的UNIX版本情况,AT&T综合了其他大学和公司开发的各种UNIX,开发了UNIX System V Release 1。 + +这个新的UNIX商业发布版本不再包含源代码,所以加州大学柏克莱分校继续开发BSD UNIX,作为UNIX System III和V的替代选择。BSD对UNIX最重要的贡献之一是TCP/IP。BSD有8个主要的发行版中包含了TCP/IP:4.1c、4.2、4.3、4.3-Tahoe、4.3-Reno、Net2、4.4以及4.4-lite。这些发布版中的TCP/IP代码几乎是现在所有系统中TCP/IP实现的前辈,包括AT&T System V UNIX和Microsoft Windows。其他一些公司也开始为其自己的小型机或工作站提供商业版本的UNIX系统,有些选择System V作为基础版本,有些则选择了BSD。BSD的一名主要开发者,比尔·乔伊,在BSD基础上开发了SunOS,并最终创办了太阳计算机系统公司。 + +1991年,一群BSD开发者(Donn Seeley、Mike Karels、Bill Jolitz和Trent Hein)离开了加州大学,创办了Berkeley Software Design, Inc (BSDI)。BSDI是第一家在便宜常见的Intel平台上提供全功能商业BSD UNIX的厂商。后来Bill Jolitz离开了BSDI,开始了386BSD的工作。386BSD被认为是FreeBSD、OpenBSD和NetBSD、DragonFlyBSD的先辈。AT&T继续为UNIX System V增加了文件锁定,系统管理,作业控制,流和远程文件系统。1987到1989年,AT&T决定将Xenix(微软开发的一个x86-pc上的UNIX版本),BSD,SunOS和System V融合为System V Release 4(**SVR4**)。这个新发布版将多种特性融为一体,结束了混乱的竞争局面。 + +1993年以后,大多数商业UNIX发行商都基于SVR4开发自己的UNIX变体了。 + +UNIX System V Release 4发布后不久,AT&T就将其所有UNIX权利出售给了Novell。Novell期望以此来对抗微软的Windows NT,但其核心市场受到了严重伤害,最终Novell将SVR4的权利出售给了X/OPEN Consortium,后者是定义UNIX标准的产业团体。最后X/OPEN和OSF/1合并,创建了Open Group。Open Group定义的多个标准定义着什么是以及什么不是UNIX。实际的UNIX代码则辗转到了Santa Cruz Operation,这家公司后来出售给了Caldera Systems。Caldera原来也出售Linux系统,交易完成后,新公司又被重命名为SCO Group。 + +下图以树状图的形式展示了从UNIX系统衍生出的各种操作系统[2]: + + + + +### 二、总结 + +本小节中我们简要介绍了有关Linux内核的一个重要基础——UNIX操作系统。下一小节我们将介绍Linux应用程序的一个重要来源——GNU。 + +参考文献 + +[1]《Linux程序设计(第四版)》 + +[2] https://www.cnblogs.com/alantu2018/p/8991158.html \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/Derivate-OS-of-NUIX.gif b/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/Derivate-OS-of-NUIX.gif new file mode 100644 index 0000000000000000000000000000000000000000..3ea5b2b4e56fab916aefa3998871f4fc66f7cfaf Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/003History-of-Linux-kernel-2/Derivate-OS-of-NUIX.gif differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/004History-of-Linux-kernel-3/004History-of-Linux-kernel-3 .md b/web-ui/docs/zh/blog/luoyuzhe/004History-of-Linux-kernel-3/004History-of-Linux-kernel-3 .md new file mode 100644 index 0000000000000000000000000000000000000000..be1228f19b5ffa1b49389e65151e319a7f709df2 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/004History-of-Linux-kernel-3/004History-of-Linux-kernel-3 .md @@ -0,0 +1,65 @@ +--- +title: 第二期Linux内核发展史-3 +date: 2020-08-06 +tags: + - Linux + - 内核 + - 发展史 +archives: 2020-08 +author: 罗宇哲 +summary: Linux内核发展史-3 +--- + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +这一小节我们主要介绍Linux系统应用程序的主要来源——GNU。 + +### 一、GNU + +Linux包含系统内核和提供系统服务和工具的应用程序两个部分。Linux所使用的应用程序是由许多程序元编写并自由发布的。Linux支持自由软件的概念,即软件本身不应受限,它们应遵守GNU(GNU是GNU's Not UNIX的递归缩写)通用公共许可证(GPL)[1]。软件通常是以源代码的形式发布的,但也可能需要支付一定的费用。这里提到的GNU项目最初是由自由软件基金会(Free Software Foundation)发起的,这个基金会的创始人是Richard Stallman。GNU项目的宗旨是:试图创建一个与UNIX系统兼容,但并不受UNIX名字和源代码私有权限制的操作系统和开发环境。[1]因此GNU为软件社区贡献了许多UNIX系统上应用程序的仿制品,这些应用程序都遵循GPL许可证。 + +下面是在GPL条款下发布的一些主要的GNU项目软件[1]: + +- GCC: GNU编译器集,它包括GNU C编译器。 +- G++: C++编译器,是GCC的一部分。 +- GDB:源代码级的调试器。 +- GNU make: UNIX make命令的免费版本。 +- Bison:与UNIX yacc兼容的语法分析程序生成器。 +- bash:命令解释器(shell)。 +- GNU Emacs:文本编辑器及环境。 + +许多其他的软件包也是在遵守自由软件的原则和GPL条款的情况下开发和发行的,包括电子表格、源代码控制工具、编译器和解释器、因特网工具、图形图像处理工具(如Gimp),以及两个完整的基于对象的环境(GNOME和KDE)。 + +### 二、常见开源协议简介 + +木兰协议:木兰协议是我国首个开源协议,这一开源协议共有五个主要方面,涉及授予版权许可、授予专利许可、无商标许可、分发限制和免责申明与责任限制。在版权许可方面,木兰协议允许“每个‘贡献者’根据’本许可证‘授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其‘贡献’,不论修改与否。”木兰协议比Apache License更友好一些,Apache License要求列出每个修改文件,其实很多项目做不到这一点,所以MulanPSL直接取消了这项要求[2]。 + +GPL协议:GPL协议采取两种措施来保护程序员的权利:(1)给软件以版权保护;(2)给程序员提供许可证。它给程序员复制,发布和修改这些软件的法律许可。在复制和发布方面,GPL协议规定“只要你在每一副本上明显和恰当地出版版权声明和不承担担保声明,保持此许可证的声明和没有担保的声明完整无损,并和程序一起给每个其他的程序接受者一份许可证的副本,你就可以用任何媒体复制和发布你收到的原始的程序的源代码。你可以为转让副本的实际行动收取一定费用。你也有权选择提供担保以换取一定的费用。”[3]GPL的出发点是代码的开源/免费使用和引用/修改/衍生代码的开源/免费使用,但**不允许**修改后和衍生的代码做为**闭源的商业软件发布和销售**。GPL协议的主要内容是只要在一个软件中使用(“使用”指**类库**引用,修改后的**代码**或者**衍生代码**)GPL协议的产品,则该软件产品必须也采用**GPL协议**,既必须也是**开源和免费**[4]。 + +LGPL协议:LGPL是一个为主要为**类库使用**设计的开源协议。和GPL要求任何使用/修改/衍生之GPL类库的的软件必须采用GPL协议**不同**。LGPL允许**商业软件**通过类库**引用(link)方式**使用LGPL类库而**不需要**开源商业软件的代码。这使得采用**LGPL协议**的开源代码可以被**商业软件**作为类库引用并发布和销售。但是如果**修改LGPL协议的代码**或者**衍生**,则所有修改的代码,涉及修改部分的额外代码和衍生的代码都**必须采用LGPL协议**[4]。 + +BSD协议:BSD开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。当你发布使用了BSD协议的代码,或者以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件: + +1.如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。 + +2.如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的BSD协议。 + +3.不可以用开源代码的作者/机构名字和原来产品的名字做市场推广。 + +BSD代码鼓励代码共享,但需要尊重代码作者的著作权。BSD由于允许使用者修改和重新发布代码,也允许使用或在BSD代码上开发商业软件发布和销售,因此是对商业集成很友好的协议[5]。 + +### 三、总结 + +本小节中我们简要介绍了有关Linux应用程序的一个重要来源——GNU。从下一小节开始我们将介绍Linux内核源码结构。 + +参考文献 + +[1] 《Linux程序设计(第四版)》 + +[2] https://iot.ofweek.com/2019-08/ART-132216-8120-30401877.html + +[3] https://baike.baidu.com/item/GPL/2357903?fromtitle=GPL%E5%8D%8F%E8%AE%AE&fromid=8274607&fr=aladdin + +[4] https://blog.csdn.net/xiaoxiao133/article/details/83049959 + +[5] https://www.runoob.com/note/13176 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/005Linux-kernel-source-structure-1 .md b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/005Linux-kernel-source-structure-1 .md new file mode 100644 index 0000000000000000000000000000000000000000..24a2d983d5aef4a5e31eeb429254a91f948e6bce --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/005Linux-kernel-source-structure-1 .md @@ -0,0 +1,71 @@ +--- +title: 第五期Linux内核源码结构-1 +date: 2020-08-06 +tags: + - Linux + - 内核 + - 源码 +archives: 2020-08 +author: 罗宇哲 +summary: Linux内核源码结构-1 +--- + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +在上一期中,我们介绍了Linux内核发展的历史,也介绍了与其相关的UNIX和GNU的相关知识。从这一期开始,我们将介绍Linux内核的源码结构。我们将先根据Linux源码的目录结构进行分析,到本文章发布前,Linux 4.19的最新版本为Linux 4.19.94,我们将依据openEuler开源社区源码并参考Linux 4.19.94版内核源码进行分析。 + +### 一、Linux内核源码的目录结构分析 + +下图列出了截至文章发表前openEuler开源社区kernel目录下的目录结构[5]: + + + + + + + +其中各个文件夹中**源代码的功能**如下表所示[1][3]: + +| **目录/文件名** | **源码功能简介** | +| ---------------- | ------------------------------------------------------------ | +| `/Documentation` | 说明文档,对每个目录的具体作用进行说明。 | +| `/arch` | 不同CPU架构下的核心代码。其中的每一个子目录都代表Linux支持的CPU架构。 | +| `/block` | 块设备通用函数。 | +| `/certs` | 与证书相关。 | +| `/crypto` | 常见的加密算法的C语言实现代码,譬如crc32、md5、sha1等。 | +| `/drivers` | 内核中所有设备的驱动程序,其中的每一个子目录对应一种设备驱动。 | +| `/include` | 内核编译通用的头文件。 | +| `/init` | 内核初始化的核心代码。 | +| `/ipc` | 内核中进程间的通信代码。 | +| `/kernel` | 内核的核心代码,此目录下实现了大多数Linux系统的内核函数。与处理器架构相关的内核代码在`/kernel/$ARCH/kernel`。 | +| `/lib` | 内核共用的函数库,与处理器架构相关的库在`/kernel/$ARCH/lib`。 | +| `/mm` | 内存管理代码,譬如页式存储管理内存的分配和释放等。与具体处理器架构相关的内存管理代码位于`/arch/$ARCH/mm`目录下。 | +| `/net` | 网络通信相关代码。 | +| `/samples` | 示例代码。 | +| `/scripts` | 用于内核配置的脚本文件,用于实现内核配置的图形界面。 | +| `/security` | 安全性相关的代码。 | +| `/sound` | 与音频有关的代码,包括与音频有关的驱动程序[2]。 | +| `/tools` | Linux中的常用工具。 | +| `/usr` | 该目录中的代码为内核尚未完全启动时执行用户空间代码提供了支持。 | +| `/virt` | 此文件夹包含了虚拟化代码,它允许用户一次运行多个操作系统。 | +| `COPYING` | 许可和授权信息。 | +| `CREDITS` | 贡献者列表。 | +| `Kbuild` | 内核设定脚本,可以对内核中的变量进行设定。 | +| `Kconfig` | 配置哪些文件编译,那些文件不用编译[4]。 | +| `Makefile` | 该文件将编译参数、编译所需的文件和必要的信息传给编译器。 | + +### 二、结语 + +本期我们根据openEuler的目录,并参考Linux目录结构简要介绍了openEuler kernel中各个子目录的功能,下一期我们将结合Linux 内核的Kernel Map介绍**Linux内核的基本功能和抽象层级**。 + +参考文献 + +[1] https://www.cnblogs.com/CaesarTao/p/10600462.html + +[2] http://blog.chinaunix.net/uid-30374564-id-5571674.html + +[3] https://blog.csdn.net/wangyachao0803/article/details/81380882 + +[4] https://blog.csdn.net/jianwen_hi/article/details/53398141 + +[5] https://gitee.com/openeuler/kernel \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-1.png b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-1.png new file mode 100644 index 0000000000000000000000000000000000000000..4fdfef00b595f6779b5ab7ae995bdc52f8a0dc0a Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-1.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-2.png b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-2.png new file mode 100644 index 0000000000000000000000000000000000000000..e06297fff41b070204e611ca381ee38ad2760921 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-2.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-3.png b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4158ee769a31414217b2fd93bf0e253ba3312e Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/005Linux-kernel-source-structure-1/Directory-structure-3.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/006Linux-kernel-source-structure-2.md b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/006Linux-kernel-source-structure-2.md new file mode 100644 index 0000000000000000000000000000000000000000..4924a3829d5e7fe21d51c3a978d4d47b000fe921 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/006Linux-kernel-source-structure-2.md @@ -0,0 +1,51 @@ +--- +title: 第六期Linux内核源码结构-2 +date: 2020-08-06 +tags: + - Linux + - 内核 + - 源码 +archives: 2020-08 +author: 罗宇哲 +summary: Linux内核源码结构-2 +--- + + _作者:罗宇哲,中国科学院软件研究所智能软件研究中心_ + +在上一期中,我们按照openEuler内核的目录结构简要介绍了openEuler内核目录中各个子目录的功能,这一期我们将简要介绍**Linux内核的基本功能和抽象层级。** + +### 一、Linux内核Kernel Map简介 + +Linux内核的Kernel Map从功能上将Linux内核划分为不同功能的区域,并展示了不同区域中函数互相之间的调用关系。下图展示了Linux 2.6.36版内核的Kernel Map[1]: + + + +从Kernel Map中我们可以看出,操作系统事实上提供了硬件资源的抽象,供用户程序调用,例如在图中操作系统管理的硬件资源有用户外设(如键盘、摄像头和图形卡等)、IO端口(如USB、PCI接口等)、CPU、内存、磁盘和网络设备等。 + +针对所有硬件资源的使用,在用户态程序看来都是一系列的系统调用,这些系统调用展示在user space interface层,例如对于进程来说有fork、execve等系统调用,分别用于创建新的进程和运行可执行文件等;而对于文件系统则有read和write等系统调用,用于读写文件等。Linux系统可以通过执行软中断将系统控制权交给内核,内核可以执行不同的系统调用再将结果返回[2]。下表列出了**Linux内核各系统调用的基本功能**[2]: + + + +硬件设备之上是设备驱动程序,驱动程序能控制硬件设备上的微控制器,如磁盘的磁盘控制器,来达到控制硬件设备的目的。然而,在高层的系统调用和设备驱动程序之间有着很大的鸿沟,需要用不同级别的软件抽象来实现。以用于管理磁盘的文件系统为例,对用户程序来说,只需要关注一般的读写功能统一函数接口就可以了,而不需要关注具体使用的是什么样的文件系统,例如是Ext2还是Ext4文件系统,这是因为虚拟文件系统(VFS)对这些不同的文件系统进行了统一的抽象。虚**拟文件系统与具体的文件系统的关系**如下图所示[3]: + + + +以Ext2文件系统的写数据为例,在调用用户态的write()接口的时候,需要传入文件描述符。内核根据文件描述符找到file,然后调用函数接口(file-\>fop-\>write)将数据写入文件。其中file结构体的fop指针就是在打开文件的时候通过inode初始化的[3]。这个过程如下图所示: + + + +此外,从Kernel Map中可以看出,有一些对系统资源抽象的重要功能,如进程/线程的调度,也在Kernel Map的中间层实现。注意在Linux中,进程和线程都是由task_struct数据结构来管理的,它们的区别在于线程间共享虚拟地址空间而进程的内存资源互相独立[4]。内核从靠近硬件的底层到靠近用户程序的高层,抽象程度逐渐提升,实现了提供给用户程序的各种硬件资源抽象和使用它们所需要的公共功能,最终抽象为系统调用供用户程序使用。内核程序一般运行在CPU的特权级别,可以访问系统的所有资源,而用户态程序运行在CPU的用户级别下,只能访问其进程的资源,这种设计增加了系统的稳定性。 + +### 二、结语 + +本期我们结合Linux内核Kernel Map简要介绍了Linux内核的基本功能和抽象层级,从下一期开始我们将介绍Linux内核编程环境。 + +参考文献 + +[1] https://makelinux.github.io/kernel/map/ + +[2] https://baijiahao.baidu.com/s?id=1604601045858159778&wfr=spider&for=pc + +[3] https://baijiahao.baidu.com/s?id=1621555464151870974&wfr=spider&for=pc + +[4] https://blog.csdn.net/u012218309/article/details/81912074 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-1.png b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-1.png new file mode 100644 index 0000000000000000000000000000000000000000..89746235ec11b37a3ad73c0412d9ccf3800bd2f8 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-1.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-2.jpg b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..331d29fa0e7befadaef21fe47c415f978cf579a0 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-2.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-3.jpg b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c37b5b74219b200a274fec497f774a9cdbb68f4f Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-3.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-4.jpg b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0369cf28774f814a0a401f3c405acb111b9f4a6 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/006Linux-kernel-source-structure-2/Kernel-6-4.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/1606730405603.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/1606730405603.png new file mode 100644 index 0000000000000000000000000000000000000000..66b3a8acff79dd4b223031289c7beeac081d16eb Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/1606730405603.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/1607262150081.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/1607262150081.png new file mode 100644 index 0000000000000000000000000000000000000000..e39b0f099ba935c6c9ca2e782eb9b0b88c35d5d0 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/1607262150081.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/Read-Copy Update.md b/web-ui/docs/zh/blog/luoyuzhe/RCU/Read-Copy Update.md new file mode 100644 index 0000000000000000000000000000000000000000..a782ef152aed2c4f3ad86c162a6dcae1b821daf2 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/RCU/Read-Copy Update.md @@ -0,0 +1,561 @@ +--- +title: openEuler中的Read-Copy Update机制 +date: 2021-01-05 +tags: + - kernel + - Read-Copy Update Mechanism +archives: 2021-01 +author: luoyuzhe +summary: 介绍openEuler中的RCU机制的基本原理、使用方法、相关的数据结构、静止状态监测机制和上报机制以及回调函数的处理机制等。 +--- + +# openEuler中的Read-Copy Update机制 + +​ 随着CPU核的指令执行速度的提升超过多核架构中延迟下降的速度,全局同步的开销将会被进一步加大,这种情况催生了更有效率的锁机制,Read-Copy Update(RCU)机制就是在这样的背景之下诞生的。RCU机制是针对读访问频率远高于写访问的数据结构而实际的一种非对称的读写同步机制。其基本原理是通过以提升写访问开销的代价换取读访问开销的下降,从而降低对数据结构频繁读少量写的整体开销。RCU机制对读操作不施加同步操作或者锁,从而对数据结构的更新不会阻塞读操作,这就意味着读操作有可能读到旧的值,而读旧值在RCU机制中是允许出现的。 + +​ 为了更好地理解RCU机制,我们需要首先了解以下基本概念: + +- 被保护的数据结构(Guarded Data Structure):被锁等同步机制保护的数据结构,如果没有这些机制的保护该数据结构就不能被安全地访问; + +- 静止状态(Quiescent state):在静止状态中的线程不保留任何被保护的数据结构的前置状态(prior state); + +- 静止期(Quiescent period):在一个静止期中,每一个线程都至少经历了一个静止状态; + + + +![image-20201122221131008](./image-20201122221131008.png) + +上图展示了静止状态和静止期之间的关系,在静止期中,线程1-4先后经历了一个静止状态。容易理解,任何一个包含静止期的时间段都是静止期。**静止期能够保证任何在静止期之前发生的对被保护数据结构的操作都能在静止期之后被观察到。** + +​ 在RCU机制中,读者可以无锁地对相关数据结构进行读取操作;当写者对相关数据结构进行写操作时,如果读者正在进行读者操作,那么写者需要将原数据结构重新拷贝一份,然后在重新拷贝的数据结构上进行更新操作,再等到适当的时机用新的数据结构替换旧的数据结构。这个合适的时机就是所有读者都退出的时机,这时候更新新的值,那么接下来的读者就能读到新值了。那么如何找到这个读者都退出的时机呢?这就是静止期的作用,如果线程最近经历了一个静止期,那么该线程没有保留所有之前的数据结构的状态,我们就可以确认线程的读操作都退出了。在操作系统中,典型的静止状态有CPU idle状态、运行用户程序、halt和进行上下文切换,在这些操作中,线程不再保留对任何内核数据结构的访问。 + +​ 下面我们来看一个RCU机制的例子,假设线程0正在更新链表中的元素B而线程1在无锁便利该链表: + +![image-20201122222732114](./image-20201122222732114.png) + +​ 如果线程0无法对元素B进行原子更新操作,那么在线程1的干扰下,它就无法直接修改元素B的值。根据RCU机制的规则,它首先将B拷贝到B Prime: + +![image-20201122222937227](./image-20201122222937227.png) + +​ 线程0更新被拷贝的B值后,元素A的下一个元素变成了B Prime,但这不影响线程1,因为元素B的旧值仍然存在且其下一个元素为C。现在,线程0只需要等待线程1不再访问元素B就能释放它了: + +![image-20201122223303691](./image-20201122223303691.png) + +​ 线程0等待一个静止期,这时候线程1已经无法再访问元素B了,是时候释放元素B的空间了: + +![image-20201122223428013](./image-20201122223428013.png) + +​ 释放元素B之后,链表中的B值已经被新的值替换: + +![image-20201122223518123](./image-20201122223518123.png) + +​ RCU机制中,我们需要了解合适静止期结束,从而我们需要一个静止期的检测算法: + +1. 任何需要等待静止期的实体将其在静止期后要进行的操作用回调函数的方式注册到其CPU的回调函数链表中; +2. 一段时间之后,该CPU通知其它CPU静止期开始; +3. 每个接到新静止期开始通知的其它CPU保存一个静止状态计数器的快照(我的理解,这个计数器保存了当前已经经历静止状态的CPU的数目,即一个CPU经历了静止状态后,就给该计数器进行加一的原子操作,一个静止期内一个CPU只有一次修改该计数器的机会); +4. 当每个CPU都发现其快照值与当前的静止状态计数器的快照值不同时,可以确定已经经历了一个静止期,最后一个经历静止状态的CPU同时记录已经经历了一个静止期; +5. 每一个CPU得知新的静止期结束后,调用其回调函数列表中注册的回调函数操作; + +在实际的系统设计中,操作系统往往需要支持大量的CPU,从而要求RCU机制具有良好的扩展性,树状RCU孕育而生。在现代操作系统中,**RCU原本设计中的静止期一般也被称为宽限期(grace period)**。实际上,RCU机制中的核心问题是确定何时静止期结束,从而能在适当的时候调用回调函数。然而,在大规模的多CPU系统中记录CPU的静止状态变得更加复杂,而树状RCU能更好地适应这种情况。树状RCU中有两种关键的数据结构:rcu_node和rcu_data。rcu_data用于记录每个处理器的静止状态,它是一个每处理器数据结构, 并构成rcu_node构成的树中的叶子节点中;rcu_node用于将其子节点的静止状态信息上传到根节点,以及从根节点将静止期信息传到CPU。一旦一个rcu_node的子节点全部上报了静止状态信息,该节点就会向父节点报告静止状态信息。当根节点收到了所有静止状态报告后,它会向叶子节点下发静止期结束的通知,从而处理器可以执行该静止期中或在更早的时间注册的回调函数,例如销毁对象的回调函数。 + +rcu_node在kernel/rcu/tree.h文件中: + +``` +/* + * Definition for node within the RCU grace-period-detection hierarchy. + */ +struct rcu_node { + raw_spinlock_t __private lock; /* Root rcu_node's lock protects */ + /* some rcu_state fields as well as */ + /* following. */ + unsigned long gp_seq; /* Track rsp->rcu_gp_seq. */ + unsigned long gp_seq_needed; /* Track rsp->rcu_gp_seq_needed. */ + unsigned long completedqs; /* All QSes done for this node. */ + unsigned long qsmask; /* CPUs or groups that need to switch in */ + /* order for current grace period to proceed.*/ + /* In leaf rcu_node, each bit corresponds to */ + /* an rcu_data structure, otherwise, each */ + /* bit corresponds to a child rcu_node */ + /* structure. */ + unsigned long rcu_gp_init_mask; /* Mask of offline CPUs at GP init. */ + unsigned long qsmaskinit; + …… + /* Only one bit will be set in this mask. */ + int grplo; /* lowest-numbered CPU or group here. */ + int grphi; /* highest-numbered CPU or group here. */ + u8 grpnum; /* CPU/group number for next level up. */ + u8 level; /* root is at level 0. */ + bool wait_blkd_tasks;/* Necessary to wait for blocked tasks to */ + /* exit RCU read-side critical sections */ + /* before propagating offline up the */ + /* rcu_node tree? */ + bool wait_blkd_tasks;/* Necessary to wait for blocked tasks to */ + /* exit RCU read-side critical sections */ + /* before propagating offline up the */ + /* rcu_node tree? */ + struct rcu_node *parent; + struct list_head blkd_tasks; + /* Tasks blocked in RCU read-side critical */ + /* section. Tasks are placed at the head */ + /* of this list and age towards the tail. */ + struct list_head *gp_tasks; + /* Pointer to the first task blocking the */ + /* current grace period, or NULL if there */ + /* is no such task. */ + + + + …… +} ____cacheline_internodealigned_in_smp; +``` + +其中gp_seq为本节点的当前静止期编号;qsmask记录了本节点的子节点的静止状态,一个bit为1表明该bit对应的子节点还没有报告静止期;level记录了本rcu_node在树中所处的层数,根节点处在第0层;parent指针指向本节点的父节点;blkd_tasks为阻塞进程列表,保存了在读端临界区里被其它进程抢占的进程;gp_tasks指向阻塞当前静止期的第一个进程。 + +rcu_data数据结构的源码也可以在同一个文件中找到: + +``` +/* Per-CPU data for read-copy update. */ +struct rcu_data { + /* 1) quiescent-state and grace-period handling : */ + unsigned long gp_seq; /* Track rsp->rcu_gp_seq counter. */ + unsigned long gp_seq_needed; /* Track rsp->rcu_gp_seq_needed ctr. */ + unsigned long rcu_qs_ctr_snap;/* Snapshot of rcu_qs_ctr to check */ + /* for rcu_all_qs() invocations. */ + union rcu_noqs cpu_no_qs; /* No QSes yet for this CPU. */ + bool core_needs_qs; /* Core waits for quiesc state. */ + bool beenonline; /* CPU online at least once. */ + bool gpwrap; /* Possible ->gp_seq wrap. */ + struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ + unsigned long grpmask; /* Mask to apply to leaf qsmask. */ + /* 2) batch handling */ + struct rcu_segcblist cblist; /* Segmented callback list, with */ + /* different callbacks waiting for */ + /* different grace periods. */ + …… + + int cpu; + struct rcu_state *rsp; +}; +``` + +其中gp_seq为本处理器看到的当前最高的静止期编号;cpu_no_qs数据结构记录了本处理器是否经历过静止状态; core_need_qs变量表示RCU需要本处理器报告静止状态;cblist本处理器中注册的回调函数列表;cpu是本处理器的编号;rsp则指向一个维护RCU全局状态的数据结构rcu_state。 + +RCU机制的基本流程,可以用rcu_read_lock(), rcu_read_unlock()和synchronize_rcu()三个API来描述。其中rcu_read_lock()函数用于进入读端临界区;rcu_read_unlock()用于退出读端临界区;synchronize_rcu()函数用于等待静止期结束。 + +例如对于如下一段代码: + +![1606730405603](./1606730405603.png) + +假设CPU0运行rcu_reader(),CPU1运行rcu_update(),那么该树状RCU包含两个rcu_data数据结构(分别对应CPU0和CPU1),它们的父节点为一个rcu_node: + +![image-rcu_example](./image-rcu_example.png) + +在理想状态下,CPU1将x设置为1并调用synchronize_rcu()等待静止期结束,synchronize_rcu()会阻塞CPU1中的进程并造成上下文切换,从而CPU1经历静止状态并由rcu_data记录;CPU0进入读端临界区,读取x和y的值,然后退出读端临界区,一个随后的上下文切换将会使CPU0的rcu_data记录静止状态,从而系统的静止期结束,这时候CPU1的rcu_update()函数可以将y值设置为1了。 + +其中rcu_read_lock()函数最终调用了函数 **__rcu_read_lock**() ,该函数将读端临界区嵌套次数加一,这种设计允许RCU读者在读端临界区里被其它进程抢占,然后迁移到其它处理器退出读端临界区, **__rcu_read_lock**() 的代码在kernel/rcu/tree_plugin.h文件中可以找到: + +![1607262150081](./1607262150081.png) + +相比于进入读端临界区只需要增加读端临界区的嵌套次数,退出读端临界区的过程较为复杂,其代码也在tree_plugin.h文件中: + +``` +/* + * Preemptible RCU implementation for rcu_read_unlock(). + * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost + * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then + * invoke rcu_read_unlock_special() to clean up after a context switch + * in an RCU read-side critical section and other special cases. + */ +void __rcu_read_unlock(void) +{ + struct task_struct *t = current; + + if (t->rcu_read_lock_nesting != 1) { + --t->rcu_read_lock_nesting; + } else { + barrier(); /* critical section before exit code. */ + t->rcu_read_lock_nesting = INT_MIN; + barrier(); /* assign before ->rcu_read_unlock_special load */ + if (unlikely(READ_ONCE(t->rcu_read_unlock_special.s))) + rcu_read_unlock_special(t); + barrier(); /* ->rcu_read_unlock_special load before assign */ + t->rcu_read_lock_nesting = 0; + } +#ifdef CONFIG_PROVE_LOCKING + { + int rrln = READ_ONCE(t->rcu_read_lock_nesting); + + WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2); + } +#endif /* #ifdef CONFIG_PROVE_LOCKING */ +} +EXPORT_SYMBOL_GPL(__rcu_read_unlock); +``` + +如果嵌套层数不为1,那么说明不是最后一个退出读端临界区的进程,只需要将嵌套层数减一;否则将嵌套层数设置为负数,这样如果被其它进程抢占,则其它进程会意识到该进程正在退出读端临界区的最外层,并继续执行从读端临界区退出的剩余部分,而这个被抢占的进程也会调用rcu_read_unlock_special()函数将自己从rcu_node的阻塞进程列表中删除,最后退出读端临界区最外层的进程将嵌套层数设为0。 + +synchronize_rcu()的代码也在tree_plugin.h文件中: + +``` +/** + * synchronize_rcu - wait until a grace period has elapsed. + * + * Control will return to the caller some time after a full grace + * period has elapsed, in other words after all currently executing RCU + * read-side critical sections have completed. Note, however, that + * upon return from synchronize_rcu(), the caller might well be executing + * concurrently with new RCU read-side critical sections that began while + * synchronize_rcu() was waiting. RCU read-side critical sections are + * delimited by rcu_read_lock() and rcu_read_unlock(), and may be nested. + * + * See the description of synchronize_sched() for more detailed + * information on memory-ordering guarantees. However, please note + * that -only- the memory-ordering guarantees apply. For example, + * synchronize_rcu() is -not- guaranteed to wait on things like code + * protected by preempt_disable(), instead, synchronize_rcu() is -only- + * guaranteed to wait on RCU read-side critical sections, that is, sections + * of code protected by rcu_read_lock(). + */ +void synchronize_rcu(void) +{ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu() in RCU read-side critical section"); + if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE) + return; + if (rcu_gp_is_expedited()) + synchronize_rcu_expedited(); + else + wait_rcu_gp(call_rcu); +} +EXPORT_SYMBOL_GPL(synchronize_rcu); +``` + +其基本作用是用于等待静止期的结束。它调用了wait_rcu_gp()函数,该函数会调用wake_me_after_rcu()函数等待所有读者退出临界区。当所有读者退出临界区后,wake_me_after_rcu()会唤醒wait_rcu_gp()函数,随后synchronize_rcu()函数就能返回调用者了。 + +那么如何判断静止期结束呢?在树状RCU中,当处理器经历了静止状态,还需将静止状态向上一层汇报,只有当根节点的所有成员都汇报了静止状态,当前静止期才可以结束。在报告静止期的过程中,首先时钟中断函数会调用函数rcu_check_callbacks(),该函数代码在kernel/rcu/tree.c文件中: + +``` +/* + * Check to see if this CPU is in a non-context-switch quiescent state + * (user mode or idle loop for rcu, non-softirq execution for rcu_bh). + * Also schedule RCU core processing. + * + * This function must be called from hardirq context. It is normally + * invoked from the scheduling-clock interrupt. + */ +void rcu_check_callbacks(int user) +{ + trace_rcu_utilization(TPS("Start scheduler-tick")); + increment_cpu_stall_ticks(); + if (user || rcu_is_cpu_rrupt_from_idle()) { + + /* + * Get here if this CPU took its interrupt from user + * mode or from the idle loop, and if this is not a + * nested interrupt. In this case, the CPU is in + * a quiescent state, so note it. + * + * No memory barrier is required here because both + * rcu_sched_qs() and rcu_bh_qs() reference only CPU-local + * variables that other CPUs neither access nor modify, + * at least not while the corresponding CPU is online. + */ + + rcu_sched_qs(); + rcu_bh_qs(); + rcu_note_voluntary_context_switch(current); + + } else if (!in_softirq()) { + + /* + * Get here if this CPU did not take its interrupt from + * softirq, in other words, if it is not interrupting + * a rcu_bh read-side critical section. This is an _bh + * critical section, so note it. + */ + + rcu_bh_qs(); + } + rcu_preempt_check_callbacks(); + /* The load-acquire pairs with the store-release setting to true. */ + if (smp_load_acquire(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs))) { + /* Idle and userspace execution already are quiescent states. */ + if (!rcu_is_cpu_rrupt_from_idle() && !user) { + set_tsk_need_resched(current); + set_preempt_need_resched(); + } + __this_cpu_write(rcu_dynticks.rcu_urgent_qs, false); + } + if (rcu_pending()) + invoke_rcu_core(); + + trace_rcu_utilization(TPS("End scheduler-tick")); +} + + +``` + +该函数首先检查了CPU是否经历了非Context Switch的静止状态,如用户模式或idle loop。如果是,那么调用rcu_sched_qs()函数将静止状态记录在CPU对应的rcu_data中;否则,判断该中断不是在软中断中触发,如果不是的话就调用rcu_bh_qs()函数记录静止状态。然后调用rcu_preempt_check_callbacks()函数,进而调用rcu_preempt_qs()函数记录静止状态。最后调用rcu_pending()函数检查是否有RCU相关的工作需要处理,如果有,那么调用invoke_rcu_core()函数,该函数的代码在同一个文件中: + +``` +static void invoke_rcu_core(void) +{ + if (cpu_online(smp_processor_id())) + raise_softirq(RCU_SOFTIRQ); +} +``` + +它触发了一个RCU软中断,该软中断的处理函数为rcu_process_call_backs(),从而一旦CPU有中断、抢占或底半机制使能的情况,就会调用rcu_process_call_backs()函数,这就启动了当前静止期的回调函数处理机制。rcu_process_call_backs()函数的代码在kernel/rcu/tree.c文件中可以找到: + +``` +/* + * Do RCU core processing for the current CPU. + */ +static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) +{ + struct rcu_state *rsp; + + if (cpu_is_offline(smp_processor_id())) + return; + trace_rcu_utilization(TPS("Start RCU core")); + for_each_rcu_flavor(rsp) + __rcu_process_callbacks(rsp); + trace_rcu_utilization(TPS("End RCU core")); +} +``` + +该函数调用了__rcu_process_callbacks()函数,其代码在同一个文件中可以找到: + +``` +/* + * This does the RCU core processing work for the specified rcu_state + * and rcu_data structures. This may be called only from the CPU to + * whom the rdp belongs. + */ +static void +__rcu_process_callbacks(struct rcu_state *rsp) +{ + unsigned long flags; + struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); + struct rcu_node *rnp = rdp->mynode; + + WARN_ON_ONCE(!rdp->beenonline); + + /* Update RCU state based on any recent quiescent states. */ + rcu_check_quiescent_state(rsp, rdp); + + /* No grace period and unregistered callbacks? */ + if (!rcu_gp_in_progress(rsp) && + rcu_segcblist_is_enabled(&rdp->cblist)) { + local_irq_save(flags); + if (!rcu_segcblist_restempty(&rdp->cblist, RCU_NEXT_READY_TAIL)) + rcu_accelerate_cbs_unlocked(rsp, rnp, rdp); + local_irq_restore(flags); + } + + rcu_check_gp_start_stall(rsp, rnp, rdp); + + /* If there are callbacks ready, invoke them. */ + if (rcu_segcblist_ready_cbs(&rdp->cblist)) + invoke_rcu_callbacks(rsp, rdp); + + /* Do any needed deferred wakeups of rcuo kthreads. */ + do_nocb_deferred_wakeup(rdp); +} +``` + +该函数首先调用rcu_check_quiescent_state(),后者检查是否有新的宽限期开始或者本处理器是否已经经历了一个静止状态,其代码在同一个文件中可以找到: + +``` +/* + * Check to see if there is a new grace period of which this CPU + * is not yet aware, and if so, set up local rcu_data state for it. + * Otherwise, see if this CPU has just passed through its first + * quiescent state for this grace period, and record that fact if so. + */ +static void +rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp) +{ + /* Check for grace-period ends and beginnings. */ + note_gp_changes(rsp, rdp); + + /* + * Does this CPU still need to do its part for current grace period? + * If no, return and let the other CPUs do their part as well. + */ + if (!rdp->core_needs_qs) + return; + + /* + * Was there a quiescent state since the beginning of the grace + * period? If no, then exit and wait for the next call. + */ + if (rdp->cpu_no_qs.b.norm) + return; + + /* + * Tell RCU we are done (but rcu_report_qs_rdp() will be the + * judge of that). + */ + rcu_report_qs_rdp(rdp->cpu, rsp, rdp); +} +``` + +如果处理器经历了一个静止状态,rcu_check_quiescent_state()函数调用rcu_report_qs_rdp()函数将静止状态记录到处理器的rcu_data中。在更新了处理器的状态后,__rcu_process_callbacks()函数将调用invoke_rcu_callbacks()函数处理当前静止期结束前注册的回调函数,其代码也在tree.c文件中: + +``` +/* + * Schedule RCU callback invocation. If the specified type of RCU + * does not support RCU priority boosting, just do a direct call, + * otherwise wake up the per-CPU kernel kthread. Note that because we + * are running on the current CPU with softirqs disabled, the + * rcu_cpu_kthread_task cannot disappear out from under us. + */ +static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) +{ + if (unlikely(!READ_ONCE(rcu_scheduler_fully_active))) + return; + if (likely(!rsp->boost)) { + rcu_do_batch(rsp, rdp); + return; + } + invoke_rcu_callbacks_kthread(); +} +``` + +如果处理器支持RCU priority boosting,则直接调用rcu_do_batch()函数处理回调函数;否则唤醒每处理器的kthread处理回调函数。rcu_do_bach()函数的代码也在tree.c文件中: + +``` +/* + * Invoke any RCU callbacks that have made it to the end of their grace + * period. Thottle as specified by rdp->blimit. + */ +static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) +{ + unsigned long flags; + struct rcu_head *rhp; + struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl); + long bl, count; + + /* If no callbacks are ready, just return. */ + if (!rcu_segcblist_ready_cbs(&rdp->cblist)) { + trace_rcu_batch_start(rsp->name, + rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist), 0); + trace_rcu_batch_end(rsp->name, 0, + !rcu_segcblist_empty(&rdp->cblist), + need_resched(), is_idle_task(current), + rcu_is_callbacks_kthread()); + return; + } + + /* + * Extract the list of ready callbacks, disabling to prevent + * races with call_rcu() from interrupt handlers. Leave the + * callback counts, as rcu_barrier() needs to be conservative. + */ + local_irq_save(flags); + WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); + bl = rdp->blimit; + trace_rcu_batch_start(rsp->name, rcu_segcblist_n_lazy_cbs(&rdp->cblist), + rcu_segcblist_n_cbs(&rdp->cblist), bl); + rcu_segcblist_extract_done_cbs(&rdp->cblist, &rcl); + local_irq_restore(flags); + + /* Invoke callbacks. */ + rhp = rcu_cblist_dequeue(&rcl); + for (; rhp; rhp = rcu_cblist_dequeue(&rcl)) { + debug_rcu_head_unqueue(rhp); + if (__rcu_reclaim(rsp->name, rhp)) + rcu_cblist_dequeued_lazy(&rcl); + /* + * Stop only if limit reached and CPU has something to do. + * Note: The rcl structure counts down from zero. + */ + if (-rcl.len >= bl && + (need_resched() || + (!is_idle_task(current) && !rcu_is_callbacks_kthread()))) + break; + } + + local_irq_save(flags); + count = -rcl.len; + trace_rcu_batch_end(rsp->name, count, !!rcl.head, need_resched(), + is_idle_task(current), rcu_is_callbacks_kthread()); + + /* Update counts and requeue any remaining callbacks. */ + rcu_segcblist_insert_done_cbs(&rdp->cblist, &rcl); + smp_mb(); /* List handling before counting for rcu_barrier(). */ + rcu_segcblist_insert_count(&rdp->cblist, &rcl); + + /* Reinstate batch limit if we have worked down the excess. */ + count = rcu_segcblist_n_cbs(&rdp->cblist); + if (rdp->blimit == LONG_MAX && count <= qlowmark) + rdp->blimit = blimit; + + /* Reset ->qlen_last_fqs_check trigger if enough CBs have drained. */ + if (count == 0 && rdp->qlen_last_fqs_check != 0) { + rdp->qlen_last_fqs_check = 0; + rdp->n_force_qs_snap = rsp->n_force_qs; + } else if (count < rdp->qlen_last_fqs_check - qhimark) + rdp->qlen_last_fqs_check = count; + + /* + * The following usually indicates a double call_rcu(). To track + * this down, try building with CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. + */ + WARN_ON_ONCE(rcu_segcblist_empty(&rdp->cblist) != (count == 0)); + + local_irq_restore(flags); + + /* Re-invoke RCU core processing if there are callbacks remaining. */ + if (rcu_segcblist_ready_cbs(&rdp->cblist)) + invoke_rcu_core(); +} +``` + +该函数遍历已经准备好的回调函数的列表,并执行函数,最后调用invoke_rcu_core()函数处理剩余的回调函数,invoke_rcu_core()函数直接触发rcu软中断: + +``` +static void invoke_rcu_core(void) +{ + if (cpu_online(smp_processor_id())) + raise_softirq(RCU_SOFTIRQ); +} +``` + +另一方面,唤醒每处理器的kthread处理回调函数的invoke_rcu_callbacks_kthread()函数的代码在kernel/rcu/tree_plugin.h文件中可以找到: + +``` +/* + * Wake up the per-CPU kthread to invoke RCU callbacks. + */ +static void invoke_rcu_callbacks_kthread(void) +{ + unsigned long flags; + + local_irq_save(flags); + __this_cpu_write(rcu_cpu_has_work, 1); + if (__this_cpu_read(rcu_cpu_kthread_task) != NULL && + current != __this_cpu_read(rcu_cpu_kthread_task)) { + rcu_wake_cond(__this_cpu_read(rcu_cpu_kthread_task), + __this_cpu_read(rcu_cpu_kthread_status)); + } + local_irq_restore(flags); +} +``` + +到这里为止,我们已经介绍了openEuler中RCU相关的一些基础知识,包括RCU的基本原理、RCU的使用方法、RCU相关的数据结构、RCU中的静止状态监测机制和上报机制以及回调函数的处理机制等。 + +------ + +参考文献 + +[1]Mckenney, Paul & SLINGWINE, JOHN. (1998). Read-copy update: Using execution history to solve concurrency problems. Parallel and Distributed Computing and Systems. + +[2] Liang L , Mckenney P E , Kroening D , et al. Verification of tree-based hierarchical read-copy update in the Linux kernel[C]// Design, Automation and Test in Europe Conference and Exhibition. 0. + +[3]《Linux内核深度解析》,余华兵著,2019 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122221131008.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122221131008.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6f10fed4a0c4920892d83be3f1c26d57d897f3 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122221131008.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222732114.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222732114.png new file mode 100644 index 0000000000000000000000000000000000000000..af46827192cc9170793379a5f50f6490d093292e Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222732114.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222937227.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222937227.png new file mode 100644 index 0000000000000000000000000000000000000000..285e2d9a24080490997471c0cb482cf2b825e7d3 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122222937227.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223303691.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223303691.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7099e9f216ad0165c424f77e7c124d986b7eea Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223303691.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223428013.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223428013.png new file mode 100644 index 0000000000000000000000000000000000000000..33e59353d660e466d561c610a03392cf7254d061 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223428013.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223518123.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223518123.png new file mode 100644 index 0000000000000000000000000000000000000000..ce370871e489f0db3db4e61e92aa0246351993b6 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-20201122223518123.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/RCU/image-rcu_example.png b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-rcu_example.png new file mode 100644 index 0000000000000000000000000000000000000000..415067efc3389209efcc90019f6f5b1254070527 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/RCU/image-rcu_example.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/TEE/Architecture.jpg b/web-ui/docs/zh/blog/luoyuzhe/TEE/Architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c75128a39ec44ffafedf446e4b347503e7b1905b Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/TEE/Architecture.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/TEE/Execution-Level.jpg b/web-ui/docs/zh/blog/luoyuzhe/TEE/Execution-Level.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3615c05da8848b0acadbd63a4e7fb1bbe8b296cc Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/TEE/Execution-Level.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE Architecture.jpg b/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE Architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c75128a39ec44ffafedf446e4b347503e7b1905b Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE Architecture.jpg differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE_For_OpenEuler.md b/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE_For_OpenEuler.md new file mode 100644 index 0000000000000000000000000000000000000000..aca00d02f6dc58e1edf6d9bd04da831043de1b9f --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/TEE/OP-TEE_For_OpenEuler.md @@ -0,0 +1,72 @@ +--- +title: openEuler与OP-TEE的适配 +date: 2021-01-10 +tags: + - Kunpeng920 + - OP-TEE +archives: 2021-01 +author: luoyuzhe +summary: 介绍openEuler与OP-TEE适配的相关知识 +--- + +# openEuler与OP-TEE的适配 + +Kunpeng920芯片支持ARM Trust Zone技术,理论上可以支持基于ARM的可信执行环境(Trusted Execution Environment)解决方法。Trust Zone技术将ARM CPU 的执行环境分为正常世界状态(Normal World State)和安全世界状态(Secure World State)两种状态,其中在正常世界状态执行的程序不能访问安全世界状态中的内存、缓存和其他外围安全硬件设备,从而提供了硬件级别的安全隔离。 + +在ARMv8架构中,CPU的执行等级可以分配EL0~EL3,其中EL0执行等级用于运行用户应用程序;EL1执行等级用于运行操作系统内核;EL2执行等级用于支持非安全操作下的虚拟化;EL3则用于安全世界状态和正常世界状态之间的转换。执行等级与安全状态之间的关系如下图所示: + +![](./Execution-Level.jpg) + + + +在上图中我们可以看到,Guest OS(如Linux,Android等)运行在正常世界状态中,它们的运行资源较为丰富,也被称为丰富执行环境(Rich Execution Environment)。而在安全世界状态中,则运行着安全操作系统(也叫可信执行环境操作系统,TEE OS )和安全应用(也叫可信应用 Trusted Application, TA)。即使REE不可信,它也无法访问安全世界状态中的系统资源,如安全设备、安全内存数据和安全缓存数据等。从而用户可以将敏感数据保存在安全世界状态中,然后由TA来完成相关的数据处理。运行在安全世界状态的代码可以访问REE侧的地址空间。REE侧的程序可以通过运行在正常世界状态的客户端应用(Client Application,CA)来获取安全世界状态中特定的数据和调用特定的功能。为完成安全世界状态和正常世界状态之间的切换,系统执行smc指令进入EL3的Secure Monitor模式,并在该模式下实现状态切换。 + +从硬件的角度来看,为实现Trust Zone, ARMv8架构(1)为总线增加了安全位;(2)对MMU中的页表增加了安全位;(3)为缓存增加了安全位;(4)为外围组件进行扩展,增加安全操作全新控制和安全造作信号。当主设备发起读写操作时,从设备能检查总线上的安全位,从而防止从正常世界状态访问安全设备。同时,TrustZone也通过地址空间控制组将将从设备地址空间分为安全空间和非安全空间,安全空间的地址将会拒绝正常世界状态的访问,这种机制也用于控制对片外DRAM的访问。对于片上ROM或片上静态ARM,Trust Zone通过内存适配器组件将其划分为安全区域和非安全区域。对于外设,Trust Zone则通过保护控制器组件区分安全外设和非安全外设。 + +OP-TEE( https://github.com/OP-TEE )是一款由Linaro和ST合作开发的开源TEE解决方案,它遵循GlobalPlatform规范,主要包含正常世界状态的客户端API(optee_client)、一个Linux内核的TEE设备驱动(optee_linuxdriver)和一个Trusted OS(optee_os)。其中Trusted OS 采用BSD开源协议,因此SoC厂商和设备厂商可以在不公布修改内容的情况下对OP-TEE进行修改,从而有利于OP-TEE进入商业产品中。OP-TEE的架构如下图所示: + +![](./Architecture.jpg) + +在上图中,GlobalPlatform TEE Client API在OP-TEE中由libteec库提供,共有10个。它们提供了REE侧的应用程序向TEE侧请求建立联系、请求分配共享内存以及发送命令等功能。这些信息经由OP-TEE在Linux中的驱动程序传递给TEE侧。TEE Supplicant则是REE侧的一个常驻进程,负责接收并处理来自TEE侧的请求。TEE侧的应用程序(Trusted Application, TA)通过远程过程调用(RPC)将请求通过OP-TEE驱动发送给REE侧。TEE Supplicant会监控驱动中来自TEE侧的RPC请求的状况,一旦接到请求就会对该请求进行解析和处理。常见的来自TA的RPC请求有TA镜像加载、REE侧文件系统操作、Socket操作和REE侧数据库操作等。OP-TEE在Linux中的驱动程序会为RPC请求创建一个请求队列,TEE Supplicant每次接到一个来自TEE侧的RPC请求后都会自动创建一个线程用于接收来自请求队列的其他RPC请求,从而实现RPC请求的并发处理。TEE Supplicant将RPC请求处理完成后将处理结果通过OP-TEE驱动发送给TEE侧。 + +在ARMv8架构上OP-TEE和Linux内核的加载和启动过程一般是由ARM可信固件(ARM Trusted Firmware, ATF)来完成的。ATF提供了统一的ARM底层接口标准,从而便于代码移植,其主要功能如下[1]: + +> - 初始化安全世界状态运行环境、异常向量、控制寄存器、中断控制器、配置平台的中断; +> - 初始化ARM通用中断控制器(GIC 2.0 或 GIC 3.0)的驱动程序; +> - 执行ARM系统IP的标准初始化操作和安全扩展组件的初始配置; +> - 安全监控模式调用请求的逻辑处理代码; +> - 实现可信的板级引导功能,对引导过程中加载的镜像文件进行电子签名检查; +> - 支持自有固件引导,开发者可以根据具体需求将自有固件添加到ATF的引导流程中。 + +ATF完成了ARMv8的安全启动功能,其源代码分为bl1、bl2、bl31、bl32和bl33等部分,前一部分的代码用于加载后一部分的镜像文件,并提供后一部分代码的启动入口,在加载每一个镜像文件之前都会验证其电子签名以保证镜像文件的合法性。其中,bl31用于完成安全世界和正常世界之间的切换,bl32用于加载TEE OS,bl33用于加载REE OS。ATF的安全启动过程如下[1]: + +> 1. 执行Chip ROM; +> 2. 获取并验证bl1的电子签名信息; +> 3. 跳转到bl1,验证bl2镜像的电子签名信息; +> 4. 运行bl2镜像并验证bl31镜像的电子签名信息; +> 5. 运行bl31镜像,完成EL3运行状态的软件配置, 验证TEE OS镜像是否合法; +> 6. 启动TEE OS,验证BootLoader是否合法; +> 7. 启动BootLoader(嵌入式系统支持,服务器一般使用BIOS),验证内核或Recovery镜像是否合法; +> 8. 启动内核或Recovery镜像。 + +其中任何一步合法性验证失败都会导致系统挂死。其中,BootLoader一般用于嵌入式系统的启动过程,在服务器中一般使用BIOS,这就意味着在Kunpeng920启动的过程中,我们需要将上述过程中的BootLoader换成BIOS。OP-TEE启动BIOS的结构可以参考QEMU上运行OP-TEE所采用的BIOS结构。在QEMU上运行OP-TEE时,首先会通过编译过程生成bios.bin镜像文件,该文件中包含Linux Kernel的镜像、OP-TEE OS的镜像和rootfs的镜像。在启动过程中/bios/entry.S文件中的入口函数会进行中断向量表、BSS段和堆栈空间的初始化操作,并调用main_init_sec函数加载OP-TEE OS的镜像和调用main_init_ns函数启动Linux内核镜像。main_init_sec函数将OP-TEE OS镜像、Linux内核镜像、rootfs加载以及device tree相关信息到RAM中。在QEMU工程中device tree的信息处存放在DTB_START地址中而不是在bios.bin中(在openEuler中是否是这样?)。启动Linux的过程中会挂载rootfs和OP-TEE驱动。OP-TEE驱动是在编译阶段被编译到Linux内核镜像中的。最后,Linux在启动的过程中会自动创建TEE Supplicant作为常驻进程,该进程的启动信息时在编译时被写入/etc/init.d文件中的。 + +参考以上过程,在Kunpeng920上适配OP-TEE的初步方案如下: + +1. 基于QEMU-v8的OP-TEE编译文件进行修改,去掉与QEMU相关的编译项; +2. 基于QEMU-v8编译结果进行bios修改,注意device tree的加载过程; +3. 修改ATF的安全引导过程,将BootLoader换成修改后的bios,这一过程应该可以通过ATF支持的自有固件引导实现。 + + + + + +------ + +### 参考文献 + +[1]《手机安全和可信应用开发指南:Trust Zone与OP-TEE技术详解》帅峰云,黄腾,宋洋著,2018 + +[2] https://www.linaro.org/blog/op-tee-open-source-security-mass-market/ + +[3]https://blog.csdn.net/yiyueming/article/details/72897362 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/1.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/1.png new file mode 100644 index 0000000000000000000000000000000000000000..523d165e7c8ec25103755ad389f337b0c5ee7552 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/1.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/10.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/10.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e9181f21edc9e07f69489873af5b9c1bc7a34d Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/10.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/11.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/11.png new file mode 100644 index 0000000000000000000000000000000000000000..b63014caee4769a79675ac18221d050d6b9f4b74 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/11.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/12.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/12.png new file mode 100644 index 0000000000000000000000000000000000000000..0898e823638a0958d347302ba3a2cc40c05ed21c Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/12.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/2.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/2.png new file mode 100644 index 0000000000000000000000000000000000000000..3cb9164a8080872803439c524d0faedaa2bb88b0 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/2.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/3.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/3.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b58506b507d9abf2f01a8dd505a1a90bce8f6b Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/3.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/4.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/4.png new file mode 100644 index 0000000000000000000000000000000000000000..d47013571029c99ace3673e19b823b9393cfcb46 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/4.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/5.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/5.png new file mode 100644 index 0000000000000000000000000000000000000000..9f76d548019b8028e20afc0512b40739b104a98e Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/5.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/6.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/6.png new file mode 100644 index 0000000000000000000000000000000000000000..38b6c6a8787d217847e76ded4921591afc1dd868 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/6.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/7.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/7.png new file mode 100644 index 0000000000000000000000000000000000000000..e19f07a54ef2740ac7ee2faacec709f17248cc6c Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/7.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/8.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/8.png new file mode 100644 index 0000000000000000000000000000000000000000..909e2a0e62075a1d4bd681e0610675dad9b37fc2 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/8.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/9.png b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/9.png new file mode 100644 index 0000000000000000000000000000000000000000..35049d9b44bb12d5d9dc0922dcc913a4b5db5c27 Binary files /dev/null and b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/9.png differ diff --git a/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/The_Communication_Of_Threads_In_openEuler.md b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/The_Communication_Of_Threads_In_openEuler.md new file mode 100644 index 0000000000000000000000000000000000000000..68dcc30e9b0e7f7bb2ed6487cd8074d12f48c5b8 --- /dev/null +++ b/web-ui/docs/zh/blog/luoyuzhe/The_Communication_Of_Threads_In_openEuler/The_Communication_Of_Threads_In_openEuler.md @@ -0,0 +1,178 @@ +--- +title: openEuler中的排队读写锁 +date: 2021-01-05 +tags: + - kernel + - 排队读写锁 +archives: 2021-01 +author: luoyuzhe +summary: 介绍openEuler中排队读写锁,涉及自旋锁与原子操作等相关知识 +--- + +# openEuler中的排队读写锁 + +同一个线程组中的线程共享了数据结构mm_struct和vm_area_struct,从而实现对内存的共享。然而,当两个线程同时需要访问同一块被共享的内存时,会出现竞争,也就是说两个线程访问该内存的顺序可能不确定,从而导致程序的输出结果不确定。为了保证线程访问共享变量的顺序是程序员期望的,我们需要线程间通信的机制,常用的线程间通信机制有锁和信号量。锁和信号量机制可以用于保证同一时间只有一个线程进入访问某一共有资源的程序片段,这样的程序片段被称为临界区。openEuler中的锁有自旋锁和互斥锁。本期我们介绍自旋锁,包含排队自旋锁和排队读写锁。 + +自旋锁用于保护较短的临界区,在临界区内不允许睡眠。自旋锁的定义代码在include/linux/spinlock_types.h文件中可以找到: + +![1604842309144](./1.png) + +这段代码封装了另一个结构体raw_spinlock,其定义代码在同一个文件中可以找到: + +1604842650827 + +arch_spinlock_t这个类型对于单处理器和SMP情形的定义是不同的,对于单处理器类型它的定义在spinlock_types_up.h这个文件中,而对于SMP情形则在spinlock_types.h文件中: + +1604843071888 + +对于单处理器情形,arch_spinlock_t类型被定义为空: + +![1605016728313](./4.png) + +对于SMP的情形,我们在arch/arm64/include/asm/spinlock_types.h文件中可以看到其定义包含在两个文件中: + +1604843758966 + +在qspinlock_types.h文件中我们可以找到arch_spinlock_t的定义: + +``` +typedef struct qspinlock { + union { + atomic_t val; + + /* + * By using the whole 2nd least significant byte for the + * pending bit, we can allow better optimization of the lock + * acquisition for the pending bit holder. + */ + +#ifdef __LITTLE_ENDIAN + struct { + u8 locked; + u8 pending; + }; + struct { + u16 locked_pending; + u16 tail; + }; +#else + struct { + u16 tail; + u16 locked_pending; + }; + struct { + u8 reserved[2]; + u8 pending; + u8 locked; + + }; + +#endif + }; +} arch_spinlock_t; +``` + +其中locked位表示锁的状态,该位为1表示锁不可获取,为0则表示锁可以获取;pending是未决位,该位为1时表示至少有一个线程在等待锁,该位为0时表示要么锁被持有但没有争用,要么等待队列已经存在[2]。 + +这两个文件中分为定义了排队自旋锁和排队读写锁,读写锁是自旋锁的改进,自旋锁在同一时刻只允许一个线程进入临界区,而读写锁则允许多个读者并发地访问临界区,但只允许一个写者在同一时刻访问临界区(也就是说写者和写者、读者和写者之间是互斥的,但读者和读者之间可以并发)。排队指的是使用队列算法来管理多个希望持有锁的线程,在openEuler中使用的是FIFO算法来管理排队等待的线程。排队自旋锁在参考文献[2]中已有详细介绍,本文主要介绍排队读写锁。 + +排队读写锁的定义代码在include/asm-generic/qrwlock_types.h 文件中可以找到: + +![1604844850419](./6.png) + +其中cnts原子变量的低9位用来标识该队列读写锁是否有写者持有,将该变量右移九位则表示持有该队列读写锁的读者数量。同时,我们可以看到该读写锁中还定义了一个排队自旋锁wait_lock。为了更好地理解这段代码,我们首先来了解一下openEuler中的原子变量和其操作。原子变量可以用来实现对整数变量的互斥访问,对原子变量的原子操作是不可分割的。原子变量用atomic_t类型标识,对原子变量常用的操作有[1]: + +- atomic_read(v):读取原子变量的值; +- atomic_add_return(i,v):把原子变量v的值加上i并返回新值; +- atomic_sub_return(i,v):把原子变量v的值减去i,并且返回新值; +- atomic_cmpxchg(v,old,new):如果原子变量v的值等于old,那么将v的值设置为new,并返回旧值; + +在openEuler中,include/linux/atomic.h文件中定义了一系列原子操作,如atomic_add_return_aquire: + +![1605003305448](./7.png) + +atomic_cmpxchg_aquire: + +![1605003249589](./8.png) + +使用这些原子操作,可以对队列读写锁中的cnts变量进行操作,例如在include/asm-generic/qrwlock.h 文件中的queued_read_trylock()函数中,首先使用atomic_read()函数读出原子变量cnts的值,如果没有写者持有该锁,则增加持有该锁的读者数量并返回1,否则维持读者数量不变并返回0: + +![1605004268622](./9.png) + +其中有关的定义值的定义如下: + +![1605004339762](./10.png) + +因此cnts & QW_WMASK用来检查是否有写者占有锁,而使用_QR_BIAS对cnts进行原子加则可以用cnts的高位对读者数量进行计数。再考察一下queued_write_trylock()函数: + +![1605011384999](./11.png) + +该函数通过判断cnts变量是否为0来判断是否有读者或写者已经占有该读写锁,如果已经占有,则抢锁失败;如果锁没有被读者或写者占有,则将cnts的低八位置为0xff,表示锁已经被写者持有。 + +再来看看queued_read_lock()函数,该函数在确认没有写者占有希望抢占的锁时调用queued__read_lock_slow_path()函数: + +![1605011841027](./12.png) + +该函数的代码在./kernel/locking/qrwlock.c文件中可以找到: + +``` +/** + + * queued_read_lock_slowpath - acquire read lock of a queue rwlock + + * @lock: Pointer to queue rwlock structure + */ + void queued_read_lock_slowpath(struct qrwlock *lock) + { + /* + * Readers come here when they cannot get the lock without waiting + */ + if (unlikely(in_interrupt())) { + /* + * Readers in interrupt context will get the lock immediately + * if the writer is just waiting (not holding the lock yet), + * so spin with ACQUIRE semantics until the lock is available + * without waiting in the queue. + */ + atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED)); + return; + } + atomic_sub(_QR_BIAS, &lock->cnts); + + /* + * Put the reader into the wait queue + */ + arch_spin_lock(&lock->wait_lock); + atomic_add(_QR_BIAS, &lock->cnts); + + /* + * The ACQUIRE semantics of the following spinning code ensure + * that accesses can't leak upwards out of our subsequent critical + * section in the case that the lock is currently held for write. + */ + atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED)); + + /* + * Signal the next one in queue to become queue head + */ + arch_spin_unlock(&lock->wait_lock); + } + EXPORT_SYMBOL(queued_read_lock_slowpath); + + +``` + +atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED))的含义是等待写者释放锁,如果有写者持有锁就一直等待。arch_spin_lock()通过排队自旋锁的机制将读者放入队列中,arch_spin_unlock()函数则将队列中的下一个读者放到队列头。在排队自旋锁的机制中队列机制中,如果锁处于可获取的状态,则线程直接获取锁;如果锁已经被其它线程持有了,但没有其它线程等待,那么线程以自旋的方式不断尝试获取锁;如果有更多的线程等待,那么线程组成队列,队列头的线程自旋并不断尝试获取锁,其余线程休眠[2]。有关这一部分的内容可以查看参考文献[2]第6章或参考文献[3]。写者获取锁的排队机制也是类似的,区别在于读者获取锁只需要等待写者释放,而写者获取锁需要等待其他读者和写者都释放。 + +--- + + + +### 参考文献 + +[1]《Linux内核深度解析》,余华兵著,2019 + +[2]《openEuler操作系统》,任炬、张尧学、彭许红编著,2020 + +[3]https://zhuanlan.zhihu.com/p/100546935 + diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-01.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-01.png new file mode 100644 index 0000000000000000000000000000000000000000..1a5c6a57bd438db30df59f9dde0b57596d53326d Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-01.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-02.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-02.png new file mode 100644 index 0000000000000000000000000000000000000000..a4ca563c31b0d3c2aba27a20b0a1a480a4699c2e Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-02.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-03.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-03.png new file mode 100644 index 0000000000000000000000000000000000000000..7a019250ded0b7854b3d3185148a29f7d0170341 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-03.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-04.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-04.png new file mode 100644 index 0000000000000000000000000000000000000000..699b287b8de429d837efeec27890a0a13b0ca1c2 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-04.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-05.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-05.png new file mode 100644 index 0000000000000000000000000000000000000000..ed78e12aff804afbf70508bd2ea3d9fe73594c62 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-05.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-06.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-06.png new file mode 100644 index 0000000000000000000000000000000000000000..e621a3f1817d0c2efaa66c6f2c41822f293276df Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-06.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-07.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-07.png new file mode 100644 index 0000000000000000000000000000000000000000..c2da9e5863b394a1fa0ad1e346fc6d1f7fd8601a Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-07.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-08.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-08.png new file mode 100644 index 0000000000000000000000000000000000000000..5951e30880c8e125652aaa44bb041cba0b9838ca Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-08.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-09.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-09.png new file mode 100644 index 0000000000000000000000000000000000000000..227c8305c8456399a1b51e64cb37b6f788da09e7 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-09.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-10.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-10.png new file mode 100644 index 0000000000000000000000000000000000000000..9a2c9b562d1a38ecb79175c0f8811af9940200e1 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-10.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-11.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-11.png new file mode 100644 index 0000000000000000000000000000000000000000..23a933080145c5c7797b19296a100a7438db17c9 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-11.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-12.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-12.png new file mode 100644 index 0000000000000000000000000000000000000000..c4caf1c1248d7425022d940acd6411e1a42889bd Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-12.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-13.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-13.png new file mode 100644 index 0000000000000000000000000000000000000000..df83169fd67aef6a0d3605d2c867bda28cb2d52e Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-13.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-14.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-14.png new file mode 100644 index 0000000000000000000000000000000000000000..6d33c81d2ae00f6d1d862737a897851e2b42f333 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-14.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-15.png b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-15.png new file mode 100644 index 0000000000000000000000000000000000000000..521ff9ff6d819af15459fa13bac2cefb2733acc6 Binary files /dev/null and b/web-ui/docs/zh/blog/myeuler/2020-05-13-openEuler-travel-15.png differ diff --git a/web-ui/docs/zh/blog/myeuler/2020-5-13-openEuler-Travel.md b/web-ui/docs/zh/blog/myeuler/2020-5-13-openEuler-Travel.md new file mode 100644 index 0000000000000000000000000000000000000000..9eb424ec39b8417d7cdfff858b45fdcff253df75 --- /dev/null +++ b/web-ui/docs/zh/blog/myeuler/2020-5-13-openEuler-Travel.md @@ -0,0 +1,470 @@ +--- +title: openEuler社区参与之旅 +date: 2020-05-13 +tags: + - 社区运营 + - 参与贡献 +archives: 2020-05 +author: myeuler +summary: openEuler社区参与之旅,介绍如何一步步参与到开源社区以及我能在社区贡献什么。 +--- + +## 引言 + +openEuler社区已经建立起来了,也有不少合作伙伴, OSV, ISV等参与进来。整个社区的治理结构也初步建立了起来。但毕竟是一个年轻的社区,因此有一些流程方面还有待优化,很多文档还有待于完善。 + +鉴于有很多希望参与到社区里的工程师对整个社区的运作流程,开发流程还比较陌生,我总结了一个文档来帮助一个工程师更容易的参与到社区中。 + +## openEuler社区概要 + +openEuler的主站点是https://www.openeuler.org/ + + + + +主站点主要是提供一些入口,对于工程师来说,最重要的应该是下载链接: + +https://www.openeuler.org/zh/releases.html + + + +除了下载以外,对工程师来说,真正的社区开始之旅的起点: + +https://www.openeuler.org/zh/developer.html + +这个链接给大家做了一个简要的引导,但是不幸的是,对于一个新人来说,信息量依然非常大,可能有些摸不到头脑。下面,就让我带着大家一步步的化繁为简的做一次openEuler参与之旅吧。 + +## 法律合规是第一步,也是最重要的一步 + +“开源”这两个字眼虽然在很大程度上代表了自由,奔放,随心所欲,符合码农天生追“自由飞翔”的特质。但是开源并不是法外之地,因此法律合规是一个社区健康发展最重要的前提,没有之一。因此,任何一个人,如果想要参与到openEuler项目中,第一步就是要签署CLA协议。协议的签署网址是: + +https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI= + +虽然协议并不复杂,但是作为一个码农,通常我都对这类法律文书都是免疫的,我们连需要给自己赔钱的保险合同都不会多花上一分钟时间看上一眼,对于这种需要自己奉献的条款又怎会关注呢?还有更关键的是,如果码农看懂了法律文书,那还是码农么? 虽然这很大程度是我们码农的现状,但是我还是建议大家认真阅读一下协议,了解一下权益范围并没有坏处。 + +## 我们是开源的 + +openEuler社区原则上只接受开源协议的软件,哪些开源协议是社区认可的开源协议呢?大家可以参考下面的网址。这个网站上所列举的开源协议都是openEuler社区所能接纳的协议。 + +https://opensource.org/licenses/alphabetical + +对于社区本身,我们默认使用mulan V2协议,https://opensource.org/licenses/MulanPSL-2.0,这是一个非常友好的开源协议,也欢迎大家更多的使用这个协议来开发开源软件。 + +## 我能做点什么 + +在签署完CLA协议,了解我们所认可的开源协议范围以后,需要完成社区的注册。 + +由于openEuler本身是开放到gitee.com上,因此需要大家在gitee上拥有账号。我们也衷心希望gitee能成长为世界级的代码托管平台。 + +当大家完成了这些过程以后,就需要考虑在社区里具体能做点什么了。参与社区有很多种方法和形式,如果总结起来,大体有下面的四类: + +1. 提交一些需求,或者bug,简单来说就是发觉哪里用的不爽,直接提要求。 或者在用openEuler的过程中发现了一些问题,然后需要在社区把这个问题提出来。 + +2. 为社区修正bug,这是更高一个层面的参与社区了,在这个层面,参与者实质上是以一个开发者的姿态进入到了社区中。一般我们都提倡,除了提出问题,更期待大家能解决问题。 + +3. 贡献软件包,发现openEuler缺失了一个软件包,帮openEuler把这个软件包补上。实际上贡献软件包的过程就是帮助openEuler提供更丰富功能的过程。希望随着大家的参与,openEuler能够成为一个“无所不有”的软件生态系统。 + +4. 开发新软件,有自己的一些想法,独立开发一个全新的软件,并将这个软件贡献到openEuler社区,成为openEuler发行版本中的一份子。 + + +我们就一个个来看看这4种参与方式如何进行把。 + + +## 网站和社区 + +在具体讨论这四类参与方法之前,我先给出三个网址链接。 + +1. https://www.openeuler.org/ + +2. https://gitee.com/openeuler/ + +3. https://gitee.com/src-openeuler + + +第一个网址是openEuler的门户网站,是供大家获取一些通用信息的地方,前面已经提到过了。而真正我们所谓的“社区”则是体现在2,3这两个网址上。 + +这两个网址互相有链接,它们分别长这个样子: + + + + + +长得这么像,为什么要分两个网址呢? 两者有什么分工呢?我们在后续讲解中会慢慢的给大家说清楚。 + +不论怎么样,这两个网址,以及里面的内容将会是社区工作的主要场所。虽然人机界面并不友好,但我相信对于码农来说这不是一个大问题,因为码农们的世界从来都不曾经友好过。 + + +## 参与方式一:提交需求&bug + +最基本参与社区的方式当然是要先用一用社区的物件,看看还有哪些需要改进的地方。提出一些有价值的建议和意见了。这几乎是最简单参与社区的方式了。 + +在社区中,我们提交问题都是通过“issue”机制来进行。但是在提交之前,提交人得先明确这个issue要提交给谁。在社区里,我们是一个个“repo”来对功能进行分组的。比如我们著名的Linux操作系统的“内核”(kernel)就有一个独立的“repo”(通常我们称之为“仓”)。 + +如果你发现了一个内核的问题,或者需求,那么就需要找到内核相关的repo地址:https://gitee.com/openeuler/kernel + +它的界面这个样子。 + + + +其中红圈里大家可以看到Issues这个字样,这就是我们所有问题&bug&需求的入口了。点进去以后可以看到: + + + + +红圈位置的按钮就是我们建立一个新的Issue的入口。 + +进入以后,就可以提交issue了,有分类栏来说明这个issue属于什么类别。 + + + +在这里,可能会有一些同学们会问:为什么没有一个bugzilla +?这是一个拷问灵魂的问题,是呀,为啥没有建立一个工程师们更为熟悉的bugzilla呢?我没有办法给出一个合理的解释,不过目前看越来越多的项目都逐步通过issue,PR等机制来管理项目,如果再独立构建一个bugzilla系统,那么和PR,Merge合入等的工作就需要进行交联,复杂度会增加,因此目前我们还是选择通过issue来管理bug和需求。 + +这里有一个小问题,我的问题需要提交到哪里去呢? + +### Issue的归宿 + +总体来说,提交issue分如下几类: + +1. 具体软件的问题直接提交到相关的软件repo中,比如上面所提到的kernel的repo中。 + +2. 社区中的一些基础设施用的不爽,比如网页看起来不顺眼等,提交到https://gitee.com/openeuler/infrastructure,基础设施组。 + +3. 如果是一些社区治理方面问题,例如技术选型,软件的增加,删除,gnome和KDE哪个更图形界面原教旨主义一些等问题可以提到https://gitee.com/openeuler/community里。 + +4. 如果你实在不知道该提到什么地方,就统统提交到https://gitee.com/openeuler/community-issue,这里会为你排忧解难。 + + +更为详细的issue提交流程可以参见如下的专业讲解。 + +https://gitee.com/openeuler/community/blob/master/zh/contributors/issue-submit.md + + +## 参与方式二:修复bug + +在社区里,通常我们希望提出问题并同时解决问题,如果有一个问题,当然最好的情况是同时提供问题解决的patch补丁。我们以社区的轻量化容器引擎iSulad为例,https://gitee.com/openeuler/iSulad,假定我们需要为iSulad提交一个patch补丁,基本流程如下: + +### 第一步:建立自己的分支 + + + +在红圈处先要Fork一个“分支”到自己的账号下。如果大家不清楚fork的含义,建议学习一下git的使用方法。在这里要提一句,无论如何,现代工程师要理解git的开发模式,不了解git在当代几乎会寸步难行。 + + +### 第二步,修改代码并生成Pull Request(简称PR) + +当fork完毕以后,大家可以在下图的红圈1中发现,目录已经从openEuler切换成了自己的账户。 + + + +接下来,就可以在自己的“分支”上进行代码的修改了。 + +修改完以后,点击红圈2中的+Pull Request,这可能是提交代码中最关键的一个步骤,这里会正式生成一个patch并送到https://gitee.com/openeuler/iSulad这个原始社区。 + +比如我修改了一个函数,增加了一行printf(“hello, world”)这行代码。那么PR看起来就是这样的: + + + +你需要为这个PR起一个名字,同时填写一个说明。分别是红圈1和2,最后确定patch没有问题以后,点击红圈3中的“创建”按钮提交。 + +你会在openEuler/iSulad上看到你所提交的PR,红圈一表明你提交的PR已经进入了iSulad的社区,红圈2中的数字228是这个PR的编号。同时这个PR的URL是:https://gitee.com/openeuler/iSulad/pulls/228 + + + +至此,作为一个patch提交者的工作就做完了,你剩下所要做的事情就是耐心的等待iSulad开发组的maintainer来审核你的patch,比如我相信今天晚上他会非常诧异,谁提交了这么一个stupid的patch,而且公然用useless demo这样的PR题目来挑战他脆弱而敏感的maintainer神经。 + + + +因此,你的PR可能有三种命运: + +1. 被iSulad社区接受。 + +2. 被iSulad社区残忍的拒绝。 + +3. 提出修改意见,修改后再提交PR。goto 1 + + +不仅仅是可以提交代码的PR,任何修改,甚至是为readme修正了一个拼写错误,所遵循的流程都一摸一样。 + + +更细致,更专业的介绍请参考: + +https://gitee.com/openeuler/community/blob/master/zh/contributors/Gitee-workflow.md + +这里有一步步的教程引导大家来提交。 + + +另外,PR的提交也在很大程度上体现了提交者的专业能力和亲和力。Be nice很重要,下面的链接可以帮助大家理解如何更优雅的提交一个PR。 + +https://gitee.com/openeuler/community/blob/master/zh/contributors/pull-request.md + + +好了,恭喜您,至此,您的第一次真正意义上的社区开发之旅就画上了一个完美的句号。 + + + +让我们进入下一个挑战环节,为openEuler增加一个新的软件包。 + + +## 参与方式三:贡献软件包 + +在能够为openEuler贡献一个软件包之前,需要我们的开发者理解两个基本的概念: + +1. 什么是Linux的软件包。或者说Linux操作系统是怎么组织的。 + +2. 如何制作一个软件包。 + + +### OS是怎么组织的 + +显然这是一个非常巨大的话题,可能需要写一本书来讲OS是怎么组织,怎么构建出来的。在这里我只能简要的给大家介绍一下。 + + +实际上,一个OS系统的组成既复杂,也简单。 + + +何所谓简单呢,其实OS本质上就是一堆安装包的大杂烩,就类似我们不论使用Windows也好,使用Android也罢,或者使用Linux,我们都经历过“安装”这个概念,就是从网上,或者是从“仓库”中下载一个安装包,然后安装到系统上,所以大家可以看到安装的“进度条”。实际上,一个OS的安装过程和在andorid上安装微信的道理一摸一样。只不过所谓的安装OS是需要一次性的要把几千个软件包按照一定的顺序安装到机器中。 + + +那么OS所谓的组织很复杂呢,大家可以想象以下,几千个软件,他们之间会有很多的交联关系,通常我们叫做“依赖关系”,就好比,如果你想用微信小程序,那么前提是必须先得有微信,那么安装微信小程序的前提就是必须要先安装微信。因此,即使我们考虑一个OS的安装过程,其实也是非常复杂的,必须要精确的计算哪些软件需要先安装,哪些需要后安装。随着系统的膨胀,那么这些软件包之间就形成了复杂的网状关系。即使我们这些行业内的人都为此头痛不已。 + + +讲了这么多,和我们的openEuler社区开发有啥关系呢?其实,上面的讲解是要让大家理解,任何OS的基本零件就是软件包,就类似组成人体的基本零件是细胞一样。这一个个软件包就是构成OS的一个个基本零件。 + + +在Linux的世界,有两种基本的安装包格式: + +#### RPM + +这个格式是redhat, suse, WindRiver, openEuler等所选用,目前在企业市场,基本是以这些厂家为主,因此rpm格式在商用企业市场用的比较多。 + +#### Deb + +这个格式是debian, Ubuntu, android使用的,目前在desktop,终端侧用的比较广泛。 + + +这两种格式本身没有什么优劣之分,只是不用厂商的选择而已。当然,对于客户,开发者来说,世界被割裂成为两个互不兼容的部分总归是一种不必要的残忍。对于这个问题社区也有不同的尝试,但目前为止还没有出现某个大一统的软件包格式能够终结这个分裂的世界。 + + +不过幸好我们有容器,很大程度上,容器的出现缓解了这个问题。那未来能不能找到一条优雅的技术道路将这些不兼容,将这些复杂的软件包的依赖带来的诸多痛苦一并解决掉呢?我把这个问题留给本文的爱好者吧,也许在你们中间就会出现这样的“历史终结者”。 + +所以,一个软件从源代码到能进入到我们的OS安装光盘中,要经历三个步骤。 + + + +#### 第一步: + +源代码开发阶段,也就是写程序的阶段。这个阶段可以在任何地方,可以在github,gitlab, gitee等代码托管平台上,也可以是自己的笔记本电脑上。 + +#### 第二步: + +将代码编译,生成二进制可执行程序。并且制作RPM软件包,其中“制作RPM”的过程实际上也是一种“编程”,只不过使用的是一种定义好的脚本语言,“程序”是一种叫做spec的文件。讲真,spec的编写是非常不符合老派程序员思维的,那种分段式的,跳跃式的,宏式的写法绝对挑战老派程序员的神经。所以,我们有很多很好的程序员,但是却很少有程序员能将一个程序真正制作成一个rpm包(或者deb包)。希望大家能挑战一下自己,成为一个RPMer。真的,不难,但是够你手忙脚乱一阵的。 + +我们有一个rpm的编写规范,可以供大家参考。 + +https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md + + +#### 第三步 + +将这些rpm包放在iso中,做成安装光盘。这一步一般的工程师不用感知,后台有自动化的系统来完整整个工作,而且相关的工具我们也会开源到openEuler中。也就是说,后续任何人都可以简单的为自己构建一个My Linux。 + + +那就让我们看看如果你有一个项目在github上,我们如何将它最终转变成为安装光盘上的一个软件包吧。 + + +### 首先,你得有一个组织 + +人生活在社会中,无时无刻不属于某个组织,并受到一些人的领导,比如白天,你需要属于某一个公司组织,晚上,你需要属于一个家庭组织。 + + +社区也一样,在你想要把一个软件做成软件包放到openEuler系统中之前,你需要明确两件事情: + +1. **你自己属于哪个组织**? + +2. **你要加入的这个软件包属于哪个组织**? + + +在openEuler社区中,它的基本“组织”单元是SIG组,也就是special interest group,我至今没有弄明白为什么“兴趣”要加上“特殊”这个极易产生歧义和联想的前缀。不过anyway,如果你想有归属感,你有两种选择: + +1. 寻找到和你具有同样“特殊爱好”的小组,然后申请加入。 + +2. 你的爱好太“特殊”以至于目前还没有志同道合的人,自己申请建一个。 + + +openEuler所有的SIG组都在https://gitee.com/openeuler/community/tree/master/sig列出来,大家可以参考。 + + +如果你有意愿,同时也展示了对某些“特殊爱好”有着深厚的积累或者惊人的天赋,那么欢迎你参照https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/README.md完成一个新的SIG组的申请。我不得不说,这个流程不光看起来有一些复杂,也不友好,实际操作起来也是这样的。但我相信这难不倒码农,我们不就是为了制造这些复杂和不友好而生的吗! + + +最后一步,当创建完SIG的PR申请以后,需要到技术委员会(TC)的例行会议上进行评审,在https://gitee.com/openeuler/community/tree/master/zh/technical-committee可以找到TC委员会的基本信息,还有联系方式,大家可以订阅TC的邮件列表来获取一些动态,特别是例会的信息。 + + +既然说到了TC(技术委员会),我们就简要讲一下openEuler的组织结构吧。 + +## 组织结构 + +openEuler是一个完全开放的组织架构,而且非常简单,https://gitee.com/openeuler/community这里可以看到基本的情况。 + + + +我想这副图已经说的很清楚了。 + + +### 开始干活,先要弄明白干什么 + +当然,即使你完全不属于任何一个SIG组,理论上也能提交一个软件包到openEuler中,只是被接受的概率相对较低而已。其主要原因是很难来评估相关提交的质量,SIG组很大的意义就在于一些专业方面的人能够为每次提交做出质量的保证。 + + +软件包本身必须是要属于某一个SIG的。以我自己常用的一个软件包为例,我每次写完程序以后,都总会执行一下cloc这个命令,看一下今天又新增了多少行代码,以期获得一下码农与生俱来的成就感,并中和一下写PPT带来的空虚和乏力感。 + + +显然cloc是一个开发类的工具,帮助码农统计代码行,幸运的是,拥有同样“特殊爱好”的人并不在少数,他们建立了一个dev-utils的SIG组,https://gitee.com/openeuler/community/tree/master/sig/dev-utils,我们可以将cloc这个软件归属于这个SIG组。 + + +### 如何把大象放到冰箱里 + +一般来说,增加一个软件包到openEuler中,需要如下的几个大步骤 + +1. 让系统为你的cloc软件包建立一个“仓”,也就是git仓。 + +2. 上传制作cloc软件包所需要的“零件” + +3. 将这个软件系统加入到openEuler的自动化编译系统中,由系统自动化构建出软件。 + + +#### 建仓 + +建仓其实就是提交一个PR,一般来说需要修改三个文件。 + +1. https://gitee.com/openeuler/community/blob/master/sig/dev-utils/README.md + +2. https://gitee.com/openeuler/community/blob/master/sig/sigs.yaml + +3. https://gitee.com/openeuler/community/blob/master/repository/src-openeuler.yaml + + +修改第一个文件README.md将你要加入的cloc软件的名字和地址放上去。 + +修改sigs.yaml文件,将cloc软件增加到dev-utils这个SIG分组下面。 + +修改src-openeuler.yaml将cloc增加到src-openeuler里。 + + +你要做的就是照猫画虎的把这三个文件修改了,然后提交PR就可以了。剩下的就是等待“命运的裁决”。 + + +当申请的结果被批准以后,你所需要的“仓”就会被系统自动建立起来,对于cloc来说,它的代码仓的位置在https://gitee.com/src-openeuler/cloc,这是PR被批准以后由系统自动为我建立的。 + + +剩下的时间,你就可以开始真正上传制作cloc软件的原材料了。 + +#### 上传软件包 + +一般来说,一个软件只需要上传两个“原材料”就足够制作一个软件包了。如下图所示: + + + +第一个材料:首先要上传这个软件包的spec文件,也就是告诉构建系统如何编译,制作cloc这个软件包。 + +第二个材料:cloc的源代码压缩包。 + +其它零件:如果spec中需要有patch,那么也需要把相关的patch文件上传到仓中。 + + +上传完毕一个软件包所需要的原材料,下一步就是要把这些原材料加入到构建系统中,使之能够被真正编译,生成一个实际的软件包。 + + +#### 加入构建系统 + +openEuler现在使用obs作为构建工具系统,大家可以参考下面的这个链接把自己的软件加入到obs中 + +https://gitee.com/openeuler/community/blob/master/zh/contributors/create-obs-package.md + + +加入到构建系统中,就意味着你的软件可以被系统自动编译,自动生成rpm包,继而在后续的openEuler发行版本中出现。 + + +#### TIPS + +在整个过程中有几点需要开发者要注意: + +1. 能够本地构建:提交的软件包首先要在自己的笔记本,或者服务器上能够编译通过。也就是如果你的软件包在本地无法构建成功,那么上传到openEuler社区也不会构建成功。因此。我们建议最好能下载最新的openEuler版本,安装以后通过rpmbuild等命令来进行构建验证。 + +2. 保证软件包可用:软件除了能够被编译和生成软件包,还要能正确运行,因此,在本地环境要保证制作出来的软件包能够: + +a) 正确的安装 + +b) 正确的卸载 + +c) 正确的升级 + +d) 软件的功能是正常的。 + +3. 保证多体系架构支持:openEuler目前支持x86_64和ARM64两种指令集,因此在构建过程中需要能够保证软件包在这两种环境下都能被正确编译和运行。虽然ARM64环境可能并不那么容易获取,但幸运的是,一般性软件在这两个系统上没有那么大的差异。 + +4. 保证正确的依赖关系:一个软件通常都需要依赖其它的一些软件才能运行,比如所有软件都需要依赖glibc这个库来执行,一些复杂的软件可能会依赖很多软件包来提供功能。这些软件包可能已经在openEuler社区中有了,也可能没有。如果没有,那么就需要同时在openEuler社区中将这这些软件包补齐才行。比如cloc这样一个小软件,缺需要依赖如下的几个perl的软件包: + +![img](http://image.huawei.com/tiny-lts/v1/images/e505b26c4c16514e5669_678x206.png@900-0-90-f.png) + +也就是说在提交cloc软件包的同时,也需要同时提交这几个软件包,这样才能保证cloc能够被系统正确的编译和构建出来。 + +5. 保证spec文件的规范性:要保证spec文件是“规范”的,避免将外部的spec直接引入到openEuler中,因为如前所述,因为选择包的范围,依赖关系,版本等都不相同,同时保证所有软件包spec是一致的,请依照前面的rpm制作规范中的内容来书写spec文件。 + + + +因此,制作一个软件包,有的时候远比想象中的要复杂一些。但好在这并不是一个难度很大的事情,只需要提交一个软件包,走一遍流程,后续就会轻车熟路了。 + + +## 参与方式四:开发新软件 + +上面讲的过程都是怎么给“别人”的软件提意见,怎么把“别人”做的软件添加到openEuler社区。但是每一个真正做软件的人内心都希望能拥有属于自己的作品,那么如何建立自己的作品,如何将自己的作品融入到openEuler社区呢? + + + +将自己的作品融入到openEuler社区有如下两种方法: + + +### 方法一:在其它社区开发,集成到openEuler中 + +假定你已经在github,gitlab或者gitee上拥有了自己的项目,那么只需要按照参与方式三那样,将软件加入到src-openeuler这个repo仓就可以了。 + + +### 方法二:在openEuler社区中开发,在openEuler中集成 + +另外一种方法是,直接在https://gitee.com/openeuler中建立项目,类似将项目“托管”到openEuler社区。比如现在社区中的iSula和A-Tune这样的项目就是这样的模式。 + + + + +至此,我相信所有人都能明白了为什么openEuler会建立两个仓: + +https://gitee.com/openeuler + +https://gitee.com/src-openeuler + + +openeuler这个仓是存储所有“原生态”的软件,也就是为原创性的软件提供一个展示的舞台,或者是一个孵化器平台。 + +而src-openeuler则是为openEuler的release发行版提供生成rpm包等构建信息等的地方。 + + +因此,当一个很有梦想,很有情怀的工程师突然有一天有了一个很棒的idea,那么他可以依照下面的过程来深度参与到openEuler中。 + +1. 在TC委员会的例会meeting中申请一个开源项目,比如项目名称叫做“broken_dream”。 + +2. 如果TC委员会认为这是一个很好的idea,并且认为值得为破碎的梦想提供一个机会,那么我们会在https://gitee.com/openeuler中建立一个repo,网址就是https://gitee.com/openeuler/broken_dream + +3. 这个项目在openeuler中持续开发和孵化,直到有一天,大家认为broken_dream已经足以成熟到为所有人提供破碎的梦想服务了,那么就可以在src-openeuler中建立一个仓,为broken_dream提供相关的spec文件,制作成为一个rpm。 + +4. 最终broken_dream.rpm会随着openEuler的发布版本走遍全世界,为世界人民提供broken_dream功能。 + + +我始终认为,一个工程师,在他的职业生涯中,至少要有一个,哪怕只有一个项目和他自己的名字是息息相关的。只有这样,才能在孙子,孙女骑在我们背上,问我们这辈子做的最棒的事情是什么的时候,我们可以让他们爬下来,然后直起身,看着他们天真无邪,对未来充满憧憬的大眼睛,认真的问他们:你知道broken_dream的作者是谁吗? + + +最后,我要感谢openEuler社区中每一个贡献者,特别是文档的撰写者们,文档对于码农们来说永远是痛苦的源泉,但正是各位文档的撰写者的辛勤工作,才使得本文能够有一个机会为大家呈现一个完整的openEuler参与之旅。 + + +## openEuler社区欢迎大家 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/openeuler/20190829_ai_summit.md b/web-ui/docs/zh/blog/openeuler/20190829_ai_summit.md new file mode 100644 index 0000000000000000000000000000000000000000..188f430fa9f4de8e43ee1959b29caa6863ecbf6e --- /dev/null +++ b/web-ui/docs/zh/blog/openeuler/20190829_ai_summit.md @@ -0,0 +1,62 @@ +--- +title: 华为马海旭:鲲鹏展翅,力算未来,共赢多样性计算时代 +date: 2019-08-29 +tags: + - theme +author: 华为智能计算 +archives: 2019-08 +summary: 8月29日,在第二届世界人工智能大会上,华为智能计算业务部总裁马海旭发表了《鲲鹏展翅,力算未来,共赢多样性计算时代》 的主题演讲。 +--- + +大家好,非常荣幸能参加本次世界人工智能大会,同时也感谢大家,在百忙之中莅临华为智能计算大会·上海站。计算是人类永恒的需求,是智能世界的源动力,华为一直持续投入计算产业,今天我将与大家一起分享,华为在计算产业的创新之路。 + +18世纪中叶以来,人类历史上先后经历了三次工业革命,蒸汽机推动了农耕文明向工业文明的过渡,电力促进了通信、钢铁、机械等工业兴起,极大提高了生产力,信息技术让国家和地区都进入到全球一体化的进程中。当前,人类正在迎来以智能技术为代表的第四次工业革命,人工智能、物联网、5G、机器人、生物工程等新技术已融入到人类社会的方方面面。智能技术成为经济增长的新动能,驱动产业数字化转型,智能技术作为关键引擎,将推动世界的进步与发展。 + +智能世界带来了丰富的应用,产生了海量的数据。根据华为GIV 2025预测,97%的大企业将使用AI,14%的家庭将拥有智能机器人,蜂窝车联网技术将嵌入到全球15%的汽车中,而全球58%的人口将享有优质的5G网络服务。丰富的应用将带来数据的爆炸增长,预计2025年全球每年的数据量将达到180ZB。丰富的应用和海量的数据对算力产生了极大的需求,而CPU的性能却从每年提升超过1.5倍降到1.1倍,摩尔定律逐渐失效,带来了算力供应的稀缺和昂贵,严重制约着行业数字化和智能化的发展。 + +为了应对这一矛盾,突破摩尔定律,华为提出了多样性计算理念,面向不同应用,通过多种算力组合,在系统级恢复摩尔定律,推动计算创新。 + +PU、NPU、GPU、FPGA等同时存在。华为聚焦把计算产业核心竞争力构筑在「鲲鹏处理器」和「昇腾AI处理器」上,鲲鹏面向通用计算场景,昇腾面向人工智能场景,通过两个芯片系列来引领计算产业迈向智能和多样性计算时代。 + +**华为从鲲鹏计算平台、昇腾计算平台和x86计算平台进行多样性计算战略布局:** + +- **基于鲲鹏计算平台**,打造面向通用计算的TaiShan服务器产品,在大数据、分布式存储、ARM原生等应用场景,为客户提供性能出众、能效更优、安全可靠的解决方案; + +- **基于昇腾计算平台**,打造面向AI计算的Atlas系列产品,在平台、架构、算法和应用软件等多个层次与业界ISV深入合作,共同实现普惠AI的战略目标; + +- **基于x86计算平台**,我们会继续与Intel保持合作,面向数据中心场景,引入智能加速和智能管理,持续为客户和合作伙伴提供有竞争力的计算产品。 + +今天的计算系统仍然遵循冯•诺依曼架构,由计算子系统、存储子系统、I/O子系统和管理子系统组成,同时随着人工智能的兴起,AI算力已经成为计算产品不可或缺的重要能力,对每一个子系统,都需要一颗关键的芯片。华为从2004年投资研发第一颗处理器芯片开始,历经15年,已累计投入超过2万名工程师,形成了以 “鲲鹏处理器 + 昇腾AI处理器”为核心的芯片族。 + +鲲鹏920是华为第三代处理器,单处理器拥有64核,整型计算的性能跑分达930分,超过当前业界处理器最高性能25%。基于鲲鹏处理器,我们打造了TaiShan系列服务器,其是华为在计算技术和整机工程方面17年长期积累的精品之作,充分优化了散热、高速互联、可靠性设计以及质量品控等工程工艺技术。泰山是中国的五岳之首,我们用泰山命名基于鲲鹏处理器的服务器,是希望TaiShan服务器能够引领中国的计算产业,成为计算标杆产品。 + +**TaiShan服务器包括三个型号:** + +> - **2280均衡型**,计算、存储和网络能力均衡,可适用于多种应用; + +> - **5280存储型**,适用于海量存储场景,单柜可达5.6PB容量; + +> - **X6000高密型**,适用于海量整型计算场景,单柜可达10240核,约等于5000台个人电脑的算力。 + + +华为在鲲鹏计算产业与各行业ISV共同孵化、完善了五大解决方案,在多个行业实现了规模商用,通过多核并行处理的优势,在大数据场景下性能比传统平台提升30%以上;通过内置数据压缩引擎与多核并行处理的优势,减少分布式存储场景66%的压缩时间,实现每秒I/O操作的性能提升20%以上;在数据库、原生应用以及云服务场景,TaiShan服务器都表现出了极致的性能。 + +**下面我为大家介绍一下华为全栈全场景AI解决方案。** + +我们提出的全场景,是指包括公有云、私有云、各种边缘计算、物联网行业终端以及消费类终端等应用场景。全栈是技术功能视角,包括芯片、芯片使能、训练和推理框架和应用使能在内的全堆栈方案。 + +昇腾(Ascend)系列AI处理器,采用华为自研的面向张量计算的达芬奇架构,通过独创的3D Cube设计,每时钟周期可以进行4096个16位半精度浮点MAC运算,为人工智能提供强劲的算力支持。昇腾310在2018年10月10日已经上市,面向推理场景,具有极致高能效,8W功耗可以提供16TOPS INT8的算力。昇腾910在上周8月23日刚刚进行了全球上市发布,获得业界一致关注与好评,是目前面向训练场景中算力最强的AI处理器,性能是当前主流产品的2倍,在今年9月18日上海的华为全联接大会上,华为还将重磅发布基于昇腾910的系列新品,让我们共同期待。 + +基于昇腾AI处理器,我们开发了Atlas系列人工智能产品。Atlas源自古希腊神话中撑起宇宙的擎天大力神,华为用Atlas命名人工智能计算产品,是希望其能够成为撑起万物智能时代的“擎天大力神”,实现智能无所不及。其中,「Atlas 200 AI加速模块」,可以嵌入到机器人、摄像头、无人机等实现终端智能;「Atlas 500 智能小站」是面向边缘部署的智能小站,可实现交通、楼宇、园区等边缘智能场景;在数据中心面向训练和推理场景,我们则提供了「Atlas 300 AI加速卡」和「Atlas 800 AI服务器」;同时面向广大开发者,我们还提供「Atlas 200 DK AI开发者套件」,方便开发者快速熟悉Atlas的开发环境。 + +**任何IT产业的成功都是生态系统的成功,使能伙伴是华为在智能计算产业的重要使命,我们有以下3个具体措施:** + +- **以行业聚合应用**:在政府、金融、运营商、互联网等关键行业,形成完整的生态链和具有竞争力的解决方案。 + +- **以联盟孵化标准**:通过绿色计算产业联盟、边缘计算产业联盟构建基础软硬件的标准体系,促进产业的健康发展。 + +- **以社区发展开发者**:开发者是一个产业的灵魂,华为将鲲鹏开发者社区打造成计算产业的主流社区,力争通过5年时间,发展100万开发者。 + +创新重塑产业,科技引领未来,我们希望携手广大合作伙伴与客户,立足中国,面向全球,打造开放的计算产业生态,共赢多样性计算新时代!一年一度的华为全联接大会将于9月18日至20日在上海盛大举行,届时业界领袖与产业精英将共聚一堂,共同探讨产业发展方向,同时华为也将向业界重磅发布多款计算产品。 + +期待与大家一起见证智能新高度,谢谢大家! diff --git a/web-ui/docs/zh/blog/openeuler/20190918.md b/web-ui/docs/zh/blog/openeuler/20190918.md new file mode 100644 index 0000000000000000000000000000000000000000..27185462d89c35d8290598d8e8ed7d81cd5bcc5f --- /dev/null +++ b/web-ui/docs/zh/blog/openeuler/20190918.md @@ -0,0 +1,125 @@ +--- +title: 华为发布全世界最快AI产品,训练ResNet-50只需59.8秒 +date: 2019-09-18 +tags: + - theme +author: 华为智能计算 +archives: 2019-09 +summary: 不止5G和鸿蒙,华为最新大招,扔出AI计算核弹。刚刚,华为全联接大会开幕,推出又一重量级AI产品Atlas900。 +--- + +不止5G和鸿蒙,华为最新大招,扔出AI计算核弹。 + +刚刚,华为全联接大会开幕,推出又一重量级AI产品Atlas900。 + +此前接受外媒采访时,任正非就已经预告:这是“目前全世界最快的AI平台”。 + +全球最快是多快? + +华为给出数据——训练ResNet-50只需59.8秒。 + +在同等精度上,比排名第二的选手快15%。 + +华为副董事长胡厚崑说,如此算力还可以广泛应用到科学研究与商业创新中,比如天文探索、气象预测、自动驾驶、石油勘探等领域。 + +与此同时,华为方面也宣布:Atlas900的相关集群服务,也会以极优惠的价格向全球科研机构和大学开放。 + +伴随该产品发布,华为还披露了整体计算战略,这也是华为首次对外公开这一战略。 + +#### 集成数千颗算力最强AI芯片 + +Atlas 900由数千颗昇腾910组成,算力能达256~1024 PFLOPS@FP16。 + +训练ResNet-50只用了59.8秒的集群规模,用到了1024颗昇腾910。 + +实际应用中表现也非常亮眼。在天文领域,能够将传统169天的任务,缩短到10秒02。 + +昇腾910芯片亮相于去年的全联接大会,今年8月正式商用,是全球第三款、中国首款AI训练芯片。 + +昇腾910采用华为自研的达芬奇架构,号称“算力最强的AI处理器”,7nm工艺制程,最大功耗为350W,实测310W。 + +该芯片跑分对标也很明确。直接对标英伟达Tesla V100,主打深度学习的训练场景,客户面向AI数据科学家和工程师。 + +芯片如何强悍?华为同样给出了“吊打”友商的数据: + +相同的功耗下,昇腾910的算力是V100的两倍,训练速度更快,用户需要得出训练产出的时间会更短。在典型案例下,对比V100,昇腾910的计算速度可以提升50%-100%。 + +而伴随着Atlas 900的发布,华为的计算版图宣告正式构建完成,全面迈入落地阶段。 + +华为将如何落地?怎样驱动落地?华为现在也全盘托出。 + +#### 华为计算战略首次披露 + +整体来看,华为的计算战略以“芯片”为核心,一共分为四大部分,囊括芯片技术,整体规划,商业策略以及生态建设: + +首先,是架构创新。 + +核心面向投资基础研究,比如达芬奇架构,重点解决全场景智能的架构问题。 + +其次,是全场景芯片,也就是处理器族。 + +目前,华为一共有4大芯片系列,其中包括面向通用计算的鲲鹏系列,面向AI的昇腾系列,面向智能终端的麒麟系列,以及面向智慧屏的鸿鹄系列。 + +胡厚崑说,将来还有一系列处理器,面向更多的场景。 + +第三是商业策略,有所为有所不为。 + +华为也再次明确了自己的芯片商业模式,硬件开放、软件开源,使能应用开发和迁移。 + +但芯片不直接对外销售,以云服务和部件的形式面向客户,优先支持合作伙伴发展整机。 + +最后,构建开发生态。 + +在这一步,华为倡导开放,更新沃土计划,目标是未来5年,投入15亿美元,汇聚500万开发者,来使能全球合作伙伴发展应用及解决方案。 + +这些背后,是新的商业机遇和更大的空间。华为,早已不再是一个销售通信设备的供应商。 + +胡厚崑开场即强调,之前华为被人以“联接”认知,但新时代新阶段面临新机遇,华为如今要面向智能产业,打造从联接到计算的宏伟蓝图。 + +#### 华为怎么看未来? + +不仅仅只是发布战略,胡厚崑也披露了背后的逻辑,并给出预判。 + +他说,随着计算模式不断演进,面向机器学习的计算已成为主流。 + +但现在,计算正在进入智能时代,其具备三大特征:暴力计算、从中心侧、到端侧无处不在的泛在计算,以及端边云高效联动的协同计算。 + +最好的解决方式是,在中心节点暴力计算,训练通用模型,在边缘进行个性化部署。 + +但是,想要实现这一规划,仍旧面临着不少难点,比如能够支持全场景智能计算的新架构,这是当前计算产业发展面临的巨大挑战,同时也是巨大的机会。 + +到底有多大? + +胡厚崑援引了Gatener报告——全球计算产业总空间为两万亿美元。 + +在他看来,这是一片大蓝海,华为将坚定在计算领域的投入,并推进落地。 + +#### 回应吹下的牛:AI落地进展 + +在现场,华为也对去年吹下的牛,给出答辩。 + +2018年全连接大会,华为发布全栈全场景AI战略,而计算,正是这一战略的基石与核心。 + +今天,胡厚崑答辩心态,交出一年落地成绩单:年8月份,伴随着昇腾910以及MindSpore发布,华为的AI解决方案已经搭建完成。 + +从全栈来看,华为已经拥有了昇腾处理器系列IP和芯片、芯片使能CANN(芯片算子库和高度自动化算子开发工具)、应用使能ModelArts及训练和AI框架MindSpore。 + +从全场景角度来看,昇腾处理器的产品和解决方案,已经覆盖了云、边、端。在华为云上,提供了相应的推理和训练服务。 + +Atlas系列板卡、模组和服务器已经上市。搭载昇腾系列处理器,已经广泛应用在华为的智能手机上。 + +而且, 华为也将进一步介绍了通用计算的落地状况,总共分四步走: + +首先,打造有竞争力的通用计算处理器。 + +其次,持续投资板卡、服务器、操作系统、数据库、编译器等关键技术和产品,打通生态全链条,完成系统级验证,帮助合作伙伴更好地销售整机。 + +第三,华为与伙伴合作共同打造鲲鹏产业生态基地,目前已落地北京、上海、重庆、深圳、成都等城市,在平台搭建、培养人才、应用示范等领域开展全面合作。 + +而且,这些产品不仅仅只在中国。 + +之前华为就透露,基于鲲鹏处理器的系列产品、解决方案和服务,将面向全球市场,起于中国,服务全世界。 + +华为副董事长说:华为有AI,华为在务实落地,大家可以放心跟华为合作。 + +你怎么评价华为这次扔出的“核弹”? diff --git a/web-ui/docs/zh/blog/openeuler/20191001.md b/web-ui/docs/zh/blog/openeuler/20191001.md new file mode 100644 index 0000000000000000000000000000000000000000..41fa57b6c47ad7572fd1caad3606b589ae1b4d80 --- /dev/null +++ b/web-ui/docs/zh/blog/openeuler/20191001.md @@ -0,0 +1,31 @@ +--- +title: openEuler 2019年9月动态 +date: 2019-10-01 +tags: + - theme +author: openEuler Community +archives: 2019-10 +summary: 从2019年9月19日openEuler宣布开源到现在,openEuler社区有哪些进展? +--- + +### 2019年9月openEuler社区动态 + +1、2019年9月19日,openEuler正式开源 + +在[HUAWEI CONNECT 2019](https://www.huawei.com/cn/press-events/events/huaweiconnect2019)的第二天,华为宣布[openEuler开源](https://www.huawei.com/cn/press-events/news/2019/9/atlas-series-products-cloud-services-all-scenario-ai-solutions)。 + +2、openEuler软件仓升级 + +为了适应服务器操作系统开源软件的开发特征(Repo数量众多,并行开发者多),[Gitee](gitee.com)已经默默地将[openEuler](https://gitee.com/openeuler)升级为企业版。 + +3、CI对接启动 + +如果你查看,你会发现增加了新的Repo: + + * [ci-bot](https://gitee.com/openeuler/ci-bot) + * [go-gitee](https://gitee.com/openeuler/go-gitee) + +没错,CI对接正在进行中。 + +欢迎有兴趣的您,加入到我们来共同[筹建](https://www.openeuler.org/zh/developer.html)这个新开业社区。 + diff --git a/web-ui/docs/zh/blog/openeuler/2019huaweiconnect.md b/web-ui/docs/zh/blog/openeuler/2019huaweiconnect.md new file mode 100644 index 0000000000000000000000000000000000000000..76289efdece2d90691ab618e0f28e36b1941aaee --- /dev/null +++ b/web-ui/docs/zh/blog/openeuler/2019huaweiconnect.md @@ -0,0 +1,19 @@ +--- +title: 2019华为全联接大会于9月18日 - 9月20日在上海举行 +date: 2019-09-18 +tags: + - meetup + - summit +author: openEuler +archives: 2019-09 +summary: 2019华为全联接大会于9月18日 - 9月20日在上海世博展览馆&世博中心举行。 +--- + +ADVANCE INTELLIGENCE + +共创智能新高度 + +2019华为全联接大会于9月18日 - 9月20日在上海世博展览馆&世博中心举行。 + +会议链接:https://www.huawei.com/cn/press-events/events/huaweiconnect2019 + diff --git a/web-ui/docs/zh/blog/openeuler/20200101.md b/web-ui/docs/zh/blog/openeuler/20200101.md new file mode 100644 index 0000000000000000000000000000000000000000..d464acfce8b1dbd96fc83ab14682e3bd7cbf6254 --- /dev/null +++ b/web-ui/docs/zh/blog/openeuler/20200101.md @@ -0,0 +1,31 @@ +--- +title: openEuler开源社区基础设施上线 +date: 2020-01-01 +tags: + - theme +author: openEuler Infrastructure Team +archives: 2020-01 +summary: 历经3个多月的准备,openEuler开源社区基础设施上线了。 +--- + +openEuler开源社区基础设施上线 +在2019年9月17日openEuler被宣布要在年底开源之日起,openEuler基础设施团队开始准备基础设施。在历经3个多月的开源准备后,openEuler社区基础设施正式启用。 + +2019年12月31日晚,openEuler基础设施团队做年度总结是提到:“我们走到现在这一刻,是一件非常激动人心的事,很难想象的是我们要管理上千个代码仓库,并保证它们能编译通过,在这里要非常感谢所有参与贡献的人”。构建这个社区最大的挑战在于要管理如此多的代码仓库,这个数量的仓库会对整个基础设施系统带来很大的负载。 + +如Gitee展示,openEuler主要包含两个组织仓库,一个用于源代码存放,当前显示该仓库有20+仓库,在这里,被重点推荐的有两个项目:iSulad和A-Tune。iSulad是一个轻量级基于gRPC服务的容器运行时,相比runc来讲,iSulad是用C语言编写但所有接口兼容OCI。另一个项目是A-Tune,A-Tune是一个基于AI技术能自动优化的基础系统软件。除此之外,你还将能看到几个支持基础设施的项目,它们组建起了社区的运行系统,从这些项目的提交记录来看,这些系统是通过脚本自动化在华为云上构建而成。 + +另一个组织是src-openeuler,主要是用来存放软件包,这些软件包构建起了openEuler操作系统的ISO和安装包,从Gitee的统计来看,这里当前存放了1000个左右软件包,每一个软件包都提供了ARM64和X86架构的版本,这样数量的工程超出了任何人的想象。并且这些包的数量还会继续增加。 + +从Gitee的统计来看,目前社区有超过50个贡献者,近600次commit,网站上也定义了将近20个SIG(项目组)。 + +目前openEuler社区还处于筹备阶段,如果您有兴趣,请联系infra@openeuler.org加入基础设施小组。 + +特别感谢如下贡献者: + + - dogsheng + - freesky-edward + - imjoey + - tommyhusheng(husheng) + - xiangxinyong + - zerodefect(Fred_Li) diff --git "a/web-ui/docs/zh/blog/ouyanghaitao/2021-7-28-\345\274\200\346\272\220\347\244\276\345\214\272\345\256\236\344\271\240\350\256\260 - \346\210\221\346\212\212 openEuler \347\247\273\346\244\215\345\210\260\344\272\206 Windows WSL.md" "b/web-ui/docs/zh/blog/ouyanghaitao/2021-7-28-\345\274\200\346\272\220\347\244\276\345\214\272\345\256\236\344\271\240\350\256\260 - \346\210\221\346\212\212 openEuler \347\247\273\346\244\215\345\210\260\344\272\206 Windows WSL.md" new file mode 100644 index 0000000000000000000000000000000000000000..38c5f1dc6b85ab63303d202eda3bce2b5d70472b --- /dev/null +++ "b/web-ui/docs/zh/blog/ouyanghaitao/2021-7-28-\345\274\200\346\272\220\347\244\276\345\214\272\345\256\236\344\271\240\350\256\260 - \346\210\221\346\212\212 openEuler \347\247\273\346\244\215\345\210\260\344\272\206 Windows WSL.md" @@ -0,0 +1,93 @@ +--- +title: 开源社区实习记 - 我把 openEuler 移植到了 Windows WSL +date: 2021-07-28 +tags: + - WSL + - 移植 +archives: 2021-07 +author: ouyanghaitao +summary: 将openEuler移植到WSL(Windows Subsystem for Linux)的过程 +--- + +# 开源社区实习记 - 我把 openEuler 移植到了 Windows WSL + +![1](https://gitee.com/ouyanghaitao/images/raw/master/1.png) + +## 初入华为,确定目标 + +我叫王海涛,哈尔滨工业大学(深圳)校区计算机专业的大三学生。 + +为了准备第一届全国大学生操作系统比赛,我的老师建议参加一些RISC-V相关的比赛,提前熟悉RISC-V,为从零写内核做好准备。于是我在2020年寒假期间参加了“2020 openEuler 高校开发者大赛”,选择的题目是“为openEuler-RISC-V添加Grub的引导启动方式”。从安装openEuler、注册gitee账号,再到用QEMU模拟RISC-V、学习Grub,这个比赛让我学到了操作系统启动流程相关的硬核知识,也让我开始了解openEuler开源社区。 + +带着对openEuler社区的好奇以及对华为公司实习的向往,在2021年1月份,我向负责华为四大开源社区运营的华为计算开源开发与运营部投递了简历。经历了3个月的漫长等待,终于如愿以偿收到了华为实习的Offer,获得了深度参与openEuler社区开发、运营的机会。 + +在社区实习几天后,我发现在学校深受大家欢迎的WSL居然还不支持openEuler。WSL即Windows Subsystem for Linux,是 Microsoft 原生的虚拟化方案,能用更快的速度、更少的磁盘,运行各种 Linux发行版,目前主流的Linux发行版都支持: + +![2](https://gitee.com/ouyanghaitao/images/raw/master/2.png) + +于是我心想,要不我来补上这块空缺吧。和导师沟通后,导师非常支持我的想法。就这样,我的第一个实习任务就确定了—— 将openEuler发行版移植到Windows WSL。 + +## 提前完成?准备发布? + +阅读了WSL相关文档后,我确定Windows WSL可以导入任意的Linux发行版,对于openEuler 而言是没有任何限制的。 + +首先是需要一个Linux发行版的根文件系统,使用WSL命令直接将这个文件系统导入即可。为了得到 Linux 发行版的根文件系统,微软建议使用发行版的docker官方镜像,启动容器后使用命令docker export导出容器镜像的快照作为所需的根文件系统。 + +在openEuler官网下载板块,我发现每个openEuler发行版都有对应的docker镜像。我下载了[openEuler 20.03 LTS SP1](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/docker_img/x86_64/) 的docker镜像,跟着文档一步一步操作,第二天就在WSL上启动了openEuler。 + +满心欢喜的我跟着微软的 WSL 发布文档继续边学习边实践,又用了两三天成功地编译好了安装包。这样在windows下,双击安装包就能安装openEuler 的 WSL 版本。 + +安装包编译完成后,我想把项目代码上传到openEuler社区做存档。这时候我遇到了一个问题:提交代码需要挂靠到某一个SIG下。 + +但是目前并没有WSL相关的SIG,于是我阅读了openEuler官网SIG申请流程,发现如果要成立新的SIG,需要通过社区TC委员会的邮件列表发起申请。于是,我写下了人生第一封开源社区的邮件,向TC委员会提问是否需要创建WSL SIG。很快便收到TC答复,明确不需要新建一个WSL SIG,加入OS-builder SIG即可。后来便参加了OS-builder SIG 双周例会,介绍了当前移植工作以及遇到的问题,并且在OS-builder SIG以及社区帮助下,成功在OS-builder下建立了WSL仓库。 + +中间还有个有趣的小插曲,在社区发邮件期间,民族棋 SIG 的 Maintainer,同时也是为中学生做树莓派科普的袁老师找到我,说看到了我热情洋溢的邮件,问能不能代表同学们采访一下 WSL 项目,说实话当时的我实在是受宠若惊但又内心狂喜。在采访中,首先介绍了openEuler移植到WSL的进展,以及一些Linux入门的知识,其次按照袁老师的建议分享了自己高考考上哈工大(深圳)的经验与心得,同时也分享了多姿多彩的大学生活([采访链接](https://gitee.com/yuandj/siger/blob/master/%E7%AC%AC10%E6%9C%9F%20%E5%8D%97%E5%BE%81%E5%8C%97%E6%88%98%EF%BC%88%E4%B8%8A12%EF%BC%89.md#%E4%B8%80%E5%B0%81%E9%9D%A2%E6%95%85%E4%BA%8B%E9%98%B3%E5%85%89%E6%B5%B7%E6%B6%9B))。 + +在和导师沟通后我了解到,代码如果要提交到openEuler社区,必须要经过测试。如何测试呢?带着问题,我参与了QA(Quality Assurance)SIG,以及release-management SIG的例会,并在两个SIG的成员建议下,使用了最新的mugen测试框架,搭配integration-test的测试脚本,对移植的系统进行测试。在测试期间,顺便发现了一个测试脚本的bug,修补后提交了PR 。这个bug很简单,就是grep命令与后面的文件名黏在一起了,加个空格隔开就行,但是蚊子腿再小也是肉,第一次找到bug内心还是小有成就滴。 + +测试结束后,基本操作系统的功能即os-basic文件夹下的测试用例都通过了,不过还有一半的测试用例都没有通过。深入分析报错的log后发现,由于WSL缺少部分原生Linux的功能,导致了很多功能无法开启,相关测试也就无法通过。比如,WSL不支持systemctl,而大部分测试脚本都需要使用systemctl来开启系统功能再进行测试,自然WSL无法通过这些测试,所以测试只好暂时告一段落。虽然这部分测试没有通过,但我使用移植后的openEuler一段时间后没有发现问题,应该不影响正常使用。 + +将测试后的代码提交到wsl仓库,等待PR合入时,我便想同步将安装包提交到Microsoft Store。 + +## 为了发布,寻求帮助 + +为了在微软商城发布openEuler的安装包,我需要解决一些技术之外的问题,社区是寻求帮助的最佳途径。 + +比如,虽然安装包的搞定了,但是安装后在开始菜单显示的logo,效果不如Ubuntu的好。因为openEuler的logo,由蓝色的字母E以及底部的黑色字体openEuler组成。这带来两个问题,一是带文字图标在微软的开始菜单会显得比较小;另一个是我开了windows深色模式,黑色字体在深色背景下根本看不清楚。 + +简单粗暴的解决办法也很好想,我找到logo的矢量图,把字删掉,然后放大就行。但是身边的同事提醒我,去掉文字的logo还有法律效力吗?我能随便去掉一个已注册商标的文字部分,然后拿去发布吗?带着问题,我询问了社区的其他成员,最后辗转找到华为法务部的一位律师姐姐,向她请教logo的法律问题后,她给我了一个商标检索报告截图,告诉我去掉文字的logo也有法律效力。每次想起这个logo,都提醒我在开源社区开发也要注意法务合规。 + +解决了Logo问题后,便可以准备提交到微软商城了。WSL文档里提到,如果要发布,需要写邮件给WSL团队,经过他们的测试后,才能发布,于是我便第一时间写了一封英文邮件给WSL团队。 + +等了两个星期,WSL团队没有回复。我只好再发一封邮件,运气不错的是,这次等了几天后,WSL团队终于回复我了,说前段时间正处于微软一年中专门开会的月份,很忙,所以没看到邮件。并且表示,WSL移植好后可以直接提交,无需测试。 + +文档里说,如果要将软件安装包发布到微软商城,需要注册一个微软合作中心账户,这个账户分公司账户和个人账户。前者需要提交创办公司的官方证明文件,微软审核通过后才能发布软件,后者则无需微软审核。在公司与个人账户的选择之间,我想先试试能不能创建公司账号。虽然openEuler不是公司,只是一个社区,但是毕竟公司账号能支持更多人登录,且能发布特定功能的APP,权限更高。于是我在社区,找到了社区基础设施SIG的Maintainer,在他的帮助下,使用了openEuler的一个公共邮箱注册微软账号。在验证完邮箱后,微软合作中心提示,employment verification失败,需要提供openeuler.io这个域名是由我们注册的证明。于是我又向社区基础设施SIG要证明材料,得到几个管理员界面的截图后,按照微软文档里面的说明提交了材料,又开始了新的漫长的等待。 + +又是两周,微软还是没有回复。在微软合作中心的论坛中,发现有几个人卡在了相同的验证阶段,他们发帖称自己按照文档提交了证明材料后,微软拖了很久都没回应,短的几个星期,慢的几个月。但在他们发帖表示微软拖延后,都有微软的管理员立即跟进,人工帮助他们解决了验证问题。学到这招后我便在讨论区提交了support,希望有客服也来帮助我通过验证。 + +几天后,果然有从美国打来的电话与我沟通。但是我们讨论了一下午,她都没有解决我的问题。后来发现,我问题分类找错了,原因是与账号相关的问题有好几个,彼此之间都很相似。 + +在漫长的发布过程中,我学到了如果合作伙伴没有第一时间答复,应该想办法去主动沟通、推进,比如去论坛上发帖,去帮助中心找人工客服,向相关团队发邮件等。 + +## 喜提发布,收获满满 + +人工客服无法解决我的问题,我只好继续等待我的证明材料能被微软工作人员处理。运气不错的是,过了一个星期左右,微软发邮件告诉我,除了截图以外,要提供创办公司的PDF官方证明,可是openEuler是一个开源社区而不是商业公司,没有官方证明。于是经过openEuler 社区的讨论,我们决定先用个人账户发布。 + +这次使用另一个openEuler的邮箱来创建了一个微软的个人账户,由于不需要繁琐的验证,我很顺利地,提交了应用上传的所需信息。但是发布时,我却怎么也无法提交安装包,一直提示错签名不对。在翻看YouTube上微软发布软件的介绍,以及在Stack Overflow上搜索相应问题时,我发现签名需要提供开发者账号的Windows publisher ID,即CN开头的一串号码。使用这个号码来作为Visual Studio签名安装包的Publisher common name,签名后的安装包能正确被微软合作中心成功识别,于是我便成功将安装包提交到了微软合作伙伴中心。而这一点,我翻遍了微软开发文档都没找到相关提醒。 + +让人意外的是,这次没有等几个星期,而是在三天后我就收到了微软的修改建议。我按照微软要求,修改privacy链接,加上openEuler不支持Windows 10 S申明后,重新提交了应用上传请求,本以为仍需要等待一段时间才能发布,没想到数日后,商城居然可以搜到openEuler !发布成功了! + +![3](https://gitee.com/ouyanghaitao/images/raw/master/3.png) + +上面是 openEuler 在 Microsoft Store 的截图,感兴趣的朋友可以通过[链接1](https://www.microsoft.com/zh-cn/p/openeuler/9ngf0q0xp03d?rtc=1&activetab=pivot:overviewtab)来安装。需要注意的是,在安装WSL 任何发行版之前,需要先启用 WSL 这个功能,具体可以参考[链接2](https://gitee.com/openeuler/wsl)。 + +三个月的工作终于是告一段落了。在这期间,我写下了人生第一封英文邮件给微软,写下了第一封给开源社区的邮件,第一次与社区成员沟通讨论openEuler,在这个过程中,我感觉自己已经融入到了openEuler这个大家庭中。 + +同时在华为实习工作中,工作氛围很好,同事之间互助友爱。于是我决定延长实习,从原计划7月结束实习,延长到9月底结束。希望在后续的三个月实习时间里,我能学到更多,也能为openEuler做更多贡献! + +最后附上我总结的关于移植openEuler到WSL的技术文档,里面介绍了如何在WSL里安装openEuler,以及移植的过程: +https://gitee.com/openeuler/wsl 。如果有任何问题,欢迎在openEuler社区wsl仓库提 Issue,https://gitee.com/openeuler/wsl/issues 。 + +如果你想参与 openEuler 开发,可以搜索微信小程序 “openEuler”,里面有 80 多个 SIG 例会时间、议题以及 openEuler 的线上和线下的 Meetup 。你可以选择你感兴趣议题参与例会,在会议中和社区成员进行详细的沟通,也可以到现场来参与 Meetup 活动。 + +欢迎为 openEuler 社区添砖加瓦! \ No newline at end of file diff --git a/web-ui/docs/zh/blog/overweight/2020-06-10-my-traval-of-openeuler.md b/web-ui/docs/zh/blog/overweight/2020-06-10-my-traval-of-openeuler.md new file mode 100644 index 0000000000000000000000000000000000000000..f34d86e26a48e80c8c07b2a9db3d260627172696 --- /dev/null +++ b/web-ui/docs/zh/blog/overweight/2020-06-10-my-traval-of-openeuler.md @@ -0,0 +1,890 @@ +--- +title: 我的社区参与之旅 +date: 2020-06-10 +tags: + - 社区运营 + - 参与贡献 + - 流程规范 +archives: 2020-06 +author: overweight +summary: 我的社区参与之旅,介绍openEuler社区流程和操作。 +--- + + +## openEuler是什么? + +openEuler是一个开源、免费的Linux发行版平台,将通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。同时,openEuler也是一个创新的平台,鼓励任何人在该平台上提出新想法、开拓新思路、实践新方案。 + +**安装界面:** + +![img](./openEuler-traval.assets/chooselanguage.png) + + + +**openEuler的官方网站: https://www.openeuler.org/** + +**repo 下载地址: https://repo.openeuler.org** + +**文档手册:https://www.openeuler.org/zh/docs/20.03_LTS/docs/Releasenotes/release_notes.html** + +![image-20200521203551777](./openEuler-traval.assets/image-20200521203551777.png) + + + +## openEuler版本怎么规划? + +![image-20200521204342097](./openEuler-traval.assets/image-20200521204342097.png) + +![img](./openEuler-traval.assets/2020-03-25-lifecycle-02.png) + +说明: + +1. 有创新版本和LTS(Long term support)版本两条线的版本。 + +2. 遵循Upstream First原则,软件带包直接来源于原生社区,并反哺原生社区。 + +3. master分支即为当前最新版本开发分支,一旦发布创新版本或LTS版本, + + 即会基于当前master主干拉出对应版本分支进入维护阶段。 + +| | openEuler 创新版本(非LTS) | **openEuler** LTS版本 | +| -------- | -------------------------------------- | -------------------------- | +| 版本定位 | 构筑开发者生态,新特性活跃,版本演进快 | 支持合作伙伴构筑商业发行版 | +| 发布周期 | 0.5年 | 2年 | +| 维护周期 | 0.5年 | 4年 or more | +| 质量标准 | 低,对标fedora质量要求 | 中,对标centos质量要求 | +| 关键工作 | **新特性、**bugfix、CVE、升级选型等 | **有限特性、**bugfix、CVE | +| 对应分支 | 当前无,下一个版本openEuler-20.09 | 最新分支openEuler-20.03LTS | + +## openEuler 版本如何构建? + +**openEuler构建模型:** + +![image-20200521210943225](./openEuler-traval.assets/image-20200521210943225.png) + +**版本如何构建:** + +![image-20200521211038388](./openEuler-traval.assets/image-20200521211038388.png) + +**说明:** + +| 名字 | 说明 | 备注 | +| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 码云 openuler Group | 这个组织下存放的都是由openEuler社区发起的原生项目,
相当于一个一个的上游社区。例如isula、atune项目。 | https://gitee.com/openeuler | +| 码云 src-openeuler Group | 这里存放的是以rpm 源码形式的代码。每个仓库源码都可以直接构建rpm二进制。 | https://gitee.com/src-openeuler | +| OBS | open build service,opensuse发布的一套开源构建系统,类似于koji、yacto等。 | https://build.openeuler.org
https://openbuildservice.org | +| jenkins | CI/CD,持续集成平台,主要用于门禁任务、版本构建任务调度等 | http://114.116.250.98/ | +| repo | 用于归档发布的交付件及yum 软件源。 | https://repo.openeuler.org/ | + +## openEuler 版本里有啥软件? + +最直观的方式是访问openEuler官方repo,看看发布件。 + +| 发布件 | **构建工具** | **Repo****归档地址** | +| ------------------------------------------------------------ | ----------------------------- | ------------------------------------------------------------ | +| ISO:
Dvd ISO 、
Debuginfo ISO
Everything ISO
Source ISO | mkdvdiso(待开源)、 kiwi | http://repo.openeuler.org/openEuler-20.03-LTS/ISO | +| Qcow2镜像 | CreateImage(待开源) | http://repo.openeuler.org/openEuler-20.03-LTS/docker_img | +| 容器镜像 | kiwi | http://repo.openeuler.org/openEuler-20.03-LTS/virtual_machine_img | +| LiveCD ? | | | +| … | | | + +另外一种方式,就是访问openEuler OBS上的构建工程,可以知道每个版本里包含哪些软件,当前的构建状态是啥样的。 + +| 版本 | OBS工程 | 说明 | 约束 | 地址 | +| --------------------- | ----------------------------- | ------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------ | +| master主干 | openEuler:Factory(新包引入) | 新软件加入,首先引入到openEuler软件工场,master分支代码 | 构建rpm,不会集成到iso或repo中 | https://build.openeuler.org/project/show/openEuler:Factory | +| | openEuler:Mainline | 主线工程,master分支代码 | 里面涉及的包都会随着openEuler的版本发布 | https://build.openeuler.org/project/show/openEuler:Mainline | +| LTS版本 | openEuler:20.03:LTS | LTS版本构建工程,openeuler-20.03-LTS分支代码 | | https://build.openeuler.org/project/show/openEuler:20.03:LTS | +| 20.09版本(未拉分支) | --- | | | --- | + +## 软件是如何管理的? + +**openeuler源码仓库管理:** + +- openEuler所有代码托管在gitee.com +- 有openeuler、src-openeuler两个group +- 都是源码化、配置化管理 + +| **group** | **openeuler** | **src-openeuler** | +| --------- | --------------------------- | ------------------------------- | +| 定位 | 代码仓、原生社区 | 软件包仓、制品仓 | +| 内容 | openEuler发起的原生项目 | spec rpm格式归档的软件包仓库 | +| URL | https://gitee.com/openeuler | https://gitee.com/src-openeuler | +| 仓库数量 | 50+ | 2500+ | +| 代码管理 | 源码树 | src rpm格式 | +| 关系 | 是src-openeuler的上游社区 | | + +当前openEuler 软件的管理是**以sig组来承载**,所有的软件**唯一的归属于某个sig**。通过[sigs.yaml文件](https://gitee.com/openeuler/community/blob/3f8f9a73de9435857ce524e1ce387d2499a51f32/sig/sigs.yaml),你可以查询到该软件属于哪个sig,并通过[sigs专有归档目](https://gitee.com/openeuler/community/tree/3f8f9a73de9435857ce524e1ce387d2499a51f32/sig)你可以查询对应的maintainer。**只有对应的maintainer才有对应仓库代码合入权限。** + +image-20200521225454468 + +openeuler/community仓库下,以下三个文件比较重要: + +[sig/sigs.yaml](https://gitee.com/openeuler/community/blob/master/sig/sigs.yaml) 管理和维护各sig下维护的软件包,划分sig管理的软件包范围。 + +[repository/openeuler.yaml](https://gitee.com/openeuler/community/blob/master/repository/openeuler.yaml) openeuler下维护的软件包仓库信息。 + +[repository/src-openeuler.yaml](./[src-openeuler.yaml](https://gitee.com/openeuler/community/blob/master/repository/src-openeuler.yaml)) src-openeuler下维护的软件包仓库信息。 + +通过修改这几个文件,来新增、删除软件包仓库,来给相应的软件包划分sig,从而实现sig的owner对软件包的权限管理。 + +## 了解openEuler SIGs + +SIG就是Special Interest Group的缩写,openEuler社区按照不同的SIG来组织,以便于更好的管理和改善工作流程。 + +- SIG组和SIG的邮件列表是开放的,欢迎任何人和团体加入并参与贡献。 +- SIG都是针对特定的一个或多个技术主题而成立的。SIG内的成员推动交付成果输出,并争取让交付成果成为openEuler社区发行的一部分。 +- SIG的核心成员主导SIG的治理。请查看[SIG的角色说明](https://gitee.com/openeuler/community/blob/master/community-membership_cn.md)。您可以在贡献的同时积累经验和提升影响力。 +- 每一个SIG在Gitee上都会拥有一个或多个项目,这些项目会拥有一个或多个Repository。SIG的交付成果会保存在这些Repository内。 +- 可以在SIG对应的Repository内提交Issue、针对特定问题参与讨论,提交和解决问题,参与评审等。 +- 您也可以通过邮件列表、IRC或视频会议和SIG内的成员进行交流。 + +**openEuler SIG 维护策略** + +1. 根据所有软件所涉及领域和方向,openEuler已经垂直的划分了很多基础的SIG。 +2. 每个独立软件要归属到唯一SIG里,SIG的maintainer管理该SIG涉及的软件包,并定期审视。 +3. SIG之间要避免正交、耦合,粒度要合理,管理的软件仓规模避免太大。 +4. 新成立SIG时,应提前了解当前openEuler是否已经存在相同或类似的SIG。 +5. 新SIG申请时,应考虑和其他SIG沟通,将该SIG领域涉及软件一并接管过来。 +6. SIG的成立、运营、废弃受TC委员会监管。 + +## openEuler社区开发全景? + +image-20200506152118205 + +上图是openEuler社区开发指引图。 + +说明: + +1. 软件包管理按照软件包所处的时间点分为:![image-20200506152426591](./openEuler-traval.assets/image-20200506152426591.png)、![image-20200506152440903](./openEuler-traval.assets/image-20200506152440903.png)、![image-20200506152503864](./openEuler-traval.assets/image-20200506152503864.png)。 +2. 每个阶段的输入是圆框绿底,如![image-20200506152347249](./openEuler-traval.assets/image-20200506152347249.png)。 +3. 所有的开发和维护动作是由issue触发。issue可分为需求、问题、CVE等类型。image-20200506152831297。 +4. 所有修改和操作通过PR来发起。 +5. 全景图中,每个动作都可能涉及规范或指导。将在后面以表格的方式整理呈现。 + +**全景图中涉及的规范:** + +| 阶段 | 动作 | 规范或指导 | +| --------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 引入 | | | +| | ![image-20200506154105394](./openEuler-traval.assets/image-20200506154105394.png) | 指导:《如何申请SIG》 --待输出-- | +| | ![image-20200506153902264](./openEuler-traval.assets/image-20200506153902264.png) | 规范:[《软件包引入和退出要求》](https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/software-management.md)
指导:《openEuler加包指导》 --待输出-- | +| | ![image-20200506154028448](./openEuler-traval.assets/image-20200506154028448.png) | 规范:[《软件包打包规范》](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md) | +| 开发&维护 | | | +| | ![image-20200506154538225](./openEuler-traval.assets/image-20200506154538225.png) | 规范:《软件包升级选型规范》 --待输出-- | +| | ![image-20200506154610817](./openEuler-traval.assets/image-20200506154610817.png) | 指导:[《软件包打包规范》](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md) | +| | ![image-20200506154459319](./openEuler-traval.assets/image-20200506154459319.png) | 规范:[《软件包打包规范》](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md)
指导:《如何提交PR、发起检视及合入验证》 --待输出-- | +| | ![image-20200506154518672](./openEuler-traval.assets/image-20200506154518672.png) | 规范:[《openEuler漏洞处理流程》](https://gitee.com/openeuler/security-committee/blob/master/security-process.md)
规范:[《openEuler漏洞严重性评估》](https://gitee.com/openeuler/security-committee/blob/master/security-evaluation.md)
指导:[《如何申请CVE、漏洞上报》](https://www.openeuler.org/zh/security.html) | +| | ![image-20200506154813993](./openEuler-traval.assets/image-20200506154813993.png) | 规范:《openEuler软件包随版本发布规范》 --待输出--
指导:《如何将软件包加入openEuler发布版本》--待输出-- | +| | ![image-20200506154918752](./openEuler-traval.assets/image-20200506154918752.png) | 规范:[《安全漏洞处理和发布流程》](https://gitee.com/openeuler/security-committee/blob/master/security-process.md) | +| 退出 | | | +| | ![image-20200506154436536](./openEuler-traval.assets/image-20200506154436536.png) | 规范:[《软件包引入和退出要求》](https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/software-management.md) | + +## 如果参与openEuler社区贡献? + +第一步,开源并不意味者随心所欲,**签署CLA**:[“贡献者许可协议”](https://www.openeuler.org/zh/cla.html)是第一步,阅读并遵守openEuler社区的[行为守则](https://gitee.com/openeuler/community/blob/master/code-of-conduct.md); + +第二步,从了解、安装、使用、测试openEuler开始,**积极反馈问题和建议**,相关的[文档和手册](https://www.openeuler.org/zh/docs/20.03_LTS/docs/Releasenotes/release_notes.html),以及相关的[资讯](https://www.openeuler.org/zh/blog.html)可以帮助你更加深入的了解openEuler。 + +第三步,开发者熟悉社区的开发流程后——[《贡献者指南》](https://www.openeuler.org/zh/developer.html),可以基于自己感兴趣的项目和软件,在码云上openEuler对应的项目提交自己的贡献。 + +## 了解gitee工作流 + +- **准备工作** + + [安装GIT](https://git-scm.com/downloads)、[注册账号](https://gitee.com/help/articles/4113)、[环境配置](https://gitee.com/openeuler/community/blob/master/zh/contributors/prepare-environment.md)、[找到感兴趣的项目](https://gitee.com/openeuler/community/blob/master/zh/contributors/README.md) + +- **Fork仓库** + + ![img](./openEuler-traval.assets/Gitee-workflow-fork.png) + +- **克隆到本地** + + ```bash + git clone https://gitee.com/openeuler/kernel + ``` + +![Gitee-workflow-CopyLink](./openEuler-traval.assets/Gitee-workflow-CopyLink.png) + +- **拉分支** + + ```bash + git checkout -b myfeature + ``` + +- **修改验证提交** + + ```bash + git add . + git commit -m "提交原因" + ``` + +- **推送到码云** + + ```bash + git push -f origin myfeature + ``` + +- **创建PR** + + 访问你的个人主页,选择目标分支,点击 **`+ Pull Request`** 来创建一个PR + + ![image-20200610173341921](./openEuler-traval.assets/image-20200610173341921.png) + + + +- **关注代码审查意见** + + 给PR指派检视人员,及时回复reviewers的意见。 + + ![image-20200610173629091](./openEuler-traval.assets/image-20200610173629091.png) + +- **更新PR** + + 码云默认会把个人仓库的分支与目标仓库的对应分支的差异作为一个PR,所以本地对该分支的修改,当push后,自动会更新到PR中。 + +**建议:** + +1. 相关的修改,单独拉分支来修改提交,并创建PR。如果可以,一次commit一个分支。 +2. 当PR合入后,可以强制同步最新代码到个人仓库。![image-20200610174315367](./openEuler-traval.assets/image-20200610174315367.png) +3. 不要在master上提交代码,当PR未merge时,强制同步会失败。 + +## 开发者可以在openEuler社区做些什么? + +**包括但不限于:** + +- **提交一些需求,并尽可能实现它** +- **提交一个bug并修复它** +- **上报漏洞及漏洞处理** +- **提出一些建议,包括不限于网站改进、文档改进、流程规范改进、体验提升等。** +- **为社区添加新的软件** +- **发起社区新项目** + +**结合前面的开发者全景图,可以分解成以下动作:** + +### 1、创建issue,提交需求&问题&建议 + +- **提出问题**:如果您发现并想向社区上报问题或缺陷,问题提交的方式就是创建一个Issue。您只要将问题以Issue的方式提交到该项目Repository的Issue列表内,并查看[Issue提交指南](https://gitee.com/openeuler/community/blob/master/zh/contributors/issue-submit.md)以获取更多的信息。提交问题时,**请尽量遵守**问题提交准则。 +- **提出建议**:如果您想对SIG领域内贡献出自己的意见或建议,也可以通过提交Issue的方式分享给大家。大家可以在该Issue上充分的交流和讨论。为了吸引更广泛的注意,您也可以把Issue的链接附在邮件内,通过邮件列表发送给所有人。 +- **提出需求**:如果你希望某个特性或是技术在openEuler上落地,可以提交需求类issue,**清晰完整的描述有助于团队成员理解,并被更快的接受和排入开发计划。** + +### 2、提交PR,修复一个问题(bug、cve、新特性) + +当你提交一个PR的时候,就意味您已经开始给社区贡献代码了。请参考[openEuler社区PR提交指导](https://gitee.com/openeuler/community/blob/master/zh/contributors/pull-request.md) 与 [码云PR提交流程](http://git.mydoc.io/?t=153749)。 + +**注意事项**: + +- openEuler只接受PR的形式来提交代码,不允许直接向openEuler下的仓库直接push代码。 + +- 首先,要找到修复问题对应的仓库,以[src-openEuler/mock](https://gitee.com/src-openeuler/mock)为例,点击fork按钮,复制仓库代码到个人名下。 + + ![image-20200521232246188](./openEuler-traval.assets/image-20200521232246188.png) + +- 将代码git clone到本地,如果你的修改不涉及二进制源码软件包的变化,将所修改的代码做成一个patch,因为仓库是以rpm源码包的格式组织的。 + +- 每个PR都会触发openEuler门禁的检查,包括不定命名、代码规范、代码构建。门禁的结果会稍后回显在评论中,存在失败的检查项要及时修正。 + +- 通过门禁中的openeuler-rpm-build的链接,你可以逐层找到这次提交构建的临时rpm二进制。后续会将生成的二进制直接回显到评论里。 + + ![image-20200522002832030](./openEuler-traval.assets/image-20200522002832030.png) + + ![image-20200522003012593](./openEuler-traval.assets/image-20200522003012593.png) + +- 代码reviewers可以针对提交给出自己意见,当他认可你的提交时,会`/lgtm`来给出ok的意见。 + +- 仓库的maintainers有合入的权限,`/approve`的评论会触发robot自动合入,如果存在冲突,你需要提前解决冲突。 + +- 针对别人给出的检视意见。如果涉及修改代码,可以使用`git commit --amend; git push -f`来在同一个PR更新PR。 + +**检视代码**: + +openEuler是一个开放的社区,我们希望所有参与社区的人都能成为活跃的检视者。可以参考[社区成员](https://gitee.com/openeuler/community/blob/master/community-membership_cn.md),该文档描述了不同贡献者的角色职责。 + +**对于贡献者**,为了使您的提交更容易被接受,您需要: + +- 遵循SIG组的编码约定,如果有的话 +- 准备完善的提交信息 +- 如果一次提交的代码量较大,建议将大型的内容分解成一系列逻辑上较小的内容,分别进行提交会更便于检视者理解您的想法 +- 使用适当的SIG组和监视者标签去标记PR:社区机器人会发送给您消息,以方便您更好的完成整个PR的过程 + +**对于检视者**,强烈建议本着[行为准则](https://gitee.com/openeuler/community/blob/master/code-of-conduct.md),超越自我,相互尊重和促进协作。[《补丁审核的柔和艺术》](https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/)一文中提出了一系列检视的重点,说明代码检视的活动也希望能够促进新的贡献者积极参与,而不会使贡献者一开始就被细微的错误淹没,所以检视的时候,可以重点关注包括: + +- 贡献背后的想法是否合理 +- 贡献的架构是否正确 +- 贡献是否完善 + +注意:如果您的PR请求没有引起足够的关注,可以在SIG的邮件列表或[dev@openeuler.org](./mailto:dev@openeuler.org)求助。 + +这里是一个[可供参考的示例](https://gitee.com/open_euler/dashboard/projects/src-openeuler/ct-ng/pulls/2?tab=comments)。 + +### 3、创建兴趣小组 + +```mermaid + +stateDiagram + [*] --> 查找sig列表 + 查找sig列表 --> 加入SIG : 已存在 + 查找sig列表 --> 按模板提交PR : 不存在 + + 按模板提交PR --> 订阅邮件,申请议题 + + 订阅邮件,申请议题 --> TC评审 + + TC评审 --> 合入PR : 评审通过 + TC评审 --> 按模板提交PR : 不通过 + 合入PR --> [*] + 加入SIG --> [*] + +``` + +![image-20200611162154651](./openEuler-traval.assets/image-20200611162154651.png) + +```markdown + SIG列表: gitee.com/openeuler/community/tree/master/sig + TC邮件列表:gitee.com/openeuler/community/tree/master/zh/technical-committee + PR模板: gitee.com/openeuler/community/tree/master/sig/sig-template + 提交示例: gitee.com/openeuler/community/pulls/398 +``` +**找到您感兴趣的SIG或项目** + +找到您感兴趣的SIG组,可以帮助您在正确的地方提出问题,并得到更快的社区响应。 + +- 方式一:如果您不了解有哪些SIG或项目,您可以查看[SIG列表](https://gitee.com/openeuler/community/tree/master/sig),它包含当前openEuler社区成立的所有SIG团队的清单。您可以通过该列表快速的定位到您感兴趣的领域所对应SIG团队。同时还会向您提供该SIG团队的如下信息: + - SIG下的项目,以及项目的Repository地址 + - SIG内的交流方式,包括邮件列表、IRC或视频会议等 + - Maintainer的联系方式 +- **方式二**:如果您知道感兴趣的项目名称,可以在openEuler的Repository列表下进行模糊搜索,从而快速定位到对应项目的首页地址。通常情况下,在该项目首页地址的`README.md`文件中,可以找到该项目所属的SIG信息、交流方式、成员和联系方式等。 + +如果上述两种方式都定位不到您感兴趣的SIG,您可以向[community@openeuler.org](./mailto:community@openeuler.org)发求助邮件。建议您在邮件列表内用“【开发过程疑问】”作为标题,在内容中写出你寻找的SIG或项目的特征,我们会为您提供帮助。 + +确定好你要创建小组后,可以按照[模板](./gitee.com/openeuler/community/tree/master/sig/sig-template)创建一个新的sig目录,并提交 PR 到 [community仓库](https://gitee.com/openeuler/community/tree/master/sig),并在TC例会上申请议题(订阅tc@openeuler.org,并关注议题收集的邮件),经过大家一致同意后,合入PR,就代表sig创立成功。 + +这里是一个PR提交创立sig-golang的[具体例子](https://gitee.com/openeuler/community/commit/27b68ca952fffe175ff86b5debe286ea356347db),包括sig的raodmap、职责、管理的仓库(也许是从别的sig中移交过来)、联系方式和maintainer等信息。 + +### 4、贡献软件包 + +```mermaid +stateDiagram + [*] --> 查找软件 + 查找软件 --> [*] : 已存在 + 查找软件 --> 引入软件 : 不存在 + 引入软件 --> 确定所属SIG + 确定所属SIG --> SIG是否存在 + SIG是否存在 --> 创建SIG兴趣小组 :不存在 + SIG是否存在 --> 对应SIG下添加仓库 :存在 + 对应SIG下添加仓库 --> 评审合入 + 评审合入 --> [*] +``` +![image-20200611162225682](./openEuler-traval.assets/image-20200611162225682.png) + +当前发现openEuler社区缺少你需要的软件时,你可以尝试动手为社区贡献软件包。这里不再赘述OS是如何由linux软件包组成的,以及如何制作一个rpm包。这里着重讲解贡献软件包的流程。 + +- 首先,要明确贡献的软件包的功能,遵循[openEuler软件包引入和退出原则](https://gitee.com/openeuler/community/blob/master/zh/technical-committee/governance/software-management.md)。 + +- 再者,由于软件唯一的归属于一个sig,你需要查看当前是否有合适的sig承载,如果没有,需要你按照步骤3申请成立一个新的sig。 + +- 然后,你可以通过提交PR的方式,在对应的sig下添加软件仓库。可参考[这个提交](https://gitee.com/openeuler/community/pulls/438),一旦审核通过,后台会自动为你在对应的src-openeuler group下创建同名仓库,并在[Factory](https://build.openeuler.org/project/show/openEuler:Factory)工程中去创建同名package开始构建,由于默认仓库里只有readme,并不会进行真正的构建,而是exclude状态。 + + ![image-20200522001706202](./openEuler-traval.assets/image-20200522001706202.png) + +- 接着你可以按照2的操作提交一个PR,来上传可以构建的代码。一旦合入,Factory工程便会触发构建。 + + ![image-20200522001826061](./openEuler-traval.assets/image-20200522001826061.png) + +- 软件打包符合打包规范,请参考[如何打包](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md)。 + +- 该工程下所有软件包成功的构建结果,归档在: + + ![image-20200522002217686](./openEuler-traval.assets/image-20200522002217686.png) + + **它是以repo源的方式归档,可以直接使用yum安装。** + + ![image-20200522002316316](./openEuler-traval.assets/image-20200522002316316.png) + + + +## openEuler OBS使用 + +这两片文章帮助你了解obs的基本使用。[如何使用 openEuler OBS - (一)介绍](https://www.openeuler.org/zh/blog/2020/03/26/2020-03-26-how-to-OBS.html) 和[如何使用 openEuler OBS - (二)与gitee的联动](https://www.openeuler.org/zh/blog/2020/03/26/2020-03-26-OBS-with-Git.html) + +### 什么是obs? + +OBS是Open Build Service 的简写(官方网址:https://openbuildservice.org/), + +原本是作为发行版openSUSE专用的rpm打包的平台,后续扩展为面向多发行版、多架构、多格式的打包发布平台。 + + +**与koji的不同** + +- 管理范围 + +与koji只管理包(包括源码包与二进制包)仓库不同,OBS同时管理着源码与包两个仓库。koji是从一个包编译完成后开始接手,根据包的NVR(Name-Version-Release)确定包的位置,在编译验证后入库保存。而OBS是从源码阶段开始管理,它拥有自己的包版本标记与changelog日志。**OBS可以像git一样保存源码的历史版本,对源码进行分支管理**。并生成各版本的二进制包与源码包。 + +换句话说,OBS可以同时实现koji和git的功能。 > OBS接受源码的格式与git普遍的保存格式并不相同,所以OBS无法完全取代git。 + +- 适用格式 + +OBS可以生成rpm、deb等格式的包,而koji只适用于rpm格式。 + +- 支持Rest API + +方便测试框架、构建工程调用。 + +### 如何配置obs + +**安装osc** + +osc是OBS的命令行程序,您可以在[这里](https://download.opensuse.org/repositories/openSUSE:/Tools/) ,选择自己的系统版本,添加软件源到自身包管理器中。 + +这里以Fedora30为例: + +1. 添加软件源 + +将文件`http://download.opensuse.org/repositories/openSUSE:/Tools/Fedora_30/openSUSE:Tools.repo`另存到/etc/yum.repo.d/中。 > 需要root权限。 + +1. 安装osc + +执行 `dnf install osc` 命令安装osc。 + +**配置openEuler的OBS** + +有很多方法可以将osc链接至openEuler外网的OBS: + +1. 最基础的方法为在每次执行 `osc` 命令时添加参数: `-A http://openeuler-build.huawei.com/` + +2. 使用alias:`alias iosc="osc -A http://openeuler-build.huawei.com/"` + +3. 修改位于`home`目录下的osc配置文件:`vi ~/.oscrc`,并写入以下内容: + + ``` + [general] + apiurl = http://openeuler-build.huawei.com/ + + [http://openeuler-build.huawei.com/] + ``` + +**注册OBS账号** + +打开 http://openeuler-build.huawei.com/,点击右上角“Sign Up”,注册自己喜欢的帐号。 + +注册完成后,重新回到上面网址。点击右上角的“Login”,用新账户登录。系统会在注册时自动创建一个以“home:用户名”为格式命名的Home Project。 + +后续需要邮箱向infra@openEuler.org申请。 + +### OSC 命令 + +osc help 是帮助指南。类似git命令。 + +List Existing Content on the Server + +``` +osc ls #list projects +osc ls Apache #list packages in a project +osc ls Apache flood #list files of package of a project +``` + +Checkout Content + +``` +osc co Apache # entire project +osc co Apache flood # a package +osc co Apache flood flood.spec # single file +``` + +Update a Working Ddirectory + +``` +osc up +osc up [directory] +osc up * # from within a project dir, update all packages +osc up # from within a project dir, update all packages AND check out all newly added packages +``` + +Upload Changed Content + +``` +osc ci # current dir +osc ci [file1] [file2] # only specific files +osc ci [dir1] [dir2] ... # multiple packages +osc ci -m "updated foobar" # specify a commit message +``` + +Check the Commit Log + +``` +osc log +``` + +Show the status (which files have been changed locally) + +``` +osc st +osc st [directory] +``` + +If an update cannot be merged automatically, a file is in 'C' (conflict) state, and conflicts are marked with special lines. After manually resolving the problem, use `osc resolved *FILE*`. + +Mark files to be Added or Removed on the Next Checkin + +``` +osc add foo +osc rm foo +``` + +Add all New Files in Local Copy and Removes all Disappeared files + +``` +osc addremove +``` + +Generate a diff to view the changes + +``` +osc diff [file] +``` + +Show the Build Results of the Package + +``` +osc results +osc results [platform] +``` + +Show the Log File of a Package + +(you need to be inside a package directory) + +``` +osc buildlog [platform] [arch] +``` + +在本地机器上构建 + +``` +osc build [platform] [arch] [specfile] [--clean|--noinit|...] +``` + +以abuild用户进入chroot环境,方便调试 + +``` +osc chroot [platform] [arch] +``` + +### 如何创建自己的工程,package + +**配置Project** + +两种方法:网页操作、命令行操作 + +- 网页操作: + +在obs主页点击右上角 + + +依次进入 Home Project -> Repositories -> Add from a Distribution 。 + + + +按上图所示填写基础配置,并在Name栏填写喜欢的名字。 + +在选择后后退至Repositories界面,可以看到如下图所示的环境: + + + +1. 第一个为编辑按钮,可以选择当前发行版编译架构 +2. 第二个为添加按钮,可在发行版标准环境上额外添加单独的包(例如其他私人编译的依赖包) +3. 第三个为下载,点击后转到当前环境的仓库 +4. 第四个为删除 + +- 命令行操作: + +执行命令: `osc meta prj -e [project名]` ,会看到类似如下文本: + + + +其中, 1. repository标签为仓库标签, 可添加此项添加编译时的基础环境 2. Path标签为可用包路径标签, 需手动添加发行版包路径。如需要额外依赖, 也可以单独添加。 3. Arch标签为编译架构, 可同时添加多个。 + +例如: + +``` +​```xml + + + //此为额外添加依赖 + aarch64 + armv7l //此为多架构选项 + +​``` +``` + +**新建包** + +进入Project目录: `cd [project名]` + +新建Package: `osc mkpac [package名]` + +进入Package目录并将下载源码以【tar包、所有patch、spec文件、其他source文件】格式放置: + + + +向新创建的package中添加以上文件: `osc add *` + + + +将更改上传至服务器: `osc commit` + + + +在这里可以注明本次上传的简短介绍,用`:wq`保存并退出 + +之后就可以在网页上等待编译并查看结果了。 + +**查看包状态与下载包** + +您可以在Project与Package主页右侧看到当前编译状态 + + + +- `finished` 表示在某个系统平台执行编译链接、安装检查的过程结束 +- `succeeded` 状态为编译成功 +- `failed` 为编译失败,您可以点击查看日志 + +您可以点击*编译平台 -> Go to download repository* 到达编译仓库,获得此Project的repo源与所有编译成功的package。 + +**更新包** + +进入project文件夹: `cd [project名]` + +更新本地代码为最新代码: `osc up` + +进入package目录,使用 `osc add` 命令将新文件添加到package,修改spec文件后使用`osc commit`命令上传新版本。 + +### _service 的使用,与码云的联动 + +分为两部分: + +- 利用Source Services(下称源服务)直接获取git源码并编译成包 +- 利用webhook 使源服务在git仓库push时触发,从而实现OBS始终跟进git仓库最新版本源码的效果 + +#### 利用源服务直接获取git源码并编译成包 + +**Source Services 相关** + +> Source Services 是用于以可靠方式验证,生成或修改源的工具。它们被设计为最小的工具,并且可以按照经典UNIX设计的强大思想进行组合。 + +源服务就像是系统中的函数,我们可以通过运行脚本调用它;而脚本就是Package中的_service文件。 + +**创建使用源服务的Package** + +1. 通过命令行工具或者网页新建一个空的Package + + + +1. 进入Package目录并创建_service: + - 网页端点击*Add file* ,点击*Choose a file*,并选择本地建好的_service文件。 + - 命令行则在Package目录中新建_service文件并上传之服务器。 +2. 准备编辑_service文件 + +**编辑_service文件** + +最基础的_service文件将会如下所示: + +```powershell + + + git + git://github.com/cs2c-fu/hi.git + + + xz + *.tar + + + +``` + +最外层为``标记,在``内则为一个个``函数,而``则为``函数的参数。 + +为了实现“**利用源服务直接获取git源码并编译成包**”这个目标, + +我们的_service应该类似于这样(以下格式请根据具体情况选择合适的顺序): + +```xml + + + + git + helloworld + git://github.com/cs2c-fu/hi.git + VERSION.git + + + + *.* + */*.spec */*.patch + + + + xz + *.tar + + + + + +``` + +下面将对所需的服务逐一进行介绍: + +**第一个服务:[tar_scm](https://github.com/openSUSE/obs-service-tar_scm)** + +**tar_scm** 会将链接 url 中的仓库下载下来并打包为 tar 文件,文件包命名格式为: + +> [Name]-[Version].[commit_timestamp].tar + +其中,[commit_timestamp]为 commit 十六进制时间戳。 + +可选参数: + +- **filename** 定义打包后文件的 Name,默认为git仓库名。 +- **versionprefix** 定以打包后文件的 Version 格式,默认为当前十进制时间戳。 + +在OBS官方服务器中, **tar_scm** 服务由于在空间利用率上表现不佳, 已被 **obs_scm**、**tar** 服务取代,但openEuler的外网OBS暂时还不支持**obs_scm**,所以这里选择 **tar_scm** 。 + +> 详见:[链接](https://openbuildservice.org/2016/04/08/new_git_in_27/) + +**第二个服务:[extract_file](https://github.com/openSUSE/obs-service-extract_file)** + +**extract_file** 可以从tar包中提取文件, 具体需要提取什么文件取决于git仓库中的文件格式。 + +一般来说我们可以将打包需要的内容分为四大类: + +- **源码** : 参与编译过程的文件 +- **spec文件** : 指导如何打包的规范文件 +- **patch文件** : 修改源码的差异文件 +- **源文件** : 不参与编译但需要打包的文件 + +对于**git仓库**来说,一般会将所有文件放到仓库的根目录。 + + + +此时我们需要将**spec文件、patch文件、源文件**提取出来, **源码**则留在tar包中等待之后的服务将其压缩打包。 + +对于**OBS仓库**来说,为了方便OBS系统使用,人们已经对源码进行压缩打包。 + + + +此时我们需要将**所有文件**提取出来并省略之后的压缩打包环节。 + +参数: + +- **archive** 定义提取来源文件格式 +- **files** 定义提取文件类型 *注意:存在一个顶层目录,其名称未知,因此文件名应以 “\*/” 开头* + +**第三个服务:[recompress](https://github.com/openSUSE/obs-service-recompress)** + +**recompress** 会对指定文件进行压缩 + +参数: + +- **compression** 压缩格式,可选:none、gz、bz2、xz +- **file** 压缩内容 + +**第四个服务:[set_version](https://github.com/openSUSE/obs-service-set_version)** + +会将spec文件中的Version替换为obs_scm时的 + +``` +[Version].[commit_timestamp] +``` + +spec文件中可以以 + +``` +helloworld-%{version}.tar.xz +``` + +格式定位源码包。 + +**等待编译完成** + +由于使用源服务获取源码,所以编译时需要额外过程与时间。 + + + +当状态显示为 **blocked** 时, 表明源服务正在运行。当源服务运行完毕时会正常开始打包过程。 + +我的参考案例:[链接](http://openeuler-build.huawei.com/package/show/home:changjie_fu/hi) + +**Source Services 在实际场景中的应用** + +在[oVirt-SIG](http://openeuler-build.huawei.com/project/show/oVirt-SIG)组中,我们应用了源服务实现代码由git到OBS的同步。 + +首先,我们在git仓库中以:**spec文件、patch文件、 **源码tar包** 的格式上传并管理源码。 + + + +在OBS系统中建立对应包并以一下格式定义_service文件: + +```xml + + + git + ioprocess + https://gitee.com/openkylin/ioprocess.git + + + *.* + */* + + +``` + +由于我们已经很好的在git仓库中设置了存储格式, 此时我们只需将所有文件下载并提取即可。 + +在这之后,OBS系统会帮助我们完成编译与打包的环节。 + +#### 利用 webhook 使源服务在git仓库push时触发 + +在写此文时,OBS系统还不支持gitee格式的webhook,所以以下内容为使用github仓库实现。 + +obs可以创建令牌(token),当令牌被触发时,OBS会运行源服务。 + +将网址与令牌添加到git仓库的webhook列表中,就可以在git仓库中实现触发源服务,进而更新OBS中的包版本。 + +**具体步骤:** + +创建专属包的OBS Token(OBS令牌): + +``` +osc token --create +``` + +命令将生成仅对Project/Package生效的token。 + +- 使用命令 `osc token` 可以查看当前生效的令牌列表。 +- 使用命令`osc token --delete ` 可以删除令牌 + +打开git仓库网址(以github为例): + + + +打开仓库 -> Setting -> Webhooks + + +点击左上方的 Add webhook 。 + + +在 Payload URL中以: + +``` +http://openeuler-build.huawei.com/trigger/webhook?id=<令牌ID> +``` + +为格式填入。 + +在 Secret 中填入令牌秘匙,按需求选择trigger类型, 保证Webhook为Active状态。 + +之后点击 Add webhook 即成功实现。 + +可尝试触发trigger以验证成果。 diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/2020-03-25-lifecycle-02.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/2020-03-25-lifecycle-02.png new file mode 100644 index 0000000000000000000000000000000000000000..74212ce828c419501d83d0b59a22db1c20fc17be Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/2020-03-25-lifecycle-02.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-CopyLink.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-CopyLink.png new file mode 100644 index 0000000000000000000000000000000000000000..59029b2621005e7d965563a199071778561cbc27 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-CopyLink.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-PR1.JPG b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-PR1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..46135a459e9ad558f9a7e512f8801ec18d10103b Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-PR1.JPG differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-fork.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-fork.png new file mode 100644 index 0000000000000000000000000000000000000000..e933145b99f47e18659692eabab92ada6c09fdc8 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/Gitee-workflow-fork.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/chooselanguage.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/chooselanguage.png new file mode 100644 index 0000000000000000000000000000000000000000..44e736d20c86098b0e69e0a7027103871d19032b Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/chooselanguage.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152118205.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152118205.png new file mode 100644 index 0000000000000000000000000000000000000000..24d26666d01c2ea4e4335029abdb259407d55d80 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152118205.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152347249.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152347249.png new file mode 100644 index 0000000000000000000000000000000000000000..d74f84942378e47e1bac5fa70d0b1840d702c4ee Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152347249.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152426591.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152426591.png new file mode 100644 index 0000000000000000000000000000000000000000..19b847b9bdab502d83c112e84ba440a729ffaf7e Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152426591.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152440903.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152440903.png new file mode 100644 index 0000000000000000000000000000000000000000..5473daf1a2cc9a5e290f74c03060a2ec2c1b7704 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152440903.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152503864.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152503864.png new file mode 100644 index 0000000000000000000000000000000000000000..bc7e3ba5f20b5555c5b3c4ddd1f17f342fd1dfee Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152503864.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152831297.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152831297.png new file mode 100644 index 0000000000000000000000000000000000000000..7f11db418856114e07ccf995dccd99b32760df3a Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506152831297.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153453648.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153453648.png new file mode 100644 index 0000000000000000000000000000000000000000..c6cc9bb3c3ec3137c6e248e0f956b0339c17bbc5 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153453648.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153902264.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153902264.png new file mode 100644 index 0000000000000000000000000000000000000000..4171d61eeee442c0eab8ee9ea3005899b2591aac Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506153902264.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154028448.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154028448.png new file mode 100644 index 0000000000000000000000000000000000000000..1d42b10b5d9729fbe32f91e757b6a638f55ab9ac Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154028448.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154105394.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154105394.png new file mode 100644 index 0000000000000000000000000000000000000000..2556ac49832b2667ea9655445a9385f18ce74a28 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154105394.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154436536.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154436536.png new file mode 100644 index 0000000000000000000000000000000000000000..8fe34d6c39a0f66e42fee00b11193489b3a6c034 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154436536.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154459319.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154459319.png new file mode 100644 index 0000000000000000000000000000000000000000..dac25454e2077740c6361ceb9469b7ef1c1227fa Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154459319.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154518672.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154518672.png new file mode 100644 index 0000000000000000000000000000000000000000..ebfadecad8b309655c5c867037cbcd2f83d659da Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154518672.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154538225.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154538225.png new file mode 100644 index 0000000000000000000000000000000000000000..05e376f662bb188f0591343a33455efec5b04a3b Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154538225.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154610817.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154610817.png new file mode 100644 index 0000000000000000000000000000000000000000..4973da22936ec073c76a03cc5d002ce223f478b8 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154610817.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154813993.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154813993.png new file mode 100644 index 0000000000000000000000000000000000000000..0856348fe472e5df2b312d771ecc1556d5af84b3 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154813993.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154918752.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154918752.png new file mode 100644 index 0000000000000000000000000000000000000000..f536aa2fe01a74295f0121bf181ed22f064a3ee0 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200506154918752.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521203551777.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521203551777.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e920f3215d582f7ed7909bcc344842e6ea545c Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521203551777.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521204342097.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521204342097.png new file mode 100644 index 0000000000000000000000000000000000000000..432ac51a94ccc07c51935ff4b2ea47579bbaf101 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521204342097.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521210943225.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521210943225.png new file mode 100644 index 0000000000000000000000000000000000000000..2de8d3b81f7c0ed1b81fac9c0a5f2faf96fdc309 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521210943225.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521211038388.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521211038388.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2c1dcadf55fe7dc4db0d8964c88142221369a0 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521211038388.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521225454468.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521225454468.png new file mode 100644 index 0000000000000000000000000000000000000000..2d49ee9a9a2304ea2073896430eb32b5e6e1ac7e Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521225454468.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521232246188.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521232246188.png new file mode 100644 index 0000000000000000000000000000000000000000..ddaa598e2d05563ce4cb75acfd232e9f42db7cf6 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200521232246188.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001706202.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001706202.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ae03e66f5962d959a34ef3f2bd80d1a63e1d7c Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001706202.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001826061.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001826061.png new file mode 100644 index 0000000000000000000000000000000000000000..1b08a4ac7390c02d49176d12e56721039eb3de18 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522001826061.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002217686.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002217686.png new file mode 100644 index 0000000000000000000000000000000000000000..cb09ca36d14120908234992dd11590d95fde02a7 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002217686.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002316316.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002316316.png new file mode 100644 index 0000000000000000000000000000000000000000..50dbdff8e4796253394d313cbb1a991d974c6f1f Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002316316.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002832030.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002832030.png new file mode 100644 index 0000000000000000000000000000000000000000..294f0c03be7a1706a575c3bebf4f8f211b9f31aa Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522002832030.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522003012593.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522003012593.png new file mode 100644 index 0000000000000000000000000000000000000000..f39631c5c16f4abd128a470b267a2cda49baac10 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200522003012593.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173341921.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173341921.png new file mode 100644 index 0000000000000000000000000000000000000000..a8e0387c51af6fe070d5bab9806c941b7b8e97a4 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173341921.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173629091.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173629091.png new file mode 100644 index 0000000000000000000000000000000000000000..796e4944d55dfa965c4734f77d104499fa186394 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610173629091.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610174315367.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610174315367.png new file mode 100644 index 0000000000000000000000000000000000000000..747a2d9a79c7de5acb5a45c646e1895d137733ea Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200610174315367.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162154651.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162154651.png new file mode 100644 index 0000000000000000000000000000000000000000..0c8f4f582b1e3ff7245b7314e6e8709982127a05 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162154651.png differ diff --git a/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162225682.png b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162225682.png new file mode 100644 index 0000000000000000000000000000000000000000..6b489de1cc95a3f0d88d7aa9e178999b887188f4 Binary files /dev/null and b/web-ui/docs/zh/blog/overweight/openEuler-traval.assets/image-20200611162225682.png differ diff --git a/web-ui/docs/zh/blog/randy1568/Apache 2-4-39-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Apache 2-4-39-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..c3fc1670ab58af65426cd64a673e74c52f3e3ce2 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Apache 2-4-39-porting-guide.md @@ -0,0 +1,132 @@ +--- +title: Apache 2.4.39 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Apache + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Apache 2.4.39 +--- + +# Apache 2.4.39 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 + +Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,将Perl/Python等解释器编译到服务器中。 + +开发语言:C + +一句话描述:Web 服务器 + +## 建议的版本 + +建议使用版本为“Apache httpd 2.4.39”及以上版本。 + +# 环境要求 + +## 硬件要求 + +硬件要求如下所示。 + +项目 | 说明 +----- | ----- +服务器 | TaiShan 200服务器(型号2280) +CPU | 鲲鹏920 5250处理器 +磁盘分区 | 对磁盘分区无要求 + +## 操作系统要求 + +操作系统要求如下所示。 + +项目 | 版本 +----- | ----- +openEuler | 20.03 sp1 aarch64 +Kernel | 4.19 + +说明: + + 如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 + +# 配置编译环境 + +1. 安装开发包 + + yum update + yum install gcc gcc-c++ + +2. 安装依赖库 + + yum install apr-devel.aarch64 apr-util-devel.aarch64 pcre-devel.aarch64 -y + +3. 获取源码 + + 下载地址: http://archive.apache.org/dist/httpd/httpd-2.4.39.tar.gz + +## 配置安装 + + tar xzvf httpd-2.4.39.tar.gz + +## 修改源码配置 + + cd httpd-2.4.39 + vi ./build/config.sub + + 找到下面两行进行修改,添加aarch64: + + | x86 | xc16x | xstormy16 | xtensa \ + => + | x86 | aarch64 | xc16x | xstormy16 | xtensa \ + + + | x86-* | x86_64-* | xc16x-* | xps100-* \ + => + | x86-* | aarch64-* | x86_64-* | xc16x-* | xps100-* \ + +## 编译安装 + + ./configure --host=aarch64 --build=aarch64 + make -j4 + make install + +# 参数配置 + +## 修改httpd.conf + + vi /usr/local/apache2/conf/httpd.conf + + 89行取消注释: + LoadModule socache_shmcb_module modules/mod_socache_shmcb.so + + 196行取消注释,修改为当前服务器IP + #ServerName www.example.com:80 + => + ServerName local_server_ip:80 + + 461行取消注释 + Include conf/extra/httpd-mpm.conf + + 488行取消注释 + Include conf/extra/httpd-default.conf + +## 修改httpd-default.conf + + vi /usr/local/apache2/conf/extra/httpd-default.conf + + 23行值修改为0 + MaxKeepAliveRequests 0 + +# 验证: + + apache启动命令: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start + + apache停止命令: + /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k stop + + 查看服务进程: + ps -ef |grep httpd + diff --git a/web-ui/docs/zh/blog/randy1568/Dubbo 2-6-8-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Dubbo 2-6-8-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..ea55c7c5802588eef061c3336e7e28b727ea692f --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Dubbo 2-6-8-porting-guide.md @@ -0,0 +1,231 @@ +--- +title: Dubbo 2.6.8 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Dubbo 2.6.8 +--- + +# Dubbo 2.6.8 移植指南(openEuler 20.03 LTS SP1) + +## 介绍 + +### 简要介绍 + +Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC(远程过程调用)实现服务的输出和输入功能,可以和Spring框架无缝集成。简单地说,Dubbo是一个基于Spring的RPC框架,能够实现服务的远程调用、服务的治理。 + + + +### 建议版本 + +建议使用Dubbo 2.6.8版本。 + + + +## 环境要求 + + + +### 硬件要求 + +硬件要求如[表1](https://support.huaweicloud.com/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html#kunpengdubbo268_02_0002__d0e90)所示。 + +| 项目 | 说明 | +| ---- | ------------- | +| CPU | 鲲鹏920处理器 | +| 网络 | 可访问外网 | +| 存储 | 无要求 | +| 内存 | 无要求 | + + + +### 操作系统要求 + +操作系统要求如[表2](https://support.huaweicloud.com/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html#kunpengdubbo268_02_0002__d0e141)所示。 + + + +| 项目 | 版本 | +| --------- | --------------------- | +| openEuler | 20.03 LTS-SP1 aarch64 | +| Kernel | 4.19.90 | + + + +## 配置编译环境 + +### 配置DNS服务器 + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + + + +### 安装依赖包 + +1. 下载并安装依赖包 + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + + + +2. 查看Java版本 + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + + + +### 安装Maven + + + +1. 下载Maven安装包 + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + + + +2. 解压安装包到指定目录 + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + + + +3. 配置Maven环境变量。 + +a.在“/etc/profile” 文件末尾增加Maven路径 + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo "export PATH=$MAVEN_HOME/bin:$PATH" >> /etc/profile +``` + + + +b.使修改的环境变量生效。 + +``` +source /etc/profile +``` + + + +4. 检查配置是否生效。 + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + + + +5. 修改Maven配置文件中的本地仓、远程仓、代理等。 + +配置文件路径:“/opt/apache-maven-3.6.3/conf/settings.xml”。 + +配置网络代理,其中host,port,username,password需要根据当前环境修改: + +``` + + + my-proxy + true + https + 代理服务器网址 + 代理服务器端口 + 用户名 + 密码 + local.net|some.host.com + + + my-proxy1 + true + http + 代理服务器网址 + 代理服务器端口 + 用户名 + 密码 + local.net|some.host.com + + +``` + +配置远程仓库: + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + + + +## 编译Dubbo 2.6.8 + + + +### 获取源码 + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.6.8.tar.gz +&& tar -xvf dubbo-2.6.8.tar.gz +``` + + + +### 编译dubbo-rpc-redis模块 + +``` +mvn install +``` + + + +![img](https://support.huaweicloud.com/prtg-dubbo-kunpengwebs/zh-cn_image_0301675619.png) + +若窗口显示 **BUILD SUCCESS**,则dubbo-rpc-redis模块编译成功。 + + + +### 编译Dubbo 2.6.8 + + /home/Dubbo/dubbo-dubbo-2.6.8/pom.xml文件552行后增加如下内容: + + + + +若显示 **BUILD SUCCESS**,则Dubbo 2.6.8编译成功。 + + + + + +编译完成后的dubbo-2.6.8.jar包保存在“all/target”目录。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/Dubbo 2-7-5-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Dubbo 2-7-5-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..7bdeb8769a94ba5c5bc411c43c7e06e54f57adc0 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Dubbo 2-7-5-porting-guide.md @@ -0,0 +1,439 @@ +--- +title: Dubbo 2.7.5 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Dubbo + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Dubbo 2.7.5 +--- + +# Dubbo 2.7.5 移植指南(openEuler-20.03 LTS-SP2) + + + +## 介绍 + +### 简要介绍 + +Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC(远程过程调用)实现服务的输出和输入功能,可以和Spring框架无缝集成。简单地说,Dubbo是一个基于Spring的RPC框架,能够实现服务的远程调用、服务的治理。 + + + +### 建议版本 + +建议使用Dubbo 2.7.5版本。 + + + +## 环境要求 + + + +### 硬件要求 + +硬件要求如[表1](https://support.huaweicloud.com/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html#kunpengdubbo268_02_0002__d0e90)所示。 + +| 项目 | 说明 | +| ---- | ------------- | +| CPU | 鲲鹏920处理器 | +| 网络 | 可访问外网 | +| 存储 | 无要求 | +| 内存 | 无要求 | + + + +### 操作系统要求 + +操作系统要求如[表2](https://support.huaweicloud.com/prtg-dubbo-kunpengwebs/kunpengdubbo268_02_0002.html#kunpengdubbo268_02_0002__d0e141)所示。 + + + +| 项目 | 版本 | +| --------- | --------------------- | +| openEuler | 20.03 LTS-SP1 aarch64 | +| Kernel | 4.19.90 | + + + +## 配置编译环境 + +### 配置DNS服务器 + +``` +# cat /etc/resolv.conf +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` + + + +### 安装依赖包 + +1. 下载并安装依赖包 + +``` +yum install java-1.8.0* tcl git gcc gcc-c++ make cmake libtool autoconf automake -y +``` + + + +2. 查看Java版本 + +``` +[root@localhost ~]# java -version +openjdk version "1.8.0_272" +OpenJDK Runtime Environment Bisheng (build 1.8.0_272-b10) +OpenJDK 64-Bit Server VM Bisheng (build 25.272-b10, mixed mode) + +``` + + + +### 安装Maven + + + +1. 下载Maven安装包 + +``` +wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz +``` + + + +2. 解压安装包到指定目录 + +``` +tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /opt/ +``` + + + +3. 配置Maven环境变量。 + +a.在“/etc/profile” 文件末尾增加Maven路径 + +``` +echo "MAVEN_HOME=/opt/apache-maven-3.6.3/" >> /etc/profile +echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> /etc/profile +``` + + + +b.使修改的环境变量生效。 + +``` +source /etc/profile +``` + + + +4. 检查配置是否生效。 + +``` +[root@localhost ~]# mvn -v +Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) +Maven home: /opt/apache-maven-3.6.3 +Java version: 1.8.0_272, vendor: Bisheng, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.272.b10-7.oe1.aarch64/jre +Default locale: en_US, platform encoding: UTF-8 +OS name: "linux", version: "4.19.90-2012.4.0.0053.oe1.aarch64", arch: "aarch64", family: "unix" + +``` + + + +5. 修改Maven配置文件中的本地仓、远程仓、代理等。 + +配置文件路径:“/opt/apache-maven-3.6.3/conf/settings.xml”。 + +配置网络代理,其中host,port,username,password需要根据当前环境修改: + +``` + + + my-proxy + true + https + 代理服务器网址 + 代理服务器端口 + 用户名 + 密码 + local.net|some.host.com + + + my-proxy1 + true + http + 代理服务器网址 + 代理服务器端口 + 用户名 + 密码 + local.net|some.host.com + + +``` + +配置远程仓库: + +``` + + + huaweicloud + * + https://mirrors.huaweicloud.com/repository/maven/ + + +``` + + + +## 编译 + + + +### 获取源码 + +``` +mkdir /home/Dubbo && cd /home/Dubbo && wget https://github.com/apache/dubbo/archive/dubbo-2.7.5.tar.gz +&& tar -xvf dubbo-2.7.5.tar.gz +``` + + + +### 编译dubbo-common模块 + + + +### 编译dubbo-remoting-netty模块 + + + +1. 修改NettyClientTest.java文件。 + + + + a. 打开文件,将第76行中的“6000”改为“9000”。 + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/NettyClientTest.java ` + + + + + + b. 编译dubbo-remoting-netty模块 + + ``` + cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-netty && mvn install + ``` + + + + + +若显示 **BUILD SUCCESS**,则dubbo-remoting-netty模块编译成功。 + +​ + +### 编译dubbo-rpc-redis模块 + +1. 获取支持aarch64的embedded-redis-0.6.jar包 + +``` + mkdir -p /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar -O /root/.m2/repository/com/github/kstyrc/embedded-redis/0.6/embedded-redis-0.6.jar +``` + + + +2. 编译dubbo-rpc-redis模块 + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-rpc/dubbo-rpc-redis/ && mvn install +``` + + + +若显示 **BUILD SUCCESS**,则dubbo-rpc-redis模块编译成功。 + +### 编译dubbo-remoting-etcd3模块 + +1. 安装docker + +``` +yum -y install docker +``` + +2. 配置环境变量 + +``` +echo "export TESTCONTAINERS_RYUK_DISABLED=true" >> /etc/profile && source /etc/profile +``` + +3. 修改“/root/.testcontainers.properties”文件 + +``` +echo "checks.disable=true" >> /root/.testcontainers.properties +``` + +4. 替换支持ARM 64镜像的jetcd-launcher-0.3.0.jar包 + +``` +wget https://mirrors.huaweicloud.com/kunpeng/maven/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar -O /root/.m2/repository/io/etcd/jetcd-launcher/0.3.0/jetcd-launcher-0.3.0.jar +``` + + + +5. 编译dubbo-remoting-etcd3模块 + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-remoting/dubbo-remoting-etcd3/ && mvn install +``` + + + +若显示 **BUILD SUCCESS**,则dubbo-remoting-etcd3模块编译成功。 + +### 编译dubbo- registry-consul模块 + +``` +cd /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-registry/dubbo-registry-consul/ && mvn install + +``` + +==若编译过程中出现“EmbeddedConsul Could not start Consul process in...”的报错,则需要将ARM 64版本的consul_1.1.0_linux_arm64.zip包放在本地“/tmp/embedded-consul-1.1.0”目录下。== + +``` +wget https://releases.hashicorp.com/consul/1.1.0/consul_1.1.0_linux_arm64.zip && unzip consul_1.1.0_linux_arm64.zip && mv consul /tmp/embedded-consul-1.1.0/consul +``` + + + +然后再重新编译 + + + +若显示 **BUILD SUCCESS**,则dubbo- registry-consul模块编译成功。 + + + +### 修改其余配置文件 + +1. 替换本地仓库的netty-all-4.1.25.Final.jar包。 + + + + ``` + mkdir -p /root/.m2/repository/io/netty/netty-all/4.1.25.Final/ && wget https://mirrors.huaweicloud.com/kunpeng/maven/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar -O /root/.m2/repository/io/netty/netty-all/4.1.25.Final/netty-all-4.1.25.Final.jar + ``` + + + + + +2. 修改“/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml”文件。 + + + + 1. 打开pom.xml文件。 + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-config/dubbo-config-api/pom.xml ` + + 2. 添加以下代码后,保存并退出文件。 + + - 在第31行添加代码。 + + ``` + true + ``` + + + + + + - 在第206行添加代码。 + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + + + + + +3. 修改“/home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml”文件。 + + + + 1. 打开pom.xml文件。 + + `vim /home/Dubbo/dubbo-dubbo-2.7.5/dubbo-compatible/pom.xml ` + + 2. 添加以下代码后,保存并退出。 + + - 在第30行添加代码。 + + ``` + + true + + ``` + + + + + + - 在第110行添加代码。 + + ``` + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipIntegrationTests} + + + + + ``` + + + + + + + +### 编译Dubbo 2.7.5 + + /home/Dubbo/dubbo-dubbo-2.7.5/pom.xml文件592行后增加如下内容: + +``` + + true + +``` + + + + + + + +若显示 **BUILD SUCCESS**,则Dubbo 2.7.5编译成功。 + +编译完成后的dubbo-2.7.5.jar包保存在“dubbo-all/target”目录 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/HAProxy 1-9-0-porting-guide.md b/web-ui/docs/zh/blog/randy1568/HAProxy 1-9-0-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..1371e66cd55e17aa8c339ffc7846799d938b84a2 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/HAProxy 1-9-0-porting-guide.md @@ -0,0 +1,198 @@ +--- +title: HAProxy 1.9.0 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - HAProxy + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the HAProxy 1.9.0 +--- + +# HAProxy 1.9.0 移植指南(openEuler 20.03 LTS SP1) + +## 介绍 + +#### 简要介绍 + +HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。 +开发语言:C + +一句话描述:Web负载均衡 + +#### 建议的版本 + +建议使用版本为“HAProxy 1.9.0”。 + +说明: + +本文档适用于HAProxy 1.9.0,其他版本的HAProxy移植步骤也可参考本文档。 + +## 环境要求 + +#### 硬件要求 + +| 项目 | 说明 | +| -------- | ----------------------------- | +| 服务器 | TaiShan 200服务器(型号2280) | +| CPU | 鲲鹏920 5250处理器 | +| 磁盘分区 | 对磁盘分区无要求 | + +#### 操作系统要求 + +| 项目 | 版本 | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 aarch64 | +| Kernel | 4.19 | + +检查当前系统版本信息 + +```bash +cat /etc/os-release +``` + + + +安装openEuler操作系统,请参考https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html +说明: +安装方式建议选择“Server with GUI”安装方式。 + +## 镜像站RPM方式安装 + +若您的服务器可以访问网络,执行 wget https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm 命令下载RPM包。否则,请访问 https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/haproxy-1.9.0-1.el7.aarch64.rpm 下载RPM包并复制到服务器“/home”目录。 + +说明: +镜像站中的RPM包都是通过开源代码编译打包而成,然后将其上传到镜像站。 + +以本地下载RPM包并上传到服务器为例说明安装操作 + +2. 安装HAProxy + + ```bash + rpm -ivh haproxy-1.9.0-1.el7.aarch64.rpm + ``` + + + +3. 查看安装目录 + + ```bash + ls /usr/local/haproxy + ``` + + + +## 运行和验证 + +- 配置参数 + + a. 打开option-http_proxy.cfg文件 + + ```bash + vi /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + + b. 修改option-http_proxy.cfg为如下内容后,保存并退出文件 + + ```bash + global + maxconn 20000 + log 127.0.0.1 local0 info + uid 0 + gid 0 + chroot /usr/local/haproxy + nbproc 4 + daemon + defaults + mode http + retries 3 + timeout connect 10s + timeout client 20s + timeout server 30s + timeout check 2s + frontend test-proxy + bind *:80 + mode http + log global + default_backend test-proxy-srv + backend test-proxy-srv + balance roundrobin + option http-server-close + option httpchk GET /index.html + http-check expect status 200 + server web1 IP1:PORT1 weight 3 + server web2 IP2:PORT2 weight 3 + ``` + + 配置文件示例参数说明见[下表](https://support.huaweicloud.com/prtg-kunpengwebs/kunpenghaproxy_02_0011.html#kunpenghaproxy_02_0011__table177828478439)。 + +| 参数 | 说明 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| global | - | +| maxconn 20000 | 默认最大连接数。 | +| log 127.0.0.1 local0 info | 定义日志输出设备,info表示日志级别。 | +| uid 0 | 运行HAProxy的用户id。 | +| gid 0 | 运行HAProxy的用户组id。 | +| chroot /usr/local/haproxy | chroot运行路径。 | +| nbproc 4 | 设置进程数量。 | +| daemon | 以后台形式运行HAProxy。 | +| defaults | - | +| mode http | 所处理的类别(7层代理http,4层代理tcp)。 | +| retries 3 | 设置连接后端服务器的失败重试次数,超过此值标记后端服务器为不可用。 | +| timeout connect 10s | HAProxy与后端服务器建立连接的最长等待时间。 | +| timeout client 20s | 和客户端保持空闲连接的超时时间。 | +| timeout server 30s | 和服务端保持空闲连接的超时时间。 | +| timeout check 2s | 对服务端的检测超时时间。 | +| frontend test-proxy | - | +| bind *:80 | 定义一个或几个监测的套接字,*表示当前所有的ipv4地址。 | +| mode http | 所处理的类别(7层代理http,4层代理tcp)。 | +| log global | 继承global中log的定义。 | +| default_backend test-proxy-srv | 指定默认的后端服务器池。 | +| backend test-proxy-srv | - | +| balance roundrobin | 指定负载均衡算法 roundrobin是基于权重进行轮询的算法,适用于服务器性能均匀时。 | +| option http-server- | 当开启长连接时,应该开启此项。 | +| option httpchk GET /index.htmlhttp-check expect status 200 | 启用HTTP的服务状态检测(健康检查)。检查返回的状态码,接受不到200就不给后端server调度。 | +| server web1IP1:PORT1 weight 3 server web2 IP2:PORT2 weight 3 | 定义多个后端真实服务器。格式:server :[port] [param*]**说明:**IP1:PORT1和IP2:PORT2为后端服务器IP及端口号。weight表示权重。 | + +- 启动HAProxy + + ```bash + taskset -c 0-3 /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/option-http_proxy.cfg + ``` + +- 验证HAProxy + + ```bash + ps -ef | grep haproxy + ``` + + 可以看到HAProxy进程。 + + 打开浏览器在url处输入:http://IP:80,(IP为HAproxy所在服务器IP)可以看到后端服务器的页面,则说明HAProxy运行成功。刷新页面,显示页面在后端服务器间来回切换。 + + 说明: + + - (可选)停止HAProxy命令如下,业务运行中不需要执行该命令。 + + ```bash + pkill haproxy + ``` + + - (可选)卸载HAProxy,并查询。 + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rpm -e --nodeps haproxy-1.9.0 + ``` + + ```bash + rpm -qa | grep haproxy + ``` + + ```bash + rm -rf /usr/local/haproxy + ``` \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/Iok 2.1.3-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Iok 2.1.3-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..44a55e3758f15a907c21bba70176c9458d081e1a --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Iok 2.1.3-porting-guide.md @@ -0,0 +1,147 @@ +--- +title: Iok 2.1.3 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - lok + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the lok 2.1.3 +--- + +# Iok 2.1.3 移植指南 (openEuler 20.03 LTS SP1) + +## 简介 + +>Iok是一款在屏幕上显示印度语言的键盘映射应用 + +### 选用版本 + +> 2.1.3 + +### 安装指南 + +> https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html + +### 检查当前系统版本信息 + +```shell +cat /etc/os-release +``` + + + +### 兼容性检查 + +#### 下载iok-2.1.3 SRPM + +``` +wget http://mirror.centos.org/centos/7/os/x86_64/Packages/iok-2.1.3-6.el7.x86_64.rpm +``` + +#### 下载x2openEuler工具 + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ + +``` + +#### 部署工具 + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 扫描软件 + +``` +x2openEuler scan iok-2.1.3-6.el7.x86_64.rpm +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` + +## 查看评估结果 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + + + + + +> 结果:根据依赖报告可知,iok移植到openEuler 20.03 LTS SP1需要解决unique3依赖问题 + +## 依赖包引入 + +- 在openEuler/oec-application仓库中发起issue + +> 仓库地址:https://gitee.com/openeuler/oec-application + + + +- 持续追踪issue至缺失的依赖包被引入openEuler 20.03 LTS SP1 的YUM repo中 + +## 构建流程 + +> 当缺失的依赖包被引入后可进行 + +- 获取iok的Centos 7.6.1810 SRPM包 +- 在openEuler 20.03 LTS SP1上构建二进制包 + +###构建二进制包 + +```shell +yum install -y rpm-build +``` + +> 提供rpmbuild命令 + +- 从网络安装SRPM包 + +```shell +rpm -i https://vault.centos.org/7.6.1810/os/Source/SPackages/iok-2.1.3-6.el7.src.rpm +``` + +- 安装依赖 + +```shell +yum-builddep -y ~/rpmbuild/SPECS/iok.spec +``` + +- 构建二进制包 + +```shell +rpmbuild -bb ~/rpmbuild/SPECS/iok.spec +``` + +- 二进制包安装 + +``` +rpm -i ~/rpmbuild/RPMS/x86_64/*.rpm +``` + +- 查看二进制文件 + +``` +which iok +``` \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/Lighttpd 1-4-53-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Lighttpd 1-4-53-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..c82eadad8d21cf79f6e03447842ac26f4e5b97d7 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Lighttpd 1-4-53-porting-guide.md @@ -0,0 +1,214 @@ +--- +title: Lighttpd 1.4.53 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Lighttpd + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Lighttpd 1.4.53 +--- + +# Lighttpd 1.4.53 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 + +Lighttpd 是开源Web服务器软件,其根本的目的是提供一个专门针对高性能网站,安全、快速、兼容性好并且灵活的Web Server环境。具有非常低的内存开销、CPU占用率低、效能好以及丰富的模块等特点。 + +Lighttpd是众多OpenSource轻量级的Web Server中较为优秀的一个。支持FastCGI,CGI,Auth,输出压缩(output compress),URL重写,Alias等重要功能;而Apache之所以流行,很大程度也是因为功能丰富,在Lighttpd上很多功能都有相应的实现了,这点对于Apache的用户是非常重要的,因为迁移到Lighttpd就必须面对这些问题。 + +开发语言:C + +一句话描述:Web 服务器 + +## 建议的版本 + +建议使用版本为“Lighttpd 1.4.53”。 + +# 环境要求 + +## 硬件要求 + +###硬件要求如下所示。 + +|项目|说明| +|-----|-----| +|服务器 |TaiShan 200服务器(型号2280)| +|CPU|鲲鹏920 5250处理器| +|磁盘分区|对磁盘分区无要求| + +## 操作系统要求 + +操作系统要求如下所示。 + +项目 | 版本 +----- | ----- +openEuler | 20.03 sp1 aarch64 +Kernel | 4.19 + +说明: + + 如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 + +# 配置编译环境 + +1. 安装依赖库 + + yum -y install gcc gcc-c++ glib2-devel pcre-devel bzip2-devel zlib-devel gamin-devel + +3. 获取源码 + + 下载地址:https://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.53.tar.gz + +## 配置安装 + +``` +cp lighttpd-1.4.53.tar.gz $HOME && cd $HOME +tar xzvf lighttpd-1.4.53.tar.gz +``` + +## 编译安装 + +``` +cd lighttpd-1.4.53 +./configure --prefix=/usr/local/lighttpd --with-fam +make -j60 && make install +``` + +说明: + + --prefix=PATH:指定Lighttpd的安装目录。 + --with-fam:fam 用于减少stat()函数调用次数。 + + +# 参数配置 + +## 创建软件目录 + +``` +cd /usr/local/lighttpd/ +mkdir log webpages cache config +``` + +## 拷贝配置文件/目录 + +``` +cp $HOME/lighttpd-1.4.53/doc/config/lighttpd.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/modules.conf /usr/local/lighttpd/config/ +cp $HOME/lighttpd-1.4.53/doc/config/conf.d /usr/local/lighttpd/config/ -r +``` + +说明: + + Lighttpd安装后的安装路径下只有三个文件夹 lib,sbin和share,其他文件需要自己拷贝和创建。 + +## 修改lighttpd.conf + +``` +vi /usr/local/lighttpd/config/lighttpd.conf + +``` + +修改第16-20行为: + +``` +var.log_root = "/usr/local/lighttpd/log" +var.server_root = "/usr/local/lighttpd" +var.state_dir = "/usr/local/lighttpd" +var.home_dir = "/usr/local/lighttpd" +var.conf_dir = "/usr/local/lighttpd/config" +``` + +修改第61行为: + +``` +var.cache_dir = "/usr/local/lighttpd/cache" +``` + +第93行加注释: + +``` +#server.use-ipv6 = "enable" +``` + +修改第104-105行(该项为操作权限,不建议使用root)为: + +``` +server.username = "lighttpd1" +server.groupname = "lighttpd" +``` + +修改第115行(访问页面存放路径)为: + +``` +server.document-root = server_root + "webpages" +``` + +修改第246行(缓存模式,默认为simple,官方解释fam要优于simple)为: + +``` +server.stat-cache-engine = "fam" +``` + +在第182行添加如下内容(该项为配置多进程模式,Lighttpd默认单进程,数值可根据实际需求修改) : + +``` +server.max-worker = 4 +``` + +## 创建用户组 + +``` +groupadd lighttpd +useradd -g lighttpd lighttpd1 +``` + +## 修改权限 + +``` +chown lighttpd1 /usr/local/lighttpd/log +``` + +## 添加测试页面 + + cd /usr/local/lighttpd/webpages + vi index.html + +``` + <html> + <head> + <title>lighttpd test</title> + </head> + <body> + <p>this is a testing</p> + </body> + </html> +``` + +# 服务测试 + +启动lighttpd: + +``` +/usr/local/lighttpd/sbin/lighttpd -f /usr/local/lighttpd/config/lighttpd.conf +``` + +查看程序进程: + + +``` +ps -ef |grep lighttpd +``` + +停止apache: + +``` +pkill lighttpd +``` + +测试网页: + + http://{{ server_ip }}:80/index.html diff --git "a/web-ui/docs/zh/blog/randy1568/Memcached 1-5-12-porting-guide\357\274\211.md" "b/web-ui/docs/zh/blog/randy1568/Memcached 1-5-12-porting-guide\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..9d794449bdceae28f7ad59a2e26b7d746ccd22da --- /dev/null +++ "b/web-ui/docs/zh/blog/randy1568/Memcached 1-5-12-porting-guide\357\274\211.md" @@ -0,0 +1,215 @@ +--- +title: Memcached 1.5.12 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Memcached + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Memcached 1.5.12 +--- + +# Memcached 1.5.12 移植指南 + +## 介绍 + +#### 简要介绍 + +Memcached是LiveJournal旗下Danga Interactive公司以Brad Fitzpatric为首开发的一款高性能分布式内存对象缓存系统,通过缓存数据库查询结果,减少数据库访问次数,来提高动态Web应用的访问速度、提高可扩展性。 + +Memcached的官方链接:https://memcached.org/ + +开发语言:C + +一句话描述:分布式内存对象缓存系统 + +## 环境要求 + +#### 硬件要求 + +硬件要求如下表所示。 + +| 项目 | 说明 | +| -------- | ----------------------------- | +| 服务器 | TaiShan 200服务器(型号2280) | +| CPU | 鲲鹏920 5250处理器 | +| 磁盘分区 | 对磁盘分区无要求 | + +#### 操作系统要求 + +操作系统要求如下表所示。 + +| 项目 | 版本 | +| --------- | --------------------- | +| openEuler | 20.03 LTS SP1 aarch64 | +| Kernel | 4.19 | + +查询当前系统版本信息 + +``` +cat /etc/os-release +``` + + + +安装openEuler操作系统,请参考https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html +说明: +安装方式建议选择“Server with GUI”安装方式。 + +## 配置编译环境 + +编译Memcached需要准备C编译器、GNU、make、automake、libevent和libevent-devel。 + +1. 安装gcc,已安装则跳过 + + ```bash + yum -y install gcc gcc-c++ kernel-devel + ``` + +2. 安装GNU make和automake、unzip、telnet,已安装则跳过 + + ```bash + yum -y install make automake unzip telnet + ``` + +3. 安装libevent和libevent-devel + + ```bash + yum -y install libevent libevent-devel + ``` + +## 获取源码 + +若您的服务器可以访问网络,执行 wget https://github.com/memcached/memcached/archive/1.5.12.zip 命令下载源码。否则,请访问 https://github.com/memcached/memcached/archive/1.5.12.zip 下载源码并复制到服务器“/home”目录。 + +## 编译和安装 + +以本地下载源码并上传到服务器为例说明编译和安装操作 + +1. 解压源码包 + + ```bash + cd /home + ``` + + ```bash + unzip 1.5.12.zip + ``` + +2. 进入“memcached-1.5.12”目录 + + ```bash + cd memcached-1.5.12 + ``` + +3. 配置Memcached + + ```bash + sh autogen.sh + ``` + + ```bash + ./configure --prefix=/opt/memcached + ``` + + 可在该步骤指定Memcached安装目录,例如本文指定安装在“/opt/memcached”目录下。 + +4. 执行编译 + + ```bash + make -j60 + ``` + + -j60参数充分利用多核CPU优势,加快编译速度。 + +5. 执行安装 + + ```bash + make install + ``` + +6. 进入指定的Memcached安装目录“/opt/memcached”,若生成的“bin”目录中出现“memcached”可执行文件,说明编译安装完成 + +7. 配置环境变量 + + a. 将以下命令添加至“/etc/profile”文件中 + + ```bash + export PATH=/opt/memcached/bin/:$PATH + ``` + + b. 使环境变量生效 + + ```bash + source /etc/profile + ``` + +## 运行和验证 + +- 使用命令启动 + + ```bash + memcached -t 24 -p 11211 -u root -m 49152 -c 10240 + ``` + + 启动命令参数说明如下表所示。 + +| 命令参数 | 说明 | 默认值 | +| -------- | ------------------------------------- | -------------------------- | +| -t | 线程数。 | 4 | +| -p | 监测的TCP端口。 | 11211 | +| -u | 指定用户启动。 | 默认不能用root用户启动进程 | +| -m | 分配给Memcached的内存大小。单位:MB。 | 64M | +| -c | 最大并发连接数。 | 1024 | +| -d | 后台启动一个守护进程。 | - | + +- 另外启动一个Shell窗口,连接到Memcached + + ```bash + telnet 127.0.0.1 11211 + ``` + +- 创建连接之后,可使用stats命令获取到Memcached服务端的统计信息 + + ```bash + stats + ``` + + + +常用的stats命令如[下表](https://support.huaweicloud.com/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table1896316817714)所示。 + + + +| 命令 | 功能 | +| --------------- | ------------------------------------------------------------ | +| stats | 显示Memcached总体状态信息,包括启动时间、存储数据量、缓存命中率、当前连接数等。 | +| stats items | 输出各个slab中item的信息。 | +| stats slabs | 输出更详细的slab信息。 | +| stats sizes | 显示所有item的大小和个数。 | +| stats cachedump | 导出下的数据,是输出个数,若传入0则输出该slab下所有数据。 | +| stats detail | 设置(on/off)或显示(dump)详细操作记录,如get/set操作。 | +| flush_all | 使内存中所有item失效,该操作并不会暂停服务端,因为不会真正释放内存空间,而是将现有item标记为失效状态。 | + + 说明: + 如需退出Telnet连接可执行**quit**命令。 + + ```bash + quit + ``` + +除Telnet连接Memcached服务获取数据信息以外,源码中还提供了一些工具脚本,可以直接使用,如memcached-tool,位于源码中的scripts目录下。 + +memcached-tool的使用方法如[下表](https://support.huaweicloud.com/prtg-kunpengwebs/kunpengmemcached_02_0006.html#kunpengmemcached_02_0006__table15821759181818)所示。 + + + +| 命令 | 功能 | +| -------------------------------------------- | ------------------------ | +| ./memcached-tool localhost display | 显示slabs信息 | +| ./memcached-tool 10.0.0.5:11211 display | 显示slabs信息 | +| ./memcached-tool 10.0.0.5:11211 stats | 显示Memcached统计信息 | +| ./memcached-tool 10.0.0.5:11211 settings | 显示Memcached设置信息 | +| ./memcached-tool 10.0.0.5:11211 sizes | 显示items的大小和个数 | +| ./memcached-tool 10.0.0.5:11211 dump [limit] | 导出缓存中的Keys和Values | \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/MySQL 5-7-21-migrate-guide.md b/web-ui/docs/zh/blog/randy1568/MySQL 5-7-21-migrate-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..6b924ca480333d8ddabbfdb255493723d17ccd01 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/MySQL 5-7-21-migrate-guide.md @@ -0,0 +1,270 @@ +--- +title: MySQL 5.7.21 移植指南(openEuler 20.03 LTS SP1) +date: 2022-01-05 +tags: + - MySQL + - Migrate Case +sig: sig-Compatibility-Infra +archives: 2022-01 +author: xielihao +summary: Just about everything of the MySQL 5.7.21 migrate case +--- + +# MySQL 5.7.21 移植指南(openEuler 20.03 LTS SP1) + + +## 1.简要介绍 + +本文主要用于指导在openEuler 20.03 sp1 操作系统上部署mysql数据库。 + +MySQL 是一款安全、跨平台、高效的,并与 PHP、Java 等主流编程语言紧密结合的数据库系统。 +本案例使用x86_64架构虚拟机,通过评估工具x2openEuler评估MySQL 5.7.21软件移植到openEuler操作系统的兼容性,再实施数据搬迁。 + +建议使用版本为MySQL 5.7.21。 + +> 说明: +> 本文档适用于MySQL 5.7.21,其他版本的MySQL移植步骤也可参考本文档。 + +## 2.案例环境 + +服务器 +| 项目 | 说明 | +| -------- | ----------------- | +| 服务器 | TaiShan 200服务器 | +| CPU | 华为鲲鹏920处理器 | +| Raid卡 | SAS3508 | +| 网络卡 | Mellanox SP333 | +| | TM210 | +| | TM280 | +| 磁盘容量 | 500GB以上 | + +OS +| 软件 | 版本 | 备注 | +| ---- | ------------------- | ------------------- | +| OS | Centos 7.6.1810 | 当前mysql集群服务器 | +| OS | openEuler 20.03 SP1 | 迁移目标服务器 | + +软件包 +| 软件 | 版本 | +| --------------------- | ------ | +| mysql5 | 5.7.21 | +| mysql5-common | 5.7.21 | +| mysql5-embedded | 5.7.21 | +| mysql5-embedded-devel | 5.7.21 | +| mysql5-errmsg | 5.7.21 | +| mysql5-libs | 5.7.21 | +| mysql5-server | 5.7.21 | +| mysql5-test | 5.7.21 | + +## 3.软件兼容性评估 + +openEuler社区提供了 [x2openEuler 工具](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/) ,针对已经编译好的二进制程序,进行主要完成软件包、接口级评估,明确应用软件是否需要移植适配,是否有依赖的软件包待引入;同时评估软件调用的接口原型在两个系统中是否有差异。 + +注:已经编译好的二进制程序,难以保障全部兼容新OS,严重时会引发才内存风险,往往这种问题很难通过验证的方式识别出来,迁移前针对软件兼容性评估尤为重要。 + +#### 3.1获取mysql的RPM包并解压到/opt/mysql目录下 + +``` +wget -P /opt https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar +``` +``` +cd /opt/ +mkdir mysql +tar -xf mysql-5.7.21-1.el7.x86_64.rpm-bundle.tar -C mysql +``` + +#### 3.2下载x2openEuler工具到/opt/mysql + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ +``` +#### 3.3部署工具 + +``` +cd /opt/mysql +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 3.4扫描mysql + +``` +x2openEuler scan /opt/mysql/ +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` +## 4.评估结果分析 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + +#### 4.1报告分析 + +``` +打开html报告,逐行分析,得出结论:在openEuler上直接使用centos的mysql包存在风险,风险如下: +1个待确认接口表明mysql系列软件包会调用到libaio.so.1.0.1,其函数参数数量从4变为5,直接影响了功能,在某个功能调用时可能会触发异常; + +另外,报告显示需要确认3个依赖软件包,经过人工确认属于mysql系列包自闭环的依赖,故软件包安装无影响 +``` + + + + + +#### 4.2分析结果建议 + +``` +建议:由于函数调用风险,建议直接使用在openEuler官方编译移植过的mysql-5.7.21系列软件包 +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mariadb-common-10.3.9-9.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-common-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-server-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mysql5-errmsg-5.7.21-3.oe1.x86_64.rpm +https://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/x86_64/Packages/mecab-0.996-2.oe1.x86_64.rpm +``` + +## 5.安装数据库mysql + +#### 5.1安装mysql并配置密码 + +**1)安装mariadb及mysql相关服务。** + +rpm -ivh mysql5-5.7.21-3.oe1.x86_64.rpm mariadb-common-10.3.9-9.oe1.x86_64.rpm mysql5-common-5.7.21-3.oe1.x86_64.rpm mysql5-server-5.7.21-3.oe1.x86_64.rpm mecab-0.996-2.oe1.x86_64.rpm mysql5-errmsg-5.7.21-3.oe1.x86_64.rpm + +**2) 启动mysql。** + +systemctl start mysqld + +**3)mysql状态查询。** + +systemctl status mysqld + +状态为running则启动成功: + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 ~# systemctl status mysqld + +● mysqld.service - MySQL 5.7 database server + + Loaded: loaded (/usr/lib/systemd/system/mysqld.service; disabled; vendor preset: disabled) + + Active: active (running) since Thu 2021-09-09 10:23:25 CST; 1 day 4h ago + + Process: 103715 ExecStartPre=/usr/libexec/mysql-check-socket (code=exited, status=0/SUCCESS) + + Process: 103738 ExecStartPre=/usr/libexec/mysql-prepare-db-dir mysqld.service (code=exited, sta> + + Process: 103773 ExecStart=/usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld> + + Process: 103803 ExecStartPost=/usr/libexec/mysql-check-upgrade (code=exited, status=0/SUCCESS) + + Main PID: 103775 (mysqld) + + Tasks: 37 + + Memory: 188.4M + + CGroup: /system.slice/mysqld.service + +​ └─103775 /usr/libexec/mysqld --daemonize --basedir=/usr --pid-file=/run/mysqld/mysqld. +``` + +**4) 登录并修改默认密码。** + +mysql -uroot -p + +a. 默认没有密码,按回车即可登录。 + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 2 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +mysql> +``` + +b. 设置密码。 + +alter user 'user'@'localhost' identified by 'passward'; + +``` +mysql> alter user 'root'@'localhost' identified by '123456'; + +Query OK, 0 rows affected (0.00 sec) + +mysql> flush privileges; + +Query OK, 0 rows affected (0.00 sec) + +mysql> +``` + +> **flush privileges**必须执行,否则设置不生效。 + +**5) 验证密码。** + +退出后重新登录,查看密码是否修改成功。 + +``` +root@vm-2p32g.2288hv5-2s44p-384g--b5-0 /# mysql -uroot -p + +Enter password: + +Welcome to the MySQL monitor. Commands end with ; or \g. + +Your MySQL connection id is 3 + +Server version: 5.7.21 MySQL Community Server (GPL) + + +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + + +Oracle is a registered trademark of Oracle Corporation and/or its + +affiliates. Other names may be trademarks of their respective + +owners. + + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + + +mysql> +``` diff --git a/web-ui/docs/zh/blog/randy1568/Nginx 1-14-2-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Nginx 1-14-2-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..0722aec8c43bee7bc89bb2bc87d53fca699a7ce4 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Nginx 1-14-2-porting-guide.md @@ -0,0 +1,520 @@ +--- +title: Nginx 1.14.2 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Nginx + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Nginx 1.14.2 +--- + +# Nginx 1.14.2 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 +Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,其特点是占有内存少,并发能力强,支持FastCGI、SSL、Virtual Host、URL Rewrite、gzip等功能,并且支持很多第三方的模块扩展。 + +开发语言:C + +一句话描述:Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器 +## 建议的版本 +建议使用版本为“Nginx 1.14.2”。 + 说明: + 本文档适用于Nginx 1.14.2版本,其他版本的Nginx移植步骤也可参考本文档。 + + +# 环境要求 +## 硬件要求 +硬件要求如表1所示。 +表1 硬件要求 + +|项目 |说明 | +|---------|--------------------------| +|服务器 |TaiShan 200服务器(型号2280)| +|CPU |鲲鹏920 5250处理器 | +|磁盘分区 |对磁盘分区无要求 | + +## 操作系统要求 +操作系统要求如表2所示。 +表2 操作系统要求 + +|项目 |版本 |版本查看命令 | +|------------|---------|---------------------------------| +|openEuler |20.03 LTS SP1 |```cat /etc/openEuler-release``` | +|Kernel |4.19.90 |``` uname -r``` | + +# 配置编译环境 +## 配置Yum源 +说明: +如果组网环境处于外网受限情况下,服务器yum命令无法通过外界获取依赖包时,可参考本节内容进行本地源配置。 +1. 将操作系统镜像文件openEuler-20.03-LTS-everything-aarch64-dvd.iso文件拷贝到每台服务器的“/root”目录下。 +2. 镜像文件挂载。 + a. 将“/root”目录下的openEuler操作系统对应iso文件挂载到“/mnt”目录下。 + ```mount /root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt``` + 说明: + 该操作单次生效,重启后失效。若需要配置开机启动自动挂载镜像(可选),可参考下面步骤。 + 1. 打开fstab文件。 + ```vi /etc/fstab``` + 2. 编辑fstab文件,在文件末尾添加如下信息: + ```/root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt iso9660 loop 0 0``` + 3. 保存并退出fstab文件。 +3. 添加本地源文件。 + a. 进入“/etc/yum.repos.d”目录。 + ```cd /etc/yum.repos.d``` + 说明: + 此时,建议将此目录下的*.repo文件移到任意其他备份目录下。 + b. 创建local.repo文件。 + 1. 打开local.repo文件。 + ```vi local.repo``` + 2. 编辑local.repo文件,在local.repo文件中添加如下内容: + ``` + [local] + name=local.repo + baseurl=file:///mnt + enabled=1 + gpgcheck=0 + ``` + 说明: + 其中,baseurl中file路径为镜像挂载路径,与镜像文件挂载中的目录“/mnt” 对应。 + 3. 保存并退出local.repo文件。 + 4. 生效本地源。 + ``` + yum clean all + yum makecache + yum list + ``` + +## 安装依赖包 +下载并安装依赖包 + +``` +yum -y install gcc gcc-c++ make libtool zlib zlib-devel pcre pcre-devel pcre2-devel perl-devel perl-ExtUtils-Embed openssl openssl-devel +``` + +# 获取源码 +本文使用源码编译安装,因此需要获取到Nginx。 + +1. 下载Nginx源码 +``` cd /home``` +```wget https://nginx.org/download/nginx-1.14.2.tar.gz --no-check-certificate``` + +说明: +也可以通过本地浏览器下载源码之后上传到服务器"/home"目录下。 +源码地址:https://nginx.org/download/nginx-1.14.2.tar.gz + +注意: +若及其需要配置代理才可以访问外网,请参考下面操作配置网络代理。 +1. 打开profile文件 +```vi /etc/profile``` +2. 添加如下代码后,保存并退出文件。 +其中,代理服务用户名、代理服务器密码、代理服务器IP和代理服务端口需要根据当前环境配置 +``` +export http_proxy="http://代理服务器名:代理服务器密码@代理服务器IP:代理服务器端口" +export http_proxy=$http_proxy +export no_proxy=127.0.0.1,.huawei.com,localhost,local,.local +``` +3. 使用代理效。 +```source /etc/profile``` +4. 查看环境变量中的代理信息。 +```env``` +5. 验证代理是否配置成功。 +```curl www.baidu.com``` +可以正常解析百度即为配置成功。 + +# 编译和安装 +1. 解压Nginx安装包。 +```tar -xvf nginx-1.14.2.tar.gz``` + +2. 进入"nginx-1.14.2"目录。 +```cd /home/nginx-1.14.2/``` + +3. 配置Nginx。 +```./configure --prefix=/usr/local/nginx --with-http_ssl_module``` +说明: +- --prefix=PATH:用来制定Nginx的安装目录,默认安装目录为"/usr/local/nginx"。 +- 不需要配置with-http_stub_status_module模块,该统计模块会影响Nginx性能。 +4. 编译并安装Nginx +```make -j96 && make -j96 install``` + 说明: + -j96: 充分利用CPU多核优势,加快编译安装速度。 + CPU 的核数可以通过lscpu查看。 +5.查看安装目录。 +```ls /usr/local/nginx``` + + +# 运行和验证 +## 生成证书 +1. 进入"/usr/local/nginx"目录,在该目录下生成密钥key。 +```cd /usr/local/nginx``` +```openssl genrsa -des3 -out server_2048.key 2048``` +会有两次要求输入密码,输入同一个即可,此时会生成server_2048.key文件。 +``` +[root@localhost nginx]# openssl genrsa -des3 -out server_2048.key 2048 +Generating RSA private key, 2048 bit long modulus (2 primes) +..................................................................................+++++ +................+++++ +e is 65537 (0x010001) +Enter pass phrase for server_2048.key: +Verifying - Enter pass phrase for server_2048.key: +``` + + 说明: + 可通过如下命令实现免密码使用此文件: + ```openssl rsa -in server_2048.key -out -server_2048.key``` + + ``` + [root@localhost nginx]# openssl rsa -in server_2048.key -out -server_2048.key + Enter pass phrase for server_2048.key + writing RSA key + ``` + +2. 创建服务器证书的申请文件。 +``` +openssl req -new -key server_2048.key -out server_2048.csr +``` + +``` +[root@localhost nginx]# openssl req -new -key server_2048.key -out server_2048.csr +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []: +Organization Name (eg, company) [Internet Widgits Pty Ltd]: +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []: +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +输入1中设置的密码,其中Country Name 选项输入CN,其他选项可以不填。 +3. 重写密钥key。 +```openssl rsa -in server_2048.key -out server_2048.key``` +``` +[root@localhost nginx]# openssl rsa -in server_2048.key -out server_2048.key +writing RSA key +``` +4. 生成证书。 +```openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt``` +``` +[root@localhost nginx]# openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt +Signature ok +subject=C = CN, ST = Some-State, O = Internet Widgits Pty Ltd +Getting Private key +``` +输入1中设置的密码。若已经设置免密码使用该文件,则无需输入密码。 + +## 配置功能 +### 配置Nginx的HTTPS功能 +1. 打开nginx.conf配置文件。 +```vi /usr/local/nginx/conf/nginx.conf``` +2. 修改nginx.conf配置文件以下三处配置后,保存并退出(Esc+ :wq)。 + - 定义Nginx运行的用户权限user为root。 + - 修改listen监测端口,可以使用默认端口,本文修改为20000。 + - 指定ssl_certificate和ssl_certificate_key文件。 + +#### 原文默认内容: +``` +#user nobody; +... + # HTTPS server + # + #server { + # listen 443 ssl; + # server_name localhost; + + # ssl_certificate cert.pem; + # ssl_certificate_key cert.key; + + # ssl_session_cache shared:SSL:1m; + # ssl_session_timeout 5m; + + # ssl_ciphers HIGH:!aNULL:!MD5; + # ssl_prefer_server_ciphers on; + + # location / { + # root html; + # index index.html index.htm; + # } + #} +``` + +#### 修改后内容: +``` +user root; + ... + HTTPS server + + server { + listen 20000 ssl; + server_name localhost; + + ssl_certificate /usr/local/nginx/server_2048.crt; + ssl_certificate_key /usr/local/nginx/server_2048.key; + + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location / { + root html; + index index.html index.htm; + } + } + +``` + + +### 配置Nginx的HTTP功能 + +1. 打开nginx.conf配置文件。 +```vi /usr/local/nginx/conf/nginx.conf``` +2. 修改nginx.conf配置文件以下三处配置后,保存并退出(Esc+ :wq)。 + - 定义Nginx运行的用户权限user为root。 + - 修改listen监测端口,可以使用默认端口,本文修改为10000。 + +#### 原文件默认内容: +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 80; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +#### 修改后内容: +``` +user root; +... +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on + + server { + listen 10000; + server_name localhost; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + } +} +``` + +## 运行Nginx +1. 启动Nginx(两种方式)。 + + - 通过Service服务启动(使用该方法需要先将Nginx加入Service服务再执行启动命令)。 + 1. 修改“/etc/init.d/nginx”文件。 + a. 删除原文件nginx。 + ```rm -rf /etc/init.d/nginx``` + b. 新建nginx文件。 + ```vi /etc/init.d/nginx``` + c. 添加如下内容后,保存并退 +``` + #!/bin/bash + # chkconfig: 2345 10 90 + # description: nginx + case "$1" in + 'start') + /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf + echo "$0_start"; + ;; + 'stop') + /usr/local/nginx/sbin/nginx -s quit + echo "$0_stop"; + ;; + esac +``` + + 2. 修改“/etc/init.d/nginx”文件权限。 +```chmod 777 /etc/init.d/nginx``` + 3. 将Nginx加入chkconfig管理列表。 +```chkconfig --add /etc/init.d/nginx``` + 4. 设置Nginx开机自动启动。 +```chkconfig nginx on``` + 5. 启动Nginx。 +```service nginx start``` + - 通过脚本命令启动。 +```/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf``` +2. 查看Nginx的进程。 +```ps -ef | grep nginx``` +``` +[root@localhost nginx]# ps -ef | grep nginx +root 9463 1 0 18:22 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf +root 9464 9463 0 18:22 ? 00:00:00 nginx: worker process +root 9466 1352 0 18:23 ttyAMA0 00:00:00 grep --color=auto nginx +``` + 说明: + 关闭Nginx命令如下(3种方式,可选)。业务运行中不要执行该命令。 + - 通过Service服务关闭。 + ```service nginx stop``` + - 通过脚本命令关闭。 + ```/usr/local/nginx/sbin/nginx -s quit``` + - 使用结束进程命令。 + + ```pkill nginx``` + +``` +[root@localhost nginx]# pkill nginx +[root@localhost nginx]# ps -ef | grep nginx +root 9469 1352 0 18:27 ttyAMA0 00:00:00 grep --color=auto nginx +``` + +## 验证Nginx +1. 查看Nginx的监测端口(10000是HTTP监测端口,20000是HTTPS监测端口)。 +```netstat -anp | grep 10000``` +```netstat -anp | grep 20000``` +```netstat -anpt``` + +``` +[root@localhost nginx]# netstat -anp | grep 10000 +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anp | grep 20000 +tcp 0 0 0.0.0.0:20000 0.0.0.0:* LISTEN 9535/nginx: master +[root@localhost nginx]# netstat -anpt +Active Internet connections (servers and established) +Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name +tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 9535/nginx: master +tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 775/sshd: /usr/sbin +``` +2. 查看Nginx的HTML文件所在目录。 +```ll -h /usr/local/nginx/html/``` +``` +[root@localhost nginx]# ll -h /usr/local/nginx/html/ +total 8.0K +-rw-r--r--. 1 root root 537 Mar 20 16:46 50x.html +-rw-r--r--. 1 root root 612 Mar 20 16:46 index.html +``` +3. 验证HTTPS功能。 +通过curl本地访问Nginx的HTML页面。 +```curl -k https://127.0.0.1:20000/index.html``` + +``` +[root@localhost nginx]# curl -k https://127.0.0.1:20000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` +4. 验证HTTP功能。 +通过curl本地访问Nginx的HTML页面。 +```curl http://127.0.0.1:10000/index.html``` + +``` +[root@localhost nginx]# curl http://127.0.0.1:10000/index.html + + + +Welcome to nginx! + + body { + width: 35em; + margin: 0 auto; + font-family: Tahoma, Verdana, Arial, sans-serif; + } + + + +

Welcome to nginx!

+If you see this page, the nginx web server is successfully installed and +working. Further configuration is required. + +For online ation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com. + +Thank you for using nginx. + + +``` + +# 卸载Nginx +1. 编译安装只是生成对应的文件,不涉及卸载,直接删除对应的安装目录即可。 +```rm -rf /usr/local/nginx``` + + + diff --git a/web-ui/docs/zh/blog/randy1568/Squid 4.8-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Squid 4.8-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..83d811c83c2008cf278d07b3cc08acb71525504a --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Squid 4.8-porting-guide.md @@ -0,0 +1,112 @@ +--- +title: Squid 4.8 移植指南 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Squid + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything of the Squid 4.8 Porting Case +--- + +# Squid 4.8 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +#### 简要介绍 + +Squid cache(简称为Squid)是一个流行的代理服务器和Web缓存服务器,是一个开源软件(GNU通用公共许可证)。Squid有广泛的用途,从作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度,到为一组人共享网络资源而缓存万维网,域名系统和其他网络搜索,到通过过滤流量帮助网络安全,到局域网通过代理上网。Squid主要设计用于在Unix一类系统运行。Squid的发展历史相当悠久,功能也相当完善。除了HTTP外,对于FTP与HTTPS的支持也相当好,在3.0测试版中也支持了IPv6。 + +开发语言:C++ + +一句话描述:Web 代理服务、Web缓存服务器 + +#### 建议的版本 + +建议使用版本为“Squid 4.8”。 + +> 说明: +> 本文档适用于Squid 4.8,其他版本的Squid移植步骤也可参考本文档。 + +# 环境要求 + +#### 硬件要求 + +| 项目 | 说明 | +| -------- | ----------------------------- | +| 服务器 | TaiShan 200服务器(型号2280) | +| CPU | 鲲鹏920 5250处理器 | +| 内存 | 内存 >= 8G | +| 磁盘分区 | 对磁盘分区无要求 | + +#### 操作系统要求 + +| 项目 | 版本 | +| --------- | --------------------------------- | +| openEuler | openEuler 20.03 LTS SP1 aarch64 | +| Kernel | 4.19.90-2003.4.0.0036.oe1.aarch64 | + +#### 安装操作系统 + +请参考:[20.03 LTS SP1 安装指南](https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html) + + +#### 检查当前系统版本信息 + +```bash +[root@localhost ~]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +ID="openEuler" +VERSION_ID="20.03" +PRETTY_NAME="openEuler 20.03 (LTS-SP1)" +ANSI_COLOR="0;31" +``` + +> 说明: +> 如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 + +# 安装Squid + +## 配置dns解析文件 + +```bash +[root@localhost ~]# echo "nameserver 114.114.114.114" >> /etc/resolv.conf +``` + +## 安装依赖包 + +```bash +[root@localhost ~]# yum install gcc libxml2-devel libcap-devel libtool-ltdl-devel perl* -y +``` + +## 源码编译安装Squid + +### 获取Squid 4.8的源码包。 + +```bash +[root@localhost ~]# cd /home +[root@localhost home]# wget http://www.squid-cache.org/Versions/v4/squid-4.8.tar.gz +``` + +### 安装Squid 4.8。 + +```bash +[root@localhost home]# tar -xf squid-4.8.tar.gz +[root@localhost home]# cd squid-4.8 +[root@localhost squid-4.8]# ./configure +[root@localhost squid-4.8]# make -j 64 && make install +[root@localhost squid-4.8]# chmod 777 /usr/local/squid/var/logs/ +``` + +# 运行和验证 + +```bash +[root@localhost squid-4.8]# /usr/local/squid/sbin/squid +[root@localhost squid-4.8]# ps -ef |grep squid +root 79023 1 0 19:40 ? 00:00:00 /usr/local/squid/sbin/squid +nobody 79025 79023 0 19:40 ? 00:00:00 (squid-1) --kid squid-1 +nobody 79026 79025 0 19:40 ? 00:00:00 (logfile-daemon) /usr/local/squid/var/logs/access.log +root 79028 1405 0 19:40 pts/0 00:00:00 grep --color=auto squid +``` \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/Tengine 2.2.2-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Tengine 2.2.2-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..3e7156bce841783a95891cbafd251ee0cf0428b8 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Tengine 2.2.2-porting-guide.md @@ -0,0 +1,261 @@ +--- +title: Tengine 2.2.2 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Tengine + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything of the tengine 2.2.2 porting case +--- + +# Tengine 2.2.2 移植指南 + +# 介绍 + +#### 简要介绍 + +Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。它的目的是打造一个高效、安全的Web平台。 + +开发语言:C + +一句话描述:轻量级Web服务器 + + +#### 建议的版本 + +建议使用版本为“Tengine 2.2.2”。 + +> 说明: +> 本文档适用于Tengine 2.2.2,其他版本的Tengine移植步骤也可参考本文档。 + +# 环境要求 + +#### 硬件要求 + +| 项目 | 说明 | +| -------- | ----------------------------- | +| 服务器 | TaiShan 200服务器(型号2280) | +| CPU | 鲲鹏920 5250处理器 | +| 磁盘分区 | 对磁盘分区无要求 | + +#### 操作系统要求 + +| 项目 | 版本 | +| --------- | --------------------------------- | +| openEuler | openEuler 20.03 LTS SP1 aarch64 | +| Kernel | 4.19.90-2003.4.0.0036.oe1.aarch64 | + +#### 安装操作系统 + +请参考:[20.03 LTS SP1 安装指南](https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html) + +#### 检查当前系统版本信息 + +```bash +[root@localhost ~]# cat /etc/os-release +NAME="openEuler" +VERSION="20.03 (LTS-SP1)" +ID="openEuler" +VERSION_ID="20.03" +PRETTY_NAME="openEuler 20.03 (LTS-SP1)" +ANSI_COLOR="0;31" +``` + +> 说明: +> 如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 + +# 安装Tengine + +## 配置dns解析文件 + +```bash +[root@localhost ~]# echo "nameserver 114.114.114.114" >> /etc/resolv.conf +``` + +## 安装依赖包 + +```bash +[root@localhost ~]# yum install gcc gcc-c++ make libtool zlib zlib-devel pcre pcre-devel perl-devel perl-ExtUtils-Embed wget vim -y +``` + +## 镜像站RPM方式安装tengine + +> 说明: +> 镜像站中的RPM包都是通过开源代码编译打包而成,然后将其上传到镜像站。 + +### 获取Tengine 2.2.2的RPM包。 + +```bash +[root@localhost ~]# cd /home +[root@localhost home]# wget https://mirrors.huaweicloud.com/kunpeng/yum/el/7/aarch64/Packages/web/tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +``` + +### 兼容性评估 + +#### 下载x2openEuler工具 + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ +``` + +#### 部署工具 + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 扫描软件 + +``` +x2openEuler scan tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` + +## 查看评估结果 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + + + +结果:通过报告可知外部接口兼容性100%,依赖包兼容性人工复核后通过,经评估tengine2.2.2软件包在openEuler 20.03 LTS SP1系统上兼容,可安装此软件包至openEuler 20.03 LTS SP1系统进行验证。 + +### 安装Tengine + +```bash +[root@localhost home]# rpm -ivh tengine-2.2.2-1.el7_4.ngx.aarch64.rpm +Verifying... ################################# [100%] +Preparing... ################################# [100%] +Updating / installing... + 1:tengine-1:2.2.2-1.el7_4.ngx ################################# [100%] +``` + + +### 查看安装目录。 + +```bash +[root@localhost home]# cd /usr/local/tengine-nginx/ +[root@localhost tengine-nginx]# ls +conf html include logs modules sbin +``` + + +# 运行和验证 + +## 配置HTTPS功能 + +### 生成证书 + +```bash +[root@localhost tengine-nginx]# openssl genrsa -des3 -out server_2048.key 2048 +Generating RSA private key, 2048 bit long modulus (2 primes) +...................................+++++ +..................+++++ +e is 65537 (0x010001) +Enter pass phrase for server_2048.key: +Verifying - Enter pass phrase for server_2048.key: +[root@localhost tengine-nginx]# openssl rsa -in server_2048.key -out server_2048.key +Enter pass phrase for server_2048.key: +writing RSA key +[root@localhost tengine-nginx]# openssl req -new -key server_2048.key -out server_2048.csr +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []: +Organization Name (eg, company) [Internet Widgits Pty Ltd]: +Organizational Unit Name (eg, section) []: +Common Name (e.g. server FQDN or YOUR name) []: +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +[root@localhost tengine-nginx]# openssl rsa -in server_2048.key -out server_2048.key +writing RSA key +[root@localhost tengine-nginx]# openssl x509 -req -days 365 -in server_2048.csr -signkey server_2048.key -out server_2048.crt +Signature ok +subject=C = CN, ST = Some-State, O = Internet Widgits Pty Ltd +Getting Private key +[root@localhost tengine-nginx]# ls +conf html include logs modules sbin server_2048.crt server_2048.csr server_2048.key +``` + +## 配置Tengine + +```bash +vim /usr/local/tengine-nginx/conf/nginx.conf +``` + +修改如下内容 + +``` + # HTTPS server + # + #server { + # listen 443 ssl; + # server_name localhost; + + # <== 修改这里: 证书位置 ==> + # ssl_certificate /usr/local/tengine-nginx/server_2048.crt; + # ssl_certificate_key /usr/local/tengine-nginx/server_2048.key; + + # ssl_session_cache shared:SSL:1m; + # ssl_session_timeout 5m; +``` + + +## 运行Tengine + +```bash +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# ps -ef | grep nginx +root 5710 1 0 17:25 ? 00:00:00 nginx: master process /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nobody 5711 5710 0 17:25 ? 00:00:00 nginx: worker process +root 5713 1407 0 17:25 pts/0 00:00:00 grep --color=auto nginx +``` + +提示: + +- 报`http upstream check_shm_size is too small`错误 + +```bash +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nginx: [crit] ngx_slab_alloc() failed: no memory +nginx: [emerg] http upstream check_shm_size is too small, you should specify a larger size. +[root@localhost tengine-nginx]# +[root@localhost tengine-nginx]# sed -i "/http {/a\check_shm_size 50m;" /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +[root@localhost tengine-nginx]# ps -ef | grep nginx +root 5710 1 0 17:25 ? 00:00:00 nginx: master process /usr/local/tengine-nginx/sbin/nginx -c /usr/local/tengine-nginx/conf/nginx.conf +nobody 5711 5710 0 17:25 ? 00:00:00 nginx: worker process +root 5713 1407 0 17:25 pts/0 00:00:00 grep --color=auto nginx +``` \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/Varnish 6-2-0-porting-guide.md b/web-ui/docs/zh/blog/randy1568/Varnish 6-2-0-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..07f37f505eab21bdc419d5588b15b6547a82c262 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/Varnish 6-2-0-porting-guide.md @@ -0,0 +1,232 @@ +--- +title: Varnish 6.2.0 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - Varnish + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the Varnish 6.2.0 +--- + +# Varnish 6.2.0 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 +Varnish是一款高性能且开源的反向代理服务器和HTTP加速器,与传统的缓存服务器相比,Varnish具有性能更高、速度更快、管理更加方便等诸多优点,很多大型的网站都开始尝试使用Varnish来替换Squid,这些都促进Varnish迅速发展起来。 + +开发语言:C++ + +一句话描述:反向代理服务器和HTTP加速器 + +## 建议的版本 +建议使用版本为“Varnish 6.2.0”。 + +# 环境要求 +## 硬件要求 +硬件要求如表1所示。 +表1 硬件要求 + +|项目| 说明 | +|------|----------------------------| +|服务器| TaiShan 200服务器(型号2280)| +|CPU| 鲲鹏920 5250处理器| +|磁盘分区|对磁盘分区无要求| + +## 操作系统要求 +操作系统要求如表2所示。 +表2 操作系统要求 + +|项目| 版本| 版本查看命令| +|----------|--------|-------| +|openEuler| 20.03 LTS SP1| ```cat /etc/openEuler-release```| +|Kernel| 4.19.90| uname -r| + +# 配置编译环境 +## 配置Yum源 + 说明: + 如果组网环境处于外网受限情况下,服务器yum命令无法通过外界获取依赖包时,可参考本节内容进行本地源配置。 +1. 将操作系统镜像文件openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso文件拷贝到每台服务器的“/root”目录下。 +2. 镜像文件挂载。 + a. 将“/root”目录下的openEuler操作系统对应iso文件挂载到“/mnt”目录下。 + ```mount /root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt``` + 说明: + 该操作单次生效,重启后失效。若需要配置开机启动自动挂载镜像(可选),可参考下面步骤。 + 1. 打开fstab文件。 + ```vi /etc/fstab``` + 2. 编辑fstab文件,在文件末尾添加如下信息: + ```/root/openEuler-20.03-LTS-SP1-everything-aarch64-dvd.iso /mnt iso9660 loop 0 0``` + 3. 保存并退出fstab文件。 +3. 添加本地源文件。 + a. 进入“/etc/yum.repos.d”目录。 + ```cd /etc/yum.repos.d``` + 说明: + 此时,建议将此目录下的*.repo文件移到任意其他备份目录下。 + b. 创建local.repo文件。 + 1. 打开local.repo文件。 + ```vi local.repo``` + 2. 编辑local.repo文件,在local.repo文件中添加如下内容: + ``` + [local] + name=local.repo + baseurl=file:///mnt + enabled=1 + gpgcheck=0 + ``` + 说明: + 其中,baseurl中file路径为镜像挂载路径,与镜像文件挂载中的目录“/mnt” 对应。 + 3. 保存并退出local.repo文件。 +4. 生效本地源。 +``` +yum clean all +yum makecache +yum list +``` + +## 安装依赖包 +下载并安装依赖包 +1. 安装所需依赖。 +``` +yum install -y autoconf automake jemalloc-devel libedit-devel libtool ncurses-devel pcre-devel pkgconfig python-docutils python-sphinx graphviz httpd +``` +2. 查看Python3版本 + ``` + [root@localhost]# python3 --version + Python 3.7.9 + ``` + +# 安装 +## 安装方式介绍 +本文将介绍源码编译安装方式 + +## 源码编译安装 +### 获取源码 +1. 在本地浏览器下载Varnish源码。 +下载地址:https://varnish-cache.org/_downloads/varnish-6.2.0.tgz +2. 将源码复制至服务器“/home”目录。 +说明: +若服务器可以访问网络,则可以直接在服务器上使用wget命令下载源码。 + +### 编译和安装 +1. 进入“home”目录。 +```cd /home/``` +2. 解压源码包。 +```tar -zxvf varnish-6.2.0.tgz``` +3. 进入“varnish-6.2.0”目录。 +```cd /home/varnish-6.2.0/``` +4. 执行自动编译。 +```sh autogen.sh``` +5. 检查依赖。 +```./configure --prefix=/usr/local/varnish``` +``` +[root@localhost varnish-6.2.0]# ./configure --prefix=/usr/local/varnish +checking for gcc... gcc +checking whether the C compiler works... yes +checking for C compiler default output file name... a.out +checking for suffix of executables... +checking whether we are cross compiling... no +checking for suffix of files... o +checking whether we are using the GNU C compiler... yes +checking whether gcc accepts -g... yes +``` +说明: +--prefix=PATH:指定Varnish的安装目录。 + +6. 编译安装Varnish。 +```make && make install``` +``` +[root@localhost varnish-6.2.0]# make && make install +make all-recursive +make[1]: Entering directory '/home/varnish-6.2.0' +Making all in include +make[2]: Entering directory '/home/varnish-6.2.0/include' +make all-am +make[3]: Entering directory '/home/varnish-6.2.0/include' +``` + +### 配置文件 +1. 在Varnish安装路径中创建配置文件所需的文件夹。 +```cd /usr/local/varnish && mkdir config``` +2. 复制配置文件到“config”中。 +```cp /usr/local/varnish/share/doc/varnish/example.vcl /usr/local/varnish/config/default.vcl``` + +# 运行与验证 +以本机作为Varnish后端对象为例,运行和验证Varnish。 +1. 修改后端地址端口用于反向代理测试。 +若需配置缓存策略,请从官网获取最新的Varnish Book)。此处配置本机作为后端对象,端口默认80。 + + a. 打开配置文件。 + ```vi /usr/local/varnish/config/default.vcl``` + + b. 配置如下内容后,保存并退出。 + ``` + vcl 4.0; + # Default backend definition. Set this to point to your content server. + backend default { + .host = "127.0.0.1"; + .port = "80"; + } + + sub vcl_recv { + } + sub vcl_backend_response { + } + sub vcl_deliver { + } + ``` + +2. 启动后端对象的HTTP服务。 +```systemctl start httpd``` +3. 启动Varnish。 +```/usr/local/varnish/sbin/varnishd -a :12345 -T 127.0.0.1:6082 -s malloc,10GB -f /usr/local/varnish/config/default.vcl``` +``` +[root@localhost ~]# /usr/local/varnish/sbin/varnishd -a :12345 -T 127.0.0.1:6082 -s malloc,10GB -f /usr/local/varnish/config/default.vcl +Debug: Version: varnish-6.2.0 revision b14a3d38dbe918ad50d3838b11aa596f42179b54 +Debug: Platform: Linux,4.19.90-2012.4.0.0053.oe1.aarch64,aarch64,-jnone,-smalloc,-sdefault,-hcritbit +Debug: Child (30634) Started +``` +Varnish启动参数说明见表 Varnish启动参数说明。 +参数 : 说明 + + -a address:port : 表示Varnish对HTTP的监测地址及其端口, 此处IP默认为本机。 + + -T address:port : 设定Varnish的Telnet管理地址及其端口。 + + -s : 指定Varnish缓存存放的方式,此处采用malloc的形式,总共分配10GB内存空间。 + + -f : 指定Varnish的配置文件位置。 + +4. 访问本机即可看到后端服务的测试页面。 + ```curl http://localhost:80``` + ``` + ... +
+ This page is used to test the proper operation of the Apache HTTP server after it has been installed. If you can read this page, it means that the Apache HTTP server installed at this site is working properly. +
+
+ +
+
+

If you are a member of the general public:

+ + The fact that you are seeing this page indicates that the website you just visited is either experiencing problems, or is undergoing routine maintenance. + + If you would like to let the administrators of this website know that you've seen this page instead of the page you expected, you should send them e-mail. In general, mail sent to the name "webmaster" and directed to the website's domain should reach the appropriate person. + + For example, if you experienced problems while visiting www.example.com, you should send e-mail to "webmaster@example.com". + + For information on openEuler Linux, please visit the openEuler, Inc. website. The ation for openEuler Linux is available on the openEuler, Inc. website. + + ... + ``` + 说明: + - 若需要停止Varnish,则使用如下命令,业务运行中不需要执行该命令。 + ```pkill varnish``` + - 卸载Varnish,并查询。 + 卸载源码方式安装的Varnish。 + ```rm -rf /usr/local/varnish/``` + + + diff --git a/web-ui/docs/zh/blog/randy1568/X86 hardware compatibility assessment migration guide.md b/web-ui/docs/zh/blog/randy1568/X86 hardware compatibility assessment migration guide.md new file mode 100644 index 0000000000000000000000000000000000000000..79154a34bf9f2ffc0a6654fe52c98c64a53f6df5 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/X86 hardware compatibility assessment migration guide.md @@ -0,0 +1,117 @@ +--- +title: X86硬件兼容性移迁指南(openEuler 20.03 LTS SP1) +date: 2022-01-07 +tags: + - X86 hardware compatibility evaluation + - CX5&3108raid + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2022-01 +author: randy1568 +summary: Just about everything you'll need to evaluate the compatibility of X86 hardware(Hi1822&3408raid) +--- + +# X86硬件兼容性移迁指南(openEuler 20.03 LTS SP1) + +[TOC] + +# 案例环境 + +## 硬件 + +硬件如下表所示 + +项目 | 说明 +----- | ----- +服务器 | 2288H V5 +CPU | Inter(R) Xeon(R) Gold 6266C CPU @ 3.00GHz +NIC卡 | CX5(CX5网卡是mellanox公司生产的一款网卡) +RIAD卡 | LTS SAS 3108(3108raid卡是华为生产的一款raid卡) + +## 操作系统 + +操作系统如下所示 + +项目 | 说明 | +----- | ----- | +Centos Linux | 7.9.2009(Core) +Kernel | 3.10.0 x86_64 + +检查当前系统版本信息 +cat /etc/os-release + + + +# x2openEuler软件运行和硬件兼容性评估 + +openEuler社区提供了 [x2openEuler 工具](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP1/stable/contrib/x2openEuler/noarch/Packages/) ,具有硬件评估、软件评估、系统配置评估的功能,其中硬件评估针对centos系统上正常运行的板卡在openEuler上兼容性,工具采集板卡信息生成html报告,直观快捷展示硬件的兼容性。 + +## 下载x2openEuler工具 + +``` +工具指引:https://www.openeuler.org/zh/other/migration/ +``` + +## 部署工具 + +``` +cd /opt/ +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +## 硬件兼容性分析 + + x2openEuler hardware-analyse + 返回信息如下: + 2021-11-30 09:41:20,865 - INFO - Log save directory: /var/log/x2openEuler + 2021-11-30 09:41:20,887 - INFO - x2openEuler hardware-analyse + 2021-11-30 09:41:20,888 INFO manager/get_param_config/179: Parameter configuration file loaded. + 2021-11-30 09:41:20,905 INFO manager/get_regex_config/218: Regex pattern compiled. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/233: All builtin parsers loaded. + 2021-11-30 09:41:20,905 INFO manager/load_parsers/236: All custom parsers loaded. + 2021-11-30 09:41:21,254 INFO time_utils/wrapper/21: 0.35s taken for running function [get_data] + 2021-11-30 09:41:21,269 WARNING list/parse_content/47: no data in ls_dev + 2021-11-30 09:41:21,377 INFO time_utils/wrapper/21: 0.12s taken for running function [get_parsed_content] + 2021-11-30 09:41:21,377 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_startup_param.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/syscall_interface.json. + 2021-11-30 09:41:21,378 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/path.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/port.json. + 2021-11-30 09:41:21,379 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/device_interface.json. + 2021-11-30 09:41:21,380 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/linux_command.json. + 2021-11-30 09:41:21,387 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/hardware_configure.json. + 2021-11-30 09:41:21,396 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/proc.json. + 2021-11-30 09:41:21,404 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_configure.json. + 2021-11-30 09:41:21,408 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/system_service.json. + 2021-11-30 09:41:21,412 INFO manager/write_res/135: write to /opt/x2openEuler/_tmp_18ambppj_/run/9e81f536-517e-11ec-ae65-a01c8dfeddfa/sysconf/kernel_configure.json. + 2021-11-30 09:41:21,426 - INFO - Producing report... + 2021-11-30 09:41:21,427 - INFO - Generate Success! The results are saved: /opt/x2openEuler/output/hw_compat_report-20211130094121.html + 返回信息中,“/opt/x2openEuler/output/hw_compat_report-20211130094121.html“为评估报告文件。 + +# 硬件评估结果分析 + +硬件兼容性评估报告可直接展示每项板卡是否兼容以及整机是否兼容,有任意一项不在兼容清单里的则需要适配。 + + + + +通过VID、DID、SVID、SSID四元组值可确定唯一一种板卡。从上面的截图可以看到,每一项板卡都可以在南向兼容性清单查询到,因此该硬件服务器从centos迁移到openEuler 20.03 LTS SP1可以实施。 diff --git a/web-ui/docs/zh/blog/randy1568/enca1-19-porting-guide.md b/web-ui/docs/zh/blog/randy1568/enca1-19-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..0c25eaf1cda78a5eceda1b95b120a16d9a823600 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/enca1-19-porting-guide.md @@ -0,0 +1,130 @@ +--- +title: enca 1.19 移植指南 (openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - enca + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the enca 1.19 +--- + +# enca 1.19 移植指南 (openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 + +enca是一个实用的编码转换工具。本案例使用x86_64架构虚拟机,通过评估工具x2openEuler评估enca1.19软件移植到openEuler操作系统的兼容性,并根据评估结果完成软件移植。 + +开发语言:C + +## 建议的版本 + +建议使用版本为enca 1.19.1。 + +> 说明: +> 本文档适用于enca 1.19.1,其他版本的enca移植步骤也可参考本文档。 + +# 环境要求 + +## 操作系统要求 +| 操作系统 | 版本 | +|---|---| +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +## 安装操作系统 + + 如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 +安装openEuler操作系统请参考:https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html。 + +# 兼容性评估 + +评估工具:x2openEuler +评估环境:CentOS7.6 + +#### 下载x2openEuler工具 + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ +``` + +#### 部署工具 + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 扫描软件 + +``` +wget http://rpmfind.net/linux/epel/7/x86_64/Packages/e/enca-1.19-1.el7.x86_64.rpm +x2openEuler scan enca-1.19-1.el7.x86_64.rpm +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` + +## 查看评估结果 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + + + +结果:通过报告可知外部接口兼容性100%,依赖包兼容性人工复核后通过,经评估enca1.19软件包在openEuler 20.03 LTS SP1系统上兼容,可安装此软件包至openEuler 20.03 LTS SP1系统进行验证。 + +# RPM方式安装enca + +1. 下载rpm包:http://rpmfind.net/linux/epel/7/x86_64/Packages/e/enca-1.19-1.el7.x86_64.rpm。 +2. 上传至openEuler服务器。 + > 说明: + > 若服务器可以访问网络,则可以直接在服务器上使用wget命令下载源码包。 + +3. 执行如下命令,安装enca。 +```shell + rpm -ivh enca-1.19-1.el7.x86_64.rpm +``` + +# 运行和验证 + +1. 执行如下命令,验证enca是否安装成功。 +```shell + enca --version +``` +2. 回显信息如下,则表示安装成功。 +```shell + enca 1.19 + + Features: -librecode-interface +iconv-interface +external-converter +language-detection +locale-alias+ + target-charset-auto +ENCAOPT + + Copyright (C) 2000-2005 David Necas (Yeti) (<yeti@physics.muni.cz>), + 2005 Zuxy Meng (<zuxy.meng@gmail.com>). + + Enca is free software; it can be copied and/or modified under the terms of + version 2 of GNU General Public License, run `enca --license' to see the full + license text. There is NO WARRANTY; not even for MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. +``` + diff --git a/web-ui/docs/zh/blog/randy1568/flask 1-1-2-porting-guide.md b/web-ui/docs/zh/blog/randy1568/flask 1-1-2-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..5ce334397169982381efaae9fc15da7789e28b04 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/flask 1-1-2-porting-guide.md @@ -0,0 +1,191 @@ +--- +title: flask 1.1.2 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - flask + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything of the flask 1.1.2 Porting Case +--- + +# flask 1.1.2 移植指南(openEuler 20.03 LTS SP1) + + + +## 介绍 + +### 简要介绍 + +Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。 +本案例使用x86_64架构虚拟机,通过评估工具x2openEuler评估flask 1.1.2软件移植到openEuler操作系统的兼容性,并根据评估结果完成软件移植。 + +开发语言:Python + +开源协议:BSD + +### 建议的版本 + +建议使用版本为flask 1.1.2。 + +> 说明: +> 本文档适用于flask 1.1.2,其他版本的flask移植步骤也可参考本文档。 + +## 环境要求 + +### 操作系统要求 + +| 操作系统 | 版本 | +| :-------- | :------------ | +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +### 安装操作系统 + +如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 +安装openEuler操作系统请参考:[https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html。](https://bbs.huaweicloud.com/forum/thread-116157-1-1.html#) + +## 兼容性评估 + +### 获取flask的RPM包 + +``` +wget https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-flask-1.1.2-4.el7.noarch.rpm +``` + +#### 下载x2openEuler工具 + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ +``` + +#### 部署工具 + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 扫描软件 + +``` +x2openEuler scan python36-flask-1.1.2-4.el7.noarch.rpm +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` + +## 查看评估结果 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + + + +结果:通过报告可知外部接口兼容性100%,依赖包兼容性人工复核后确认缺失,由于该软件包属于python包,建议使用pip3方式安装依赖及python-flask对应版本。 + +## 安装flask + +### rpm安装 + +由于兼容性报告显示依赖包缺失,尝试直接用下载的rpm包安装做个验证。 + +``` +[root@localhost test]# yum install -y python36-flask-1.1.2-4.el7.noarch.rpm +Last metadata expiration check: 1:39:08 ago on Mon 22 Mar 2021 10:35:29 AM CST. +Error: + Problem: conflicting requests + - nothing provides python36-setuptools needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python(abi) = 3.6 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-click >= 5.1 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-itsdangerous >= 0.24 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-jinja2 >= 2.10.1 needed by python36-flask-1.1.2-4.el7.noarch + - nothing provides python36-werkzeug >= 0.15 needed by python36-flask-1.1.2-4.el7.noarch +(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages) +``` + +由于依赖原因未能安装。 + +### pip方式安装 + +使用pip安装同版本的flask,由于flask依赖python3,使用pip3。 + +``` +[root@localhost ~]# pip3 install flask +WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead. +Collecting flask + Using cached Flask-1.1.2-py2.py3-none-any.whl (94 kB) +Requirement already satisfied: itsdangerous>=0.24 in /usr/lib/python3.7/site-packages (from flask) (1.1.0) +Requirement already satisfied: Werkzeug>=0.15 in /usr/local/lib/python3.7/site-packages (from flask) (1.0.1) +Requirement already satisfied: click>=5.1 in /usr/local/lib/python3.7/site-packages (from flask) (7.1.2) +Requirement already satisfied: Jinja2>=2.10.1 in /usr/lib/python3.7/site-packages (from flask) (2.11.2) +Requirement already satisfied: MarkupSafe>=0.23 in /usr/lib64/python3.7/site-packages (from Jinja2>=2.10.1->flask) (1.1.1) +Installing collected packages: flask +Successfully installed flask-1.1.2 +``` + +## 运行和验证 + +### 检查版本 + +``` +[root@localhost ~]# python3 +Python 3.7.9 (default, Dec 16 2020, 03:16:57) +[GCC 7.3.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> import flask +>>> flask.__version__ +'1.1.2' +``` + +### 使用flask + +使用flask官网 ([https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application](https://bbs.huaweicloud.com/forum/thread-115817-1-1.html#)) 提供的入门程序 + +``` +vim hello.py +``` + +编辑内容如下: + +``` +from flask import Flask +app = Flask(__name__) + +@app.route('/') +def hello_world(): + return 'Hello, World!' +``` + +编辑后保存退出,在终端输入如下命令: + +``` +[root@localhost ~]# export FLASK_APP=hello.py +[root@localhost ~]# python3 -m flask run + * Serving Flask app "hello.py" + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: off + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + +可见运行成功。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-1.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-1.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-10.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-10.png new file mode 100644 index 0000000000000000000000000000000000000000..36a9f77639b1141cb7e1fdb460b6261caa751e08 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-10.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-11.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-11.png new file mode 100644 index 0000000000000000000000000000000000000000..70466f513236b842a5528197751f0e286ea75cfa Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-11.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-12.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-12.png new file mode 100644 index 0000000000000000000000000000000000000000..360d9169962901c7b28a7a3c883e027e0a2c173f Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-12.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-13.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-13.png new file mode 100644 index 0000000000000000000000000000000000000000..02873d6b02031ccfe7762298e1ad5b8b7a81a16e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-13.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-2.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ea89b334d288854dfc4403570f7892dd7749f1a3 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-2.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-3.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9518a15004dec9da4856bcc6c6e2bb22942941e1 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-3.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-4.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-4.png new file mode 100644 index 0000000000000000000000000000000000000000..429f02e0e97e1c7d556fd80f11b4a9cf1a5a5c3e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-4.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-5.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-5.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fe8ad56cb34ab2788458dd77e555af08ef315e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-5.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-6.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-6.png new file mode 100644 index 0000000000000000000000000000000000000000..9b1b2903df4caec60872d48556e4914446cd4a50 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-6.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-7.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-7.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3dead21a92ced874dadbcd904e387a30882b86 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-7.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-8.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-8.png new file mode 100644 index 0000000000000000000000000000000000000000..f43d97c66f49b4dfd37c12dc13a19d9efd7151d0 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-8.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Dubbo-9.png b/web-ui/docs/zh/blog/randy1568/image/Dubbo-9.png new file mode 100644 index 0000000000000000000000000000000000000000..188b4cb375fc3cecef034a70c61613f7cc429b38 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Dubbo-9.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/HAProxy-1.jpeg b/web-ui/docs/zh/blog/randy1568/image/HAProxy-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/HAProxy-1.jpeg differ diff --git a/web-ui/docs/zh/blog/randy1568/image/HAProxy-2.png b/web-ui/docs/zh/blog/randy1568/image/HAProxy-2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd0dc9e9f6e82c49274a7cba090fe3bf11e0e5cd Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/HAProxy-2.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/HAProxy-3.png b/web-ui/docs/zh/blog/randy1568/image/HAProxy-3.png new file mode 100644 index 0000000000000000000000000000000000000000..41ec8fc71a9ee5c151bcdd08ecb5adf9256fb90d Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/HAProxy-3.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Memcached-1.jpeg b/web-ui/docs/zh/blog/randy1568/image/Memcached-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5a5e5e917faa3645f9ea6a4fae887bc056a94f44 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Memcached-1.jpeg differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Memcached-2.jpeg b/web-ui/docs/zh/blog/randy1568/image/Memcached-2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7ada68ee64f6cd59bbb77ca65990f0be66277060 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Memcached-2.jpeg differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-1.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9c228b2fec0e957f1f05a89b934be90c3d4990fa Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-10.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-10.png new file mode 100644 index 0000000000000000000000000000000000000000..9377e82ec38ca760333b203a04943c6a26e1038f Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-10.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-11.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-11.png new file mode 100644 index 0000000000000000000000000000000000000000..a6e500638fc1535b21d224ede49d163c0e9aeb27 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-11.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-12.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-12.png new file mode 100644 index 0000000000000000000000000000000000000000..6236cb96efb4470d83a778f95008303ee86b47e5 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-12.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-13.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-13.png new file mode 100644 index 0000000000000000000000000000000000000000..a815168b374b9c7ff53a36d2c5097883621609e6 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-13.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-14.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-14.png new file mode 100644 index 0000000000000000000000000000000000000000..747deb0f385f8e3cb97cfa3b891ea63eb6483f2e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-14.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-15.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-15.png new file mode 100644 index 0000000000000000000000000000000000000000..46028686a22fe9b59f5dd86d0ae5d4b44561083e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-15.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-16.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-16.png new file mode 100644 index 0000000000000000000000000000000000000000..d661d47c76ba0d0b8abc96a4d4a57a4348af440f Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-16.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-2.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba5a60a4a486102b467d2a9619b05c897af59d6 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-2.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-3.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-3.png new file mode 100644 index 0000000000000000000000000000000000000000..ae658e3f3fd6410e53222bf4f76f76f203ccc2ff Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-3.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-4.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-4.png new file mode 100644 index 0000000000000000000000000000000000000000..edce2dca3416f469abb66d4c41e0313e5842d89a Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-4.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-5.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-5.png new file mode 100644 index 0000000000000000000000000000000000000000..63366d404770cca4c52678c312d5b372b69cf421 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-5.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-6.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-6.png new file mode 100644 index 0000000000000000000000000000000000000000..217579de0dbf629e004cf6100cb5800875b89bb6 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-6.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-7.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-7.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec1a2f0c99146a139acac3e86e4570515c72aef Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-7.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-8.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-8.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ba68e8b9ec933e0f4b320355bd8526eb869d50 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-8.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/Mysql-9.png b/web-ui/docs/zh/blog/randy1568/image/Mysql-9.png new file mode 100644 index 0000000000000000000000000000000000000000..8185430fdc2c289ed608a8112f1ed1a497799615 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/Mysql-9.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/enca-1.png b/web-ui/docs/zh/blog/randy1568/image/enca-1.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb40ca4cfd36d7cbbbc44a8bd0acd7d857817b4 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/enca-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/flask.png b/web-ui/docs/zh/blog/randy1568/image/flask.png new file mode 100644 index 0000000000000000000000000000000000000000..8004338375496e5f7917674614e06656ce7f487e Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/flask.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/hardware-1.png b/web-ui/docs/zh/blog/randy1568/image/hardware-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d2119d020cf332d441b7d42a487116bcf51b1716 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/hardware-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/hardware-2.png b/web-ui/docs/zh/blog/randy1568/image/hardware-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f88a964c1e237f4130737ca06863d6b44f6fce Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/hardware-2.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/hardware-3.png b/web-ui/docs/zh/blog/randy1568/image/hardware-3.png new file mode 100644 index 0000000000000000000000000000000000000000..864094f4313c0345ab84d3740b3d9fd73a7ee06f Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/hardware-3.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/hardware-4.png b/web-ui/docs/zh/blog/randy1568/image/hardware-4.png new file mode 100644 index 0000000000000000000000000000000000000000..d2119d020cf332d441b7d42a487116bcf51b1716 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/hardware-4.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/hardware-5.png b/web-ui/docs/zh/blog/randy1568/image/hardware-5.png new file mode 100644 index 0000000000000000000000000000000000000000..6993e87130be90ec1acfd814c80248af254ef995 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/hardware-5.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/iok-1.png b/web-ui/docs/zh/blog/randy1568/image/iok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..e363ede291eda60a81a551ee5f2e4051ace74d0d Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/iok-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/lok-1.png b/web-ui/docs/zh/blog/randy1568/image/lok-1.png new file mode 100644 index 0000000000000000000000000000000000000000..19b4f36ba04958bf7bd113adeb02fac4b3e42976 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/lok-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/lok-2.png b/web-ui/docs/zh/blog/randy1568/image/lok-2.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae07942545bf232fe50e5fa663a671cc32292ca Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/lok-2.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/tengine-1.png b/web-ui/docs/zh/blog/randy1568/image/tengine-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2cb844125a867acfd6517c8906a60b1e27a38d3c Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/tengine-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/image/tornado-1.png b/web-ui/docs/zh/blog/randy1568/image/tornado-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c5d729335775795228f37a37f82510ffa1b58f98 Binary files /dev/null and b/web-ui/docs/zh/blog/randy1568/image/tornado-1.png differ diff --git a/web-ui/docs/zh/blog/randy1568/pkgship 2-1-0-porting-guide.md b/web-ui/docs/zh/blog/randy1568/pkgship 2-1-0-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..2785cb6385519bdaa991aa1804c375adecfaa0fe --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/pkgship 2-1-0-porting-guide.md @@ -0,0 +1,203 @@ +--- +title: pkgship 2.1.0 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - pkgship + - Porting Guide +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything you'll need to migrate the pkgship 2.1.0 +--- + +# pkgship 2.1.0 移植指南 (openEuler 20.03 LTS SP1) + +## 简介 + +>pkgship是一款管理OS软件包依赖关系,提供依赖和被依赖关系完整图谱的查询工具,pkgship提供软件包依赖查询、生命周期管理、补丁查询等功能。 + +### 选用版本 + +> 2.1.0 + +## 检查当前系统版本信息 + +```shell +cat /etc/os-release +``` +## 兼容性检查 + +> 使用x2openEuler对工具目录中的pkgship-2.1.0 RPM包进行分析 + +```shell +x2openEuler scan pkgship-2.1.0-7.oe1.noarch.rpm +``` + +> 根据依赖报告可知,移植到openEuler 20.03-LTS-sp1需要解决不同python版本的依赖相关问题 + +# 源码包安装 + +## 安装流程 + +- 安装依赖包 +- 配置yum源 +- 获取pkgship的源码包pkgship-2.1.0.tar.gz +- 解压源码包 +- 修改部分源码内容以便和python3.7兼容 +- 使用安装脚本setup.py安装pkgship +- 成功安装 + +## 安装pkgship + +- 安装依赖包 + +```shell +[root@master ~]# yum install -y libffi-devel + + +[root@master ~]# vim requirements.txt + +prettytable==0.7.2 +Flask_RESTful==0.3.8 +Flask_Session==0.3.1 +Flask_Script==2.0.6 +Flask_Limiter==1.4 +Flask==1.1.2 +marshmallow==3.5.1 +PyYAML==5.3.1 +gevent==20.12.1 +requests==2.21.0 +uwsgi==2.0.18 +elasticsearch==7.10.1 +redis==3.5.3 +retrying==1.3.3 + +[root@master ~]# pip3 install -r requirements.txt +``` + + +- 配置yum源 + +```shell +[root@master ~]# cd /etc/yum.repos.d/ +[root@master yum.repos.d]# vim openEuler.repo +[openeuler] +name=openEuler-21.03 +baseurl=http://119.3.219.20:82/openEuler:/21.03/standard_aarch64/ +enabled=1 +gpgcheck=0 + + +[fedora] +name=fedora +baseurl=https://mirrors.huaweicloud.com/fedora/releases/30/Everything/aarch64/os/ +enabled=0 +gpgcheck=0 + +[elasticsearch] +name=Elasticsearch repository for 7.x packages +baseurl=https://artifacts.elastic.co/packages/7.x/yum +gpgcheck=1 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md + +``` + +- 获取源码包 + +> 从 https://gitee.com/src-openeuler/pkgship?_from=gitee_search 获取pkgship-2.1.0.tar.gz源码包。 + +- 解压源码包 + +```shell +tar -xzvf pkgship-2.1.0.tar.gz +``` + +- 修改部分源码文件 + +> 进入解压后的源码目录,修改源码路径下 +```shell +./packageship/application/query/pkg.py +./packageship/application/query/depend.py +``` + +> 这两个文件中第19行的monkey.patch_all()为monkey.patch_all(thread=False, ssl=False) + +> 进入源码目录的packageship目录下创建一个version.yaml文件,文件内容为 + +```shell +Version: 2.1.0 +Release: 7.oe1 +``` +> 避免安装时因为缺少文件报如下错误 + +```shell +installing package data to build/bdist.linux-x86_64/egg +running install_data +creating /etc/pkgship +copying packageship/package.ini -> /etc/pkgship/ +copying conf.yaml -> /etc/pkgship/ +copying packageship/auto_install_pkgship_requires.sh -> /etc/pkgship/ +copying packageship/uwsgi_logrotate.sh -> /etc/pkgship/ +copying packageship/pkgshipd -> /usr/bin +copying packageship/pkgship -> /usr/bin +copying packageship/pkgship.service -> /lib/systemd/system/ +copying packageship/application/common/rsp/mapping.xml -> build/bdist.linux-x86_64/egg/packageship/application/common/rsp +error: can't copy 'packageship/version.yaml': doesn't exist or not a regular file +``` + + +- 安装pkgship + +> 进入pkgship主目录,开始使用setup.py脚本安装pkgship + +```shell +[root@localhost ~]# python3 --version +Python 3.7.9 +[root@localhost ~]# python3 setup.py install +``` + + +- 成功安装 + +```shell +Processing packageship-2.1.0-py3.7.egg +creating /usr/local/lib/python3.7/site-packages/packageship-2.1.0-py3.7.egg +Extracting packageship-2.1.0-py3.7.egg to /usr/local/lib/python3.7/site-packages +Adding packageship 2.1.0 to easy-install.pth file + +Installed /usr/local/lib/python3.7/site-packages/packageship-2.1.0-py3.7.egg +Processing dependencies for packageship==2.1.0 +Finished processing dependencies for packageship==2.1.0 + +[root@localhost pkgship-2.1.0]# pip3 list | grep packageship +packageship 2.1.0 +[root@localhost pkgship-2.1.0]# pkgship +usage: pkgship [-h] [-v] [-remote] + {init,list,builddep,installdep,selfdepend,bedepend,pkginfo,dbs} + ... + +package related dependency management + +positional arguments: + {init,list,builddep,installdep,selfdepend,bedepend,pkginfo,dbs} + package related dependency management + init initialization of the database + list get all package data + builddep query the compilation dependencies of the specified + package + installdep query the installation dependencies of the specified + package + selfdepend query the self-compiled dependencies of the specified + package + bedepend dependency query for the specified package + pkginfo query the information of a single package + dbs Get all data bases + +optional arguments: + -h, --help show this help message and exit + -v Get version information + -remote The address of the remote service +``` diff --git a/web-ui/docs/zh/blog/randy1568/tornado 4-2-1-porting-guide.md b/web-ui/docs/zh/blog/randy1568/tornado 4-2-1-porting-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..84d6ee682e81a51990eaedf442984f42983d3929 --- /dev/null +++ b/web-ui/docs/zh/blog/randy1568/tornado 4-2-1-porting-guide.md @@ -0,0 +1,235 @@ +--- +title: tornado 4.2.1 移植指南(openEuler 20.03 LTS SP1) +date: 2021-12-29 +tags: + - tornado + - Porting Case +sig: sig-Compatibility-Infra +archives: 2021-12 +author: randy1568 +summary: Just about everything of the tornado 4.2.1 porting case +--- + +# tornado 4.2.1 移植指南(openEuler 20.03 LTS SP1) + +# 介绍 + +## 简要介绍 + +Tornado是一个Python Web框架和异步网络库,最初由FriendFeed开发。 通过使用非阻塞网络I / O,Tornado可以扩展到成千上万的开放连接,非常适合长时间轮询,WebSocket和需要与每个用户建立长期连接的其他应用程序。 +本案例使用x86_64架构虚拟机,通过评估工具x2openEuler评估tornado 4.2.1软件移植到openEuler操作系统的兼容性,并根据评估结果完成软件移植。 + +语言:C++/Python + +一句话描述:一个Python Web框架和异步网络库 + +开源协议:Apache + +## 建议的版本 + +建议使用版本为tornado 4.2.1。 + +> 说明: +> 本文档适用于tornado 4.2.1,其他版本的tornado移植步骤也可参考本文档。 + +# 环境要求 + +## 操作系统要求 + +| 操作系统 | 版本 | +| :-------- | :------------ | +| openEuler | 20.03 LTS SP1 | +| CentOS | 7.6 | + +## 安装操作系统 + +如果是全新安装操作系统,安装方式建议不要使用最小化安装,否则很多软件包需要手动安装,可选择“Server with GUI”安装方式。 +安装openEuler操作系统请参考:[https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html。](https://bbs.huaweicloud.com/forum/thread-116157-1-1.html#) + +# 兼容性评估 + +## 获取tornado的RPM包 + +``` +wget http://mirror.centos.org/centos/7/os/x86_64/Packages/python-tornado-4.2.1-5.el7.x86_64.rpm +``` + +#### 下载x2openEuler工具 + +``` +下载指引:https://www.openeuler.org/zh/other/migration/ +``` + +#### 部署工具 + +``` +rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm +``` + +> 注意:安装rpm时需要使用root用户,且目前需要网络(用于下载安装依赖) +> 注意:根据提示安装依赖包如bzip2-devel等 + +``` +su x2openEuler +x2openEuler redis-db -init +``` + +> 依次录入redis数据库的ip:127.0.0.1 +> 端口:6379 +> 数据库索引号(0-16):0 +> 密码(工具会对密码加密处理):如果redis密码没有设置或者为空时,直接回车即可 + +``` +x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz +``` + +> 备注:x2openEuler使用rpm安装完成后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包 +> 需要支持centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的静态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:`x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz`,请示情况选择对应的资源包 + +#### 扫描软件 + +``` +x2openEuler scan python-tornado-4.2.1-5.el7.x86_64.rpm +注意要分析的移植文件需要有能够让x2openEuler用户可以读取的权限 +扫描完成后会在/opt/x2openEuler/output目录生成html格式的报告 +``` + +## 查看评估结果 + +软件兼容性评估报告分三块内容展示软件兼容性,分别是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包安装过程中的直接依赖,非100%表明无法正确安装;接口兼容性反映的是单个软件运行过程中对其他软件包、动态库或系统接口的调用变化,非100%表明在某个功能调用时可能会触发异常,未调用到时可能表现正常;部分结果建议人工复核,最终软件包使用建优先级建议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 + + + +结果:通过报告可知外部接口兼容性100%,依赖包兼容性人工复核后通过,经评估tornado4.2.1软件包在openEuler 20.03 LTS SP1系统上兼容,可安装此软件包至openEuler 20.03 LTS SP1系统进行验证。 + +# 安装tornado + +## rpm安装 + +由于兼容性报告显示兼容,尝试直接用下载的rpm包安装。 + +``` +[root@localhost ~]# yum install python-tornado-4.2.1-5.el7.x86_64.rpm -y +Last metadata expiration check: 0:11:53 ago on Mon 22 Mar 2021 01:25:06 PM CST. +Dependencies resolved. +================================================================================ + Package Arch Version Repository Size +================================================================================ +Installing: + python-tornado x86_64 4.2.1-5.el7 @commandline 641 k +Installing dependencies: + python2-backports x86_64 1.0-17.oe1 everything 9.2 k + python2-backports-ssl_match_hostname noarch 3.7.0.1-2.oe1 everything 16 k + python2-ipaddress noarch 1.0.23-1.oe1 everything 41 k + python3-pycurl x86_64 7.43.0.3-1.oe1 OS 65 k + +Transaction Summary +================================================================================ +Install 5 Packages + +Total size: 772 k +Total download size: 131 k +Installed size: 4.1 M +Downloading Packages: +(1/4): python2-backports-1.0-17.oe1.x86_64.rpm 53 kB/s | 9.2 kB 00:00 +(2/4): python2-backports-ssl_match_hostname-3.7 63 kB/s | 16 kB 00:00 +(3/4): python2-ipaddress-1.0.23-1.oe1.noarch.rp 126 kB/s | 41 kB 00:00 +(4/4): python3-pycurl-7.43.0.3-1.oe1.x86_64.rpm 113 kB/s | 65 kB 00:00 +-------------------------------------------------------------------------------- +Total 226 kB/s | 131 kB 00:00 +warning: /var/cache/dnf/OS-fcb43ce6e8cef091/packages/python3-pycurl-7.43.0.3-1.oe1.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID b25e7f66: NOKEY +OS 14 kB/s | 2.1 kB 00:00 +Importing GPG key 0xB25E7F66: + Userid : "private OBS (key without passphrase) " + Fingerprint: 12EA 74AC 9DF4 8D46 C69C A0BE D557 065E B25E 7F66 + From : http://repo.openeuler.org/openEuler-20.03-LTS-SP1/OS/x86_64/RPM-GPG-KEY-openEuler +Key imported successfully +Running transaction check +Transaction check succeeded. +Running transaction test +Transaction test succeeded. +Running transaction + Preparing : 1/1 + Installing : python2-ipaddress-1.0.23-1.oe1.noarch 1/5 + Installing : python2-backports-1.0-17.oe1.x86_64 2/5 + Installing : python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.n 3/5 + Installing : python3-pycurl-7.43.0.3-1.oe1.x86_64 4/5 + Installing : python-tornado-4.2.1-5.el7.x86_64 5/5 + Running scriptlet: python-tornado-4.2.1-5.el7.x86_64 5/5 + Verifying : python3-pycurl-7.43.0.3-1.oe1.x86_64 1/5 + Verifying : python2-backports-1.0-17.oe1.x86_64 2/5 + Verifying : python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.n 3/5 + Verifying : python2-ipaddress-1.0.23-1.oe1.noarch 4/5 + Verifying : python-tornado-4.2.1-5.el7.x86_64 5/5 +Installed: + python-tornado-4.2.1-5.el7.x86_64 + python2-backports-1.0-17.oe1.x86_64 + python2-backports-ssl_match_hostname-3.7.0.1-2.oe1.noarch + python2-ipaddress-1.0.23-1.oe1.noarch + python3-pycurl-7.43.0.3-1.oe1.x86_64 + +Complete! +``` + +安装成功。 + +# 运行和验证 + +## 检查版本 + +``` +[root@localhost ~]# python +Python 2.7.18 (default, Dec 8 2020, 03:37:36) +[GCC 7.3.0] on linux2 +Type "help", "copyright", "credits" or "license" for more information. +>>> import tornado +>>> tornado.version +'4.2.1' +``` + +## 使用tornado + +编写一个handlers来响应一个标准的http请求。(代码来自tornado官网[https://www.tornadoweb.org/en/stable/](https://bbs.huaweicloud.com/forum/thread-115816-1-1.html#)) + +``` +vim hello.py +``` + +编辑内容如下: + +``` +import tornado.ioloop +import tornado.web + +class MainHandler(tornado.web.RequestHandler): + def get(self): + self.write("Hello, world") + +def make_app(): + return tornado.web.Application([ + (r"/", MainHandler), + ]) + +if __name__ == "__main__": + app = make_app() + app.listen(8888) + tornado.ioloop.IOLoop.current().start() +``` + +编辑后保存退出,在终端输入如下命令: + +``` +python hello.py +``` + +打开另外一个终端,输入如下命令。 + +``` +curl http://localhost:8888 +``` + +系统回显如下,则表示安装成功。 + +``` +Hello, world +``` \ No newline at end of file diff --git "a/web-ui/docs/zh/blog/rosinL/2021-12-25-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-11-29~2021-12-12).md" "b/web-ui/docs/zh/blog/rosinL/2021-12-25-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-11-29~2021-12-12).md" new file mode 100644 index 0000000000000000000000000000000000000000..a56c2dce2603a8649b42ded994ae422f026cf1e3 --- /dev/null +++ "b/web-ui/docs/zh/blog/rosinL/2021-12-25-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-11-29~2021-12-12).md" @@ -0,0 +1,60 @@ +--- +title: Ceph社区动态(2021-11-29~2021-12-12) +date: 2021-12-25 +tags: + - Ceph + - 动态 + - Pacific +sig: ceph-sig +archives: 2021-12 +author: rosinL +summary: Ceph社区动态 +--- +# Ceph社区动态(2021-11-29~2021-12-12) +## Pacific v16.2.7版本发布 +2021.12.7,Ceph社区发布了Pacific v16.2.7版本,Pacific版本系列的第7次回合版本,建议所有用户升级到此版本。 +本次主要更新: +- 修复OMAP格式升级中的严重缺陷。如果bluestore-quick-fix-on-mount参数设置为true或调用ceph-Bluestore-tool的快速修复命令, +Pacific版本升级后可能会导致数据损坏(格式不正确的OMAP密钥)。相关跟踪:https://tracker.ceph.com/issues/53062。 +bluestore-quick-fix-on-mount继续默认设置为false。 +- MGR: pg_autoscaler将使用“scale-up”配置文件作为默认配置文件。16.2.6将默认配置文件更改为“scale-down”, +但遇到了device_health_metrics池占用过多PG的问题,这对性能并不理想。因此,在对默认池应消耗的PG数量与“scal-down”配置文件结合 +实施限制之前,将默认继续使用“scale-up”配置文件。 +- Cephadm和Cephdashboard:NFS管理已完全重新设计,以确保NFS导出在不同Ceph组件中得到一致的管理。 +在此之前,有3个不兼容的实现用于配置NFS导出:Ceph-Ansible/ OpenStack Manila、Ceph dashboard和'mgr/nfs'模块。 +在此版本中,“mgr/nfs”方式成为官方界面,其余组件(Cephadm和Ceph dashboard)都会遵守它。虽然这可能需要从过时实现手动迁移, +但它将简化那些严重依赖NFS导出的用户体验。 +- dashboard:“集群扩展向导”。在“cephdm bootstrap”步骤之后,登录Ceph dashboard的用户将显示欢迎页面。 +如果他们选择遵循安装向导,他们将收到一组步骤来帮助他们配置Ceph集群:通过添加更多主机来扩展集群、检测和定义其存储设备、 +部署和配置不同的Ceph服务。 +- OSD:当使用mclock_shceduler进行QoS时,不再需要运行任何手动基准。OSD现在通过在初始化期间运行简单的基准, +自动为osd_mclock_max_capacity_iops设置适当的值。 +- MGR:优化进度模块中的全局恢复事件,在统计信息收集之间增加了5秒的睡眠间隔,以减少进度模块对MGR的影响, +特别是在大型集群中有较好收益。 +## 近期社区合入pr +- 在mgr中新增rgw管理模块 [pr#42710](https://github.com/ceph/ceph/pull/42710) +- 支持用perf dump的方式导出bluestore/bluefs的实际分配单元大小 [pr#44098](https://github.com/ceph/ceph/pull/44098) +- 调整了部分bluestore/bluefs内部的计数器的描述,使得描述更加准确,提升可用性 [pr#41557](https://github.com/ceph/ceph/pull/41557) +- 将bluestore_compression_min_blob_size_ssd的大小从8K调整至64K,能够有效减少空间的浪费,并兼顾性能 [pr#39691](https://github.com/ceph/ceph/pull/39691) +- OSD不再支持LevlDB作为KV DB [pr#43612](https://github.com/ceph/ceph/pull/43612) +- 通过自动探测设备的最优io size,并调整min_alloc_size为设备的最优io size。如果设备不支持报告最优的io size,则使用默认的min_alloc_size值 [pr#43691](https://github.com/ceph/ceph/pull/43691) +## 近期Ceph Developer动态 +Ceph社区各个模块会定期举行会议,讨论和对齐开发进展,会后有视频上传至[youtube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos),主要会议信息如下: +|会议名称|说明|频率| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & Seastore开发周例会|周| +|Ceph Orchestration Meeting|Ceph管理模块(Mgr)开发|周| +|Ceph DocUBetter Meeting |文档优化|双周| +|Ceph Performance Meeting|Ceph性能优化|双周| +|Ceph Developer Monthly|Ceph开发者月度例会|月| +|Ceph Testing Meeting|版本验证及发布例会|月| +|Ceph Science User Group Meeting|Ceph科学计算领域会议|不定期| + +近期主要关注了Developer/Performance/Crimson3个会议,会议讨论了如下内容: +- Developer会议主要介绍了新增的jaeger rgw跟踪功能:能跟踪rgw中每个用户请求,将大对象多次put请求合并到一个对象tag下。 +正在进行性能测试:对比编译时开关trace的性能差异、运行时开关trace的性能差异。Jaeger是ceph 16版本引入的新trace,比之前的lttng trace更方便, +不需要额外安装其他依赖包,参见[jaeger文档](https://ceph.com/en/news/blog/2021/distributed-tracing-in-ceph-using-jaeger) +- Performance会议主要讨论了bluestore的共享blob fsck内存使用;通过ceph.conf配置tcmalloc线程缓存值TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES; +glibc malloc导致了内存碎片,即使是tcmalloc也有待进一步优化。 +- Crimson会议同步了SeaStore的开发进展、问题: 完善crimson OSD,实现了经典OSD已有的功能。当ceph.conf没有配置ip时,OSD从mon获取公共ip地址用于心跳。 +讨论了LBA CPU开销时间长的问题,修改策略待定;GC占用了CPU从而导致了整体性能下降,需要提升GC性能。 diff --git "a/web-ui/docs/zh/blog/rosinL/2022-1-30-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-12-13~2022-1-16).md" "b/web-ui/docs/zh/blog/rosinL/2022-1-30-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-12-13~2022-1-16).md" new file mode 100644 index 0000000000000000000000000000000000000000..8c88d705120b9243d2ed756bdba7c879685963ee --- /dev/null +++ "b/web-ui/docs/zh/blog/rosinL/2022-1-30-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-12-13~2022-1-16).md" @@ -0,0 +1,48 @@ +--- +title: Ceph社区动态(2022-12-13~2022-1-16) +date: 2022-1-30 +tags: + - Ceph + - 动态 + - Pacific +sig: ceph-sig +archives: 2022-1 +author: rosinL +summary: Ceph社区动态 +--- +# Ceph社区动态(2022-12-13~2022-1-16) +## Qunicy 版本特性冻结,将于3月份发布 +Qunicy特性已于2022.1.15特性冻结,进入测试阶段,除了常规测试,此次比之前做更多的伸缩测试,测试规模达到1000+ osd,预计将于2022年3月发布。 +## 近期社区合入pr +- common,PriorityCache优化,将缓存内容按时间进行组织,更细粒度的优先级划分,不过测试来看,性能提升不明显 [pr#43299](https://github.com/ceph/ceph/pull/43299) +- bluestore,写过程优化,检查写数据bufferlist中0,并跳过,不进行写入,有相关的计数器可以进行观测 [pr#43337](https://github.com/ceph/ceph/pull/43337) +- bluestore,启动过程中减少fsck内存的消耗 [pr#43667](https://github.com/ceph/ceph/pull/43667) +- bluestore bluefs锁优化,调整锁粒度 [pr#43794](https://github.com/ceph/ceph/pull/43794) +- bluestore 使用基于大页的读buffer,暂时默认关闭 [pr#43691](https://github.com/ceph/ceph/pull/43691) +- mon,在create pool时新增--bulk的标记,pg autoscaler会将pool的初始pg数调整为最大的值,默认情况下,pg autoscaler将pool的初始pg数调整为最小值,并动态更改[pr#44241](https://github.com/ceph/ceph/pull/44241) +- mgr, 新增pg_autoscaler全局的打开和关闭命令 [pr#43716](https://github.com/ceph/ceph/pull/43716) +- mgr,实现TTL cache, 来缓存集群信息,减少与集群的交互 [pr#44088](https://github.com/ceph/ceph/pull/44088) +- mgr balancer优化,重构calc_pg_upmaps [pr#44002](https://github.com/ceph/ceph/pull/44002),准备在Qunicy版本实现primary balancer,以实现容量和负载的均衡 +- 重删,cephdeduptool, 新增按chunk(偏移、长度)和对象进行去重的功能,更易于使用重删功能[pr#43686](https://github.com/ceph/ceph/pull/43686) +- rgw, s3select功能,基于arrow实现parquet格式支持[pr#40802](https://github.com/ceph/ceph/pull/40802), 由于依赖的问题,编译时暂时默认关闭该功能[pr#44603](https://github.com/ceph/ceph/pull/44603) +- rgw,新增用户/bucket级别的速率限制 [pr#42891](https://github.com/ceph/ceph/pull/42891) +- rgw中,减少不必要的bucket stats load [pr#44538](https://github.com/ceph/ceph/pull/44538) +- rgw 添加max_header_size的选项,来调整beast的parse buffer大小,默认的大小为16K,最大64K,较大的buffer size能够减少socket read的个数 [pr#44029](https://github.com/ceph/ceph/pull/44029),对比之前的版本中,在[pr#29776](https://github.com/ceph/ceph/pull/29776)固定为64K,增加了灵活性。 +## 近期Ceph Developer动态 +Ceph社区各个模块会定期举行会议,讨论和对齐开发进展,会后有视频上传至[youtube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos),主要会议信息如下: +|会议名称|说明|频率| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & Seastore开发周例会|周| +|Ceph Orchestration Meeting|Ceph管理模块(Mgr)开发|周| +|Ceph DocUBetter Meeting |文档优化|双周| +|Ceph Performance Meeting|Ceph性能优化|双周| +|Ceph Developer Monthly|Ceph开发者月度例会|月| +|Ceph Testing Meeting|版本验证及发布例会|月| +|Ceph Science User Group Meeting|Ceph科学计算领域会议|不定期| +|Ceph Leadership Team Meeting|Ceph领导团队例会|周| + +近期主要关注Performance,会议讨论了如下内容: +- Quincy版本性能测试,需要与pacific版本进行对比,nvme性能测试将基于mako(amd EPYC 7742)进行,部署120 osd,测试涵盖单节点多节点(副本,ec),测试工具主要有fio(rbd cephfs), hsbench(rgw),tcmu-runner(iscsi/nbd), omapbench(mds) +- Qunicy版本可能会加入恢复测试 +- Pacific 测试过程发现,perf cycles/op monitoring对性能有影响,up to 15% +- ceph中内存使用情况并不透明,有好多模块内存跟踪不到,可能需要更多内存相关优化。 \ No newline at end of file diff --git "a/web-ui/docs/zh/blog/rosinL/2022-2-23-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-1-17~2022-2-16).md" "b/web-ui/docs/zh/blog/rosinL/2022-2-23-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-1-17~2022-2-16).md" new file mode 100644 index 0000000000000000000000000000000000000000..38215029827e6c34454339dbb0bff8e0e4b0ce4e --- /dev/null +++ "b/web-ui/docs/zh/blog/rosinL/2022-2-23-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2021-1-17~2022-2-16).md" @@ -0,0 +1,88 @@ +--- +title: Ceph社区动态(2022-1-17~2022-2-16) +date: 2022-2-23 +tags: + - Ceph + - 动态 + - Pacific +sig: ceph-sig +archives: 2022-2 +author: rosinL +summary: Ceph社区动态 +--- +# Ceph社区动态(2021-1-17~2022-2-16) +## Cephalocon 2022推迟举办 +由于COVID-19大流行,原定于美国东部时间4月5-7日(北京时间4月6-8日)举办的Cephalocon 2022推迟举办,修订时间待定。本次Cephalocon 2022会议有关议题已经公布,整理如下,详情请参考[Cephalocon 2022 sched](https://ceph2022.sched.com/) +|分类|议题|演讲者|机构| +|----|-------|----|----| +|RGW, Performance|[Optimizing RGW Object Storage Mixed Media through Storage Classes and Lua Scripting](https://sched.co/w9FL)|Curt Bruns & Anthony D'Atri|Intel| +|RGW|[RGW: Sync What? Sync Info Provider: Early Peek](https://sched.co/w9Fm)|Yehuda Sadeh-Weinraub|Red Hat| +|RGW|[RGW – An Ultimate S3 Frontend for MultipleBackends: An Implementation Story](https://sched.co/w9GJ)|Gregory Touretsky & Andriy Tkachuk|Seagate| +|RGW, S3select|[S3select: Computational Storage in S3](https://sched.co/w9GY)|Gal Salomon & Girjesh Rajoria|Red Hat| +|RGW|[Testing S3 Implementations: RGW & Beyond](https://sched.co/w9Gh)|Robin Hugh Johnson|DigitalOcean| +|RGW|[Introduction to Container Object Storage Interface aka COSI for ceph RGW](https://sched.co/w9Fs)|Jiffin Tony Thottan|Red Hat| +|RGW|[RGW Zipper](https://sched.co/w9GD)|Daniel Gryniewicz & Soumya Koduri|Red Hat| +|Cephadm|[Lightning Talk: Introduction to Cephadm](https://sched.co/w9EW)|Melissa Li|Red Hat| +|Dashboard|[Dashboard: Exploring Centralized Logging with Ceph Storage](https://sched.co/w9GP)|Gaurav Sitlani & Aashish Sharma|Red Hat| +|Dashboard|[Operating Ceph from the Ceph Dashboard: Past, Present and Future](https://sched.co/w9F0)|Ernesto Puerta|Red Hat| +|Ceph, QoS, mClock|[Ceph QoS Refinements for Background Operations using mClock](https://sched.co/w9Fv)|Sridhar Seshasayee|Red Hat| +|Ceph, PG|[pgremapper: CRUSHing Cluster OperationaComplexity](https://sched.co/w9EZ)|Joshua Baergen|DigitalOcean| +|Ceph, PG|[New Workload Balancer in Ceph](https://sched.co/w9Eo)|Josh Salomon & Laura Flores|Red Hat| +|Ceph, DPDK|[Lightning Talk: Ceph Messenger DPDkstack Development and Debugging](https://sched.co/w9FO)|Chunsong Feng|Huawei| +|Ceph, Windows|[Ceph on Windows](https://sched.co/w9Ei)|Alessandro Pilotti|Cloudbase Solutions| +|Seastore|[What's New with Crimson and Seastore?](https://sched.co/w9FI)|Samuel Just|Red Hat| +|Seastore, Crimson|[Lightning Talk: Introduction to Crimson from a Newbie](https://sched.co/w9FF)|Joseph Sawaya|Red Hat| +|Seastore|[Understanding SeaStore Through Profiling](https://sched.co/w9ET)|Yingxin Cheng & Tushar Gohad|Intel| +|Bluestore|[Accelerating PMEM Device Operations in BlueStore with Hardware Based Memory Offloading Technique](https://sched.co/w9F9)|Ziye Yang|Intel| +|Bluestore|[Revealing BlueStore Corruption Bugs in Containerized Ceph Clusters](https://sched.co/w9Fj)|Satoru Takeuchi|Cybozu| +|Dev|[Chasing Bad Checksums: A Journey through Ceph, TCMalloc, and the Linux kernel](https://sched.co/w9Fd)|Mauricio Faria de Oliveira & Dan Hill|Canonical| +|Dev|[Lightning Talk: Improving Ceph Build and Backport Automations Using Github Actions](https://sched.co/w9Gt)|Deepika Upadhyay|Red Hat| +|Dev|[Ceph Crash Telemetry Observability in Action](https://sched.co/w9Ec)|Yaarit Hatuka|Red Hat| +|Performance|[DisTRaC: Accelerating High-Performance Compute Processing for Temporary Data Storage](https://sched.co/w9Ef)|Gabryel Mason-Williams|Rosalind Franklin Institute| +|Performance|[Putting the Compute in your Storage](https://sched.co/w9Fg)|Federico Lucifredi & Brad Hubbard|Red Hat| +|Performance|[Modifying Ceph for Better HPC Performance](https://sched.co/w9Gb)|Darren Soothill|CROIT| +|Performance|[Over A Billion Requests Served Per Day: Ensuring Everyone is Happy with Our Ceph Clusters’ Performance](https://sched.co/w9FR)|Jane Zhu & Matthew Leonard|Bloomberg LP| +|Performance|[Lessons Learned from Hardware Acceleration Initiatives for Ceph-specific Workloads](https://sched.co/w9G4)|Harry Richardson & Lionel Corbet|SoftIron| +|Performance|[The Effort to Exploit Modern SSDs on Ceph](https://sched.co/w9GG)|Myoungwon Oh|Samsung Electronics| +|Performance|[NVMe-over-Fabrics Support for Ceph](https://sched.co/w9GS)|Jonas Pfefferle, IBM & Scott Peterson|Intel| +|Security|[Introducing the New RBD Image Encryption Feature](https://sched.co/w9F3)|Or Ozeri & Danny Harnik|IBM| +|Security|[CephFS At-Rest Encryption with fscrypt](https://sched.co/w9Eu)|Jeffrey Layton|Red Hat| +|Security|[Secure Token Service in Ceph](https://sched.co/w9Ex)|Pritha Srivastava|Red Hat| +|Security|[Data Security and Storage Hardening in Rook and Ceph](https://sched.co/w9Fp)|Federico Lucifred & Michael Hackett|Red Hat| +|Ceph应用|[Improved Business Continuity for an Existing Large Scale Ceph Infrastructure: A Story from Practical Experience](https://sched.co/w9G7)|Enrico Bocch & Arthur Outhenin-Chalandre|CERN| +|Ceph应用|[How we Operate Ceph at Scale](https://sched.co/w9Fy)|Matt Vandermeulen|Digital Ocean| +|Ceph应用|[BoF Session: Ceph in Scientific Computing and Large Clusters](https://sched.co/w9FC)|Kevin Hrpcek|Space Science & Engineering Center, University of Wisconsin - Madison| +|Ceph应用|[Aquarium: An Easy to Use Ceph Appliance](https://sched.co/w9Ge)|Joao Eduardo Luis & Alexandra Settle|SUSE| +|Ceph应用|[Stretch Clusters in Ceph: Algorithms, Use Cases, and Improvements](https://sched.co/w9Gn)|Gregory Farnum|Red Hat| +|Ceph应用|[We Added 6 Petabytes of Ceph Storage and No Clients Noticed! Here’s How We Did It.](https://sched.co/w9FX)|Joseph Mundackal & Matthew Leonard|Bloomberg LP| +|Ceph应用|[Why We Built A “Message-Driven Telemetry System At Scale” Ceph Cluster](https://sched.co/w9FU)|Xiaolin Lin & Matthew Leonard|Bloomberg LP| +|Ceph应用|[Lightning Talk: Ceph and 6G: Are We Ready for zettabytes?](https://sched.co/w9Gk)|Babar Khan|Technical University Darmstadt| +|Ceph应用|[Bringing emails@ceph Into the Field](https://sched.co/w9G1)|Danny Al-Gaaf|Deutsche Telekom AG| +|Ceph应用|[Lightning Talk: Ceph and QCOW2 a Match Made in Heaven: From Live Migration to Differential Snapshots](https://sched.co/w9F6)|Effi Ofer|IBM| +|Ceph应用|[Lightning Talk: Installing Ceph on Kubernetes Using the Rook Operator and Helm](https://sched.co/w9GM)|Mike Petersen|Platform9| +|Benchmark|[Connecting The Dots: Benchmarking Ceph at Scale](https://sched.co/w9GA)|Shon Paz & Ido Pal|Red Hat| +|Benchmark|[Introducing Sibench: A New Open Source Benchmarking Optimized for Ceph](https://sched.co/w9GV)|Danny Abukalam|SoftIron| +## 近期社区合入pr +近期pr主要以bug修复为主,摘选了部分如下: +- mgr, 当osd in/out时,默认关闭pg recovery,需要时手动开启,以降低对服务集群的影响 [pr#44588](https://github.com/ceph/ceph/pull/44588) +- osd, 增加ceph daemon perf dump中dump_blocked_ops_count选项,来快速获取blocked ops 个数,以解决原来的dump_blocked_ops操作带来的较大开销 [pr#44780](https://github.com/ceph/ceph/pull/44780) +- rgw, rgw s3 CopyObject接口支持条件拷贝 [pr#44678](https://github.com/ceph/ceph/pull/44678) +- rgw, 修复radosgw-admin bucket chown过程中大量内存使用的问题 [pr#44357](https://github.com/ceph/ceph/pull/44357) +- rbd, krbd中引入rxbounce选项,解决image作为windows系统块设备时,crc校验出错和带来性能下降的问题 [pr#44842](https://github.com/ceph/ceph/pull/44842) +## 近期Ceph Developer动态 +Ceph社区各个模块会定期举行会议,讨论和对齐开发进展,会后有视频上传至[youtube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos),主要会议信息如下: +|会议名称|说明|频率| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & Seastore开发周例会|周| +|Ceph Orchestration Meeting|Ceph管理模块(Mgr)开发|周| +|Ceph DocUBetter Meeting |文档优化|双周| +|Ceph Performance Meeting|Ceph性能优化|双周| +|Ceph Developer Monthly|Ceph开发者月度例会|月| +|Ceph Testing Meeting|版本验证及发布例会|月| +|Ceph Science User Group Meeting|Ceph科学计算领域会议|不定期| +|Ceph Leadership Team Meeting|Ceph领导团队例会|周| + +近期社区重点投入Quincy版本的冻结测试与验证,提取关键内容: +- Quincy测试,读性能符合预期,写性能部分场景有下降,但可以确定4k min_alloc_size,bluestore allocator优化有助于性能提升。 +- 随着omap规模增长,omap_iterator效率会导致大量的slow_ops甚至拒绝响应。[issue](https://tracker.ceph.com/issues/53926)记录了两种压缩方式测试结果:手动触发压缩,时延无法恢复至压缩前的水平;Rocksdb提供的周期性[ttl压缩功能](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide#periodic-and-ttl-compaction),使能后,时延可以恢复至压缩前水平。 +- CBT(Ceph Benchmark Tool)工具新增大量PR合入,重点关注大规模osd测试时对mem资源的控制,以及多client并发测试用例的测试。 diff --git "a/web-ui/docs/zh/blog/rosinL/2022-3-31-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-2-17~2022-3-13).md" "b/web-ui/docs/zh/blog/rosinL/2022-3-31-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-2-17~2022-3-13).md" new file mode 100644 index 0000000000000000000000000000000000000000..761527e8a5ce268ef599f13d6f624cbb743cafc3 --- /dev/null +++ "b/web-ui/docs/zh/blog/rosinL/2022-3-31-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-2-17~2022-3-13).md" @@ -0,0 +1,52 @@ +--- +title: Ceph社区动态(2022-2-17~2022-3-13) +date: 2022-3-31 +tags: + - Ceph + - 动态 + - Pacific +sig: ceph-sig +archives: 2022-3 +author: rosinL +summary: Ceph社区动态 +--- +# Ceph社区动态(2022-2-17~2022-3-13) +## Cephalocon 2022推迟至7月11~13日 +Cephalocon 2022推迟至7月11~13日举办,详细会议信息及报名请参考:[Cephalocon 2022 sched](https://ceph2022.sched.com/) +## [Ceph Octopus v15.2.16](https://ceph.com/en/news/blog/2022/v15-2-16-octopus-released/)发布 +重点修复: +- 修复OSD 重启后可能导致PGs进入WAIT状态的读租约逻辑bug; +- 修复了BlueStore中的几个bug,包括对象列表bug的修复,该bug可能会导致统计不匹配的擦除错误。 + +## 近期社区合入pr +近期pr主要以bug修复为主,摘选了部分如下: +- cephfs: cephfs-top工具新增读时延、写时延、元数据访问时延指标[pr#41397](https://github.com/ceph/ceph/pull/41397) +- rbd: rbd工具中支持pool和image级别的rbd map option的设置和修改[pr#44904](https://github.com/ceph/ceph/pull/44904) +- common: 小的优化,使用trhead-local变量替代分片的计算[pr#44479](https://github.com/ceph/ceph/pull/44479) +## 近期Ceph Developer动态 +Ceph社区各个模块会定期举行会议,讨论和对齐开发进展,会后有视频上传至[youtube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos),主要会议信息如下: +|会议名称|说明|频率| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & Seastore开发周例会|周| +|Ceph Orchestration Meeting|Ceph管理模块(Mgr)开发|周| +|Ceph DocUBetter Meeting |文档优化|双周| +|Ceph Performance Meeting|Ceph性能优化|双周| +|Ceph Developer Monthly|Ceph开发者月度例会|月| +|Ceph Testing Meeting|版本验证及发布例会|月| +|Ceph Science User Group Meeting|Ceph科学计算领域会议|不定期| +|Ceph Leadership Team Meeting|Ceph领导团队例会|周| +|Ceph Tech talks|Ceph社区技术相关主题讨论|月| + +### Performance Meeting +- 3月3日[performance weekly](https://www.youtube.com/watch?v=syq_LTg25T4),Intel Michal Wysoczanski介绍了openCAS相关的版本及应用,结合ceph部署应用等相关特性应用,但没有提供对ceph的性能优化情况,期望未来可以介绍。 +- 3月15日[performance weekly](https://www.youtube.com/watch?v=RFYA-0k6QEk),重点讨论如下性能相关内容: + - PGLog优化讨论 + - Crimson cyanstore 性能测试 + - rocksdb iterator 性能 +### [Ceph Talks](https://ceph.io/en/community/tech-talks/) +Ceph社区每月技术相关主题的讨论,3月讨论主题如下: +- 2022-3-24, Ceph Tech Talk: How Teuthology Works with Kamoltat (Junior) Sirivadhna +## Ceph Community Newsletter +Ceph社区新增月度简报[Ceph Community Newsletter March 2022 Edition](https://ceph.com/en/news/blog/2022/newsletter-march/) +3月主要内容有: +- Ceph Quincy Release Canadidate v17.1.0发布。 diff --git "a/web-ui/docs/zh/blog/rosinL/2022-4-26-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-3-15~2022-4-15).md" "b/web-ui/docs/zh/blog/rosinL/2022-4-26-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-3-15~2022-4-15).md" new file mode 100644 index 0000000000000000000000000000000000000000..21ce801fc9cc7b5b1e73154d6a819abf2fd8af77 --- /dev/null +++ "b/web-ui/docs/zh/blog/rosinL/2022-4-26-Ceph\347\244\276\345\214\272\345\212\250\346\200\201(2022-3-15~2022-4-15).md" @@ -0,0 +1,102 @@ +--- +title: Ceph社区动态(2022-3-15~2022-4-15) +date: 2022-4-26 +tags: + - Ceph + - 动态 + - Quincy + - OpenEuler + - ODD +sig: ceph-sig +archives: 2022-4 +author: rosinL +summary: Ceph社区动态 +--- +# Ceph社区动态(2022-3-15~2022-4-15) +## openEuler社区Ceph进展 +### ODD 2022(openEuler Developer Day 2022)存储相关议题 +2022-04-13~2022-04-15,openEuler Developer Day 2022(简称[ODD 2022](https://www.openeuler.org/zh/interaction/summit-list/devday2022/))在线上举行,ODD是开放原子开源基金会的 openEuler 社区发起的开发者大会。旨在推动 openEuler 在服务器、云计算、边缘计算和嵌入式四大场景的技术探索和创新。本次 ODD 2022 正式发布 openEuler 22.03 全场景长周期版本,展示社区伙伴联合创新成果,分享多行业使用 openEuler 规模部署的商业案例,举办社区治理机构的线上工作会议。 +openEuler Ceph版本紧跟Ceph原生社区,针对ARM架构开展优化,打造高质量、高可靠、高性能的Ceph版本。本次ODD大会与Ceph存储相关的议题有如下: +* 缓存策略对Ceph性能的影响 (XSKY 池信泽) + - 主要是介绍CEPH RADOS架构下各级缓存策略对性能的影响 +* 基于UADK加速器提升Ceph与大数据应用性能 (华为 戴志威) + - 数据存储中的加密、压缩对CPU算力提出了更高的要求。UADK是鲲鹏CPU上基于SVA的用户态加速开发套件,支持加密、压缩的计算加速和卸载。介绍Ceph数据体系和压缩特性,以及UADK在Ceph和大数据应用上的适配进展,性能表现 +* 大数据+Ceph存算分离、算子下推提升计算存储效率(华为 吴启庆) + - 大数据+Ceph采用数据直通和算子下推方案,实现存算分离,提升计算存储效率,性能和存储率优于HDFS存储,成为数据湖实现的解决方案之一 +* Arm SVE 向量指令为⾼性能计算库加速(Linaro 徐国栋,庄浩坚) + - ⾯向⾼性能计算(HPC)和存储领域, Arm 推出了 SVE(Scalable Vector Extenstion),⾄今演进有 SVE2 ,SME (armv9)。本演讲介绍 SVE 演进,⼯具链⽀持,软件适配状况。最后结合在 ISA-L , XXHash 的编码,讲解SVE 的优势,同时介绍开发技术要点 +### openEuler 22.09 Ceph相关版本规划 + * 在Ceph上使能鲲鹏加速器压缩和加密特性 + * 性能优化 + * Ceph国密支持 + * Crimson特性使能与评估 + * Ceph集群关机、开机自动化实现 + > 详情查看[2022年4月14日 sig-Ceph openEuler Developer Day 2022纪要](https://gitee.com/src-openeuler/ceph/wikis/%E4%BC%9A%E8%AE%AE%E7%BA%AA%E8%A6%81/2022%E5%8F%8C%E5%91%A8%E4%BE%8B%E4%BC%9A%E4%BC%9A%E8%AE%AE%E7%BA%AA%E8%A6%81) +## [Ceph v17.2.0 Quincy released](https://ceph.io/en/news/blog/2022/v17-2-0-quincy-released/)发布 +相比于Pacific版本,有如下主要更新: +* General + - FileStore已被弃用,BlueStore成为默认的ObjectStore + - `device_health_metric pool`重命名为`.mgr`, 用作ceph-mgr模块的公共存储 + - `ceph pg dump`命令增加了3个新列:`LAST_SCRUB_DURATION`, `SCRUB_SCHEDULING`,`OBJECTS_SCRUBBED` + - `WITH_LEVEL_DB`已被移除,全部迁移到RocksDB + - `osd_memory_target_autotune`默认被开启,被设置为总内存的0.7 +* Rados + - OSD:使用`mclock_scheduler`作为BlueStore OSD的默认的`osd_op_queue`来提供Qos + - MGR:`pg_autoscaler`现在可以使用`noautoscale`标志全局打开和关闭,默认设置为`on` + - OSD:支持了osd-osd之间的通信压缩,默认为`off` + - OSD:集群日志中`slow ops`的简明报告,通过将`osd_aggrregated_slow_ops_logging`设置为`false`可以恢复旧的和更详细的日志记录 +* RBD + - rbd-nbd:增加了`rbd device attch`和`rbd device detach`命令,允许在rbd-nbd守护进程重启之后可以安全的连接(kernel5.14) + - rbd-nbd:增加了`notrim`映射选项,以支持**thick-provisioned images** + - 针对SSD设备上的客户端持久缓存进行了大量稳定性修复工作 +* RGW + - RGW现在支持按照`user`和`bucket`进行限速,可以通过全局配置应用于所有的`user`和`bucket` + - 修复S3 bucket通知事件的消息格式 + - 修复`Multipart upload`行为:仅在multipart upload完成之后发送一个CompleteMultipartUpload通知,Upload开始时的POST通知和每个part上发送的通知将不再发送 +* CephFS + - 可以使用特定的ID("fscid")创建文件系统,这对文件系统恢复场景非常有效(当Mon数据库丢失并重建时,恢复的文件系统会拥有和之前系统相同的ID) + +## 近期社区合入pr +近期pr主要以bug修复为主,摘选了部分如下: +* BlueStore: + - 在磁盘设备上,禁用NCB功能,NCB代码在OSD crash之后用于恢复allocation Map,但是由于HDD的性能比SSD慢了20倍,因此该功能在HDD环境下不适用,因此禁用该功能 [pr#45340](https://github.com/ceph/ceph/pull/45340) + - 修复NCB SimpleBitMap边界检查的bug [pr#45733](https://github.com/ceph/ceph/pull/45733) + - 重构bluefs中的get_block_extents接口 [pr#45250](https://github.com/ceph/ceph/pull/44250) +* crimson: + - 修复由于bufferlist参数引用引起的OSD crash的bug [pr#45415](https://github.com/ceph/ceph/pull/45415) + - 在vstart.sh中,针对crimson-osd禁用pg-autoscaling功能 [pr#45317](https://github.com/ceph/ceph/pull/45317) + - 增加如下功能:cmp xattr cancel operation [pr#45774](https://github.com/ceph/ceph/pull/45774),omap cmp [pr#45630](https://github.com/ceph/ceph/pull/45630),osd_op_assert_ver [pr#45348](https://github.com/ceph/ceph/pull/45348) +* osd: + - 修复快照删除中的bug:仅在scrub完成之后重新启动快照删除,修复CephFS场景下的,大量快照删除中PG状态不能恢复的bug [pr#45785](https://github.com/ceph/ceph/pull/45785) + - sparse reads支持truncation sequnces [pr#45103](https://github.com/ceph/ceph/pull/45103) +* mon: + - 修改`target_size_ratio`的范围从原来的`0.0->1.0`为`0.0->nolimit`,主要解决`ceph osd pool create --target_size_ratio `时传入的ratio大于1.0的错误 [pr#45078](https://github.com/ceph/ceph/pull/45078) +* 其他: + - 主要包括dashboard和cephadm的一些bug修复 + - rbd和rgw的bug修复 + - 文档修复 +## 近期Ceph Developer动态 +Ceph社区各个模块会定期举行会议,讨论和对齐开发进展,会后有视频上传至[youtube](https://www.youtube.com/channel/UCno-Fry25FJ7B4RycCxOtfw/videos),主要会议信息如下: +|会议名称|说明|频率| +|-------|----|----| +|Crimson SeaStore OSD Weekly Meeting |Crimson & Seastore开发周例会|周| +|Ceph Orchestration Meeting|Ceph管理模块(Mgr)开发|周| +|Ceph DocUBetter Meeting |文档优化|双周| +|Ceph Performance Meeting|Ceph性能优化|双周| +|Ceph Developer Monthly|Ceph开发者月度例会|月| +|Ceph Testing Meeting|版本验证及发布例会|月| +|Ceph Science User Group Meeting|Ceph科学计算领域会议|不定期| +|Ceph Leadership Team Meeting|Ceph领导团队例会|周| +|Ceph Tech talks|Ceph社区技术相关主题讨论|月| + +### Performance Meeting +* 2022-03-17:[performace weekly](https://www.youtube.com/watch?v=RFYA-0k6QE) + - Crimson cyanstore性能测试 + - rocksdb iterator性能讨论 + - PGLog优化点讨论 +* 2022-03-24: [performace weekly](https://www.youtube.com/watch?v=tulzatiqqHo) + - Quincy版本large write性能测试回归 + - RocksDB TombStone:在LSM中删除一个deleter是快速的,但是会使后续的查询变慢,尤其是大量的TombStone可能会妨碍查询,特别是范围查询 +* 2022-03-31 [performace weekly](https://www.youtube.com/watch?v=NuofFc1539I) ~ 2022-04-07[performace weekly](https://www.youtube.com/watch?v=F34BvWvEDf4) + - Quincy版本 写测试回归 + - 测试性能结果相比与Pacific16.2.7低,原因还在分析和讨论中 diff --git a/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-01.png b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-01.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b33622c987de72a650f9636b1f045c7d13102e Binary files /dev/null and b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-01.png differ diff --git a/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-02.png b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-02.png new file mode 100644 index 0000000000000000000000000000000000000000..32d092547f8f4ded6418b325a6a8ba4091c4244b Binary files /dev/null and b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-02.png differ diff --git a/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-03.png b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-03.png new file mode 100644 index 0000000000000000000000000000000000000000..66dab6cd84613a51a26b5550b7ec898c79048a6a Binary files /dev/null and b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-03.png differ diff --git a/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-04.png b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-04.png new file mode 100644 index 0000000000000000000000000000000000000000..52195713233c8dd390ab71119c4159274e2f742f Binary files /dev/null and b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter-04.png differ diff --git a/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter.md b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter.md new file mode 100644 index 0000000000000000000000000000000000000000..796fe39351dc2af888cfd964b0e126e65010bdaf --- /dev/null +++ b/web-ui/docs/zh/blog/shanshishi/2020-05-08-atune-tuning-smarter.md @@ -0,0 +1,108 @@ +--- +title: A-Tune让系统调优更智能 +date: 2020-05-08 +tags: + - A-Tune + - 调优 + - 智能 +archives: 2020-05 +author: openEuler Blog Maintainer +summary: A-Tune让系统调优更智能。 +--- + +# A-Tune让系统调优更智能 + +2020年1月1日,openEuler开源社区如约而至。2020年3月27日,在华为开发者大会(HDC 2020)上,openEuler首个长期支持版openEuler LTS 20.03正式推出。自此,我们的计算世界将变得更为精彩。 + +那么,openEuler社区除了提供openEuler这个开源Linux操作系统的标准组件之外,还有哪些厉害的子项目呢? A-Tune和iSula便是答案。 + +接下来,就让我们来揭开A-Tune的神秘面纱吧。 + +## A-Tune是什么 + +让我们先从名字来认识下A-Tune吧。“Tune”代表了**性能调优**;“A”则承载了Tune的愿景与定位,其蕴含了3层寓意Aware、Adaptive、Auto,即 + +**自感知(Aware)**- 自动感知负载和业务模型; + +**自适应(Adaptive)**- 动态监测负载特征变化,适时调整资源; + +**自调节(Auto)**- 通过感知负载模型,自动匹配优化库。 + +顾名思义,A-Tune就是一款基于openEuler开发的,自动化、智能化性能调优引擎。它利用人工智能,对运行在操作系统上的业务建立精准模型,感知并推理出业务特征,根据业务特征及负载情况给出最佳的参数配置组合,从而使业务处于最佳系统性能状态下运行。 + +## 为什么要开发A-Tune + +系统调优一直是一个门槛高的系统性工程,强依赖工程师的技能和经验。如,一个简单的应用,除了自身代码外,支撑其运行的环境,如硬件平台、操作系统、数据库等都可能是影响性能的因素。如何在众多因素中找到性能瓶颈,需要工程师们熟悉大量参数的含义、配置方法,以及业务场景,并不断积累经验,才能对系统进行快速精准调优。 + +随着各行各业数字化智能化转型,新应用、新技术、新计算架构层出不穷,传统系统调优更是面临以下挑战: + +- 涉及上万的能力组合,挑战人工调优极限 + + +运行在操作系统上的业务类型成百上千,形态千差万别,从硬件到操作系统,到中间件再到上层应用,涉及的调优参数组合上万+。随着业务复杂度和调优对象的增加,调优组合和调优所需成本指数级增长,大大超过了工程师的能力范围。 + + + +- 应用场景剧增,实验室测试无法穷举 + +实际业务场景成千上万,计算、网络、存储等硬件配置层出不穷,实验室无法遍历所有的应用和业务场景,不可能完全模拟动态负载,无法对不同的场景组合进行穷举测试。 + +为了降低调优门槛、提升调优效率,A-Tune应运而生。 + +## A-Tune的优势 + +A-Tune利用大数据和人工智能技术,通过对各种类型的业务进行大数据分析,建立精准业务模型,并制定相应的调优策略。A-Tune具有如下优势: + +- **简化系统调优** + +A-Tune尽可能的屏蔽了硬件和操作系统底层细节,工程师无需感知底层细节,就可以快速上手调优。因此,降低了对工程师的技能要求,简化了系统调优。 + +- **提升调优效率** + +A-Tune利用大数据和人工智能技术,从CPU、IO、网络、内存等多个维度抽象刻画不同业务类型系统行为的特征,并对收集到的结果进行大数据分析和机器学习,识别有效的调优参数,快速匹配多种配置组合,从而找到最佳配置。对于业务复杂、配置项多,能够大大提升调优效率。 + +- **持续积累调优经验** + +A-Tune能够利用人工智能技术自动分析业务特征,寻找优化配置,建立优化模型库。针对具体的业务场景,结合历史经验,训练并持续优化业务模型,积累和优化模型库,满足多业务多场景下的调优。 + +## A-Tune的架构 + +A-Tune分层架构如下图所示,主要包括智能决策层、系统画像层、交互系统层以及优化模式库。 + + + +- **智能决策层**:包含感知系统和决策系统。感知系统获取环境资源使用数据,利用人工智能技术推理判断业务类型;决策系统根据感知子系统获得的数据进行调优决策。 + +- **系统画像层**:包含数据平台、标注系统和学习系统。数据平台用于存放软硬件数据;标注系统用于业务环境数据采集和业务模型的聚类;学习系统用于业务模型的学习和分类。 + +- **交互系统层**:用于各类系统资源的监控和配置,执行调优策略。 + +- **优化模式库**:构建并积累各种业务模型对应的优化能力和配置。 + +## A-Tune应用场景 + +当前,A-Tune根据不同的负载情况,在如下场景进行了测试 + +| **应用类型** | **已支持应用** | +| ------------------- | ----------------------------------- | +| https应用 | Nginx | +| 数据库 | MongoDB、MySQL、PostgreSQL、MariaDB | +| 大数据 | Hadoop、Spark | +| 内存密集型应用 | SPECjbb2015 | +| 计算+网络密集型应用 | Redis | +| 计算密集型应用 | SPECCPU2006 | +| 网络密集型应用 | Dubbo | + +实验结果如下图所示: + + + +注:实验室测试数据,结果在不同环境存在偏差 + +## 关注A-Tune + +当前A-Tune还在不断的开发和完善当中,如你对A-Tune感兴趣,欢迎关注A-Tune项目(扫描二维码,点击star),我们将在此发布开发路标并进行讨论,期待你的加入。 + +https://gitee.com/openeuler/A-Tune + + diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-Installation-manual-for-Virt-Install.md b/web-ui/docs/zh/blog/small_leek/2020-10-26-Installation-manual-for-Virt-Install.md new file mode 100644 index 0000000000000000000000000000000000000000..f24d354b28f5b878bb93a0165d000a99f393bfe5 --- /dev/null +++ b/web-ui/docs/zh/blog/small_leek/2020-10-26-Installation-manual-for-Virt-Install.md @@ -0,0 +1,186 @@ +--- +title: virt-intall安装openEuler手册 +date: 2020-10-26 +tags: + - 安装openEuler +archives: 2020-10 +author: sigui small_leek +summary: 用virt-install安装openeuler的指导,Arm的目前支持vnc连接/命令行安装;x86的目前只支持vnc连接安装。 +--- + +# aarch64安装流程 +## 环境信息 + +1. 宿主机环境: openEuler release 20.09 + +2. 虚拟机iso:openEuler-20.09-aarch64-dvd.iso + +3. iso获取地址: +https://repo.openeuler.org/openEuler-20.09/ISO/aarch64/openEuler-20.09-aarch64-dvd.iso + +## 准备工作 + +### 1. 准备好iso,在宿主机安装虚拟机化相关组件libvirt*、qemu*、virt-install,并开启libvirtd服务: + yum install –y libvirt* + yum install –y qemu* + yum install –y virt-install + systemctl start libvirtd + +### 2. 安装edk2 + yum install –y edk2 + +在windows侧或者可以连通该宿主机的且有图形界面的机器上安装vncviewer,设置VNC客户端选项: + + +## 图形界面安装 +### 1. 执行如下命令使用vnc安装: + +virt-install --connect qemu:///system --virt-tpye kvm --vcpus [cpu_num] --memory [memory size] --name [domain name] --cdrom [iso_path] --disk [disk_path_and_parameter] --boot cdrom --network [network] --graphics vnc,listen=0.0.0.0 + +例: +virt-install --connect qemu:///system --virt-tpye kvm --vcpus 4 --memory 4096 --name sgs-oe-20.09 --cdrom /home/images/openEuler-20.09-aarch64-dvd.iso --disk path=/home/images/test.img,size=50,format=qcow2,bus=scsi --boot cdrom --network network=default --graphics vnc,listen=0.0.0.0 + +### 2. 重新开启一个终端,使用如下命令查看vnc端口号 +virsh vncdisplay [domain name] + +### 3. 打开vncviewer输入【主机名:端口号】连接,进入如下界面: + + +注意:如果打不开,请再宿主机使用如下命令开通端口: + + firewall-cmd --add-port=[port]/tcp + firewall-cmd --add-port=[port]/tcp --permanent + +其中,[port]的值应该等于5900+端口号的值,比如,此处应该是: + + firewall-cmd --add-port=5903/tcp + firewall-cmd --add-port=5903/tcp --permanent + + + +#### 选择安装或者测试后安装,进入如下界面: + + +#### 选择continue,进入下一步: + + +#### 选中标黄的部分,设置后,开始安装: + +等待安装完毕,重启。 + +### 4. 由于virt-install时设置的启动方式是boot,当安装完毕重启系统时,会进入如下界面,输入exit,退出console + + +### 5. 进入bios界面,选择系统启动方式Boot Manager->UEFI QEMU QEMU HARDDISK + + + +### 6. 系统重启,安装完成 + + +## 文本方式安装 +### 1. 执行如下命令使用vnc安装: +virt-install --connect qemu:///system --virt-tpye kvm --vcpus [cpu_num] --memory [memory size] --name [domain name] --cdrom [iso_path] --disk [disk_path_and_parameter] --boot cdrom --network [network] + +例: +virt-install --connect qemu:///system --virt-tpye kvm --vcpus 4 --memory 4096 --name wx-oe-20.09 --cdrom /home/images/openEuler-20.09-aarch64-dvd.iso --disk path=/home/images/test.img,size=50,format=qcow2,bus=scsi --boot cdrom --network network=default + +### 2. 输入e,编辑文本模式,设置console=ttyAMA0,115200,tty0 + + + +修改console,设置console=ttyAMA0,115200,tty0 + + +修改完成后,输入Ctrl-x开始 + +### 3. 选择2),使用文本模式安装 + + +### 4. 系统自定义安装。“!”感叹号的条目需要自定义设置 + + +输入r,对Processing的条目状态进行刷新 + + + + + +### 5. 设置root用户的密码 + + +### 6. 上述自定义设置完成后,输入b,开始安装系统 + + + +### 7. 系统安装完成后,由于virt-install时设置的启动方式是boot,当安装完毕重启系统时,会进入如下界面,输入exit,退出console + + +### 8. 进入bios界面,选择系统启动方式Boot Manager->UEFI QEMU QEMU HARDDISK + + + +### 9. 系统重启,安装完成 + + +# x86_64安装流程 +## 环境信息 + +1. 宿主机环境: openEuler release 20.09 +2. 虚拟机iso:openEuler-20.09-x86_64-dvd.iso +3. iso获取地址: +https://repo.openeuler.org/openEuler-20.09/ISO/x86_64/openEuler-20.09-x86_64-dvd.iso + + +## 准备工作 +### 1. 准备好iso,在宿主机安装虚拟机化相关组件libvirt*、qemu*、virt-install,并开启libvirtd服务: + yum install –y libvirt* + yum install –y qemu* + yum install –y virt-install + systemctl start libvirtd + +### 2. 安装edk2 + yum install –y edk2 + +### 3. 在windows侧或者可以连通该宿主机的且有图形界面的机器上安装vncviewer,设置VNC客户端选项 + + + +## 图形界面安装 +### 1. 执行如下命令使用vnc安装: +virt-install --connect qemu:///system --vcpus [cpu_num] --memory [memory size] --name [domain name] --cdrom [iso_path] --disk [disk_path_and_parameter] --boot cdrom --network [network] --graphics vnc,listen=0.0.0.0 + +例: +virt-install --connect qemu:///system --vcpus 4 --memory 4096 --name wx-oe-20.09 --cdrom /home/images/openEuler-20.09-x86_64-dvd.iso --disk path=/home/images/test.img,size=50,format=qcow2,bus=virtio --video virtio --boot cdrom --network network=default --graphics vnc,listen=0.0.0.0 + +### 2. 重新开启一个终端,使用如下命令查看vnc端口号 + virsh vncdisplay [domain name] + +### 3.打开vncviewer输入【主机名:端口号】连接,进入如下界面: + + +注意:如果打不开,请再宿主机使用如下命令开通端口: + + firewall-cmd --add-port=[port]/tcp + firewall-cmd --add-port=[port]/tcp --permanent +其中,[port]的值应该等于5900+端口号的值,比如,此处应该是 + + firewall-cmd --add-port=5903/tcp + firewall-cmd --add-port=5903/tcp --permanent + + +### 4. 选择安装或者测试后安装,进入如下界面: + +选择continue,进入下一步: + +选中标黄的部分,设置后,开始安装: + +等待安装完毕,重启。 + +### 5. 重新开启一个终端,关闭新安装的虚拟机 + virsh destroy [domain name] +### 6. 编辑虚拟机的启动方式,更改boot dev='cdrom'为boot dev='hd' + virsh edit [domain name] +### 7. 重启虚拟机 + virsh start [domain name] +### 8.通过vncviewer再次连接虚拟机,确认虚拟机重启ok。 diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-01.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f080579e0189d27dbe39116211be211fbb65c9a Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-01.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-02.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd298f03df44e9aa76bae1c8d23ff4b3e4b70aeb Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-02.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-03.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..90cca14eabe1711f5f26762e7faa57ac7d03bea5 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-03.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-04.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d032bdfd94e02c8f6baac91849bfa4f6beda9a1 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-04.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-05.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99489f1a106e0284c836136de4654ce7a012f694 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-05.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-06.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d9aac02baee85b6d50e4d445f586b12cb8211d70 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-06.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-07.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-07.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7451106a06f5bd96e1b9f19e06ed6279ec0ee55f Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-07.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-08.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-08.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ede7bf26d01358567770bec866e8d016d87b228c Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-08.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-09.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-09.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5db31396259a7e761174b075d6747aef19c90812 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-09.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-10.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e323aecee741a7be76fd9b5db7f9f328bf60ed42 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-10.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-11.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bbd93001db76a06900aa23af6b0cb5afd7175a1b Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-11.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-12.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-12.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b342cbc0a35ae2b647c001fbe290920d0719170 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-12.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-13.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-13.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6b665581b930edad13c6de38ea38d010570faae Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-13.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-14.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-14.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2df98d43a9ba3c854ac8d9f4ac664afc9bfc0a5b Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-14.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-15.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-15.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a5bdc7863e8bb6f01f8178c34168973ef74431b8 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-15.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-16.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-16.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b20381fd5b3eabd63fcbbdb3b253829345e5f500 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-16.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-17.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-17.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e705e34e36f2d8285da32f5d98afa4eff2fe8f2 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-17.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-18.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-18.jpg new file mode 100644 index 0000000000000000000000000000000000000000..64a72094c3e5fa6025f67a1266949c8993ffe847 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-18.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-19.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-19.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ecb596aca783b7d404a0afc700a1762674068fde Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-19.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-20.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-20.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a07e759adfb79e94c34e595d83339972689dac08 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-20.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-21.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-21.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8337a379e16ed4ff5e8dc201c4198f73081af5a0 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-21.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-22.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-22.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fed4a5e2925cfc2d9e42adb17db4697bf2e0e500 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-22.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-23.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-23.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7451106a06f5bd96e1b9f19e06ed6279ec0ee55f Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-23.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-24.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-24.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ede7bf26d01358567770bec866e8d016d87b228c Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-24.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-25.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-25.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5db31396259a7e761174b075d6747aef19c90812 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-25.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-26.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-26.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e323aecee741a7be76fd9b5db7f9f328bf60ed42 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-26.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-27.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-27.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f080579e0189d27dbe39116211be211fbb65c9a Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-27.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-28.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd298f03df44e9aa76bae1c8d23ff4b3e4b70aeb Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-28.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-29.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-29.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca5008868b6b46113e1269c8d90d079ba135c48c Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-29.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-30.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-30.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d032bdfd94e02c8f6baac91849bfa4f6beda9a1 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-30.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-31.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-31.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99489f1a106e0284c836136de4654ce7a012f694 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-31.jpg differ diff --git a/web-ui/docs/zh/blog/small_leek/2020-10-26-post-32.jpg b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d9aac02baee85b6d50e4d445f586b12cb8211d70 Binary files /dev/null and b/web-ui/docs/zh/blog/small_leek/2020-10-26-post-32.jpg differ diff --git a/web-ui/docs/zh/blog/t_feng/2020-07-31-boothole.md b/web-ui/docs/zh/blog/t_feng/2020-07-31-boothole.md new file mode 100644 index 0000000000000000000000000000000000000000..14322bab2e6d63d7d1dc091307e4788a77736416 --- /dev/null +++ b/web-ui/docs/zh/blog/t_feng/2020-07-31-boothole.md @@ -0,0 +1,73 @@ +--- +title: BootHole漏洞分析 +date: 2020-07-31 +tags: + - 漏洞分析 + - CVE +archives: 2020-07 +author: t.feng +summary: BootHole漏洞分析 +--- + +# BootHole漏洞分析 +## 漏洞描述 +UEFI Secure Boot是由UEFI Forum主导,用于保护引导过程免受攻击的安全模式。为了防止引导组件被恶意篡改,它通过校验引导过程中所有组件的签名来保障引导阶段的安全性。GRUB2支持在efi文件中注入签名,参与安全启动的校验流程。但是,由Eclypsium公司发现GRUB2引导程序存在漏洞,导致使用UEFI Secure Boot的系统容易被恶意攻击者利用,进而跳过安全校验流程,修改引导过程或引导的内核及其他恶意动作。(CVE-2020-10713)。 +## 漏洞分析 +- 经过分析,该漏洞在解析grub.cfg文件时在grub2内部发生了一个缓冲区溢出的漏洞。grub.cfg文件位于EFI分区中,因此只要拥root权限的攻击者,可以跳过修改shim或者grub2引导程序文件的前提下,修改grub.cfg。由于缓冲区溢出使得攻击者可以在UEFI引导阶段获得执行任意代码的权限,从而跳过原有的安全校验流程。 +- 当前之所以可以造成解析grub.cfg文件溢出后可以造成攻击者拥有执行任意代码权限的原因是因为:这个缓冲区溢出覆盖了词法分析器Flex在堆中的部分字段,这些字段包括多个内部解析元素,拥有任意读写能力。所以,会造成攻击者获得执行任意代码的权限并篡改引导过程。 +### 代码分析 +GRUB2提供的YY_FATAL_ERROR函数并没有停止执行或者退出,仅仅是向串口打印一个错误并返回调用的函数。所以会导致yy_flex_strncpy将长度超大的字符串复制到yytext中从而造成缓冲区溢出。 +``` +#define YY_FATAL_ERROR(msg) \ + do { \ + grub_printf (_("fatal error: %s\n"), _(msg)); \ + } while (0) +``` +``` +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + if ( yyleng >= YYLMAX ) \ + YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \ + yy_flex_strncpy( yytext, yyg->yytext_ptr, yyleng + 1 , yyscanner); \ + yyg->yy_c_buf_p = yy_cp; +``` +## 影响性分析 +1. 系统上已经存在的攻击者能够劫持引导过程并在系统启动期间执行恶意代码。 +2. 使用此漏洞可以绕过利用UEFI安全启动的系统。 +## 规避措施 +无 +## 解决方案 +- 下载openEuler发布的最新版本grub2软件包: + - [漏洞SA](https://cve.openeuler.org/#/infoDetails/openEuler-SA-2020-1038) + - [aarch64架构](https://repo.openeuler.org/openEuler-20.03-LTS/update/aarch64/Packages/) + - [x86_64架构](https://repo.openeuler.org/openEuler-20.03-LTS/update/x86_64/Packages/) +- 查看当前系统已安装的grub2软件包: + - rpm -aq | grep grub2 +- 找到下载的grub2包中与系统对应的软件包,置于同一目录并执行升级: + - rpm -Uvh grub2-*.rpm +- 升级完成之后,进入/boot/efi/EFI/openEuler目录下,重新生成grub.cfg文件: + - grub2-mkconfig -o grub.cfg + +## FAQ +1. Legacy模式是否受此漏洞影响? +Legacy模式属于非安全启动,无漏洞的触发场景,但是代码本身存在漏洞,建议修复。 + +2. Legacy模式如何修复漏洞? +需要按照解决方案中的步骤进行软件包升级。但是,在第4步执行完软件包升级之后,需要重新安装bootloader。如,启动盘是/dev/sda,则需要执行(Legacy模式与UEFI模式grub.cfg文件路径存在差异): +grub2-install /dev/sda +grub2-mkconfig –o /boot/grub2/grub.cfg + +3. UEFI模式+非安全启动是否受此漏洞影响? +UEFI模式+非安全启动无漏洞的触发场景,但是代码本身存在漏洞,建议修复。 + +4. UEFI模式+安全启动是否受此漏洞影响? +会触发漏洞场景,跳过安全启动限制,影响系统安全性、可用性、机密性,强烈建议修复。 + +5. 普通用户是否可以修改grub.cfg文件 +普通用户无修改权限,仅root用户可以修改grub.cfg文件。 + +6. 其他的组件:shim,kernel,bios等是否要同步升级? +OSV厂商如果使能了安全启动,受此漏洞影响,强烈建议升级grub2软件包修复此漏洞。同时,需要吊销原来安全启动的证书,更新shim、grub2、fwupdate、kernel这些包的签名。如果不更新安全启动证书,系统回退到原来受影响的grub2版本后,仍受此漏洞影响。 diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/4G.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/4G.png new file mode 100644 index 0000000000000000000000000000000000000000..34dae6caa282c244c7cbd362b384f13480d0ed63 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/4G.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/64G.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/64G.png new file mode 100644 index 0000000000000000000000000000000000000000..a506a8f7a9d1f7d2e18328a07580259b024ce756 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/64G.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/VirtualBox-main.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/VirtualBox-main.png new file mode 100644 index 0000000000000000000000000000000000000000..5e33d4e64b6ec23228eb4e36cd5750973fba2a8f Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/VirtualBox-main.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/begin_install.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/begin_install.png new file mode 100644 index 0000000000000000000000000000000000000000..0b2dcd04bd5863584ba366a12feb03b254b05c74 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/begin_install.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/config-virtual-machine.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/config-virtual-machine.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbeecc2f96aabaef15d41c62cac1c8d9c270fbd Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/config-virtual-machine.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/continue.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/continue.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d40a6751343c04679052869c080afd5753344a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/continue.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/dynamic.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/dynamic.png new file mode 100644 index 0000000000000000000000000000000000000000..63a6199790fbe53f7ea1546a2db74db2ca9d9419 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/dynamic.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/file_icon.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/file_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..42d51ded6187d68a93690e750af9d614b3024594 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/file_icon.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/global.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/global.png new file mode 100644 index 0000000000000000000000000000000000000000..52e5ad26575f6ed81a885688f9e3773b93c6a23a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/global.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/hard.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/hard.png new file mode 100644 index 0000000000000000000000000000000000000000..d82d3581f57079fd9043839d2a625be3f877c22a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/hard.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/index-x86.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/index-x86.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb9e5bc6574fbe85b1f4b0520593a98070e6b23 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/index-x86.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_destination.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_destination.png new file mode 100644 index 0000000000000000000000000000000000000000..3482b93f28af92c0c98510a44d148227ce3653ec Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_destination.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_lts.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_lts.png new file mode 100644 index 0000000000000000000000000000000000000000..9b02fc6d2d513ad39d3b3bacce104336aec76a77 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_lts.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_over.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_over.png new file mode 100644 index 0000000000000000000000000000000000000000..05265913d4c62b65e73e6608a346d72f767ab1a7 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_over.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_status.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_status.png new file mode 100644 index 0000000000000000000000000000000000000000..a13673698b1d2651ccae9feb6ec2dd872ad92783 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/install_status.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot.png new file mode 100644 index 0000000000000000000000000000000000000000..8e6426154c3ffb0e7ca8d8107b655c561b42a049 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot_start.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot_start.png new file mode 100644 index 0000000000000000000000000000000000000000..ceee2f73cc4d97e6a3d907015531bf7044a5d698 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/reboot_start.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/return.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/return.png new file mode 100644 index 0000000000000000000000000000000000000000..2880b32dfdb54b057411b7801fc0a517646dfedd Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/return.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/route.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/route.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a4657e753e9c405ef90a44d9414571c410ba1c Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/route.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/save.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/save.png new file mode 100644 index 0000000000000000000000000000000000000000..55c7e5db89ec9604df3e6db2156b71f0ffd97758 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/save.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_disk.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_disk.png new file mode 100644 index 0000000000000000000000000000000000000000..166b5b4b060937c8a0afe64338482b940c85514a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_disk.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_iso.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_iso.png new file mode 100644 index 0000000000000000000000000000000000000000..3563de1ac8ce786ba2860c2bbadcdfad8f33c539 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_iso.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_start.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_start.png new file mode 100644 index 0000000000000000000000000000000000000000..370f7d7a4402d91305f005d13a08afcc6cc26988 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/select_start.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/set_pass.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/set_pass.png new file mode 100644 index 0000000000000000000000000000000000000000..313ec69e05c1407dbbece135dff909a67352082a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/set_pass.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/start.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/start.png new file mode 100644 index 0000000000000000000000000000000000000000..9a214852d04b23b0d32de96ced0bdd9271953510 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/start.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_done.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_done.png new file mode 100644 index 0000000000000000000000000000000000000000..790c008eb5fc75cdb44cab0b754ffe05f9677033 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_done.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_file.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_file.png new file mode 100644 index 0000000000000000000000000000000000000000..f20dbffd47682dff779e41a8a7c99a6fd5c59183 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox-media/virtual_file.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox.md b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox.md new file mode 100644 index 0000000000000000000000000000000000000000..7442fc8e61bcb4ce747b10a51046dfad5ab39749 --- /dev/null +++ b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-VirtualBox.md @@ -0,0 +1,139 @@ +--- +title: 初试openEuler(二):windows下使用VirtualBox安装openEuler +date: 2020-03-27 +tags: + - 安装openEuler +archives: 2020-03 +author: traffic_millions +summary: windows下使用VirtualBox安装openEuler虚拟机。 + +--- + +### 【背景】 +今天华为开发者大会上,openEuler开源社区发布了最新的LTS版本,手上只有一台windows机器,考虑使用VirtualBox安装openEuler虚拟机. + +### 【环境准备】 + +- Windows10 64位 +- Oracle VM VirtualBox 6.1.4 +- openEuler开源社区下载:[openEuler-20.03-LTS-x86_64-dvd.iso](https://repo.openeuler.org/openEuler-20.03-LTS/ISO/x86_64/openEuler-20.03-LTS-x86_64-dvd.iso) (X86) + + + +### 【安装步骤】 + +##### 一、下载安装Virtual Box + +在[VirtualBox官网](https://www.virtualbox.org/wiki/Downloads)下载安装程序 + + + +安装的时候可以自定义安装路径如(D:\software\Oracle\VirtualBox),然后一路next即可; + + + +安装结束之后,使用Ctrl+G打开全局设置,修改默认虚拟电脑位置如(D:\myVM),方便之后查找; + + + +##### 二、创建虚拟机 + +选择 【控制】-->【新建】,填写虚拟机的配置信息,示例如下 + +名称:openEuler,类型:Linux,由于没有openEuler,所以版本选择Other Linux(64-bit),下一步 + + + +设置虚拟机的内存,此内存即为虚拟机所占用的系统内存,这里将虚拟内存设置为4G + + + +选择【现在创建虚拟硬盘(c)】 + + + +虚拟硬盘文件类型,选择默认的【VDI(VirtualBox磁盘映像)】,下一步 + + + +选择【动态分配】,下一步 + +分配给虚拟机的内存空间较大,使用时逐渐占用磁盘空间,闲置时自动缩减比较合理 + + + +这里选择设置虚拟机硬盘大小为64G + + + +虚拟机创建完成,openEuler所需的硬件资源准备完毕 + + + +##### 三、安装openEuler + +启动上一步创建好的虚拟机 + + + +点击右侧“文件夹图标” + + + +点击注册,选择准备阶段下载好的**openEuler-20.03-LTS-x86_64-dvd.iso** + + + +选择【启动】,进入到安装界面 + + + +选择 【Install openEuler 20.03-LTS】回车,进行安装 + + + +选择Continue + + + +选择Installation Destination + + + +选择要安装的磁盘,Done + + + +选择Begin Installation + + + +安装状态如下 + + + +选择Root Password 设置root用户的密码(后面登录要用到!~) + + + +安装完成后,选择Reboot重启虚拟机 + + + +显示重新回到了安装界面 + + + +关闭虚拟机,选择【设置】选中openEuler-20.03-LTS-x86_64-dvd.iso,鼠标右键,删除盘片,保存退出 + + + +重新启动虚拟机,显示如下界面,直接回车 + + + +输入用户(root)密码(安装阶段设置的密码),进入openEuler虚拟机 + + + +到这里openEuler虚拟机已经安装完成了~ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image003.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image003.png new file mode 100644 index 0000000000000000000000000000000000000000..96ea343fddc150a30ea0f08dc168e22f89392a73 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image003.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image005.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image005.png new file mode 100644 index 0000000000000000000000000000000000000000..32c9cde7e6fdf8709c336fc94e8f1f1b26cc5724 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image005.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image007.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image007.png new file mode 100644 index 0000000000000000000000000000000000000000..5ea7078b4acfe0cb991620c108d1ed1d13c45478 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image007.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image009.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image009.png new file mode 100644 index 0000000000000000000000000000000000000000..82f9504ad782b4a71f5eb8411daaa16daa0ec22e Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image009.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image011.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image011.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1665c5fa44f0573e1ea1d3a45494d7bb127ab8 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image011.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image012.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image012.png new file mode 100644 index 0000000000000000000000000000000000000000..203e3fe2f90f801428db67161319a3731ae3bf9a Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image012.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image013.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image013.png new file mode 100644 index 0000000000000000000000000000000000000000..195c8151cec4c3811a55828a713be67f34fa42de Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image013.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image014.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image014.png new file mode 100644 index 0000000000000000000000000000000000000000..05a713790aecbdb8972d39fda355fd5c601bc87f Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image014.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image015.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image015.png new file mode 100644 index 0000000000000000000000000000000000000000..9c6cf2771e28784360600e5db610dac007ca047b Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image015.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image016.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image016.png new file mode 100644 index 0000000000000000000000000000000000000000..611adcb51b17417565a9286a27388361b6f420e4 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image016.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image017.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image017.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3a188afb0e58e2933269da2cd1d094d545cd62 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image017.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image018.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image018.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e1251d59a19bb1e7c0941a0988da1dbbd47830 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image018.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image019.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image019.png new file mode 100644 index 0000000000000000000000000000000000000000..7d12a78e09c6f04c62de8ff63a04bf71614fcac7 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image019.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image020.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image020.png new file mode 100644 index 0000000000000000000000000000000000000000..9a62cd6c87c2932a8820ee1cdfa116bba5bcddb7 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image020.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image021.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image021.png new file mode 100644 index 0000000000000000000000000000000000000000..67b82c66bf7d180253c940c432a6ef7a7f751530 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image021.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image022.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image022.png new file mode 100644 index 0000000000000000000000000000000000000000..bb2ea02325be4bf6120ca6207a89c3634a935688 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image022.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image023.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image023.png new file mode 100644 index 0000000000000000000000000000000000000000..790b9c363e0be0e1d08136e6276bb0eaed6f8aee Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image023.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image024.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image024.png new file mode 100644 index 0000000000000000000000000000000000000000..d950846af1bab6036e8135adba1c888afd6d8d34 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image024.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image025.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image025.png new file mode 100644 index 0000000000000000000000000000000000000000..d0fbb09b02a0f1870c679b76cb5677b99748c45f Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image025.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image026.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image026.png new file mode 100644 index 0000000000000000000000000000000000000000..f63666fcc9989cfa8908a2aaf4cf813fa8fbecba Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/clip_image026.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/copy_fd.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/copy_fd.png new file mode 100644 index 0000000000000000000000000000000000000000..f559c00ba10449bbf07965b57949821fad8ea613 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/copy_fd.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/download_qcow2.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/download_qcow2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f278b30399c2b4175732ee1e776ff41009940a6 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/download_qcow2.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/ended.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/ended.png new file mode 100644 index 0000000000000000000000000000000000000000..e14c9e7067175bf4d2c15d8b8df4f7b9b9a5f953 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/ended.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_iso.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_iso.png new file mode 100644 index 0000000000000000000000000000000000000000..adb300d0132a094f4d217958266b99cd8c0f9430 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_iso.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_qcow2_to_create.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_qcow2_to_create.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e5821c9e69e13593fa3dcbb511dea042905bc6 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/exec_qcow2_to_create.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/generate_qcow2.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/generate_qcow2.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d308910875cd8be1d581f3765305e5bd5d2773 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/generate_qcow2.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/index-arm.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/index-arm.png new file mode 100644 index 0000000000000000000000000000000000000000..aabcce0b2759e59c235e5154a30e12bdd6aac90c Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/index-arm.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/put_iso.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/put_iso.png new file mode 100644 index 0000000000000000000000000000000000000000..79417cf8d472ec23c62f7313a57869a447d9e6b3 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/put_iso.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_fd.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_fd.png new file mode 100644 index 0000000000000000000000000000000000000000..0582cddeb5fde51f40f05c5afda2ebf762ecd3fd Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_fd.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_done.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_done.png new file mode 100644 index 0000000000000000000000000000000000000000..bf1070666916886d7cacea7870fdfd0f5238e50c Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_done.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_show.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_show.png new file mode 100644 index 0000000000000000000000000000000000000000..fd01ef45110e1293354795c2bc837defc6b8d851 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/qcow2_install_show.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/show_qcow2.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/show_qcow2.png new file mode 100644 index 0000000000000000000000000000000000000000..1079fbc3cc80420fc66919948f66039ce8cf0843 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/show_qcow2.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/wait_login.png b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/wait_login.png new file mode 100644 index 0000000000000000000000000000000000000000..8e48681f4b6d9010e0d9ba03b249d2b669630786 Binary files /dev/null and b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu-media/wait_login.png differ diff --git a/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu.md b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu.md new file mode 100644 index 0000000000000000000000000000000000000000..4b625f645bd6b912cef94b8f47d28581040a03c8 --- /dev/null +++ b/web-ui/docs/zh/blog/traffic_millions/2020-03-27-qemu.md @@ -0,0 +1,185 @@ +--- +title: 初试openEuler(一):windows下使用qemu安装openEuler +date: 2020-03-27 +tages: + - 安装openEuler +archives: 2020-03 +author: traffic_millions +summary: windows下使用qemu安装openEuler虚拟机。 +--- + +### 【背景】 +今天华为开发者大会上,openEuler开源社区发布了最新的LTS版本,本着第一个吃螃蟹的原则,赶紧下载下来玩一玩;由于手上只有一台windows机器,考虑使用qemu安装openEuler虚拟机; + +### 【环境准备】 +- Windows10 64位 +- openEuler开源社区下载qcow2镜像:[openEuler-20.03-LTS.aarch64.qcow2.xz](http://repo.openeuler.org/openEuler-20.03-LTS/virtual_machine_img/aarch64/openEuler-20.03-LTS.aarch64.qcow2.xz) (aarch64) + + + + +### 【安装步骤】 + +##### 一、安装qemu-for-windows + +在[QEMU home page](https://qemu.weilnetz.de/w64/2019/)下载qemu安装程序 + + + +安装的时候可以自定义安装路径如(D:\software\qemu) + + + +安装结束之后设置qemu的环境变量:环境变量配置窗口有时候很难找到,win10可以直接在搜索框搜索“环境变量” + + + +选择【编辑系统环境变量】即可; + + + +高级->环境变量->系统变量->Path->新建,添加qemu的安装路径,保存退出即可,比如(D:\software\qemu) + + + +##### 二、运行qemu & 安装openEuler + +新建一个openEuler_test文件夹,将下载解压好的openEuler镜像文件(openEuler-20.03-LTS.aarch64.qcow2)放到该文件夹中 + + + +进入到qemu的安装路径(D:\software\qemu)将edk2-aarch64-code.fd拷贝到qcow2镜像文件的同级路径下; + + + +拷贝之后如下所示 + + + +在dos窗口进入到该路径下,执行如下命令创建虚拟机: + +`qemu-system-aarch64 -m 4096 -cpu cortex-a57 -smp 4 -M virt -bios edk2-aarch64-code.fd -hda openEuler-20.03-LTS.aarch64.qcow2 -serial vc:800x600` + + + +弹出qemu显示窗口 + + + +在打开的qemu的虚拟化窗口中,按下Ctrl+Alt+2切换到串口控制台,如下图所示: + + + +回车,等待出现如下界面 + + + +输入用户名:root,密码:openEuler12#$ + + + +到这里虚拟机就算是安装完成了~ + + + +--- + +分界线 + +--- + + + +可能有些小伙伴想要亲自用ISO安装一把openEuler,下面我也用ISO装了一下,不过会出现概率性安装失败,不推荐这种安装办法,当然体验一把openEuler安装界面也是可以的~ + +### 【环境准备】 + +- openEuler开源社区下载openEuler ISO:[openEuler-20.03-LTS-aarch64-dvd.iso](https://repo.openeuler.org/openEuler-20.03-LTS/ISO/aarch64/openEuler-20.03-LTS-aarch64-dvd.iso) (aarch64) + + + +### 【安装步骤】 + +##### 一、安装qemu-for-windows + +同上 + +##### 二、创建qcow2镜像文件 + +将下载好的openEuler ISO(openEuler-20.03-LTS-aarch64-dvd.iso)放openEuler_test文件夹中 + + + +以管理员身份运行cmd,进入到openEuler_test路径下,执行如下命令创建qcow2格式的镜像文件; + +`qemu-img create –f qcow2 disk.qcow2 100G` 生成disk.qcow2文件 + + + +##### 三、运行qemu & 安装openEuler + +进入到qemu的安装路径(D:\software\qemu)将edk2-aarch64-code.fd拷贝到ISO和qcow2镜像文件的同级路径下; + + + +拷贝之后如下所示 + + + +在dos窗口进入到该路径下,执行如下命令创建虚拟机: + +`qemu-system-aarch64 -m 4096 -cpu cortex-a57 -smp 4 -M virt -bios edk2-aarch64-code.fd -cdrom openEuler-20.03-LTS-aarch64-dvd.iso -hda disk.qcow2 -serial vc:800x600` + + + +弹出qemu显示窗口,在打开的qemu的虚拟化窗口中,按下Ctrl+Alt+2切换到串口控制台,如下图所示: + + + +将光标停留在Install openEuler 20.03 LTS处,并按e键,进入grub2引导参数界面: + + + +由于此时的串口控制台是被-serial参数重定向到vc monitor中,故需要修改一下openEuler引导菜单中的启动参数,删除console=tty0 (注意删除console=tty0的时候,移动光标要逐步移动,不要长按“—>”按钮,是个大坑~) + +注:由于windows没有图形化所必要的驱动程序,故qemu for windows安装openEuler的过程,只能使用文本安装模式。 + + + +在此界面中删除console=tty0参数,注意删除的时候需要将光标移动到console=tty0的左端,再按“<---” + + + + +删除之后按下Ctrl+x键执行OS的引导过程,稍等一会之后,便可看到qemu的控制台提示系统安装 + + + +按下2回车,使用文本模式安装openEuler: + + + +安装程序总共有8个过程,分别是:语言设置,时区设置,安装源设置,安装软件选择,安装位置,网络设置,root密码,用户创建。其中,[x]表示已经设置完成,[!]表示未设置完成。在所有的配置选择完毕之后,我们即可进行安装(用户创建不是必选项): + + + +有时候这个qemu显示窗口出现滞留的情况,导致相互遮盖看不清选项 + + + +这个显示也是一个大坑~,根本看不清选项,推荐使用一串神秘代码进行安装(5+回车+c+回车+2+回车+c+回车+c+回车+7+回车+密码+回车+密码+回车+b+回车) + +![img](https://media.giphy.com/media/RiWWsA60e3bXrwrdb9/giphy.gif) + + +执行完这串神秘代码之后,显示如下(这个时候等着就行了…) + + + +出现如下显示,表示正在安装软件包(58/523, 继续等着吧…) + + + +安装完成之后,按下回车重启,输入用户名root和密码openEuler12#$即可~ + + diff --git a/web-ui/docs/zh/blog/trainey/imgs/oemaker_example.png b/web-ui/docs/zh/blog/trainey/imgs/oemaker_example.png new file mode 100644 index 0000000000000000000000000000000000000000..cce56d1e808ed4fb16847972f3964e8db381d140 Binary files /dev/null and b/web-ui/docs/zh/blog/trainey/imgs/oemaker_example.png differ diff --git a/web-ui/docs/zh/blog/trainey/yaml_compilation_guide.md b/web-ui/docs/zh/blog/trainey/yaml_compilation_guide.md new file mode 100644 index 0000000000000000000000000000000000000000..4a282c86191e3c5160fa2f880faab596f4c11ad1 --- /dev/null +++ b/web-ui/docs/zh/blog/trainey/yaml_compilation_guide.md @@ -0,0 +1,92 @@ +--- +title: yaml文件编写指导 +date: 2020-08-11 +tags: + - 参与贡献 + - 流程规范 +archives: 2020-08 +author: Trainey +summary: 介绍yaml文件用途及编写方法 +--- + +#### 一、背景介绍 + +通过`yaml`文件承载`openEuler`制品仓软件包的上游社区信息,便于统一校验及管理。 + +#### 二、yaml文件命名及位置要求 + +`yaml`文件名称与仓库名称应该保持一致,并跟软件包的`spec`文件在同级目录,一般放置到根目录。例如,`oemaker`代码仓的`yaml`文件名称是`oemaker.yaml`,放置到根目录,如下所示: + + + +#### 三、yaml文件字段介绍 + +`yaml`文件中需要人工填写的字段有 `version_control`、`src_repo`、`tag_prefix`、`separator`。 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字段名字段描述备注
version_control上游仓库使用的版本控制协议目前支持svn, git, hg, github, gnome, metacpan, pypi, gitee
src_repo上游仓库的实际地址通过version_control和src_repo我们可以使用工具下载对应的代码
tag_prefix上游仓库的tag名version前缀例如,上游给的tag名是v1_0_1, 那么tag_prefix应该配置为"^v"
separatortag中版本的间隔符例如,上游给的tag名是v1_0_1, 那么separator应该配置为"_"
+#### 四、常见类型写法示例 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
version_control类型示例写法(链接)
svnamanda.yaml
gitmdadm.yaml
hgnginx.yaml
githubasciidoc.yaml
gnomegnome-terminal.yaml
metacpanperl-Authen-SASL.yaml
pypipython-apipkg.yaml
giteeoemaker.yaml
\ No newline at end of file diff --git a/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png new file mode 100644 index 0000000000000000000000000000000000000000..fe48cd586b437d4a173476330084ef1b3f0dfa29 Binary files /dev/null and b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-1.png differ diff --git a/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c4fc79bf6a0d48dab1f46982e688378b7b2cbd Binary files /dev/null and b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-2.png differ diff --git a/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5a8667a7a322807f1071b1a65b6a3725340c821c Binary files /dev/null and b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2-3.png differ diff --git a/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md new file mode 100644 index 0000000000000000000000000000000000000000..caf2226654bc67e5935c85405bdb8c49a0f5b638 --- /dev/null +++ b/web-ui/docs/zh/blog/wangfengtu/2021-04-19-isulad-cgroupv2.md @@ -0,0 +1,268 @@ +--- +title: iSulad支持cgroup v2功能介绍及原理解析 +date: 2021-04-19 +tags: + - iSulad +archives: 2021-04 +author: wangfengtu +summary: 本文主要介绍iSulad如何使用cgroup v2并介绍该功能的实现原理 + +--- + +cgroup是linux中用于限制进程组资源的功能。cgroup目前包括两个版本,cgroup v1和cgroup v2。cgroup v2的目标是取代cgroup v1,出于兼容性的考虑,cgroup v1并没有在内核中删除,并且大概率会长期存在。iSulad目前已支持pure cgroup v2,该功能目前还是实验功能。 + + + +## cgroup v2相比cgroup v1有什么变化 + +cgroup v2和cgroup v1相比的主要差异如下: + +1. cgroup v1的各个子系统(控制器)单独挂载在各自的目录下,而cgroup v2里所有子系统都挂载在同一个目录下扁平分布。 +2. 进程只能绑定到cgroup的“/”目录和叶子节点,无法绑定到中间节点。 +3. 需要在cgroup.subtree_control中开启对应的控制器才能在子目录中使用该控制器的功能。 +4. 去掉了cgroup v1中的tasks文件,cpu控制器中的cgroup.clone_children也被移除了。 +5. 修改了通知机制,cgroup v2通过cgroup.events文件进行通知。 +6. 去掉了部分接口(见下面iSulad支持cgroup v2和cgroup v1的功能对比),并将部分cgroup的实现方式修改为ebpf方式实现(后面有介绍ebpf方式的实现原理)。 + + + +下面我们介绍一下iSulad里面会用到的几个重要差异。 + +1. 在cgroup v1中,各个子系统都是各自独立实现并单独挂载的,像这样: + +``` +root@wft-pc:~# ls /sys/fs/cgroup/ +blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event rdma unified +cpu cpu,cpuacct devices hugetlb net_cls net_prio pids systemd +root@wft-pc:~# +``` + +在cgroup v2中,各个子系统的实现进行了统一的规划(例如值的取值范围基本都是1到10000),并全部挂载到同一个目录下,像这样: + +``` +root@wft-pc:/sys/fs/cgroup/isulad# ls +cgroup.controllers cpu.max cpu.weight hugetlb.2MB.events.local memory.events.local memory.swap.high +cgroup.events cpu.pressure cpu.weight.nice hugetlb.2MB.max memory.high memory.swap.max +cgroup.freeze cpuset.cpus hugetlb.1GB.current hugetlb.2MB.rsvd.current memory.low pids.current +cgroup.max.depth cpuset.cpus.effective hugetlb.1GB.events hugetlb.2MB.rsvd.max memory.max pids.events +cgroup.max.descendants cpuset.cpus.partition hugetlb.1GB.events.local io.max memory.min pids.max +cgroup.procs cpuset.mems hugetlb.1GB.max io.pressure memory.oom.group rdma.current +cgroup.stat cpuset.mems.effective hugetlb.1GB.rsvd.current io.stat memory.pressure rdma.max +cgroup.subtree_control cpu.stat hugetlb.1GB.rsvd.max io.weight memory.stat +cgroup.threads cpu.uclamp.max hugetlb.2MB.current memory.current memory.swap.current +cgroup.type cpu.uclamp.min hugetlb.2MB.events memory.events memory.swap.events +root@wft-pc:/sys/fs/cgroup/isulad# +``` + +2. cgroup v1中,挂载了的控制器就是可用的,但在cgroup v2中,需要开启才能使用。在cgroup目录中有一个cgroup.controllers文件和一个cgroup.subtree_control文件。 + +​ cgroup.controllers:当前目录可用的控制器,只读文件无法修改,内容由上一层文件夹中的cgroup.subtree_control决定。 + +​ cgroup.subtree_control:子目录可用的控制器。需要开启控制器则需要在该文件中增加对应的控制器,开启后在子目录可使用该控制器。 + +可以使用echo +memory > cgroup.subtree_control命令开启子目录的控制器,这里的+memory可以是cgroup.controllers里支持的任意一种控制器。看下面的例子,一开始在test目录下没有memory设置相关的控制器,当开启memory控制器后,目录下的test目录下就出现了memory相关的控制器。 + +``` +root@wft-pc:/sys/fs/cgroup/test# cat cgroup.controllers +cpuset cpu io memory hugetlb pids rdma +root@wft-pc:/sys/fs/cgroup/test# cat cgroup.subtree_control +root@wft-pc:/sys/fs/cgroup/test# mkdir test +root@wft-pc:/sys/fs/cgroup/test# ls test +cgroup.controllers cgroup.freeze cgroup.max.descendants cgroup.stat cgroup.threads cpu.pressure io.pressure +cgroup.events cgroup.max.depth cgroup.procs cgroup.subtree_control cgroup.type cpu.stat memory.pressure +root@wft-pc:/sys/fs/cgroup/test# echo +memory > cgroup.subtree_control +root@wft-pc:/sys/fs/cgroup/test# ls test +cgroup.controllers cgroup.max.descendants cgroup.threads io.pressure memory.high memory.oom.group memory.swap.events +cgroup.events cgroup.procs cgroup.type memory.current memory.low memory.pressure memory.swap.high +cgroup.freeze cgroup.stat cpu.pressure memory.events memory.max memory.stat memory.swap.max +cgroup.max.depth cgroup.subtree_control cpu.stat memory.events.local memory.min memory.swap.current +root@wft-pc:/sys/fs/cgroup/test# +``` + + + +## 配置iSulad支持cgroup v2 + +内核虽然在4.5版本就正式支持了cgroup v2,但是支持的功能并不全,建议使用尽可能新的内核版本以便支持更多的cgroup子系统。要验证iSulad支持cgroup v2的功能,建议至少使用5.8的内核版本,例如openEuler 21.03创新版本采用5.10的内核版本,可以使用uname -r命令查询内核的版本。iSulad会自动检测当前的cgroup版本,如果系统配置成了只支持cgroup v2并将cgroup v2挂载到/sys/fs/cgroup目录下(系统自动挂载),则iSulad会使用cgroup v2来限制容器的资源。可以在系统的启动命令行参数中配置cgroup_no_v1=all参数表示禁用所有V1的cgroup,这样系统启动时就会只开启cgroup v2并默认将cgroup v2子系统挂载到/sys/fs/cgroup目录下。系统重启后,执行mount | grep cgroup命令,如果已经将cgroup2挂载到了/sys/fs/cgroup,则说明支持cgroup v2的环境配置好了: + +``` +root@wft-pc:~# mount | grep cgroup +cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime) +root@wft-pc:~# +``` + + + +## iSulad使用cgroup v2限制资源 + +### 简单示例: + +1. 以限制内存资源为例,假设我们需要限制单个容器最多使用10M内存,则可以在运行容器时加上-m 10m参数进行限制: + + ``` + root@wft-pc:~# isula run -tid -m 10m busybox sh + dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + root@wft-pc:~# + ``` + + -m 10m表示限制容器内最多只能使用10m内存,可以通过isula stats命令查看资源的限制情况: + + ``` + root@wft-pc:~# isula stats --no-stream dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + CONTAINER CPU % MEM USAGE / LIMIT MEM % BLOCK I / O PIDS + dcea83315b7b 0.00 300.00 KiB / 10.00 MiB 2.93 0.00 B / 0.00 B 1 + root@wft-pc:~# + ``` + + 可以动态更新资源的限制: + + ``` + root@wft-pc:~# isula update -m 20m dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + root@wft-pc:~# isula stats --no-stream dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 + CONTAINER CPU % MEM USAGE / LIMIT MEM % BLOCK I / O PIDS + dcea83315b7b 0.00 300.00 KiB / 20.00 MiB 1.46 0.00 B / 0.00 B 1 + root@wft-pc:~# + ``` + +2. 假设我们要将设备/dev/nvme0n1挂载到容器中成为/dev/sdx并限制为只读设备,则可以这么配置: + + ``` + root@wft-pc:~# isula run -ti --rm --device=/dev/nvme0n1:/dev/sdx:wm busybox fdisk /dev/sdx + fdisk: can't open '/dev/sdx' + root@wft-pc:~# + ``` + + 挂载设备到容器的语法为--device=$host:$container:rwm + $host指定设备在主机上的绝对路径,$container指定设备在容器内的绝对路径,r表示可读,w表示可写,m表示可以创建node + 上述命令中rwm三个参数缺少r参数,也就是说允许写和创建node但是不允许读(即只读)。 + +### 更多资源限制: + +无论是cgroup v1还是cgroup v2,iSulad提供给用户使用的接口都是一致的。不过由于有部分cgroup v1支持的功能在cgroup v2中被去掉了或者实现方式有所变化,因此部分接口在cgroup v2中不可用或者含义发生变化。iSulad支持限制如下资源: + +| 资源 | 功能 | 和cgroup v1的差异 | +| ---------- | ---------------------------------------------- | ------------------------------------------------------------ | +| devices | 限制对应的设备是否可以在容器中访问以及访问权限 | devcies子系统不再使用往cgroup文件里写值的方式进行限制,而是采用ebpf的方式进行限制 | +| memory | 限制容器的内存资源 | 不支持swappiness,不支持kmem相关参数,不支持oom_control | +| cpu/cpuset | 限制容器的cpu资源 | 不支持rt_*相关(实时线程)的限制 | +| blkio/io | 限制容器的块设备io | 不仅限制块设备的IO,也能限制buffer IO | +| hugetlb | 限制大页内存的使用 | 无差异 | +| pids | 限制容器使用的pid | 无差异 | +| files | 限制容器使用的fd | 无差异 | +| freeze | 暂停容器 | 无差异 | + +以上资源限制的用法示例请参考如下脚本中的示例: + +https://gitee.com/openeuler/iSulad/blob/master/CI/test_cases/manual_cases/cgroupv2.sh + + + +## iSulad支持cgroup v2实现原理解析: + + + + + +iSulad的资源限制流程如上图所示。iSulad负责参数的合法性校验,lcr负责生成lxc.conf中对应的lxc可识别的配置,lxc负责解析lxc.conf的参数并将参数配置给容器对应的cgroup的接口文件或使用eBPF方式实现对应的功能。 + +lcr中根据/sys/fs/cgroup文件系统的magic值来判断当前是cgroup v1还是cgroup v2: + +``` +int lcr_util_get_cgroup_version() +{ + struct statfs fs = {0}; + + if (statfs(CGROUP_MOUNTPOINT, &fs) != 0) { + ERROR("failed to statfs %s: %s", CGROUP_MOUNTPOINT, strerror(errno)); + return -1; + } + + if (fs.f_type == CGROUP2_SUPER_MAGIC) { + return CGROUP_VERSION_2; + } else { + return CGROUP_VERSION_1; + } +} +``` + +如果当前是cgroup v2则生成cgroup v2的配置,否则生成cgroup v1的配置: + +``` +static struct lcr_list *trans_oci_resources(const defs_resources *res) +{ + int cgroup_version = 0; + + cgroup_version = lcr_util_get_cgroup_version(); + if (cgroup_version < 0) { + return NULL; + } + + if (cgroup_version == CGROUP_VERSION_2) { + return trans_oci_resources_v2(res); + } else { + return trans_oci_resources_v1(res); + } +} +``` + +lcr生成的cgroup v2的配置如下: + +``` +root@wft-pc:/var/lib/isulad/engines/lcr/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat config | grep cgroup2 +lxc.cgroup2.devices.deny = a *:* rwm +lxc.cgroup2.devices.allow = c *:* m +lxc.cgroup2.devices.allow = b *:* m +lxc.cgroup2.devices.allow = c 1:3 rwm +lxc.cgroup2.devices.allow = c 1:5 rwm +lxc.cgroup2.devices.allow = c 1:7 rwm +lxc.cgroup2.devices.allow = c 5:0 rwm +lxc.cgroup2.devices.allow = c 5:1 rwm +lxc.cgroup2.devices.allow = c 5:2 rwm +lxc.cgroup2.devices.allow = c 1:8 rwm +lxc.cgroup2.devices.allow = c 1:9 rwm +lxc.cgroup2.devices.allow = c 136:* rwm +lxc.cgroup2.devices.allow = c 10:200 rwm +lxc.cgroup2.devices.deny = c 10:229 rwm +lxc.cgroup2.memory.max = 10485760 +lxc.cgroup2.memory.swap.max = 10485760 +root@wft-pc:/var/lib/isulad/engines/lcr/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# +``` + +其中lxc.cgroup2.memory.max = 10485760是根据配置-m 10m生产的,lxc.cgroup2.memory.swap.max = 10485760也是根据这个配置生成的(swap不配置的话默认和内存限制相同),其他的lxc.cgroup2.devices相关参数是lcr为容器配置的默认devices参数。 + +### 通用配置cgroup v2文件的方式实现资源限制 + +大部分的配置,lxc根据lxc.conf中的配置,将配置写入容器对应的cgroup目录下对应的文件即可实现对资源的限制: + +``` +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# pwd +/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat memory.max +10485760 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# cat memory.swap.max +10485760 +root@wft-pc:/sys/fs/cgroup/isulad/dcea83315b7b23d094f629f397c196df6e59be9e9fcd4774afa8428f078338a3# +``` + +注意容器的cgroup目录为/sys/fs/cgroup/isulad/$container_id,而文件则为lxc.conf配置文件中的配置去掉"lxc.cgroup2."前缀后的值,例如lxc.cgroup2.memory.max配置对应的文件为memory.max + +剩下的就交给内核了,内核会更据cgroup的配置来实现对该资源的限制。 + +### 使用eBPF实现cgroup v2的devices资源限制 + +前面介绍过,部分cgroup v2的资源限制是通过ebpf来实现的,iSulad使用的资源中,devices就是通过ebpf来实现资源限制的,也就是前面的lxc.cgroup2.devices.开头的那些配置。下面我们来介绍一下如何通过eBPF方式实现devices资源限制。 + + + +ebpf不需要重新编译内核,也不需要加载内核模块,就可以动态地将一段字节码加载到内核中执行,从而使用内核的数据进行数据的观测或限制。和linux内核模块(LKM)不同的是,ebpf不像LKM一样直接不受限地访问内核的资源,而是采用类似虚拟机的机制,在隔离环境中执行代码。eBPF运行过程如下: + +1. 用户编写eBPF程序,eBPF程序通常是一小段汇编代码,用于实现用户自定义的功能,例如进行内核数据的观察或者进行控制权限过滤等。实现cgroup v2的devices功能时,就是由lxc代码中编写的一小段汇编程序用于实现设备的过滤功能。 + +2. eBPF被真正加载前,验证器会对eBPF程序进行严格的验证。验证器会根据代码生成有向无环图并进行验证,确保程序合法,合法的程序必须没有递归,没有控制循环,没有无法到达的指令,指令条数在允许的范围内,指令不会超过程序界限。除了基本的校验外,验证器还会分析程序执行的每条指令进行预执行。验证通过后eBPF程序会被编译成机器代码用于执行。 + +3. eBPF程序加载时需要指定程序附加的执行点,执行点是根据eBPF程序的类型决定的,eBPF程序根据指定的类型被挂接到指定的内核事件上,当有对应的内核事件产生时,就会执行eBPF机器代码。cgroup v2的devices功能的eBPF程序的类型是BPF_PROG_TYPE_CGROUP_DEVICE,加载点是/sys/fs/cgroup/isulad/$container_id。 + +4. lxc在创建容器时,根据lxc.conf中的lxc.cgroup2.devices.*相关配置,生成eBPF程序并attach到容器的cgroup根文件夹,从而实现对容器内设备权限的过滤。lxc在销毁容器时,卸载eBFP程序。 + + diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/1.jpg" "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/1.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..675d9ed7f44cd0765a2d729c0148cda84cc2ba70 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/1.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/2.jpg" "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/2.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..99bb1eebd895fceee1cedb64cb152b38aa803785 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/2.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/3.jpg" "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/3.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..5dbc79a5b8a2a91e531d12c1b5fd7e6262069eae Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/3.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc+locale\344\275\277\347\224\250\347\256\200\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc+locale\344\275\277\347\224\250\347\256\200\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..fb797f55eab56e0ce15b9ab88ef599d08e08503b --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc+locale\344\275\277\347\224\250\347\256\200\346\236\220.md" @@ -0,0 +1,292 @@ +--- +title: glibc locale使用简析 +date: 2021-03-10 +tags: + - glibc + - locale +archives: 2021-03 +author: wangshuo +summary: 介绍glibc locale的使用方法 +--- + +# 1 概述 +IBM社区曾有篇名为《glibc与Linux 的国际化与本地化机制》的帖子(链接:https://cutt.ly/KzjZUxW ),详细介绍了glibc的国际化和本地化的相关知识,本文将在此基础上这次将结合openEuler glibc及其子包提供的文件详细说明glibc locale相关的使用方法。

+软件信息如下: +|
软件项
|
版本信息
| +| :------------------------------------:| :------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +
+ +# 2 功能介绍 +这部分我们从文件粒度、用户使用粒度和rpm包粒度来说明,具体内容见下图: +
+
+ +## 2.1 文件层面 +文件层面,各个模块的功能如下: +
+
+ +## 2.2 用户层面 +用户使用层面,各个模块的功能如下: +
+
+ +## 2.3 rpm包层面 +rpm包层面,各个模块的功能如下: +
+
+ +图中各个层面都已有大致的介绍,在此不再加文字赘述。 +

+ +# 3 常用功能 +## 3.1 本地化 +通俗地讲,locale就是本地交互环境的呈现形式,再通俗的说,就是shell界面显示哪种语言,哪种组织形式,让我们通过具体案例来认识locale。 +
+ +### 3.1.1 locale与子语言包 +直接敲locale命令: +``` +$ locale +LANG=en_US.UTF-8 +LC_CTYPE="en_US.UTF-8" +LC_NUMERIC="en_US.UTF-8" +LC_TIME="en_US.UTF-8" +LC_COLLATE="en_US.UTF-8" +LC_MONETARY="en_US.UTF-8" +LC_MESSAGES="en_US.UTF-8" +LC_PAPER="en_US.UTF-8" +LC_NAME="en_US.UTF-8" +LC_ADDRESS="en_US.UTF-8" +LC_TELEPHONE="en_US.UTF-8" +LC_MEASUREMENT="en_US.UTF-8" +LC_IDENTIFICATION="en_US.UTF-8" +LC_ALL=en_US.UTF-8 +``` + +可以看出,locale按照将文化传统的各个方面分成12个大类,这12个大类分别是: +``` +1、语言符号及其分类(LC_CTYPE) +2、数字(LC_NUMERIC) +3、比较和排序习惯(LC_COLLATE) +4、时间显示格式(LC_TIME) +5、货币单位(LC_MONETARY) +6、信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES) +7、姓名书写方式(LC_NAME) +8、地址书写方式(LC_ADDRESS) +9、电话号码书写方式(LC_TELEPHONE) +10、度量衡表达方式 (LC_MEASUREMENT) +11、默认纸张尺寸大小(LC_PAPER) +12、对locale自身包含信息的概述(LC_IDENTIFICATION) +``` + +所以说,locale就是某一个地域内的人们的语言习惯和文化传统和生活习惯。一个地区的locale就是根据这几大类的习惯定义的,这些locale定义文件放在 /usr/share/i18n/locales 目录下面,例如en_US, zh_CN and de_DE@euro都是locale的定义文件。
+ +通过修改环境变量即可修改locale,比如: +``` +# echo $LANG +en_US.UTF-8 +# LANG="zh_CN.UTF-8" + +``` +我们修改了LANG这个环境变量,这时候输入date命令: +``` +# date +2021年 03月 09日 星期二 11:11:02 CST +``` + +已经成功将loacle变成中文了,但是如果随便一个--help(例如iconv --help)发现还是英文,这是为什么? +``` +# iconv --help +Usage: iconv [OPTION...] [FILE...] +Convert encoding of given files from one encoding to another. + + Input/Output format specification: + -f, --from-code=NAME encoding of original text + -t, --to-code=NAME encoding for output + + Information: + -l, --list list all known coded character sets + + Output control: + -c omit invalid characters from output + -o, --output=FILE output file + -s, --silent suppress warnings + --verbose print progress information + + -?, --help Give this help list + --usage Give a short usage message + -V, --version Print program version + +Mandatory or optional arguments to long options are also mandatory or optional +for any corresponding short options. + +For bug reporting instructions, please see: +. +``` +这就需用到glibc的子语言包了,具体来说,我们需要安装glibc-langpack-zh子语言包,我们可以先把这个包解压开来看看有什么: +``` +. +└── usr +   ├── lib + │   └── locale +   └── share + └── locale +``` + +/usr/lib/locale这个位置是不是很熟悉,没错,就是放置locale-archive文件的目录,在2.1小节的图中其实有提到“语言_地域”文件夹所对应的每个子语言包提供的/usr/lib/locale下的文件实际上和全量locale-archive是有交叉的。 +
+ +继续分析子语言包,另一个/usr/share/locale目录下实际上是一个mo文件,名字为libc,而glibc作为基础库主要提供的文件就是 libc.so,这下其实很明朗了,我们刚才输入的iconv命令是glibc提供的,而子语言包也提供了一个以libc命名的mo文件,因此只有安装了提供命令本地化的语言包,glibc提供的命令本地化才能生效。对其他命令来说也是这个道理,一般mo文件会由命令所属的rpm包一并提供。比如我们一直使用的date命令,该命令由coreutils包提供,我们通过rpm -ql列出coreutils包提供的文件可以发现其提供了本地化所需的mo文件,因此我们在通过LANG修改当前的环境信息后,就可以使date命令显示我们需要的语言了。 +``` +# rpm -ql coreutils | grep mo +... +/usr/share/locale/zh_CN/LC_MESSAGES/coreutils.mo +/usr/share/locale/zh_CN/LC_TIME/coreutils.mo +... +``` +
+ +安装glibc-langpack-zh包再试一下,已显示中文。 +``` +# iconv --help +用法: iconv [选项...] [文件...] +转换给定文件的编码。 + + 输入/输出格式规范: + -f, --from-code=名称 原始文本编码 + -t, --to-code=名称 输出编码 + + 信息: + -l, --list 列举所有已知的字符集 + + 输出控制: + -c 从输出中忽略无效的字符 + -o, --output=文件 输出文件 + -s, --silent 关闭警告 + --verbose 打印进度信息 + + -?, --help 给出此帮助列表 + --usage 给出简要的用法信息 + -V, --version 打印程序版本号 + +长选项的强制或可选参数对对应的短选项也是强制或可选的。 + +要知道错误报告指令,请参看: +。 +``` +
+ +我们来总结一下,/usr/share/locale目录提供了包括glibc本身在内的各个包本地化相关的mo文件夹,后续mo文件由rpm来提供,配合LANG环境变量即可实现命令的本地化。 +

+ +### 3.1.2 locale-archive +经常有人会问,locale-archive是什么?能不能删?这么大,能不能裁?我在网上找了很久也没找到locale-archive的定义。不妨通俗地给它下个定义:locale-archive是fedora系的glibc提供的一种本地化缓存,未裁剪的全量locale-archive,等效于所有子语言包提供的/usr/lib/locale/目录下文件的集合。 +
+ +举个例子就好懂了,假设我们把locale-archive给mv走,然后修改LANG会怎么样? +``` +# pwd +/usr/lib/locale +# mv locale-archive bak +# LANG="zh_CN.UTF-8" +# date +Wed Mar 10 09:21:27 CST 2021 +``` +此时,我们试图修改成中文环境,但没有生效。如果安装了glibc-langpack-zh子语言包呢? +``` +# date +2021年 03月 10日 星期三 09:22:59 CST +``` +修改生效了,我们卸载掉中文子语言包,把locale-archive给mv回来 +``` +# pwd +/usr/lib/locale +# mv bak locale-archive +# LANG="zh_CN.UTF-8" +# date +2021年 03月 10日 星期三 09:24:17 CST +``` + +同样生效了,好了,破案了。其实glibc在spec中已经申明了,当你安装了所需的子语言包,实际上可以卸载掉all-langpacks这个包,即去掉locale-archive这个文件来节省空间。 +``` +glibc.spec + +# The glibc-all-langpacks provides the virtual glibc-langpack, +# and thus satisfies glibc's requirement for installed locales. +# Users can add one more other langauge packs and then eventually +# uninstall all-langpacks to save space. +%package all-langpacks +Summary: All language packs for %{name}. +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} +Provides: %{name}-langpack = %{version}-%{release} +%description all-langpacks +``` +
+ +这里附上locale-archive的裁剪方法:
+step1、列出当前环境中的所有locale +``` +# localedef --list-archive +``` +step2、指定需要裁剪的locale +``` +# localedef --delete-from-archive [待裁剪locale] +``` +step3、用当前的locale-archive覆盖locale-archive.tmpl +``` +# mv /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl +``` +step4、重新生成locale-archive +``` +# build-locale-archive +``` +
+ +例如:裁剪掉非英文支持 +``` +# localedef --list-archive | grep -v -i ^en | xargs localedef --delete-from-archive +# mv /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl +# build-locale-archive +``` +注意:执行build-locale-archive后,可能出现ssh断掉的现象,重新连接即可 +

+ +## 3.2 国际化 +所谓国际化指的是一个程序或软件可给特定的人群使用而无须修改或重新编译源代码。glibc提供了两个相关的命令(iconv/iconvconfig)和三个接口(iconv_open、iconv和iconv_close),这部分网上有很详细的资料,这里首推《字符编码知识简介和iconv函数的简单使用》这篇帖子(链接:https://cutt.ly/HzcP6nG ),具体作用不再赘述,这里仅稍微补充一点:/usr/lib64/gconv/目录(也可能在/usr/lib/gconv目录)下的文件,其使用逻辑为:iconv接口通过gconv-modules.cache来加载对应so做转码操作,而gconv-modules.cache由iconvconfig命令读取gconv-modules文件来生成。 +

+ +# 4 参考资料 +1、浅析 Linux 的国际化与本地化机制: +https://cutt.ly/KzjZUxW + +2、字符编码知识简介和iconv函数的简单使用: +https://www.cnblogs.com/qingergege/p/7491590.html + +3、locale localedef --之Linux字符集理解: +https://www.cnblogs.com/wn1m/p/10837609.html + +4、捣鼓一下linux下的locale: +http://www.360doc.com/content/15/1105/08/14513665_510854234.shtml + +5、locale的设定及其LANG、LC_ALL、LANGUAGE环境变量的区别: +https://cutt.ly/DzjXdvr + +6、GNU官方关于gconv-modules文件作用以及iconv转码方式的讲解: +https://cutt.ly/5zjXoOr +

+ +# glibc相关文章推荐 +glibc malloc系列文章:
+    原理简析:https://cutt.ly/NzcDUEd
+    数据结构:https://cutt.ly/JzcSBfB
+    malloc:https://cutt.ly/TzcSjUX
+    free:https://cutt.ly/QzcSy5G
+ +glibc问题定位与分析系列文章:
+    memcpy 1k字节x86_64虚拟机性能下降分析:https://cutt.ly/8zcDyPi
diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc\350\257\255\350\250\200\345\255\227\347\254\246.jpg" "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc\350\257\255\350\250\200\345\255\227\347\254\246.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..565c26a9c605af8a40a073a8553e90281ceac5cf Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc locale\344\275\277\347\224\250\347\256\200\346\236\220/glibc\350\257\255\350\250\200\345\255\227\347\254\246.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/allocated-chunk.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/allocated-chunk.png" new file mode 100644 index 0000000000000000000000000000000000000000..96aa67d1fffb18029069420ee70b2571a41c3630 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/allocated-chunk.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-multi-segments.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-multi-segments.png" new file mode 100644 index 0000000000000000000000000000000000000000..458e755613517c0e1b573d9ad763ffdd1656f9f6 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-multi-segments.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-single-segment.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-single-segment.png" new file mode 100644 index 0000000000000000000000000000000000000000..03eadd371735f6469d0c84fb357886ad317b57ed Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/arena-single-segment.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/fast-bin.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/fast-bin.png" new file mode 100644 index 0000000000000000000000000000000000000000..66734e914fe438b08582e3c38512db0a43aa3838 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/fast-bin.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/free-chunk.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/free-chunk.png" new file mode 100644 index 0000000000000000000000000000000000000000..eb7ddd6989ac7fb2a84fd639164e2e5605b2e29e Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/free-chunk.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..83f23621676ddf8b3614ddec5c5efe01aed61207 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220.md" @@ -0,0 +1,139 @@ +--- +title: glibc malloc原理简析 +date: 2021-01-27 +tags: + - glibc + - malloc +archives: 2021-01 +author: wangshuo +summary: 介绍glibc malloc原理 +--- + +# 1 概述 +内存分配器ptmalloc,即glibc中的malloc,实现了 malloc(),free()以及一组其它的函数,以提供动态内存管理的支持。分配器处在用户程序和内核之间,它响应用户的分配请求,向操作系统申请内存,然后将其返回给用户程序。 +为了保持高效的分配,分配器一般都会预先分配一块大于用户请求的内存,并通过某种算法管理这块内存。来满足用户的内存分配要求,用户释放掉的内存也并不是立即就返回给操作系统,相反,分配器会管理这些被释放掉的空闲空间,以应对用户以后的内存分配要求。也就是说,分配器不但要管理已分配的内存块,还需要管理空闲的内存块,当响应用户分配要求时,分配器会首先在空闲空间中寻找一块合适的内存给用户,在空闲空间中找不到的情况下才分配一块新的内存。 +

+ +# 2 malloc数据结构 +## 2.1 内存管理结构 +### 2.1.1 chunk +chunk原意是块,用在内存中表示的意思就是一块内存,chunk是glibc内存管理的最小单位,其数据结构如下图所示 +
+ +chunk中几个关键的成员有prev_size、mchunk_size、fd和bk,其作用分别为:
+
prev_size:
如果前一个chunk是free chunk,则这个内容保存的是前一个chunk的大小。 如果前一个chunk是allocated chunk,则这个区域保存的是前一个chunk的用户数据; + +
mchunk_size:
+当前chunk的大小。最后的 3 位作为标志位,具体为:
第0比特位用于表示前一个chunk是否为allocated chunk,而当前是不是chunk allocated可以通过查询下一个chunk的这个标志位来得知;
第1比特位用于标记该chunk是否是通过系统调用申请的(子线程是mmap,主线程则是通过 brk)。如果是,则该chunk不再由后续将会介绍的内存管理数据结构来标记,申请释放流程将简化;
第2比特位用于标记该chunk是否属于主分配区,关于分配区将在下文详细介绍。 + +
fd:
前向指针,即指向当前chunk在同一个bin的下一个chunk的指针,仅chunk未使用的时候存在。 + +
bk:
后向指针,即指向当前chunk在同一个bin的上一个chunk的指针,仅chunk未使用的时候存在。 + +### 2.1.2 arena +arena一般称为分配区,是一个结构体,内含指向各自类型内存块的指针等元素,每个线程在申请内存时会获取一个。分配区分为主分配区和thread分配区,前者仅有一个,其余均为thread分配区。当新创建的线程需要申请内存时,将从一个全局的链表中获取一个空闲的分配区,如果没有得到且分配区数量没有超过最大值(M_ARENA_MAX),malloc将会新建一个。 +

+ +### 2.2.3 heap +heap包括帧头和内存块, glibc以heap为单位从操作系统批量申请和释放内存。 +主分配区有一个heap,thread分配区在刚创建时也只有一个,当超过一定大小时会新增heap,heap直接以链表形式相连,数量没有限制,单个heap最大默认64M。新建heap时里面只有一个chunk,称为top chunk,每次申请内存时都会从top chunk中分裂出一块chunk,而top chunk本身则始终位于heap的末端。 + +下图是只有一个heap的main arena和thread arena的内存分布图: +
+下图是一个thread arena中含有多个heap的情况: +
+从以上两图可以看出,thread arena只含有一个arena,却有两个heap_info(即 heap header)。由于两个heap是通过mmap从操作系统申请的内存,两者在内存布局上并不相邻而是分属于不同的内存区间,所以为了便于管理,glibc的malloc将第二个heap_info结构体的prev成员指向了第一个heap_info结构体的起始位置(即ar_ptr成员),而第一个heap_info结构体的ar_ptr成员指向了arena,这样就构成了一个单链表,方便后续管理。 +

+ +## 2.2 内存管理链表 +glibc提供了几种链表来管理不同大小的chunk。其中,除tcache外,其余均为arena结构体中的成员变量。 +

+ +### 2.2.1 tcache +tcache是glibc为了提升小块内存申请释放性能引入的缓存机制。单个tcache有64个链表项,每一项里面最多可保存7块大小相同的chunk,tcache链表本身的数据结构从分配区管理的heap中申请,线程退出时释放回原heap,由于tcache是线程变量,每个线程都会有一个自己的tcache,因此理论上数量无上限。 +

+ +### 2.2.2 fastbin +fastbin为管理小块chunk(64位为160字节)的链表,应对频繁申请小块内存的场景。链表项管理的chunk值按一定规律递增,可通过一定的算法算出指定大小的chunk所在的链表项索引,从而找到对应大小的chunk。 +
+

+ +### 2.2.3 unsortedbin +fastbin中整合的chunk和small chunk、 large chunk free之后的chunk被放入unsortedbin,加速内存申请释放,unsortedbin管理的chunk值无规律。 +
+

+ +### 2.2.4 smallbin、largebin +smallbin和largebin管理的chunk值按一定规律递增,可通过一定的算法算出指定大小的chunk所在的链表项索引,从而找到对应大小的chunk。 +

+# 3 malloc原理分析 +## 3.1 malloc缓存模型 +为了兼顾性能和内存占用,glibc的malloc通过一系列的内存管理链表实现了一套复杂的内存缓存机制,其基本思想可以由如下两图概括。 +
+可以看出,当用户需要申请内存时,malloc会先向操作系统申请一个heap,然后对该heap进行切分,根据切分后的内存块的大小交由不同的链表管理。在后续内存申请时,会按照tcache→fastbin→unsortedbin→smallbin/largebin的顺序来获取内存。内存释放过程则与此相反。 +

+ +## 3.2 malloc工作流程 +### 3.2.1 内存申请流程 + +
+

+ +### 3.2.2 内存释放流程 +
+

+ +# 4 参数配置 +## 4.1 参数列表 +glibc提供了一系列的可调参数,用户可以通过设置环境变量的方式调节这些参数从而改变malloc的一些行为。 + +| 参数名 | 默认值 | 取值范围 | 作用 | +| :----: | :----: | :----: | :---- | +|
M_MMAP_MAX
|
65536
|
>= 0
|
使用mmap分配的最大chunk数,取0时,相当于不使用mmap功能
| +|
M_MMAP_THRESHOLD
|
128 * 1024(字节)
|
0 ~ 32M
|
所有大于该值的chunk都使用mmap分配内存。如果未设置此参数且未禁用动态调整时,该值将会被动态调整,具体表现为如果上次申请的内存大于该值,则该值将随之增大;如果用户手动设置了这一参数,则将同时禁用动态调整,该值始终保持不变。
| +|
M_TOP_PAD
|
0 |
-
|
内存申请和释放时额外保留的内存量,避免过多的系统调用
| +|
M_TRIM_THRESHOLD
|
128 * 1024(字节)
|
-
|
收缩阈值,当arena的top值超过收缩阈值将触发收缩操作把多余的内存还给操作系统。如果未设置此参数且未禁用动态调整时,该值将会被动态调整,具体表现为当M_MMAP_THRESHOLD更新时,该值随之更新为前者的两倍;如果用户手动设置了这一参数,则将同时禁用动态调整,该值始终保持不变。
| +|
M_ARENA_MAX
|
CPU核数 * 8
|
-
|
arena最大数量
| +|
M_ARENA_TEST
|
8
|
-
|
限制arena数量,只有当进程现有的arena不足且需求量超过M_ARENA_TEST时才会触发修改arena数量上限的动作。如果设置了M_ARENA_MAX,将忽略M_ARENA_TEST
| +|
tcache_count
|
7
|
>= 0
|
设置tcache的链表bin数量,当取0时,多余的chunk不会放到tcache里面,相当于关闭了tcache,如:
```export GLIBC_TUNABLES=glibc.malloc.tcache_count=0```
| +|
tcache_unsorted_limit
|
0
|
>= 0
|
限制tcache从unsorted bin中获取chunk的数量,当取0时,不做限制
| +|| + +

+## 4.2 使用环境变量设置参数 +### 4.2.1 兼容模式环境变量 +这一方式与低于2.26版本的glibc兼容,但是没有tcache相关的设置。 +示例: +``` +# export MALLOC_ARENA_MAX=1 +``` + +

+### 4.2.2 tunables模式环境变量 +这一方式适用于2.26及以上的glibc版本,默认使用 + +示例: +``` +# GLIBC_TUNABLES=glibc.malloc.mmap_max=1:glibc.malloc.top_pad=1 +``` +

+# 5 调测工具 +malloc_stats是glibc提供的一个可用统计本进程具体的内存使用情况的接口,精确到字节, malloc_stats()函数声明如下: +``` +#include +#include +void malloc_stats(void); +``` + +malloc_stats()可以在编写代码时加入编译宏来使用,也可以在gdb中直接调用。malloc_stats()执行结果如下: + +``` +Arena 0: //分配区编号,这里只有一个线程 +system bytes = 135168 //本线程从操作系统获得的动态内存,这里是132KB +in use bytes = 1152 //本线程在使用的动态内存,1152字节 +Total (incl. mmap): //总的使用情况,各个线程使用动态内存的累加值 +system bytes = 135168 //本进程从操作系统获得的动态内存,这里是132KB +in use bytes = 1152 //本进程在使用的动态内存,1152字节 +max mmap regions = 0 //使用mmap区域的个数 +max mmap bytes = 0 //mmap区域对应内存大小 +``` diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/main arena.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/main arena.png" new file mode 100644 index 0000000000000000000000000000000000000000..f3bf347373684e69fe73ba1f5ee74cbf7e4fcadc Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/main arena.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/thread arena.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/thread arena.png" new file mode 100644 index 0000000000000000000000000000000000000000..7f9d3cd3d9ce74020cde4598a99c8a06a9c5f1c7 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/thread arena.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/unsorte small large.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/unsorte small large.png" new file mode 100644 index 0000000000000000000000000000000000000000..d73cc0287ebece4ac26e854a34c239a0575e14c3 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/unsorte small large.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\347\224\263\350\257\267\346\265\201\347\250\213.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\347\224\263\350\257\267\346\265\201\347\250\213.png" new file mode 100644 index 0000000000000000000000000000000000000000..1fea3b9950d43d8d7ee6a9186b95ce436cb56994 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\347\224\263\350\257\267\346\265\201\347\250\213.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\351\207\212\346\224\276\346\265\201\347\250\213.png" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\351\207\212\346\224\276\346\265\201\347\250\213.png" new file mode 100644 index 0000000000000000000000000000000000000000..69fad7eedb727ca0379b254aba6a0afb7004b05a Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\345\216\237\347\220\206\347\256\200\346\236\220/\351\207\212\346\224\276\346\265\201\347\250\213.png" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\270\211).md" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\270\211).md" new file mode 100644 index 0000000000000000000000000000000000000000..f02f3441641f117de6808835ad5e21a9ad46d1ce --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\270\211).md" @@ -0,0 +1,689 @@ +--- +title: glibc malloc源码简析(三) +date: 2021-03-01 +tags: + - glibc + - malloc +archives: 2021-03 +author: wangshuo +summary: 结合源码进一步分析glibc malloc原理,本文对free的代码流程进行分析。 +--- +# 1 前言 +在上一篇文章中我们了解了glibc malloc执行流程,本文将结合glibc源码介绍free的执行流程。 + +软件信息如下: +|
软件项
|
版本信息
| +| :------------------------------------:| :------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +
+ +# 2 free执行流程分析 +## 2.1 整体流程 +glibc free的整体流程如下: +``` +void +__libc_free (void *mem) +{ + mstate ar_ptr; + mchunkptr p; /* chunk corresponding to mem */ + + void (*hook) (void *, const void *) + = atomic_forced_read (__free_hook); + if (__builtin_expect (hook != NULL, 0)) + { + (*hook)(mem, RETURN_ADDRESS (0)); + return; + } + + if (mem == 0) /* free(0) has no effect */ + return; + + p = mem2chunk (mem); + + if (chunk_is_mmapped (p)) /* release mmapped memory. */ + { + /* See if the dynamic brk/mmap threshold needs adjusting. + Dumped fake mmapped chunks do not affect the threshold. */ + if (!mp_.no_dyn_threshold + && chunksize_nomask (p) > mp_.mmap_threshold + && chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX + && !DUMPED_MAIN_ARENA_CHUNK (p)) + { + mp_.mmap_threshold = chunksize (p); + mp_.trim_threshold = 2 * mp_.mmap_threshold; + LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2, + mp_.mmap_threshold, mp_.trim_threshold); + } + munmap_chunk (p); + return; + } + + MAYBE_INIT_TCACHE (); + + ar_ptr = arena_for_chunk (p); + _int_free (ar_ptr, p, 0); +} +libc_hidden_def (__libc_free) +``` +
+ +首先查看是否有__free_hook函数,如果有就直接调用,这个钩子与《glibc malloc源码分析(二)》中的__malloc_hook是成对出现的,目的同样是实现mtrace调测功能。接下来通过mem2chunk将虚拟内存的指针mem转换为对应的chunk指针p。 +``` +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) +``` +
+接下来,chunk_is_mmapped用来检查size最低三位中的标志位,判断该chunk是否是由mmap分配的,如果是,就调用munmap_chunk释放该chunk并返回,在调用munmap_chunk之前,需要更新全局的mmap阀值和收缩阀值。
+接下来又碰到MAYBE_INIT_TCACHE这个宏,其定义如下,可以看出,在开启了tcache的情况下,这部分代码是基本上不会执行到的。增加这个的目的也是为后续内存优先放入tcache做铺垫。 + +``` +# define MAYBE_INIT_TCACHE() \ + if (__glibc_unlikely (tcache == NULL)) \ + tcache_init(); + +#else /* !USE_TCACHE */ +# define MAYBE_INIT_TCACHE() +``` +
+ +再往下,如果该chunk不是由mmap分配的,就通过arena_for_chunk获得分配区指针ar_ptr,其定义如下: +``` +#define arena_for_chunk(ptr) \ + (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr) +``` +
+ +获得了分配区的指针后便调用_int_free释放内存。_int_free将在下文详细分析,这里先分析一下munmap_chunk函数,源码如下: +``` +static void +munmap_chunk (mchunkptr p) +{ + INTERNAL_SIZE_T size = chunksize (p); + + assert (chunk_is_mmapped (p)); + + /* Do nothing if the chunk is a faked mmapped chunk in the dumped + main arena. We never free this memory. */ + if (DUMPED_MAIN_ARENA_CHUNK (p)) + return; + + uintptr_t block = (uintptr_t) p - prev_size (p); + size_t total_size = prev_size (p) + size; + /* Unfortunately we have to do the compilers job by hand here. Normally + we would test BLOCK and TOTAL-SIZE separately for compliance with the + page size. But gcc does not recognize the optimization possibility + (in the moment at least) so we combine the two values into one before + the bit test. */ + if (__builtin_expect (((block | total_size) & (GLRO (dl_pagesize) - 1)) != 0, 0)) + malloc_printerr ("munmap_chunk(): invalid pointer"); + + atomic_decrement (&mp_.n_mmaps); + atomic_add (&mp_.mmapped_mem, -total_size); + + /* If munmap failed the process virtual memory address space is in a + bad shape. Just leave the block hanging around, the process will + terminate shortly anyway since not much can be done. */ + __munmap ((char *) block, total_size); +} +``` +
+ +munmap_chunk函数首先获得前一个chunk的指针block,计算这两个chunk的size之和至total_size,接着对全局结构mp_进行相应的设置后,就通过__munmap释放这两个chunk。根据malloc的源码可知,由mmap分配的chunk是独立的,大部分情况下,p->prev_size为0,因此这里还是释放一个chunk,特殊情况下需要释放两个chunk,特殊情况请参考_int_malloc中的代码。__munmap再往下就是系统调用了,这里不多赘述。 +

+ +## 2.2 _int_free +_int_free是glibc free的核心函数,这里依旧分步来分析其源码。
+第一部分源码如下,我们仍然先忽略掉tcache进行分析。 +``` +static void +_int_free (mstate av, mchunkptr p, int have_lock) +{ + + ... + + size = chunksize (p); + + /* Little security check which won't hurt performance: the + allocator never wrapps around at the end of the address space. + Therefore we can exclude some size values which might appear + here by accident or by "design" from some intruder. */ + if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0) + || __builtin_expect (misaligned_chunk (p), 0)) + malloc_printerr ("free(): invalid pointer"); + /* We know that each chunk is at least MINSIZE bytes in size or a + multiple of MALLOC_ALIGNMENT. */ + if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size))) + malloc_printerr ("free(): invalid size"); + + check_inuse_chunk(av, p); + +#if USE_TCACHE + + ... + +#endif + + /* + If eligible, place chunk on a fastbin so it can be found + and used quickly in malloc. + */ + + if ((unsigned long)(size) <= (unsigned long)(get_max_fast ()) + +#if TRIM_FASTBINS + /* + If TRIM_FASTBINS set, don't place chunks + bordering top into fastbins + */ + && (chunk_at_offset(p, size) != av->top) +#endif + ) { + + if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size)) + <= 2 * SIZE_SZ, 0) + || __builtin_expect (chunksize (chunk_at_offset (p, size)) + >= av->system_mem, 0)) + { + bool fail = true; + /* We might not have a lock at this point and concurrent modifications + of system_mem might result in a false positive. Redo the test after + getting the lock. */ + if (!have_lock) + { + __libc_lock_lock (av->mutex); + fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ + || chunksize (chunk_at_offset (p, size)) >= av->system_mem); + __libc_lock_unlock (av->mutex); + } + + if (fail) + malloc_printerr ("free(): invalid next size (fast)"); + } + + free_perturb (chunk2mem(p), size - 2 * SIZE_SZ); + + atomic_store_relaxed (&av->have_fastchunks, true); + unsigned int idx = fastbin_index(size); + fb = &fastbin (av, idx); + + /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ + mchunkptr old = *fb, old2; + + if (SINGLE_THREAD_P) + { + /* Check that the top of the bin is not the record we are going to + add (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + malloc_printerr ("double free or corruption (fasttop)"); + p->fd = old; + *fb = p; + } + else + do + { + /* Check that the top of the bin is not the record we are going to + add (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + malloc_printerr ("double free or corruption (fasttop)"); + p->fd = old2 = old; + } + while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) + != old2); + + ... + + } + + ... + +} +``` +
+ +首先是检查size变量的合法性,然后比较get_max_fast()判断size是否在fastbin的范围内,如果在fastbin的管理范围内,就通过set_fastchunks设置分配区的标志位表示fastbin有空闲chunk,接下来根据size获得即将添加的chunk在fastbin中的索引idx,并通过该索引获得头指针fb,最后通过CAS操作将该chunk添加到fastbin中。这里需要注意fastbin中存放的chunk是按照单向链表组织的。
+tcache宏中的内容如下,读过上文的话应该一下子就能大致猜出这段的逻辑,即:将符合条件的内存放入tcache。因此不多赘述。 +``` +#if USE_TCACHE + { + size_t tc_idx = csize2tidx (size); + if (tcache != NULL && tc_idx < mp_.tcache_bins) + { + /* Check to see if it's already in the tcache. */ + tcache_entry *e = (tcache_entry *) chunk2mem (p); + + /* This test succeeds on double free. However, we don't 100% + trust it (it also matches random payload data at a 1 in + 2^ chance), so verify it's not an unlikely + coincidence before aborting. */ + if (__glibc_unlikely (e->key == tcache)) + { + tcache_entry *tmp; + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); + for (tmp = tcache->entries[tc_idx]; + tmp; + tmp = tmp->next) + if (tmp == e) + malloc_printerr ("free(): double free detected in tcache 2"); + /* If we get here, it was a coincidence. We've wasted a + few cycles, but don't abort. */ + } + + if (tcache->counts[tc_idx] < mp_.tcache_count) + { + tcache_put (p, tc_idx); + return; + } + } + } +#endif +``` +
+ +第二部分代码如下,如果将要释放的chunk不属于fastbin,且不是由mmap分配的,就首先获得下一个chunk的指针nextchunk和大小nextsize,如果前一个chunk空闲,就和前一个chunk合并,并通过unlink将该chunk从空闲链表中脱离。接下来,如果刚才前面取出的下一个chunk也为空闲,并且该chunk不是top chunk,则继续合并,否则将其设为空闲。再往下,就是取出unsortedbin的头指针,将合并后的chunk插入unsortedbin链表头部,并进行相应的设置。如果下一个chunk为top chunk,就将要释放的chunk合并到top chunk中。 +``` +static void +_int_free (mstate av, mchunkptr p, int have_lock) +{ + + ... + + if ((unsigned long)(size) <= (unsigned long)(get_max_fast ()) { + ... + } + else if (!chunk_is_mmapped(p)) { + + /* If we're single-threaded, don't lock the arena. */ + if (SINGLE_THREAD_P) + have_lock = true; + + if (!have_lock) + __libc_lock_lock (av->mutex); + + nextchunk = chunk_at_offset(p, size); + + /* Lightweight tests: check whether the block is already the + top block. */ + if (__glibc_unlikely (p == av->top)) + malloc_printerr ("double free or corruption (top)"); + /* Or whether the next chunk is beyond the boundaries of the arena. */ + if (__builtin_expect (contiguous (av) + && (char *) nextchunk + >= ((char *) av->top + chunksize(av->top)), 0)) + malloc_printerr ("double free or corruption (out)"); + /* Or whether the block is actually not marked used. */ + if (__glibc_unlikely (!prev_inuse(nextchunk))) + malloc_printerr ("double free or corruption (!prev)"); + + nextsize = chunksize(nextchunk); + if (__builtin_expect (chunksize_nomask (nextchunk) <= 2 * SIZE_SZ, 0) + || __builtin_expect (nextsize >= av->system_mem, 0)) + malloc_printerr ("free(): invalid next size (normal)"); + + free_perturb (chunk2mem(p), size - 2 * SIZE_SZ); + + /* consolidate backward */ + if (!prev_inuse(p)) { + prevsize = prev_size (p); + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size while consolidating"); + unlink(av, p, bck, fwd); + } + + if (nextchunk != av->top) { + /* get and clear inuse bit */ + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + + /* consolidate forward */ + if (!nextinuse) { + unlink(av, nextchunk, bck, fwd); + size += nextsize; + } else + clear_inuse_bit_at_offset(nextchunk, 0); + + /* + Place the chunk in unsorted chunk list. Chunks are + not placed into regular bins until after they have + been given one chance to be used in malloc. + */ + + bck = unsorted_chunks(av); + fwd = bck->fd; + if (__glibc_unlikely (fwd->bk != bck)) + malloc_printerr ("free(): corrupted unsorted chunks"); + p->fd = fwd; + p->bk = bck; + if (!in_smallbin_range(size)) + { + p->fd_nextsize = NULL; + p->bk_nextsize = NULL; + } + bck->fd = p; + fwd->bk = p; + + set_head(p, size | PREV_INUSE); + set_foot(p, size); + + check_free_chunk(av, p); + } + + /* + If the chunk borders the current high end of memory, + consolidate into top + */ + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + check_chunk(av, p); + } + + ... + + } + ... +} +``` +
+ +第三部分源码如下。如果前面释放的chunk比较大,就需要做一些处理了。首先对fastbin中的chunk进行合并并添加到unsortedbin中。然后,如果是主分配区,并且主分配区的top chunk大于一定的值,就通过systrim缩小top chunk。如果是thread分配区,就获得top chunk对应的非主分配区的heap_info指针,调用heap_trim尝试缩小该heap(systrim和heap_trim这两个函数将在下文分析)。最后,如果chunk还是通过mmap分配的,就调用munmap_chunk释放它。 +``` +static void +_int_free (mstate av, mchunkptr p, int have_lock) +{ + + ... + + if ((unsigned long) (size) <= (unsigned long) (get_max_fast ())) { + ... + } + else if (!chunk_is_mmapped(p)) { + + ... + + /* + If freeing a large space, consolidate possibly-surrounding + chunks. Then, if the total unused topmost memory exceeds trim + threshold, ask malloc_trim to reduce top. + + Unless max_fast is 0, we don't know if there are fastbins + bordering top, so we cannot tell for sure whether threshold + has been reached unless fastbins are consolidated. But we + don't want to consolidate on each free. As a compromise, + consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD + is reached. + */ + + if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { + if (atomic_load_relaxed (&av->have_fastchunks)) + malloc_consolidate(av); + + if (av == &main_arena) { +#ifndef MORECORE_CANNOT_TRIM + if ((unsigned long)(chunksize(av->top)) >= + (unsigned long)(mp_.trim_threshold)) + systrim(mp_.top_pad, av); +#endif + } else { + /* Always try heap_trim(), even if the top chunk is not + large, because the corresponding heap might go away. */ + heap_info *heap = heap_for_ptr(top(av)); + + assert(heap->ar_ptr == av); + heap_trim(heap, mp_.top_pad); + } + } + + if (!have_lock) + __libc_lock_unlock (av->mutex); + } + /* + If the chunk was allocated via mmap, release via munmap(). + */ + + else { + munmap_chunk (p); + } +} +``` +
+ +## 2.3 systrim +systrim函数用于缩小主分配区top chunk的大小,其源码如下: +``` +/* + systrim is an inverse of sorts to sysmalloc. It gives memory back + to the system (via negative arguments to sbrk) if there is unused + memory at the `high' end of the malloc pool. It is called + automatically by free() when top space exceeds the trim + threshold. It is also called by the public malloc_trim routine. It + returns 1 if it actually released any memory, else 0. + */ + +static int +systrim (size_t pad, mstate av) +{ + + ... + + pagesize = GLRO (dl_pagesize); + top_size = chunksize (av->top); + + top_area = top_size - MINSIZE - 1; + if (top_area <= pad) + return 0; + + /* Release in pagesize units and round down to the nearest page. */ + extra = ALIGN_DOWN(top_area - pad, pagesize); + + if (extra == 0) + return 0; + + /* + Only proceed if end of memory is where we last set it. + This avoids problems if there were foreign sbrk calls. + */ + current_brk = (char *) (MORECORE (0)); + if (current_brk == (char *) (av->top) + top_size) + { + /* + Attempt to release memory. We ignore MORECORE return value, + and instead call again to find out where new end of memory is. + This avoids problems if first call releases less than we asked, + of if failure somehow altered brk value. (We could still + encounter problems if it altered brk in some very bad way, + but the only thing we can do is adjust anyway, which will cause + some downstream failure.) + */ + + MORECORE (-extra); + /* Call the `morecore' hook if necessary. */ + void (*hook) (void) = atomic_forced_read (__after_morecore_hook); + if (__builtin_expect (hook != NULL, 0)) + (*hook)(); + new_brk = (char *) (MORECORE (0)); + + LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra); + + if (new_brk != (char *) MORECORE_FAILURE) + { + released = (long) (current_brk - new_brk); + + if (released != 0) + { + /* Success. Adjust top. */ + av->system_mem -= released; + set_head (av->top, (top_size - released) | PREV_INUSE); + check_malloc_state (av); + return 1; + } + } + } + return 0; +} +``` +
+ +首先,如果主分配区的top chunk本来就没什么空间,就直接返回,否则就将主分配区中可以缩小的大小保存在extra中。下面检查当前堆的brk指针是否和top chunk的结束地址相等,如果相等就可以通过MORECORE降低堆的大小,MORECORE是brk的系统调用,最后也是通过do_munmap释放虚拟内存的。__after_morecore_hook函数指针为空,不管它。再下来,获得释放后的堆指针保存在new_brk中,计算释放的虚拟内存的大小released,并将该信息更新到主分配区中,然后设置新top chunk的size。 +
+ +## 2.4 heap_trim +heap_trim用来缩小thread分配区的heap大小,其源码如下 +``` +static int +heap_trim (heap_info *heap, size_t pad) +{ + + ... + + /* Can this heap go away completely? * + while (top_chunk == chunk_at_offset (heap, sizeof (*heap))) + { + prev_heap = heap->prev; + prev_size = prev_heap->size - (MINSIZE - 2 * SIZE_SZ); + p = chunk_at_offset (prev_heap, prev_size); + /* fencepost must be properly aligned. */ + misalign = ((long) p) & MALLOC_ALIGN_MASK; + p = chunk_at_offset (prev_heap, prev_size - misalign); + assert (chunksize_nomask (p) == (0 | PREV_INUSE)); /* must be fencepost */ + p = prev_chunk (p); + new_size = chunksize (p) + (MINSIZE - 2 * SIZE_SZ) + misalign; + assert (new_size > 0 && new_size < (long) (2 * MINSIZE)); + if (!prev_inuse (p)) + new_size += prev_size (p); + assert (new_size > 0 && new_size < HEAP_MAX_SIZE); + if (new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz) + break; + ar_ptr->system_mem -= heap->size; + LIBC_PROBE (memory_heap_free, 2, heap, heap->size); + delete_heap (heap); + heap = prev_heap; + if (!prev_inuse (p)) /* consolidate backward */ + { + p = prev_chunk (p); + unlink (ar_ptr, p, bck, fwd); + } + assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0); + assert (((char *) p + new_size) == ((char *) heap + heap->size)); + top (ar_ptr) = top_chunk = p; + set_head (top_chunk, new_size | PREV_INUSE); + /*check_chunk(ar_ptr, top_chunk);*/ + } + + /* Uses similar logic for per-thread arenas as the main arena with systrim + and _int_free by preserving the top pad and rounding down to the nearest + page. */ + top_size = chunksize (top_chunk); + if ((unsigned long)(top_size) < + (unsigned long)(mp_.trim_threshold)) + return 0; + + top_area = top_size - MINSIZE - 1; + if (top_area < 0 || (size_t) top_area <= pad) + return 0; + + /* Release in pagesize units and round down to the nearest page. */ + extra = ALIGN_DOWN(top_area - pad, pagesz); + if (extra == 0) + return 0; + + /* Try to shrink. */ + if (shrink_heap (heap, extra) != 0) + return 0; + + ar_ptr->system_mem -= extra; + + /* Success. Adjust top accordingly. */ + set_head (top_chunk, (top_size - extra) | PREV_INUSE); + /*check_chunk(ar_ptr, top_chunk);*/ + return 1; +} +``` +
+ +第一个while表示,如果top chunk指针正好在heap_info上,则考虑删掉整个heap。这是因为此时,该heap只有一个top chunk。再删掉该heap之前,需要检查该heap的前一个heap是否有足够的空间,否则删掉该heap后,剩余的空间太小。
+经过计算后,newsize保存了前一个heap高地址处的fencepost和前一个空闲chunk(如果存在)的总大小组成,如果newsize加上该heap还未使用的内存(HEAP_MAX_SIZE - prev_heap->size)太小,就break退出循环,取消对整个heap的释放。否则,在更新了相应的信息后,调用delete_heap删除整个heap,delete_heap是一个宏,定义如下,delete_heap其最终通过__munmap释放整个heap,大小为HEAP_MAX_SIZE,以64位平台为例,默认为64M。 +``` +#define delete_heap(heap) \ + do { \ + if ((char *) (heap) + HEAP_MAX_SIZE == aligned_heap_area) \ + aligned_heap_area = NULL; \ + __munmap ((char *) (heap), HEAP_MAX_SIZE); \ + } while (0) +``` +
+ +删除掉整个heap后,如果前一个heap的fencepost的前面有一个空闲chunk,就将该空闲chunk从空闲链表中脱离,然后设置fencepost或者该空闲chunk(如果存在)的地址为新的top chunk,该top chunk的大小为前面计算的new_size。 +然后返回while继续检查,如果新的top chunk指针又正好在heap_info上,就表示该heap也就只有一个chunk即top chunk,就继续释放该heap。
+再往下,如果新的top chunk剩余空间top_area太小,就直接返回了。如果还有足够的空间,且top_area大于收缩阀值,就调用shrink_heap进一步将新的top chunk的大小减少extra。最后设置一些分配区的信息,并设置减少后的top chunk的大小为top_size - extra,这里其实就是减小heap_info的size变量。 +``` +/* Shrink a heap. */ + +static int +shrink_heap (heap_info *h, long diff) +{ + long new_size; + + new_size = (long) h->size - diff; + if (new_size < (long) sizeof (*h)) + return -1; + + /* Try to re-map the extra heap space freshly to save memory, and make it + inaccessible. See malloc-sysdep.h to know when this is true. */ + if (__glibc_unlikely (check_may_shrink_heap ())) + { + if ((char *) MMAP ((char *) h + new_size, diff, PROT_NONE, + MAP_FIXED) == (char *) MAP_FAILED) + return -2; + + h->mprotect_size = new_size; + } + else + __madvise ((char *) h + new_size, diff, MADV_DONTNEED); + /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/ + + h->size = new_size; + LIBC_PROBE (memory_heap_less, 2, h, h->size); + return 0; +} +``` +
+ +关于heap_trim函数,其实是有不合理的地方的,从上面的流程可以看出,假设一个分配区有多个heap时,如果最新的heap(即top chunk所在的heap)还有被占用的chunk,则会直接break,但是如果中间的heap都已经空闲了,比如下图这种情况,此时显然会存在内存空洞。 +``` +|---------------------| |---------------------| +| top chunk | | | +|---------------------| | | +| allocated chunk | | | +|---------------------| | | +| ... | | free chunk | +|---------------------| | | +| free chunk | | | +|---------------------| | | +| allocated chunk | | | +|---------------------| |---------------------| +| | | | +| heap info | ---> | heap info | +| | | | +|---------------------| |---------------------| +``` +
+这个问题我曾向社区发过邮件,链接如下,但未得到答复。
+https://sourceware.org/pipermail/libc-alpha/2021-January/122001.html +

+ +实际上我们自己也可以解释,假设我们把中间的heap释放掉,那么下次如果又有大颗粒的内存需求,还需要走系统调用向内核申请内存,这个的性能开销显然是较大的;如果我们保留了这块chunk,显然它还是会被之前介绍的各种bin来管理的(具体来说应该是unsorted bin来管理),那么下次如果有内存申请时,从这块大的chunk中挖下来一块就好了。说白了,还是性能和空间占用的折中。 +

+ +# 参考资料 +Ptmalloc2 源代码分析 华庭(庄明强) + +Linux 堆内存管理深入分析:https://murphypei.github.io/blog/2019/01/linux-heap + +glibc tcache 机制: https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/4.14_glibc_tcache.html + +malloc源码分析: https://introspelliam.github.io/2018/05/21/malloc%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E2%80%94%E2%80%941/ diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\272\214).md" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\272\214).md" new file mode 100644 index 0000000000000000000000000000000000000000..6ae30c43d59abb2648bb35317468669a73f393eb --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220(\344\272\214).md" @@ -0,0 +1,1943 @@ +--- +title: glibc malloc源码简析(二) +date: 2021-02-27 +tags: + - glibc + - malloc +archives: 2021-02 +author: wangshuo +summary: 结合源码进一步分析glibc malloc原理,本文对malloc的代码流程进行分析。 +--- +# 1 前言 +在上一篇文章中我们了解了glibc内存管理相关的数据结构,本文将结合glibc源码介绍malloc的具体执行流程。 + +软件信息如下: +|
软件项
|
版本信息
| +| :------------------------------------:| :------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +
+ +# 2 malloc执行流程分析 +## 2.1 总体流程 +glibc malloc操作的总体流程我们在《glibc malloc原理简析》中已有提及,建议结合3.2.1小结中的流程图来阅读接下来的内容。
+glibc malloc的代码量有几千行,由于glibc社区奇葩的编码规范,常常会出现几百行的for循环以及犬牙交错的缩进,因此阅读起来极为不变。为了便于理解,本文将先梳理malloc的主函数,然后再对较为关键的函数(如_int_malloc和sysmalloc)进行单独分析。
+glibc malloc主函数源码如下: + +``` +malloc/malloc.c + +void * +__libc_malloc (size_t bytes) +{ + mstate ar_ptr; + void *victim; + + void *(*hook) (size_t, const void *) + = atomic_forced_read (__malloc_hook); + if (__builtin_expect (hook != NULL, 0)) + return (*hook)(bytes, RETURN_ADDRESS (0)); +#if USE_TCACHE + /* int_free also calls request2size, be careful to not pad twice. */ + size_t tbytes; + checked_request2size (bytes, tbytes); + size_t tc_idx = csize2tidx (tbytes); + + MAYBE_INIT_TCACHE (); + + DIAG_PUSH_NEEDS_COMMENT; + if (tc_idx < mp_.tcache_bins + /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */ + && tcache + && tcache->entries[tc_idx] != NULL) + { + return tcache_get (tc_idx); + } + DIAG_POP_NEEDS_COMMENT; +#endif + + if (SINGLE_THREAD_P) + { + victim = _int_malloc (&main_arena, bytes); + assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || + &main_arena == arena_for_chunk (mem2chunk (victim))); + return victim; + } + + arena_get (ar_ptr, bytes); + + victim = _int_malloc (ar_ptr, bytes); + /* Retry with another arena only if we were able to find a usable arena + before. */ + if (!victim && ar_ptr != NULL) + { + LIBC_PROBE (memory_malloc_retry, 1, bytes); + ar_ptr = arena_get_retry (ar_ptr, bytes); + victim = _int_malloc (ar_ptr, bytes); + } + + if (ar_ptr != NULL) + __libc_lock_unlock (ar_ptr->mutex); + + assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || + ar_ptr == arena_for_chunk (mem2chunk (victim))); + return victim; +} +libc_hidden_def (__libc_malloc) +``` +
+ +主函数首先会调用ptmalloc_init进行初始化,而后,如果开启了tcache则会对相关的链表进行初始化,每次malloc时都优先查找tcache中的链表,如果满足条件直接返回。接下来,如果当前仅支持单线程,则直接调用_int_malloc来申请内存返回给malloc调用者,否则先获取分配区,然后基于分配区来调用_int_malloc申请内存。以上便是malloc主函数的流程。 +

+ +## 2.2 ptmalloc_init +在进程首次调用malloc时,会进入__malloc_hook进行初始化,设置这个钩子的目的是实现mtrace调测功能,相关代码在malloc/mtrace.c路径下,本文不展开讲解。malloc_hook_ini的定义如下: +``` +malloc/hooks.c + +static void * +malloc_hook_ini (size_t sz, const void *caller) +{ + __malloc_hook = NULL; + ptmalloc_init (); + return __libc_malloc (sz); +} +``` +
+ +默认情况下使用的是glibc的ptmalloc_init函数,执行完初始化后会回到malloc主函数,ptmalloc_init函数源码如下: +``` +malloc/arena.c + +static void +ptmalloc_init (void) +{ + if (__malloc_initialized >= 0) + return; + + __malloc_initialized = 0; + +#ifdef SHARED + /* In case this libc copy is in a non-default namespace, never use brk. + Likewise if dlopened from statically linked program. */ + Dl_info di; + struct link_map *l; + + if (_dl_open_hook != NULL + || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0 + && l->l_ns != LM_ID_BASE)) + __morecore = __failing_morecore; +#endif + + thread_arena = &main_arena; + + malloc_init_state (&main_arena); + +#if HAVE_TUNABLES + TUNABLE_GET (check, int32_t, TUNABLE_CALLBACK (set_mallopt_check)); + TUNABLE_GET (top_pad, size_t, TUNABLE_CALLBACK (set_top_pad)); + TUNABLE_GET (perturb, int32_t, TUNABLE_CALLBACK (set_perturb_byte)); + TUNABLE_GET (mmap_threshold, size_t, TUNABLE_CALLBACK (set_mmap_threshold)); + TUNABLE_GET (trim_threshold, size_t, TUNABLE_CALLBACK (set_trim_threshold)); + TUNABLE_GET (mmap_max, int32_t, TUNABLE_CALLBACK (set_mmaps_max)); + TUNABLE_GET (arena_max, size_t, TUNABLE_CALLBACK (set_arena_max)); + TUNABLE_GET (arena_test, size_t, TUNABLE_CALLBACK (set_arena_test)); +# if USE_TCACHE + TUNABLE_GET (tcache_max, size_t, TUNABLE_CALLBACK (set_tcache_max)); + TUNABLE_GET (tcache_count, size_t, TUNABLE_CALLBACK (set_tcache_count)); + TUNABLE_GET (tcache_unsorted_limit, size_t, + TUNABLE_CALLBACK (set_tcache_unsorted_limit)); +# endif +#else + const char *s = NULL; + if (__glibc_likely (_environ != NULL)) + { + char **runp = _environ; + char *envline; + + while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL, + 0)) + { + size_t len = strcspn (envline, "="); + + if (envline[len] != '=') + /* This is a "MALLOC_" variable at the end of the string + without a '=' character. Ignore it since otherwise we + will access invalid memory below. */ + continue; + + switch (len) + { + case 6: + if (memcmp (envline, "CHECK_", 6) == 0) + s = &envline[7]; + break; + case 8: + if (!__builtin_expect (__libc_enable_secure, 0)) + { + if (memcmp (envline, "TOP_PAD_", 8) == 0) + __libc_mallopt (M_TOP_PAD, atoi (&envline[9])); + else if (memcmp (envline, "PERTURB_", 8) == 0) + __libc_mallopt (M_PERTURB, atoi (&envline[9])); + } + break; + case 9: + if (!__builtin_expect (__libc_enable_secure, 0)) + { + if (memcmp (envline, "MMAP_MAX_", 9) == 0) + __libc_mallopt (M_MMAP_MAX, atoi (&envline[10])); + else if (memcmp (envline, "ARENA_MAX", 9) == 0) + __libc_mallopt (M_ARENA_MAX, atoi (&envline[10])); + } + break; + case 10: + if (!__builtin_expect (__libc_enable_secure, 0)) + { + if (memcmp (envline, "ARENA_TEST", 10) == 0) + __libc_mallopt (M_ARENA_TEST, atoi (&envline[11])); + } + break; + case 15: + if (!__builtin_expect (__libc_enable_secure, 0)) + { + if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0) + __libc_mallopt (M_TRIM_THRESHOLD, atoi (&envline[16])); + else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0) + __libc_mallopt (M_MMAP_THRESHOLD, atoi (&envline[16])); + } + break; + default: + break; + } + } + } + if (s && s[0] != '\0' && s[0] != '0') + __malloc_check_init (); +#endif + +#if HAVE_MALLOC_INIT_HOOK + void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook); + if (hook != NULL) + (*hook)(); +#endif + __malloc_initialized = 1; +} +``` +
+ +ptmalloc_init用来对整个ptmalloc框架进行初始化,首先检查全局变量__malloc_initialized是否大于等于0,如果该值大于0, +表示ptmalloc已经初始化,如果改值为0,表示ptmalloc正在初始化,全局变量__malloc_initialized用来保证全局只初始化ptmalloc一次。
+接下来会调用malloc_init_state函数来初始化主分配区,其定义如下: +``` +/* + Initialize a malloc_state struct. + + This is called from ptmalloc_init () or from _int_new_arena () + when creating a new arena. + */ + +static void +malloc_init_state (mstate av) +{ + int i; + mbinptr bin; + + /* Establish circular links for normal bins */ + for (i = 1; i < NBINS; ++i) + { + bin = bin_at (av, i); + bin->fd = bin->bk = bin; + } + +#if MORECORE_CONTIGUOUS + if (av != &main_arena) +#endif + set_noncontiguous (av); + if (av == &main_arena) + set_max_fast (DEFAULT_MXFAST); + atomic_store_relaxed (&av->have_fastchunks, false); + + av->top = initial_top (av); + init_malloc_par(); +} +``` +
+ +该函数做了四件事情,第一是初始化malloc_state中的bins数组,初始化的结果是对bins数组中的每一个fd和对应的bk, +都初始化为fd的地址,即fd=bk=&fd;第二是设置fastbin可管理的内存块的最大值,即global_max_fast,第三是设置一些标志位; +第四是初始化分配去中的top chunk,就是一个malloc_chunk指针,fd保存在bins[0]中(smallbin中不使用bins[0]和bins[1])。
+回到ptmalloc_init,之后的代码虽然很长,其实只做了一件事,那就是读取当前的环境变量来设置malloc的一些参数,相关参数的定义和作用可以参考《glibc malloc原理简析》的4.1小节。需要注意的是,这部分代码包含了两种设置方式:TUNABLES和非TUNABLES,编译的时候通过HAVE_TUNABLES宏来决定开启或关闭,《glibc malloc原理简析》的4.2小节给出了两种方式的区别和使用方法。 +
+ +## 2.3 tcache init +tcache的初始化操作最终会通过MAYBE_INIT_TCACHE宏调用tcache_init函数实现,后者的源码如下: +``` +malloc/malloc.c + +static void +tcache_init(void) +{ + mstate ar_ptr; + void *victim = 0; + const size_t bytes = sizeof (tcache_perthread_struct); + + if (tcache_shutting_down) + return; + + arena_get (ar_ptr, bytes); + victim = _int_malloc (ar_ptr, bytes); + if (!victim && ar_ptr != NULL) + { + ar_ptr = arena_get_retry (ar_ptr, bytes); + victim = _int_malloc (ar_ptr, bytes); + } + + + if (ar_ptr != NULL) + __libc_lock_unlock (ar_ptr->mutex); + + /* In a low memory situation, we may not be able to allocate memory + - in which case, we just keep trying later. However, we + typically do this very early, so either there is sufficient + memory, or there isn't enough memory to do non-trivial + allocations anyway. */ + if (victim) + { + tcache = (tcache_perthread_struct *) victim; + memset (tcache, 0, sizeof (tcache_perthread_struct)); + } + +} +``` +
+ +如果将这部分代码与malloc主函数对比的话会发现非常相似,没错,这部分实际上是使用malloc操作申请了sizeof (tcache_perthread_struct)大小的一块内存(我们在glibc malloc源码简析(一)的第6节提到tcache_perthread_struct是tcache管理内存块的基本数据结构),并通过memset初始化。内存申请这一块涉及的函数我们将在接下来几个小节中陆续进行分析。 +

+ +## 2.4 arena_get +上文提到,对于默认的非单线程模式,需要先获取一个分配区,从分配区中获取内存,获取分配区通过宏定义arena_get来实现,源码如下: +``` +/* arena_get() acquires an arena and locks the corresponding mutex. + First, try the one last locked successfully by this thread. (This + is the common case and handled with a macro for speed.) Then, loop + once over the circularly linked list of arenas. If no arena is + readily available, create a new one. In this latter case, `size' + is just a hint as to how much memory will be required immediately + in the new arena. */ + +#define arena_get(ptr, size) do { \ + ptr = thread_arena; \ + arena_lock (ptr, size); \ + } while (0) + +#define arena_lock(ptr, size) do { \ + if (ptr) \ + __libc_lock_lock (ptr->mutex); \ + else \ + ptr = arena_get2 ((size), NULL); \ + } while (0) +``` +
+ +在ptmalloc_init中有一个对变量thread_arena的赋值操作,该变量为线程变量,定义如下: +``` +/* Thread specific data. */ + +static __thread mstate thread_arena attribute_tls_model_ie; +``` +
+ +而根据ptmalloc_init仅在第一次malloc时被调用,此时thread_arena线程变量获得main_arena的值,之后再次malloc则不会对thread_arena初始化,结合arena_get定义可知对于第一次malloc,则直接在main_arena中申请内存,对于后续的malloc则通过arena_get2获取一个thread分配区,arena_get2函数的源码如下: +``` +static mstate +arena_get2 (size_t size, mstate avoid_arena) +{ + mstate a; + + static size_t narenas_limit; + + a = get_free_list (); + if (a == NULL) + { + /* Nothing immediately available, so generate a new arena. */ + if (narenas_limit == 0) + { + if (mp_.arena_max != 0) + narenas_limit = mp_.arena_max; + else if (narenas > mp_.arena_test) + { + int n = __get_nprocs (); + + if (n >= 1) + narenas_limit = NARENAS_FROM_NCORES (n); + else + /* We have no information about the system. Assume two + cores. */ + narenas_limit = NARENAS_FROM_NCORES (2); + } + } + repeat:; + size_t n = narenas; + /* NB: the following depends on the fact that (size_t)0 - 1 is a + very large number and that the underflow is OK. If arena_max + is set the value of arena_test is irrelevant. If arena_test + is set but narenas is not yet larger or equal to arena_test + narenas_limit is 0. There is no possibility for narenas to + be too big for the test to always fail since there is not + enough address space to create that many arenas. */ + if (__glibc_unlikely (n <= narenas_limit - 1)) + { + if (catomic_compare_and_exchange_bool_acq (&narenas, n + 1, n)) + goto repeat; + a = _int_new_arena (size); + if (__glibc_unlikely (a == NULL)) + catomic_decrement (&narenas); + } + else + a = reused_arena (avoid_arena); + } + return a; +} +``` +
+ +glibc维护了一个全局的arena free list,当进入arena_get2后,会优先从free list中查找是否有可用的arena,如果有则直接加锁并返回,否则,通过_int_new_arena创建一个新的arena加锁并返回。获得分配区的指针后,就会调用_int_malloc开始分配内存。 +

+ +## 2.5 _int_malloc +_int_malloc是实现glibc malloc的核心函数,主体代码有600多行,其中包括大量百行的判断和循环等语句,因此我们分步分析。
+_int_malloc开头部分的源码如下: +``` +static void * +_int_malloc (mstate av, size_t bytes) +{ + + ... + + /* + Convert request size to internal form by adding SIZE_SZ bytes + overhead plus possibly more to obtain necessary alignment and/or + to obtain a size of at least MINSIZE, the smallest allocatable + size. Also, checked_request2size traps (returning 0) request sizes + that are so large that they wrap around zero when padded and + aligned. + */ + + checked_request2size (bytes, nb); + + /* There are no usable arenas. Fall back to sysmalloc to get a chunk from + mmap. */ + if (__glibc_unlikely (av == NULL)) + { + void *p = sysmalloc (nb, av); + if (p != NULL) + alloc_perturb (p, bytes); + return p; + } + + ... + +} +``` +
+ +_int_malloc首先调用checked_request2size将需要分配的内存大小bytes转换为chunk的大小。checked_request2size是个宏定义,主要调用request2size进行计算,定义如下: +``` +/* pad request bytes into a usable size -- internal version */ + +#define request2size(req) \ + (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ + MINSIZE : \ + ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* Same, except also perform an argument and result check. First, we check + that the padding done by request2size didn't result in an integer + overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting + size isn't so large that a later alignment would lead to another integer + overflow. */ +#define checked_request2size(req, sz) \ +({ \ + (sz) = request2size (req); \ + if (((sz) < (req)) \ + || REQUEST_OUT_OF_RANGE (sz)) \ + { \ + __set_errno (ENOMEM); \ + return 0; \ + } \ +}) +``` +
+ +在glibc malloc源码简析(一)的第2小节中曾提到,当一个chunk为空闲时,至少要有mchunk_prev_size、mchunk_size、fd和bk四个参数,而当一个chunk被使用时,mchunk_prev_size可能会被前一个chunk用来存储,fd和bk也会被当作内存存储数据,因此当chunk被使用时,只剩下了mchunk_size参数需要设置,request2size中的SIZE_SZ就是INTERNAL_SIZE_T类型的大小,因此至少需要req+SIZE_SZ的内存大小。MALLOC_ALIGN_MASK用来对齐,因此request2size就计算出了所需的chunk的大小。
+传入的参数av即为调用arena_get获得的分配区指针,如果为null,就表示没有分配区可用,这时候就直接调用sysmalloc通过mmap获取chunk,关于sysmalloc我们将在2.7小节进行分析。
+_int_malloc接下来会处理申请的内存大小落入fastbin区间时的情况,源码如下: +``` +static void * +_int_malloc (mstate av, size_t bytes) +{ + + ... + + if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) + { + idx = fastbin_index (nb); + mfastbinptr *fb = &fastbin (av, idx); + mchunkptr pp; + victim = *fb; + + if (victim != NULL) + { + if (SINGLE_THREAD_P) + *fb = victim->fd; + else + REMOVE_FB (fb, pp, victim); + if (__glibc_likely (victim != NULL)) + { + size_t victim_idx = fastbin_index (chunksize (victim)); + if (__builtin_expect (victim_idx != idx, 0)) + malloc_printerr ("malloc(): memory corruption (fast)"); + check_remalloced_chunk (av, victim, nb); +#if USE_TCACHE + /* While we're here, if we see other chunks of the same size, + stash them in the tcache. */ + size_t tc_idx = csize2tidx (nb); + if (tcache && tc_idx < mp_.tcache_bins) + { + mchunkptr tc_victim; + + /* While bin not empty and tcache not full, copy chunks. */ + while (tcache->counts[tc_idx] < mp_.tcache_count + && (tc_victim = *fb) != NULL) + { + if (SINGLE_THREAD_P) + *fb = tc_victim->fd; + else + { + REMOVE_FB (fb, pp, tc_victim); + if (__glibc_unlikely (tc_victim == NULL)) + break; + } + tcache_put (tc_victim, tc_idx); + } + } +#endif + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + } + } + + ... + +} +``` +
+ +我们先不考虑USE_TCACHE判断中的内容进行分析,如果需要分配的内存大小nb落在fastbin的范围内,首先调用fastbin_index获得chunk大小nb对应的fastbin索引。获得索引idx后,就通过fastbin取出空闲chunk链表指针,mfastbinptr其实就是malloc_chunk指针,其定义如下 +``` +#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx]) +``` +
+ +其中REMOVE_FB实际是一个do、while循环,其定义如下,本质上是一个CAS操作,其作用是从刚刚得到的空闲chunk链表指针中取出第一个空闲的chunk(victim),并将链表头设置为该空闲chunk的下一个chunk(victim->fd)。 +``` +#define REMOVE_FB(fb, victim, pp) \ + do \ + { \ + victim = pp; \ + if (victim == NULL) \ + break; \ + } \ + while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \ + != victim); +``` +
+ +这里注意,fastbin中使用的是单链表,而后面smallbin使用的是双链表。获得空闲chunk后,需要转换为可以存储的内存指针,假设fastbin中没有找到空闲chunk,或者fastbin根本没有初始化,或者其他原因,就进入下一步,从smallbin中获取内存。
+让我们回到USE_TCACHE判断,当fastbin中有不止一个相同大小的chunk时,会尝试把其它的chunk放入tcache,这样的好处是下一次malloc如果还申请这一个大小的内存,则会直接从tcache中获取,由于tcache是线程变量,因此消除了加锁放锁的开销,提升了性能,这一流程在接下来的步骤中还会多次遇到。
+另外,为了保证小块内存申请释放的性能,fast bin和tcache都不会对free chunk进行合并操作,因此当free chunk被放入fastbin和tcache时, 系统会保留其使用标志位以避免自动合并操作。 +``` +static void * +_int_malloc (mstate av, size_t bytes) +{ + + ... + + /* + If a small request, check regular bin. Since these "smallbins" + hold one size each, no searching within bins is necessary. + (For a large request, we need to wait until unsorted chunks are + processed to find best fit. But for small ones, fits are exact + anyway, so we can check now, which is faster.) + */ + + if (in_smallbin_range (nb)) + { + idx = smallbin_index (nb); + bin = bin_at (av, idx); + + if ((victim = last (bin)) != bin) + { + bck = victim->bk; + if (__glibc_unlikely (bck->fd != victim)) + malloc_printerr ("malloc(): smallbin double linked list corrupted"); + set_inuse_bit_at_offset (victim, nb); + bin->bk = bck; + bck->fd = bin; + + if (av != &main_arena) + set_non_main_arena (victim); + check_malloced_chunk (av, victim, nb); +#if USE_TCACHE + /* While we're here, if we see other chunks of the same size, + stash them in the tcache. */ + + ... + +#endif void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + } + + /* + If this is a large request, consolidate fastbins before continuing. + While it might look excessive to kill all fastbins before + even seeing if there is space available, this avoids + fragmentation problems normally associated with fastbins. + Also, in practice, programs tend to have runs of either small or + large requests, but less often mixtures, so consolidation is not + invoked all that often in most programs. And the programs that + it is called frequently in otherwise tend to fragment. + */ + + else + { + idx = largebin_index (nb); + if (atomic_load_relaxed (&av->have_fastchunks)) + malloc_consolidate (av); + } + + ... + +} +``` +
+ +当申请内存的大小落在small bin区间时,将会执行以上逻辑。我们同样先不考虑USE_TCACHE判断中的内容进行分析,其实这里的操作就很简单了,设置标志位,将chunk返回。同样,如果使能了tcache,且申请的chunk的大小在tcache管理的chunk的大小的范围内,则会遍历smallbin中同样大小的chunk放入tcache中。下次如果同一线程申请同样大小的内存,则会优先从tcache中获取。
+当申请内存的大小落入large bin区间时,malloc会先试图通过malloc_consolidate函数执行一次合并操作,具体代码如下所示,该函数的作用是遍历fastbin中每个chunk链表的每个malloc_chunk指针,合并前一个不在使用中的chunk,如果后一个chunk是top chunk,则直接合并到top chunk中,如果后一个chunk不是top chunk,则合并后一个chunk并添加进unsorted_bin中。 +``` +/* + ------------------------- malloc_consolidate ------------------------- + + malloc_consolidate is a specialized version of free() that tears + down chunks held in fastbins. Free itself cannot be used for this + purpose since, among other things, it might place chunks back onto + fastbins. So, instead, we need to use a minor variant of the same + code. +*/ + +static void malloc_consolidate(mstate av) +{ + + ... + + atomic_store_relaxed (&av->have_fastchunks, false); + + unsorted_bin = unsorted_chunks(av); + + /* + Remove each chunk from fast bin and consolidate it, placing it + then in unsorted bin. Among other reasons for doing this, + placing in unsorted bin avoids needing to calculate actual bins + until malloc is sure that chunks aren't immediately going to be + reused anyway. + */ + + maxfb = &fastbin (av, NFASTBINS - 1); + fb = &fastbin (av, 0); + do { + p = atomic_exchange_acq (fb, NULL); + if (p != 0) { + do { + { + unsigned int idx = fastbin_index (chunksize (p)); + if ((&fastbin (av, idx)) != fb) + malloc_printerr ("malloc_consolidate(): invalid chunk size"); + } + + check_inuse_chunk(av, p); + nextp = p->fd; + + /* Slightly streamlined version of consolidation code in free() */ + size = chunksize (p); + nextchunk = chunk_at_offset(p, size); + nextsize = chunksize(nextchunk); + + if (!prev_inuse(p)) { + prevsize = prev_size (p); + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size in fastbins"); + unlink(av, p, bck, fwd); + } + + if (nextchunk != av->top) { + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + + if (!nextinuse) { + size += nextsize; + unlink(av, nextchunk, bck, fwd); + } else + clear_inuse_bit_at_offset(nextchunk, 0); + + first_unsorted = unsorted_bin->fd; + unsorted_bin->fd = p; + first_unsorted->bk = p; + + if (!in_smallbin_range (size)) { + p->fd_nextsize = NULL; + p->bk_nextsize = NULL; + } + + set_head(p, size | PREV_INUSE); + p->bk = unsorted_bin; + p->fd = first_unsorted; + set_foot(p, size); + } + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + } + + } while ( (p = nextp) != 0); + + } + } while (fb++ != maxfb); +} +``` +
+ +如果走到这儿还没找到所需的内存,将会执行最后一步,一个近500行的for循环,这里再拆出几步进行分析。 +``` +static void * +_int_malloc (mstate av, size_t bytes) +{ + + ... + + for (;; ) + { + int iters = 0; + while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) + { + bck = victim->bk; + if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0) + || __builtin_expect (chunksize_nomask (victim) + > av->system_mem, 0)) + malloc_printerr ("malloc(): memory corruption"); + size = chunksize (victim); + + /* + If a small request, try to use last remainder if it is the + only chunk in unsorted bin. This helps promote locality for + runs of consecutive small requests. This is the only + exception to best-fit, and applies only when there is + no exact fit for a small chunk. + */ + + if (in_smallbin_range (nb) && + bck == unsorted_chunks (av) && + victim == av->last_remainder && + (unsigned long) (size) > (unsigned long) (nb + MINSIZE)) + { + /* split and reattach remainder */ + remainder_size = size - nb; + remainder = chunk_at_offset (victim, nb); + unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder; + av->last_remainder = remainder; + remainder->bk = remainder->fd = unsorted_chunks (av); + if (!in_smallbin_range (remainder_size)) + { + remainder->fd_nextsize = NULL; + remainder->bk_nextsize = NULL; + } + + set_head (victim, nb | PREV_INUSE | + (av != &main_arena ? NON_MAIN_ARENA : 0)); + set_head (remainder, remainder_size | PREV_INUSE); + set_foot (remainder, remainder_size); + + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + + /* remove from unsorted list */ + if (__glibc_unlikely (bck->fd != victim)) + malloc_printerr ("malloc(): corrupted unsorted chunks 3"); + unsorted_chunks (av)->bk = bck; + bck->fd = unsorted_chunks (av); + + /* Take now instead of binning if exact fit */ + + if (size == nb) + { + set_inuse_bit_at_offset (victim, size); + if (av != &main_arena) + set_non_main_arena (victim); +#if USE_TCACHE + /* Fill cache first, return to user only if cache fills. + We may return one of these chunks later. */ + if (tcache_nb + && tcache->counts[tc_idx] < mp_.tcache_count) + { + tcache_put (victim, tc_idx); + return_cached = 1; + continue; + } + else + { +#endif + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } +#if USE_TCACHE + } +#endif + + ... + + } + + ... + + } +} +``` +
+ +这部分代码的整体意思就是遍历unsortedbin,从中查找是否有符合用户要求大小的chunk并返回,我们同样先忽略掉tcache。
+第一个while循环从尾到头依次取出unsortedbin中的所有chunk,将该chunk对应的前一个chunk保存在bck中,并将大小保存在size中。如果用户需要分配的内存大小对应的chunk属于smallbin,unsortedbin中只有这一个chunk,并且该chunk属于last remainder chunk且其大小大于用户需要分配内存大小对应的chunk大小加上最小的chunk大小(保证可以拆开成两个chunk),就将该chunk拆开成两个chunk,分别为victim和remainder,进行相应的设置后,将用户需要的victim返回。如果不能拆开,就从unsortedbin中取出该chunk(victim)。再下来,如果刚刚从unsortedbin中取出的victim正好是用户需要的大小nb,就设置相应的标志位,直接返回该victim。
+在加入tcache重新看这段代码可以发现,在这里依旧是之前的思想,多出来的chunk优先放入tcache中,下次申请内存可以快速返回。 +``` +static void * +_int_malloc (mstate av, size_t bytes) +{ + + ... + + for (;; ) + { + int iters = 0; + while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) + { + + ... + + /* place chunk in bin */ + + if (in_smallbin_range (size)) + { + victim_index = smallbin_index (size); + bck = bin_at (av, victim_index); + fwd = bck->fd; + } + else + { + victim_index = largebin_index (size); + bck = bin_at (av, victim_index); + fwd = bck->fd; + + /* maintain large bins in sorted order */ + if (fwd != bck) + { + /* Or with inuse bit to speed comparisons */ + size |= PREV_INUSE; + /* if smaller than smallest, bypass loop below */ + assert (chunk_main_arena (bck->bk)); + if ((unsigned long) (size) + < (unsigned long) chunksize_nomask (bck->bk)) + { + fwd = bck; + bck = bck->bk; + + victim->fd_nextsize = fwd->fd; + victim->bk_nextsize = fwd->fd->bk_nextsize; + fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; + } + else + { + assert (chunk_main_arena (fwd)); + while ((unsigned long) size < chunksize_nomask (fwd)) + { + fwd = fwd->fd_nextsize; + assert (chunk_main_arena (fwd)); + } + + if ((unsigned long) size + == (unsigned long) chunksize_nomask (fwd)) + /* Always insert in the second position. */ + fwd = fwd->fd; + else + { + victim->fd_nextsize = fwd; + victim->bk_nextsize = fwd->bk_nextsize; + if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) + malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)"); + fwd->bk_nextsize = victim; + victim->bk_nextsize->fd_nextsize = victim; + } + bck = fwd->bk; + if (bck->fd != fwd) + malloc_printerr ("malloc(): largebin double linked list corrupted (bk)"); + } + } + else + victim->fd_nextsize = victim->bk_nextsize = victim; + } + + mark_bin (av, victim_index); + victim->bk = bck; + victim->fd = fwd; + fwd->bk = victim; + bck->fd = victim; + +#if USE_TCACHE + /* If we've processed as many chunks as we're allowed while + filling the cache, return one of the cached ones. */ + ++tcache_unsorted_count; + if (return_cached + && mp_.tcache_unsorted_limit > 0 + && tcache_unsorted_count > mp_.tcache_unsorted_limit) + { + return tcache_get (tc_idx); + } + +#define MAX_ITERS 10000 + if (++iters >= MAX_ITERS) + break; + } + +#if USE_TCACHE + /* If all the small chunks we found ended up cached, return one now. */ + if (return_cached) + { + return tcache_get (tc_idx); + } +#endif + + ... + + } +} +``` +
+ +这部分代码的整体意思是如果从unsortedbin中取出的chunk不符合用户要求的大小,就将该chunk合并到smallbin或者largebin中,我们依旧先忽略掉tcache进行分析。
+首先如果取出的chunk(victim)属于smallbin,就通过smallbin_index计算需要插入的位置victim_index,然后获取smallbin中对应位置的链表头指针保存在bck中,最后直接插入到smallbin中,由于smallbin中的chunk不使用fd_nextsize和bk_nextsize指针,插入操作只需要更新bk和fd指针,具体的插入操作在后面。这里需解释一下,fd_nextsize指针指向的是chunk双向链表中下一个大小不同的chunk,bk_nextsize指向的是chunk双向链表中前一个大小不同的chunk。
+如果取出的chunk(victim)属于largebin,通过largebin_index计算需要插入的位置victim_index,然后获取largebin链表头指针保存在bck中。
+如果fwd等于bck,即bck->fd=bck,则表示largebin中对应位置上的chunk双向链表为空,直接进入后面的else部分中,代码victim->fd_nextsize = victim->bk_nextsize = victim表示插入到largebin中的victim是唯一的chunk,因此其fd_nextsize和bk_nextsize指针都指向自己。
+如果fwd不等于bck,对应的chunk双向链表存在空闲chunk,这时就要在该链表中找到合适的位置插入了。因为largebin中的chunk链表是按照chunk大小从大到小排序的,如果victim的size小于bck->bk->size即最后一个chunk的大小,则表示即将插入victim的大小在largebin的chunk双向链表中是最小的,因此要把victim插入到该链表的最后。
+如果要插入的victim的size不是最小的,就要通过一个while循环遍历找到合适的位置,这里是从双向链表头bck->fd开始遍历,利用fd_nextsize加快遍历的速度,找到第一个size>=fwd->size的chunk。如果size=fwd->size,就只是改变victim以及前后相应chunk的bk、fd指针就行。
+再往下,如果size不相等,则直接插入在fwd的左边,这样也能保证所有的fd_nextsize和bk_nextsize指针设置在相同chunk大小的最地地址处(最左边)。
+再往下,mark_bin用来标识malloc_state中的binmap,标识相应位置的chunk空闲。然后就更改fd、bk指针,插入到双向链表中,这个插入操作同时适用于smallbin和largebin,因此放在这里。最后如果在unsortedbin中处理了超过10000个chunk,就直接退出循环,这里保证不会因为unsortedbin中chunk太多,处理的时间太长了。
+重新加入tcache分析,这里有两块用到tcache,其思路都是上文在合并时通过return_cached变量标记是否已找到所需大小的内存(如果找到会优先放入tcache中),然后等合并完毕执行到这一步时,直接从tcache拿出满足条件的chunk返回。
+ +``` +static void * _int_malloc(mstate av, size_t bytes) { + + ... + + for (;;) { + + ... + + /* + If a large request, scan through the chunks of current bin in + sorted order to find smallest that fits. Use the skip list for this. + */ + + if (!in_smallbin_range (nb)) + { + bin = bin_at (av, idx); + + /* skip scan if empty or largest chunk is too small */ + if ((victim = first (bin)) != bin + && (unsigned long) chunksize_nomask (victim) + >= (unsigned long) (nb)) + { + victim = victim->bk_nextsize; + while (((unsigned long) (size = chunksize (victim)) < + (unsigned long) (nb))) + victim = victim->bk_nextsize; + + /* Avoid removing the first entry for a size so that the skip + list does not have to be rerouted. */ + if (victim != last (bin) + && chunksize_nomask (victim) + == chunksize_nomask (victim->fd)) + victim = victim->fd; + + remainder_size = size - nb; + unlink (av, victim, bck, fwd); + + /* Exhaust */ + if (remainder_size < MINSIZE) + { + set_inuse_bit_at_offset (victim, size); + if (av != &main_arena) + set_non_main_arena (victim); + } + /* Split */ + else + { + remainder = chunk_at_offset (victim, nb); + /* We cannot assume the unsorted list is empty and therefore + have to perform a complete insert here. */ + bck = unsorted_chunks (av); + fwd = bck->fd; + if (__glibc_unlikely (fwd->bk != bck)) + malloc_printerr ("malloc(): corrupted unsorted chunks"); + remainder->bk = bck; + remainder->fd = fwd; + bck->fd = remainder; + fwd->bk = remainder; + if (!in_smallbin_range (remainder_size)) + { + remainder->fd_nextsize = NULL; + remainder->bk_nextsize = NULL; + } + set_head (victim, nb | PREV_INUSE | + (av != &main_arena ? NON_MAIN_ARENA : 0)); + set_head (remainder, remainder_size | PREV_INUSE); + set_foot (remainder, remainder_size); + } + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + } + + ... + } +} +``` +
+ +这部分代码的整体意思就是要尝试从largebin中取出对应的chunk了。这里的idx是在前面根据宏largebin_index计算的。接下来就要根据idx获得largebin中的双向链表头指针bin,然后从bin->bk开始从尾到头(根据chunk大小从小到大)遍历整个双向链表,找到第一个大于用户需要分配的chunk大小nb的chunk指针victim。找到victim后,需要将其拆开成两部分,第一部分是要返回给用户的chunk,第二部分分为两种情况,如果其大小小于MINSIZE,则不能构成一个最小chunk,这种情况下就将拆开前的整个victim返回给用户;如果大于MINSIZE,就将拆开后的第二部分remainder插入到unsortedbin中,然后把第一部分victim返回给用户。
+ +``` +static void * _int_malloc(mstate av, size_t bytes) { + + ... + + for (;;) { + + ... + + /* + Search for a chunk by scanning bins, starting with next largest + bin. This search is strictly by best-fit; i.e., the smallest + (with ties going to approximately the least recently used) chunk + that fits is selected. + + The bitmap avoids needing to check that most blocks are nonempty. + The particular case of skipping all bins during warm-up phases + when no chunks have been returned yet is faster than it might look. + */ + + ++idx; + bin = bin_at (av, idx); + block = idx2block (idx); + map = av->binmap[block]; + bit = idx2bit (idx); + + for (;; ) + { + /* Skip rest of block if there are no more set bits in this block. */ + if (bit > map || bit == 0) + { + do + { + if (++block >= BINMAPSIZE) /* out of bins */ + goto use_top; + } + while ((map = av->binmap[block]) == 0); + + bin = bin_at (av, (block << BINMAPSHIFT)); + bit = 1; + } + + /* Advance to bin with set bit. There must be one. */ + while ((bit & map) == 0) + { + bin = next_bin (bin); + bit <<= 1; + assert (bit != 0); + } + + /* Inspect the bin. It is likely to be non-empty */ + victim = last (bin); + + /* If a false alarm (empty bin), clear the bit. */ + if (victim == bin) + { + av->binmap[block] = map &= ~bit; /* Write through */ + bin = next_bin (bin); + bit <<= 1; + } + + else + { + size = chunksize (victim); + + /* We know the first chunk in this bin is big enough to use. */ + assert ((unsigned long) (size) >= (unsigned long) (nb)); + + remainder_size = size - nb; + + /* unlink */ + unlink (av, victim, bck, fwd); + + /* Exhaust */ + if (remainder_size < MINSIZE) + { + set_inuse_bit_at_offset (victim, size); + if (av != &main_arena) + set_non_main_arena (victim); + } + + /* Split */ + else + { + remainder = chunk_at_offset (victim, nb); + + /* We cannot assume the unsorted list is empty and therefore + have to perform a complete insert here. */ + bck = unsorted_chunks (av); + fwd = bck->fd; + if (__glibc_unlikely (fwd->bk != bck)) + malloc_printerr ("malloc(): corrupted unsorted chunks 2"); + remainder->bk = bck; + remainder->fd = fwd; + bck->fd = remainder; + fwd->bk = remainder; + + /* advertise as last remainder */ + if (in_smallbin_range (nb)) + av->last_remainder = remainder; + if (!in_smallbin_range (remainder_size)) + { + remainder->fd_nextsize = NULL; + remainder->bk_nextsize = NULL; + } + set_head (victim, nb | PREV_INUSE | + (av != &main_arena ? NON_MAIN_ARENA : 0)); + set_head (remainder, remainder_size | PREV_INUSE); + set_foot (remainder, remainder_size); + } + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + } + + ... + + } +} +``` +
+ +这一部分的整体意思是,前面在largebin中寻找特定大小的空闲chunk,如果没找到,这里就要遍历largebin中的其他更大的chunk双向链表,继续寻找。
+开头的++idx就表示,这里要从largebin中下一个更大的chunk双向链表开始遍历。ptmalloc中用一个bit表示malloc_state的bins数组中对应的位置上是否有空闲chunk,bit为1表示有,为0则没有。ptmalloc通过4个block(一个block 4字节)一共128个bit管理bins数组。因此,代码中计算的block表示对应的idx属于哪一个block,map就表是block对应的bit组成的二进制数字。 +接下来进入for循环,如果bit > map,表示该map对应的整个block里都没有大于bit位置的空闲的chunk,因此就要找下一个block。因为后面的block只要不等于0,就肯定有空闲chunk,并且其大小大于bit位置对应的chunk,下面就根据block,取出block对应的第一个双向链表的头指针。这里也可以看出,设置map和block也是为了加快查找的速度。如果遍历完所有block都没有空闲chunk,这时只能从top chunk里分配chunk了,因此跳转到use_top。
+如果有空闲chunk,接下来就通过一个while循环依次比较找出到底在哪个双向链表里存在空闲chunk,最后获得空闲chunk所在的双向链表的头指针bin和位置bit。
+接下来,如果找到的双向链表又为空,则继续前面的遍历,找到空闲chunk所在的双向链表的头指针bin和位置bit。如果找到的双向链表不为空,就和上面一部分再largebin中找到空闲chunk的操作一样了,这里就不继续分析了。
+ +``` + use_top: + /* + If large enough, split off the chunk bordering the end of memory + (held in av->top). Note that this is in accord with the best-fit + search rule. In effect, av->top is treated as larger (and thus + less well fitting) than any other available chunk since it can + be extended to be as large as necessary (up to system + limitations). + + We require that av->top always exists (i.e., has size >= + MINSIZE) after initialization, so if it would otherwise be + exhausted by current request, it is replenished. (The main + reason for ensuring it exists is that we may need MINSIZE space + to put in fenceposts in sysmalloc.) + */ + + victim = av->top; + size = chunksize (victim); + + if (__glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): corrupted top size"); + + if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) + { + remainder_size = size - nb; + remainder = chunk_at_offset (victim, nb); + av->top = remainder; + set_head (victim, nb | PREV_INUSE | + (av != &main_arena ? NON_MAIN_ARENA : 0)); set_head (remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; + } + + /* When we are using atomic ops to free fast chunks we can get + here for all block sizes. */ + else if (atomic_load_relaxed (&av->have_fastchunks)) + { + malloc_consolidate (av); + /* restore original bin index */ + if (in_smallbin_range (nb)) + idx = smallbin_index (nb); + else + idx = largebin_index (nb); + } + + /* + Otherwise, relay to handle system-dependent cases + */ + else + { + void *p = sysmalloc (nb, av); + if (p != NULL) + alloc_perturb (p, bytes); + return p; + } + } +} +``` +
+ +这里就是_int_malloc的最后一部分了,这部分代码的整体意思分为三部分,首先从top chunk中尝试分配内存;如果失败,就检查fastbin中是否有空闲内存了(其他线程此时可能将释放的chunk放入fastbin中了),如果不空闲,就合并fastbin中的空闲chunk并放入smallbin或者largebin中,然后会回到_int_malloc函数中最前面的for循环,重新开始查找空闲chunk;如果连fastbin中都没有空闲内存了,这时只能通过sysmalloc从系统分配内存了。 +

+ +## 2.6 sysmalloc +sysmalloc顾名思义,就是在当前glibc malloc在用户态管理的内存不足的情况下从OS申请内存,因此应用场景有二:一个是初始化的时候,另一个便是内存不足的时候。考虑到sysmalloc代码量依旧庞大,这里继续分段来讲解。

+第一部分代码如下,如果需要分配的内存大小大于实用mmap进行分配的阀值mp_.mmap_threshold,且mp_.n_mmaps判断系统还可以有可以使用mmap分配的空间时会执行try_mmap分支。
+首先会重新计算需要分配多少内存,因为通过使用mmap直接分配的chunk不需要添加到链表中,因此不存在前后关系,当一个chunk被使用时,不能借用后一个chunk的prev_size字段,这里需要把该字段的长度SIZE_SZ加上。并且这里假设MALLOC_ALIGNMENT == 2 * SIZE_SZ。
+接下来判断需要分配的内存大小是否会溢出,然后就调用MMAP分配内存,MMAP是一个宏定义,最后就是通过系统调用来分配内存,后面来看这个函数。
+再往下就是通过set_head在chunk中的size参数里设置标志位,因为chunk是按8字节对齐的,而size标识chunk占用的字节数,所以最后三位是没有用的,ptmalloc将这三位用来作为标志位,这里便是设置其中一个标志位,用来标识该chunk是直接通过mmap分配的。
+设置完标志位后,接下来就是设置全局变量_mp,将mp_.n_mmaps加1,后者表示当前进程通过mmap分配的chunk个数,对应的mp_.max_n_mmaps表示最大chunk个数。mp_.mmapped_mem标识已经通过mmap分配的内存大小,mp_.max_mmapped_mem对应可分配内存的最大值。最后,通过chunk2mem返回chunk中内存的起始指针。
+回到_int_malloc函数中,假设通过sysmalloc分配成功,接下来就需要调用alloc_perturb对刚刚分配的内存进行初始化。 +``` +static void * +sysmalloc (INTERNAL_SIZE_T nb, mstate av) +{ + ... + + /* + If have mmap, and the request size meets the mmap threshold, and + the system supports mmap, and there are few enough currently + allocated mmapped regions, try to directly map this request + rather than expanding top. + */ + + if (av == NULL + || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) + && (mp_.n_mmaps < mp_.n_mmaps_max))) + { + char *mm; /* return value from mmap call*/ + + try_mmap: + /* + Round up size to nearest page. For mmapped chunks, the overhead + is one SIZE_SZ unit larger than for normal chunks, because there + is no following chunk whose prev_size field could be used. + + See the front_misalign handling below, for glibc there is no + need for further alignments unless we have have high alignment. + */ + if (MALLOC_ALIGNMENT == 2 * SIZE_SZ) + size = ALIGN_UP (nb + SIZE_SZ, pagesize); + else + size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize); + tried_mmap = true; + + /* Don't try if size wraps around 0 */ + if ((unsigned long) (size) > (unsigned long) (nb)) + { + mm = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0)); + + if (mm != MAP_FAILED) + { + /* + The offset to the start of the mmapped region is stored + in the prev_size field of the chunk. This allows us to adjust + returned start address to meet alignment requirements here + and in memalign(), and still be able to compute proper + address argument for later munmap in free() and realloc(). + */ + + if (MALLOC_ALIGNMENT == 2 * SIZE_SZ) + { + /* For glibc, chunk2mem increases the address by 2*SIZE_SZ and + MALLOC_ALIGN_MASK is 2*SIZE_SZ-1. Each mmap'ed area is page + aligned and therefore definitely MALLOC_ALIGN_MASK-aligned. */ + assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0); + front_misalign = 0; + } + else + front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) + { + correction = MALLOC_ALIGNMENT - front_misalign; + p = (mchunkptr) (mm + correction); + set_prev_size (p, correction); + set_head (p, (size - correction) | IS_MMAPPED); + } + else + { + p = (mchunkptr) mm; + set_prev_size (p, 0); + set_head (p, size | IS_MMAPPED); + } + + /* update statistics */ + + int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1; + atomic_max (&mp_.max_n_mmaps, new); + + unsigned long sum; + sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size; + atomic_max (&mp_.max_mmapped_mem, sum); + + check_chunk (av, p); + + return chunk2mem (p); + } + } + } + + /* There are no usable arenas and mmap also failed. */ + if (av == NULL) + return 0; + + ... + +} +``` +

+ +接下来是第二部分,代码如下: +``` +static void * +sysmalloc (INTERNAL_SIZE_T nb, mstate av) +{ + ... + + /* Record incoming configuration of top */ + + old_top = av->top; + old_size = chunksize (old_top); + old_end = (char *) (chunk_at_offset (old_top, old_size)); + + brk = snd_brk = (char *) (MORECORE_FAILURE); + + /* + If not the first time through, we require old_size to be + at least MINSIZE and to have prev_inuse set. + */ + + assert ((old_top == initial_top (av) && old_size == 0) || + ((unsigned long) (old_size) >= MINSIZE && + prev_inuse (old_top) && + ((unsigned long) old_end & (pagesize - 1)) == 0)); + + /* Precondition: not enough current space to satisfy nb request */ + assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE)); + + + if (av != &main_arena) + { + heap_info *old_heap, *heap; + size_t old_heap_size; + + /* First try to extend the current heap. */ + old_heap = heap_for_ptr (old_top); + old_heap_size = old_heap->size; + if ((long) (MINSIZE + nb - old_size) > 0 + && grow_heap (old_heap, MINSIZE + nb - old_size) == 0) + { + av->system_mem += old_heap->size - old_heap_size; + set_head (old_top, (((char *) old_heap + old_heap->size) - (char *) old_top) + | PREV_INUSE); + } + else if ((heap = new_heap (nb + (MINSIZE + sizeof (*heap)), mp_.top_pad))) + { + /* Use a newly allocated heap. */ + heap->ar_ptr = av; + heap->prev = old_heap; + av->system_mem += heap->size; + /* Set up the new top. */ + top (av) = chunk_at_offset (heap, sizeof (*heap)); + set_head (top (av), (heap->size - sizeof (*heap)) | PREV_INUSE); + + /* Setup fencepost and free the old top chunk with a multiple of + MALLOC_ALIGNMENT in size. */ + /* The fencepost takes at least MINSIZE bytes, because it might + become the top chunk again later. Note that a footer is set + up, too, although the chunk is marked in use. */ + old_size = (old_size - MINSIZE) & ~MALLOC_ALIGN_MASK; + set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ), 0 | PREV_INUSE); + if (old_size >= MINSIZE) + { + set_head (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ) | PREV_INUSE); + set_foot (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ)); + set_head (old_top, old_size | PREV_INUSE | NON_MAIN_ARENA); + _int_free (av, old_top, 1); + } + else + { + set_head (old_top, (old_size + 2 * SIZE_SZ) | PREV_INUSE); + set_foot (old_top, (old_size + 2 * SIZE_SZ)); + } + } + else if (!tried_mmap) + /* We can at least try to use to mmap memory. */ + goto try_mmap; + } + else /* av == main_arena */ + { + ... + } + + ... + +} +``` +
+ +首先,old_top、old_size和old_end分别保存了top chunk的指针,大小以及尾部的地址。如果是thread分配区,首先通过heap_for_ptr获得原top chunk对应的heap_info指针,heap_for_ptr的定义如下。对于thread分配区,因为每个heap是按照HEAP_MAX_SIZE的大小分配且对齐的,而每个top chunk存在于每个heap的剩余空间(高地址处),因此通过heap_for_ptr就能取出heap_info指针,heap_info保存了每个heap的相关信息。获得heap_info指针后,就能获得该heap当前被使用的大小并将其保存在old_heap_size中。 +``` +#define heap_for_ptr(ptr) \ + ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1))) +``` +
+ +由上文可知,进入到sysmalloc前会尝试在top chunk分配内存,因此代码执行到这里肯定失败了。所以这里只有MINSIZE + nb - old_size>0这一种情况,即这时的top chunk空间不足了,因此首先通过grow_heap尝试向heap的高地址处增加heap当前使用的大小,即top chunk的大小,函数的定义如下: +``` +/* Grow a heap. size is automatically rounded up to a + multiple of the page size. */ + +static int +grow_heap (heap_info *h, long diff) +{ + size_t pagesize = GLRO (dl_pagesize); + long new_size; + + diff = ALIGN_UP (diff, pagesize); + new_size = (long) h->size + diff; + if ((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE) + return -1; + + if ((unsigned long) new_size > h->mprotect_size) + { + if (__mprotect ((char *) h + h->mprotect_size, + (unsigned long) new_size - h->mprotect_size, + PROT_READ | PROT_WRITE) != 0) + return -2; + + h->mprotect_size = new_size; + } + + h->size = new_size; + LIBC_PROBE (memory_heap_more, 2, h, h->size); + return 0; +} +``` +
+ +grow_heap最终的结果是将h->size增大到new_size,二者的差值等于所需内存的大小按照page size对齐。假设grow_heap成功,即将top chunk的大小设置为MINSIZE + nb,则重新设置分配区使用的内存大小,并且设置top chunk的size至新值。假设grow_heap失败,大部分情况下说明heap的使用大小已经接近其最大值HEAP_MAX_SIZE了,此时只能通过new_heap重新分配一个heap,注意传入的参数mp_.top_pad表示在分配内存时,额外多分配的内存。 +``` +static heap_info * +new_heap (size_t size, size_t top_pad) +{ + + ... + + if (size + top_pad < HEAP_MIN_SIZE) + size = HEAP_MIN_SIZE; + else if (size + top_pad <= HEAP_MAX_SIZE) + size += top_pad; + else if (size > HEAP_MAX_SIZE) + return 0; + else + size = HEAP_MAX_SIZE; + size = ALIGN_UP (size, pagesize); + + /* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed. + No swap space needs to be reserved for the following large + mapping (on Linux, this is the case for all non-writable mappings + anyway). */ + p2 = MAP_FAILED; + if (aligned_heap_area) + { + p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE, + MAP_NORESERVE); + aligned_heap_area = NULL; + if (p2 != MAP_FAILED && ((unsigned long) p2 & (HEAP_MAX_SIZE - 1))) + { + __munmap (p2, HEAP_MAX_SIZE); + p2 = MAP_FAILED; + } + } + if (p2 == MAP_FAILED) + { + p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, MAP_NORESERVE); + if (p1 != MAP_FAILED) + { + p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1)) + & ~(HEAP_MAX_SIZE - 1)); + ul = p2 - p1; + if (ul) + __munmap (p1, ul); + else + aligned_heap_area = p2 + HEAP_MAX_SIZE; + __munmap (p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul); + } + else + { + /* Try to take the chance that an allocation of only HEAP_MAX_SIZE + is already aligned. */ + p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE); + if (p2 == MAP_FAILED) + return 0; + + if ((unsigned long) p2 & (HEAP_MAX_SIZE - 1)) + { + __munmap (p2, HEAP_MAX_SIZE); + return 0; + } + } + } + if (__mprotect (p2, size, PROT_READ | PROT_WRITE) != 0) + { + __munmap (p2, HEAP_MAX_SIZE); + return 0; + } + h = (heap_info *) p2; + h->size = size; + h->mprotect_size = size; + LIBC_PROBE (memory_heap_new, 2, h, h->size); + return h; +} +``` +
+ +首先对需要分配的内存大小size做相应的调整。aligned_heap_area表示上一次MMAP分配后的结束地址,如果存在,就首先尝试从该地址分配大小为HEAP_MAX_SIZE的内存。MMAP最后是系统调用,这里只是一些标志位的区别。分配完后,会检查地址是否对齐,如果不对齐也是失败。
+如果第一次分配失败了,就会再尝试一次,这次分配HEAP_MAX_SIZE * 2大小的内存,并且新内存的起始地址由内核决定。因为尝试分配了HEAP_MAX_SIZE*2大小的内存,其中必定包含了大小为HEAP_MAX_SIZE且和HEAP_MAX_SIZE对齐的内存,因此一旦分配成功,就从中截取出这部分内存。
+如果连第二次也分配失败了,就会通过MMAP进行第三次分配,这次只分配HEAP_MAX_SIZE大小的内存,并且起始地址由内核决定,如果又失败了就返回0。
+如果三面三次分配内存任何一次成功,就设置相应的可读写位置,并且返回分配区的heap_info指针。
+重新回到sysmalloc中,假设分配成功,就会对刚刚分配得到的heap做相应的设置,其中ar_ptr表示所属的分配区的指针,prev表示上一个heap,所有的heap通过prev形成单向链表,然后通过set_head设置av分配区top chunk的size,这里也可以看出,对于刚分配的heap,包含了heap_info指针、top chunk、以及大于size的未被使用的部分。
+再接下来就要对原来的top chunk进行最后的处理,这里假设对齐,如果原top chunk的大小不够大,就将其分割成old_size + 2 * SIZE_SZ和2 * SIZE_SZ大小;如果原top chunk的大小足够大,就将其分割成old_size,2 * SIZE_SZ和2 * SIZE_SZ大小,并通过_int_free进行释放。

+ +接下来是第三部分,代码如下: +``` +static void * +sysmalloc (INTERNAL_SIZE_T nb, mstate av) +{ + ... + + if (av != &main_arena) + { + ... + } + else /* av == main_arena */ + { /* Request enough space for nb + pad + overhead */ + size = nb + mp_.top_pad + MINSIZE; + + /* + If contiguous, we can subtract out existing space that we hope to + combine with new space. We add it back later only if + we don't actually get contiguous space. + */ + + if (contiguous (av)) + size -= old_size; + + /* + Round to a multiple of page size. + If MORECORE is not contiguous, this ensures that we only call it + with whole-page arguments. And if MORECORE is contiguous and + this is not first time through, this preserves page-alignment of + previous calls. Otherwise, we correct to page-align below. + */ + + size = ALIGN_UP (size, pagesize); + + /* + Don't try to call MORECORE if argument is so big as to appear + negative. Note that since mmap takes size_t arg, it may succeed + below even if we cannot call MORECORE. + */ + + if (size > 0) + { + brk = (char *) (MORECORE (size)); + LIBC_PROBE (memory_sbrk_more, 2, brk, size); + } + + if (brk != (char *) (MORECORE_FAILURE)) + { + /* Call the `morecore' hook if necessary. */ + void (*hook) (void) = atomic_forced_read (__after_morecore_hook); + if (__builtin_expect (hook != NULL, 0)) + (*hook)(); + } + else + { + /* + If have mmap, try using it as a backup when MORECORE fails or + cannot be used. This is worth doing on systems that have "holes" in + address space, so sbrk cannot extend to give contiguous space, but + space is available elsewhere. Note that we ignore mmap max count + and threshold limits, since the space will not be used as a + segregated mmap region. + */ + + /* Cannot merge with old top, so add its size back in */ + if (contiguous (av)) + size = ALIGN_UP (size + old_size, pagesize); + + /* If we are relying on mmap as backup, then use larger units */ + if ((unsigned long) (size) < (unsigned long) (MMAP_AS_MORECORE_SIZE)) + size = MMAP_AS_MORECORE_SIZE; + + /* Don't try if size wraps around 0 */ + if ((unsigned long) (size) > (unsigned long) (nb)) + { + char *mbrk = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0)); + + if (mbrk != MAP_FAILED) + { + /* We do not need, and cannot use, another sbrk call to find end */ + brk = mbrk; + snd_brk = brk + size; + + /* + Record that we no longer have a contiguous sbrk region. + After the first time mmap is used as backup, we do not + ever rely on contiguous space since this could incorrectly + bridge regions. + */ + set_noncontiguous (av); + } + } + } + + ... + + } + + ... + +} +``` +
+ +以上代码的关键是通过MORECORE向内核申请内存,MORECORE是一个宏定义,其最终是通过系统调用分配内存。假设分配成功,会查找是否有__after_morecore_hook函数并执行,这里假设该函数指针为null。假设分配失败,则进入else部分,首先对需要分配的大小按地址对齐,并且设置分配size的最小值为MMAP_AS_MORECORE_SIZE(1MB),然后通过MMAP宏分配内存。这里注意,如果是通过mmap分配的内存,则设置分配区为不连续标志位。

+接下来是第四部分,代码如下: +``` +static void * sysmalloc(INTERNAL_SIZE_T nb, mstate av) { + ... + if (av != &main_arena) { + ... + } + else{ + + ... + + if (brk != (char *) (MORECORE_FAILURE)) + { + if (mp_.sbrk_base == 0) + mp_.sbrk_base = brk; + av->system_mem += size; + + /* + If MORECORE extends previous space, we can likewise extend top size. + */ + + if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE)) + set_head (old_top, (size + old_size) | PREV_INUSE); + + else if (contiguous (av) && old_size && brk < old_end) + /* Oops! Someone else killed our space.. Can't touch anything. */ + malloc_printerr ("break adjusted to free malloc space"); + + /* + Otherwise, make adjustments: + + * If the first time through or noncontiguous, we need to call sbrk + just to find out where the end of memory lies. + + * We need to ensure that all returned chunks from malloc will meet + MALLOC_ALIGNMENT + + * If there was an intervening foreign sbrk, we need to adjust sbrk + request size to account for fact that we will not be able to + combine new space with existing space in old_top. + + * Almost all systems internally allocate whole pages at a time, in + which case we might as well use the whole last page of request. + So we allocate enough more memory to hit a page boundary now, + which in turn causes future contiguous calls to page-align. + */ + + else + { + front_misalign = 0; + end_misalign = 0; + correction = 0; + aligned_brk = brk; + + /* handle contiguous cases */ + if (contiguous (av)) + { + /* Count foreign sbrk as system_mem. */ + if (old_size) + av->system_mem += brk - old_end; + + /* Guarantee alignment of first new chunk made from this space */ + + front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) + { + /* + Skip over some bytes to arrive at an aligned position. + We don't need to specially mark these wasted front bytes. + They will never be accessed anyway because + prev_inuse of av->top (and any chunk created from its start) + is always true after initialization. + */ + + correction = MALLOC_ALIGNMENT - front_misalign; + aligned_brk += correction; + } + + /* + If this isn't adjacent to existing space, then we will not + be able to merge with old_top space, so must add to 2nd request. + */ + + correction += old_size; + + /* Extend the end address to hit a page boundary */ + end_misalign = (INTERNAL_SIZE_T) (brk + size + correction); + correction += (ALIGN_UP (end_misalign, pagesize)) - end_misalign; + + assert (correction >= 0); + snd_brk = (char *) (MORECORE (correction)); + + /* + If can't allocate correction, try to at least find out current + brk. It might be enough to proceed without failing. + + Note that if second sbrk did NOT fail, we assume that space + is contiguous with first sbrk. This is a safe assumption unless + program is multithreaded but doesn't use locks and a foreign sbrk + occurred between our first and second calls. + */ + + if (snd_brk == (char *) (MORECORE_FAILURE)) + { + correction = 0; + snd_brk = (char *) (MORECORE (0)); + } + else + { + /* Call the `morecore' hook if necessary. */ + void (*hook) (void) = atomic_forced_read (__after_morecore_hook); + if (__builtin_expect (hook != NULL, 0)) + (*hook)(); + } + } + + ... + + } + } + } + + ... + +} +``` +
+ +假设增加了主分配区的top chunk成功,则更新sbrk_base和分配区已分配的内存大小。然后,第一个判断表示,新分配的内存地址和原来的top chunk连续,并且不是通过MMAP分配的,这时只需要更新原来top chunk的大小size。第二个判断表示如果分配区的连续标志位置位,top chunk的大小大于0,但是分配的brk小于原来的top chunk结束地址,这里就判定出错了。进入第三个判断表示新分配的内存地址大于原来的top chunk的结束地址,但是不连续。这种情况下,如果分配区的连续标志位置位,则表示不是通过MMAP分配的,肯定有其他线程调用了brk在堆上分配了内存,av->system_mem += brk - old_end表示将其他线程分配的内存一并计入到该分配区分配的内存大小。然后将刚刚分配的地址brk按MALLOC_ALIGNMENT对齐。再往下就要处理地址不连续的问题了,因为地址不连续,就要放弃原来top chunk后面一部分的内存大小,并且将这一部分内存大小“补上”到刚刚分配的新内存后面。首先计算堆上补上内存后的结束地址并保存在correction中,然后调用MORECORE继续分配一次,将新分配内存的开始地址保存在snd_brk中。如果分配失败,则将correction设为0,并将snd_brk重置为原来分配的内存的结束地址,表示放弃该次补偿操作;如果分配成功,就调用__after_morecore_hook函数,这里假设该函数指针为null。

+ +接下来是第五部分,代码如下: +``` +static void * sysmalloc(INTERNAL_SIZE_T nb, mstate av) { + ... + if (av != &main_arena) { + ... + } + else{ + ... + if (brk != (char *) (MORECORE_FAILURE)) { + ... + if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE)) + ... + else if (contiguous (av) && old_size && brk < old_end) { + ... + } + else { + ... + if (contiguous(av)) { + ... + } + + /* handle non-contiguous cases */ + else + { + if (MALLOC_ALIGNMENT == 2 * SIZE_SZ) + /* MORECORE/mmap must correctly align */ + assert (((unsigned long) chunk2mem (brk) & MALLOC_ALIGN_MASK) == 0); + else + { + front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) + { + /* + Skip over some bytes to arrive at an aligned position. + We don't need to specially mark these wasted front bytes. + They will never be accessed anyway because + prev_inuse of av->top (and any chunk created from its start) + is always true after initialization. + */ + + aligned_brk += MALLOC_ALIGNMENT - front_misalign; + } + } + + /* Find out current end of memory */ + if (snd_brk == (char *) (MORECORE_FAILURE)) + { + snd_brk = (char *) (MORECORE (0)); + } + } + + /* Adjust top based on results of second sbrk */ + if (snd_brk != (char *) (MORECORE_FAILURE)) + { + av->top = (mchunkptr) aligned_brk; + set_head (av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); + av->system_mem += correction; + + /* + If not the first time through, we either have a + gap due to foreign sbrk or a non-contiguous region. Insert a + double fencepost at old_top to prevent consolidation with space + we don't own. These fenceposts are artificial chunks that are + marked as inuse and are in any case too small to use. We need + two to make sizes and alignments work out. + */ + + if (old_size != 0) + { + /* + Shrink old_top to insert fenceposts, keeping size a + multiple of MALLOC_ALIGNMENT. We know there is at least + enough space in old_top to do this. + */ + old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head (old_top, old_size | PREV_INUSE); + + /* + Note that the following assignments completely overwrite + old_top when old_size was previously MINSIZE. This is + intentional. We need the fencepost, even if old_top otherwise gets + lost. + */ + set_head (chunk_at_offset (old_top, old_size), + (2 * SIZE_SZ) | PREV_INUSE); + set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ), + (2 * SIZE_SZ) | PREV_INUSE); + + /* If possible, release the rest. */ + if (old_size >= MINSIZE) + { + _int_free (av, old_top, 1); + } + } + } + } + } + } /* if (av != &main_arena) */ + + ... + +} +``` +
+ +开头的else表示分配区的连续标志没有置位,这时只要按照MALLOC_ALIGNMENT做简单的对齐就行了,如果是通过brk分配的内存,则通过MORECORE (0)得到新分配的内存的结束地址并保存在snd_brk中。再往下进入if,设置分配区的top指针为经过对齐之后的起始地址aligned_brk,设置top chunk的大小size,aligned_brk表示对齐造成的误差,correction是因为要补偿原来top chunk剩余内存造成的误差,然后设置分配区已分配的内存大小。因为不连续,最后if内是设置原top chunk的fencepost,将原来top chunk的剩余空间拆成两个SIZE_SZ*2大小的chunk,如果剩下的大小大于可分配的chunk的最小值MINSIZE,就通过_int_free释放掉整个剩余内存。

+ +最后一部分代码如下: +``` +static void * sysmalloc(INTERNAL_SIZE_T nb, mstate av) { + + ... + + if ((unsigned long) av->system_mem > (unsigned long) (av->max_system_mem)) + av->max_system_mem = av->system_mem; + check_malloc_state (av); + + /* finally, do the allocation */ + p = av->top; + size = chunksize (p); + + /* check that one of the above allocation paths succeeded */ + if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) + { + remainder_size = size - nb; + remainder = chunk_at_offset (p, nb); + av->top = remainder; + set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); + set_head (remainder, remainder_size | PREV_INUSE); + check_malloced_chunk (av, p, nb); + return chunk2mem (p); + } + + /* catch all failure paths */ + __set_errno (ENOMEM); + return 0; +} +``` +
+ +这里就是获得前面所有代码更新后的top chunk,然后从该top chunk中分配用户需要的大小chunk并返回,如果失败则返回0。 +

+ +# 参考资料 +Ptmalloc2 源代码分析 华庭(庄明强) + +Linux 堆内存管理深入分析:https://murphypei.github.io/blog/2019/01/linux-heap + +glibc tcache 机制: https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/4.14_glibc_tcache.html + +malloc源码分析: https://introspelliam.github.io/2018/05/21/malloc%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E2%80%94%E2%80%941/ \ No newline at end of file diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..f9e78153583d08aed0e86770cc0cd80a1ec84c67 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc+malloc\346\272\220\347\240\201\347\256\200\346\236\220.md" @@ -0,0 +1,454 @@ +--- +title: glibc malloc源码简析(一) +date: 2021-01-29 +tags: + - glibc + - malloc +archives: 2021-01 +author: wangshuo +summary: 结合源码进一步分析glibc malloc原理,本文先对malloc的基本数据结构进行详细说明。 +--- +# 1 前言 +在上一篇文章中我们了解了glibc内存管理的基本原理,从本章开始,我们将在这一基础上深入代码细节对glibc的malloc/free操作作进一步分析。本文将结合glibc源码介绍malloc相关的数据结构。 + +软件信息如下: +|
软件项
|
版本信息
| +| :----:| :----: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +
+ +# 2 chunk +chunk原意是块,用在内存中表示的意思就是一块内存,chunk是glibc内存管理的最小单位,其定义如下: +``` +/* + This struct declaration is misleading (but accurate and necessary). + It declares a "view" into memory allowing access to necessary + fields at known offsets from a given base. See explanation below. +*/ + +struct malloc_chunk { + + INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ + + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; + + /* Only used for large blocks: pointer to next larger size. */ + struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ + struct malloc_chunk* bk_nextsize; +}; +``` +chunk的的结构十分巧妙,通过空间复用,能在占用最少的空间的情况下实现malloc的内存管理算法。空闲时,一个 chunk 中至少需要 4个size_t大小的空间,用来存储mchunk_prev_size,mchunk_size,fd和bk。当一个 chunk 处于使用状态时,它的下一个chunk的prev_size域肯定是无效的。所以实际上,这个空间也可以被当前chunk使用。 + +上文提到mchunk_size后三位作为标志位分别用于表示前一个chunk的使用情况、chunk的申请方式(brk或mmap)和分配区归属情况,glibc给出了如下宏定义用于确定标志位的信息。 +``` +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ +#define PREV_INUSE 0x1 + +/* extract inuse bit of previous chunk */ +#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE) + + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ +#define IS_MMAPPED 0x2 + +/* check for mmap()'ed chunk */ +#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED) + + +/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained + from a non-main arena. This is only set immediately before handing + the chunk to the user, if necessary. */ +#define NON_MAIN_ARENA 0x4 +``` +
+ +# 3 bin +为了提高堆内存分配和释放的效率,glibc的malloc引入了显示链表技术来管理chunk。所谓的显示链表就是我们在数据结构中常用的链表,而链表本质上就是将一些属性相同的结点串联起来,方便管理。在glibc的malloc中这些链表统称为bin,链表中的结点就是各个 free的chunk,系统针对不同大小的free chunk,将bin分为了4类: +
    fast bin +
    unsorted bin +
    small bin +
    large bin + +按照bin的管理方式,又可以分别为以下两类: +
    fastbinsY: 这是一个数组,用于记录所有小块chunk,大小无规律 +
    bin 数组: 这也是一个数组,用于记录颗粒相对较大的chunk。默认有126个元素(bin[0]和bin[127]未使用),分别是: +
        [1] 为 unsorted bin +
        [2~63] 为 small bin +
        [64~126] 为 large bin + +从上文可知,free chunk中存在fd和bk指针,因此bin得以通过这一结构成为双向链表。bin的初始化操作如下: +``` +/* + Initialize a malloc_state struct. + + This is called from ptmalloc_init () or from _int_new_arena () + when creating a new arena. + */ + +static void +malloc_init_state (mstate av) +{ + int i; + mbinptr bin; + + /* Establish circular links for normal bins */ + for (i = 1; i < NBINS; ++i) + { + bin = bin_at (av, i); + bin->fd = bin->bk = bin; + } + + ... + +} +``` +从上面代码可以看出在初始化的时候glibc的malloc将所有bin的指针都指向了自己——这就代表这些bin都是空的。需要注意的是,在初始化时,将bin数组中的第一个成员索引值设置为了1,而不是0,这个从下面访问unsorted bin的定义可以进一步证实。 +``` +... + +/* + Unsorted chunks + + All remainders from chunk splits, as well as all returned chunks, + are first placed in the "unsorted" bin. They are then placed + in regular bins after malloc gives them ONE chance to be used before + binning. So, basically, the unsorted_chunks list acts as a queue, + with chunks being placed on it in free (and malloc_consolidate), + and taken off (to be either used or placed in bins) in malloc. + + The NON_MAIN_ARENA flag is never set for unsorted chunks, so it + does not have to be taken into account in size comparisons. + */ + +/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ +#define unsorted_chunks(M) (bin_at (M, 1)) + +... + +/* addressing -- note that bin_at(0) does not exist */ +#define bin_at(m, i) \ + (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2])) \ + - offsetof (struct malloc_chunk, fd)) + +... + +``` +
+ +## 3.1 fastbin +fastbin主要是用于提高小内存的分配效率,在引入tcache之前,fastbin是内存申请和释放时首要访问的结构。fastbin的规格定义如下: +``` +/* offset 2 to use otherwise unindexable first 2 bins */ +#define fastbin_index(sz) \ + ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2) + + +/* The maximum fastbin request size we support */ +#define MAX_FAST_SIZE (80 * SIZE_SZ / 4) + +#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1) +``` +以64位平台为例,fastbin链表数目为10,所能放置的最大chunk为160字节,glibc默认通过global_max_fast全局变量将最大chunk值限制到128字节。因此,默认情况下大小为16到128字节,公差为16的chunk将被分类到fast chunk。 + +每个fast bin都是一个单链表,内存申请释放时按照LIFO(后入先出)算法进行操作,添加操作(free 内存)就是将新的fast chunk加入链表尾,删除操作(malloc 内存)就是将链表尾部的fast chunk删除。为了实现LIFO算法,fastbinsY数组中每个fastbin元素均指向了该链表的尾结点,而尾结点通过其fd指针指向前一个结点,依次类推。 + +另外,为了保证小块内存申请释放的性能,fast bin不会对free chunk进行合并操作(chunk的合并操作将在后续详细分析),因此当free chunk被放入fastbin时, 系统会保留其使用标志位以避免自动合并操作。 +
+ +## 3.2 smallbin +smallbin用于管理相对小块的chunk,以64位平台为例,smallbin管理的chunk大小小于1024字节。smallbin的特点如下: +
    1、smallbin共有62个。每个smallbin为循环双链表,采用FIFO(先入先出)算法:内存释放操作就将新释放的chunk添加到链表的前端,分配操作就从链表的尾端中获取chunk。 +
    2、同一个smallbin中所有chunk大小是一样的。 +
    3、相邻的freechunk需要进行合并操作,即合并成一个大的freechunk。 + +通过如下宏可以确定当前chunk是否属于smallbin以及在smallbin中的索引: +``` +#define NSMALLBINS 64 +#define SMALLBIN_WIDTH MALLOC_ALIGNMENT +#define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > 2 * SIZE_SZ) +#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH) + +#define in_smallbin_range(sz) \ + ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE) + +... + +#define smallbin_index(sz) \ + ((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\ + + SMALLBIN_CORRECTION) +``` +以64位平台为例,第一个smallbin中chunk大小为 32 ~ 47 字节,后续每个smallbin中chunk的大小依次增加16字节,即最后一个smallbin的chunk最小值为 32+62*16=1008 字节。 +
+ +## 3.3 largebin +largebin用于管理相对大块的chunk,以64位平台为例,largebin管理的chunk大小大于等于1024字节的chunk,largebin的特点如下: +
    1、large bin 总共有63个。largebin类似于smallbin,只是需要注意两点:一是同一个largebin中每个chunk的大小可以不一样,但必须处于某个给定的范围;二是largechunk可以添加、删除在largebin的任何一个位置。 +
    2、largebin的合并操作类似于smallbin。 + +通过如下宏可以确定当前chunk是否属于largebin以及在largebin中的索引: +``` +#define largebin_index_32(sz) \ + (((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\ + ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ + ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ + ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ + ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ + 126) + +#define largebin_index_32_big(sz) \ + (((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\ + ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ + ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ + ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ + ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ + 126) + +// XXX It remains to be seen whether it is good to keep the widths of +// XXX the buckets the same or whether it should be scaled by a factor +// XXX of two as well. +#define largebin_index_64(sz) \ + (((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\ + ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ + ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ + ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ + ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ + 126) + +#define largebin_index(sz) \ + (SIZE_SZ == 8 ? largebin_index_64 (sz) \ + : MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \ + : largebin_index_32 (sz)) +``` +从以上定义可以看出,largebin中chunk链表的大小不是单纯的递增关系。以64位平台为例,前32个largebin依次以64字节步长为间隔,即第一个largebin中chunksize为 1024 ~ 1087 字节。。。第二个largebin中chunksize为 1088 ~ 1151 字节。紧随其后的16个largebin依次以512字节步长为间隔;之后的8个bin以步长4096为间隔;再之后的4个bin以32768字节为间隔;之后的2个bin以262144字节为间隔;剩下的chunk就放在最后一个largebin中。鉴于同一个largebin中每个chunk的大小不一定相同,因此为了加快内存分配和释放的速度,就将同一个largebin中的所有chunk按照chunksize进行从大到小的排列:最大的chunk放在链表的前端,最小的chunk放在尾端。 + +当用户请求的大小超过smallbin的最大值时将进入largebin的判断逻辑,具体来说就是找到用户请求的大小落在哪个largebin的区间,然后判断该largebin中最大的chunk的size是否大于用户请求的大小。如果大于,就从尾部开始遍历该largebin,找到第一个大小相等或接近的chunk,分配给用户;如果尾端最小的chunk大于用户请求的大小的话,就将该chunk拆分为两个chunk:前者返回给用户,大小等同于用户请求的大小,剩余的部分做为一个新的chunk添加到unsortedbin中;如果该largebin中最大的chunk的大小小于用户请求的大小的话,那么就依次查看后续的largebin中是否有满足需求的chunk。 + +另外,为了提高检索速度,glibc malloc引入了binmap,其定义和使用方式如下: +``` + /* Bitmap of bins */ + unsigned int binmap[BINMAPSIZE]; + +... + +#define mark_bin(m, i) ((m)->binmap[idx2block (i)] |= idx2bit (i)) +#define unmark_bin(m, i) ((m)->binmap[idx2block (i)] &= ~(idx2bit (i))) +#define get_binmap(m, i) ((m)->binmap[idx2block (i)] & idx2bit (i)) +``` +binmap记录了各个bin中是否为空,通过位图算法可以避免检索一些空的bin。如果通过binmap找到了下一个非空的largebin的话,就按照上一段中的方法分配chunk,否则就使用topchunk来分配合适的内存,后者的分配方式将在后续详细讲解。 +
+ +## 3.4 unsortedbin +unsortedbin顾名思义,为大小无规律的bin链表。当释放较小或较大的chunk的时候,如果系统没有将它们添加到对应的bin中系统就将这些chunk添加到unsortedbin中。利用unsortedbin,可以加快内存的分配和释放操作,因为整个操作都不再需要花费额外的时间去查找合适的bin了。unsortedbin的特性如下: +
    1、unsortedbin只有1个,unsortedbin是一个由freechunk组成的循环双链表。 +
    2、不同于其他的bin,在unsortedbin中,对chunk的大小并没有限制,任何大小的chunk都可以归属到unsortedbin中。 + +unsorted chunks的访问方式如下,为了便于管理,glibc malloc将bin链表中的bin[1]设置为了unsorted chunk的链表头。 +``` +/* + Unsorted chunks + + All remainders from chunk splits, as well as all returned chunks, + are first placed in the "unsorted" bin. They are then placed + in regular bins after malloc gives them ONE chance to be used before + binning. So, basically, the unsorted_chunks list acts as a queue, + with chunks being placed on it in free (and malloc_consolidate), + and taken off (to be either used or placed in bins) in malloc. + + The NON_MAIN_ARENA flag is never set for unsorted chunks, so it + does not have to be taken into account in size comparisons. + */ + +/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ +#define unsorted_chunks(M) (bin_at (M, 1)) +``` +
+ + + +# 4 arena +arena原本的翻译是竞技场,网上一般都将glibc中的arena翻译成分配区。arena被用于降低SMP多线程环境下锁竞争激烈的问题。分配区分为主分配区和thread分配区,前者每个进程仅有一个,其余均为thread分配区。glibc malloc根据系统对分配区的争用情况动态增加thread分配区的数量,分配区的数量一旦增加,就不会再减少了。主分配区可以访问进程的heap区域和mmap映射区域,也就是说主分配区可以使用sbrk和mmap向操作系统申请虚拟内存。而thread分配区只能访问进程的mmap映射区域,thread分配区每次使用mmap()向操作系统“批发”HEAP_MAX_SIZE(64位系统默认为64MB)大小的虚拟内存,当用户向thread分配区请求分配内存时再切割成小块“零售”出去以减少系统调用开销。 +``` +/* + have_fastchunks indicates that there are probably some fastbin chunks. + It is set true on entering a chunk into any fastbin, and cleared early in + malloc_consolidate. The value is approximate since it may be set when there + are no fastbin chunks, or it may be clear even if there are fastbin chunks + available. Given it's sole purpose is to reduce number of redundant calls to + malloc_consolidate, it does not affect correctness. As a result we can safely + use relaxed atomic accesses. + */ + + +struct malloc_state +{ + /* Serialize access. */ + __libc_lock_define (, mutex); + + /* Flags (formerly in max_fast). */ + int flags; + + /* Set if the fastbin chunks contain recently inserted free blocks. */ + /* Note this is a bool but not all targets support atomics on booleans. */ + int have_fastchunks; + + /* Fastbins */ + mfastbinptr fastbinsY[NFASTBINS]; + + /* Base of the topmost chunk -- not otherwise kept in a bin */ + mchunkptr top; + + /* The remainder from the most recent split of a small request */ + mchunkptr last_remainder; + + /* Normal bins packed as described above */ + mchunkptr bins[NBINS * 2 - 2]; + + /* Bitmap of bins */ + unsigned int binmap[BINMAPSIZE]; + + /* Linked list */ + struct malloc_state *next; + + /* Linked list for free arenas. Access to this field is serialized + by free_list_lock in arena.c. */ + struct malloc_state *next_free; + + /* Number of threads attached to this arena. 0 if the arena is on + the free list. Access to this field is serialized by + free_list_lock in arena.c. */ + INTERNAL_SIZE_T attached_threads; + + /* Memory allocated from the system in this arena. */ + INTERNAL_SIZE_T system_mem; + INTERNAL_SIZE_T max_system_mem; +}; +``` +分配区的定义如上所示,从定义中我们可看到上文提到的fastbinsY、bins等结构。可以看出,分配区实际上可以理解为glibc malloc数据的根管理结构,从分配区出发,不同大小的内存块被保存在不同类型的链表中,从而应对用户不同的内存需求,并实现内存碎片和性能的折中。 + +需要注意的是分配区中的top成员,我们称其为top chunk,top chunk处于一个arena的最顶部(即最高内存地址处)。该chunk并不属于任何bin,而是在当前的heap所有的freechunk都无法满足用户请求的内存大小的时候,将此chunk当做一个应急消防员,分配给用户使用。如果top chunk的大小比用户请求的大小要大的话,就仅从top chunk中切分出一部分给用户,剩余的部分仍做top chunk。否则,就需要扩展heap或分配新的heap了,在主分配区中通过sbrk扩展heap,而在thread分配区中通过mmap分配新的heap。 + +``` +/* + Top + + The top-most available chunk (i.e., the one bordering the end of + available memory) is treated specially. It is never included in + any bin, is used only if no other chunk is available, and is + released back to the system if it is very large (see + M_TRIM_THRESHOLD). Because top initially + points to its own bin with initial zero size, thus forcing + extension on the first malloc request, we avoid having any special + code in malloc to check whether it even exists yet. But we still + need to do so when getting memory from system, so we make + initial_top treat the bin as a legal but unusable chunk during the + interval between initialization and the first call to + sysmalloc. (This is somewhat delicate, since it relies on + the 2 preceding words to be zero during this interval as well.) + */ + +/* Conveniently, the unsorted bin can be used as dummy top on first call */ +#define initial_top(M) (unsorted_chunks (M)) +``` +top chunk的初始化定义如上,可以看出glibc暂时把top chunk看做一个unsorted chunk来初始化,当然,后续使用的时候还是认为top chunk不属于任何bin。 +
+ +# 5 heap +上文提到thread分配区每次使用mmap()向操作系统“批发”HEAP_MAX_SIZE(64位系统默认为64MB)大小的虚拟内存,这部分内存在glibc中被称为heap。需要注意的是,此处的heap并非广义上的进程的虚拟内存空间中的堆,而是子线程通过系统调用mmap从操作系统申请的一块内存空间。一块heap由heap_info来管理,其定义如下: +``` +/* A heap is a single contiguous memory region holding (coalesceable) + malloc_chunks. It is allocated with mmap() and always starts at an + address aligned to HEAP_MAX_SIZE. */ + +typedef struct _heap_info +{ + mstate ar_ptr; /* Arena for this heap. */ + struct _heap_info *prev; /* Previous heap. */ + size_t size; /* Current size in bytes. */ + size_t mprotect_size; /* Size in bytes that has been mprotected + PROT_READ|PROT_WRITE. */ + /* Make sure the following data is properly aligned, particularly + that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of + MALLOC_ALIGNMENT. */ + char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK]; +} heap_info; +``` +在当前heap不够用的时候,malloc会通过系统调用mmap申请新的heap,同一个thread分配区至少有一个heap,heap与heap直接也通过链表的形式穿起来,当出现空heap时glibc又可以将其回收。 +
+ + +# 6 tcache +tcache全名thread local caching,2.26版本正式引入,具体commitd5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc。该机制通过给每个线程创建一个缓存,实现无锁的分配算法,用于提升性能,目前openEuler的glibc默认开启,用户可以在编译时通过USE_TCACHE条件来设置tcache机制开启或关闭。 + +tcache引入了两个新的数据结构:tcache_entry和tcache_perthread_struct,具体定义如下: +``` +#if USE_TCACHE + +/* We overlay this structure on the user-data portion of a chunk when + the chunk is stored in the per-thread cache. */ +typedef struct tcache_entry +{ + struct tcache_entry *next; + /* This field exists to detect double frees. */ + struct tcache_perthread_struct *key; +} tcache_entry; + +/* There is one of these for each thread, which contains the + per-thread cache (hence "tcache_perthread_struct"). Keeping + overall size low is mildly important. Note that COUNTS and ENTRIES + are redundant (we could have just counted the linked list each + time), this is for performance reasons. */ +typedef struct tcache_perthread_struct +{ + char counts[TCACHE_MAX_BINS]; + tcache_entry *entries[TCACHE_MAX_BINS]; +} tcache_perthread_struct; + +static __thread bool tcache_shutting_down = false; +static __thread tcache_perthread_struct *tcache = NULL; + +... + +#endif +``` + +tcache_perthread_struct包含一个数组entries,用于放置bins,bins的数目定义如下,可知默认可存放64个bins,数组 counts存放每个bins中的chunk数量。每个被放入相应bins中的chunk都会在其用户数据中包含一个tcache_entry(FD指针),指向同 bins 中的下一个 chunk,构成单链表。 + +值得注意的比如每个线程默认使用64个单链表结构的bins,每个bins最多存放7个chunk。chunk的大小在64位机器上以16字节递增,从24到1032 字节。32位机器上则是以8字节递增,从12到512字节。所以tcache bin只用于存放non-large的chunk。 +``` +#if USE_TCACHE +/* We want 64 entries. This is an arbitrary limit, which tunables can reduce. */ +# define TCACHE_MAX_BINS 64 +# define MAX_TCACHE_SIZE tidx2usize (TCACHE_MAX_BINS-1) + +/* Only used to pre-fill the tunables. */ +# define tidx2usize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE - SIZE_SZ) + +/* When "x" is from chunksize(). */ +# define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT) +/* When "x" is a user-provided size. */ +# define usize2tidx(x) csize2tidx (request2size (x)) + +/* With rounding and alignment, the bins are... + idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit) + idx 1 bytes 25..40 or 13..20 + idx 2 bytes 41..56 or 21..28 + etc. */ + +/* This is another arbitrary limit, which tunables can change. Each + tcache bin will hold at most this number of chunks. */ +# define TCACHE_FILL_COUNT 7 +#endif +``` +
+ +# 参考资料 +Ptmalloc2 源代码分析 华庭(庄明强) + +Linux 堆内存管理深入分析:https://murphypei.github.io/blog/2019/01/linux-heap + +glibc tcache 机制: https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/4.14_glibc_tcache.html diff --git "a/web-ui/docs/zh/blog/wangshuo/glibc\351\227\256\351\242\230\345\256\232\344\275\215--\346\216\250\346\240\210\351\227\256\351\242\230\345\210\206\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/glibc\351\227\256\351\242\230\345\256\232\344\275\215--\346\216\250\346\240\210\351\227\256\351\242\230\345\210\206\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..1f8849c5825984ba29f07fb59096dc190fbe0016 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/glibc\351\227\256\351\242\230\345\256\232\344\275\215--\346\216\250\346\240\210\351\227\256\351\242\230\345\210\206\346\236\220.md" @@ -0,0 +1,383 @@ +--- +title: glibc问题定位--malloc调用栈问题分析 +date: 2021-03-13 +tags: + - glibc +archives: 2021-03 +author: wangshuo +summary: 通过一个案例介绍glibc的社区bug以及修复策略,同时介绍aarch64架构下推栈相关的知识 +--- + +# 1 概述 +在某业务场景通过gdb调试进入malloc函数获取调用栈时,发现调用栈信息无法显示,后经过定位发现是社区bug,因此向社区推送了修改方案,并在2.28-50版本将该补丁回合,本文将介绍这一bug的原因及解决方案。
+软件信息如下: +|
软件项
|
版本信息
| +| :------------------------------------:| :--------------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1.aarch64
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +

+ +# 2 问题背景 +在某业务场景中,当malloc函数中打调用栈时,应用层的栈信息丢失,如下所示。已确认安装了debuginfo包,且由于已经使用了unwind推栈算法,因此也不是-fomit-frame-pointer选项的问题。 +``` +(gdb) b malloc +Breakpoint 2 at 0xfffff7e0d198: malloc. (2 locations) +(gdb) c +Continuing. + +Thread 2 "xxxxxxx" hit Breakpoint 2, __GI___libc_malloc (bytes=10532) at malloc.c:3039 +3039 = atomic_forced_read (__malloc_hook); +(gdb) bt +#0 __GI___libc_malloc (bytes=10532) at malloc.c:3039 +#1 0x0000fffff7fce484 in allocate_dtv_entry (size=, alignment=64) + at dl-tls.c:594 +#2 allocate_and_init (map=0x4212c0) at dl-tls.c:607 +#3 tls_get_addr_tail (ti=0x424050, dtv=0x425200, the_map=0x4212c0) at dl-tls.c:787 +#4 0x0000fffff7fd2e90 in _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:214 +#5 0x0000fffff6dfab44 in OurFunction (threadId=10532) + at /home/test/test_function.c:30 +#6 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +``` +
+ +从现有的信息可以发现此次malloc并非业务直接调用,而是_dl_tlsdesc_dynamic这个glibc提供的函数间接调用。对比业务得知该语句发生在给线程变量赋值时。查阅资料,结合业务了解到这部分涉及线程局部存储(Thread Local Storage,TLS)的初始化操作,因此malloc函数本身的嫌疑下降,问题更有可能出现在_dl_tlsdesc_dynamic。
+而后我们将该业务场景抽象成一个demo,复现了该问题,精确定位到问题发生在位于sysdeps/aarch64/dl-tlsdesc.S的_dl_tlsdesc_dynamic函数,具体来说,在进入该函数后才发生了推栈失败现象。同时,异常点有两处,第一处如下: + +``` +Thread 2 "xxxxxxx" hit Breakpoint 1, _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +149 stp x1, x2, [sp, #-32]! +Missing separate debuginfos, use: dnf debuginfo-install libgcc-7.3.0-20190804.h24.aarch64 +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +150 stp x3, x4, [sp, #16] +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +157 mrs x4, tpidr_el0 +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=3194870184) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +``` +同时,当离开150行的语句后,调用栈信息恢复。第二处异常如下: +``` +Thread 2 "xxxxxxx" hit Breakpoint 1, _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:149 +149 stp x1, x2, [sp, #-32]! +Missing separate debuginfos, use: dnf debuginfo-install libgcc-7.3.0-20190804.h24.aarch64 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:150 +150 stp x3, x4, [sp, #16] +(gdb) +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:157 +157 mrs x4, tpidr_el0 +(gdb) +158 ldr PTR_REG (1), [x0,#TLSDESC_ARG] +(gdb) +159 ldr PTR_REG (0), [x4,#TCBHEAD_DTV] +(gdb) +160 ldr PTR_REG (3), [x1,#TLSDESC_GEN_COUNT] +(gdb) +161 ldr PTR_REG (2), [x0,#DTV_COUNTER] +(gdb) +162 cmp PTR_REG (3), PTR_REG (2) +(gdb) +163 b.hi 2f +(gdb) +165 ldp PTR_REG (2), PTR_REG (3), [x1,#TLSDESC_MODID] +(gdb) +166 add PTR_REG (0), PTR_REG (0), PTR_REG (2), lsl #(PTR_LOG_SIZE + 1) +(gdb) +167 ldr PTR_REG (0), [x0] /* Load val member of DTV entry. */ +(gdb) +168 cmp PTR_REG (0), #TLS_DTV_UNALLOCATED +(gdb) +169 b.eq 2f +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:169 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=4294967295) + at /home/test/test_function.c:30 +#2 0x0000000000400c08 in initaaa () at thread.c:58 +#3 0x0000000000400c50 in thread_proc (param=0x0) at thread.c:71 +#4 0x0000ffffbf6918bc in start_thread (arg=0xfffffffff29f) at pthread_create.c:486 +#5 0x0000ffffbf5669ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 +(gdb) ni +_dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:184 +184 stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]! +(gdb) bt +#0 _dl_tlsdesc_dynamic () at ../sysdeps/aarch64/dl-tlsdesc.S:184 +#1 0x0000ffffbe4fbb44 in OurFunction (threadId=4294967295) + at /home/test/test_function.c:30 +#2 0x0000000000000000 in ?? () +Backtrace stopped: previous frame identical to this frame (corrupt stack?) +``` +从184行开始,调用栈信息无法打出,直到离开_dl_tlsdesc_dynamic函数。

+ + +# 3 流程梳理 +这里我们简单梳理一下_dl_tlsdesc_dynamic函数的流程。_dl_tlsdesc_dynamic函数架构相关,此次异常实现位于sysdeps/aarch64/dl-tlsdesc.S目录下,该函数由汇编实现,但是代码编写人员很贴心地以注释形式提供了该函数的C语言实现,具体如下: +``` + /* Handler for dynamic TLS symbols. + Prototype: + _dl_tlsdesc_dynamic (tlsdesc *) ; + + The second word of the descriptor points to a + tlsdesc_dynamic_arg structure. + + Returns the offset between the thread pointer and the + object referenced by the argument. + + ptrdiff_t + __attribute__ ((__regparm__ (1))) + _dl_tlsdesc_dynamic (struct tlsdesc *tdp) + { + struct tlsdesc_dynamic_arg *td = tdp->arg; + dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + TCBHEAD_DTV); + if (__builtin_expect (td->gen_count <= dtv[0].counter + && (dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED), + 1)) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset + - __thread_pointer; + + return ___tls_get_addr (&td->tlsinfo) - __thread_pointer; + } + */ +``` +
+ +可以看出,该函数用于返回线程指针与参数引用的对象之间的偏移量。具体采用了两个分支来实现,官方称之为“fast path”和“slow path”,判断条件为gen计数变量为超过限值以及TLS已完成初始化,满足即可走fast path,反之走slow path,本次问题就发生在后者,具体来说,第一处异常发生在进入_dl_tlsdesc_dynamic,第二处异常发生在判断需要执行slow path,发生跳转的地方。另外,我们曾尝试不依赖业务场景编写demo复现走slow path的逻辑,但是没有成功,这部分如果有专业人士明白如何执行到也希望能不吝赐教。

+ + +# 4 调用栈背景知识 +由于此次问题设计arm架构下的推栈操作,这里有必要对推栈原理进行简单介绍。

+## 4.1 寄存器与汇编指令 +以aarch64为例,aarch拥有31个通用寄存器,系统运行在64位状态下的时候名字叫Xn,运行在32位的时候就叫Wn。按照功能又分为:参数寄存器(X0-X7)、来电保存的临时寄存器(X9-X15)、被调用者保存的寄存器(X19-X29)和特殊用途寄存器(X8,X16-X18,X29,X30),此次我们重点关注特殊用途寄存器:
+    X8: 是间接结果寄存器,用于保存子程序返回地址
+    X16和X17: 程序内调用临时寄存器
+    X18: 平台寄存器,保留用于平台
+    X29: 帧指针寄存器(FP)
+    X30: 链接寄存器(LR)
+    X31: 堆栈指针寄存器SP或零寄存器ZXR
+
+ +## 4.2 推栈原理 +这里以一个main函数调用func1为例,其调用栈如下图所示,每个函数都有自己的栈空间,这一部分我们称为栈帧,在函数被调用的时候创建,在函数返回后销毁。其中我们看到这其中涉及到四个比较关键的寄存器:PC、LR、SP、FP。需要注意的是,每个栈帧中的PC、LR、SP、FP都是寄存器的历史值,而不是当前值。 +``` + ________________ /_________________ + | | \ | + memory: | PC | | +high address |________________| | + /|\ | | | + | | LR | | + | |________________| | + | | | | + | | SP | | + | |________________| | + | | | | + | | FP | | + | |________________| | + | | | | + | main | main:argc | | + | |________________| | + | | | | + | | main:argv | | + | |________________| | + | | | | + | | main:val:i | | + | |________________| | + | | | | + | | main:val:j | | + | |________________| | + | | | | + | | func1 param | | + | ________\ |________________| /________ | + | / | | \ | | + | | PC | | | + | |________________| | | + | | | | | + | | LR | | | + | |________________| | | + | func1 | | _________| | + | | SP | | + | |________________| | + | | | _________________| + | | FP | + | |________________| + | | | + | | func1 val:p1 | + | |________________| + | | | + memory: | func1 val:p2 | +low address |________________| + | | + | func1 val:p3 | + |________________| + 栈顶 +``` +
+PC寄存器和LR寄存器均指向代码段,PC表示当前的代码指向到何处,LR表示当前函数返回后要到哪里去继续执行。SP和FP用于维护函数的栈空间,其中SP指向栈顶,FP指向上一个函数栈帧的栈顶。如果函数准备调用另一个函数,跳转之前临时变量区先要保存另一个函数的参数。在栈回溯的过程中,我们主要是利用的是这个FP寄存器进行回溯,因为根据FP寄存器就可以找到下一个FP寄存器的栈底,获得PC指针,然后固定偏移,又可以回溯到上个PC指针,这样回溯下去,然后就可以完全的跟踪到函数的运行过程了。

+ + +# 5 解决方案简析 +## 5.1 结论 +进过定位分析,该问题系社区缺陷,我们已向社区提交了补丁(commit ID:cd62740 和 f5082c7),与社区沟通情况见下链接:
+https://sourceware.org/pipermail/libc-alpha/2021-January/121272.html
+https://sourceware.org/pipermail/libc-alpha/2021-January/121330.html

+ +## 5.2 分析 +上文提过,此次问题涉及两处异常点,后经过定位证明确实是两处bug,这里分别这两处进行介绍。
+第一处异常点是刚跳转到_dl_tlsdesc_dynamic函数时产生的,涉及的代码如下: +``` +144 _dl_tlsdesc_dynamic: +145 DELOUSE (0) +146 +147 /* Save just enough registers to support fast path, if we fall +148 into slow path we will save additional registers. */ +149 stp x1, x2, [sp, #-32]! +150 stp x3, x4, [sp, #16] +151 cfi_adjust_cfa_offset (32) +152 cfi_rel_offset (x1, 0) +153 cfi_rel_offset (x2, 8) +``` +具体来说,是执行到第150行时推栈失败,执行完了之后又可以正常推栈。这里我们注意一下第151行,这是一个cfi宏,实际运行时并不会执行到,其作用是知会调试器当前CFA与刚进入此函数时的基CFA的编译,至于CFA (Canonical Frame Address),我们可以简单地将其理解为上一级调用者的堆栈指针。

+在151行之前,是两个stp操作,149行表示将x1和x2寄存器的值存入sp偏移32个字节的位置,同时sp也做出相应偏移,由于栈是从高地址向低地址生长,因此是-32。第150行将x3和x4寄存器的值入栈,并且没有更新sp。结合刚才关于cfi的介绍可知,在149行时sp被更新,但是原来的代码没有及时向调试器知会这一变动从而导致了150行推栈失败,又由于在执行完150行之后进行了申明,因此后面又可以正常推栈,我们调整了cfi宏的位置,第一个异常解决。

+ +在定位第二处异常时我们发现其发生在跳转结束之后,对应代码如下: +``` +169 b.eq 2f +170 sub PTR_REG (3), PTR_REG (3), PTR_REG (4) +171 add PTR_REG (0), PTR_REG (0), PTR_REG (3) +172 1: +173 ldp x3, x4, [sp, #16] +174 ldp x1, x2, [sp], #32 +175 cfi_adjust_cfa_offset (-32) +176 RET +177 2: +178 /* This is the slow path. We need to call __tls_get_addr() which +179 means we need to save and restore all the register that the +180 callee will trash. */ +181 +182 /* Save the remaining registers that we must treat as caller save. */ +183 # define NSAVEXREGPAIRS 8 +184 stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]! +185 cfi_adjust_cfa_offset (16*NSAVEXREGPAIRS) +186 cfi_rel_offset (x29, 0) +187 cfi_rel_offset (x30, 8) +``` +具体为第169行跳转到184行时,一直到此函数运行结束之前都再也无法正常推栈。我们在同目录下找到了另一个功能类似的文件,其源码如下: +``` +sysdeps/aarch64/dl-trampoline.S + +219 bge 1f +220 cfi_remember_state +221 +222 /* Save the return. */ +223 mov ip0, x0 +224 +225 /* Get arguments and return address back. */ +226 ldp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0] +227 ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] +228 ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] +229 ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +230 ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +231 ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +232 ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +233 ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] +234 +235 cfi_def_cfa_register (sp) +236 ldp x29, x30, [x29, #0] +237 cfi_restore(x29) +238 cfi_restore(x30) +239 +240 add sp, sp, SF_SIZE + 16 +241 cfi_adjust_cfa_offset (- SF_SIZE - 16) +242 +243 /* Jump to the newly found address. */ +244 br ip0 +245 +246 cfi_restore_state +247 1: +248 /* The new frame size is in ip0. */ +``` +
+ +可以发现,同样是跳转,在第220行和246行,该逻辑分别使用了cfi_remember_state和cfi_restore_state宏。binutils的官网给出了这两个宏的使用场景,具体表述如下。简单来说就是aarch64如果需要推栈,则在跳转前应通过cfi_remember_state保存推栈相关寄存器的状态,跳转后通过cfi_restore_state宏恢复这个状态,加上这对宏之后,问题解决。 +``` +7.11.20 .cfi_remember_state and .cfi_restore_state +.cfi_remember_state pushes the set of rules for every register onto an implicit stack, while .cfi_restore_state pops them off the stack and places them in the current row. This is useful for situations where you have multiple .cfi_* directives that need to be undone due to the control flow of the program. For example, we could have something like this (assuming the CFA is the value of rbp): + + je label + popq %rbx + .cfi_restore %rbx + popq %r12 + .cfi_restore %r12 + popq %rbp + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 + ret +label: + /* Do something else */ +Here, we want the .cfi directives to affect only the rows corresponding to the instructions before label. This means we’d have to add multiple .cfi directives after label to recreate the original save locations of the registers, as well as setting the CFA back to the value of rbp. This would be clumsy, and result in a larger binary size. Instead, we can write: + + je label + popq %rbx + .cfi_remember_state + .cfi_restore %rbx + popq %r12 + .cfi_restore %r12 + popq %rbp + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 + ret +label: + .cfi_restore_state + /* Do something else */ +That way, the rules for the instructions after label will be the same as before the first .cfi_restore without having to use multiple .cfi directives. +``` +
+ +# 6 小结 +此次碰到的问题属于社区代码的疏漏,由于之前也没有碰到类似问题,因此主要还是依靠参考正常代码的逻辑,配合收集现有的相关资料来解决。对于比较生冷的问题场景,这种思路都适用。

+ +# 参考资料 +binutils官方说明:https://sourceware.org/binutils/docs/as/CFI-directives.html
+ARMv8-aarch64 寄存器和指令集:https://winddoing.github.io/post/7190.html
+arm上backtrace的分析与实现原理:https://cloud.tencent.com/developer/article/1599605
+Unwind 栈回溯详解:https://blog.csdn.net/pwl999/article/details/107569603
+
+ +# glibc相关文章推荐 +glibc malloc系列文章:
+    原理简析:https://cutt.ly/NzcDUEd
+    数据结构:https://cutt.ly/JzcSBfB
+    malloc:https://cutt.ly/TzcSjUX
+    free:https://cutt.ly/QzcSy5G
+
+ +glibc问题定位与分析系列文章:
+    memcpy 1k字节x86_64虚拟机性能下降分析:https://cutt.ly/8zcDyPi
+
+ +glibc locale使用简析:https://cutt.ly/wxoH9OG
+
\ No newline at end of file diff --git "a/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex.jpg" "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..99c94f57a596c0fc686b02a8a5cc4a7e77ef42e0 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wait.jpg" "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wait.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..c5acaa0ee0916b5c2f6ee22715428d7f7ed86cd6 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wait.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wake.jpg" "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wake.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..c6c080f69f484c5ff422a32cd576bd998d83cb0f Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/futex_wake.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..0cbf4bd02ceac239b65b5df2e05e0526ed84def8 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220/linux--futex\345\216\237\347\220\206\345\210\206\346\236\220.md" @@ -0,0 +1,313 @@ +--- +title: linux--futex原理分析 +date: 2021-06-1 +tags: + - linux + - kernel + - futex +archives: 2021-06 +author: wangshuo +summary: 结合futex源码介绍futex的基本功能 +--- +# 前言 +Futex是Fast Userspace mutexes的缩写,翻译过来就是快速用户空间互斥体。其设计思想是通过增加在用户态原子检查来决定是否陷入内核进行wait。关于用户态的逻辑这里暂且不表,接下来本文将结合linux源码介绍futex的基本功能。 +
+ +软件信息如下: +|
软件项
|
版本信息
| +| :------------------------------------:| :--------------------------------------------------------------: | +|
OS
|
openEuler 20.03 (LTS)
| +|
kernel
|
4.19.90-2003.4.0.0036.oe1.aarch64
| +|
glibc
|
2.28
| +|
gcc
|
7.3.0
| +

+ + +# 原理简介 +Futex是一种用户态和内核态混合的同步机制,支持进程内的线程之间和进程间的同步锁操作。当用于线程同步时,因为线程共享虚拟内存空间,虚拟地址就可以唯一的标识出futex变量,即线程用同样的虚拟地址来访问futex变量。当用于进程间时,进程有独立的虚拟内存空间,因此只有通过mmap()让它们共享同一段物理地址空间来使用futex变量。
+以进程同步为例,首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不用再执行系统调用,仅当通过访问futex变量告诉进程有竞争发生时,才执行系统调用去完成相应的处理。
+当任务需要陷入内容等待时最终会调用futex_wait,当需要唤醒其它任务时最终会调用futex_wake,这两个函数完成了最基本的futex机制,其简化版的定义如下: + +``` +//uaddr指向一个地址,val代表这个地址期待的值,当*uaddr==val时,才会进行wait +int futex_wait(int *uaddr, int val); + +//唤醒n个在uaddr指向的锁变量上挂起等待的进程 +int futex_wake(int *uaddr, int n); +``` +
+ +# 数据结构 +上文提到,futex变量创建于用户空间,在进程或线程间共享,当进程或线程想要进入临界区时,通常会判断futex变量是否满足条件,若满足则成功进入临界区,否则则阻塞在该futex变量上;当进程或线程将要离开临界区时,则会唤醒阻塞在futex变量上的其他进程或线程。在内核中通过struct futex_q结构将一个futex变量与一个挂起的进程(线程)关联起来,其定义以及关键成员的作用如下: +``` +struct futex_q { + struct plist_node list; //链表节点 + struct task_struct *task; //挂起在该futex变量关联的进程(线程) + spinlock_t *lock_ptr; //自旋锁,控制链表访问 + union futex_key key; //futex变量地址标识 + + //下面三个与优先级继承相关,在此不多介绍 + struct futex_pi_state *pi_state; + struct rt_mutex_waiter *rt_waiter; + union futex_key *requeue_pi_key; + + u32 bitset; //类似掩码匹配 +}; +``` +
+ +在内核中通过一个全局哈希表来维护所有挂起阻塞在futex变量上的进程(线程),不同的futex变量会根据其地址标识计算出一个hash key并定位到一个bucket上,因此挂起阻塞在同一个futex变量的所有进程(线程)会对应到同一个bucket上,数据结构如下: +``` +//bucket +struct futex_hash_bucket { + //当前自旋等待哈希桶的waiter数目 + atomic_t waiters; + + //自旋锁,用于控制chain的访问, + //struct futex_q中lock_ptr,就是引用其所在的bucket的自旋锁 + spinlock_t lock; + + //优先级链,与传统等待队列不同,futex使用优先级链表来实现等待队列, + //是为了实现优先级继承,从而解决优先级翻转问题 + struct plist_head chain; +} ____cacheline_aligned_in_smp; + +//全局哈希表 +static struct { + struct futex_hash_bucket *queues; + unsigned long hashsize; +} __futex_data __read_mostly __aligned(2*sizeof(long)); +#define futex_queues (__futex_data.queues) +#define futex_hashsize (__futex_data.hashsize) +``` +
+ +上文提到进程(线程)对应的bucket为全局哈希表的value,这里展示一下哈希表的key,其结构如下。 +``` +union futex_key { + struct { + u64 i_seq; + unsigned long pgoff; + unsigned int offset; + } shared; //不同进程间通过文件共享futex变量,表明该变量在文件中的位置 + + struct { + union { + struct mm_struct *mm; + u64 __tmp; + }; + unsigned long address; + unsigned int offset; + } private; //同一进程的不同线程共享futex变量,表明该变量在进程地址空间中的位置 + + struct { + u64 ptr; + unsigned long word; + unsigned int offset; + } both; +}; +``` +
+futex_key是一个union类型的结构,可以给进程和线程使用。futex会根据用户态的uaddr和进程(线程)的信息填充futex_key,并通过jhash计算出一个全局哈希表的索引,从而对应到一个bucket,尝试获取同一个futex的进程(线程)会映射到同一个bucket,然后再根据futex_key中的值在bucket链表中找到其它进程(线程)。
+几个结构体之间的关系如下图所示: +
+

+ +# 源码分析 +## futex前期操作 +futex初始化的源码如下,可以看出在kernel启动的时候即完成了初始化。初始化的内容也比较简单,申请固定数量的bucket交由全局哈希表__futex_data管理,然后初始化每个bucket的链表的自旋锁。 +``` +static int __init futex_init(void) +{ + + ... + +#if CONFIG_BASE_SMALL + futex_hashsize = 16; +#else + futex_hashsize = roundup_pow_of_two(256 * num_possible_cpus()); +#endif + + futex_queues = alloc_large_system_hash("futex", sizeof(*futex_queues), + futex_hashsize, 0, + futex_hashsize < 256 ? HASH_SMALL : 0, + &futex_shift, NULL, + futex_hashsize, futex_hashsize); + futex_hashsize = 1UL << futex_shift; + + futex_detect_cmpxchg(); + + for (i = 0; i < futex_hashsize; i++) { + atomic_set(&futex_queues[i].waiters, 0); + plist_head_init(&futex_queues[i].chain); + spin_lock_init(&futex_queues[i].lock); + } + + return 0; +} +core_initcall(futex_init); +``` +
+ +futex系统调用进入内核后都会先走到do_futex,源码如下。用户态需要确定入参(入参个数,具体操作等),在内核会根据入参来决定采取何种操作,本文作为futex的入门帖,仅需关注futex_wait和futex_wake即可。 +``` +long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, + u32 __user *uaddr2, u32 val2, u32 val3) +{ + int cmd = op & FUTEX_CMD_MASK; + unsigned int flags = 0; + + ... + + switch (cmd) { + case FUTEX_WAIT: + val3 = FUTEX_BITSET_MATCH_ANY; + fallthrough; + case FUTEX_WAIT_BITSET: + return futex_wait(uaddr, flags, val, timeout, val3); + case FUTEX_WAKE: + val3 = FUTEX_BITSET_MATCH_ANY; + fallthrough; + case FUTEX_WAKE_BITSET: + return futex_wake(uaddr, flags, val, val3); + case FUTEX_REQUEUE: + return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0); + case FUTEX_CMP_REQUEUE: + return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0); + case FUTEX_WAKE_OP: + return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3); + case FUTEX_LOCK_PI: + return futex_lock_pi(uaddr, flags, timeout, 0); + case FUTEX_UNLOCK_PI: + return futex_unlock_pi(uaddr, flags); + case FUTEX_TRYLOCK_PI: + return futex_lock_pi(uaddr, flags, NULL, 1); + case FUTEX_WAIT_REQUEUE_PI: + val3 = FUTEX_BITSET_MATCH_ANY; + return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3, + uaddr2); + case FUTEX_CMP_REQUEUE_PI: + return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1); + } + return -ENOSYS; +} +``` +

+ +## futex wait分析 +futex的执行流程参考下图。 +
+

+futex源码如下,下面让我们结合流程图来分析源码。对于带超时的场景,futex wait会首先通过futex_setup_timer设置定时器。接下来调用futex_wait_setup函数,后者主要做了两件事,一是根据入参获取全局哈希表的key从而找到task所属的bucket并获取自旋锁;二是在入队之前最后判断*uaddr是否为预期值。如果*uaddr被更新即非预期值,则会重新返回用户态去抢锁。否则执行下一步,即调用futex_wait_queue_me。后者主要做了几件事:1、将当前的task插入等待队列;2、启动定时任务;3、触发重新调度。接下来当task能够继续执行时会判断自己是如何被唤醒的,并释放hrtimer退出。 + +``` +static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, + ktime_t *abs_time, u32 bitset) +{ + + ... + + to = futex_setup_timer(abs_time, &timeout, flags, + current->timer_slack_ns); +retry: + /* + * Prepare to wait on uaddr. On success, holds hb lock and increments + * q.key refs. + */ + ret = futex_wait_setup(uaddr, val, flags, &q, &hb); + if (ret) + goto out; + + /* queue_me and wait for wakeup, timeout, or a signal. */ + futex_wait_queue_me(hb, &q, to); + + /* If we were woken (and unqueued), we succeeded, whatever. */ + ret = 0; + /* unqueue_me() drops q.key ref */ + if (!unqueue_me(&q)) + goto out; + ret = -ETIMEDOUT; + if (to && !to->task) + goto out; + + /* + * We expect signal_pending(current), but we might be the + * victim of a spurious wakeup as well. + */ + if (!signal_pending(current)) + goto retry; + + ret = -ERESTARTSYS; + if (!abs_time) + goto out; + + ... + +out: + if (to) { + hrtimer_cancel(&to->timer); + destroy_hrtimer_on_stack(&to->timer); + } + return ret; +} +``` +

+ +## futex wake分析 +futex_wake的执行流程如下。
+
+

+ +futex_wake源码如下,首先是通过get_futex_key生成全局哈希表的key,并通过hash_futex找到对应的bucket。以上两步实际上在上文提到的futex_wait_setup函数中也被调用到。接下来会遍历bucket根据key找目前wait在当前futex的task,并将其从bucket取出放入临时队列wake_q。随后释放bucket的自旋锁并逐个唤醒wake_q中的task。 +``` +static int +futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) +{ + + ... + + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ); + if (unlikely(ret != 0)) + return ret; + + hb = hash_futex(&key); + + /* Make sure we really have tasks to wakeup */ + if (!hb_waiters_pending(hb)) + return ret; + + spin_lock(&hb->lock); + + plist_for_each_entry_safe(this, next, &hb->chain, list) { + if (match_futex (&this->key, &key)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + break; + } + + /* Check if one of the bits is set in both bitsets */ + if (!(this->bitset & bitset)) + continue; + + mark_wake_futex(&wake_q, this); + if (++ret >= nr_wake) + break; + } + } + + spin_unlock(&hb->lock); + wake_up_q(&wake_q); + return ret; +} +``` +

+ +# 小结 +本文结合linux中futex的源码简单介绍了其最基本的两个功能futex_wait和futex_wake,后续有机会将陆续介绍futex相关的其它实现。 +

+ +# 参考文献 +futex内核实现源码分析(1-3):https://www.jianshu.com/p/8f4b8dd37cbf
+linux内核级同步机制--futex: https://cloud.tencent.com/developer/article/1474735
+

+ diff --git "a/web-ui/docs/zh/blog/wangshuo/memcpy_1k\345\255\227\350\212\202x86_64\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\344\270\213\351\231\215\345\210\206\346\236\220.md" "b/web-ui/docs/zh/blog/wangshuo/memcpy_1k\345\255\227\350\212\202x86_64\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\344\270\213\351\231\215\345\210\206\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..9d0c9f6ac489954dbbeb058d597705da08392b69 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/memcpy_1k\345\255\227\350\212\202x86_64\350\231\232\346\213\237\346\234\272\346\200\247\350\203\275\344\270\213\351\231\215\345\210\206\346\236\220.md" @@ -0,0 +1,217 @@ +--- +title: memcpy 1k字节x86_64虚拟机性能下降分析 +date: 2021-01-14 +tags: + - glibc + - 性能 +archives: 2021-01 +author: wangshuo +summary: 从memcpy 1k字节虚拟机性能下降入手介绍glibc x86_64 memcpy相关逻辑 +--- + +# 1 问题背景 +## 1.1 问题现象 +x86_64环境上运行memcpy 1k字节时虚拟机的性能比物理机下降了40倍。 + +## 1.2 软件信息 +| 软件项 | 版本信息 | +| :----:| :----: | +| OS | openEuler 20.03 (LTS) | +| kernel| 4.19.90-2003.4.0.0036.oe1.x86_64| +| glibc| 2.28 | +| gcc| 7.3.0 | + +# 2 结论与解决方法 +## 2.1 结论 +起虚拟机的xml文件没有开超线程导致memcpy L3 cache水线在物理机和虚拟机中存在差异,从而引起性能差异。 + +## 2.2 解决方法 +### 方法一 虚拟机开超线程 +``` + + ... + + + +``` +### 方法二 调整memcpy水线 +以下为glibc社区推荐配置 +``` +# export GLIBC_TUNABLES=glibc.tune.x86_non_temporal_threshold=$(($(getconf LEVEL3_CACHE_SIZE) * 3 / 4)) +``` + +# 3 memcpy算法综述 +在glibc-2.28中,memcpy和memove共享一套逻辑,其实现算法在glibc的源码中有简要介绍: +``` +sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S + +/* memmove/memcpy/mempcpy is implemented as: + 1. Use overlapping load and store to avoid branch. + 2. Load all sources into registers and store them together to avoid + possible address overlap between source and destination. + 3. If size is 8 * VEC_SIZE or less, load all sources into registers + and store them together. + 4. If address of destination > address of source, backward copy + 4 * VEC_SIZE at a time with unaligned load and aligned store. + Load the first 4 * VEC and last VEC before the loop and store + them after the loop to support overlapping addresses. + 5. Otherwise, forward copy 4 * VEC_SIZE at a time with unaligned + load and aligned store. Load the last 4 * VEC and first VEC + before the loop and store them after the loop to support + overlapping addresses. + 6. If size >= __x86_shared_non_temporal_threshold and there is no + overlap between destination and source, use non-temporal store + instead of aligned store. */ +``` + +其中,如第6条所述,如果超过__x86_shared_non_temporal_threshold水线,将使用non-temporal store代替aligned store,本次性能下降问题就属于该场景。 + +# 4 执行逻辑 +x86环境上进程启动之前,会对水线进行一系列的初始化操作,本次涉及的水线初始化动作如下: +``` +sysdeps/x86/cacheinfo.c + +533 /* A value of 0 for the HTT bit indicates there is only a single +534 logical processor. */ +535 if (HAS_CPU_FEATURE (HTT)) +536 { + ... + 计算threads + ... +693 } + + ... + +781 /* The large memcpy micro benchmark in glibc shows that 6 times of +782 shared cache size is the approximate value above which non-temporal +783 store becomes faster on a 8-core processor. This is the 3/4 of the +784 total shared cache size. */ +785 __x86_shared_non_temporal_threshold +786 = (cpu_features->non_temporal_threshold != 0 +787 ? cpu_features->non_temporal_threshold +788 : __x86_shared_cache_size * threads * 3 / 4); +``` +可以看出,虚拟机在没有开超线程的情况下__x86_shared_non_temporal_threshold为0,而物理机为__x86_shared_cache_size * threads * 3 / 4. 当执行memcpy 1k操作时,会按照如下逻辑判断具体需要执行的分支,虚拟机和物理机的逻辑在此之后产生差别。 +``` +sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S + +455 #if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc) +456 /* Check non-temporal store threshold. */ +457 cmpq __x86_shared_non_temporal_threshold(%rip), %rdx +458 ja L(large_backward) +459 #endif +``` +具体逻辑如下: +``` +物理机逻辑 +sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S + +460 L(loop_4x_vec_backward): +461 /* Copy 4 * VEC a time backward. */ +462 VMOVU (%rcx), %VEC(0) +463 VMOVU -VEC_SIZE(%rcx), %VEC(1) +464 VMOVU -(VEC_SIZE * 2)(%rcx), %VEC(2) +465 VMOVU -(VEC_SIZE * 3)(%rcx), %VEC(3) +466 subq $(VEC_SIZE * 4), %rcx +467 subq $(VEC_SIZE * 4), %rdx +468 VMOVA %VEC(0), (%r9) +469 VMOVA %VEC(1), -VEC_SIZE(%r9) +470 VMOVA %VEC(2), -(VEC_SIZE * 2)(%r9) +471 VMOVA %VEC(3), -(VEC_SIZE * 3)(%r9) +472 subq $(VEC_SIZE * 4), %r9 +473 cmpq $(VEC_SIZE * 4), %rdx +474 ja L(loop_4x_vec_backward) +475 /* Store the first 4 * VEC. */ +476 VMOVU %VEC(4), (%rdi) +477 VMOVU %VEC(5), VEC_SIZE(%rdi) +478 VMOVU %VEC(6), (VEC_SIZE * 2)(%rdi) +479 VMOVU %VEC(7), (VEC_SIZE * 3)(%rdi) +480 /* Store the last VEC. */ +481 VMOVU %VEC(8), (%r11) +482 VZEROUPPER +483 ret +``` + +``` +虚拟机逻辑 +sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S + +528 L(loop_large_backward): +529 /* Copy 4 * VEC a time backward with non-temporal stores. */ +530 PREFETCH_ONE_SET (-1, (%rcx), -PREFETCHED_LOAD_SIZE * 2) +531 PREFETCH_ONE_SET (-1, (%rcx), -PREFETCHED_LOAD_SIZE * 3) +532 VMOVU (%rcx), %VEC(0) +533 VMOVU -VEC_SIZE(%rcx), %VEC(1) +534 VMOVU -(VEC_SIZE * 2)(%rcx), %VEC(2) +535 VMOVU -(VEC_SIZE * 3)(%rcx), %VEC(3) +536 subq $PREFETCHED_LOAD_SIZE, %rcx +537 subq $PREFETCHED_LOAD_SIZE, %rdx +538 VMOVNT %VEC(0), (%r9) +539 VMOVNT %VEC(1), -VEC_SIZE(%r9) +540 VMOVNT %VEC(2), -(VEC_SIZE * 2)(%r9) +541 VMOVNT %VEC(3), -(VEC_SIZE * 3)(%r9) +542 subq $PREFETCHED_LOAD_SIZE, %r9 +543 cmpq $PREFETCHED_LOAD_SIZE, %rdx +544 ja L(loop_large_backward) +545 sfence +546 /* Store the first 4 * VEC. */ +547 VMOVU %VEC(4), (%rdi) +548 VMOVU %VEC(5), VEC_SIZE(%rdi) +549 VMOVU %VEC(6), (VEC_SIZE * 2)(%rdi) +550 VMOVU %VEC(7), (VEC_SIZE * 3)(%rdi) +551 /* Store the last VEC. */ +552 VMOVU %VEC(8), (%r11) +553 VZEROUPPER +554 ret +``` + +# 5 指令差异分析 +从上文可知,物理机和虚拟机执行逻辑的最大区别在于mov指令,指令的定义如下: +``` +sysdeps/x86_64/memmove.S + + 23 #define PREFETCHNT prefetchnta + 24 #define VMOVNT movntdq + 25 /* Use movups and movaps for smaller code sizes. */ + 26 #define VMOVU movups + 27 #define VMOVA movaps +``` +可知,物理机逻辑使用的是movaps指令,特点是16字节对齐,而虚拟机逻辑使用的是movntdq指令,该指令是bypass main cache的,这里附上相关介绍。 +>https://stackoverflow.com/questions/14106477/how-do-non-temporal-instructions-work +>The streaming read/write with non-temporal hints are typically used to reduce cache pollution (often with WC memory). The idea is that a small set of cache lines are reserved on the CPU for these instructions to use. Instead of loading a cache line into the main caches, it is loaded into this smaller cache. +> +>The comment supposes the following behavior (but I cannot find any references that the hardware actually does this, one would need to measure or a solid source and it could vary from hardware to hardware): - Once the CPU sees that the store buffer is full and that it is aligned to a cache line, it will flush it directly to memory since the non-temporal write bypasses the main cache. + +通过分析上文的代码可知,movntdq以bypass main cache的方式将数据放入内存,因此性能自然不如movaps指令。 + +在与社区沟通后我们得知,社区采取的是一种折中策略。对于大块数据的memcpy操作,如果都走L3 cache,虽然能提升memcpy的性能,但是却会对整个系统的性能造成影响,因此制定了水线。 +>https://sourceware.org/pipermail/libc-alpha/2021-January/121510.html +>\> The performance of memcpy 1024 has recovered. However, there is performance +>\> reduce in host. This is test result (cycle): +>\> +>\> memcpy_10 memcpy_1k memcpy_10k memcpy_1m memcpy_10m +>\> before backport 8 34 187 130848 2325409 +>\> after backport 8 34 182 515156 5282603 +>\> Performance improvement 0.00% 0.00% 2.67% -293.71% -127.17% +> +>I think this is expected because the large copies no longer stay within +>the cache. This is required to avoid blowing away the entire cache +>contents for such large copies, negatively impacting whole system +>performance. This will of course not show up in a micro-benchmark. + + +# 6 修改水线后 +通过之前的分析可知,虚拟机默认的水线为0,在此参考社区的推荐配置在虚拟机和物理机上进行验证,结果如下(单位cycle数): + +| 物理机 | memcpy_10 | memcpy_1k | memcpy_10k | memcpy_1M | memcpy_10M | +| :----:| :----: | :----: | :----: | :----: | :----: | +| 配置前 | 8 | 34 | 187| 130848| 2325409| +| 配置后 | 8 | 34 | 182| 515156| 5282603| +| 性能提升 | 0.00% | 0.00% |2.67% | -293.71% | -127.17% | + +| 虚拟机 | memcpy_10 | memcpy_1k | memcpy_10k | memcpy_1M | memcpy_10M | +| :----:| :----: | :----: | :----: | :----: | :----: | +| 配置前 | 8 | 1269| 4555| 523740| 5304273| +| 配置后 | 8 | 35| 183| 509297| 5260913| +| 性能提升 | 0.00% | 97.24% |95.98% | 2.76% | 0.82% | +对比虚拟机和物理机配置前后的数据可以发现,调整了水线后虚拟机和物理机的性能是一致的。同时,对于物理机,之前水线为__x86_shared_cache_size * threads * 3 / 4,修改后为__x86_shared_cache_size * 3 / 4,水线降低,更容易进入movntdq指令,因此会在1M以后有下降。 diff --git "a/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213.md" "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..37f644a1b0a18da6d7a68c21b1362e1238bbc50c --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213.md" @@ -0,0 +1,391 @@ +--- +title: musl源码分析--fopen简介 +date: 2021-05-19 +tags: + - musl + - fopen +archives: 2021-05 +author: wangshuo +summary: 结合musl的源码介绍fopen系列接口的原理 +--- +# 前言 +musl是在Linux系统调用API之上构建的C标准库的实现,其中包括在基本语言标准POSIX中定义的接口,以及广泛认可的扩展。相比于glibc,musl轻巧,快速,简单并且协议友好,本文将以musl的fopen为切入点,结合源码介绍musl对文件的基本操作。 +

+ +# 数据结构 +musl涉及文件的关键数据结构如下,该结构体即为我们平时使用的FILE,本文重点关注4个函数指针(close、read、write和seek)和5个位置指针(读两个:rpos、rend,写三个:wend、wpos和wbase)即可。 +``` +struct _IO_FILE { + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE *); + unsigned char *wend, *wpos; + unsigned char *mustbezero_1; + unsigned char *wbase; + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + unsigned char *buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long lockcount; + int mode; + volatile int lock; + int lbf; + void *cookie; + off_t off; + char *getln_buf; + void *mustbezero_2; + unsigned char *shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + struct __locale_struct *locale; +}; +``` +

+ +# 接口 +## fopen +fopen的源码如下,逻辑非常简单,判断打开的模式,然后使用open系统调用从内核获取一个fd,随后通过__fdopen函数将fd封装为一个FILE,并为4个函数指针(close、read、write和seek)挂上默认的函数。
+FILE初始状态可以用下图表示。最前面一段即为FILE的主体,接下来是一个名为UNGET的预留区域处理不缓冲时的场景(默认8字节),接下来便是musl预留的一段缓冲区,默认1024字节。 +``` +FILE *fopen(const char *restrict filename, const char *restrict mode) +{ + FILE *f; + int fd; + int flags; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + /* Compute the flags to pass to open() */ + flags = __fmodeflags(mode); + + fd = sys_open(filename, flags, 0666); + if (fd < 0) return 0; + if (flags & O_CLOEXEC) + __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + f = __fdopen(fd, mode); + if (f) return f; + + __syscall(SYS_close, fd); + return 0; +} + +... + +FILE *__fdopen(int fd, const char *mode) +{ + ... + + /* Allocate FILE+buffer or fail */ + if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return 0; + + /* Zero-fill only the struct, not the buffer */ + memset(f, 0, sizeof *f); + + ... + + f->fd = fd; + f->buf = (unsigned char *)f + sizeof *f + UNGET; + f->buf_size = BUFSIZ; + + ... + + /* Initialize op ptrs. No problem if some are unneeded. */ + f->read = __stdio_read; + f->write = __stdio_write; + f->seek = __stdio_seek; + f->close = __stdio_close; + + ... + +} +``` +

+ +
+

+ +## fclose +fclose函数源码如下,这里只列出了关键步骤。将写缓冲的内容刷入文件,通过f->close(f)调用真正的close函数__stdio_close,通过系统调用关闭fd对应的文件,然后释放掉外部封装的数据结构。 +``` +int fclose(FILE *f) +{ + int r; + + FLOCK(f); + r = fflush(f); + r |= f->close(f); + FUNLOCK(f); + + ... + + free(f->getln_buf); + free(f); + + return r; +} + +... + +int __stdio_close(FILE *f) +{ + return syscall(SYS_close, __aio_close(f->fd)); +} +``` +

+ +## fread +分析fread的时候我们把顺序反过来,先看_IO_FILE中的read成员,上文已提过该成员为指针函数,在fopen的时候初始化,fread最终会调用该函数,其源码如下。其核心思想是在满足用户读取len长度内容到buf之外,预读一部分到FILE中的缓冲区。
+从iov结构体数组的初始化可知,第一个元素是用户的buf,第二个是FILE的缓冲区,即先读出给用户,然后再读到缓冲区,读到缓冲区的内容默认小于等于1023,为何不是1024?
+让我们把视线重新放回到iov的初始化,其中第一个元素的起始地址确实是用户的地址,但是长度实际上减去了1,即iov[0]最多只会读出len - 1个元素,最后一个元素会放入iov[1],在结尾时重新赋给buf[len - 1],这么做的目的是使rpos指针在读取后偏移一个字节从而表明FILE的缓冲区已经有预读的内容。预读之后的指针情况可以用下图表示(与写相关的三个指针此时为空)。
+
+

+ +``` +size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) +{ + struct iovec iov[2] = { + { .iov_base = buf, .iov_len = len - !!f->buf_size }, + { .iov_base = f->buf, .iov_len = f->buf_size } + }; + ssize_t cnt; + + cnt = iov[0].iov_len ? syscall(SYS_readv, f->fd, iov, 2) + : syscall(SYS_read, f->fd, iov[1].iov_base, iov[1].iov_len); + if (cnt <= 0) { + f->flags |= cnt ? F_ERR : F_EOF; + return 0; + } + if (cnt <= iov[0].iov_len) return cnt; + cnt -= iov[0].iov_len; + f->rpos = f->buf; + f->rend = f->buf + cnt; + if (f->buf_size) buf[len-1] = *f->rpos++; + return len; +} +``` +

+ + +接下来看fread函数,其源码如下。上文提到每次__stdio_read都会预读一部分内容,因此fread会优先通过memcpy从缓冲区读,如果读完仍不满足用户需求才会调用__stdio_read从文件中读取。 +``` +size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) +{ + unsigned char *dest = destv; + size_t len = size*nmemb, l = len, k; + if (!size) nmemb = 0; + + FLOCK(f); + + f->mode |= f->mode-1; + + if (f->rpos != f->rend) { + /* First exhaust the buffer. */ + k = MIN(f->rend - f->rpos, l); + memcpy(dest, f->rpos, k); + f->rpos += k; + dest += k; + l -= k; + } + + /* Read the remainder directly */ + for (; l; l-=k, dest+=k) { + k = __toread(f) ? 0 : f->read(f, dest, l); + if (!k) { + FUNLOCK(f); + return (len-l)/size; + } + } + + FUNLOCK(f); + return nmemb; +} +``` +

+ +这里提一下fread在调用__stdio_read之前调用的一个函数__toread,其源码如下。该函数可以理解为读写模式的切换,如果上一次是写,由于读写共用一个缓冲区,因此需要先把写缓存刷入文件并把写相关的三个指针清零,然后再执行读操作,此外,__toread函数还负责判断文件是否可读。 +``` +int __toread(FILE *f) +{ + f->mode |= f->mode-1; + if (f->wpos != f->wbase) f->write(f, 0, 0); + f->wpos = f->wbase = f->wend = 0; + if (f->flags & F_NORD) { + f->flags |= F_ERR; + return EOF; + } + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; +} +``` +

+ + +## fwrite +同样还是先从__stdio_write来看,源码如下。其核心思想是先把用户buf中的内容写入到FILE提供的缓冲区,写满了之后才会往文件中写,相较__stdio_read来说比较简单,在完成一次__stdio_write并且未写满缓冲区的情况下,FILE的指针位置如下图所示。 +``` +size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) +{ + struct iovec iovs[2] = { + { .iov_base = f->wbase, .iov_len = f->wpos-f->wbase }, + { .iov_base = (void *)buf, .iov_len = len } + }; + struct iovec *iov = iovs; + size_t rem = iov[0].iov_len + iov[1].iov_len; + int iovcnt = 2; + ssize_t cnt; + for (;;) { + cnt = syscall(SYS_writev, f->fd, iov, iovcnt); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; + return len; + } + if (cnt < 0) { + f->wpos = f->wbase = f->wend = 0; + f->flags |= F_ERR; + return iovcnt == 2 ? 0 : len-iov[0].iov_len; + } + rem -= cnt; + if (cnt > iov[0].iov_len) { + cnt -= iov[0].iov_len; + iov++; iovcnt--; + } + iov[0].iov_base = (char *)iov[0].iov_base + cnt; + iov[0].iov_len -= cnt; + } +} +``` +

+ +
+

+接下来看fwirte函数,其源码如下。同样也是先通过__towrite切换模式,如果写缓冲区的剩余空间不足,则会调用__stdio_write,由上文可知,此时是先刷缓冲区的内容,然后才操作用户buf的内容。如果缓冲区空间充足则直接通过memcpy写入缓冲区。 + +``` +size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) +{ + size_t i=0; + + if (!f->wend && __towrite(f)) return 0; + + if (l > f->wend - f->wpos) return f->write(f, s, l); + + if (f->lbf >= 0) { + /* Match /^(.*\n|)/ */ + for (i=l; i && s[i-1] != '\n'; i--); + if (i) { + size_t n = f->write(f, s, i); + if (n < i) return n; + s += i; + l -= i; + } + } + + memcpy(f->wpos, s, l); + f->wpos += l; + return l+i; +} + +size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) +{ + size_t k, l = size*nmemb; + if (!size) nmemb = 0; + FLOCK(f); + k = __fwritex(src, l, f); + FUNLOCK(f); + return k==l ? nmemb : k/size; +} +``` +

+ +类似于__toread,__towrite用作切换到写操作,源码如下。这里其实有个bug,我们在下文细说。 +``` +int __towrite(FILE *f) +{ + f->mode |= f->mode-1; + if (f->flags & F_NOWR) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} +``` +

+ +# 一点不足 +如果仔细对比__towrite和__toread的代码可以发现,二者其实并不“对称”,具体来说,__toread即切换到写之前会通过f->write(f, 0, 0)将写缓冲刷到文件,但是__towrite即切换到写时则是简单粗暴地把读相关的指针(rpos、rend)清理,这样做会有什么问题呢?我们看以下操作:
+ +|
步骤
|
动作
|
期望pos
|
实际pos
| +|:------------------------------------:|:--------------------------------------:|:--------------------------------------:|:--------------------------------------:| +|
1
|
写30
|
30
|
30
| +|
2
|
返回开头
|
0
|
0
| +|
3
|
读15
|
15
|
15
| +|
4
|
写15
|
30
|
45
| +

+ +如果在第4步执行完时通过fgetpos获取当前文件指针的位置,则会发现并非期望的30,而是45,事实上,第4步期望是覆盖文件的后15字节,实际上变成了追加写15字节,pos自然是45,这是为什么?
+由上文可知,fread实际上会预读一部分内容,因此当我们在第三步读15时,实际上fread读了30即整个文件,至于这一步为何没有问题,可以看以下代码: + +``` +off_t __ftello_unlocked(FILE *f) +{ + off_t pos = f->seek(f, 0, + (f->flags & F_APP) && f->wpos != f->wbase + ? SEEK_END : SEEK_CUR); + if (pos < 0) return pos; + + /* Adjust for data in buffer. */ + if (f->rend) + pos += f->rpos - f->rend; + else if (f->wbase) + pos += f->wpos - f->wbase; + return pos; +} +``` +

+ +fgetpos最终调用了__ftello_unlocked,该函数通过系统调用从内核获取文件pos的真实位置,然后会做一个矫正,具体来说,我们在第3步做了读操作,因此读指针rend非空,__ftello_unlocked会减去多读的内容,因此第3步没问题。但是到第4步,由于__towrite简单粗暴地把读指针清空,写的15字节内容直接放入了FILE的缓冲区,下一次读时这15字节会直接追加到文件的末尾。 +
+对于这个问题,处理方式也很简单,在__towrite清理读指针之前把pos移动回多读之前的位置即可。

+ +# 小结 +本文结合musl的源码分析了fopen相关的接口实现。相较于glibc,musl的代码浅显易懂,当然也存在考虑不完善的问题。
+
+ +# 文章推荐 +glibc malloc系列文章:
+    原理简析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90.html
+    数据结构:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90.html
+    malloc:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%BA%8C).html
+    free:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%B8%89).html
+
+ +glibc问题定位与分析系列文章:
+    memcpy 1k字节x86_64虚拟机性能下降分析:
+     https://www.openeuler.org/zh/blog/wangshuo/memcpy_1k%E5%AD%97%E8%8A%82x86_64%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%88%86%E6%9E%90.html
+    调用栈问题分析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D--%E6%8E%A8%E6%A0%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html
+
+ +    glibc locale使用简析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc%20locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90/glibc+locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90.html
\ No newline at end of file diff --git "a/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/original.jpg" "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/original.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..38c93ef47b5c67c0b9cc102dbfc1b6095b428bbc Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/original.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/read.jpg" "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/read.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..37d548976990ad0c67e656fb66569daeacc6d635 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/read.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/write.jpg" "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/write.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..050f03f7f8ac5b1c816e3afa1e1967806a6f5e93 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/musl\346\272\220\347\240\201\345\210\206\346\236\220--fopen\347\256\200\344\273\213/write.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx+tmpfs\347\256\200\344\273\213.md" "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx+tmpfs\347\256\200\344\273\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..97b489569a1b952db86f3d0227f60e82b23d2a82 --- /dev/null +++ "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx+tmpfs\347\256\200\344\273\213.md" @@ -0,0 +1,1992 @@ +--- +title: 文件系统--nuttx tmpfs简介 +date: 2021-05-18 +tags: + - 文件系统 + - tmpfs + - nuttx +archives: 2021-05 +author: wangshuo +summary: 结合nuttx的源码介绍nuttx的tmpfs +--- +# 前言 +tmpfs(temporary filesystem)直译为临时文件系统,类似于虚拟磁盘(ramdisk),但ramdisk是一个块设备,而且需要一个mkfs之类的命令格式化后才能使用。而tmpfs是一个独立的文件系统,不是块设备,只要挂载,就可以立即使用。本文将以nuttx-10.0.1的tmpfs为研究对象介绍其基本数据结构和基础接口功能实现。
+
+ +# 数据结构 +tmpfs的源码位于nuttx的fs/tmpfs目录下,只有一个C文件,因此阅读起来相对比较简单,这里先介绍一下tmpfs的关键数据结构。
+
+ +## object +目录和文件的抽象,从下图几个结构体的对比也可以看出,object结构体可以认为是为了便于统一接口而将文件和目录的结构体进行的抽象,从面向对象的角度来看,object可以理解为file和directory结构体的的父类。 +``` +/* The generic form of a TMPFS memory object */ + +struct tmpfs_object_s +{ + FAR struct tmpfs_dirent_s *to_dirent; + struct tmpfs_sem_s to_exclsem; + + size_t to_alloc; /* Allocated size of the memory object */ + uint8_t to_type; /* See enum tmpfs_objtype_e */ + uint8_t to_refs; /* Reference count */ +}; +``` +

+ +
+

+ +## dirent +可以理解为检索项,后续将通过dirent来找到对应的object,从源码可以看出,dirent只是在object之外增加了对象的名称。 +``` +/* The form of one directory entry */ + +struct tmpfs_dirent_s +{ + FAR struct tmpfs_object_s *tde_object; + FAR char *tde_name; +}; +``` +
+ +## directory +目录,directory里面有一个或多个dirent,目录中的dirent可以指向文件或子目录,从根目录开始文件和目录交织在一起构成一棵tmpfs树。 +``` +/* The form of a directory memory object */ + +struct tmpfs_directory_s +{ + /* First fields must match common TMPFS object layout */ + + FAR struct tmpfs_dirent_s *tdo_dirent; + struct tmpfs_sem_s tdo_exclsem; + + size_t tdo_alloc; /* Allocated size of the directory object */ + uint8_t tdo_type; /* See enum tmpfs_objtype_e */ + uint8_t tdo_refs; /* Reference count */ + + /* Remaining fields are unique to a directory object */ + + uint16_t tdo_nentries; /* Number of directory entries */ + struct tmpfs_dirent_s tdo_entry[1]; +}; +``` +
+ +## file +文件,书面地讲是有顺序的字节流。每个文件都有一个可阅读的文件名,用户可以对指定文件名的文件进行读、写、创建删除等操作。 +``` +/* The form of a regular file memory object + * + * NOTE that in this very simplified implementation, there is no per-open + * state. The file memory object also serves as the open file object, + * saving an allocation. This has the negative side effect that no per- + * open state can be retained (such as open flags). + */ + +struct tmpfs_file_s +{ + /* First fields must match common TMPFS object layout */ + + FAR struct tmpfs_dirent_s *tfo_dirent; + struct tmpfs_sem_s tfo_exclsem; + + size_t tfo_alloc; /* Allocated size of the file object */ + uint8_t tfo_type; /* See enum tmpfs_objtype_e */ + uint8_t tfo_refs; /* Reference count */ + + /* Remaining fields are unique to a directory object */ + + uint8_t tfo_flags; /* See TFO_FLAG_* definitions */ + size_t tfo_size; /* Valid file size */ + uint8_t tfo_data[1]; /* File data starts here */ +}; +``` +
+ +## tmpfs_s +tmpfs的实例,其tfs_root成员指向了tmpfs的根目录。 +``` +/* This structure represents one instance of a TMPFS file system */ + +struct tmpfs_s +{ + /* The root directory */ + + FAR struct tmpfs_dirent_s tfs_root; + struct tmpfs_sem_s tfs_exclsem; +}; +``` +
+ + +## 结构体关系 +以上结构体的之间的关系如下图所示。 +
+

+ +# 主要内部接口 +这里根据操作内容将关键的内部接口分为以下四类。 +

+## dirent操作 +### tmpfs_add_dirent +上文提到dirent是object加上名称的简化封装版本,而object是目录和文件的抽象,因此文件和目录的新增都会用到tmpfs_add_dirent,其源码如下。
+可以看出tmpfs_add_dirent其实只做了一件事,即在对当前目录tdo进行realloc,新增一项tdo_entry,并把新的object(即to)和name赋值给新的tdo_entry。 +``` +/**************************************************************************** + * Name: tmpfs_add_dirent + ****************************************************************************/ + +static int tmpfs_add_dirent(FAR struct tmpfs_directory_s **tdo, + FAR struct tmpfs_object_s *to, + FAR const char *name) +{ + FAR struct tmpfs_directory_s *oldtdo; + FAR struct tmpfs_directory_s *newtdo; + FAR struct tmpfs_dirent_s *tde; + FAR char *newname; + unsigned int nentries; + int index; + + /* Copy the name string so that it will persist as long as the + * directory entry. + */ + + newname = strdup(name); + if (newname == NULL) + { + return -ENOMEM; + } + + /* Get the new number of entries */ + + oldtdo = *tdo; + nentries = oldtdo->tdo_nentries + 1; + + /* Reallocate the directory object (if necessary) */ + + index = tmpfs_realloc_directory(tdo, nentries); + if (index < 0) + { + kmm_free(newname); + return index; + } + + /* Save the new object info in the new directory entry */ + + newtdo = *tdo; + tde = &newtdo->tdo_entry[index]; + tde->tde_object = to; + tde->tde_name = newname; + + /* Add backward link to the directory entry to the object */ + + to->to_dirent = tde; + return OK; +} +``` +
+
+ +### tmpfs_find_dirent +tmpfs_find_dirent函数用于在指定的目录tdo中查找指定name的dirent,其源码如下,实现较为简单,就是单纯的遍历查找。 +``` +/**************************************************************************** + * Name: tmpfs_find_dirent + ****************************************************************************/ + +static int tmpfs_find_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name) +{ + int i; + + /* Search the list of directory entries for a match */ + + for (i = 0; + i < tdo->tdo_nentries && + strcmp(tdo->tdo_entry[i].tde_name, name) != 0; + i++); + + /* Return what we found, if anything */ + + return i < tdo->tdo_nentries ? i : -ENOENT; +} +``` +

+ +### tmpfs_remove_dirent +tmpfs_remove_dirent函数用于从指定的目录tdo中删除名称为name的dirent,其源码如下。这里首先free掉在tmpfs_add_dirent函数中strdup的name,然后判断被删除的dirent是否为最后一个,如果是直接退出,否则把最后一个dirent覆盖到要删除的dirent中从而空出最后一个dirent以备后续使用,避免频繁realloc。 +``` +/**************************************************************************** + * Name: tmpfs_remove_dirent + ****************************************************************************/ + +static int tmpfs_remove_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name) +{ + int index; + int last; + + /* Search the list of directory entries for a match */ + + index = tmpfs_find_dirent(tdo, name); + if (index < 0) + { + return index; + } + + /* Free the object name */ + + if (tdo->tdo_entry[index].tde_name != NULL) + { + kmm_free(tdo->tdo_entry[index].tde_name); + } + + /* Remove by replacing this entry with the final directory entry */ + + last = tdo->tdo_nentries - 1; + if (index != last) + { + FAR struct tmpfs_dirent_s *newtde; + FAR struct tmpfs_dirent_s *oldtde; + FAR struct tmpfs_object_s *to; + + /* Move the directory entry */ + + newtde = &tdo->tdo_entry[index]; + oldtde = &tdo->tdo_entry[last]; + to = oldtde->tde_object; + + newtde->tde_object = to; + newtde->tde_name = oldtde->tde_name; + + /* Reset the backward link to the directory entry */ + + to->to_dirent = newtde; + } + + /* And decrement the count of directory entries */ + + tdo->tdo_nentries = last; + return OK; +} +``` +

+ +## object操作 +### tmpfs_find_object +上文提到object是目录和文件的抽象,因此文件和目录的find都用tmpfs_find_object来实现,其源码如下。
+函数虽然在150行左右,但是并不复杂。入参中的relpath为绝对路径,函数从tmpfs的根目录开始查找,具体某一目录下的查找用到了上文提到的tmpfs_find_dirent函数,如果找不到则返回错误码,如果找到则目标object以及其所在的目录上锁,to_refs和tdo_refs都加1。 +``` +/**************************************************************************** + * Name: tmpfs_find_object + ****************************************************************************/ + +static int tmpfs_find_object(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_object_s **object, + FAR struct tmpfs_directory_s **parent) +{ + FAR struct tmpfs_object_s *to = NULL; + FAR struct tmpfs_directory_s *tdo = NULL; + FAR struct tmpfs_directory_s *next_tdo; + FAR char *segment; + FAR char *next_segment; + FAR char *tkptr; + FAR char *copy; + int index; + int ret; + + /* Make a copy of the path (so that we can modify it via strtok) */ + + copy = strdup(relpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Traverse the file system for any object with the matching name */ + + to = fs->tfs_root.tde_object; + next_tdo = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + for (segment = strtok_r(copy, "/", &tkptr); + segment != NULL; + segment = next_segment) + { + /* Get the next segment after the one we are currently working on. + * This will be NULL is we are working on the final segment of the + * relpath. + */ + + next_segment = strtok_r(NULL, "/", &tkptr); + + /* Search the next directory. */ + + tdo = next_tdo; + + /* Find the TMPFS object with the next segment name in the current + * directory. + */ + + index = tmpfs_find_dirent(tdo, segment); + if (index < 0) + { + /* No object with this name exists in the directory. */ + + kmm_free(copy); + return index; + } + + to = tdo->tdo_entry[index].tde_object; + + /* Is this object another directory? */ + + if (to->to_type != TMPFS_DIRECTORY) + { + /* No. Was this the final segment in the path? */ + + if (next_segment == NULL) + { + /* Then we can break out of the loop now */ + + break; + } + + /* No, this was not the final segment of the relpath. + * We cannot continue the search if any of the intermediate + * segments do no correspond to directories. + */ + + kmm_free(copy); + return -ENOTDIR; + } + + /* Search this directory for the next segment. If we + * exit the loop, tdo will still refer to the parent + * directory of to. + */ + + next_tdo = (FAR struct tmpfs_directory_s *)to; + } + + /* When we exit this loop (successfully), to will point to the TMPFS + * object associated with the terminal segment of the relpath. + * Increment the reference count on the located object. + */ + + /* Free the dup'ed string */ + + kmm_free(copy); + + /* Return what we found */ + + if (parent) + { + if (tdo != NULL) + { + /* Get exclusive access to the parent and increment the reference + * count on the object. + */ + + ret = tmpfs_lock_directory(tdo); + if (ret < 0) + { + return ret; + } + + tdo->tdo_refs++; + } + + *parent = tdo; + } + + if (object) + { + if (to != NULL) + { + /* Get exclusive access to the object and increment the reference + * count on the object. + */ + + ret = tmpfs_lock_object(to); + if (ret < 0) + { + return ret; + } + + to->to_refs++; + } + + *object = to; + } + + return OK; +} +``` +

+ + +## 文件操作 +### tmpfs_alloc_file +tmpfs_alloc_file函数用于为新的文件分配空间,其源码如下,实现也非常简单,申请内存,结构体初始化,仅此而已。 +``` +/**************************************************************************** + * Name: tmpfs_alloc_file + ****************************************************************************/ + +static FAR struct tmpfs_file_s *tmpfs_alloc_file(void) +{ + FAR struct tmpfs_file_s *tfo; + size_t allocsize; + + /* Create a new zero length file object */ + + allocsize = SIZEOF_TMPFS_FILE(CONFIG_FS_TMPFS_FILE_ALLOCGUARD); + tfo = (FAR struct tmpfs_file_s *)kmm_malloc(allocsize); + if (tfo == NULL) + { + return NULL; + } + + /* Initialize the new file object. NOTE that the initial state is + * locked with one reference count. + */ + + tfo->tfo_alloc = allocsize; + tfo->tfo_type = TMPFS_REGULAR; + tfo->tfo_refs = 1; + tfo->tfo_flags = 0; + tfo->tfo_size = 0; + + tfo->tfo_exclsem.ts_holder = getpid(); + tfo->tfo_exclsem.ts_count = 1; + nxsem_init(&tfo->tfo_exclsem.ts_sem, 0, 0); + + return tfo; +} +``` +

+ +### tmpfs_create_file +tmpfs_create_file用于创建一个新文件,其源码如下。一开始会先判断是否是在根目录下创建文件,如果是则parent变量为根目录,反正则通过tmpfs_find_directory函数找到待创建文件的上一级目录。然后会通过tmpfs_find_dirent函数查找当前文件是否存在,如果存在则返回错误码退出;如果不存在则调用tmpfs_alloc_file函数为新文件分配空间,调用tmpfs_add_dirent函数在新文件所在的目录下为其分配一个dirent。 +``` +/**************************************************************************** + * Name: tmpfs_create_file + ****************************************************************************/ + +static int tmpfs_create_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_file_s **tfo) +{ + FAR struct tmpfs_directory_s *parent; + FAR struct tmpfs_file_s *newtfo; + FAR char *copy; + FAR char *name; + int ret; + + /* Duplicate the path variable so that we can modify it */ + + copy = strdup(relpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Separate the path into the file name and the path to the parent + * directory. + */ + + name = strrchr(copy, '/'); + if (name == NULL) + { + /* No subdirectories... use the root directory */ + + name = copy; + parent = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + /* Lock the root directory to emulate the behavior of + * tmpfs_find_directory() + */ + + ret = tmpfs_lock_directory(parent); + if (ret < 0) + { + kmm_free(copy); + return ret; + } + + parent->tdo_refs++; + } + else + { + /* Terminate the parent directory path */ + + *name++ = '\0'; + + /* Locate the parent directory that should contain this name. + * On success, tmpfs_find_directory() will lock the parent + * directory and increment the reference count. + */ + + ret = tmpfs_find_directory(fs, copy, &parent, NULL); + if (ret < 0) + { + goto errout_with_copy; + } + } + + /* Verify that no object of this name already exists in the directory */ + + ret = tmpfs_find_dirent(parent, name); + if (ret != -ENOENT) + { + /* Something with this name already exists in the directory. + * OR perhaps some fatal error occurred. + */ + + if (ret >= 0) + { + ret = -EEXIST; + } + + goto errout_with_parent; + } + + /* Allocate an empty file. The initial state of the file is locked with + * one reference count. + */ + + newtfo = tmpfs_alloc_file(); + if (newtfo == NULL) + { + ret = -ENOMEM; + goto errout_with_parent; + } + + /* Then add the new, empty file to the directory */ + + ret = tmpfs_add_dirent(&parent, (FAR struct tmpfs_object_s *)newtfo, name); + if (ret < 0) + { + goto errout_with_file; + } + + /* Release the reference and lock on the parent directory */ + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + + /* Free the copy of the relpath and return success */ + + kmm_free(copy); + *tfo = newtfo; + return OK; + + /* Error exits */ + +errout_with_file: + nxsem_destroy(&newtfo->tfo_exclsem.ts_sem); + kmm_free(newtfo); + +errout_with_parent: + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + +errout_with_copy: + kmm_free(copy); + return ret; +} + +``` +

+ +### tmpfs_find_file +tmpfs_find_file函数用于从指定的绝对路径中查找目标文件,其源码如下。可以看出本质上就是调用了tmpfs_find_object,同时增加了判断,如果找到的目标文件的属性(to_type)不是文件,则返回错误码退出。 +``` +/**************************************************************************** + * Name: tmpfs_find_file + ****************************************************************************/ + +static int tmpfs_find_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_file_s **tfo, + FAR struct tmpfs_directory_s **parent) +{ + FAR struct tmpfs_object_s *to; + int ret; + + /* Find the object at this path. If successful, tmpfs_find_object() will + * lock both the object and the parent directory and will increment the + * reference count on both. + */ + + ret = tmpfs_find_object(fs, relpath, &to, parent); + if (ret >= 0) + { + /* We found it... but is it a regular file? */ + + if (to->to_type != TMPFS_REGULAR) + { + /* No... unlock the object and its parent and return an error */ + + tmpfs_release_lockedobject(to); + + if (parent) + { + FAR struct tmpfs_directory_s *tdo = *parent; + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + } + + ret = -EISDIR; + } + + /* Return the verified file object */ + + *tfo = (FAR struct tmpfs_file_s *)to; + } + + return ret; +} +``` +

+ + +### tmpfs_realloc_file +tmpfs_realloc_file函数用于扩充当前文件的空间,其源码如下。结构体tmpfs_file_s中的tfo_alloc成员记录了当前file的实际大小,且在文件新创建时会预分配一部分空间,因此当待扩充的大小不超过文件的实际大小时,改变tfo_size的值即可。否则通过kmm_realloc函数进行扩充并完成结构体的更新。 +``` +/**************************************************************************** + * Name: tmpfs_realloc_file + ****************************************************************************/ + +static int tmpfs_realloc_file(FAR struct tmpfs_file_s **tfo, + size_t newsize) +{ + FAR struct tmpfs_file_s *oldtfo = *tfo; + FAR struct tmpfs_file_s *newtfo; + size_t objsize; + size_t allocsize; + size_t delta; + + /* Check if the current allocation is sufficient */ + + objsize = SIZEOF_TMPFS_FILE(newsize); + + /* Are we growing or shrinking the object? */ + + if (objsize <= oldtfo->tfo_alloc) + { + /* Shrinking ... Shrink unconditionally if the size is shrinking to + * zero. + */ + + if (newsize > 0) + { + /* Otherwise, don't realloc unless the object has shrunk by a + * lot. + */ + + delta = oldtfo->tfo_alloc - objsize; + if (delta <= CONFIG_FS_TMPFS_FILE_FREEGUARD) + { + /* Hasn't shrunk enough.. Return doing nothing for now */ + + oldtfo->tfo_size = newsize; + return OK; + } + } + } + + /* Added some additional amount to the new size to account frequent + * reallocations. + */ + + allocsize = objsize + CONFIG_FS_TMPFS_FILE_ALLOCGUARD; + + /* Realloc the file object */ + + newtfo = (FAR struct tmpfs_file_s *)kmm_realloc(oldtfo, allocsize); + if (newtfo == NULL) + { + return -ENOMEM; + } + + /* Adjust the reference in the parent directory entry */ + + DEBUGASSERT(newtfo->tfo_dirent); + newtfo->tfo_dirent->tde_object = (FAR struct tmpfs_object_s *)newtfo; + + /* Return the new address of the reallocated file object */ + + newtfo->tfo_alloc = allocsize; + newtfo->tfo_size = newsize; + *tfo = newtfo; + return OK; +} +``` +

+ +## 目录操作 +### tmpfs_alloc_directory +tmpfs_alloc_directory函数用于为新的目录分配空间,类似于tmpfs_alloc_file,其实现主要为申请内存,结构体初始化,在此不多赘述。 +

+ +### tmpfs_create_directory +tmpfs_create_directory用于创建一个新目录,类似于tmpfs_create_file,在此不多赘述。 +

+ +### tmpfs_find_directory +tmpfs_find_directory函数用于从指定的绝对路径中查找目标兖,类似于tmpfs_find_file。本质上也是是调用了tmpfs_find_object,同时增加了判断,如果找到的目标文件的属性(to_type)不是目录,则返回错误码退出。 +

+ + +### tmpfs_realloc_directory +tmpfs_realloc_directory用于为指定目录tdo扩充一个dirent,其源码如下。不同于tmpfs_realloc_file,这里tmpfs_realloc_directory的入参为期望realloc后dirent的总数。上文提到tmpfs不会立即删去dirent而是将结尾部分预留出来,因此如果当前目录中预留的dirent满足需求,则仅需更新tdo_nentries即可。反之则调用kmm_realloc扩充空间并更新相关结构体。 +``` +/**************************************************************************** + * Name: tmpfs_realloc_directory + ****************************************************************************/ + +static int tmpfs_realloc_directory(FAR struct tmpfs_directory_s **tdo, + unsigned int nentries) +{ + FAR struct tmpfs_directory_s *oldtdo = *tdo; + FAR struct tmpfs_directory_s *newtdo; + size_t objsize; + int ret = oldtdo->tdo_nentries; + + /* Get the new object size */ + + objsize = SIZEOF_TMPFS_DIRECTORY(nentries); + if (objsize <= oldtdo->tdo_alloc) + { + /* Already big enough. + * REVISIT: Missing logic to shrink directory objects. + */ + + oldtdo->tdo_nentries = nentries; + return ret; + } + + /* Added some additional amount to the new size to account frequent + * reallocations. + */ + + objsize += CONFIG_FS_TMPFS_DIRECTORY_ALLOCGUARD; + + /* Realloc the directory object */ + + newtdo = (FAR struct tmpfs_directory_s *)kmm_realloc(oldtdo, objsize); + if (newtdo == NULL) + { + return -ENOMEM; + } + + /* Adjust the reference in the parent directory entry */ + + DEBUGASSERT(newtdo->tdo_dirent); + newtdo->tdo_dirent->tde_object = (FAR struct tmpfs_object_s *)newtdo; + + /* Return the new address of the reallocated directory object */ + + newtdo->tdo_alloc = objsize; + newtdo->tdo_nentries = nentries; + *tdo = newtdo; + + /* Return the index to the first, newly allocated directory entry */ + + return ret; +} +``` +

+ + +# 接口 +与一般的文件系统一样,tmpfs也提供了一些标准接口作为系统调用的最终实现,这里我们着重讲几个常用的接口。

+ +## bind +### 作用 +被调用于初始化阶段,用于创建一个tmpfs根文件系统实例。 +

+ +### 源码分析 +从源码可以看出,bind函数其实就做了两件事:tmpfs_s结构体的内存申请和初始化,涉及的接口在上文已介绍,这里不多赘述。 +``` +/**************************************************************************** + * Name: tmpfs_bind + ****************************************************************************/ + +static int tmpfs_bind(FAR struct inode *blkdriver, FAR const void *data, + FAR void **handle) +{ + FAR struct tmpfs_directory_s *tdo; + FAR struct tmpfs_s *fs; + + finfo("blkdriver: %p data: %p handle: %p\n", blkdriver, data, handle); + DEBUGASSERT(blkdriver == NULL && handle != NULL); + + /* Create an instance of the tmpfs file system */ + + fs = (FAR struct tmpfs_s *)kmm_zalloc(sizeof(struct tmpfs_s)); + if (fs == NULL) + { + return -ENOMEM; + } + + /* Create a root file system. This is like a single directory entry in + * the file system structure. + */ + + tdo = tmpfs_alloc_directory(); + if (tdo == NULL) + { + kmm_free(fs); + return -ENOMEM; + } + + fs->tfs_root.tde_object = (FAR struct tmpfs_object_s *)tdo; + fs->tfs_root.tde_name = ""; + + /* Set up the backward link (to support reallocation) */ + + tdo->tdo_dirent = &fs->tfs_root; + + /* Initialize the file system state */ + + fs->tfs_exclsem.ts_holder = TMPFS_NO_HOLDER; + fs->tfs_exclsem.ts_count = 0; + nxsem_init(&fs->tfs_exclsem.ts_sem, 0, 1); + + /* Return the new file system handle */ + + *handle = (FAR void *)fs; + return OK; +} +``` +

+ +## unbind +### 作用 +释放整个tmpfs文件系统 +

+ +### 源码分析 +unbind的核心为tmpfs_foreach函数,该函数通过层层遍历逐级释放掉tmpfs中的内容,最后tmpfs释放掉根文件系统。 +``` +/**************************************************************************** + * Name: tmpfs_unbind + ****************************************************************************/ + +static int tmpfs_unbind(FAR void *handle, FAR struct inode **blkdriver, + unsigned int flags) +{ + FAR struct tmpfs_s *fs = (FAR struct tmpfs_s *)handle; + FAR struct tmpfs_directory_s *tdo; + int ret; + + finfo("handle: %p blkdriver: %p flags: %02x\n", + handle, blkdriver, flags); + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Lock the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Traverse all directory entries (recursively), freeing all resources. */ + + tdo = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + ret = tmpfs_foreach(tdo, tmpfs_free_callout, NULL); + + /* Now we can destroy the root file system and the file system itself. */ + + nxsem_destroy(&tdo->tdo_exclsem.ts_sem); + kmm_free(tdo); + + nxsem_destroy(&fs->tfs_exclsem.ts_sem); + kmm_free(fs); + return ret; +} +``` +

+ +## open +### 作用 +对应于用户态使用open系统调用,用于打开一个文件。 +

+ +### 源码分析 + +代码虽150行左右,但是内部接口我们之前已有介绍,因此此时再看并不复杂。首先是通过tmpfs_find_file函数查找文件,如果文件确实不存在,则根据用户态传进来的flag来决定是tmpfs_create_file创建一个新文件还是报错退出;如果文件存在,则根据用户态传进来的flag来决定是返回EEXIST错误码退出还是将文件清零。 +``` +/**************************************************************************** + * Name: tmpfs_open + ****************************************************************************/ + +static int tmpfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct inode *inode; + FAR struct tmpfs_s *fs; + FAR struct tmpfs_file_s *tfo; + off_t offset; + int ret; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL); + + /* Get the mountpoint inode reference from the file structure and the + * mountpoint private data from the inode structure + */ + + inode = filep->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Skip over any leading directory separators (shouldn't be any) */ + + for (; *relpath == '/'; relpath++); + + /* Find the file object associated with this relative path. + * If successful, this action will lock both the parent directory and + * the file object, adding one to the reference count of both. + * In the event that -ENOENT, there will still be a reference and + * lock on the returned directory. + */ + + ret = tmpfs_find_file(fs, relpath, &tfo, NULL); + if (ret >= 0) + { + /* The file exists. We hold the lock and one reference count + * on the file object. + * + * It would be an error if we are asked to create it exclusively + */ + + if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + /* Already exists -- can't create it exclusively */ + + ret = -EEXIST; + goto errout_with_filelock; + } + + /* Check if the caller has sufficient privileges to open the file. + * REVISIT: No file protection implemented + */ + + /* If O_TRUNC is specified and the file is opened for writing, + * then truncate the file. This operation requires that the file is + * writeable, but we have already checked that. O_TRUNC without write + * access is ignored. + */ + + if ((oflags & (O_TRUNC | O_WRONLY)) == (O_TRUNC | O_WRONLY)) + { + /* Truncate the file to zero length (if it is not already + * zero length) + */ + + if (tfo->tfo_size > 0) + { + ret = tmpfs_realloc_file(&tfo, 0); + if (ret < 0) + { + goto errout_with_filelock; + } + } + } + } + + /* ENOENT would be returned by tmpfs_find_file() if the full directory + * path was found, but the file was not found in the final directory. + */ + + else if (ret == -ENOENT) + { + /* The file does not exist. Were we asked to create it? */ + + if ((oflags & O_CREAT) == 0) + { + /* No.. then we fail with -ENOENT */ + + ret = -ENOENT; + goto errout_with_fslock; + } + + /* Yes.. create the file object. There will be a reference and a lock + * on the new file object. + */ + + ret = tmpfs_create_file(fs, relpath, &tfo); + if (ret < 0) + { + goto errout_with_fslock; + } + } + + /* Some other error occurred */ + + else + { + goto errout_with_fslock; + } + + /* Save the struct tmpfs_file_s instance as the file private data */ + + filep->f_priv = tfo; + + /* In write/append mode, we need to set the file pointer to the end of the + * file. + */ + + offset = 0; + if ((oflags & (O_APPEND | O_WRONLY)) == (O_APPEND | O_WRONLY)) + { + offset = tfo->tfo_size; + } + + filep->f_pos = offset; + + /* Unlock the file file object, but retain the reference count */ + + tmpfs_unlock_file(tfo); + tmpfs_unlock(fs); + return OK; + + /* Error exits */ + +errout_with_filelock: + tmpfs_release_lockedfile(tfo); + +errout_with_fslock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ + +## close +### 作用 +对应于用户态使用close系统调用,用于关闭一个文件。 +

+ +### 源码分析 +close函数的实现也非常简单,其核心其实就是对tfo_refs成员的操作,源码如下,不多赘述。 +``` +/**************************************************************************** + * Name: tmpfs_close + ****************************************************************************/ + +static int tmpfs_close(FAR struct file *filep) +{ + FAR struct tmpfs_file_s *tfo; + int ret; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Decrement the reference count on the file */ + + DEBUGASSERT(tfo->tfo_refs > 0); + if (tfo->tfo_refs > 0) + { + tfo->tfo_refs--; + } + + filep->f_priv = NULL; + + /* If the reference count decremented to zero and the file has been + * unlinked, then free the file allocation now. + */ + + if (tfo->tfo_refs == 0 && (tfo->tfo_flags & TFO_FLAG_UNLINKED) != 0) + { + /* Free the file object while we hold the lock? Weird but this + * should be safe because the object is unlinked and could not + * have any other references. + */ + + kmm_free(tfo); + return OK; + } + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return OK; +} +``` +

+ +## read +### 作用 +对应于用户态使用read系统调用,用于从文件中读取内容到指定buf。 +

+ +### 源码分析 +read函数的源码如下,核心是调用memcpy将文件指定位置的内容复制到用户提供的buf中。 +``` +/**************************************************************************** + * Name: tmpfs_read + ****************************************************************************/ + +static ssize_t tmpfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct tmpfs_file_s *tfo; + ssize_t nread; + off_t startpos; + off_t endpos; + int ret; + + finfo("filep: %p buffer: %p buflen: %lu\n", + filep, buffer, (unsigned long)buflen); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Handle attempts to read beyond the end of the file. */ + + startpos = filep->f_pos; + nread = buflen; + endpos = startpos + buflen; + + if (endpos > tfo->tfo_size) + { + endpos = tfo->tfo_size; + nread = endpos - startpos; + } + + /* Copy data from the memory object to the user buffer */ + + memcpy(buffer, &tfo->tfo_data[startpos], nread); + filep->f_pos += nread; + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return nread; +} +``` +

+ +## write +### 作用 +对应于用户态使用write系统调用,用于把指定buf中的内容写入文件。 +

+ +### 源码分析 +write函数的源码如下,核心是调用memcpy将用户提供的buf中的内容复制到文件指定位置。如果文件空间不足则会先调用tmpfs_realloc_file函数进行扩容。 +``` +/**************************************************************************** + * Name: tmpfs_write + ****************************************************************************/ + +static ssize_t tmpfs_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct tmpfs_file_s *tfo; + ssize_t nwritten; + off_t startpos; + off_t endpos; + int ret; + + finfo("filep: %p buffer: %p buflen: %lu\n", + filep, buffer, (unsigned long)buflen); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + ret = tmpfs_lock_file(tfo); + if (ret < 0) + { + return ret; + } + + /* Handle attempts to write beyond the end of the file */ + + startpos = filep->f_pos; + nwritten = buflen; + endpos = startpos + buflen; + + if (endpos > tfo->tfo_size) + { + /* Reallocate the file to handle the write past the end of the file. */ + + ret = tmpfs_realloc_file(&tfo, (size_t)endpos); + if (ret < 0) + { + goto errout_with_lock; + } + + filep->f_priv = tfo; + } + + /* Copy data from the memory object to the user buffer */ + + memcpy(&tfo->tfo_data[startpos], buffer, nwritten); + filep->f_pos += nwritten; + + /* Release the lock on the file */ + + tmpfs_unlock_file(tfo); + return nwritten; + +errout_with_lock: + tmpfs_unlock_file(tfo); + return (ssize_t)ret; +} +``` +

+ +## seek +### 作用 +对应于用户态使用lseek系统调用,用于获取或移动文件指针的位置。 +

+ +### 源码分析 +tmpfs中用f_pos成员表示当前文件指针的位置,上文中也可以看到open时f_pos根据用户需要会清理或追加到文件尾部。tmpfs的seek源码如下,实现较为简单, 这里不多赘述。 +``` +/**************************************************************************** + * Name: tmpfs_seek + ****************************************************************************/ + +static off_t tmpfs_seek(FAR struct file *filep, off_t offset, int whence) +{ + FAR struct tmpfs_file_s *tfo; + off_t position; + + finfo("filep: %p\n", filep); + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover our private data from the struct file instance */ + + tfo = filep->f_priv; + + /* Map the offset according to the whence option */ + + switch (whence) + { + case SEEK_SET: /* The offset is set to offset bytes. */ + position = offset; + break; + + case SEEK_CUR: /* The offset is set to its current location plus + * offset bytes. */ + position = offset + filep->f_pos; + break; + + case SEEK_END: /* The offset is set to the size of the file plus + * offset bytes. */ + position = offset + tfo->tfo_size; + break; + + default: + return -EINVAL; + } + + /* Attempts to set the position beyond the end of file will + * work if the file is open for write access. + * + * REVISIT: This simple implementation has no per-open storage that + * would be needed to retain the open flags. + */ + +#if 0 + if (position > tfo->tfo_size && (tfo->tfo_oflags & O_WROK) == 0) + { + /* Otherwise, the position is limited to the file size */ + + position = tfo->tfo_size; + } +#endif + + /* Save the new file position */ + + filep->f_pos = position; + return position; +} +``` +

+ +## mkdir +### 作用 +对应于用户态使用mkdir系统调用,用于创建一个新目录。 +

+ +### 源码分析 +write函数的源码如下,核心是调用tmpfs_create_directory来创建目录,具体实现上文已介绍,这里不多赘述。 +``` +/**************************************************************************** + * Name: tmpfs_mkdir + ****************************************************************************/ + +static int tmpfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, + mode_t mode) +{ + FAR struct tmpfs_s *fs; + int ret; + + finfo("mountpt: %p relpath: %s mode: %04x\n", mountpt, relpath, mode); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Create the directory. */ + + ret = tmpfs_create_directory(fs, relpath, NULL); + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## opendir +### 作用 +对应于用户态使用opendir,用于打开一个目录。 +

+ +### 源码分析 +opendir函数的源码如下,核心是调用tmpfs_find_directory找到指定的目录,并将目录结构体返回给调用opendir的上一级,并经过处理返回给用户。 +``` +/**************************************************************************** + * Name: tmpfs_opendir + ****************************************************************************/ + +static int tmpfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *tdo; + int ret; + + finfo("mountpt: %p relpath: %s dir: %p\n", + mountpt, relpath, dir); + DEBUGASSERT(mountpt != NULL && relpath != NULL && dir != NULL); + + /* Get the mountpoint private data from the inode structure */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Skip over any leading directory separators (shouldn't be any) */ + + for (; *relpath == '/'; relpath++); + + /* Find the directory object associated with this relative path. + * If successful, this action will lock both the parent directory and + * the file object, adding one to the reference count of both. + * In the event that -ENOENT, there will still be a reference and + * lock on the returned directory. + */ + + ret = tmpfs_find_directory(fs, relpath, &tdo, NULL); + if (ret >= 0) + { + dir->u.tmpfs.tf_tdo = tdo; + dir->u.tmpfs.tf_index = tdo->tdo_nentries; + + tmpfs_unlock_directory(tdo); + } + + /* Release the lock on the file system and return the result */ + + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## closedir +### 作用 +对应于用户态使用closedir,用于关闭通过opendir打开的目录。 +

+ +### 源码分析 +closedir函数的源码如下,核心就是将tdo_refs自减,该成员在opendir的使用由于调用了tmpfs_find_object发生了自增。 +``` +/**************************************************************************** + * Name: tmpfs_closedir + ****************************************************************************/ + +static int tmpfs_closedir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_directory_s *tdo; + + finfo("mountpt: %p dir: %p\n", mountpt, dir); + DEBUGASSERT(mountpt != NULL && dir != NULL); + + /* Get the directory structure from the dir argument */ + + tdo = dir->u.tmpfs.tf_tdo; + DEBUGASSERT(tdo != NULL); + + /* Decrement the reference count on the directory object */ + + tmpfs_lock_directory(tdo); + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + return OK; +} +``` +

+ +## readdir +### 作用 +对应于用户态使用readdir,用于读取opendir打开的目录。 +

+ +### 源码分析 +readdir的源码如下,其核心是使用opendir时获取的tf_index从后往前访问目标目录下的dirent,然后index自减。 +``` +/**************************************************************************** + * Name: tmpfs_readdir + ****************************************************************************/ + +static int tmpfs_readdir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir) +{ + FAR struct tmpfs_directory_s *tdo; + unsigned int index; + int ret; + + finfo("mountpt: %p dir: %p\n", mountpt, dir); + DEBUGASSERT(mountpt != NULL && dir != NULL); + + /* Get the directory structure from the dir argument and lock it */ + + tdo = dir->u.tmpfs.tf_tdo; + DEBUGASSERT(tdo != NULL); + + tmpfs_lock_directory(tdo); + + /* Have we reached the end of the directory? */ + + index = dir->u.tmpfs.tf_index; + if (index-- == 0) + { + /* We signal the end of the directory by returning the special error: + * -ENOENT + */ + + finfo("End of directory\n"); + ret = -ENOENT; + } + else + { + FAR struct tmpfs_dirent_s *tde; + FAR struct tmpfs_object_s *to; + + /* Does this entry refer to a file or a directory object? */ + + tde = &tdo->tdo_entry[index]; + to = tde->tde_object; + DEBUGASSERT(to != NULL); + + if (to->to_type == TMPFS_DIRECTORY) + { + /* A directory */ + + dir->fd_dir.d_type = DTYPE_DIRECTORY; + } + else /* to->to_type == TMPFS_REGULAR) */ + { + /* A regular file */ + + dir->fd_dir.d_type = DTYPE_FILE; + } + + /* Copy the entry name */ + + strncpy(dir->fd_dir.d_name, tde->tde_name, NAME_MAX); + + /* Save the index for next time */ + + dir->u.tmpfs.tf_index = index; + ret = OK; + } + + tmpfs_unlock_directory(tdo); + return ret; +} +``` +

+ +## unlink +### 作用 +对应于用户态使用unlink系统调用,用于删除一个文件。 +

+ +### 源码分析 +unlink函数源码如下,首先通过tmpfs_find_file找到目标文件以及其所在的目录,然后通过tmpfs_remove_dirent函数将目标文件的dirent从所在目录中删去。随后会判断文件的tfo_refs值,如果小于等于1,则会调用kmm_free释放目标文件占用的内存。 +``` +/**************************************************************************** + * Name: tmpfs_unlink + ****************************************************************************/ + +static int tmpfs_unlink(FAR struct inode *mountpt, FAR const char *relpath) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *tdo; + FAR struct tmpfs_file_s *tfo = NULL; + FAR const char *name; + int ret; + + finfo("mountpt: %p relpath: %s\n", mountpt, relpath); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Find the file object and parent directory associated with this relative + * path. If successful, tmpfs_find_file will lock both the file object + * and the parent directory and take one reference count on each. + */ + + ret = tmpfs_find_file(fs, relpath, &tfo, &tdo); + if (ret < 0) + { + goto errout_with_lock; + } + + DEBUGASSERT(tfo != NULL); + + /* Get the file name from the relative path */ + + name = strrchr(relpath, '/'); + if (name != NULL) + { + /* Skip over the file '/' character */ + + name++; + } + else + { + /* The name must lie in the root directory */ + + name = relpath; + } + + /* Remove the file from parent directory */ + + ret = tmpfs_remove_dirent(tdo, name); + if (ret < 0) + { + goto errout_with_objects; + } + + /* If the reference count is not one, then just mark the file as + * unlinked + */ + + if (tfo->tfo_refs > 1) + { + /* Make the file object as unlinked */ + + tfo->tfo_flags |= TFO_FLAG_UNLINKED; + + /* Release the reference count on the file object */ + + tfo->tfo_refs--; + tmpfs_unlock_file(tfo); + } + + /* Otherwise we can free the object now */ + + else + { + nxsem_destroy(&tfo->tfo_exclsem.ts_sem); + kmm_free(tfo); + } + + /* Release the reference and lock on the parent directory */ + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + tmpfs_unlock(fs); + + return OK; + +errout_with_objects: + tmpfs_release_lockedfile(tfo); + + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + +errout_with_lock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## rmdir +### 作用 +对应于用户态使用rmdir系统调用,用于删除一个目录。 +

+ +### 源码分析 +rmdir的源码如下,类似于unlink,先通过tmpfs_find_directory查找目标目录,不同的是如果目标目录下还有文件或目标目录被其它进程打开,会直接返回错误码退出。其余过程与unlink基本一致。 +``` +/**************************************************************************** + * Name: tmpfs_rmdir + ****************************************************************************/ + +static int tmpfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_directory_s *parent; + FAR struct tmpfs_directory_s *tdo; + FAR const char *name; + int ret; + + finfo("mountpt: %p relpath: %s\n", mountpt, relpath); + DEBUGASSERT(mountpt != NULL && relpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + return ret; + } + + /* Find the directory object and parent directory associated with this + * relative path. If successful, tmpfs_find_file will lock both the + * directory object and the parent directory and take one reference count + * on each. + */ + + ret = tmpfs_find_directory(fs, relpath, &tdo, &parent); + if (ret < 0) + { + goto errout_with_lock; + } + + /* Is the directory empty? We cannot remove directories that still + * contain references to file system objects. No can we remove the + * directory if there are outstanding references on it (other than + * our reference). + */ + + if (tdo->tdo_nentries > 0 || tdo->tdo_refs > 1) + { + ret = -EBUSY; + goto errout_with_objects; + } + + /* Get the directory name from the relative path */ + + name = strrchr(relpath, '/'); + if (name != NULL) + { + /* Skip over the fidirectoryle '/' character */ + + name++; + } + else + { + /* The name must lie in the root directory */ + + name = relpath; + } + + /* Remove the directory from parent directory */ + + ret = tmpfs_remove_dirent(parent, name); + if (ret < 0) + { + goto errout_with_objects; + } + + /* Free the directory object */ + + nxsem_destroy(&tdo->tdo_exclsem.ts_sem); + kmm_free(tdo); + + /* Release the reference and lock on the parent directory */ + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + tmpfs_unlock(fs); + + return OK; + +errout_with_objects: + tdo->tdo_refs--; + tmpfs_unlock_directory(tdo); + + parent->tdo_refs--; + tmpfs_unlock_directory(parent); + +errout_with_lock: + tmpfs_unlock(fs); + return ret; +} +``` +

+ +## rename +### 作用 +对应于用户态使用rename系统调用,用于重命名文件或目录。 +

+ +### 源码分析 +rename源码如下,tmpfs_rename传入的oldrelpath和newrelpath均已经处理为绝对路径。首先先判断newrelpath是否在根目录,若是则父目录为根文件系统,否则通过tmpfs_find_directory函数查找新文件名对应的新父目录,找到后通过tmpfs_find_dirent函数在新父目录中查找新文件名是否已经有对应的文件存在,如果是则返回错误码,否则继续执行。接下来会查找旧文件名对应的父目录以及文件本身的结构体,并将旧文件名对应的dirent从旧父目录中删去,然后将新文件名对应的dirent与文件结构体关联并添加到新的父目录,如此便rename完成。 +``` +/**************************************************************************** + * Name: tmpfs_rename + ****************************************************************************/ + +static int tmpfs_rename(FAR struct inode *mountpt, + FAR const char *oldrelpath, + FAR const char *newrelpath) +{ + FAR struct tmpfs_directory_s *oldparent; + FAR struct tmpfs_directory_s *newparent; + FAR struct tmpfs_object_s *to; + FAR struct tmpfs_s *fs; + FAR const char *oldname; + FAR char *newname; + FAR char *copy; + int ret; + + finfo("mountpt: %p oldrelpath: %s newrelpath: %s\n", + mountpt, oldrelpath, newrelpath); + DEBUGASSERT(mountpt != NULL && oldrelpath != NULL && newrelpath != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Duplicate the newpath variable so that we can modify it */ + + copy = strdup(newrelpath); + if (copy == NULL) + { + return -ENOMEM; + } + + /* Get exclusive access to the file system */ + + ret = tmpfs_lock(fs); + if (ret < 0) + { + kmm_free(copy); + return ret; + } + + /* Separate the new path into the new file name and the path to the new + * parent directory. + */ + + newname = strrchr(copy, '/'); + if (newname == NULL) + { + /* No subdirectories... use the root directory */ + + newname = copy; + newparent = (FAR struct tmpfs_directory_s *)fs->tfs_root.tde_object; + + tmpfs_lock_directory(newparent); + newparent->tdo_refs++; + } + else + { + /* Terminate the parent directory path */ + + *newname++ = '\0'; + + /* Locate the parent directory that should contain this name. + * On success, tmpfs_find_directory() will lockthe parent + * directory and increment the reference count. + */ + + ret = tmpfs_find_directory(fs, copy, &newparent, NULL); + if (ret < 0) + { + goto errout_with_lock; + } + } + + /* Verify that no object of this name already exists in the destination + * directory. + */ + + ret = tmpfs_find_dirent(newparent, newname); + if (ret != -ENOENT) + { + /* Something with this name already exists in the directory. + * OR perhaps some fatal error occurred. + */ + + if (ret >= 0) + { + ret = -EEXIST; + } + + goto errout_with_newparent; + } + + /* Find the old object at oldpath. If successful, tmpfs_find_object() + * will lock both the object and the parent directory and will increment + * the reference count on both. + */ + + ret = tmpfs_find_object(fs, oldrelpath, &to, &oldparent); + if (ret < 0) + { + goto errout_with_newparent; + } + + /* Get the old file name from the relative path */ + + oldname = strrchr(oldrelpath, '/'); + if (oldname != NULL) + { + /* Skip over the file '/' character */ + + oldname++; + } + else + { + /* The name must lie in the root directory */ + + oldname = oldrelpath; + } + + /* Remove the entry from the parent directory */ + + ret = tmpfs_remove_dirent(oldparent, oldname); + if (ret < 0) + { + goto errout_with_oldparent; + } + + /* Add an entry to the new parent directory. */ + + ret = tmpfs_add_dirent(&newparent, to, newname); + +errout_with_oldparent: + oldparent->tdo_refs--; + tmpfs_unlock_directory(oldparent); + + tmpfs_release_lockedobject(to); + +errout_with_newparent: + newparent->tdo_refs--; + tmpfs_unlock_directory(newparent); + +errout_with_lock: + tmpfs_unlock(fs); + kmm_free(copy); + return ret; +} +``` +

+ + +# 小结 +本文结合nuttx源码介绍了tmpfs的基本数据结构以及常用的几个系统调用实现。nuttx tmpfs的内容虽然并不复杂但是功能基本完备,并且对于后续理解linux中复杂的文件系统具有一定的参考价值。
+
+ +# 文章推荐 +glibc malloc系列文章:
+    原理简析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90/glibc+malloc%E5%8E%9F%E7%90%86%E7%AE%80%E6%9E%90.html
+    数据结构:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90.html
+    malloc:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%BA%8C).html
+    free:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc+malloc%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90(%E4%B8%89).html
+
+ +glibc问题定位与分析系列文章:
+    memcpy 1k字节x86_64虚拟机性能下降分析:
+     https://www.openeuler.org/zh/blog/wangshuo/memcpy_1k%E5%AD%97%E8%8A%82x86_64%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E5%88%86%E6%9E%90.html
+    调用栈问题分析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D--%E6%8E%A8%E6%A0%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html
+
+ +    glibc locale使用简析:
+     https://www.openeuler.org/zh/blog/wangshuo/glibc%20locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90/glibc+locale%E4%BD%BF%E7%94%A8%E7%AE%80%E6%9E%90.html
diff --git "a/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx.jpg" "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ff6bde1a1d1693a0c6fabb8c03a874d78582cdf0 Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/nuttx.jpg" differ diff --git "a/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/tmpfs.jpg" "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/tmpfs.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1fd30102b027343730b7e0508c0ee4a9772d14fd Binary files /dev/null and "b/web-ui/docs/zh/blog/wangshuo/nuttx+tmpfs\347\256\200\344\273\213/tmpfs.jpg" differ diff --git a/web-ui/docs/zh/blog/wangxun/2020-03-25-lifecycle-02.png b/web-ui/docs/zh/blog/wangxun/2020-03-25-lifecycle-02.png new file mode 100644 index 0000000000000000000000000000000000000000..74212ce828c419501d83d0b59a22db1c20fc17be Binary files /dev/null and b/web-ui/docs/zh/blog/wangxun/2020-03-25-lifecycle-02.png differ diff --git a/web-ui/docs/zh/blog/wangxun/openeuler-lifecycle.md b/web-ui/docs/zh/blog/wangxun/openeuler-lifecycle.md new file mode 100644 index 0000000000000000000000000000000000000000..305e4b34939719b4124103e9ec40a2706aaf4088 --- /dev/null +++ b/web-ui/docs/zh/blog/wangxun/openeuler-lifecycle.md @@ -0,0 +1,25 @@ +--- +title: openEuler社区版本命名,发布时间与生命周期管理 +date: 2020-03-25 +tags: + - Release + - Lifecycle +archives: 2020-03 +author: WangXun, Technical Committee +summary: openEuler lifecycle。 +--- + +# openEuler社区版本命名,发布时间与生命周期管理 + + + +* 社区版本按按照交付年份和月份进行版本号命名。例如,openEuler 20.09于2020年09月发布。 +* openEuler release is named based on the delivery year and month. For example, openEuler 20.09 will be released in September 2020. +* 社区版本分为长期支持版本和创新版本。 +* We have two kinds of release: long-term support release and innovation release. +* 长期支持版本:发布间隔周期定为2年,提供4年社区支持。社区首个LTS版本openEuler 20.03 将于20年3月正式发布。 +* Long-term support release: The release interval is set to two years, and four-year-community-support is provided. OpenEuler 20.03-the first LTS will be officially released in March 2020. +* 社区创新版本:LTS版本之间每隔6个月openEuler会发布一个社区创新版本,提供6个月社区支持。 +* Innovation release: openEuler publishes an innovation version every six months between LTS versions and provides six-month community support. +* 欢迎社区开发者和用户提出宝贵建议,以上规则将根据反馈意见以及社区实施情况不断完善。 +* Developers and users are welcome to provide your valuable suggestions. The rule will be updated based on feedback and implementation. diff --git a/web-ui/docs/zh/blog/wangzhigang/2020-09-25-stratovirt-intro.md b/web-ui/docs/zh/blog/wangzhigang/2020-09-25-stratovirt-intro.md new file mode 100644 index 0000000000000000000000000000000000000000..fc1cfed359c8108a6aa41c5ba7f5e58b9e6788b1 --- /dev/null +++ b/web-ui/docs/zh/blog/wangzhigang/2020-09-25-stratovirt-intro.md @@ -0,0 +1,91 @@ +--- +title: 下一代全场景虚拟化平台StratoVirt +date: 2020-09-25 +tags: + - Virt +archives: 2020-09 +author: Xiaohe Yang, Zhigang Wang +summary: Introduction of StratoVirt +--- + +# openEuler重磅利器: StratoVirt下一代全场景虚拟化平台 + + + +**StratoVirt**是计算产业中面向云数据中心的企业级虚拟化平台,实现了一套架构统一支持虚拟机、容器、Serverless三种场景。StratoVirt在轻量低噪、软硬协同、Rust语言级安全等方面具备关键技术竞争优势。 + + + +## 为什么叫StratoVirt? + + + +Strato, 取自stratosphere ,意指地球大气层中的平流层,寓意为保护openEuler平台上业务平稳运行的轻薄保护层。Strato承载了项目的愿景与未来: 轻量、灵活、 安全和完整的保护能力。 + +以Strato入名,同样代表着openEuler对推进下一代全场景虚拟化技术的繁荣、构建虚拟化关键技术竞争力,有着必胜的信心! + + + + +## 为什么需要StratoVirt? + + + +在数据中心领域,虚拟化是资源隔离的重要手段,能以多种粒度提供安全的虚拟运行时环境。传统的虚拟化软件Qemu存在代码量庞大、CVE安全漏洞频出的问题,业界逐步演进出以Rust语言实现microVM形态的趋势。安全、轻量、高性能、低损耗,组件灵活拆分,全场景(数据中心、终端、边缘设备)通用的虚拟化技术是未来的趋势。 + +作为华为自研的下一代全场景、性能领先的虚拟化平台,StratoVirt以极致轻量快速的特质、灵巧的组件配置能力,为轻量虚拟化场景注入澎湃动力,同时也为向标准虚拟化场景的演进提供了无限可能。 + + + +## StratoVirt优势 + +更轻、更快、更强!StratoVirt具有极大的行业竞争力, 在于 + +* 强安全性与隔离性 + * 采用内存安全语言Rust编写, 保证语言级安全性; + * 基于硬件辅助虚拟化实现安全多租户隔离,并通过seccomp进一步约束非必要的系统调用,减小系统攻击面; +* 轻量低噪 + * 轻量化场景下冷启动时间<50ms,内存底噪<4M; +* 高速稳定的IO能力 + * 具有精简的设备模型,并提供了稳定高速的IO能力; +* 资源伸缩 + * 具有ms级别的设备伸缩时延,为轻量化负载提供灵活的资源伸缩能力; +* 全场景支持 + * 完美支持X86和Arm平台:X86支持VT,鲲鹏支持Kunpeng-V,实现多体系硬件加速; + * 可完美集成于容器生态,与Kubernetes生态完美对接,在虚拟机、容器和serverless场景有广阔的应用空间; +* 扩展性 + * 架构设计完备,各个组件可灵活地配置和拆分; + * 设备模型可扩展,可扩展PCIe等复杂设备规范,实现标准虚拟机演进; + + + +## StratoVirt架构 + + + + + +麻雀虽小,五脏俱全。StratoVirt核心架构自顶向下分为三层: + +* OCI兼容接口:兼容qmp协议,具有完备的OCI兼容能力。 +* BootLoader:抛弃传统的BIOS + GRUB启动模式, 实现了更轻更快的BootLoader,并达到极限启动时延。 +* MicroVM:充分利用软硬协同能力;精简化设备模型;低时延资源伸缩能力; + + + +## StratoVirt未来 + +StratoVirt的发展路标为, 通过一套架构,支持轻量虚拟机和标准虚拟机两种模式: + +* 轻量虚拟机模式下,单虚机内存底噪小于4MB,启动时间小于50ms,且支持ms级时延的设备极速伸缩能力,当前已经开发完毕,2020年9月已经在openEuler社区开源; +* 标准虚拟机模式下,可支持完整的机器模型,启动标准内核镜像,可以达成Qemu的能力,同时在代码规模和安全性上有较大优势。 + + + + + +## 关注我们 + +目前StratoVirt已经在openEuler社区开源,期待你的围观和加入! + +项目地址:https://gitee.com/openeuler/stratovirt \ No newline at end of file diff --git a/web-ui/docs/zh/blog/wangzhigang/2020-10-27-stratoVirt-deep-dive-6-1.md b/web-ui/docs/zh/blog/wangzhigang/2020-10-27-stratoVirt-deep-dive-6-1.md new file mode 100644 index 0000000000000000000000000000000000000000..f492097bce18ea5b6954bd693d630cc0b371921e --- /dev/null +++ b/web-ui/docs/zh/blog/wangzhigang/2020-10-27-stratoVirt-deep-dive-6-1.md @@ -0,0 +1,68 @@ +--- +title: 下一代虚拟化平台StratoVirt详解 +date: 2020-10-27 +tags: + - Virt + - StratoVirt +archives: 2020-10 +author: Zhigang Wang +summary: Deep diive of StratoVirt +--- + +## 首先罗列一些问题。阅读完本文,你将会有比较清晰的答案 + +- StratoVirt是什么,有何产品特点? + +- StratoVirt的开发背景,为何要做StratoVirt? + +- StratoVirt的架构设计原原理是什么? + +- StratoVirt未来在openEuler社区的开发路标和演进路线是什么? + +## StratoVirt是什么 + +可能大家心里都会有个疑问:StratoVirt这个名字是什么意思?Strato这个单词的发音[stretə],意思是大气层中的平流层。 + +大家知道,大气层地球能够诞生生命关键性因素,能够保护地球不受外太空陨石的侵害。而虚拟化技术是操作系统平台之上的隔离层,既能保护操作系统平台不被恶意应用侵害,又能给上层应用提供安全隔离的环境。 + +StratoVirt是计算产业中面向云数据中心的企业级虚拟化平台,实现了一套架构统一支持虚拟机、容器、Serverless三种场景,在轻量低噪、软硬协同、安全等方面具备关键技术竞争优势。Strato承载了项目的愿景与未来: 轻量、灵活、 安全和完整的保护能力。这就是StratoVirt这个名字的寓意。 + +因此StratoVirt项目就是要通过openEuler社区为广大用户引入最先进、最开放的虚拟化技术。 + +## 为何要做StratoVirt? + +- Insight 1: QEMU的演进历史 + +提到虚拟化,咱们不得不提到qemu。qemu-kvm是整个虚拟化产业发展的基石和主线,但是在多年的发展历史中,也积累了庞大的代码基线和繁多的历史设备。 + +按照我们的统计,现在qemu已经有157万代码,而且其中又有很大一部分代码是用来支持legacy特性或者设备的,功能和设备严重耦合在一起,导致无法轻装上阵。 + +另外一个insight就是CVE,我们分析统计了过去十几年中QEMU的CVE问题,其中有将近一半是因为内存问题导致的。 + +做过基础设施的兄弟都应该都深有感触,碰到CVE,加班熬夜通宵都不是事,而且搞不好还是加了班还背锅,因此我们也在积极探寻一条自我救赎的道路。 + +我们期望这个答案是Rust。 + + - Insight 2:资源隔离方案演进 + +还有一个insight就是如何进行资源隔离。大家都知道,一台服务器上的资源太大了,肯定要分开了用或者分开卖。咱们手里的两个有力的武器是container和虚拟机,都可以实现资源的分割。当然,从管理面上咱们可以看到K8S,openstack,libvirt这些东西。 + +container这玩意非常好,但是就是不够安全,所以咱们又搞了一条新的路,用虚拟机套容器(其实也就是所谓的安全容器)。安全性的问题解决了,但是又带来一个新的问题,虚拟机太重了,对于一些常驻的业务还好,对一些轻量的业务(比如serverless),那就真是要命了。向左走,还是向右走?咱们的解决方案是啥,microvm。 + +在轻量化场景下,openEuler在开源的解决方案做了很多探索,也尝试来解题。 + +第一个发现是docker太重了,对每个vm的管理开销接近100MB,因此我们有了isula。同时我们发现qemu也太重了,因此有了stratovirt。 + +## StratoVirt的架构设计原原理是什么? + +从顶层架构上看,当前StratoVirt在软件栈中所处的位置和qemu、Firecracker类似:向下借助KVM模块实现硬件加速,例如X86的VT和鲲鹏平台的Kunpeng-V;向上通过容器引擎isula或docker对接容器生态,通过虚拟机引擎libvirt对接虚拟机生态,以此实现对端、边、云中多种应用场景的支持。 + +就StratoVirt本身而言,相比于Rust-VMM最大的架构特征就是组件化、可灵活配置:例如在StratoVirt中引入了device model的概念,基于此实现了CPU、扁平内存、堆叠内存、virtio设备PCI设备等多种公共组件; + +针对轻量化场景,我们可以选用轻量机型主板并在此基础上增加CPU、扁平内存、Virtio设备等必要组件; + +针对标准化场景不,我们可以选用标准机型主板并增加CPU、堆叠内存模型、PCI系统、Virtio设备等组件,这样便可以灵活应对各种场景的需求。 + +## StratoVirt的的技术路标和演进节奏? + +StratoVirt会放在openEuler社区进行开发,相关的特性只要成熟就能合入主线。同时,每个每个季度也会release一个包含所有成熟特性的正式版本。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/wangzhigang/StratoVirt-arch.png b/web-ui/docs/zh/blog/wangzhigang/StratoVirt-arch.png new file mode 100644 index 0000000000000000000000000000000000000000..25ecb5c99fcba9da64a0104766f6adf8ff0ef460 Binary files /dev/null and b/web-ui/docs/zh/blog/wangzhigang/StratoVirt-arch.png differ diff --git a/web-ui/docs/zh/blog/wangzhigang/howToUseStratoVirt.md b/web-ui/docs/zh/blog/wangzhigang/howToUseStratoVirt.md new file mode 100644 index 0000000000000000000000000000000000000000..7bd08c2e87c8440275358467066664cce757ca27 --- /dev/null +++ b/web-ui/docs/zh/blog/wangzhigang/howToUseStratoVirt.md @@ -0,0 +1,268 @@ +--- +title: 如何安装并启动StratoVirt +date: 2020-12-02 +tags: + - StratoVirt + - Virt +archives: 2020-12 +author: Xinle Guo, Zhigang Wang +summary: 本文介绍了如何快速上手安装StratoVirt,并用StratoVirt运行虚拟机。提供StratoVirt对接iSulad并运行安全容器的使用指导。 +--- + +## 背景介绍 + +StratoVirt 作为虚拟化平台,实现了一套架构统一支持虚拟机,容器,Serverless三种场景。我们的 StratoVirt 同时具备了虚拟化的安全特性和容器的轻量级开销。是否想要实际上手操作一番呢?本文就来介绍如何使用 StratoVirt 运行一台虚拟机。另外,在容器场景下,小编也会带来对接 iSulad 容器引擎,运行一台安全容器的操作指导。 + +## 软硬件要求 + +### 最低硬件要求 + +- 处理器架构:仅支持 AArch64 和 x86\_64 处理器架构。AArch64 需要 ARMv8 及更高版本且支持虚拟化扩展;x86\_64支持 VT-x。 +- 2核 CPU +- 4GiB 内存 +- 16GiB 可用磁盘空间 + +### 软件要求 + +操作系统:openEuler 20.09 及更高版本 + +## 安装 StratoVirt + +这里提供了两种方式安装 StratoVirt。如果你只想要使用 StratoVirt 运行一台虚拟机,小编推荐组件安装的方式。你只需要按照软硬件要求,安装 [openEuler 20.09][1] 及更高版本,并且配置好 openEuler yum 源。那么就可以直接使用 yum 命令安装啦。 + +如果你有很强的好奇心,希望深入了解我们的 StratoVirt。那太好了,编译安装的方式更适合你。作为开源项目,我们的 StratoVirt 源码放在[码云][2]平台上。 你可以下载我们的源码,了解它的架构,甚至对其做一些代码修改。 + +### 组件安装 + +步骤1:用 yum 命令安装 + +\`\`\` +[root@openeuler \~]# yum install -y stratovirt +\`\`\` + +说明:安装前,确保已经配置好 openEuler yum 源。 + +### 编译安装 + +步骤1:环境准备,确保 Rust 语言环境和 Cargo 软件已经安装成功。 + +请参考链接的指导进行安装:[https://www.rust-lang.org/tools/install][3] + +步骤2:编译软件 + +\`\`\` +[root@openeuler \~]# git clone https://gitee.com/openeuler/stratovirt.git +[root@openeuler \~]# cd stratovirt +[root@openeuler \~]# cargo build --release +\`\`\` + +生成的二进制文件在 target/release/stratovirt 路径下。 + +## StratoVirt 运行虚拟机 + +步骤1:准备设备和工具 + +\`\`\` +[root@openeuler \~]# modprobe vhost\_vsock +[root@openeuler \~]# yum install nmap +\`\`\` + +步骤2:制作PE格式的 kernel 镜像 + +\`\`\` +[root@openeuler \~]# yum install git; yum install gcc; yum install make; yum install bison; yum install flex +[root@openeuler \~]# cd /home; git clone https://gitee.com/openeuler/kernel +[root@openeuler \~]# cd kernel; git checkout kernel-4.19 +[root@openeuler \~]# cd /home; git clone https://gitee.com/openeuler/stratovirt.git +[root@openeuler \~]# cp stratovirt/docs/kernel\_config/config\_openeuler\_4.19\_aarch64 kernel/.config +[root@openeuler \~]# cd kernel; make –j vmlinux; objcopy -O binary vmlinux vmlinux.bin +\`\`\` + +生成的 /home/kernel/vmlinux.bin 就是制作好的 kernel 镜像。 + +说明:如果使用 x86\_64 处理器架构,需要拷贝 stratovirt/docs/kernel\_config/config\_openeuler\_4.19\_x86\_64 到 kernel 路径下并重命名为.config。 + +步骤3:制作EXT4格式的 rootfs 镜像 + +\`\`\` +[root@openeuler \~]# cd /home +[root@openeuler \~]# dd if=/dev/zero of=./rootfs bs=1G count=5 +[root@openeuler \~]# mkfs.ext4 ./rootfs +[root@openeuler \~]# mkdir /mnt/rootfs; mount /home/rootfs /mnt/rootfs +[root@openeuler \~]# cd /mnt/rootfs +[root@openeuler \~]# wget http://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/aarch64/alpine-minirootfs-3.12.0-aarch64.tar.gz +[root@openeuler \~]# tar -zxvf alpine-minirootfs-3.12.0-aarch64.tar.gz; rm alpine-minirootfs-3.12.0-aarch64.tar.gz +[root@openeuler \~]# rm sbin/init; touch sbin/init && cat \> sbin/init \<\ + +上图展示的容器都运行在单独的虚拟机中,StratoVirt 虚拟化技术提供了虚拟化层的安全隔离。我们将使用 iSulad容器引擎,kata containers 容器运行时和 StratoVirt 虚拟化平台,运行一个安全容器。如果你希望在其他openEuler 版本或 linux 平台上运行安全容器,你可以在 bilibili - openEuler - 如何安装并使用 StratoVirt 视频中找到相应的方法。 + +### 准备工作 + +步骤1:准备设备和工具 + +\`\`\` +[root@openeuler \~]# modprobe vhost\_vsock +[root@openeuler \~]# yum install nmap +\`\`\` + +步骤2:安装 iSulad 和 kata-containers + +\`\`\` +[root@openeuler \~]# yum install iSulad; yum install kata-containers +\`\`\` + +步骤3:添加 iSulad 的 runtime + +\`\`\` +[root@openeuler \~]# vi /etc/isulad/daemon.json // 在runtimes节点中添加如下内容: +"kata-runtime": { + "path": "/usr/bin/kata-runtime" +} +\`\`\` + +步骤4:配置 Storage + +\`\`\` +[root@openeuler \~]# dd if=/dev/zero of=/home/isula\_images bs=1G count=10 +[root@openeuler \~]# losetup /dev/loop1 /home/isula\_images +[root@openeuler \~]# pvcreate /dev/loop1 +[root@openeuler \~]# vgcreate isulaVG0 /dev/loop1 +[root@openeuler \~]# lvcreate --wipesignatures y -n thinpool isulaVG0 -l 95%VG +[root@openeuler \~]# lvcreate --wipesignatures y -n thinpoolmeta isulaVG0 -l 1%VG +[root@openeuler \~]# lvconvert -y --zero n -c 512K --thinpool isulaVG0/thinpool --poolmetadata isulaVG0/thinpoolmeta +[root@openeuler \~]# vi /etc/lvm/profile/isulaVG0-thinpool.profile // 添加如下内容: +activation { + thin_pool_autoextend_threshold=80 + thin_pool_autoextend_percent=20 +} +[root@openeuler \~]# vi /etc/isulad/daemon.json // 更改storage-driver和storage-opts为如下内容: +"storage-driver": "devicemapper", +"storage-opts": [ + "dm.thinpooldev=/dev/mapper/isulaVG0-thinpool", + "dm.fs=ext4", + "dm.min_free_space=10%" +], +\`\`\` + +步骤5:重启 iSulad + +\`\`\` +[root@openeuler \~]# systemctl daemon-reload; systemctl restart isulad +\`\`\` + +使用 isula info 方式,显示 isula 配置信息。如果配置信息有如下显示,恭喜你,isula存储驱动已经配置成功了。 + +\`\`\` +Storage Driver: devicemapper +\`\`\` + +### 配置 kata-containers + +步骤1:制作 kata-containers 的 kernel 镜像 + +\`\`\` +[root@openeuler \~]# cd /home +[root@openeuler \~]# git clone https://github.com/kata-containers/packaging.git +[root@openeuler \~]# cp packaging/kernel/configs/arm64\_kata\_kvm\_4.19.x kernel/.config +[root@openeuler \~]# cd kernel; make –j vmlinux; objcopy -O binary vmlinux vmlinux.bin +[root@openeuler \~]# cp vmlinux.bin vmlinux\_kata +\`\`\` + +步骤2:修改 kata 配置 + +\`\`\` +[root@openeuler \~]# vi /usr/share/defaults/kata-containers/configuration.toml // 修改下面几项内容: +[hypervisor.stratovirt] +path = "/home/stratovirt.sh" +kernel = "/home/kernel/vmlinux\_kata " +initrd = "/var/lib/kata/kata-containers-initrd.img" +block\_device\_driver = "virtio-mmio" +use\_vsock = true +enable\_netmon = false +internetworking\_model="none" +sandbox\_cgroup\_with\_emulator = false +\`\`\` + +### 运行安全容器 + +步骤1:创建运行脚本 + +\`\`\` +[root@openeuler \~]# cat \> /home/stratovirt.sh \<\ | STE 2 | + | STE 3 | + +-------+ +``` + +STE表项中保存了从IOVA到PA的地址翻译过程,为了适应虚拟化场景下的访存需求,SMMU设计了类似EPT页表的两级地址翻译过程。Stage 1 完成从虚拟地址VA到中间地址IPA的翻译过程,stage 2 完成从IPA到实际物理地址的翻译过程。 + +Stream Table Entry: +``` +Stream Table Entry (STE) ++-----------------------+ +| Config | S1ContextPtr | -> CD -> Stage 1 translation tables ++-----------------------+ +| VMID | S2TTB | -> Stage 2 translation tables ++-----------------------+ +| Other attributes, | +| configuration | ++-----------------------+ +``` + +对于非虚拟化场景,设备使用IOVA经过IOMMU进行DMA只需要经过Stage 1的地址转换,因为多个设备可能使用一个设备,所以每个设备的STE中还记录了CD(Context Descriptor)表的信息,由S1ContextPtr指向内存中CD表的基地址,CD表也是一个数组,使用SubstreamID来进行访存,简称ssid,也叫做pasid,pasid是与进程关联的id,用于区分不同进程的虚拟地址空间。在使用pasid找到对应的CD表项之后,也就找到了Stage 1地址翻译的IO页表,保存在TTB0和TTB1中。 + +Context Descriptor: +``` + +-------+ +S1ContextPtr ---- | CD 0 | + | CD 1 | +SubStreamID -> | CD 2 | + | CD 3 | + +-------+ + +Context Desctriptor (CD) ++-----------------------+ +| Configuration | TTB0 | ++-----------------------+ +| ASID | TTB1 | ++-----------------------+ +``` + +值得一提的是,在一般情况下,进程通过设备驱动让设备进行DMA时使用的IOVA由内核态驱动分配,当存在多个进程时,将该内核态的IOVA映射到进程的虚拟地址空间即可,也就是说不同进程在DMA时其实使用的是相同的IOVA地址空间,所以这时只需要第0项CD即可,一般只需要在CD0中保存IO页表的基地址。然而,当需要统一设备的IO地址空间和进程的虚拟地址空间,如共享虚拟地址访问(SVA)时,则会用到多个CD项分别绑定不同进程的虚拟地址空间。 + +设备经过SMMU进行地址翻译是一个很复杂的过程,首先会根据设备的sid(Stream ID)找到对应的STE项,STE项中的配置信息记录了是否需要Bypass Stage 1 的地址翻译,Bypass意味着直接使用PA(或IPA),如果没有Bypass会根据sid(Substream ID)找到对应CD项,CD项中记录了Stage 1地址翻译的页表,会将VA翻译成IPA,然后如果STE中还配置了Stage 2 的页表翻译,会根据Stage 2地址翻译的页表,将IPA翻译成最终的PA地址,如果没有配置Stage 2地址翻译,则之前获取到的IPA就是最终的PA地址。 + +SMMU地址翻译过程: +``` + VA + | + ----------- + | | ++---------------------+ | +| Stage 1 translation | Bypass +| VA->IPA | | ++---------------------+ | + | | + ----------- + | + IPA + | + ----------- + | | ++---------------------+ | +| Stage 2 translation | Bypass +| IPA->VA | | ++---------------------+ | + | | + ----------- + | + PA +``` + +## Arm SMMU V3 初始化 + +所有IOMMU相关的驱动都在内核 drivers/iommu 目录下面,arm平台的最新的架构SMMU-v3的驱动为arm-smmu-v3.c,SMMU本身是一个平台设备,`struct arm_smmu_device`结构体在内存中管理SMMU设备的关键信息,内核对SMMU设备本身的初始化过程主要就是在填充这个结构体。 + +```c +/* An SMMUv3 instance */ +struct arm_smmu_device { + struct device *dev; + void __iomem *base; + u32 features; + u32 options; + + struct arm_smmu_cmdq cmdq; + struct arm_smmu_evtq evtq; + struct arm_smmu_priq priq; + + int gerr_irq; + int combined_irq; + u32 sync_nr; + + unsigned long ias; /* IPA */ + unsigned long oas; /* PA */ + unsigned long pgsize_bitmap; + +#define ARM_SMMU_MAX_ASIDS (1 << 16) + unsigned int asid_bits; + DECLARE_BITMAP(asid_map, ARM_SMMU_MAX_ASIDS); + +#define ARM_SMMU_MAX_VMIDS (1 << 16) + unsigned int vmid_bits; + DECLARE_BITMAP(vmid_map, ARM_SMMU_MAX_VMIDS); + + unsigned int ssid_bits; + unsigned int sid_bits; + + struct arm_smmu_strtab_cfg strtab_cfg; + + /* IOMMU core code handle */ + struct iommu_device iommu; +}; +``` + +驱动加载的入口为 arm_smmu_device_probe 函数,其主要做了如下几件事情: + + 1. 从dts的SMMU节点或ACPI的SMMU配置表中读取SMMU中断等属性 + 2. 用struct resource 来从设备获取到其资源信息,并IO重映射 + 3. probe SMMU的硬件特性 + 4. 中断和事件队列初始化 + 5. 建立STE表 + 6. 设备reset + 7. 将SMMU注册到IOMMU + +### 1. 读取dts的SMMU节点信息 + +函数 arm_smmu_device_dt_probe 读取节点信息主要是从 smmu->dev->of_node中读取对应的属性,并记录到 smmu->options 中,此外还会检查 DMA 是否支持 coherent, 是的话会设置COHERENCY特性。 +```c +if (of_dma_is_coherent(dev->of_node)) + smmu->features |= ARM_SMMU_FEAT_COHERENCY; +``` + +### 2. 获取设备资源信息并IO重映射 + +获取到SMMU设备的资源信息保存在 `struct resource` 结构体中,记录IO基地址,并用 smmu->base 记录完成IO重映射之后的基地址。之后就可以通过 smmu->base 加偏移读写SMMU的硬件寄存器。 + +```c +/* Base address */ +res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +ioaddr = res->start; +smmu->base = devm_ioremap_resource(dev, res); +``` + +### 3. probe SMMU硬件特性 + +函数 arm_smmu_device_hw_probe 通过读取 SMMU 的寄存器获取SMMU的硬件特性, + +IDR0寄存器: +``` +reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0); +``` +* 是否支持:两级STE表、两级CD表 +* 是否支持:PRI、ATS、SEV、MSI、HYP、STALL、Stage 1、Stage 2 +* 获取:ias长度、asid_bits、vmid_bits + +IDR1寄存器: +```c +reg = readl_relaxed(smmu->base + ARM_SMMU_IDR1); +``` +* 获取:evtq和priq的队列长度、ssid_bits、sid_bits、 + +IDR5寄存器: +```c +reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5); +``` +* 获取:evtq最多能stall的的数量 +* 是否支持:VAX、oas长度、pgsize_bitmap + +### 4. 中断和事件队列初始化 + +函数 arm_smmu_init_structures 会完成内存中的数据结构的初始化,包括三条队列evtq、priq、cmdq,cmdq用于SMMU驱动向硬件发送命令,比如刷新TLB、写CD内容等,event队列用于SMMU上挂载的platform设备向驱动发送异常消息,priq队列功能类似只不过用于挂载的PCI设备。event队列和pri队列分别有各自的中断号完成异常事件的通知,此外还有一个gerror的中断号用于上报不可恢复(unrecoverable)的严重错误,其直接中断处理不需要队列。 + +```c +irq = platform_get_irq_byname(pdev, "combined"); +if (irq > 0) + smmu->combined_irq = irq; +else { + irq = platform_get_irq_byname(pdev, "eventq"); + if (irq > 0) + smmu->evtq.q.irq = irq; + + irq = platform_get_irq_byname(pdev, "priq"); + if (irq > 0) + smmu->priq.q.irq = irq; + + irq = platform_get_irq_byname(pdev, "gerror"); + if (irq > 0) + smmu->gerr_irq = irq; +} + +/* Initialise in-memory data structures */ +ret = arm_smmu_init_structures(smmu); +``` + +在驱动进行SMMU设备reset的时候,arm_smmu_setup_unique_irqs 会注册相应的事件处理,eventq和priq会注册内核线程完成事件处理,而对于不可恢复错误gerror则直接注册函数完成中断处理。 + +### 5. 建立STE表 + +根据SMMU的配置不同,可以建立两级或者线性STE表,相对于线性STE表,两级STE表不需要一开始创建所有的STE项,只需要先分配第一级的目录项即可。对于STE线性表,根据sid_bits和STE项的大小,在内存中用dma分配一块连续的内存,在配置中记录其基地址,然后将所有的STE项配置成默认情况下的bypass模式。 + +```c +static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu) +{ + void *strtab; + u64 reg; + u32 size; + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + + size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3); + strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma, + GFP_KERNEL | __GFP_ZERO); + + cfg->strtab = strtab; + cfg->num_l1_ents = 1 << smmu->sid_bits; + + /* Configure strtab_base_cfg for a linear table covering all SIDs */ + reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_LINEAR); + reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits); + cfg->strtab_base_cfg = reg; + + arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents); + return 0; +} +``` +### 6. 设备 reset + +函数 arm_smmu_device_reset 会进行设备的复位操作,通过前面获取到的设备寄存器,对控制寄存器CR1和CR2写入队列内存属性等信息,对STRTAB_BASE寄存器写入STE表的基地址和配置信息,将三条队列在内存中的基地址、队首和队尾信息分别写入对应的寄存器中,之后 reset 会调用arm_smmu_setup_irqs注册中断事件的处理操作。 + +### 7. 将SMMU注册到IOMMU + +不同平台的IOMMU设备在Linux内核中抽象出了统一的IOMMU接口,SMMU的初始化会在sys目录下面注册一个smmu->iommu设备节点,并且将arm_smmu_ops注册给该设备以及系统PCI总线和平台设备总线。这样当使用IOMMU公共接口时,会调用smmu提供的功能,具体可以查看arm_smmu_ops中提供的各种IOMMU接口实现。 + +```c +iommu_device_sysfs_add(&smmu->iommu, dev, NULL, + "smmu3.%pa", &ioaddr); + +iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops); +iommu_device_set_fwnode(&smmu->iommu, dev->fwnode); + +iommu_device_register(&smmu->iommu); + +bus_set_iommu(&pci_bus_type, &arm_smmu_ops); +bus_set_iommu(&platform_bus_type, &arm_smmu_ops); +``` + +## IOMMU与DMA + +IOMMU的主要功能之一就是避免设备在进行DMA访问内存的时候直接使用物理地址不安全,所以就产生了IOVA地址,在dma_alloc分配内存的时候,首先在IO地址空间分配一个IOVA地址,然后在IOMMU管理的页表中建立IOVA和dma_alloc分配的物理地址的映射关系,外设在进行dma的时候,只需要使用IOVA地址即可。 + +调用 dma alloc 系列函数分配内存最终会调到 iommu_dma_alloc 函数,其会分配iova和实际的物理内存,并用iommu_map建立iova到物理内存的映射关系,也就是找到设备对应的STE,并找到CD项(一般是第0项),然后找到内存中对应的页表,将iova到物理地址的映射写入页表中,arm SMMU 相关的页表操作在 io-pgtable.c中完成。 + +```c +iommu_dma_alloc + pages = __iommu_dma_alloc_pages(count, alloc_sizes >> PAGE_SHIFT, gfp); + iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev); + + iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot +``` + +可以有多种方式bypass掉IOMMU,首先Linux提供了iommu.passthrough的方式,可以配置dma默认不走iommu,通过软件的地址映射技术swiotlb来访存;其次,SMMU v3驱动中提供了参数可以bypass掉某个SMMU;第三十可以在ACPI或者DTS中不配置对应的SMMU节点,这样系统加载的时候就不会probe对应的SMMU了。 + +## 小结 + +IOMMU的主要功能就是为设备访问物理内存提供IOVA到PA的映射,使得设备不会直接使用物理地址来访存比较安全。Arm SMMUv3 作为IOMMU的一种具体实现,为其提供相应的接口。与IOMMU相关的包括设备进行DMA操作,VFIO直通将设备硬件能力安全的暴露给用户态等,本质上都是为了建立设备能够识别的IOVA到实际物理地址的映射关系。 + +## Reference: +* https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +* https://developer.arm.com/documentation/ihi0070/latest +* https://kernel.taobao.org/2020/06/ARM-SMMU-and-IOMMU/ \ No newline at end of file diff --git a/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-1.md b/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-1.md new file mode 100644 index 0000000000000000000000000000000000000000..be76e75cd683ca42d81f9b43efeb5af4e53139c5 --- /dev/null +++ b/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-1.md @@ -0,0 +1,290 @@ +--- +title: VFIO设备直通原理(一) +date: 2020-11-29 +tags: + - IOMMU + - SMMU + - DMA +archives: 2020-11 +author: Wang Xingang +summary: 介绍VFI设备直通原理,主要是基本概念和用户态使用接口分析 +--- + +现代系统大多提供DMA和中断重映射功能来确保I/O设备在有限的范围内运行,比如x86平台的AMD-Vi和Intel VT-d。VFIO(Virtual Function I/O)是一个可以将设备I/O、中断和DMA等能力安全的暴露到用户态空间,从而使用用户态驱动实现设备驱动的框架。通过VFIO进行设备直通到虚拟机,可以获得更高的设备I/O性能。 + +实现用户态驱动最关键的问题在于如何安全可控的将设备的DMA能力暴露到用户空间,IOMMU的出现可以限制设备对内存的访问,恶意的设备不能直接读写物理内存,经过IOMMU映射之后才能使用IOVA或者虚拟地址进行访存,由IOMMU来保证访存的安全性。 + +## VFIO内核组件 + +VFIO内核组件主要包括如下图所示,通过设备文件向用户态提供统一访问接口vfio interface层,包括: + +* VFIO container +* VFIO group +* VFIO device + +``` ++-----------------------------------------+ +| vfio interface | ++-----------------------------------------+ +| vfio_iommu_driver | vfio_pci | ++--------------------+--------------------+ +| iommu | pci_bus | ++--------------------+--------------------+ +``` + +vfio interface 封装了vfio_iommu_driver和vfio_pci分别和底层的IOMMU、PCI驱动进行交互,vfio_iommu_driver为VFIO提供了IOMMU重映射驱动,向用户态暴露DMA操作,主要是vfio_iommu_type1驱动,利用IOMMU管理IO页表的能力来进行IO重映射。vfio_pci模块封装pci设备驱动并和用户态程序进行配合完成用户态的设备配置模拟、Bar空间重定向及中断重映射等功能。 + +VFIO框架中比较重要的几个概念包括:Container、Group和Device,其相互之间的关系如图所示,一个container可以理解为实际的物理资源集合,每个container中可以有多个group,group描述了设备在物理上的划分,一个group可以有多个device,划分的逻辑取决于硬件上的IOMMU拓扑结构。 + +``` +container ++------------------------+ +| group0 group1 | +| +-------+ +------+ | +| | dev0 | | dev2 | | +| | dev1 | +------+ | +| +-------+ | ++------------------------+ +``` + +可以结合内核中vfio.txt文件来理解Container、Group、Device和IOMMU之间的关系。 + +## VFIO Container + +```c +// container: /dev/vfio/vfio +struct vfio_container { + struct kref kref; + struct list_head group_list; + struct rw_semaphore group_lock; + struct vfio_iommu_driver *iommu_driver; + void *iommu_data; + bool noiommu; +}; +``` + +Container是管理内存资源,和IOMMU、DMA及地址空间相关,可以通过打开设备文件/dev/vfio/vfio来获取container对应的文件描述符,在内核vfio/vfio.c中有对应该vfio设备文件的具体操作实现,ioctl主要是可以获取IOMMU相关的信息,vfio会将用户态对IOMMU相关操作发给底层的vfio_iommu驱动进行操作,通过vfio ioctl提供的接口如下: + +* 获取API versio +* 设置IOMMU的类型,如设置为常用的VFIO_TYPE1_IOMMU +* 获取IOMMU的信息 +* 分配空间并进行DMA映射 + +``` c +int container, group, device, i; +struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) }; +struct vfio_iommu_type1_dma_map dma_map = { .argsz = sizeof(dma_map) }; + +/* Create a new container */ +container = open("/dev/vfio/vfio", O_RDWR); + +if (ioctl(container, VFIO_GET_API_VERSION) != VFIO_API_VERSION) + /* Unknown API version */ + +if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) + /* Doesn't support the IOMMU driver we want. */ + +/* Enable the IOMMU model we want */ +ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); + +/* Get addition IOMMU info */ +ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info); + +/* Allocate some space and setup a DMA mapping */ +dma_map.vaddr = mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); +dma_map.size = 1024 * 1024; +dma_map.iova = 0; /* 1MB starting at 0x0 from device view */ +dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE; + +ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map); +``` + +## VFIO Group + +```c +// group: /dev/vfio/%group_id +struct vfio_group { + struct kref kref; + int minor; + atomic_t container_users; + struct iommu_group *iommu_group; + struct vfio_container *container; + struct list_head device_list; + struct mutex device_lock; + struct device *dev; + struct notifier_block nb; + struct list_head vfio_next; + struct list_head container_next; + struct list_head unbound_list; + struct mutex unbound_lock; + atomic_t opened; + wait_queue_head_t container_q; + bool noiommu; + struct kvm *kvm; + struct blocking_notifier_head notifier; +}; +``` + +Group是IOMMU进行DMA隔离的最小硬件单元,设备属于哪个group取决于IOMMU和设备的物理结构,在设备直通时需要将一个group里的所有设备都分配给一个虚拟机,其实就是多个group可以从属于一个container,而group下的所有设备也随着该group从属于该container。这样能够做到DMA隔离,避免一个container里的device通过DMA来攻击获取另一个container里的数据。 + +对于一个PCI设备0000:06:0d.0::,通过readlink可以在sys文件目录下获取其iommu_group,比如该PCI设备在ID为26的IOMMU group中。 + +``` shell +$ readlink /sys/bus/pci/devices/0000:06:0d.0/iommu_group +../../../../kernel/iommu_groups/26 +``` + +设备挂载在pci bus下,可以使用 vfio-pci 来管理这个group。使用vfio-pci来管理设备时,首先从原来的驱动里unbind该PCI设备,然后将id写入新的vfio-pci路径下,会为这个group创建一个字符设备。 + +``` shell +$ lspci -n -s 0000:06:0d.0 +06:0d.0 0401: 1102:0002 (rev 08) +$ echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind +$ echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id +``` + +当设备绑定到vfio之后,在/dev/vfio/路径下面会产生一个新的group id,通过该id可以获取到group,完成以下操作: + +* 查询group状态,是否所有设备都绑定到vfio驱动 +* 设置group的container +* 根据设备的BDF号为设备分配一个文件描述符 + +``` c +struct vfio_group_status group_status = + { .argsz = sizeof(group_status) }; +/* Open the group */ +group = open("/dev/vfio/26", O_RDWR); + +/* Test the group is viable and available */ +ioctl(group, VFIO_GROUP_GET_STATUS, &group_status); + +if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) + /* Group is not viable (ie, not all devices bound for vfio) */ + +/* Add the group to the container */ +ioctl(group, VFIO_GROUP_SET_CONTAINER, &container); + +/* Get a file descriptor for the device */ +device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:06:0d.0"); +``` + +## VFIO Device + +```c +struct vfio_device { + struct kref kref; + struct device *dev; + const struct vfio_device_ops *ops; + struct vfio_group *group; + struct list_head group_next; + void *device_data; +}; +``` + +为了兼顾platform和pci设备,vfio统一对外提供 `struct vfio_device` 来描述vfio设备,并用device_data来指向如 `struct vfio_pci_device`。Device即设备,但与真正的物理设备有区别的是,对于一个在硬件上独立的设备,单独构成一个iommu group,而如果是multi-function的设备,多个function之间是互联的,相互可以访问对方的数据,所以必须放到一个group里面。 + +通过group的ioctl操作和设备的的BDF号获取到设备描述符之后,在vfio_pci中有对应描述符的内核操作vfio_pci_ops,这个ops是在vfio_pci设备驱动vfio_pci_probe调用的时候注册到PCI设备的,probe的时候还会将设备加入到对应的group中。vfio_pci设备的ops中比较重要的是 vfio_pci_ioctl函数,提供了如下功能: + +* VFIO_DEVICE_GET_INFO:获取设备信息,region数量、irq数量等 +* VFIO_DEVICE_GET_REGION_INFO:获取vfio_region的信息,包括配置空间的region和bar空间的region等 +* VFIO_DEVICE_GET_IRQ_INFO:获取设备中断相关的信息 +* VFIO_DEVICE_SET_IRQS:完成中断相关的设置 +* VFIO_DEVICE_RESET:设备复位 +* VFIO_DEVICE_GET_PCI_HOT_RESET_INFO:获取PCI设备hot reset信息 +* VFIO_DEVICE_PCI_HOT_RESET:设置PCI设备 hot reset +* VFIO_DEVICE_IOEVENTFD:设置ioeventfd + +要暴露设备的能力到用户态空间,要让用户态能够直接访问设备配置空间并处理设备中断,对于PCI设备而言,其配置其配置空间是一个VFIO region,对应着一块MMIO内存,通过建立dma重映射让用户态能够直接访问设备配置空间,另外还需要建立中断重映射以让用户态驱动处理设备中断事件。 + +``` c +struct vfio_device_info device_info = { .argsz = sizeof(device_info) }; + +/* Get a file descriptor for the device */ +device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:06:0d.0"); + +/* Test and setup the device */ +ioctl(device, VFIO_DEVICE_GET_INFO, &device_info); + +for (i = 0; i < device_info.num_regions; i++) { + struct vfio_region_info reg = { .argsz = sizeof(reg) }; + + reg.index = i; + + ioctl(device, VFIO_DEVICE_GET_REGION_INFO, ®); + + /* Setup mappings... read/write offsets, mmaps + + * For PCI devices, config space is a region */ +} + +for (i = 0; i < device_info.num_irqs; i++) { + struct vfio_irq_info irq = { .argsz = sizeof(irq) }; + + irq.index = i; + + ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &irq); + + /* Setup IRQs... eventfds, VFIO_DEVICE_SET_IRQS */ +} + +/* Gratuitous device reset and go... */ +ioctl(device, VFIO_DEVICE_RESET); +``` + +## Container,group和device绑定 + +1.VFIO_SET_IOMMU: Container 绑定 IOMMU: + +首先,VFIO的Container和IOMMU之间的绑定,通过在用户态通过ioctl调用VFIO_SET_IOMMU完成,绑定意味着将container管理的所有group都attach到IOMMU中,最终会将每个group中的每个设备都attach到IOMMU中,这意味着为设备建立IO页表完成初始化 + +```c +ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU) + vfio_ioctl_set_iommu + list_for_each_entry(group, &container->group_list, container_next) { + ret = driver->ops->attach_group(data, group->iommu_group); + __iommu_attach_group + ret = __iommu_group_for_each_dev(group, domain, + iommu_group_do_attach_device); + __iommu_attach_device + arm_smmu_attach_dev + 建立设备的IO页表 +``` + +2.VFIO_GROUP_SET_CONTAINER: 将Group设置到对应的Container: + +VFIO提供接口由用户态指定Group绑定到哪个Container中,这个绑定操作会将group记录到container的链表中进行管理,并且如果已经设置好了vfio_iommu_driver,会进行group的attach操作,并进而完成该group中的设备的IO页表初始化 + +```c +VFIO_GROUP_SET_CONTAINER: + vfio_group_set_container + driver = container->iommu_driver; + if (driver) { + ret = driver->ops->attach_group(container->iommu_data, + group->iommu_group); + if (ret) + goto unlock_out; + } + + group->container = container; + container->noiommu = group->noiommu; + list_add(&group->container_next, &container->group_list); +``` + +3.Device和Group之间的绑定关系源自设备和IOMMU的物理拓扑结构 + +## 小结 + +VFIO内核组件的实现与Linux内核的IOMMU、设备模型等紧密相连,通过抽象出VFIO的概念来完成对Linux内核组件的封装。本文主要通过VFIO的用户态接口的使用来介绍了VFIO的几个基本概念,包括VFIO Container、Group和Device。要让物理设备通过VFIO驱动暴露给用户态,需要完成以下步骤: + +* 首先将设备与原有驱动进行解绑,并重新绑定到VFIO驱动,VFIO驱动会为设备指定对应的group,设备属于哪个IOMMU group与设备和IOMMU的物理拓扑结构有关。 +* 完成上述绑定之后,用户态驱动就可以通过 `/dev/vfio/vfio`获取到VFIO 的container,设置vfio_iommu_driver的类型,通过container可以间接访问IOMMU完成dma映射。 +* 然后可以通过 `/dev/vfio/%group_id` 获取到设备所属的group,通过ioctl将该group上的所有设备加入到container中。 +* 然后通过group和设备BDF号可以获取到VFIO device的fd,并通过vfio提供的接口访问设备的配置空间和irq信息等,完成在用户态访问物理设备。 + +VFIO设备直通有几个关键问题需要关注,如何访问直通设备的IO地址空间,如何完成中断重映射和DMA重映射让用户态驱动访问物理设备能力. + +## Reference + +* https://www.kernel.org/doc/Documentation/vfio.txt +* https://kernelgo.org/vfio-introduction.html diff --git a/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-2.md b/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-2.md new file mode 100644 index 0000000000000000000000000000000000000000..8f4911a82efac449c8aa5b7e691289862bd21a96 --- /dev/null +++ b/web-ui/docs/zh/blog/wxggg/2020-11-29-vfio-passthrough-2.md @@ -0,0 +1,321 @@ +--- +title: VFIO设备直通原理(二) +date: 2020-11-21 +tags: + - IOMMU + - SMMU + - DMA +archives: 2020-11 +author: Wang Xingang +summary: 介绍VFIO设备直通原理,包括DMA重映射,中断重映射和配置空间模拟等 +--- + +设备直通给虚拟机能够极大提升虚拟机对物理设备访问的性能,本文通过vfio内核模块和qemu用户态实现介绍vfio设备直通时的关键部分,包括:用户态访问设备IO地址空间,DMA重映射,中断重映射等. + +## VFIO访问直通设备IO地址空间 + +1.PIO和MMIO + +设备的IO地址空间的访问有PIO和MMIO两种方式,前者通过独立的IO端口访问设备,而MMIO是在物理内存中映射一段区间,直接访问该内存就可以访问设备的配置空间.在虚拟化的场景下,虚拟机通过PIO访问直通设备时,首先会VM-exit到qemu,由qemu通过转换表完成对该PIO操作的转发.对于PCI设备而言,其bar空间地址是通过PIO的方式设置的,如果将设备的PIO访问完全暴露给虚拟机,虚拟机修改了真实的物理设备的PCI Bar空间基地址配置,与host上不一致,可能会出现严重的问题,所以对于设备的PIO访问需要建立转换表,在VM-exit之后由qemu来完成设置的转发. + +对于设备的MMIO空间访问,则可以通过建立EPT页表将设备的MMIO物理内存映射到虚拟的MMIO地址空间,让虚拟机能够直接通过MMIO访问PCI设备的bar空间,提高IO性能. + +2.获取直通设备信息 + +通过VFIO提供的接口可以获取到设备的基本信息,包括设备的描述符、region的数量等。 + +```c +vfio_get_device: + fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name); + ret = ioctl(fd, VFIO_DEVICE_GET_INFO, &dev_info); + + vbasedev->fd = fd; + vbasedev->group = group; + QLIST_INSERT_HEAD(&group->device_list, vbasedev, next); + + vbasedev->num_irqs = dev_info.num_irqs; + vbasedev->num_regions = dev_info.num_regions; + vbasedev->flags = dev_info.flags; + +``` + +2.直通设备PCI配置空间模拟 + +Qemu为每个PCI直通设备都建立一个虚拟数据结构 VFIOPCIDevice,保存物理PCI设备的相关信息,由vfio_get_device来获取,保存到vbasedev中。 + +```c +typedef struct VFIOPCIDevice { + PCIDevice pdev; + VFIODevice vbasedev; +``` + +VFIO设备作为qemu的设备模型的一部分,qemu对直通设备的模拟初始化入口在 vfio_realize,通过vfio_get_device获取到直通设备的基本信息之后,会调用pread设备的fd获取到设备的配置空间信息的一份拷贝,qemu会写入一些自定义的config配置。 + +```c +vfio_realize: + /* Get a copy of config space */ + ret = pread(vdev->vbasedev.fd, vdev->pdev.config, + MIN(pci_config_size(&vdev->pdev), vdev->config_size), + vdev->config_offset); + if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { + ret = ret < 0 ? -errno : -EFAULT; + error_setg_errno(errp, -ret, "failed to read device config space"); + goto error; + } + + /* vfio emulates a lot for us, but some bits need extra love */ + vdev->emulated_config_bits = g_malloc0(vdev->config_size); + + /* QEMU can choose to expose the ROM or not */ + memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4); + + /* QEMU can change multi-function devices to single function, or reverse */ + vdev->emulated_config_bits[PCI_HEADER_TYPE] = + PCI_HEADER_TYPE_MULTI_FUNCTION; + + /* Restore or clear multifunction, this is always controlled by QEMU */ + if (vdev->pdev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + vdev->pdev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } else { + vdev->pdev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + /* + * Clear host resource mapping info. If we choose not to register a + * BAR, such as might be the case with the option ROM, we can get + * confusing, unwritable, residual addresses from the host here. + */ + memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24); + memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4); +``` + +3.直通设备MMIO映射 + +直通PCI设备的MMIO内存主要是指其Bar空间,qemu使用vfio_populate_device函数调用VFIO接口获取到PCI设备的Bar空间信息,然后通过vfio_region_setup获取到对应region的信息,并将qemu内存虚拟化的MemoryRegion设置为IO类型的region。重要的是,qemu会为该IO类型的MemoryRegion设置ops为vfio_region_ops,这样后续对于该块内存的读写会经过qemu VFIO模块注册的接口来进行。 + +```c +vfio_populate_device: + for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) { + char *name = g_strdup_printf("%s BAR %d", vbasedev->name, i); + + ret = vfio_region_setup(OBJECT(vdev), vbasedev, &vdev->bars[i].region, i, name); + -> vfio_get_region_info + -> memory_region_init_io(region->mem, obj, &vfio_region_ops, + region, name, region->size); + QLIST_INIT(&vdev->bars[i].quirks); + } + ret = vfio_get_region_info(vbasedev, VFIO_PCI_CONFIG_REGION_INDEX, ®_info); + -> ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); +``` + +到这里已经获取到了PCI设备的MMIO内存信息,但是还没有真正的将物理内存中的Bar空间映射到qemu,这一动作在vfio_bars_setup中完成,vfio_region_mmap会对region中每个需要map的内存地址完成映射,然后将映射的物理内存通过qemu注册到虚拟机作为一段虚拟机的物理地址空间。 + +```c +vfio_bars_setup: + for (i = 0; i < PCI_ROM_SLOT; i++) + vfio_bar_setup(vdev, i); + vfio_region_mmap(&bar->region) + for (i = 0; i < region->nr_mmaps; i++) { + region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot, + MAP_SHARED, region->vbasedev->fd, + region->fd_offset + + region->mmaps[i].offset); + memory_region_init_ram_device_ptr + memory_region_add_subregion + pci_register_bar(&vdev->pdev, nr, type, bar->region.mem); + +``` + +这里的映射mmap接口对应的是VFIO设备在内核中注册的vfio_pci_mmap 函数,在内核中,该函数会为vma注册一个mmap的ops,对应着注册了一个缺页处理函数,当用户态程序访问该段虚拟内存缺页时,调用注册的缺页处理函数,完成虚拟地址到实际物理地址的映射。 + +```c +vfio_pci_mmap: + vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &vfio_pci_mmap_ops; + -> .fault = vfio_pci_mmap_fault, + -> if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) +``` + +简单来说,对于MMIO内存的的映射,主要是将物理内存中的MMIO空间映射到了qemu的虚拟地址空间,然后再由qemu将该段内存注册进虚拟机作为虚拟机的一段物理内存,在这个过程中会建立从gpa到hpa的EPT页表映射,提升MMIO的性能。 + +## DMA重映射 + +首先关于DMA,设备通过DMA可以直接使用iova地址访问物理内存,从iova到实际物理地址的映射是在IOMMU中完成的,一般在dma_allooc分配设备能够访问的内存的时候,会分配iova地址和实际的物理地址空间,并在iommu中建立映射关系。 +所以说要让设备进行DMA最关键的几个部分: + +* 设备能够识别的地址:IOVA +* 一段物理内存 +* IOVA到物理内存在IOMMU中的映射关系 + +基于这几点来看VFIO的DMA重映射就比较清晰,首先从VFIO设备的初始化开始,在获取设备信息之前会先获取到设备所属的group和Container,并调用VFIO_SET_IOMMU完成container和IOMMU的绑定,并attach由VFIO管理的所有设备。此外注意到这里的 pci_device_iommu_address_space 函数,意思是qemu为设备dma注册了一段专门的地址空间,这段内存作为虚拟机的一段物理内存存在,在VFIO_SET_IOMMU之后,注册该地址空间,其region_add函数为 vfio_listener_region_add,意思是当内存空间布局发生变化这里是增加内存的时候都会调用该接口。 + +```c +vfio_realize: + group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp); + vfio_connect_container(group, as, errp) + ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); + container->listener = vfio_memory_listener; + memory_listener_register(&container->listener, container->space->as); + -> .region_add = vfio_listener_region_add, +``` + +那么跟DMA有什么关系呢,当为设备进行DMA分配一块内存时,实际是以MemoryRegion的形式存在的,也就是说虚拟机进行dma alloc 会调用region_add函数,进而调用注册的memory_listener_region_add函数,MemoryRegion有了意味着分配了一块物理内存,还需要IOVA和映射关系才行。这里,IOVA地址使用的是section->offset_within_address_space,为什么可以这样,因为IOVA地址只是作为设备识别的地址,只要建立了映射关系就有意义。 + +```c +vfio_listener_region_add: + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + /* Here we assume that memory_region_is_ram(section->mr)==true */ + vaddr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region + + (iova - section->offset_within_address_space); + ret = vfio_dma_map(container, iova, int128_get64(llsize), + vaddr, section->readonly); + +vfio_dma_map: + struct vfio_iommu_type1_dma_map map = { + .argsz = sizeof(map), + .flags = VFIO_DMA_MAP_FLAG_READ, + .vaddr = (__u64)(uintptr_t)vaddr, + .iova = iova, + .size = size, + }; + + ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) +``` + +建立映射的关键在于vfio_dma_map,通过ioctl调用container->fd接口VFIO_IOMMU_MAP_DMA完成DMA重映射。为什么是container->fd,因为VFIO Container管理内存资源,与IOMMU直接绑定,而IOMMU是完成IOVA到实际物理内存映射的关键。值得注意的是qemu只知道这一段内存的虚拟地址vaddr,所以将vaddr,iova和size传给内核,由内核获取物理内存信息完成映射。 + +```c +vfio_dma_do_map: + vfio_pin_map_dma + while (size) { + /* Pin a contiguous chunk of memory */ + npage = vfio_pin_pages_remote(dma, vaddr + dma->size, + size >> PAGE_SHIFT, &pfn, limit); + /* Map it! */ + vfio_iommu_map(iommu, iova + dma->size, pfn, npage, + dma->prot); + list_for_each_entry(d, &iommu->domain_list, next) + iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT, + npage << PAGE_SHIFT, prot | d->prot); + arm_smmu_map + __arm_lpae_map + size -= npage << PAGE_SHIFT; + dma->size += npage << PAGE_SHIFT; + } +``` + +内核完成建立iova到物理内存的映射之前会将分配的DMA内存给pin住,使用vfio_pin_pages_remote接口可以获取到虚拟地址对应的物理地址和pin住的页数量,然后vfio_iommu_map进而调用iommu以及smmu的map函数,最终用iova,物理地址信息pfn以及要映射的页数量在设备IO页表中建立映射关系。 + +``` ++--------+ iova +--------+ gpa +----+ +| device | -> | memory | <- | vm | ++--------+ +--------+ +----+ +``` + +最终完成了DMA重映射,设备使用qemu分配的iova地址通过IOMMU映射访问内存,虚拟机使用gpa通过Stage 2页表映射访问内存 + +## 中断重映射 + +对于PCI直通设备中断的虚拟化,主要包括三种类型INTx,Msi和Msi-X。 + +1.INTx中断初始化及enable + +对于INTx类型的中断,在初始化的时候就进行使能了,qemu通过VFIO device的接口将中断irq set设置到内核中,并且会注册一个eventfd,设置了eventfd的handler,当发生intx类型的中断时,内核会通过eventfd通知qemu进行处理,qemu会通知虚拟机进行处理。 + +```c +vfio_realize: + if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { + pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_intx_update); + ret = vfio_intx_enable(vdev, errp); + *pfd = event_notifier_get_fd(&vdev->intx.interrupt); + qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev); + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); +``` + +2.MSI-X初始化 + +MSIX在vfio_realzie初始化时,首先获取到物理设备的中断相关的配置信息,将其设置到注册给对应的MMIO内存中 + +```c +vfio_msix_early_setup: + pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX); + + if (pread(fd, &ctrl, sizeof(ctrl), + vdev->config_offset + pos + PCI_MSIX_FLAGS) != sizeof(ctrl)) { + if (pread(fd, &table, sizeof(table), + vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) { + if (pread(fd, &pba, sizeof(pba), + vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) { + + ctrl = le16_to_cpu(ctrl); + table = le32_to_cpu(table); + pba = le32_to_cpu(pba); + + msix = g_malloc0(sizeof(*msix)); + msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK; + msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK; + msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK; + msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; + msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; + +vfio_msix_setup: + msix_init(&vdev->pdev, vdev->msix->entries, + vdev->bars[vdev->msix->table_bar].region.mem, + vdev->msix->table_bar, vdev->msix->table_offset, + vdev->bars[vdev->msix->pba_bar].region.mem, + vdev->msix->pba_bar, vdev->msix->pba_offset, pos); + + memory_region_init_io(&dev->msix_table_mmio, OBJECT(dev), &msix_table_mmio_ops, dev, + "msix-table", table_size); + memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio); + memory_region_init_io(&dev->msix_pba_mmio, OBJECT(dev), &msix_pba_mmio_ops, dev, + "msix-pba", pba_size); + memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio); + +vfio_realize: + /* QEMU emulates all of MSI & MSIX */ + if (pdev->cap_present & QEMU_PCI_CAP_MSIX) { + memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff, + MSIX_CAP_LENGTH); + + if (pdev->cap_present & QEMU_PCI_CAP_MSI) { + memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff, + vdev->msi_cap_size); +``` + +3. MSI/MSI-X enable 与 irqfd的注册 + +当虚拟机因为写PCI配置空间而发生VM-exit时,最终会完成msi和msix的使能,以MSIX的使能为例,在qemu侧会设置eventfd的处理函数,并通过kvm将irqfd注册到内核中,进而注册虚拟中断给虚拟机。 + +```c +kvm_cpu_exec: + vfio_pci_write_config: + vfio_msi_enable(vdev); + vfio_msix_enable(vdev); + for (i = 0; i < vdev->nr_vectors; i++) { + if (event_notifier_init(&vector->interrupt, 0)) { + + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + vfio_msi_interrupt, NULL, vector); + + vfio_add_kvm_msi_virq(vdev, vector, i, false); + kvm_irqchip_add_msi_route(kvm_state, vector_n, &vdev->pdev); + vfio_add_kvm_msi_virq + kvm_irqchip_add_irqfd_notifier_gsi + kvm_vm_ioctl(s, KVM_IRQFD, &irqfd); + /* Set interrupt type prior to possible interrupts */ + vdev->interrupt = VFIO_INT_MSI; + ret = vfio_enable_vectors(vdev, false); + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); +``` + +## 小结 + +要让设备直通给虚拟机,需要将设备的DMA能力、中断响应和IO地址空间访问安全地暴露给用户态,本文主要介绍了VFIO设备直通关键的几个环节,包括如何在用户态访问物理设备的IO地址空间、如何进行DMA重映射和中断重映射。 + +## Reference + +* https://kernelgo.org/vfio-insight.html diff --git a/web-ui/docs/zh/blog/xing_zhu/20200214_some_problems_about_IP.md b/web-ui/docs/zh/blog/xing_zhu/20200214_some_problems_about_IP.md new file mode 100644 index 0000000000000000000000000000000000000000..133adb692772da209d074cda7cd7d3458ff52111 --- /dev/null +++ b/web-ui/docs/zh/blog/xing_zhu/20200214_some_problems_about_IP.md @@ -0,0 +1,55 @@ +--- +title: 开源知识产权相关的几个问题 +date: 2020-02-14 +tags: +- copyright +- copyleft +- patent +- trademark +- license +archives: 2020-02 +author: Xing Zhu +summary: 本文简要讨论了跟开源相关的几个重要的知识产权的基本问题。 +--- + +# 开源知识产权相关的几个问题 + +## Copyright vs. Copyleft +* Copyright + * 软件版权属于知识产权的著作权范畴,具有知识产权的特征,即时间性,专有性和地域性。 + * 软件版权在法律上称为“计算机软件著作权”。属于著作权(知识产权)的一种。国家颁布有《计算机软件保护条例》,保护权益人的软件著作权。 + * 具体权力内容:包括对计算机软件的发表权、开发者身份权、复制权、展示权、发行权、修改权、翻译权、注释权、使用许可权、获得报酬权、转让权等,其保护期限是50年。 +* Copyleft + * Copyleft是一种在现有著作权体制下的授权方式,它要求使用者必须要以同等的授权方式回馈社群。 **Copyleft虽然与常见的著作权模式不同,但不是反对著作权的基本体制。** + * Copyleft是将一个程序成为自由软件的通用方法,同时也使得这个程序的修改和扩充版本成为自由软件。提出并使用Copyleft观念的是GNU计划,具体的发布条款包含在GNU通用公共许可证、GNU宽通用公共许可证和GNU自由文档许可证里。 + * Copyleft作品是有版权的;但它们加入了法律上的分发条款,保障任何人都拥有对该作品及其衍生品的使用、修改和重新发布的权力,前提是这些发布条款不能被改变。 + * Copyleft作品的使用者若不按Copyleft的许可证要求保持同样的授权条款,并将更改的版本回馈社群的话,就是**违反著作权法**的侵权行为。 + * Copyleft授权许可有时被认为具有“传染性”,因为任何从Copyleft许可衍生出的作品也必须是遵守Copyleft许可的规定。 + +## 开源软件许可证(License)与开源软件著作权的关系(Copyright)的关系 +* 开源软件起源于对软件著作权的对抗,但开源软件的延续和发展同样需要著作权法的保护,因为没有著作权法的存在,开源许可证授权也就无从谈起。 +* 开源软件以许可证的方式承认开发者的著作权,并且对后续的使用行为以许可证模式进行法律约束,即无论通过何种方式利用开源软件的方式均要以严格遵循条约的方式进行。 +* 开源许可协议是在软件开源时所依据的协议,其在用于贡献软件的贡献者和用于获取软件的获取者之间建立了一种合同。 +* 相较于传统计算机软件著作权,开源软件著作权的特殊性在于,开源软件的作者通过许可证的方式,将部分著作权( 修改权、复制权等财产性著作权) 无偿的授予给愿意接受许可证的人,但开源软件著作权人依然享有著作权法所赋予的其他权利( 如署名权等) 。大部分开源软件的许可证都规定,他人分发软件时应当尊重原作者的具有人身属性的著作权。比如,保留版权声明、不得擅自使用他人的姓名和商标; 在修改源代码软件时,必须注明修改之人、修改之处及修改时间,以避免源代码的混淆及对原作者的不尊重。 +* 从绝大多数开源软件许可证来看,均提出了对原作者署名权的保护,即衍生代码的作者也必须署名且要说明作者对哪一部分进行了修改,其结果是后续程序开发者通过继续修改时,即便出现问题也不至影响上游开发者的声誉。开源软件的精神是让每一位参加作者的署名权得到保护,同时也保证开源软件有继续向下延伸和传递的可能性。开源软件的开发者而言,这种人身意义“著作权”对他们而言有非常大的创新动力。 + + +## 开源软件的商标问题 +* 从法律角度来说,由于商标权是私权,除法律规定的极有限的合理使用外,使用商标的前提都必须获得明确授权。因此,对于没有明确规定商标问题的开源许可证,亦不能认为开源许可证给予使用开源软件的人任何商标权利,而没有获得授权的前提下的商业性使用别人合法的商标存在侵权风险。 +* 一旦涉及到开源软件相关商标合规问题,无论是贡献者商标、社区商标还是项目商标,均需要平衡**开源许可证中的相关商标规定**,**开源组织中的相关商标规定**,及**使用地的商标法律规定**,**使用地的在先商标注册情况**等,进行专业的商标综合分析。 + +## 开源软件的专利问题 +* 软件开源和专利权看似是处于对立的两端,但是其实是在不同的角度来发展和保护软件技术。专利法为开源软件的贡献者提供专有保护以促进其创新研发的积极性,开源软件通过共享源代码来促进软件技术的发展。 +* 在开源软件领域,专利侵权风险一直存在。更宽泛地,对于通过技术积累而不断壮大的各技术领域,专利侵权风险是普遍存在的。利用开源许可协议,可以避免一部分专利侵权风险。例如,在Apache-2.0许可证下,贡献者将其贡献的开源软件中的专利权许可给获取者,并且约束获取者不能就自己对该开源软件中的贡献向任何实体主张专利侵权。 +* 在软件技术的发展过程中,开源软件和软件专利不可避免地交织在一起。开源软件在抵制专利保护的同时,也在利用开源协议中的专利相关条款进行保护。借助于开源许可协议有效地融合了软件技术中的技术创新和技术共享,但是二者并不互斥。软件企业在参与软件开源的同时,仍然需要利用专利来保护自身的技术创新,维持核心竞争力。要结合企业的发展策略、专利布局等来选择合适的开源许可协议,从而借助于开源软件共享的当前研发成果和专利保护制度来维护企业的发展。 + 1. 对于研发技术涉及开源软件的单位或个人,要确定技术研发中不进入开源领域的软件代码,并加强对这部分软件的专利保护;对于技术研发中要进入开源领域的软件代码,则可以根据规划进行区分保护。 + 2. 对于开源协议的捐献者,在开源前慎重筛查专利申请,特别是好的技术构思要申请专利。 + 3. 对于开源协议的获取者,选择开源软件时,在定位到与企业的领域和研发方向匹配的开源协议的基础上,要慎重考虑开源软件所遵从的开源协议,分析开源软件中关于专利许可的相关条款,并特别关注许可终止的相关条款。 + +## Resource +- [开源软件及其法律风险](https://zhuanlan.zhihu.com/p/91071379) +- [应用开源软件的法律风险与理性应对](https://www.zhihedongfang.com/8919.html) +- [软件版权](https://baike.baidu.com/item/%E8%BD%AF%E4%BB%B6%E7%89%88%E6%9D%83) +- [开源软件中的商标问题](https://cloud.tencent.com/developer/article/1563078) +- [开源软件涉及的专利问题探讨](http://news.zhichanli.cn/article/8087.html) +- [开源软件:保护的智慧](https://www.lexology.com/library/detail.aspx?g=24c6f397-64c0-4a88-832b-8936a75b59d6) diff --git a/web-ui/docs/zh/blog/xinleguo/2020-11-02-securecontainer-1.png b/web-ui/docs/zh/blog/xinleguo/2020-11-02-securecontainer-1.png new file mode 100644 index 0000000000000000000000000000000000000000..dcd0f47e10c0f8ef2002603c1d501e114df0c82d Binary files /dev/null and b/web-ui/docs/zh/blog/xinleguo/2020-11-02-securecontainer-1.png differ diff --git "a/web-ui/docs/zh/blog/xinleguo/2020-11-02-\345\246\202\344\275\225\345\256\211\350\243\205\345\271\266\345\220\257\345\212\250StratoVirt.md" "b/web-ui/docs/zh/blog/xinleguo/2020-11-02-\345\246\202\344\275\225\345\256\211\350\243\205\345\271\266\345\220\257\345\212\250StratoVirt.md" new file mode 100644 index 0000000000000000000000000000000000000000..637807dab520a8976e6034a6a36809f99fb08a57 --- /dev/null +++ "b/web-ui/docs/zh/blog/xinleguo/2020-11-02-\345\246\202\344\275\225\345\256\211\350\243\205\345\271\266\345\220\257\345\212\250StratoVirt.md" @@ -0,0 +1,263 @@ +--- +title: 如何安装并启动StratoVirt +date: 2020-11-02 +tags: + - StratoVirt + - 虚拟化 +archives: 2020-11 +author: Xinle Guo +summary: 本文介绍了如何快速上手安装StratoVirt,并用StratoVirt运行虚拟机。提供StratoVirt对接iSulad并运行安全容器的使用指导。 +--- + +## 背景介绍 + +StratoVirt 作为虚拟化平台,实现了一套架构统一支持虚拟机,容器,Serverless三种场景。我们的 StratoVirt 同时具备了虚拟化的安全特性和容器的轻量级开销。是否想要实际上手操作一番呢?本文就来介绍如何使用 StratoVirt 运行一台虚拟机。另外,在容器场景下,小编也会带来对接 iSulad 容器引擎,运行一台安全容器的操作指导。 + +## 软硬件要求 + +### 最低硬件要求 + +- 处理器架构:仅支持 AArch64 和 x86_64 处理器架构。AArch64 需要 ARMv8 及更高版本且支持虚拟化扩展;x86_64支持 VT-x。 +- 2核 CPU +- 4GiB 内存 +- 16GiB 可用磁盘空间 + +### 软件要求 + +操作系统:openEuler 20.09 及更高版本 + +## 安装 StratoVirt + +这里提供了两种方式安装 StratoVirt。如果你只想要使用 StratoVirt 运行一台虚拟机,小编推荐组件安装的方式。你只需要按照软硬件要求,安装 [openEuler 20.09](https://www.openeuler.org/zh/docs/20.09/docs/Installation/installation.html) 及更高版本,并且配置好 openEuler yum 源。那么就可以直接使用 yum 命令安装啦。 + +如果你有很强的好奇心,希望深入了解我们的 StratoVirt。那太好了,编译安装的方式更适合你。作为开源项目,我们的 StratoVirt 源码放在[码云](https://gitee.com/openeuler/stratovirt)平台上。 你可以下载我们的源码,了解它的架构,甚至对其做一些代码修改。 + +### 组件安装 + +步骤1:用 yum 命令安装 + +``` +[root@openeuler ~]# yum install -y stratovirt +``` + +说明:安装前,确保已经配置好 openEuler yum 源。 + +### 编译安装 + +步骤1:环境准备,确保 Rust 语言环境和 Cargo 软件已经安装成功。 + +请参考链接的指导进行安装: + +步骤2:编译软件 + +``` +[root@openeuler ~]# git clone https://gitee.com/openeuler/stratovirt.git +[root@openeuler ~]# cd stratovirt +[root@openeuler ~]# cargo build --release +``` + +生成的二进制文件在 target/release/stratovirt 路径下。 + +## StratoVirt 运行虚拟机 + +步骤1:准备设备和工具 + +``` +[root@openeuler ~]# modprobe vhost_vsock +[root@openeuler ~]# yum install nmap +``` + +步骤2:制作PE格式的 kernel 镜像 + +``` +[root@openeuler ~]# yum install git; yum install gcc; yum install make; yum install bison; yum install flex +[root@openeuler ~]# cd /home; git clone https://gitee.com/openeuler/kernel +[root@openeuler ~]# cd kernel; git checkout kernel-4.19 +[root@openeuler ~]# cd /home; git clone https://gitee.com/openeuler/stratovirt.git +[root@openeuler ~]# cp stratovirt/docs/kernel_config/config_openeuler_4.19_aarch64 kernel/.config +[root@openeuler ~]# cd kernel; make –j vmlinux; objcopy -O binary vmlinux vmlinux.bin +``` + +生成的 /home/kernel/vmlinux.bin 就是制作好的 kernel 镜像。 + +说明:如果使用 x86_64 处理器架构,需要拷贝 stratovirt/docs/kernel_config/config_openeuler_4.19_x86_64 到 kernel 路径下并重命名为.config。 + +步骤3:制作EXT4格式的 rootfs 镜像 + +``` +[root@openeuler ~]# cd /home +[root@openeuler ~]# dd if=/dev/zero of=./rootfs bs=1G count=5 +[root@openeuler ~]# mkfs.ext4 ./rootfs +[root@openeuler ~]# mkdir /mnt/rootfs; mount /home/rootfs /mnt/rootfs +[root@openeuler ~]# cd /mnt/rootfs +[root@openeuler ~]# wget http://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/aarch64/alpine-minirootfs-3.12.0-aarch64.tar.gz +[root@openeuler ~]# tar -zxvf alpine-minirootfs-3.12.0-aarch64.tar.gz; rm alpine-minirootfs-3.12.0-aarch64.tar.gz +[root@openeuler ~]# rm sbin/init; touch sbin/init && cat > sbin/init < /home/stratovirt.sh <qemu_net_queue_send_iov->qemu_net_queue_flush- >qemu_net_queue_deliver。qemu 后端最终调用 tap_write_packet- >writev 写入 tap 字符设备。 + +接着在内核的字符设备驱动中,tun_chr_write_iter 会被调用,在 TCP/IP 协议栈进一步处理网络包。 + +### 创建设备 + +````c +virtio_net_class_init + virtio_net_device_realize + virtio_net_get_config + virtio_net_get_features + ... +```` + +virtio_net_device_realize 完成对 virtio-net 设备的初始化过程。 + +```c +virtio_net_device_realize + virtio_net_set_config_size + virtio_init + virtio_net_set_default_queue_size + virtio_net_add_queue + n->ctrl_vq = virtio_add_queue(virtio_net_handle_ctrl) + qemu_new_nic +``` + +这个函数创建了一个 VirtIODevice,virtio_init 用来初始化这个设备。接着调用 virtio_net_add_queue 初始化队列。当设置多队列特性,还要额外增加一个 ctrl_vq 队列,用作控制队列。最后,qemu_new_nic 会创建一个虚拟机里面的网卡。这里的网卡对应的是后端 tap 设备。 + +### 模拟网卡 + +tap 设备的使用:qemu 使用 tap 作为网络后端。首先需要在宿主机上创建 tap 设备,并添加到网桥 br0 上。 + +```shell +# brctl addbr br0 +# ip tuntap add dev tap0 mode tap +# brctl addif br0 tap0 +# ip link set dev tap0 up +``` + +在使用 qemu 命令启动虚拟机的过程中,传递参数:net,nic,model,netdev,ifname... + +其中 nic 表示前端虚拟机网卡,model 表示创建网卡类型,netdev 定义后端 tap 设备,ifname 表示 tap 设备的名字。 + +qemu 的 main 函数会调用 net_init_clients 进行网络设备的初始化 ,在该函数内对 netdev 参数进行解析。 + +```c +net_init_clients + qemu_opts_foreach(qemu_find_opts("netdev"),net_init_netdev, NULL, errp)) + net_init_netdev + net_client_init->net_client_init1 // 根据不同的driver类型,调用不同的初始化函数 + net_init_tap + net_tap_init + tap_open +``` + +tap_open 函数打开一个文件 "/dev/net/tun" ,然后通过 ioctl 操作这个文件。 + +```c +tap_open{ + fd = open(PATH_NET_TUN, O_RDWR) + ioctl(fd, TUNGETFEATURES, &features) + ioctl(fd, TUNSETVNETHDRSZ, &len) + ioctl(fd, TUNSETIFF, (void *) &ifr) +} +``` + +最终,通过宿主机内核复杂的网络协议栈,形成一个网络包,发送到外部网络中。这样做的原因是:虚拟机将网络包发送给 qemu,qemu 没有自己的网络协议栈,因此,qemu 将网络包转换成文件流,写入 "/dev/net/tun" 字符设备。内核TUN/TAP 字符设备驱动收到这个写入的文件流,然后交给 TUN/TAP 虚拟网卡驱动。驱动将文件流再次转成网络包,交给TCP/IP 协议栈,从 tap 设备发出标准的网络包。 + +## Virtio-Net 前端 + +虚拟机里面的进程发送一个网络包,通过文件系统和 Socket 调用网络协议栈,到达网络设备层。 这里将调用 virtio-net 驱动做进一步处理。 + +前端 driver 将报文发送出去,注册的 ops 函数定义如下,其中指定的发送函数为 start_xmit。 + +```c +kernel/drivers/net/virtio_net.c +static const struct net_device_ops virtnet_netdev = { + .ndo_open = virtnet_open, + .ndo_stop = virtnet_close, + .ndo_start_xmit = start_xmit, + ... +}; +``` + +调用 start_xmit 函数,将 skb 发送到 virtqueue 中, 然后调用 virtqueue_kick 通知 qemu 后端将数据包发送出去。 + +```c +start_xmit{ + free_old_xmit_skbs // 释放backend处理过的desc + xmit_skb // 发包 + sg_init_table + sg_set_buf(sq->sg, hdr, hdr_len); // 数据包头部填入scatterlist + num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); // 数据包填入scatterlist + virtqueue_add_outbuf // sg table 写入desc描述符表,head desc信息写vring.avail + virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq) // kick通知qemu后端 +} +``` + +当虚拟机写入一个 I/O 会使得 qemu 触发 VM exit 。接下来进入 qemu 做 virtio-net 相关处理。 + +## 流程总结 + +1. 在虚拟机里面的用户态,应用程序通过 write 系统调用写入 socket。 +2. 写入的内容经过 VFS 层,内核协议栈,到达虚拟机里面的内核的网络设备驱动,即 virtio_net。 +3. virtio_net 网络设备有一个操作结构 struct net_device_ops,里面定义了发送一个网络包调用的函数为 start_xmit。 +4. 在 virtio_net 的前端驱动和 qemu 中的后端驱动之间,有两个队列 virtqueue,一个用于发送,一个用于接收。然后,我们需要在 start_xmit 中调用 virtqueue_add,将网络包放入发送队列,然后调用 virtqueue_notify 通知 qemu。 +5. qemu 本来处于 KVM_RUN 的状态,收到通知后,通过 VM exit 指令退出客户机模式,进入宿主机模式。发送网络包的时候,virtio_net_handle_tx_bh 函数会被调用。 +6. 接下来是一个 for 循环,我们需要在循环中调用 virtqueue_pop,从传输队列中获取要发送的数据,然后调用 qemu_sendv_packet_async 进行发送。 +7. qemu 会调用 writev 向字符设备文件写入,进入宿主机的内核。 +8. 在宿主机内核中字符设备文件的 file_operations 里面的 write_iter 会被调用,也即会调用 tun_chr_write_iter。 +9. 在 tun_chr_write_iter 函数中,tun_get_user 将要发送的网络包从 qemu 拷贝到宿主机内核里面来,然后调用 netif_rx_ni 开始调用宿主机内核协议栈进行处理。 +10. 宿主机内核协议栈处理完毕之后,会发送给 tap 虚拟网卡,完成从虚拟机里面到宿主机的整个发送过程。 \ No newline at end of file diff --git a/web-ui/docs/zh/blog/xinleguo/2020-11-23-virtionet.png b/web-ui/docs/zh/blog/xinleguo/2020-11-23-virtionet.png new file mode 100644 index 0000000000000000000000000000000000000000..a80d915a18c5b92bd7036a5866e741b28e94d138 Binary files /dev/null and b/web-ui/docs/zh/blog/xinleguo/2020-11-23-virtionet.png differ diff --git a/web-ui/docs/zh/blog/xiyuanwang/2020-04-14-Web-ARM64-Support.md b/web-ui/docs/zh/blog/xiyuanwang/2020-04-14-Web-ARM64-Support.md new file mode 100644 index 0000000000000000000000000000000000000000..7f163c47cf038fe411cbf8c92ce4730a0b0985cf --- /dev/null +++ b/web-ui/docs/zh/blog/xiyuanwang/2020-04-14-Web-ARM64-Support.md @@ -0,0 +1,120 @@ +--- +title: Web开源服务之ARM64现状 +date: 2020-04-14 +tags: + - web + - arm64 +archives: 2020-04 +author: Xiyuan Wang +summary: 本文介绍华为在Web主流开源服务中推动ARM64支持的情况。 +--- + +社区核心参与者:[Martin Grigorov](https://github.com/martin-g)、[Michael Rumph](https://www.linkedin.com/in/mikerumph/)、[王玺源](https://github.com/wangxiyuan) + +# 背景 + +开源界中Web服务众多,但其中很多软件对ARM64的支持并不理想。或是没有官方CI测试保证代码质量,或是在ARM64上的性能明显差于X86_64,甚至有的服务根本无法在ARM上运行。为了完善Web领域的ARM64生态,我们参与了主流的几个开源社区,旨在推动Web on ARM64。以下是我们近期的一些进展,以供大家参考。 + + +# 概述 + +我们目前参与了主流的共9个Web相关项目。如下所示 + +| 项目 | 主要语言 | +| --- | --- | +| Apache Httpd Server | C | +| Apache Tomcat | Java | +| Memcached | C | +| Nginx | C | +| Lighttpd | C | +| JBoss/WildFly | Java | +| HAProxy | C | +| Squid | C++ | C | +| Varnish Cache | C | + +针对这些项目,我们按照以下三个方面循序渐进的推动中: + +1. 能不能在ARM上运行 +2. 如何稳定在ARM上运行 +3. 怎么更好的在ARM上运行 + +# 能不能在ARM上运行 + +我们可以看到这9大项目主要由Java和C/C++编写。 + +首先,像Python、Java这种自带runtime的语言天生就是跨平台的。这样的项目在ARM64平台上至少可以保证程序的可运行。 + +而C/C++项目则需要先编译成ARM64平台的目标可执行文件。这样的项目则需要先进行编译测试。 + +经过我们的测试,这9个Web项目都可以在ARM64上成功编译并运行。 + +# 如何稳定在ARM上运行 + +所谓稳定,包含两个方面: + +1. 软件在ARM64上是否和在X86_64上行为一致? +2. 随着代码更新迭代,软件在ARM64上是否持续可用? + +## 行为一致 + +我们常遇到两类行为一致的问题: + +1. 同样的代码,不同的结果 +2. 同样的功能,不同的支持 + +很遗憾,由于架构不同、底层实现不同等原因,很多软件的某些行为在X86_64和ARM64上的行为并不一致。 + +例如,之前的[文章](https://kunpengcompute.github.io/2020/04/08/arm-you-hua-he-java-math-ku-you-guan-de-na-xie-keng/)提到的Java中Math计算结果的差异。 + +又或者某些功能依赖独有的平台特性或者特殊的第三方库,导致在X86_64上可以运行的功能,在ARM64上却执行失败。 + +例如我们发现WildFly官方发布的源码包中缺少了个别ARM64平台的`.so`文件,这就导致个别调用`.so`的功能不可用。 + +针对这种问题,我们需要打开代码逐个分析、逐个修复。保证所有测试在ARM64上全部通过。 + +## 持续可用 + +CI/CD是保证软件持续可用的重要方法。主流软件的CI系统都有X86_64平台的测试。而ARM64平台的少之又少。 + +针对这个问题,我们推动了这9个项目的ARM CI支持。除Lighttpd还在推动中以外,其他8个项目目前都已支持了ARM CI。甚至其中4个项目已经官方声明了ARM64的支持(详见附录)。 + +其中Httpd、Tomcat、Memcached、HAProxy和Varnish Cache通过Travis CI支持了ARM64测试。Nginx使用内部CI,对外不可见。Squid使用自己的树莓派。而JBOSS使用了我们捐献的基于Kunpeng 920的ARM虚拟机。同时我们也计划捐献同样的测试机到Lighttpd社区中。 + +随着ARM CI的落地,我们将持续保证ARM CI的稳定。我们相信在不久的将来,这9大核心Web项目都会官方声明ARM64的支持,并满足用户在ARM64上稳定、高效使用Web服务的需求。 + +# 怎么更好的在ARM上运行 + +我们不仅希望软件在ARM64上能用,还在不断探索如何让软件在ARM64上用的好。其中**性能优化**是重中之重,也是我们未来一段时间的主要投入点。 + +例如,有些软件只实现了X86_64的汇编实现,但缺少ARM64的汇编代码。 + +又或者有些在X86_64上纯软实现的功能,可以在ARM64上通过下沉至硬编码的方式提高性能。 + +甚至还可以考虑如何最大化利用ARM64的多核优势,或规避ARM64的锁劣势等等。 + +关于性能优化的内容,我们将在以后的文章中针对不同的软件一一细说。敬请期待。 + +# 操作系统支持 + +一般情况下,开源软件很少自己分发不同操作系统的安装包。以我们参与的9个Web服务为例,只有Nginx提供了Ubuntu的安装包,Varnish Cache只提供了编译好的可执行文件,而其他7个服务仅仅提供了源码。 + +针对Nginx这种官方提供安装包的项目,我们希望它能提供更多操作系统的安装包,在我们的推动下,Nginx社区已表示下一步会推出CentOS和Alpine的安装包。OpenEuler也在我们的规划中。敬请期待。 + +大多数只提供源码或可执行文件的服务,针对这种情况,各个操作系统需要自行打包、分发。以OpenEuler为例,可以看到在官方[Repo](https://repo.openeuler.org)中已经支持了部分Web服务aarch64安装包。丰富的安装包支持也是操作系统易用性的重要体现。我们相信随着ARM64软件生态的不断丰富,OpenEuler的仓库也会不断充实。 + + +# 附录 + +最后附上我们参与Web社区的总览表格及相关链接,感兴趣的同学可以进一步详读,有任何问题,欢迎留言。 + +| | Official arm64 CI | CI tool | Package in Downloads | Official ARM support | +| ---- | ---- | ---- | ---- | ---- | +| [Apache Tomcat](https://tomcat.apache.org/) | [YES](https://github.com/apache/tomcat/commit/f386fbb4abaa3fe8f3b3df1da7d14f756c729e2e) | [TravisCI](https://github.com/apache/tomcat/blob/master/.travis.yml) | [Binary](https://tomcat.apache.org/download-90.cgi) | WIP(work in progress) | +| [Memcached](https://memcached.org/) | [YES](https://github.com/memcached/memcached/pull/593) | 1. [BuildBot](http://build.memcached.org:8010/) 2. [TravisCI](https://github.com/memcached/memcached/blob/master/.travis.yml) | [Source Code](https://memcached.org/downloads) | [YES](https://github.com/memcached/memcached/wiki/Hardware) | +| [Apache httpd](https://httpd.apache.org/) | [YES](https://markmail.org/message/ajm3eouaqfhm22ox) | [TravisCI](https://github.com/apache/httpd/blob/trunk/.travis.yml) | [Source Code](http://httpd.apache.org/download.cgi) | [YES](https://github.com/apache/httpd/blob/2.4.x/CHANGES#L17-L20) | +| [NGINX](https://nginx.org/) | [YES](https://mailman.nginx.org/pipermail/nginx-devel/2020-January/012943.html) | Internal | Only for [Ubuntu](https://nginx.org/en/linux_packages.html) LTSs | [YES](https://nginx.org/en/linux_packages.html#Ubuntu) | +| [Lighttpd](https://www.lighttpd.net/) | NO | [Jenkins](https://ci.lighttpd.net/view/lighttpd1.4/job/lighttpd1.4/) | [Source Code](https://www.lighttpd.net/download/) | NO | +| [JBoss/Wildfly](https://www.wildfly.org/) | [YES](https://ci.wildfly.org/viewType.html?buildTypeId=WF_MasterLinuxArm64OpenJ911) | [TeamCity](https://ci.wildfly.org/) | [Source Code](https://wildfly.org/downloads/) | NO | +| [HAProxy](https://www.haproxy.org/) | [YES](https://github.com/haproxy/haproxy/commit/9bf2a1be89a6eaddb00f07b9d069a9a16c24c037) | 1. [CirrusCI](https://cirrus-ci.com/github/haproxy/haproxy)
2. [TravisCI](https://github.com/haproxy/haproxy/blob/master/.travis.yml) | [Source Code](http://www.haproxy.org/) | [YES](https://www.haproxy.org/#plat) | +| [Squid](http://www.squid-cache.org/) | [YES](http://build.squid-cache.org/computer/arm64-rpi/) | [Jenkins](http://build.squid-cache.org/) | [Source Code](http://squid-cache.org/Versions/) | NO | +| [Varnish Cache](https://github.com/varnishcache/varnish-cache/) | [YES](https://github.com/varnishcache/varnish-cache/pull/3195) | [Travis](https://github.com/varnishcache/varnish-cache/blob/master/.travis.yml) | 1. [Source Code](https://varnish-cache.org/releases/index.html)
2. [Package](https://packagecloud.io/varnishcache) | NO | diff --git a/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv-01.jpg b/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1469ce8927b0eff3e9281700d165598834d90a60 Binary files /dev/null and b/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv-01.jpg differ diff --git a/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv.md b/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv.md new file mode 100644 index 0000000000000000000000000000000000000000..f207487f5cda3d384d810999f4bf44ea6ed99b2c --- /dev/null +++ b/web-ui/docs/zh/blog/yang_yanchao/2021-3-12-start-a-containerd-on-riscv.md @@ -0,0 +1,210 @@ +--- +title: 手把手教你搭建基于 RISC-V 的 openEuler 系统,部署 runc并运行容器 +date: 2021-03-11 +tags: + - RISC-V + - 容器 + - runc +archives: 2021-03 +author: yang_yanchao +summary: Teach you to build an openEuler system based on RISC-V, deploy runc, and run containers. +--- + +# 手把手教你搭建基于 RISC-V 的 openEuler 系统,部署 runc并运行容器 + +RISC-V 是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。openEuler 在 RISC-V 上进行了一些探索: + +[^]: 以下相关信息来自于 https://gitee.com/openeuler/RISC-V + +- 2020年 6 月,openEuler 发布了第一版支持 RISC-V 的文件系统 rootfs 和 kernel 镜像。 +- 2020年 8 月,在 OBS 构建系统开始构建 openEuler RISC-V 软件包。 +- 2020年 9 月,在华为全联接(HC)2020 大会上发布了 openEuler RISC-V,国内首发 RISC-V 版 Linux。 +- 2020年 10 月,中科院成功移植 openEuler RISC-V 到果壳(nutshell)。 +- 2020年 11 月,在 openEuler 镜像仓发布第二版 rootfs 和 kernel 镜像,可以在 qemu 中启动镜像,体验 openEuler RISC-V 移植版。 + +![openEuler summit 上展示的运行在果壳芯片上的openEuler RISC-V ](./2021-3-12-start-a-containerd-on-riscv-01.jpg) + +**openEuler Summit 上展示的运行在果壳芯片上的 openEuler RISC-V ** + +在容器技术炙手可热的今天,各个技术公司都积极拥抱容器。如何使用 QEMU 模拟器启动 openEuler RISC-V 移植版,并在其中运行容器呢?本文将带你一探究竟。 + +### 环境要求 + +- 运行环境:Linux +- 所需文件:openEuler RISC-V 系统镜像,请参见 "获取 openEuler RISC-V 移植版系统镜像" +- 软件环境:QEMU >= 4.0.0 <=5.0.1,请参见 "获取 openEuler RISC-V 移植版系统镜像" + +#### 获取 openEuler RISC-V 移植版系统镜像 + +在 openEuler 官网可以获得 openEuler RISC-V 移植版发布的最新版本的 openEuler RISC-V 镜像以及 repo 源,名称为 **openEuler Preview** +```https +https://repo.openeuler.org/openEuler-preview/RISC-V/Image/ +``` +其中的两个文件是启动 openEuler RISC-V 移植版所必需的: +- **fw_payload_oe_docker.elf** 利用 openSBI 将 kernel-5.5 的 image 作为 payload 所制作的用于 QEMU 启动的 image,同时它也增加了 Docker 相关的启动配置。 +- **openEuler-preview.riscv64.qcow2** openEuler RISC-V移植版的rootfs镜像。 + +#### 通过 QEMU 启动一个 openEuler RISC-V +首先你需要在你的 Host Linux 环境中有 qemu-system-riscv64 的二进制程序,如果你的 Linux 环境的 repo源中没有提供这个二进制,那么则需要手动从 QEMU 的源码构建出来,具体的构建方式如 QEMU 的官方指导所述: + +[Build QEMU for Platforms/RISCV](https://wiki.qemu.org/Documentation/Platforms/RISCV) + +可以参考以下命令: + +``` +git clone https://gitee.com/openeuler/qemu.git +cd qemu +./configure --target-list=riscv64-softmmu && make +cp riscv64-softmmu/qemu-system-riscv64 /bin +``` +QEMU 的启动方式,这里以主机端口转发的方式实现网络功能 +``` +$ qemu-system-riscv64 \ + -nographic -machine virt \ + -smp 8 -m 2G \ + -kernel fw_payload_oe_docker.elf \ + -drive file=openEuler-preview.riscv64.qcow2,format=qcow2,id=hd0 \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-device,rng=rng0 \ + -device virtio-blk-device,drive=hd0 \ + -device virtio-net-device,netdev=usernet \ + -netdev user,id=usernet,hostfwd=tcp::12055-:22 \ + -append 'root=/dev/vda1 rw console=ttyS0 systemd.default_timeout_start_sec=600 selinux=0 highres=off mem=4096M earlycon' +``` +当系统启动之后,可以通过 ssh 登录 Guest OS,并且在模拟器中应当是可以访问互联网的。系统默认的登录用户名/密码是:root/openEuler12#$ +```shell + ssh -p 12055 root@localhost +``` + + +### 部署 runc 并运行容器 + +说明:接下来的操作均在所启动的 openEuler RISC-V 的模拟器运行的 Guest OS 中。 + +#### 安装 runc 软件包 + +openEuler RISC-V repo 源中包含了 runc 软件包,配置 repo 并安装 runc 的参考命令如下: + +```shell +# yum-config-manager --add-repo https://repo.openeuler.org/openEuler-preview/RISC-V/everything/ +# yum install docker-runc +``` + +#### 准备容器镜像 + +1. 准备工作目录 + + 在正式部署之前,先来准备一个工作目录,比如 mycontainer,本文后续的所有操作都在这个目录下执行。 + + ```shell + mkdir mycontainer + cd mycontainer + ``` + +2. 准备容器启动镜像 + + 使用自己制作的 rootfs 作为容器启动镜像。假设自制的文件系统中需要 gcc(根据用户自己实际情况确定安装的软件),则参考命令如下: + + ```shell + mkdir rootfs + yum install gcc --installroot=`pwd`/rootfs + ``` + +#### 使用 runc 运行容器 + +有了 rootfs 之后,我们需要按照 OCI 标准,有一个配置文件`config.json` 说明如何运行容器,包括要运行的命令、权限、环境变量等内容,runc 提供了一个命令可以自动帮我们生成该配置文件: + +```bash +[root@openEuler-RISCV-rare mycontainer]# runc spec +[root@openEuler-RISCV-rare mycontainer]# ls +config.json rootfs +``` + +这样就构成了一个 [OCI runtime bundle](https://github.com/opencontainers/runtime-spec/blob/master/bundle.md) 的内容,这个 bundle 非常简单,就上面两个内容:config.json 文件和 rootfs 文件系统。`config.json` 里面的内容很长,这里就不贴出来了,我们暂时也不会对其进行修改,直接使用这个默认生成的文件。有了这些信息,runc 就能知道怎么运行容器了,我们先来看看简单的方法 `runc run`(这个命令需要 root 权限),它会创建并启动一个容器: + +```bash +[root@openEuler-RISCV-rare mycontainer]# runc run openEuler_container +sh-5.0# ls +bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var +sh-5.0# whoami +root +sh-5.0# pwd +/ +sh-5.0# echo hello container +hello container +``` + +最后一个参数是容器的名字,需要在主机上保证唯一性。运行之后直接进入到了容器的 `sh` 交互界面,但是这个容器并没有配置网络方面的内容,只是有一个默认的 `lo` 接口,因此无法和外部通信,但其他功能都正常。 + +此时,另开一个终端,可以查看运行的容器信息: + +```bash +[root@openEuler-RISCV-rare ~]# runc list +ID PID STATUS BUNDLE CREATED OWNER +openEuler_container 17318 running /home/mycontainer 2019-09-03T15:27:25.5978852Z root + +``` + +启动容器的第二种方式是使用specs生命周期操作,可以更好地创建和管理容器。但是这样会使容器在后台启动,所以需要对 `config.json` 进行修改。改动有两处,把 `terminal` 的值改成 `false`,修改 `args` 命令行参数为 `sleep 20`。`args `的命令只是一个样例,使用中可以根据实际需求进行修改: + +```json +"process": { + "terminal": false, + "consoleSize": { + "height": 0, + "width": 0 + }, + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sleep", "20" + ], + ··· +} +``` + +接着用 runc 命令来控制容器的运行,实现各个容器状态的转换 + +1. 使用 `create` 创建容器。此时容器没有运行,只是准备好了所有运行环境,使用 `list` 查看,此时容器状态为 `created`。 + + 假设容器名为 openEuler,参考命令如下: + +```bash +[root@openEuler-RISCV-rare mycontainer]# runc create openEuler +[root@openEuler-RISCV-rare mycontainer]# runc list +ID PID STATUS BUNDLE CREATED OWNER +openEuler 17402 created /home/mycontainer 2019-09-03T15:37:46.6289281Z root +``` + +2. 运行容器,会执行启动命令 `sleep 20`。使用 `list` 查看,此时容器状态为`running`。 + +```shell +[root@openEuler-RISCV-rare mycontainer]# runc start openEuler +[root@openEuler-RISCV-rare mycontainer]# runc list +ID PID STATUS BUNDLE CREATED OWNER +openEuler 17402 running /home/mycontainer 2019-09-03T15:37:46.6289281Z root +``` +3. 容器运行 20 秒之后,容器关闭,状态为`stop`。 + +```shell +[root@openEuler-RISCV-rare mycontainer]# runc list +ID PID STATUS BUNDLE CREATED OWNER +openEuler 0 stopped /home/mycontainer 2019-09-03T15:37:46.6289281Z root +``` + +4. 删除容器,容器的信息就不在了。 + +```shell +[root@openEuler-RISCV-rare mycontainer]# runc delete openEuler +[root@openEuler-RISCV-rare mycontainer]# runc list +ID PID STATUS BUNDLE CREATED OWNER +``` + +今天的介绍就到这里,更多关于 runc 使用的介绍可以用 `runc -h` 查看。后续 openEuler RISC-V 的 Docker 也会使能哦! +更多关于 openEuler RISC-V 的内容请关注 + +```https +https://gitee.com/openeuler/RISC-V +``` diff --git a/web-ui/docs/zh/blog/yorifang/2020-10-24-arm-virtualization-overview.md b/web-ui/docs/zh/blog/yorifang/2020-10-24-arm-virtualization-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..98c11e8ad090fadde6e4ec3d0a9dfa3b1d16546c --- /dev/null +++ b/web-ui/docs/zh/blog/yorifang/2020-10-24-arm-virtualization-overview.md @@ -0,0 +1,376 @@ +--- +title: ARMv8虚拟化系统概述 +date: 2020-10-24 +tags: + - Virtualization + - ARMv8 +archives: 2020-10 +author: Ying Fang +summary: ARMv8虚拟化系统概述 +--- + +### 摘要: + +ARM处理器在移动领域已经大放异彩占据了绝对优势,但在服务器领域ARM仍处于发展上升阶段。 +为了能够和X86在服务器领域展开竞争,ARM也逐渐对虚拟化扩展有了较为完善的支持。 +本文的目的是介绍一下ARMv8处理器的虚拟化扩展中的一些相关知识点, +将主要从ARM体系结构、内存虚拟化、中断虚拟化、I/O虚拟化等几个方面做一些概括总结。 +本文将尽可能的在特性层面将ARM和X86做一些对比,以加深我们对于ARM Virtualizaiton Extension的印象。 + +### 0. ARMv8 System Architecture + +在进入正题之前先回顾一下ARMv8体系结构的一些基本概念。 + +ARMv8支持两种执行状态:AArch64和AArch32。 + +AArch64 64-bit执行状态: + +* 提供31个64bit的通用处理器,其中X30是Procedure link register +* 提供一个64bit的程序寄存器PC,堆栈指针(SPs)和Exception link registers(ELRs) +* 提供了32个128bit的寄存器以支持SIMD矢量和标量浮点运算 +* 定义了4个Exception Level (EL0-EL3) +* 支持64bit虚拟机地址(virtual address) +* 定义了一些PSTATE eletems来存储PE的状态 +* 过后ELn后缀来表示不同Exception Level下可以操作的系统寄存器 + +AArch32 32-bit执行状态: + +* 提供了13个32bit通用寄存器,1个32bit的PC,SP和Link Register(LR) +* 为Hyper Mode下的异常返回值提供给了一个单一的ELR +* 提供32个64bit的寄存器来支持SIMD矢量和标量浮点运算支持 +* 提供了2个指令集,A32和T32, +* 支持ARMv7-A Exception Mode,基于PE modes并且可以对应到ARMv8的Exception model中 +* 使用32bit的虚拟地址 +* 使用一个单一的CPSR来保存PE的状态 + +ARM 内存模型: + +* 非对齐的内存访问将产生一个异常 +* 限制应用程序访问指定的内存区域 +* 程序执行中的虚拟地址将被翻译成物理地址 +* 内存访问顺序受控 +* 控制cache和地址翻译的结构 +* 多个PE之间共享内存的访问同步 + +ARM 内存管理([参考ARM Address Translation](https://static.docs.arm.com/100940/0100/armv8_a_address%20translation_100940_0100_en.pdf)): + +* ARMv8-A架构支持的最大物理内存地址宽度是48bit,支持4KB、16KB、或者64KB的页面大小 +* 使用虚拟内存管理机制,VA的最高有效位(MSB)为0时MMU使用TTBR0的转换表来翻译,VA的最高有效位为1时MMU使用TTBR1的转换表来翻译 +* EL2和EL3有TTBR0,但是没有TTBR1,这意味着EL2和EL3下只能使用0x0~0x0000FFFF_FFFFFFFF范围的虚拟地址空间 + +``` +------------------------------------------------------------------------- +AArch64 Linux memory layout with 4KB pages + 4 levels:: + Start End Size Use + 0000000000000000 0000ffffffffffff 256TB user + ffff000000000000 ffffffffffffffff 256TB kernel +------------------------------------------------------------------------- +``` + +![ARM Address Translation](./arm_address_translation.png) + +OK,假装我们现在的ARMv8-A已经有了一个初步的了解,下面再从几个大的维度去看下ARMv8对虚拟化是怎么支持的。 + +### 1. ARMv8 Virtualization Extension Overview + +ARM为了支持虚拟化扩展在CPU的运行级别上引入了Exception Level(异常级别)的概念,AArch64对应的Exception Level视图如下图: + +![ARM Exception Level](./aarch64_exception_levels_2.svg) + +* EL0:用户态程序的运行级别,Guest内部的App也运行在这个级别 +* EL1:内核的运行级别,Guest的内核也运行在这个级别 +* EL2:Hypervisor的运行级别,Guest在运行的过程中会触发特权指令后陷入到EL2级别,将控制权交给Hypervisor +* EL3:Monitor Mode,CPU在Secure World和 Normal World直接切换的时候会先进入EL3,然后发生World切换 + +注:当CPU的Virtualization Extension被disable的时候,软件就运行在EL0和EL1上,这时候EL1有权限访问所有的硬件。 + +ARM的异常级别可以分为同步(synchronous)和异步(asynchronous)两类: + +* 同步异常:未定义异常,未对齐异常,陷阱执行异常,系统调用异常。例如:SVC、HVC、SMC等。 + SVC被Application用于申请OS的特权操作或者访问系统资源,HVC被用来申请hypervisor服务;SMC则用于申请firmware服务。 +* 异步异常:中断 + +与ARMv8不同的是,在X86为支持CPU虚拟化引入了Root Mode和None-Root Mode的概念和一套特殊的VMX指令集, +其中非根模式是Guest CPU的执行环境,根模式是Host CPU的执行环境。 +根模式、非根模式与CPU的特权级别是两个完全独立的概念,二者完全正交, +也就是说非根模式下支持和根模式下一样的用户态(Ring 3)、内核态(Ring 0)特权级。 +而这和ARM是不同的,ARM CPU是依靠在不同的EL之间切换来支持虚拟化模式切换。 +但二者都有一个相同点:那就是ARM和X86在虚拟化模式下如果执行了敏感指令会分别退出到EL2和Root Mode之间。 +同时,X86上为了更好地支持Root/Non-root Mode在内存中实现了一个叫做VMCS的数据结构, +用来保存和恢复Root/None-root模式切换过程中的寄存器信息,VMX指令集则专门用来操作VMCS数据结构。 +但在RISC-style的ARM处理器上,则没有类似的实现,而是让Hypervisor软件自己来决定哪些信息需要保存和恢复, +这在一定程度上带来了一些灵活性[[Ref1](http://www.cs.columbia.edu/~cdall/pubs/isca2016-dall.pdf)]。 + +为了优化多个异常级别带来的虚拟化上下文切换开销,ARMv8中引入了虚拟化主机扩展特性(virtual Host Extension, VHE) +[Ref2](https://developer.arm.com/architectures/learn-the-architecture/aarch64-virtualization/virtualization-host-extensions)。 +其实现原理是直接将宿主机内核运行在EL2上。为了实现EL2引入HCR_EL2寄存器,用来控制这一特性。 +VHE带来的好处是减少了2次异常级别的切换,只需要保存和恢复部分Host的上下文, +减少了虚拟化的开销,带来了性能的提升。 + + +### 2. Memory Virtualization + +在ARMv8-A上,每个tarnslation regime可能包括1个stage,也可能包括2个sate。 +每个Exception Level都有自己的地址翻译机制,使用不同的页表基地址寄存器,地址翻译可以细分到stage, +大部分的EL包括一个stage的地址翻译过程, Non-Secure EL1&0包括了2个stage的地址翻译过程。 +每个stage都有自己独立的一系列Translation tables,每个stage都能独立的enable或者disable。 +每个stage都是将输入地址(IA)翻译成输出地址(OA)[[Ref3](http://www.wowotech.net/memory_management/arm64-memory-addressing.html)]。 + +所以在虚拟化场景下,ARM和X86上的方案是类似的,都是采用两阶段地址翻译实现GPA -> HPA的地址翻译过程。 +虚拟机运行在None-secure EL1&0,当虚拟机内的进程访问GVA的时候MMU会将GVA翻译成IPA(intermediate physical address,中间物理地址:GPA), +这就是所谓的stage 1地址翻译。然后MMU会再次将IPA翻译成HPA,这就是所谓的stage 2地址翻译。 + +![Two State Translation](./arm_mmu_trans.png) + +在不同的Eexception Level下有不同的Address Space,那么如何去控制不同地址空间的翻译呢? + +ARMv8-A上有一个TCR(Translation Control Register)寄存器来控制地址翻译。 +例如:对于EL1&0来说,由于在该运行模式下VA存在2个独立的映射空间(User Space和Kernel Space), +所以需要两套页表来完成地址翻译,这2个页表的及地址分别放在TTBR0_EL1和TTBR1_EL1中。 + +对于每一个地址翻译阶段: + +* 有一个system control register bit来使能该阶段的地址翻译 +* 有一个system control register bit来决定翻译的时候使用的大小端策略 +* 有一个TCR寄存器来控制整个阶段的地址翻译过程 +* 如果某个地址翻译阶段支持将VA映射到两个subranges,那么该阶段的地址翻译需要为每个VA subrange提供不同的TTBR寄存器 + +内存虚拟化也没有太多可以说道,理解了原理之后就可以去梳理KVM相关代码,相关代码实现主要在arch/arm/mm/mmu.c里面。 + +### 3. I/O Virtualization + +设备直通的目的是能够让虚拟机直接访问到物理设备,从而提升IO性能。 +在X86上使用VT-d技术就能够实现设备直通,这一切都得益于VFIO驱动和Intel IOMMU的加持。 +那么在ARMv8-A上为了支持设备直通,又有哪些不同和改进呢? + +同X86上一样,ARM上的设备直通关键也是要解决DMA重映射和直通设备中断投递的问题。 +但和X86上不一样的是,ARMv8-A上使用的是SMMU v3.1来处理设备的DMA重映射, +中断则是使用GICv3中断控制器来完成的,SMMUv3和GICv3在设计的时候考虑了更多跟虚拟化相关的实现, +针对虚拟化场景有一定的改进和优化。 + +先看下SMMUv3.1的在ARMv8-A中的使用情况以及它为ARM设备直通上做了哪些改进[[Ref4](https://static.docs.arm.com/ihi0070/b/SMMUv3_architecture_specification_IHI0070B.pdf)]。 +SMMUv3规定必须实现的特性有: + +* SMMU支持2阶段地址翻译,这和内存虚拟化场景下MMU支持2阶段地址翻译类似, +第一阶段的地址翻译被用做进程(software entity)之间的隔离或者OS内的DMA隔离, +第二阶段的地址翻译被用来做DMA重映射,即将Guest发起的DMA映射到Guest的地址空间内。 +* 支持16bit的ASIDs +* 支持16bit的VMIDs +* 支持SMMU页表共享,允许软件选择一个已经创建好的共享SMMU页表或者创建一个私有的SMMU页表 +* 支持49bit虚拟地址 (matching ARMv8-A’s 2×48-bit translation table input sizes),SMMUv3.1支持52bit VA,IPA,PA + +SMMUv3支持的可选特性有: + +* Stage1和Stage2同时支持AArch32(LPAE: Large Page Address Extension)和AArch64地址翻译表格式(兼容性考虑) +* 支持Secure Stream (安全的DMA流传输) +* 支持SMMU TLB Invalidation广播 +* 支持HTTU(Hardware Translation Table Update)硬件自动刷新页表的Access/Dirty标志位 +* 支持PCIE ATS和PRI(PRI特性非常厉害,后面单独介绍) +* 支持16K或者64K页表粒度 + +我们知道,一个平台上可以有多个SMMU设备,每个SMMU设备下面可能连接着多个Endpoint, +多个设备互相之间可能不会复用同一个页表,需要加以区分,SMMU用StreamID来做这个区分, +通过StreamID去索引Stream Table中的STE(Stream Table Entry)。 +同样x86上也有类似的区分机制,不同的是x86是使用Request ID来区分的,Request ID默认是PCI设备分配到的BDF号。 +不过看SMMUv3 Spec,又有说明:对于PCI设备StreamID就是PCI设备的RequestID, +好吧,两个名词其实表示同一个东西,只是一个是从SMMU的角度去看就成为StreamID,从PCIe的角度去看就称之为RequestID。 +同时,一个设备可能被多个进程使用,多个进程有多个页表,设备需要对其进行区分,SMMU使用SubstreamID来对其进行表示。 +SubstreamID的概念和PCIe PASID是等效的,这只不过又是在ARM上的另外一种称呼而已。 +SubstreamID最大支持20bit和PCIe PASID的最大宽度是一致的。 + +STE里面都有啥呢?Spec里面有说明: + +* STE里面包含一个指向stage2地址翻译表的指针,并且同时还包含一个指向CD(Context Descriptor)的指针 +* CD是一个特定格式的数据结构,包含了指向stage1地址翻译表的基地址指针 + +理论上,多个设备可以关联到一个虚拟机上,所以多个STE可以共享一个stage2的翻译表。 +类似的,多个设备(stream)可以共享一个stage1的配置,因此多个STE可以共享同一个CD。 + +Stream Table是存在内存中的一张表,在SMMU设备初始化的时候由驱动程序创建好。 +Stream Table支持2种格式,Linear Stream Table 和 2-level Stream Table, +Linear Stream Table就是将整个Stream Table在内存中线性展开为一个数组,优点是索引方便快捷,缺点是当平台上外设较少的时候浪费连续的内存空间。 +2-level Stream Table则是将Stream Table拆成2级去索引,优点是更加节省内存。 + +![2-level Stream Table](./arm_strtab.png) + +在使能SMMU两阶段地址翻译的情况下,stage1负责将设备DMA请求发出的VA翻译为IPA并作为stage2的输入, +stage2则利用stage1输出的IPA再次进行翻译得到PA,从而DMA请求正确地访问到Guest的要操作的地址空间上。 + +在stage1地址翻译阶段:硬件先通过StreamID索引到STE,然后用SubstreamID索引到CD, +CD里面包含了stage1地址翻译(把进程的GVA/IOVA翻译成IPA)过程中需要的页表基地址信息、per-stream的配置信息以及ASID。 +在stage1翻译的过程中,多个CD对应着多个stage1的地址翻译,通过Substream去确定对应的stage1地址翻译页表。 +所以,Stage1地址翻译其实是一个(RequestID, PASID) => GPA的映射查找过程。 +注意:只有在使能了stage1地址翻译的情况下,SubstreamID才有意义,否则该DMA请求会被丢弃。 + +在stage2地址翻译阶段:STE里面包含了stage2地址翻译的页表基地址(IPA->HPA)和VMID信息。 +如果多个设备被直通给同一个虚拟机,那么意味着他们共享同一个stage2地址翻译页表[[Ref5](https://static.docs.arm.com/ihi0070/b/SMMUv3_architecture_specification_IHI0070B.pdf)]。 + +![arm_smmu_2stage_translation.png](./arm_smmu_2stage_translation.png) + +值得注意的是:CD中包含一个ASID,STE中包含了VMID,CD和VMID存在的目的是作为地址翻译过程中的TLB Tag,用来加速地址翻译的过程。 + +系统软件通过Command Queue和Event Queue来和SMMU打交道,这2个Queue都是循环队列。 +系统软件将Command放到队列中SMMU从队列中读取命令来执行,同时设备在进行DMA传输或者配置发生错误的时候会上报事件, +这些事件就存放在Event Queue当中,系统软件要及时从Event Queue中读取事件以防止队列溢出。 + +![arm smmu all](./arm_smmu_all.png) + +SMMU支持两阶段地址翻译的目的只有1个,那就是为了支持虚拟化场景下的SVM特性(Shared Virtual Memory)。 +SVM特性允许虚拟机内的进程都能够独立的访问直通给虚拟机的直通设备,在进程自己的地址空间内向设备发起DMA。 +SVM使得虚拟机里面的每个进程都能够独立使用某个直通设备,这能够降低应用编程的复杂度,并提升安全性。 + +为了实现虚拟化场景下的SVM,QEMU需要模拟一个vSMMU(或者叫vIOMMU)的设备。 +虚拟机内部进程要访问直通设备的时候,会调用Guest驱动创建PASID Table(虚拟化场景下这个表在Guest内部), +在这个场景下PASID将作为虚拟机内进程地址空间的一个标志,设备在发起DMA请求的时候会带上PASID Prefix,这样SMMU就知道如何区分了。 +创建PASID Table的时候会访问vSMMU,这样Guest就将PASID Table的地址(GPA)传给了QEMU, +然后QEMU再通过VFIO的IOCTL调用(VFIO_DEVICE_BIND_TASK)将表的信息传给SMMU, +这样SMMU就获得了Guest内部进程的PASID Table的shadow信息,它就知道该如何建立Stage1地址翻译表了。 + +所以,在两阶段地址翻译场景下,Guest内部DMA请求的处理步骤 + +``` +Step1: Guest驱动发起DMA请求,这个DMA请求包含GVA + PASID Prefix +Step2: DMA请求到达SMMU,SMMU提取DMA请求中的RequestID就知道这个请求是哪个设备发来的,然后去StreamTable索引对应的STE +Step3: 从对应的STE表中查找到对应的CD,然后用PASID到CD中进行索引找到对应的S1 Page Table +Step4: IOMMU进行S1 Page Table Walk,将GVA翻译成GPA(IPA)并作为S2的输入 +Step5: IOMMU执行S2 Page Table Walk,将GPA翻译成HPA,done! +``` + +纵观SMMUv3,从设计上来和Intel IOMMU的设计和功能基本类似,毕竟这里没有太多可以创新的地方。 +但ARM SMMUv3有2个比较有意思的改进点: +一个是支持Page Request Interface(PRI),PRI是对ATS的进一步改进。当设备支持PRI特性的时候, +设备发送DMA请求的时候可以缺页IOPF(IO Page Fault),这就意味着直通虚拟机可以不需要进行内存预占, +DMA缺页的时候SMMU会向CPU发送一个缺页请求,CPU建立好页表之后对SMMU进行回复,SMMU这时候再将内容写到DMA Buffer中。 +另外一个改进就是,DMA写内存之后产生脏页可以由硬件自动更新Access/Dirty Bit, +这样就对直通设备热迁移比较友好,但这个功能是需要厂商选择性支持的, +而且在这种场景下如何解决SMMU和MMU的Cache一致性是最大的挑战。 + +### 4. Interrupt Virtualization + +ARM的中断系统和x86区别比较大,x86用的是IOAPIC/LAPIC中断系统,ARM则使用的是GIC中断控制器, +并且随着ARM的演进陆续出现了GICv2,GICv3,GICv4等不同版本, +看了GICv3手册感觉着玩儿设计得有点复杂,并不像x86上那样结构清晰。 + +![ARM GIC](./arm_gic_history.png) + +GICv1和GICv2最大只支持8个PE,这放在现在显然不够用了。 +所以,GICv3对这里进行改进,提出了*affinity routing*机制以支持更多的PE。 + +GICv3定义了以下中断类型[[Ref6](https://static.docs.arm.com/dai0492/b/GICv3_Software_Overview_Official_Release_B.pdf)]: +ARM上的中断类型: + +* LPI(Locality-specific Peripheral Interrupt) LPI始终是基于消息的中断,边缘触发、经过ITS路由,它们的配置保存在表中而不是寄存器,比如PCIe的MSI/MSI-x中断,GITS_TRANSLATER控制中断 +* SGI (Software Generated Interrupt) 软件触发的中断,软件可以通过写GICD_SGIR寄存器来触发一个中断事件,一般用于核间通信(对应x86 IPI中断) +* PPI(Private Peripheral Interrupt) 私有外设中断,这是每个核心私有的中断,PPI太冗长会送达到指定的CPU上,边缘触发或者电平触发、有Active转态,应用场景有CPU本地时钟,类似于x86上的LAPIC Timer Interrupt +* SPI(Shared Peripheral Interrupt) 公用的外部设备中断,也定义为共享中断,边缘触发或者电平触发、有Active转态,可以多个CPU或者说Core处理,不限定特定的CPU,SPI支持Message格式(GICv3),GICD_SETSPI_NSR设置中断,GICD_CLRSPI_NSR清除中断 + +ARM上的中断又可以分为两类: +一类中断要通过Distributor分发的,例如SPI中断。 +另一类中断不通过Distributor的,例如LPI中断,直接经过ITS翻译后投递给某个Redistributor。 + + +INTID | Interrupt Type | Notes +------------|----------------|------------ +0-15 | SGI | Banked per PE +16-31 | PPI | Banked per PE +32-1019 | SPI | +1020-1023 | Special Interrupt Number | Used to signal special cases +1024-8191 | Reserved | +8192- | LPI | + +ARM上又搞出来一个*Affinity Routing*的概念,GICv3使用*Affinity Routing*来标志一个特定的PE或者是一组特定的PE, +有点类似于x86上的APICID/X2APIC ID机制。ARM使用4个8bit的域来表示affinity,格式如: +``` + ... +``` +例如,现在有个ARM Big.Little架构的移动处理器SOC,拥有2个Cluster,小核心拥有4个Cortex-A53大核心拥有2个A72,那么可以表示为: +``` +0.0.0.[0:3] Cores 0 to 3 of a Cortex-A53 processor +0.0.1.[0:1] Cores 0 to 1 of a Cortex-A72 processor +``` + +GICv3的设计上和x86的IOAPIC/LAPIC架构差异甚远,GICv3的设计架构如下图所示: + +![GICv3 Arch](./arm_gicv3_arch.png) + +GICv3中断控制器由Distributor,Redistributor和CPU Interface三个部分组成。 +Distributor负责SPI中断管理并将中断发送给Redistributor,Redistributor管理PPI,SGI,LPI中断,并将中断投递给CPU Interface, +CPU Interface负责将中断注入到Core里面(CPU Interface本身就在Core内部)。 + +Distributor的主要功能有: + +* 中断优先级管理和中断分发 +* 启用和禁用SPI +* 为每个SPI设置设置中断优先级 +* 为每个SPI设置路由信息 +* 设置每个SPI的中断触发属性:边沿触发或者电平触发 +* 生成消息格式的SPI中断 +* 控制SPI中断的active状态和pending状态 + +每个PE都对应有一个Redistributor与之相连,Distributor的寄存器是memory-mapped, +并且它的配置是全局生效的,直接影响所有的PE。Redistributor的主要功能有: + +* 使能和禁用SGI和PPI +* 设置SGI和PPI的中断优先级 +* 设置PPI的触发属性:电平触发或者边沿触发 +* 为每个SGI和PPI分配中断组 +* 控制SGI和PPI的状态 +* 控制LPI中断相关数据结构的基地址 +* 对PE的电源管理的支持 + +每个Redistributor都和一个CPU Interface相连, 在GICv3中CPU Interface的寄存器是是通过System registers(ICC_\*ELn)来访问的。 +在使用这些寄存器之前软件必须使能系统寄存器,CPU Interface的主要功能: + +* 控制和使能CPU的中断处理。如果中断disable了,即使Distributor分发了一个中断事件到CPU Interface也会被Core屏蔽掉。 +* 应答中断 +* 进行中断优先级检测和中断deassert +* 为PE设置一个中断优先级mask标志,可以选择屏蔽中断 +* 为PE定义抢占策略 +* 为PE断定当前pending中断的最高优先级(优先级仲裁) + +GICv3中为了处理LPI中断,专门引入了ITS(Interrupt Translation Service)组件。 +外设想发送LPI中断时(比如PCI设备的MSI中断),就去写ITS的寄存器GITS_TRANSLATER,这个写操作就会触发一个LPI中断。 +ITS接收到LPI中断后,对其进行解析然后发送给对应的redistributor,然后再由redistributor发送给CPU Interface。 +那么这个写操作里面包含了哪些内容呢?主要是2个关键域。 + +* EventID:这个是写入到GITS_TRANSLATER的值,EventID定义了外设要触发的中断号,EventID可以和INTID一样,或者经过ITS翻译后得到一个INTID +* DeviceID:这个是外设的标志,实现是自定义的,例如可以使用AXI的user信号传递。 + + +ITS使用3种类型的表来完成LPI的翻译和路由: + +* Device Table: 将DeviceID映射到Interrupt Translation Table中 +* Interrupt Translation Table:包含了EventID到INTID映射关系之间和DeviceID相关的信息,同时也包含了INTID Collection +* Collection Table:将collections映射到Redistributor上 + +![GICv3 ITS](./gicv3_its.png) + +整个流程大概是: +``` +Step1: 外设写GITS_TRANSLATER,ITS使用DeviceID从Device Table中索引出这个外设该使用哪个Interrupt Translation Table +Step2: 使用EventID去选中的Interrupt Translation Table中索引出INTID和对应的Collection ID +Step3: 使用Collection ID从Collection Table中选择对应的Collection和路由信息 +Step4: 把中断送给目标Redistributor +``` +看来看去总觉得GICv3中断控制器设计比较复杂,不如x86上那样结构清晰,目前只是理了个大概,要深入理解再到代码级熟悉还得花不少时间。 +上面说了这么多,还是在将GICv3控制器的逻辑,具体QEMU/KVM上是怎么实现的还得去看代码,为了提升中断的性能, +GICv3的模拟是直接放到KVM里面实现的。比如说virtio设备的MSI中断,那肯定类型上是LPI中断,QEMU模拟的时候机制上还是使用irqfd方式来实现的, +前面也有从代码角度去分析过,后面再单独从代码层级去分析具体的实现方案。 + +### 5. Overview +ARM体系结构和x86存在不少差异,其中差异最大的还是中断控制器这块,这里需要投入事件好好分析一下. +内存虚拟化和I/O虚拟化这块二者可能细节上有些不同,但背后的原理还是近似的. +例如:SMMUv3在设计上和Intel IOMMU都支持了二次地址翻译,但SMMU有针对性的改进点. +更多的详细的ARM虚拟化知识和细节需要阅读ARMv8的spec文档深入去了解。 + +### 6. References + +1. [ARMv8 Architecture Reference Manual](https://developer.arm.com/documentation/ddi0487/latest) +2. [Virtualization Host Extensions +](https://developer.arm.com/architectures/learn-the-architecture/aarch64-virtualization/virtualization-host-extensions) +3. [ARMv8-A Address Translation Version 1.0](https://static.docs.arm.com/100940/0100/armv8_a_address%20translation_100940_0100_en.pdf) +4. [ARM64 Address Translation](http://www.wowotech.net/memory_management/arm64-memory-addressing.html) +5. [SMMU architecture version 3.0 and version 3.1](https://static.docs.arm.com/ihi0070/b/SMMUv3_architecture_specification_IHI0070B.pdf) +6. [GICv3 Software Overview Official Release](https://static.docs.arm.com/dai0492/b/GICv3_Software_Overview_Official_Release_B.pdf) +7. [SVM on ARM SMMUv3](https://blog.linuxplumbersconf.org/2017/ocw/system/presentations/4812/original/plumbers17-smmu-svm.pdf) +8. [SVM and PASID](https://lwn.net/Articles/747230/) diff --git a/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.png b/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.png new file mode 100644 index 0000000000000000000000000000000000000000..4e55c2176a64c186a6ffc6bfde8bd8a32fa696df Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.png differ diff --git a/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.svg b/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.svg new file mode 100644 index 0000000000000000000000000000000000000000..3a07740bda2cc766aa520c230135487f1a39545c --- /dev/null +++ b/web-ui/docs/zh/blog/yorifang/aarch64_exception_levels_2.svg @@ -0,0 +1,220 @@ + + + + + + + + + + Page-1 + + + + Block.3 + Secure firmware + + + + + + + + + + + + Secure firmware + + Sheet.6 + + + + Block.7 + Application + + + + + + + + + + + + Application + + Sheet.10 + Normal world + + + + Normal world + + Sheet.11 + Secure world + + + + Secure world + + Block.1 + Application + + + + + + + + + + + + Application + + Block.16 + Application + + + + + + + + + + + + Application + + Block.17 + Application + + + + + + + + + + + + Application + + Sheet.18 + No Hypervisor in Secure world + + + + No Hypervisor in Secure world + + Dynamic connector.24 + + + + Sheet.26 + EL0 + + + + EL0 + + Sheet.27 + EL1 + + + + EL1 + + Sheet.28 + EL3 + + + + EL3 + + Sheet.29 + EL2 + + + + EL2 + + Sheet.25 + + + + Sheet.30 + Guest OS + + + + Guest OS + + Sheet.2 + Guest OS + + + + Guest OS + + Sheet.8 + Trusted OS + + + + Trusted OS + + Sheet.4 + Hypervisor + + + + Hypervisor + + Sheet.9 + Secure monitor + + + + Secure monitor + + Dynamic connector.19 + + + + diff --git a/web-ui/docs/zh/blog/yorifang/address-translation.png b/web-ui/docs/zh/blog/yorifang/address-translation.png new file mode 100644 index 0000000000000000000000000000000000000000..e89457194fe9b572012b8dd805787fb1dd84523b Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/address-translation.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_address_translation.png b/web-ui/docs/zh/blog/yorifang/arm_address_translation.png new file mode 100644 index 0000000000000000000000000000000000000000..fb043d93e6df4e0eebe279b692db4e060bcc870b Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_address_translation.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_gic_history.png b/web-ui/docs/zh/blog/yorifang/arm_gic_history.png new file mode 100644 index 0000000000000000000000000000000000000000..200d8b67e3ea3c699d58c5c5b64244aaaf23e76f Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_gic_history.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_gicv3_arch.png b/web-ui/docs/zh/blog/yorifang/arm_gicv3_arch.png new file mode 100644 index 0000000000000000000000000000000000000000..1dbfb28f202c450714bc7c299b6a44c5f96eeae9 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_gicv3_arch.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_mmu_trans.png b/web-ui/docs/zh/blog/yorifang/arm_mmu_trans.png new file mode 100644 index 0000000000000000000000000000000000000000..e3b6aed2d381c42768a5fba18ef591827c6f87e3 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_mmu_trans.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_smmu_2stage_translation.png b/web-ui/docs/zh/blog/yorifang/arm_smmu_2stage_translation.png new file mode 100644 index 0000000000000000000000000000000000000000..321d0701caa8d61024c387adc28808527b9eca47 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_smmu_2stage_translation.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_smmu_all.png b/web-ui/docs/zh/blog/yorifang/arm_smmu_all.png new file mode 100644 index 0000000000000000000000000000000000000000..c9fcd3b6f381aed5982bbc06337d0a225618c044 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_smmu_all.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_smmu_translation_stages_and_addresses.png b/web-ui/docs/zh/blog/yorifang/arm_smmu_translation_stages_and_addresses.png new file mode 100644 index 0000000000000000000000000000000000000000..ae7df21746ed1d3d5b6dddc499229382b76203f6 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_smmu_translation_stages_and_addresses.png differ diff --git a/web-ui/docs/zh/blog/yorifang/arm_strtab.png b/web-ui/docs/zh/blog/yorifang/arm_strtab.png new file mode 100644 index 0000000000000000000000000000000000000000..b94e34c81cf9497ae9c50540302aa01a40d93cd6 Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/arm_strtab.png differ diff --git a/web-ui/docs/zh/blog/yorifang/gicv3_its.png b/web-ui/docs/zh/blog/yorifang/gicv3_its.png new file mode 100644 index 0000000000000000000000000000000000000000..97e51d3746cd37b59740eb67aa054bfa29b1f85f Binary files /dev/null and b/web-ui/docs/zh/blog/yorifang/gicv3_its.png differ diff --git a/web-ui/docs/zh/blog/yorifang/virtio-spec-overview.md b/web-ui/docs/zh/blog/yorifang/virtio-spec-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..2161592eb3df6e8861cea5b91be566dda41da6b1 --- /dev/null +++ b/web-ui/docs/zh/blog/yorifang/virtio-spec-overview.md @@ -0,0 +1,810 @@ +--- +title: Virtio协议概述 +date: 2020-11-04 +tags: + - Virtualization + - Virtio +archives: 2020-11 +author: Ying Fang +summary: Virtio协议概述 +--- +## 摘要 + +半虚拟化设备(Virtio Device)在当前云计算虚拟化场景下已经得到了非常广泛的应用, +并且现在也有越来越多的物理设备也开始支持Virtio协议,即所谓的`Virtio Offload`, +通过将virtio协议卸载到硬件上(例如virtio-net网卡卸载,virtio-scsi卸载)让物理机和虚拟机都能够获得加速体验。 +本文中我们来重点了解一下virtio技术中的一些关键点,方便我们加深对半虚拟化的理解。 +本文适合对IO虚拟化有一定了解的人群阅读,本文的目的是对想要了解virtio内部机制的读者提供帮助。 + +在开始了解virtio之前,我们先思考一下几个相关问题: + +* virtio设备有哪几种呈现方式? +* virtio-pci设备的配置空间都有哪些内容? +* virtio前端和后端基于共享内存机制进行通信,它是凭什么可以做到无锁的? +* virtio机制中有那几个关键的数据结构?virtio配置接口存放在哪里?virtio是如何工作的? +* virtio前后端是如何进行通信的?irqfd和ioeventfd是什么回事儿?在virtio前后端通信中是怎么用到的? +* virtio设备支持MSIx,在qemu/kvm中具体是怎么实现对MSIx的模拟呢? +* virtio modern相对于virtio legay多了哪些新特性? + +## 0. 简单了解一下Virtio Spec协议 + +virtio协议标准最早由IBM提出,virtio作为一套标准协议现在有专门的技术委员会进行管理, +具体的标准可以访问[`virtio`官网](http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html), +开发者可以向技术委员会提供新的virtio设备提案(`RFC`),经过委员会通过后可以增加新的virtio设备类型。 + +组成一个virtio设备的四要素包括: +**设备状态域,`feature bits`,设备配置空间,一个或者多个`virtqueue`**。 +其中设备状态域包含6种状态: + +* ACKNOWLEDGE(1):GuestOS发现了这个设备,并且认为这是一个有效的virtio设备; +* DRIVER (2) : GuestOS知道该如何驱动这个设备; +* FAILED (128) : GuestOS无法正常驱动这个设备,Something is wriong; +* FEATURES_OK (8) : GuestOS认识所有的feature,并且feature协商一完成; +* DRIVER_OK (4) : 驱动加载完成,设备可以投入使用了; +* DEVICE_NEEDS_RESET (64) :设备触发了错误,需要重置才能继续工作。 + +`feature bits`用来标志设备支持那个特性,其中bit0-bit23是特定设备可以使用的`feature bits`, +bit24-bit37预给队列和feature协商机制,bit38以上保留给未来其他用途。 +例如:对于virtio-net设备而言,feature bit0表示网卡设备支持checksum校验。 +`VIRTIO_F_VERSION_1`这个feature bit用来表示设备是否支持virtio 1.0 spec标准。 + + 在virtio协议中,所有的设备都使用virtqueue来进行数据的传输。 + **每个设备可以有0个或者多个virtqueue,每个virtqueue占用2个或者更多个4K的物理页**。 + virtqueue有`Split Virtqueues`和`Packed Virtqueues`两种模式, + 在`Split virtqueues`模式下virtqueue被分成若干个部分, + 每个部分都是前端驱动或者后端单向可写的(不能两端同时写)。 + 每个virtqueue都有一个16bit的queue size参数,表示队列的总长度。 + 每个virtqueue由3个部分组成: + +``` + +-------------------+--------------------------------+-----------------------+ + | Descriptor Table | Available Ring (padding) | Used Ring | + +-------------------+--------------------------------+-----------------------+ +``` + + * Descriptor Table:存放IO传输请求信息; + * Available Ring:记录了Descriptor Table表中的哪些项被更新了,前端Driver可写但后端只读; + * Used Ring:记录Descriptor Table表中哪些请求已经被提交到硬件,前端Driver只读但后端可写。 + +整个virtio协议中设备IO请求的工作机制可以简单地概括为: + +1. 前端驱动将IO请求放到`Descriptor Table`中,然后将索引更新到`Available Ring`中,然后kick后端去取数据; +1. 后端取出IO请求进行处理,然后结果刷新到`Descriptor Table`中再更新`Using Ring`,然后发送中断notify前端。 + +从virtio协议可以了解到**virtio设备支持3种设备呈现模式**: + +* Virtio Over PCI BUS,依旧遵循PCI规范,挂在到PCI总线上,作为virtio-pci设备呈现; +* Virtio Over MMIO,部分不支持PCI协议的虚拟化平台可以使用这种工作模式,直接挂载到系统总线上; +* Virtio Over Channel I/O:主要用在s390平台上,virtio-ccw使用这种基于channel I/O的机制。 + +其中,Virtio Over PCI BUS的使用比较广泛,作为PCI设备需按照规范要通过PCI配置空间来向操作系统报告设备支持的特性集合, +这样操作系统才知道这是一个什么类型的virtio设备,并调用对应的前端驱动和这个设备进行握手,进而将设备驱动起来。 +QEMU会给virtio设备模拟PCI配置空间,对于virtio设备来说PCI Vendor ID固定为0x1AF4, +PCI Device ID 为 0x1000到0x107F之间的是virtio设备。 +同时,在不支持PCI协议的虚拟化平台上,virtio设备也可以直接通过MMIO进行呈现, +virtio-spec 4.2 [Virtio Over MMIO](https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1440002)有针对virtio-mmio设备呈现方式的详细描述,mmio相关信息可以直接通过内核参数报告给Linux操作系统。 +本文主要基于virtio-pci展开讨论。 + +前面提到virtio设备有`feature bits`,`virtqueue`等四要素,那么在virtio-pci模式下是如何呈现的呢? +从virtio spec来看,老的virtio协议和新的virtio协议在这一块有很大改动。 +virtio legacy(virtio 0.95)协议规定,对应的配置数据结构(virtio common configuration structure) +应该存放在设备的BAR0里面,我们称之为`virtio legay interface`,其结构如下: + +``` + virtio legacy ==> Mapped into PCI BAR0 + +------------------------------------------------------------------+ + | Host Feature Bits[0:31] | + +------------------------------------------------------------------+ + | Guest Feature Bits[0:31] | + +------------------------------------------------------------------+ + | Virtqueue Address PFN | + +---------------------------------+--------------------------------+ + | Queue Select | Queue Size | + +----------------+----------------+--------------------------------+ + | ISR Status | Device Stat | Queue Notify | + +----------------+----------------+--------------------------------+ + | MSI Config Vector | MSI Queue Vector | + +---------------------------------+--------------------------------+ +``` + +对于新的`virtio modern`,协议将配置结构划分为5种类型: +``` +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 +``` +以上的每种配置结构是直接映射到virtio设备的BAR空间内,那么如何指定每种配置结构的位置呢? +答案是通过`PCI Capability list`方式去指定,这和物理PCI设备是一样的,体现了virtio-pci的协议兼容性。 +``` +struct virtio_pci_cap { + u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + u8 cap_next; /* Generic PCI field: next ptr. */ + u8 cap_len; /* Generic PCI field: capability length */ + u8 cfg_type; /* Identifies the structure. */ + u8 bar; /* Where to find it. */ + u8 padding[3]; /* Pad to full dword. */ + le32 offset; /* Offset within bar. */ + le32 length; /* Length of the structure, in bytes. */ +}; +``` +只是略微不同的是,virtio-pci的Capability有一个统一的结构, +其中`cfg_type`表示Cap的类型,bar表示这个配置结构被映射到的BAR空间号。 +这样每个配置结构都可以通过BAR空间直接访问,或者通过PCI配置空间的`VIRTIO_PCI_CAP_PCI_CFG`域进行访问。 +每个Cap的具体结构定义可以参考virtio spec 4.1.4.3小节。 + + +# 1. 前后端数据共享 + +传统的纯模拟设备在工作的时候,会触发频繁的陷入陷出, +而且IO请求的内容要进行多次拷贝传递,严重影响了设备的IO性能。 +virtio为了提升设备的IO性能,采用了共享内存机制, +***前端驱动会提前申请好一段物理地址空间用来存放IO请求,然后将这段地址的GPA告诉QEMU***。 +前端驱动在下发IO请求后,QEMU可以直接从共享内存中取出请求,然后将完成后的结果又直接写到虚拟机对应地址上去。 +**整个过程中可以做到直投直取,省去了不必要的数据拷贝开销**。 + +**`Virtqueue`是整个virtio方案的灵魂所在**。每个virtqueue都包含3张表, +`Descriptor Table`存放了IO请求描述符,`Available Ring`记录了当前哪些描述符是可用的, +`Used Ring`记录了哪些描述符已经被后端使用了。 + +``` + +------------------------------------+ + | virtio guest driver | + +-----------------+------------------+ + / | ^ + / | \ + put update get + / | \ + V V \ + +----------+ +------------+ +----------+ + | | | | | | + +----------+ +------------+ +----------+ + | available| | descriptor | | used | + | ring | | table | | ring | + +----------+ +------------+ +----------+ + | | | | | | + +----------+ +------------+ +----------+ + | | | | | | + +----------+ +------------+ +----------+ + \ ^ ^ + \ | / + get update put + \ | / + V | / + +----------------+-------------------+ + | virtio host backend | + +------------------------------------+ +``` +`Desriptor Table`中存放的是一个一个的`virtq_desc`元素,每个`virq_desc`元素占用16个字节。 + +``` ++-----------------------------------------------------------+ +| addr/gpa [0:63] | ++-------------------------+-----------------+---------------+ +| len [0:31] | flags [0:15] | next [0:15] | ++-------------------------+-----------------+---------------+ +``` +其中,addr占用64bit存放了单个IO请求的GPA地址信息,例如addr可能表示某个DMA buffer的起始地址。 +len占用32bit表示IO请求的长度,flags的取值有3种, +`VIRTQ_DESC_F_NEXT`表示这个IO请求和下一个`virtq_desc`描述的是连续的, +`IRTQ_DESC_F_WRITE`表示这段buffer是write only的, +`VIRTQ_DESC_F_INDIRECT`表示这段buffer里面放的内容是另外一组buffer的`virtq_desc`(相当于重定向), +next是指向下一个`virtq_desc`的索引号(前提是`VIRTQ_DESC_F_NEXT` & flags)。 + +`Available Ring`是前端驱动用来告知后端那些IO buffer是的请求需要处理,每个Ring中包含一个`virtq_avail`占用8个字节。 +其中,flags取值为`VIRTQ_AVAIL_F_NO_INTERRUPT`时表示前端驱动告诉后端: +“当你消耗完一个IO buffer的时候,不要立刻给我发中断”(防止中断过多影响效率)。 +idx表示下次前端驱动要放置`Descriptor Entry`的地方。 + +``` ++--------------+-------------+--------------+---------------------+ +| flags [0:15] | idx [0:15] | ring[0:15] | used_event [0:15] | ++--------------+-------------+--------------+---------------------+ +``` +Used Ring结构稍微不一样,flags的值如果为`VIRTIO_F_EVENT_IDX`并且前后端协商`VIRTIO_F_EVENT_IDX` feature成功, +那么Guest会将used ring index放在available ring的末尾,告诉后端说: +“Hi 小老弟,当你处理完这个请求的时候,给我发个中断通知我一下”, +同时host也会将avail_event index放到used ring的末尾,告诉guest说: +“Hi 老兄,记得把这个idx的请求kick给我哈”。 +`VIRTIO_F_EVENT_IDX`对virtio通知/中断有一定的优化,在某些场景下能够提升IO性能。 + +```c +/* The Guest publishes the used index for which it expects an interrupt + * at the end of the avail ring. Host should ignore the avail->flags field. */ +/* The Host publishes the avail index for which it expects a kick + * at the end of the used ring. Guest should ignore the used->flags field. */ + +struct virtq_used { +#define VIRTQ_USED_F_NO_NOTIFY 1 + le16 flags; + le16 idx; + struct virtq_used_elem ring[ /* Queue Size */]; + le16 avail_event; /* Only if VIRTIO_F_EVENT_IDX */ +}; + +/* le32 is used here for ids for padding reasons. */ +struct virtq_used_elem { + /* Index of start of used descriptor chain. */ + le32 id; + /* Total length of the descriptor chain which was used (written to) */ + le32 len; +}; +``` + +原理就到这里,后面会以virtio网卡为例进行详细流程说明。 + +## 2. 前后端通信机制(irqfd 与 ioeventfd) + +共享内存方式解决了传统设备IO过程中内存拷贝带来的性能损耗问题,除此之外前端驱动和后端驱动的通信问题也是有可以改进的地方。 +Virtio前后端通信概括起来只有两个方向,即GuestOS通知QEMU和QEMU通知GuestOS。 +当前端驱动准备好IO buffer之后,需要通知后端(QEMU),告诉后端: +“小老弟,我有一波IO请求已经准备好了,你帮我处理一下”。 +前端通知出去后,就可以等待IO结果了(操作系统可以进行一次调度),这时候vCPU可以去干点其他的事情。 +后端收到消息后开始处理IO请求,当IO请求处理完成之后,后端就通过中断机制通知GuestOS: +“老哥,你的IO给你处理好了,你来取一下”。 +前后端通信机制如下图所示: + +``` + +-------------+ +-------------+ + | | | | + | | | | + | GuestOS | | QEMU | + | | | | + | | | | + +---+---------+ +----+--------+ + | ^ | ^ + | | | | + +---|-----|-------------------------|----|---+ + | | | irqfd | | | + | | +-------------------------+ | | + | | ioeventfd | | + | +------------------------------------+ | + | KVM | + +--------------------------------------------+ + +``` + +前端驱动通知后端比较简单,QEMU设置一段特定的MMIO地址空间,前端驱动访问这段MMIO触发VMExit, +退出到KVM后利用`ioeventfd`机制通知到用户态的QEMU,QEMU主循环(main_loop poll) +检测到ioeventfd事件后调用callback进行处理。 + +```c +前端驱动通知后端: +内核流程mark一下,PCI设备驱动流程这个后面可以学习一下,先扫描PCI bus发现是virtio设备再扫描virtio-bus。 +worker_thread --> process_one_work --> pciehp_power_thread --> pciehp_enable_slot --> +pciehp_configure_device --> pci_bus_add_devices --> pci_bus_add_device --> device_attach --> +__device_attach --> bus_for_each_drv --> __device_attach_driver --> driver_probe_device --> +pci_device_probe --> local_pci_probe --> virtio_pci_probe --> register_virtio_device --> +device_register --> device_add --> bus_probe_device --> device_initial_probe +--> __device_attach --> bus_for_each_drv --> __device_attach_driver --> +driver_probe_device --> virtio_dev_probe --> virtnet_probe (网卡设备驱动加载的入口) + +static int virtnet_probe(struct virtio_device *vdev) +{ + ...... + virtio_device_ready(vdev); +} + +/** + * virtio_device_ready - enable vq use in probe function + * @vdev: the device + * + * Driver must call this to use vqs in the probe function. + * + * Note: vqs are enabled automatically after probe returns. + */ +static inline +void virtio_device_ready(struct virtio_device *dev) +{ + unsigned status = dev->config->get_status(dev); + + BUG_ON(status & VIRTIO_CONFIG_S_DRIVER_OK); + dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK); +} + +# QEMU/KVM后端的处理流程如下: +# 前端驱动写Status位,val & VIRTIO_CONFIG_S_DRIVER_OK,这时候前端驱动已经ready +virtio_pci_config_write --> virtio_ioport_write --> virtio_pci_start_ioeventfd +--> virtio_bus_set_host_notifier --> virtio_bus_start_ioeventfd --> virtio_device_start_ioeventfd_impl +--> virtio_bus_set_host_notifier + --> virtio_pci_ioeventfd_assign + --> memory_region_add_eventfd + --> memory_region_transaction_commit + --> address_space_update_ioeventfds + --> address_space_add_del_ioeventfds + --> kvm_io_ioeventfd_add/vhost_eventfd_add + --> kvm_set_ioeventfd_pio + --> kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick) +``` + +其实,这就是QEMU的`Fast MMIO`实现机制。 +我们可以看到,QEMU会为每个设备MMIO对应的MemoryRegion注册一个ioeventfd。 +最后调用了一个KVM_IOEVENTFD ioctl到KVM内核里面,而在KVM内核中会将MMIO对应的(gpa,len,eventfd)信息会注册到KVM_FAST_MMIO_BUS上。 +这样当Guest访问MMIO地址范围退出后(触发`EPT Misconfig`),KVM会查询一下访问的GPA是否落在某段MMIO地址空间range内部, +如果是的话就直接写eventfd告知QEMU,QEMU就会从coalesced mmio ring page中取MMIO请求 +(注:pio page和 mmio page是QEMU和KVM内核之间的共享内存页,已经提前mmap好了)。 + +```c +#kvm内核代码virt/kvm/eventfd.c中 +kvm_vm_ioctl(KVM_IOEVENTFD) + --> kvm_ioeventfd + --> kvm_assign_ioeventfd + --> kvm_assign_ioeventfd_idx + +# MMIO处理流程中(handle_ept_misconfig)最后会调用到ioeventfd_write通知QEMU。 +/* MMIO/PIO writes trigger an event if the addr/val match */ +static int +ioeventfd_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, + int len, const void *val) +{ + struct _ioeventfd *p = to_ioeventfd(this); + + if (!ioeventfd_in_range(p, addr, len, val)) + return -EOPNOTSUPP; + + eventfd_signal(p->eventfd, 1); + return 0; +} +``` + +不了解`MMIO`是如何模拟的童鞋,可以结合本站的文章[`MMIO`模拟实现分析](https://kernelgo.org/mmio.html)去了解一下, +如果还是不懂的可以在文章下面评论。 + +**后端通知前端,是通过中断的方式**,QEMU/KVM中有一套完整的中断模拟实现框架, + +如果对QEMU/KVM中断模拟不熟悉的童鞋, +建议阅读一下这篇文章:[`QEMU学习笔记-中断`](https://www.binss.me/blog/qemu-note-of-interrupt/)。 +对于virtio-pci设备,可以通过Cap呈现MSIx给虚拟机,这样在前端驱动加载的时候就会尝试去使能MSIx中断, +后端在这个时候建立起MSIx通道。 + +前端驱动加载(probe)的过程中,会去初始化`virtqueue`,这个时候会去申请MSIx中断并注册中断处理函数: + +```c +virtnet_probe + --> init_vqs + --> virtnet_find_vqs + --> vi->vdev->config->find_vqs [vp_modern_find_vqs] + --> vp_find_vqs + --> vp_find_vqs_msix // 为每virtqueue申请一个MSIx中断,通常收发各一个队列 + --> vp_request_msix_vectors // 主要的MSIx中断申请逻辑都在这个函数里面 + --> pci_alloc_irq_vectors_affinity // 申请MSIx中断描述符(__pci_enable_msix_range) + --> request_irq // 注册中断处理函数 + + // virtio-net网卡至少申请了3个MSIx中断: + // 一个是configuration change中断(配置空间发生变化后,QEMU通知前端) + // 发送队列1个MSIx中断,接收队列1MSIx中断 +``` + +在QEMU/KVM这一侧,开始模拟MSIx中断,具体流程大致如下: +```c +virtio_pci_config_write + --> virtio_ioport_write + --> virtio_set_status + --> virtio_net_vhost_status + --> vhost_net_start + --> virtio_pci_set_guest_notifiers + --> kvm_virtio_pci_vector_use + |--> kvm_irqchip_add_msi_route //更新中断路由表 + |--> kvm_virtio_pci_irqfd_use //使能MSI中断 + --> kvm_irqchip_add_irqfd_notifier_gsi + --> kvm_irqchip_assign_irqfd + +# 申请MSIx中断的时候,会为MSIx分配一个gsi,并为这个gsi绑定一个irqfd,然后调用ioctl KVM_IRQFD注册到内核中。 +static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq, + bool assign) +{ + struct kvm_irqfd irqfd = { + .fd = fd, + .gsi = virq, + .flags = assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN, + }; + + if (rfd != -1) { + irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE; + irqfd.resamplefd = rfd; + } + + if (!kvm_irqfds_enabled()) { + return -ENOSYS; + } + + return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd); +} + +# KVM内核代码virt/kvm/eventfd.c +kvm_vm_ioctl(s, KVM_IRQFD, &irqfd) + --> kvm_irqfd_assign + --> vfs_poll(f.file, &irqfd->pt) // 在内核中poll这个irqfd + +``` + +从上面的流程可以看出,**QEMU/KVM使用`irqfd`机制来模拟MSIx中断**, +即设备申请MSIx中断的时候会为MSIx分配一个gsi(这个时候会刷新irq routing table), +并为这个gsi绑定一个`irqfd`,最后在内核中去`poll`这个`irqfd`。 +当QEMU处理完IO之后,就写MSIx对应的irqfd,给前端注入一个MSIx中断,告知前端我已经处理好IO了你可以来取结果了。 + +例如,virtio-scsi从前端取出IO请求后会取做DMA操作(DMA是异步的,QEMU协程中负责处理)。 +当DMA完成后QEMU需要告知前端IO请求已完成(Complete),那么怎么去投递这个MSIx中断呢? +答案是调用`virtio_notify_irqfd`注入一个MSIx中断。 + +```c +#0 0x00005604798d569b in virtio_notify_irqfd (vdev=0x56047d12d670, vq=0x7fab10006110) at hw/virtio/virtio.c:1684 +#1 0x00005604798adea4 in virtio_scsi_complete_req (req=0x56047d09fa70) at hw/scsi/virtio-scsi.c:76 +#2 0x00005604798aecfb in virtio_scsi_complete_cmd_req (req=0x56047d09fa70) at hw/scsi/virtio-scsi.c:468 +#3 0x00005604798aee9d in virtio_scsi_command_complete (r=0x56047ccb0be0, status=0, resid=0) at hw/scsi/virtio-scsi.c:495 +#4 0x0000560479b397cf in scsi_req_complete (req=0x56047ccb0be0, status=0) at hw/scsi/scsi-bus.c:1404 +#5 0x0000560479b2b503 in scsi_dma_complete_noio (r=0x56047ccb0be0, ret=0) at hw/scsi/scsi-disk.c:279 +#6 0x0000560479b2b610 in scsi_dma_complete (opaque=0x56047ccb0be0, ret=0) at hw/scsi/scsi-disk.c:300 +#7 0x00005604799b89e3 in dma_complete (dbs=0x56047c6e9ab0, ret=0) at dma-helpers.c:118 +#8 0x00005604799b8a90 in dma_blk_cb (opaque=0x56047c6e9ab0, ret=0) at dma-helpers.c:136 +#9 0x0000560479cf5220 in blk_aio_complete (acb=0x56047cd77d40) at block/block-backend.c:1327 +#10 0x0000560479cf5470 in blk_aio_read_entry (opaque=0x56047cd77d40) at block/block-backend.c:1387 +#11 0x0000560479df49c4 in coroutine_trampoline (i0=2095821104, i1=22020) at util/coroutine-ucontext.c:115 +#12 0x00007fab214d82c0 in __start_context () at /usr/lib64/libc.so.6 +``` + +在`virtio_notify_irqfd `函数中,会去写`irqfd`,给内核发送一个信号。 + +```c +void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq) +{ + ... + /* + * virtio spec 1.0 says ISR bit 0 should be ignored with MSI, but + * windows drivers included in virtio-win 1.8.0 (circa 2015) are + * incorrectly polling this bit during crashdump and hibernation + * in MSI mode, causing a hang if this bit is never updated. + * Recent releases of Windows do not really shut down, but rather + * log out and hibernate to make the next startup faster. Hence, + * this manifested as a more serious hang during shutdown with + * + * Next driver release from 2016 fixed this problem, so working around it + * is not a must, but it's easy to do so let's do it here. + * + * Note: it's safe to update ISR from any thread as it was switched + * to an atomic operation. + */ + virtio_set_isr(vq->vdev, 0x1); + event_notifier_set(&vq->guest_notifier); //写vq->guest_notifier,即irqfd +} +``` + +QEMU写了这个`irqfd`后,KVM内核模块中的irqfd poll就收到一个`POLL_IN`事件,然后将MSIx中断自动投递给对应的LAPIC。 +大致流程是:`POLL_IN` -> `kvm_arch_set_irq_inatomic` -> `kvm_set_msi_irq`, `kvm_irq_delivery_to_apic_fast` + +```c +static int +irqfd_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync, void *key) +{ + if (flags & EPOLLIN) { + idx = srcu_read_lock(&kvm->irq_srcu); + do { + seq = read_seqcount_begin(&irqfd->irq_entry_sc); + irq = irqfd->irq_entry; + } while (read_seqcount_retry(&irqfd->irq_entry_sc, seq)); + /* An event has been signaled, inject an interrupt */ + if (kvm_arch_set_irq_inatomic(&irq, kvm, + KVM_USERSPACE_IRQ_SOURCE_ID, 1, + false) == -EWOULDBLOCK) + schedule_work(&irqfd->inject); + srcu_read_unlock(&kvm->irq_srcu, idx); + } + +``` + +这里还有一点没有想明白,结合代码和调试来看,virtio-blk/virtio-scsi的msi中断走irqfd机制, +但是virtio-net(不开启vhost的情况下)不走irqfd,而是直接调用`virtio_notify`/`virtio_pci_notify`, +最后通过KVM的ioctl投递中断? +从代码路径上来看,后者明显路径更长,谁知道原因告诉我一下!!!。 +https://patchwork.kernel.org/patch/9531577/ +``` +Once in virtio_notify_irqfd, once in virtio_queue_guest_notifier_read. + +Unfortunately, for virtio-blk + MSI + KVM + old Windows drivers we need the one in virtio_notify_irqfd. +For virtio-net + vhost + INTx we need the one in virtio_queue_guest_notifier_read. +这显然路径更长啊。 +``` + +Ok,到这里virtio前后端通信机制已经明了,最后一个小节我们以virtio-net为例,梳理一下virtio中的部分核心代码流程。 + + +## 3. virtio核心代码分析,以virtio-net为例 + +这里我们已virtio-net网卡为例,在没有使用vhost的情况下(网卡后端收发包都走QEMU处理), +后端收发包走vhost的情况下有些不同,后面单独分析。 + +### 3.1 前后端握手流程 +QEM模拟PCI设备对GuestOS进行呈现,设备驱动加载的时候尝试去初始化设备。 + +```c +# 先在PCI总线上调用probe设备,调用了virtio_pci_probe,然后再virtio-bus上调用virtio_dev_probe +# virtio_dev_probe最后调用到virtnet_probe +pci_device_probe --> local_pci_probe --> virtio_pci_probe --> register_virtio_device --> +device_register --> device_add --> bus_probe_device --> device_initial_probe +--> __device_attach --> bus_for_each_drv --> __device_attach_driver --> driver_probe_device --> +virtio_dev_probe --> virtnet_probe + +# 在virtio_pci_probe里先尝试以virtio modern方式读取设备配置数据结构,如果失败则尝试virio legacy方式。 +# 对于virtio legacy,我们前面提到了virtio legacy协议规定设备的配置数据结构放在PCI BAR0里面。 +/* the PCI probing function */ +int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) +{ + rc = pci_request_region(pci_dev, 0, "virtio-pci-legacy"); //将设备的BAR0映射到物理地址空间 + vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0); //获得BAR0的内核地址 +} + +#对于virtio modern,通过capability方式报告配置数据结构的位置,配置数据结构有5种类型。 +int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) +{ + /* check for a common config: if not, use legacy mode (bar 0). */ + common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG, + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); + + /* If common is there, these should be too... */ + isr = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_ISR_CFG, + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); + notify = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_NOTIFY_CFG, + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); + + /* Device capability is only mandatory for devices that have + * device-specific configuration. + */ + device = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_DEVICE_CFG, + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); + + err = pci_request_selected_regions(pci_dev, vp_dev->modern_bars, + "virtio-pci-modern"); + sizeof(struct virtio_pci_common_cfg), 4, + 0, sizeof(struct virtio_pci_common_cfg), + NULL); + // 将配virtio置结构所在的BAR空间MAP到内核地址空间里 + vp_dev->common = map_capability(pci_dev, common, + sizeof(struct virtio_pci_common_cfg), 4, + 0, sizeof(struct virtio_pci_common_cfg), + NULL); + ...... +} + +# 接着来到virtio_dev_probe里面看下: +static int virtio_dev_probe(struct device *_d) +{ + /* We have a driver! */ + virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); // 更新status bit,这里要写配置数据结构 + + /* Figure out what features the device supports. */ + device_features = dev->config->get_features(dev); // 查询后端支持哪些feature bits + + // feature set协商,取交集 + err = virtio_finalize_features(dev); + + // 调用特定virtio设备的驱动程序probe,例如: virtnet_probe, virtblk_probe + err = drv->probe(dev); +} +``` + +再看下`virtnet_probe`里面的一些关键的流程,这里包含了virtio-net网卡前端初始化的主要逻辑。 + +```c +static int virtnet_probe(struct virtio_device *vdev) +{ + // check后端是否支持多队列,并按情况创建队列 + /* Allocate ourselves a network device with room for our info */ + dev = alloc_etherdev_mq(sizeof(struct virtnet_info), max_queue_pairs); + + // 定义一个网络设备并配置一些属性,例如MAC地址 + dev->ethtool_ops = &virtnet_ethtool_ops; + SET_NETDEV_DEV(dev, &vdev->dev); + + // 初始化virtqueue + err = init_vqs(vi); + + // 注册一个网络设备 + err = register_netdev(dev); + + // 写状态位DRIVER_OK,告诉后端,前端已经ready + virtio_device_ready(vdev); + + // 将网卡up起来 + netif_carrier_on(dev); +} +``` +其中关键的流程是`init_vqs`,在`vp_find_vqs_msix`流程中会尝试去申请MSIx中断,这里前面已经有分析过了。 +其中,"configuration changed" 中断服务程序`vp_config_changed`, +virtqueue队列的中断服务程序是 `vp_vring_interrupt`。 + +```c +init_vqs --> virtnet_find_vqs --> vi->vdev->config->find_vqs --> vp_modern_find_vqs +--> vp_find_vqs --> vp_find_vqs_msix + +static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], vq_callback_t *callbacks[], + const char * const names[], bool per_vq_vectors, + const bool *ctx, + struct irq_affinity *desc) +{ + /* 为configuration change申请MSIx中断 */ + err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors, + per_vq_vectors ? desc : NULL); + for (i = 0; i < nvqs; ++i) { + // 创建队列 --> vring_create_virtqueue --> vring_create_virtqueue_split --> vring_alloc_queue + vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], + ctx ? ctx[i] : false, + msix_vec); + // 每个队列申请一个MSIx中断 + err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), + vring_interrupt, 0, + vp_dev->msix_names[msix_vec], + vqs[i]); + } +``` + +`vp_setup_vq`流程再往下走就开始分配共享内存页,至此建立起共享内存通信通道。 +值得注意的是一路传下来的callbacks参数其实传入了发送队列和接收队列的回调处理函数, +好家伙,从`virtnet_find_vqs`一路传递到了`__vring_new_virtqueue`中最终赋值给了`vq->vq.callback`。 + +``` +static struct virtqueue *vring_create_virtqueue_split( + unsigned int index, + unsigned int num, + unsigned int vring_align, + struct virtio_device *vdev, + bool weak_barriers, + bool may_reduce_num, + bool context, + bool (*notify)(struct virtqueue *), + void (*callback)(struct virtqueue *), + const char *name) +{ + /* TODO: allocate each queue chunk individually */ + for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) { + // 申请物理页,地址赋值给queue + queue = vring_alloc_queue(vdev, vring_size(num, vring_align), + &dma_addr, + GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); + } + + + queue_size_in_bytes = vring_size(num, vring_align); + vring_init(&vring, num, queue, vring_align); // 确定 descriptor table, available ring, used ring的位置。 +} +``` + +我们看下如果`virtqueue`队列如果收到MSIx中断消息后,会调用哪个`hook`来处理? + +```c +irqreturn_t vring_interrupt(int irq, void *_vq) +{ + struct vring_virtqueue *vq = to_vvq(_vq); + + if (!more_used(vq)) { + pr_debug("virtqueue interrupt with no work for %p\n", vq); + return IRQ_NONE; + } + + if (unlikely(vq->broken)) + return IRQ_HANDLED; + + pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); + if (vq->vq.callback) + vq->vq.callback(&vq->vq); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(vring_interrupt); +``` + +不难想到中断服务程序里面会调用队列上的callback。 +我们再回过头来看下`virtnet_find_vqs`,原来接受队列的回调函数是`skb_recv_done`,发送队列的回调函数是`skb_xmit_done`。 + +``` +static int virtnet_find_vqs(struct virtnet_info *vi) +{ + /* Allocate/initialize parameters for send/receive virtqueues */ + for (i = 0; i < vi->max_queue_pairs; i++) { + callbacks[rxq2vq(i)] = skb_recv_done; + callbacks[txq2vq(i)] = skb_xmit_done; + } +} +``` + +OK,这个小节就到这里。Are you clear ? + +### 3.2 virtio-net网卡收发在virtqueue上的实现 + +这里以virtio-net为例(非vhost-net模式)来分析一下网卡收发报文在virtio协议上的具体实现。 +virtio-net模式下网卡收发包的流程为: + +* 收包:Hardware => Host Kernel => Qemu => Guest +* 发包:Guest => Host Kernel => Qemu => Host Kernel => Hardware + +#### 3.2.1 virtio-net网卡发包 + +前面我们看到virtio-net设备初始化的时候会创建一个`net_device`设备: +`virtnet_probe` -> `alloc_etherdev_mq`注册了`netdev_ops` = `&virtnet_netdev`, +这里`virtnet_netdev`是网卡驱动的回调函数集合(收发包和参数设置)。 + +```c +static const struct net_device_ops netdev_ops = { + .ndo_open = rio_open, + .ndo_start_xmit = start_xmit, + .ndo_stop = rio_close, + .ndo_get_stats = get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_rx_mode = set_multicast, + .ndo_do_ioctl = rio_ioctl, + .ndo_tx_timeout = rio_tx_timeout, +}; +``` + +网卡发包的时候调用`ndo_start_xmit`,将TCP/IP上层协议栈扔下来的数据发送出去。 +对应到virtio网卡的回调函数就是`start_xmit`,从代码看就是将skb发送到virtqueue中, +然后调用virtqueue_kick通知qemu后端将数据包发送出去。 + +Guest内核里面的virtio-net驱动发包: +```c +内核驱动 virtio_net.c +start_xmit + // 将skb放到virtqueue队列中 + -> xmit_skb -> sg_init_table,virtqueue_add_outbuf -> virtqueue_add + // kick通知qemu后端去取 + virtqueue_kick_prepare && virtqueue_notify + // kick次数加1 + sq->stats.kicks++ +``` + +Guest Kick后端从KVM中VMExit出来退出到Qemu用户态(走的是ioeventfd)由Qemu去将数据发送出去。 +大致调用的流程是: +`virtio_queue_host_notifier_read` -> `virtio_net_handle_tx_bh` -> `virtio_net_flush_tx` +-> `virtqueue_pop`拿到发包(skb) -> `qemu_sendv_packet_async` + +```c +Qemu代码virtio-net相关代码: +virtio_queue_host_notifier_read -> virtio_queue_notify_vq + -> vq->handle_output -> virtio_net_handle_tx_bh 队列注册的时候,回注册回调函数 + -> qemu_bh_schedule -> virtio_net_tx_bh + -> virtio_net_flush_tx + -> virtqueue_pop + -> qemu_sendv_packet_async // 报文放到发送队列上,写tap设备的fd去发包 + -> tap_receive_iov -> tap_write_packet + +// 最后调用 tap_write_packet 把数据包发给tap设备投递出去 +``` + +#### 3.2.2 virtio-net网卡收包 + +网卡收包的时候,tap设备先收到报文,对应的virtio-net网卡tap设备fd变为可读, +Qemu主循环收到POLL_IN事件调用回调函数收包。 + +```c +tap_send -> qemu_send_packet_async -> qemu_send_packet_async_with_flags + -> qemu_net_queue_send + -> qemu_net_queue_deliver + -> qemu_deliver_packet_iov + -> nc_sendv_compat + -> virtio_net_receive + -> virtio_net_receive_rcu +``` + +virtio-net网卡收报最终调用了`virtio_net_receive_rcu`, +和发包类似都是调用`virtqueue_pop`从前端获取virtqueue element, +将报文数据填充到vring中然后`virtio_notify`注入中断通知前端驱动取结果。 + +这里不得不吐槽一下,为啥收包函数取名要叫`tap_send`。 + +## 4. 参考文献 + +1. [virtio spec v1.1 ](https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html) +1. [Towards a De-Facto Standard For Virtual](https://ozlabs.org/~rusty/virtio-spec/virtio-paper.pdf) +1. https://github.com/qemu/qemu/blob/master/hw/net/virtio-net.c +1. https://github.com/torvalds/linux/blob/master/drivers/net/virtio_net.c diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/001A-Tune-install-process.md b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/001A-Tune-install-process.md new file mode 100644 index 0000000000000000000000000000000000000000..177941aa3eaf5c1428593d24f99636699e5c7337 --- /dev/null +++ b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/001A-Tune-install-process.md @@ -0,0 +1,148 @@ +--- +title: 'A-Tune 实战: 安装, 部署和启动' +date: 2020-10-19 +tags: + - A-Tune + - 调优 + - 智能 +archives: 2020-10 +author: 张苗, 中国科学院软件研究所智能软件研究中心 +summary: A-Tune 安装和启动过程详解 +--- + + +### A-Tune介绍 + +A-Tune 是 openEuler 系统推出的一款性能自优化软件. 众所周知, 操作系统和应用软件的配置参数浩如烟海, 同时现代软件和业务场景层出不穷, 如何让操作系统和应用软件达到最佳性能一直是程序员的重大挑战之一. 近几年, AI 技术取得了快速的发展, 在各个领域大显身手. 但一款利用人工智能技术优化操作系统和应用软件参数的框架还是一片空白. + +A-Tune 利用 AI 技术降低操作系统和应用程序参数的调优难度. 通过系统画像, 自动感知, 算法模型, 为每一款应用, 每一个场景, 找到最适合的参数配置. + +A-Tune 实战系列文章, 旨在展示官方用户手册的基础上, 通过步骤分解和大量示例, 记录过程中遇到的各种问题.详细讲解 A-Tune 的功能. + + + +### 1. 安装 + +- 硬件: 鲲鹏 920 +- 操作系统: openEuler + +A-Tune 是一款专门针对鲲鹏 920 服务器和 openEuler 操作系统的性能优化软件. + +A-Tune 支持单机和分布式两种安装方式. 本文尝试的是单机部署方式, client 和 server 端安装在相同的机器上. + +A-Tune 的软件包已经集成在 openEuler 公布的软件源中, 可以方便的通过 yum 进行安装. + +##### 1.1 安装 atune client 和 db + +``` +# yum install atune +``` + +这个过程安装的包分为以下几类: + +- atune client端 +- atune db +- 操作系统参数采集: hwloc, perf, sysstat, prefetch_tuning, lm_sensors +- Web微框架: python3_flask等 +- 科学计算: python3_numpy, python3_pandas + +![](./atune-install.png) + +##### 1.2 安装 atune-engine +``` +# yum install atune-engine +``` + +atune-engine 依赖的包基本都是 AI 的科学计算库和算法库 + +![](./atune-engine-install.png) + +##### 1.3 确认安装结果成功 + +![](./atune-install-check.png) + + + +### 2. 配置文件 + +A-Tune 的配置文件位于```/etc/atuned/``` 路径下 + +![](./atuned-folder.png) + +两个最重要的配置文件 ```atuned.cnf``` 和 ```engine.cnf``` + +##### 2.1 查看配置文件 `atuned.cnf` + +``` +cat /etc/atuned/atuned.cnf +``` + +![](./atuned-cnf-1.png) + +![](./atuned-cnf-2.png) + +![](./atuned-cnf-3.png) + +##### 2.2 修改参数 ` network` + +可以通过```ifconfig```命令查询网卡名称 + +![](./ifconfig.png) + +设置到`atuned.cnf`中 + +``` +# the network to be analysis +network = enp125s0f0 +``` + + + +##### 2.3 查看配置文件 `engine.cnf` + +``` +cat /etc/atuned/atuned.cnf +``` + +![](./engine-cnf.png) + + + +### 3. 部署和启动 + +##### 3.1 用 `systemctl` 启动 A-Tune 服务 + +``` +# systemctl start atuned +# systemctl status atuned +``` + +![](./systemctl-start.png) + +其中黄色字体的 log 是一段 warning , 这是因为 A-Tune 服务启动时, 没有进行 workload type 检测, 因此没有激活任何 profile, 通过```atune-adm list``` 命令也能看出来当前所有的 profile 状态都为 false + +##### 3.2 显示当前支持的 workload type + +``` +# atune-adm list +``` + +![](./atune-adm-list.png) + +##### 3.3 分析系统性能和自动激活相应的 profile + +``` +# atune-adm analysis +``` + +![](./analysis-1.png) + +![](./analysis-2.png) + +经过 analysis 过程, 利用工具( perf , sysstat 等)采集操作系统的参数, 将采集到的参数输入给训练好的模型, 识别出当前系统 workload 为 default 类型, 最后将 default workload type 对应的 profile 设置到系统中. + + + +### 4. 小结 + +本文实践了 A-Tune 的安装, 部署和启动过程, 分步骤分过程详细解释了其中的具体细节. 通过本文, 可以简单快速的熟悉 A-Tune 软件. 下一步我们将详解 A-Tune 的其它功能. diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-1.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-1.png new file mode 100644 index 0000000000000000000000000000000000000000..989b02ac9cf0523545070db072f7f3ebbced82d9 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-1.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-2.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6a8852a4506b4a3976dc7922432831cb84970207 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/analysis-2.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-adm-list.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-adm-list.png new file mode 100644 index 0000000000000000000000000000000000000000..d1514f5e0cd2a8f6ec6a028375b7f42c556df687 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-adm-list.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-engine-install.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-engine-install.png new file mode 100644 index 0000000000000000000000000000000000000000..62cf097b25ad83e3aa4005bef2fa928dd4283895 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-engine-install.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install-check.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install-check.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a91be4553165986e7ed0792f75ab84728102e3 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install-check.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install.png new file mode 100644 index 0000000000000000000000000000000000000000..ef40247e22b15d4a4528762f5dbb154397d126b5 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atune-install.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-1.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-1.png new file mode 100644 index 0000000000000000000000000000000000000000..24dd9d19e0317e11203309816c72d39eb6047290 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-1.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-2.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-2.png new file mode 100644 index 0000000000000000000000000000000000000000..2258985b44d9784d368006325f76eab0255198a2 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-2.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-3.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-3.png new file mode 100644 index 0000000000000000000000000000000000000000..ab25a6877ad9d683f3525b180c780da1fd60929a Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-cnf-3.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-folder.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-folder.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8c75e7577dae0ffdfd3774500f7b449d2a71fc Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/atuned-folder.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/engine-cnf.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/engine-cnf.png new file mode 100644 index 0000000000000000000000000000000000000000..0c3a7b8549d1fe34c912f0168191436acf1533a6 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/engine-cnf.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/ifconfig.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/ifconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..017f06129624f4c0d7e8f3d5cb826385bcc83349 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/ifconfig.png differ diff --git a/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/systemctl-start.png b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/systemctl-start.png new file mode 100644 index 0000000000000000000000000000000000000000..4a72493f15708f68c03961d8c14eb320555b39c4 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangmiao_iscas/001A-tune-install-process/systemctl-start.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/2020-11-28-RISC-V.md b/web-ui/docs/zh/blog/zhangxinhao/risc-v/2020-11-28-RISC-V.md new file mode 100644 index 0000000000000000000000000000000000000000..37c01cd09c2bd44b4989b64165ff210752a2f93a --- /dev/null +++ b/web-ui/docs/zh/blog/zhangxinhao/risc-v/2020-11-28-RISC-V.md @@ -0,0 +1,548 @@ +--- +title: RISC-V特权级架构与系统启动 +date: 2020-11-28 +tags: + - RISC-V + - opensbi + - kernel +archives: 2020-11 +author: Xinhao Zhang +summary: RISC-V特权级架构以及CPU、中断、内存初始化介绍 + +--- + +### RISC-V + +RISC-V架构主要由美国加州大学伯克利分校发明,相比于x86和ARM架构,RISC-V开源采用BSD协议,它允许用户自由地使用、修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。计算机体系结构的传统方法是增量ISA,新处理器不仅必须实现新的ISA扩展,还必须 实现过去的所有扩展。目的是为了保持向后的二进制兼容性,这样几十年前程序的二进制 版本仍然可以在最新的处理器上正确运行。导致了传统ISA的体量随时间大幅增长。而RISC-V是模块化的。它的核心是一个名为RV32I的基础ISA,支持运行一个完整的软件栈。RV32I是固定的,永远不会改变。这为编译器编写者,操作系统开发人员和汇编语言程序员提供了稳定的目标。模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。 + +### 1. RISC-V 特权级架构 + +RISC-V定义了三种特权模式,分别为Machine Mode(M Mode),Supervisor Mode(S Mode),User Mode(U Mode)。 + +![](./figures/img1.png) + +在特权级架构实现中,M Mode为必选模式,另外两种为可选模式。通过不同的模式组合可以实现不同用途的系统。 + +![](./figures/img2.png) + +* M Mode:通常为简单的嵌入式系统 +* M Mode + U Mode:该系统可以实现用户和机器模式的区分,从而实现资源的保护 +* M Mode + U Mode + U Mode:该系统可以实现类Unix操作系统 + +### 2. RISC-V 通用寄存器 + +基本整数指令集是RISC-V最基本也是唯一强制要求实现的指令集模块,能够实现完整的软件编译器,支持现代操作系统运行。RV32I是其中一种整数指令集,支持32个通用整数寄存器,每一个寄存器有32位,由x0~x31表示,其中x0寄存器被预留为常数0.在汇编语言中,通用寄存器组中的每一个寄存器都有别名。 + +| Register | ABI Name | Description | +| :------ | :------ | :------ | +| x0 | zero | Hard-wired zero | +| x1 | ra | Return address | +| x2 | sp | Stack pointer | +| x3 | gp | Global pointer | +| x4 | tp | Thread pointer | +| x5-7 | t0-2 | Temporaries | +| x8 | s0/fp | Saved register/frame pointer | +| x9 | s1 | Saved register | +| x10-11 | a0-1 | Function arguments/retrurn values | +| x12-17 | a2-7 | Function arguments | +| x18-27 | s2-11 | Saved register | +| x28-31 | t3-6 | Temporaries | + + +### 3. RISC-V 特权级寄存器 + +除了通用寄存器,RISC-V针对各个特权级,还定义了一系列特权级控制状态寄存器。本节以M模式为例介绍相关控制状态寄存器。 + +* misa:表示hart支持的架构扩展,包括整数、乘除、原子、浮点数、双精度浮点数和压缩指令扩展等 +* mhartid:当前正在执行代码的hart id +* medeleg:默认情况下,所有的异常都是在M模式下处理。当相应的medeleg位置1时,该异常直接由S模式或U模式处理。 +* mideleg:默认情况下,所有的中断都是在M模式下处理。当相应的mideleg位置1时,该中断直接由S模式或U模式处理。 +* mtime:存储当前的时钟计数值 +* mtimecmp:时钟计数比较器。当当前mtime寄存器中的值大于mtimecmp中的值时,触发时钟中断 +* mstatus:表示当前处理器的控制状态,包括全局中断使能位。内存特权级,字节序控制位等 +* mtvec:保存发生trap时处理器需要跳转到的地址 +* mip:指示正准备处理的中断类型。EIP表示外部中断,TIP表示时钟中断,SIP表示软件中断。当相应的中断位置1时,表示存在该类型中断待处理 +![](./figures/mip.png) +* mie:指示处理器目前使能和忽略的中断类型。EIP表示外部中断,TIP表示时钟中断,SIP表示软件中断。当相应的中断位置1时,表示该类型中断可以被处理器响应 +![](./figures/mie.png) +* mscratch:保存指向当前hart上下文的指针 +* mepc:保存引发异常的指令 +* mtval:它保存了trap的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身,对于其他trap,它的值为 0 +* mcause:指示发生trap的种类。当最高位为1时,低位字段表示发生中断的类型;当最高位为0时,低位字段表示发生异常或系统调用的类型。 + +| Interrupt | Exception Code | Description | +| :------ | :------ | :------ | +| 1 | 0 | Reserved | +| 1 | 1 | Supervisor software interrupt | +| 1 | 2 | Reserved | +| 1 | 3 | Machine software interrupt | +| 1 | 4 | Reserved | +| 1 | 5 | Supervisor timer interrupt | +| 1 | 6 | Reserved | +| 1 | 7 | Machine timer interrupt | +| 1 | 8 | Reserved | +| 1 | 9 | Supervisor external interrupt | +| 1 | 10 | Reserved | +| 1 | 11 | Machine external interrupt | +| 1 | 12-15 | Reserved | +| 1 | >=16 | Available for platform use | +| 0 | 0 | Instruction address misaligned | +| 0 | 1 | Instruction access fault | +| 0 | 2 | Illegal instruction | +| 0 | 3 | Breakpoint | +| 0 | 4 | Load address misaligned | +| 0 | 5 | Load access fault | +| 0 | 6 | Store/AMO address misaligned | +| 0 | 7 | Store/AMO access fault | +| 0 | 8 | Environment call from U-mode | +| 0 | 9 | Environment call from S-mode | +| 0 | 10 | Reserved | +| 0 | 11 | Environment call from M-mode | +| 0 | 12 | Instruction page fault | +| 0 | 13 | Load page fault | +| 0 | 14 | Reserved | +| 0 | 15 | Store/AMO page fault | +| 0 | 16-23 | Reserved | +| 0 | 24-31 | Available for custom use | +| 0 | 32-47 | Reserved | +| 0 | 48-63 | Available for custom use | +| 0 | >=64 | Reserved | + +### 4. RISC-V CPU初始化 + +opensbi是M模式的一种实现。本节以opensbi为例介绍M模式下的CPU初始化。在硬件超线程处理器中,一个处理器核存在多个硬件线程,单以处理器核描述一个硬件线程不太精准。RISC-V提出了hart的概念(Hardware Thread),表示一个硬件线程。opensbi可以作为一种固件为其他特权级模式的软件提供运行时服务。在机器上电后,作为加载的第一个启动阶段代码,opensbi固件需要对cpu进行初始化。 + +每一个hart都有自己的上下文状态,上下文状态的指针保存在mscratch寄存器中。opensbi首先根据平台定义的hart的数量和hart栈的大小分配栈空间,然后依次为每一个hart初始化sbi scratch结构体,包括固件在内存中的地址,下一个启动阶段要执行的代码入口地址,参数以及特权级等信息,并将sbi scratch的地址赋值给mscratch寄存器。 + +```c +/* sbi_scratch结构体定义 */ +struct sbi_scratch { + /** opensbi固件地址 */ + unsigned long fw_start; + /** opensbi固件大小 */ + unsigned long fw_size; + /** 下一个启动阶段的参数 */ + unsigned long next_arg1; + /** 下一个启动阶段代码入口 */ + unsigned long next_addr; + /** 下一个启动阶段执行特权级 */ + unsigned long next_mode; +··· +··· +} __packed; +``` + + +```c +_relocate_done: +··· +··· + /* 根据hart的数量和hart栈的大小分配栈空间 */ + la tp, _fw_end + mul a5, s7, s8 + add tp, tp, a5 + +_scratch_init: + /* 对第t1个hart进行初始化,将指针指向第t1个hart的栈空间 */ + add tp, t3, zero + mul a5, s8, t1 + sub tp, tp, a5 + li a5, SBI_SCRATCH_SIZE + sub tp, tp, a5 + + /* 初始化第t1个hart的sbi_scratch结构体 */ + /* 初始化fw_start和fw_size */ + la a4, _fw_start + la a5, _fw_end + mul t0, s7, s8 + add a5, a5, t0 + sub a5, a5, a4 + REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp) + REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp) + /* 将下一阶段传入的参数赋值给next_arg1,通常是fdt的地址 */ + MOV_3R s0, a0, s1, a1, s2, a2 + call fw_next_arg1 + REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp) + MOV_3R a0, s0, a1, s1, a2, s2 + /* 将下一阶段代码的入口地址赋值给next_addr */ + MOV_3R s0, a0, s1, a1, s2, a2 + call fw_next_addr + REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp) + MOV_3R a0, s0, a1, s1, a2, s2 + /* 将下一阶段执行特权级模式赋值给next_mode */ + MOV_3R s0, a0, s1, a1, s2, a2 + call fw_next_mode + REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp) + /* 初始化下一个hart */ + add t1, t1, t2 + blt t1, s7, _scratch_init +··· +··· +``` + +hart上下文初始化完成后,需要初始化trap。通过清空mie寄存器和mip寄存器关闭所有中断,将trap handler的地址赋值给mtvec寄存器,作为trap服务总控函数的入口地址。当系统发生中断时,将通过tvec寄存器找到trap处理函数。 + + +```c +_start_warm: + /* 清空通用寄存器 */ + li ra, 0 + call _reset_regs + + /* 关闭中断,清空mie寄存器和mip寄存器 */ + csrw CSR_MIE, zero + csrw CSR_MIP, zero +··· +··· + /* 设置trap处理函数 */ + la a4, _trap_handler + csrw CSR_MTVEC, a4 + + /* 进入启动阶段 */ + csrr a0, CSR_MSCRATCH + call sbi_init +``` + +启动hart。随机选择一个hart作为主hart。其他hart通过将mie寄存器中的MSIE位置1打开软件中断开关,并陷入WFI,等待主hart发出中断唤醒。主hart执行冷启动,进行一系列初始化,初始化完成后向其他hart发出处理器间中断以唤醒其他hart,并执行下一阶段代码。如果是目标是裸机程序,则下一段代码为用户程序代码;如果想启动内核,则下一段为内核代码,并将fdt地址作为参数传给下一段代码,进入下一阶段。 + + +```c +void __noreturn sbi_init(struct sbi_scratch *scratch) +{ + bool coldboot = FALSE; + u32 hartid = current_hartid(); +··· +··· + /* 随机选择一个hart作为主hart,执行冷启动,其他hart执行热启动 */ + if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0) + coldboot = TRUE; + + if (coldboot) + init_coldboot(scratch, hartid); + else + init_warmboot(scratch, hartid); +} + +static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) +{ + int rc; + unsigned long *init_count; + const struct sbi_platform *plat = sbi_platform_ptr(scratch); + /* 打开进程间中断开关,陷入WFI,等待冷启动结束 */ + wait_for_coldboot(scratch, hartid); +··· +··· + /* 执行下一阶段代码 */ + sbi_hsm_prepare_next_jump(scratch, hartid); + sbi_hart_switch_mode(hartid, scratch->next_arg1, + scratch->next_addr, + scratch->next_mode, FALSE); +} + +static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) +{ + int rc; + unsigned long *init_count; + const struct sbi_platform *plat = sbi_platform_ptr(scratch); + ··· + ··· + + /* 初始化终端串口 */ + rc = sbi_console_init(scratch); + if (rc) + sbi_hart_hang(); + + /* 初始化中断控制器 */ + rc = sbi_platform_irqchip_init(plat, TRUE); + if (rc) { + sbi_printf("%s: platform irqchip init failed (error %d)\n", + __func__, rc); + sbi_hart_hang(); + } + + /* 处理器间中断初始化 */ + rc = sbi_ipi_init(scratch, TRUE); + if (rc) { + sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc); + sbi_hart_hang(); + } + + /* TLB初始化 */ + rc = sbi_tlb_init(scratch, TRUE); + if (rc) { + sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc); + sbi_hart_hang(); + } + + /* 时钟初始化 */ + rc = sbi_timer_init(scratch, TRUE); + if (rc) { + sbi_printf("%s: timer init failed (error %d)\n", __func__, rc); + sbi_hart_hang(); + } + + /* 注册系统调用 */ + rc = sbi_ecall_init(); + if (rc) { + sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc); + sbi_hart_hang(); + } + + /* 物理内存保护机制配置 */ + rc = sbi_hart_pmp_configure(scratch); + if (rc) { + sbi_printf("%s: PMP configure failed (error %d)\n", + __func__, rc); + sbi_hart_hang(); + } + + /* 调整ftd内存布局 */ + rc = sbi_platform_final_init(plat, TRUE); + if (rc) { + sbi_printf("%s: platform final init failed (error %d)\n", + __func__, rc); + sbi_hart_hang(); + } + + /* 发出软件中断,唤醒其他hart */ + wake_coldboot_harts(scratch, hartid); + + /* 执行下一阶段代码 */ + init_count = sbi_scratch_offset_ptr(scratch, init_count_offset); + (*init_count)++; + sbi_hsm_prepare_next_jump(scratch, hartid); + sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr, + scratch->next_mode, FALSE); +} + +``` + + + +### 5. RISC-V 中断、异常、系统调用 + +RISC-V将trap分为两类,一类是同步trap,在指令执行期间产生,包括地址访问错误异常,断点异常,非法指令异常,非对齐地址异常和系统调用。另一类是中断。RISC-V中定义了三种标准的中断源,软件中断、时钟中断和外部中断。 + +当发生trap时,硬件会将mpec寄存器设置为触发trap的指令地址,将mcause寄存器设置为trap的来源,将mstatus寄存器的SIE位置零以禁用中断,将mtval寄存器设置为trap相关的附加信息,将pc寄存器设置为stvec寄存器中指向的trap服务总控函数的入口地址。 + +opensbi将 trap handler设置为stvec寄存器指向的trap服务总控函数入口地址。trap handler首先在异常栈上存储sp寄存器,通过改变sp寄存器的值以分配异常栈空间,然后保存通用寄存器,调用sbi trap handler处理trap,trap处理结束后恢复通用寄存器和sp寄存器。 + +```c +_trap_handler: +... +... + /* 保存sp寄存器 */ + REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0) + + /* 分配异常栈空间 */ + add sp, t0, -(SBI_TRAP_REGS_SIZE) + + /* 保存通用寄存器 */ + REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) + REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp) + REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp) + REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp) + REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp) + REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp) + REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp) + REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp) + REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp) + REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp) + REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp) + REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp) + REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp) + REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp) + REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp) + REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp) + REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp) + REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp) + REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp) + REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp) + REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp) + REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp) + REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp) + REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp) + REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp) + REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp) + REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp) + REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp) + REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp) + REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp) + + /* 调用sbi_trap_handler处理trap */ + add a0, sp, zero + call sbi_trap_handler + + /* 恢复通用寄存器 */ + REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp) + REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp) + REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp) + REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp) + REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp) + REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp) + REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp) + REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp) + REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp) + REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp) + REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp) + REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp) + REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp) + REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp) + REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp) + REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp) + REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp) + REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp) + REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp) + REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp) + REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp) + REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp) + REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp) + REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp) + REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp) + REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp) + REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp) + REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp) + REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp) + +... +... + /* 恢复sp寄存器 */ + REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp) +``` + +sbi trap handler作为trap处理服务,首先会读取mcause寄存器的最高位,判断trap类型。 + +* 当mcause寄存器的最高位为1时,此时trap类型为中断。读取mcause的Exception Code. + * 若Exception Code为7,则此时trap为时钟中断,调用时钟中断处理函数 + * 若Exception Code为3,则此时trap为软件中断,调用软件中断处理函数 +* 当mcause寄存器的最高位为0时,此时trap类型为异常或系统调用。读取mcause的Exception Code. + * 若Exception Code为2,4或者6,则此时trap为异常,调用相应的异常处理函数 + * 若Exception Code为9或11,则此时trap为系统调用,调用ecall处理函数。 + +```c +void sbi_trap_handler(struct sbi_trap_regs *regs) +{ +... +... + /** 当mcause寄存器的最高位为1时,此时trap类型为中断 **/ + if (mcause & (1UL << (__riscv_xlen - 1))) { + mcause &= ~(1UL << (__riscv_xlen - 1)); + switch (mcause) { + /** 时钟中断 **/ + case IRQ_M_TIMER: + sbi_timer_process(); + break; + /** 软件中断 **/ + case IRQ_M_SOFT: + sbi_ipi_process(); + break; + default: + msg = "unhandled external interrupt"; + goto trap_error; + }; + return; + } + + /** 当mcause寄存器的最高位为0时,此时trap类型为异常或系统调用 **/ + switch (mcause) { + /** 异常 **/ + case CAUSE_ILLEGAL_INSTRUCTION: + rc = sbi_illegal_insn_handler(mtval, regs); + msg = "illegal instruction handler failed"; + break; + case CAUSE_MISALIGNED_LOAD: + rc = sbi_misaligned_load_handler(mtval, mtval2, mtinst, regs); + msg = "misaligned load handler failed"; + break; + case CAUSE_MISALIGNED_STORE: + rc = sbi_misaligned_store_handler(mtval, mtval2, mtinst, regs); + msg = "misaligned store handler failed"; + break; + /** 系统调用 **/ + case CAUSE_SUPERVISOR_ECALL: + case CAUSE_MACHINE_ECALL: + rc = sbi_ecall_handler(regs); + msg = "ecall handler failed"; + break; + default: +... +... + break; + }; + +trap_error: + if (rc) + sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs); +} + +``` + +### 6. RISC-V 虚拟内存 + +相比于M模式,S模式提供了基于页面的虚拟内存系统,将内存划分为固定大小的页来进行地址的转换和对内存内容的保护。RISC-V的分页方案有很多种,linux kernel使用Sv39作为页表的实现。 + +Sv39模式支持39位的虚拟内存地址空间,其中第38-12位为虚拟页号,第11-0位为页内偏移,每一个页面4KB。物理内存地址为56位,其中第55-12位为物理页号。27位的虚拟页号通过三级页表映射到44位的物理页号。 + +![](./figures/img5.png) + +![](./figures/img4.png) + +Sv39模式中每一个页表项为64位。其中63-54位为保留位。53-10位为物理页号。9-0位为页状态的描述位。V表示该页表项是否有效。R,W,X为权限控制位,分别表示页的可读可写可执行权限,当R,W,X为都为0时,表示该页表项指向的是下一级页表,为非叶页表项。U表示该页是否可以被User模式访问,只有当U位为1时,User模式的软件才可以访问该页。G为为全局映射位。当G位为1且该页表项为非叶页表项时,表示该页表项所指向的下一级页表为全局可访问的。A表示Accessed,当A位为1时,表示该页表项所指向的页面自从上次A位被清零后有被访问过。D表示Dirty,当D位为1时,表示该页表项所指向的页面自从上次D位被清零后有被修改过。RSW位为预留位。 + +![](./figures/img6.png) + +每一级的页表项都可以为叶页表项。当三级页表的页表项为叶页表项时,所指向的页面大小为4KB;当二级页表的页表项为叶页表项时,所指向的页面大小为2MB;当一级页表的页表项为叶页表项时,所指向的页面大小为1GB。 + +S模式使用satp寄存器控制虚拟内存分页系统。satp有三个域。MODE可以开启分页并选择页表级数。ASID是地址空间标识符,可以用来降低上下文切换的开销。PPN字段保存了页表的基址地址。 + +![](./figures/satp.png) + +当在satp寄存器中启用了分页时,S 模式和 U 模式中的虚拟地址会以从根部遍历页表 的方式转换为物理地址。 + +1. satp.PPN 给出了一级页表的基址,VA[31:22]给出了一级页号,因此处理器会读取 位于地址(satp. PPN × 4096 + VA[31: 22] × 4)的页表项。 +2. 该PTE包含二级页表的基址,VA[21:12]给出了二级页号,因此处理器读取位于地址(PTE. PPN × 4096 + VA[21: 12] × 4)的叶节点页表项。 +3. 叶节点页表项的PPN字段和页内偏移(原始虚址的最低12个有效位)组成了最终结果:物理地址就是(LeafPTE. PPN × 4096 + VA[11: 0]) + +![](./figures/img3.png) + + +linux kernel使用Sv39作为页表的实现。当内核开启了MMU选项时,会读取已经分配好的页表数组的物理地址,并将其作为参数传入relocate函数。relocate函数中首先会获取页表数组的物理页号,与SATP MODE39拼接在一起赋值给satp寄存器。在CPU内部,使用TLB来作为虚拟页号到物理页号映射的缓存。当修改了satp寄存器时,TLB中的将失效。S模式使用sfence.vma解决这个问题,会通知处理器,软件可能已经修改了页表,于是处理器可以相应地刷新转换缓存。在赋值satp寄存器后,使用sfence.vma刷新TLB。 + + +```c +#define PAGE_SHIFT (12) +#define SATP_MODE_39 _AC(0x8000000000000000, UL) +#define SATP_MODE SATP_MODE_39 + +#ifdef CONFIG_MMU + /* 使能虚拟内存并重新分配虚拟地址并重新分配虚拟地址 */ + /* swapper_pg_dir为页表基地址 */ + la a0, swapper_pg_dir + call relocate +#endif + +.align 2 +#ifdef CONFIG_MMU +relocate: + /* 重新分配返回地址 */ + li a1, PAGE_OFFSET + la a2, _start + sub a1, a1, a2 + add ra, ra, a1 + + /* 计算satp寄存器的值 */ + srl a2, a0, PAGE_SHIFT + li a1, SATP_MODE + or a2, a2, a1 +··· +··· + /* 设置satp寄存器的值并刷新TLB */ + csrw CSR_SATP, a2 + sfence.vma +``` + +### 7. 参考文献 + +1. [RISC-V spec](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf) +2. [RISC-V privileged spec](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf) +3. [RISC-V-Reader-Chinese](http://riscvbook.com/chinese/RISC-V-Reader-Chinese-v2p1.pdf) diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img1.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img1.png new file mode 100644 index 0000000000000000000000000000000000000000..371ff0407c364544cc188e7e7bbccf31520f9945 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img1.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img2.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img2.png new file mode 100644 index 0000000000000000000000000000000000000000..999a2cf98f7c47f91ddaffe7152a38e5309222a4 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img2.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img3.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img3.png new file mode 100644 index 0000000000000000000000000000000000000000..7ae1d35b0adde096fecd7e2e91d99fe004d54f96 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img3.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img4.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img4.png new file mode 100644 index 0000000000000000000000000000000000000000..910b0c0339eccf5b5a2ab58157cfe8a6b2f47e61 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img4.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img5.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img5.png new file mode 100644 index 0000000000000000000000000000000000000000..4f309b8ef8590f7ea3df62478d3fffdbe0721b4f Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img5.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img6.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img6.png new file mode 100644 index 0000000000000000000000000000000000000000..50b8fd46a38bbfca3f82a1630744cd43b62f2ec4 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/img6.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mie.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mie.png new file mode 100644 index 0000000000000000000000000000000000000000..752a0b9c7284da7ea59b464a9e51a33e29835ba4 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mie.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mip.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mip.png new file mode 100644 index 0000000000000000000000000000000000000000..add3a03d373e0c5548d49a8f8e7bbae3a3ab9d7d Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/mip.png differ diff --git a/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/satp.png b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/satp.png new file mode 100644 index 0000000000000000000000000000000000000000..84a303ece628dd14cf52d018cf07753ff1ecdf20 Binary files /dev/null and b/web-ui/docs/zh/blog/zhangxinhao/risc-v/figures/satp.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-01.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-01.png new file mode 100644 index 0000000000000000000000000000000000000000..bf44920abcb46f376c91be1d7b88cacdc4570f87 Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-01.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-02.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-02.png new file mode 100644 index 0000000000000000000000000000000000000000..66d1df8c3a8ff331ea196e2a08a262f72ca21d91 Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-02.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-03.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-03.png new file mode 100644 index 0000000000000000000000000000000000000000..82856947b3d257b455e26a53dd87561f61071c18 Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-03.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-04.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-04.png new file mode 100644 index 0000000000000000000000000000000000000000..37e1d572a5cba29fe3c61abd5d14ea7e14b4ad54 Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-04.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-05.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-05.png new file mode 100644 index 0000000000000000000000000000000000000000..2e09265e6a71ef394862250ad6d4c26b0912c6c6 Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-05.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-06.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-06.png new file mode 100644 index 0000000000000000000000000000000000000000..439a5473a85db7420f0423e72a5d9c61f954efbc Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-06.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-07.png b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-07.png new file mode 100644 index 0000000000000000000000000000000000000000..cf6b239d1887abd5a447a7b6deec74553d1e9dfa Binary files /dev/null and b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild-07.png differ diff --git a/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild.md b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild.md new file mode 100644 index 0000000000000000000000000000000000000000..ddc2b9e026c53b97b86ea8a3557726b2e4c9f719 --- /dev/null +++ b/web-ui/docs/zh/blog/zhengyaohui/2022-03-21-ci_guild.md @@ -0,0 +1,200 @@ +--- +title: 门禁功能指导手册 +date: 2022-03-21 +tags: + - 门禁 + - openeuler + - src-openeuler +sig: sig-Gatekeeper +archives: 2022-03 +author: zhengyaohui +summary: 介绍openeuler门禁功能,帮助openeuler社区贡献者高效提交代码。 +--- + +# 一、门禁功能介绍 + +## 1. 门禁功能 + +openEuler社区代码均托管在gitee上,为了保证代码提交质量,开发者在gitee提交PR时,会自动触发门禁执行编码规范检查、构建、安装、接口变更等检查,最后将门禁检查结果返回到PR评论中,帮助开发者定位问题及maintainer检视代码。 + +门禁代码开源https://gitee.com/openeuler/openeuler-jenkins。 + +## 2. src-openeuler门禁检查项 + +### 2.1 门禁触发方式 + +首次提交PR,或评论/retest + + + +### 2.2 门禁开始运行标志 + + + +开发者可通过链接查看实时门禁构建日志。 + +### 2.3 门禁检查结果 + +
基本检查项
+ + + +
接口变更检查
+ + + +门禁基本检查项包括6项,如表1所示。接口变更检查因为子项较多,单独以一个表格显示。 + +### 2.4 检查项对应门禁代码位置 + +| 检查项 | 功能描述 | 主要代码位置 | +| ----------------------- | ------------------------ | ------------------------------------------------------------ | +| check_binary_file | 二进制文件检查 | [check_binary_file.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/binary/check_binary_file.py) | +| check_package_license | license合法性检查 | [check_spec.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/spec/check_spec.py)、[Licenses.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_license/config/Licenses.yaml) | +| check_package_yaml_file | yaml文件格式检查 | [check_yaml.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_yaml/check_yaml.py)、[check_repo.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/package_yaml/check_repo.py) | +| check_spec_file | spec文件格式检查 | [check_spec.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/spec/check_spec.py) | +| check_build | 包构建 | [osc_build_k8s.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/osc_build_k8s.py)、 | +| check_install | 验证构建出的包能否安装 | [extra_work.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/extra_work.py) | +| compare_package | x86-64环境下接口变更检查 | [compare_package.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/utils/compare_package.py) | + +此外,门禁目前支持部分检查项(check_code_style、check_package_license、check_package_yaml_file和check_spec_file)的选择性配置,配置文件位于[ac.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/framework/ac.yaml)。负责检查项PR回显的代码位于[gitee_comment.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/gitee_comment.py) + +### 2.5 基本检查项功能描述 + +| 检查项 | 功能 | SUCCESS | FAILED | WARNING | +| ----------------------- | ---------------------------- | ------------------------------------------------------------ | ------------------- | ----------------------------------------------- | +| check_binary_file | 检查仓库中是否存在二进制文件 | 不存在以.pyc、.jar、.ko、.o为后缀的文件(包括压缩包内,但不包括以链接形式给出的上游社区) | 不符合SUCCESS的情况 | 不涉及 | +| check_package_license | 检查license合法性 | 全部为白名单,并且源码和spec描述的license保持一致 | 存在黑名单license | 全部为白名单,但是源码和spec描述的license不一致 | +| check_package_yaml_file | 检查yaml格式 | version_control、src_repo、tag_prefix、seperator字段完整,并且version_control字段内容与spec文件中url对应的域名一致 | 不符合SUCCESS的情况 | 不涉及 | +| check_spec_file | 检查sepc合法性 | 版本号不变时,release号必须递增;版本号变化时,release必须置为1;补丁在编译时必须全部应用;changelog格式正确 | 不符合SUCCESS的情况 | 不涉及 | +| check_build | 验证编译 | 构建rpm包成功 | 不符合SUCCESS的情况 | 不涉及 | +| check_install | 验证安装 | 成功安装构建出的rpm包 | 不符合SUCCESS的情况 | 不涉及 | + +### 2.6 接口变更检查各检查项功能描述 + +| 检查项 | 功能 | SUCCESS | FAILED | WARNING | +| ------------ | ------------------------------------------- | ------------------------------------------------------------ | ------------------- | ------- | +| add_rpms | 检查PR是否新增rpm包 | 相比于同分支上一个成功合入pr,无新增rpm包 | 不符合SUCCESS的情况 | 不涉及 | +| delete_rpms | 检查pr是否删除rpm包 | 相比于同分支上一个成功合入pr,无删除rpm包 | 不符合SUCCESS的情况 | 不涉及 | +| rpm_files | 检查pr生成的rpm包是否新增或者删除文件 | 相比于同分支上一个成功合入pr,每个rpm的文件列表无增减(不检查文件变化) | 不符合SUCCESS的情况 | 不涉及 | +| rpm_provides | 检查pr生成的rpm包提供的组件名,是否变化组件 | 相比于同分支上一个成功合入pr,每个rpm提供的组件名称无变化 | 不符合SUCCESS的情况 | 不涉及 | +| rpm_requires | 检查pr生成的rpm包依赖组件名是否变化 | 相比于同分支上一个成功合入pr,每个rpm依赖的组件名称无变化 | 不符合SUCCESS的情况 | 不涉及 | +| check_abi | 检查pr生成的rpm包二进制接口是否变化(C++) | 相比于同分支上一个成功合入pr,每个rpm的二进制接口无变化 | 不符合SUCCESS的情况 | 不涉及 | +| check_jabi | 检查pr生成的rpm包二进制接口是否变化(java) | 相比于同分支上一个成功合入pr,每个rpm的二进制接口无变化 | 不符合SUCCESS的情况 | 不涉及 | +| check_kabi | 检查pr生成的rpm包二进制接口是否变化(内核) | 相比于同分支上一个成功合入pr,每个rpm的二进制接口无变化 | 不符合SUCCESS的情况 | 不涉及 | + +## 3 openeuler门禁检查项 + +### 3.1 门禁检查项PR回显 + + + +### 3.2 检查项对应门禁代码位置 + +| 检查项 | 功能描述 | 主要代码位置 | +| -------------- | ------------------------------- | ------------------------------------------------------------ | +| check_code | 编码规范检查 | [check_code.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/openlibing/check_code.py) | +| check_sca | 代码片段扫描 | [check_sca.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/acl/sca/check_sca.py) | +| x86-64/仓库名 | x86-64环境下包构建及构建后检查 | 维护者自行实现,不属于门禁代码 | +| aarch64/仓库名 | aarch64环境下包构建及构建后检查 | 同上 | + +此外,门禁支持检查项check_openlibing和check_sca的选择性配置,配置文件位于[ac.yaml](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/ac/framework/ac.yaml)。负责检查项PR回显的代码位于[gitee_comment.py](https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/build/gitee_comment.py) + +当前check_openlibing是调用远端服务(https://majun.osinfra.cn:8384/api/openlibing/codecheck)实现的;check_sca则是调用远端服务(https://sca-beta.osinafra.cn)实现的。 + +# 二、 门禁结果答疑&&误报反馈 + +## 1. 门禁责任田划分 + +| 责任田 | 责任人 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| 门禁总接口人 | [郑耀辉](https://gitee.com/open_euler/dashboard/members/zhengyaohui) | +| community仓库维护人员 | [曹志](https://gitee.com/open_euler/dashboard/members/georgecao), [刘奇 ](https://gitee.com/open_euler/dashboard/members/liuqi469227928), [赵春江](https://e.gitee.com/open_euler/members/trend/dakang_siji) | +| obs_meta仓库维护人员 | [董杰](https://e.gitee.com/open_euler/members/trend/dongjie110) | +| release_management仓库维护人员 | [董杰](https://e.gitee.com/open_euler/members/trend/dongjie110) | +| 软件包单仓门禁维护人员 | [王欢](https://e.gitee.com/open_euler/members/trend/wanghuan158), [程少巍](https://e.gitee.com/open_euler/members/trend/MementoMoriCheng), [郑耀辉](https://gitee.com/open_euler/dashboard/members/zhengyaohui) | +| 基础设施维护(包括obs、gitee、jenkins基础服务,也包括硬件和网络)人员 | [曹志](https://gitee.com/open_euler/dashboard/members/georgecao), [刘奇 ](https://gitee.com/open_euler/dashboard/members/liuqi469227928), [赵春江](https://e.gitee.com/open_euler/members/trend/dakang_siji) | +| obs工程维护人员 | [王冲](https://gitee.com/open_euler/dashboard/members/wangchong1995924), [夏森林](https://e.gitee.com/open_euler/members/trend/small_leek), [周夏香](https://e.gitee.com/open_euler/members/trend/zhouxiaxiang) | +| majun维护人员 | 张亚雄(openlibing@163.com) | + +注:1. 软件包单仓门禁中的代码片段扫描(check_sca)和编码规范检查(check_code)是通过调用majun平台服务实现的 + +2. 软件包单仓门禁维护人员是作为openeuler以及src-openeuler单仓门禁接口人,单仓门禁问题都可以找他们;如果是obs或者是基础设施服务问题,则需要再联系相应的维护人员。常见问题及解决方案可参考[门禁问题排查手册](https://gitee.com/openeuler/openeuler-jenkins/blob/master/doc/%E9%97%A8%E7%A6%81%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%89%8B%E5%86%8C.md)。 + +## 2. 门禁结果 + +如果对门禁结果有疑问或者认为门禁结果不准确,可以向相关负责人反馈问题,我们会尽快解决,无法短时间解决的可以向门禁仓库[https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins)提issue跟踪进展。之后,您可以通过pr评论反馈门禁误报情况,这些统计数据便于我们以后能做得更好。 + +标记误报的评论格式为:/ci_unmistake build_no或者/ci_mistake build_no + +注: + +1. ci_mistake用于标记误报,ci_unmistake用于撤回标记,必选其一 +2. build_no指的是trigger工程的构建号,门禁开始执行时会在评论中打印门禁任务链接及构建号,由于同一个pr可以有多次构建结果,因此通过构建号区分。必选参数 +3. mistake_type表示误报类型。可选参数,可以选择ci,obs,infra或者不填,这里将误报结果划分为门禁本身,obs以及基础设施三类 +4. ci_mistake_stage表示误报阶段。可选参数,check_binary_file, check_package_license, check_package_yaml_file, check_spec_file, check_build, check_install, compare_package, build_exception选一项或多项,也可不填,除build_exception外均与门禁检查项一一对应,而build_exception表示门禁运行异常(如门禁结果不返回)。 +5. mistake_type和ci_mistake_stage的填写顺序没有要求,可以调换 + +# 三、门禁代码上线流程 + +依次包括3个步骤:向门禁代码仓提交并合入PR(找maintainer);为此次提交生成tag(找maintainer);更新容器镜像(找门禁看护人员[王欢](https://e.gitee.com/open_euler/members/trend/wanghuan158), [程少巍](https://e.gitee.com/open_euler/members/trend/MementoMoriCheng), [郑耀辉](https://gitee.com/open_euler/dashboard/members/zhengyaohui))。少数情况下需要门禁看护人员修改jenkins配置。 + +## 1. 提交并合入PR + +门禁代码放在[https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins),找maintainer合入代码。 + +## 2. 生成tag + +理论上每次提交,均可以生成tag(tag相比于commit号,更易读);一般情况下,不是每个PR合入都是需要立即上线的,因此不必每个commit均生成一个tag。 + + + +## 3. 生成容器镜像 + +目前门禁代码机器环境已经放到了容器镜像中,因此每次更新门禁代码时均需要更新容器镜像代码才能生效,镜像版本通过tag区分。 + + + +# 四、运行节点定制 + +## 1. 当前节点/镜像列表 + + + +下表列出了与门禁相关的节点: + +| 节点 | 工程 | +| ------------------------------------------------------------ | -------------------------------------- | +| k8s-x86-soe和k8s-aarch64-soe | src-openeuler全部门禁工程 | +| k8s-x86-oe | openeuler中trigger和comment工程 | +| **k8s-x86-openeuler、k8s-x86-openeuler-20.03-lts、k8s-x86-openeuler-20.03-lts-sp1、k8s-x86-openeuler-20.03-lts-sp2、k8s-x86-openeuler-20.03-lts-sp3、k8s-x86-openeuler-20.09、k8s-x86-openeuler-21.03、k8s-aarch64-openeuler、k8s-aarch64-openeuler-20.03-lts、k8s-aarch64-openeuler-20.03-lts-sp1、k8s-aarch64-openeuler-20.03-lts-sp2、k8s-aarch64-openeuler-20.03-lts-sp3、k8s-aarch64-openeuler-20.09、k8s-aarch64-openeuler-21.03** | **openeuler中x86-64和aarch64构建工程** | + +注:1. 当前src-openeuler全部门禁工程、openeuler中trigger和comment工程,全部代码有门禁侧统一配置,使用环境相同,因此节点固定 + +2.openeuler中x86-64和aarch64构建工程执行的代码是相关sig组自行管理的,使用的环境各不相同,节点可在**加粗部分**自由选择,请不要使用其他节点,以免干扰其他jenkins任务的功能 + + + +## 2. 节点定制 + +部分任务可能需要定制门禁运行节点。 + +### 2.1 基础镜像缺乏依赖包,运行时安装比较耗时 + +门禁提供的容器环境是可以在运行时安装依赖包的,因此少量依赖包建议直接在运行脚本中使用sudo yum install -y xxx安装。当缺乏的依赖包比较多时,则建议向门禁仓库[https://gitee.com/openeuler/openeuler-jenkins](https://gitee.com/openeuler/openeuler-jenkins)提交一个dockfile,由门禁侧检视合入后重新制作镜像,并创建一个新的运行节点。 + +dockerfile格式可参考https://gitee.com/openeuler/openeuler-jenkins/blob/master/src/dockerfile/release-tools-dockerfile,通常只需要修改前两条语句即可: + +``` +FROM swr.cn-north-4.myhuaweicloud.com/openeuler/openjdk/OPENJDK:TAG +RUN set -eux; \ + yum install -y python3-pip cpio bsdtar expect openssh sudo vim git strace python-jenkins python3-requests python-concurrent-log-handler python3-gevent python3-marshmallow python3-pyyaml python-pandas python-xlrd python-retrying python-esdk-obs-python git +``` + +### 2.2 基础镜像版本不是openeuler + +此时除了编写dockerfile外,还需要提供对应版本的基础镜像。 + +### 2.3 机器架构不符合要求 + +在前面的基础上还需要额外提供对应架构的机器,然后完成步骤2.2和2.1,此时门禁代码需要做适配。 diff --git a/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2-01.png b/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2-01.png new file mode 100644 index 0000000000000000000000000000000000000000..0ecdde1688d687e45f25e52de5adcf966f4c23d2 Binary files /dev/null and b/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2-01.png differ diff --git a/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2.md b/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2.md new file mode 100644 index 0000000000000000000000000000000000000000..be2f2ac71705fb2c68a6199fd82fdae6f6dcea05 --- /dev/null +++ b/web-ui/docs/zh/blog/zhongjun2/2020-05-07-os-metrics-2.md @@ -0,0 +1,82 @@ +--- +title: 浅谈openEuler开源社区运营度量分析系统选型 +date: 2020-05-07 +tags: + - 社区运营 + - 度量 +archives: 2020-05 +author: zhongjun +summary: 浅谈openEuler开源社区运营度量分析系统选型,属于系列博客的第二篇。 +--- + + +## 背景 + +openEuler开源社区建立后,我们采取了一系列的运营措施,可是如何知道这些运营措施是有效的,如何才能知道哪些措施更优呢,如何判断一次运营活动真正带来了多少用户呢?为了解决这一系列问题,我们试图搭建一个运营度量分析系统,用数字去量化这些指标。 + +## 如何选型 + +通常选型方法是4看3定,看业界、看友商、看客户、看自己,定方案、定策略、定计划。根据这个思路,我们先来看看当前业界主流的社区用了哪些运营系统: + +### 看业界 + +|社区/基金会 |系统 |连接 | +| ------------ | ------------ | ------------ | +|CNCF |[devstats](https://github.com/cncf/devstats) |https://github.com/cncf/devstats | +|开源数据统计 |[chaoss](https://github.com/chaoss/grimoirelab) |https://github.com/chaoss/grimoirelab | +|OpenStack |[stackalytics](https://opendev.org/x/stackalytics) |https://opendev.org/x/stackalytics | +|Apache |[kibble](https://github.com/apache/kibble) |https://github.com/apache/kibble | + +横向对比了一下各个系统的实现、生态、能力等指标,详见下图 + + +| |OpenStack stackalytics|CNCF devstate|Chaoss Grimoirelab|Apache kibble| +| ------------ | ------------ | ------------ | ------------ | ------------ | +|生态 |少(4个) |少(2个) Git github|多 10+ |一般 | +|数据库 | Memcached|PostgresSQL|ElasticSearch|ElasticSearch +|界面|Dashboard自定义|Grafana|Kibiter(kibana增强)|Kibble UI +|分析能力|把需要分析的数据配置到yaml文件中|弱|一般(借助elasticsearch自身算法)|一般 +|是否支持Gitee|否|否|否|否 +|数据类型|Key/value|时序|日志文本|日志文本 +|是否支持企业用户映射|否(仅以domain区分)|是(companies.yaml)|是(sortinghat)|否 +|获取数据工具|Stackalytics.processor|sh脚本调用cli/API命令收集|Perceval 程序调用API或者CLI命令获取日志或API返回信息|Kibble-scanners +|语言|python|sh|python|Python +|数据结构定义|[schema.py](https://opendev.org/x/stackalytics/src/branch/master/stackalytics/processor/schema.py)|[Structure.sql](https://github.com/cncf/devstats/blob/master/structure.sql)文件中定义|[grimoirelab-elk](https://github.com/chaoss/grimoirelab-elk)工程中定义raw(原始数据)和enrich(处理后的结构化数据)的mapping| + +### 看自己 + +再看看我们自身的需要的数据: + +|数据类型|详细| +| ------------ | ------------ | +|git|git提交日志数据 | +|Gitee|1.Gitee issue数据 2.Gitee pull request数据 3.repo数据 4.评论数据 5.事件数据 6.clone review来源数据等| +|Download|1.下载iso数据 2.下载rpm源数据 | +|maillist|1.message数据(个数、内容、收发发件信息等) 2.用户注册数据等| +|SIG|组织用户数据| +|网站|1.访问量数据 2.访问访客数据 3.搜索词 4.来源网站 5.入口页面 6.受访页面等 | +|容器服务|1.基础服务数据 2.容器pod日志数据等| + + +根据这些数据我们期望得到基本的用户模型(详见上一篇[文章](https://www.openeuler.org/zh/blog/2020/05/06/2020-05-06-os-metrics-1.html)提到的人、组织的度量框架),或者更深入的用户轨迹行为分析,数据挖掘等。 +我们自身的主要代码仓库托管在Gitee数据库下面,以上的方案都不能支持我们对数据运营的诉求。我们有同事试图在Chaoss上提供Gitee的[backend](https://github.com/chaoss/grimoirelab-perceval/pull/645)让Chaoss支持Gitee生态,chaoss方表示不是很愿意维护。 + +上面的方案进行了简单的数据统计以及简单的数据加权计算统计,对于我们需求的80%的数据不支持,也就没有对这些数据的一些分析处理的逻辑参考。 + +因此我们初步通过借鉴上面方案的python部分框架,按照我们自己的数据处理及分析逻辑编写自己的轻量级数据收集及分析、建模程序。 + +## 初定方案 + + + + +当前我们将原始的数据git、Gitee、maillist等通过api或者日志的方式,以backend的形式接入om-collect服务。K8 pod日志通过Fluentd收集日志数据,里面包括了所有pod的服务访问日志、服务运行日志等等全量的日志。 + +考虑到Elasticsearch服务在大数据场景下搜索的速度,深度搜索会导致Elasticsearch内部产生副本数过多占用内存空间过大等导致Elasticsearch集群索引变成red不可用的状态,或者Elasticsearch集群挂掉的状态。我们对数据都做了一个备份,备份到OBS对象存储服务上。 + +Identity服务用以做company用户与社区用户的映射关系。CSS是华为云的云搜索服务,将原始的日志数据存储到CSS中。再将数据字段解析出来保存到CSS云搜索服务,这时候的数据就带了基础的索引字段,根据日志解析的最原始的字段。Grafana可以取CSS Enrich里面的数据直接显示一些用户的基本信息,比如用户名、用户贡献的issue个数、pull request个数等。当前也是只做到基本信息的展示。 + +数据建模分析程序会对原始字段进行建模,比如将用户按照时间分类,分析用户的行为轨迹,哪一类用户更关注哪一类的topic信息等。为后期的运营策略提供数据支持。 + +## 结束语 +我们当前只做到基本的数据采集及显示部分,根据这些数据能得到一些基本的分析结果(详见下一章openeuler运营系统发现的用户习惯》),到更复杂的数据建模与分析还没开始,欢迎大家贡献更好的思路到[社区](https://gitee.com/opensourceway),有对度量分析系统的诉求也可以往[社区issue](https://gitee.com/opensourceway/om-collections)上提。 diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration.md b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration.md new file mode 100644 index 0000000000000000000000000000000000000000..ad62f2e4218a72902ab35b892695df7eebbbbc2e --- /dev/null +++ b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration.md @@ -0,0 +1,288 @@ +--- +title: 小白虚拟化之虚拟机热迁移 +date: 2020-08-28 +tags: + - 热迁移操作 + - 配置nfs +archives: 2020-08 +author: zhuhuankai +summary: 热迁移操作 +--- + +# 小白虚拟化之虚拟机热迁移 + +​ 在了解过虚拟机最基本的操作流程之后,我们终于把一只脚踏进了openEuler虚拟化的大门了。不过虚拟化的世界还有很多精彩的内容等待着我们去探索。比如这个乍一听就非常高大上的技术——虚拟机热迁移! + +## Why-为什么要有热迁移 + +​ 在学习使用这个技术之前,我们先来一起了解一下,为什么要有这个技术,它的作用又是什么?我们都知道虚拟机运行在物理机之上,而物理机会遇到负载过重、硬件更换、软件升级、组网调整和故障处理等情况。此时,既要完成这些操作,又要保证虚拟机保持正常的运行,我们就需要用到虚拟机热迁移的技术了。 + +## What-热迁移是什么意思 + +​ 虚拟机热迁移又称作虚拟机动态迁移,一般指将整个虚拟机运行状态完整保留,在其他不同的硬件平台上快速恢复的技术。在其他硬件平台上恢复后,虚拟机运行平滑如初,用户不会感受任何差异。相对的还有虚拟机冷迁移也叫静态迁移,但这种技术需要关闭虚拟机,在这里我们就不多提了。 + +虚拟机的迁移就是数据的迁移。数据又分为两种形式: + +1. 静态数据,指的是镜像文件。 + +2. 动态数据,虚拟机运行时存在内存里的动态变化的数据。 + +## When-什么时候需要用到热迁移 + +场景1:当物理服务器的硬件设备需要更新升级或者增加设备的时候,虚拟机不能停止运行,对于用户的重要业务在上面运行。(硬件更新) + +场景2:当物理服务器软件系统需要打补丁或者更新版本。(软件更新) + +场景3:当某些物理服务器负载过重或者故障的时候,需要把虚拟机迁移出去。(负载 + +过重,故障) + +场景4:在跨域环境下,多数物理服务器负载过轻,虚拟机做迁移整合,可以减少物理机器的数量,提要资源利用率。(整合资源) + +更多场景可以查看社区文档哟。 + +## Where-热迁移用在什么地方 + +​ 从上面可以看出,热迁移技术是用在不同的硬件平台上的。这里需要注意的是,虚拟机迁移的存储方式分为共享存储和非共享存储两种。 + +​ 共享存储就是虚拟机的数据存在共享磁盘上,这样迁移的时候只需要完成内存数据的迁移即可。 + +​ 非共享存储就是虚拟机的数据存在本地磁盘上,这样迁移的时候就需要把镜像文件和内存数据同时迁移。 + +## How-使用方法 + +简要思路 +-------- + +![](./2020-08-28-vm-migration01.png) + +环境准备 +-------- + +重要的环节到了。我们找了两个物理机分别作为源端和目的端来简单演示虚拟机热迁移的方法。 + +两个物理机的基本信息: + +源端ip 9.13.165.221 + +版本信息: + +![](./2020-08-28-vm-migration02.png) + +目的端ip 9.13.7.124 + +版本信息: + +![](./2020-08-28-vm-migration03.png) + +热迁移前的必要检查: + +### 1.权限检查 + +> 检查一下当前用户有无权限执行热迁移。 + +### 2.网络检查 + +> 检查一下源端和目的端主机之间的网络是互通的,并保证两个主机在相同网段,否则虚拟机迁移后悔出现网络异常。 +> +> ![](./2020-08-28-vm-migration04.png) + +### 3.检查存储资源 + +> 检查两端是否可以访问相同的存储资源。 + +对两端进行必要的健康检查,并确保目的端主机有足够的CPU、内存和存储资源。 + +### 4.检查cpu资源 + +> Cpu检查: 可以看到两个主机都有96个cpu。 +> +> ![](./2020-08-28-vm-migration05.png) +> +> ![](./2020-08-28-vm-migration06.png) +> +> 内存检查: +> +> ![](./2020-08-28-vm-migration07.png) +> +> ![](./2020-08-28-vm-migration08.png) +> +> 存储检查: +> +> ![](./2020-08-28-vm-migration09.png) +> +> ![](./2020-08-28-vm-migration10.png) + +### 5.检查虚拟机状态 + +> 检查被迁移的虚拟机是否是 running 状态。 +> +> 我们以vm11作为被热迁移的例子 +> +> ![](./2020-08-28-vm-migration11.png) + +### 6.设置热迁移参数(可选) + +> 比如设置虚拟机热迁移过程中能够容忍的最大停机时间 +> +> 使用 +> ```shell +> virsh migrate-setmaxdowntime vm11 500 +> ``` +> 设置名为vm11的虚拟机最大停机时间为500ms,之后使用virsh migrate-getmaxdowntime vm11命令来查看名为vm11的虚拟机最大停机时间。 +> +> ![](./2020-08-28-vm-migration12.png) +> +> 设置虚拟机热迁移过程中的最大带宽 +> +> 使用 +> +> ```shell +> virsh migrate-setspeed vm11 --bandwidth 1000 +> ``` +> 设置名为vm11的虚拟机热迁移带宽为500Mbps,之后使用virsh migrate-getspeed vm11命令来查看名为vm11的虚拟机热迁移过程中的最大带宽。 +> +> ![](./2020-08-28-vm-migration13.png) + +1. 是共享存储还是非共享存储 + +> ![](./2020-08-28-vm-migration14.png) +> +> 再通过查询sdb的存储方式,我们知道这个是非共享存储方式。但是我们可以通过配置nfs,来使得两个主机共享这个目录。 + +配置nfs +------------------- + +我们顺便提一下如何配置nfs: + +一、yum 安装(以下操作是对源端进行的操作) + +>```shell +>yum -y install nfs-utils rpcbind +>``` +> +> nfs 的配置文件 /etc/exports +> +> 默认为空 +>```shell +> vi /etc/exports +>``` +> \#注意下面的9.13.7.124指的是目的端的ip网段 下面这段配置全部写在exports里 +> +> /data 9.13.7.124(rw,no\_root\_squash,no\_all\_squash,sync,anonuid=501,anongid=501) +> +> 我们要共享的目录是/home/migrate-test 也就是思路中所说的/data +> +> 注:配置文件说明: +> +> /data 为共享目录 +> +> 9.13.7.124 可以为一个网段,一个IP,也可以是域名,域名支持通配符 如: \*.abc.com +> +> rw:read-write,可读写; +> +> ro:read-only,只读; +> +> sync:文件同时写入硬盘和内存; +> +> async:文件暂存于内存,而不是直接写入内存; +> +> no\_root\_squash:NFS客户端连接服务端时如果使用的是root的话,那么对服务端分享的目录来说,也拥有root权限。显然开启这项是不安全的。 +> +> root\_squash:NFS客户端连接服务端时如果使用的是root的话,那么对服务端分享的目录来说,拥有匿名用户权限,通常他将使用nobody或nfsnobody身份; +> +> all\_squash:不论NFS客户端连接服务端时使用什么用户,对服务端分享的目录来说都是拥有匿名用户权限; +> +> anonuid:匿名用户的UID值,可以在此处自行设定。 +> +> anongid:匿名用户的GID值。 +> +> 二、使配置生效 +> +>```shell +>exportfs –r +>``` +> +> 如果要取消: +> +> exportfs -u 9.13.7.124:/data 取消对特定IP和网段共享某本地目录 +> +> 三、启动 nfs +> +>```shell +>systemctl start rpcbind +> +>systemctl start nfs +>``` +> +> 查询nfs状态 +>```shell +>systemctl status nfs +>``` +> ![](./2020-08-28-vm-migration15.png) +> +> 查询rpcbind状态 +>```shell +>systemctl status rpcbind +>``` +> ![](./2020-08-28-vm-migration16.png) +> +> Note: +> +> 切记检查下iptables 设置 以及 nfs路径的权限! +> +> \#清空iptables 规则 +> +>```shell +>iptables -F +> +>iptables -X +> +>chmod -R 755 /data +>``` +> +> +> 四、目的端挂载:(以下操作是对目的端进行的操作) +> +>```shell +>showmount -e 9.13.165.221 +>``` +> +> ![](./2020-08-28-vm-migration17.png) +> +> mkdir /data(data指的是目的端要被挂载的目录哟) +> +>```shell +>mount -t nfs 9.13.165.221:/data /data +>``` +> +> 这里的例子是: +>```shell +>mount -t nfs 9.13.165.221: /home/migrate-test /home/migrate-test +>``` +> +> 使用命令:df –h 检查是否成功 +> +> 除了nfs,还有其他方式可以配置共享存储,这里就不一一介绍了,等待大家去探索。 + +热迁移操作 +---------- + +> 最后使用virsh migrate --live --unsafe vm11 qemu+ssh://9.13.7.124/system tcp://9.13.7.124进行热迁移。 + +如果使用非共享存储 + +> 我们需要在xml配置中找到镜像目录。 +> +> ![](./2020-08-28-vm-migration18.png) +> +> 执行热迁移之前需要在目的端主机相同磁盘目录下创建一个虚拟磁盘文件,注意磁盘的格式和大小必须保持一致。 +> +>```shell +> qemu-img create -f qcow2 /home/data1 /openEuler011.qcow2 40G +>``` +> 使用下面这个命令来进行热迁移 +> +>```shell +> virsh migrate --live --unsafe --copy-storage-all --migrate-disks sda \\vm11 qemu+ssh://9.13.7.124 /system tcp://9.13.7.124 +> ``` diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration01.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration01.png new file mode 100644 index 0000000000000000000000000000000000000000..f374653395ddbd9393af2b286e7597437fcdfe65 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration01.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration02.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration02.png new file mode 100644 index 0000000000000000000000000000000000000000..72160be88912ecce2a97b34d16807d97d2072045 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration02.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration03.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration03.png new file mode 100644 index 0000000000000000000000000000000000000000..75a31040b96c1be7e3a9af734c79ed4e8e2e8937 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration03.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration04.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration04.png new file mode 100644 index 0000000000000000000000000000000000000000..f6cab3c2c3cd2ca38d54a04e7b60e3ceef218b9b Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration04.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration05.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration05.png new file mode 100644 index 0000000000000000000000000000000000000000..95c9cb04319b608b80732ffad46a7f0d784dfa0c Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration05.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration06.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration06.png new file mode 100644 index 0000000000000000000000000000000000000000..e316e1248e95fc7d5bf26b618f6337a311d5ba68 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration06.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration07.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration07.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb73a0fc3cf50510e4060e9226061f25ef2e641 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration07.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration08.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration08.png new file mode 100644 index 0000000000000000000000000000000000000000..3a89fdb32156d1fe4d759c7ae620aab144a20963 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration08.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration09.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration09.png new file mode 100644 index 0000000000000000000000000000000000000000..7a4c07f33b25eae685141beade472d4a99124435 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration09.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration10.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration10.png new file mode 100644 index 0000000000000000000000000000000000000000..61ff15a1ac934e1e544f8ed066b2e61744c33b01 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration10.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration11.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration11.png new file mode 100644 index 0000000000000000000000000000000000000000..de957647865799f88590d030757695234f6faa7a Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration11.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration12.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration12.png new file mode 100644 index 0000000000000000000000000000000000000000..c785fcd00da5cb2f11d4f996fbabdc0c0d832b46 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration12.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration13.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration13.png new file mode 100644 index 0000000000000000000000000000000000000000..7313c4b98bdccf72533d9f042daab28e6326bbf8 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration13.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration14.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration14.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3b962355d3dffad035b737c25582d0e8d10a75 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration14.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration15.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration15.png new file mode 100644 index 0000000000000000000000000000000000000000..f17c748f5709e2a3bf27f6ffcf34f5722f1f1c81 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration15.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration16.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration16.png new file mode 100644 index 0000000000000000000000000000000000000000..2a25f04a582b21435c14af2a364aedb924f273a5 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration16.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration17.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration17.png new file mode 100644 index 0000000000000000000000000000000000000000..81b17a7dd940837d4f759039ae1a7bb4b801c81b Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration17.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration18.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration18.png new file mode 100644 index 0000000000000000000000000000000000000000..ea8076f25f5c8900cac251534a9b244dcedc24ee Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-08-28-vm-migration18.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-an-openEuler-image.md b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-an-openEuler-image.md new file mode 100644 index 0000000000000000000000000000000000000000..cb8a5879f9db7ba4144a12e5324d00b23ea2bb85 --- /dev/null +++ b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-an-openEuler-image.md @@ -0,0 +1,146 @@ +--- +title: openEuler镜像 +date: 2020-12-8 +tags: + - 下载iso + - 制作镜像 + - 安装系统 + - 添加rpm包 +archives: 2020-12 +author: zhuhuankai +summary: 制作openEuler镜像 +--- + +# openEuler镜像制作 + +虚拟机镜像是一个文件,包含了已经完成安装并且可启动操作系统的虚拟磁盘。虚拟机镜像具有不同格式,常见的有raw格式和qcow2格式。qcow2格式镜像相比raw格式,具有占用更小的空间,支持快照、Copy-On-Write、AES加密、zlib压缩等特性,但性能略逊于raw格式镜像。镜像文件的制作借助于qemu-img工具,本节以qcow2格式镜像文件为例,介绍虚拟机镜像制作过程。qcow2格式的镜像文件,本身是稀疏文件,只有在虚拟机实际占用了磁盘空间后,qcow2文件才会增长,而raw格式不支持动态增长。对于现在常用的可以支持稀疏文件的文件系统(ext4)来说,qcow2十分有优势。 + +## 制作流程 + +1.下载iso +--------- + +可以使用wget命令来下到本地 + +openEuler: + +每日构建https://www.openeuler.org/zh/download/ + +如图下载好了需要用到的iso。 + +![](./2020-12-08-download-iso.png) + +2.制作镜像 +---------- + +1.使用命令: + +```shell +yum install -y qemu-img root +``` + +安装好qemu-img包。 + +2. +使用create命令来创建镜像文件 +```shell +qemu-img create -f -o +``` + +注: + +imgFormat:镜像格式,取值为raw, qcow2等。 + +fileOption:文件选项,用于设置镜像文件的特性,如指定后端镜像文件,压缩,加密等特性。 + +fileName:文件名称。 + +diskSize:磁盘大小,用于指定块磁盘设备的大小,支持的单位有K、M、G、T,分别代表KiB、MiB、GiB、TiB。 + +![](./2020-12-08-download-iso.png) + +如图我创建了一个磁盘设备大小为24GB、格式为qcow2的镜像文件openEuler-2009-final.qcow2镜像文件。(因为是稀疏文件,所以它的实际大小是很小的) + +3.安装系统 +---------- + +### 配置xml + +首先需要准备好一个xml文件来定义虚拟机。其中需要将启动方式写成从cdrom启动: + +![](./2020-12-08-create-image01.png) + +之后如图所示分别设置两个存储设备分别对应iso和qcow2文件: + +![](./2020-12-08-create-image02.png) + +其他的配置按照一般虚拟机xml配置即可。 + +### 从cdrom启动虚拟机 + +![](./2020-12-08-create-image03.png) + +### 安装步骤 + +如图选择安装openEuler 20.09。 + +![](./2020-12-08-create-image04.png) + +进入安装界面,选择continue。 + +![](./2020-12-08-create-image05.png) + +点击选择安装目的。 + +![](./2020-12-08-create-image06.png) + +选择我们刚刚创建好的qcow2镜像文件作为安装目的点。 + +![](./2020-12-08-create-image07.png) + +设置root用户的密码 + +![](./2020-12-08-create-image08.png) + +输入密码。 + +![](./2020-12-08-create-image09.png) + +完成后会发现用户将会被自动创建好。 + +![](./2020-12-08-create-image10.png) + +接下来进入自动化安装啦。 + +![](./2020-12-08-create-image11.png) + +### 从hd启动虚拟机 + +完成上一步的安装后先销毁刚刚的虚拟机。 + +![](./2020-12-08-create-image12.png) + +之后来修改xml配置,将启动方式从cdrom启动改为从hd启动。 + +![](./2020-12-08-create-image13.png) + +紧接着把之前存储启动项里的iso项注释或者删除掉,如果不删除,则iso会成为一个额外的盘,也可以用来做yum源。 + +![](./2020-12-08-create-image14.png) + +完成后就可以启动虚拟机啦。 + +4.添加rpm包 +----------- + +安装好的系统可能缺少一些需要的包,这里主要有两种方式来安装。 + +一种是通过配置yum源,在/etc/yum.repos.d下的openEuler.repo文件中来添加yum源,注意虚拟机使用的网段和yum源的网段是否一致,不一致则不能使用,需要配置虚拟机的网卡。或者就是配置本地yum源作为来源。 + +![](./2020-12-08-create-image14.png) + +如上图,把iso做为cdrom,启动虚拟机后,把/dev/sr0挂载在/mnt下,在/etc/yum.repos.d下的openEuler.repo,配置如下图。 + +![](./2020-12-08-create-image15.png) + +另一种方法是直接下载或拷贝rpm包到虚拟机上安装,但是注意有些rpm包会有前置依赖,需要一起下载。使用哪种方法视具体情况而定,如果有前置依赖,建议配置yum源。 diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image01.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image01.png new file mode 100644 index 0000000000000000000000000000000000000000..429dd2b44df4fb819c39d2e7f057a7db4cced116 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image01.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image02.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image02.png new file mode 100644 index 0000000000000000000000000000000000000000..de0af9ae169edc1d6bcbe5b2b6e9b5ee974ccd8c Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image02.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image03.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image03.png new file mode 100644 index 0000000000000000000000000000000000000000..75c1ace43da63cfdc45551da2c5dac59baff9b0c Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image03.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image04.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image04.png new file mode 100644 index 0000000000000000000000000000000000000000..54921b024afb97f5d5fcf6be9e4b1e1ffeb5f007 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image04.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image05.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image05.png new file mode 100644 index 0000000000000000000000000000000000000000..0e0cf7d55ac8042316650d6d64981d84d21b4550 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image05.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image06.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image06.png new file mode 100644 index 0000000000000000000000000000000000000000..cfb5a4f81103852dffacd3cab94409aefd9a2be0 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image06.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image07.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image07.png new file mode 100644 index 0000000000000000000000000000000000000000..b880424cb6c0e0ddaa860a8302468586b18637e6 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image07.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image08.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image08.png new file mode 100644 index 0000000000000000000000000000000000000000..3041155959276fb48ce4b174db33b67ee2ff915e Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image08.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image09.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image09.png new file mode 100644 index 0000000000000000000000000000000000000000..a0f6d14a1456e10f38d1a19ff8d5be660f632b10 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image09.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image10.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image10.png new file mode 100644 index 0000000000000000000000000000000000000000..f699fba519af0592e8a9c364d0b3f087e0f1ed12 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image10.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image11.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image11.png new file mode 100644 index 0000000000000000000000000000000000000000..5a2f0bc3d01caa282f820b7faed79bf6b51df04f Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image11.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image12.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image12.png new file mode 100644 index 0000000000000000000000000000000000000000..d36016cbd9aa224db762fc910d1fb3c291c49075 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image12.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image13.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image13.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f79568b8d1c57305753562a67e2b1a25585ce1 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image13.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image14.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image14.png new file mode 100644 index 0000000000000000000000000000000000000000..5300b4500ee4335adfe8d172b7b0c3fc9f512b3d Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image14.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image15.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image15.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8698f0f0ab2fee32de98dd22ed681f1b7f8be4 Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-create-image15.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-download-iso.png b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-download-iso.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb22e8e1fcc8cf72255269d6bb14272cd491a3f Binary files /dev/null and b/web-ui/docs/zh/blog/zhuhuankai1/2020-12-08-download-iso.png differ diff --git a/web-ui/docs/zh/blog/zhuhuankai1/2021-01-30-virttest-avocado-vt-testcases.md b/web-ui/docs/zh/blog/zhuhuankai1/2021-01-30-virttest-avocado-vt-testcases.md new file mode 100644 index 0000000000000000000000000000000000000000..46afd139853a63ba522a0cfa7af5e746bc80f719 --- /dev/null +++ b/web-ui/docs/zh/blog/zhuhuankai1/2021-01-30-virttest-avocado-vt-testcases.md @@ -0,0 +1,254 @@ +--- +title: 玩转虚拟化测试框架avocado-vt之用例编写 +date: 2021-01-30 +tags: + - virttest + - avocado-vt +archives: 2021-01 +author: zhuhuankai +summary: 以vmtop的用例为例,介绍avocado-vt测试用例的执行流程和编写方法。 +--- + +# 简介 + +本文以vmtop的用例为例,介绍如何使用avocado-vt框架来编写用例,执行测试。如果还没完成前置部署,可以前往本系列文章《玩转虚拟化测试框架avocado-vt之安装部署》。 + +# 用例执行流程 + +- 获取配置的参数 + + 框架配置好的默认参数和开发者自定义配置的参数 + +- 根据配置的参数,准备环境 + + 比如创建或销毁虚拟机实例 + +- 执行测试主体 + + 使用前面配置好的参数,进行测试。通常在经过每个测试点时,如果引发了TestFail异常则失败,如果没有引发异常,则通过。 + +- 结束阶段,清理环境 + + 根据测试过程中的情况来执行清理环境的操作。包括销毁虚拟机,删除镜像等等。 + +# 笛卡尔配置 + +- Keys and values + + Avocado-VT框架用 "key" = "value“ 的方式来定义参数key,如下图中第16行中test_type就是"key", start就是"value"。 + 要注意的是,Avocado-VT框架的参数解析是自顶向下的。所以后面的key实际上会覆盖前面的key。其实这也很符合正常的逻辑。 + +- Variants + + Variants是参数配置的关键,每个Variant块都可以包含多个同级别的参数。 + + 两个不同的variants间可以组成所有可能的组合。 + + 可以看到下图中,第10行的variants下,包含了positive_test和negative_test两个分支,这两个分支是独立的,分别代表正向测试用例和反向测试用例。在positive_test的分支里面包含了两个variants,第一个variant里的有life_cycle、data_events、cmdline_d、multivmtop、vcpu_hotplug五个元素,第二个variant里有single_vm、multi_vms两个元素。单就这两个同级的variants最大可以得到10个组合。 + + 因为life_cycle下还有一个variant,其中有start、destroy、reboot、pause_resume四个元素。所以理论上最大可以得到8乘2共16个组合。组合出来的名称会形如:positive_test.single_vm.life_cycle.start。 + +- Filters + + 过滤器,帮助筛选用例组合,常用的过滤器一共两种,分别是only 和 no。下图中,因为第41行的only过滤器的存在。所以multi_vms只会和life_cycle.start组合,不会和其余的7个元素组合。positive_test一共有共9个组合。 + +``` +- vmtop: + type = vmtop + start_vm = "no" + output_file = "vmtop_output" + vcpu_max = 8 + vcpu_cur = 4 + vcpu_live = 6 + vm_num = 1 + only aarch64 + variants: + - positive_test: + variants: + - life_cycle: + variants: + - start: + test_type = start + - destroy: + test_type = destroy + - reboot: + test_type = reboot + - pause_resume: + test_type = pause + - data_events: + test_type = data_events + - cmdline_d: + option = "d" + interval = 2 + - multivmtop: + test_type = multivmtop + vmtopnum = 6 + - vcpu_hotplug: + test_type = vcpu_hotplug + vcpu_placement = "static" + variants: + - single_vm: + test_type = single_vm + vm_num = 1 + - multi_vms: + test_type = multi_vms + vm_num = 3 + only life_cycle.start + - negative_test: + variants: + - invalid_cmdline: + option = "x" +``` + +# 用例要点 + +- 依赖库 + + Python和avocado-vt框架提供了大量的封装好的库。利用好这些库,可以大大提升编写用例的效率,精简用例的代码,提高可读性。 + +```python +import os +import logging + +from avocado.utils import process +from avocado.utils import path +from avocado.core import exceptions + +import virttest.utils_libguestfs as lgf +from virttest.utils_test import libvirt +from virttest.libvirt_xml import vm_xml +from virttest import virsh +from virttest import data_dir +``` + + +- run函数 + + run函数是avocado-vt用例必不可缺的部分,我们所要做的就是往run函数中添加测试逻辑,run函数提供的test、params、env三个参数将帮助我们完成对虚拟机实例的大量操作以及对测试点的设计和实现。 + + test:avocado/avocado/core/test.py + params: avocado-vt/virttest/utils_params.py + env: avocado-vt/virttest/utils_env.py + +```python +def run(test, params, env): +``` + +- 参数配置 + + 包括获取虚拟机实例,从cfg文件获取预置的参数。这部分类似于定义和初始化变量。 + +```python +vmname = params.get("main_vm", "avocado-vt-vm1") +vm = env.get_vm(vmname) + +output = params.get("output_file", "output") +output_path = os.path.join(data_dir.get_tmp_dir(), output) +option = params.get("option") +interval = params.get("interval") +test_type = params.get("test_type", "") +vcpu_placement = params.get("vcpu_placement") +vcpu_cur = int(params.get("vcpu_cur")) +vcpu_max = int(params.get("vcpu_max")) +vcpu_live = int(params.get("vcpu_live")) +vm_num = int(params.get("vm_num")) +vmtopnum = params.get("vmtopnum") +``` + +- 对虚拟机实例的操作最常用的库来源 + + libvirt: avocado-vt/virttest/libvirt_vm.py +avocado-vt/virttest/virsh.py +qemu: avocado-vt/virttest/qemu_vm.py + +# 用例测试点 + +- 在环境上安装vmtop + + 在hostos上使用“yum install -y vmtop”命令来安装vmtop工具。process.run是python提供的库,这里用于执行shell命令。如果没有成功安装,利用try-except的语法,合理地抛出异常。 + +```python +#Install vmtop command +install_cmd = "yum install -y vmtop" +process.run(install_cmd, shell=True) +#Find vmtop command +try: + vmtop = path.find_command("vmtop") +except path.CmdNotFoundError as info: + raise exceptions.TestSkipError("No vmtop command found - %s" % info) +``` + +- virsh.start + + 利用virsh.start来启动libvirt虚拟机实例。注意libvirt类型的用例需要先用xml文件define一个虚拟机。 + +```python +virsh.start(vmname, ignore_status=True) +``` + +- test.fail + + 编写一个vmtop_info函数,获取其返回值,根据返回值来判断是否符合我们的预期。如果不符合,进入test.fail,用例执行失败。这就是一个典型的测试点。 + +```python +#Test vmtop when start vm +res = vmtop_info(vmtop, output_path, info_type="Domains") +if int(res) != vm_num: + test.fail("start failed and the res = %s" % res) +``` + +- vmtop_info + + 该函数使用vmtop命令,将vmtop显示的结果存放到在参数配置阶段就预置好的临时路径output_path里(临时路径的能力是os库提供的,没人希望跑完用例后,产生一堆东西占用磁盘吧,用例执行过程中的临时存放路径很好地解决了这个问题) + 通常单独提取出这样一个函数,而不直接在run函数中测试,是为了能更好的复用。如果要对vmtop显示出的其他信息进行验证,只要在这个vmtop_info函数中去扩充即可。 + +```python +def vmtop_info(vmtop, output_path, info_type): + """ + Collect and return vmtop infomation + """ + cmd = "%s -b -H -n 1 > %s" % (vmtop, output_path) + process.run(cmd, ignore_status=True, shell=True) + + if info_type == "Domains": + cmd = "cat %s | grep Domains | awk '{ print $2 }'" % output_path + res = process.run(cmd, ignore_status=True, shell=True) + elif info_type == "Cpu": + cmd = "cat %s | grep /KVM | awk 'END{ print NR }'" % output_path + res = process.run(cmd, ignore_status=True, shell=True) + elif info_type == "Data": + cmd = "cat %s | grep DID" % output_path + res = process.run(cmd, ignore_status=True, shell=True) + + return res.stdout_text +``` + +- 环境清理 + + 为了保证每个用例之间不要相互影响,我们需要在用例执行的结尾阶段,清理一下我们的环境。比如清除虚拟机实例,删除磁盘等等 + +```python +finally: + # Destroy vm_clone + if test_type == "multi_vms": + num = 1 + while num < vm_num: + if virsh.domain_exists(vm_clone_name[num - 1]): + if virsh.is_alive(vm_clone_name[num - 1]): + virsh.destroy(vm_clone_name[num - 1]) + virsh.remove_domain(vm_clone_name[num - 1], \ + "--remove-all-storage", debug=True) + num = num + 1 + + if vm.is_alive(): + vm.destroy() + vmxml.sync() +``` + +- 完整的用例源码 + + [1.python文件](https://gitee.com/openeuler/tp-libvirt/tree/openEuler-20.03/libvirt/tests/src/virt_cmd/vmtop.py + ) + [2.cfg文件](https://gitee.com/openeuler/tp-libvirt/tree/openEuler-20.03/libvirt/tests/cfg/virt_cmd/vmtop.cfg + ) + diff --git a/web-ui/docs/zh/building/README.md b/web-ui/docs/zh/building/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f14b76a1efc2719e262f7df6fed2ec51d8db4e0e --- /dev/null +++ b/web-ui/docs/zh/building/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/community/certification-services/README.md b/web-ui/docs/zh/community/certification-services/README.md new file mode 100644 index 0000000000000000000000000000000000000000..57ef1d65d62cc272b0cd28c192b4ed82a94fb75f --- /dev/null +++ b/web-ui/docs/zh/community/certification-services/README.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/community/certification-services/down.md b/web-ui/docs/zh/community/certification-services/down.md new file mode 100644 index 0000000000000000000000000000000000000000..aff1dd4f4e03e625656105802aef2c2b6114f8e1 --- /dev/null +++ b/web-ui/docs/zh/community/certification-services/down.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/community/certification-services/search.md b/web-ui/docs/zh/community/certification-services/search.md new file mode 100644 index 0000000000000000000000000000000000000000..584078cba784f885ec509e091b66f6b5725569e0 --- /dev/null +++ b/web-ui/docs/zh/community/certification-services/search.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/community/conduct/README.md b/web-ui/docs/zh/community/conduct/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a2132f266139192b8bd33f81201a387086ebb1d8 --- /dev/null +++ b/web-ui/docs/zh/community/conduct/README.md @@ -0,0 +1,59 @@ +--- +title: "行为守则" +--- + + + +
+ + +openEuelr社区遵守开源社区《贡献者公约》V1.4中规定的行为守则,请参考V1.4版本 + +如需举报侮辱、骚扰或其他不可接受的行为,您可以发送邮箱至,联系openEuler技术委员会处理。 + +## 贡献者们的承诺 +为建设开放友好的环境,我们贡献者和维护者承诺:不论年龄、体型、身体健全与否、民族、性征、性别认同与表征、经验水平、教育程度、社会地位、国籍、相貌、种族、信仰、性取向,我们项目和社区的参与者皆免于骚扰。 + +## 我们的准则 +有助于创造积极环境的行为包括但不限于: + ++ 措辞友好且包容 + ++ 尊重不同的观点和经验 + ++ 耐心接受有益批评 + ++ 关注对社区最有利的事情 + ++ 与社区其他成员友善相处 + +参与者不应采取的行为包括但不限于: + ++ 发布与性有关的言论或图像、不受欢迎地献殷勤 + ++ 捣乱/煽动/造谣行为、侮辱/贬损的评论、人身及政治攻击 + ++ 公开或私下骚扰 + ++ 未经明确授权便发布他人的资料,如住址、电子邮箱等 + ++ 其他有理由认定为违反职业操守的不当行为 + +## 我们的义务 + +项目维护者有义务诠释何谓“妥当行为”,并妥善公正地纠正已发生的不当行为。
+项目维护者有权利和义务去删除、编辑、拒绝违背本行为标准的评论(comments)、提交(commits)、代码、wiki 编辑、问题(issues)等贡献;项目维护者可暂时或永久地封禁任何他们认为行为不当、威胁、冒犯、有害的参与者。 + +## 适用范围 + +本行为标准适用于本项目。当有人代表本项目或本社区时,本标准亦适用于此人所处的公共平台。
+代表本项目或本社区的情形包括但不限于:使用项目的官方电子邮件、通过官方媒体账号发布消息、作为指定代表参与在线或线下活动等。
+代表本项目的行为可由项目维护者进一步定义及解释。 + +## 贯彻落实 + +可以致信,向项目团队举报滥用、骚扰及不当行为。
+维护团队将审议并调查全部投诉,妥善地予以必要的回应。项目团队有义务保密举报者信息。具体执行方针或将另行发布。
+未切实遵守或执行本行为标准的项目维护人员,经项目负责人或其他成员决议,可能被暂时或永久地剥夺参与本项目的资格。 + +
\ No newline at end of file diff --git a/web-ui/docs/zh/community/contribution/README.md b/web-ui/docs/zh/community/contribution/README.md new file mode 100644 index 0000000000000000000000000000000000000000..984a024584b7ebe827c78a504d8e8d7c2ebcefd5 --- /dev/null +++ b/web-ui/docs/zh/community/contribution/README.md @@ -0,0 +1,6 @@ +--- +title: "贡献攻略" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/community/contribution/detail.md b/web-ui/docs/zh/community/contribution/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..530cd0b54de2409e1650ea4425d0972913bc426e --- /dev/null +++ b/web-ui/docs/zh/community/contribution/detail.md @@ -0,0 +1,140 @@ +--- +title: "贡献攻略" +--- + + + + +
+ +欢迎来到openEuler! + +## 1. 体验openEuler +### 1.1 体验openEuler操作系统 + +您可以通过以下四种方式体验openEuler操作系统: + +- [公有云](https://huaweicloud.com/product/ecs.html) +- [虚拟机](https://www.openeuler.org/zh/docs/20.03_LTS/docs/Virtualization/virtualization.html) +- [硬件](https://www.openeuler.org/zh/docs/20.03_LTS/docs/Installation/installation.html) +- [树莓派](https://gitee.com/openeuler/raspberrypi) + +### 1.2 体验原创开源项目 + +您可以体验openEuler社区里的以下原创开源项目: + +- [StratoVirt](https://www.openeuler.org/zh/other/projects/stratovirt/):面向云数据中心的企业级虚拟化平台 +- [A-Tune](https://www.openeuler.org/zh/other/projects/atune/):一款基于AI开发的智能优化引擎 +- [iSula](https://www.openeuler.org/zh/other/projects/isula/):轻量级容器解决方案 +- [secGear](https://www.openeuler.org/zh/other/projects/secgear/):面向计算产业的机密计算安全应用开发套件 +- [pkgship](https://pkgmanage.openeuler.org/):管理OS软件包依赖关系,提供依赖和被依赖关系完整图谱的查询工具 +- [BiSheng JDK](https://www.openeuler.org/zh/other/projects/bishengjdk/): OpenJDK定制版Huawei JDK的开源版本,是一个高性能、可用于生产环境的OpenJDK发行版 +- [Compass-CI ](https://compass-ci.openeuler.org/): 可持续集成的开源软件平台, 构建一个开放、完整的测试系统 + +## 2. 签署CLA + +在参与社区贡献前,您需要签署openEuler社区贡献者许可协议(CLA)。 +根据您的参与身份,选择签署个人CLA、员工CLA或企业CLA,请点击[这里](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)签署 + +- 个人CLA:以个人身份参与社区,请签署个人CLA +- 企业CLA: 以企业身份参与社区,请签署企业CLA +- 员工CLA: 以企业员工的身份参与社区,请签署员工CLA + +## 3. 参与openEuler社区 +### 3.1 参与社区活动 + +您可以了解并参与丰富多彩的社区活动: + +- [Meeting](/zh/#meeting):查看官网首页SIG公开例会日程安排,可参与你感兴趣的会议 +- [Meetups](https://www.openeuler.org/zh/interaction/salon-list/) +- [直播](https://www.openeuler.org/zh/interaction/live-list/) +- [峰会](https://www.openeuler.org/zh/interaction/summit-list/summit2021/) + +### 3.2 找到您想参与的SIG +#### 3.2.1 了解SIG并找到您感兴趣的SIG +SIG就是Special Interest Group的缩写,openEuler社区按照不同的SIG来组织,以便于更好的管理和改善工作流程。因此参与社区事务正确的起始姿势是先找到您感兴趣的SIG, SIG组均是开放的,欢迎任何人来参与。 +目前openEuler社区已有70+ SIG组,可查看 [openEuler SIG 列表](https://www.openeuler.org/zh/sig/sig-list/) 找到您感兴趣的SIG。 +如果定位不到您感兴趣的SIG,您可以向[community@openeuler.org](mailto:community@openeuler.org)发求助邮件。建议您在邮件列表内用“【开发过程疑问】”作为标题,在内容中写出你寻找的SIG或项目的特征,我们会为您提供帮助。 + +#### 3.2.2 成立新的SIG + +如果在已有的SIG组列表里面没有找到您感兴趣的SIG,而您对某个方向有浓厚的兴趣,希望在openEuler社区成立一个新的相关SIG进行维护和发展,那您可以参考 [申请新SIG流程指南](https://www.openeuler.org/zh/sig/sig-guidance/) 来申请创建新的SIG. + +### 3.3 参与社区贡献 + +在签署了[CLA协议](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)、找到了你想参与的[SIG组](https://www.openeuler.org/zh/sig/sig-list/)之后,就可以开始你的社区贡献之旅啦!社区贡献的方式有很多种,每一种贡献都将受到社区的欢迎和重视。 +##### 1.提交Issue/处理issue任务 + +- 找到Issue列表: + 在您感兴趣的SIG项目Gitee主页内,点击“Issues”,您可以找到其Issue列表(如[Community团队的Issue列表](https://gitee.com/openeuler/community/issues)) +- 提交Issue + 如果您准备向社区上报Bug或者提交需求,或者为openEuler社区贡献自己的意见或建议,请在openEuler社区对应的仓库上提交Issue。 + 提交Issue请参考 [Issue提交指南](https://gitee.com/openeuler/community/blob/master/zh/contributors/issue-submit.md)。为了吸引更广泛的注意,您也可以把Issue的链接附在邮件内,通过[邮件列表](https://www.openeuler.org/zh/community/mailing-list/)发送给所有人。 +- 参与Issue内的讨论 + 每个Issue下面可能已经有参与者们的交流和讨论,如果您感兴趣,也可以在评论框中发表自己的意见。 +- 找到愿意处理的Issue + 如果您愿意处理其中的一个issue,可以将它分配给自己。只需要在评论框内输入 /assign或 /assign @yourself,机器人就会将问题分配给您,您的名字将显示在负责人列表里。 + +##### 2.贡献编码 + +- 准备openEuler的开发环境 + 如果您想参与编码贡献,需要准备openEuler的开发环境,请参考[开发环境准备](https://gitee.com/openeuler/community/blob/master/zh/contributors/prepare-environment.md)。 +- 了解SIG和项目内的开发注意事项 + 每个SIG内的项目使用的编码语言、开发环境、编码约定等都可能存在差异的。如果您想了解并参与到编码类贡献,可以先找到该项目给开发者提供的贡献者指南——这个指南一般是在该SIG的首页地址内,以CONTRIBUTING.md文件的形式提供,或者就直接在该项目的README.md内。 +- 下载代码和拉分支 + 如果要参与代码贡献,您还需要了解如何在Gitee下载代码,通过PR合入代码等。openEuler使用Gitee代码托管平台,想了解具体的指导,请参考[Gitee Workflow Guide](https://gitee.com/openeuler/community/blob/master/zh/contributors/Gitee-workflow.md)。该托管平台的使用方法类似GitHub,如果您以前使用过GitHub,本节的内容您可以大致了解甚至跳过。 +- 修改、构建和本地验证 + 在本地分支上完成修改后,进行构建和本地验证,请参考[构建软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/package-install.md)。 +- 提交一个Pull-Request + 当你提交一个PR的时候,就意味您已经开始给社区贡献代码了。请参考 openEuler社区PR提交指导。 + 为了使您的提交更容易被接受,您需要: + - 遵循SIG组的编码约定,如果有的话 + - 准备完善的提交信息 + - 如果一次提交的代码量较大,建议将大型的内容分解成一系列逻辑上较小的内容,分别进行提交会更便于检视者理解您的想法 + - 使用适当的SIG组和监视者标签去标记PR:社区机器人会发送给您消息,以方便您更好的完成整个PR的过程 + + 注意:如果您的PR请求没有引起足够的关注,可以在SIG的邮件列表或dev@openeuler.org求助。 + +##### 3.贡献软件包 +如果你发现openEuler缺失了一个软件包,可以帮openEuler把这个软件包补上。实际上贡献软件包的过程就是帮助openEuler提供更丰富功能的过程。希望随着大家的参与,openEuler能够成为一个“无所不有”的软件生态系统。openEuler支持在gitee新增软件包的同时自动在obs的openEuler:Fctory上创建同名仓库。这样在向已创建的gitee仓库提交代码时,会自动对代码编译进行检测。具体流程可参考 [如何新增软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/create-package.md)。 +##### 4.贡献原创开源项目 +如果你想将自己原创的开源项目贡献到openEuler社区,成为openEuler发行版本中的一份子,那么可参考以下两种方式: +- 方式一:在其它社区开发,集成到openEuler中 + 假定你已经在github,gitlab或者gitee上拥有了自己的项目,那么只需要按照以上提到的 [如何新增软件包](https://gitee.com/openeuler/community/blob/master/zh/contributors/create-package.md) 那样,将软件加入到src-openeuler这个repo仓就可以了。 +- 方式二:在openEuler社区中开发,在openEuler中集成 + 直接在https://gitee.com/openeuler中建立原创项目,类似将项目“托管”到openEuler社区,比如现在社区中的iSula和A-Tune就是这样的模式。 + 如果你有了一个很棒的idea想要在openEuler社区里实现,那么他可以依照下面的过程来深度参与到openEuler中。 + 1.在[TC委员会的例会](https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org)中申请一个开源项目; + 2.如果TC委员会认为这是一个很好的idea,并且认为值得去推进,那么我们会在[https://gitee.com/openeuler](https://gitee.com/openeuler)中建立一个repo; + 3.这个项目在openeuler中持续开发和孵化,直到项目逐渐成熟,那么就可以在src-openeuler中建立一个仓,为该项目提供相关的spec文件,制作成为一个rpm; + 4.最终这个原创的开源项目会随着openEuler的发布版本走遍全世界,为世界人民所使用。 + +##### 5.检视代码 +openEuler是一个开放的社区,我们希望所有参与社区的人都能成为活跃的检视者。当成为SIG组的committer或maintainer角色时,便拥有审核代码的责任与权利。 +强烈建议本着[行为准则](https://gitee.com/openeuler/community/blob/master/code-of-conduct.md),超越自我,相互尊重和促进协作。[《补丁审核的柔和艺术》](https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/)一文中提出了一系列检视的重点,说明代码检视的活动也希望能够促进新的贡献者积极参与,而不会使贡献者一开始就被细微的错误淹没,所以检视的时候,可以重点关注包括: +  1.贡献背后的想法是否合理 +  2.贡献的架构是否正确 +  3.贡献是否完善 + +##### 6.测试 +测试——是所有贡献者的责任,对于社区版本来说,[sig-qa](https://gitee.com/openeuler/QA)组是负责测试活动的社区官方组织。如果您希望在自己的基础架构上开展测试活动,可以参考:[社区测试体系介绍](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E6%B5%8B%E8%AF%95%E4%BD%93%E7%B3%BB%E4%BB%8B%E7%BB%8D.md) 。 +为了成功发行一个社区版本,需要完成多种测试活动。不同的测试活动,测试代码的位置也有所不同,成功运行测试所需的环境的细节也会有差异,有关的信息可以参考:[社区开发者测试贡献指南](https://gitee.com/openeuler/QA/blob/master/%E7%A4%BE%E5%8C%BA%E5%BC%80%E5%8F%91%E8%80%85%E6%B5%8B%E8%AF%95%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97.md)。 +##### 7.选择社区组件打包 +您也可以参与社区组件打包,请参考 [如何打包](https://gitee.com/openeuler/community/blob/master/zh/contributors/packaging.md)。 +##### 8.参与非代码类贡献 +如果您的兴趣不在编写代码方面,可以在[ 非代码贡献指南 ](https://gitee.com/openeuler/community/blob/master/zh/contributors/non-code-contributions.md)中找到感兴趣的工作。 +##### 9.社区安全问题披露 +[安全处理流程](https://gitee.com/openeuler/security-committee/blob/master/%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.jpg)——简要描述了处理安全问题的过程。 +[安全披露信息](https://gitee.com/openeuler/security-committee/blob/master/security-disclosure.md)——如果您希望报告安全漏洞,请参考此页面。 + +## 4. 和社区一起成长 +### 4.1 社区角色说明 + +社区不同角色对应不同的责任与权利,每种角色都是社区不可或缺的一部分,您可以通过积极贡献不断积累经验和影响力,并获得角色上的成长。更详细角色说明与责任权利描述请查看 [角色说明](https://gitee.com/openeuler/community/blob/master/community-membership_cn.md)。 + +### 4.2 技术委员会 + +openEuler技术委员会(Technical Committee,简称TC)是openEuler社区的技术决策机构,负责社区技术决策和技术资源的协调。 +详情请查看 [openEuler技术委员会介绍](https://www.openeuler.org/zh/sig/sig-list/sig-detail.html?id=21&name=TC&mail=dev%40openeuler.org) + +
\ No newline at end of file diff --git a/web-ui/docs/zh/community/mailing-list/README.md b/web-ui/docs/zh/community/mailing-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35068515e9c9a13e5c906ab270dffee613c135c2 --- /dev/null +++ b/web-ui/docs/zh/community/mailing-list/README.md @@ -0,0 +1,6 @@ +--- +title: "邮件列表" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/compatibility/README.md b/web-ui/docs/zh/compatibility/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7620c171b4783007a6447126569755231627f9c8 --- /dev/null +++ b/web-ui/docs/zh/compatibility/README.md @@ -0,0 +1,7 @@ +--- +title: "Compatibility" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/compatibility/hardware-info/README.md b/web-ui/docs/zh/compatibility/hardware-info/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af845b8f47b801a22fcdcd66528f1173db870534 --- /dev/null +++ b/web-ui/docs/zh/compatibility/hardware-info/README.md @@ -0,0 +1,7 @@ +--- +title: "HardwareInfo" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/compatibility/hardware/README.md b/web-ui/docs/zh/compatibility/hardware/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7d8b33fb2d5f45ddfae96413aad95f0615ca0793 --- /dev/null +++ b/web-ui/docs/zh/compatibility/hardware/README.md @@ -0,0 +1,7 @@ +--- +title: "Hardware" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/compatibility/software/README.md b/web-ui/docs/zh/compatibility/software/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f3e56f9888177cfd236b15a98cefa7a5e2047da6 --- /dev/null +++ b/web-ui/docs/zh/compatibility/software/README.md @@ -0,0 +1,7 @@ +--- +title: "Software" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/download/README.md b/web-ui/docs/zh/download/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d85ff3f152819f6c24cadb20ba370fd9e49ace7e --- /dev/null +++ b/web-ui/docs/zh/download/README.md @@ -0,0 +1,6 @@ +--- +title: "下载" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/blog-list/README.md b/web-ui/docs/zh/interaction/blog-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..53905ddf2df252ff517e9b6e49c2c4a8b9996b05 --- /dev/null +++ b/web-ui/docs/zh/interaction/blog-list/README.md @@ -0,0 +1,6 @@ +--- +title: "博客" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/live-list/README.md b/web-ui/docs/zh/interaction/live-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f4c4ce57bf23110e231df15b95a90e1e11cd5b51 --- /dev/null +++ b/web-ui/docs/zh/interaction/live-list/README.md @@ -0,0 +1,6 @@ +--- +title: "直播" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/news-list/README.md b/web-ui/docs/zh/interaction/news-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3c367e359a3c2f229736bf0df29ddd0cc20b23cd --- /dev/null +++ b/web-ui/docs/zh/interaction/news-list/README.md @@ -0,0 +1,6 @@ +--- +title: "新闻" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/post-blog/README.md b/web-ui/docs/zh/interaction/post-blog/README.md new file mode 100644 index 0000000000000000000000000000000000000000..991d24b36b88c1750f7c5ed26368aea31ccd4ab7 --- /dev/null +++ b/web-ui/docs/zh/interaction/post-blog/README.md @@ -0,0 +1,174 @@ +--- +title: "Guidance to Post a Blog" + +--- + + + + +
+ +## 准备 + +1. 参考 http://git.mydoc.io/?t=179267 注册Gitee账号。 + +2. 在Gitee个人设置中设置主邮箱地址,在此https://gitee.com/profile/emails。 + +3. 签署贡献者协议,https://www.openeuler.org/zh/other/cla。 + +4. 参考http://git.mydoc.io/?t=180692准备你的git环境 + +## 理解博客格式 + +openEuler是用markdown格式写博客的。 +请阅读该文章 来理解openEuler博客是如何设计的。 + +文件头需要包含如下信息: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: sig-xxx +archives: 2020-03 +author: openEuler Blog Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your blog. +``` + +小提示:你可以复制 https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post.md 到你的工作路径下然后继续编辑。 + +## 提交博客 + +博客的提交利用了Gitee的PR(Pull Request)。 + +1. Fork openEuler 博客项目 到你自己的Gitee上。如果需要具体指导请参考 。 + +2. Clone代码 + +``` +git clone https://gitee.com//website-v2 +``` + +3. 创建分支 + +``` +git checkout -b +``` + +4. 创建工作路径 + +如果你发表中文博客,工作路径是 web-ui/docs/zh/blog 。 +假设你要写一个英文博客: + +``` +cd web-ui/docs/en/blog +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +你可以以你的md文档名来命名你的资源文件,方便使用。例如: +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +其中,YEAR, MONTH, DAY, 和 title 和你的博客md文件名一致。NN 是01、02、03这样的序号。MARKUP文件扩展名。如下例子: +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +使用HTML \ 标签嵌入图片, 但你的图片资源需要放入当前目录下(即your-gitee-id目录下),输入图片名称作为 src 值: +``` + +``` + +1. Commit 你的博客 + +``` +git add +git commit -m "" +git push origin : +``` + +2. 参考 提交你的PR + +3. 等待评审和合入。 + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/post-blog/blog_design/README.md b/web-ui/docs/zh/interaction/post-blog/blog_design/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d8fe18cf28ac1cd80b3c5634d541e81afee4f855 --- /dev/null +++ b/web-ui/docs/zh/interaction/post-blog/blog_design/README.md @@ -0,0 +1,100 @@ +# Posts +This file is to explain in which way the content of the blogs are stored and read by the blog system. + +## What is supported in the blog +A blog can include many formats of information, like text, pictures, videos, animations or others. + +openEuler Blog is designed to support the following formats: + +1. text +2. static picture +3. links +4. animation + +## Folder design +The content of blogs are under + +``` +|__ web-ui/docs/en/interaction/post-blog/blog_example --list the some blog examples +|__ web-ui/docs/zh/blog/guidance --house the guidance to post and maintain the blogs in Chinese +|__ web-ui/docs/en/blog/guidance --house the guidance to post and maintain the blogs in English +|__ web-ui/docs/zh/blog --house all the final posts in Chinese + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID +|__ web-ui/docs/en/blog --house all the final posts in English + |__ author_1 --house the blogs by authors' gitee ID, and each author need create your own foler by your id. + |__ author_2 --house the blogs by authors' gitee ID + +``` + +## Post content design +### Choose languange +If you are going to post a blog in English, the web-ui/docs/en/blog is your work path. + +And if you are going to post a blog in Chinese, the web-ui/docs/zh/blog is your work path. + +### File name (Assuming to write a post in Enlgish) +To create a post, add a file to your web-ui/docs/en/blog/author_1/_ directory with the following format: + +``` +YEAR-MONTH-DAY-title.MARKUP +``` +Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers, and MARKUP is the file extension representing the format used in the file. For example, the following are examples of valid post filenames: +``` +2020-01-01-new-years-is-coming.md +2020-02-15-how-to-write-a-blog.md +``` + +### File headers +Functionally, the post should support categories, archives, title, date, brief description, thus the file headers should be as below. +``` +--- +title: ... +date: yyyy-mm-dd +tags: + - aaaa + - bbbb + - cccc +archives: yyyy-mm +author: name of author +summary: ... +--- +``` + +### Including resources + +At some point, you’ll want to include images, downloads, or other digital assets along with your text content. + +You can put the resources in the same folder as your text file's, and name the resources as +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +Where the YEAR, MONTH, DAY, and title are the same as your blog file, and NN is the serial number of the pictures, like 01, 02 and so on. The MARKUP is the file extension, and for pictures it is recommended to use png. +The following are one example. +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +Then, from within any post, they can be linked to using the site’s root as the path for the asset to include. Here are some simple examples in Markdown: + +Including an image asset in a post: +``` +...Use the html tag,and enter relative path of the image as src attribute. + +``` + +Linking to a PDF for readers to download: +``` +... +Use the html tag,and enter relative path of the file as href attribute. +The file will be downloaded once the link is clicked. +get the PDF. +``` +Linking to a url for readers to visit: +``` +... you can [read more](). +``` + +## Thanks \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post.md b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post.md new file mode 100644 index 0000000000000000000000000000000000000000..e3e8f4b7699f6fabbb2736a8694192a54b997872 --- /dev/null +++ b/web-ui/docs/zh/interaction/post-blog/blog_example/2020-03-03-sample-post.md @@ -0,0 +1,84 @@ +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: A-Tune +archives: 2020-03 +author: openEuler Blog Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +## HTML Elements + +Below is just about everything you'll need to style in the blog. + +# Heading 1 + +## Heading 2 + +### Heading 3 + +#### Heading 4 + +##### Heading 5 + +### Body text + +This blog is about bla bla. **This is strong**. + +![openEuler is open](./2020-03-03-sample-post-01.png) +### Quotation + +> The sites that have been chosen are listed and described next to each work, with encapsulating quotes or pieces of text narrating central themes for the groups. + +## List Types + +### Ordered Lists + +1. Item one + 1. sub item one + 2. sub item two + 3. sub item three +2. Item two + +### Unordered Lists + +* Item one +* Item two +* Item three + +## Tables + +| Header1 | Header2 | Header3 | +|:--------|:-------:|--------:| +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|---- +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|===== +| Foot1 | Foot2 | Foot3 +{: rules="groups"} + +## Code + +``` +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; +``` + +## Attachment + +Download the file here download: +[get the PNG](![The architecture]() +) directly. diff --git a/web-ui/docs/zh/interaction/post-news/README.md b/web-ui/docs/zh/interaction/post-news/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a4d0c5c5ceae68f500dab12b2366e3aff3c6a47e --- /dev/null +++ b/web-ui/docs/zh/interaction/post-news/README.md @@ -0,0 +1,172 @@ +--- +title: "Guidance to Post a News" + +--- + + + + +
+ +## 准备 + +1. 参考 http://git.mydoc.io/?t=179267 注册Gitee账号。 + +2. 在Gitee个人设置中设置主邮箱地址,在此https://gitee.com/profile/emails。 + +3. 签署贡献者协议,https://www.openeuler.org/zh/other/cla。 + +4. 参考http://git.mydoc.io/?t=180692准备你的git环境 + +## 理解新闻格式 + +openEuler是用markdown格式写新闻的。 +请阅读该文章 来理解openEuler新闻是如何设计的。 + +文件头需要包含如下信息: +``` +--- +title: Sample Post +date: 2020-03-03 +tags: + - theme +banner: img/banners/banner-2020hdc.png +author: openEuler +sig: sig-xxx +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +Here you can edit your news. +``` + +小提示:你可以复制 https://gitee.com/openeuler/website-v2/blob/master/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post.md 到你的工作路径下然后继续编辑。 + +## 提交新闻 + +新闻的提交利用了Gitee的PR(Pull Request)。 + +1. Fork openEuler 新闻项目 到你自己的Gitee上。如果需要具体指导请参考 。 + +2. Clone代码 + +``` +git clone https://gitee.com//website-v2 +``` + +3. 创建分支 + +``` +git checkout -b +``` + +4. 创建工作路径 + +如果你发表中文新闻,工作路径是 web-ui/docs/zh/news 。 +假设你要写一个英文新闻: + +``` +cd web-ui/docs/en/news +mkdir +cd +touch YEAR-MONTH-DAY-title.md +``` + +你可以以你的md文档名来命名你的资源文件,方便使用。例如: +``` +YEAR-MONTH-DAY-title-NN.MARKUP +``` +其中,YEAR, MONTH, DAY, 和 title 和你的新闻md文件名一致。NN 是01、02、03这样的序号。MARKUP文件扩展名。如下例子: +``` +2020-01-01-new-years-is-coming.md +2020-01-01-new-years-is-coming-01.png +2020-01-01-new-years-is-coming-02.gif +2020-01-01-new-years-is-coming-03.pdf +``` +使用HTML \ 标签嵌入图片, 但你的图片资源需要放入当前目录下(即your-gitee-id目录下),输入图片名称作为 src 值: +``` + +``` + +1. Commit 你的新闻 + +``` +git add +git commit -m "" +git push origin : +``` + +2. 参考 提交你的PR + +3. 等待评审和合入。 + + +
+ + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01.png b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png new file mode 100644 index 0000000000000000000000000000000000000000..630a1e649721df84e96024add2356abc5cca166d Binary files /dev/null and b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post-01/2020-03-03-sample-post-01.png differ diff --git a/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post.md b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1bb635ce0f8af793b1ce09b57d8a5d5e597aa0 --- /dev/null +++ b/web-ui/docs/zh/interaction/post-news/news_example/2020-03-03-sample-post.md @@ -0,0 +1,85 @@ +--- +title: Sample Post +date: 2020-03-03 +tags: + - Sample + - ABC + - cccc +sig: A-Tune +banner: img/news/20201225/poster.png +archives: 2020-03 +author: openEuler news Maintainer +summary: Just about everything you'll need to style in the theme:headings, paragraphs, blockquotes, tables, code blocks, and more. +--- + +## HTML Elements + +Below is just about everything you'll need to style in the news. + +# Heading 1 + +## Heading 2 + +### Heading 3 + +#### Heading 4 + +##### Heading 5 + +### Body text + +This news is about bla bla. **This is strong**. + +![openEuler is open](./2020-03-03-sample-post-01.png) +### Quotation + +> The sites that have been chosen are listed and described next to each work, with encapsulating quotes or pieces of text narrating central themes for the groups. + +## List Types + +### Ordered Lists + +1. Item one + 1. sub item one + 2. sub item two + 3. sub item three +2. Item two + +### Unordered Lists + +* Item one +* Item two +* Item three + +## Tables + +| Header1 | Header2 | Header3 | +|:--------|:-------:|--------:| +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|---- +| cell1 | cell2 | cell3 | +| cell4 | cell5 | cell6 | +|===== +| Foot1 | Foot2 | Foot3 +{: rules="groups"} + +## Code + +``` +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; +``` + +## Attachment + +Download the file here download: +[get the PNG](![The architecture]() +) directly. diff --git a/web-ui/docs/zh/interaction/salon-list/README.md b/web-ui/docs/zh/interaction/salon-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a2fc7592964e171185d764b034ef8d3f7086b779 --- /dev/null +++ b/web-ui/docs/zh/interaction/salon-list/README.md @@ -0,0 +1,6 @@ +--- +title: "沙龙" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/salon-list/detail/README.md b/web-ui/docs/zh/interaction/salon-list/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c72b08ab511949f1c404e2f7eb9b312a028a166b --- /dev/null +++ b/web-ui/docs/zh/interaction/salon-list/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "沙龙详情" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/summit-list/README.md b/web-ui/docs/zh/interaction/summit-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d63ad4826a9eec396c52449f2c9585c5931d15a6 --- /dev/null +++ b/web-ui/docs/zh/interaction/summit-list/README.md @@ -0,0 +1,6 @@ +--- +title: "峰会" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/summit-list/devday2021/README.md b/web-ui/docs/zh/interaction/summit-list/devday2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..93d427f5b35f2fc44b4292eb01114e745fe2262c --- /dev/null +++ b/web-ui/docs/zh/interaction/summit-list/devday2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/summit-list/devday2022/README.md b/web-ui/docs/zh/interaction/summit-list/devday2022/README.md new file mode 100644 index 0000000000000000000000000000000000000000..88d19760d9da30c24fd47848003074ed59de4e27 --- /dev/null +++ b/web-ui/docs/zh/interaction/summit-list/devday2022/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Developer Day 2022" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/summit-list/list/README.md b/web-ui/docs/zh/interaction/summit-list/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7c6e01026468b13919f197e072693c0a82253a02 --- /dev/null +++ b/web-ui/docs/zh/interaction/summit-list/list/README.md @@ -0,0 +1,6 @@ +--- +title: "峰会" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/interaction/summit-list/summit2021/README.md b/web-ui/docs/zh/interaction/summit-list/summit2021/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1d9d1ad9ef1d5c6d03167f760be3cb6cdebe4e9a --- /dev/null +++ b/web-ui/docs/zh/interaction/summit-list/summit2021/README.md @@ -0,0 +1,7 @@ +--- +title: "openEuler Summit 2021" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/internship/README.md b/web-ui/docs/zh/internship/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5d8870869c275cf1bf87c43e6708e0c3eedf8c1a --- /dev/null +++ b/web-ui/docs/zh/internship/README.md @@ -0,0 +1,7 @@ +--- +title: "Internship" + +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/learn/mooc/README.md b/web-ui/docs/zh/learn/mooc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..48c80c6d0f6023ef0e17eb93ac8514b26f4611d8 --- /dev/null +++ b/web-ui/docs/zh/learn/mooc/README.md @@ -0,0 +1,6 @@ +--- +title: "慕课" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/learn/mooc/detail/README.md b/web-ui/docs/zh/learn/mooc/detail/README.md new file mode 100644 index 0000000000000000000000000000000000000000..04992b3543a8d1177b1236d7b6e4a4154531331b --- /dev/null +++ b/web-ui/docs/zh/learn/mooc/detail/README.md @@ -0,0 +1,6 @@ +--- +title: "慕课详情" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/mirror/list/README.md b/web-ui/docs/zh/mirror/list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cb6e5d68171140ae744a1e79a6431f331044511c --- /dev/null +++ b/web-ui/docs/zh/mirror/list/README.md @@ -0,0 +1,6 @@ +--- +title: "镜像列表" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/mirror/select/README.md b/web-ui/docs/zh/mirror/select/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e742141e55d6178b503b17f1e379dfab1ee04ecb --- /dev/null +++ b/web-ui/docs/zh/mirror/select/README.md @@ -0,0 +1,6 @@ +--- +title: "镜像选择" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/news/2020010401.md b/web-ui/docs/zh/news/2020010401.md new file mode 100644 index 0000000000000000000000000000000000000000..8deaecf5d9c870c328d44ae62a6d9baf193a3278 --- /dev/null +++ b/web-ui/docs/zh/news/2020010401.md @@ -0,0 +1,101 @@ +--- +title: "去HDC.Cloud 2020参加黑客松,玩儿openEuler,赢取大礼" +date: "2020-01-04" +tags: + - theme +banner: "img/events/banner-20200104.png" +author: "Fred Li" +summary: "在2020年2月11日和12日在深圳举办的HDC.Cloud 2020黑客松上,openEuler将与其他开源项目一起组成黑客松。欢迎开发者前来参与。" +--- + + + + + +
+ +### openEuler技术生态发展,大有可为 +[HDC.Cloud 华为开发者大会 2020](https://www.huaweicloud.com/HDC.Cloud.html) 将于2020年2月11日-12日在深圳会展中心举办,这是华为面向ICT(信息与通信)领域全球开发者的年度顶级旗舰活动。大会旨在搭建一个全球性的交流和实践平台,开放华为三十年积累的ICT技术和能力,以“鲲鹏+昇腾”硬核双引擎,为开发者提供澎湃动力,改变世界,变不可能为可能。 + +Cloud & AI将在其中举办开源黑客松(Hackathon),这是一场面向全球开源开发者举办的编程马拉松大赛。 + +openEuler作为一个操作系统,发展技术生态是重中之重。虽然openEuler是一个Linux操作系统,生态天然不差,也能够运行在ARM架构的服务器上,但面对海量的中间件、应用软件,应对起来就不一定跟从容了。所以,发展技术生态是当务之急。 + + +### 黑客松奖项 + + +所有***完成任务***的团队将获得: + +- 香蕉派开发板,团队成员**每人一台**! + +- 黑客松纪念T恤,团队成员**每人一件**! + +本次大赛包含5大赛题,***每个赛题排名第一和第二的团队***将获得: + +- HDC.Cloud 2020 开源黑客松获奖证书 + +- ***价值3999元的Atlas 200 DK开发者套件***,团队成员每人一套 + + + + +### 报名方式 + +本次黑客松以团队赛形式进行,开发者可自由组队报名,每个队伍3-5人。 + +**报名成功即可获得价值2048元的HDC.Cloud 2020门票一张**。 + +报名及组队方式请见各赛题详情链接。 + +### 比赛日程 + +- 报名阶段:2019年12月24日9时-2020年2月4日18时 + +- 比赛阶段:2020年2月11日11时- 2020年2月12日16时(HDC.Cloud 2020现场比赛) + +### 赛题介绍 + +本次黑客松大赛包含以下5大赛题,请报名者自行选择感兴趣的主题进行组队报名。 + +* 1. 边缘计算中的前沿AI + +利用KubeEdge、ONNX runtime在Atlas 200 DK中搭建人脸识别应用,在Atlas 200 DK上安装KubeEdge、Docker、mosquitto等组件,并连接云上k8s,搭建KubeEdge集群。实体应用为开发者可以体验如何在开源的云环境里,在ONNX Edge Runtime中添加Atlas 200 DK的插件,并配合KubeEdge来部署模型在边缘。 + +赛题详情链接: + +https://competition.huaweicloud.com/information/1000029324/introduction + +* 2. 智能识手绘 + +利用Kubernetes、Volcano、Kube-Acc、Kubeflow搭建AI流水线,开发手绘图Demo。在OpenLab(openlabtesting.org)集群环境上安装Kubernetes,Volcano, Kube-Acc,以及Kubeflow代码以组建开源AI流水线环境,并用此流水线运行DeepSBIR等模型的推理,或者基于quick-draw数据集的再训练。实体应用为开发者可以手绘某种物品的图像,通过更换模型来找到最适合的手绘图应用。 + +赛题详情链接: + +https://competition.huaweicloud.com/information/1000029293/introduction + +* 3. 微服务化的Web AI智能相册 + +本赛题在TaiShan、openEuler 的基础环境上,利用Apache ServiceComb微服务框架及其组件,开发一个具有照片智能标注,并能根据标注情况高效浏览的Web智能相册应用。 + +赛题详情链接: + +https://competition.huaweicloud.com/information/1000029327/introduction + +* 4. 数据管理的自动驾驶 + + 本赛题在华为云虚拟机中搭建SODA智能开发数据自治管理平台,利用SODA的南向控制器模块Controller、多云模块Multi-Cloud、数据智能预测模块Telemetry模块展示telemetry检测到数据,发现异常数据后,驱动控制器模块和多云模块将数据自动迁移走,达到自动发现异常,自动解决异常,恢复正常的数据自治过程。 + +赛题详情链接: + +https://competition.huaweicloud.com/information/1000029325/introduction + +* 5. ARM加速冲冲冲 + +在TaiShan服务器上安装OpenStack Nova、Cyborg、Placement等组件,搭建最小集群,HostOS使用openEuler。实体应用为开发者可以体验如何在开源的云环境里,创建一个挂载Atlas 300的虚拟机。 + +赛题详情链接: + +https://competition.huaweicloud.com/information/1000029323/introduction + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20200607.md b/web-ui/docs/zh/news/20200607.md new file mode 100644 index 0000000000000000000000000000000000000000..6d0dc062d6d32c8da030d33e2a460ae3d66f007d --- /dev/null +++ b/web-ui/docs/zh/news/20200607.md @@ -0,0 +1,271 @@ +--- +title: "开源软件供应链点亮计划 - 暑期2020 openEuler 社区任务发布" +date: "2020-05-07" +tags: + - summer2020 + - collegeStudent +banner: "img/events/summer1.png" +author: "openEuler 社区" +summary: "“开源软件供应链点亮计划-暑期2020” 是由中科院软件所与 openEuler 社区共同举办的一项面向高校学生的暑期活动,旨在鼓励在校学生积极参与开源软件的开发维护,促进国内优秀开源软件社区的蓬勃发展。openEuler 社区 Maintainer 总共发布了 16 个类别 102 个任务供参与活动的高校学生申请。" +--- + + + + + +
+ +### 1. 开源软件供应链点亮计划-暑期2020” 活动是什么? + +“开源软件供应链点亮计划-暑期2020”(以下简称暑期2020)是由 [中科院软件所](https://isrc.iscas.ac.cn/) 与 [openEuler 社区](https://www.openeuler.org) 共同举办、中科院软件研究所南京软件技术研究院承办的一项面向高校学生的暑期活动,旨在鼓励学生积极参与开源软件的开发维护,促进国内优秀开源软件社区的蓬勃发展。 + +[中科院软件所](https://isrc.iscas.ac.cn/) 和 [openEuler 社区](https://www.openeuler.org) 联合国内外开源社区,对开源软件的开发与维护提供多种难度的任务,2020 年 6 月 1 日起面向全国高校学生开放报名。学生可自主选择感兴趣的项目进行申请,在中选后获得该软件资深维护者(社区导师)亲自指导。根据项目的难易程度和完成情况,参与者还将获得“开源软件供应链点亮计划-暑期2020”活动奖金和奖杯。 [openEuler 社区](https://www.openeuler.org) 在本次活动中总共发布了 [102](https://gitee.com/openeuler/marketing/issues) 个任务,并对任务进行了分类和解释,请参见 [openEuler 社区 暑期 2020 任务详解分类](https://www.openeuler.org/zh/blog/2020/06/03/summer-2020-openeuler-tasks.html) ,访问地址: https://www.openeuler.org/zh/blog/2020/06/03/summer-2020-openeuler-tasks.html + +### 2. 浏览选择感兴趣的任务和对应的社区导师沟通 + +在 暑期2020 [任务列表](https://gitee.com/openeuler/marketing/blob/master/events/summer2020/tasks.md) 页面或本页 *openEuler 社区任务详解* 浏览选择感兴趣的任务进入到详细页面。 + +1. 在任务说明中均标有导师的邮箱,请通过邮件针对任务和导师详细沟通。 + - 如果任务有多个导师,请把所有导师的邮箱都加在收件人中。 + - 邮件标题写清楚自己的学校、姓名和感兴趣题目的编号。 + - 邮件正文首先介绍自己的基本情况,包括来自什么学校、年级和专业。 + - 列举自己参与过相关项目的的经验,举证有能力完成任务。 + - 如果在 Github、Gitee 有参与过开源项目,请提供 ID 给导师。 + - **重要** 对于完成任务有提出自己的方案,包含技术方案、时间计划等。 + - 导师会对你的方案的可行性进行指导。 + - 导师会对任务的分解进行指导。 +2. 在订阅 *Community* 邮件列表[订阅页面](https://mailweb.openeuler.org/postorius/lists/community.openeuler.org) 订阅 *Community* 邮件列表,订阅成功后向 community@openeuler.org 发送邮件针对感兴趣的任务进行咨询,编写邮件的建议同上。 + - **重要** 发送到邮件列表的申请沟通邮件可能会有机会得到社区技术大咖的额外指导机会。 +3. 准备项目申请书,第一时间报名心仪的任务。在和导师沟通的时候可以同时进行任务报名,2020 年 6 月 1 日至 6 月 20 日 期间,学生可参考 [项目申请模板](https://isrc.iscas.ac.cn/summer2020/help/assets/%E9%A1%B9%E7%9B%AE%E7%94%B3%E8%AF%B7%E6%A8%A1%E6%9D%BF.txt) 中的要求发送申请邮件给组委会邮箱 summer2020@iscas.ac.cn,提交申请材料报名。组委会将收到的申请审核后交给社区选择承担项目的学生,并于 6 月 30 日公布中选项目及承担学生的名单。编写好的项目申请书有利于提高项目申请成功的概率,在编写时建议参考组委会提供的 [如何写好项目申请书](https://isrc.iscas.ac.cn/summer2020/help/proj_apply.html#%E5%A6%82%E4%BD%95%E5%86%99%E5%A5%BD%E9%A1%B9%E7%9B%AE%E7%94%B3%E8%AF%B7%E4%B9%A6) 。 + + +### 3. 团体任务 - 参与人数 3 ~ 6 人,奖金 6 万元人民币 + +#### [No.88 - 移植 openEuler 至 RK3399 平台 - 【团体任务】](https://gitee.com/openeuler/marketing/issues/I1IJ4B) + +- **openEuler** 是一款开源操作系统。当前 **openEuler** 内核源于 Linux,支持鲲鹏及其它多种处理器,能够充分释放计算芯片的潜能,是由全球开源贡献者构建的高效、稳定、安全的开源操作系统。 +- **RK3399** 是瑞芯微推出的一款低功耗、高性能的应用处理器芯片。作为 **Firefly** 新一代的顶级开源平台, **RK3399** 凭借其高稳定性、高性能、高集成度、高扩展性而广泛用于人脸识别设备、无人机、机器人、游戏机等应用产品。 +- 本项目的目标是将 **openEuler** 移植到 **Firefly-RK3399** 上,并保证 **RK3399** 的外设均可用。 +- **本任务为团体项目,参与人数 3 -6 人,奖金 6 万元人民币。** + +_难度_ 高 + +_导师_ + +- overweight +- woqidaideshi + +_联系方式_ + +- hexiaowen@huawei.com +- yafen@iscas.ac.cn + +_产出标准_ + +- openEuler 的 RK3399 的镜像 + - 内核基于 openEuler 20.03 LTS 版本的 Linux 内核 + - 文件系统基于 openEuler 20.03 LTS 软件源制作 + - 支持 AArch64 架构 + - 支持通过 dnf 安装 openEuler 20.03 LTS 软件源中的软件包 + - 支持编译 Linux 内核 + - RK3399 的硬件模块均可用,如 音频输入输出、USB 3.0、USB 2.0、以太网、Wifi、蓝牙、红外、摄像头、GPIO 等 +- openEuler 内核适配到 RK3399 的内核源码补丁以及针对其他软件包的源码补丁 +- 镜像制作程序和文档 +- RK3399 的 音频输入输出、USB 3.0、USB 2.0、以太网、Wifi、蓝牙、红外、摄像头、GPIO 等的使用文档 + +_任务链接_ https://gitee.com/openeuler/marketing/issues/I1IJ4B + +### 4. openEuler 社区任务详解分类 + +- [openEuler](https://www.openeuler.org) 社区在 [暑期 2020](https://isrc.iscas.ac.cn/summer2020) 活动中共发布了 [102](https://gitee.com/openeuler/marketing/blob/master/events/summer2020/tasks.md) 个任务,涵盖了 Linux 、容器、云计算和编程语言等多个技术栈。参与暑期 2020 活动的同学可以通过阅读本文的深度解析,找到感兴趣和符合自身技术栈的任务,这样可以在申请任务的过程中提高成功率。同时,openEuler 社区在 June 7th, 2020 、June 8th, 2020 和 June 9th, 2020 三天点晚间 19:00 ~ 20:00 间在[ Bilibili ](https://live.bilibili.com/527064077) 进行直播,由相关任务的社区 Maintainer 为大家更为详细的讲解技术点、具体要求等,现场回答同学们的问题。 + - 关于直播活动请大家加入到暑期 2020 学生的微信群,关注微信群的时间通知。 + + + + - B 站直播计划 + - [[June 7th, 2020]] 19:00 ~ 20:00 方亚芬讲解 + - 暑期 2020 团体任务 - [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) + - [No.1 - 为 openEuler 添加 Xfce 桌面环境并能够运行在树莓派 4B 上](https://gitee.com/openeuler/marketing/issues/I1H8G3) + - [No.2 - 精简 openEuler 的树莓派 4B 镜像体积小于 500 MiB](https://gitee.com/openeuler/marketing/issues/I1H8H9) + - [No.3 - 为 openEuler 树莓派 4B 镜像提供 UEFI 启动支持](https://gitee.com/openeuler/marketing/issues/I1H8HV) + - [[June 8th, 2020]] 19:00 ~ 20:00 何晓文讲解 + - 暑期 2020 团体任务 [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) + - [No.49 - 基于 openEuler 的 ABI 检查工具](https://gitee.com/openeuler/marketing/issues/I1HQSE) + - [No.47 - 开发 openEuler bootstrap 工具](https://gitee.com/openeuler/marketing/issues/I1HAXJ) + - [[June 9th, 2020]] 19:00 ~ 20:00 蔡灏旻讲解容器技术相关任务 + - [No.7 - 构建可运行 iSulad 点容器镜像,并推送到 Docker Hub 镜像仓库](https://gitee.com/openeuler/marketing/issues/I1HVZF) + - [No.9 - iSula 相关项目支持编译 Debian 包](https://gitee.com/openeuler/marketing/issues/I1HWDZ) + - [No.10 - iSula 项目内存池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX3G) + - [No.11 - iSula 项目线程池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX5Y) + - [No.12 - iSula-kits 支持在多个 OS 发型版上运行](https://gitee.com/openeuler/marketing/issues/I1HXE7) + - [No. 13 - iSula 容器镜像构建工具支持多存储驱动](https://gitee.com/openeuler/marketing/issues/I1HXS9)- + - [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1HXS9) + - June 15th, 2020 20:00 ~ 21:00 虚拟化相关任务讲解 + - [No.52 - openEuler 虚拟化调度性能评估工具及方法构建](https://gitee.com/openeuler/marketing/issues/I1I9XJ) + - [No.6 - 虚拟化场景下的类似 top 点调测工具 virttop](https://gitee.com/openeuler/marketing/issues/I1HVM7) + - [No.66 - QEMU 中集成 virtio-fuzz 能力以支持模拟设备的模糊测试](https://gitee.com/openeuler/marketing/issues/I1IHCJ) + - [No.62 - QEMU 用户态进程热补丁框架](https://gitee.com/openeuler/marketing/issues/I1IG8E) + - June 16th, 2020 20:00 ~ 21:00 测试相关任务讲解 + - [No.69 - api-sanity-checker 与 oss-fuzz 测试结合的误报优化](https://gitee.com/openeuler/marketing/issues/I1IHNM) + - [No.34 - 对 openEuler 社区发布包 keepalived 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CG) + - [No.35 - 对 openEuler 社区发布包 kmod-kvdo 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CY) + - [No.36 - 对 openEuler 社区发布包 OpenVPN 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6D6) + - [No.37 - 对 openEuler 社区发布包 lrzsz 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6EO) + - [No.38 - 对 openEuler 社区发布包 ipvsadm 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6F2) + - [No.39 - 对 openEuler 社区发布包 MongoDB 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GM) + - [No.40 - 对 openEuler 社区发布包 Redis 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GW) + - [No.41 - 对 openEuler 社区发布包 sssd 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IK) + - [No.42 - 对 openEuler 社区发布包 MySQL 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IN) + - [No.43 - 对 openEuler 社区发布包 rpcbind 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JE) + - [No.44 - 对 openEuler 社区发布包 haproxy 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JI) + - [No.29 - 对openEuler社区发布包osc和obs-build进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I5WZ) + - June 17th, 2020 20:00 ~ 21:00 openEuler 社区之旅参与介绍 + - 介绍如何在 openEuler 社区贡献 + +1. [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) 团体项目 - **建议申请此任务的团队需要有一定的 Linux 操作系统实战能力,掌握 Linux 内核及硬件驱动相关知识,熟悉掌握操作系统引导与启动机制。** + + - [No.88 - 移植 openEuler 至 RK3399 平台](https://gitee.com/openeuler/marketing/issues/I1IJ4B) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4B + +2. Raspberry Pi 树莓派相关任务 - **建议申请此任务的同学需要有一定的 Linux 操作系统实战能力,掌握 Linux DNF/RPM 管理方案,熟悉 Linux 桌面系统的同学申请此类任务** + + - [No.2 - 精简 openEuler 的树莓派 4B 镜像体积小于 500 MiB](https://gitee.com/openeuler/marketing/issues/I1H8H9) 任务链接 https://gitee.com/openeuler/marketing/issues/I1H8H9 + - [No.1 - 为 openEuler 添加 Xfce 桌面环境并能够运行在树莓派 4B 上](https://gitee.com/openeuler/marketing/issues/I1H8G3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1H8G3 + - [No.3 - 为 openEuler 树莓派 4B 镜像提供 UEFI 启动支持](https://gitee.com/openeuler/marketing/issues/I1H8HV) 任务链接 https://gitee.com/openeuler/marketing/issues/I1H8HV + +3. Linux 桌面相关任务 - **建议申请此任务的同学掌握 Linux DNF/RPM 管理方案,熟悉 Linux 桌面系统的同学申请此类任务** + + - [No.100 - 将 UKUI 移植到 openEuler,并支持生物识别](https://gitee.com/openeuler/marketing/issues/I1IRJ3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IRJ3 + +4. Linux 容器引擎相关任务 - **建议熟悉 Linux 容器引擎技术实现(如 Docker )的同学申请此类任务** + + - [No.7 - 构建可运行 iSulad 点容器镜像,并推送到 Docker Hub 镜像仓库](https://gitee.com/openeuler/marketing/issues/I1HVZF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HVZF + - [No.9 - iSula 相关项目支持编译 Debian 包](https://gitee.com/openeuler/marketing/issues/I1HWDZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HWDZ + - [No.10 - iSula 项目内存池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX3G) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HX3G + - [No.11 - iSula 项目线程池设计与实现](https://gitee.com/openeuler/marketing/issues/I1HX5Y) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HX5Y + - [No.12 - iSula-kits 支持在多个 OS 发型版上运行](https://gitee.com/openeuler/marketing/issues/I1HXE7) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXE7 + - [No.13 - iSula 容器镜像构建工具支持多存储驱动](https://gitee.com/openeuler/marketing/issues/I1HXS9) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXS9 + - [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1HXS9) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXS9 + - [No.8 - C 语言 JSON 解析转换代码生成框架](https://gitee.com/openeuler/marketing/issues/I1HWB3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HWB3 + +5. Kubernetes 相关任务 - **建议熟悉 Kubernetes 编排调度技术的同学申请此类任务** + + - [No61. - openEuler 集成 Kubernetes 相关软件包](https://gitee.com/openeuler/marketing/issues/I1IF4R) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IF4R + - [No.91 - 用RUST实现基于FUSE的Kubernetes CSI接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No. 14 - openEuler 集成 Harbor 项目](https://gitee.com/openeuler/marketing/issues/I1HXBE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXBE + +6. 虚拟化、云相关任务 - **建议熟悉 QEMU 等虚拟化技术的同学申请此类任务** + + - [No.56 - 以 openEuler LTS 为基础生成公有云镜像](https://gitee.com/openeuler/marketing/issues/I1ICCJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICCJ + - [No.52 - openEuler 虚拟化调度性能评估工具及方法构建](https://gitee.com/openeuler/marketing/issues/I1I9XJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I9XJ + - [No.6 - 虚拟化场景下的类似 top 点调测工具 virttop](https://gitee.com/openeuler/marketing/issues/I1HVM7) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HVM7 + - [No.66 - QEMU 中集成 virtio-fuzz 能力以支持模拟设备的模糊测试](https://gitee.com/openeuler/marketing/issues/I1IHCJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHCJ + - [No.62 - QEMU 用户态进程热补丁框架](https://gitee.com/openeuler/marketing/issues/I1IG8E) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IG8E + +7. Golang 相关任务 - **建议熟悉 Golang 语言、对 aarch64 架构和算法有一定程度了解等的同学申请此类任务** + + - [No.81 - 优化Go同步包中锁或原子操作在 ARM64 上的实现,提升安全并发的性能](https://gitee.com/openeuler/marketing/issues/I1IJ86) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ86 + - [No.80 - 增强 Golang 编译器基于ARM64的智能化编译](https://gitee.com/openeuler/marketing/issues/I1IJ5W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5W + - [No.79 - Golang 编解码算法性能优化](https://gitee.com/openeuler/marketing/issues/I1IJ5T) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5T + - [No.78 - 基于ARM的硬件加速能力软硬件协同调优go数学库函数](https://gitee.com/openeuler/marketing/issues/I1IJ4X) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4X + - [No.76 - 优化golang压缩库的压缩率或压缩性能](https://gitee.com/openeuler/marketing/issues/I1IJ4M) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4M + - [No.74 - 优化Golang图像库功能和性能](https://gitee.com/openeuler/marketing/issues/I1IJ24) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ24 + - [No.73 - 增强Golang运行时库在ARM上的性能和安全性](https://gitee.com/openeuler/marketing/issues/I1IJ0J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ0J + - [No.72 - 针对Go加解密库进行ARM64相关的优化](https://gitee.com/openeuler/marketing/issues/I1IIW6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IIW6 + +8. Rust 相关任务 - **建议熟悉 Rust 语言、具有一定存储知识(部分任务需要)的同学申请此类任务** + + - [No.93 - 用 Rust 实现无锁 HashMap](https://gitee.com/openeuler/marketing/issues/I1IMNX) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMNX + - [No.92 - 用Rust实现无锁LRU缓存](https://gitee.com/openeuler/marketing/issues/I1IMNR) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMNR + - [No.91 - 用RUST实现基于FUSE的Kubernetes CSI接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No.89 - 基于Rust实现HDFS的用户态FUSE驱动](https://gitee.com/openeuler/marketing/issues/I1IMGW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMGW + - [no.87 - 基于Rust高性能HTTP库Hyper或Tide实现S3服务端](https://gitee.com/openeuler/marketing/issues/I1IMFO) 任务链接 https://gitee.com/openeuler/marketing/issues/ + +9. 存储相关任务 - **建议熟悉 Linux 存储知识的同学申请此类任务** + + - [No.91 - 用RUST实现基于FUSE的Kubernetes CSI接口](https://gitee.com/openeuler/marketing/issues/I1IMJY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMJY + - [No.89 - 基于Rust实现HDFS的用户态FUSE驱动](https://gitee.com/openeuler/marketing/issues/I1IMGW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMGW + - [No.82 - 基于 SPDK 的高性能用户态用户态文件系统](https://gitee.com/openeuler/marketing/issues/I1IKCX) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKCX + - [No.90 - 基于Perf或eBPF对FUSE进行tracing分析](https://gitee.com/openeuler/marketing/issues/I1IMIA) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMIA + +10. ARM64 相关任务 - **建议熟悉 aarch64 架构,算法有一定能力的同学申请此类任务** + + - [No.16 - 为 ARM 平台优化开源软件的 CRC 实现](https://gitee.com/openeuler/marketing/issues/I1HYCD) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HYCD + - [No.81 - 优化Go同步包中锁或原子操作在 ARM64 上的实现,提升安全并发的性能](https://gitee.com/openeuler/marketing/issues/I1IJ86) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ86 + - [No.80 - 增强 Golang 编译器基于ARM64的智能化编译](https://gitee.com/openeuler/marketing/issues/I1IJ5W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ5W + - [No.78 - 基于ARM的硬件加速能力软硬件协同调优go数学库函数](https://gitee.com/openeuler/marketing/issues/I1IJ4X) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4X + - [No.77 - 在Eigen社区中提供ARM的CI环境](https://gitee.com/openeuler/marketing/issues/I1IJ4N) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ4N + - [No.75 - Numpy 在 ARM 平台的优化](https://gitee.com/openeuler/marketing/issues/I1IJ3H) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ3H + - [No.73 - 增强Golang运行时库在ARM上的性能和安全性](https://gitee.com/openeuler/marketing/issues/I1IJ0J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IJ0J + - [No.72 - 针对Go加解密库进行ARM64相关的优化](https://gitee.com/openeuler/marketing/issues/I1IIW6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IIW6 + - [No.65 - adler32算法在ARM平台的优化](https://gitee.com/openeuler/marketing/issues/I1IGXZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IGXZ + +11. RISC-V 相关任务 - **建议熟悉 RISC-V 架构的同学申请此类任务** + + - [No.84 - 在 RISC-V 架构 openEuler 平台上提供 iSulad](https://gitee.com/openeuler/marketing/issues/I1IKQO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKQO + - [No.83 - 在 RISC-V 架构openEuler平台上提供golang支持](https://gitee.com/openeuler/marketing/issues/I1IKOI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IKOI + - [No.21 - 为openEuler - RISC-V 添加grub的引导启动方式](https://gitee.com/openeuler/marketing/issues/I1I1TS) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1TS + +12. 安全相关任务 - **建议熟悉 Linux 安全的同学申请此类任务** + + - [No.50 - 提供 openEuler 满足 openscap 标准的安全配置基线](https://gitee.com/openeuler/marketing/issues/I1I7JW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I7JW + - [No.46 - SELinux 策略应用指导](https://gitee.com/openeuler/marketing/issues/I1I7H3) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I7H3 + - [No.45 - 移植 libapparmor 到 openEuler 社区](https://gitee.com/openeuler/marketing/issues/I1I77C) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I77C + - [No.51 - optee 移植到 openEuler](https://gitee.com/openeuler/marketing/issues/I1I8IS) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I8IS + +13. 测试相关任务 - **建议测试专业的同学申请此类任务** + + - [No.69 - api-sanity-checker 与 oss-fuzz 测试结合的误报优化](https://gitee.com/openeuler/marketing/issues/I1IHNM) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHNM + - [No.34 - 对 openEuler 社区发布包 keepalived 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CG) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6CG + - [No.35 - 对 openEuler 社区发布包 kmod-kvdo 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6CY) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6CY + - [No.36 - 对 openEuler 社区发布包 OpenVPN 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6D6) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6D6 + - [No.37 - 对 openEuler 社区发布包 lrzsz 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6EO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6EO + - [No.38 - 对openEuler社区发布包ipvsadm进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6F2) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6F2 + - [No.39 - 对 openEuler 社区发布包 MongoDB 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GM) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6GM + - [No.40 - 对 openEuler 社区发布包 Redis 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6GW) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6GW + - [No.41 - 对 openEuler 社区发布包 sssd 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6IK + - [No.42 - 对 openEuler 社区发布包 MySQL 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6IN) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6IN + - [No.43 - 对 openEuler 社区发布包 rpcbind 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6JE + - [No.44 - 对 openEuler 社区发布包 haproxy 进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I6JI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I6JI + - [No.29 - 对openEuler社区发布包osc和obs-build进行加固测试](https://gitee.com/openeuler/marketing/issues/I1I5WZ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I5WZ + +14. AI、大数据相关任务 - **建议熟悉 AI 、大数据框架的同学申请此类任务** + + - [No.5 - 在 openEuler aarch64 架构上完成 PyTorch 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1HR9C) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HR9C + - [No.4 -在 openEuler aarch64 架构上完成 Tensorflow 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1HR7W) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HR7W + - [No.23 - 在 openEuler aarch64 架构上完成 Hadoop WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I290) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I290 + - [No.22 - 在 openEuler aarch64 架构上完成 mlpack 基于公开数据集完成 mnist 训练过程](https://gitee.com/openeuler/marketing/issues/I1I281) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I281 + - [No.24 - 在 openEuler aarch64 架构上完成 Spark WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I29G) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I29G + - [No.25 - 在 openEuler aarch64 架构上完成 Flink WordCount 统计过程](https://gitee.com/openeuler/marketing/issues/I1I2A0) 任务链接 https://gitee.com/openeuler/marketing/issues/ + +15. Linux 系统相关任务 - **建议熟悉 Linux 系统的同学申请此类任务** + + - [No.67 - 基于需求覆盖度判断的用例筛选方法(RBC,requirement-based coverage)探索及工程构建](https://gitee.com/openeuler/marketing/issues/I1IHGJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHGJ + - [No.98 - 众核场景下OS基础设施机制线性度探索](https://gitee.com/openeuler/marketing/issues/I1IO7D) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IO7D + - [No.97 - 优化glibc内存管理框架内容空洞导致内存占用不断增加的问题](https://gitee.com/openeuler/marketing/issues/I1IO19) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IO19 + - [No.96 - 优化nfs-utils锁以解决并发性能差问题](https://gitee.com/openeuler/marketing/issues/I1INR1) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INR1 + - [No.95 - openEuler CPU 故障隔离](https://gitee.com/openeuler/marketing/issues/I1INPO) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INPO + - [No.102 - 内核态CR(Checkpoint and Restore )用户态应用程序](https://gitee.com/openeuler/marketing/issues/I1INPF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1INPF + - [No.94 - 实现API识别软件包依赖的功能](https://gitee.com/openeuler/marketing/issues/I1IMTI) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMTI + - [No.90 - 基于Perf或eBPF对FUSE进行tracing分析](https://gitee.com/openeuler/marketing/issues/I1IMIA) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IMIA + - [No.57 - 内核数据竞争检测工具](https://gitee.com/openeuler/marketing/issues/I1ICGN) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICGN + - [No.71 - openEuler 不同系统间源码包成分信息比较](https://gitee.com/openeuler/marketing/issues/I1IHVG) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHVG + - [No.70 - openEuler 源码包成分提取、归档](https://gitee.com/openeuler/marketing/issues/I1IHUT) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IHUT + - [No.20 - LUTF - Linux Userspace Task Framework](https://gitee.com/openeuler/marketing/issues/I1I1RK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1RK + - [No.60 - everything tool on openEuler](https://gitee.com/openeuler/marketing/issues/I1IELF) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IELF + - [No. 19 - LSCA - Linux 系统调用代理](https://gitee.com/openeuler/marketing/issues/I1I1JR) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1JR + - [No. 18 - SVA (Share Virtual Address)引擎](https://gitee.com/openeuler/marketing/issues/I1I1D1) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I1D1 + - [No.17 - 库函数行为收集器](https://gitee.com/openeuler/marketing/issues/I1I06J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I06J + - [No.15 - 改进 openEuler-Advisor 来支持 openEuler 快速滚动升级](https://gitee.com/openeuler/marketing/issues/I1HXMV) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HXMV + - [No.49 - 基于 openEuler 的 ABI 检查工具](https://gitee.com/openeuler/marketing/issues/I1HQSE) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HQSE + - [No.47 - 开发 openEuler bootstrap 工具](https://gitee.com/openeuler/marketing/issues/I1HAXJ) 任务链接 https://gitee.com/openeuler/marketing/issues/I1HAXJ + - [No.33 - 基于 Posix 接口的协程框架](https://gitee.com/openeuler/marketing/issues/I1I66U) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I66U + - [No.32 - 系统资源负载预测框架](https://gitee.com/openeuler/marketing/issues/I1I64J) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I64J + - [No.31 - Linux 内核 Crash 问题自动定位工具](https://gitee.com/openeuler/marketing/issues/I1I632) 任务链接 https://gitee.com/openeuler/marketing/issues/I1I632 + +16. 开源基础设施相关任务 - **建议具有基本开发能力的同学申请此类任务** + + - [No.53 - 为 openEuler 创建用户轨迹运营看板](https://gitee.com/openeuler/marketing/issues/I1IAOD) 任务链接 https://gitee.com/openeuler/marketing/issues/I1IAOD + - [No.58 - 为 openEuler 提供 PR Preview 功能](https://gitee.com/openeuler/marketing/issues/I1ICRB) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICRB + - [No.59 - 开源基础设施智能自检自愈系统](https://gitee.com/openeuler/marketing/issues/I1ICRK) 任务链接 https://gitee.com/openeuler/marketing/issues/I1ICRK + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20200707-openeluer-live.md b/web-ui/docs/zh/news/20200707-openeluer-live.md new file mode 100644 index 0000000000000000000000000000000000000000..6b14576db6c65cd5fe580353f112a4c9c5818747 --- /dev/null +++ b/web-ui/docs/zh/news/20200707-openeluer-live.md @@ -0,0 +1,89 @@ +--- +title: "【手把手带你玩转openEuler】系列直播进行中" +date: "2020-07-07" +tags: + - openEuler + - live +banner: "img/banners/banner-20200707-openeluer-live.png" +author: "openEuler" +summary: "【手把手带你玩转openEuler】系列直播进行中" +--- + + + + + +
+ + 为了让更多人更深入认识openEuler并积极参与进来,社区将通过一系列直播和大家近距离接触,邀请openEuler开源的重要参与者、SIG组maintainer等资深专家来进行持续分享,带你深入认识openEuler,教你使用openEuler,分享如何参与到openEuler社区贡献。 + + +欢迎来B站openEuler直播间和社区讲师互动! + + + **已播出回顾:** + + **1、初识openEuler** 讲师:朱延朋 + +​ 视频回顾:https://www.bilibili.com/video/BV1it4y197KQ + + + + **​ 2、安装 openEuler** 讲师:冯涛 + +​ 视频回顾:https://www.bilibili.com/video/BV1vK4y1s7QG + + + **3、使用openEuler** 讲师:沈洋洋 + + 视频回顾:https://www.bilibili.com/video/BV13z4y1D7mq + + + **4、openEuler构建之OBS使用指导** 讲师:朱春意 + + 视频回顾:https://www.bilibili.com/video/BV1YK411H7E2 + + + **5、openEuler软件包的构建、开发与维护** + + 视频回顾:https://www.bilibili.com/video/BV1pK411J7R9 + + + **6、虚拟化介绍** + + 视频回顾:https://www.bilibili.com/video/BV1of4y1X7p1 + + + + **后续直播计划:** + +8月6号20:00(周四) iSula容器镜像构建 + +8月11号20:00(周二) 开源license©right + +8月13号20:00(周四) 如何参与 openEuler kernel 开发 + +8月18号20:00(周二) openEuler 网络配置 + + **【iSula容器系列】** + +8月20号20:00(周四) 深入理解容器镜像构建工具 isula-build + +8月25号20:00(周二) isula-build之安全特性 + +8月27号20:00(周四) 轻量级容器引擎 iSulad 之功能介绍及架构解析 + +9月1号20:00(周二) iSulad 之性能测试、分析与比较 + +9月3号20:00(周四) iSulad 之安全特性实现解析 + +9月8号20:00(周二) iSula 容器之系统容器 + +9月10号20:00(周四) iSula 容器之安全容器 + +9月15号20:00(周二) 手把手带你完成 openEuler 环境部署 K8S + + + **欢迎准时到B站openEuler直播间收看!直播间地址:http://live.bilibili.com/22290444** + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20200930.md b/web-ui/docs/zh/news/20200930.md new file mode 100644 index 0000000000000000000000000000000000000000..beaacb881928e64fe8272d60c3e20d568e55dd54 --- /dev/null +++ b/web-ui/docs/zh/news/20200930.md @@ -0,0 +1,60 @@ +--- +title: "openEuler 20.09 如约而至" +date: "2020-09-30" +tags: + - release +banner: "img/banners/openeuler2009.jpg" +author: "openEuler" +summary: "openEuler 20.09 如约而至" +--- + + + + + +
+ +# openEuler 20.09 如约而至 + +经过社区贡献者的共同努力,openEuler 正式发布了 **openEuler 20.09** 版本。根据版本计划,**openEuler 20.09** 版本属于创新版本而非 **LTS (Long Term Support)** 版本。该版本的 Linux Kernel 使用 **4.19.140** 版本,修复了自 20.03 版本发布以来发现的 CVE 漏洞。在该版本的开发过程中社区贡献者总共合并了 **11485** 个 Pull Request,SIG 组的数量也增加到了 **71** 个,覆盖了从云计算、云原生到桌面端等多个领域。同时社区开发者在 openEuler 20.09 版本中带来了众多的新特性,尤其是带来了全新的开源项目 **StratoVirt** ,它是一个安全、轻量、高性能、低损耗、组件化的面向全场景的通用化虚拟机运行时项目,同时 **iSula** 项目也发布了 **isula-build** 实现了镜像构建能力。 + +### 下载地址 +ISO 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.09/ISO/) + +Raspberry IMG 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.09/raspi_img/aarch64/) + +### 新特性列表 +- StratoVirt: + - 采用 **Rust** 语言,支持 seccomp,支持多租户隔离,提供可信安全运行环境 + - 具备 **<50ms** 的启动性能,**<4M** 的内存底噪,极致性能和轻量,适用端、边、云等多样场景 + - X86 VT,鲲鹏 Kunpeng-V 等多体系硬件加速虚拟引擎支持 + - ms 级设备扩缩能力,为轻量化负载提供灵活的资源伸缩能力 + - 设备模型可扩展,支持 PCI 等复杂设备规范,兼容 QEMU 软件生态 + - 多种计算、网络,存储加速方案支持,异构算力灵活协同 +- iSula + - 优化启动和容器生命周期操作性能 + - 容器镜像构建工具 isula-build,提供了安全、快速的容器镜像构建能力 + - 支持虚拟机安全启动和可信启动,增强虚拟机安全性 +- 虚拟化特性增强 + - 通过双层调度和 Hypervisor 感知 VM 调度,优化 VM 锁抢占,提升多核超分场景性能 + - 通过 Guest-Idle-Haltpoll 机制优化IPI中断性能,提升数据库业务性能 + - 针对 ARM 平台虚拟化特性,支持 CPU /内存热插、支持 KVM CPU 可配置为 custom 模式,提高资源配置灵活性 + - 运维工具 VMTOP,支持虚拟机陷入陷出等性能指标快速采集 + - PMU NMI watchdog 特性使能 hardlockup 检测 +- 内核特性增强 + - IMA 商用增强: 在开源IMA方案基础上,增强安全性、提升性能、提高易用性,助力商用落地 + - NUMA Aware Qspinlock 支持:减少锁竞争跨 NUMA 的 Cache 同步和乒乓,提升系统性能 + - Ktask 并行化支持:内核任务并行化框架,支持内核任务并行化运行 + - MPAM 资源管控: ARM64 架构 Cache QoS 以及内存带宽控制技术 + - 内存系统锁优化:vmalloc 分配大锁优化、Pagecache 锁优化 +- 编程语言和编译器 + - JDK8 增强:APPCDS 特性和 crc32 硬加速指令支持 + - GCC 优化:循环优化、自动矢量化、全局优化 +- 硬件和芯片使能 + - Raspberry Pi支持:Raspberry 系列板卡支持 +- 桌面支持 + - UKUI:麒麟操作系统的默认桌面环境,其布局、风格和使用习惯接近传统 Windows +- 智能运维 + - A-Tune:智能系统性能优化引擎,推理出业务特征,配置最佳的系统参数集合,使业务处于最优运行状态 + +
diff --git a/web-ui/docs/zh/news/20201225.md b/web-ui/docs/zh/news/20201225.md new file mode 100644 index 0000000000000000000000000000000000000000..623f136c5d349f33e404cc6c43ffd05f3128c780 --- /dev/null +++ b/web-ui/docs/zh/news/20201225.md @@ -0,0 +1,47 @@ +--- +title: "打造最具活力的操作系统开源社区,全产业链共享多样性算力创新价值" +date: "2020-12-25" +tags: + - theme +banner: "img/news/20201225/poster.png" +author: "openEuler" +summary: "欢迎更多企业、组织、开发者加入openEuler,共同打造最具活力的操作系统开源社区,共享多样性算力创新价值" +--- + + + + + +
+ +人类社会和商业演进正在被数字技术重新定义,数字经济已经渗透到经济活动的方方面面。数字经济的技术创新属性,使其成为世界及中国经济长期增长的重要动力。这既包括对新技术本身的创新,也包括与传统行业深度融合时新技术在应用场景的创新。因此,数字经济的实施对加快推进产业数字化转型升级提出了要求。 + +加快产业数字化转型的关键在于夯实数字化底座,硬件+操作系统是数字化底座的基础。硬件提供算力,操作系统上连应用、下接硬件,释放算力价值。新技术的发展使得数据量以指数级增长,据IDC预测,2025年全球存储数据量将达到180ZB,数据量激增带来算力需求的爆炸式增长,同时,应用场景的多样化使得单一算力很难满足产业升级带来的所有需求,多样性计算的时代正在来临。为支持多样性算力,拥抱数字化转型的需求,操作系统迎来新的挑战和机遇。 + +### 开源社区“共建、共享、共治”,打造协作创新平台 + +在以数字科技创新为引擎的经济发展新阶段,打造协同共生的计算产业生态尤为重要。为了加快多样性算力生态建设,华为计算确定“硬件开放、软件开源、使能合作伙伴”的生态战略。开源社区是社会高效协作打造软件生态的重要模式,华为把多年实践积累的软件能力开源开放出来,例如,将操作系统(EulerOS)、数据库(GaussDB)、 AI框架等系列基础软件开源开放,主导建立openEuler、openGauss、MindSpore开源社区,以加速多样性计算产业生态繁荣。 + +以openEuler社区为例,正式开源不到1年,已经有超过2000名贡献者、在全球120个城市近3万次下载、3万社区用户;吸引了包括中国移动、中国联通、银联、飞腾等60多家企业、机构和高校的加入;社区SIG特别兴趣组已增加到70多个,覆盖了内核、虚拟化、云原生、桌面等方向;openEuler社区已正式成立理事会、技术委员会等组织,通过开放治理模式,共同推动社区的繁荣和发展、技术创新与迭代。未来3~5年社区将发展千家企业、万级开发者、百万级用户,使openEuler成为最具活力的操作系统开源社区。同时,社区也会继续保持与全球开源体系融合,与各开源社区、开源项目广泛协作,积极推动全球开源软件技术生态更好的支持多样性算力。 + +### 使能合作伙伴商业发行,全产业链共享多样性算力创新价值 + +openEuler社区致力于打造成全产业共享的开源社区,在硬件厂商、基础软件厂商、应用软件厂商、系统开发商、开发者到用户的全产业链之间,形成产业正循环,打造商业可闭环的良性生态系统,从而持续、高效地创新。这就需要全产业链达成共识,保护知识产权,加快正版化,真正还原基础软件价值,为软件产业的长期、可持续创新提供市场保障。 + +坚持有所为、有所不为,华为自己不做操作系统的商业发行,全面使能合作伙伴发展自有品牌的商业版本,快速实现商业成功。现在中国主流的操作系统厂家:麒麟软件、统信软件、中科院软件所、普华基础软件、麒麟信安、拓林思等,都已加入openEuler社区并发布了商业发行版,同时也在积极参与社区贡献。其中,麒麟软件已经成为社区第二大贡献者、并在金融、电力等行业实现规模商用。 + +### 培养基础软件开发人才,激活开发者创新 + +创新循环的实质是人才驱动。创新驱动产业发展,产业发展聚集人才,人才又激发创新,从而引领产业持续发展。操作系统的开发是一项复杂而庞大的工程,围绕操作系统的内核创新、端边云多场景、安全可信等方向,需要培养大量专业人才。而中国基础软件的人才瓶颈问题突出,加快操作系统等基础软件人才培育成为重中之重。 + +华为与教育部合作建立“智能基座”产教融合协同育人基地, 与72所高校在联合课程开发和教学合作、课外实践活动和认证考试等方面开展合作,深化信息技术领域人才培养模式改革和协同创新,培养适应和引领新一轮科技创新和产业变革的卓越创新人才。 + +同时,openEuler社区与中国科学院软件研究所共同推动“开源软件供应链点亮计划”,针对重要开源软件的开发与维护提供Mini项目,向全国高校学生开放报名,学生可自主选择感兴趣的项目进行申请,并获得该项目资深维护者(社区导师)亲自指导的机会,优秀成果将进入相关开源软件的主线版本。培育创新人才是一项长期而艰巨的任务,“智能基座”产教融合协同育人基地和“开源软件供应链点亮计划”是华为激活下一代创新人才而迈出的坚实步伐。未来,我们也将坚持开放、与各界合作,共建人才生态圈。 + +
+ +数字经济是当前全球经济发展的焦点,计算产业是数字经济的底座和引擎,可持续循环的创新生态是计算产业成功的关键。华为将持续投入基础软件的创新,openEuler将秉承“共建、共享、共治”的理念,携手全产业链共建可持续发展的操作系统产业生态。 + +欢迎更多企业、组织、开发者加入openEuler,共同打造最具活力的操作系统开源社区,共享多样性算力创新价值。 + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20201228.md b/web-ui/docs/zh/news/20201228.md new file mode 100644 index 0000000000000000000000000000000000000000..fdf09a51a35ee86692d60efa4cc302855847c6bd --- /dev/null +++ b/web-ui/docs/zh/news/20201228.md @@ -0,0 +1,66 @@ +--- +title: "openEuler 20.03 LTS SP1 现已发布" +date: "2020-12-28" +tags: + - release +banner: "img/banners/openeuler2003LTSSP1.png" +author: "openEuler" +summary: "openEuler 20.03 LTS SP1是openEuler 20.03 LTS 的补丁版本,欢迎体验。" +--- + + + + + +
+ +经过社区贡献者的共同努力,openEuler 正式发布了 **openEuler 20.03 LTS SP1** 版本。此版本是openEuler 20.03 LTS 的补丁版本,生命周期与LTS版本相同。在该版本的开发过程中社区贡献者总共修复了**306**个cve,新增软件包**1400**个。 + +### 下载地址 +ISO 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/ISO/) + +Raspberry IMG 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.03-LTS-SP1/raspi_img/aarch64/) + +### 关键特性列表 +- iSula轻量级容器解决方案,统一IoT,边缘和云计算容器解决方案 + - 支持配置匿名卷,支持镜像配置匿名卷并支持本地卷的管理,方便用户使用卷管理功能 + - isula-build 支持pull、push镜像功能,支持save多个镜像到一个tarball +- A-Tune智能系统性能优化引擎,推理出业务特征,配置最佳的系统参数合,使业务处于最优运行状态。 + - 新增了增量式调优功能 + - 新增了敏感参数识别和过滤调优功能 + - 新增了虚拟机场景的调优能力 + - 支持一键式模型训练能力 +- 支持多版本JDK版本,满足不同客户对兼容性,性能和功能的诉求 + - 操作系统现在提供方便的JDK多版本支持,方便用户部署多版本Java应用 + - 支持Java 11,详见[JDK 11](http://openjdk.java.net/projects/jdk/11/) + - 支持TLS 1.3,提供安全性更高的安全协议 + - 支持Java Flight Recorder`,低性能损耗、高效率的Java应用诊断工具 + - 支持实验性质的低时延ZGC算法 + - 支持最新的STS(Short Term Support)版本,目前是JDK 15,详见[JDK 15](http://openjdk.java.net/projects/jdk/15/) + - 支持`Pattern Matching for instanceof (Second Preview)` + - 支持`生产级别的ZGC` + - 支持`生产级别的Shenandoah GC` + - 支持`Foreign-Memory Access API (Second Incubator)` + - 支持`Records (Second Preview)` +- 内核特性增强 + - 支持华为1822 HBA卡驱动 + - 支持NVDIMM提升大数据等业务场景性能 + - 支持飞腾CPU FT2000+/64通用计算 + - 支持iscsi work线程按numa亲和性绑核,提升IO性能 + - 文件缓存percpu免锁优化,减少原子开销,提升并发访问文件性能,提升Nginx场景性能 +- 虚拟化特性增强 + - ARM虚拟化支持CPU/内存热插、提高资源配置灵活性 + - 使能KVM CPU可配置为custom模式(ARM),实现虚拟机测CPU feature的自定义配置 + - 运维工具VMTOP,支持虚拟机陷入陷出等性能指标快速采集 + - 虚拟化支持安全启动,提高虚拟机安全性 +- 桌面支持 + - UKUI麒麟操作系统的默认桌面环境 + - DDE统信开发桌面系统 +- 高可靠支持 + - 由pacemaker + corosync的高可用集群软件 +- 硬件使能 + - Raspberry Pi支持:Raspberry系列板卡支持 + +### 特别说明 +

Python核心团队已经于2020年1月停止对Python 2的维护。2020年,openEuler 20.03 LTS SP1仅修复Python 2的致命CVE,并将于2020年12月31日全面停止维护。请您尽快切换到Python 3。

+
diff --git a/web-ui/docs/zh/news/2020hdc.md b/web-ui/docs/zh/news/2020hdc.md new file mode 100644 index 0000000000000000000000000000000000000000..ecab6ef76e65ff22b64c263668566733a70d3e89 --- /dev/null +++ b/web-ui/docs/zh/news/2020hdc.md @@ -0,0 +1,297 @@ +--- +title: "HDC.Cloud | openEuler黑客马拉松" +date: "2019-12-10" +tags: + - meetup + - summit +banner: "img/banners/banner-2020hdc.png?t=20191219" +author: "openEuler" +summary: "HDC.Cloud | openEuler黑客马拉松" +--- + + + + + +
+ +
+ +
+
+

竞赛简介

+ +华为HDC 2020 openEuler黑客松大赛,是华为公司面向全球操作系统爱好者举办的一场编程马拉松大赛。 + +华为在服务器操作系统领域已有近10年的技术积累,内部解决方案已广泛应用于运营商、政府、金融等行业ICT系统中。 + +华为鲲鹏处理器,兼容ARM架构,最大可集成64个物理核,采用多合一SoC芯片架构,单颗处理器实现了CPU、 RoCE网卡、SAS控制器、桥片等4颗芯片的功能, 是业界领先的数据中心处理器。 + +针对鲲鹏处理器,华为在服务器操作系统的性能、可靠性、安全性等方面做了深度优化。 + +为了促进鲲鹏计算产业的发展和生态建设,华为将内部服务器操作系统解决方案进行开源,并命名为openEuler。当前openEuler内核源于Linux,支持鲲鹏及其它多种处理器,能够充分释放硬件的计算潜能。 + +本次大赛将通过“线上初赛+线下决赛”的形式,让广大参赛者进一步体验和熟悉基于”鲲鹏处理器 + openEuler操作系统”的基础架构环境(构建、编译、部署、运行等),共同推动软硬件应用生态的创新和发展。 + +

参赛要求

+ +参赛对象:操作系统技术爱好者,如高校学生、开源社区贡献者、企业职员等,华为员工除外 + +组队要求:2人(最多)/队 + +

赛题介绍

+ +##### 初赛内容 + +各大Linux操作系统发行版的OS基础容器镜像是用户构建应用镜像的基础,其大小对使用有比较大的影响;本题目重点解决如下问题: + +1. 构建尽量小的容器基础镜像,减小应用镜像的体积 + +2. 提供跨架构的容器镜像构建工具,实现在x86平台上开发制作的容器镜像,可以在鲲鹏(ARM64)平台上运行 + +具体的要求如下: + +1. 基于openEuler ISO构建最小的基础容器镜像 + + a. 构建环境不限 + + b. 生成的镜像包含基础能力(vim,bash,yum),但是不破坏应用包之间的依赖关系 + + c. 需要给出安装的应用包列表 + + d. 尽量删除无用、冗余数据 + +2. 编码实现异构镜像构建工具,并制作基于基础镜像的最小httpd服务镜像 + + a. 在使用Intel X86处理器的本地设备(Desktop or Laptop)上通过本工具能够构建可以在基于华为鲲鹏处理器(ARM64)的服务器上运行的容器镜像 + + b. 生成的容器镜像应该符合OCI规范 + + c. 容器镜像构建工具需要具备Pull/Push/Build功能: + + Pull: + + * 参考docker命令行格式 + * 能够从容器镜像仓库中拉取public镜像 + + Push: + + * 参考docker命令行格式 + * 能够上传镜像到容器镜像仓库(支持用户名、密码配置) + + Build: + + * 参考Docker命令行格式 + * 支持最简单语法(FROM,CP,RUN,PORT,CMD) + +上述过程生成的镜像,可以在鲲鹏服务器/虚拟机上使用iSulad容器引擎正常运行。 + +##### 初赛验收标准 + +1. 参赛期间编写的代码需要公开可访问,且正确引用其他开源代码(如涉及) + +2. 镜像需要符合OCI格式 + +3. 镜像需要上传到公开可获取的镜像仓库 + +4. 应用镜像的Dockerfile需要上传到公开可获取的git仓库 + +5. 镜像可以在鲲鹏服务器(ARM64)上正常运行 + +6. 项目获胜者的递进关系如下: + + a. 完成基础镜像者晋级 + + b. 如果均完成a,完成httpd服务镜像者且能正常运行者晋级 + + c. 如果均完成b,则httpd服务镜像最小者晋级 + +##### 初赛作品提交指南 + +为了便于提交结果的自动化处理,需要以json格式组织作品信息,并以邮件正文形式发送到邮箱:,格式如下: + +``` +{ + "app_image": { + "bin_path": "bin/imagetool", <= 容器镜像构建工具 + "make_method": "make", + "url": "xxx" <= 应用容器镜像地址 + }, + "base_image": { + "bin_path": "bin/makeBase.sh", <= 基础镜像构建脚本 + "make_method": "make", + "url": "xxx" <= 基础容器镜像地址 + }, + "code_source": https://gitee.com/xxxx/xxxxx <= 容器镜像构建工具源码地址 +} +``` + +相关字段说明如下(以Golang为例) + +``` +type Image struct { + // Url表示镜像地址 + Url string `json:"url"` + // MakeMethod表示源码编译的方式(地址由CodeSource指定) + MakeMethod string `json:"make_method"` + // BinPath表示镜像生成可执行文件的地址 + BinPath string `json:"bin_path"` +} + +type work struct { + // BaseImage表示BaseImage相关信息 + BaseImage Image `json:"base_image"` + // AppImage表示AppImage相关信息 + AppImage Image `json:"app_image"` + // CodeSoure表示源代码地址 + CodeSource string `json:"code_source"` +} +``` + +##### 初赛操作指南 + +1. OCI规范请参考 - https://github.com/opencontainers/image-spec + +2. 代码实现参考项目: + + • https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html + + • https://www.tomczhen.com/2018/05/13/cross-platform-build-docker-image/ + + • https://lantian.pub/article/modify-computer/build-arm-docker-image-on-x86-docker-hub-travis-automatic-build.lantian + + • https://github.com/docker/buildx + + • https://github.com/containers/buildah + +3. openEuler操作系统请参考 - https://www.openeuler.org/ + +4. openEuler 操作系统 ISO: 点击下载 + +5. openEuler Repo源配置: 点击下载 + +6. iSulad 使用指南: 点击下载 + +7. 基于鲲鹏处理器云服务平台: 鹏城生态开发者云 - https://dw.pcl.ac.cn/cloud/login + +   申请鲲鹏虚拟机指南(请按指南内容填写相关信息, 否则资源申请请求不予批准): + +   a. 登陆https://dw.pcl.ac.cn/cloud/login, 注册新用户: + +    用户名: 以”openEuler-”为前缀 + +    邮箱: 与参赛报名时提供的联系邮箱一致 + +   b.新建项目, 指定项目信息: + +    项目名称 – 以“openEuler@hdc-”为前缀 + +    项目信息 - “其他”, 以”HDC 2020 openEuler 参赛项目”为前缀 + +    领域信息 – “其他”,“国产操作系统” + +     + +   c. 产品信息: + +    产品名称 – 以”openEuler-iSula@hdc-”为前缀 + +    产品信息 – “互联网类产品” + +    云服务器用途 – “开发” + +     + +   d. 基本信息: + +    名称 – 以”openEuler-iSula@hdc-”为前缀 + +    类型 – “虚拟机” + +    使用时长 – “90天” + +    数量 – “1” + +    CPU架构要求 – “鲲鹏920” + +    OS 版本要求 – “openEuler 1.0 Beta” + +   e. 资源: + +    CPU – 2 + +    虚拟机内存 – 4G + +    系统磁盘容量 – 80G + +    网卡数量 – 1 + +    是否申请云硬盘 – 否 + +     + +

大赛日程及报名安排

+ +##### 初赛(线上) + +  报名时间:2019年12月10日——2019年12月31日 + +  初赛时间:2019年12月23日——2020年1月17日 + +  阶段晋级队伍:共15支队伍 + +##### 决赛(线下,深圳) + +  决赛时间:2020年2月11日 + +  阶段晋级队伍:共3个等级获奖队伍 + +##### 报名方式 + +  报名邮箱: + +  报名邮件主题:openEuler黑客松报名+参赛队伍名称 + +  报名邮件内容: + +   • 参队名称 + +   • 参赛者姓名 + +   • 所在院校或公司名称 + +   • 专业或者职位 + +   • 联系电话 + +   • 联系邮箱 + +

奖项设置

+ +##### 大赛奖项 + +  一等奖:1队 + +  二等奖:2队 + +  三等奖:3队 + +##### 参赛者权益 + +1. 2020华为开发者大会入场通券,参与华为面向ICT(信息与通信)领域全球开发者的年度顶级旗舰活动 + +2. 华为开发者大会纪念版T恤 + +3. 每支初赛晋级队伍可获得树莓派4开发板1块 + +4. 获奖选手获得赛事荣誉证书 + +5. 获奖选手将在华为相关宣传渠道(官网、社区、社媒)得到宣传报道 + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20210330.md b/web-ui/docs/zh/news/20210330.md new file mode 100644 index 0000000000000000000000000000000000000000..c10e58a1a7f46a698b521e132b50f10f31931e70 --- /dev/null +++ b/web-ui/docs/zh/news/20210330.md @@ -0,0 +1,119 @@ +--- +title: "openEuler 21.03 现已发布" +date: "2021-03-31" +tags: + - release +banner: "img/banners/openeuler2103.png" +author: "openEuler" +summary: "openEuler 21.03 现已发布,欢迎体验" +--- + + + + + +
+ +# openEuler 21.03 如约而至 + +经过社区贡献者的共同努力,openEuler 正式发布了 **openEuler 21.03** 版本。根据版本计划,**openEuler 21.03** 版本属于创新版本而非 **LTS (Long Term Support)** 版本。 + +### 下载地址 +ISO 下载地址 [点击这里](https://repo.openeuler.org/openEuler-21.03/ISO/) + +Raspberry IMG 下载地址 [点击这里](https://repo.openeuler.org/openEuler-21.03/raspi_img/) + +## 关键特性 + +### 全新的5.10内核 +深度优化调度、IO、内存管理,提供Arm64、x86、RISC-V等更多算力支持。 + +- **调度器优化**,优化了 CFS Task 的公平性,新增 numa aware 异步调用机制,在 NVDIMM 初始化方面有明显的提升;优化 SCHED_IDLE 的调度策略,显著改善高优先级任务的调度延迟,降低对其他任务的干扰。 +- **numa balancing 机制优化**,带来更好的亲和性、更高的使用率和更少的无效迁移。 +- **CPU 隔离机制增强**,支持中断隔离,支持 unbound kthreads 隔离,增强 CPU 核的隔离性,可以更好的避免业务间的相互干扰。 +- **cgroup单线程迁移性能优化**,消除对 thread group 读写信号量的依赖;引入Time Namespaces 使容器迁移更方便。 +- **系统容器限制容器内使用文件句柄数能力支持**,文件句柄包括普通文件句柄和网络套接字,启动容器时,可以通过指定`--files-limit`参数限制容器内打开的最大句柄数。 +- **PSI 能力支持**,PSI (Pressure Stall Information)提供了一种评估系统资源如 CPU、Memory、IO 压力的方法。准确的检测方法可以帮助资源使用者确定合适的工作量,同时也可以帮助系统制定高效的资源调度策略,最大化利用系统资源,最大化改善用户体验。 +- **进程间通信优化**,pipe/epoll_wait 唤醒机制优化,解决唤醒多个等待线程的性能问题。 +- **内存管理增强**,精细化内存控制、统计,异构内存,热插拔、内存初始化等功能均有改善,并提供更有效的用户控制接口; 热点锁及信号量优化,激进内存规整和碎片整理,优化vmap/vmalloc机制,显著提升内存申请效率提升; KASAN、kmemleak、slub_debug、oom等内存维测特性增强,提升内存问题定位及解决效率。 +- **Early Departure Time模型切换**,解决了原来发包过程中TCP框架的限制,根据调度策略给数据包设置EDT时间戳,避免大的队列缓存带来的时延,带来tcp性能的较大提高。 +- **MultiPath TCP 支持**,可在移动与数据场景提升性能和可靠性,支持在负载均衡场景多条子流并行传输。 +- **日志 fast commit 方法引入**,EXT4 引入了新的、更轻量级的日志方法 `-fast commit`,可以大大加快 `fsync` 等耗时较长的操作,带来更好的性能。 +- **支持dm writecache 特性**,提升 SSD 大块顺序写性能,提高 DDR 持久性内存的性能。 +- **支持 io_uring**, io_uring 是一个新的异步IO框架和实现,支持 polling 模式,在polling模式下,性能提升显著,与spdk接近,在队列深度较高时性能更好。 +- **支持 ILP32**, 在鲲鹏920 Arm64 环境上支持 32 位的应用程序。 +- **IMA 商用增强**,在开源 IMA 方案基础上,增强安全性、提升性能、提高易用性,助力商用落地。 +- **支持 per task 栈检查**,增强对 ROP 攻击的防护能力。 +- **MPAM资源管控**,支持 Arm64架构Cache QoS 以及内存带宽控制技术。 +- **支持基于 SEDI 的 NMI 机制和基于 PMU 的 NMI 机制**,使能 hard lockup 检测;使能 perf nmi,能更精确的进行性能分析。 +- **Arm64 平台支持虚拟机 CPU 热插拔**,提高资源配置的灵活性。 +- **Arm64 kdump 增强**, 支持对 4G 以上地址的内存预留,使 kdump 能预留更多的内存空间,支持更大内存的机器。 +- **支持 Raspberry PI 系列板卡**,树莓派的支持已经合入原生的 openEuler 21.03 内核,可以直接使用 openEuler 21.03 内核源码调试。 +- **RISC-V 平台支持 KVM 虚拟化** +- **支持 1822 智能网卡** + +### 内核热升级 +内核热升级是一种 OS 漏洞修复及升级解决方案,实现内核快速热替换,业务不感知。 + +- **Cpu Park、Quick Kexec 特性**加速系统启停,减少宕机时间,增加系统可用性。 +- **Pin Memory、Pmem 特性**保证业务进程快速准确恢复,提升业务韧性。 +- **内核热升级控制器**提供 gRPC 通信接口,容易使用。 + +### 内存分级扩展 +支持多种内存、存储介质统一管理,系统容量平滑扩展。 + +- **冷热页面识别**,通过内核态的内存页面忙闲统计机制,精确识别进程内存页面访问冷热分布。 +- **淘汰策略可配置**,提供配置接口,可定制内存页面冷热分级策略。 +- **平滑扩展**,冷页面自动换出到扩展内存,部署在其上的软件不需要改变和适配编程方式的情况下兼容的运行。 +- **多介质扩展支持**,支持SCM、XL Flash、NVMe SSD等多种介质作为扩展内存,根据介质自身访问速度指定内存冷热分层方案,达到扩展内存并减少性能损失的目的。 + +### 虚拟化功能和可维测能力增强 +增加热迁移 Pro 能力扩展,提升可维可测能力。 + +- **热迁移Pro特性**,增强热迁移 multifd 支持 TLS,保障迁移过程数据安全;支持热迁移数据并行压缩,提升迁移性能;增加数据页面访问频率统计,支撑热迁移数据提前预测。 +- **性能调试工具(vmtop)**, 可以实时动态查看虚拟机的资源使用情况,包括CPU使用率,内存使用率等信息。新增扩展支持x86_64架构。 +- **IO悬挂支持**,IO发生错误时默认自动重试,超时会上报告警。 + +### 轻量虚拟运行时(Stratovirt) +增加弹性内存、大页功能、系统调用过滤功能,增强IO子系统提升性能和稳定性。 + +- **弹性内存支持**,根据工作负载的内存需求,实现内存的分配和回收, virtio-balloon内存回收速度达3GB/秒。 +- **大页支持**,在轻量级框架下提供大页的支持,可为轻量级虚拟机提供连续的物理内存页面,提高虚拟机内存访问效率。 +- **系统调用过滤**,简化设备模型,增加系统调用过滤支持,最简配置下仅需使用35个系统调用,有效减小系统攻击面。 +- **IO子系统增强**,支持多通道并发IO能力支持,提升性能;支持IO-QOS能力,提升虚拟机IO流量管理的灵活性和稳定性。 + +### OpenStack Victoria集成 +简单、可大规模扩展、丰富、标准统一的云管理操作系统。更多特性,请参考OpenStack Victoria官方发行说明。 + +- **集成openStack Vicoria版本**,使能基础设施即服务(IaaS)解决方案。 +- **增强块存储服务能力**,增加容量扩展、快照和虚拟机镜像克隆等高级功能。 +- **增强容器化部署和网络能力**,与容器能更好的集成。 +- **增加扩展服务支持**,支持控制面板管理、裸机部署、云资源追踪等扩展服务。 + +### Kubernetes 1.20 集成 +用于自动部署,扩展和管理容器化应用程序的云原生操作系统它更多特性,请参考Kubernetes 1.20官方发行说明。 + +- **自动上线和回滚**,Kubernetes 会自动将应用或其配置的更改后的实例上线,同时监视应用程序运行状况,失败就会回滚之前所作更改。 +- **服务发现和负载均衡**,服务发现和基于容器IP和DNS名称的负载均衡机支持。 +- **存储编排**,支持多种存储后端的自动挂载,如本地存储、NFS、iSCSI、Gluster、Ceph等网络存储系统。 +- **水平扩展**,支持命令行、UI手动操作扩展,以及基于 CPU 使用情况自动扩展方式。 + +### HA 高可用集群方案 +麒麟软件贡献的高可用集群方案,故障秒级切换,为用户提供业务连续性保障、数据持续保护、灾难恢复的高可用环境。 + +- **支持多种保护模式**,双机热备、双机互备、多机备份(N+M)等多种保护模式支持,满足业务应用各种保护需求。 +- **物理机场景和云场景双支持**,既可以在虚拟机池中进行配置高可用,也可以对物理服务器节点进行高可用保护。 +- **支持网络(包括单心跳和双心跳模式)等心跳方式**,全方位监控共享数据资源,在极端情况下保障数据的一致性。 +- **资源损耗低**,软件消耗的系统资源少,对应用部署和资源使用安全影响小。 +- **支持主流系统服务及应用软件**,如nginx、httpd、mariaDB等,支持二次开发。 +- **支持HA-WEB人机交互接口**,如用户登录、集群状态展示、资源控制等。 +- **支持HA-API集群控制REST接口**,如后端集群控制、资源管理、集群状态监控、资源状态监控等。 + +### 更多桌面环境的支持 +提供更多的开发桌面选择,更好的开发体验。 + +- **Xfce桌面支持**,Xfce是一款轻量级 Linux 桌面,与主流UI相比对资源占用小。 +- **DDE桌面支持**,是统信软件旗下的一款linux桌面环境,具有美观,易用,高效等特点。 + + +
diff --git a/web-ui/docs/zh/news/20210715.md b/web-ui/docs/zh/news/20210715.md new file mode 100644 index 0000000000000000000000000000000000000000..3f739084e62dec75aa0c96b325ee9f5299058318 --- /dev/null +++ b/web-ui/docs/zh/news/20210715.md @@ -0,0 +1,63 @@ +--- +title: "openEuler 20.03 LTS SP2 正式发布" +date: "2021-07-15" +tags: + - release +banner: "img/banners/openeuler2003LTSSP2.png" +author: "openEuler" +summary: "openEuler 20.03 LTS SP2是openEuler 20.03 LTS 的补丁版本,欢迎体验。" +--- + + + + + +
+ +经过社区贡献者的共同努力,openEuler 正式发布了 **openEuler 20.03 LTS SP2** 版本。此版本是openEuler 20.03 LTS 的第二个补丁版本,生命周期与LTS版本相同。 + +### 下载地址 +ISO 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.03-LTS-SP2/ISO/) + +Raspberry IMG 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.03-LTS-SP2/raspi_img/) + +### 关键特性列表 +#### 内存分级扩展 +支持多种内存、存储介质统一管理,系统容量平滑扩展。对于内存敏感和内热访问明显的业务,同等性能下,内存成本显著降低。 + +- **冷热页面识别**,通过内核态的内存页面忙闲统计机制,精确识别进程内存页面访问冷热分布。 +- **淘汰策略可配置**,提供配置接口,可定制内存页面冷热分级策略。 +- **平滑扩展**,冷页面自动换出到扩展内存,部署在其上的软件不需要改变和适配编程方式的情况下兼容的运行。 +- **多介质扩展支持**,支持SCM、XL Flash、NVMe SSD等多种介质作为扩展内存,根据介质自身访问速度指定内存冷热分层方案,达到扩展内存并减少性能损失的目的。 + +#### 虚拟化功能和可维测能力增强 +增加热迁移 Pro 能力扩展,提升可维可测能力。 + +- **热迁移Pro特性**,增强热迁移 multifd 支持 TLS,保障迁移过程数据安全;支持热迁移数据并行压缩,提升迁移性能;增加数据页面访问频率统计,支撑热迁移数据提前预测。 +- **性能调试工具(vmtop)**, 可以实时动态查看虚拟机的资源使用情况,包括CPU使用率,内存使用率等信息。新增扩展支持x86_64架构。 +- **IO悬挂支持**,IO发生错误时默认自动重试,超时会上报告警。 + +#### 轻量虚拟运行时(Stratovirt) +增加弹性内存、大页功能、系统调用过滤功能,增强IO子系统提升性能和稳定性。 + +- **弹性内存支持**,根据工作负载的内存需求,实现内存的分配和回收, virtio-balloon内存回收速度达3GB/秒。 +- **大页支持**,在轻量级框架下提供大页的支持,可为轻量级虚拟机提供连续的物理内存页面,提高虚拟机内存访问效率。 +- **系统调用过滤**,简化设备模型,增加系统调用过滤支持,最简配置下仅需使用35个系统调用,有效减小系统攻击面。 +- **IO子系统增强**,支持多通道并发IO能力支持,提升性能;支持IO-QOS能力,提升虚拟机IO流量管理的灵活性和稳定性。 + +#### secGear机密计算编程框架 +secGear 统一机密计算编程框架,提供了易用的开发套件,包括安全区(使用 secGear 编程会将系统区分为安全区域和非安全区域) 生命周期管理、安全开发库、代码辅助生成工具、代码构建与签名工具、安全能力和安全服务组件实现方案。可用于信任环、密态数据库、多方计算、AI安全保护等多种场景。 + +- **服务层**,提供完整的运行在安全侧的安全服务 +- **中间件层**,提供一套协议接口,满足用户基本安全应用 +- **基础层**,提供丰富的 enclave 开发接口或工具,并且在安全侧支持 C POSIX APIs 和标准 OpenSSL 接口,用户基于这些接口可以自由开发安全应用程序 + +#### OpenStack Queens/Rocky支持 +OpenStack Queens/Rocky是一款简单、可大规模扩展、丰富、标准统一的云管理操作系统,更多特性请参考OpenStack Queens/Rocky官方发行说明。[oepkg](https://repo.oepkgs.net/openEuler/rpm/openEuler-20.03-LTS-SP2/budding-openeuler/openstack/)提供软件包下载服务。 + +- **集成openStack Queens/Rocky版本**,使能基础设施即服务(IaaS)解决方案。 +- **增强块存储服务能力**,增加容量扩展、快照和虚拟机镜像克隆等高级功能。 +- **增强容器化部署和网络能力**,与容器能更好的集成。 +- **增加扩展服务支持**,支持控制面板管理、裸机部署、云资源追踪等扩展服务。 + +
diff --git a/web-ui/docs/zh/news/20211108CULinux.md b/web-ui/docs/zh/news/20211108CULinux.md new file mode 100644 index 0000000000000000000000000000000000000000..55263c5550e96765c792942d0f97267f69393f30 --- /dev/null +++ b/web-ui/docs/zh/news/20211108CULinux.md @@ -0,0 +1,30 @@ +--- +title: "中国联通CULinux自主知识产权操作系统发布" +date: "2021-11-08" +tags: + - 操作系统 +banner: "img/banners/20211108.jpg" +author: "openEuler" +summary: "中国联通操作系统开发团队设计研发的自主知识产权操作系统 CULinux(China Unicom Linux)8 日在北京发布。" +--- + + + + + +
+ +中国联通操作系统开发团队设计研发的自主知识产权操作系统 CULinux(China Unicom Linux)8 日在北京发布,该操作系统可广泛应用于服务器、边缘计算、云基础设施等多种场景。并支持多样性算力,已适配 X86 和鲲鹏、飞腾等主流国产化算力底座。 + + + 中国联通,致力于打造“云大物智链安”六大创新基础平台能力,推动各领域数字化优化升级,全方位加速数字化变革。面对国家新基建提速和 5G 快速发展,各行业需要一个可以支持底层多样化的算力架构,同时需要支持云边端协同,能够满足安全可靠要求的操作系统。 + + +中国联通一直着力发展国产化云生态,积极加入各开源社区,并在欧拉社区 OpenStack SIG 小组中负责 Maintainer 工作。基于长期技术积累,打造了 CULinux 操作系统。 + + +CULinux 结合了中国联通轻量级虚拟化、高性能网络、安全容器等技术,能够充分地支持云基座、云原生、边缘站点等多层次的技术架构。同时发挥中国联通在网络基础建设上的优势,为算网融合提供关键技术保障,实现完善统一的底层技术体系。 + +**中国联通正在围绕国家建设数字中国、智慧社会的决策部署,聚焦云网一体,立足自研云能力**,依托中国联通强大的云网融合基础设施资源优势、优质的客户群优势和安全可靠的品牌信誉,面向智慧城市、数字政府、医疗健康、工业互联网、智慧教育、生态环境、文化旅游、数字国企、智慧农业等行业客户,提供 IaaS、PaaS、SaaS、云网及云管服务,为客户提供数字化转型新基座。 + +
diff --git a/web-ui/docs/zh/news/20211117-openeuler.md b/web-ui/docs/zh/news/20211117-openeuler.md new file mode 100644 index 0000000000000000000000000000000000000000..74914705a3a634c89392100f1ebd159a8e1aa5ad --- /dev/null +++ b/web-ui/docs/zh/news/20211117-openeuler.md @@ -0,0 +1,98 @@ +--- +title: "欧拉人才发展加速计划" +date: "2021-11-17" +tags: + - openEuler + - 人才培养 +banner: "img/banners/20211117ol.png" +author: "openEuler" +summary: "凝心聚力,众智行远,培养百万欧拉人才,共筑数字经济发展人才根基" +--- + + + + + +
+ +
+ +### 欧拉人才发展加速计划简介 + +

+ + +“欧拉人才发展加速计划”是华为公司基于“智能基座-产教融合协同育人基地”的教学实践成果,围绕操作系统方向从72所高校向应用本科进一步深化推进的一项人才发展举措,旨在鼓励更多高校师生加入欧拉生态,全面加速欧拉全栈人才发展。 + +
+ +### 关键价值 + +

+ +#### 加速操作系统教材知识体系更新 + +支持老师系统性制定教学培养方案 + +#### 加速操作系统师资力量培养 + +支持优秀老师培养更优秀老师 + +#### 加速操作系统教学与开源结合 + +支持老师结合欧拉社区实现教学模式创新 + +#### 加速学生积累开源实践 + +支持学生在欧拉社区在线实习、研究创新 + +
+ +### 享有权益 + +

+ +##### 加入欧拉人才发展加速计划后,申请单位可以享受如下权益 + +
+ +| 权益项目 | 数量 | 权益说明 | +| -------------------------------------------------- | ------------------------ | ------------------------------------------------------------ | +| 可参加“欧拉操作系统课程建设园丁奖”年度评选 | 10位老师 | 鼓励老师在教材书籍和教学培养方案中系统性融入欧拉自主创新技术的最新成果 | +| 可参加“欧拉操作系统授业传道杰出教师贡献奖”年度评选 | 10位老师 | 鼓励优秀老师培养更优秀老师 | +| 可参加“欧拉操作系统教改创新杰出青年教师奖”年度评选 | 10位老师 | 鼓励青年老师基于欧拉社区开源技术和开源模式,实现教改创新 | +| 可参加“欧拉社区开源贡献高校卓越奖”年度评选 | 社区贡献前30加盟高校 | 鼓励老师在欧拉社区参加开源项目,建设教学训战平台 | +| 可参加“欧拉社区开源贡献精英奖学金”年度评选 | 社区贡献前30加盟高校学生 | 鼓励学生在欧拉社区参加开源项目、在线实习、开展毕设课题 | +| 可参加“欧拉学术研究金匠奖”年度评选 | 10个项目 | 鼓励学生基于欧拉进行原创性科学研究、在国际国内高水平会议和期刊上发表学术论文 | +| 可获得操作系统课程欧拉融入教学课程包 | 1套 | 支持操作系统课程欧拉知识融入 | +| 可获赠HCIA-openEuler认证考试券 | 1套 | 鼓励学生参加HCIA-openEuler认证考核 | +| 可获赠微认证考试券 | 1套 | 鼓励学生参加欧拉微认证考核 | +| 优先受邀参加“欧拉操作系统教学研讨会” | \- - | \- - | +| 优先受邀参加“鲲鹏众智计划”开发项目 | \- - | \- - | +| 优先获得“鲲鹏优才实习计划”岗位推荐 | \- - | \- - | +| 优先获得“欧拉生态创新中心”开放资源 | \- - | \- - | +| 可受邀合作“鲲鹏&昇腾产教融合育人基地” | \- - | \- - | + +注:具体奖励方案即将公布,敬请期待 + +
+ +### 申请要求 + +

+ +##### 满足如下条件,即可申请加入欧拉人才发展加速计划 + +
+ +| 要求 | 标准 | +| ---------------------------------------------------- | ---- | +| 国家教育部认定的高等院校 | 必选 | +| 加盟院系操作系统理论课程与实验课程融入欧拉知识点 | 必选 | +| 加盟院系入驻欧拉开源社区 | 必选 | +| 加盟院系鼓励学生在欧拉社区实习实践,实习结果计入学分 | 必选 | + +注:具体申请流程即将公布,敬请期待 + + +
\ No newline at end of file diff --git a/web-ui/docs/zh/news/20211231.md b/web-ui/docs/zh/news/20211231.md new file mode 100644 index 0000000000000000000000000000000000000000..7eff3c59d00a6be333660e3b87de95c1b67741f6 --- /dev/null +++ b/web-ui/docs/zh/news/20211231.md @@ -0,0 +1,64 @@ +--- +title: "openEuler 20.03 LTS SP3 正式发布" +date: "2021-12-31" +tags: + - release +banner: "img/banners/openeuler2003LTSSP3.png" +author: "openEuler" +summary: "openEuler 20.03 LTS SP3是openEuler 20.03 LTS 的补丁版本,欢迎体验。" +--- + + + + + +
+ +经过社区贡献者的共同努力,openEuler 正式发布了 **openEuler 20.03 LTS SP3** 版本。此版本是openEuler 20.03 LTS 的最后一个补丁版本,生命周期与LTS版本相同。 + +### 下载地址 +ISO 下载地址 [点击这里](https://repo.openeuler.org/openEuler-20.03-LTS-SP3/ISO/) + +
+ +## 关键特性 + +### KubeOS容器操作系统 + +云原生是云计算发展的下一跳、k8s事实上已经成为云原生软件基础设施的底座。业界主流操作系统厂商都推出了针对云原生场景的OS,如Rehat RCHOS,AWS BottleRocket等,实现OS容器化部署、运维,提供与业务容器一致的管理和运维体验 +openEuler适应云原生发展趋势,推出容器化操作系统KubeOS,实现云原生集群OS的统一容器化管理,具备如下特点: + +- OS容器化管理、对接K8S,原子化的生命周期管理; +- OS轻量化裁剪,减少不必要的冗余包,可实现快速升级、替换等。 + +**应用场景**:基于K8S容器云平台的业务节点服务器主机OS的容器化管理,提供容器业务相同的生命周期管理和运维体验; + +### Eggo K8s部署工具 + +Eggo是openEuler云原生Sig组K8S集群部署管理项目,提供高效稳定的集群部署集群的能力。支持单集群多架构、支持在线和离线部署模式多种部署模式,结合GitOps管理能力、感知集群配置变化,驱动集群OS统一高效部署。 + +- **集群配置版本化管理**,配置统一Git repo版本化管理,使用仓库汇总和跟踪集群的配置信息 +- **配置感知**, GitOps会感知git配置库中集群配置信息的变化,给部署引擎发起集群相应的操作请求 +- **部署引擎**,部署引擎负责下发任务给业务集群,触发部署业务集群、销毁业务集群、新增节点和删除节点等任务 + +**应用场景**:X86/ARM双平面云基础设施,基于K8S云原生框架,实现OS统一集群化部署、监控、审计等场景 + +### OpenStack Train支持 + +OpenStack Train是一款简单、可大规模扩展、丰富、标准统一的云管理操作系统,更多特性请参考OpenStack Train官方发行说明。 + +- **集成openStack Queens/Rocky版本**,使能基础设施即服务(IaaS)解决方案。 +- **增强块存储服务能力**,增加容量扩展、快照和虚拟机镜像克隆等高级功能。 +- **增强容器化部署和网络能力**,与容器能更好的集成。 +- **增加扩展服务支持**,支持控制面板管理、裸机部署、云资源追踪等扩展服务。 + +### 桌面支持 + +- Kiran麒麟信安桌面系统:是一款以用户和市场需求为主导的稳定、高效、易用的桌面环境,主要包括了桌面、任务栏、托盘、控制中心和窗口管理等组件。 + +### 兼容性清单 + +- 上线[北向兼容性清单](https://www.openeuler.org/zh/compatibility/) +- 支持intel ice lake + +
diff --git a/web-ui/docs/zh/news/20220402.md b/web-ui/docs/zh/news/20220402.md new file mode 100644 index 0000000000000000000000000000000000000000..a2b6234a653a350681f69f9040b594892c9c06ee --- /dev/null +++ b/web-ui/docs/zh/news/20220402.md @@ -0,0 +1,34 @@ +--- +title: "openEuler 22.03 LTS 正式发布" +date: "2022-04-02" +tags: + - release +banner: "img/banners/openeuler2203LTS.png" +author: "openEuler" +summary: "openEuler 22.03 LTS是欧拉首个支持全场景融合的社区长周期版本,欢迎体验。" +--- + + + + + +
+ +2022年3月31日,openEuler 22.03 LTS 如期而至。 + +openEuler 22.03 LTS 是欧拉完成正式捐赠后发布的首个共建社区版本。此版本也是欧拉首个支持全场景融合的社区长周期版本,满足服务器、云计算、边缘计算和嵌入式四大场景的多种不同类型设备部署要求和应用场景。作为长周期版本,openEuler 22.03 LTS 面向不同场景采用统一的 Linux Kernel 5.10 内核,面向服务器、云计算、边缘计算和嵌入式实现了统一构建、统一 SDK、统一联接,方便开发者构建面向全场景的数字基础设施操作系统。 + +openEuler 22.03 LTS 合入了 openEuler 三个创新版中经过商业验证的创新特性,并针对四大场景首次发布新增特性,共新增代码 2300 万行。 + +针对四大场景提供不同系统镜像: + +- 服务器场景:openEuler 22.03 LTS Server +- 云计算场景:openEuler 22.03 LTS Cloud +- 边缘计算场景:openEuler 22.03 LTS Edge +- 嵌入式场景:openEuler 22.03 LTS Embedded + +openEuler 22.03 LTS 全面支持多样性计算,包括鲲鹏、英特尔、飞腾、申威、龙芯、兆芯等主流芯片。全面支持 Intel Icelake,并且提供了对下一代 Intel Sapphire Rapids 的基础支持,其他特性将陆续合入到 openEuler 22.03 LTS 后续的更新中。 + +**openEuler 22.03 LTS:**[点此下载](https://repo.openeuler.org/openEuler-22.03-LTS/) + +
diff --git a/web-ui/docs/zh/news/openeuler summit2021.md b/web-ui/docs/zh/news/openeuler summit2021.md new file mode 100644 index 0000000000000000000000000000000000000000..1fa7f72c16243d63f9c7cd9d10c3be64cf8b642f --- /dev/null +++ b/web-ui/docs/zh/news/openeuler summit2021.md @@ -0,0 +1,297 @@ +--- +title: "盘点 | openEuler Summit 2021精彩时刻" +date: "2021-12-01" +tags: + - summit + - 2021 +banner: "img/banners/summit-2021.jpg" +author: "leikeke" +summary: "11月10日,openEuler Summit 2021在北京如期举行。" +--- + + + + + +
+ +关于11月10日, openEuler Summit 2021在北京举行。本次峰会是欧拉捐赠之后的首次峰会,也是社区一年一度的盛事。
+ +欧拉开源社区的开发者们共同见证了欧拉(openEuler)开源社区的重大进展,其中包括:**欧拉开源社区理事会升级、欧拉开源社区技术委员会换届升级、“开源雨林”企业开源赋能计划迎来新伙伴等。
+ +### 操作系统成为数字变革的关键力量 +
+ +随着全球数字化进程的加快,对数字基础设施提出了新的挑战,操作系统作为数字基础设施的根技术已经成为数字变革的关键力量。
+ +**作为我国首个开源基金会,开放原子开源基金会致力于推动全球开源产业的发展。** +
+ +**开放原子开源基金会理事长杨涛**在致辞时表示:开放原子将通过中立、开放、透明的运营和治理,帮助欧拉开源项目在开发者聚集、核心技术提升、知识产权合规、生态发展等方面进一步提速;同时将促进该项目与其他开源项目之间的能力共享、生态互通,做到协同发展、共同壮大。
+ + + +
+ +开放原子开源基金会理事长 杨涛 + +

+ +**欧拉开源社区理事长江大勇**表示,欧拉开源社区在捐赠后的一年内,社区治理模式将采用架构平移的方式,维持现有的治理模式不变。欧拉开源社区继续从技术、生态、商业三个层面协同发展,互相促进,并在开源文化建设、人才培养持续投入。作为开源实践者,欧拉做出了有益的探索,正走出一条开源共建的创新之路。
+ + +
+ +欧拉开源社区理事长 江大勇 + +

+ + +**国内开源泰斗陆首群对欧拉进行了极高评价:**“欧拉开源社区通过不到两年的社区化运作,已从华为一家贡献过渡到汇集数百厂商、上万开发者联合贡献。昨天openEuler正式宣布捐献给开放原子开源基金会进行孵化,我相信将更能体现开源的开放、共享、协同开发的威力。当今,拥抱开源的欧拉操作系统,作为数字基础设施的根技术,将成为推动数字化变革、数字化转型、智能化重构的关键。”
+ + +
+ +原国务院信息办常务副主任
+中国开源软件推进联盟名誉主席 陆首群 + +

+ +### 欧拉开源社区理事会升级 +
+ +欧拉开源社区理事会在社区成长的过程中起到了关键作用,负责指导社区发展方向、基础设施建设,面向全球各行业宣传和推广社区工作,吸引生态合作伙伴、科研机构和开发者加入到欧拉大家庭。
+ +经过欧拉开源社区理事会的评议和选举,麒麟软件有限公司副总裁韩乃平先生和中国科学院软件研究所副所长武延军先生,新晋成为欧拉开源社区理事会副理事。中国移动云能力中心和北京百度网讯科技有限公司作为新成员正式加入,欧拉开源社区理事会成员公司达到 15 家。
+ + +
+ +欧拉开源社区理事会升级仪式 + +

+ +### 欧拉开源社区技术委员会换届升级 +
+ +本次大会迎来新的技术委员会换届。技术委员会是欧拉开源社区的技术领导机构,可决策社区技术的发展愿景和方向,引导技术创新,构建社区的核心竞争力。新一届技术委员会将会带领社区继往开来,引领中国操作系统技术发展,带领社区开发者共建数字基础设施开源操作系统的技术领导力。
+ + +
+ +欧拉开源社区技术委员会换届升级仪式 + +

+ +### 全场景构建 唯有无边界开放才能无止境增长 +
+ +**欧拉开源社区技术委员会主席胡欣蔚**在分享中表示:正是因为社区有这样对于核心能力的投入,对于社区基础设施的投入,有社区这么多开发者共同的协同,有我们对于创新,对于长生命周期版本的维护,所以我们当前对于多样性算力,对于多样化的硬件以及场景有了全方面的发展。
+ +不同的操作系统在不同的领域里面,最开始可能正是因为多样化发展,使得这些嵌入式操作系统做得成功,但这些成功随着时代的发展,原来的成功正在成为进一步发展的阻力,这些阻力应该被打破。
+ + +
+ +欧拉开源社区技术委员会主席 胡欣蔚 + +

+ + +### 欧拉生态多样性场景展示 +
+ +**在本次峰会上,来自中国电信、中国移动、中国联通、招商银行、华为、中科创达、品高软件的社区核心开发者联手为大家带来了精彩的openEuler联合创新成果演示,包括:A-Tune、A-OPS、Eggo、iSula、StratoVirt、OpenStack、etMem、EulerFS社区原创项目在生产环境的场景落地。**
+ +伴随越来越多的厂商、研究机构和大学积极在社区里面深入探讨和协作,欧拉开源社区未来将会孵化更多的先进项目,也将在各个行业的核心系统持续推进部署和应用。
+ +### **社区OSV伙伴及用户行业实践案例分享** +
+ +在该环节,中国银行及麒麟软件、中国移动及SUSE、国家电网用户及麒麟信安、中邮信科及统信软件带来了四场关于行业实践案例分享的联合演讲。
+ +**中国银行股份有限公司信息科技部总工室、主管级高级经理王伟南:**
+ +我们和麒麟软件公司有深入合作,从去年开始,选取了七八个生态系统,为了保证正式运行,主要先选用办公类的。 + + +今年大概有十几套系统会按期投产,年底大概有二十套系统都会使用麒麟操作系统进行试点推进,我们也会进一步的明确中国银行下一步的规划,特别是包括私有云平台,数据服务,大数据平台,企业级架构,中间业务平台,手机银行,网上银行这种关键的渠道类的平台,包括柜面的关键系统,都会进入加速迭代更换的过程中,这也会加速麒麟操作系统在我行运行的规模。 + + +中国银行将携手麒麟软件,为中国金融科技数字化转型以及国产化生态发展做出贡献! + + +
+ +中国银行股份有限公司信息科技部总工室、主管级高级经理 王伟南 + +

+ + + **欧拉开源社区用户委员会主席、麒麟软件有限公司高级副总裁高巍:** + + + +麒麟软件一直深度参与社区建设,秉承、共享、共建、共治的社区发展理念。我们共同打造强硬核优秀的商业发行版,更具专业化的交付和服务,麒麟软件在近两年的过程中也取得了不俗的成绩。由麒麟发起主导六个主社区,积极参与67个SIG组签约超过150人,PR贡献达到两千三百多个。 + + + +欧拉已经站到了一个新的里程碑,站到了一个新的舞台,所以社区需要更多的黑科技,更多的硬实力,但同时我们需要一个优秀的商业发行版,更需要极具专业度的服务,使我们的生态真正满足用户的需求。“欧拉+麒麟”的技术路线代表着最硬核的社区、最优秀的产品和最具专业度的服务。 + + + +**欧拉立根,麒麟遨天!“欧拉+麒麟”将共同打造满足用户需求的中国操作系统核心力量!** + + +
+ +欧拉开源社区用户委员会主席、麒麟软件有限公司高级副总裁 高巍 + +

+ + **中国移动信息技术中心、高级技术专家任林:** + + +新世纪开源软件所涉及到的领域越来越宽,一大批优秀的开源软件如雨后春笋,在整个行业里高举了共享,共赢,包容,开放、创新的大旗,欧拉社区正在成为业界最有活力的社区之一。 + + +展望未来基于欧拉的操作系统发展,离不开上下游企业的联动,我们愿意与欧拉社区的同道们一起努力,通过聚合开源产业,开放、创新优势,从而持续提升科技供给能力,汇聚创新发展合力,激发科技创新的活力,为助力建设网络强国,科技中国,智慧社会做出我们的贡献。 + + +
+ +中国移动信息技术中心、高级技术专家 任林 + +

+ + **SUSE大中华区董事长江永清:** + + + +我们要带领欧拉社区一起做好,通过SUSE在开源领域的深厚积累,既能帮助欧拉成长壮大,同时也能更好地服务中国客户,更重要在于能够帮助欧拉走向全球市场。欧拉铸就中国魂,SUSE实现全球梦! + + +
+ +SUSE大中华区董事长 江永清 + +

+ + + **国家电网用户代表吕继锋:** + + + +在建设智能电网调度控制系统中,我们选用了麒麟操作系统欧拉版本,由麒麟操作系统提供了全面的四级的安全防护,在电网对于调度控制系统最大的要求之一实际上就是安全,所以说等级比较高,安全的这个四级,这里面提到了安全可信度三权分立,还有应用进程白名单,安全审计这几块部分。 + + + +除了提供了安全防护以外,欧拉版本也为运力提供了定制的功能模块。麒麟信安操作系统是电力调度领域里面重要的操作系统厂商,我们将一如既往的进行相应的电力调度控制系统的建设。 + + +
+ +国家电网用户代表 吕继锋 + +

+ + + **麒麟信安总裁王攀:** + + + +之前我们国内所有的操作系统都是基于Linux技术线路,大家选择的开源的社区版本有不同,因此给我们带来了很多重复开发和重复投入,生态割裂的问题。 + + + +我们国内迫切需要一个属于中国自己的开源操作系统的社区,欧拉顺势而为,我们国内的大批国产操作系统以及合作伙伴都积极加入到社区,麒麟信安也和大家一样坚持共赢共治,参与到欧拉的社区。 + + + +2019年麒麟选择欧拉的线路之后,基于欧拉形成的商业版本已经完成了和华为泰山服务器的认证。 + + +
+ +麒麟信安总裁 王攀 + +

+ + + **中邮信科李传波:** + + + +我们从技术时代主要就是采用国产化+开源。因为从企业应用的角度来讲,纯粹的国产化技术有些地方可能还在发展过程中,那么我们还是从需求出发尽量选择国产化的技术,在此基础上进行补充,构建成了支撑企业架构的应用。 + + + +那么对下平台目前已经实现了X86等等这些国产化包括存储方面,那么我们的云主要的特点分层解耦,那么我们在此基础上,兼容适配所有的标准化的这种金融ISSA,那么这样的话ISSA完成了分离解耦对业务提供统一的技术支持。 + + +
+ +中邮信科 李传波 + +

+ + + **统信软件CTO张磊:** + + + +对于服务器来说有个非常重要的,高存储高性能,高性能方面的话我们今年做了一些比较大的努力,主要在两个方面一个是调度上优化,一个是系统配置上以及边缘参数等等。这些工作使得我们今年国际操作系统得到了很大的提升,在这里可以看到不同的平台上都有或大或小非常明显的体系。 + + + +所以可以有效的保障我们用户的业务系统运行支撑。那么在高可用方面它是非常重要的一点,我们考虑到各个环节,包括网络,包括存储,包括应用,包括数据。所以不管在哪一点,我们都可以让用户的系统得到很好的保障。 + + +
+ +统信软件CTO 张磊 + +

+ + +随后,**华为操作系统首席科学家、中央软件院副总裁,上海交通大学特聘教授、博导陈海波**在线上给现场观众带来了《仰望星空-操作系统前沿发展思考》的主题演讲。 + +他在演讲中表示: + + + +操作系统承上(应用),启下(硬件),是系统的“魂”。面向未来我们要从传统的单一操作系统思路,也就是One OS For All转变为打造一组有竞争力的操作系统能力集合, for all,面向不同场景需求进行组合,从而打造一个优秀的弹性架构。 + + + +业界正在以从CPU为中心的算力演进到以XPU为中心的多样化协同算力,因此操作系统也要与这个演进的的过程相适应。从而对操作系统而言,我们也将从CPU上的一个单一OS演进为XPU上的一组高效协同的操作系统。 + +### “开源雨林”企业开源赋能计划迎来新伙伴 +
+ +本次峰会上,来自华为云与计算开源业务总经理堵俊平分享了“开源雨林”企业开源赋能计划的最新进展。
+ +**中科院软件所加入了“开源雨林”企业开源赋能计划,同时该计划得到开放原子开源基金会的支持。该计划旨在通过开源课程、咨询服务和联创项目等形式,提升企业开源能力,汇聚全产业链的力量,推动全行业软件创新。** + + +
+ +华为云与计算开源业务总经理 堵俊平 + +

+ + +### 六大技术专场精彩纷呈 +
+ +此外,内核分论坛、云&虚拟化分论坛、安全&可靠性&运维分论坛、兼容性分论坛、边缘&嵌入式分论坛、分布式&多样性计算分论坛 6 大技术专场同期举行,分论坛聚焦操作系统几大核心维度开展深度探讨,全面介绍操作系统、多样性计算等领域的前沿实践经验与技术干货。
+ +openEuler Summit 2021由开放原子开源基金会指导,欧拉开源社区联合麒麟软件、麒麟信安、SUSE、统信软件共同主办。本次大会齐聚产业界代表,共议产业政策、商业验证、技术创新、生态共建等话题,推动操作系统产业发展,加速开源社区建设,以技术创新助力产业实现新增长。 + +
+ + \ No newline at end of file diff --git a/web-ui/docs/zh/other/brand/README.md b/web-ui/docs/zh/other/brand/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d9adc2be304fe14ea9b877521515b2d9c931aae8 --- /dev/null +++ b/web-ui/docs/zh/other/brand/README.md @@ -0,0 +1,6 @@ +--- +title: "品牌" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/legal/README.md b/web-ui/docs/zh/other/legal/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c1811bedb065435eac96dbabc4c369e536766446 --- /dev/null +++ b/web-ui/docs/zh/other/legal/README.md @@ -0,0 +1,67 @@ +--- +title: "法律声明" +--- + + + +
+ +本法律声明包含openEuler社区的若干法律政策。这些政策适用于本网站以及openEuler社区项目发布。 + +## 规则及openEuler网站访问条件 + +openEuler网站指由openEuler社区运营的网站,域名为。以下规则适用于所有访问openEuler网站的用户或浏览者,openEuler社区保留根据国家法律法规及市场行情等变化修改这些规则的权利。访问openEuler网站的权利由openEuler社区根据下列条款授予。如果您不同意下列任何条款、请停止使用本网址。如果您使用服务,您的使用行为将被视为对本声明全部内容的认可。对于违反这些规则的行为,openEuler社区有权采取法律和公平的补救措施。 + +## 个人信息的保护 + +openEuler社区尊重访问本网站的任何个人信息。当您访问本网站的时候可能被要求提供您个人的基本资料(如姓名、电子邮件、电话号码等),您可以自行选择是否提供。对于您提供的个人信息,openEuler社区将根据中华人民共和国相关法律进行保密并严格保管,不会将这些信息以任何方式提供或展示给任何第三方,但下述情况除外: + +(一)在获取您明确同意情况下的共享。在向您告知第三方的名称或者姓名、联系方式、处理目的、处理方式和个人信息的种类,且获得您的明确同意后,openEuler社区会向您同意的第三方共享您授权范围内的信息; + +(二)在法定情形下的共享。根据适用的法律法规、法律程序、诉讼/仲裁、政府的强制命令、监管要求而需要共享您的个人信息; + +(三)在法律要求或允许的范围内,为了保护您或社会公众的利益、财产或安全免遭损害而有必要提供您的个人信息给第三方; + +(四)为了保护国家安全、公共安全以及您和其他个人的重大合法权益而需要共享您的个人信息; + +(五)您自行公开的或者其他已经合法公开的您的个人信息。 + +## 不承诺责任声明 + +openEuler网站所载的材料和信息,包括但不限于文本、图片、数据、观点、建议、网页或链接,openEuler社区力图在网站上提供准确的材料和信息, +但openEuler社区并不保证这些材料和内容的准确、完整、充分和可靠性,并且明确声明不对这些材料和内容的错误或遗漏承担责任, +也不对这些材料和内容作出任何明示或默示的、包括但不限于有关所有权担保、没有侵犯第三方权利、质量和没有计算机病毒的保证。 +openEuler社区可以在没有任何通知或提示的情况下随时对openEuler网站上的内容进行修改,为了得到最新版本的信息,请您定时访问openEuler网站。 +openEuler社区在openEuler网站上所提及的非openEuler产品或服务仅仅是为了提供相关信息,并不构成对这些产品、服务的认可或推荐。 +openEuler社区并不就网址上提供的任何产品、服务或信息做出任何声明、保证或认可。 +鉴于提供的部分服务属于电子公告牌(BBS)服务, +上关于其会员或其会员发布的相关信息(包括但不限于用户名称、公司名称、 联系人及联络信息,相关图片、视讯等)的信息均是由会员自行提供, +会员依法应对其提供的任何信息承担全部责任。 +任何企业或个人认为网页内容(包括但不限于会员发布的商品信息)可能涉嫌侵犯其合法权益,应该及时向openEuler社区提出书面权利通知,并提供身份证明、权属证明、具体链接(URL)及详细侵权情况证明。 +openEuler社区在收到上述法律文件后,将会依法尽快移除相关涉嫌侵权的内容。 + +## 著作权说明 + +openEuler网站所载的所有材料或内容受版权法的保护,所有版权由openEuler社区拥有,但注明引用其他方的内容除外。未经openEuler社区或其他方事先书面许可,任何人不得将openEuler网站上的任何内容以任何方式进行复制、经销、翻印、传播、以超级链路连接或传送、以镜像法载入其他服务器上、存储于信息检索系统或者其他任何商业目的的使用,但对于非商业目的的、用户使用的下载或打印(条件是不得修改,且须保留该材料中的版权说明或其他所有权的说明)除外。 + +## 商标 + +openEuler网站上使用和显示的所有商标、标志皆属openEuler社区所有,但注明属于其他方拥有的商标、标志、商号除外。未经openEuler社区或其他方书面许可,openEuler网站所载的任何内容不应被视作以暗示、不反对或其他形式授予使用前述任何商标、标志的许可或权利。未经事先书面许可,任何人不得以任何方式使用openEuler社区的名称及openEuler社区的商标、标记。 + +## 第三方链接 + +openEuler网站可能保留有与第三方网站或网址的链接,访问这些链接将由用户自己作出决定,openEuler社区并不保证这些链接上所提供的任何信息、数据、观点、图片、陈述或建议的准确性、完整性、充分性和可靠性。openEuler社区提供这些链接仅仅在于提供方便,并不表示openEuler社区对这些信息的认可和推荐,也不是用于宣传或广告目的。 +## 网站的更新与变更 + +openEuler网站提供的本网站上的内容仅为方便您获取信息,openEuler网站有权单方面在任何时间,对本网站的内容进行变更或更新,此种变更或更新无需以通知您或任何第三方为前提。您承认并接受上述变更或更新。我们建议您定期访问本网站以尽快获知有关的更新或变更的信息。 + +## 适用法律与争议解决 + +您同意,与您访问或使用本网站相关的所有事项,应根据中华人民共和国法律解释、理解和管辖。您同意,中国广东省深圳市有管辖权的法院具有相关的管辖权。 + +
\ No newline at end of file diff --git a/web-ui/docs/zh/other/lifecycle/README.md b/web-ui/docs/zh/other/lifecycle/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4bb92d0394c5d18d50d03be8659e62a02bab3134 --- /dev/null +++ b/web-ui/docs/zh/other/lifecycle/README.md @@ -0,0 +1,41 @@ +--- +title : "openEuler版本规划及生命周期" +--- + +
+ +## 1、openEuler社区版本生命周期管理规范(总体) + +社区版本按照交付年份和月份进行版本号命名。例如,openEuler 20.09于2020年09月发布。 + +社区版本分为长期支持版本和创新版本。 + +- **长期支持版本**:发布间隔周期定为2年,提供4年社区支持。社区首个LTS版本openEuler 20.03 LTS于20年3月发布,基于5.10内核的openEuler 22.03 LTS于22年3月发布。 + +- **社区创新版本**:openEuler每隔6个月会发布一个社区创新版本,提供6个月社区支持。下一个社区创新版本将于2022年9月发布。 + +![](./lifecycle.png) + +
+
+ +## 2、openEuler社区版本生命周期管理规范(LTS+SP) + _* 方案已经在TC和Release SIG汇报,并完成了社区邮件列表公示(2022/3/15~2022/3/31)_ + +![](./lts-sp-lifecycle.png) + +- 目前LTS版本**全版本**生命周期4年( 2+2 ),到生命周期结束前半年~1年由**相关团队组建联合维护团队,申请**延长至6年 + +- LTS版本SP版本生命周期原则上按照小SP(6月份Release,可选) 9个月,大SP (12月份Release)24个月执行;**大规模使用**建议选择大SP + +- SP0**默认执行大SP策略**,可基于社区使用情况和社区规则提前半年~1年审视是否提前结束;SP3作为LTS最后一个SP,随LTS全版本生命周期结束 + +- Maintenance Support:CVE、Bugfix,新硬件支持和少量新特性(保证LTS内前向兼容的情况) + +- Extend Support:修复"主要"以上CVE和Bug + +- 单个版本生命周结束前,以邮件和公告的方式提前3个月知会 + +
+ +
\ No newline at end of file diff --git a/web-ui/docs/zh/other/lifecycle/lifecycle.png b/web-ui/docs/zh/other/lifecycle/lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..cb0a0b6dc24dc4546dd285a15e9e1fd881b0ed3a Binary files /dev/null and b/web-ui/docs/zh/other/lifecycle/lifecycle.png differ diff --git a/web-ui/docs/zh/other/lifecycle/lts-sp-lifecycle.png b/web-ui/docs/zh/other/lifecycle/lts-sp-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..620d8467d2836325b1881b9186af06106ac62b8b Binary files /dev/null and b/web-ui/docs/zh/other/lifecycle/lts-sp-lifecycle.png differ diff --git a/web-ui/docs/zh/other/migration/README.md b/web-ui/docs/zh/other/migration/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9bdce50e6d439f5703d17e11b27df163ee8af7d2 --- /dev/null +++ b/web-ui/docs/zh/other/migration/README.md @@ -0,0 +1,6 @@ +--- +title: "Migration" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/privacy/README.md b/web-ui/docs/zh/other/privacy/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d24cc7b1fd1415e5c059e0008e95d7eb99821f8 --- /dev/null +++ b/web-ui/docs/zh/other/privacy/README.md @@ -0,0 +1,82 @@ +--- +title: "隐私政策" +--- + + + +
+ +我们深知您的隐私对您的重要性,并充分尊重您的隐私。**在向我们提交您的个人信息之前,请您仔细阅读本《隐私政策声明》(以下简称“本声明”)。**如果您对于我们处理您的个人信息的方式有任何疑问,欢迎与我们联系。除非另有约定,本声明中的“我们”是指**openEuler**社区。 + +## 1.我们如何收集和处理您的个人信息 +**如果您仅仅浏览openEuler社区网站(以下简称“本网站”)的一般性内容,我们通常并不要求您提供个人信息,但在以下情形,我们会相应收集您的个人信息:**
+**a) 邮件订阅**,当您使用我们的邮件订阅服务时,我们将收集您的**电子邮件地址以及您的姓名(可选)。**我们会通过该邮箱为您提供邮件订阅服务,便于您参与社区中的讨论。
+**b) 服务优化**,为持续了解**openEuler**社区的运行状况,以便我们更好地为您服务,我们会将第三方插件部署在本程序中,该第三方会通过插件收集并记录您的浏览器和计算机、移动设备上的信息,包括但不限于您的**IP地址、访问来源、访问社区的次数、停留时长、访问时间戳、浏览器类型、访问社区所用服务器类型版本**等,我们会在此基础上进行数据统计,以便我们了解**openEuler**社区的运营状况。
+**c) 贡献者协议签署**,当您通过贡献者许可协议(简称“**CLA**”)签署系统(点击[此处](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZvcGVuZXVsZXI=)了解)参与代码贡献时,您需要向**CLA**签署系统提交您的相关个人信息,我们会取得这些个人信息用于校验您是否已经签署**CLA**,并进行相关统计分析,用于了解社区的运营状况。 + +我们还可能会在您的授权同意范围内从第三方,包括其他平台或社区收集到您的个人信息,或者我们能从其他合法公开渠道获取到您的个人信息。我们保证严格依照相关法律规定处理您的个人信息,同时请您详细阅读该第三方的隐私政策及用户协议。如使用openEuler社区需要第三方提供您的个人信息,但您拒绝第三方在提供服务时收集、使用传递或者分享您的个人信息,将可能导致您无法使用openEuler社区相关服务。例如,当您使用经授权的第三方帐号登录openEuler社区时,我们会在征得您的同意后,从第三方获取您的相关个人信息。 + +## 2.我们如何使用Cookie及类似技术 + +**a)** 为确保网站正常运转,我们有时会在计算机或移动设备上存储 **Cookie**。**Cookie**是访问网站时放置在您的计算机或移动设备上的小型数据文件。**Cookie** 的内容只能由创建它的服务器检索或读取。**Cookie**服务于不同的目的,例如帮助我们了解网站如何被使用,让您高效地浏览页面,记住您的偏好并总体上改善您的浏览体验。
+**b)** 我们使用二种类型的**Cookie**:
+**  1)** 严格必要的**Cookie**: 用于登录和验证。当您使用**HUAWEI** **ID**登录网站时,**Cookie**将确保您对该网站的访问尽可能顺利;
+**  2)** 统计分析**Cookie**:我们收集关于您使用服务的信息,包括您的单次或多次访问,这些**Cookie**帮助我们了解服务是如何运行、使用的。我们使用百度提供的统计分析插件。
+  许多服务需要**Cookie**才能运行。如果拟选择不允许与这些服务相关的**Cookie**,则您可能无法使用该等服务或该等服务的某些功能。
+**c) 请勿追踪**,很多网络浏览器均提供 **Do Not Track** 功能,该功能可向网站发布 **Do Not Track** 请求。目前,主要互联网标准组织尚未设立相关政策来规定网站应如何处理此类请求。如果您启用了“请勿追踪”或您的浏览器可能提供的其他类似功能,我们将不会更改本声明中所述的收集和使用您数据的方式。但是,我们保留对您的“请勿追踪”请求做出回应并停止收集您的数据而不另行通知的权利。
+**d) 您的选择**,大多数浏览器允许您删除或拒绝**Cookie**。为此,请按照浏览器设置中的说明进行操作。默认情况下,许多浏览器接受**Cookie**,直到您更改设置为止。 + +## 3.我们如何共享您的个人信息 + +共享是指我们向第三方提供个人信息,且我们和第三方分别对个人信息进行独立处理的过程。除非您的同意,我们不会向第三方共享您的个人信息,但以下情况或本声明规定的情形除外:
+**a) 在获取明确同意情况下的共享**。获得您的明确同意后,我们会向您指定的第三方共享您授权范围内的信息;
+**b) 为合规、防止欺诈和安全目的共享**。我们可能为上述提及的合规、防止欺诈和安全目的共享您的个人信息。
+**c) 我们可能会将您的个人信息向我们的关联公司披露,以供它们为您提供交易支持、服务支持或安全支持**。
+**d) 共享给业务合作伙伴**。我们可能会向合作伙伴等第三方共享您的信息。但我们仅会出于合法、正当、必要、特定、明确的目的共享您的个人信息,并且只会共享提供服务所必需的个人信息。我们的合作伙伴包括:
+**  1) 开发者,平台及社交媒体**:某些产品或服务由第三方直接向您提供,我们须将交易相关信息共享给第三方来实现您的需求。例如,如果您通过激活或关联使得我们提供的服务或产品与第三方平台或社交媒体相关联(例如通过第三方网站直接登录、虚拟登录或关联登录),我们可能会根据您就此的授权将您的个人信息进行披露。我们不控制第三方对您个人信息的使用。
+**  2) 服务供应商或专业服务提供商**:我们可能会将您的个人信息共享给按照我们指示进行服务或产品提供或支持我们网站运营的第三方,包括为我们供货或提供基础设施技术服务、托管、客户支持、市场推广和分析、信息处理服务的第三方等。我们共享这些信息的目的仅限于本声明披露或在您允许的范围内进行,比如百度。我们可能因获取专业服务,如审计、保险、金融或法律之目的,向相关专业人士共享您的个人信息。
+在我们根据上述内容向关联公司或合作伙伴共享信息时,我们将通过合同等方式规定其责任和义务,并要求他们采取必要措施保障所处理的个人信息的安全。 + +## 4.我们将保留多久您的个人信息 + +我们将会在达成本声明所述目的所需的期限内保留您的个人信息,除非按照法律要求或您的要求需要延长保留期。
+一般而言,我们会自您使用我们的社区服务时获取您的个人信息之日起,根据可适用法律的要求或服务协议的约定,在留存期限内存储或保留您的个人信息。在您的个人信息超出保留期限后,且没有法律要求我们继续处理您的特定个人信息的情况下,我们将会根据可适用法律的要求删除您的个人信息,或进行匿名化处理。 + +## 5.我们将如何保护您的个人信息 + +我们重视您的个人信息安全。我们采用适当的物理、管理和技术保障措施来保护您的个人信息。例如,我们会使用加密技术确保信息的机密性;我们会使用保护机制防止信息遭到恶意攻击;我们会部署访问控制机制,确保只有授权人员才可访问个人信息;以及我们会举办安全和隐私保护培训等。**总之,我们会尽力保护您的个人信息。尽管如此,任何措施都无法做到无懈可击,也没有任何产品与服务、网站、信息传输、计算机系统、网络连接是绝对安全的**。 + +## 6.如何访问或控制您的个人信息 + +根据适用的法律法规,就您的个人信息,您可能享有如下权利:
+**a)** 访问我们持有的您的个人信息并获得副本的权利; 
+**b)** 要求我们更新或更正您的个人信息的权利;
+**c)** 要求我们删除您的个人信息的权利;
+**d)** 反对我们对您的个人信息进行处理的权利;
+**e)** 限制我们对您的个人信息进行处理的权利;以及
+**f)** 向有权的个人信息保护部门提起投诉、举报的权利。
+请注意该等权利不是绝对的,且可能根据适用的法律受到限制。如果您需要我们协助行使上述请求或权利,请通过下述“如何联系我们”联系。
+**除非适用的法律法规另有要求,我们会在一个月内响应您的请求。根据您请求的复杂度,我们可能另行延迟两个月。如果发生该情况,我们会在收到请求的一个月内向您告知延迟及其原因。**请注意在某些情况下,您的请求将被驳回,比如我们无法验证您的身份,或您提出的要求超出适用的法律下赋予您的权利。我们将书面告知您提出的请求被驳回以及被驳回的原因。
+您可以改变您授权我们继续收集个人信息的范围或撤回您的授权,但您撤回同意或授权的决定,不会影响此前基于您的授权而开展的个人信息处理行为。 + +## 7.个人信息存储地点 + +我们通过遍布全球的资源和服务器为您提供产品与服务,我们收集您的个人信息可能存储在我们及其关联方、服务提供商/分包商所在的国家/地区。这意味着,您的个人信息可能会被转移到您使用的产品或服务所在的国家/地区以外的其他司法管辖区,或者受到来自这些司法管辖区的访问。
+此类个人信息存储地的司法管辖区可能采用保护程度不一的个人信息保护法律,甚至未订立相关法律。我们会确保您的个人信息得到适用的法律法规和本声明的保护。 + +## 8.如何更新本声明 + +我们可能会根据我们的服务或数据处理的变化不时更新或修改本声明。如果我们更新本声明,我们会将最新版隐私声明发布在本网站上,并自发布时立即生效。建议您定期查看本声明以了解任何更改。如果我们对本声明做出任何重大更改(收集的个人信息范围和使用目的变更),我们将通过适当渠道通知您,并获取您的同意。 + +## 9.如何联系我们 + +如果您想联系我们或行使您的相关权利,请通过以下方式与我们联系: **** + +

最近更新时间:**2022**年**3**月 + +
\ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/atune/README.md b/web-ui/docs/zh/other/projects/atune/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b32c575cb8fd67bb4926ac5466282876a9dff191 --- /dev/null +++ b/web-ui/docs/zh/other/projects/atune/README.md @@ -0,0 +1,6 @@ +--- +title: "A-Tune" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/bishengjdk/README.md b/web-ui/docs/zh/other/projects/bishengjdk/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cabd76f544889481ce06dd87dd26e0644c7c3b6e --- /dev/null +++ b/web-ui/docs/zh/other/projects/bishengjdk/README.md @@ -0,0 +1,6 @@ +--- +title: "毕昇JDK" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/bishengjdk/tck-affidavit/README.md b/web-ui/docs/zh/other/projects/bishengjdk/tck-affidavit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..94cb562181c485b1c725172dff7b4ae92f4db63d --- /dev/null +++ b/web-ui/docs/zh/other/projects/bishengjdk/tck-affidavit/README.md @@ -0,0 +1,22 @@ +--- +title: "毕昇JDK" +--- + +
+ +# Huawei BiSheng Statement of Java SE Compatibility + + All Huawei BiSheng(JDK 8) binaries available from have passed all requirements of the then-current Java SE 8 Compatibility test suite(JCK tests), and are compliant and compatible implementations. + +
+ + \ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/isula/README.md b/web-ui/docs/zh/other/projects/isula/README.md new file mode 100644 index 0000000000000000000000000000000000000000..303f5a64312ea876a3987aa89b03919aec2880f8 --- /dev/null +++ b/web-ui/docs/zh/other/projects/isula/README.md @@ -0,0 +1,6 @@ +--- +title: "iSula" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/secgear/README.md b/web-ui/docs/zh/other/projects/secgear/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6f9ac611eacf3a1010fc5dfa5a8fe67c6075c721 --- /dev/null +++ b/web-ui/docs/zh/other/projects/secgear/README.md @@ -0,0 +1,6 @@ +--- +title: "secgear" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/projects/stratovirt/README.md b/web-ui/docs/zh/other/projects/stratovirt/README.md new file mode 100644 index 0000000000000000000000000000000000000000..13e1c7f3bd30f84aa90386a77a123de3ae8deade --- /dev/null +++ b/web-ui/docs/zh/other/projects/stratovirt/README.md @@ -0,0 +1,6 @@ +--- +title: "StratoVirt" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/other/search/README.md b/web-ui/docs/zh/other/search/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c78242da2f31291c11652ccffff63682785f9488 --- /dev/null +++ b/web-ui/docs/zh/other/search/README.md @@ -0,0 +1,6 @@ +--- +title: "搜索" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/security/cve/README.md b/web-ui/docs/zh/security/cve/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fc1451fe288cabe19affed7ea74c74b1c28a9f1f --- /dev/null +++ b/web-ui/docs/zh/security/cve/README.md @@ -0,0 +1,6 @@ +--- +title: "CVE" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/security/cve/detail.md b/web-ui/docs/zh/security/cve/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..f26f61cdd529d996c8974e0f55374fcd90a0a4c4 --- /dev/null +++ b/web-ui/docs/zh/security/cve/detail.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/security/safety-bulletin/README.md b/web-ui/docs/zh/security/safety-bulletin/README.md new file mode 100644 index 0000000000000000000000000000000000000000..29192070c8ec48b0e078351a4a91222a3ad88656 --- /dev/null +++ b/web-ui/docs/zh/security/safety-bulletin/README.md @@ -0,0 +1,6 @@ +--- +title: "安全公告" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/security/safety-bulletin/detail.md b/web-ui/docs/zh/security/safety-bulletin/detail.md new file mode 100644 index 0000000000000000000000000000000000000000..7dc0fb37fe44d1f122eac316f4dbea162065cde6 --- /dev/null +++ b/web-ui/docs/zh/security/safety-bulletin/detail.md @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/web-ui/docs/zh/security/vulnerability-reporting/README.md b/web-ui/docs/zh/security/vulnerability-reporting/README.md new file mode 100644 index 0000000000000000000000000000000000000000..338d6a55620f10d294583e31e741be8464e714aa --- /dev/null +++ b/web-ui/docs/zh/security/vulnerability-reporting/README.md @@ -0,0 +1,152 @@ +--- +title: "漏洞管理" +--- + + + +
+ +## 漏洞响应 +openEuler社区非常重视社区版本的安全性,openEuler安全委员会负责接收、调查和披露openEuler社区相关的安全漏洞。我们鼓励漏洞研究人员和行业组织主动将openEuler社区的疑似安全漏洞报告给openEuler社区安全委员会。我们会快速的响应、分析和解决上报的安全问题或安全漏洞。 + +## 支持版本 +漏洞响应流程主要支持openEuler社区的LTS发行版和其分支版本。 + +## 漏洞处理流程 +每个一个安全漏洞都会有一个指定的人员进行跟踪和处理,协调员是openEuler安全委员会的成员,他将负责跟踪和推动漏洞的修复和披露。漏洞端到端的处理流程如下图。 + + + + + + +在这里我们主要介绍流程中漏洞上报、漏洞评估和漏洞披露这三部分内容。 + +## 漏洞上报 +如果您认为openEuler产品存在一个疑似安全漏洞,我们希望您将漏洞上报给openEuler社区,并与我们配合以负责任的方式修复和披露该问题。 + +### 漏洞上报方式 +您可以通过email将openEuler产品的潜在安全漏洞发送到openEuler安全团队邮箱()。因为漏洞信息比较敏感,建议您使用安全团队邮箱PGP公钥对邮件信息进行加密。 +安全团队成员信息如下: + ++ 刘金刚[@liujingang09],, PGP公钥。 + ++ 颜小兵[@yanxiaobing2020],, PGP公钥。 + ++ 朱健伟[@zhujianwei001],, PGP公钥。 + ++ 魏刚[@gwei3],<11015100@qq.com>,PGP公钥。 + ++ 崔雷[@kylincuilei],。 + +### 漏洞上报内容 +为了便于快速的确认和验证疑似漏洞,请在漏洞上报邮件中包含但不限于以下内容: +- 基本信息:包括漏洞影响的模块、漏洞的触发条件和成功利用后对系统的影响等。 + +- 技术细节:包括系统配置、定位方法、Exploit的描述、POC、问题重现方法和步骤等。 + +- 修复方案建议。 + +- 上报者的组织和联系方式。 + +- 上报者可能的漏洞披露计划。 + + +### 邮件响应时间 +我们将在48小时内响应通过邮箱上报的疑似安全漏洞,并向上报者反馈漏洞处理的进展。 + + +## 漏洞严重性评估 +业界普遍使用CVSS标准评估漏洞的严重性,openEuler在使用CVSSv3进行漏洞评估时,需要设定漏洞攻击场景,基于在该攻击场景下的实际影响进行评估。漏洞严重等级评估是指针对漏洞利用难易程度,以及利用后对机密性、完整性、可用性的影响进行评估,并生成一个评分值。 +### 评估标准 +openEuler社区采用CVSS v3对漏洞进行评估,CVSS V3由通过对以下向量来评估一个漏洞的影响: + +- 攻击向量(AV)-表示攻击的“远程性”以及如何利用此漏洞。 + +- 攻击复杂性(AC)-讲述攻击执行的难度以及成功进行攻击需要哪些因素。 + +- 用户交互(UI)-确定攻击是否需要用户参与。 + +- 所需的权限(PR)-记录成功进行攻击所需的用户身份验证级别。 + +- 范围(S)-确定攻击者是否可以影响具有不同权限级别的组件。 + +- 机密性(C)-衡量信息泄露给非授权方后导致的影响程度。 + +- 完整性(I)-衡量信息被篡改后导致的影响程度。 + +- 可用性(A)-衡量用户在需要访问数据或服务时受影响的程度。 + +### 评估原则 +- 评估漏洞的严重等级,不是评估风险。 + +- 评估时必须基于攻击场景,且保证在该场景下,攻击者成功攻击后能对系统造成机密性、完整性、可用性影响。 + +- 当安全漏洞有多个攻击场景时,应以造成最大的影响,即CVSS评分最高的攻击场景为依据。 + +- 被嵌入调用的库存在漏洞,要根据该库在产品中的使用方式,确定漏洞的攻击场景后进行评估。 + +- 安全缺陷不能被触发或不影响CIA(机密性/完整性/可用性),CVSS评分为0分。 + +### 评估步骤 +对漏洞进行评估时,可根据下述步骤进行操作: + +- 设定可能的攻击场景,基于攻击场景评分。 + +- 确定漏洞组件(Vulnerable Component)和受影响组件(Impact Component)。 + +- 选择基础评估指标的值:通过对可利用指标(攻击向量/攻击复杂度/所需权限/用户交互/范围)和受影响指标(机密性/完整性/可用性)给出漏洞影响评估。 + + +### 严重等级划分 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
严重等级(Severity Rating)CVSS评分(Score)
致命(Critical)9.0 - 10.0
高(High)7.0 - 8.9
中(Medium)4.0 - 6.9
低(Low)0.1 - 3.9
无(None)0.0
+ +### 和NVD评估分数差异说明 +CVSS基础评分与受影响组件的版本号,提供和使用的方式,平台以及软件的编译方式相关,NVD评分考虑了漏洞被利用的所有场景,而openEuler是基于上游社区自己构建的,主要应用于服务器场景,所以对于openEuler开源产品来说,直接采用NVD评分是不合适的,因此openEuler对所有受影响的CVE有自己的评分,存在打分和NVD不同的情况。 + +## 漏洞披露 +为了保护openEuler用户的安全,在进行调查、修复和发布安全公告之前,openEuler社区不会公开披露、讨论或确认openEuler产品的安全问题。安全漏洞修复后openEuler社区会发布安全公告,安全公告内容包括该漏洞的技术细节、CVE编号、CVSS安全评分、严重性等级以及受到该漏洞影响的版本和修复版本等信息。安全公告提供邮件订阅功能,您可以通过“[sa-announce](https://mailweb.openeuler.org/postorius/lists/sa-announce.openeuler.org/)"链接订阅openEuler社区的安全公告。我们也提供CVRF格式的安全公告,可通过"[CVRF文档](https://repo.openeuler.org/security/data/cvrf/)"链接获取。 + +
+ + \ No newline at end of file diff --git a/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh)-mobile.png b/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh)-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..75e34a973907e60e8b096ba01f22f61a06d5e9db Binary files /dev/null and b/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh)-mobile.png differ diff --git a/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh).png b/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh).png new file mode 100644 index 0000000000000000000000000000000000000000..6af1336c25c8273d65551d69f95b04fdafd18b84 Binary files /dev/null and b/web-ui/docs/zh/security/vulnerability-reporting/procedure(zh).png differ diff --git a/web-ui/docs/zh/sig/meeting-guide/README.md b/web-ui/docs/zh/sig/meeting-guide/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2145a63c049fb3047ccc154c506957db71743c3d --- /dev/null +++ b/web-ui/docs/zh/sig/meeting-guide/README.md @@ -0,0 +1,58 @@ + + + + +
+ +# openEuler Developer Day 2022 SIG组版本工作会议指南 + +## 介绍 +openEuler开源社区按照不同的 SIG(Special Interests Group) 来组织开发及版本发布工作,openEuler开源社区的主要技术产品通过 openEuler 开源操作系统承载,它在每年的 3 月和 9 月发布两个版本。当一个版本发布完成后,openEuler开源社区将召开下一个版本的开发规划会议,会议以SIG组为单位,时长为0.5~1天,用于集中讨各SIG组未来 6 个月的规划、工作事项、任务分工、优先级等相关内容。openEuler开源社区将为各SIG组的规划会议提供场地和技术支持。 + +SIG版本规划工作会议遵循开源、开放原则,议题收集、技术讨论、会议纪要等各讨论过程均对外开放。 + + +## 会议类型 + +**单SIG组工作会议**:单一SIG组内的工作会议,由该SIG组Maintainer进行组织,包括议题收集、议程安排、主持讨论、会议纪要输出等。 + +**跨SIG组工作会议**:跨SIG组之间的协作工作会议,需要各相关SIG组Maintainer提前通过邮件或其他方式与版本规划会议组织者联系并沟通场地安排并由各相关SIG组Maintainer负责进行组织,包括议题收集、议程安排、主持讨论、会议纪要输出等。 + +## 需求收集 + +各SIG应择时启动针对后续版本的需求收集,各SIG组Maintainer在openEuler Etherpad平台()创建相应的会议收集目录(建议命名方式为: sig名-版本名(例如22.09)-Planning)用于收集该版本规划工作会议的需求收集及计划,并将该会议目录反馈至openEuler开源社区SIG版本规划会议组织者。(参考模板:) + +任何人均可以在SIG版本工作会议中提出需求,通过在各SIG版本工作会议指定的Etherpad共享文件中的Topics环节根据要求进行填写,通常需要包含以下内容: +- 需求发起人 +- 需求的具体描述 +- Issue 反馈的在线地址 +- 已有的技术方案或PR +- 已有的讨论纪要 + +需求收集完成后由SIG组Maintainers按照所有收集到的需求的具体情况(类型、技术难度、工作量等),根据会议时间安排指定会议议程,会议安排在工作会议召开前3天在Etherpad共享文件及社区邮件列表Maillist中公开发布,方便与会者了解会议议程。 + +## 召开会议 + +会议由各SIG组版本规划负责人主持召开,按照预先制定的会议议程进行会议,会议过程中需要注意时间控制,确保所有已经在会议议程中的需求都能得到相应的讨论时间。各与会者需要在Etherpad的Attendees环节根据要求填写自己的名字和Gitee_ID,若未到场且未指定代参加人员则该需求视为自动放弃。 + +各议题讨论可以分为下面几个阶段: +1. 需求陈述:由需求发起人对需求进行陈述,包括需求目标、需求来源、提议的技术方案及既往的讨论及结果等,需求陈述阶段其余听众不允许打断。 +2. 讨论:由各参会者针对该需求进行相应的讨论,所有与会者均可参与讨论,主持人负责记录各方观点及重点意见。 +3. 总结:在达成共识后,由主持人根据共识输出该议题的结论。若现场没有达成共识,则应商议再次讨论的具体时间。 + +所有议题讨论完成后,由SIG Maintainer团队根 据各议题讨论情况及SIG组实际情况对各需求进行优先级排序及分工,“任务分工”靠贡献者“认领任务”的方式完成。 + +## 会议纪要 + +各SIG组版本规划负责人在工作会议结束后一周内整理完成会议纪要,并在Etherpad及SIG组、dev, tc, release sig邮件列表Maillist上公开发布该会议纪要,以便开发者、用户了解未来版本各SIG的工作计划,会议纪要需要包含以下内容: +- 所有参与讨论的议题及该议题的结论 +- 下一版本各工作的负责人 +- 下一版本的工作优先级 +会议纪要内容参考链接: + +
diff --git a/web-ui/docs/zh/sig/role-description/README.md b/web-ui/docs/zh/sig/role-description/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fe9026fe39d5defc1efe4b2b0d50f207090c8856 --- /dev/null +++ b/web-ui/docs/zh/sig/role-description/README.md @@ -0,0 +1,120 @@ +--- +title: "角色说明" +--- + + + +
+ + +*说明*:Maintainer和Committer在Gitee的权限上不做区分,两者的区分主要是集中在SIG治理的管理范围上。详细可以见下面的描述。 + + + +## 新的贡献者 + +欢迎新成员加入社区。我们有关于如何开始贡献的指导文档请参考:[openEuler贡献者指南](https://gitee.com/openeuler/community/blob/master/zh/contributors/README.md) + + + +## 既有社区成员 + + +既有的社区成员应证明能够遵守本文中的原则,熟悉SIG的组织、角色、政策、软件、约定等,以及相关的技术和/或写作能力。社区成员角色的期望、职责和要求,请参考下面的内容。 + + + +## 贡献者 Contributor +贡献者是社区中持续活跃的贡献者,他们可以认领问题和PR,可以参与SIG组活动,并且可以为PR提交前完成测试。 + + + +### 要求 + ++ Gitee上的注册会员 ++ 为SIG或社区做出多方面贡献,包括不限于: + + 在Gitee上提交或审核PR + + 在Gitee上对问题进行归档或评论 + + 参与SIG或社区讨论 ++ 已阅读[贡献者指南](https://gitee.com/openeuler/community/blob/master/zh/contributors/README.md) ++ 积极参与1个或多个SIG + + + +### 责任与权利 + ++ 响应被分配的问题和PR ++ 贡献的代码应该 + + 经过良好的测试 + + 能够让测试用例始终通过 + + 解决后继发生的错误或问题 + ++ 可以通过 `/lgtm`打开PR ++ 可以分配问题或PR,可以通过 `/cc @username`要求成员进行评论 ++ 可以针对PR自动运行测试。`/ok-to-test`不是必要的 ++ 可以使用`/ok-to-test`为具有`needs-ok-to-test`标签的PR进行操作,并使用诸如`/close`对PR进行关闭。 + +**注意**:经常贡献代码的成员应积极的参与代码审查,并努力成为SIG的*审核者Committer*。 + + + +## 审核者 Committer + +审核者能够在SIG或SIG的某些部分中审核代码的质量和正确性。审核者对代码库和软件工程原理非常了解。 + +定义者:openEuler SIG拥有的存储库中OWNERS文件中的*developer*条目。 + +### 要求 + ++ 作为贡献者至少3个月 ++ 作为主要审阅者至少参与了6次PR的审阅 ++ 审阅或合并至少20个基本PR到代码库 ++ 熟悉代码库 ++ 可以自我提名,或由该SIG的审核者或维护者提名 + +### 责任与权力 + ++ **评审PR**:对Contributor提交的PR完成评审,评审可以参考社区的[编程建议]()和[安全编程规范]()。 ++ **分发处理问题**:请参考“[问题处理流程]()“。 ++ **跟踪依赖性问题**:在开发分支中,其他SIG组的软件包的更新可能会到导致破坏本SIG内软件包的依赖关系。此时Committer会收到告警提示,Committer应尽力重建软件包。依赖关系出错可能会使最终用户无法更新系统,打包团队也会介入并重建存在依赖性问题的软件包,但Maintainer不应依赖这些重建。 ++ **如有接口变更,通知可能会影响到的SIG**:其他SIG或项目会依赖本SIG的软件包,对软件包接口的变更可能会对他们造成影响。Maintainer应了解并评审&决策变更造成的依赖影响,并公告和发送API或ABI变更的告警邮件。这类公告应在变更发生至少一周前完成,并应通知到所有可能受影响的SIG。具体请参考[接口变更通知流程]()。 ++ **更新和维护软件包版本**:遵守社区的[软件包更新质量控制策略]()完成软件包的更新。 ++ **和上游社区合作**,包括: + + 将所有变更推送到上游社区 + + 参与上游社区邮件列表 + + 获取上游社区的bug跟踪器的账户,并跟踪上游社区的重要bug + + 将严重的错误转发给上游社区以寻求帮助 + 更多信息,请参考“[上游社区软件包管理建议]()” ++ **和测试团队合作**,包括: + + 在提交软件包时,向质量检查人员提供如何调试/分类软件包的信息,以供问题的分类 + + 提供基本功能的测试用例,用于测试回归 + + 提交软件包更新时,提供有关更新中已经修复问题的测试用例,以供质量检查人员使用。 + + + +## 维护者 Maintainer + +维护者是SIG组的组长或者管理委员会成员,也是软件包的维护者,能够像Committer一样审查和批准代码贡献。代码审查的重点是代码质量和正确性,而批准的重点是对贡献的整体接受度。**所有Committer的责任与权力,Maintainer均具有**。除此之外,Maintainer还承担了团队的技术路线、内外协调等工作。 + +**定义**:openEuler SIG拥有的存储库中OWNERS文件中的*developer*条目 + + + +### 要求 + ++ 作为审核者至少3个月 ++ 作为主要审阅者至少参与了12次PR的审阅 ++ 审阅或合并至少30个基本PR到代码库 ++ 熟悉代码库 ++ 可以自我提名,也可以由子项目Maintainer提名,并且没有其他子项目Maintainer的反对 + +### 责任与权力 + +- **确定SIG所负责项目的技术路线**:包括规划和决策SIG技术方向、路标规划、架构演进。 +- **制定SIG所负责项目的发布计划**:确定SIG的关键需求和发布计划;参与社区的PM活动,并协调SIG计划和社区版本的里程碑时间表匹配 +- **参与社区协调活动**:作为SIG的代表参与openEuler技术委员会或理事会组织的活动和特定会议等 +- **召集SIG组会议**:定期召集SIG会议,决策SIG内上升的争议 + + +
+ diff --git a/web-ui/docs/zh/sig/sig-guidance/README.md b/web-ui/docs/zh/sig/sig-guidance/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8517010843757703733012d8998f527449901aee --- /dev/null +++ b/web-ui/docs/zh/sig/sig-guidance/README.md @@ -0,0 +1,6 @@ +--- +title: "申请流程" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/sig/sig-list/README.md b/web-ui/docs/zh/sig/sig-list/README.md new file mode 100644 index 0000000000000000000000000000000000000000..338d15d9ec2236d801dd7fad61d0e751f233d09a --- /dev/null +++ b/web-ui/docs/zh/sig/sig-list/README.md @@ -0,0 +1,6 @@ +--- +title: "查看SIG" +--- + + + \ No newline at end of file diff --git a/web-ui/docs/zh/sig/sig-list/sig-detail.md b/web-ui/docs/zh/sig/sig-list/sig-detail.md new file mode 100644 index 0000000000000000000000000000000000000000..de0b4f61074e5a1ef56c2feacdbf70403adc1eaf --- /dev/null +++ b/web-ui/docs/zh/sig/sig-list/sig-detail.md @@ -0,0 +1,6 @@ +--- +title: "SIG" +--- + + + \ No newline at end of file diff --git a/web-ui/package-lock.json b/web-ui/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..7a8ba2f3e72913bd84296695e440739a414cb19f --- /dev/null +++ b/web-ui/package-lock.json @@ -0,0 +1,24754 @@ +{ + "name": "website-v2", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "website-v2", + "version": "0.0.1", + "dependencies": { + "axios": "^0.19.2", + "dayjs": "^1.8.31", + "echarts": "^5.0.2", + "element-ui": "^2.13.2", + "gsap": "^3.9.0", + "less-loader": "^6.2.0", + "optimize-css-assets-webpack-plugin": "5.0.6", + "swiper": "^5.2.0", + "vue-awesome-swiper": "^4.1.1", + "vue-baidu-map": "^0.21.11", + "vue-lazyload": "^1.3.3", + "vue-router": "3.4.5", + "vuepress": "~1.5.2", + "vuepress-plugin-code-copy": "^1.0.6", + "vuepress-plugin-sitemap": "^2.3.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.0", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "dependencies": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz", + "integrity": "sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", + "dependencies": { + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz", + "integrity": "sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", + "dependencies": { + "@babel/types": "^7.18.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "dependencies": { + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz", + "integrity": "sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.2.tgz", + "integrity": "sha512-kbDISufFOxeczi0v4NQP3p5kIeW6izn/6klfWBrIIdGZZe4UpHR+QU03FAoWjGGd9SUXAwbw2pup1kaL4OQsJQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/plugin-syntax-decorators": "^7.17.12", + "charcodes": "^0.2.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz", + "integrity": "sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw==", + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.12.tgz", + "integrity": "sha512-D1Hz0qtGTza8K2xGyEdVNCYLdVHukAcbQr4K3/s6r/esadyEriZovpJimQOpu8ju4/jV8dW/1xdaE0UpDroidw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz", + "integrity": "sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz", + "integrity": "sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz", + "integrity": "sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz", + "integrity": "sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", + "@babel/helper-split-export-declaration": "^7.16.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz", + "integrity": "sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz", + "integrity": "sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz", + "integrity": "sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz", + "integrity": "sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.18.2", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.4.tgz", + "integrity": "sha512-lH2UaQaHVOAeYrUUuZ8i38o76J/FnO8vu21OE+tD1MyP9lxdZoSfz+pDbWkq46GogUrdrMz3tiz/FYGB+bVThg==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-identifier": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz", + "integrity": "sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", + "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz", + "integrity": "sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.2.tgz", + "integrity": "sha512-mr1ufuRMfS52ttq+1G1PD8OJNqgcTFjq3hwn8SZ5n1x1pBhi0E36rYMdTK0TsKtApJ4lDEdfXJwtGobQMHSMPg==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz", + "integrity": "sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.2.tgz", + "integrity": "sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q==", + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.18.0", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.18.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.17.12", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.18.0", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.18.1", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.18.0", + "@babel/plugin-transform-modules-commonjs": "^7.18.2", + "@babel/plugin-transform-modules-systemjs": "^7.18.0", + "@babel/plugin-transform-modules-umd": "^7.18.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.18.0", + "@babel/plugin-transform-reserved-words": "^7.17.12", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.18.2", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.2", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/types": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + }, + "node_modules/@types/node": { + "version": "17.0.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", + "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" + }, + "node_modules/@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz", + "integrity": "sha512-QOi5OW45e2R20VygMSNhyQHvpdUwQZqGPc748JLGCYEy+yp8fNFNdbNIGAgZmi9e+2JHPd6i6idRuqivyicIkA==" + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz", + "integrity": "sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.1.tgz", + "integrity": "sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "@vue/babel-helper-vue-transform-on": "^1.0.2", + "camelcase": "^6.0.0", + "html-tags": "^3.1.0", + "svg-tags": "^1.0.0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.2.1.tgz", + "integrity": "sha512-HJuqwACYehQwh1fNT8f4kyzqlNMpBuUK4rSiSES5D4QsYncv5fxFsLyrxFPG2ksO7t5WP+Vgix6tt6yKClwPzA==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-preset-app": { + "version": "4.5.17", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.17.tgz", + "integrity": "sha512-iFv9J3F5VKUPcbx+TqW5qhGmAVyXQxPRpKpPOuTLFIVTzg+iwJnrqVbL4kJU5ECGDxPESW2oCVgxv9bTlDPu7w==", + "dependencies": { + "@babel/core": "^7.11.0", + "@babel/helper-compilation-targets": "^7.9.6", + "@babel/helper-module-imports": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.11.0", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.0", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.2.4", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.6.5", + "core-js-compat": "^3.6.5", + "semver": "^6.1.0" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.0.0-0" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-preset-app/node_modules/core-js": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz", + "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/@vue/babel-preset-app/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@vue/babel-preset-jsx": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.2.4.tgz", + "integrity": "sha512-oRVnmN2a77bYDJzeGSt92AuHXbkIxbf/XXSE3klINnh9AXBmVS1DGa1f0d+dDYpLfsAKElMnqKTQfKn7obcL4w==", + "dependencies": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "@vue/babel-sugar-composition-api-inject-h": "^1.2.1", + "@vue/babel-sugar-composition-api-render-instance": "^1.2.4", + "@vue/babel-sugar-functional-vue": "^1.2.2", + "@vue/babel-sugar-inject-h": "^1.2.2", + "@vue/babel-sugar-v-model": "^1.2.3", + "@vue/babel-sugar-v-on": "^1.2.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.2.1.tgz", + "integrity": "sha512-4B3L5Z2G+7s+9Bwbf+zPIifkFNcKth7fQwekVbnOA3cr3Pq71q71goWr97sk4/yyzH8phfe5ODVzEjX7HU7ItQ==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.2.4.tgz", + "integrity": "sha512-joha4PZznQMsxQYXtR3MnTgCASC9u3zt9KfBxIeuI5g2gscpTsSKRDzWQt4aqNIpx6cv8On7/m6zmmovlNsG7Q==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.2.2.tgz", + "integrity": "sha512-JvbgGn1bjCLByIAU1VOoepHQ1vFsroSA/QkzdiSs657V79q6OwEWLCQtQnEXD/rLTA8rRit4rMOhFpbjRFm82w==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.2.2.tgz", + "integrity": "sha512-y8vTo00oRkzQTgufeotjCLPAvlhnpSkcHFEp60+LJUwygGcd5Chrpn5480AQp/thrxVm8m2ifAk0LyFel9oCnw==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.2.3.tgz", + "integrity": "sha512-A2jxx87mySr/ulAsSSyYE8un6SIH0NWHiLaCWpodPCVOlQVODCaSpiR4+IMsmBr73haG+oeCuSvMOM+ttWUqRQ==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@vue/babel-sugar-v-model/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.2.3.tgz", + "integrity": "sha512-kt12VJdz/37D3N3eglBywV8GStKNUhNrsxChXIV+o0MwVXORYuhDTHJRKPgLJRb/EY3vM2aRFQdxJBp9CLikjw==", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-on/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/@vuepress/core": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.5.4.tgz", + "integrity": "sha512-RaHJiX0Yno4S3zoV64JNd3xE55sza8rayyWvXAJY381XVMxKrsLBrgW6ntNYSkzGnZcxi6fwMV/CVOUhEtkEkA==", + "dependencies": { + "@babel/core": "^7.8.4", + "@vue/babel-preset-app": "^4.1.2", + "@vuepress/markdown": "1.5.4", + "@vuepress/markdown-loader": "1.5.4", + "@vuepress/plugin-last-updated": "1.5.4", + "@vuepress/plugin-register-components": "1.5.4", + "@vuepress/shared-utils": "1.5.4", + "autoprefixer": "^9.5.1", + "babel-loader": "^8.0.4", + "cache-loader": "^3.0.0", + "chokidar": "^2.0.3", + "connect-history-api-fallback": "^1.5.0", + "copy-webpack-plugin": "^5.0.2", + "core-js": "^3.6.4", + "cross-spawn": "^6.0.5", + "css-loader": "^2.1.1", + "file-loader": "^3.0.1", + "js-yaml": "^3.13.1", + "lru-cache": "^5.1.1", + "mini-css-extract-plugin": "0.6.0", + "optimize-css-assets-webpack-plugin": "^5.0.1", + "portfinder": "^1.0.13", + "postcss-loader": "^3.0.0", + "postcss-safe-parser": "^4.0.1", + "toml": "^3.0.0", + "url-loader": "^1.0.1", + "vue": "^2.6.10", + "vue-loader": "^15.7.1", + "vue-router": "^3.1.3", + "vue-server-renderer": "^2.6.10", + "vue-template-compiler": "^2.6.10", + "vuepress-html-webpack-plugin": "^3.2.0", + "vuepress-plugin-container": "^2.0.2", + "webpack": "^4.8.1", + "webpack-chain": "^6.0.0", + "webpack-dev-server": "^3.5.1", + "webpack-merge": "^4.1.2", + "webpackbar": "3.2.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@vuepress/core/node_modules/core-js": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz", + "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/@vuepress/markdown": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.5.4.tgz", + "integrity": "sha512-bgrR9LTcAa2O0WipTbH3OFKeAfXc/2oU6cUIoMkyihSKUo1Mr5yt1XKM7vHe1uFEZygNr8EAemep8chsuVuISA==", + "dependencies": { + "@vuepress/shared-utils": "1.5.4", + "markdown-it": "^8.4.1", + "markdown-it-anchor": "^5.0.2", + "markdown-it-chain": "^1.3.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-table-of-contents": "^0.4.0", + "prismjs": "^1.13.0" + } + }, + "node_modules/@vuepress/markdown-loader": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.5.4.tgz", + "integrity": "sha512-3R5quGIXQm7gfPWN67SVZ9OBA7VrGEEXJjjV01MYkbfhqVGgO6lBRq73Og0XdKs4RPx4nqJUPthhL8FJVNRTIg==", + "dependencies": { + "@vuepress/markdown": "1.5.4", + "loader-utils": "^1.1.0", + "lru-cache": "^5.1.1" + } + }, + "node_modules/@vuepress/markdown-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/@vuepress/markdown-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@vuepress/plugin-active-header-links": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.5.4.tgz", + "integrity": "sha512-FI1Dr/44HVqxLMRSuaVEEwegGVEGFlaWYE3nsXwL7klKr6c+2kXHEw9rSQlAxzJyzVfovTk4dd+s/AMOKuLGZQ==", + "dependencies": { + "lodash.debounce": "^4.0.8" + } + }, + "node_modules/@vuepress/plugin-last-updated": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.5.4.tgz", + "integrity": "sha512-9kezBCxPM+cevKRNML6Q7v6qkI8NQvKbVkwohlzsElM8FBmjlZmgFyZje66ksTnb/U6ogazCCq9jdOyipNcQ2A==", + "dependencies": { + "cross-spawn": "^6.0.5" + } + }, + "node_modules/@vuepress/plugin-nprogress": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.5.4.tgz", + "integrity": "sha512-2bGKoO/o2e5mIfOU80q+AkxOK5wVijA/+8jGjSQVf2ccMpJw+Ly1mMi69r81Q0QkEihgfI9VN42a5+a6LUgPBw==", + "dependencies": { + "nprogress": "^0.2.0" + } + }, + "node_modules/@vuepress/plugin-register-components": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.5.4.tgz", + "integrity": "sha512-Y1U9j6unZp1ZhnHjQ9yOPY+vxldUA3C1EwT6UgI75j5gxa5Hz6NakoIo6mbhaYHlGmx33o/MXrxufLPapo/YlQ==", + "dependencies": { + "@vuepress/shared-utils": "1.5.4" + } + }, + "node_modules/@vuepress/plugin-search": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.5.4.tgz", + "integrity": "sha512-wikU9XYiZ3Olbii0lI+56mcSdpzHHkduVBMB4MNEV5iob23qDxGPmvfZirjsZV20w1UnLRptERyHtZkTLW9Mbg==" + }, + "node_modules/@vuepress/shared-utils": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.5.4.tgz", + "integrity": "sha512-HCeMPEAPjFN1Ongii0BUCI1iB4gBBiQ4PUgh7F4IGG8yBg4tMqWO4NHqCuDCuGEvK7lgHy8veto0SsSvdSKp3g==", + "dependencies": { + "chalk": "^2.3.2", + "escape-html": "^1.0.3", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "gray-matter": "^4.0.1", + "hash-sum": "^1.0.2", + "semver": "^6.0.0", + "toml": "^3.0.0", + "upath": "^1.1.0" + } + }, + "node_modules/@vuepress/shared-utils/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@vuepress/theme-default": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.5.4.tgz", + "integrity": "sha512-kHst1yXzqTiocVU7w9x4cfJ08vR9ZbREC6kTRtH1ytQSEUL5tM0b9HFicfg1kDp7YNq2qntRro+WmfjU9Ps/eg==", + "dependencies": { + "@vuepress/plugin-active-header-links": "1.5.4", + "@vuepress/plugin-nprogress": "1.5.4", + "@vuepress/plugin-search": "1.5.4", + "docsearch.js": "^2.5.2", + "lodash": "^4.17.15", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.2", + "vuepress-plugin-container": "^2.0.2", + "vuepress-plugin-smooth-scroll": "^0.0.3" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agentkeepalive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", + "integrity": "sha512-TnB6ziK363p7lR8QpeLC8aMr8EGYBKZTpgzQLfqTs3bR0Oo5VbKdwKf8h0dSzsYrB7lSCgfJnMZKqShvlq5Oyg==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/algoliasearch": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz", + "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==", + "dependencies": { + "agentkeepalive": "^2.2.0", + "debug": "^2.6.9", + "envify": "^4.0.0", + "es6-promise": "^4.1.0", + "events": "^1.1.0", + "foreach": "^2.0.5", + "global": "^4.3.2", + "inherits": "^2.0.1", + "isarray": "^2.0.1", + "load-script": "^1.0.0", + "object-keys": "^1.0.11", + "querystring-es3": "^0.2.1", + "reduce": "^1.0.1", + "semver": "^5.1.0", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/algoliasearch/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==" + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", + "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "node_modules/async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "dependencies": { + "babel-runtime": "6.x" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autocomplete.js": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.36.0.tgz", + "integrity": "sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q==", + "dependencies": { + "immediate": "^3.2.3" + } + }, + "node_modules/autoprefixer": { + "version": "9.8.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", + "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "picocolors": "^0.2.1", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", + "dependencies": { + "follow-redirects": "1.5.10" + } + }, + "node_modules/babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "dependencies": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bmaplib.curveline": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz", + "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q==" + }, + "node_modules/bmaplib.heatmap": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz", + "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q==" + }, + "node_modules/bmaplib.lushu": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/bmaplib.lushu/-/bmaplib.lushu-1.0.7.tgz", + "integrity": "sha512-LVvgpESPii6xGxyjnQjq8u+ic4NjvhdCPV/RiSS/PGTUdZKeTDS7prSpleJLZH3ES0+oc0gYn8bw0LtPYUSz2w==" + }, + "node_modules/bmaplib.markerclusterer": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz", + "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==", + "dependencies": { + "bmaplib.texticonoverlay": "^1.0.2" + } + }, + "node_modules/bmaplib.texticonoverlay": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz", + "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg==" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", + "dependencies": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "node_modules/buffer-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", + "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.12", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.12.tgz", + "integrity": "sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-3.0.1.tgz", + "integrity": "sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw==", + "dependencies": { + "buffer-json": "^2.0.0", + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.2.3", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/cache-loader/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cache-loader/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cache-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/cache-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/cache-loader/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cache-loader/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cache-loader/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/cache-loader/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cache-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==" + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/charcodes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", + "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", + "dependencies": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "node_modules/copy-webpack-plugin/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/copy-webpack-plugin/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/copy-webpack-plugin/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/copy-webpack-plugin/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/core-js-compat": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.7.tgz", + "integrity": "sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA==", + "dependencies": { + "browserslist": "^4.20.3", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "engines": { + "node": "*" + } + }, + "node_modules/css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dependencies": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "engines": { + "node": ">4" + } + }, + "node_modules/css-loader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", + "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "dependencies": { + "camelcase": "^5.2.0", + "icss-utils": "^4.1.0", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.14", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.6", + "postcss-modules-scope": "^2.1.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/css-loader/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/css-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/css-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/css-loader/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/css-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", + "dependencies": { + "css": "^2.0.0" + } + }, + "node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", + "dependencies": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "dependencies": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==" + }, + "node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dependencies": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "dependencies": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", + "dependencies": { + "buffer-indexof": "^1.0.0" + } + }, + "node_modules/docsearch.js": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/docsearch.js/-/docsearch.js-2.6.3.tgz", + "integrity": "sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @docsearch/js.", + "dependencies": { + "algoliasearch": "^3.24.5", + "autocomplete.js": "0.36.0", + "hogan.js": "^3.0.2", + "request": "^2.87.0", + "stack-utils": "^1.0.1", + "to-factory": "^1.0.0", + "zepto": "^1.2.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/dom7": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-2.1.5.tgz", + "integrity": "sha512-xnhwVgyOh3eD++/XGtH+5qBwYTgCm0aW91GFgPJ3XG+jlsRLyJivnbP0QmUBFhI+Oaz9FV0s7cxgXHezwOEBYA==", + "dependencies": { + "ssr-window": "^2.0.0" + } + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domhandler/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/echarts": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz", + "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.3.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.141", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.141.tgz", + "integrity": "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA==" + }, + "node_modules/element-ui": { + "version": "2.15.8", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.8.tgz", + "integrity": "sha512-N54zxosRFqpYax3APY3GeRmtOZwIls6Z756WM0kdPZ5Q92PIeKHnZgF1StlamIg9bLxP1k+qdhTZvIeQlim09A==", + "dependencies": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + }, + "peerDependencies": { + "vue": "^2.5.17" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", + "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", + "dependencies": { + "esprima": "^4.0.0", + "through": "~2.3.4" + }, + "bin": { + "envify": "bin/envify" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dependencies": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/file-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/file-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dependencies": { + "debug": "=3.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gsap": { + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.10.4.tgz", + "integrity": "sha512-6QatdkKxXCMfvCW4rM++0RqyLQAzFX5nwl3yHS0XPgkZBkiSEY3VZVbMltrdtsbER/xZonLtyHt684wRp4erlQ==" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hogan.js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", + "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==", + "dependencies": { + "mkdirp": "0.3.0", + "nopt": "1.0.10" + }, + "bin": { + "hulk": "bin/hulk" + } + }, + "node_modules/hogan.js/node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "engines": { + "node": "*" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==" + }, + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==" + }, + "node_modules/html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" + }, + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dependencies": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-minifier/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "node_modules/html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/htmlparser2/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dependencies": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==" + }, + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + }, + "node_modules/import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==", + "dependencies": { + "import-from": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==", + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dependencies": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==" + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "node_modules/internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dependencies": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dependencies": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/less": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz", + "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==", + "dependencies": { + "copy-anything": "^2.0.1", + "tslib": "^1.10.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "native-request": "^1.0.5", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-6.2.0.tgz", + "integrity": "sha512-Cl5h95/Pz/PWub/tCBgT1oNMFeH1WTD33piG80jn5jr12T4XbxZcjThwNXDQ7AG649WEynuIzO4b0+2Tn9Qolg==", + "dependencies": { + "clone": "^2.1.2", + "less": "^3.11.3", + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/less/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==" + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" + }, + "node_modules/lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/loglevel": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "dependencies": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "peerDependencies": { + "markdown-it": "*" + } + }, + "node_modules/markdown-it-chain": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", + "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", + "dependencies": { + "webpack-chain": "^4.9.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "markdown-it": ">=5.0.0" + } + }, + "node_modules/markdown-it-chain/node_modules/javascript-stringify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", + "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==" + }, + "node_modules/markdown-it-chain/node_modules/webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" + } + }, + "node_modules/markdown-it-container": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", + "integrity": "sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU=" + }, + "node_modules/markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" + }, + "node_modules/markdown-it-table-of-contents": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", + "engines": { + "node": ">6.4.0" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", + "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", + "dependencies": { + "loader-utils": "^1.1.0", + "normalize-url": "^2.0.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.4.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dependencies": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dependencies": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "node_modules/nan": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/native-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.0.tgz", + "integrity": "sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==", + "optional": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==" + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", + "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", + "dependencies": { + "array.prototype.reduce": "^1.0.4", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/optimize-css-assets-webpack-plugin": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.6.tgz", + "integrity": "sha512-JAYw7WrIAIuHWoKeSBB3lJ6ZG9PSDK3JJduv/FMpIY060wvbA8Lqn/TCtxNGICNlg0X5AGshLzIhpYrkltdq+A==", + "dependencies": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dependencies": { + "retry": "^0.12.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/portfinder/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "dependencies": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dependencies": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-colormin/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "dependencies": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dependencies": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/postcss-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dependencies": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dependencies": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dependencies": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "dependencies": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dependencies": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dependencies": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-safe-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", + "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", + "dependencies": { + "postcss": "^7.0.26" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-svgo/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dependencies": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prismjs": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz", + "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reduce": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.2.tgz", + "integrity": "sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ==", + "dependencies": { + "object-keys": "^1.1.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + }, + "node_modules/regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "node_modules/renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + } + }, + "node_modules/renderkid/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "node_modules/selfsigned": { + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", + "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", + "dependencies": { + "node-forge": "^0.10.0" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/sitemap": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz", + "integrity": "sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg==", + "dependencies": { + "lodash.chunk": "^4.2.0", + "lodash.padstart": "^4.6.1", + "whatwg-url": "^7.0.0", + "xmlbuilder": "^13.0.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=4.0.0" + } + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/smoothscroll-polyfill": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz", + "integrity": "sha512-TK5ZA9U5RqCwMpfoMq/l1mrH0JAR7y7KRvOBx0n2869aLxch+gT9GhN3yUfjiw+d/DiF1mKo14+hd62JyMmoBg==" + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", + "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", + "dependencies": { + "debug": "^3.2.7", + "eventsource": "^2.0.2", + "faye-websocket": "^0.11.4", + "inherits": "^2.0.4", + "url-parse": "^1.5.10" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://tidelift.com/funding/github/npm/sockjs-client" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/sockjs-client/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssr-window": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-2.0.0.tgz", + "integrity": "sha512-NXzN+/HPObKAx191H3zKlYomE5WrVIkoCB5IaSdvKokxTpjBdWfr0RaP+1Z5KOfDT0ZVz+2tdtiBkhsEQ9p+0A==" + }, + "node_modules/ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "node_modules/stack-utils": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", + "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.3.1.tgz", + "integrity": "sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g==", + "dependencies": { + "ci-info": "^3.1.1" + } + }, + "node_modules/std-env/node_modules/ci-info": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==" + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/stylehacks/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylus": { + "version": "0.54.8", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", + "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", + "dependencies": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.6", + "mkdirp": "~1.0.4", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.3.0", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dependencies": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + }, + "peerDependencies": { + "stylus": ">=0.52.4" + } + }, + "node_modules/stylus-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/stylus-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/stylus/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stylus/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/stylus/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=" + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/swiper": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-5.4.5.tgz", + "integrity": "sha512-7QjA0XpdOmiMoClfaZ2lYN6ICHcMm72LXiY+NF4fQLFidigameaofvpjEEiTQuw3xm5eksG5hzkaRsjQX57vtA==", + "hasInstallScript": true, + "dependencies": { + "dom7": "^2.1.5", + "ssr-window": "^2.0.0" + }, + "engines": { + "node": ">= 4.7.0" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/vladimirkharlampidi" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "node_modules/throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "node_modules/to-factory": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-factory/-/to-factory-1.0.0.tgz", + "integrity": "sha1-hzivi9lxIK0dQEeXKtpVY7+UebE=" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, + "node_modules/toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=" + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dependencies": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "node_modules/uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/update-notifier/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated" + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "dependencies": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/url-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/url-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/url-loader/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/vue": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", + "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==" + }, + "node_modules/vue-awesome-swiper": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vue-awesome-swiper/-/vue-awesome-swiper-4.1.1.tgz", + "integrity": "sha512-50um10t6N+lJaORkpwSi1wWuMmBI1sgFc9Znsi5oUykw2cO5DzLaBHcO2JNX21R+Ue4TGoIJDhhxjBHtkFrTEQ==", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "swiper": "^5.2.0", + "vue": "2.x" + } + }, + "node_modules/vue-baidu-map": { + "version": "0.21.22", + "resolved": "https://registry.npmjs.org/vue-baidu-map/-/vue-baidu-map-0.21.22.tgz", + "integrity": "sha512-WQMPCih4UTh0AZCKKH/OVOYnyAWjfRNeK6BIeoLmscyY5aF8zzlJhz/NOHLb3mdztIpB0Z6aohn4Jd9mfCSjQw==", + "dependencies": { + "bmaplib.curveline": "^1.0.0", + "bmaplib.heatmap": "^1.0.4", + "bmaplib.lushu": "^1.0.7", + "bmaplib.markerclusterer": "^1.0.13", + "markdown-it": "^8.4.0" + }, + "peerDependencies": { + "vue": "^2.1.8" + } + }, + "node_modules/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==" + }, + "node_modules/vue-lazyload": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.3.tgz", + "integrity": "sha512-uHnq0FTEeNmqnbBC2aRKlmtd9LofMZ6Q3mWvgfLa+i9vhxU8fDK+nGs9c1iVT85axSua/AUnMttIq3xPaU9G3A==" + }, + "node_modules/vue-loader": { + "version": "15.9.8", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.8.tgz", + "integrity": "sha512-GwSkxPrihfLR69/dSV3+5CdMQ0D+jXg8Ma1S4nQXKJAznYFX14vHdc/NetQc34Dw+rBbIJyP7JOuVb9Fhprvog==", + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "peerDependencies": { + "css-loader": "*", + "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/vue-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/vue-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/vue-router": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.5.tgz", + "integrity": "sha512-ioRY5QyDpXM9TDjOX6hX79gtaMXSVDDzSlbIlyAmbHNteIL81WIVB2e+jbzV23vzxtoV0krdS2XHm+GxFg+Nxg==" + }, + "node_modules/vue-server-renderer": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.14.tgz", + "integrity": "sha512-HifYRa/LW7cKywg9gd4ZtvtRuBlstQBao5ZCWlg40fyB4OPoGfEXAzxb0emSLv4pBDOHYx0UjpqvxpiQFEuoLA==", + "dependencies": { + "chalk": "^1.1.3", + "hash-sum": "^1.0.2", + "he": "^1.1.0", + "lodash.template": "^4.5.0", + "lodash.uniq": "^4.5.0", + "resolve": "^1.2.0", + "serialize-javascript": "^3.1.0", + "source-map": "0.5.6" + } + }, + "node_modules/vue-server-renderer/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vue-server-renderer/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vue-server-renderer/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vue-server-renderer/node_modules/serialize-javascript": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", + "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/vue-server-renderer/node_modules/source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vue-server-renderer/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vue-server-renderer/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dependencies": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "node_modules/vue-style-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/vue-style-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz", + "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" + }, + "node_modules/vuepress": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.5.4.tgz", + "integrity": "sha512-F25r65BzxDFAJmWIN9s9sQSndLIf1ldAKEwkeXCqE4p2lsx/eVvQJL3DzOeeR2WgCFOkhFMKWIV+CthTGdNTZg==", + "hasInstallScript": true, + "dependencies": { + "@vuepress/core": "1.5.4", + "@vuepress/theme-default": "1.5.4", + "cac": "^6.5.6", + "envinfo": "^7.2.0", + "opencollective-postinstall": "^2.0.2", + "update-notifier": "^4.0.0" + }, + "bin": { + "vuepress": "cli.js" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/vuepress-html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-BebAEl1BmWlro3+VyDhIOCY6Gef2MCBllEVAP3NUAtMguiyOwo/dClbwJ167WYmcxHJKLl7b0Chr9H7fpn1d0A==", + "dependencies": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/vuepress-html-webpack-plugin/node_modules/big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "engines": { + "node": "*" + } + }, + "node_modules/vuepress-html-webpack-plugin/node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vuepress-html-webpack-plugin/node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/vuepress-html-webpack-plugin/node_modules/loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==", + "dependencies": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "node_modules/vuepress-html-webpack-plugin/node_modules/util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dependencies": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/vuepress-plugin-code-copy": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vuepress-plugin-code-copy/-/vuepress-plugin-code-copy-1.0.6.tgz", + "integrity": "sha512-FiqwMtlb4rEsOI56O6sSkekcd3SlESxbkR2IaTIQxsMOMoalKfW5R9WlR1Pjm10v6jmU661Ex8MR11k9IzrNUg==" + }, + "node_modules/vuepress-plugin-container": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vuepress-plugin-container/-/vuepress-plugin-container-2.1.5.tgz", + "integrity": "sha512-TQrDX/v+WHOihj3jpilVnjXu9RcTm6m8tzljNJwYhxnJUW0WWQ0hFLcDTqTBwgKIFdEiSxVOmYE+bJX/sq46MA==", + "dependencies": { + "@vuepress/shared-utils": "^1.2.0", + "markdown-it-container": "^2.0.0" + } + }, + "node_modules/vuepress-plugin-sitemap": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/vuepress-plugin-sitemap/-/vuepress-plugin-sitemap-2.3.1.tgz", + "integrity": "sha512-n+8lbukhrKrsI9H/EX0EBgkE1pn85LAQFvQ5dIvrZP4Kz6JxPOPPNTQmZMhahQV1tXbLZQCEN7A1WZH4x+arJQ==", + "dependencies": { + "sitemap": "^3.0.0" + }, + "bin": { + "vuepress-sitemap": "cli.js" + }, + "peerDependencies": { + "chalk": "^2.0.0", + "commander": "^2.0.0", + "esm": "^3.0.0" + } + }, + "node_modules/vuepress-plugin-smooth-scroll": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", + "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", + "dependencies": { + "smoothscroll-polyfill": "^0.4.3" + } + }, + "node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, + "node_modules/watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "dependencies": { + "chokidar": "^2.1.8" + } + }, + "node_modules/watchpack/node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/watchpack/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "optional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/watchpack/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/watchpack/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/watchpack/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/watchpack/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/watchpack/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "dependencies": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz", + "integrity": "sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA==", + "dependencies": { + "ansi-html-community": "0.0.8", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 6.11.5" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-server/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack-dev-server/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/webpack-dev-server/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dependencies": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/webpack/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpackbar": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", + "integrity": "sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw==", + "dependencies": { + "ansi-escapes": "^4.1.0", + "chalk": "^2.4.1", + "consola": "^2.6.0", + "figures": "^3.0.0", + "pretty-time": "^1.1.0", + "std-env": "^2.2.1", + "text-table": "^0.2.0", + "wrap-ansi": "^5.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/zepto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz", + "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" + }, + "node_modules/zrender": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz", + "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "dependencies": { + "tslib": "2.3.0" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==" + }, + "@babel/core": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.0", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "requires": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz", + "integrity": "sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", + "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "requires": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + } + }, + "@babel/helper-replace-supers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz", + "integrity": "sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-member-expression-to-functions": "^7.17.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + } + }, + "@babel/helper-simple-access": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", + "requires": { + "@babel/types": "^7.18.2" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" + }, + "@babel/helper-wrap-function": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "requires": { + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" + } + }, + "@babel/helpers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + } + }, + "@babel/highlight": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", + "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", + "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.17.12" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", + "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", + "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz", + "integrity": "sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.2.tgz", + "integrity": "sha512-kbDISufFOxeczi0v4NQP3p5kIeW6izn/6klfWBrIIdGZZe4UpHR+QU03FAoWjGGd9SUXAwbw2pup1kaL4OQsJQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/plugin-syntax-decorators": "^7.17.12", + "charcodes": "^0.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", + "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", + "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", + "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", + "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz", + "integrity": "sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw==", + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.17.12" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", + "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", + "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", + "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", + "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.12.tgz", + "integrity": "sha512-D1Hz0qtGTza8K2xGyEdVNCYLdVHukAcbQr4K3/s6r/esadyEriZovpJimQOpu8ju4/jV8dW/1xdaE0UpDroidw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz", + "integrity": "sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz", + "integrity": "sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", + "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", + "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-remap-async-to-generator": "^7.16.8" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz", + "integrity": "sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz", + "integrity": "sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-replace-supers": "^7.18.2", + "@babel/helper-split-export-declaration": "^7.16.7", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", + "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz", + "integrity": "sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", + "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz", + "integrity": "sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "requires": { + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", + "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz", + "integrity": "sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA==", + "requires": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz", + "integrity": "sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ==", + "requires": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-simple-access": "^7.18.2", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.4.tgz", + "integrity": "sha512-lH2UaQaHVOAeYrUUuZ8i38o76J/FnO8vu21OE+tD1MyP9lxdZoSfz+pDbWkq46GogUrdrMz3tiz/FYGB+bVThg==", + "requires": { + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-identifier": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz", + "integrity": "sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA==", + "requires": { + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", + "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.17.12", + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", + "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", + "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz", + "integrity": "sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", + "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.2.tgz", + "integrity": "sha512-mr1ufuRMfS52ttq+1G1PD8OJNqgcTFjq3hwn8SZ5n1x1pBhi0E36rYMdTK0TsKtApJ4lDEdfXJwtGobQMHSMPg==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.17.12", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", + "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz", + "integrity": "sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", + "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/preset-env": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.2.tgz", + "integrity": "sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q==", + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-plugin-utils": "^7.17.12", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-async-generator-functions": "^7.17.12", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-class-static-block": "^7.18.0", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.17.12", + "@babel/plugin-proposal-json-strings": "^7.17.12", + "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.18.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", + "@babel/plugin-proposal-private-property-in-object": "^7.17.12", + "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.17.12", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.17.12", + "@babel/plugin-transform-async-to-generator": "^7.17.12", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.17.12", + "@babel/plugin-transform-classes": "^7.17.12", + "@babel/plugin-transform-computed-properties": "^7.17.12", + "@babel/plugin-transform-destructuring": "^7.18.0", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.17.12", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.18.1", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.17.12", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.18.0", + "@babel/plugin-transform-modules-commonjs": "^7.18.2", + "@babel/plugin-transform-modules-systemjs": "^7.18.0", + "@babel/plugin-transform-modules-umd": "^7.18.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", + "@babel/plugin-transform-new-target": "^7.17.12", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.17.12", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.18.0", + "@babel/plugin-transform-reserved-words": "^7.17.12", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.17.12", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.18.2", + "@babel/plugin-transform-typeof-symbol": "^7.17.12", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.2", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", + "requires": { + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + } + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@babel/types": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==" + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + }, + "@types/node": { + "version": "17.0.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", + "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" + }, + "@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz", + "integrity": "sha512-QOi5OW45e2R20VygMSNhyQHvpdUwQZqGPc748JLGCYEy+yp8fNFNdbNIGAgZmi9e+2JHPd6i6idRuqivyicIkA==" + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz", + "integrity": "sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==" + }, + "@vue/babel-plugin-jsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.1.tgz", + "integrity": "sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "@vue/babel-helper-vue-transform-on": "^1.0.2", + "camelcase": "^6.0.0", + "html-tags": "^3.1.0", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-plugin-transform-vue-jsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.2.1.tgz", + "integrity": "sha512-HJuqwACYehQwh1fNT8f4kyzqlNMpBuUK4rSiSES5D4QsYncv5fxFsLyrxFPG2ksO7t5WP+Vgix6tt6yKClwPzA==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "dependencies": { + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==" + } + } + }, + "@vue/babel-preset-app": { + "version": "4.5.17", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.17.tgz", + "integrity": "sha512-iFv9J3F5VKUPcbx+TqW5qhGmAVyXQxPRpKpPOuTLFIVTzg+iwJnrqVbL4kJU5ECGDxPESW2oCVgxv9bTlDPu7w==", + "requires": { + "@babel/core": "^7.11.0", + "@babel/helper-compilation-targets": "^7.9.6", + "@babel/helper-module-imports": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.11.0", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.0", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.2.4", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.6.5", + "core-js-compat": "^3.6.5", + "semver": "^6.1.0" + }, + "dependencies": { + "core-js": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz", + "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@vue/babel-preset-jsx": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.2.4.tgz", + "integrity": "sha512-oRVnmN2a77bYDJzeGSt92AuHXbkIxbf/XXSE3klINnh9AXBmVS1DGa1f0d+dDYpLfsAKElMnqKTQfKn7obcL4w==", + "requires": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "@vue/babel-sugar-composition-api-inject-h": "^1.2.1", + "@vue/babel-sugar-composition-api-render-instance": "^1.2.4", + "@vue/babel-sugar-functional-vue": "^1.2.2", + "@vue/babel-sugar-inject-h": "^1.2.2", + "@vue/babel-sugar-v-model": "^1.2.3", + "@vue/babel-sugar-v-on": "^1.2.3" + } + }, + "@vue/babel-sugar-composition-api-inject-h": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.2.1.tgz", + "integrity": "sha512-4B3L5Z2G+7s+9Bwbf+zPIifkFNcKth7fQwekVbnOA3cr3Pq71q71goWr97sk4/yyzH8phfe5ODVzEjX7HU7ItQ==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-composition-api-render-instance": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.2.4.tgz", + "integrity": "sha512-joha4PZznQMsxQYXtR3MnTgCASC9u3zt9KfBxIeuI5g2gscpTsSKRDzWQt4aqNIpx6cv8On7/m6zmmovlNsG7Q==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-functional-vue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.2.2.tgz", + "integrity": "sha512-JvbgGn1bjCLByIAU1VOoepHQ1vFsroSA/QkzdiSs657V79q6OwEWLCQtQnEXD/rLTA8rRit4rMOhFpbjRFm82w==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-inject-h": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.2.2.tgz", + "integrity": "sha512-y8vTo00oRkzQTgufeotjCLPAvlhnpSkcHFEp60+LJUwygGcd5Chrpn5480AQp/thrxVm8m2ifAk0LyFel9oCnw==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-v-model": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.2.3.tgz", + "integrity": "sha512-A2jxx87mySr/ulAsSSyYE8un6SIH0NWHiLaCWpodPCVOlQVODCaSpiR4+IMsmBr73haG+oeCuSvMOM+ttWUqRQ==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==" + } + } + }, + "@vue/babel-sugar-v-on": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.2.3.tgz", + "integrity": "sha512-kt12VJdz/37D3N3eglBywV8GStKNUhNrsxChXIV+o0MwVXORYuhDTHJRKPgLJRb/EY3vM2aRFQdxJBp9CLikjw==", + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "camelcase": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } + } + }, + "@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "prettier": "^1.18.2 || ^2.0.0", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "@vuepress/core": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.5.4.tgz", + "integrity": "sha512-RaHJiX0Yno4S3zoV64JNd3xE55sza8rayyWvXAJY381XVMxKrsLBrgW6ntNYSkzGnZcxi6fwMV/CVOUhEtkEkA==", + "requires": { + "@babel/core": "^7.8.4", + "@vue/babel-preset-app": "^4.1.2", + "@vuepress/markdown": "1.5.4", + "@vuepress/markdown-loader": "1.5.4", + "@vuepress/plugin-last-updated": "1.5.4", + "@vuepress/plugin-register-components": "1.5.4", + "@vuepress/shared-utils": "1.5.4", + "autoprefixer": "^9.5.1", + "babel-loader": "^8.0.4", + "cache-loader": "^3.0.0", + "chokidar": "^2.0.3", + "connect-history-api-fallback": "^1.5.0", + "copy-webpack-plugin": "^5.0.2", + "core-js": "^3.6.4", + "cross-spawn": "^6.0.5", + "css-loader": "^2.1.1", + "file-loader": "^3.0.1", + "js-yaml": "^3.13.1", + "lru-cache": "^5.1.1", + "mini-css-extract-plugin": "0.6.0", + "optimize-css-assets-webpack-plugin": "^5.0.1", + "portfinder": "^1.0.13", + "postcss-loader": "^3.0.0", + "postcss-safe-parser": "^4.0.1", + "toml": "^3.0.0", + "url-loader": "^1.0.1", + "vue": "^2.6.10", + "vue-loader": "^15.7.1", + "vue-router": "^3.1.3", + "vue-server-renderer": "^2.6.10", + "vue-template-compiler": "^2.6.10", + "vuepress-html-webpack-plugin": "^3.2.0", + "vuepress-plugin-container": "^2.0.2", + "webpack": "^4.8.1", + "webpack-chain": "^6.0.0", + "webpack-dev-server": "^3.5.1", + "webpack-merge": "^4.1.2", + "webpackbar": "3.2.0" + }, + "dependencies": { + "core-js": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz", + "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==" + } + } + }, + "@vuepress/markdown": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.5.4.tgz", + "integrity": "sha512-bgrR9LTcAa2O0WipTbH3OFKeAfXc/2oU6cUIoMkyihSKUo1Mr5yt1XKM7vHe1uFEZygNr8EAemep8chsuVuISA==", + "requires": { + "@vuepress/shared-utils": "1.5.4", + "markdown-it": "^8.4.1", + "markdown-it-anchor": "^5.0.2", + "markdown-it-chain": "^1.3.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-table-of-contents": "^0.4.0", + "prismjs": "^1.13.0" + } + }, + "@vuepress/markdown-loader": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.5.4.tgz", + "integrity": "sha512-3R5quGIXQm7gfPWN67SVZ9OBA7VrGEEXJjjV01MYkbfhqVGgO6lBRq73Og0XdKs4RPx4nqJUPthhL8FJVNRTIg==", + "requires": { + "@vuepress/markdown": "1.5.4", + "loader-utils": "^1.1.0", + "lru-cache": "^5.1.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "@vuepress/plugin-active-header-links": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.5.4.tgz", + "integrity": "sha512-FI1Dr/44HVqxLMRSuaVEEwegGVEGFlaWYE3nsXwL7klKr6c+2kXHEw9rSQlAxzJyzVfovTk4dd+s/AMOKuLGZQ==", + "requires": { + "lodash.debounce": "^4.0.8" + } + }, + "@vuepress/plugin-last-updated": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.5.4.tgz", + "integrity": "sha512-9kezBCxPM+cevKRNML6Q7v6qkI8NQvKbVkwohlzsElM8FBmjlZmgFyZje66ksTnb/U6ogazCCq9jdOyipNcQ2A==", + "requires": { + "cross-spawn": "^6.0.5" + } + }, + "@vuepress/plugin-nprogress": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.5.4.tgz", + "integrity": "sha512-2bGKoO/o2e5mIfOU80q+AkxOK5wVijA/+8jGjSQVf2ccMpJw+Ly1mMi69r81Q0QkEihgfI9VN42a5+a6LUgPBw==", + "requires": { + "nprogress": "^0.2.0" + } + }, + "@vuepress/plugin-register-components": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.5.4.tgz", + "integrity": "sha512-Y1U9j6unZp1ZhnHjQ9yOPY+vxldUA3C1EwT6UgI75j5gxa5Hz6NakoIo6mbhaYHlGmx33o/MXrxufLPapo/YlQ==", + "requires": { + "@vuepress/shared-utils": "1.5.4" + } + }, + "@vuepress/plugin-search": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.5.4.tgz", + "integrity": "sha512-wikU9XYiZ3Olbii0lI+56mcSdpzHHkduVBMB4MNEV5iob23qDxGPmvfZirjsZV20w1UnLRptERyHtZkTLW9Mbg==" + }, + "@vuepress/shared-utils": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.5.4.tgz", + "integrity": "sha512-HCeMPEAPjFN1Ongii0BUCI1iB4gBBiQ4PUgh7F4IGG8yBg4tMqWO4NHqCuDCuGEvK7lgHy8veto0SsSvdSKp3g==", + "requires": { + "chalk": "^2.3.2", + "escape-html": "^1.0.3", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "gray-matter": "^4.0.1", + "hash-sum": "^1.0.2", + "semver": "^6.0.0", + "toml": "^3.0.0", + "upath": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@vuepress/theme-default": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.5.4.tgz", + "integrity": "sha512-kHst1yXzqTiocVU7w9x4cfJ08vR9ZbREC6kTRtH1ytQSEUL5tM0b9HFicfg1kDp7YNq2qntRro+WmfjU9Ps/eg==", + "requires": { + "@vuepress/plugin-active-header-links": "1.5.4", + "@vuepress/plugin-nprogress": "1.5.4", + "@vuepress/plugin-search": "1.5.4", + "docsearch.js": "^2.5.2", + "lodash": "^4.17.15", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.2", + "vuepress-plugin-container": "^2.0.2", + "vuepress-plugin-smooth-scroll": "^0.0.3" + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "agentkeepalive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", + "integrity": "sha512-TnB6ziK363p7lR8QpeLC8aMr8EGYBKZTpgzQLfqTs3bR0Oo5VbKdwKf8h0dSzsYrB7lSCgfJnMZKqShvlq5Oyg==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "requires": {} + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "algoliasearch": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz", + "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==", + "requires": { + "agentkeepalive": "^2.2.0", + "debug": "^2.6.9", + "envify": "^4.0.0", + "es6-promise": "^4.1.0", + "events": "^1.1.0", + "foreach": "^2.0.5", + "global": "^4.3.2", + "inherits": "^2.0.1", + "isarray": "^2.0.1", + "load-script": "^1.0.0", + "object-keys": "^1.0.11", + "querystring-es3": "^0.2.1", + "reduce": "^1.0.1", + "semver": "^5.1.0", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==" + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + }, + "array.prototype.reduce": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", + "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" + }, + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "requires": { + "babel-runtime": "6.x" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autocomplete.js": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.36.0.tgz", + "integrity": "sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q==", + "requires": { + "immediate": "^3.2.3" + } + }, + "autoprefixer": { + "version": "9.8.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", + "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "picocolors": "^0.2.1", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bmaplib.curveline": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz", + "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q==" + }, + "bmaplib.heatmap": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz", + "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q==" + }, + "bmaplib.lushu": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/bmaplib.lushu/-/bmaplib.lushu-1.0.7.tgz", + "integrity": "sha512-LVvgpESPii6xGxyjnQjq8u+ic4NjvhdCPV/RiSS/PGTUdZKeTDS7prSpleJLZH3ES0+oc0gYn8bw0LtPYUSz2w==" + }, + "bmaplib.markerclusterer": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz", + "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==", + "requires": { + "bmaplib.texticonoverlay": "^1.0.2" + } + }, + "bmaplib.texticonoverlay": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz", + "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg==" + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + } + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + } + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", + "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "cac": { + "version": "6.7.12", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.12.tgz", + "integrity": "sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==" + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-3.0.1.tgz", + "integrity": "sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw==", + "requires": { + "buffer-json": "^2.0.0", + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.2.3", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==" + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "charcodes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", + "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==" + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "requires": { + "source-map": "~0.6.0" + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "requires": { + "bluebird": "^3.1.1" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" + }, + "copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + } + } + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "core-js-compat": { + "version": "3.22.7", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.7.tgz", + "integrity": "sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA==", + "requires": { + "browserslist": "^4.20.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==" + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-loader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", + "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "requires": { + "camelcase": "^5.2.0", + "icss-utils": "^4.1.0", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.14", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.6", + "postcss-modules-scope": "^2.1.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", + "requires": { + "css": "^2.0.0" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==" + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==" + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + } + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "docsearch.js": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/docsearch.js/-/docsearch.js-2.6.3.tgz", + "integrity": "sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A==", + "requires": { + "algoliasearch": "^3.24.5", + "autocomplete.js": "0.36.0", + "hogan.js": "^3.0.2", + "request": "^2.87.0", + "stack-utils": "^1.0.1", + "to-factory": "^1.0.0", + "zepto": "^1.2.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + } + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "dom7": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-2.1.5.tgz", + "integrity": "sha512-xnhwVgyOh3eD++/XGtH+5qBwYTgCm0aW91GFgPJ3XG+jlsRLyJivnbP0QmUBFhI+Oaz9FV0s7cxgXHezwOEBYA==", + "requires": { + "ssr-window": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + } + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "echarts": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.2.tgz", + "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.3.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.141", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.141.tgz", + "integrity": "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA==" + }, + "element-ui": { + "version": "2.15.8", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.8.tgz", + "integrity": "sha512-N54zxosRFqpYax3APY3GeRmtOZwIls6Z756WM0kdPZ5Q92PIeKHnZgF1StlamIg9bLxP1k+qdhTZvIeQlim09A==", + "requires": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "envify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", + "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", + "requires": { + "esprima": "^4.0.0", + "through": "~2.3.4" + } + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "peer": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" + }, + "eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + }, + "foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "requires": { + "ini": "1.3.7" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "requires": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + } + }, + "gsap": { + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.10.4.tgz", + "integrity": "sha512-6QatdkKxXCMfvCW4rM++0RqyLQAzFX5nwl3yHS0XPgkZBkiSEY3VZVbMltrdtsbER/xZonLtyHt684wRp4erlQ==" + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + } + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==" + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hogan.js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", + "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==", + "requires": { + "mkdirp": "0.3.0", + "nopt": "1.0.10" + }, + "dependencies": { + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==" + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==" + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + } + } + }, + "html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + } + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==" + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "requires": { + "postcss": "^7.0.14" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true + }, + "immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==", + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==" + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==" + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + }, + "dependencies": { + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + } + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "less": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz", + "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==", + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "native-request": "^1.0.5", + "source-map": "~0.6.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "less-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-6.2.0.tgz", + "integrity": "sha512-Cl5h95/Pz/PWub/tCBgT1oNMFeH1WTD33piG80jn5jr12T4XbxZcjThwNXDQ7AG649WEynuIzO4b0+2Tn9Qolg==", + "requires": { + "clone": "^2.1.2", + "less": "^3.11.3", + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==" + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" + }, + "lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "loglevel": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==" + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + } + } + }, + "markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "requires": {} + }, + "markdown-it-chain": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", + "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", + "requires": { + "webpack-chain": "^4.9.0" + }, + "dependencies": { + "javascript-stringify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", + "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==" + }, + "webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" + } + } + } + }, + "markdown-it-container": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", + "integrity": "sha1-ABm0P9Au7+zi8ZYKKJX7qBpARpU=" + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" + }, + "markdown-it-table-of-contents": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==" + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "requires": { + "source-map": "^0.6.1" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } + }, + "mini-css-extract-plugin": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", + "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "^2.0.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "nan": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "native-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.0.tgz", + "integrity": "sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==", + "optional": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==" + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", + "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", + "requires": { + "array.prototype.reduce": "^1.0.4", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==" + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.6.tgz", + "integrity": "sha512-JAYw7WrIAIuHWoKeSBB3lJ6ZG9PSDK3JJduv/FMpIY060wvbA8Lqn/TCtxNGICNlg0X5AGshLzIhpYrkltdq+A==", + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-safe-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", + "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", + "requires": { + "postcss": "^7.0.26" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "optional": true + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" + }, + "prismjs": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz", + "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + } + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "reduce": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.2.tgz", + "integrity": "sha512-xX7Fxke/oHO5IfZSk77lvPa/7bjMh9BuCk4OOoX5XTXrM7s0Z+MkPfSDfz0q7r91BhhGSs8gii/VEN/7zhCPpQ==", + "requires": { + "object-keys": "^1.1.0" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpu-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + }, + "regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "requires": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "selfsigned": { + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", + "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sitemap": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz", + "integrity": "sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg==", + "requires": { + "lodash.chunk": "^4.2.0", + "lodash.padstart": "^4.6.1", + "whatwg-url": "^7.0.0", + "xmlbuilder": "^13.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + }, + "smoothscroll-polyfill": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz", + "integrity": "sha512-TK5ZA9U5RqCwMpfoMq/l1mrH0JAR7y7KRvOBx0n2869aLxch+gT9GhN3yUfjiw+d/DiF1mKo14+hd62JyMmoBg==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "sockjs-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", + "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", + "requires": { + "debug": "^3.2.7", + "eventsource": "^2.0.2", + "faye-websocket": "^0.11.4", + "inherits": "^2.0.4", + "url-parse": "^1.5.10" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssr-window": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-2.0.0.tgz", + "integrity": "sha512-NXzN+/HPObKAx191H3zKlYomE5WrVIkoCB5IaSdvKokxTpjBdWfr0RaP+1Z5KOfDT0ZVz+2tdtiBkhsEQ9p+0A==" + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", + "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "std-env": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.3.1.tgz", + "integrity": "sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g==", + "requires": { + "ci-info": "^3.1.1" + }, + "dependencies": { + "ci-info": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==" + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylus": { + "version": "0.54.8", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", + "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", + "requires": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.6", + "mkdirp": "~1.0.4", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.3.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "swiper": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-5.4.5.tgz", + "integrity": "sha512-7QjA0XpdOmiMoClfaZ2lYN6ICHcMm72LXiY+NF4fQLFidigameaofvpjEEiTQuw3xm5eksG5hzkaRsjQX57vtA==", + "requires": { + "dom7": "^2.1.5", + "ssr-window": "^2.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-factory": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-factory/-/to-factory-1.0.0.tgz", + "integrity": "sha1-hzivi9lxIK0dQEeXKtpVY7+UebE=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + } + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + } + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "vue": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", + "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==" + }, + "vue-awesome-swiper": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vue-awesome-swiper/-/vue-awesome-swiper-4.1.1.tgz", + "integrity": "sha512-50um10t6N+lJaORkpwSi1wWuMmBI1sgFc9Znsi5oUykw2cO5DzLaBHcO2JNX21R+Ue4TGoIJDhhxjBHtkFrTEQ==", + "requires": {} + }, + "vue-baidu-map": { + "version": "0.21.22", + "resolved": "https://registry.npmjs.org/vue-baidu-map/-/vue-baidu-map-0.21.22.tgz", + "integrity": "sha512-WQMPCih4UTh0AZCKKH/OVOYnyAWjfRNeK6BIeoLmscyY5aF8zzlJhz/NOHLb3mdztIpB0Z6aohn4Jd9mfCSjQw==", + "requires": { + "bmaplib.curveline": "^1.0.0", + "bmaplib.heatmap": "^1.0.4", + "bmaplib.lushu": "^1.0.7", + "bmaplib.markerclusterer": "^1.0.13", + "markdown-it": "^8.4.0" + } + }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==" + }, + "vue-lazyload": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.3.tgz", + "integrity": "sha512-uHnq0FTEeNmqnbBC2aRKlmtd9LofMZ6Q3mWvgfLa+i9vhxU8fDK+nGs9c1iVT85axSua/AUnMttIq3xPaU9G3A==" + }, + "vue-loader": { + "version": "15.9.8", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.8.tgz", + "integrity": "sha512-GwSkxPrihfLR69/dSV3+5CdMQ0D+jXg8Ma1S4nQXKJAznYFX14vHdc/NetQc34Dw+rBbIJyP7JOuVb9Fhprvog==", + "requires": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "vue-router": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.5.tgz", + "integrity": "sha512-ioRY5QyDpXM9TDjOX6hX79gtaMXSVDDzSlbIlyAmbHNteIL81WIVB2e+jbzV23vzxtoV0krdS2XHm+GxFg+Nxg==" + }, + "vue-server-renderer": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.14.tgz", + "integrity": "sha512-HifYRa/LW7cKywg9gd4ZtvtRuBlstQBao5ZCWlg40fyB4OPoGfEXAzxb0emSLv4pBDOHYx0UjpqvxpiQFEuoLA==", + "requires": { + "chalk": "^1.1.3", + "hash-sum": "^1.0.2", + "he": "^1.1.0", + "lodash.template": "^4.5.0", + "lodash.uniq": "^4.5.0", + "resolve": "^1.2.0", + "serialize-javascript": "^3.1.0", + "source-map": "0.5.6" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "serialize-javascript": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", + "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "vue-template-compiler": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz", + "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==", + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" + }, + "vuepress": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/vuepress/-/vuepress-1.5.4.tgz", + "integrity": "sha512-F25r65BzxDFAJmWIN9s9sQSndLIf1ldAKEwkeXCqE4p2lsx/eVvQJL3DzOeeR2WgCFOkhFMKWIV+CthTGdNTZg==", + "requires": { + "@vuepress/core": "1.5.4", + "@vuepress/theme-default": "1.5.4", + "cac": "^6.5.6", + "envinfo": "^7.2.0", + "opencollective-postinstall": "^2.0.2", + "update-notifier": "^4.0.0" + } + }, + "vuepress-html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vuepress-html-webpack-plugin/-/vuepress-html-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-BebAEl1BmWlro3+VyDhIOCY6Gef2MCBllEVAP3NUAtMguiyOwo/dClbwJ167WYmcxHJKLl7b0Chr9H7fpn1d0A==", + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==" + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==", + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + } + } + }, + "vuepress-plugin-code-copy": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vuepress-plugin-code-copy/-/vuepress-plugin-code-copy-1.0.6.tgz", + "integrity": "sha512-FiqwMtlb4rEsOI56O6sSkekcd3SlESxbkR2IaTIQxsMOMoalKfW5R9WlR1Pjm10v6jmU661Ex8MR11k9IzrNUg==" + }, + "vuepress-plugin-container": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vuepress-plugin-container/-/vuepress-plugin-container-2.1.5.tgz", + "integrity": "sha512-TQrDX/v+WHOihj3jpilVnjXu9RcTm6m8tzljNJwYhxnJUW0WWQ0hFLcDTqTBwgKIFdEiSxVOmYE+bJX/sq46MA==", + "requires": { + "@vuepress/shared-utils": "^1.2.0", + "markdown-it-container": "^2.0.0" + } + }, + "vuepress-plugin-sitemap": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/vuepress-plugin-sitemap/-/vuepress-plugin-sitemap-2.3.1.tgz", + "integrity": "sha512-n+8lbukhrKrsI9H/EX0EBgkE1pn85LAQFvQ5dIvrZP4Kz6JxPOPPNTQmZMhahQV1tXbLZQCEN7A1WZH4x+arJQ==", + "requires": { + "sitemap": "^3.0.0" + } + }, + "vuepress-plugin-smooth-scroll": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vuepress-plugin-smooth-scroll/-/vuepress-plugin-smooth-scroll-0.0.3.tgz", + "integrity": "sha512-qsQkDftLVFLe8BiviIHaLV0Ea38YLZKKonDGsNQy1IE0wllFpFIEldWD8frWZtDFdx6b/O3KDMgVQ0qp5NjJCg==", + "requires": { + "smoothscroll-polyfill": "^0.4.3" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + }, + "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "optional": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + } + } + }, + "webpack-dev-server": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz", + "integrity": "sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA==", + "requires": { + "ansi-html-community": "0.0.8", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "requires": { + "lodash": "^4.17.15" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "webpackbar": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", + "integrity": "sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw==", + "requires": { + "ansi-escapes": "^4.1.0", + "chalk": "^2.4.1", + "consola": "^2.6.0", + "figures": "^3.0.0", + "pretty-time": "^1.1.0", + "std-env": "^2.2.1", + "text-table": "^0.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } + } + }, + "zepto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz", + "integrity": "sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=" + }, + "zrender": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.1.tgz", + "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "requires": { + "tslib": "2.3.0" + } + } + } +} diff --git a/web-ui/package.json b/web-ui/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6b39e992b8a82563155b5c0151a5099b755e575c --- /dev/null +++ b/web-ui/package.json @@ -0,0 +1,30 @@ +{ + "name": "website-v2", + "version": "0.0.1", + "description": "", + "main": "index.js", + "scripts": { + "dev": "vuepress dev docs", + "build": "node --max_old_space_size=10240 node_modules/vuepress/cli.js build docs" + }, + "keywords": [], + "author": "", + "license": "", + "dependencies": { + "axios": "^0.19.2", + "dayjs": "^1.8.31", + "echarts": "^5.0.2", + "element-ui": "^2.13.2", + "gsap": "^3.9.0", + "less-loader": "^6.2.0", + "optimize-css-assets-webpack-plugin": "5.0.6", + "swiper": "^5.2.0", + "vue-awesome-swiper": "^4.1.1", + "vue-baidu-map": "^0.21.11", + "vue-lazyload": "^1.3.3", + "vue-router": "3.4.5", + "vuepress": "~1.5.2", + "vuepress-plugin-code-copy": "^1.0.6", + "vuepress-plugin-sitemap": "^2.3.1" + } +} diff --git a/web-ui/packages/eularTrace/eularTrace.js b/web-ui/packages/eularTrace/eularTrace.js new file mode 100644 index 0000000000000000000000000000000000000000..1a37525f171367cb3ecdb8d0189e1a72d342d05e --- /dev/null +++ b/web-ui/packages/eularTrace/eularTrace.js @@ -0,0 +1,910 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.webtracing = {})); +})(this, (function (exports) { 'use strict'; + + /** + * 补全字符 + * @param {*} num 初始值 + * @param {*} len 需要补全的位数 + * @param {*} placeholder 补全的值 + * @returns 补全后的值 + */ + function pad(num, len, placeholder = '0') { + const str = String(num); + if (str.length < len) { + let result = str; + for (let i = 0; i < len - str.length; i += 1) { + result = placeholder + result; + } + return result; + } + return str; + } + + /** + * 获取一个随机字符串(全局唯一标识符) + */ + function uuid() { + const date = new Date(); + + // yyyy-MM-dd的16进制表示,7位数字 + const hexDate = parseInt(`${date.getFullYear()}${pad(date.getMonth() + 1, 2)}${pad(date.getDate(), 2)}`, 10).toString(16); + + // hh-mm-ss-ms的16进制表示,最大也是7位 + const hexTime = parseInt(`${pad(date.getHours(), 2)}${pad(date.getMinutes(), 2)}${pad(date.getSeconds(), 2)}${pad(date.getMilliseconds(), 3)}`, 10).toString(16); + + // 第8位数字表示后面的time字符串的长度 + let guid = hexDate + hexTime.length + hexTime; + + // 补充随机数,补足32位的16进制数 + while (guid.length < 32) { + guid += Math.floor(Math.random() * 16).toString(16); + } + + // 分为三段,前两段包含时间戳信息 + return `${guid.slice(0, 8)}-${guid.slice(8, 16)}-${guid.slice(16)}`; + } + + /** + * 获取cookie中目标name的值 + * @param {String} name cookie名 + * @returns + */ + function getCookieByName(name) { + const result = document.cookie.match(new RegExp(`${name}=([^;]+)(;|$)`)); + return result ? result[1] : undefined; + } + + /** + * 向下兼容发送信号的方法 + */ + const sendBeacon = navigator.sendBeacon + ? (url, data) => { + if (data) navigator.sendBeacon(url, JSON.stringify(data)); + } + : (url, data) => { + // 传统方式传递参数 + const beacon = new Image(); + beacon.src = `${url}?v=${encodeURIComponent(JSON.stringify(data))}`; + }; + + const arrayMap = Array.prototype.map || function polyfillMap(fn) { + const result = []; + for (let i = 0; i < this.length; i += 1) { + result.push(fn(this[i], i, this)); + } + return result; + }; + + /** + * map方法 + * @param {Array} arr 源数组 + * @param {Function} fn 条件函数 + * @returns + */ + function map(arr, fn) { + return arrayMap.call(arr, fn); + } + + /** + * 可以理解为异步执行 + * requestIdleCallback 是浏览器空闲时会自动执行内部函数 + * requestAnimationFrame 是浏览器必须执行的 + * 关于 requestIdleCallback 和 requestAnimationFrame 可以参考 https://www.cnblogs.com/cangqinglang/p/13877078.html + */ + const nextTime = window.requestIdleCallback || window.requestAnimationFrame || ((callback) => setTimeout(callback, 17)); + + const DEVICE_KEY = '_warden_device_id'; // deviceKey - 固定 + + const SESSION_KEY = '_warden_session_id'; // sessionKey(一个站点只允许运行一个埋点程序) - 固定 + + const SURVIVIE_MILLI_SECONDS = 1800000; // session存活时长(30minutes) - 固定 + + const MAX_CACHE_LEN = 5; // 最大缓存数 + + const MAX_WAITING_TIME = 5000; // 最大等待时间 + + const { screen } = window; + const { clientWidth, clientHeight } = document.documentElement; + const { width, height, colorDepth, pixelDepth } = screen; + + let deviceId = getCookieByName(DEVICE_KEY); + + if (!deviceId) { + deviceId = `t_${uuid()}`; + document.cookie = `${DEVICE_KEY}=${deviceId};path=/;`; + } + + var device = { + clientHeight, // 网页可见区高度 + clientWidth, // 网页可见区宽度 + colorDepth, // 显示屏幕调色板的比特深度 + pixelDepth, // 显示屏幕的颜色分辨率 + deviceId, // id + screenWidth: width, // 显示屏幕的宽度 + screenHeight: height, // 显示屏幕的高度 + vendor: navigator.vendor, // 浏览器名称 + platform: navigator.platform, // 浏览器平台的环境,不是电脑系统的x64这样的(浏览器平台的环境可能是x32) + }; + + /** + * 会话控制,此会话只和具体的浏览器相关,与业务无关,和业务意义上的登录态没有任何关联,只是用于追踪同一个浏览器上访问页面的动作 + */ + + /** + * 刷新会话存续期 + */ + function refreshSession() { + const id = getCookieByName(SESSION_KEY) || `s_${uuid()}`; + const expires = new Date(Date.now() + SURVIVIE_MILLI_SECONDS); + document.cookie = `${SESSION_KEY}=${id};path=/;max-age=1800;expires=${expires.toUTCString()}`; + return id; + } + + /** + * 获取sessionid + */ + function getSessionId() { + return getCookieByName(SESSION_KEY) || refreshSession(); + } + + refreshSession(); // 初始化 + + // import { version } from '../../package.json' + + // 当前应用ID,在整个页面生命周期内不变,单页应用路由变化也不会改变,加载SDK时创建,且只创建一次 + const pageId = uuid(); + + // 与一般业务上理解的sessionId做区分,此session与业务无关,单纯就是浏览器端和后端直接的联系 + const sessionId = getSessionId(); + + let requestUrl = ''; // 服务请求地址 + let events = []; // 批次队列 + let timer = null; // 定时发送定时器 + const base = { // 基础数据 + ...device, + pageId, + sessionId, + // sdkVersion: version, + }; + + /** + * 初始化基础数据 + * @param {*} options 基础配置 + */ + function init$5(options = {}) { + const { appName, appCode, ext } = options; + requestUrl = options.requestUrl; + base.appName = appName; + base.appCode = appCode; + base.ext = ext; + } + + /** + * 记录需要发送的埋点数据 + * @param {*} e 需要发送的事件信息 + * @param {boolean} flush 是否立即发送 + */ + function emit(e, flush = false) { + events = events.concat(e); // 追加到事件队列里 + refreshSession(); + clearTimeout(timer); + + // 满足最大记录数,立即发送,否则定时发送(flush为true代表立即发送) + events.length >= MAX_CACHE_LEN || flush + ? send() + : timer = setTimeout(() => { send(); }, MAX_WAITING_TIME); + } + + /** + * 发送埋点信息 + */ + function send() { + if (events.length) { + // 选取首部的部分数据来发送,performance会一次性采集大量数据追加到events中 + const sendEvents = events.slice(0, MAX_CACHE_LEN); // 需要发送的事件 + events = events.slice(MAX_CACHE_LEN); // 剩下待发的事件 + + const time = Date.now(); + sendBeacon(requestUrl, { + baseInfo: { ...base, sendTime: time }, + eventInfo: map(sendEvents, (e) => { + e.sendTime = time; // 设置发送时间 + + // 补充type字段,将click、scroll、change、submit事件作为一类存储 + if (e.eventType === 'click' || e.eventType === 'scroll' || e.eventType === 'submit' || e.eventType === 'change') { + e.type = 'mix'; + return e; + } + + if (e.eventType === 'performance') { + // 将性能进行分类,不同类型的性能数据差异较大,分开存放,资源、页面、请求 + switch (e.eventId) { + case 'resource': + e.type = 'resourcePerformance'; + break; + case 'page': + e.type = 'pagePerformance'; + break; + case 'server': + e.type = 'serverPerformance'; + break; + } + return e; + } + e.type = e.eventType; // 其他类型type同eventType + return e; + }), + }); + if (events.length) nextTime(send); // 继续传输剩余内容,在下一个时间择机传输 + } + } + + /** + * 设置额外的 customerId + * @param {*} id 需要设置的id + */ + function setCustomerId(id) { + base.customerId = id; + } + + /** + * 设置额外的 userUuid + * @param {*} id 需要设置的id + */ + function setUserUuid(id) { + base.userUuid = id; + } + + var base$1 = { + init: init$5, + emit, + pageId, + setCustomerId, + setUserUuid, + }; + + let oldURL = window.location.href; // 最后一次的url + let historyLength = window.history.length; // 最后一次history栈的长度 + + /** + * 发送数据 + * option 请求参数 + */ + function tracePageView(option = {}) { + const { url = window.location.href, referer = oldURL, actions = '', params } = option; + let action = actions; + if (!action && window.history.length < 50) { + action = historyLength === window.history.length ? 'back_forward' : 'navigation'; + historyLength = window.history.length; + } + // 如果option.title为空,则等待框架处理document.title,延迟17ms + // 为什么是17ms? 一秒60Hz是基准,平均1Hz是17毫秒,只要出来了页面那就有 document.title + setTimeout(() => { + emit({ + eventType: 'pv', + eventId: pageId, + url, + referer, + params, + title: option.title || document.title, + action, + triggerTime: Date.now(), + }); + }, option.title ? 0 : 17); + oldURL = url; + historyLength = window.history.length; + } + + /** + * 路由Pv采集 + * pvHashtag 是否监听hash变化 + */ + function init$4(options = {}) { + const { pvCore, pvHashtag } = options; + if (!pvCore) return; + + let lastIsPop = false; // 最后一次触发路由变化是否为popState触发 + // tracePageView({ url: oldURL, referer });// reason:这个可以给它注释掉 + + if (window.history.pushState) { + // 劫持history.pushState history.replaceState + const push = window.history.pushState.bind(window.history); + window.history.pushState = (data, title, url) => { + lastIsPop = false; + const result = push(data, title, url); + tracePageView({ actions: 'navigation' }); + return result; + }; + + const repalce = window.history.replaceState.bind(window.history); + window.history.replaceState = (data, title, url) => { + lastIsPop = false; + const result = repalce(data, title, url); + tracePageView({ actions: 'navigation' }); + return result; + }; + + // hash变化也会触发popstate事件,而且会先触发popstate事件 + // 可以使用popstate来代替hashchange,如果支持History H5 Api + // https://developer.mozilla.org/zh-CN/docs/Web/API/Window/popstate_event + window.addEventListener('popstate', () => { + if (window.location.hash !== '') { + const oldHost = oldURL.indexOf('#') > 0 // 多页面情况下 history模式刷新还是在pv页面 + ? oldURL.slice(0, oldURL.indexOf('#')) + : oldURL; + if (window.location.href.slice(0, window.location.href.indexOf('#')) === oldHost && !pvHashtag) return; + } + lastIsPop = true; + tracePageView(); + }); + } + // 监听hashchange + window.addEventListener('hashchange', () => { + if (pvHashtag && !lastIsPop) tracePageView(); + lastIsPop = false; + }); + } + + var pv = { + init: init$4, + tracePageView + }; + + function setFullErrInfo(errorInfo) { + const info = { + ...errorInfo, + eventType: 'error', + url: window.location.href, + triggerTime: Date.now(), + }; + emit(info); + } + + function init$3({ errorCore }) { + if (!errorCore) return; + } + + /** + * 主动触发错误上报 + * @param {*} eventId 事件ID + * @param {*} message 错误信息 + * @param {*} options 自定义配置信息 + * @returns + */ + function traceError(eventId, message, options = {}) { + const customErrorRecord = { eventId, errMessage: message, ...options }; + + // 针对自定义的异常上报,对params对特殊处理,将其序列化为string + const { params } = customErrorRecord; + if (params) { + customErrorRecord.params = params; + } + return setFullErrInfo(customErrorRecord); + } + + var err = { + init: init$3, + traceError, + }; + + class RequestTemplate { + constructor(config = {}) { + const list = ['eventType', 'eventId', 'url', 'referer', 'action', 'params', 'millisecond']; + list.forEach((key) => { this[key] = config[key] || null; }); + } + } + class RequestTemplateClick { + constructor(config = {}) { + const list = ['eventType', 'eventId', 'url', 'params', 'title', 'x', 'y']; + list.forEach((key) => { this[key] = config[key] || null; }); + } + } + + /** + * 是否为简单的标签 + * 只包含下面的arr数组内的标签才是简单的标签 + */ + function isSimpleEl(children) { + if (children.length > 0) { + const arr = ['em', 'b', 'strong', 'span', 'img', 'i', 'code']; + const a = children.filter(({ tagName }) => arr.indexOf(tagName.toLowerCase()) >= 0); + return a.length === children.length; + } + return true; + } + + /** + * 获取元素到最外层元素组成的数组 + */ + function getNodePath(node, options = {}) { + if (!node) return []; + const { includeSelf = true, order = 'asc' } = options; + let parent = includeSelf ? node : node.parentElement; + let result = []; + while (parent) { + result = order === 'asc' ? result.concat(parent) : [parent].concat(result); + parent = parent.parentElement; + } + return result; + } + + /** + * 获取元素的关系字符串 + * 例如两层div的关系会得到字符串: div>div + */ + function getNodeXPath(node, curPath = '') { + if (!node) return curPath; + const parent = node.parentElement; + let index = 0; // 这个index 暂时没什么用 + const { id } = node; + const tagName = node.tagName.toLowerCase(); + const path = curPath ? `>${curPath}` : ''; + const indexBrackets = index ? `.${index}` : ''; + + if (!parent || parent === window || parent === document.documentElement || parent === document.body) return `${tagName}${path}`; + + if (id) return `#${id}${path}`; // 知道了id 就不需要获取上下级关系了(id是唯一的) + + if (parent.children.length > 1) index = Array.prototype.indexOf.call(parent.children, node); + + return getNodeXPath(parent, `${tagName}${indexBrackets}${path}`); + } + + /** + * 点击事件 + */ + function clickCollection() { + document.addEventListener('click', (e) => { // 点击事件 + const _config = new RequestTemplateClick({ eventType: 'click' }); + let { path } = e; + if (path === undefined) path = e.target ? getNodePath(e.target) : []; // 获取被点击的元素到最外层元素组成的数组 + + const target = path.find((el) => // 检查被点击的元素以及其父级元素是否有这些属性(从内到外,只会取第一个检查到的) + el.hasAttribute && (el.hasAttribute('data-warden-container') + || el.hasAttribute('data-warden-event-id') + || el.hasAttribute('data-warden-title'))); + if (!target) return; // :在这里return 掉了很多东西 + + _config.title = extractTitleByTarget(target); + _config.eventId = extractDataByPath(path); + _config.params = extractParamsByPath(path); + _config.elementPath = getNodeXPath(target).slice(-128); // 长度限制128字符 + const { top, left } = e.target.getBoundingClientRect(); // 元素距离html的距离 + const { scrollTop, scrollLeft } = document.documentElement; // html距离上和左侧的距离(一般都是0) + const x = left + scrollLeft; + const y = top + scrollTop; + _config.x = x; + _config.y = y; + _config.triggerTime = Date.now(); // 点击时间 + _config.url = window.location.href; // 当前页面的url + emit(_config); + }, true); + } + + /** + * 加载 & 卸载事件 + */ + function dwellCollector(eventUnload) { + const _config = new RequestTemplate({ eventType: 'dwell' }); + window.addEventListener('load', () => { // 加载完成事件 + _config.entryTime = Date.now(); + }, true); + + if (!eventUnload) return; + window.addEventListener('beforeunload', () => { // 卸载事件 + _config.eventId = uuid(); + _config.url = window.location.href; // 当前页面 url + _config.referer = document.referrer; // 上级页面 url(从哪个页面跳过来的就是上级页面) + _config.triggerTime = Date.now(); // 卸载时间 + _config.millisecond = Date.now() - _config.entryTime; // 停留多久 + const mapping = { + 0: 'navigate', // 网页通过点击链接,地址栏输入,表单提交,脚本操作等方式加载 + 1: 'reload', // 网页通过“重新加载”按钮或者location.reload()方法加载 + 2: 'back_forward', // 网页通过“前进”或“后退”按钮加载 + 255: 'reserved', // 任何其他来源的加载 + }; + const { type } = performance.navigation; // 表示加载来源, type为 0,1,2,255 + _config.operateAction = mapping[type] || null; + emit(_config, true); + }, false); + } + + /** + * 提取数据事件ID + */ + function extractDataByPath(list = []) { + /* data-warden-event-id */ + const hasIdEl = getElByAttr(list, 'data-warden-event-id'); + if (hasIdEl) return hasIdEl.getAttribute('data-warden-event-id'); + + /* title */ + const hasTitleEl = getElByAttr(list, 'title'); + if (hasTitleEl) return hasTitleEl.getAttribute('title'); + + /* container */ + const container = getElByAttr(list, 'data-warden-container'); + if (container) { + if (container.getAttribute('data-warden-event-id') || container.getAttribute('title')) { + return container.getAttribute('data-warden-event-id') || container.getAttribute('title'); + } + const id2 = container.getAttribute('data-warden-container'); + if (typeof id2 === 'string' && id2) return id2; + } + return list[0].tagName.toLowerCase(); + } + + /** + * 提取数据参数 + * 如果本身节点没有埋点属性的话会用上一层埋点属性 + */ + function extractParamsByPath(list = []) { + const regex = /^data-warden-/; + let target; + let targetIndex; + try { + // 遍历从子节点到body下最大的节点,遍历他们的属性,直到某个节点的属性能通过校验的节点 + list.forEach((el, index) => { + const attributes = el && el.attributes && Array.from(el.attributes) || []; + target = attributes.find((item) => (item.nodeName.match(regex) + ? item.nodeName.match(regex) + : item.nodeName.indexOf('data-warden-container') !== -1)); + if (target) { + targetIndex = index; + throw Error(); + } + }); + } catch (error) { + } + if (targetIndex < 0) return {}; + + const container = list[targetIndex]; + const attrList = Array.from(container.attributes) || []; + const params = {}; + attrList.forEach((item) => { + // 过滤多结构属性 如 data-warden-event-id width + // if(item.nodeName.split("-").length != 3 )return; + // 过滤非标准命名 如 data-v-fbcf7454 + if (item.nodeName.indexOf('data-warden') < 0) return; + const key = item.nodeName.replace(regex, ''); + params[key] = item.nodeValue; + }); + + // 过滤sdk自定义属性 + const defaultKey = ['container', 'title', 'event-id']; + defaultKey.forEach((item) => { delete params[item]; }); + return params; + } + + /** + * 根据属性查找元素 + */ + function getElByAttr(list, key) { + return list.find((item) => (item.hasAttribute && item.hasAttribute(key))); + } + + /** + * 获取title属性(data-warden-title 或者 title) + */ + function extractTitleByTarget(target = {}) { + const selfTitle = getNodeTitle(target); + if (selfTitle) return selfTitle; + + let container = target.parent; // 向上找container + + while (container && container !== document.body) { + if (container.hasAttribute('data-warden-container')) break; + container = container.parent; + } + const superTitle = getNodeTitle(container); + if (superTitle) return superTitle; + + const { tagName } = target; // 没有container,没有任何title标记的情况下 + return (!target.hasChildNodes() || tagName.toLowerCase() === 'svg') + ? handleLeafNode(target) + : handleNoLeafNode(target); + } + + /** + * 获取元素的 data-warden-title属性或者 title属性 + */ + function getNodeTitle(node) { + if (node) { + return node.hasAttribute('data-warden-title') ? node.getAttribute('data-warden-title') : node.title; + } + return null; + } + + /** + * 点击叶子元素(也就是不包含其他HTML元素,也不能有文本内容) + */ + function handleLeafNode(target) { + const { tagName, textContent } = target; + + if (tagName === 'IMG') return target.getAttribute('alt') || null; + + if (tagName === 'svg') { + const a = [...target.children].find((item) => (item.tagName === 'use')); + if (a) return a.getAttribute('xlink:href') || null; + } + return textContent; + } + + /** + * 点击非叶子元素 + */ + function handleNoLeafNode(target) { + const { tagName, textContent } = target; + if (tagName === 'A') { + const res = isSimpleEl([...target.children]); + return res ? textContent : target.getAttribute('href') || null; + } + if (tagName === 'BUTTON') { + const name = target.getAttribute('name'); + const res = isSimpleEl([...target.children]); + return name || res ? textContent : target.getAttribute('href') || null; + } + const { length } = [...target.children].filter(() => target.hasChildNodes()); + return length > 0 ? null : textContent; + } + + function init$2({ eventCore, eventUnload }) { + if (!eventCore && !eventUnload) return; + + if (eventCore) clickCollection(); + dwellCollector(eventUnload); + } + + /** + * 主动触发事件上报 + * @param {*} eventId 事件ID + * @param {*} title 事件标题 + * @param {*} params 自定义配置信息 + * @returns + */ + function traceCustomEvent(eventId, title, params = {}) { + emit({ eventId, title, params, eventType: 'custom', triggerTime: Date.now() }); + } + + var event = { + init: init$2, + traceCustomEvent, + }; + + // 兼容判断 + const supported = { + performance: !!window.performance, + getEntriesByType: !!(window.performance && performance.getEntriesByType), + PerformanceObserver: 'PerformanceObserver' in window, + MutationObserver: 'MutationObserver' in window, + PerformanceNavigationTiming: 'PerformanceNavigationTiming' in window, + }; + + /** + * 格式化性能记录,小数位数保留最多两位,等于0的字段不传输,标记为undefined + */ + function normalizePerformanceRecord(e) { + Object.keys(e).forEach((p) => { + const v = e[p]; + if (typeof v === 'number') e[p] = v === 0 ? undefined : parseFloat(v.toFixed(2)); + }); + return e; + } + + /** + * 发送首次页面性能数据 + */ + function observeNavigationTiming() { + const times = {}; + const { performance } = window; + let t = performance.timing; + + times.fmp = 0; // 首屏时间 (渲染节点增量最大的时间点) + if (supported.getEntriesByType) { + const paintEntries = performance.getEntriesByType('paint'); + if (paintEntries.length) times.fmp = paintEntries[paintEntries.length - 1].startTime; + + // 优先使用 navigation v2 https://www.w3.org/TR/navigation-timing-2/ + if (supported.PerformanceNavigationTiming) { + const nt2Timing = performance.getEntriesByType('navigation')[0]; + if (nt2Timing) t = nt2Timing; + } + } + + // 从开始发起这个页面的访问开始算起,减去重定向跳转的时间,在performanceV2版本下才进行计算,v1版本的fetchStart是时间戳而不是相对于访问起始点的相对时间 + if (times.fmp && supported.PerformanceNavigationTiming) times.fmp -= t.fetchStart; + + // 白屏时间 (从请求开始到浏览器开始解析第一批HTML文档字节的时间差) + // times.fpt = t.responseEnd - t.fetchStart; + + times.tti = t.domInteractive - t.fetchStart; // 首次可交互时间 + + times.ready = t.domContentLoadedEventEnd - t.fetchStart; // HTML加载完成时间 + + times.loadon = t.loadEventStart - t.fetchStart; // 页面完全加载时间 + + times.firstbyte = t.responseStart - t.domainLookupStart; // 首包时间 + + times.dns = t.domainLookupEnd - t.domainLookupStart; // dns查询耗时 + + times.appcache = t.domainLookupStart - t.fetchStart; // dns缓存时间 + + times.tcp = t.connectEnd - t.connectStart; // tcp连接耗时 + + times.ttfb = t.responseStart - t.requestStart; // 请求响应耗时 + + times.trans = t.responseEnd - t.responseStart; // 内容传输耗时 + + times.dom = t.domInteractive - t.responseEnd; // dom解析耗时 + + times.res = t.loadEventStart - t.domContentLoadedEventEnd; // 同步资源加载耗时 + + times.ssllink = t.connectEnd - t.secureConnectionStart; // SSL安全连接耗时 + + times.redirect = t.redirectEnd - t.redirectStart; // 重定向时间 + + times.unloadTime = t.unloadEventEnd - t.unloadEventStart; // 上一个页面的卸载耗时 + + emit(normalizePerformanceRecord({ + ...times, + eventType: 'performance', + eventId: 'page', + url: window.location.href, + })); + } + + function init$1({ performanceFirstResource, performanceCore }) { + if (!performanceFirstResource && !performanceCore) return; + + // 初始化方法可能在onload事件之后才执行,此时不会触发load事件了,检查document.readyState属性来判断onload事件是否会被触发 + if (document.readyState === 'complete') { + if (supported.performance && performanceFirstResource) observeNavigationTiming(); + } else { + window.addEventListener('load', () => { + if (supported.performance && performanceFirstResource) observeNavigationTiming(); + }); + } + } + + /** + * 主动触发性能事件上报 + * @param {*} eventId 事件ID + * @param {*} options 自定义配置信息 + */ + function tracePerformance(eventId, options) { + const record = { + triggerTime: Date.now(), + url: window.location.href, + ...options, + eventId, + eventType: 'performance', + }; + emit(normalizePerformanceRecord(record)); + } + + var performance$1 = { + init: init$1, + tracePerformance, + }; + + const methods = { + setCustomerId: base$1.setCustomerId, + setUserUuid: base$1.setUserUuid, + traceError: err.traceError, + tracePerformance: performance$1.tracePerformance, + traceCustomEvent: event.traceCustomEvent, + tracePageView: pv.tracePageView, + }; + + const init = (options = {}) => { + const _options = { + requestUrl: '', // 请求地址 + appName: '', // 应用名称 + appCode: '', // 应用code + appVersion: '', // 应用版本 + ext: '', // 自定义全局附加参数 + debug: false, // 是否开启触发事件时控制台输出 + + pvCore: false, // 页面跳转-是否自动发送页面跳转相关数据 + pvHashtag: false, // 页面跳转-浏览器的动作发生时(例如浏览器的回退按钮)是否监听hash变化,如果是hash路由请开启此开关 + + performanceCore: false, // 性能数据-是否采集静态资源、接口的相关数据 + performanceFirstResource: false, // 性能数据-是否采集首次进入页面的数据(ps: tcp连接耗时,HTML加载完成时间,首次可交互时间) + performanceServer: false, // 接口请求-是否采集接口请求(成功的才会采集) + + errorCore: false, // 是否采集异常数据(ps: 资源引入错误,promise错误,控制台输出错误) + errorServer: false, // 接口请求-是否采集报错接口数据 + + eventCore: false, // 页面点击-是否采集点击事件 + eventUnload: false, // 页面卸载-是否在页面卸载时采集页面状态信息 + }; + + // 将传过来的参数转换 + transitionOptions(_options, options); + + base$1.init(_options); + event.init(_options); + pv.init(_options); + performance$1.init(_options); + }; + + const transitionOptions = (_options, options) => { + const { + requestUrl, + appName, + appCode, + appVersion, + ext, + debug, + pv = {}, + performance = {}, + error = {}, + event = {}, + } = options; + + if (!requestUrl) throw Error('请传入requestUrl参数'); + if (!appName) throw Error('请传入appName参数'); + + _options.requestUrl = requestUrl; + _options.appName = appName; + _options.appCode = appCode; + _options.appVersion = appVersion; + _options.ext = ext; + _options.debug = debug; + + if (typeof pv === 'boolean') { + _options.pvCore = _options.pvHashtag = pv; + } else { + _options.pvCore = Boolean(pv.core); + _options.pvHashtag = Boolean(pv.server); + } + + if (typeof performance === 'boolean') { + _options.performanceCore = _options.performanceFirstResource = _options.performanceServer = performance; + } else { + _options.performanceCore = Boolean(performance.core); + _options.performanceFirstResource = Boolean(performance.firstResource); + _options.performanceServer = Boolean(performance.server); + } + + if (typeof error === 'boolean') { + _options.errorCore = _options.errorServer = error; + } else { + _options.errorCore = Boolean(error.core); + _options.errorServer = Boolean(error.server); + } + + if (typeof event === 'boolean') { + _options.eventCore = _options.eventUnload = event; + } else { + _options.eventCore = Boolean(event.core); + _options.eventUnload = Boolean(event.unload); + } + }; + + const install = (Vue, options = {}) => { + init(options); + if (Vue.prototype) { + Vue.prototype.$trace = { ...methods }; + } else { + Vue.config.globalProperties.$trace = { ...methods }; + } + }; + + var index = { + install, + init, + ...methods + }; + + exports["default"] = index; + exports.init = init; + exports.install = install; + exports.methods = methods; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); +//# sourceMappingURL=test3.umd.js.map diff --git a/web-ui/packages/eularTrace/index.js b/web-ui/packages/eularTrace/index.js new file mode 100644 index 0000000000000000000000000000000000000000..1d36e34b0689134bd75d9fbfaa88ad3f16a0d807 --- /dev/null +++ b/web-ui/packages/eularTrace/index.js @@ -0,0 +1,117 @@ +import base from './lib/base' +import pv from './lib/pv' +import err from './lib/err' +import event from './lib/event' +import performance from './lib/performance' + +const methods = { + setCustomerId: base.setCustomerId, + setUserUuid: base.setUserUuid, + traceError: err.traceError, + tracePerformance: performance.tracePerformance, + traceCustomEvent: event.traceCustomEvent, + tracePageView: pv.tracePageView, +} + +const init = (options = {}) => { + const _options = { + requestUrl: '', // 请求地址 + appName: '', // 应用名称 + appCode: '', // 应用code + appVersion: '', // 应用版本 + ext: '', // 自定义全局附加参数 + debug: false, // 是否开启触发事件时控制台输出 + + pvCore: false, // 页面跳转-是否自动发送页面跳转相关数据 + pvHashtag: false, // 页面跳转-浏览器的动作发生时(例如浏览器的回退按钮)是否监听hash变化,如果是hash路由请开启此开关 + + performanceCore: false, // 性能数据-是否采集静态资源、接口的相关数据 + performanceFirstResource: false, // 性能数据-是否采集首次进入页面的数据(ps: tcp连接耗时,HTML加载完成时间,首次可交互时间) + performanceServer: false, // 接口请求-是否采集接口请求(成功的才会采集) + + errorCore: false, // 是否采集异常数据(ps: 资源引入错误,promise错误,控制台输出错误) + errorServer: false, // 接口请求-是否采集报错接口数据 + + eventCore: false, // 页面点击-是否采集点击事件 + eventUnload: false, // 页面卸载-是否在页面卸载时采集页面状态信息 + }; + + // 将传过来的参数转换 + transitionOptions(_options, options); + + base.init(_options); + event.init(_options); + pv.init(_options); + err.init(_options); + performance.init(_options); +} + +const transitionOptions = (_options, options) => { + const { + requestUrl, + appName, + appCode, + appVersion, + ext, + debug, + pv = {}, + performance = {}, + error = {}, + event = {}, + } = options; + + if (!requestUrl) throw Error('请传入requestUrl参数'); + if (!appName) throw Error('请传入appName参数'); + + _options.requestUrl = requestUrl; + _options.appName = appName; + _options.appCode = appCode; + _options.appVersion = appVersion; + _options.ext = ext; + _options.debug = debug; + + if (typeof pv === 'boolean') { + _options.pvCore = _options.pvHashtag = pv; + } else { + _options.pvCore = Boolean(pv.core); + _options.pvHashtag = Boolean(pv.server); + } + + if (typeof performance === 'boolean') { + _options.performanceCore = _options.performanceFirstResource = _options.performanceServer = performance; + } else { + _options.performanceCore = Boolean(performance.core); + _options.performanceFirstResource = Boolean(performance.firstResource); + _options.performanceServer = Boolean(performance.server); + } + + if (typeof error === 'boolean') { + _options.errorCore = _options.errorServer = error; + } else { + _options.errorCore = Boolean(error.core); + _options.errorServer = Boolean(error.server); + } + + if (typeof event === 'boolean') { + _options.eventCore = _options.eventUnload = event; + } else { + _options.eventCore = Boolean(event.core); + _options.eventUnload = Boolean(event.unload); + } +} + +const install = (Vue, options = {}) => { + init(options); + if (Vue.prototype) { + Vue.prototype.$trace = { ...methods }; + } else { + Vue.config.globalProperties.$trace = { ...methods }; + } +} + +export default { + install, + init, + ...methods +}; +export { install, init, methods }; \ No newline at end of file diff --git a/web-ui/packages/eularTrace/lib/base.js b/web-ui/packages/eularTrace/lib/base.js new file mode 100644 index 0000000000000000000000000000000000000000..d1b19da72834305a36339e50c3d810d975f533ae --- /dev/null +++ b/web-ui/packages/eularTrace/lib/base.js @@ -0,0 +1,136 @@ +import { uuid, sendBeacon, map, nextTime } from '../utils/methods'; +import device from '../utils/device'; +import { getSessionId, refreshSession } from '../utils/session'; +import { DEBUG_LOG, MAX_CACHE_LEN, MAX_WAITING_TIME } from '../utils/constant'; +// import { version } from '../../package.json' + +// 当前应用ID,在整个页面生命周期内不变,单页应用路由变化也不会改变,加载SDK时创建,且只创建一次 +const pageId = uuid(); + +// 与一般业务上理解的sessionId做区分,此session与业务无关,单纯就是浏览器端和后端直接的联系 +const sessionId = getSessionId(); + +let requestUrl = ''; // 服务请求地址 +let events = []; // 批次队列 +let timer = null; // 定时发送定时器 +const base = { // 基础数据 + ...device, + pageId, + sessionId, + // sdkVersion: version, +}; + +/** + * 初始化基础数据 + * @param {*} options 基础配置 + */ +function init(options = {}) { + const { appName, appCode, ext } = options; + requestUrl = options.requestUrl; + base.appName = appName; + base.appCode = appCode; + base.ext = ext; +} + +/** + * 记录需要发送的埋点数据 + * @param {*} e 需要发送的事件信息 + * @param {boolean} flush 是否立即发送 + */ +function emit(e, flush = false) { + events = events.concat(e); // 追加到事件队列里 + refreshSession(); + debug('receive event, waiting to send', e); + clearTimeout(timer); + + // 满足最大记录数,立即发送,否则定时发送(flush为true代表立即发送) + events.length >= MAX_CACHE_LEN || flush + ? send() + : timer = setTimeout(() => { send(); }, MAX_WAITING_TIME); +} + +/** + * 发送埋点信息 + */ +function send() { + if (events.length) { + // 选取首部的部分数据来发送,performance会一次性采集大量数据追加到events中 + const sendEvents = events.slice(0, MAX_CACHE_LEN); // 需要发送的事件 + events = events.slice(MAX_CACHE_LEN); // 剩下待发的事件 + debug('send events', sendEvents); + + const time = Date.now(); + sendBeacon(requestUrl, { + baseInfo: { ...base, sendTime: time }, + eventInfo: map(sendEvents, (e) => { + e.sendTime = time; // 设置发送时间 + + // 补充type字段,将click、scroll、change、submit事件作为一类存储 + if (e.eventType === 'click' || e.eventType === 'scroll' || e.eventType === 'submit' || e.eventType === 'change') { + e.type = 'mix'; + return e; + } + + if (e.eventType === 'performance') { + // 将性能进行分类,不同类型的性能数据差异较大,分开存放,资源、页面、请求 + switch (e.eventId) { + case 'resource': + e.type = 'resourcePerformance'; + break; + case 'page': + e.type = 'pagePerformance'; + break; + case 'server': + e.type = 'serverPerformance'; + break; + default: + break; + } + return e; + } + e.type = e.eventType; // 其他类型type同eventType + return e; + }), + }); + if (events.length) nextTime(send); // 继续传输剩余内容,在下一个时间择机传输 + } +} + +/** + * 设置额外的 customerId + * @param {*} id 需要设置的id + */ +function setCustomerId(id) { + base.customerId = id; +} + +/** + * 设置额外的 userUuid + * @param {*} id 需要设置的id + */ +function setUserUuid(id) { + base.userUuid = id; +} + +/** + * 控制台输出信息 + * @param {...any} args 输出信息 + */ +function debug(...args) { + if (DEBUG_LOG) console.log(...args); +} + +export { + emit, + debug, + pageId, +}; + +export default { + init, + emit, + pageId, + setCustomerId, + setUserUuid, +}; + diff --git a/web-ui/packages/eularTrace/lib/err.js b/web-ui/packages/eularTrace/lib/err.js new file mode 100644 index 0000000000000000000000000000000000000000..4f06479b0b0a30bbc7d7a1c8de208f884419b4ee --- /dev/null +++ b/web-ui/packages/eularTrace/lib/err.js @@ -0,0 +1,38 @@ +import { emit } from './base'; + +function setFullErrInfo(errorInfo) { + const info = { + ...errorInfo, + eventType: 'error', + url: window.location.href, + triggerTime: Date.now(), + }; + emit(info); +} + +function init({ errorCore }) { + if (!errorCore) return; +} + +/** + * 主动触发错误上报 + * @param {*} eventId 事件ID + * @param {*} message 错误信息 + * @param {*} options 自定义配置信息 + * @returns + */ +function traceError(eventId, message, options = {}) { + const customErrorRecord = { eventId, errMessage: message, ...options }; + + // 针对自定义的异常上报,对params对特殊处理,将其序列化为string + const { params } = customErrorRecord; + if (params) { + customErrorRecord.params = params; + } + return setFullErrInfo(customErrorRecord); +} + +export default { + init, + traceError, +}; diff --git a/web-ui/packages/eularTrace/lib/event.js b/web-ui/packages/eularTrace/lib/event.js new file mode 100644 index 0000000000000000000000000000000000000000..fad4baef8ef1649058a315c69b21d701d5943be3 --- /dev/null +++ b/web-ui/packages/eularTrace/lib/event.js @@ -0,0 +1,286 @@ +import { emit, debug } from './base'; +import { uuid } from '../utils/methods'; + +class RequestTemplate { + constructor(config = {}) { + const list = ['eventType', 'eventId', 'url', 'referer', 'action', 'params', 'millisecond']; + list.forEach((key) => { this[key] = config[key] || null; }); + } +} +class RequestTemplateClick { + constructor(config = {}) { + const list = ['eventType', 'eventId', 'url', 'params', 'title', 'x', 'y']; + list.forEach((key) => { this[key] = config[key] || null; }); + } +} + +/** + * 是否为简单的标签 + * 只包含下面的arr数组内的标签才是简单的标签 + */ +function isSimpleEl(children) { + if (children.length > 0) { + const arr = ['em', 'b', 'strong', 'span', 'img', 'i', 'code']; + const a = children.filter(({ tagName }) => arr.indexOf(tagName.toLowerCase()) >= 0); + return a.length === children.length; + } + return true; +} + +/** + * 获取元素到最外层元素组成的数组 + */ +function getNodePath(node, options = {}) { + if (!node) return []; + const { includeSelf = true, order = 'asc' } = options; + let parent = includeSelf ? node : node.parentElement; + let result = []; + while (parent) { + result = order === 'asc' ? result.concat(parent) : [parent].concat(result); + parent = parent.parentElement; + } + return result; +} + +/** + * 获取元素的关系字符串 + * 例如两层div的关系会得到字符串: div>div + */ +function getNodeXPath(node, curPath = '') { + if (!node) return curPath; + const parent = node.parentElement; + let index = 0; // 这个index 暂时没什么用 + const { id } = node; + const tagName = node.tagName.toLowerCase(); + const path = curPath ? `>${curPath}` : ''; + const indexBrackets = index ? `.${index}` : ''; + + if (!parent || parent === window || parent === document.documentElement || parent === document.body) return `${tagName}${path}`; + + if (id) return `#${id}${path}`; // 知道了id 就不需要获取上下级关系了(id是唯一的) + + if (parent.children.length > 1) index = Array.prototype.indexOf.call(parent.children, node); + + return getNodeXPath(parent, `${tagName}${indexBrackets}${path}`); +} + +/** + * 点击事件 + */ +function clickCollection() { + document.addEventListener('click', (e) => { // 点击事件 + const _config = new RequestTemplateClick({ eventType: 'click' }); + debug('caught click event: ', e); + let { path } = e; + if (path === undefined) path = e.target ? getNodePath(e.target) : []; // 获取被点击的元素到最外层元素组成的数组 + + const target = path.find((el) => // 检查被点击的元素以及其父级元素是否有这些属性(从内到外,只会取第一个检查到的) + el.hasAttribute && (el.hasAttribute('data-warden-container') + || el.hasAttribute('data-warden-event-id') + || el.hasAttribute('data-warden-title'))); + if (!target) return; // :在这里return 掉了很多东西 + + _config.title = extractTitleByTarget(target); + _config.eventId = extractDataByPath(path); + _config.params = extractParamsByPath(path); + _config.elementPath = getNodeXPath(target).slice(-128); // 长度限制128字符 + const { top, left } = e.target.getBoundingClientRect(); // 元素距离html的距离 + const { scrollTop, scrollLeft } = document.documentElement; // html距离上和左侧的距离(一般都是0) + const x = left + scrollLeft; + const y = top + scrollTop; + _config.x = x; + _config.y = y; + _config.triggerTime = Date.now(); // 点击时间 + _config.url = window.location.href; // 当前页面的url + emit(_config); + }, true); +} + +/** + * 加载 & 卸载事件 + */ +function dwellCollector(eventUnload) { + const _config = new RequestTemplate({ eventType: 'dwell' }); + window.addEventListener('load', () => { // 加载完成事件 + _config.entryTime = Date.now(); + }, true); + + if (!eventUnload) return; + window.addEventListener('beforeunload', () => { // 卸载事件 + _config.eventId = uuid(); + _config.url = window.location.href; // 当前页面 url + _config.referer = document.referrer; // 上级页面 url(从哪个页面跳过来的就是上级页面) + _config.triggerTime = Date.now(); // 卸载时间 + _config.millisecond = Date.now() - _config.entryTime; // 停留多久 + const mapping = { + 0: 'navigate', // 网页通过点击链接,地址栏输入,表单提交,脚本操作等方式加载 + 1: 'reload', // 网页通过“重新加载”按钮或者location.reload()方法加载 + 2: 'back_forward', // 网页通过“前进”或“后退”按钮加载 + 255: 'reserved', // 任何其他来源的加载 + }; + const { type } = performance.navigation; // 表示加载来源, type为 0,1,2,255 + _config.operateAction = mapping[type] || null; + emit(_config, true); + }, false); +} + +/** + * 提取数据事件ID + */ +function extractDataByPath(list = []) { + /* data-warden-event-id */ + const hasIdEl = getElByAttr(list, 'data-warden-event-id'); + if (hasIdEl) return hasIdEl.getAttribute('data-warden-event-id'); + + /* title */ + const hasTitleEl = getElByAttr(list, 'title'); + if (hasTitleEl) return hasTitleEl.getAttribute('title'); + + /* container */ + const container = getElByAttr(list, 'data-warden-container'); + if (container) { + if (container.getAttribute('data-warden-event-id') || container.getAttribute('title')) { + return container.getAttribute('data-warden-event-id') || container.getAttribute('title'); + } + const id2 = container.getAttribute('data-warden-container'); + if (typeof id2 === 'string' && id2) return id2; + } + return list[0].tagName.toLowerCase(); +} + +/** + * 提取数据参数 + * 如果本身节点没有埋点属性的话会用上一层埋点属性 + */ +function extractParamsByPath(list = []) { + const regex = /^data-warden-/; + let target; + let targetIndex; + try { + // 遍历从子节点到body下最大的节点,遍历他们的属性,直到某个节点的属性能通过校验的节点 + list.forEach((el, index) => { + const attributes = el && el.attributes && Array.from(el.attributes) || []; + target = attributes.find((item) => (item.nodeName.match(regex) + ? item.nodeName.match(regex) + : item.nodeName.indexOf('data-warden-container') !== -1)); + if (target) { + targetIndex = index; + throw Error(); + } + }); + } catch (error) { + } + if (targetIndex < 0) return {}; + + const container = list[targetIndex]; + const attrList = Array.from(container.attributes) || []; + const params = {}; + attrList.forEach((item) => { + // 过滤多结构属性 如 data-warden-event-id width + // if(item.nodeName.split("-").length != 3 )return; + // 过滤非标准命名 如 data-v-fbcf7454 + if (item.nodeName.indexOf('data-warden') < 0) return; + const key = item.nodeName.replace(regex, ''); + params[key] = item.nodeValue; + }); + + // 过滤sdk自定义属性 + const defaultKey = ['container', 'title', 'event-id']; + defaultKey.forEach((item) => { delete params[item]; }); + return params; +} + +/** + * 根据属性查找元素 + */ +function getElByAttr(list, key) { + return list.find((item) => (item.hasAttribute && item.hasAttribute(key))); +} + +/** + * 获取title属性(data-warden-title 或者 title) + */ +function extractTitleByTarget(target = {}) { + const selfTitle = getNodeTitle(target); + if (selfTitle) return selfTitle; + + let container = target.parent; // 向上找container + + while (container && container !== document.body) { + if (container.hasAttribute('data-warden-container')) break; + container = container.parent; + } + const superTitle = getNodeTitle(container); + if (superTitle) return superTitle; + + const { tagName } = target; // 没有container,没有任何title标记的情况下 + return (!target.hasChildNodes() || tagName.toLowerCase() === 'svg') + ? handleLeafNode(target) + : handleNoLeafNode(target); +} + +/** + * 获取元素的 data-warden-title属性或者 title属性 + */ +function getNodeTitle(node) { + if (node) { + return node.hasAttribute('data-warden-title') ? node.getAttribute('data-warden-title') : node.title; + } + return null; +} + +/** + * 点击叶子元素(也就是不包含其他HTML元素,也不能有文本内容) + */ +function handleLeafNode(target) { + const { tagName, textContent } = target; + + if (tagName === 'IMG') return target.getAttribute('alt') || null; + + if (tagName === 'svg') { + const a = [...target.children].find((item) => (item.tagName === 'use')); + if (a) return a.getAttribute('xlink:href') || null; + } + return textContent; +} + +/** + * 点击非叶子元素 + */ +function handleNoLeafNode(target) { + const { tagName, textContent } = target; + if (tagName === 'A') { + const res = isSimpleEl([...target.children]); + return res ? textContent : target.getAttribute('href') || null; + } + if (tagName === 'BUTTON') { + const name = target.getAttribute('name'); + const res = isSimpleEl([...target.children]); + return name || res ? textContent : target.getAttribute('href') || null; + } + const { length } = [...target.children].filter(() => target.hasChildNodes()); + return length > 0 ? null : textContent; +} + +function init({ eventCore, eventUnload }) { + if (!eventCore && !eventUnload) return; + + if (eventCore) clickCollection(); + dwellCollector(eventUnload); +} + +/** + * 主动触发事件上报 + * @param {*} eventId 事件ID + * @param {*} title 事件标题 + * @param {*} params 自定义配置信息 + * @returns + */ +function traceCustomEvent(eventId, title, params = {}) { + emit({ eventId, title, params, eventType: 'custom', triggerTime: Date.now() }); +} + +export default { + init, + traceCustomEvent, +}; diff --git a/web-ui/packages/eularTrace/lib/performance.js b/web-ui/packages/eularTrace/lib/performance.js new file mode 100644 index 0000000000000000000000000000000000000000..3fa733c097e9f08ccb7fdcc9b9a6cd9888130782 --- /dev/null +++ b/web-ui/packages/eularTrace/lib/performance.js @@ -0,0 +1,117 @@ +import { emit } from './base'; + +// 兼容判断 +const supported = { + performance: !!window.performance, + getEntriesByType: !!(window.performance && performance.getEntriesByType), + PerformanceObserver: 'PerformanceObserver' in window, + MutationObserver: 'MutationObserver' in window, + PerformanceNavigationTiming: 'PerformanceNavigationTiming' in window, +}; + +/** + * 格式化性能记录,小数位数保留最多两位,等于0的字段不传输,标记为undefined + */ +function normalizePerformanceRecord(e) { + Object.keys(e).forEach((p) => { + const v = e[p]; + if (typeof v === 'number') e[p] = v === 0 ? undefined : parseFloat(v.toFixed(2)); + }); + return e; +} + +/** + * 发送首次页面性能数据 + */ +function observeNavigationTiming() { + const times = {}; + const { performance } = window; + let t = performance.timing; + + times.fmp = 0; // 首屏时间 (渲染节点增量最大的时间点) + if (supported.getEntriesByType) { + const paintEntries = performance.getEntriesByType('paint'); + if (paintEntries.length) times.fmp = paintEntries[paintEntries.length - 1].startTime; + + // 优先使用 navigation v2 https://www.w3.org/TR/navigation-timing-2/ + if (supported.PerformanceNavigationTiming) { + const nt2Timing = performance.getEntriesByType('navigation')[0]; + if (nt2Timing) t = nt2Timing; + } + } + + // 从开始发起这个页面的访问开始算起,减去重定向跳转的时间,在performanceV2版本下才进行计算,v1版本的fetchStart是时间戳而不是相对于访问起始点的相对时间 + if (times.fmp && supported.PerformanceNavigationTiming) times.fmp -= t.fetchStart; + + // 白屏时间 (从请求开始到浏览器开始解析第一批HTML文档字节的时间差) + // times.fpt = t.responseEnd - t.fetchStart; + + times.tti = t.domInteractive - t.fetchStart; // 首次可交互时间 + + times.ready = t.domContentLoadedEventEnd - t.fetchStart; // HTML加载完成时间 + + times.loadon = t.loadEventStart - t.fetchStart; // 页面完全加载时间 + + times.firstbyte = t.responseStart - t.domainLookupStart; // 首包时间 + + times.dns = t.domainLookupEnd - t.domainLookupStart; // dns查询耗时 + + times.appcache = t.domainLookupStart - t.fetchStart; // dns缓存时间 + + times.tcp = t.connectEnd - t.connectStart; // tcp连接耗时 + + times.ttfb = t.responseStart - t.requestStart; // 请求响应耗时 + + times.trans = t.responseEnd - t.responseStart; // 内容传输耗时 + + times.dom = t.domInteractive - t.responseEnd; // dom解析耗时 + + times.res = t.loadEventStart - t.domContentLoadedEventEnd; // 同步资源加载耗时 + + times.ssllink = t.connectEnd - t.secureConnectionStart; // SSL安全连接耗时 + + times.redirect = t.redirectEnd - t.redirectStart; // 重定向时间 + + times.unloadTime = t.unloadEventEnd - t.unloadEventStart; // 上一个页面的卸载耗时 + + emit(normalizePerformanceRecord({ + ...times, + eventType: 'performance', + eventId: 'page', + url: window.location.href, + })); +} + +function init({ performanceFirstResource, performanceCore }) { + if (!performanceFirstResource && !performanceCore) return; + + // 初始化方法可能在onload事件之后才执行,此时不会触发load事件了,检查document.readyState属性来判断onload事件是否会被触发 + if (document.readyState === 'complete') { + if (supported.performance && performanceFirstResource) observeNavigationTiming(); + } else { + window.addEventListener('load', () => { + if (supported.performance && performanceFirstResource) observeNavigationTiming(); + }) + } +} + +/** + * 主动触发性能事件上报 + * @param {*} eventId 事件ID + * @param {*} options 自定义配置信息 + */ +function tracePerformance(eventId, options) { + const record = { + triggerTime: Date.now(), + url: window.location.href, + ...options, + eventId, + eventType: 'performance', + }; + emit(normalizePerformanceRecord(record)); +} + +export default { + init, + tracePerformance, +}; diff --git a/web-ui/packages/eularTrace/lib/pv.js b/web-ui/packages/eularTrace/lib/pv.js new file mode 100644 index 0000000000000000000000000000000000000000..666cb48867753b7c87f9760c4c63b3c713849b84 --- /dev/null +++ b/web-ui/packages/eularTrace/lib/pv.js @@ -0,0 +1,91 @@ +import { emit, pageId } from './base'; + +let oldURL = window.location.href; // 最后一次的url +let historyLength = window.history.length; // 最后一次history栈的长度 + +/** + * 发送数据 + * option 请求参数 + */ +function tracePageView(option = {}) { + const { url = window.location.href, referer = oldURL, actions = '', params } = option; + let action = actions; + if (!action && window.history.length < 50) { + action = historyLength === window.history.length ? 'back_forward' : 'navigation'; + historyLength = window.history.length; + } + // 如果option.title为空,则等待框架处理document.title,延迟17ms + // 为什么是17ms? 一秒60Hz是基准,平均1Hz是17毫秒,只要出来了页面那就有 document.title + setTimeout(() => { + emit({ + eventType: 'pv', + eventId: pageId, + url, + referer, + params, + title: option.title || document.title, + action, + triggerTime: Date.now(), + }); + }, option.title ? 0 : 17); + oldURL = url; + historyLength = window.history.length; +} + +/** + * 路由Pv采集 + * pvHashtag 是否监听hash变化 + */ +function init(options = {}) { + const { pvCore, pvHashtag } = options; + // pvCore: true, // 页面跳转-是否自动发送页面跳转相关数据 + // pvHashtag: true, // 页面跳转-浏览器的动作发生时(例如浏览器的回退按钮)是否监听hash变化,如果是hash路由请开启此开关 + const referer = document.referrer; // 获取是从哪个页面跳转来的 + if (!pvCore) return; + + let lastIsPop = false; // 最后一次触发路由变化是否为popState触发 + // tracePageView({ url: oldURL, referer });// reason:这个可以给它注释掉 + + if (window.history.pushState) { + // 劫持history.pushState history.replaceState + const push = window.history.pushState.bind(window.history); + window.history.pushState = (data, title, url) => { + lastIsPop = false; + const result = push(data, title, url); + tracePageView({ actions: 'navigation' }); + return result; + }; + + const repalce = window.history.replaceState.bind(window.history); + window.history.replaceState = (data, title, url) => { + lastIsPop = false; + const result = repalce(data, title, url); + tracePageView({ actions: 'navigation' }); + return result; + }; + + // hash变化也会触发popstate事件,而且会先触发popstate事件 + // 可以使用popstate来代替hashchange,如果支持History H5 Api + // https://developer.mozilla.org/zh-CN/docs/Web/API/Window/popstate_event + window.addEventListener('popstate', () => { + if (window.location.hash !== '') { + const oldHost = oldURL.indexOf('#') > 0 // 多页面情况下 history模式刷新还是在pv页面 + ? oldURL.slice(0, oldURL.indexOf('#')) + : oldURL; + if (window.location.href.slice(0, window.location.href.indexOf('#')) === oldHost && !pvHashtag) return; + } + lastIsPop = true; + tracePageView(); + }); + } + // 监听hashchange + window.addEventListener('hashchange', () => { + if (pvHashtag && !lastIsPop) tracePageView(); + lastIsPop = false; + }); +} + +export default { + init, + tracePageView +}; diff --git a/web-ui/packages/eularTrace/rollup.config.js b/web-ui/packages/eularTrace/rollup.config.js new file mode 100644 index 0000000000000000000000000000000000000000..71c8ed2652166cca8641e91dd87415732681c465 --- /dev/null +++ b/web-ui/packages/eularTrace/rollup.config.js @@ -0,0 +1,9 @@ +export default { + input: 'index.js', + output:{ // 输出配置 + file: 'dist/test3.umd.js', + format: 'umd', + name: 'webtracing', + sourcemap: true, + } +} \ No newline at end of file diff --git a/web-ui/packages/eularTrace/utils/constant.js b/web-ui/packages/eularTrace/utils/constant.js new file mode 100644 index 0000000000000000000000000000000000000000..3525d6062cb578e454cb1433d646e2f25f576124 --- /dev/null +++ b/web-ui/packages/eularTrace/utils/constant.js @@ -0,0 +1,20 @@ +const DEVICE_KEY = '_warden_device_id'; // deviceKey - 固定 + +const SESSION_KEY = '_warden_session_id'; // sessionKey(一个站点只允许运行一个埋点程序) - 固定 + +const SURVIVIE_MILLI_SECONDS = 1800000; // session存活时长(30minutes) - 固定 + +const MAX_CACHE_LEN = 5; // 最大缓存数 + +const MAX_WAITING_TIME = 5000; // 最大等待时间 + +const DEBUG_LOG = false; // 是否输出采集信息 + +export { + DEVICE_KEY, + SESSION_KEY, + SURVIVIE_MILLI_SECONDS, + MAX_CACHE_LEN, + MAX_WAITING_TIME, + DEBUG_LOG, +} \ No newline at end of file diff --git a/web-ui/packages/eularTrace/utils/device.js b/web-ui/packages/eularTrace/utils/device.js new file mode 100644 index 0000000000000000000000000000000000000000..7bfc3c012edb7a58e810f2e2ae5547aada5ee1a1 --- /dev/null +++ b/web-ui/packages/eularTrace/utils/device.js @@ -0,0 +1,25 @@ +import { DEVICE_KEY } from './constant' +import { getCookieByName, uuid } from './methods'; + +const { screen } = window; +const { clientWidth, clientHeight } = document.documentElement; +const { width, height, colorDepth, pixelDepth } = screen; + +let deviceId = getCookieByName(DEVICE_KEY); + +if (!deviceId) { + deviceId = `t_${uuid()}`; + document.cookie = `${DEVICE_KEY}=${deviceId};path=/;`; +} + +export default { + clientHeight, // 网页可见区高度 + clientWidth, // 网页可见区宽度 + colorDepth, // 显示屏幕调色板的比特深度 + pixelDepth, // 显示屏幕的颜色分辨率 + deviceId, // id + screenWidth: width, // 显示屏幕的宽度 + screenHeight: height, // 显示屏幕的高度 + vendor: navigator.vendor, // 浏览器名称 + platform: navigator.platform, // 浏览器平台的环境,不是电脑系统的x64这样的(浏览器平台的环境可能是x32) +}; diff --git a/web-ui/packages/eularTrace/utils/methods.js b/web-ui/packages/eularTrace/utils/methods.js new file mode 100644 index 0000000000000000000000000000000000000000..8063953ecbcfe51d0d62c125d1b5ccaa17b81743 --- /dev/null +++ b/web-ui/packages/eularTrace/utils/methods.js @@ -0,0 +1,156 @@ +/** + * 补全字符 + * @param {*} num 初始值 + * @param {*} len 需要补全的位数 + * @param {*} placeholder 补全的值 + * @returns 补全后的值 + */ +function pad(num, len, placeholder = '0') { + const str = String(num); + if (str.length < len) { + let result = str; + for (let i = 0; i < len - str.length; i += 1) { + result = placeholder + result; + } + return result; + } + return str; +} + +/** + * 获取一个随机字符串(全局唯一标识符) + */ +function uuid() { + const date = new Date(); + + // yyyy-MM-dd的16进制表示,7位数字 + const hexDate = parseInt(`${date.getFullYear()}${pad(date.getMonth() + 1, 2)}${pad(date.getDate(), 2)}`, 10).toString(16); + + // hh-mm-ss-ms的16进制表示,最大也是7位 + const hexTime = parseInt(`${pad(date.getHours(), 2)}${pad(date.getMinutes(), 2)}${pad(date.getSeconds(), 2)}${pad(date.getMilliseconds(), 3)}`, 10).toString(16); + + // 第8位数字表示后面的time字符串的长度 + let guid = hexDate + hexTime.length + hexTime; + + // 补充随机数,补足32位的16进制数 + while (guid.length < 32) { + guid += Math.floor(Math.random() * 16).toString(16); + } + + // 分为三段,前两段包含时间戳信息 + return `${guid.slice(0, 8)}-${guid.slice(8, 16)}-${guid.slice(16)}`; +} + +/** + * 获取cookie中目标name的值 + * @param {String} name cookie名 + * @returns + */ +function getCookieByName(name) { + const result = document.cookie.match(new RegExp(`${name}=([^;]+)(;|$)`)); + return result ? result[1] : undefined; +} + +/** + * 向下兼容发送信号的方法 + */ +const sendBeacon = navigator.sendBeacon + ? (url, data) => { + if (data) navigator.sendBeacon(url, JSON.stringify(data)); + } + : (url, data) => { + // 传统方式传递参数 + const beacon = new Image(); + beacon.src = `${url}?v=${encodeURIComponent(JSON.stringify(data))}`; + }; + +const arrayMap = Array.prototype.map || function polyfillMap(fn) { + const result = []; + for (let i = 0; i < this.length; i += 1) { + result.push(fn(this[i], i, this)); + } + return result; +}; + +/** + * map方法 + * @param {Array} arr 源数组 + * @param {Function} fn 条件函数 + * @returns + */ +function map(arr, fn) { + return arrayMap.call(arr, fn); +} + +const arrayFilter = Array.prototype.filter || function filterPolyfill(fn) { + const result = []; + for (let i = 0; i < this.length; i += 1) { + if (fn(this[i], i, this)) { + result.push(this[i]); + } + } + return result; +}; + +/** + * filter方法 + * @param {Array} arr 源数组 + * @param {Function} fn 条件函数 + * @returns + */ +function filter(arr, fn) { + return arrayFilter.call(arr, fn); +} + +const arrayFind = Array.prototype.find || function findPolyfill(fn) { + for (let i = 0; i < this.length; i += 1) { + if (fn(this[i], i, this)) { + return this[i]; + } + } + return undefined; +}; + +/** + * find方法 + * @param {Array} arr 源数组 + * @param {Function} fn 条件函数 + * @returns + */ +function find(arr, fn) { + return arrayFind.call(arr, fn); +} + +/** + * 去除头部或者尾部的空格 + * @param {*} str 需要去除的字符串 + * @returns 去除后的字符串 + */ +function trim(str = '') { + return str.replace(/(^\s+)|(\s+$)/, ''); +} + +/** + * 可以理解为异步执行 + * requestIdleCallback 是浏览器空闲时会自动执行内部函数 + * requestAnimationFrame 是浏览器必须执行的 + * 关于 requestIdleCallback 和 requestAnimationFrame 可以参考 https://www.cnblogs.com/cangqinglang/p/13877078.html + */ +const nextTime = window.requestIdleCallback || window.requestAnimationFrame || ((callback) => setTimeout(callback, 17)); + +/** + * 取消异步执行 + */ +const cancelNextTime = window.cancelIdleCallback || window.cancelAnimationFrame || clearTimeout; + +export { + uuid, + getCookieByName, + sendBeacon, + map, + filter, + find, + trim, + nextTime, + cancelNextTime, +} \ No newline at end of file diff --git a/web-ui/packages/eularTrace/utils/session.js b/web-ui/packages/eularTrace/utils/session.js new file mode 100644 index 0000000000000000000000000000000000000000..22de0adb52d2f0a48fe75690c83e0adf6388e900 --- /dev/null +++ b/web-ui/packages/eularTrace/utils/session.js @@ -0,0 +1,29 @@ +/** + * 会话控制,此会话只和具体的浏览器相关,与业务无关,和业务意义上的登录态没有任何关联,只是用于追踪同一个浏览器上访问页面的动作 + */ +import { getCookieByName, uuid } from './methods'; +import { SURVIVIE_MILLI_SECONDS, SESSION_KEY } from './constant' + +/** + * 刷新会话存续期 + */ +function refreshSession() { + const id = getCookieByName(SESSION_KEY) || `s_${uuid()}`; + const expires = new Date(Date.now() + SURVIVIE_MILLI_SECONDS); + document.cookie = `${SESSION_KEY}=${id};path=/;max-age=1800;expires=${expires.toUTCString()}`; + return id; +} + +/** + * 获取sessionid + */ +function getSessionId() { + return getCookieByName(SESSION_KEY) || refreshSession(); +} + +refreshSession(); // 初始化 + +export { + getSessionId, + refreshSession, +}; diff --git a/web-ui/packages/summary2021/Dockerfile b/web-ui/packages/summary2021/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..5ab3b59ea930d1150a9cc93daac423943c8ed797 --- /dev/null +++ b/web-ui/packages/summary2021/Dockerfile @@ -0,0 +1,15 @@ +FROM nginx:stable + +LABEL image.function="2021summary for opensourceways community" + +COPY . /usr/share/nginx/html/ +WORKDIR /usr/share/nginx/html/ + +RUN chown -R nginx:nginx /usr/share/nginx/html +RUN sed -i "17i \ \ server_tokens off;" /etc/nginx/nginx.conf +RUN sed -i '21i location /2021summary/ {\n alias /usr/share/nginx/html/; \n } ' /etc/nginx/conf.d/default.conf +ENV RUN_USER nginx +ENV RUN_GROUP nginx + +EXPOSE 80 +ENTRYPOINT nginx -g "daemon off;" diff --git a/web-ui/packages/summary2021/agreement_ch.html b/web-ui/packages/summary2021/agreement_ch.html new file mode 100644 index 0000000000000000000000000000000000000000..c7a9c1f0f41b44124b3677217f77acf53ce9c416 --- /dev/null +++ b/web-ui/packages/summary2021/agreement_ch.html @@ -0,0 +1,35 @@ + + + + + + + 网站用户协议 + + + +

网站用户协议

+

1、为了生成您的个人年度报告,我们将根据您的授权查询您的Gitee账号2021年1月1日至2021年12月31日期间的登录时间、PR提交数据、评论数据等,并据此进行汇总统计分析,以用于本活动页面向您进行信息展示。

+

2、您的个人年度报告为算法自动生成结果,可能会与实际有偏差,我们无法保证相关数据的绝对准确性和有效性。

+

3、活动页面包含您的Gitee账号信息,当您选择向其他人转发活动页面的截图,其他人会看到上述信息,请谨慎选择。

+

4、除上述声明目的外,我们不会对本次查询的信息作其他处理。

+ + \ No newline at end of file diff --git a/web-ui/packages/summary2021/agreement_en.html b/web-ui/packages/summary2021/agreement_en.html new file mode 100644 index 0000000000000000000000000000000000000000..06f7ef9f641ca1b0bcaddf4a40569cec38b00802 --- /dev/null +++ b/web-ui/packages/summary2021/agreement_en.html @@ -0,0 +1,35 @@ + + + + + + + User Agreement + + + +

User Agreement

+

1. To generate the Un-Wrapped, we will query data about the login time, PRs, and comments of your Gitee account from January 1, 2021 to December 31, 2021 based on your authorization, analyze the data, and display the analysis result on the Un-Wrapped page.

+

2. The Un-Wrapped is automatically generated by the algorithm and may be different from the actual data. We cannot guarantee the absolute accuracy and validity of related data.

+

3. The Un-Wrapped shows information about your Gitee account. Exercise caution if you choose to send the screenshot of the Un-Wrapped to others.

+

4. Except for the purposes defined in this statement, no other processing is performed on the queried data.

+ + \ No newline at end of file diff --git a/web-ui/packages/summary2021/bgm/openEuler_BGM_2021.mp3 b/web-ui/packages/summary2021/bgm/openEuler_BGM_2021.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a7da00a03466c70d36097db58a09be9fd6ebbdcf Binary files /dev/null and b/web-ui/packages/summary2021/bgm/openEuler_BGM_2021.mp3 differ diff --git a/web-ui/packages/summary2021/css/common.css b/web-ui/packages/summary2021/css/common.css new file mode 100644 index 0000000000000000000000000000000000000000..4c32c4cd321ace2fb3352010b0ea8be786f55ba3 --- /dev/null +++ b/web-ui/packages/summary2021/css/common.css @@ -0,0 +1,108 @@ +/* CSS Document */ +/*css reset*/ +html { + box-sizing: border-box; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6, +pre, +form, +fieldset, +input, +textarea, +p, +blockquote, +th, +td { + margin: 0; + padding: 0; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +fieldest, +img { + border: 0; +} + +address, +caption, +cite, +code, +dfn, +em, +strong, +th, +var { + font-style: normal; + font-weight: normal; +} + +ol, +ul { + list-style: none; +} + +caption, +th { + text-align: left; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +p:before, +q:after { + content: ""; +} + +abbr, +acronym { + border: 0; +} + +@media (max-width: 1200px) { + .pc-box { + display: none !important; + } +} + + +.mob-box { + display: none; +} +@media (max-width: 1200px) { + .mob-box { + display: block ; + } +} + diff --git a/web-ui/packages/summary2021/css/mob.css b/web-ui/packages/summary2021/css/mob.css new file mode 100644 index 0000000000000000000000000000000000000000..b3478da9a2a1005614238d3507f1cfc179b501eb --- /dev/null +++ b/web-ui/packages/summary2021/css/mob.css @@ -0,0 +1,1333 @@ +html, +body, +#outer-container { + overflow: hidden; + width: 100%; + margin: 0 auto; + height: 100%; + text-align: center; + font-size: 14px; + color: white; +} + +.themeColor { + color: rgb(0, 47, 156) !important; +} + +.pinkColor { + color: #FF8884 !important; +} + +.lg-swiper, +.lg-swiper-page { + margin: 0; + padding: 0; +} + +.lg-swiper { + -webkit-user-select: none; + user-select: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + min-height: 100vh; + background-color: rgb(0, 47, 156); + min-height: -webkit-fill-available; +} + +.lg-swiper .lg-swiper-page { + position: absolute; + margin: 0 auto; + top: 0; + right: 0; + width: 100%; + height: 100%; + overflow: hidden; + display: none; +} + +.lg-swiper .lg-swiper-page.current { + z-index: 5; + display: block; + will-change: transform; +} + +.lg-swiper .lg-swiper-page.active { + z-index: 4; + display: block; + will-change: transform; +} + +.page { + position: relative; + display: flex; + max-width: 500px; + height: 100%; + margin: 0 auto; + flex-direction: column; + justify-content: space-between; +} + +.page img { + width: 100%; +} + +section { + position: relative; + width: 300px; + height: 227px; + /* 让子元素保留其3D位置 */ + transform-style: preserve-3d; + transform: translateZ(200px); + animation: rotate 20s linear infinite; + z-index: 99; +} + +section .rotate-item { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +/* 旋转 */ +section .rotate-item img { + width: 50px; + height: 50px; +} + +section .rotate-item:nth-child(1) { + transform: translateZ(150px) translateY(100px); +} + +section .rotate-item:nth-child(2) { + transform: rotateY(60deg) translateZ(150px) translateY(70px); +} + +section .rotate-item:nth-child(3) { + transform: rotateY(120deg) translateZ(150px) translateY(50px); +} + +section .rotate-item:nth-child(4) { + transform: rotateY(180deg) translateZ(150px) translateY(100px); +} + +section .rotate-item:nth-child(5) { + transform: rotateY(240deg) translateZ(150px) translateY(60px); +} + +section .rotate-item:nth-child(6) { + transform: rotateY(300deg) translateZ(150px); +} + +section .person { + position: absolute; + top: 0; + left: 0; + background-image: url(../images/pic1/blue-man.png); + background-size: 100% 100%; + height: 225px; + width: 300px; + z-index: 0; + transform: translateY(2px) translateZ(200px); + animation: rotateIndex 20s infinite linear; +} + +.one-text { + padding-bottom: 5px; +} + +.desk { + position: relative; + width: 100%; + height: 30px; + border: 1px solid black; + background-color: white; + transform: translateY(3000px) translateZ(200px); + animation: desk 3s forwards; + z-index: 0; +} + +.bg-screen { + position: relative; + width: 200px; + height: 120px; + transform: translateX(-3000px) translateZ(-200px); + background-image: url(../images/pic1/screen.png); + background-size: 100%; + animation: screen 3s forwards; + z-index: 0; +} + +.euler-title { + font-size: 20px; + font-weight: 700; +} + +.euler-title2 { + padding: 8px 0 0; + font-size: 16px; + font-weight: 700; +} + +.page-one .text-box, +.page-tow .text-box { + position: relative; + padding: 20px 15px 0; + /* background-color: rgb(0, 47, 156); */ + transform: translateY(-100%); + animation: oneMove 3s forwards; + z-index: 1; +} + +.user-name { + font-size: 18px; + padding: 3px 0 10px; + font-weight: 700; +} + +.page-five .user-name { + padding-top: 5px; + font-size: 16px; +} +.page-five p{ + opacity: 0; + animation: textMove 2s ease-in forwards; +} +.page-four p { + opacity: 0; + animation: textMove 2s ease-in forwards; +} +.geometry img { + width: 100%; +} + +.geometry .circular, +.geometry .triangle, +.geometry .hexagon-s { + position: absolute; +} + +.geometry .circular { + top: -30px; + right: 30px; + width: 60px; +} + +.geometry .circular::before { + content: ""; + position: absolute; + top: -10px; + left: -10px; + width: 80px; + height: 80px; + border-radius: 999px; + background-color: rgba(255, 255, 255, 0.22); + -webkit-animation: halo 1.5s ease-in infinite alternate; + animation: halo 1.5s ease-in infinite alternate; + z-index: -1; +} + +.geometry .triangle { + top: 70px; + left: 30px; + width: 40px; + animation: hexagon-s 10s infinite forwards; + +} + +.geometry .hexagon-s { + top: 200px; + right: 10px; + width: 30px; + animation: hexagon-s 10s infinite forwards; +} + +.page-one .pic { + position: absolute; + /* position: relative; */ + bottom: 0; + left: 0; + width: 100%; + max-width: 500px; + display: flex; + flex-direction: column; + align-items: center; + padding: 0; + justify-content: center; + animation: oneScale 3s forwards; + transform: scale(0); + perspective: 400px; +} + +.tow-text { + padding-bottom: 5px; +} + +.page-tow .click-bob, +.click-bob2 { + font-size: 14px; + font-weight: 700; +} + +.click-bob { + padding-top: 30px; +} + +.page-tow .pic { + position: relative; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + transform: translateX(500px); + animation: cloud4 3s forwards; + /* height: fit-content; */ +} + +.page-tow .pic div { + position: absolute; +} + +.cloud1 { + top: 15px; + left: -20px; + width: 100px; + animation: cloud1 10s infinite linear alternate; +} + +.cloud2 { + top: 50px; + right: 20px; + width: 90px; + animation: cloud2 20s infinite linear alternate; +} + +.cloud3 { + top: 220px; + left: 30px; + width: 100px; + animation: cloud3 3s; +} + +.cloud3 img { + animation: cloud3Img 5s infinite linear alternate; +} + +.cloud4 { + right: -25px; + bottom: 30px; + width: 200px; + animation: cloud4 3s forwards; +} + +.cloud5 { + left: -20px; + bottom: -4px; + width: 200px; + animation: cloud4 3s forwards; +} + +.green-ball { + top: 75px; + left: 50px; + width: 70px; + -webkit-animation: green-ball 3s infinite linear alternate forwards; + animation: green-ball 3s infinite linear alternate forwards; +} + +.bule-ball { + top: 100px; + right: 40px; + width: 150px; + -webkit-animation: bule-ball 3s infinite linear alternate forwards; + animation: bule-ball 3s infinite linear alternate forwards; +} + +.pink-ball { + top: 270px; + left: 60px; + width: 80px; + -webkit-animation: pink-ball 3s infinite linear alternate forwards; + animation: pink-ball 3s infinite linear alternate forwards; +} + +.bird1 { + width: 50px; + right: 22px; + bottom: 120px; +} + +.page-tow .pic .enter { + width: 200px; + height: 200px; + box-shadow: 0 0 5px rgb(163, 148, 148); + animation: flashLight 4s infinite linear both; +} + +.page-three { + display: flex; + padding: 80px 25px 0; + align-items: center; + justify-content: start; +} + +.page-three .text-box { + position: relative; + display: flex; + min-width: 300px; + min-height: 300px; + transform: translateY(-100%); + animation: oneMove 3s forwards; + padding-bottom: 30px; + align-items: center; + flex-direction: column; + background-color: white; +} + +.page-three .head { + display: flex; + width: 100%; + align-items: center; + padding: 0 15px; + height: 35px; + border-bottom: 1px solid black; +} + +.page-three .more-text { + padding-top: 8px; +} + +.more-text p { + padding-top: 10px; + font-size: 14px; + font-weight: 700; +} + +.head div { + position: relative; + margin-right: 8px; + width: 14px; + height: 14px; + border: 1px solid black; + border-radius: 50%; + background-color: #002F9C; + animation: halo1 1.5s ease-in infinite alternate linear; +} + + +.head .yellow { + background-color: #FFB32A; + animation-delay: 1.5s; +} + +.head .pink { + background-color: #FF8884; + animation-delay: 3s; +} + +.page-three .body { + display: flex; + flex-direction: column; + justify-content: center; + padding: 20px 10px 0; + color: black; + height: 100%; + font-size: 14px; +} + +.body p { + opacity: 0; + animation: textMove 1s 2s ease-in forwards; + padding-bottom: 5px; +} + +.body .themeColor { + font-size: 14px; + font-weight: 700; +} + +.page-three .logo { + opacity: 0; + width: 100px; + animation: fade 2s 20s cubic-bezier(.26, .45, 1, .56) forwards; +} + +.three-bg div { + position: absolute; +} + +.three-bg .green-ball1 { + top: -35px; + left: 20px; + width: 35px; + animation: green-ball1 0.5s infinite alternate; +} + +.mirror { + top: -50px; + left: 230px; + width: 70px; + animation: mirror 2s forwards; +} + +.mirror img { + animation: cloud3Img 5s infinite linear alternate; +} + +.dash-line { + top: -105px; + left: 0; + width: 280px; + animation: dash-line 2s forwards ease-in; +} + +.dash-line img { + /* animation: runRoude 1s 0.5s infinite linear; */ +} + +.three-bottom, +.yellow-ball { + position: absolute; + bottom: 15px; + width: 300px; +} + +.three-bottom { + animation: dash-line 2s forwards ease-in; +} + +.yellow-ball { + width: 30px; + animation: yellow-ball 5s infinite; +} + +.fade { + opacity: 0; + animation: fade 1s ease-in-out forwards; +} + +.fade-time-1 { + animation-delay: 1s; +} + +.fade-time-2 { + animation-delay: 2s; +} + +.fade-time-3 { + animation-delay: 3s; +} + +.fade-time-4 { + animation-delay: 4s; +} + +.fade-time-5 { + animation-delay: 5s; +} + +.fade-time-6 { + animation-delay: 6s; +} + +.fade-time-7 { + animation-delay: 7s; +} + +.fade-time-8 { + animation-delay: 8s; +} + +.fade-time-9 { + animation-delay: 9s; +} + +.fade-time-10 { + animation-delay: 10s; +} + +.fade-time-11 { + animation-delay: 11s; +} + +/* page4 */ + +.yellow-color { + padding: 0 2px; + font-weight: 700; + font-size: 16px; + color: #FCB42A; +} + +.page-four { + /* position: relative; */ + display: flex; + align-items: center; + justify-content: flex-end; + padding-bottom: 180px; + /* max-width: 375px; */ +} + +.page-four .text-box { + z-index: 99; +} + +/* .page-four .pic { + height: 100%; + max-width: 500px; +} */ +.page-four .pic div { + position: absolute; + /* z-index: 0; */ +} + +.keyboard { + top: -50px; + left: 10px; + width: 200px; + animation: dash-line 2s; +} + +.earth { + top: 180px; + left: 20px; + width: 50px; + animation: earth 10s infinite linear; +} + +.earth img, +.earth2 img { + animation: dash-line 2s; +} + +.earth2 { + top: -30px; + right: -20px; + width: 80px; + animation: earth2 10s infinite linear; +} + +.curtains { + top: 50px; + left: 50%; + width: 130px; + transform: translateX(-50%); +} + +.page-four p { + font-size: 14px; + padding-bottom: 8px; +} + +.girl { + top: 80px; + right: 50%; + width: 80px; + z-index: 2; +} + +.pink2 { + right: -20px; + bottom: -50px; + width: 100px; + /* animation: pink2 4s infinite linear alternate; */ +} + +.green2 { + left: -20px; + bottom: 40px; + width: 70px; + animation: dash-line 2s; +} + +.yellow2 { + top: 200px; + right: 50px; + width: 80px; + animation: dash-line 2s; +} + +.dash2 { + top: 50px; + left: 50px; + width: 100px; + animation: dash-line 2s; +} + +.dash3 { + top: 110px; + left: 50%; + width: 100px; + animation: dash-line 2s; +} + +.page-four p:nth-child(-n + 2) { + font-weight: 700; + font-size: 15px; + padding: 10px 0; +} + +/* .page-four p:nth-child(3) { + padding-bottom: 15px; +} + +.page-four p:nth-last-child(2) { + padding-bottom: 15px; +} */ + +.page-five { + /* position: relative; */ + padding: 120px 50px 0; + align-items: center; + justify-content: start; +} + +.green-color { + padding: 0 3px; + font-weight: 700; + color: #00BB84; +} + +.page-five .hexagon2 { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 230px; + height: 260px; + font-size: 14px; + color: black; + background-image: url(../images/pic5/hexagon.png); + background-repeat: no-repeat; + background-size: 100%; + z-index: 999; + animation: text-box 2s; +} + +.page-five .text-box { + padding: 10px 0; +} + +.hexagon2 p { + position: absolute; + top: 50px; + left: 50%; + transform: translateX(-50%); + padding-bottom: 10px; +} + +.hexagon2 p:nth-child(2) { + padding-bottom: 15px; +} + +.hexagon2 .honor { + text-align: center; + width: 160px; +} + +.page-five .pink-color { + font-size: 16px; + font-weight: 700; + color: #FA756C; +} + +.bg-five div { + position: absolute; +} + +.bg-five .person2 { + top: 25px; + left: 25px; + width: 130px; + animation: dash-line 2s; + +} + +.bg-five .person3 { + top: 70px; + right: 25px; + width: 90px; + animation: dash-line2 2s; +} + +.bg-five .bottom-item { + bottom: 75px; + left: 30px; + width: 160px; + animation: dash-line 2s; +} + +.bg-five .withe-logo { + bottom: 25px; + left: 30px; + width: 120px; + animation: cloud4 2s es; +} + +.qr-code { + bottom: 20px; + right: 20px; + width: 120px; + font-size: 12px; + animation: qrcode 2s; +} +.noContribution .qr-code { + padding-top: 20px; +} + +.noContribution .text-box { + transform: translateY(300px) translateZ(200px); + animation: desk 2s forwards ease-in-out; +} + +.bg-five .tip { + bottom: 170px; + right: 20px; + width: 120px; + transition: none; +} + +.bg-five div:nth-child(7) { + top: 180px; + right: 50%; + width: 25px; +} + +.bg-five div:nth-child(8) { + bottom: 180px; + right: 50px; + width: 40px; +} + +.light { + width: 35px !important; +} + +.page-six { + max-width: 375px; +} + +.bg-five .lighting { + position: absolute; + top: -4px; + left: 0; + animation: lighting 1.5s infinite alternate; +} + +.bg-six div { + position: absolute; +} + +.footer { + bottom: -30px; + z-index: 1; + animation: footer 2s; +} + +.border { + padding: 25px; + padding-bottom: 0; + top: 0; +} + +.email { + left: 120px; + bottom: 250px; + width: 40px; + animation: file 1s infinite linear alternate; +} + +.file { + right: 80px; + bottom: 200px; + width: 50px; + animation: file 2s infinite linear alternate-reverse; +} + +.paper { + left: 80px; + bottom: 180px; + width: 60px; + animation: file 2s infinite linear alternate; +} + +.main { + display: flex; + align-items: center; + flex-direction: column; + justify-content: start; + padding-top: 45px; + height: 100%; + color: black; + font-size: 14px; + z-index: 99; +} + +.main p { + text-align: center; + margin-bottom: 4px; +} + +.main p:nth-last-child(3) { + margin-bottom: 15px; +} + +.main .text-box { + display: flex; + flex-direction: column; + align-items: center; +} + +.six-logo { + padding: 20px 0 10px; + width: 100px; +} + +.bold { + font-size: 16px; + font-weight: 700; +} + +.none { + display: none; +} + +/* 圆 */ +.typing { + visibility: hidden; + width: 30ch; + animation: typing 2.5s forwards steps(30), blink 0.5s 5 alternate; + white-space: nowrap; + overflow: hidden; + border-right: 1px solid white; +} + +--:root { + --time: 2s; +} + +.delay-time1 { + width: 24ch; + animation-delay: 2.5s; + animation-timing-function: steps(24); +} + +.delay-time2 { + width: 22ch; + animation-delay: 5s; + animation-timing-function: steps(22); +} + +.delay-time3 { + width: 22ch; + animation-delay: 7.5s; + animation-timing-function: steps(22); +} + +.delay-time4 { + width: 32ch; + animation-delay: 10s; + animation-timing-function: steps(32); +} + +.delay-time5 { + width: 10ch; + animation: typing 1s steps(10) forwards, blink 1s infinite alternate; + animation-delay: 12.5s; +} + +.delay-time6 { + width: 22ch; + animation-delay: 24s; +} + +@keyframes cloud3Img { + from { + transform: translateX(-30px); + } + + to { + transform: translateX(30px); + } +} + +/* 打字效果 */ +@keyframes typing { + from { + width: 0 + } + + to { + visibility: visible; + } +} + +@keyframes blink { + 50% { + border-color: black; + } +} + +@keyframes hidden { + to { + border-color: white; + } +} + +@keyframes halo { + 0% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } + + 100% { + -webkit-transform: scale(0.81); + transform: scale(0.81); + } +} + +@keyframes halo1 { + 0% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } + + 100% { + -webkit-transform: scale(1.2); + transform: scale(1.2); + } +} + +/* 三角形 */ +@keyframes triangle { + 100% { + transform: rotate(360deg); + } +} + +/* 6边形 */ +@keyframes hexagon-s { + 50% { + transform: translateY(-100%) rotate(360deg); + } + + 100% {} +} + +/* page-one 图片动画 */ +@keyframes oneScale { + to { + transform: scale(1); + } +} + +@keyframes oneMove { + to { + transform: translateY(0); + } +} + +@keyframes textLight { + to { + transform: translate(50%, 50%); + } +} + +/* 浏览器动画 */ +@keyframes screen { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + transform: translate(-50px, 10px) translateZ(-200px); + } +} + +@keyframes fade { + 100% { + opacity: 1; + } +} + +/* 桌子 */ +@keyframes desk { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + transform: translate(0, 0); + } +} + +@keyframes myScale { + 35% { + transform: scale(0.8); + } + + 70% { + transform: scale(1.2); + } +} + +/* 旋转动画 */ +@keyframes rotate { + 0% { + transform: rotateY(0); + } + + 100% { + transform: rotateY(360deg); + } +} + +/* 中心人物不旋转 */ +@keyframes rotateIndex { + 0% { + transform: rotateY(360deg) translateY(3px); + } + + 100% { + transform: rotateY(0) translateY(3px); + } +} + +/* page-tow */ +@keyframes cloud1 { + to { + transform: translate(30px, 10px); + + } +} + +@keyframes cloud2 { + 20% { + transform: translate(-20px, -10px); + } + + 50% { + transform: translate(-50px, -30px); + } + + 70% { + transform: translate(-70px, -10px); + } + + 100% { + transform: translate(-20px, -10px); + } +} + +@keyframes cloud3 { + from { + transform: translateX(-100px); + } + + to { + transform: translateX(0); + } +} + +@keyframes green-ball { + 0% { + -webkit-transform: rotateZ(-10deg); + transform: rotateZ(-10deg); + } + + 100% { + -webkit-transform: rotateZ(0deg); + transform: rotateZ(0deg); + } +} + +@keyframes bule-ball { + 0% { + -webkit-transform: translate(-10px, -10px) rotateZ(0deg); + transform: translate(-10px, -10px) rotateZ(0deg); + } + + 100% { + -webkit-transform: translate(0, 0) rotateZ(10deg); + transform: translate(0, 0) rotateZ(10deg); + } +} + +@keyframes mirror { + 0% { + transform: translate(200px, -50%) rotate(30deg); + } + + 70% { + transform: rotate(30deg); + } + +} + +@keyframes yellow-ball { + 0% { + transform: translateX(100%) rotate(360deg); + } + + 50% { + transform: translateX(156px); + } + + 100% { + transform: translate(210px, 300px); + } +} + +@keyframes cloud4 { + from { + transform: translateY(500px); + + } + + to { + transform: translateY(0); + } +} + +@keyframes pink-ball { + 0% { + transform: rotateZ(-10deg); + } + + 100% { + transform: rotateZ(0deg); + } +} + +@keyframes dash-line { + from { + transform: translate(-300px, -300px) rotate(360deg); + } + +} + +@keyframes qrcode { + from { + transform: translate(300px, 300px) rotate(360deg); + } + +} + +@keyframes dash-line2 { + from { + transform: translate(300px, -300px) rotate(999deg); + } + +} + +@keyframes green-ball1 { + to { + transform: translateY(-50px); + } +} + +@keyframes pink2 { + from { + transform: translateZ(-200px); + } + + to { + transform: translateX(-300px); + } +} + +@keyframes earth { + to { + transform: rotate(360deg); + } +} + +@keyframes earth2 { + to { + transform: rotate(-360deg); + } +} + +@keyframes identifier {} + +/* 闪光 */ +@keyframes flashLight { + 50% { + box-shadow: 0 0 70px rgb(255, 255, 255); + } +} + +/* 灯泡 */ +@keyframes lighting { + from { + transform: scale(1.5); + } +} + +@keyframes girl1 { + from { + transform: translateX(-300px); + } +} + +@keyframes boy { + from { + transform: translateX(300px); + } +} + +@keyframes text-box { + 0% { + transform: rotate(360deg); + } +} + +@keyframes footer { + from { + transform: translateY(400px); + } + + to { + transform: translate(0, 0); + } +} + +@keyframes file { + to { + transform: translate(5px, 10px); + } +} + +@keyframes textMove { + to { + opacity: 1; + } +} + +.bgm-open { + position: absolute; + width: 23px; + top: 18px; + right: 18px; + z-index: 999; +} + +.bgm-open img { + width: 100%; +} + +.run-bgm { + animation: runBgm 4s infinite; +} + +@keyframes runBgm { + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/web-ui/packages/summary2021/css/pc.css b/web-ui/packages/summary2021/css/pc.css new file mode 100644 index 0000000000000000000000000000000000000000..615b196da4fad9c7a1f59d2235baf14301252a42 --- /dev/null +++ b/web-ui/packages/summary2021/css/pc.css @@ -0,0 +1,145 @@ + +/* 开始编写CSS */ +.pc-box { + display: flex; + justify-content: center; + overflow: hidden; + height: 100vh; + padding: 50px; +} +.contribution, +.no-contribution { + display: flex; + margin: 0 auto; + width: 100%; + align-items: center; + justify-content: space-between; + +} +body { + overflow: hidden; + width: 100%; + height: 100%; + text-align: center; + font-size: 14px; + color: white; + background-color: white; +} +.container { + position: relative; + width: 330px; + height: 750px; + overflow: hidden; +} +.no-contribution { + justify-content: space-around; +} +.front, .back { + position: absolute; + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + display: flex; + justify-content: center; + align-items: center; + transform-style: preserve-3d; + backface-visibility: hidden; + transition: transform .7s ease-in-out; +} +.front { + background-color: rgb(0, 47, 156); + z-index: 10; + background-position: -6px -2px; + background-repeat: no-repeat; +} +.no-contribution .box-one .front { + background-image: url(../images/nocontribution1.jpg); +} +.no-contribution .box-four .front { + background-image: url(../images/nocontribution2.jpg); +} + +.no-contribution .qr-code { + padding-top: 50px; +} +.noContribution .qr-code img { + border: 1px solid black; +} +.no-contribution .qr-code img{ + border: 1px solid black; +} +.no-contribution .qr-code p { + padding-top: 20px; +} +.box-one .front { + background-image: url(../images/contribution1.jpg); +} +.back { + transform: rotateY(180deg); +} +.box-tow .front { + background-image: url(../images/contribution2.jpg); +} + +.box-three .front { + background-image: url(../images/contribution3.jpg); +} + +.box-four .front { + background-image: url(../images/contribution4.jpg); +} + +.pc-box .euler-title2 { + padding: 10px 0; +} +.pc-box .euler-title3 { + padding: 0 0 10px; +} +.contents{ + width: 100%; + height: 100%; + background:rgb(0, 47, 156); + transform: translateZ(60px); +} +.contents .page { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; +} +.contents img { + width: 100%; +} +.contents .page-one { + padding-top: 20px; +} +.contents .page-five { + justify-content:start ; + padding-top: 30px; +} +.page-five p { + font-size: 12px; + padding-bottom: 8px; +} +.contents .dash-line { + top: -80px; +} +.contents .bg-five img{ + position: absolute; + width: 100px; +} +.contents .bg-five img:nth-child(1) { + top: -40px; + right: -40px; +} +.contents .bg-five img:nth-child(2) { + bottom: -20px; + left: -30px; +} +.contents .border { + padding: 20px 10px 0; +} +.contents .page-one .text-box { + padding: 20px 10px 0; +} diff --git a/web-ui/packages/summary2021/favicon.ico b/web-ui/packages/summary2021/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ba6134a0ab94b8dd83d098e059d3c4dd93dd1041 Binary files /dev/null and b/web-ui/packages/summary2021/favicon.ico differ diff --git a/web-ui/packages/summary2021/images/close.png b/web-ui/packages/summary2021/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..c9e4cb1b110aac387658cf324accd6131cfaa2bf Binary files /dev/null and b/web-ui/packages/summary2021/images/close.png differ diff --git a/web-ui/packages/summary2021/images/close.svg b/web-ui/packages/summary2021/images/close.svg new file mode 100644 index 0000000000000000000000000000000000000000..f3c38ff70cbd67943ac0d97de3f30abfcbed3fe3 --- /dev/null +++ b/web-ui/packages/summary2021/images/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web-ui/packages/summary2021/images/contribution1.jpg b/web-ui/packages/summary2021/images/contribution1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54c433c1fffea454178f4e1b91617f4b17c979ca Binary files /dev/null and b/web-ui/packages/summary2021/images/contribution1.jpg differ diff --git a/web-ui/packages/summary2021/images/contribution2.jpg b/web-ui/packages/summary2021/images/contribution2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3abc35ed48dcc4baacdb79b18edbce3bd1db53f4 Binary files /dev/null and b/web-ui/packages/summary2021/images/contribution2.jpg differ diff --git a/web-ui/packages/summary2021/images/contribution3.jpg b/web-ui/packages/summary2021/images/contribution3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f737addee9b0b51ed52fae8ed8169f85a8242a25 Binary files /dev/null and b/web-ui/packages/summary2021/images/contribution3.jpg differ diff --git a/web-ui/packages/summary2021/images/contribution4.jpg b/web-ui/packages/summary2021/images/contribution4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..945810dc1e659bae3e1f192179cd71065f3fb902 Binary files /dev/null and b/web-ui/packages/summary2021/images/contribution4.jpg differ diff --git a/web-ui/packages/summary2021/images/honor/honor1.png b/web-ui/packages/summary2021/images/honor/honor1.png new file mode 100644 index 0000000000000000000000000000000000000000..25daf06f369232a43ec2d37c4228c7ecf035ae29 Binary files /dev/null and b/web-ui/packages/summary2021/images/honor/honor1.png differ diff --git a/web-ui/packages/summary2021/images/honor/honor2.png b/web-ui/packages/summary2021/images/honor/honor2.png new file mode 100644 index 0000000000000000000000000000000000000000..3f399321cc7b5b738052c28712fda3e3ad7809ed Binary files /dev/null and b/web-ui/packages/summary2021/images/honor/honor2.png differ diff --git a/web-ui/packages/summary2021/images/honor/honor3.png b/web-ui/packages/summary2021/images/honor/honor3.png new file mode 100644 index 0000000000000000000000000000000000000000..4ced0793d12ab4ae62ecc3ea884d039a908ad631 Binary files /dev/null and b/web-ui/packages/summary2021/images/honor/honor3.png differ diff --git a/web-ui/packages/summary2021/images/honor/honor4.png b/web-ui/packages/summary2021/images/honor/honor4.png new file mode 100644 index 0000000000000000000000000000000000000000..6e310a2a001e251a96d6cbfb7e202524b2cd7c0f Binary files /dev/null and b/web-ui/packages/summary2021/images/honor/honor4.png differ diff --git a/web-ui/packages/summary2021/images/honor/honor5.png b/web-ui/packages/summary2021/images/honor/honor5.png new file mode 100644 index 0000000000000000000000000000000000000000..8755b2b42494fb140d87fabb77efd6c75f0ddba8 Binary files /dev/null and b/web-ui/packages/summary2021/images/honor/honor5.png differ diff --git a/web-ui/packages/summary2021/images/nocontribution1.jpg b/web-ui/packages/summary2021/images/nocontribution1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cfea831e96a332bd6fc9f0c01a0bcdf1b1d4fe0 Binary files /dev/null and b/web-ui/packages/summary2021/images/nocontribution1.jpg differ diff --git a/web-ui/packages/summary2021/images/nocontribution2.jpg b/web-ui/packages/summary2021/images/nocontribution2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbf0ac779ac7f4f4a951a9ccbf52e5a87972cfd1 Binary files /dev/null and b/web-ui/packages/summary2021/images/nocontribution2.jpg differ diff --git a/web-ui/packages/summary2021/images/open.png b/web-ui/packages/summary2021/images/open.png new file mode 100644 index 0000000000000000000000000000000000000000..37c1b031bb3e8343d2c08fa89e1b28f178dd50e5 Binary files /dev/null and b/web-ui/packages/summary2021/images/open.png differ diff --git a/web-ui/packages/summary2021/images/pic1/blue-man.png b/web-ui/packages/summary2021/images/pic1/blue-man.png new file mode 100644 index 0000000000000000000000000000000000000000..3d1d23d123a74b3d78b23cbd4cf67ca50d7d3f21 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/blue-man.png differ diff --git a/web-ui/packages/summary2021/images/pic1/file-one.png b/web-ui/packages/summary2021/images/pic1/file-one.png new file mode 100644 index 0000000000000000000000000000000000000000..a2abad49d37e5b6d8fb369f4ffcd9aafb2ad01f6 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/file-one.png differ diff --git a/web-ui/packages/summary2021/images/pic1/screen-big.png b/web-ui/packages/summary2021/images/pic1/screen-big.png new file mode 100644 index 0000000000000000000000000000000000000000..733a19e79c847c1604bc1dca99823a063d1002ce Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/screen-big.png differ diff --git a/web-ui/packages/summary2021/images/pic1/screen-m.png b/web-ui/packages/summary2021/images/pic1/screen-m.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d9a37f515db8fad22097fbd1295c3e826cac50 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/screen-m.png differ diff --git a/web-ui/packages/summary2021/images/pic1/screen-s.png b/web-ui/packages/summary2021/images/pic1/screen-s.png new file mode 100644 index 0000000000000000000000000000000000000000..f153d8ab40551047cddde52c7985a586a1d75bf1 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/screen-s.png differ diff --git a/web-ui/packages/summary2021/images/pic1/screen.png b/web-ui/packages/summary2021/images/pic1/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..bc358f77889f956016a1819651da945bd6cbbc9f Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/screen.png differ diff --git a/web-ui/packages/summary2021/images/pic1/talk.png b/web-ui/packages/summary2021/images/pic1/talk.png new file mode 100644 index 0000000000000000000000000000000000000000..853ac780a3068544119633f1ad960a9a29d23486 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/talk.png differ diff --git a/web-ui/packages/summary2021/images/pic1/white-paper.png b/web-ui/packages/summary2021/images/pic1/white-paper.png new file mode 100644 index 0000000000000000000000000000000000000000..cd5d421f9b39dac189b3cf57ac98a8bacffdd9bc Binary files /dev/null and b/web-ui/packages/summary2021/images/pic1/white-paper.png differ diff --git "a/web-ui/packages/summary2021/images/pic1/\346\241\214\345\255\220.png" "b/web-ui/packages/summary2021/images/pic1/\346\241\214\345\255\220.png" new file mode 100644 index 0000000000000000000000000000000000000000..14a31a8d73566ad91bd6443da328fdc5f014ec68 Binary files /dev/null and "b/web-ui/packages/summary2021/images/pic1/\346\241\214\345\255\220.png" differ diff --git "a/web-ui/packages/summary2021/images/pic1/\347\262\211\345\234\206.png" "b/web-ui/packages/summary2021/images/pic1/\347\262\211\345\234\206.png" new file mode 100644 index 0000000000000000000000000000000000000000..41110b82fb6d2b7e7fbb274cf501a7d4354dec5d Binary files /dev/null and "b/web-ui/packages/summary2021/images/pic1/\347\262\211\345\234\206.png" differ diff --git "a/web-ui/packages/summary2021/images/pic1/\347\273\277\344\270\211\350\247\222.png" "b/web-ui/packages/summary2021/images/pic1/\347\273\277\344\270\211\350\247\222.png" new file mode 100644 index 0000000000000000000000000000000000000000..6b09da114ea9721b57ec07f09c4b833219c4dbf9 Binary files /dev/null and "b/web-ui/packages/summary2021/images/pic1/\347\273\277\344\270\211\350\247\222.png" differ diff --git "a/web-ui/packages/summary2021/images/pic1/\350\223\235\345\205\255\350\276\271.png" "b/web-ui/packages/summary2021/images/pic1/\350\223\235\345\205\255\350\276\271.png" new file mode 100644 index 0000000000000000000000000000000000000000..f1b3d78409ae7eb419f7532fee3ca266d79b74f4 Binary files /dev/null and "b/web-ui/packages/summary2021/images/pic1/\350\223\235\345\205\255\350\276\271.png" differ diff --git "a/web-ui/packages/summary2021/images/pic1/\351\200\232\347\224\250\350\203\214\346\231\257.png" "b/web-ui/packages/summary2021/images/pic1/\351\200\232\347\224\250\350\203\214\346\231\257.png" new file mode 100644 index 0000000000000000000000000000000000000000..b35ea2c40e10af25ae02fdd9d2b7f6f24541255a Binary files /dev/null and "b/web-ui/packages/summary2021/images/pic1/\351\200\232\347\224\250\350\203\214\346\231\257.png" differ diff --git a/web-ui/packages/summary2021/images/pic2/bird1.png b/web-ui/packages/summary2021/images/pic2/bird1.png new file mode 100644 index 0000000000000000000000000000000000000000..2883bba619c062c6fadfd0023285718b6dc0b96d Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/bird1.png differ diff --git a/web-ui/packages/summary2021/images/pic2/blue-balloon.png b/web-ui/packages/summary2021/images/pic2/blue-balloon.png new file mode 100644 index 0000000000000000000000000000000000000000..39864ad6817838b9e1fe08b13289cc458d64fddb Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/blue-balloon.png differ diff --git a/web-ui/packages/summary2021/images/pic2/cloud1.png b/web-ui/packages/summary2021/images/pic2/cloud1.png new file mode 100644 index 0000000000000000000000000000000000000000..a257671bc21826b9c55ca44d29f90836a276ff5e Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/cloud1.png differ diff --git a/web-ui/packages/summary2021/images/pic2/cloud2.png b/web-ui/packages/summary2021/images/pic2/cloud2.png new file mode 100644 index 0000000000000000000000000000000000000000..7b2e21104c2c4e9b7bc05d65793845c53f76d870 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/cloud2.png differ diff --git a/web-ui/packages/summary2021/images/pic2/cloud3.png b/web-ui/packages/summary2021/images/pic2/cloud3.png new file mode 100644 index 0000000000000000000000000000000000000000..92c3b83356aa4be067a3fffa41b19ab84b14550e Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/cloud3.png differ diff --git a/web-ui/packages/summary2021/images/pic2/cloud4.png b/web-ui/packages/summary2021/images/pic2/cloud4.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb601afc954e7ad595a4a3603eedd956111c654 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/cloud4.png differ diff --git a/web-ui/packages/summary2021/images/pic2/cloud5.png b/web-ui/packages/summary2021/images/pic2/cloud5.png new file mode 100644 index 0000000000000000000000000000000000000000..88641721fef5a9124988e5d0cfc89e86dc820ba5 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/cloud5.png differ diff --git a/web-ui/packages/summary2021/images/pic2/green-balloon.png b/web-ui/packages/summary2021/images/pic2/green-balloon.png new file mode 100644 index 0000000000000000000000000000000000000000..4b2fdcfb22b4dab63bb593011bfe8a593d0f115e Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/green-balloon.png differ diff --git a/web-ui/packages/summary2021/images/pic2/pink-balloon.png b/web-ui/packages/summary2021/images/pic2/pink-balloon.png new file mode 100644 index 0000000000000000000000000000000000000000..c54096a26fd93c5cfe1760422843b7e5d801417c Binary files /dev/null and b/web-ui/packages/summary2021/images/pic2/pink-balloon.png differ diff --git a/web-ui/packages/summary2021/images/pic3/bottom-item.png b/web-ui/packages/summary2021/images/pic3/bottom-item.png new file mode 100644 index 0000000000000000000000000000000000000000..b6b4a07f5ea00abfd64fcd2518fb0a68f8d31304 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic3/bottom-item.png differ diff --git a/web-ui/packages/summary2021/images/pic3/logo.png b/web-ui/packages/summary2021/images/pic3/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..babedca0dca8f90795ba8eebe16145253dce3d1f Binary files /dev/null and b/web-ui/packages/summary2021/images/pic3/logo.png differ diff --git a/web-ui/packages/summary2021/images/pic3/mirror.png b/web-ui/packages/summary2021/images/pic3/mirror.png new file mode 100644 index 0000000000000000000000000000000000000000..9bdd2fa20a02654ed588fea7b08fc3ea58c02d8d Binary files /dev/null and b/web-ui/packages/summary2021/images/pic3/mirror.png differ diff --git a/web-ui/packages/summary2021/images/pic3/yellow-ball.png b/web-ui/packages/summary2021/images/pic3/yellow-ball.png new file mode 100644 index 0000000000000000000000000000000000000000..50a27814e4494326e1702bcce0ca846426125c01 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic3/yellow-ball.png differ diff --git a/web-ui/packages/summary2021/images/pic4/center-logo.png b/web-ui/packages/summary2021/images/pic4/center-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..34d8aa504e10f5dcc6ec38e14c1378f19e2e4763 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic4/center-logo.png differ diff --git a/web-ui/packages/summary2021/images/pic4/earth1.png b/web-ui/packages/summary2021/images/pic4/earth1.png new file mode 100644 index 0000000000000000000000000000000000000000..2992a4177b97b64ab687c51f54f2919c7f72611c Binary files /dev/null and b/web-ui/packages/summary2021/images/pic4/earth1.png differ diff --git a/web-ui/packages/summary2021/images/pic4/earth2.png b/web-ui/packages/summary2021/images/pic4/earth2.png new file mode 100644 index 0000000000000000000000000000000000000000..249b1400d40bf173f1b0dbf36d9b24dd8f2fd667 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic4/earth2.png differ diff --git a/web-ui/packages/summary2021/images/pic4/girl.png b/web-ui/packages/summary2021/images/pic4/girl.png new file mode 100644 index 0000000000000000000000000000000000000000..f723effd9f53a676d2bc885358c7f1d817e60fe7 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic4/girl.png differ diff --git a/web-ui/packages/summary2021/images/pic4/green-2.png b/web-ui/packages/summary2021/images/pic4/green-2.png new file mode 100644 index 0000000000000000000000000000000000000000..257b9b6ad235efcfb978ed084dc0907e539e4d03 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic4/green-2.png differ diff --git a/web-ui/packages/summary2021/images/pic5/bottom-item2.png b/web-ui/packages/summary2021/images/pic5/bottom-item2.png new file mode 100644 index 0000000000000000000000000000000000000000..5958b28013bfa7ac2054aff81db888592f786435 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/bottom-item2.png differ diff --git a/web-ui/packages/summary2021/images/pic5/hexagon.png b/web-ui/packages/summary2021/images/pic5/hexagon.png new file mode 100644 index 0000000000000000000000000000000000000000..82367d6a23932f10915982f63a1a900cd305e27f Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/hexagon.png differ diff --git a/web-ui/packages/summary2021/images/pic5/logo.png b/web-ui/packages/summary2021/images/pic5/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b133fca3f702e76fdc19efc14dc5c7fc2b060731 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/logo.png differ diff --git a/web-ui/packages/summary2021/images/pic5/person2.png b/web-ui/packages/summary2021/images/pic5/person2.png new file mode 100644 index 0000000000000000000000000000000000000000..87d7145a4607c7c25775664752a94ff00eeb78ff Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/person2.png differ diff --git a/web-ui/packages/summary2021/images/pic5/person3.png b/web-ui/packages/summary2021/images/pic5/person3.png new file mode 100644 index 0000000000000000000000000000000000000000..4c3b14b396e4bfc01b6aaec8f9312f2e27cfdd22 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/person3.png differ diff --git a/web-ui/packages/summary2021/images/pic5/qr-code.png b/web-ui/packages/summary2021/images/pic5/qr-code.png new file mode 100644 index 0000000000000000000000000000000000000000..507ee8e8bc5cf503985a33d42cf545892107974e Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/qr-code.png differ diff --git a/web-ui/packages/summary2021/images/pic5/talk2.png b/web-ui/packages/summary2021/images/pic5/talk2.png new file mode 100644 index 0000000000000000000000000000000000000000..7c17fb950e867a094947fd73ad97a4be276a2797 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic5/talk2.png differ diff --git a/web-ui/packages/summary2021/images/pic6/border.png b/web-ui/packages/summary2021/images/pic6/border.png new file mode 100644 index 0000000000000000000000000000000000000000..18b1a0c0a177baa22cd630a6b28a7ca5053de38d Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/border.png differ diff --git a/web-ui/packages/summary2021/images/pic6/crowd.png b/web-ui/packages/summary2021/images/pic6/crowd.png new file mode 100644 index 0000000000000000000000000000000000000000..69c7bf327cb0f4fe9f06ffee4885998321fdb801 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/crowd.png differ diff --git a/web-ui/packages/summary2021/images/pic6/email.png b/web-ui/packages/summary2021/images/pic6/email.png new file mode 100644 index 0000000000000000000000000000000000000000..9fdcf5aed22a81c03b6b8eeec004c87e49b0b46a Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/email.png differ diff --git a/web-ui/packages/summary2021/images/pic6/file2.png b/web-ui/packages/summary2021/images/pic6/file2.png new file mode 100644 index 0000000000000000000000000000000000000000..3a1837f1efd5a72cd6377ed9090029daad43f7b5 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/file2.png differ diff --git a/web-ui/packages/summary2021/images/pic6/logo.png b/web-ui/packages/summary2021/images/pic6/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aa19eb9b8071e18d80ba11a16f7d4bea17195536 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/logo.png differ diff --git a/web-ui/packages/summary2021/images/pic6/white-paper2.png b/web-ui/packages/summary2021/images/pic6/white-paper2.png new file mode 100644 index 0000000000000000000000000000000000000000..9b49634affab2b31b10dd55d274c819429c7f9c5 Binary files /dev/null and b/web-ui/packages/summary2021/images/pic6/white-paper2.png differ diff --git a/web-ui/packages/summary2021/index.html b/web-ui/packages/summary2021/index.html new file mode 100644 index 0000000000000000000000000000000000000000..4c0d48dffcb67df3f893e9e145f098655146a506 --- /dev/null +++ b/web-ui/packages/summary2021/index.html @@ -0,0 +1,156 @@ + + + + + + + + openEuler2021年度报告 + + + + + + + + + + +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+

openEuler两周岁

+

遇见开源世界的自己

+

Dear

+

${data.user_login}

+

openEuler 今天两周岁了!

+

在这两年的时光里,openEuler在惊喜地成长:

+

社区用户 370,000+

+

软件包8600+

+

社区贡献者8000+

+

商用OSV11家

+

企业成员300+家

+

······

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+

在这里有7900+的社区开发者

+

与你并肩同行,

+

在这里有90+个SIG组,

+

相信你总能找到和你志趣相投的人;

+

在这里会有

+

遍及全球100+个国家、

+

1200+城市的用户

+

和你不期而遇

+

期待2022年,

+

会有属于我和你的故事发生······

+

新年快来!

+

openEuler 社区

+

呈上

+
+
+

查看您的社区年度报告

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/web-ui/packages/summary2021/js/axios.js b/web-ui/packages/summary2021/js/axios.js new file mode 100644 index 0000000000000000000000000000000000000000..2f58b36526b3e0d71f55551563e48d9f92ccf040 --- /dev/null +++ b/web-ui/packages/summary2021/js/axios.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=11)}([function(e,t,n){"use strict";var r=n(3),o=Object.prototype.toString;function i(e){return"[object Array]"===o.call(e)}function s(e){return void 0===e}function a(e){return null!==e&&"object"==typeof e}function u(e){if("[object Object]"!==o.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function c(e){return"[object Function]"===o.call(e)}function f(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),i(e))for(var n=0,r=e.length;n=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){c.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){c.headers[e]=r.merge(s)})),e.exports=c},function(e,t,n){"use strict";function r(e){this.message=e}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,e.exports=r},function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}})),s):s}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(e){var r=e;return t&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return e=o(window.location.href),function(t){var n=r.isString(t)?o(t):t;return n.protocol===e.protocol&&n.host===e.host}}():function(){return!0}},function(e,t,n){"use strict";var r=n(10).version,o={};["object","boolean","number","function","string","symbol"].forEach((function(e,t){o[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}}));var i={};o.transitional=function(e,t,n){function o(e,t){return"[Axios v"+r+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,r,s){if(!1===e)throw new Error(o(r," has been removed"+(t?" in "+t:"")));return t&&!i[r]&&(i[r]=!0,console.warn(o(r," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,r,s)}},e.exports={assertOptions:function(e,t,n){if("object"!=typeof e)throw new TypeError("options must be an object");for(var r=Object.keys(e),o=r.length;o-- >0;){var i=r[o],s=t[i];if(s){var a=e[i],u=void 0===a||s(a,i,e);if(!0!==u)throw new TypeError("option "+i+" must be "+u)}else if(!0!==n)throw Error("Unknown option "+i)}},validators:o}},function(e,t,n){"use strict";var r=n(2);function o(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;this.promise.then((function(e){if(n._listeners){var t,r=n._listeners.length;for(t=0;t { + getData(res.data.user) +}) +.catch(err => { + document.querySelector('.no-contribution .user-name').innerHTML = ''; + let data = {}; + data['contribution'] = 'none'; + intaPc(data) + intaSwiper(data) +}) +function getData(user) { + let data = [] + axios.get(`https://omapi.osinfra.cn/query/newYear/2022?community=openeuler&user=${user}`).then(res => { + if (res.data.data[0]) { + data = res.data.data[0]; + let percentage = parseFloat(data.beat_percentage) * 100; + let rank = 1; + if (percentage <= 20) { + rank = 1 + } else if (20 < percentage && percentage <= 40) { + rank = 2 + } else if (40 < percentage && percentage <= 60) { + rank = 3 + } else if (60 < percentage && percentage <= 70) { + rank = 4 + } else if (70 < percentage) { + rank = 5 + } + data.total_time_of_exist_before == 1 ? data.total_time_of_exist_before = '一' : data.total_time_of_exist_before = '两'; + data['user_name'] = user; + data['percentage'] = percentage; + data['rank'] = rank; + data['contribution'] = 'yes'; + } else { + // 无贡献 + data['contribution'] = 'none'; + data['user_name'] = user; + } + intaPc(data) + intaSwiper(data) + }) +} +function Contribution() { + document.querySelector('.contribution').classList.remove('none'); + document.querySelector('.no-contribution').classList.add('none'); +} +function timeChange(time) { + if (time) { + let EndTime = new Date(time); + let y = EndTime.getFullYear(); + let m = EndTime.getMonth() + 1; + let d = EndTime.getDate(); + let h = EndTime.getSeconds() + let all = `${y}年${m}月${d}日` + return all + } else { + return 'none' + } + +} +function isZero(num) { + if (num == '0') { + return 'none' + } else { + return num + } +} +// pc端事件 +function intaPc(data) { + let front = document.querySelectorAll(".front"); + let back = document.querySelectorAll(".back"); + data.contribution == 'yes' ? Contribution() : document.querySelector('.no-contribution .user-name').innerHTML = data.user_name + for (let i = 0; i < front.length; i++) { + front[i].addEventListener('click', function () { + if (data.first_time_of_enter_before) { + back[0].innerHTML = ` +
+
+
+

openEuler两周岁

+

遇见开源世界的自己

+

Dear ${data.user_name}

+

openEuler 今天两周岁了!

+

在这两年的时光里,openEuler在惊喜地成长:

+

社区用户 370,000+

+

软件包8600+

+

社区贡献者8000+

+

商用OSV11家

+

企业成员300+家

+

······

+

openEuler 成长的过程记录着你奋斗的岁月

+

在今天这个特殊的日子里

+

请跟 openEuler 一起打开时间的匣子

+

看看你在 openEuler 开源社区中熠熠生辉的瞬间······

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
` + back[1].innerHTML = ` +
+
+
+
+
+
+
+
+
+

我们在一起${data.total_time_of_exist_before}年了!

+

${timeChange(data.first_time_of_enter_before)},

+

你第一次走进我的世界

+

${timeChange(data.first_time_of_contact)},

+

你与社区中的${data.first_user_login_of_contact}第一次建立链接;

+

${timeChange(data.first_time_of_comment_other)},

+ +

${timeChange(data.first_time_of_be_comment)},

+ +

初来乍到,${data.first_user_login_of_contact}第一个解决了你的问题;

+ +
+ +
+
+
+
+
+

时光悄然流逝,

+

但这些流光溢彩的回忆,

+

我铭记于心 ······

+
+
+ +
+
+
+
` + back[2].innerHTML = ` +
+
+
+ + +
+
+

回望2021,我快速成长

+

而你在这一年中

+

提交了${data.pr_num}个pr,

+

提交了${data.issue_num}个issue,

+

提交了${data.comment_num}条评论,

+

贡献了${data.code_lines}行代码,

+

参与了${data.sig_num}个sig组,

+

点亮了${data.star_num}个仓库,

+

在这一年里,

+

你的贡献度击败了社区${data.percentage}%开发者。

+
+
+ +
+
+
` + back[3].innerHTML = ` +
+
+
+ +
+

你们从不同途径来到我的开源世界

+

但却因相同的目的留了下来

+

谢谢你们的坚持与贡献,

+

才打造出我更好的模样!

+

期待你我携手并肩,继续坚定向前!

+

新年快乐!

+

openEuler 社区

+

呈上

+
+
+
+ +
+ +
+ +
+
+
+
+
` + + } + for (let j = 0; j < front.length; j++) { + front[j].style = "transform:rotateY(-180deg)"; + back[j].style = "transform:rotateY(0deg)"; + } + }) + back[i].addEventListener('click', function () { + for (let z = 0; z < back.length; z++) { + back[z].style = "transform:rotateY(180deg)"; + front[z].style = "transform:rotateY(0deg)"; + } + + }) + } +} +// 移动端事件 +let swper = null; +function intaSwiper(data) { + let intaData = null; + console.log(data.rank); + let noContribution = [ + { + content: ` +
+
+

openEuler两周岁

+

遇见开源世界的自己

+

Dear

+

${data.user_name}

+

openEuler 今天两周岁了!

+

在这两年的时光里,openEuler在惊喜地成长:

+

社区用户 370,000+

+

软件包8600+

+

社区贡献者8000+

+

商用OSV11家

+

企业成员300+家

+

······

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
` + }, + { + content: ` +
+
+ +
+

在这里有7900+的社区开发者

+

与你并肩同行,

+

在这里有90+个SIG组,

+

相信你总能找到和你志趣相投的人;

+

在这里会有

+

遍及全球100+个国家、

+

1200+城市的用户

+

和你不期而遇

+

期待2022年,

+

会有属于我和你的故事发生······

+

新年快来!

+

openEuler 社区

+

呈上

+
+
+

查看您的社区年度报告

+
+
+
+ +
+ +
+
+
` + } + ] + let list = [{ + content: ` +
+
+ +

openEuler两周岁

+

遇见开源世界的自己

+

Dear

+

${data.user_name}

+

openEuler 今天两周岁了!

+

在这两年的时光里,openEuler在惊喜地成长:

+

社区用户 370,000+

+

软件包8600+

+

社区贡献者8000+

+

商用OSV11家

+

企业成员300+家

+

······

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
` + }, { + content: ` +
+
+

openEuler 成长的过程记录着你奋斗的岁月

+

在今天这个特殊的日子里

+

请跟openEuler 一起打开时间的匣子

+

看看你在 openEuler 开源社区中熠熠生辉的瞬间······

+

跟着热气球一起查看你的

+

年度贡献吧!

+
+
+
+
+
+
+
+
+
+
+
+
+
` + }, { + content: ` +
+
+
+
+
+
+
+
+

我们在一起${data.total_time_of_exist_before}年了!

+

${timeChange(data.first_time_of_enter_before)},

+

你第一次走进我的世界

+

${timeChange(data.first_time_of_contact)},

+ +

${timeChange(data.first_time_of_comment_other)},

+ +

${timeChange(data.first_time_of_be_comment)},

+ + + +
+ +
+
+
+
+
+

时光悄然流逝,

+

但这些流光溢彩的回忆,

+

我铭记于心 ······

+
+
+ +
+
+
` + }, { + content: ` +
+
+
+
+
+
+
+
+
+
+

回望2021,我快速成长

+

而你在这一年中

+

提交了${data.pr_num}个pr,

+

提交了${data.issue_num}个issue,

+

提交了${data.comment_num}条评论,

+

贡献了${data.code_lines}行代码,

+

参与了${data.sig_num}个sig组,

+

点亮了${data.star_num}个仓库,

+ +
+
` + }, { + content: ` +
+
+
+
+
+ +
+

查看您的社区年度报告

+
+
+
+
+

${data.user_name}

+

在这一年里,

+

你的贡献度击败了社区${data.percentage}%开发者。

+
+
+ +
+
` + }, { + content: ` +
+
+ +
+

你们从不同途径来到我的开源世界

+

但却因相同的目的留了下来

+

谢谢你们的坚持与贡献,

+

才打造出我更好的模样!

+

期待你我携手并肩,继续坚定向前!

+

新年快乐!

+

openEuler 社区

+

呈上

+
+
+
+ +
+ +
+ +
+
+
+
` + }] + data.first_time_of_enter_before ? intaData = list : intaData = noContribution; + let container = document.querySelector('#outer-container'); + swiper = new Swiper({ + container: container, + data: intaData, + }); +} \ No newline at end of file diff --git a/web-ui/packages/summary2021/js/swiper.js b/web-ui/packages/summary2021/js/swiper.js new file mode 100644 index 0000000000000000000000000000000000000000..30afa66972a95a859a422d44658435c2b0be7f5a --- /dev/null +++ b/web-ui/packages/summary2021/js/swiper.js @@ -0,0 +1 @@ +!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}(this,function(){return function(t){function e(n){if(i[n])return i[n].exports;var s=i[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,e),s.l=!0,s.exports}var i={};return e.m=t,e.c=i,e.d=function(t,i,n){e.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=2)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.EMPTY_FUNCTION=function(){},e.EMPTY_PAGE=document.createElement("div"),e.OPPSITE={X:"Y",Y:"X"}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(){}return t.register=function(e,i){t._renders[e]=i},t.getRenderInstance=function(e){var i=t._renders[e];if(!i)throw new Error("Missing render : "+e);return new i},t.prototype.sign=function(t){return t=+t,0===t||isNaN(t)?0:t>0?1:-1},t}();n._renders={},e.default=n},function(t,e,i){"use strict";var n=this&&this.__assign||Object.assign||function(t){for(var e,i=1,n=arguments.length;i0?(this.moveDirection=a.Direction.Backward,this.lastActivePage=this.activePage,this.activePage=this.currentPage.prev):(this.moveDirection=a.Direction.Nonward,this.lastActivePage=this.activePage,this.activePage=r.EMPTY_PAGE),this.fire("swipeMoving"),this.activePage!==this.lastActivePage&&this.activePage!==r.EMPTY_PAGE&&this.fire("activePageChanged"),this.transition.direction&&this.transition.direction!==this.moveDirection&&(this.offset[this.axis]=0,this.start=this.end);var e={Forward:20,Backward:this.sideLength-20},i=a.Direction[this.moveDirection];if(this.moveDirection*this.end[this.axis]>this.moveDirection*e[i]){var n=this.moveDirection===a.Direction.Forward?"<--- near edge":"near edge ---\x3e";return this.log(n),this.endHandler()}0!==this.transition.duration&&this.render()}},t.prototype.endHandler=function(){if(!this.sliding&&this.moving&&this.transition.direction!==a.Direction.Nonward){this.moving=!1,this.log("end"),this.transition.direction&&this.transition.direction!==this.moveDirection&&(this.offset[this.axis]=0),this.endTime=(new Date).getTime();var t=this.endTime-this.startTime,e=t>300?this.sideLength/3:14,i=(this.offset[this.axis],Math.abs(this.offset[this.axis])),n=Math.abs(this.offset[r.OPPSITE[this.axis]]),s=n=e&&s&&this.activePage!==r.EMPTY_PAGE?(this.pageChange=!0,this._swipeTo()):(this.pageChange=!1,this._swipeTo(),this.fire("swipeRestore"))}},t.prototype.resizeHandler=function(){this.sliding||this.moving||(this.sideLength="X"===this.axis?this.$container.clientWidth:this.$container.clientHeight)},t.prototype.transitionEndHandler=function(t){t&&t.target!==this.currentPage||(this.$swiper.style.cssText="",this.currentPage.style.cssText="",this.activePage.style.cssText="",!1===this.pageChange?(this.activePage.classList.remove("active"),this.fire("swipeRestored")):(this.currentPage.classList.remove("current"),this.activePage.classList.remove("active"),this.activePage.classList.add("current"),this.currentPage=this.activePage,this.fire("swipeChanged")),this.activePage=r.EMPTY_PAGE,this.lastActivePage=r.EMPTY_PAGE,this.offset.X=0,this.offset.Y=0,this.sliding=!1,this.pageChange=!1)},t.prototype.swipeTo=function(t,e){if(!this.sliding){var i=this.currentPage.index;this.moveDirection=a.Direction.Nonward,this.pageChange=!0,t>i?this.moveDirection=a.Direction.Forward:t-1&&this._listeners[t].splice(i,1)}return this},t.prototype.fire=function(t,e){if(void 0===e&&(e={}),this._listeners[t])for(var i=0,s=this._listeners[t];i0?{X:t.targetTouches[0].pageX,Y:t.targetTouches[0].pageY}:{X:void 0,Y:void 0}},t.prototype.getMousePosition=function(t){return"pageX"in t?{X:t.pageX,Y:t.pageY}:{X:void 0,Y:void 0}},t.prototype.getTransitionEvent=function(){var t=document.createElement("fakeelement"),e={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(var i in e)if(void 0!==t.style[i])return e[i]},t}();e.Device=n},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});!function(t){t[t.Forward=-1]="Forward",t[t.Nonward=0]="Nonward",t[t.Backward=1]="Backward"}(e.Direction||(e.Direction={}))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(){}return t.easeOutQuad=function(e,i){var n=Math.abs(e/i),s=.5*n*(3-n);return t.sign(e)*s*i},t.rubberBand=function(e,i){var n=Math.abs(e/i),s=1-1/(.55*n+1);return t.sign(e)*s*i},t.sign=function(t){return t=+t,0===t||isNaN(t)?0:t>0?1:-1},t}();e.default=n},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=t.axis,i=t.sideOffset,n=t.sideLength,s=t.moveDirection,a="translateZ(0) translate"+e+"("+i+"px)",o="translateZ(0) translate"+e+"("+(i-s*n)+"px)";t.currentPage.style.webkitTransform=a,t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.webkitTransform=o)},e}(s.default);e.default=a},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=t.axis,i=t.sideOffset,n=t.sideLength,s=r.OPPSITE[e],a=t.moveDirection,o="Y"===e?-1:1,c="-webkit-perspective:"+4*n+"px;-webkit-transform-style:preserve-3d;",h="rotate"+s+"("+90*o*i/n+"deg) translateZ("+.889*n/2+"px) scale(0.889)",u="rotate"+s+"("+90*o*(i/n-a)+"deg) translateZ("+.889*n/2+"px) scale(0.889)";t.$swiper.style.cssText=c,t.currentPage.style.webkitTransform=h,t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.webkitTransform=u)},e}(s.default);e.default=a},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=t.axis,i=t.sideOffset,n=t.sideLength,s=r.OPPSITE[e],a="Y"===e?-1:1,o="-webkit-perspective:"+4*n+"px;-webkit-transform-style:flat;",c="translateZ("+n/2+"px) rotate"+s+"("+180*a*i/n+"deg) scale(0.875)",h="translateZ("+n/2+"px) rotate"+s+"("+180*a*(i/n+1)+"deg) scale(0.875)";t.$swiper.style.cssText=o,t.currentPage.style.webkitBackfaceVisibility="hidden",t.currentPage.style.webkitTransform=c,t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.webkitBackfaceVisibility="hidden",t.activePage.style.webkitTransform=h,t.activePage.style.zIndex=7)},e}(s.default);e.default=a},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=t.axis,i=t.sideOffset,n=t.sideLength,s=r.OPPSITE[e],a=1-.2*Math.abs(i/n),o=t.moveDirection,c="translateZ(0) scale"+s+"("+a+") translate"+e+"("+i+"px)",h="translateZ(0) translate"+e+"("+(i-o*n)+"px)";t.currentPage.style.webkitTransform=c,t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.webkitTransform=h)},e}(s.default);e.default=a},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=(t.axis,t.sideOffset),i=t.sideLength;t.currentPage.style.opacity=1-Math.abs(e/i),t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.opacity=Math.abs(e/i))},e}(s.default);e.default=a},function(t,e,i){"use strict";var n=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])};return function(e,i){function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=i(1),r=i(0),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.doRender=function(t){var e=t.axis,i=t.sideOffset,n=t.sideLength,s=(r.OPPSITE[e],1-.4*Math.min(Math.abs(i/n),.5)),a=.8+.4*Math.min(Math.abs(i/n),.5),o=t.moveDirection,c="translateZ(0) translate"+e+"("+i+"px) scale("+s+")",h="translateZ(0) translate"+e+"("+(i-o*n)+"px) scale("+a+")";t.currentPage.style.webkitTransform=c,t.activePage!==r.EMPTY_PAGE&&(t.activePage.style.webkitTransform=h)},e}(s.default);e.default=a}])}); \ No newline at end of file diff --git a/web-ui/script/add-worker-script.js b/web-ui/script/add-worker-script.js new file mode 100644 index 0000000000000000000000000000000000000000..8bc1bd571a8701543436fed16ab10e1ddb31855f --- /dev/null +++ b/web-ui/script/add-worker-script.js @@ -0,0 +1,145 @@ +const { parentPort } = require('worker_threads') +const escape = require('escape-html') +const { chalk, fs, path, logger } = require('@vuepress/shared-utils') +const { createBundleRenderer } = require('vue-server-renderer') +const { normalizeHeadTag } = require('../util/index') +const { version } = require('../../../package') + +/** + * Worker file for HTML page rendering + * + * @param {number} workerNumber + * @param {Array} pages + * @returns {Promise} + * @api private + */ + +parentPort.once('message', async payload => { + logger.setOptions({ logLevel: payload.logLevel }) + const siteConfig = JSON.parse(payload.siteConfig) + const ssrTemplate = JSON.parse(payload.ssrTemplate) + + // create server renderer using built manifests + const renderer = createBundleRenderer(JSON.parse(payload.serverBundle), { + clientManifest: JSON.parse(payload.clientManifest), + runInNewContext: false, + inject: false, + shouldPrefetch: siteConfig.shouldPrefetch || (() => false), + template: await fs.readFile(ssrTemplate, 'utf-8') + }) + + // pre-render head tags from user config + const userHeadTags = (siteConfig.head || []).map(renderHeadTag).join('\n ') + + const pages = JSON.parse(Buffer.from(payload.pages)) + logger.wait(`Worker #${payload.workerNumber} beginning rendering of ${pages.length} pages`) + const filePaths = [] + let pagesRendered = 0 + + for (const page of pages) { + const pagePath = decodeURIComponent(page.path) + + // #565 Avoid duplicate description meta at SSR. + const meta = ((page.frontmatter && page.frontmatter.meta) || []).filter( + item => item.name !== 'description' + ) + const pageMeta = renderPageMeta(meta) + + const context = { + url: page.path, + userHeadTags: userHeadTags, + pageMeta, + title: 'VuePress', + lang: 'en', + description: '', + version + } + + let html + try { + html = await renderer.renderToString(context) + } catch (e) { + console.error( + logger.error( + chalk.red( + `Worker #${payload.workerNumber} error rendering ${pagePath}:` + ), + false + ) + ) + throw e + } finally { + const filename = pagePath + .replace(/\/$/, '/index.html') + .replace(/^\//, '') + const filePath = path.resolve(payload.outDir, filename) + await fs.ensureDir(path.dirname(filePath)) + await fs.writeFile(filePath, html) + filePaths.push(filePath) + pagesRendered++ + + if (pagesRendered % 50 === 0) { + parentPort.postMessage({ + complete: false, + message: `Worker #${payload.workerNumber} has rendered ${pagesRendered} of ${pages.length} pages`, + filePaths: null + }) + } + } + } + parentPort.postMessage({ + complete: true, + message: `Worker #${payload.workerNumber} has rendered ${pagesRendered} of ${pages.length} pages`, + filePaths: filePaths + }) +}) + +/** + * Render html attributes + * + * @param {Object} attrs + * @returns {string} + */ + +function renderAttrs (attrs = {}) { + const keys = Object.keys(attrs) + if (keys.length) { + return ' ' + keys.map(name => `${name}="${escape(attrs[name])}"`).join(' ') + } else { + return '' + } +} + +/** + * Render head tag + * + * @param {Object} tag + * @returns {string} + */ + +function renderHeadTag (tag) { + const { tagName, attributes, innerHTML, closeTag } = normalizeHeadTag(tag) + return `<${tagName}${renderAttrs(attributes)}>${innerHTML}${ + closeTag ? `` : `` + }` +} + +/** + * Render meta tags + * + * @param {Array} meta + * @returns {Array} + */ + +function renderPageMeta (meta) { + if (!meta) return '' + return meta + .map(m => { + let res = ` { + res += ` ${key}="${escape(m[key])}"` + }) + return res + `>` + }) + .join('') +} \ No newline at end of file diff --git a/web-ui/script/update-build-script.js b/web-ui/script/update-build-script.js new file mode 100644 index 0000000000000000000000000000000000000000..3e521cd3d56ad7fb07471167b53da40e0075f9b9 --- /dev/null +++ b/web-ui/script/update-build-script.js @@ -0,0 +1,257 @@ +'use strict' + +const EventEmitter = require('events').EventEmitter +const webpack = require('webpack') +const readline = require('readline') +const { Worker } = require('worker_threads') + +const workerThreads = 8 + +const { + chalk, + fs, + path, + logger, + env, + performance +} = require('@vuepress/shared-utils') +const createClientConfig = require('../webpack/createClientConfig') +const createServerConfig = require('../webpack/createServerConfig') +const { applyUserWebpackConfig } = require('../util/index') + +/** + * Expose Build Process Class. + */ + +module.exports = class Build extends EventEmitter { + constructor (context) { + super() + this.context = context + this.outDir = this.context.outDir + } + + /** + * Doing somthing before render pages, e.g. validate and empty output directory, + * prepare webpack config. + * + * @returns {Promise} + * @api public + */ + + async process () { + if (this.context.cwd === this.outDir) { + throw new Error( + 'Unexpected option: "outDir" cannot be set to the current working directory' + ) + } + + this.context.resolveCacheLoaderOptions() + await fs.emptyDir(this.outDir) + logger.debug('Dist directory: ' + chalk.gray(this.outDir)) + this.prepareWebpackConfig() + } + + /** + * Compile and render pages. + * + * @returns {Promise} + * @api public + */ + + async render () { + // compile! + performance.start() + const stats = await compile([this.clientConfig, this.serverConfig]) + const serverBundle = require(path.resolve( + this.outDir, + 'manifest/server.json' + )) + const clientManifest = require(path.resolve( + this.outDir, + 'manifest/client.json' + )) + + // remove manifests after loading them. + await fs.remove(path.resolve(this.outDir, 'manifest')) + + // ref: https://github.com/vuejs/vuepress/issues/1367 + if ( + !this.clientConfig.devtool + && (!this.clientConfig.plugins + || !this.clientConfig.plugins.some( + p => + p instanceof webpack.SourceMapDevToolPlugin + || p instanceof webpack.EvalSourceMapDevToolPlugin + )) + ) { + await workaroundEmptyStyleChunk(stats, this.outDir) + } + + // if the user does not have a custom 404.md, generate the theme's default + if (!this.context.pages.some(p => p.path === '/404.html')) { + this.context.addPage({ path: '/404.html' }) + } + + // render pages + logger.wait('Rendering static HTML...') + + let activeWorkers = 0 + const pagePaths = [] + const pagesPerThread = this.context.pages.length / workerThreads + + for (let workerNumber = 0; workerNumber < workerThreads; workerNumber++) { + const startIndex = workerNumber * pagesPerThread + const pageData = this.context.pages.slice( + startIndex, + startIndex + pagesPerThread + ) + const pages = pageData.map(p => ({ + path: p.path, + frontmatter: JSON.stringify(p.frontmatter) + })) + + const payload = { + clientManifest: JSON.stringify(clientManifest), + outDir: this.outDir, + pages: Buffer.from(JSON.stringify(pages)), + serverBundle: JSON.stringify(serverBundle), + siteConfig: JSON.stringify(this.context.siteConfig), + ssrTemplate: JSON.stringify(this.context.ssrTemplate), + workerNumber, + logLevel: logger.options.logLevel + } + + const worker = new Worker(path.join(__dirname, './worker.js')) + worker.postMessage(payload) + activeWorkers++ + worker.on('message', response => { + if (response.complete) { + pagePaths.concat(response.filePaths) + } + if (response.message) { + logger.wait(response.message) + } + }) + worker.on('error', error => { + console.error( + logger.error( + chalk.red(`Worker #${workerNumber} sent error: ${error}\n\n${error.stack}`), + false + ) + ) + }) + worker.on('exit', code => { + activeWorkers-- + if (code === 0) { + logger.success(`Worker ${workerNumber} completed successfully.`) + } else { + logger.error( + chalk.red(`Worker #${workerNumber} sent exit code: ${code}`), + false + ) + } + if (activeWorkers === 0) { + // DONE. + readline.clearLine(process.stdout, 0) + readline.cursorTo(process.stdout, 0) + const relativeDir = path.relative(this.context.cwd, this.outDir) + logger.success( + `Generated static files in ${chalk.cyan(relativeDir)}.` + ) + const { duration } = performance.stop() + logger.success( + `It took a total of ${chalk.cyan( + `${duration}ms` + )} to run the ${chalk.cyan('vuepress build')}.` + ) + console.log() + } + }) + } + + await this.context.pluginAPI.applyAsyncOption('generated', pagePaths) + } + + /** + * Prepare webpack config under build. + * + * @api private + */ + + prepareWebpackConfig () { + this.clientConfig = createClientConfig(this.context).toConfig() + this.serverConfig = createServerConfig(this.context).toConfig() + + const userConfig = this.context.siteConfig.configureWebpack + if (userConfig) { + this.clientConfig = applyUserWebpackConfig( + userConfig, + this.clientConfig, + false + ) + this.serverConfig = applyUserWebpackConfig( + userConfig, + this.serverConfig, + true + ) + } + } +} + +/** + * Compile a webpack application and return stats json. + * + * @param {Object} config + * @returns {Promise} + */ + +function compile (config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) { + return reject(err) + } + if (stats.hasErrors()) { + stats.toJson().errors.forEach(err => { + console.error(err) + }) + reject(new Error(`Failed to compile with errors.`)) + return + } + if (env.isDebug && stats.hasWarnings()) { + stats.toJson().warnings.forEach(warning => { + console.warn(warning) + }) + } + resolve(stats.toJson({ modules: false })) + }) + }) +} + +/** + * find and remove empty style chunk caused by + * https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85 + * TODO remove when it's fixed + * + * @param {Object} stats + * @param {String} outDir + * @returns {Promise} + */ + +async function workaroundEmptyStyleChunk (stats, outDir) { + const styleChunk = stats.children[0].assets.find(a => { + return /styles\.\w{8}\.js$/.test(a.name) + }) + if (!styleChunk) return + const styleChunkPath = path.resolve(outDir, styleChunk.name) + const styleChunkContent = await fs.readFile(styleChunkPath, 'utf-8') + await fs.remove(styleChunkPath) + // prepend it to app.js. + // this is necessary for the webpack runtime to work properly. + const appChunk = stats.children[0].assets.find(a => { + return /app\.\w{8}\.js$/.test(a.name) + }) + const appChunkPath = path.resolve(outDir, appChunk.name) + const appChunkContent = await fs.readFile(appChunkPath, 'utf-8') + await fs.writeFile(appChunkPath, styleChunkContent + appChunkContent) +} \ No newline at end of file

&jG79ҝ'H5gjDM6Jv8ԝdu6)`֠vhᑗܦ$5&jhDr̶&dNg*|[ۅv102Y3X@PCe>{yhG" #䠲c]=^r-<{uOړG>͖ b1rm#@ :/R-[,Ys)~oDgxGZ:)ƻs~-P]@'= QuTZ>A1Th9`@Ǜ{9m닆^aĠ`Y,w>- E2)ΙQ]ôP@ L ۡL6V,aؕ̍5{1#j>)=- +Fӷ}dSC!jNlis}Pg$y7 b Th] [P`N84 +U*Y3WE!eBP_s43IWR=sM]DDOLy6NZgBY @yU=RY"d +n-7Q PݩV~/;A5c%A >m"&Z8vL&%0FM >yLS])^Jc_o8H!B*Qq)! x Heh-ml/N EֳL=lڵ\fZZ+ڔk7NiFmsdi6#!{-qčV_ITCY J&Ҥ}\NܥwVkkׇJXNna*p[aig~T\.3:XU `.\Bt@+ٴƝ{?y%lg6z`#wwXD +nuJ]DT:wD@Dxi YK'`}~8cpn%m A@GEMC*tVF {»Yb7 NE!Ί\JS%U0+([0X%MШS=?}}m1,R\Cvٲ;A@vZs)T*:R [2IŸϱ'{K`MqCgI`ΐw/S.q(_hvsjpV|Fīۺn1G6 Dh\)d;fD JQ!Q%c=?={aLj7@=gK 0 \eR$1j*> D T*_a%vޞZJ v>*E5'8Rf}. sΈ& #t.0pDwGPmJ*8ojH *mY5̜^Tq3NBHDSꪮmOS i fR=<]yΈ`[qKOtxN]H.1̵DC {)[8I'!~Gtos)Dqur8wď7wXoRÍ'6ú⶘*З2tE˒"FX\ײ{5E@&ˮ{0̈.\vr9#%b=B5"0 9LDHשpǹi[R VaɊp@ZRTķ!T= ;3?PPEu!`!0ﭷ t7'ٲڷ-uj'zP;iB +x*NozH!bEɹIFuOӏo->ל&M*(Iyg(W]$~>Qsv(-3X_Khm""Zo{]n˛=A*;j?vůJ#Ps"x@bz^V%TXd;_r5CP;cŨd<;P%8Xmyp a5&9_H5,1~Vd ϳ <{%-Aj" ?F!h\ +BҴe؄GB;lu#,T4#Hc$!&XeI{Q}`߯~-+{y{9d9?㼧p6)F<N(Ft_-m%ʀW_>oa0^b,X\ +yX`(eՄb'[fpJ>_@lKϻĨ** Gv [=im11.:٭eR8\G5kK^v^*qsǖz>/oФP Y#V(ϳ+bpz؈Z( 4@D7% V2 (3]\n1:'",)D /{AgIy ++fEQ9< rƤ}ppj)Z%?7L& GsS1<*b@:r5aAA͌k:C7ʄmW+2s}Vl+@ `t/\N[XOQ +RxxFΥyu[41Qs[@`weKIPC45s+H ezInkǎRIP;D7@6U&=]--Aɔ/V3P#xFG[ ߰u Ò&apM\'? _/b]$⵸K[n0S:xTA)o*h2MB|Dg_o*pj 'l/ o4š^?XN9 D( lj (h9U6鞰 &1g p='-EdwI8Rb3ΰ#8TuwEi;4ػ;PjQF{"b{)Um.W R~쐾E|Ye6XpS'mߔ{B)1jWɌQqpȩ jC:sٖ͂B(#e5j=@lCՈؔ/Kjr~o񐹅`K/@:%Þ 7V/ӓG8z>,pX`k(BxU]+` O̘ܺqt\a6BRN*¤ +݉X%jbCv¦мog9+82zOY_-Llj60A?iHޙə##JזPSGhmҍbF쇞D v&hJlͩbD[lfgx0\s*[3g"z2WPPa3({?<$g,-aW5쫯HKqf?6"wZ6~ö#'nC!P:Jk@L)kv[ npϟ0auig?zP]5>^_57v@NYՁܲY=Ԩa3O.:b +x*)k/ Z})HÚA GD> )ǒZUDО:|RxX|\Ͽ݋ŗ i:%[)B;￵e͟P*MhpחF%1J=j06?fpqcE7^FͿ1^Ƣ{=|g0'GG6CYy['WisJKvkb +.I%!t|Rݍ׬v%*K<kWU'E!Z[ ܰ޼+Y9[߉~c>%}Z|TH6`?Y]5ZoZsW#@Bߩ<;u?ӉR%؅bTH-mw XJqT!CmWČZmԁ֖=M2B#osI|N *w.N=(-" +*u.e7/"=͗#QQ%֎y+s)S_, O~COzEHnl;$eF_< 4>tr +ER*N$;Qw#m;`CI^rU]}ԡJPa VZpZ&ԻVbp{ȏMoެ(݅ˢENʇ+P!3zR0M"] T%d _=㿭^Kk&vfv V~o1ܡ'Q=y{> N-|xd4콅Q$SP! _CBC +ӏo^kn3T%otKw"J)@ܘAhTZqD"9S}nY9)`ThsAHZհ="?ݒjojA6;J~sr)M\gΔKJq#F&KY4JeBKTc]@l-Hrf0HwIc[ͮFּUj 青4 3F,F0!3vZruE^G|9u{ .~>t< 27.ޥ~42zO%bSq#C"klSH<(Ȃ79:$oyI>e +po>/1ol7Nio%𴘝R oofXNg(QlX;OH@ + 703-^JfFe8H 1ƒdm@qlF| .mra@V*:f))a5H;VM"3"g8o*~2n%G*veK_Xź?x uĻ"%4Ӈe30 x 2ց8Cc7@x`|l׳E:}I wfY:uEs;fA_;.S0,S6$JE=,9]5Lc8iԯ"ƑNdy&]jmsvlǢxv^Q;!AA%I/RD7S5 5_`i,M\ac +5_;yk' $ek_^%1 xU:~r-'Em}ǒ-Qe?O#"65QSR|f`{{[8H# R%*7}SObLIg Ӻzvl`ƳߴB_0<ԇԁ{hQ>PG@?#Ty]=fK v΃s$M SI>>ir*Օ$%J/ TaQc&RVf֪SyA8FFZdfxv0tFgIŮ ip{.`>t'Sy;k!L+q$tM0$D_"Bp W4K˥&0xb#x[Dq̜-A~zbFxCC'vUáZ;=f[JS[s0~Fy2״`)Gl] +CƏ P#/CB!5~AD#B=W= +̐M'>WY&qgy`ϙHn(ĕ(PB{j˯ߢC+58ŶBc p}xaJ[J0,DQ‘ہipytLƜ v AC_hU{$%l{I…Gڃ6!fmU^"QR{H+~ & 9/|CrVȌ +W1{]LM'SEX,ȣ\X}p@i4S̄rL"T赍E2aH c[k<"-ʣ01@ǃ,lNd(\]#K!E0sw3V^g 3}a;/©^KAizڳU*A&G9۴*V~Nq}_E\m.ϙ>;I'Iĥ˹Teo0!%d;#VLaDC]u +N.Cʸy/L~mU-El 3J¨6WC_;V뭡YrzĦ$m +;0,NEïQ;XEhQ:^"vusan~B|>Eѿ7',e)q&m°1[Ksӄ_SO?Je'0*ݖD㛻-1!̒NO_}_7şe40soEO%$/O~[M4 +e3>0wY2cfsa$]y[N5!Y U b>p#?ҧtc__}8Aܿ7}|W:hov>:{8,O{U7 }afn}3HJJUWVuMuWOOLcg|[,0X߷yYR%E2|2s;eGSZw߼}޿~y%~nj?=C̕7B}  m.sx?ˀ"$KgwPwHDCӇ:8 E$^~n<" v<@#d1B]d E&,hxAն=V{teLLE,jP"L'k{A߸g0)烉,2O>N҈b ^'6 O4&쳘0tr3B19 )-|QvB}tD35!0e3<.8/=0gIn1c σaZz@8Ɂtg :?x@`gȵexۧT]LXJӍΈt"\] ^jct͈ekD:I\ϠOڂ.䌈^]hj=?{s ?mZ!b+R6(={5ԣ`ثCuƂ ,õ]?XZXlpS95Ӧ04M6ѧ~&ܰ]}.V_~΂ O R+b{LHC/oߓ334ŘΈksgyO0sJwdv1}6@O#+-z ft{ӘCh̞SoZT~n晛\%>029x}KǰA=8S?sJ,hD&e1SL&ؘq7ֹf2 S#?6Qd\K>#ѹ.ek&LUMOWMc䷷ ?пδ/~,:xzU14Oແo.cD`/@s ̛ӆQ`xA0rTWHf6h=;ҋBoM[xoBZ!J cUg>41߿ظ|M,0UGP"~.qʴp$O8XwؿMDnq |_c|TEuQtgߛq  +*_f= +)ʡ0n1Ѣ9mR!lynڟ +&,|5C@W8#:RW{ +n<d5°a ?&5͖ՠeܚ7a k#"O0z`rZX;,zp5ʴUlMf:B{u1p)#H6?9naW2ZQ[L)ۛ/&1JW KgIl0f&Y{J+64#˼G#$U(,qm5jC841NwjP0UWuLbԿmihLFuɈaB,#lNSԻܑaAb;qW Aϙ||%WjxyoVZnrDDo%"bJۚsuX0'(d\0j̏;b-a}sf>b' pzAh)$̕-黆h0lU{eK=-zԨMynM,M?`7&b`\f~(K<f/bĩRIG hD"\qt#2&t7ƈ1jHQ3h C +CnQd>+㷇i^>4zfj:#Мc#Wh8McmrRILSxۃ^DeHێ;%RWC0-_@F&5&~@خJgA3]x|;}.G`T妡&!k&`9u,Y'AufQCn3KUw_r/!!?yL< n8\J1T5%1\M$p&|R] +8zV\c!+n+T@ɹFr``e?u#\JHEɘF0hjC$4N8TG΁+MNgHm=yʞд ΢h YyDǠ8wMv:->>St65fr?1f1-$t3#b44hJ +ZU"Lځn+իxQW>1fN<"byEEdF0oاޢ?m3Z$ 2i##Y _DG(Q3ӿ|XCDC\xł#z2cD;AwLO~7*!zED}&H4cnΑ!MkeM{a\=-)$=jPl(Y R(gspZ iT<ۆ~= C&@Lg ڪO)wB&Ӣ2a4Et mV #[XP46ua^ϱG666&26Z,2QOvk:0~9zDs7bjzD ywN/g4@u>sУ_<Tu# +87H]gfXSЙ޳hʊgQ>ч$D {pg莛9xs}WЎm#rf{Ol:i!VF1S#`½qUu\9@gmCe?oh eT~0e J?`(Чc5'i9׉ܘODm8#@?͉+塱zeDF p:3HEif9zmC3ADz<1z 8޼s>.?(o T"L؛HV<͢gKIMÞhP=52܃^ 8AATlqXk=۳nvB_`άg?>]D`xvڹ0P o,pj_Ft8iڰ"DS{ +,F4-SlFaaqHm[-ޗ˶U:vTc1U#/.3v =Όzig|q'.4qEP-t%+(ha}G$4k^ŅPYh=NgF'щڹn7O:tG1nEc.bb <}G`):Ǣz~jX_a4PD5 ?ȗr,ʋ@2 3%~rY߷Ť w 3^[SU{XˊtvC8c:s_/PG37MKֳcgmk rg?#T2XѶW<{ ⳷gasiԗ^Y7w.#ba@`y]aft[ȦMuӱd+Nx +dYADSjYhh +6Mqp qOiسgt\D|AmyJdR""V*dsq@ +L} *㘉럽`pPH )\*ԧ9ة%W +j^XjWO:/[T7fJ۔UĜŴRͽ6ÙJyzkIg5"0AL,#b)_gv 7(ҕx/U}Tl_-yTqU-,2aEĔ(u2P7NԨh=SsGt%R#6x)T3,Lu`hŋaaJ P-W+5Է[n]`c&YXmC;x6ė-?Xe,` H EugKDywX(&Ò<=5jJ}B pd0D,[&"j(`qx05!tW䩚J)RIIS,G0Lԕ\ GK(LɌGbӜ%Yb0KpJ$LӖ2C#GonY#PC2J^lSӧ{ +?bnK^Lt5,k *^y_zDZ4bۖыYe\rGiʚqcSbq?TDi|`?&Wk=j1,^\"L!?VܼX+z>yjMR^,KXEh Z#~X$Q%/fgum:kGʼ)P("%,R|*XWŘNu}t()|k6,#ϪD!WflZ> [o02ѸG"?`z8 Et;. X +F񋞉mXBz@ʄP3 zr;%ҩ$,\EEA%:l=!~!N3 <.H^3Qx@jXg< ~980OG|$h@aʔ@ÊxQnk܈ SU$;JY4Δg3kkBcq?G ?rޙ&X:;a),5lKQ*GZ+$}5 *C,]L2EJSLE1$>-MBG5ΑT#hs67fō"ᄘH fZ(CZҋ`3X8Ʒp(ObM?#o̔ ^Ab3·Ea:C CTn'T: AcV1f@xb0"̄ 9ez~!!oȭEdADe[X> yD,"Zhī8b˨lK)⥆rCܦ %;`{&klǢ~V(-&t\cԝp )x|DwY*¸Yz,nr *"[JC qPV@*!]'A04ukĊ@f]cH[֊D"bEā&VCÔ&QU,>\7h=T05:pZ6N$z:ez= TUo5Yp84T+.P4ÉHaq٠ջ`OV.Yۜ6 4<#Bʂ0&pWQ<+PFۦ&H*ݜ, 655j7H3%&;[Y"h*^;/uWQ]{t<D +:ewlY* Ll!Q +gYQVaK1sDtLSA\J-b=Dp6YgeDpKA--{̃Xsj7,Lq5M >R><8+T~pb1^bLtu u{vĩ%?!GM24r 6n$G:1@OOK4E9V0 Us̱g. )ü s@ +h D 06shZ$,YL< +/{CP/,R1 ֜P~lLH5 4LM|jxtZtm$E϶# peU8L ,@K&.Up> +1+S"B5eD:`LD\|L +S{c2͇Sby%5%Hn2&CԑyUCPLi>,*̘D )ʇ\:9/y7Q_-ǔahت=#k;T :l %j))?^iLy< #\]Ѳ$̱Hzѳ-UG͂t0.AX&y"R3oD(&GxIֳ-Z 4.x!B5T-H ? t.d6OEY8׳M*0Nɶ2p^-cop=K4gUGX9a|> ڎ#DYP#c1O823 "EFO1yE9/AQk +rMa62SӺJY@-zDkt DWNkq_n0B0Eay<Es ]$sͥ XFk,4_r+ܧzVo4|[,v N=p հSb0xGO]K3Uh"^-|El2͕ƾ/߁Q\\_! eRQ:] >:j@g jU(kTE[)`{MWsyZ-^ղtH$C@[1@E9$KU7 :abdsDj +r)m/[ⲪU)ցDWA_&SyuO7`Ϡ\z>5xZq1D \Q}L.42T, zkU%sW[RʘWl|e5#IT^h:X3,ԇ>G ȟt(( 1R[̕њAr;^S* t5Px$rbHLs|ҋkhHA\ Gճkn"D @a sT!H. +SZ3ErؿHtB"Bt9kL6u&7WC"aS3gڋ%\+{]#(O2*ڃsV7M'T#]HgZjFKwK)tĎ}O*CHܥQ:;ޘ&{Mu + ؜9+ BIWgs"]x6h-C/T4@*H^M1R=.~=Q8g.)XL{ sb,Sd!mN1“qc07%RjXVՄ)1f=l+A,SmKORxD$1Z"s'WB"tjˈ} 89jsf*z +^b7=s=8gSoDy`JO0Äi.詼6 8p#GDsgKz Чpxk•)ȏTCbz? ^RG7 /f>A9LcP^fZL\\ fzodA"Bz91\&5F̷}Dy\ d6^E|"N8CHF2#1YJDnnP}_q̴bW|Gy^S`2g&':mhH,`ӬgCZ/L1Q>Z5Z!QӇD @y#RB5ecHdjõ"FTⵘj4hM=Ik=W FeM?+ʘc='|clsC5+PcG)2/4KE-՞2|HJX#e(N~Em fyG3'EpJJ4 -Rk{nS0CM4RZ׉ &*xX6d2KjJbʄG1* g˔PAg0etÕy]DQNvNLy`MHq>RmQ1&hT ͷ KjKd`!6QJ%OUN[Z@" "z0iX@nDK5A5a':Ti,1f:\g؎BG=[D莌^3ӯ@x#Z$U2{rBt}{Ж&-ؙTG@#b:e+,E4KR jф*o+\%轼ؖԗZ!9خR(hJ>IlF[%4C̿`\G3=Ouٹ'nKXKdǷ7ݣ)W'ruDNWŔtpE,,Bܛ5c jQZY0kE =Wt +\XE">ڰ[u6a빻% NIߖ1k,Wl5#_eZK4jcf +Dʘ9UC:ܤJ$28!ҹ X Ёy]*unDB٢䛻TC#$YW0%4V=?7H}xT7IK/ L +$jCVB!,?Q\ xZ!VBF!*! Y5r`(d1F9kYKb3%Ő Lz"Bk_,._R>09RTrëO`~얈Am]R鶼綡,g E@oS@|5F%juH;~x QΖyELa|:PTA<4uSL))]4eAYL˃cOdw.,%;JjLr A1e<\m wr11=$P,VNmƫyDL˩-n׼gUgWsiUD0տBGg-Agg{x59cmiyz|;lo"iP{qbO|y:["7t}0'J1 sVQr5"鑺QC_?0Fz|~'#lˈn=DvefHdOHA+S*ZRDڙGtJh/A"B 𳞹+}% +Gx̒BK٩A pBk{:KH'x="E+ (^wG09>F/U$,MrKc(oCNӇ+`ō=EyxNݶypSj*ЅaQEZ-.sгd W5M${EpÈ + ?P\0Kp%G +F\.@BωnKalf"LiaeGՒ{p̍@}=.뢾@vdZr̿^^i JDX(en=8%|%0Mo|``f"$ևLJUWUUH$*`7U\QŸs%{S#X i\OΛBK . ӈ8Cy!Ň8 YNjhS &($J:n`Gs~y\Y+w>][ggGE0B &#!ȽDV"vض%8I<4O7e9 Gf** EE0_p ݭ?3 dX3[jĕXLXFA^IvF\UT +̹8EE7ЦeeL "EWWSD90zHe~f_4Eml~NTo6}gՃ0Y!g2Ij4 ł#i&( #Ңz3#*}|jfΝ ]%OwUD-3T?CY@i`a\dTM@֙̓,gG$hQ +K,gZe52t**jm;DލόLμY{'膸AۡOT"V1~1אRmOa5% +絍5oxa?۳e91OϑZ_?W;~o/^W?x݋!!}L)v_ ; Շ~Fh;tvaC]:k!貼c\q +T<6V $B]8{4 A 49Dp#,8SQ{.b"c )p Cqf!1<!V踆.>,ӛ26X-9Lf.Gh(31lN~d{x6!aI;^9rt !fOSV;'- 6hhUڬ[є#LOiV'*?yݿs|M jCO}_anrDue[8 jjf޻ +m~3|rn3\~mV?Ǖ|kS>`5)WȘ)An8ӔC{O[:bcRQx8S|! ofh*ňN4rӵ1{3 rܠL}7ܼw\3%lLG4S 6~\`|0ǙW+fGO=2%4 ؘ+BV*4s8h[|4fRg@ q]\ysfk y4ACs &!&e/0ܻD$=DC8%!4fK$ ۘtJVJ}$\Q[$u>{CncOT?CSу2 Bѫ/򳟽E۽ +g_߾Cǣ nu~.Bg yS_!8!&@B^?07>Z?qga #~l5Oqtgf6W=#/hݾw3Hv\0ɷY]V'wVysn<{#|S2j,?zCzwUAۿLy4z[&׺NOt,'aOWNrKuU},d[|'Y>oZT~6veDilCN'8U=Ul!^;*vmU>6O~ J.68Ԏcu֓)nCq'oqĝdjF*[=&͋l$Y>6;enu#|8|{[ewX-$o^􏾅/&R?ڋF8挣l<˵nҵtblXd~?߷ɔNhhI݅#li>wnS]'J,Y6)>XMllm"lt$]8ݐك]Ϣ|,nY\{%U;\"]:3kW}㴟se4}y^a g *d׉:AV2zUߦ:ze"1D~jߒsrP\lPfN +ot&ӼYeRUWt&ټ,<|_:QM'|eOdϢ-g;ʆ6~v|m\EY4aVI&ONw뿫:yi^[W!R=>r߷i=Onc}X' |}l-$+dRN uEQp+jǰ8|eA0nXt%Bn"M124:pR|އxq%VeˉXh~?Q>3e<ʚw2dtbzr. +'ټ.n/L9e<;P7핸vʅYc8 &@,f{OitLFa$߫|M|c7uZI:j_\>\8[n|~s=R:| 봷JGVdKl=tppn\o83(;'wIy>/Mޝ}שeqU~1ۼT$98ty-׀]NSh8[Lsdaongpq|X|{/oeQ?̏^8;2~nߔ۹/9fk_ūT=˄;Y4Vr\'Y< 'Z. {+H7 'e|wIO|oB`)"^ݰq!3L3GJVTuFasCKr ),K&qB|Qw߄ȨDq{\%˗NQg9UN; q`qjGG6M%vt($Bwo>*q.dvx2e+\tsF+߳%y/,4]߳H0Z:Cä +J$Q+u]{y0U:j"^>Y6vŃ|4lt"Q>.NsUm2<|oӦJGÏ9 p{:/d8^8ƲA ¤}{mn~rlԎH@?sߔuv%j'ݷv0z_6Os?o]zNvԽNv'+FmWeGvRunuFIm"Dhܕvi>;Wtz-fKv|.09ȖO&hq+ Pĝlp-+ֆݲ_ gj>[#۫fLV2Nit(kF׬ĝNhآ1:SimjONtY_ؕ:]H25km`f]yua.LRdi!LQ<z/cU+EX=[m:[7~+%s1H۩~~W!t~\ݎo"i |gvڨ_$']xyIqwֵݸ,lt/{_~hu-+wW|>k}D +{'gf f +tvޭu: +ѝDncu_6>}?.ziiCv.nov+gui\)h)]1\ (vDQgk0YPc҅\wL}_$KK;:o+>xkn#8! f=]YI -YsrakiAmdj[N7\w- _T_@[ʹ6>k݃]:'ҒшLu_g),;Lq4.`!_pak;7ul?ڴE +F'[I8NGvڻpnsЩEptvɦ;r(]{jg\˔@%x{/oZ. nym2;71jrE0NmG Ͽ}o:L>=a`m$mzf%R<́T:MW.Bfg3[TҕP9K`_Rrvc{z`8W6]"{o&V^Z]`pR-gA!σ*]>[m}Z\4D lL8u]6h~$\̠R/1h٠qOȴ73M{7r]|N{IYWA?_Iu$LQ.HZImuSP:X7!VҬ[;R&ߏ9{qa; g6/#VJG,p>\w"l(C=NR8gˬ¹]:Q-% +tPo)U[Iր/OOſ^7Ⅼ{zgIr{QՈ*F`#XOZ!x}2dɚQIfuXYu#m{U[2^zQ|]@Wk6\Z&`Yݻ{nuuݱٺؽ3ynzކXe|GïR04l~(]:K:P~|_wZJu{Uy^#}޻û5gq \.X+0RŃ-6W<9_l`g`wElR2Itw=W3u-_6Tt0Wk7`q \Z`-,~ \g9~n4H^h-vXV1X66Ͷ]toCpnT9!ጟD`:bt=[7#Ha-L'Fy4KOOi6ɇ~+/m6ac쀈/nӼUj5 'mꢾW_ՒgV֭wԠC@oMye7UzqCVghXau;ֿSt7FsjgJwuL"S;37ѺACຠx3/Åu>&Sv=0ɷ56\6 &،`7v= BOl\}o4vop-߬Elw7nӝ6vL&a*0y4Kǝ-& \[9kfl9l>nGѱ! r)XՓMf3d ^:˩X)LFv ֋ۛ ,reNwb^da߮E(l,ǸUO~ًpv𜘽0Y?W te-[i/#i%UeqփCu-< +lQ/Loj=d+V ow?,mfzvq#Tl/^:vwc)~wJcz۩Į6僃7[y`԰ֳRBSN+ym-7 n6 7{Dn +&rg+Guw|vh(׉q" +֮A~?XJ6bt{P- _E*\{P +Hcylg~6eɔvW -MM< hJ;Q*m8' tt?OYEk;.s_n؏B- +rW#l"ꎷRĨX[!&ܻj-qtT1M ؗY@F 8KFwVX:p lcl.*Vi\h JZI7W-qqZqnz4Ÿa5k>DlHO"j j۽I3P4/|dVXq)YNNݎAh4N% KO`u6J{NҨ͒&xrßka5A ۺ)ni< 4.Q;l~-@h]/sx{3qAzKF鿩:\|;ڤV(l.ۍ~z{ǧ#nqʸ d_eJ{k&*`V ; i/a(_. qw⹏& a 6nc/!馱Ifj}~/FAViYۅuuj/dhZ#zT laܲ;vl-A`=mpגP4S؉f/ KRxZ a R{yTmJ[[4¹FxհfWVJ"l)3eF4awpơ\ xiM h`NT6RT~;x㼻 _*Gkq6g8TVXM0.ŽMl([9gʡY?_Zg fo1ہ9Ezkfsըg+vԬh S; ;E88{/tvN^,.ef~)KRjE0Bk5U u4^yU۵Lo/%Q 3'ޝռ5@d5mUo9Qcs]Nr]嘳wa#h2?3fg3SZKX 1;&Jdyhld|B dõoj`w-NKlGrylZ8&Y#زz`(9:2|zf5VLaԆ5.$+Z +>׎J"ZS}AXDyvӬd\h8`cָȵCz~xR4_'Lq]NUAO[JPn(sU0ts=YMwH *t6QO#s |˗_u/T=UoTem1iX4)!6{K&EƝ&H3Кj'_'*G zvV(u&壈3IXaoݮQ9<3|(l +\!ňQ17Ѐ*fk+?:be*I ",HM| +k*wzAņz*dGN? [z}J/ rv" Zp "jNje9pKR9KA` Iq* ~Ô *l۪\܃eT- ,$W( ^;7d%jB/Vyashmf+zeGDaVlzjeC~i㪬 sZ9k[K-:0Z;O2Hl߶_o9{BclvNάo|"5Ճb#;|耖^< | 6;~_nQ8k0]ĝmWUYN( :]Gk 8jό9Lu?Q5sۈ{ER8 ;Ob4lwhꂼ07M f>4d8?L+B-4l0M` Nr-}"zRj׬muW}[GOQ2]ywGʖ N+,GӐؕhe#0@V3Ո=ȕObT3JvrI;+_/f!^W˹8xnL+삼EM{p i^ܽJ6F_l! KI&{O\\G[F]~p-0?"ÉZ̀\VWd$1wo)_L3BG~u?MnaR|Cqe}uTl80^+wWuVAv.`8.05aJSը뇌B&l"V*pU,=JH4NO'hZafhΪ-m_,'C2jt w6.mʱ<^Oo`'Fܧ<2pPx9t̀#jG;Il={D[d7tX_Fުх5X(U۽^#P 5d/ Jt'8Sn:>ׂmC_.h}PA4@ci:i&vҝDK +PISVGZ_&#Mcϰ]ns7;🮐B9j֚Bi;+0S8(v/LPha?]?!]0$AՓ,ZNW=.ˋ'`u|:( g  ŝ7T,khŦIgۮ5p@68R±Y2K0>Ty9Y $pj"\px&Z@ßmۋR,gqgb*<L~ ҥS^6*,9 ;KkЄ@3pF_W }>K ,c~=pF\ g!q2`P@voUB2sD06 - @ܚ,Hl dpa dB3b; + ~- lTX ;OPz,zX 5x ,X]=r X3*DR$>l:b$n`ZL3Acvxap ܈.ƙ36359 &6oN54:s尨0Z*4D&:oe ZWWXBp[)иޝwmOrJ2 $QCK4xZ l;ka P@U΢ -] )`9OwHȌڙj*"2J"ib?r4(GD32]wXJ鈁^y" +2{=lv ēI# z wH A ⭧jvlpX {6r}Fa*2$K$*Pk**crTTˆ'3#3F0(دu yFZac1=)Jh\3g>#Sx +a2P}BzS'DF[Xy4s@ +PqN>O* +,:`܀{" *zf_0B^.\I5U+״M+Z"KhYMhb +xgvGfo]1/fₕ/[DfoQLɓsMj`rF671)V<*TgYOeԈOP62̖ΔJl=8'oAt.R?z}f^Mlؼ2@D_p'Ĕ 4r" W<8G=u9$h5IB]{OZ}5$ȸ#ؐ;7dH: +AaB+\p |Y|5wz4`tFTW%#m0'~˱ۙjH8w>ƓbBlãQD0ⲯv(߫M!SJKΡvetKeHJaZL,||&VXy- l 4ЩI2qp!33jEJ$hebYwV5%zsʲݟ2dEZhI&ơ@Y7,NY"겉q&9 =S@D396h) aWr{jeB84nM\ёNn8$4hP8*:l\@u֕7`4`y" bVښ?^9Kp-̳< +s٩ՕDqda:l p3]vLZJ`bmy]6-,`} Xm_(ۮLwNvBޓA#=Gh| ~U ZY0iOΗ@q5vHNlC(o=eun9,X3:b.h$,ҝ6@>50Qe|#2Dp<9~4ѱbo+SSIƥKp+9+Ɲvw&WAXFx WSǓb͙[PS!'CzTzNlo{+T<Y[<MX:0B~FIoOUΤgVV"B NB +!Hgg/&1uHi.Q_@찍&&vhO0YqtsKO ǜe<9˕Wd4D@_ CBKWhIɺX'Ѯ?b cL]pxabiKtgejt==~zݘ~/kX]cWrStj>v5wþ_NMno7}qӫgG-,3C&j鱭{Gfю_66 ]XM-zt`DPBB-<̴n1mqyxA螶GɕfS$Qur+:3L:\sCfƏOڃmܼ73qw;jD9X_5 bK_?U6!\{.[lW^K:+}:"$yFrLy̕Y2b0*` +sfn/U~rF+3H.no  +Vui ,=lnԝoxjXؙ;ҏ*LBw©Gw6|8z?|`u#PZ>; +z+gLL*P^tflyuozv`gtVCK[1 :BqALF +مwlr:=qcqf:̀-j A!3W+v]*T +'‚.t|PQ,M H%Ӱ<9B'Ԙ&qEvt%zgpwd{4w:?s +myhƄ:VkQu +ud7C}ew {mj{(t&Vba8mYW+Z*X] "kmܥ"Ïyx} H@Z +endstream endobj 106 0 obj <>stream +?K"frwB58!RVAű€6:PBi)5y"?{~}|Jz/|vlg}ƪ 72&@]ںOHkJ{{d}*d=)beT+ʪHQEDdp4;ÃJ ]l9 +xJCD% ;ؤH 6]h'Z 't@}bXyLG{(`nVl_ܬ/].Lںy |{`yv|t$e#ŝRQ#ig T.z@޾2s>Z>W8n j(S "\95jqY\\(6;ZO`t*=,x!=q10 kXZ7ՑQ-I46s'@cQ,ֽ9ěcr;mrǘ͛3z*eh}0q +b +rǂL)*]#=;fg U֝ǃcd wnVGl\[\R r&w`H>O >%nr@dD۷=t jZԌ(j @=?]ov_;6M͹?sXF"_503Whlj_Yytq(Y|):vlmq XH?Χ\'^Â9<?^?Q3dآ4>X_4eArMȈQ<9vEQ_,PU*Q22gT&3ha;u4wT+1Z<ݗ^o}/~*;i ;[5N+$\3[;C\ܸpw=׏~>ybnl:sI=!b +U &$Rngviz3g}'z@Jr+eF9.T +$k?H+kG[[Z{±s>oOtozurݟjʹ̼ DeLt8Jb6/SG8s;|~z\.q2,*LW\=Yi:s#|>՟}ʷ ǒYH$̤6c|h]}G}񁧟|~^{W~η{8wXaMN3H + p$:H4sͅCg33O?|٫՟|???/Gb8xL8 +eWFtay0&mqU>#tkuKlv>з8~4}"Bٽ1J4&g;{>˯??G|Oū?~`n\< +2Ct]:ug/cO/=Ok?śo_xy?ϝ'y3&Υr+{o+O r=B fcҊ %K#sϣ߾gz7}/?gy_/m_gL-a&G't^lN,n=}[w^}ǟ>y_3CF*3G .ě8(Ds#w>ՇyO_ooGw?gꉋl r r}T,Jǒ.=>?>o}ͷ?~'~烏zZDM#E +7TJU˝ʱ3੾+{?_?#˯ؓ=v|55yة ?~OLJ|}/^cve-\h2 m,Lp'B!_\ܾ|އ3Ͻww_y?_`8?x_}WN;Gb7S兕;/]xG?z'?ٛo~ɧǟ/Obuۛl %l0[,:q౓[ۇyƫ?307?|?}G|K~{Y3&[rI C(/C=w߿ǿ⋿^ 7^^;q+T1akpJ7765uģO>xW|<׿_|?xgw.1Q!.!Hyz~o=?ͻx?sP֏?|ǿ%ϯ}Zo_! +Wer!\ C([9}zk/Wpws/;VfbJ;_2dwry;3>{3zKWϞ9w<]J2NZ=jdTiL X:QV[N{es}ysuj{{+.qλ1= p.KP_Qmʂ!t[/n'|sÏ?g gZ3SL(VRaI:xpgOt^Zyⶋ.]t?/~yl89+z%Bj͸"-dTܚή<FuJas$H 9X3<^ gY1iصpP("2iZ?hp쑨fh$ވYCt>91"㠎:_ 0a=9j qo쮠 n_q/bp8OY. GFKd@j6fwk4 p"I8o+fɨ ťf#ˆ#n- #*dHa$W'Y{)6"B&|ʑ[L]/ ^1.'/`Ha}@g@7K@zqtyӼ +Df͉႗'RFsݞxܑH CZ'w+]JLba\!WPcsN#Ut:Xo/]Mpz&3rCe|19N7 )L.¡7 E"P8sلϲB Ffh UWu>iTh.3s0xaru+5!ws6o'QظA%y%5e@Gj "blq%,Tta:Xs3i@JYUYH4V. /+jYQ~OQ~H>]F`v GԈP! ,3=bF7 b)@)n>zAѠٝ“*O(-/JTn)3N[! L쀖ג;[%舞} +Xbp=FjM^#`&|wmL$^H%A k[ue ؾkolB-/xcwH[ -N,d\B ךZ#Ä__fSY]Wѓκ5~@CM2Bv o눘3sFgdVr]ѕY4@#&Y{f~F2XBՎpcx6W +LXԷoĠF%H̛YimGclZtފS1bA3i$8rT %U+ʹK(_5{a&3'G :n?798ΚC [0K+oU[N&&|z܃Jg72GT%!g<{wgu WʈUHD\H-L@θٛwe+nbrhhN/|UO!:'/HQg& n1b c֯޾(x +94+vo˘ +ZWځɄədENZvN.X=39'a"y=GmfvT1HwI{ЀX=ņtt O}Z:,dģ\'52[=o[n6szM G\Bv`6rͻW2:V0 ̖" 6:Bg=V5 |@E=F#sLzN )W1zMZ)*\byq0aH8"xӯ$h(9$/8*vHʓ|ӌXRjo3 5W kJM!6_ X!5F{ q-!SFoA犓Buf;TQaĄF'}U4ǎ`\~06qWS>o|fieU[b,v Θ?\PA,@jTds>j(~-#ԑ 1 +إ]'1aLЈ!ꉸ+ (pG%[v]ВzV:t⊻żi휕`ޥqF2rz2jm,A=5AI- +ՙd8rg0jȯAZRjcG^3R *Gm +Dl4hɓђQ3amg'>Ɲsw$ +EkJ4OIka6NQQ`M(=q%tgIy wSsWϟ(w% $tȔ;6/d6!jvuAcN8=`([Wńf LqYA ƀ +շ\ŶcJtX(>`$ ħ 2l# >OGDi2ShhDG }L&_\c] l$Ew\]9t6_>,DoK-JM c&g0_yӭ 7FL &Tqq3 }ih CXO>^Y:<mds`wGA-8rb@(&taYmfM=ʯ)捥; wzΉgJ,ܞ!-ڜ]rx4,l5A:@~S*6ln'N76z 7y)4h-wCݝMr gcʙs\fD`6b"L2[b΀UT`)% $GC;Xٜ)#<Z5,E͸_[X kTfT`Cm Ytff`sXYuΩ6K]dHUxvPu8{tv'ݍXcEEML8o9TYKuz=R@ngx(31nk +4j r۷nÓ*v@Kڨ[л@ G-^UbC ! D-wb:P^|kiu2X7:#̫t@+R]\:0JTL +W`k1Pmé^sȢ =LlL`<_=yΧ'oc+$&"ZRo_6Uh4 jzOJL[@MX [ɠ`P(P%piK Q+]\7k*QUbmȝ8Pgl{hhy\qj0JlհWG"KjۧB xj:fu`__aeE= H&2$vGmٓXDۉvU&Q4X.H@[$BA[ۯ".)+S`R3WYxT RZ4jR +{Zwfˆ l`vwЗt%g\l2Dj@P T 휮{UQGJ@go3rQzFEl|]oS# HUȭ}*5sz"E#;hca pf@u8*GlqgsXwgAnf$QRGab&oo2 6D:b߯w#b VZAΞ-whj9͘ 3P #„m,^V1`- gn6$6VƐ@ [e7WgVB49pa~yg?}ètw~{_V J"fj\v97~9Kcz I22N@ƨ"6jw8Yl6.TMΤ.͕ϛ⋕bv9w|FM4(^~yp]r\!o =V߈  dt@lsɣm^~l>}l<l!,Alch ,] +; œѡ~_5jr & +#hg"FD%uovқ9=G{>q̴Z4g,P@{C8 ;It(m_֨FV{3=sF/{Qy>< A@ ć\/1hrb<"((OEB E=bCO8i0FNKxIdnfx>\Kgׯ&n.)'ƖOr3 '5L*|qe?j!BO Xm4 +kXcgl>悕\vyO5a/㩑Cfꘁ*"W{'LAh0&unAaR,O/`ٯ c;^.o}VS>A'"D.1GWFibK.7s'|+ bS Jq)v[IJҋ|r1PZ=x|Pmd={]V}A$4ցa'Exf;eRj_ Zi7dC=xra2PP*K3 +iFwImh>X!6Lx} +/yȬyX(R_wIXgά]~ WH%2T"0q̉XӉ. x̘l;xDv~'c# V 8;BaTj8bb&?Zڙܺ2{g䭕{˗M6RyHlC`~3FoЎzoDK<Vm4@'P:脓ٹjp_-pX u5=ˆG|)r~cHW mTƷOAr@a0_;;w^z:>yY QQVXB Z賑FHy<ܔ*+ɅsdCC\j1^_?s㭝`}rł{4F"Cl|֭>`/NsN Gm+EG@Ew6DŽvqk՟rrE44Rz"XK@d"#' 4zrvk8~wЌ$ &oD#ﴐV7d(n4ƫՉBr$?:u=\I(4jcJxm;ICqn&*u/'ԊIJ>QnGR %8^;k%AˊX&T *õ;?Y,XVra4hL.Z6b}v~^wǠ :N#TGk]x&vW/uh4 #ŴFӑ73#vI' "QDa2StoCC]&<Ȗ#Fd4#% 9ӧzl1x;xQĎ $cZH&s6, E*;ڎӲjzTHfmX^gsYT]Z5rA*&7ƿE;؄㝖;@g@[n+riM-Ab)T3-޿#Xʣb + cf>We=\f:l5y:IկJ[6 di +BC A eTmfwl8 _u[c1w)F :7eFM^ANL_=tjdurm:QCĴ`+3v*aAe.Y=+N `ڰ$l;p?2}rL40&B`nP 7Kc'mlL(qʥZج g 8CuEmBp:J(5ࠁ1xhՎһX/If&/V.ťlP*T̷׮Al~-aem!/$lb!2 +!1aE䷏}COu:ɫ0r#B(=Z0 *,1B33rr'׿n* RnMN񙃇|2&fVX#}nMgG$P>Ņ*ŕ#rMscՙtc.<H@qM-gFNo=ZޘTa-cf"뢋ƃ$TRF.z"#6UDnZz慝f&vO\/dc2,C|PSVXPm +@ \rp,\? +B89|m"6^:4s&W_7<|̯hS&ѭb`"Q'E$;<ZZל<ٚ=E\ +:mjRtUf +~+kF^t7.3$ FkIXmzkuϱEP5S3k>ѯ>f W[ Jd쾒❃^=QvXvT,Ya0&N=79/htv_X(~[.aGlNϟ|jS'Q)N9PZ24p!Vgxt[Gzu9:>; Cs;Ѻe_(fZtqz3Zi0&BBrONf"CZS5* Gpmx`%#=/U6:ᔾ5$c^K[Jny 7vfl[JObjML2i<8N62J ;2̀;`jfo]"ljOK=v⨅GJ#CLm&&,RhWC*b k%1 &cz'S."j}fU<VKt$gdž׮͜|va+gNfC 2C{6TR&r^B#z+q T3E91g0Oz Ni!R &FDNZԢRm._8}gu"Jp 7|L n̶S?YH8?>mP. "Jڈ?:Nfu^ I2ڈ /6olݩ +ɉpzj˧z,WcC[&_L8>fvl L+3ّSN?s #[`F*ٱ̀D@̅`qKUhA yP-&,Fs64,ذVK7!K 'v@a>R_WP85wcz㼍l6 ˊḙtm)%49?k@/2b^>Zyw~PZ 6dRGǯU]aS͙wN?fka[뗃y!efoE6ħÛPNnC\f.E'|j V@ WN:s5<Y*,OTȎ߈66DNPJ$g4^AX7vA,faN:r,H@hӎ'}BJM5.džrȊbjyuƉo,=V䐛 b|b-9/T7Bt?&G,HQ {CA5!@v*\Fܓ.7{VM_ d|umK(񚇎'Br-vY.^}T:j$ ޠɑv?l"\ڭG@;:uWߑF,&B~W<ʡAdB:6-VB9~"1yL @Cu0BzsorԸ If޿vm",7@%#:H|7G Ov;A4Bowڭ^)]:Yd!-"fHjd;>lR-7Ξ8̭?,Mm ˯^왗km::.-z{ܼ+UnDj$1Ԝ,CFr|vrK Mo^, o7 +4si=K9#WbJQl"q+WiRa)`ZNː7T$9-Z[ۺ;}p%@k@5wtPswí25AF2D`jUX#6,w 0>X bL%Ll 951 sՋw޼̛ע9>0AWrBl`|:\MזB>;upe0EE=ts6ڴ+v4[4/K./&~vY/n KR5H㯎X]2Dg0xJ ټkϾ闊n:Ӝ<1S6W&|v :١G]$*7||KmXnNOn:;15=J&,Ѱ[#W򓻥V<ǚӻO\ljaxG+xvbT e: jVm^{kfnm҉/{o06KVLJOo9yLM`Q~!=qq~s6ߨmo^OD'Vz3#bS6zsn6V/ʥK/\Nom?^;|eEO `f'&kRl(ԬBmDQN* X]+J# "&ĕa& ȫÀ \HgwQ)[8جM\ +dDFLv7Ҭ:\Pң3cW萇Y Gts\m#F8uUEN6G.O˹9sBTڨREak>.ce ݝfB[^S';=fʍ 7h`f8j58> }gcVbh(Rb$^N vbz +hm19JDDTbT畭h6@1I X:17#8mm?}ƃĉ/LySfWx]I  0\4}2!>*x=Ykgol!BzOŕ^J6VS&fJqvwo~~W>jÏ>ѽ>ˋJiEۭ[Wߝ8WR9fupPU\\Ƥ|usqJ-sQ1?M&F@􇆋gοsR"%G|fqlui!f%.&g+rJ zRu^B!\ղp*9揎/z XEp%P5P86l@`׌X+T[>@ +iRLClzi|\|C}&DQg,d׹D6vԀuXA_N&`)2bj$9j#T5RljVɌI&>!$#picL0c\vA|Kd4y'd<D5@FQK gU;tӆZS;ǯ'2c[VR)4P%ém_j BHi\C|F=|K`y獹L&-Hh~pA$1Ĕ$͌sndS7!ZäX8kPp॒}{PG=aw[y+'F:TEd[r &ޢ"#PH f`>tU VUH +"a.0!K LB 8>3X;]G\]&?`aCTcs  ռI6.V7q0z|z;{wM&fB͓[WމT"ֳϽww]R`kLmLm>{;7ȵ6^ňʄȎ;5񩙳_KV8?J)\WneJ/Y6[{4z;QGL1+iN"(Ç tuWT^p"s`*DXՆ)V~թّUOqbbjt>܂nBSېA9Arx</xkNq\H{jcuF0EFJ~F-"H(bE[ܜ$"499_m..S3FIqdyv.m"3IT BF =BB#u'JSkk#bA?9%l4!l^9#>+H%T/a2HԠC!6'&ULF/դ$F BqA#4:;ɧzmv8A Tt2ze:T "&eX59arZeDMGPt]AB>?xtv 5xxe 2x[02g0Ed Yז993%QBj$A]9h 3.!PZFܫX>^RRNˡ'(`7زLEIT*b'D^?1)h{ }&C5֐^BrCXf…@Bdd c I9p1?CXNp^ +f6,0`:^frOuz #bxMv Km>XzMy:3no +\ *J97}#ƧzG&ׂXqZR~ˆ:ܐÁl mMuOٜtIsZ>- x~+dp1^*Wٱ#fc(FV#Y? +x0mrͦ -ZJP>DvB4&7kF ۯz(O֍ZT'1Z#9 F$Wz٭G|Gzͽ.ф%Ƅ[bG3KK@~A#C`z>ÇnO͞8u&A jN7 +IpRNhp].&P<>8?)MjK9TȂ#3:'uF|Єv:tv;M~Wd@nIfۧllBjh_sy> _zȷz͔çCBHFzw|2ɦ`,ds8$Anj:{ +Cp6 +Ƿ.J4B@B}rd,vO]ï察9myFT0틠D4xTBEc`$iWs@G5hf0qt09{;D0H2-7=t΁(A @+aDKqB +SNJZ߆phGF~:YV2A+.QY d B&퀅dRXj({pi6e`~Fvw49wyP}n;PP$EetJfwvObuxAWJ)%6Ǩ@:ot`7,[|jhe7KRp,`AgA!x^=QNslI6Adp P148=FVHXQo*"6ڸ~vkBx G~QsZ=h&W + ۽BZPkrCOX;\V7#I-*0rjvu1+>Jb +I<:8tQ"Hg"zPz1hJk8N' -PP"9a6@Jw|`LV+yQQ]|s)$ʸH>%D\:;aXد A܈!L\dgSP8ċb ӄ`sK4Ttzy Ƃ6hq.d9V[UY*Fҥӣw'D$P(o=jR67k2B>dtDUC2ŝN/4Ka~ð@.JVJ|1 +q!K3'Fyik&sGϞ|/۽qe{nLFvP#b2V3x=0V ̍"wv ޚtOw앻'w6%Yf72 "{ T#<n.޸}qεW=ڹST**K4v-.ψqG3 6T.4r j1Y.fx"}̡c~ŎnB8"q(9=ݯ_?]}~W?y껏{w?Ͽ}'{v&`2A2%h:l+ zda+ryУS/ߞx|~.2hpJ!( aq<`/7{ޕ_~v|3/Y<a@\X P]nṊoKTbm*vDW_|NnM`6:쇎tL*P!Mdi8ޝ rw㕇gK__QEf'ڋ;wX +;aNp+Vk9S:3?w>͏_z&?ꣽ_zio%d(C,)Pnm'o~{wMO?'׏˫}>7~{[Z*&4{1J0 +$"S x*?zϯ~xo-gN-6 ~*e*XA&3imo.ryE{z?/՗.^ܫLWE.P6M +`b1(r[ wvJ>Zo~pO_>Ͽz߽vGsR uDf,F5bg)ep>w[߿}_>?ҿï?ݗ޾74䃳QnKU*q|,6-ܧLj;[.>8ۼ{د?^#{ӯ]i_\H,Ę3Fu(#mk'\dj~իXxdpB93G ,CqvN)RHj^\SJafe(7=7zKly\;h'|wUyx""DեD%6? M 9`&gB/I}؟_K㕄(HЍpaˇF,Áŵ쳧*yk_=wc:,luF+hvN>RD3:2qqwnU+O_:^~|r&.T͂;÷O|}x珖>7`\rV^2ft0*%#Xw'q|+ܣkˋXXS@V`&7|YetY# $QnȩBN{o0a1H2a(wr&H?ҥD9`8 Dԗx%" B%(VˣǻQ)^h59)yH PLZW׊C%f2 i,R&0@#}'m>;P7J*4WܥoZ>=UI +D)%TT + K4<~C@/ZKp!))`@IpzX "J|AY`cM\ #\61|v7efH +ˡO|†1CX& ͵SQ-&,%PH{&hF{L}R᠖hb5-WV[b\&3;--F r&7*tDBk1@wypÛ{ CTPd)܇Q!alhGbٱdf³3+g/PwfjH2vM BA3:.W\Rx}O9f6:U!?VWSm!7k 6.xXLL%.W;[<ÜLN)llJG䠍ظ ?ypϭDTX1ݯs^ +!GsJPH$h챧 \v)09pRyjƧ!0|ZCNQ`)ϥ6>k&3εNo]y#6@yBr5 Svxpn4֡ZsP%D$lL矗bM_Ԏ2 }i8= M7΄Ҟ\TNL^<"5L s6%tBHlQa?g_(o?=;k{O梭XI#tW(|n2ukkè&9'ѻڑ̥;6u] +LnqOjK4qR\j\:L/,_hƜ*'bǖ}1{%JT +IXzS}CҲ5s3R/6 6Ku36'.Z¾TjLJeaE'd',>_*J4 dsPuigjyoD"cuFHފir'|^? q&cCvA{_8&LncICzN6̥g_brͅPWba/;|%rȁYrPd)ķʅ~Fɪ8~Od_IGR=<;v^23z_˃˛F&Oz~S=V8Y{_)E[n6(|Hmk OgF/La2){T{F#{wR4z@, X=!ru[7_.|[9s;XfL կnX*SMS}KqOwN_gNuwPXT#4B!\{??mqì:k1c B;%e率![~܉K=7)>0q򗷡m*M:{N^hi~*G0xf4wnO򑏫J/T{w)`4{ׅrTpQ1W:sU+:;< bq9ڞ3cڋ۹ѫA"Xs%s3ގIl~ڽt"IL:M@,n+kO\*@ZGa+սϿCeoTlw+;gV=pYW2wLT"r[?~{^l>2b~֎׍÷2Ey:*7쀰1לOu2;ߔ}gFi1X92Og_={_{/,8<+M? CDDnXjӦba{88}K&(yp7~2yPR$}4{'̚ӷ7ʋVRb xf0wz]؍ȵ.&AQv?aSz?ռ̴Cb7zSmVߛVAn4{ƽT\+3\8j/T9`3XFpmq~EyTj^_N=j}U;|_=Dڻo{ycJr~tս[H +2ϗܸ/֬F{v'Ѻ@;^b)@qЦ9+t= +GdFȢ:qx /~m 3ȗ|TT7 X"3TSe*88yGhç{y7ϔ>k/Z_lP`Es[{?t/0 3rT ǓG!Tym> `mR珿}ɣ_w^˹zwC:?_@9W9GauNoPv{bai{_ѯ2Ӌ׿]~ZCwG|]~7㳟BEè6 OgO2朰vL/TwqlԞ@ӽTۗ~C^znc{3k}[x7A+]2{+U iv˯֑PaԎ"+سO~)w=p~q f4^<Ԏ[NjK5A:9<>}eM^ `9dtLd:<TvWG~p˙-rDfFdb2ոx:"ց.)-0>L*-Z\.F?Hd8/ikdf`tPnD8Vumu I57p=4;;xkH덃awfw㟐i/t!_昷ιݿ >"2Y'zT$k6Ty Oy`Ku5%e{7oRn]hᅐFoo"rt~n T+rUEҝPi>= in+ D3p);ي*gMZXn䍘fkVii'E H]HƉ#|yqftnjB vDj&q2n0qb1{NB'ѿT[R3c/cى4)_;"6-S!~*;/=Y#\ Zz";x +fɎIl$4ByT2jύϥ xIu)jgzgף߷O[HVs&~V?o=>'m\i3 nH_ NLUl.yյ磲ry^&=6:tSEp"6Xtpx~[2Uؚ>\M<:Q[?Miw_;JuP$kpv2;xo!{&Bqn=K=Q~P:>G!nVwS-?qDn3Z8\| +D-ny4:zr"w6b( }ɬR7v<63{W77ћnz+YH~aNR@Ujf5Dݠ<@f'Zڼd 0,R ɌeO,I Yr/5xe 0go[g?;yABdکV\ $aASPAJ- ̈́ ,hj#~LY<hgTAw/b5G+@M}=~nʣ}FEz暑,mFZa!3pcvRyO"tnp^\ %;g B "Le+y& UΞJ]a|y=bL9=T(xzZ1p[|aD=~uX DvK_ߓd9j7$Tb5 xЩufW/_?aJ(-s.Ɓ:Jٻ:Wwхs/Ti+L_|qs;ifc2]"{zRFTA2,䦟GBT( ۩t+mDՈpۗgT8kpzG[ڊgtj߁x7T0@KG%bb0iD1QRw#rٟMD2~۳ѷݣRӏ}Z,Q\h|)JS4'Zgtm'bh;$4ik[ =ti2j +0YSf}eiMP0F:.)M[ooz MRj}\ *S+3p[s?nS4υΧ]20`1; 3F6tO#b%ab/t ˋIP_pd~#Tv f Gfу#._飯}]>P4_وid9$ɳ_^*]f1eF|~I\JӸ 5p:}!H>ΌUw5L Yێ譭zT؈Ԭ²L,@F$œхCrOi3ꈧ{fsKAloVHhqHl-GS+!!]r㶟B `ͬΓypĘRmP)n/h΄QIk/D3* vdփ`Ƕ}-ZK<A-GzXe$ c1.J_qMݣb8c,Uie9o"*n{ucZ<>RhމH(cȰZz9(`M^QN\cb%I-B۔~Y}3/[E+͕OikifL%-i8QM.vwޔH{JۍR ژh~[v>Ocrs9N,Տ-z/xL 7*\v'%;KAMC4&ULj}hg2M9v:ko'Lv7.VBO7$nqqiVw?ٿ=Xڻ#Cf*B47nr+W07lNr]Mh%Rkm3 nD-SCL+(PØ~f\ ? V<*UUt!iM@p /,dT_d:O&ꦼЪlkQv ('=1%ct;j(}+7XqqVl6.I j;ox.*x{H̰*mF ))moZҘ6ٱ/Y)yI05%6LnPD9-LH.„׏]AlȍP!X^v+3#0kQy=l@Lz!!*T%/͙#L.]s}`[!vOzphq?=h)Q0Sxl׈%WTYGѴ1| +{͌©! ,⩄Oսoava{qBqx+{$FHeuT*`*cOqp0ft-UtIOe޹*G>Ӹ vy{/ʥ+CRBfΧ'O[Cu9O<%B.p/' + r(BHU ó\u/pԧk}|d4 [xT>?yy ][,Md\ܙ6X:)H)l2 "bk+VBAo>/-u&/ק!M$LnGC\{v^:LP!+$!Rs`\{wBuO|:`ZqlvBrn,YC@r/aBĔVN5d/@F\ 3;2Ԧne7:7AWB\)۹켮o?* h+& =7Ox`\<`1o8= os 8_]wb+.T>b+ )4e60+@Qpƒ26?_Ot%7]*g[~u²0O6C#BKx@Tgt ͸~7K-t>E͠Hz/?]ât-V`p}N7J+5uV>̞Tw^(ÈԈ>Hս`AœO}θbS|MmZ*90%لލ-` +lv<9~_y7"D" #ѻ AVcxUD-]EN]soBM&l/U睓or*NDlŦ; ťZp-İ6_:m=EX +a1.jcx෣{?/#Z|,; 'Mhm:,I'anyHŬ>\w<erOڇtͅ~R P9Wĕ~B Rsq +a`9.g7QVfּH$V>6Zr8ԏiQ2æV)R曧FHoOd&>S0v2Ɣd*BHbsԏ7$7ìYV'o{ CbQnX={{c#n{؅YcDŽŞ|4ŒIZ4vm2GR5O҆ 2e0n1X\p !f"erq{jjpf+kUZQpu!fq'D< uЇkS"3 +`f͛,.E؉Ik]. KQu&0~~qkQ WIdƱOwK'Zi .!;AɁ9%]&aTɁeʐ"<_Ҏ0\ R# SL,5p*0U+MT[ rPTvg.,sI8xy5gTqiF>|mz)J[k4#T90]{Lم CF/6 +ЮQ>eּ#Pr k?ZGW +2Y8HWe9KŶkw  MD(wS;P3V8)0eљ>lvDd3ׂ"qOhݸ\Z|>݀!UN]G_O&T\EoUTu6RnXs0~bjԐ+_,.81mTOxj/R,&om7<oԸQ3L5] +W,Im+wZT#ֈoJLv,.+`Js5,9Q IWO$h"d{!f9\Į\:i|N^-vQtK˒Hj{X{׉w\fTEn*M;R8$4?iyPkJ/rDiD56,#$؊^zYwyK/`JI}{=bir۳%'eAb*QƲ77O +@kV4㌩]ub-72b +S%`xÛ׿Gk'N1Uጋ^\[lLd#tz3@]ŀ\B\eɥä9cTmyif+z<|ͳXkg{)|Xo+ّ3w}kƔ>iL/p]t*"6-?|9DIdN)csgMdo"*ЄQ4cX(&l~xbv5; sQ=AHHjTF Mp3K~TraߛBl,|P҇*a&"dt~y9ojYD@@ӥt' ּT*GQx7&Ë%<*@ Pk G[ %" 1I-;ز_^fP9q&^\N殇B٢މ5ԓȺ̲OE-{ť.uˉ/,.6w6cisЏS1e +Fρۛ$ kx#?{%\#3m9Pe} c@^jPq0|u%h+qC#b-;BH$ ʨ Dc@!݊q!zQBJݤ>&Iut OfVD-q@-'] ?i""QsEf, n>fP3! f!(g1 X̍_˕♔}_N_I.)`]gsJyw9 .9p1kk#xɕ;ŝxn4R~}-ͭH0`Cuhrx1;L`VL>1m+a Lr5 m|~&  V2x:nh%ꗼDHuL뮸q)u6POP—Ohj4 +ek}(D}?[w'AڎIdfl +O(y7QJ:PKPoXW:S*':9jM_nUtn=eRB(fvjyj7@(% +Z > *0E"gQ$#Ri,_50z\e ]lYv*9v\Sȝp'J-Ab H=ĖEl0FKq_c`"Rˍw=t-&/>3v=xT2,tTQJ{޽RvG:Yen[^>ΕlL꣈u uwM0#J Pw أ{Ş0bkNX 2SDz;IJr2l h&"w=zow~Z I"N +] Qn4/݇҆oLS؉ZwJ=|o-LwE'^mp0r'xT'm腭DVM5c| rr]\#2+хވgڄ6z 4a`ƎPY SSmcI9T,xکX *X'1npDhg\!3$"ַueqJa:OdFb.b "U -""RfLnNo4L)3x@UaPbt?]Z!hQGkqO,Mȍ#W=#,&޼s{@zc/)#DcJOm|9^h_'inBZb{?k5 l ~5>^v7퀸Rtp 9q(Y+tfZ~"B2!jZ&Do{(Tw9k>LO70w\Cgͳ>z?{'dau/D_gXG3ޅϪ*Z+4@Yu6a& +a[,7/S&PPQ 0— OTN4%Gj jO P0׍ +=C>܎@ B|S>fbϸʼn-ޭp' f-xTxj@O\'eg7r 8'4H ʚ M0z/Lĕbga +Ml[çZI.H{ SC|>.js9\F'YV܇f͍,GթD2k %|3DrIIRK. 3ێ%/w'-Rm˻[ 3hkwq [qxۍoSWݠ*v6ܭt/1cG- n-CATکrӑXxf-a34aIm'qT|}>ʞd5 Yjd\UXzfE_!A[\vNPZp[Fk.C [Aq=\:lD]7Zf`}V\JxfU Bi3W#)7 +>Bw%GL p@( zL P%dp ?]uPFEQOʽ>U]Za] +$kXj'yrB\E_{:Jh^NH5`yP,*+'1ᠴ-wqtkqBYvw +3yC[qՃ#j?$TїAU8z0Y+6RX@l/] hz3˩\O.P@{{ +ΠJl#-EsN'aJ^Fz\w%m8?[ RyvZmb)r0-t*i# +BŻ%BK n[BTK!8}Al > \RIUAFٜS'J-֎KzKz!w>x:\pj?kVX!x@#0~楪Dz嫛 AtBBezOjSʍ9/-lm|zN[Q>h>7ϻLr#b3.Ur+N lO/^!^c~x} Jbәc\ (7]F$,/^L~?UnemάD\(v1\PV\\צI}H lPWTf{-d݊i +@k xD`|T)թ9~:&U;!*ԺS.'l% +Ԅ0P6˱ $janTy45Vj47L9 mYK@oLBqC/t(וXg T-#r+Ḥ>7ǔL/nb)Df<-joeq"p cR/e W{7Ic'Mc 0xXFOtV, kڏP2ֹ;s _;w&P!\@ UғUWRY|vO9e=BEW#bg:t's1]SWz9u`g25>\U +ۼ='/Yވ(d=$ml'4ĆJ7ܜ'!#eܸ}iQчvN 7LeC1|k{3}d.m'm P2 ظV|kE|T͋!& ` k}g16sT~Z]h0#p:Rg +)kXvƸI V?*Lߕ]7|).lYjŽ?;\c=2řF9jxf4PbDcA&aNB\M*->| Wsl8||$+m$@Ҍqp] ++Ae-^ Nw|O;/Hk +TzT3D 8>gRṔ}DO7h*J8)fTB?WL[D){G_4v +a"K{Fp"4b $= FHvvkFӣ]A[|t+rOD>.O?y0YX Qm".<z!~HO6cV\Th,SlQ$*v?">HHlWo9'Jݤk0[]: o:q̅ND9~_f|3 ӭjPFؖPf$⍨KI}\Lw"[_[d>ʫ!Ù($mΤUbg7Rcq U8vO|ՃQ6 H}kvU; ˕K5sMti=pRF}cJwj,Aj?@?uЃބ opIk*w/Yu 8O=L? +M >P^BK*Uw>n(a"/yΞTOg_*b3&St`>&g̹?>{#,G:tnǴHA҃0$~mR1+KtQn[L"=RXALjc's;M',3l(*G*^4b>n>TJ/܈捽JUπC?u9WjDAܻ0gGq/Y)vH6>kcbu%ZkNbћghB\tvBߍc( +ҼX9!OӨֻSk= zBT@!aH.vN6_wL]DjnW>qVD)wXIgIVCʼ7cK-e >mLΔtU=bS>W- 9b s0fGL3H.{ NfA|Ғa#Mרm9.;"hu?_5]uP}/6tDiE[tbDN2{N1:gӯe'鍤|3$T~ACO4eXK8WجKl5(1u Ż=c!{JD~ѫ?ew$9m:ƻ&4 C$`13kHl9[Cv C2ٝm8ʖ{/p-.[+B閟/̺?!f0y9(qJRҦr0#)FkG1)UC}خo=c@[2.e垝(x4lԢ[ HPe7Sp5;U -7] pM771]S+~n8}u`De}Xg{nzhv'| p +-<ŰrƒOZ(ˁP|N$/]pe,N骍m.=tEKA;xjӄʛNaI: S44'IG\qa=梋[rrPyd\ZT*o#KMfq|$EV| /f_3cf>bꖰa g|;_$ʊOŖi/SORevR9whς5޽K6~mVbaOltlTɔ@ @-XV˗lF.:;͇! +naC'W] +A&LRlf h+5]\/6H\mKdvl`>(-'KdfuUwE<>ru7[qEp +ςAùPDޟ.JP,cw"Mxn*sSTҙA ْkgwӽN 6nn9ɍxTE$'x ;kآ_2`.h{NHLm\ŵҘ͝䎍Fݰ6Y >ysU/[t)k&E;c -+.yg$gf{ ,z>e=ڛ|,"wVg$$B)S4}<9 `X] gLᬋ)G6Hb$Ƈz&\ 56o\[w۔> WٜGb6:NVz"ԴR`aYЌϺ钋)]ck~N0KW 3f؉֛nvѫE$>%]"5E)C?YiּZrHϖu )sHZ<}K^i-~芄=%X s0 ߇vuy=AA>'6R`a}LZ45z8jA>dݸ褮k6z=3y9' g1}TAKHvN̙Q;0%p+^H!Q]ɠ0%)Δ)˽ +5f&{:&cͰR"avuߎ\ltź2R9* }'GN>ۘ&xOjCQb ۔ zxbfwԤ9~\<[u<u0u(FN k&h| bK< Rsu_M41bwP90 P+1䎤1@aJ`'囦PWW}ª7@ϡ [ -<^HAd +Tb lxn߰GVy+Z]+ި I@ AN~-H'VI6̨ +=amknI +."}ûؒO Q }v +TP ,6UohmʔTnrKh M"ՍZH1*mi)eYfW)d*7|X>-l?A2}$ sŃ52ocg۫sh !.,PoEYv- =D6%] 4rS6Ge R0YVC2,)U+K×a<\HNCюї<<̲Cg`ְ*5$d&g˰, mq_ȋnI0YuPJ/?:Y DTQ%L%Dn H*^Dj;wF|aWz͈6=<%RK$ l%2XbH:uJ}7d%$@l o +)^~/BbK3J>-{hs*4fB8hd(69z3'm\_ x V$!8dGޢgu1ZEggfBH\uMTKC[q2ɪyFO^(UH]S 3 5dQ:lb09|52c+ 17%let>/~!s^yDR-ZhcLW|8Vgn@^3nX# \HS~i'u+Z􂍒.T mBB)Nm+BpvYA.Cv!=W8D.<mKн>IM?_`@+%tທ.xxXgN-U7앗 +*5{/W蚓ښa#,p*qP +F']|2/֍Bl[qJ*=& +;jkb)Vڃf3Jڿ|WW҅uL]Kq@#M|jZp aû)\lr: @Q`݄HzK(z|v_H`>6 +!I.&uewhjt:sI;IGȭ#PBʎw/>,|ӄ0W] V*u'R5$yYv32z25;X*"#BO1}dE ;M!_ta)l0JaJ0nL>i# 'TWDcUVm;1o x`lpFE[Q+>h7% yFCjX Ɩ/ܢ _tPN<&TiMi#@MC܄ v.~#xR#Q8/C՜f\t +d!5]L7Ү_,2"}|)0C?qފ!y%ET6EXDR l;d<ںvbm Um8xqb1(-%XE؆mp,zX ͆%Vg+2!:2t\pL3vaNW}!W] ;_zRLj HmnZ@ƭ*ϒdۗ ĒW EGxɎ-9"N +8(a͸Ǯ+4Yфf6s*n IP۬?KHNXF[ܡ-l<;Y Hxr'Y)~}Gd|+ƍivDw1.fa겋r# +%o̮}Q P؊* o8sВ^p΂3DTRw=3yLuߢ}:-6r#-c0IX܂Z ZzސBIěamtB\KJ4 [. YV4 9ńV"> 9b8HI,0ƾ/^f .&'tN8pre[pPs54ja#YѦ.֗ah˂-D1(F< {\@9ȗ9p #؟Z0b$ ,j&n:fm(!ea> 8=gA~~MΙ Nr=6E6%D.AdfD!º%R\\ A{UXu, I<\Vhu=a̓-!|AM-,ɦ&Lgrj\~cvm>fl[4EOԊ%!ɾi@6Y|% 8FDnD?r8 dGO^~+Y"+. K k~ϊG*Ѷ9ůxe[6y-8Z@8Xw>mT)iHƵ-(5KLX%b݈:u(W +s5gՠ 2tf;{$o:2?2 VqtxFGN2cw1A(".DHrl#`lv/rEf\ۉ)lshfuv5؀>  ȍطekX[qLr9G؂ÉVB Dr4|8f g7SqS%YX$=Э!Y DW4A`Bq +\ $%;,+!mIʘ1JQ女7vb%1hT6$8W\oB+{#v<d'T:" <z#e7o;Vȯ-x YCebi!= D&MU&&gFL.ֽQ mp2BDdž%[p'F r Tl%doX75!2KYD"PɭtuC;p GE3]qȜ3Ñ``<L{IeA~ y~] +XeaFKnjFB0C)`jP}suu7 & ,p$+!iqGTW8Tj~2';HMi3xWZ&B[G3Vj TQDr#ռMCTpY{v$א̼Z0J2mتO3n wJ:z` p(Ù4n*ePX?DCژ 8n줲@p65XGT6ك<hz54S(%!* +J?X x2&ԜX#ꢛE^-تrhE\r<,|L|Xjfx0_!ʚp +qFްQם]_rX BT&Dvܰu)*5t>(TC|^?+u'|@z<nQk+h wtuPZv_C=7_zÊ]MT/"y؆ʯ}w W\a86 +$L]JA" :+Y4@lSH!, 12gQ+9$D +~B*<$ d [3H-5Kn5z&HU O/iDĚ#$X;$P-7nX-$#boY% Q:ќ_u^2b &$ =來Xl4W$g' V€e_Dz+H +TXa%!9]U]Br@),ojXNPUnH(nf0A!|qvd6"6bŖ$L}g,hR^P_\&טTLBrALr޼R'1Cո5Dj`jDC*we4 kXr@KCb-P5AY2([^nAIfOdPǒ4 HCg.R!6@)t颌Հb3B$6і)E5BiĦu+iƍկ]`HI.B7a@)8q݌ezV0#4"vHBEn.v鲇,| X+X&Zs]uѐ kq l/;'cAf$ `K>5hUMXP0$D6{@"O%(Bb-4,pʴࠁ!qCD2Bu6H:uZ&RHfImŦT.9+n$Y0>pr`~,`mbmTEXpІ+>t-8BMH&xGhXE@V^0Κ"jXs1eLj چʁԯ.[ 7P}SȎڮXpAq߱R% ¼+c,HOp 3nB3#szdPIrJoRځAҢO@=]OhCGlaG!b:m smtEe7HϧC"3 +ڋ$|a66ZO e7wx=XPn N: ”N| ؜@PSt"TN-&ˤ3|JdJ'Z>˷!m/@䚃xLX'*8I5o|סCr `kg/CT*{XѤ)*p@~ /X.%{d?Q[M6Oc#7<Ԉ2N&#-V%:D+vL[jR<^MR݃5FkAjn(BkE'xr:vYck!RЍ^Y5F>H/p`Iks}|ln0E]/sl]y'!ӃpJ6t|pnZ&Wƴ!BOظ?~`v,T@r9a8E.W>"s{}'JU'o3p + +KGDz/paT v2C x =p0>NVR$7 9X#Y#|GOoewRd^\d&'BjmiwlBhcVlfL`U[ +Gck܂5*/Go|a+Q=r;Bl[WR#Ԗ|.fIzkV_f7p޼ ;aX7{:$7jny߿|{>{\~^GWR}_^ny;r8o +GKSWzXyo?n_hqfFܻCUNfx+ ,scevyv<<jA{&VT=.ki}BgҰhdnmvaj+lO2$;gAm@8xRrf'd.( U\ԆQwdN$I~wQ۟Jˆ=&wQeeqav1}D8kA2O|賃'ml(;@]:` +{繍{; nKۭWg/= [~IvcX碸<3Z{*&lɖ9$jqo|;{w>?~<:f hrf"5VMQp_fix;c[+NGȕSr?SZ 7|Lt'ͧѻG_|yߦI}68{=;L1>yh5v {/oNudꝓ_n'v#3}{ry3 +HU㽫xP4mL.TкJu78L>RGcJz^U_@QM6UQڼ{tZ2qylxnsyi 4'kLټEԆ1o<<{,°}o|{ =tBhՀ!Bn^?kP>Lm<Wj:hN\LNgP;'Z6z@܂͕㽻R\߸4)+@rX)ƆR9o=,,v(jc5-NΌх;M6#Rg ?Tu?%h NټGoz?vo%}/OT{Tfc2k*}p}?>}0?ػ|Ic-fOxO3K6p@g7@=RmWWR 5<@T=Gq +ԣq۹gW\V$In$B}G靽1`2v}=zs.[AU~5N!r@" ܻ=ᓏ;zyvӇzOo&[G?w?] 5RG>{s1"Wh\޼}}ʱ)Tbq;U.^|挠>'! ?ΏH-顾q75\~Nj|yhEhf}*?Oo7_FÃ^[otr{>]cx(? =}v+N߸ mRγ?} +(}Ku|<4l$n0~atU쵶XE,L1[؆pnvNޖj{]p.|iH5h̯2eB{N6sz VцWhjʝ/\ǧ`×Jˍ FR`4='rqޣ`l7^hO>SkMf4=zoJ~?O@U{n!n_.Mqڠ0}靼Wr.MC3ŝpj\Qܿx +AkNaKBllIz?̏b0~(U<Ֆnҹ}2*AQ:U{GÓO?M#XD㱂R{WٍGgO^0:Rfp-M5vj{n1uXuO ۏ/goo>+b[~)`J=4ܬ!jeK6x4?GjLHR!mLUAՃ\ɫGn6$Tn89 +(@Ls1P}EXUN}ދgqܦm}xھDRxV޸ Ui|gp/}Dܖ?@R6I,,րEyqup U@y6E̷6gjGк1$[~(۝d1rJy1iʵN}.(n?+u/|bnO>w\Q(^6ji[?b8uvjw>.XOc-G$*9uCJ].6e ^ft)lۈL@,sZWmZ0Mkdzga8Ij[\nkvGȨN4xX,fg|#mpJ23srP,[c< +貾,Xqz{ON_}U}K,leXA(Ktaݘ¨d}7܏@ +2>Cj]{<|TuW)dN̡+3*'+{畝gdaP5ӝP}:x /S+!Lj LTluϲ;Y}ѫ/涙H$:ɇoCŴ 2>ye}ŷ:ϳzXI~ٻfP&koc~$=Z@plƄzQT>ц7b:rÕC+V?J-: +R;$\dP*|E\PrD笶,Y3W>ٹ.c%{stju~@g *=ʍO|gx[Op .i yif +E"Uۏ'`hi77~]ֽl*ֵGkɁڸU>hC/cђVPO1CL9c=DHCշ7.>-M:h݌DdM|6anp dx/EmtGҊڔ g!7"B>$˻A` b=>n1(V뇙ڸfX_Tr睑B{ƶTbH 'A;1=FKXˎiO%kO>l]I-\+J^qr)Fųƅ\w|On=~VVEmyυ\ #&/ X'd⌶z{oSVc"] M6s-99yPrry'^=D Za+vQ S}LZ.w7N?-$s١`TUwnWwFgwҍwΌVA76{W3$T4X{sK^Hs)!e'y>??՟ٿ_o?WCq*Zvx9=ٳן|/?/W>>{꛷8E8'VSO?~/O{_oWNͷ)bqJ`rryݧÓՃ/^}/>͇Hy|9M(e*E~veVntT޺|ۯ}O{~Xm=X\LvecSiL +ik߿ػz_wW?_wW9.+ErZOgx2d[ͽAn~~o[_~џ~G/>2xI)@;q,͝ųΞы>_1EZVwρ&QC;WX#-7ѿ+$Y13ʲ,$[$lagfi!M4I!i$M)I.8s|朝||H(Z9{zΗqJiz7=qكbp*PiL.m9~|o??|O|O_[|F`nO<MW#+[|ʍǟz7 +F̋/__z?y^ګgo2#La|=Rrlibnӷ~{ᥗ_7__WLoݱ& RJkfemzemikO=7^y/}o|w{?BN\)lO`iE&K季}/~[O=7w>ջۿ7s5Naq\W^lN,n;#=W~o_~?Z񛏿ݟ3GI!C{T7{}>yg~o}?~? ym@;*a*+bTkbm+~o_ß7?~G~[_z8,`}2Jg Rr{2:r 8߼G>W׋}^z1wau0lM/n;~nܼ'ӟw˗]]Y  ,,B |q}szKyϿ__?[?w_7^tldLy2h5V jTqljyaemmcƕo|{o?z>/o'ӛ_ztbuK6o4kc3Kۻ?sڍ민{.ͷ~ß'}ɇ_{ՇY0AP哓f*R*+ww~wy߽zk;B=y5X1>7:5ulɻϾo};k_ӟӿ~ʛ?z ++*HKԤR[;̂زs{/|{zOO_;O?Ͽ~_>V ̄Cȱ?R߸ȗ^{ǿzwo◟`Z?~?ۿzwߺlIQS) 0V3GO_oK_ +;@>x\z4c5*R=6'G&FfƖg8ȝW=sDt]V;:+#R"MK҉bjW6ח7WFNZ=vo:z,N|żEҘ)3Qv[G.,n'|'|ڗ~G?|>|ɇ/ɋgZ3SPBd@u(Kw;{= ё᥅S'?y'O~_|㹯7^wǿo;׾˧u6U+V/Bjd|rzanK\r/>oa2 ̌3+k[n>‹x/s>鳻kkKh(! Hc!46#Dյk׮|绯|'z[| /|˫RyAXm $:B6j[3#kƭF0[hh"=[:$u0k¼Z x!(Rn_8zUc,6:8ē! *Փz<}zJLݛex#V"X<ΧG׎N8A-ҫrKA)ғw VGЈsBD8', #zVȥ= kP 50?2a35\Otx.Z3d4 ťf#ˆõ@<:y04d )_jŦ:Yc)6ʍGL"{ڵG +p\,ۍr"YA^1rՁ>m*D=B*K9;5, OJ$8#8DžaK#+} +\ yq@y#8tM9žHd W:X^TڥѠKn6%`b} )uߠ谠+l!0V:G +Hl`tVdcfRl 8g1_fU0 QBpOJy #_yVY:<'|f: 2PC:P#R&֡&GrY-tJJqzb?(;ԯS9{49sTxRǪ g +DuzfN /5}{,-cC:k5(Gz_k`ȩm~GֶDEDe90jȽn)l@b ~?@`bΘ+2A=23-Cx4FZc7=W-ȬU +ȈܚOm5HdxϮJTxW6&Z{J{zedfL7&7`U"=T̜'6!U{F+02*Bif_GT|90d/jdAi驸՝&2.Ā ؂Z,bSXH{Wf48RV&mGDms|PIS[2j+O|}rIL]R#@ +5 $*L(/r:Z + +[B~[m w,J#-Dj*Na\cK}0$5v5;(5Nk&:)EBz:7`t=]=! pHe5aɕ^AMjpPz  IS {D=rK&G5+6[ߥ7`'A{ve*K[wˬ}Jt_A{ CttF +y`: Ċġ~CbD +BF=dv;L"8[r_xz2 H 9te*׭֓139Vv!LL3.%a J 3+O,"!PP0Z,2quL{ rqȑ3-@;ꈺ%7syt2{`܀ǂ 0 `٩= F* +NJ ҜّUۻV028(Đʭ},5TOh`Gf4X ~&Ha~_O+$r3wv6#2kUo>$`!풫~qWaH M؜.)As084xBUpcDpGB& ҫ:fqՇ#u4&a,ԧ'n*Psv@D:H@v_uh+2Dar9"3:rHOI ̡!!U|~`h gԮJ,_!F._l\ثz ig~[Y'V._o>FUI^pP䃝@Ct +v D\FTD ])7qyP9Fw KaWBA3Nz +v_AKO&{sϠvϐk8>} P4^%";+Vyʸ +JT*@ĵdH'݁%ĕ< zV Nr "Ǯ :`~Tf!l.*, UW2P}bAܧVG%@C Wt ?׫! PO-2Q0||\bp!3ꃘ={M B XTH!4ha3_X +ۀ@,`-Ej-qڦ H0}Jb!BA 2IϹsJ"k  )[2pFGBΔDOɌ;+/p!=/7aD*=jJ iO ҆5א +8 z,rg6j7m<(hȨɕavl$w>.!Ea$DǍDKju!-էΩd橰q 'I?֯6k!C6Jk萅,)i(͐#11WjmyC=O~)\JfJM+Qɻ +endstream endobj 107 0 obj <>stream +@ `4p2SeXhHk7P 38qf{6>_FZ" 7WΝOgNZp}nאj: + oؗ_LmQBht59SG<5#6tk}!D> }iX EY&O,LnG[9[:_v/?{6Gl68|8 #}ǠVgBIfնsϿuGeC:6mΝRfLB'ɐ. o*mt}r=iLS`s'>qyXn)G8C#E2|쵸˙|fD`e(0ɰsO)ƞP>>iceS[xP 3,LWM Y1kTfT`C_+9"]l@=QqWJk!I5ѐ*- р TxT q{`04hXB.RSI,r&e*\ϷvoqNˤ5,Vt1!?g X 1z_\b Ƌm Z,d"c|iOj"JE1aXl< J!f>׭08ZŃXfGT TN\?rđ,2WEPqOR:VQ@Y7(!g$?A/:$'lήk|nEp5MvPb# L薘ݥ^Y#lt*1?4j:&Ӡ _ H0De3B*ϨԀ-;@~AA9,2{|%\?;-r;3dgWoTF[3s!%NVWFxT$:g ['t)1=v@&4t.h-SQ+ 6/ʀ ȴײ חFUgON [{b\KCC +$ -CcD m+WVځ.(.S3 g(،Y2q'`CkL{3䌉o%[&#ɋ*{O"PtWpJ-JrȪB|"=/gpSWb2j[=W1 By&̘0sWy48lNfvl7t :MbSg&Nb`FVft_zO#2L$rHΡf6jdj3X:{t!>EFkf&rӝM S „m,^UcZtn48VP A\ +#*dml0=~ug=#W:s|*qAa]΍n_/B{ڞ$#cȕN3Fm#Ɂ&&N\i]z.4δ/@|AdtūwOF p)!\'z +a \jƓ/LۼU`F{XjPaOzF-x3K0Rځ0Z0 d>UAĈdϛhL̟zjckS:W-q ;Gl:pXfK`@q+P/*%:Թ\RDn|pHhWa*,w_rqg$ԈPRy2uf D$Z(; Kt0=.9e.k#T66kֹ$ ` AƦm\ldBFXP\4ؕ0oeR&*-6{T֠Ց)KjC@`@@"(?3Cz ^&"98.͝U ʌuDŽ,ܩ9_iO+ + ͝א" ( A #o*ܷGb\aᜡ6 U7oaf#91`pN9+?DH_i6he:>q8 L f:*12Rpl^)7q\hsb|63 9r;@7d:,֓z{@fLtCu{xKo%79멑ðrd6AVufէ&B9sRgI{ >XjOm۫L {_ZZ}TùCJ-uwlAIY||\ָZzFFe(T2Bw:(>%֫@=jϺᙈ Ah(̟;.<|镋Ϧg/`I3'gGY"Q?QԀ;i *% +49`P] +ېEF+DzF+:*D6W"=Ԝ8?s}z[Mf/ f@} &W*ȣX\k(L.Ґ6g)(˪1֑*P-S_:0+a|\_S93Cz'K rO_[(_Hi+Q2,fOwnyëk^0J"]mq#Θ*3(r[q.,ŧOl$fOwX315Gl.\^=vK_ Zhe *?%ESz^;z 搆<`^94Ho ZsޑE|u[qGEWlH#pȹ-*3CFU@^ I ~Q@!.GWh#X޸.kPI.P[9;|MKDӐF*peș\:4>~SF ~s@kPƁ|Kf&򘿔/>_͛Slf&7~8/;͑ųi|r!.eR-Cxۯ8$`Cl`LDAYi)egU C* @Щ2`[/6 rAMi8\v&Xg< Il LM(kCgf.J1Wx`O p;EˬRkUb-*f50ȷxL 9:*@q-XYCţW'j#\nvCq*PSC<  W &,0iP~,UT)șJ \Tnl'Q #mᎯUGjJƅ=8DGuDN?^9uWQ#/2bv‚ ];~/oy[Y V0q}t +, #2R?#v.&֠&0o:hB>5)>mH;_mSғI>R\9KLȝ-_:`nlbKM"32@hHTl{rgf^nEj8(s=D-Y\&c3|LdqV \Ft$~MnpδTk Ĥ"6;lLf:-6;ƩDB9] K+'71f"hF}R5/G "gh_GnU@fld SŇ%jgdVfm&&TNZ'&V_o߰9_fݩI::A';`#UXࠪOh!-pPcw +8D[<oWk$o9OvO-$GG6n/UO?^9r!%4YF-50`` 4p ܽRA61MlvmJyl +Ĩo,{t ѝlk4ȘP0i4ȒԨ)mAqРx/*"S@]@媱 0HSZGp^P<*ϥ&g`U&K H)L> ɖ}D8ɡֲ/ҫm5lu%p|∑ə6#d2? (%Ăܥ4HR ِ &6NX}N院M.}_ +LL'qMWeׯ&ho4u6jG HmR]ka 0π%IGj~ўӐ֡rK bo=+2*la3hLyKK֣|4ptk;;qMOhc!^xoȱA- uF3 <ͺMa";m.\q.3m:sF'@ K\x$Y_lbDAMMHfGWhDEa{pr1wz~byt|;=mό_]?HSóǞ}-{-ǂ0W%wb +OAnF=]Gj u0Mdv:ϱb3iX=5Ov!=r.T\1--ĖF7S;I[s/&'ݾtⱛ%4V?|@ΞM{=ʆZ,KԘH@]:{ PY62x,pPdzH)`\Q4IgTuGo/qs ΌJY`P>)qHT +ˊH-t&W_8z bLpghN&&z!oGN>0yIij 0Ql|1}rl'9z˅_y9;vs&9-ҍ:XZٽ}gM<}&  j:C$l`a^fe!NC#Z,EeP`: 'VvD?d gV‘Oqq56;Hӑ6mͧY/aWKAA;AL3鰸38ۼ]h*Vhʉ$o Xsdؙkw#[GH33S1 23#2:?۫7r24BGbMswk-G.q3!EvA2:%PiW瀬[dV_Cf9ؙ9|UlC2dpΎȸbIbvQ*G׮QDpsCG\'=Ϧg=%"2a(%%3*{PE|}OQ|?=V5BdubG5*CN`_Qw+Rkq#LWc$BtzJJ,$C +4ĦH\d0\nD~x~DibMzcn94s"!|7.Udk|#R>)܎J՟h|O#Nb 7=yo=k >3.7tk#3|,09=WkNh m +ħ ٱsq"Ha <AbP9\_ώ:|x'q#/b{_0EQ-k̋n̝1MlvPpsgtv4?|+/:rzxRsSڇon_[ع&+Ӟ[W@>+`MS{$V i9 oԺh`j0GK.[#dlJQ_ΟʏnJ;\ظ^ZoQ||g#7!.gaچg`~T{Q7d. +20-L&s3Gq#Í [Ր1kT9+5R\DiovD&F j3N&fq4:Mtdԓ&NB~:^Bj#-eGMOf&P^ `r) V +SnFg1V~é^)ڣ"xy +Kq=Vj.7V[<%Zq66>MCOR!%y@bUSgQ;%r 4q3 sxe͖gvW})1zD(Ρ"8Cyc09Yŝ]2?_rP+pQ΃@F6b\x8D׏9{|sLqLl򔫴NNO^9zL9czGUdӧ= 2dSd d'7x걫Opc>;uӞ>Y+qٝ4N 2>gp0FG\ʉm!Փ)c{D V(Hxndu\ E@;+:B|~rgf?hi*Q>W4#+bLT3nD| RnlJ +DRi._,qjg H 3_@@uő;%wdl1%wUa# uwfVX2$4(W̤e0/3aGBzf3'\. o~_?˱Hk!JNL/̑+ҹ oe4wxv죧Jnˏs#3lzaw;pSjӁYoO|jZ9[X6FAèAZ('ʟϜBe!5f9::evW͎J% Ā1lȄ  8bg@C +jLfqJIgx"fρh_~o_i7>3 CjTv1w흛c&2`ܬ'dw…X}17iv재'ZQOzP@uiI VHo)vl +T#f7 5#1D HpN'͹镣'/]:=<1wd}.sF:s3>gsg'6fNkKlz ّ7ڽ%fSDx.3}N_{?={)W.fv Oݼ{^|7O|G;gzoz%6?t\y᫣2T)+8#db8}KOHu|+=ADLbzv;7fv3e559::eK+A/^dbU@w\}f=:\9(D=y̗BJԓr.tQ[ > j؇ PP)26&d&Nf:J aGD +W>?t밀m ޫ"NAM籱C2[~-&&5%  Ŋl\匍QQ&2sS(!G8ovaGr i3牌 ѩyU0+5:Ħ}:"􈀂ЇHY\9%ԛi!?+r6S!_F#*4.ۅudXӁp/lI;M F(^jƯz|xi 3;G9sc_;s7GG3G.=][R_6qpV#֯>2[i 2Z]i=鹃a{N2ʵHr2)5K5D%\rlW?m.]z4w h1 ,0Ie2 R%?_v S7r;tFt<=@ L =c6V_wV7/^ؿWvn*$}胩T~6po+E=-(mIpTw$,U0sW.}R*̳b_7~^@3FJm翽~Z,o 'lT\P[7< f{齫Ͻ;GVb͹g?_^~zH\ҥzK/\VV|źÙWJV:OR?adf%b.2ٵoyz^xG)̜pmIgy "M>jNY".>uvX [#/'KQv1wH^\g$;2.bPD5&9q9eT_oU.s>B1+KBnނk3 Dq&JYOCa:fވIQ :;^*KˇzgVnIAnt`HyA7b(_WhNh>,~-:+] UVo22FZ/B1A`&9:Qo,_\>xyCHM(iF)eRQ2'Vwx1%p:" +$AL@EO!\RF՘^+Nm"JcZVbiQOzᴃ5\' D䊟J'H|,JkƒlknGX^2!_޾rL~t|`bA:MKQgdg_Yá@(jmWKZ?FO[Z|y !#lBN FMW;ڄ45.[ȭ /\3.dP<'aLrJ/F?(V1nܕs!* +EI6pp $0# VbZ]v'bwVOdTen͜N[[ă0B,›@rf*< fғ;).ȹ7ӛA'8éQtdqE%#a' Ii'bx5PG~ dIڴ@QkՔW'!T6|bSȸب-4"&=tt)17텣\ ]!);C Y@P`|W lqF6!BtwbpPO6%Npb_2Yo$b$K͞l\O͗Ln=\{ L BxԇI^\Atғ(c騚A(*b 8Dsb*t0"$+*D9u=(ZX*LJ' +~\oHF qE(޼7=c>T KwGlMxhGPt%(y;,\VLMl<Sd}M).9>GScdN]yՊ;> eC'ĉqR0:xt 'SF2Gf`E"gIpݨ20@6%=2HPXBZMdg|%Bd dRY9uc@101OpzRBx`8fL&cА GN&/"[=;pܔRth1D2@CT2Vq;D .'QfżտtGLJ6tȁ:qJ4"Q"!;.4Zs=Zk|rE|aK| xUXv'dA8nIZ0d,Ab8M ٶN&S6gOy^)ñ 7n#\c$ȃZDpA f:>dEmuZ&{\A8`>ݕV (.6L?]_̞ƽ$p>#|`>Emkq`P VP-(ST E[BzR\6!F? bNrZ SNpų##^?)pRP!Nm 8cÑh}'PKXȣ|dE8K=tlb܊Ё!ɓS[q*IY-lemIqE"#ux4dPv@t6d'=GNL Siq@'F@PH0iS]>SX'_xlA'^㌬jÛb:X!PѦQ/y/<6`whOFb٨vp ЄP*f `!BT"5' +夌a="M]p:XRR)w HfT& q"b.ZՅ\3HZhx儣s$SV zyą({@DI cN f?O% #pB k6lD1<0%U!"=nrS8(!\ gWo8d0<8vvb  @TV n_9N8ʅd%rj;9>=r'{1&0hB2泻 + P xݏ2b.O. +! Q)afuGþ! L,ɄB[6<g󵶚ΡB!Rx>:O~ZSjr4Ht^\U6Dp!eR)=SHf񍵙;˧-SSk(D)lFxz4 eJYxnNgN !xyt;aAGEY6$Aƌ$N\Hb$-Ջ}Nˤ@P<6 dxLJj_ZJ1_,٬ 1F1%V+̸pC " +~  XQ`¹j*ʲH!:ؙ,u(b~ +BS\`?zNu;cb]2Z3K;ϼ+!9a ;8IYÔ1IE({A(!flRRN>1xYOx#aKЗOy GE:A/aaRR>1fб1{ :mt"3߉//WD$M˻7ww;ެ%)3$8ظ3eMDȫTi-i\,QL򵪸^z̃/>}k'7(Bp!ϥz j3KO>xfwnTbEKy8M빴>f:d&0ٔAsQzo4 +S͵_yԙqȄ'40}lCi-8v2^ DӼج/_bJ{0LRXԔ6*hb)2IT(%uJ:Vtvnn*3Y,d~s~+ϟ|#2P Z, !b"ֲL!wRW;\3/7_?kgOqd,F ABi3BǑ@0KF+Izfo\^w{_ꅋz: +{=lE 'm =|Bj +'xr498D?zrbpc#ˍ;\޽Ooۏ{l: r(Z)tT 4n136̭ͳt_{Ϝ9wf.*-v݋Ĩ>x2IPQ  +4Kwxp3~W^[gz{{ ExD/K_m޻Tt_/Í@Q0!(8Ҽs=o~K=;W~O}o_?g+.W +T,I”<0)'\x]go~_?~럼لd'G6/EP1F|HDZdt?\]_޷oy덗ʚ;!!JU-P@6W/~ ?[?~woon-峉(FU=ŒaN&*|e.|g]|Rm'7/g/o}m7_?o^?{ooK?zw|d!_al}OlN _}O^_+s{_?}o_?rf^'Ȩ  ⹳3goi?>{??ՙTd`Vυ(8gڿoݷw>o߾z_{wX*͎?:Ҝs!#|&+Yg bO^['W>o8W;h7g;-ވ#X]w!Ҝpa8B ґ&s8yʥ7^~~ՌQ G, O'#NbviVC|w.!e"FRnp`Ԓ +x); F[:FjöQT崦蹄,jF̬~ޜΖ^$u:>8ampҎ~y}AQXֳPTYFJRL/⭳:Ү(C!4+p#NsɋTA$F%Co:\MzDIޜ/롃i"(5*uL3YS8&,_#c *)rBSB0.|\8$FԄXo0mtٖcm +q(,D%[􄎍<\HS trk.hd}tSZ`Տ(Z!ׄ X%'w`-BދC^~'E/f`NZU˴hU\ F)RVkJv& +IFVŃy0T:ln<Ա1߰_pňޙ!Wd&FA +BȫRTI+¦7-#vkn8%'J97?h#->!Ș\6>5 ŎڨO3la3uEfOV)NJ?:5mʌB"L%˝}/xp-jkzeG(l_M`Xvĉ $NK+ϙ܄_Fѿ<=>y<rLbnn99pQU&YAx "8F J&P܁@`M|XFf4٭]% "B\\kdqx扯&&wvRH2\fgP}Ǖ:|dj^*$.2k3Lj SHcAłpVdOzKT? +* +ȭs^ʦx\]+m;D +$)+M'Wre6=[4wͤO8#X0ZG=fw4#TPr5/F18V܂>zK:)"W1u,>)Ď)R/l3`j͉jPQ3TssՓQ+ 1)kcG&*5h`M!J & v, )][paΔ#"2"7VI=-Ц/7=zژ:_Dnf̓ad`IkfRq1iDTHjz2jtC.MN.\^:x;£X\(n$&/+C0m-ᔃ=$QOk?7gpK Gj&TN ']EҶҘ9%|OyY[ 8pUgP&RA]$äuևbXkܱl<-XJȭ {IXKQcFae會.<]\ήj'Z +3Rq}N#łƜ%n:$NB6!=԰W'чOXx b φc·ƈER5$NZ¦y2 l';L3\cssN6UT&s>)s}ڜ0cd/G" e6a%D.g׻/X;Heffׯ EF$ց〉\^F8>)-LmTK~g{+W^p/;{AiePSgHL$;r ǻ1sƖDhPW;O5VooHf*@|UXvF@4מK>)z2 Ƨvq#> bkd|JE[j}Etn73jOS!؈ֱxIϳU$0$-h\0+׃\n<(]1yK,yO5S=)3'فє*љ 'QXܻNh-MɍX͗tcWt6Z|s?x,š^]SsщY"YNF<6Hc5"vড়.$^$M`Dȅk,,3(gr=} pS7S˻n*sh%v‰t*X.KJMeJeJNčVz"X5Tm]%fBmLNb@!z/zI\,]-|>v؜Kd_|9:wiH'{=&f/IanLi}!?Du9롓i/Uf2kMm>yo~;̲݃F畷>3Q[@rRq˩`Xx¯tam +ye.Z 3~q::Z$2Ux|wpcV-߹׀[+Tf>5'GVYo6 7pL,Gf=lщ6*|f[xm G k*+bL8AX)-\ҋlf4"W IGw7n^WwS.ҳ(9xs!Xnpp#7%; @[WzDe殴6,-?n` 3WX+~5Rߓk8RJo D}Cm6ޛ;{??sFrc\i$8dě犳zl&찙yuVlsPNn?\L*ӻ`4[W_>%h[:l-br5^]ݽƕ'w \xʳg. ACOBr3i~̬fxEM֘vj:;Ʋ^hmކ&_2mn 5`n|7+IMPbSgWl]mX"zH 7obIiec(iJ6P馕HԦ5/W wӇ92'^ݺ09?_UkۙE^ X:77 Z6:{V(1>N_y!S]tRDgɽXnM/y#E3,][F y}@iչnR&[Ps/bXBqSŵ~Hlّc XN=jgFq$Ab]&-lZ_0y.K E0^rT\3! T$XXa}CXCnc!@Zaw0g96yΎBvx<)bZX^>xf]Y"fS"3ONOi*!ӳPV=\+nC% gVc}Vnz׊ &5/pѣ!yQ )w;FHA% 6eK69僤1{ Tw$ϤWpyҬm$*[N41'=WBaɇ h$=lVX|'@cRZCdT)MͮK1TKTnn<\ 4Xn3tbFȮbuOXNgzruL˺%5vtdAX#^ZJW!XBzT L}.* GtP˱J~tk:8EXﴇMPk~!LՏ9#C+=X,8#I'g\vCpKwbir}xi~7MpӧAd&KWO8")+ezfzgolkpWsݝū٩3J>j]heGD\Cf:s>__3;Eť^ۻ}ՀXi_ S=pEj\䏖TF_Fڜܸ&HDmZ9|-U|SQ۝0W~d8Q]]jgcf##,aJ~CϯsF2hUb̪ 7@uj]_T–X\sFL/9Cr͕l)k)2=#*,\dCCBAoYQm':'.=t$VgGKl@;:)CJTQDE U,&-`F7GQ5ݧgrH t HH";N49`U .ș32:c4jkJmR[bj0ZQ(65}8#7{'OXuY;S.?,pҊK~{ jT6A7x8$r-j*jpCAGƍ*e+K'0 s-1m]1Q`4칸=2I/QsjGy§=qe#rx|ͯ@l'n{j-Ē?Vw U6@ra5L,Pr3U,1c!RbkD|V"rEGFCc0)S_U]'dc|1P_~8!(_dI)BpgatG4[pŰ>-fQS5~e$ $Ob_tLb- ͭ^nv6qΌ(E%OK G,G E-=4vXH[]{H=mg\D:V\[0hm*9.=* ΰP4a2 ;] @}Y\\&-dfK yy?5ݒ3+3YXb8qiqoWoӋD!x ,b\j~i0qH% Z9oeoyƥ3hj\t$_Hl,c6"uB:@P8'zqz!/@͜-Y,XVfipr̬5;hg`{]t9]'.t=墅٩D3n+[L>"koNi V=|gSbnGAʧ'\S̅2*6}d86bfrDO@"g;B! HM 8,V!$xM}lT4:m|ڼ[te  rGLK  sAA$^81;˃>Tcpp8fr{!7{""rݺ5{Gj_^N{[[2E%f0`X]LuKV,̤fc-U ,D^&p+(H:|!%cZ|݋±\ TᤋG$VqjԎvI ";\9٫Ml׋Efj֕Π'ƴa"OC^?+N"e ڠ)D*#bAdsÐ Sɩlf &%ƬR?[^ʤbwn~ +zc єf/%~&#&}DFG_`:qzbA.+x"} wR줝 +y*VvTY{$Ǧ N(!9 bf!k y\;z zh/ሤlTg4BBLx rCu1瀗tI+2*5!c65L _=agᴝ[qEh.q_d@ڸ&w܂+ Kn"!aȂ/',/ zG%̣ckS4_7W +M(rG(g4R=O]<- !)Aih}yV'h堈 ɠ%I:%` C :5bg`sMĔ;P;V\ol=lqL|Άp"^"ٰ>-l#j[QZ y"RHhXท.ЙyƜY$M6W\v( Qy*1yAnGEbD}`H({ٹŐTsFh$Mݭ',, !8)(qbB>)@T!Jcԅ R9T)]F\l+[.]kCu2k81+@!,B'06b b @qyqɸ$=@O x iCy,dٌƑy=&` H[EcH dmO[ ]xzDtu]M /Sv|"855`g_𳹰RCjP$>/U/dO %GH +׹ܒ#6l>xkr6, /hz8s5VZSnp}0"SZe#ӻI5BJk[$gL%KZ? ! YG+]c1+itsK.kgV@bSn߮Μ@ 7Ss5֜g ޱ Е(4+ +0$9-{pv +MfefgwktCrKj!ՆLB/wI/)BB0p.Qs|oV`T{.gUk.ޗFբKT<) ӧQ +AQً7qV%5!yJ={W?9d(n\ꔨ0_ 9k; BI^P)w7DPx;|?w˻_īlxy+sgߝ~ pFR5'_~u8yQcj֟X'N_cpTj7sO[(cpp񡵸4 ~\ N`qO R qs:p_Ɯ1Z LP-!1v2SOǸ}]~$t|~t9c`i[7wLpTZ;\d 'Y>&sAkz/GZT7+T jz4GS3%>uNmB6F]1 =ɛ6zAk{Ux Z[vK5g-ϻo:/57PX3#,a!,SgpK=}p9=y'zݪg>۾3?2Norvw~vq/w T &6.NﶊO]cXB*!'{v{SHFs=Li ߶!k;ċ[Œ!,LʞCpS;X ^ 9|wFi0$7sܽi&y43;կS?:ت@Ƈdacy Gg8˒MQ1 c.SU;vNm=WXA3W1Ms-28f%܎FJe׼Zp pBj&)._P'Z9gH k)*H]T='EYذ"N-Hy1d-K ({4yU̙Vr]F +_0ZQj bDjzUeE.w@(a1ʭۚ9'WZFp*1g%bI B[ yE؇ifh&G,,W/]ӬJzOLXO]{)Fg)] dxz'30F`U9gY}_CO@<|q<›:x|L"dg +Y?/˗V<ڃ[`+~οLpҽ%'5s\UGP3m>P4_BpB4]^*+X~)VϪZ HQj;RZWbꮲ|TIް7u k/ޟ.i3'OsDd +H'oK .: #b3%.)9ylxdv[_opXhV_f&3>@ r#>ӻwFJUDHmgskxsS:1g{uo ˗&DMl ~ u ЂAׯ*{WeoHfwb|֯2QѵP)LjwgOW?TO!UaI!$ל†ShBo֠"Ņd/w`^7# 02mGYSʙ#r= %Dk1^@ +@Z]Jv8Rp\"`fM֩ x h|DZ"{b5[)\ 5c8S1ؗ+J|FC?G!, "f4 oЙ'X@ִ5/sCA2tc|ؘݰbrLCnX+wO`K|إ; =߁Y^Qj0:L ]SCƚrXEUVU{U _LNֵbBp+D,6'VT +Q]qX NPmC'EGYPP6j JE O˚_U5åѾܟÌEYqU ފ!ԛ\?J>Oϝ RԼ&u ]7k NioyLJp!:ʸfNX{ZS#ywk5gA3.Re9=d{4G1}(Dfj jO\_:7P-LxVN "vH ,ƚ3պi]7s1<X{8/OMXTm7毴 +20\^,17}XVۻd{;wgO\oUM.U5 Y4:8/dOm7ٚSfk_r%m̕ҸEd&ʷŒfh_~|j!le v9y2ϥ +uHs]_V;U};&K 8sDTd):SZ7fAyo q/w)Dmϳ\E! ++[,7 Lmʘ֌4VrNíyQsGy]VڗBt( +gqM^DTqX +=MX%4 rCn&C/wL{mYm#RI贤aٲU; H aymK2DyrK W>Ël 'jZT{J2ir!d1DݪGr|>03[ehot5Ҝ:1EfEq[KoZj?A ҚzE3 iY BO|k%oqw]&eH=õԺn~;DaA9^R渳|~8Emm.XY!1'Ug%n+kR!O0 |jLkTQnJl,pO93}N^J<2:w`War nLn舌7-McV1E'^%dy}!i6H +QTQȟ:aj +7Z%ePѦB|=E{(BL\IjUkeIft;~ rZj^O}_DPvQw~8eQX B;} +I:5+BG8{pPO6T7r +b譳dE^U_ RarG{5] r,Es~ps~\MT "r@یEM&FViInپɳ'E̷*ڬ/pqčX m*X}FwTtT0,uarsA/pk]Q'PY&@.;3}+F5A.K3q \@dXoZb'Իݡ"i\p'gқW骖tH SV ewSDh3 몵7`Nxo&S9CI?[}@eA.mC +87 .sr;Muνѭ9CZqryQ5F|_~) +\u\N VU3mBmƓoxp}^{sduh}duoHAEmVń*|#Uu먽 \ lUaPķ6r!b,t$O,2K +l V-u) />NOywbf*$bԂ0Rg~IP5}* 9EX=#jMz鋿 t +\k+= u_a^-揹ƕֻa k<ƄvW,kp}?{tV7dixw +&,FHuXߑXϖwOk tAW \SmsqIks*UVVwL|6}ֻ,q8Ӓ)k}{r{\ޘZ{ x",8]q?֟<+QUk\IV@#,Νs?lxJygRfO- O25bpT3f6F1޹Ҹ.Gy>KfTYї;.8y\6 +!v1~Q!ڈ O u84l"n>eЕ:| )1AԢ=s4}{N,+9*c-"am4/t j/-vKژp 9f*Ͷ7(Gwebto ܝ#ƀ lt9f=Fd'=$䔫ߊWB1)sMN +ODrz]{/ۇ?@a f(x'=#UQVQgB(m":A\a^Լ}}ps1u .Ƕ cBXvcE 9| ܥ5pe`pV ;`(xzy?/2lQF1{ޭ?~_kYZd"߇UST|Ι<8g\0擲\3^ۨYVB[i\cA@5b-Ga@of>{Ʌ09ua7?g!_TŦ3=x'O{ͪYuQe6/sl3EE/?nOF.ރrǕe\_],L=ô}EW?w\40MPpINK3[[D_}נT-zr +0؝+Tn 鬂yI[faYJ51stf.k朱gvIRy6(m1Kx_ɾqkDj.ڝ--Navs5(.c@o\ͫ"*6jM"5<n0c0m<_N~+6/( ˋ {ゼCR +{f'WLi<܊UFB!b<.{L `?^byk_¨~k _oQ_H;jo#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵_HkeU,z7??Qъ}~Ԃkˋg72rrIl;Y_g*p +~~qvq7'HK$~#2CeOMG8Gr AqS$)JliJ)Rd)ӽD`_R+{]4)Ip$'i+#,ň%3??hGHTdt:RziLmca@枼8:vf>O ?|_}L" )Id2 MRC}lraaD $}ө'"gx7&'TiOhwX\W n)fqePd1V'\pˊ ͂PGk3=gtx\ 0瀉.b+C\a<pсܺWtt%b}$ū:3um ^Լ5N3egc̘뽧sI8C8U9;yF@>)og䭻ViAŦ{>W;}gUYI: ܚN 216{D:=Ldvo.nHw0'$)ς[1iCi:,Mq*Fwe<~ ψ]^djVE+. ХwY&,SaA&{I(\VR,ɖUAYQEۨhmLjQZ1d_޹](KL>'Ò8ӊ k[ۘWs`QuPg%yB+T%sG%]GZw:g_i։>c_uo&'_9(Wxa sy\Uݓr +;[vkN<l=AE)ӢByb~aۄYqE٨,4>mѨ"gV +1f +KLC 9w;&nlW-DͱS.3=Q9̳-Ҙ6$ qcWB| `䳒SQCS8DpǵG96GX(ĵ\uHc_thc(:nn1xJAÕv,I*{w 4޼jVz¸hӢ2*i<#PP<`Ƹ rQZprUmH[ 68 +0$ԡi3d_`s>%ee=Rp\|,su JC>89M*%lžz}Gw_ƄƬ`#y _ +55FJ狧T۸OSLFY I$.Z' fFEj%vŽ,gy>) C{nqg(*~T4@I9y#CʜV C: ]az"}y3}f66uwh@IO}tgytO٫gJۓW|tZ6):.kE&4%^VǨ:CޙYUsFrѾLzt>,7Jbf(q֤D㻊 5㬔8/糏/ݒ&}&:3wu<GfmTS|7΁k,7|'͵2\QB|jCnş?d0gZ6X| V_/ӹo>ܤ/닊>C@Y9,f&e?mgZ%*#D=*i‚`tnI) >CmC:5U1CN&Y'1m.hc^{y",n`&jjUVwpc p/Gp;kY,FU&ƍ`aEuVyY7 +5l&.r P(<**Y2 >FEB +߮pl>-p[?"%P]7rL jjo0a֣C{ ^Vf-;Gm ۚ`3a3\ϲM_r(lr:iDmּOֵ7y98Ol㜭_P!KهIY Xe/7.(O3~߮UW9iTT'5kd"۪OJBfkP?7.]Ш2Tڮ:6QiKaUoidpo"HaF * |8.S_UGy L`Rw#ʜ3 7iMB(-fgGz ڬ?~AꧦMik)rL503tp\$q'UF9m v +ӓf(/%keg8wtk{٘';5_af\Z%Y} 4ޘ63\GxE/O[G~QKvI{NנIagFPD{c:-cCG%,$Q*C\0>?xٻBʝp} @ehrg(a^W xSU5enH}(92Ei5 aN\ðY"حU}QK\ & s]&w_ai(Idꤪa~P#HЮCTkQaAӪҠ*tH+"'*ר):1, =*TI!Up̵A͞C~$=ڭPy}ҚROpwjo[|yY- X.ִg##U,Uews{gD>вXnrɵ]U7LpQG;lhwl] aƀrb b/ /~e n!^a޺j/ƙܽ7ltA:k~P]pņ'R9]W#L!-TQvgfE|R9*?K;gN!UdJճ܂<7#5::=@eE·8u&:)(m/)}\;{ ,X sb ᙿZdӲ3O]^hU6Y{sسܧ ec#x}ŵ_1gUkNV\`*; &ŧNۨkcZ<jNAXٞ|\A@`qXA쪪"hFY,[IA2r#HD 1+C0(!˒㲚mVvU2w}*z +3<$ 5HaN5e3>.0@ joTc༤hń& +4x sv 'G6~ .\IR"7Z Y҄ {Y*JEew1K~j-T\~bLp=Bm;ū&FHͰe),0=}YQ0M8~kR}3Ec²2& ֎9 +a |%Z=Wrwĭ9qZcExkWdxWi "c_Z z%<;dIa:a 7n :.m4&E|pԷHo Wtg4=h2X.Cp_v9r1ɦuBuVoPLXF +׫RE&Bܺ>~AyG%0@?ށ_͚U>⽅ջ?gG۟ +2 dp};pkĘ0B<+,5R:X|a__[k|% %a@?6ꔹ{ sJ(he4>Ta zG׿c=~4Z_V1B#TJ;odwp}*yjҟ%LZd\[(XVӣ7 LZ` FۄS_wysUz\]` r꼵ۗY>xRAj6nX9DaUOf/~7(E4.ɞZ`1 ӊ@ӹ0wvݯ>Wt,]R9{ᯆ'_4C?ɑ{¹lf*Wi:~RvvIpM[Sڝl6Sf9̉ ti @vga!l"SovFP=IW D*BLh ZG[%q3ϥ\;h0X @p#5S5cawKRp2]rTvwNIejyU] LȶI#FjV&&DgӪ1YD?G,v!-o/3Ƙv1>yM*"86ڣiƐqf=%m[ӼP߂RW]Q{{Q=X4yptvHf _PyQ[zfeh$6ld=C!)Iؕ*s׻ϼ x^^&NIbWhɫiL/uM}ܢ̪i2SbwnE:#Upm +<60ös|fhW>Fd 'C3 ,aZwVI*P-(k!uEzk|ŝAp-Ӆ\lTYEF117uQt~v=ٙ?I}[ePl"6J"ƅl䨝UI3DTo:[3U[W O풜<;Eijm`~=YkFMT J:,O ڔ*` F 򸢯p9ydxi 9%w b\RWt9.bp9P5xvcۘBke}^EhԜ~ .WBQY Kl(C:$䅆 ^sZ*F Ugeq\]dWU;yփXɂ/Q}cȍ*}0, BSqUpz##Jl"efF$(_w @[ Q8]Qg ì0kF#0Y6[QFU}Z~&Jtԯ(UQ|(>m엥aE +YLkR_a5JdZ?p(K B<ʱE-hTv.1$dBpp炻H5r[ҸE< Zρ7B +~l3Oiƒ#Q \F +sk8CzM6Wp:p5 7[EyDygJ7o\ӻa$,@诅茲YbY4ͰiŖz:)kcHR)P:\쾬RFb# +h/gE"j1f}D Kb?u\oi%Wu@Z  F.jQQF ++ꝍ2g.>)rO2Tl0!<ķ pk,誺%S'e ]v7˩2T=vj`6 +T{%~ӼTPyb.YwUFpT[e +@F().7 +̣%| T ',dTN SOjBYN>TFID40%7q !yP,GGeSCx`ꃵ#!ZTŊbFTyJ|Ey +ȝ|bA⬋h/Rl[B8G +qhk oRLj@+?µ1qsU{5m_\جO6t;6 +[5]<L'ں6eY L|Ȑh2l"+b2~%.d|6'O +2 p gBd|+]U!0P'e8Y[Ab}fHsJ ,gz_s9:Eb66[LI8(<_4dU}X*w+\6\$t Vzr-drr-"ˑ@,NsMT6 v`o)sgQfiݛ2̱qy*aE&fI{8q$lbE}],vQE NEf[Œ[ı\ǎ\b:8v;S{0of3I|?{> &;wZ '̌@MK + DLGz].@<ALܹu #p;dJp|Ɣ0HY_XdfFXAMt3T +F<¯h&}#s jda}J@jv%8gn n{j=kԾgB3 +F2h9K5 q{TRc~ x!{5b=Yju~5pqF`uHKyZʞHwa_~mȞK߹˭(]9eľ[M=n6)4UWwKjk@%oٯ=3d䴮y\baP@y;3 +-^g t(Q"eRAR[X6R&ꀙwM;[(c2[4De͞8gB,b\ 7xR5ht]K+oWA 7i=x9bWd[eQ[@ #rGL nԃl" *t'BJܞق}w ?# dɪ + b ~V x BR3z-5dxF#;2ٿgLDˁ(ү|H0Ap(#p$A`Zv˜_4mtˠHCRig7cQ-'8@C.Klkk{{Fэ9ET;RCz{uu렩O) Ȑ V0]mh@2F~Q%݊QQCa= +@tHXmco M&_\ jWRCf"xlcIWbNH! ,[x3R{x +>"9g=rL޼O [P%+SY;[պrzWVlu.9o ++d2@jr{L' Tޥt\b=9#]1R$ +g1(#S +4V&$;ݪtѸW{@k˜ɗܭ@ALiג ]Jm>51SQ;S#D[K>#7d 9`{odOR$DA oV X = M%3  ~-d7v l + +˭3 @C@2t!pkR RdpadB;j'̀6Im)@ěٯD03CX xl< +' + 2}$n},fvio9-<4z#FnTjoHL"v[WԸb["cSLi="*Klj- 5Pa3U1E'gJH+[p_j*"$5@SGxFl7gslf!8(jw@5lSGUdXRXWpEdh']  W*WL5lXH*dv.i#zap#{uz>[@p8 +OKJf`H=D + :o}%a*FwF` =&āV*G#> $P+$T쁺L0 +e`6zDv~gH'3QJ?78z<Y K(1`|3RP:8l(] +XɯFO|1 +b}l B;QPb |Wؠofv *2 =GLn`VfOJؘkY+[9)$M4E<6f`JvGheO]Z+w0X㠅-)аٛ3kF:ob + )sF 0pE])uW dVU +~Ch@|ui-6q {hLi8І|q ,8ÓXx +CHX5Tr+,zTr8v+俕=tDu ѧuڂ{ } +XbQpky~$ :}y/gBۗ!PSN +4)Us +H}Ó1U<#⓮X{3D;ʤ9"5 _i.(~{52Uxv}<" +4)VU'FLȬ}rL/9;\[HW4ޗU9S9ֻN=T\2Vnw z6^GPAQ)":Zb%3-#*4XmYvvaQ+nfiM,e =D匶hHN*F`r40r%g$ +S'"4 t*R|-f&jyJuWSC;º,e0eXbjĨR5 *a M*d8LNRl'N"3hd)&R x/k<#egd|RmG"͍#7?nWlalu|e\w|yXchJL9_wrLkLčݹ<5UVԀ2yt +T w @.=q:bu_s3d1~ooo..g3?ܽIfN֮f.D' Kw ;'^f<W$gܙ7c~9ZH6ڪ߸vS3'ˍC6xdT\a%=u̩'@k̬,2@;d[pόo= [쁊ɛ@r<-sbw\O_nYWhGZ֝?_9#ѻ#9. +3"6{2Ll &01+fwulOwG3졎x~-,trJ J(K]|"7qlvv.ǥDŽX?X;vG,,гSAiȤ +O|_:?8tN>}͟31Ggj+x J4LF;@OA `@5"=Xߚ?rY5-@0W":2rC'^1EBk;TNvގ46RSg OƎ!l_77sݍLg6ssFGږ͢zy恉Wx8T_ 6'&M`PkԽ~ݎ@˓v}ӓǃե/1'_쮜_<WOAYoM6=_Z43S[@f\+4<_41Y#!J ΡX{3:v)\aRsS*_9p}jgX yn.37鋷1gL=Q*S\aJglr$`H}舍ВR3}@]H'=iM# +,+dtJ΃521-NS-ï@H@]f [BCF}2_ +㇩ Rdsd]  +2_z-T;`] Y޴KLN R]jf`j|z|qAԒ; W+0yRGbX=Q\(gbF|ynA0•LDLmެ4:+w^>um=}zBG`T|+hbAo]"X%І._ +Տjݩ!3r\rΤd06_d!wZ%ff@87I ;WB[ X W^r6yv'XI67 :qZ}9\hqx R ~芆 + }*X;ްl;[AXкD&:ĉ`a-J!P7!T0e&|]ӾČ15Xq&meS0#Mz6wRy;uP}J{*סۊ~ +b_ $6+ +.DTB&耖A8dlTvTBgCt_N86%6{扩gJˇdOS;Xc";1hĕJp>T}3#4v·:O&6fSL_'$t:ވhS3O ǃq2U#eK !'&.MgY1xèЃA>Nj&txΤ:0/[X +T:^vgjj" +q31j f=+R#~`ϸ 7tYl:ԝ@VRA| . fBdU!HU3|?̏{~O>yd]TAJL>3§zz :]}z{ݏ~ҽq=޼ro%VZ} +rıΕO,|kqS\v}ǟ}??o,MlgNsz߈A>'3jDؽp}68q+ NR6斷?wҝ=˯??G|?Oū?z|~|= +'±L]:}].O/@}'ͷW6vcb`6 bg{y_~;|;#y7U-ΥmN&NWo<߻7'O?O`"'.-p2Ld|_['/piv>fѣy3 XqqDG?y?|gO>z 1׆=l0x<ݞ\]XV %p{eؠaatu2P[=~/?/^S0|_Ͽ?uCtiη Kǎx煻o\yGOoOݻ/⥫wͭG-:ѣ! Dw8ͦ?n&+'f<#Wv~|ow?ӏ?>W_֜)Z!PRSV2b@HJ<{߼/__;=+XM.^mǧ緎|쩧/*x/?ϿO77|Y8zR%fJkct&Se}k_z_|Ϸ=oGλ<7_G6lLaA%z#P!,lG_}g~o?o_~ ow~{~ozo._쓣J 6{LWC`=sy׿k/ T_Kw-exujPnTwje;;rpgݗ;{DE`hP!9`LT[c̓+k{z];3sl$s9*>K V n:raiX"RΝ?>?>O?zϟx=;M1g#D=BPB8vn0z@S{>_nC?x֡r{(,nKP!-5ȨSp$#s՛/k/|߼~‹uz*NDoH\cS?׿;ŻNE368"*Xd(S't7n\~}٧n]?}HD}&,+R<|k׮oꭷAqo=zӏ=xFk<$#C*܈56B0x~|k='{_kW-5J.Ʀ^ӭJ{;h-r-XG =Ql C>!A}(I"9FLv2@I=,g%@ʍ9CF^F[Zg%Lv˟q!v$x");'WWD#FFԈ MP2;Ya`<R15DžBhѬǘ!f=1_cr@ /Tcc|)JDD,--|.DrhiUJhHnd3A2tܕW*fFT,ƚSJ2U4}R=4{CJWB:τyo@n/'F,Ht3yF`%3{TnSj;"/ln5'éLy|>}&CL5q)͇ B5&gXi@(lFH4>Ge>>%&Pcm_eRDl wЙDqj Y7SyS0<'UBܐ +1 +fwnTYv#p5'G=I+8!=F*GN&5l v`VBj"a"ilֆA8cD}pi H+_|r̳78E#E55E&Lj@-X`s &CJJq( + ^7`!7OFdfUY}w@nU*La+ F Ns.Ak@G>)׺ vVehpQA3f$SϹݽa\_a< 7#Y.3i!Bxi;|#Ǣ&wzP,,6ҸhM>Qj&,;ZvDevw +Yi2d| aO\LV}66A"\S(:"bM-̎ PrQ1Ag(Gx`}2ʹ4nJ+7`Nɑѝ6UK [+oW,$D ,쓚r+C2藐LqDKh + "ߦ:gm3:,'H&ȑ=5ͻeKe3bO +_aT +?j;sf6vG<ɓY +2@f$)"D Vs;zhN1T^I0+i$R}RTvaWHĭ4ȹ>IoP8v;}̌qP;#&wk6ćAԤR625kBNoŬl|Իd”PN'c/s#Bm<4fHx&Q`9(x8fDaw՝ֻ+BD=+5+E +F ҄/56f&/Ι` #Ҝ=ih9@YՕRV{ր摝h,>8:-V\l 4 FCj!M߈y@ +_By2EE쐁52o!mĮ`._}`vp=޽ZjQk[n`L>#SE"3ºzHNBv*wt0SrGLLL Xx @ +NÞ OѨ;X阑Jk [p'aXx,#|TR 7AEW'D%PœmDۨ kN`@;EP#XP8SFoV1@H)Z-n\B^m@i;dmޢWԻSǮ =`~4VJdK*+H(ne9c `JaOS XJ.ѓ!͊l-#[G,v C$Z\l aWA>c0SՖ.BTBűhPAKmcl013j<1`bm[.4ӧQeĚ=E_y2#0GԸԸŮ'5rJ3 DP 2o@:%[_ݧ!mO-3mrd6q׈_9u`4 @:(Bz24v'tTHMآޓ ڝ[w=&#z<TtMSԸmur[ OxBc f Q5 +ꯁZ48#d#2m#FL?$0Ss[Fꈘy@Mfkd +-DN~9$5z$I =g{MmljH>A2dS1mZ s.)a-o&"LzrP # +!Wdr': Ƈ!=:jѐ!X_RRL$SShdNd'3lq%}q 19:Q5Z {F:D)#bƤzsZyȟ&{ғ_Y7/^|W.<(APru>,AL c ٯr4ĵY&ÛW`}0W-9"MW_}pAb0IM0N{ R((8JQPY16NHN\Aj j 1Obv)eJ+Z<b `h.2cUSzg^4l Ȉgsas65Ui W[6s p` ۽ Ie H4} +QJgQ_jD `; +tz踍)|9Oe%FZuhR="1 'i`ȵvO +[ѕx58ɗV2 >]FU=bm=`4XHb5(JLs'aF;XKebV}=TNZ@x"c| ]BkPO( .#X~Si *Ez2_\x¤Kv7\X'bi9;v>{z}0 8 5@ u?ta~St|65q&3u-OH!- P3Q Aج+T#M-M6;[er&'mWMؿs Yzgg~ ZlK6^.x R#9 ]tcG[uAӡrxl;=VYHvLa0(=15zO~ t15TeÕYQ3@e/Y|Y֗nww[߰1` @R~:A? wa;OR93]6Nq<:,IvUmT–Az NP ip9H VLC/֓ )6ZB޼FSZ'0,;/%q1yg +M:BxwRB\ +Řœف'l4kCґ(%"-Oǖ] 2PnNl9E"_X46RnlP5 ,v6g(e"2$8highͱL F,Fz\;;Nw=Q= DueWGGh 0(.N\"`7>gv|R;/҉RtsאqL;.a8ha@/O U(㋷ +3'ScCtn7w=s\s*<:ψAao%g/y +0ϾuKi^lGVn wrٯ#,~+S-δp@i$.+ g~(?uoUGC + ѕy."B" +L2[bΠMT:*gRJjaa7?r 9 +ruȈh%kYXYp2R0dt'#vv.f'@%Pd\V6D!sj+x <,iPV`Fmɛ KsK˗o݈7WdLgܬ;9ie+z{̗rk $z@ +_Wb1;AuzW07ª75 0bu!hWp3ZY=yc#ck-l\p`nJbS߸7#)-?# 2- y@D񟌌KmR d + ə`e4 +7PjޗQ9hmiCBazD019~:XZu&@{@X73%gt+ S~4s6cd Yj(N&5f + |5g +M rꉩkG>5yze;5~АgnڧčL͝[ \~La4vq~c ݧpJ 0ER3-ƀyFUcA-8d{@ ޝ=e da;b#B +@XJuf5=ҒX5ݧ%VF'̟*X8+â;h;#Be#0 k`JV&8woNZjJ>|J30S2d5lAj} Q;#Vu"Tel76w|!"bu/##Jtt22P8&XTev'Iƕ}{vg^(fD΅BTBU9 $R@ɒh%۲sqn;znw3䳳;gK9A:${y>{cM`=N $؄G!ri=F r'@;8DA g.4uy!2r}Ld4ӊKWn3Qa&`}{US @B #}.M~X^:o]Xls}:f1=puPpIg'[<TN0(^jE#ce;/W6}d0!mAUPDFFd|.ҹUwDy+$`bO薎0?mo3@dt + +TdH.L˥6 B|Å}R6$ŧ ް# Z2yDȺ\?0#i@n`82'Usl=DPxQLd 瓍Diafr>bjBoz1nY612P|s4*KWr"f"dNhKJ-Dۣ,m]2SN U=lNJ%cz*T鲳Os3llECйpBupAK>p9[0uX ;h#s <LuJ?$+ Pi?R/mSr~r4{v`a~etmzj3{g,I'Lp%c% ȸ+g~?JɉvBv[W'zUm4"Cll,^`/N's +GR3EF@Iw~ޡvq'񝱕NZMD@D0*5:<$õFl026A!*O3m=v$bhHBlm1i"Xtd$"0! >vhTu"0wz'oCd!J D>QdQ|Dnh=.ւpy;Z"ZfJIM8-S+xs\U&F5WBG>ke6_^@lDtv3b‚ *d!1TMٹ;W޻CX̡,4bFc&ߡga\ml5x:Hŧez2FJ|R\WLb ́A7W4C۹iEV/z5'[1g+t. #O0F %.Μx692z~y&"?=ƛkϔ'بPfz|0a$57b0zfHj; ~ϓc:Oދrr< f' 97q8zFZ{*i-_:x(@j nAX;S]ƣ: ZsNM&@L +qYbU>|U8p^(Si؎.=o`2k'#F̄("(%|ZN.|kszLMBVlʍKumR(ލ elI{%ŕHeNG ztNaD;,DGţ}.3fJVl܀ȸIzrϤתT/'pL < ܈}aTqZЖxg{_+N_{̄I \vgr[u61JhC&<QF?e:[RKw^>\܊Z~|}7?ܿ/)D.l߸ND*2*S@C%'?OK  +ts;`)̆[n3J>}\(; Q171zuԽX,idvzG6Fk7z\ۂGh=!V,w6=a{]8$m2Յ͘A;'=l҉p擝F#S}vh]38y`ZXl +'!ÉڅTX4OB;,l7Q48mu n| DF <4` ~KGP>#9ۍ)|c>YpN +Hi`Uى ّSSk?aHPy^N):6}W3f_HSg^ Jq2!gp9o'cTbSZez;Ur _R#n(*٥WXKMNh2j"2N@i-<8GNA%|)g?j&<)'g }6Ehe>=SKWμ}Na{Bf0& Bp1<\5 ^ӂ (Ma+6A+t|OA}}QkE@C^%DІ[˗dk Ƭi$GsFw&ruo/"0YZ*hi\*q:`.In>Qly:__`&@w2Ab3J V6Wn/}.8ɗ^MX0e^6CHuyU,$,Wgpot`VKN"5 $>C}Ov{m46 +?l={>'db#C\~&X]TfNgɓ\΍l,(-H;\Py3<2ؑC=vg=:R3"n Z*Lm$KnJOFАS TXfh +gBa\,d-򅸼JJc}pS1*2|bnqJm|]17)OlظBaGϼϩxx +Tƒcڲ*X5OUg` +a_m;Xw56Qa @a)7Ki JOLTW@VǷ3; <rƃ +<ɣ~'H 6.qL£ŹK-&2q#7˩A;uõ?""ZgDUzL#>Vt(eFVL|n~gLfET=Tn *!EG%)RY|v q T 3)>k0b]rRY\q; )8Xv&hehzKO̤Wwzk|qhUibaN( OJ*S瞛ۺjB6<B=7|)rmw>-L#%,&''r;ll҈淮ScsYH=I;LMfjsskKdWbfTH Rzx'}˭4Lxz`Tư@5\\tf͗a '|6DzJuQ2&'jddlg&͋/ +S\vn+1J+mFdKቭϽ @՚2SG{B96f曥:(4qNBL^*>^DKq6>ll@]Mܾzx-eb.5V8qZd @v{,\ݯ2@RY!TXdr FvN/̝VCzdp\|҄p ނ,DD=1~=;sGT57tmrRn>PX!f#L!bv*ggC&BE.@FTGʕf|xnl;=΄K+.1䤓 NxBWG^yAE4+όVok5PH݈aB)tڄ'cVYl!>wg$NЋL4r#3V áj+sd46#2bZaOnV"ߦS}`h ̈s˸Z m&fNYDjCL } Jk懅 +(QTYD?DX@AJ-?y?V]\\{/&_ݸ:yAvJvRK;7Ck_+sT6PCFOaR)@cӃbpPÆC]hDdj ZAa_dN<"*I2Rׇ7oUWo;db\MM}a\JtpS92n:L$o +cFhp l<^;usϼ8q%6 6t9( Ѓ\HX,,@R-X< t۩~ +^UBw8f.ABiTc rJa| +µhm ɡkS筄dge0IFa܉țgn=M4" 52z$-N(@96;'WVK3yG6|upp9k'"̳Kw}.1׆(g/>|jo7Ӡ,D +֮JV͙m#t1)8PEU/[ iF5чuXqER8m)hnOi2!N TP;{SZeUzل޼_MF}NIǽJ A O8s54^,,OT[ό]7Lj#BxŃE{3xdN-`ܠ廝K9~,jf +: r,H@HÆ'BRN'5/EqD@C50Bj7_‡Jr̂D.ՙgn]ه:HdpXu#: !7SAwmYmx`]> prx+:Z.fgO}[Bnbҫ>9zK_ݤ##ʩrv!\ WFネ-\%Tl͕[o^Hqԍe4[sJ5VRPfF\1VLsR7y)5WG ml͵+{KE'_'^t/.nR6pDg(uК ⷯ}g_p]LZtS g+ +s{Buaod/{'\]5zKRY`3؀dy~ IN*sImp:mV4 K|T+Lx؈k,>=wQ]Ly95R93r ٨٧9qsx,o:s}6~=#JS쬝8x!*mIp1$S0!/vm-PpvS.C40OL31 upJCL$PV(8VJ-'(C,aR`I-/|D,h֩@2v X|:1%ԲR47 gg>w^q'Nes&'|j\6.Nm]/] H1:VKƮ~͗dLH͐qGȀ<\3x hU +ҍc֭h؇"V3 x,6vp")MZ}%(/:#EzW= .2f܊z,Tu: +endstream endobj 108 0 obj <>stream +K{cm߫8,BڟN Xx4Y Z#|r paN-R FX b\lQ!|1P[Hw`AWpm""JZ\JzpdVHV'qTALQD%PVH%;sp16\%^3#@.K)T92yK+Bܜ9}7}郫߿l?{K/4ΞSG.husI51t﵎?sH[H#`};7y!#7RAC1. JB1G6BwýoD|O,$ZBnK3&B`cNAzT0 q)D*`1aZ Fkz'<0 L2-8p|dN0ƛןл!PeM؉ &,,\EVdL8LIICD9HJNJj44S^)Fcleju6;\949ukWHjecN\rt"Y[:yQіc:l#6k\T 8ɓw]VMqR?.ˡfxle/~.\Tⅇo|wmN'ftq8;b8|=nSl)ɍ;7ۺTZ#P3g^8w>9}k.+g|!VZY~KRd|M/.콺쇩\{osmV?f!Ay萞nד'O_| k3<~$B䩉kBvIY13U|c]n?F99m0F(; mlgpٙ,ZE-d>hU,{9xҌi"lRP)/UcLG߀^ʼnk\Y)+,FJ Vg"$Cjb0kyp*eh6wznzke_L4순n9il0sq7ʄùB UDЁbg^*ldM@ + OСb8٨51J6{>=ʏjVh 6sf +X>$Uo8JH2u|FgZ뗓# +"j~&MR-򑲋[ (D7))%C+Bm1RuM&Χwy97S^\;~vՃ'\"p| b&ȥ> g){o=x}2Ox۬No.VCPiIVo3S:ݽv?*5NqoS$CnB`AL @|'Og ,P>i+gp9('v0*ܦDx#1.ܚ\_پO᚜K6R(J1itfE`2916 f$a*%NU mTNAlNR\8Q쵱X4v\*! +#&;!JК_b֩@fZŗV_VLIZ$IYv3iWy$jСL\  p +!L؉ pDlL(}FJ iƩ0¥1SzS҄{01*@Hqd4ߴ{)".:̆J tɃkHq~&؈ XrIkupiXy}osބP0l K0=Hz‚Bd+@T/ Bb8yvhz} XKiN~'&;pfÄ('P!!(I(Ъ-"t` 8`* +Pn6ܕn*YN]x^C=lϻdO\z 2x; z}|F#ѐ#\ p>-%`.!\JI!6E;R 9>AD 5dAi\RlROu9@,Ėd` ,Lb/n'b Z|1I0oCW1"mQNl !4' )TǝXv$Q1pHLҍ> +Rq1ا݄Ŏt0v)` a6n}66bFt{q pyF[ ]DMDt vܝ=6 `')n\ DrIY}]#=N#m,8-Ib ~ÊZcCLQkV:$8-WGp D; +)hvީwwl=vc(FR +$ x0p?^I围w|$=(Elnč. EOl^hX +jbu2ShY +gA/x mNG=mvXZ|fGx >;Z RScoY0U6 1'@;ܘzF*k@peBuB#`aTx 1L: vh':lf0˧y N̉SaR7&p'v$j#ˣ#^Brz࿠Z|b2Ht߈vvۏ3w:z>G(/AnIK[lτBjfPH=z8 +hs$t 9l6Qvz BBoVs[ 'H6 c!ř48fx. !@Hm^bi@_@Br̰"GwN]}WOu4Y #d0}PЀi!XIॣZ`C0JSvCC%f0qt08p#6`DdFOpCtvDƥ4ǬZx|&B,S+ 7C+rrFԊVHJJoA`SD,Ʋ[;.%!0pJ =и2i;,8 2DDG̰͍8NA/.yq.`sERs0΃2wn3uڀ€2 0(*C{5g{fݭb.V.&`0.Xխ]dqǺlO~!X +\$Vyu@wOm7;MVdnD>g5:Xu C8e;n`Ԏu4B`UEN`#:zFw a(}h b~ގJ$ Tl C!-6C,}N j)9tn˂a?B(1Ih\,,/_u:2סwl}f <$ Ţs8L RQ;}r~dn0PEJ̀NK@XC~%Ù0TC% |sWS|T!T0;ɣ=LzHvQv ˱r}llv/+N7gJ%\Cl8SN-ĔF  j.D&.s2`H ~ ф`4S#4TtxxƂV0mY?X6bŋG³[[P|(Ǟ=a[(5 /D2>:(!E% y0aX CE Ĵu>s訡ѩz==zvnW0Z)pz<00Lr$M$J)>xwM^+@Na12-HdnTf +p#޸>ҨkJ,1.nYN8qQO&ِgi=٫]=]y~W>y{g?Ͽ{履}ŽV:`4Zm~2Dh* Ourd~o3}tֹ'_9޽?~?=sm'U"LP" +~֊As޸=ꍡL}}g~~g_pd=8UQ1q0.5u읯cyb+<_^ Ƹhn٦0̆^ʃ3nn}ůK/^V#3㭅퉍[V&܌LW~ɣ,ww_ɿï>_waۍ7A9Ĝ,eV7o7pˏv>8y_^~v֙|.P2Hr(˳lJvR:}e-ʳΕ{~k?77}p[ls4A+ӆ8M[$-*7W&/-i.|_˯<=ۼ^V5L\_޻>?>~~˷?ֿケ1MGi g(.᳓KҋgbO{{gΖ3v7n=n$*˚'?~1fß|p7˗7zo~ٙuDVl^ali||,2,^^ ~tՇ;< Ks_7/чg741u&U.q6^&;<+ _?}?}vcg<>5(XU%!e|[(x7/\k_̿o>7׾x_~o>{g&9*<َI2q3Wo?7oo^{/?9ˏ@=hMSEr>_!޹9[[,_~_~_~|~}O?7/Fk٠̀HsqQTtcC|bW/?9_~soP6Iї]Id?[}o/_=v޽XH4y02r0 +$"~̗sk'N?~/|xw-o~Sz,Yd +rhnF(piR( ⁼JBBU]W~[[_|/o}$b7E$R?P܋Iy󙗟)}7G^^}DF@-K(d;u%nm&]qc+|߻ +Fw^{?P+ⴵF۳+{{W/vmkq̄:W @NYlN'I!Wr/eŨ\TLܴg~?߽3p["?8]kaF"bdV  9^gwۛ$?xnwӯGwhReKAt! `9ǩ<2[Lf;UO^;kەzfaդ38LAKU5xUF*tjy|gv"QgxpDtU 4V (1! !q1M5PD*C"r1*T{ KV+`lBb4%U0gp3N^\[].*C +ㅳLw/^Ywg߾\.\UTCF vPxb8=& ^]Ѿxe?zo{xeViU5 dXfv!<χj&@4gA&2'ovq(2HE:0d0~ԛRTג\NKd>V|q}PﯔFh!Awb,=ktP&r~V'K3#Qq\^-l +ANPR抡9z `|ɎzOZP7 +4WjyիoX:=YN +D)9T<>C@/*R-5 +t0$8N6ÈX`>m̰DQY$LCHWSb6<#p E fz-Dg%R2߹*5 DkÃхdDJ,/q%TB^m"R`ԮcOp$B2`=΍Bvoyp(Zp)9Б`لc&n[rpn>[YJgGh5JHAl/xp}wo}f~ Y +>T[}Q/Xft/=t:9ufz*\L&U)hgtnriHL:WG)1c3ð vgAA2zN4R1y1dr]YܼK}N!!>bTXRL`KDPV+Ua=JP ^ +$ FpÎE`&kǟy= DPChEFH2; AR7 FvԤ/MlK醃{(VJ 0|_7Z]v~W4DϒR>Mۡ9x(Apȅi([#;&> +,bFo<RKrPIN!A-AŸ@+%;uIT +>6H)2XP)=1̀TNuă^. aB`z\IZ +J8# c*2V6mCO:{\ʓ,v[n ${Ȓewb]̴y|Uzo"2#"û̈H,_{g{p.!Z ocMZ@@BuUTf83PRJssFLLwփ77Pudyq{cq<#(m8e3B57]toi8H(__2 +s*(Ød~m'USu\/S!/]ny*"6~Djy ÆH6K0W[%3B8aLXc@-{LwʢVk9 +%ߧmƔ6aʹdqq&wtsdڨ +;q}A%=&(#%;r>^$R9t֔&1}ayDxf܅~+q: c7*t]9 3{?{UGQeaWk~"C.,cjaݠYF[nM, :'xsJ-B HʛzHx*eqSK.@M䌫Rzdm —0|}ѷp#4p,/ʽNf/a:S^va%Thي3WlD' IWj׷es%Кry +EG;E͝X |Ծe#Q}K793 U||)YٗGgx7ڮL/!&nŔQiIqGeDi{H׆L)S/߀ {Z/:Hen'O%CbG[0gcn\õXϬC~<nZ?3}ݻ/GjM^w8W{er\2Sia0 pMLaͱ< QD6ոȍ7\TǕcR݋)^B]QJR W3^s2o #SK)?|Wb@GR2!x ,%.;#b.*O[Jֺԛ6 +OTAMJS3Dj-y)?[DDnvם,[PKdFWNƌ)ܞ(R֮ڸqGUYL(EĦ,Y@Jd~68eq'JYmvF@ڊe\<ٸoXJ_ GOg?G:;йKdҁX9óxEdSg1iPWB~73xƳ3j`%zΉbk 9~DJ],3O_["=|ş_K˛F­яU9/sO.[NW]LAu2ꪏ\72j2L23~udى dDTl񜓪t Q#I'nrP+GAH3*wP}Zju/NWO)`ְf01}(UΡsӷb$O(H(]ƳG!e4^,V-QXzD1r|i'(߮<9W?W퓗C}#90y+!!G䆗χԦ-{o sYyG!dNn\^q1&ݘ=dXzN^6mT!q{u mTfx<ij5GU~̛s&3ҚF6h?~ӿrTA P:+gA\87~.I3t$ $^?9} L]ܦ>'_~S(rዟ~֎[գϫ*H{w> ӹ\-^wMe|)$,v,ӸXU=ֺOoy$YԛhjpǍ/G6f9wDSYT];*woXo2'nT,r,;|L/rQad\cVy-4La>Ծv11cݷΑ/2F8V?NWa,B*T}'6yi_gqc9qxxHuD*X.,:dfS^<˞&-`e Oυe~&TH] 3&7b +@XnPgRi{~ʠQwI_"}s,vb ¡*o*۟҅Pi ~ə_ԼP[ >7O_STs|Vl?|'j>z!7%kF=?_Lt9eǟWoˣxGèqPrs/i*{rejp !Hɋ>&:Kp}H]ވ,pr[CޛWB<,}Tj>z< ͹&P[ 6$`H6_+'HGG?"mp1Q X̌r5Ku-}F2U8zGjB"׾'r$meC*|'y~djTvl@ VHlQ"[N0qB6v\#޻T)gNJo MUNt/D sb+UɦֺJHY3#y%qJu2R#23r &+j ?mmX6[ie76œi+-x*@O;ψT [9g6z~gϒC?KAN* Re-zȌTGg_eN揅"Aœe|Kv.1E7]3%d + N;_u>L产_? ߺfP"^ O~&3zTܑot|'cڄ/vHQ|M6\67ͨFr|y&XpxSDjoD+>A0F/R릝^Ʉ:o>i ;/nn7Vz¬ݓT怪jA2sJr]=ĴAPj&.L"IYR+ae 0tfo?9~g7~[VT%rAz~;P~R½-q͸eMhj#^DY?6hfdF\u.~ QC &kQ6~:g&t[-:O]!v6`]3{Nd64B|ro© /-ҎR;tr_Y\񄯝oT_lrP3Ews݇f(JqIdƶJ,րb//BNsǵSS[v98bعH[#z=X>PJ{/"BDfFQeVkۯqBg?^$72.oUwD~Z1;WZ$ik'yuGTϣ fDjlvnbb^}bkx fOgй];/8LWijTs:5Ocz 8k5tqe P S`QIkBgk*cr}}*MuT9׀Ik*T+촏?s&,<٨ϟZ&2.@d COmF*Hdv@jx\Xȇ|*?M&[v#D;CWX;EɚDf4 :8Wz6$i-/&jynP=- =Dm]:;Qj'O$n0;Κ̝|"i诵@`Ct1Vk5Lc/.LCYASrw]DK蠟5e e2=33?#΋k?`R uuD?{;]Rzm'?:~ +m=tk!h+Q4g^X +n6лK ?0\^L)OUd-$0|FUܱ8N(K7.m(R`uy2h׺DQޯn:b.nů~Wґ yFDu&J%B.0HM;r1XzW!JI8J_*}ۈX L:XuS\ZDs|\aUtqV(Ր3*.G[4Y]7cGNT~J^n A҃53ۏKfM'0]; s7=zDƅ`Ƕm-(R0K.,@-Z8e$זh#xJ㷿ObeNuK茒@ͻtDhDJg8T"E>35dά}f(o)(dH*0X%I6R"ݦ3}Ti|-ET" Ef %%APĖ0LKxLaK*qH,KՓUu4=D<Л'ѣvXmENiu_?&La=8oq'PBq/$2qu D$e4U=o|V}Z37]A+}N(syfD$LQU*_v?MuVLMWb ꈲv)~[V6Qb;셥\9O|yFlSø2do\4x۸ mbOVI/GvLc{ SLgvR%h3vו S;v,Ӎλ??wX`w Y @ QtLjŠjLjnFe8Xs-vWgR8jP@|[}5 2%2հ#zExjKL8kË-[xy O3pc +5pY>Qkc>rnhUHհ\g;r + *Mim~]|S;՗lQE* 6X% Duކ3c/[ao/6| =.}V1UM(k }kS4m^ȥS?]t#"o9s-\i]jqcqUХ֞{js^o|Sl^8=G8߿ +e%?)LƜ.^DX^{%*bR-]?{.^shz!lKlaKd$‘zhDzs \RP diP!PZv`R3)C0kaiGdAL㆐&*|dށez%7ØY>e G̺;&b?\h)qa ]`l[PEGX^rQm 1\=ۦ +oPS4= &\&j/YܯM^UvՂ|Sg-~7~"FH(b>֘%q}Oc2JJb!aL?8d0^#r;\n>BN7v.Stij([UOSd阵(s?Y;<&yKUU,wųaΗ~J~p*΅$7~ _殇0zw2x K'?-|RԮ*\l+AՉ5x94μ;_d;gMmDR^M@t~˟HF鋸 ͭXuAX{xyP?'2sLz8cR4|` `3'p~rJ|.!0! l`0&mH#/VB'@TmHŵIlXfJy/Y:t\8TmxΎkhRvB5WT EB<ܲ r7/DĘ\o['?GTTRzP;1}5wyUU}›mIc_zz3^TecV?NWJwDLNR70r-Cl9E,)sBI  xU\C2w YcB;>|IUD[,yRyV%ʦtEaB\ǒ}'fCŨD? Ef ~ꈥoqm?Vjv4 w_X{?A`1νd7!$yk'!Ɂ  [la15M.lb6 MUIJ,Yc2CBi&5)=\DbT*|d8tWد~: _9u`<&MVygv=9m{tD Ɏ9, X'V YDڈnpri9Pk!B-rHiDpUc,n[=VԪ%Y*jZAt=sRrfKv"LT)@l@?\!( ͬS[=؂{[o9P//}tv+"ï7Sr[.(Ϳv_}hlōŦx&D堪72UXeȕ(W⭡TF:HPr䗇 Ύ1K^P:R~ϝ鼟)o,|PƒA:bC dt*^i9:gJﮛ^DA@Rx'ڸˇapW{_&тKyXPא&4qJ([@c&(W]';wle;4v-.֡r6Mҿ&7]{CIghz"ݼ `bV{~ܼeǖU;ͅ1zŲwɈ<gì͘a'kX}/sCŶT%ePy} a2@^J!_: (hJ颀TϔBH$tʰ +ը@Z,}À +Cab; mMkBj,3e9.T,3tRjqW&>"/reo +2DB +H +F5xDg|vBΓbI+6"@Fyp 5B45Ti+,xXhM[.j+"_ȎS1uJeO>;͈¬H궟6)CtaIߍ^Iq/Ķ.oerig',{Yp1kьmCp҈`Kbeoi5NXW~tsk# ?fEx}`xn% q0a:7~q)/OtEu[+A <3Zn<';T +5GTiczdD8p w÷VPc5r +"v̞9?eEJ"=қ±+Qފќ/ xm&-XXO-Q t.cT &XEB.h7* *;5\GZQ ^_*h҉2yPG J 0fxKA 7^2(W!!7/{*=>.,LDj+*HcLX[icvZbok`6D"ARShF/SRT׷=Έ[;t4h.*Ȕ+w`TiW:., `&:,EǤ5 eTYGkmxE+0ķ~BqK88z@RbOmw5'xyTanzj<5B[|I:"7M4R圯N^~C)G(uNu1k>)E[P3RQNP5mdfϿߊiN`~O܎hθ uzqu +,Fd[~xzg%ѴӢb WG@QxlX&ȕS +/n"FBdSxIHk\~KeVbAYTȻlL+! @B/#g QLfqHm!!TO?Pٕ&iDjHDa=ScjWrC? +XrOR!ˈڿVuERT +pkbՅۂB\nk ! Dw㩚#KT-"wy7rFk*vc +AaJQ.XUI9ecvT`ێp}R@c-!FPY^7V}7BP6tEB%݋?1k%~4h#挪Xgyy&@OtvjPa머7uѴ{>& g(m)}$PVY @;|V<MI]$h2& qE{\Y?Qs h!S}d%v|BTùmy:݇1͋l-ޭpu[\L:%WOc8*w7; h +ej. r>fqWbDл/]-{l~۬@982PS`-"׽7a|Z.] #&WK&wLg̶"RM PZV4锹Ä);̊W6|΃+߉dڛ-xuS[SSk'M[|/آwۜ]O DC|}[r%;`Mn˖PK+)sLT%u:2_֣*J#Fq͕pۊjaM($`"6(-' (P҉Bj#7WqPՈѴ?QQE_KnǵC@97UZs7h-kKt*8JTꦬi\5R͇N`QT?U>m&4 Ͼ*u`X*j.Cm0_lɟr˘6BvtO&Hx6$\3ʕ cARٯL>ihKK~Sod815x$=bcW-bĕ6x5? eEQkNOɽtb=npwVTqŒ!~5pok>Id*Q͟(FŝQc)l p4ОQdT*#^(K]y_p%Vwv4>r Bt{'nBձ|TEY2-8?[>9zR~\*~RoY-İ㖝;*)k!2BxŻE\S 箏]BK8 x骛~lM^}<~E/>+ 1;g6?}$GxvaNA}\=J7Ys,jX8Ru E#ИQ?؈$6ZvD݊$cO7ܘ 厛[ !@u\|G\fak`3@&3b#W̭l2^B ?s`{W 墋D#4eaOS[_ܴ-nƎ|nV#*(1@ﶘoS#F`LlU,.>| UL(U=\ $+eǵm_ˆd1 +] +~y-Z H>J}\K+ sKף:zXDu86&gRPՆ3D->y0[`>؟s=45-M>!y0_a-os,`O7#EV|l/&[La8,t?؈{ lWm`Y; SYr3qw:bkQ́讨L9^鮋[ g\zO_B6ؖ0_f(:K°F}⡋>w}c,Bj?@?Ѓo0s*Crw'Pu 8N\tC/ +M : Wn\M&;wn ADZ +r5̟O?K!TfDI$;}L"Gs>wpmrCs#(tfEmPFR $|ۊ$#|f|# ?¶xjKaA2) +4CL|#n0Xq#yv@.p" +wM"Y9|dq S!_ٿ>{z`.N9}n\ ݻ7Gي+--4LdbWJ}KS%OLǥg q{1XS£}ͭVr>?u0ۑR@QH]1H>6T!Gr#._WƜC(H&H|Gvzσy";L_I#xSG`o[A)im䈥@yS|dfF+s6%KAV趏W 74݋Jj1ᦲb>[<ڈh7W-"8-춝pa&`h#"$gF o9(FӀ1aYPA +v}1 QN> >-P>^|jW `w6ڙΏ«>Ohܲ'_jry?ȔÊ\QF'~/Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jQ_/$hc^AI1{¡cl9^-<в4˶2$D=*|(!/ +E= G^Me}9ZgKd1n_kM(݁Qmtژt^ˁ@oZ ]p>e~±eoYY.U|mxbX>($ |a_6S~'gspO.<=~0F+2 ZCP%8; 8+,,Nr2[$Z^l|w֊-Gab3[\[ Ry7n[^䎛!ٛaNX 3֢z4 ayQ"Lޏ) +-SJ D]`KΘ-(3,c0R6L[\ub&"puLK8iʌpI5ZI$APk-t-"\V"#uUVeVVUWvWwWt݋]c7{ds֌N9}wUKOBbKN,QW|'6#,*тtrc鞓3jF#r]J)n):ɼT:JnƅP=U7pTAk'1^hEӶH2@flMbrMRkqÁn Kҏ LFfo$/Da+"7gs3R MJHcRۅѴ(J7[?O &آ r0 BR?$v7ci;òJn V / /T/ezjOe@A%K;H[q- Q8WF` 3I}Ϭ47^p& 15Y5B$B4k4|!XjDmSI'gGN4(~yZVH-e! q h ?]BRc,= UQcI[TB&_EHqDZm+.D r%ؕ[QB (} Y[>1%?m~WɁ.V[ܸLd C䃫=+xz;a6jqeIJ>퟾ HE7 _ _pzV=|+6T#s'jqXԱJzI#BCr^8L pAK,T;lٚ{o,N@hçּDΎwB;r%?waG,A^,爥d%_=K7|춗-?M?ߎc?-\-h +q-/ҫ>1??wb^=&3Um]Kw趏 +ЍK]2~l1V(nD4R/Wg~LۂE ,O%B, S>yٿ_";[^ٻ64 C#a1 V$KY4W{r{0&JF=WGArT\L=$RaYmn<6#J/L8/. mGyQF>ftfDernD^iDn);TѮyh848d.L cԈ+_G/iyvB42 +ՄSVXގtmxzC[r6HL,ͭ*\߳fD'ڑ,1K~>$# n4k J;~ͱQBn-[w3>n:0f"+sDC: +1! ?U #r~Hl|!|*D&H)e7(^pǑ)\϶ ӝ(Ƅ> JʍNm!nKao15HdB}c)PBKC\k骏; @H{6LK{/J0U>&D*IuBfHfD@R3FYsW*RYD$eǠAR T=@U,ķ\TAX ωAR<9µVT"B#&ձTD~BijC0f{Jse~"(6pa+ 1O2S_ 5+Yc͈lg\<h{C6`n1yΕnMQ"؎kae3W9/:S-jMM;c)[H +>aW'la˸N|DQYk\AKjY9?׈c%Md W&ra{nIYҚ$ʨ2+sbETh)\̍fX4Kt[f<}s(?w&@KPpNlCتѸWh ڦsel=^LQ؊&t@0V0s$F4ي+Tƒߤs~kM@l{L~F׿o&%3W/r7$#sf:7v,O D . mn?NN|-Ftvo8L>oZǯ|BI./܇DLW\W&r'5'c `0jq l(ְb )hZ k'a$h'l4BD&"ui}Ṕjc!ֶ(Юpa'r0vBjS^JRT>|0NQi*&wJԇIs/׾$ӭh@eD^.38P \Җ@Ev4}Y]|HW<竧VV;d!!*Pǖ`E'ڥND"j`gDT#bMIy+e{ KC%͸> &AVTQl.B )ȷ2xc #O,2\lf'5w"w)$ۀɹ:,x[݊fDLj:J0edG ֘Jdl#ԡd~~PD4H.ЮgT,4-HUtՎh db TIvLٕE` DvƀLZª7ao1k;(@+:㺟,Ǥ@]*r+R\va:ӄڷ䍰#Ml, "gưX"*]͙ x[Rn@,-{u|d}4=pӵ-05D鋅}BjH6Oƾd+6IuNC +`Ky1m>qy.8`Y2S8EO +$b ]k.°c hp̣_u"Df8 +ڐyR 'Yp:`. ZHi ("M /_Z(WYN9 +p=n wa".#Lcg5,@!?rb6pL|,i;$A`k[P ҁۑ$[K)M? ?YeYqE?aRJύ>5$r+b+`TzJfnpM܎3 څ D#匹ixVH$@\Hf{|V$ N QTiP!&6$S,hT-숕8 +_cIT:}:;L6O©nXjR#7S@t&}j\"94@dԼSH~fs[zD吊 # ׃v>: p_Ɣ9ncFLB3V|4zfއL' +!ȯ"6H63*BxY^gQ H.Bۉ^*Y]XȻ1V(N&"6`qņ}E/魠t9$qC4#LW1."pSA+89-/p@"kZe7Q\I\s' +e[\ Nm*dlއk ]wQ@ѻ1]{`v=h2X6Pl;Ǜ+ ]m_X +B0b~.J*y0(Gn',5oƣI 73WGquC4e۷:2/ף- R0[5\H%'1}Sc@ /3~rdL;Ԏ**Lw LqR}g-$ ?RۋH}BAW77QtdATc[fȗjxU[G>3&ma;a +t' gG Ppbr+= /DnͿнΆL jèȎޱ# \P7C`Ԧ_pTH[Єk}2߈.yvnX:VxmOdcPdۏmw3,Hع* 6<b:Y/nNP@8I5=vh퐲QQ;:$>2A\s५m7UQeMH*3 +:Lh |d!.T e7#H萢{z(=u'e\V͎fXW&^Lh@f[ +0<>~S\@Z7)uRr|T뭣JLjlvdT5?揀3b*vLیQiBOPr=OD& AA g$P4 ٠X _nξݔv׉)00W*j11x<=(j\gWd +w}2|dɒ\~[> Yd wbĒm[R+&䦇%:s3DiG!4xCY N &c Mܵɏ`N"`-mam㚟q&uA,eC;;~\ۺҨ]u.=نwsFۉ +mH XjC"-oM/ËA°kv45EU U +&&dU{P U NrfAU9D?4gT!#DekG x!Ө^k4?yYN,܊'ۉURIjl&{H|Rˊjn8brXjxjux77 Q=d΍e,m y]cD-Z?KUwA(HGy2H6GQTńWwt[Tw:l7♭ʛĖ> + +H< ʹ#Y c9YՆ܌pdž6ƶIV7\tK rGULhځD.gaمhGlB af x&⺟ |\ʍi~:ܾEo{A93`+>!CLO9[^f÷ +QC{4e &dﮋ^}:wVPN ) ГN-Xb. ZzސB U ]n>'d?[ u,gbMYތ*P0eJǑ0 $U.Y/ɐ +p?[ŒK0O}|M~[^lEv'Dng @[6Ė_՘4%G DdJQJ _%knt5`ATE,^or2ȃQ\oIm:uEkZ6|=E7] & @+m ǶBITD50 W%cY>nhN@}LHܑ"TG\gwR$hF./<1~ٺ>$[4`҅e!~$ D@2cP:ְYN䶏{TЭtXqI?"N,gNPt]C}GK )QnqP{p:p Xc-,Z\3ƹx.K + I6K;8$'V9a%&zS8(^^*SK, VI'BflR![1!ٹ2wbr*}?Us!˶iM,hPEAL@Ŋ_(ENT+ pΰB5o‰W S8typ@k~ͬi='b&w4A`i7 +_D3wmؖ6N⮇܉aM,٠I4W܉{W@/@ nTM/a+xbnxbn?lݻg? b+x+~s' 0q!0Bz ۱6a`d{$@ ~ CG!, zy/(mDPek$]a5!>DEkL @0 wzXӐɖѼdC +Ww.p+HLH(RUPLvewt始,Q~y&,M 8J"T~kuFjzc%R0Ws(8z7.2p1rLa _\EvLțcR-,YLoiH46裫>߷. yDlY"$-^Yf;!56AZ8cLrN[ %*9b0!\2Ϻ#=w[!0*D X!y*A~n9DX wE~lEB+*{s|2qeK<"JV47nED JH`;>fI90 8Z"v  $U.RF+Q<ǸXXBɭ(UG$D -1 Jwgp=,/0ϔH\3&w?兏*@sHs? W{6"gG .j?3_ oAu]G ջz*H kUw|I̋oZcytcNlE,v;` pH6u.lR;" +(jY23S}LDx7_m 8}7ogeG6[Y[L_$hqݍhJ;~;w"`1na;f^[E ^Q%9KtolAebT9!w jBhPJcN#{nղ[{(JM'Ye*3 6YH]&7'37Yމe` yu/g&~nH9@rDCC9!Lv-dZ.EbW8Vx>@qĴsbaWp桛:0 8O'*yɌY&\omcP2]=CQ-1u&X.TL7PG=L%$vgk`$t (VHy~ 14uu ?[ܣ b?" + /^45Arv,`>܄Hm~qN6 3@aĝpʆ|-W;ì?Yv 7Cy-zˮFpwrV\xܶ+*9P/xCNX0~zYE⼉+k8o|弳uy-@v"*-$lyH[XnAP'2h2ی0SaiE{C*-qQ䏧Zд?AOhޕ0Jӆ}dϔBI˔L,t;ى7qB#We!B̻ DCV.%-V3ȌDjA+HL2 1܌6*yk:} QcXh&GC@hɵ@Kb2xh;5B MB#v׉B6 Е~:l_Ph×Dj.H.fɐA iz,i: $ : ӑ(8!tnsCAk0ϼ-!C MDŞxm@h $8;k6HU eR,~΃ $o 86{;[-DMz.4bˉ`-)T@F\ ÆSe} K"J"MXv;VAtPn3Vچ(L=5 L QͿcyUųS T3zUզ}|$5.΍Ozؚb4ٍH?WwQ0 k@qW$[6]xA}qmB3Li+,U1Liѽʃ8j| K"wtB0}\͌],;MHfu})!^Hlڠ\1惐Ҷ$@JPlc=؎|,ώ37:d|bQn ]iU] x!6n4գxT;qiۖ?iA_KD۵ Y$Y(:IÆQ V!BXMn~nFzB 8XCɊikPM m/chށ\-LWxm` %Ri"@qge:%Md*Sf /:(xI#.a|(ԓ0hj3bo>CP0|f1fԺB3_ S9zYQ>S$cKXIcqeaiz]g\ c)ZmDF5|-N4=%Q8@݀ e'J$ Լ'>K0|Y.ZHlNr ~Dh,8W,Z͊jpU t] =x!J/"4@ +W +6;Z3vA,ن-ܰ| +cP"(66I Va,`+GSIհT2fSNNc6$ @\?9,ƒ]TG!+I$6°$r~X:}1K 4`.(Tsu$U|iR"]tIc0$,A饋\-'mIU8Q sDi*WL/ mR!d6" +x"ʭ,?*r,L˴sf. ak,BbFDv,Ts/ dB~u)y3z }j)1m7RØhFǔAʁPY2ŅW;HOqc.ƥ|X}\ST0vBZ%L!JS^GΥ}NA܀n+=ɟfS-.{lĥ&rJ~/UXeG8>W9vRsvJw2p}F_[KV2Dq!.Һ}m@mF +n'FmÚr0nkGxv:W8s!rǚЍ!Y=5gb1HM8 PXCQ1>y׹Xffdo->'>xv\tQ3. TDW'1v9Hhhc˗1M0m@K\i̙CulIC{Ζ]Z$> 5dp2fi{39r|\>_9rSX^X[8Ǘ"$,3.7ysXl\hv +%i";D!_?JDŽqHsrСpvNFpk8T\44YMwNJ&icEv>/UBSQJ\=bJwLAaDfWJd0AaLi)/G1w -•pyPZxxc4X[sqyi~z+T3YTn'2CҀ2=GfeD:<}j]^w)Qu vOVA(Yx^~wqqtuWbI5+ +|uܾ + /sqwlW͓|PkxIC+kw\^À@+(6xZ?_<~sJ// +Ӈ#}bLoG{[{OwbjϴX;l~\]M$7e":* [en2qHUgAXJwч]{=TIvx-5/ܼ(NN2EaWJ̘ŴHiX,:WdץE @8xKf)( B|Mӭ&81hǔ>z:YJ/&(UX= yCueu9{|L"A2*/_̟y/ ڄ/i+>Kp/7ʻ.?kDvj_w3{܈Yd{Dj.}w鏿ɋxjjsrf TK +3;ǠeX֦?TQS q%6j!?2GB +T|=qohsQ_OY/NnҌH g'8}D覺,rs1:T$`ʣ~~rT/g7p"/>y_ :ӇaQ;ByI"Ie:8?BS P;\]w5\nwCR UuXg>JF4U_.LoMUo: }P{W|i.w2{w.cɒ`A +qi.*Ӈ__o\c{ar"W_o_M$% Ma&?{jտT/'_>svgOxEܤ8{2o~w̘& pE}^OzO*7XbcEy<{y)6q/!gJ'TvkEEÍ'iΧ/|dV,cTD)㩊Z3FgoT'RB Z[<JRRIT37_\>Nja)|EC-[?vsX8S2w1mf*{ӷiMy +suD`J $UO>T|=&~2Ld']Q]uO'G/9Exv&m㰽o=YTkqOji;IxU}2ҿW/<'RKq7\ߦ:h'o~ݜ<@UP=s|WׅWCh]^D*ng9:4#|ICv 4 eygӳՃO)D]K8G' (VgvOO?em|KpHŽOރgo|!~};&?V쇸2 +]\G_<.@ꃳ'YEyaJZʝ<% -B@(ز[#k,p5rdQKl3tnLWGjTiZz*Wt6N>Pq +=Fgrf׭ֱ>z_z#v)_ȭ ڂoBIgN_^_&O>}m˖VK{U<R&U.ׅ x3WWUwϙVPX3,V P\+d*!ٱ\?!XBlnRqOAAiu|L-Dnv^/L[Qi0 #Fk8ڹ9SKDO~p3\> cT~y/."]"b9UZdG1+R?;GE>+oyilEDB8tmGd|19`ڱV?xue'i^Ow>[zN0N狭Th[cj=YM._3Ƙζn?Hn(TU.RetqڽUTb)_X1c4߽ ryWË5kEDO>bix/'[>Qg.)yf?D&:z1~_o~w_ٗaAUDťX:ۗ\vcKQPP`H#rZO\X# t?ƘNoZW.9ctdMUR=V^}?7E93S"-{LtĒTv$WU{2߾X24k亙Q q qy7˓6s5XZI%.UsEGTFٿ.oK5,~*12Mu?YC"R־GSJXM8}Jh鈫U݉d庇ݳW.^~ӯgOJ9eqoS3!,b?Xd;XnL*˯ʋ3"|ow83? YJ1[\ks 2M/7?ȽX%YR'2qGkXYhCucx;}'mRфB]m|Ut֔)rӣ҃ZRxq}ˍxUWF{Q<3f]ZƵ2U ÅPn{_S~e"wU'Q֡"X +PbI*%\ˏ>o26ιY]XAK2&7$s^"Rky.BPW_U.ZÆ'I#ܣzƖȍR-̗xpկ'*BkN*|q*di*fͣ'zgIs>90*ՖᄲiX¼:zDi#GTA%#=ε_p3sUթ:Ts(QDYB@DƀmE08‍&l}|{5kiU]>\.nndp5wbDZ'ɗw,̭On<}÷|Ggg|x2kfwD]ICx(h$Ly$לΌ/on>}ëg/n_ً?he/P2}de95?vbg}}oqܗTn D0 }* Rdmvy`~wg|2MK Nz,K s2أ&pW8 UǽPm|\y[Ϝ}T@V8) VOz|(gN\O~}پDy +a.LPoR2+9xȝ,{sK=C~܃\y;{Ե>kxܹx#)=m$dlcvz3\>yK/׿}'_wcO_rcH\\8~x W~%^}^~y/^zx?w~G`8Y WmL$S:~čg7鯿o:0WApIgd?<~7y>/. +U_ XOX^8t=}?oO}_o] ,@\Yg|Ssk+O\}O~Oy?ݏ_P/`aGGw1ާIaQ|$;0zC^~1p!ٛݝџ?ϧ_>w͟mDoh0DqtyЩ oxW/~ޛoO??}ɿw?#Oy}"KbA ab \߾^}o+X7;ṋ>rg\ȣ77?~W^{ܥSˡ|PAHAn>+m]w???}տ__#7GDq.N3L:<9}zȱ\?\[o}O>?zw{ӗuH @,¥>?{|7|`Z?ӟɟW8zWwϬ:qR+t]B`4'8s_{xy׿#P^xsg1Frby W%ә+;޺rɝGSń4[Il՘*PX* 8yO4/T*+.x[bCI8C0P*#eD0J6fñDKL>}.=?[>>~w6"jĥAX:up@gǎ[~O?>/~7޸syq}c?$ZoeסSarsxhuq_ʫo/gzX6lxҠn56Yݨ %@v?瞻/ϿGϞ?^x dX&ww(Nl4s>>瓃#c[ǶO;{k.?_~Ͻ;G6t(Da +Kx?yW[#7z打P0l! nł +!QY嗖/]Wy'~~/7\xyna)S4*"2PRԲR"BIM@y4>.1`[8"\P'FhҘ,i;-@*T%x@{}BHi6 .ԙVOxo91IDcT.902|h{|q\t|:%L'S 1XH-q̛'=)!D0Za;=:JkIouHt<+ ^#>Unr(jP% &:jv&Q(, Y*4RmRTft( {he2HK5Zdvބ:!'3]*kl--b}'k+EZ[ֺDfUZ|2 .ocHaYZ0v1CCB7(~߫@K`rQgx@x:$F/i_yqJgm4WO]lR1eS֐aa5w +j5(YR'H -xzPmb/Rykc:2[-R# OS 6>]XiVͬLUr##}j<>^fX&vurWK̮451> +иI)%::jE6nPjD-ivp,7 B=ih5xj&gZi:@MHS, +ۢxI!\CF:TZBm\Of{5DY|(ǘb + Fx`~4.hhFS#}U#A-ѳm2Lz6vyH00HFN~Eldp@z *I!]RMeWaGߓRa"chbdobO~Ye(Lv .1w=Z jkБI1-X"#um +n֠Yh53zFC뗚}Z(.25%I=J-5IsX9 (z"&'tdLttf,Jfvw>脨VL\ͮHp81}RSVR)S@Ugt8& G r3C@S `/`mb[{aŏ19W#4KL23"G].-.l#PP0}j2qic9{Hٔfd4”Pw?@;j8Edӣst8V`K! B]Z,`qTi-ѩ`~%p@h !#:$5sN31F'Tab-`]0 ++\pVj4,}{Ŧn--#T`N\ޯیH~W5lc=jCy{xwTaY},3}jWiba}FW +,GS%΃3722n&$P_[Vitt&4zhM/,l18&‚]jpbLUde uDՍw-zBx)Ad/(0+ݭ!H8Z:< 0+`om-̡}ҹWnV3XΡeHhž[WO?,Ý[)DxfjDhy+PpmIapy5"ZgRA l—4ޕłC-'ջ*aHY;GK[ IwÀ'uxB53 ҒۥJ @Q`SOQ>.B}r:rĸͫm1L.ݻq +WQ62ILx#'pct)Z"f 4Kg"5o}.4J?Z:Gj?̶0%9*b&9dfoR LɴҚ + +!WPAIr7 [tԙһZGEG|dXr!l;0={J *ҭ 5YnZ*ird5l7"] T,ɞ5XB5hg&x+ysѣg=6!&W\Yߟg- +@x +rёHs{#B#GE8"&:GnT`O3%jIoE[͇c'MPi=8Z$.AG;ͥgA:܏ -1 K q%Gí6V&:z@+Y=*@x:DFMLIKj*0V֝Q d&B յxix~!ig@Y\:{*XY.L.̟Cj(zWLQ#[ +R@nffPp:>ltWXLzx˗2lnў `y`=XXܾuVs鴁M3g>ˌ >iuأS\ )h4QIvKcW%_`dABCB-4BC"rJ`~{|WZB\52Pa%Ϊ)3ύwH@1Pav#&E54{fLOi8ug vI%"#?6KX\ghWh`đ\#pmF[Dp To]>xtb +P> ֩N\^0ߥv*0l*,_nVt=%NŷwZBg]e.œrOzjoMd/BKpHwjhfDtBU#S o?l=! Hfb #U/%VK +s=RX`r>α[ʹ3SKW*s#K g9NfgZ+'"{4US#21-@&Ttʫ$)Q!+ &^d<\Όkw(T\8U:F@|`+ȏnY#, +X.8 L&Moj +tl&C!WޕN\-l@7{u`90_3Rߜ?z'vtF!Az.1ڡ)ѐJѠ@\9Ʒ)P lvvsyWa]' "3":<t]}zKG' |?=jk0@y|8Iu L *. +b|].6y=s@gw{U#&wMvK>Sv^FUXFZkSML֕[f0SX62YE0YWT^bp v!5"Cg$z'wuу ԁDxP h5Xj WNT7H舨mu'%΋H(?oEJS(0@4{u6bQ$C[2JYz O \;}/<ŝ_yOF2kUBvDc +O}-FA 1ʭlA-N7WtBKFA  gWRmf1ӿp+\}p=B` ryPZ2ҫ&&'ٙ3]~?xT`䳳1bC1:j mOL|CKg=&%%4mB8$1߰/n:" nhotN1ƒz'a@'GT)hڳڿxvާ:+*-3djAmOp$?;"C, /+ҁwujvhڤ[9P^Z5Pc3cln2ܿIFL`[=F1&ea_c£R/|*9#iRB[amibfb,"(M`p%'@Ey p- '6ǣHnz|L&in_Bu(WYC⌧3ëG.Ol\;r6{SYQ"po,c^0q)Q#r~5S[2SabTŞ =By3J̣!Z:%޲-XM7?{m g8>%*rW[m(WH3;si8*+Q:2NϥG&'6{2s Kc+z6ĩ0JUir!D˓(URK&NpLJp58ttS瞱Che +ף&ERZ/C^:Ho:t}*#йm~;ӫ#;P +!]r $hƦĢZ[O +Y@2S-5Co^nOf:#2#$ipPJ X=BТ#ROV*+7g/M/Z&i6=GdO\@6΍ tQ2*zunGmQƁv|KFG0_1U{7ƻՙm'fƙdvH\:b3v_%~U{{zmBH [kӭ=2Tlzqhkpd=r<, +K#J<'5q`DD dpz8o5t:<2 +v[IG.5HqOM:PI3S8వу*ZLTX%:Bր̹c + t3%f.jHAy"SBMobZ:Ot,;wh{[7?{_c:`vyf}} +{בi:,ǽ"qO%PV\~Kix*Lv1:̸=Y9"R ldG'7ol}g?hKNXT}-P]#8_.[)ߐj-Ԯ7zFhp5*CG.>t՝jf㫗V.ƒC1Z(3heBjN֣i1U"~Rwary48Z2cǼ~#J W΍/;y2FM&ǶNRS|@hPҮLslkrNvYĬF(s5 +D-Q[>제Ydv(ٴ@chHuRTgW@i=ЫT#*džN4vL +q gtJgZ;w(>]O@UfVjphi`2#w߽﮽=Yte)Q9R>_]z'_8rd _śr%(k-͝V`.JF`^le"dfrtX*mʓg/vm3h*oHK+9;n7DFI׍F2jJ%F@oz +[J0VּWc#NmV ĕU2t@TjUڄHE']$$FOBU'sG; "]Rx`|!9~ !|L2 6ݩ&5# @)֡0zWquC"PF+:gН̟ VfLsR+Z\9vv&p.]>#ܿS'tr,(A24"(Ĥ*\`(lv xn`fhqtY3ڼrbq0E|oJWDVsJt(\2/^ǹLqGX)3ر t>+ouW*GVKi*2H ,|f;4 +jm]wܧ|0fXW +V2G/ϝ"原9o\V;M(”TxDhzJP"4:R5q#TY8,X97rĩK[Dy浟ߣ/0.X=55Sq&pˀc5 +>.]{ jA[ I_@?ױ A.ԛsCD-w+꫗ }-"2䋍lm?8{fML!X]$ P1JlZ[E@&'SIY&OJtƍKp/VO4xA0z a:„'kCuTÎud.l5oH[9h=j>`Z*?♧ +3g t4^_[|ۍ#h,' ;ѱ+11tЙ'j3;_GG#@iO(KO`4AK @G0O8wvtr#LfH=Qi91p4y>P^>5Ee+jGdl JGGm13+TFK&=PQ #$G#*35)^%rSg: W"U͇:CCs'@VCyaoT x+mN*+K^b3҂/q96T4vzxLꝝ + D3WHq PI"ۑƖ={c(Q@ ^|v3ܒ^WOHG<(A+rBfhfřΥG/<<TZ|슍K ktq|Ĕ%u@v(ˌe1&ݥ Z[sj(UcobWmmݙTS*  d$ tRQg0&WSi,8z2{ޘ3r 5r +dȐ`kP=#7 oWuLX}5ohHOzsed2y.5|_dFTX+Z0F2&FtXaʰ= YC*W^&jKԩb F+VOZ?l$Xm.5J rc`%Y_ݺ8~*?+Ls1G٤]T@G`BPgO4ph1vSc[׊fߞ$mړCb>ryܓ{3k>XxClhg+/=Kpݩg!JVL͟ QOy8}ɛ'{_M5]p7UB=ܔku`Z(W&WTD-*QW~PZk&RndS47*F[D%@jX:eY"=ڬqůB&:bEM+P ە[yԓ,K3tj +ZC2מj/58DE5VNF1 -ի;<i:":"fvC(Hѽӡݡ[׈A3Rzݭ}gJkf;;[P~4Zˎlذ՝qGjY7➜/?篬Y"Q"~S K jH.Gu 9SAܗ2jcz{bб7fgo߷ڼ3Tb#tejk=6ĥ'*'G.'OLj "W߾9bDhM5qV<Y_3 U2[#ǯݾ/G𳭝_Mi:>/5.M-te<""**F' gԄWF\wFpI[ ^8~ $]+Rva^GrAIdtt y9No @S=L9@IQ"%J$JV,ɲ׶dzuX[޽Uݺ܃bs,_z׾~ч7_~w|fjs zowO=uĄ!>3~ _5'O%cٗ֯غWsn6fB+Nol]7ۿ&b7yTy"ǭGaiW)v/n2Zk;uTFI 7=`F@|Xԍ(H>RΠT$&IF/ԗf:{JCyRJ ZR֒'m@cشW\Z"̨O ++h.uOJOX8}~<y.9%6VbrK&OÓ~ $Hr^ʮR¦"RXkwMĘԦӎ {F6hcznHÕtƍB\ѕA[婭gk7~އDCA"~4AD7*ir :)KrR*!RxL*΋+vlDP`R $`I3[gBK+́[qO\ދF]! I?sK_9Ĺ0+t8 66jxgl=8  [= b@|Rg". OgÕz4KVykG 7 qKxؤ? +|ЂzXdaCG] WJi`|*Mb5i Rvꤏ3( sڼ9!6êEK:}b>a Ϝ>LmՉ,%IC ;9!.ba &xB! ?Z|`$cn򱣓fttZ®qVnIf{nt|̊Z k6_ #+$2IKG-V@?10 2%M.F@ө 8<4J%qyl/<9ĐTPZV !Qqf?kXhpS̘-(sg?::hu(KDc"͕@''njEWP0NU30"~BU0VL G]0IQ3Ï6!ɤ3LIcHfNI.HD & B|h|&=YgH?e,F10\A~sDy38n\Ш)A1 +ӛrи"]AIR8xN;}($ BpNo,ۿr=@#㾣A'p ցnҜ]>5*J)%FfC&QqDn?1nSXf./Q5%\0a~D'?izutcu8A„?87=hr>yL v'$DBNx-'&mAb:Ŝ춐BP)U[J* s3+f\!1KBRS ""U+7W\q‡ ![02˱'2k& 1FD8TQ#>_F2iP}R?Kڅ+{|+"{q ?2 QPAuW"@);M~2ZaǪda(և~y'G_HC1QizKQ1kȋʼ2~Z^dbOO81E0\5/1gTTQ6eB$@{&&Y;H<'CuYN$DZE}]*ݸоznW[1t"DW/րѓvpxiT%IDQ0,KQ 9FLc'_>>:baܞP<]BT0Hbƭ84[CP{BΘhvly\kųEq_:ݼ{}v5X҈D^;:06>ay2#aleUVkL4\"ԗ}…go{zTN8NNxAؓT#8dcn5~N~/~>|F1"@$plJjdw*ҙNv"Wk[k^{؞uФ+48~rMm?=FVx nOFpV+c+B@HDᐟ!)J'bB-jZ~:=w2zr}joiL?v +딐c<#W3t.wjRG=X+׿r/?_~ƃ;S͒Ǐ[$L8|(fV.'~C]K/v;k7_Z{덗^yp SZ*xu8mj ǎ[_kO^ýL\4Y|7_{3L} s'z?O\&a%"R8^ ^ ^L|||p;on_~c?}ۿy=O>yfev~6YU5 ^߹wyk[WokPnbRؑՒb YY֖{{쥟Ͽ7oσ麾whJ08@s +Bjj<ݚZM/B"{}uo>:OWݛ?':ވ?Tne E +w37=Oo;WG}k޻3;N +ڨ"W"/>~߻ׯo_?}o?8 kŤJpܐ9EN"TQTg +/^0Ss{ ￵[;]_+5ÁlD„g*F !sv޽S/{K6_>ANTOlY$>JQɒ!T 5~G}xן/o7g/~͝OV,.HRtG4!mͷrY^So{_Ǐ>η ksI|P:T8&)a:~6^`wSlt^g;Ͽ}7_csA1M6;Qo&XinK3s/U߼{wW梗fŋsr]ON%i`p.`sR\,F+~y˿߼AѾ`S|x&t܉C`u>Ƥ# d'M :ՠfvW/|o_/][*FDZbWR)$R +S+|.}o~u%a0Nt -5XU"fZ91{\(=2O75%!!Š1jIKś[׶`njɹbR*C;6q*^Î}*EvS+gNǿ|տ?7?}޻ոM^"Bfs;8o?k?߻ͽj7j#gL2 ZB,*b-+e kt)c\IIJrcU5ydt3(tr) +AI'Ҫ\L'*iQ2#la2$7za>Q肚 #Z(ʋvkҭ^o!O7ղ\R*<Πex;:1:*Edep%?'7̍;>AB)&D(V +s7 :Ii.H6.dUQZZ/岪P ^l>jԎ Z,%֕z΅VY#ѠL6ZvV[~L 4+aӨb@ 6ZCuh22f^RZ6mqi;.m6g2sE 4yM8n<JK <˨ =yҋafbYJ8pO Z ^ى >ޠׇ1; x(L$2B8ca& k!2+S1;b + *BZV V/ׂWL2D5X@>:v! ˣ_|b|h"ŨWp).&,b>4lGaJħΉ>- 8SJy5a>"ʐ+tt;bC\}H.:Mn2c +*^D1d ;&]KZ)ڑ -!snTvsCa+ycS+jE Tvaq7*&Im6"4-ۉ VmftraƄ_EBRJ5RӼVFABԠ̐mr!.D%m&.Qψw\kOa>l=F H)b"*aÎs*.WcS!>QԬ& L.Q +1?h}t)Qe2 2a$+ {CB/K[1$]1fܚV>K&ITG_ʌX=N'2}6/?ŀrD/fODH@r>~t|; }a+t$=:1[AS&|ˆf,9 ǿɮ"dVN(l֔ͅ +5"NaML`X+AnnSħcP"Xf +%+XCŪL۱Ȣ,\BiBix ju[8TDWcZMd/Q +KeJk2Hu'RXe=T*Uіj/H6lɕ\q]')X<|Z=K3>Nۙkx0V)CjM!+2륫&gr\û?Pu:ZRk;^则Is"c,62W,xo[ϻ*1sx1/;=B%ܑ*цJ9R([[8KL~ɬ?>H =|tfgLPJ颛ȘC +ac,H⤝+~EtNax(6X7e/3#FcJ·}8w#c?:\9،JE2}.x $y!7;J>nB+չMe @r7䲓oXƘ+Trv&SiHqla0gچ̐ u&5ֶ3zm[̯AZ+ՙ g;Ϸէϥ{(e*}z"9t0ē+rLzѽm;$1m:$6\ ;XQ.-m1$6S/?cspFl8AZMz%bᵚ +RE&Jm,Z%Ϟcp'܌{GTs=Zavpg\ڌGB8:V`m&3!I>cKְH:_jH06sr%*TxrѯtƑdX nf2(P,ܦ9S M +endstream endobj 109 0 obj <>stream + 6dg(K(Rq/FԐqm_LX|H: O$,VB<()lX'Mh]Љ^M'..LogR\,G)QHHB)SY/_stBngLYNu^).1Sg8Lέ_nj!(1\L/}y\8>ñi$Dk  \r3s, {iݓQDjvfs1ƛcUʭ(-^H/Us98 +%;RZX{>9P=". +~zD?S%bKdr-RRj tnbjjuicTr19bm Gҩy& +F FofZNd+:16!`lid}GLϟVs8 Tz-I$w.0 ǞR\+R r}{+Լpy#2!\Y~YEƂVYAxdSY7qٍ1lGQjē6z+g6թ9;>r*8 S(aC ; '*,O!OdҝdIi'PY_R|}CP.ٞJNd:{ +j Dlf ||^v!H)*5 > +i](cؿR?6=|,VؘrKD[|y*s2)o@%ٹʩd~MHw^~|oHu>rۘ>'\7p+p1" i3;EXk֙]D[Cļѽ6Q}/9b pЉ$wpu\GKg-? ++TyCp#NrſL7Lӷ_G쿀,Dۯ)=XB}Ҕډ$63KBn +;_\U꧍9K._-]rs}hp.djGlrO7#f~շ3^LV'GZKn^z27O*JO مL{7?{>? 76h%Huλ! 5SgN ;ZRHmD3˕E :w[wsu09:Vk[J}/9zzZmݝYM}b-TL/4Y-Joԗؔ 7YE\~&_n<;ֹgFPcL30x镚Awv8s'm0CZ0ėz)WӬorA(̧/+-kƪ[L._WWX\Oel{pL-2E x V4\HW[Q\;N`ѹ_r+ApkhmG64-n134` ?a!l\PƔ6u&cCn ;T]UNg_R ˓b'S@  ,(5j jxmEhe4vgOyepT-.^v*Xla>}Ak*J7DI3BsMR-Q;=u96ࠓy~xpʋJwK\UVO_}u뽽Sy6V8wK/~w5P;CW}B#V\rqZ9Efյko2_lnk }ْkӽpt7[+7'Є̺[l)lvrgVvo֮VP@ZoKY4o{Ne} +(}i%PK\?\f.fH2ιm]~(S^, X7z7b dRS/.5A*fvP|6|Lٻbh RKvS;RvI-١1h.]y<}Nڏ6qLF0_üMj/$4P8b4Tj#Vz,6$uf$ic^E@4Z+3 "baM͆5{XmE֦\T +;:dW1c) d+H|yoA{M8>m'K>hU+5RSJj,e&FR#I7 Up[(?](l0g4F#!c *>MFW:OUTJ:t at/=lm|irEmsHnI-^[ϽĘan7[^q>,7}[O{2{}uu8. RK//[9{W--/9(Di*ONMS2&Rs~Z;Z%6!#ElMJh _9j3tnAx`p*n ͣ >O)\bԩQ7 %;Z6vأ8VM.Q݈p|'b]"U:|~Ӊ±6RXJϗ\L!m!YS!NbJuh5Zk +DGBqGaAL uKgJHZff/ݗ+kDr.5l)ʥ ~Ne\t5LmiťDm5EK َV1!EZ ZgY^lB~tA E0$UW2[# #V)_p %Nke{g`J^FJ^}Z$`?$k|lfEXPMubqj}̭Xq~5Mpf@dƧK{OЅZFrgw{vd8*nomwK&)oGAsvG>q=CP<nv'TTƕ4e,@JxN,YH06al476;)B.4oL-_atFJr#ȖN8XlW.d{=1b2<\L=rE4 ZP@uP݀jUfG;b~K(q#lÐpE;SIhyvH͂q%$>:8 r@@sK^ة4$"Q`CN"kv*@vRk!FFyy +hK1cg͘ᥳ\ $Hnނ:cZÎǽH*vI٘#*.ƬAFu\\]%)zg/ :H\]1sEXR IT;NfdrʭD.Dt@3CWEzvN Sc 9s缴Af͝\"_i39o]V189D<3~ m,Zbv)׽ \ʥFg sHtI*9W]xEM~<ңnF|4kvL 9"ޓ*gOԐ DJ۩>(#B>^fbуi,>\ kSdH8c667,pK~is jd4@!"*|p†dzhy TWᴋʁ蕗M":);g["4#ABG2cT3H` V<n*'f"vOc҂e[39:SӋ,a'RW x4$|R.>cL.r#Y,1Hԅ%|b {-='B>Ɋޮ-ܪ,A_Ѓ נK λheJ̭`z;,\5j f"51+kl7:sܯ94*MajێH!O.)`&M5h!%륥KІ&b%EN9P +6H[kH9iXJ*Rc'' K@ך]y{8 +P$AV42x$N M7(vs^2a %f.{!f`RsA +KLs+ݷ:"b2 ,MPPi2='.{>0H O&iͳ[.:t}9y/ mu}LI Zj '01Q琛vZ̀ec1hB;b N5.fŒCa7ה¬l@*E2DbA#'VrHVIi'&1̶NqN>q< +ͺ+zLnUSHql':9/ ް0\hTfI`lRv^.C W..շ)c{3xҊ0U7M~C!yZȮB8? sX "'$(s> ;> H-:uF"-a Hj5m!mMz$qTԺ_(фHyᷩpt(T=( -xy0`J&X O_KLa'@!֫?|r\Ťlv99Z#> ruuk+^i_>b|LImi2>hjBS;0#1 `:9'ŦΡZ+4mdނtsNXtu4:gr틄6U|ŗsfn֖pj#ZG"ZLv/ ٫|*Hr&=Ϥն_l0m\q +DHs ˂bnC*H@~l5RS>6x`raV7 Ka,3jws 'qE&eD{xuc[׋ Jo=O'EӐ<㗺ZmKرPJԦ! %~΍2b[0],Ek|aMT9u7׿ Knbsni +$D}KĴ1)*uBǺ%Ş04\e)+pU6,5H&gG|u>G&{ N,aay'pscnSdxm*dnᗚHX$٧٥aH;ᕝTi" Nn0{gg +*Sv8~\3)*$h;ȗo3P.V^spGƧTGbov{ޜD2e-b#%B kH&2'm!3$)sSy*=O}7"Dcf&p S9H*. ! u3+gS+XzU87u^v[(ZClL6n*Aq{xۡ_MDcQ;[XwQꚟ;"ρdTr,vB?{h҄c{z$یȌt建{{jgw{vf!Ha'IHq*P"Ǽy~GOt&}1XNϾ"1wՊDaQjC$Mq?DlspM3A1<(͒SG@Op}&CLno>,Yw!:}YR2t,AAz QPERzt>\!B Z>A#1'Xypu$'$qb_>vu&\FHm'\2x8av ;{5ѼڒT#KXK6fV.8w)]Ťgn{ TO(HuR26C8 DƬSnr$zK>Os.<5P^z@z-b|oƩFoէz?0SzTfiQ ׄC~ǤGYߎUB(]d+VYnq4+:˂f.Pmgw@WO-^]LR0ᥜ S?m!5rcbϤ9[=kowj$1IX/msv,VVW/].<{/tRis\EG8S;s,OIY FbCݛ/7%UT +"7LXڡ?|PQRWOPi*HSU،bק)fR]$t2d@P8.Q" ѝpfZ% +VE=y TVLa w8I%T}B3t +g|;S[pXDTaVg>oΉ?6{qoU2LԞpҾ%᫇>,6eyv"R˲u;Ei6aΥyI+z7.ReӲf<RŪ-wtsuUI6(Do*E6ꪳ7'/X0=JfJ`.a0yzZq,:Eے| 5XE+9&Xcȃe};{o+]m̍(,&:,zgՇ..@R b88zD| s2l3'P^9'ʘӊ1%cbw++<xXigE^B4:ӭ[eK/sgCqP~Qۈә^W.r*7C.m sLułY) =\ᜩ? &/X&"JBHjDV缱z=z\&(g;*rgד EtqƞBtR3ښ~e (gJ}ڙ"R5x4d_Y<'V%3[[(u/ZyA[VgߖٚwN}ˇK@&z^ "\uYnqC[TTQŚeaBH,mf̎X -ĭm̄ٓ`LmF ,`^s0eL`Vsș,K=w"Ey/#q!ykkn%2&w>I)GR=4GW[k yﰤz*!|a~R褘*+8RC{[{e[1?ךW58# t~yz?#s^ SD B;S1s:nWUk03#>L$wݻ|,ޢGrTgՓq},Dc\jqKp&^L W qkA3aBtd9=dw =sVy#.½%T # [5a,m(vJ,5~ٺ؂M5\rzfJr6} TfplG޿"Ygkļ4!m=|ȕZvA~rDwmƘċ]V]ޑ1|FEgjќB;BxxgT;Y %zm>9I;ScţRk%Sw+M^~%PˋyQŨ+K^lqQU}gP=VYA]Acq{!/ `uXlbʍgJi:5r9+Σh~ARάx-6'9s{9y_M~_mFhQΚ\F"VFL5y +Ui^B|C18)CY<"30!LR W}u·_R,^}ȸGCܧ(F9¶Z4fC.7K|XW+R weW6.Ipl'K{@em/1cF[SPGi&P\ǔ.rZ:b.}6氬~m4UKb=abB7{;e9G9TxRr@r`wpw52l =̋5LJ'wP1kӕp e*^kǜ ]\j'Y%49@hhK!X/Tõlb>nOX;נE _4zQ[ z/CyhI٫Pۮx֎+FlL9y\󚩟1,DNBiAA@jY.SZGd) P(u3l'oO}1/PmB0Nt9_?~gqsԙIg5+ژ0&7R%jLg$0E0}'/@ j+_@Bo_EZ@Dk'k}@=ЄoK~Wkbmk`5z̾[yUR r-ΚsfjH6 %7DpVTJP@腌k͓g~_';>))%%# +6$b(4S6vP 3RgcXntv1aNY#1 *\MX/zCĩzj'aL7s5:F$aX',ӈP{UPFy]{dis*}qX3>]Q  '}Z|6kӍ-ԆNQQZk!q^(@5XJ +p]N^u%n0 kb6Oѭ8ɋuSve"V ~x'g6ITE:[ \CҬriMV|B: T+ƙ^AsI̓2Q)UgB+:vto9H.iu +w֌ (v;>:ϸ`d/ 7+$ cЙ3y%!*I[%5KW./vĺs]\g`7E|㴾x;JdH{d) mo%XFkPrRk]K50JM9<כWi8+FA_u77Eg]6'Ts?VgZpt=ӏQa^ } e`|Tbd#ŴSLkR|lΔsoVT}=HKІA>EUAA&)$Yo꣗+ƨ(!`P3bqNftN{s] '2Sjk3\JQ!9:dO.X6ھ,8C?P[eci΄sb0n;zǃ,yFJ4!H{،f{gpw]2w]·gqigViQ!Ӳ q ^pt Nl'CCqѺȐI\omk*bY{wv"m i֨f&J;[slQVLݽ"sm I1<KlP;9܃C4( L_b /.5q13:jx9; d@)@Bw b7'vY{M\m3i<.I3)9Ee.ggw 稵NUpS;W:7<6T%6_;}㎞eɠ, {0)!ac ?8Bjz{}M2qmRR%yHGs".rlAM6.Tu"ƢZ}]]}xʣ}]EeZ8y6 +>Zlķ)L]I3݌0=}R1yRw 0S9V>+MOʝ8)Cއguo|&G;8@.J#}e(EGY͉O{H)SϹ9XCS {.0uV 4PcU^9PE̜"+w #+zC{6*AT~ZΞڻ؈<}6Œa ^swR>/7UZ8zoai<¼]F:K +qʱN>KPDky::4;3|.w0X9K&+ƍ5~kvB`Ry1VYw +ek[%}#/繦T;L XGEslM<}G-/aRdl-< +'O!_5^>:Q6vI]U_h ޳XPIC-^߷7OR( >?h_3գdԙ~E%fqY3> V3G 3lk;N:~9ss2u`b[ VNLiCYgr#6nP'EU½/ћ5aqңqm䭒ҝ}VLVom,&#wz7 RE8lxŅx[TFjŗ=TW8xMTKu^i@#eDX oSIBuE:SDD/s\RB*Rzy ?& +j HOn{_ړWYY2cnXSTNy w19v4?Q<̉]-}k=5_vv+uN?Mw ㌸MB6s}fFWD3)‡,Cx0#R#p YFج&mwjk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵Ϥ5Lڿf{uGY#`ӏ?jM{>ݿ=}rz:!FI'"Q;'^+8,&R?"?B1'Yig1#x$E'.EsU!i#d C s4p/*4C 0ݝOQ^'4?j(a4>nV> Ô<) |xۇ/N;Of8zw(S!*4.Zi`*1O=Ewp@'><:Q H%UsM +R0G= 5Wwק! !-)w^;i%}\:k `O1>b-47/!,S?'ci$}!\+ wV%yLx>4"gO\feVICSdP;Bon1-|vJ YCD_1H4_7:O[}\?oWeg5CQ^l)/%>D:ek%($LͬF aa>.h?-j8خquv d(8o0Ľ"y8X۴9KfAеs׮XKY#Ϸ/IUaZJb{9'`3l#F8y:}t>(( +j&PKa|5VeHAm&iP;J߈ qwl6eZ1hw͹78vA1ށ>cuӘ]d[eeY6 xNҘh%G88Ӭ؄(ݧ׫$a&p4ROk 锕<&/zVR2_5Wr(3Z}˜Dbײl5̈́ixཛྷϋxAmvt66X-cvj߶W_=Uhe*mQ{EZ]2T{9@ԃRtDul]CVI)yj0QӒ9ʃݣ:Mey1:Bygi:6is!GwPZsbsTSNA@:+y ȷb l4ĂUi^QQf+G0 EwS\o=߽a/ląGA7JP!lو0ǷBR0+C{F´>4Y#xkvJ\UVVl/?W[e e)76.7Y\{euG(I#\nrQ '6 @itۿm˼"́8tqJykm0~9:?KA0S O +l5x>c/B{vpgJ~LWG9qW;tS8,Jo=+m %[=KP-'ɰtjN¨F +e#Vvz稚{UT *,FV*(E9EGb^Yn85 JBJ ϭKD}jIh`$(ubcR̃Œ[GYQvio/I[o6QG!xJFfAihﰠ+P>&`_i 1Lj5/c̘@I5=ZG=cqBee +XPg#DQAꃰ$*_@ؓLbtK=LƐvgtVgJk]ֽ:Tx'.__SGq&Sx/+>.Wqa@y~☻[6ӥ}D/M(mb7FQB]"ţ@6+et|N8̀Ieml͜@9i J51iF9k6<$xoZ8em'@>xtphgaNjޭ;{A*tgQ35PsN@yf +#aVΒ$"p`'ehDKa."Z="\lzWU\'/R (pcdȓ,,ks\,'qSAkl4*4 @TsbbcЍ k1yJ:Qv4eAC1\` nPѧq̎vCZ@ Amd+cҘ@@!:PITVT>"M f Qe(wRև5}EEX=+}V۸+{Ynun3y {Vl ƵCa4~9dctӸ*j9 AX:1qEt/°-0kN:{K|(JRgwnǿPbŸs&<P~ &ت@ _Uiuh/ +Nb.ds'ʣO^. +](9"Ya  !V\´imUsL& k+#Y{gNR8DL!,Yb+}$tx$BXwд+$e$amCnn`qe{A?h`f &e{LicԞ.в\vZA,K;Ȋm7ι~rW|d_0gy}uozgU6\Xl_+:8%_=Hsu.po|JkYIH2\3IWt c>A~tQ*Sȼ1kNyo*`Nl$G4#Μ<_Z9,Dj&qg+AC\iEäQ,2@0$8DgA@ &"C:$Y@S%[4Y*JiY{y[{YUڂȒNQfE J%plm(3#5kBo@96q̃4U-m$b&0 +ol 7P,Shno~($Nl$LLKIF4lO3,U:9Ĭ8bDDL3{Cݗj ]cò5%\]ޝR=kIJUqsRz^.(BV)VP{H؝})wo(tڽIsЬ8n]IՆ֋MB3P䚏&RY3q̄$jnfGYiM=z\R%aY 8s_cA +W2V +N/qYT!^7J|Pqu[4CBuY mޥsFo޻Hr~"|%J\*s1\ԝƔpYi7WPJ9^o[cDߒ]M hhST(]([;806ƥ7|AسTlsCMq|y6NS:|׺(,Ii\g7nQNN Qlg y.,Գ4ZۨJcRp+vt7j2ol<+iA I6 "$1(-ZCJ-}|X4U/I=ʘFR+1a֚f,VT' 6lkDA]̀v$Pu@o j#ÂFAFR Ra/Ix VCZz+fJ -Tty# +E:˒E"tr4,G-e!T Ƣ|<2ڌ}^q&r"`l 0,% \IfYhrW33:|}tuCa@ 6g,j#ʚ)'i63smo_ËdfQ0c6%JViA2*N|opi {v+tx2j`U@5)+㨭$W{T.t?*8bCTm +7F$ >•㺴s-lT*ji + EXdj7X.Cv^EȄ9- fAnVof/1 b3A)~&" ceT;o6rNI-iPZ;95_&FOxYy.ȋpN"X"e?r1uIV%`Dc+٣USxPBZEgԳ;oP"M.̒>1θ `ڠ$wJR=o)Ppu,8k~N^2yMwp Ŗcqg1? ?$"tYq oLN݃ c-Se}yPNl x{lB!&k(x~nӵMT:pV L3'3`4 %$2%',!ذ,48of>+Ⱐ.+>zU{6ʰ0R$rJmgnZBg)&-p)P{!op5cURzEC7_H/ӂ:r2*铼ԍSf:Y8]qiR-Yn>a s] cqtpgR: _%yY*ڌ`eE,N`NKR:(3l S,Qy8(Me0-^%͂d {h4nnC_7#L OPmI G`Jt 8 $ _LLz鲖\R P+% bsz*{DIAllFA:yeyiP[e3Cd?MsMbȗnp,2S|JaNAv0q5+>JsIILtŏcğXYP5DP^¥<W 4I}ԁ0_#Ȋs,5o{vKVvY4Ƽ1K#Nuw =7ecWe=%M$jJl(}`Ded$ʵ'Z?a#CEŢ5x^`|<~\66K:DX8BU30rB=g& 0FQD[_; u!I}Ba@fNctHD%/bɣ"e8tڻ^|u7RSd7slgjWRd(g1+@n2G!bÇi@IȪ2qݟŰqj<ƩxɂP\NGɷEY[ 3\'Nՠ"6A;S@ĭf+HiQNAOј:1Xdml\ MD9z.smܵIlKVMgA @ ކpӻF3FY\$Knqkq%v؉c'8{_f-YK )RB"!?,K%R^_h ]{1DaXJ5x-z@~AM#:2 腖!S*r 6E:d.|Wn +-3"ӰޯsTPDGELR, =DTҩU4ݭC9*Gu7 MξxJZ!gL; bZ@aqH`cFl`xDg*Ry?FWqdTRnv!w T!CUbA%[lQcj7~ʯČiR$ƅZzLi7b{-7ocjjRnQ:=Jҥ4tdJ?K,Q=z@

&jG79ҝ'H5gjDM6Jv8ԝdu6)`֠vhᑗܦ$5&jhDr̶&dNg*|[ۅv102Y3X@PCe>{yhG" #䠲c]=^r-<{uOړG>͖ b1rm#@ :/R-[,Ys)~oDgxGZ:)ƻs~-P]@'= QuTZ>A1Th9`@Ǜ{9m닆^aĠ`Y,w>- E2)ΙQ]ôP@ L ۡL6V,aؕ̍5{1#j>)=- +Fӷ}dSC!jNlis}Pg$y7 b Th] [P`N84 +U*Y3WE!eBP_s43IWR=sM]DDOLy6NZgBY @yU=RY"d +n-7Q PݩV~/;A5c%A >m"&Z8vL&%0FM >yLS])^Jc_o8H!B*Qq)! x Heh-ml/N EֳL=lڵ\fZZ+ڔk7NiFmsdi6#!{-qčV_ITCY J&Ҥ}\NܥwVkkׇJXNna*p[aig~T\.3:XU `.\Bt@+ٴƝ{?y%lg6z`#wwXD +nuJ]DT:wD@Dxi YK'`}~8cpn%m A@GEMC*tVF {»Yb7 NE!Ί\JS%U0+([0X%MШS=?}}m1,R\Cvٲ;A@vZs)T*:R [2IŸϱ'{K`MqCgI`ΐw/S.q(_hvsjpV|Fīۺn1G6 Dh\)d;fD JQ!Q%c=?={aLj7@=gK 0 \eR$1j*> D T*_a%vޞZJ v>*E5'8Rf}. sΈ& #t.0pDwGPmJ*8ojH *mY5̜^Tq3NBHDSꪮmOS i fR=<]yΈ`[qKOtxN]H.1̵DC {)[8I'!~Gtos)Dqur8wď7wXoRÍ'6ú⶘*З2tE˒"FX\ײ{5E@&ˮ{0̈.\vr9#%b=B5"0 9LDHשpǹi[R VaɊp@ZRTķ!T= ;3?PPEu!`!0ﭷ t7'ٲڷ-uj'zP;iB +x*NozH!bEɹIFuOӏo->ל&M*(Iyg(W]$~>Qsv(-3X_Khm""Zo{]n˛=A*;j?vůJ#Ps"x@bz^V%TXd;_r5CP;cŨd<;P%8Xmyp a5&9_H5,1~Vd ϳ <{%-Aj" ?F!h\ +BҴe؄GB;lu#,T4#Hc$!&XeI{Q}`߯~-+{y{9d9?㼧p6)F<N(Ft_-m%ʀW_>oa0^b,X\ +yX`(eՄb'[fpJ>_@lKϻĨ** Gv [=im11.:٭eR8\G5kK^v^*qsǖz>/oФP Y#V(ϳ+bpz؈Z( 4@D7% V2 (3]\n1:'",)D /{AgIy ++fEQ9< rƤ}ppj)Z%?7L& GsS1<*b@:r5aAA͌k:C7ʄmW+2s}Vl+@ `t/\N[XOQ +RxxFΥyu[41Qs[@`weKIPC45s+H ezInkǎRIP;D7@6U&=]--Aɔ/V3P#xFG[ ߰u Ò&apM\'? _/b]$⵸K[n0S:xTA)o*h2MB|Dg_o*pj 'l/ o4š^?XN9 D( lj (h9U6鞰 &1g p='-EdwI8Rb3ΰ#8TuwEi;4ػ;PjQF{"b{)Um.W R~쐾E|Ye6XpS'mߔ{B)1jWɌQqpȩ jC:sٖ͂B(#e5j=@lCՈؔ/Kjr~o񐹅`K/@:%Þ 7V/ӓG8z>,pX`k(BxU]+` O̘ܺqt\a6BRN*¤ +݉X%jbCv¦мog9+82zOY_-Llj60A?iHޙə##JזPSGhmҍbF쇞D v&hJlͩbD[lfgx0\s*[3g"z2WPPa3({?<$g,-aW5쫯HKqf?6"wZ6~ö#'nC!P:Jk@L)kv[ npϟ0auig?zP]5>^_57v@NYՁܲY=Ԩa3O.:b +x*)k/ Z})HÚA GD> )ǒZUDО:|RxX|\Ͽ݋ŗ i:%[)B;￵e͟P*MhpחF%1J=j06?fpqcE7^FͿ1^Ƣ{=|g0'GG6CYy['WisJKvkb +.I%!t|Rݍ׬v%*K<kWU'E!Z[ ܰ޼+Y9[߉~c>%}Z|TH6`?Y]5ZoZsW#@Bߩ<;u?ӉR%؅bTH-mw XJqT!CmWČZmԁ֖=M2B#osI|N *w.N=(-" +*u.e7/"=͗#QQ%֎y+s)S_, O~COzEHnl;$eF_< 4>tr +ER*N$;Qw#m;`CI^rU]}ԡJPa VZpZ&ԻVbp{ȏMoެ(݅ˢENʇ+P!3zR0M"] T%d _=㿭^Kk&vfv V~o1ܡ'Q=y{> N-|xd4콅Q$SP! _CBC +ӏo^kn3T%otKw"J)@ܘAhTZqD"9S}nY9)`ThsAHZհ="?ݒjojA6;J~sr)M\gΔKJq#F&KY4JeBKTc]@l-Hrf0HwIc[ͮFּUj 青4 3F,F0!3vZruE^G|9u{ .~>t< 27.ޥ~42zO%bSq#C"klSH<(Ȃ79:$oyI>e +po>/1ol7Nio%𴘝R oofXNg(QlX;OH@ + 703-^JfFe8H 1ƒdm@qlF| .mra@V*:f))a5H;VM"3"g8o*~2n%G*veK_Xź?x uĻ"%4Ӈe30 x 2ց8Cc7@x`|l׳E:}I wfY:uEs;fA_;.S0,S6$JE=,9]5Lc8iԯ"ƑNdy&]jmsvlǢxv^Q;!AA%I/RD7S5 5_`i,M\ac +5_;yk' $ek_^%1 xU:~r-'Em}ǒ-Qe?O#"65QSR|f`{{[8H# R%*7}SObLIg Ӻzvl`ƳߴB_0<ԇԁ{hQ>PG@?#Ty]=fK v΃s$M SI>>ir*Օ$%J/ TaQc&RVf֪SyA8FFZdfxv0tFgIŮ ip{.`>t'Sy;k!L+q$tM0$D_"Bp W4K˥&0xb#x[Dq̜-A~zbFxCC'vUáZ;=f[JS[s0~Fy2״`)Gl] +CƏ P#/CB!5~AD#B=W= +̐M'>WY&qgy`ϙHn(ĕ(PB{j˯ߢC+58ŶBc p}xaJ[J0,DQ‘ہipytLƜ v AC_hU{$%l{I…Gڃ6!fmU^"QR{H+~ & 9/|CrVȌ +W1{]LM'SEX,ȣ\X}p@i4S̄rL"T赍E2aH c[k<"-ʣ01@ǃ,lNd(\]#K!E0sw3V^g 3}a;/©^KAizڳU*A&G9۴*V~Nq}_E\m.ϙ>;I'Iĥ˹Teo0!%d;#VLaDC]u +N.Cʸy/L~mU-El 3J¨6WC_;V뭡YrzĦ$m +;0,NEïQ;XEhQ:^"vusan~B|>Eѿ7',e)q&m°1[Ksӄ_SO?Je'0*ݖD㛻-1!̒NO_}_7şe40soEO%$/O~[M4 +e3>0wY2cfsa$]y[N5!Y U b>p#?ҧtc__}8Aܿ7}|W:hov>:{8,O{U7 }afn}3HJJUWVuMuWOOLcg|[,0X߷yYR%E2|2s;eGSZw߼}޿~y%~nj?=C̕7B}  m.sx?ˀ"$KgwPwHDCӇ:8 E$^~n<" v<@#d1B]d E&,hxAն=V{teLLE,jP"L'k{A߸g0)烉,2O>N҈b ^'6 O4&쳘0tr3B19 )-|QvB}tD35!0e3<.8/=0gIn1c σaZz@8Ɂtg :?x@`gȵexۧT]LXJӍΈt"\] ^jct͈ekD:I\ϠOڂ.䌈^]hj=?{s ?mZ!b+R6(={5ԣ`ثCuƂ ,õ]?XZXlpS95Ӧ04M6ѧ~&ܰ]}.V_~΂ O R+b{LHC/oߓ334ŘΈksgyO0sJwdv1}6@O#+-z ft{ӘCh̞SoZT~n晛\%>029x}KǰA=8S?sJ,hD&e1SL&ؘq7ֹf2 S#?6Qd\K>#ѹ.ek&LUMOWMc䷷ ?пδ/~,:xzU14Oແo.cD`/@s ̛ӆQ`xA0rTWHf6h=;ҋBoM[xoBZ!J cUg>41߿ظ|M,0UGP"~.qʴp$O8XwؿMDnq |_c|TEuQtgߛq  +*_f= +)ʡ0n1Ѣ9mR!lynڟ +&,|5C@W8#:RW{ +n<d5°a ?&5͖ՠeܚ7a k#"O0z`rZX;,zp5ʴUlMf:B{u1p)#H6?9naW2ZQ[L)ۛ/&1JW KgIl0f&Y{J+64#˼G#$U(,qm5jC841NwjP0UWuLbԿmihLFuɈaB,#lNSԻܑaAb;qW Aϙ||%WjxyoVZnrDDo%"bJۚsuX0'(d\0j̏;b-a}sf>b' pzAh)$̕-黆h0lU{eK=-zԨMynM,M?`7&b`\f~(K<f/bĩRIG hD"\qt#2&t7ƈ1jHQ3h C +CnQd>+㷇i^>4zfj:#Мc#Wh8McmrRILSxۃ^DeHێ;%RWC0-_@F&5&~@خJgA3]x|;}.G`T妡&!k&`9u,Y'AufQCn3KUw_r/!!?yL< n8\J1T5%1\M$p&|R] +8zV\c!+n+T@ɹFr``e?u#\JHEɘF0hjC$4N8TG΁+MNgHm=yʞд ΢h YyDǠ8wMv:->>St65fr?1f1-$t3#b44hJ +ZU"Lځn+իxQW>1fN<"byEEdF0oاޢ?m3Z$ 2i##Y _DG(Q3ӿ|XCDC\xł#z2cD;AwLO~7*!zED}&H4cnΑ!MkeM{a\=-)$=jPl(Y R(gspZ iT<ۆ~= C&@Lg ڪO)wB&Ӣ2a4Et mV #[XP46ua^ϱG666&26Z,2QOvk:0~9zDs7bjzD ywN/g4@u>sУ_<Tu# +87H]gfXSЙ޳hʊgQ>ч$D {pg莛9xs}WЎm#rf{Ol:i!VF1S#`½qUu\9@gmCe?oh eT~0e J?`(Чc5'i9׉ܘODm8#@?͉+塱zeDF p:3HEif9zmC3ADz<1z 8޼s>.?(o T"L؛HV<͢gKIMÞhP=52܃^ 8AATlqXk=۳nvB_`άg?>]D`xvڹ0P o,pj_Ft8iڰ"DS{ +,F4-SlFaaqHm[-ޗ˶U:vTc1U#/.3v =Όzig|q'.4qEP-t%+(ha}G$4k^ŅPYh=NgF'щڹn7O:tG1nEc.bb <}G`):Ǣz~jX_a4PD5 ?ȗr,ʋ@2 3%~rY߷Ť w 3^[SU{XˊtvC8c:s_/PG37MKֳcgmk rg?#T2XѶW<{ ⳷gasiԗ^Y7w.#ba@`y]aft[ȦMuӱd+Nx +dYADSjYhh +6Mqp qOiسgt\D|AmyJdR""V*dsq@ +L} *㘉럽`pPH )\*ԧ9ة%W +j^XjWO:/[T7fJ۔UĜŴRͽ6ÙJyzkIg5"0AL,#b)_gv 7(ҕx/U}Tl_-yTqU-,2aEĔ(u2P7NԨh=SsGt%R#6x)T3,Lu`hŋaaJ P-W+5Է[n]`c&YXmC;x6ė-?Xe,` H EugKDywX(&Ò<=5jJ}B pd0D,[&"j(`qx05!tW䩚J)RIIS,G0Lԕ\ GK(LɌGbӜ%Yb0KpJ$LӖ2C#GonY#PC2J^lSӧ{ +?bnK^Lt5,k *^y_zDZ4bۖыYe\rGiʚqcSbq?TDi|`?&Wk=j1,^\"L!?VܼX+z>yjMR^,KXEh Z#~X$Q%/fgum:kGʼ)P("%,R|*XWŘNu}t()|k6,#ϪD!WflZ> [o02ѸG"?`z8 Et;. X +F񋞉mXBz@ʄP3 zr;%ҩ$,\EEA%:l=!~!N3 <.H^3Qx@jXg< ~980OG|$h@aʔ@ÊxQnk܈ SU$;JY4Δg3kkBcq?G ?rޙ&X:;a),5lKQ*GZ+$}5 *C,]L2EJSLE1$>-MBG5ΑT#hs67fō"ᄘH fZ(CZҋ`3X8Ʒp(ObM?#o̔ ^Ab3·Ea:C CTn'T: AcV1f@xb0"̄ 9ez~!!oȭEdADe[X> yD,"Zhī8b˨lK)⥆rCܦ %;`{&klǢ~V(-&t\cԝp )x|DwY*¸Yz,nr *"[JC qPV@*!]'A04ukĊ@f]cH[֊D"bEā&VCÔ&QU,>\7h=T05:pZ6N$z:ez= TUo5Yp84T+.P4ÉHaq٠ջ`OV.Yۜ6 4<#Bʂ0&pWQ<+PFۦ&H*ݜ, 655j7H3%&;[Y"h*^;/uWQ]{t<D +:ewlY* Ll!Q +gYQVaK1sDtLSA\J-b=Dp6YgeDpKA--{̃Xsj7,Lq5M >R><8+T~pb1^bLtu u{vĩ%?!GM24r 6n$G:1@OOK4E9V0 Us̱g. )ü s@ +h D 06shZ$,YL< +/{CP/,R1 ֜P~lLH5 4LM|jxtZtm$E϶# peU8L ,@K&.Up> +1+S"B5eD:`LD\|L +S{c2͇Sby%5%Hn2&CԑyUCPLi>,*̘D )ʇ\:9/y7Q_-ǔahت=#k;T :l %j))?^iLy< #\]Ѳ$̱Hzѳ-UG͂t0.AX&y"R3oD(&GxIֳ-Z 4.x!B5T-H ? t.d6OEY8׳M*0Nɶ2p^-cop=K4gUGX9a|> ڎ#DYP#c1O823 "EFO1yE9/AQk +rMa62SӺJY@-zDkt DWNkq_n0B0Eay<Es ]$sͥ XFk,4_r+ܧzVo4|[,v N=p հSb0xGO]K3Uh"^-|El2͕ƾ/߁Q\\_! eRQ:] >:j@g jU(kTE[)`{MWsyZ-^ղtH$C@[1@E9$KU7 :abdsDj +r)m/[ⲪU)ցDWA_&SyuO7`Ϡ\z>5xZq1D \Q}L.42T, zkU%sW[RʘWl|e5#IT^h:X3,ԇ>G ȟt(( 1R[̕њAr;^S* t5Px$rbHLs|ҋkhHA\ Gճkn"D @a sT!H. +SZ3ErؿHtB"Bt9kL6u&7WC"aS3gڋ%\+{]#(O2*ڃsV7M'T#]HgZjFKwK)tĎ}O*CHܥQ:;ޘ&{Mu + ؜9+ BIWgs"]x6h-C/T4@*H^M1R=.~=Q8g.)XL{ sb,Sd!mN1“qc07%RjXVՄ)1f=l+A,SmKORxD$1Z"s'WB"tjˈ} 89jsf*z +^b7=s=8gSoDy`JO0Äi.詼6 8p#GDsgKz Чpxk•)ȏTCbz? ^RG7 /f>A9LcP^fZL\\ fzodA"Bz91\&5F̷}Dy\ d6^E|"N8CHF2#1YJDnnP}_q̴bW|Gy^S`2g&':mhH,`ӬgCZ/L1Q>Z5Z!QӇD @y#RB5ecHdjõ"FTⵘj4hM=Ik=W FeM?+ʘc='|clsC5+PcG)2/4KE-՞2|HJX#e(N~Em fyG3'EpJJ4 -Rk{nS0CM4RZ׉ &*xX6d2KjJbʄG1* g˔PAg0etÕy]DQNvNLy`MHq>RmQ1&hT ͷ KjKd`!6QJ%OUN[Z@" "z0iX@nDK5A5a':Ti,1f:\g؎BG=[D莌^3ӯ@x#Z$U2{rBt}{Ж&-ؙTG@#b:e+,E4KR jф*o+\%轼ؖԗZ!9خR(hJ>IlF[%4C̿`\G3=Ouٹ'nKXKdǷ7ݣ)W'ruDNWŔtpE,,Bܛ5c jQZY0kE =Wt +\XE">ڰ[u6a빻% NIߖ1k,Wl5#_eZK4jcf +Dʘ9UC:ܤJ$28!ҹ X Ёy]*unDB٢䛻TC#$YW0%4V=?7H}xT7IK/ L +$jCVB!,?Q\ xZ!VBF!*! Y5r`(d1F9kYKb3%Ő Lz"Bk_,._R>09RTrëO`~얈Am]R鶼綡,g E@oS@|5F%juH;~x QΖyELa|:PTA<4uSL))]4eAYL˃cOdw.,%;JjLr A1e<\m wr11=$P,VNmƫyDL˩-n׼gUgWsiUD0տBGg-Agg{x59cmiyz|;lo"iP{qbO|y:["7t}0'J1 sVQr5"鑺QC_?0Fz|~'#lˈn=DvefHdOHA+S*ZRDڙGtJh/A"B 𳞹+}% +Gx̒BK٩A pBk{:KH'x="E+ (^wG09>F/U$,MrKc(oCNӇ+`ō=EyxNݶypSj*ЅaQEZ-.sгd W5M${EpÈ + ?P\0Kp%G +F\.@BωnKalf"LiaeGՒ{p̍@}=.뢾@vdZr̿^^i JDX(en=8%|%0Mo|``f"$ևLJUWUUH$*`7U\QŸs%{S#X i\OΛBK . ӈ8Cy!Ň8 YNjhS &($J:n`Gs~y\Y+w>][ggGE0B &#!ȽDV"vض%8I<4O7e9 Gf** EE0_p ݭ?3 dX3[jĕXLXFA^IvF\UT +̹8EE7ЦeeL "EWWSD90zHe~f_4Eml~NTo6}gՃ0Y!g2Ij4 ł#i&( #Ңz3#*}|jfΝ ]%OwUD-3T?CY@i`a\dTM@֙̓,gG$hQ +K,gZe52t**jm;DލόLμY{'膸AۡOT"V1~1אRmOa5% +絍5oxa?۳e91OϑZ_?W;~o/^W?x݋!!}L)v_ ; Շ~Fh;tvaC]:k!貼c\q +T<6V $B]8{4 A 49Dp#,8SQ{.b"c )p Cqf!1<!V踆.>,ӛ26X-9Lf.Gh(31lN~d{x6!aI;^9rt !fOSV;'- 6hhUڬ[є#LOiV'*?yݿs|M jCO}_anrDue[8 jjf޻ +m~3|rn3\~mV?Ǖ|kS>`5)WȘ)An8ӔC{O[:bcRQx8S|! ofh*ňN4rӵ1{3 rܠL}7ܼw\3%lLG4S 6~\`|0ǙW+fGO=2%4 ؘ+BV*4s8h[|4fRg@ q]\ysfk y4ACs &!&e/0ܻD$=DC8%!4fK$ ۘtJVJ}$\Q[$u>{CncOT?CSу2 Bѫ/򳟽E۽ +g_߾Cǣ nu~.Bg yS_!8!&@B^?07>Z?qga #~l5Oqtgf6W=#/hݾw3Hv\0ɷY]V'wVysn<{#|S2j,?zCzwUAۿLy4z[&׺NOt,'aOWNrKuU},d[|'Y>oZT~6veDilCN'8U=Ul!^;*vmU>6O~ J.68Ԏcu֓)nCq'oqĝdjF*[=&͋l$Y>6;enu#|8|{[ewX-$o^􏾅/&R?ڋF8挣l<˵nҵtblXd~?߷ɔNhhI݅#li>wnS]'J,Y6)>XMllm"lt$]8ݐك]Ϣ|,nY\{%U;\"]:3kW}㴟se4}y^a g *d׉:AV2zUߦ:ze"1D~jߒsrP\lPfN +ot&ӼYeRUWt&ټ,<|_:QM'|eOdϢ-g;ʆ6~v|m\EY4aVI&ONw뿫:yi^[W!R=>r߷i=Onc}X' |}l-$+dRN uEQp+jǰ8|eA0nXt%Bn"M124:pR|އxq%VeˉXh~?Q>3e<ʚw2dtbzr. +'ټ.n/L9e<;P7핸vʅYc8 &@,f{OitLFa$߫|M|c7uZI:j_\>\8[n|~s=R:| 봷JGVdKl=tppn\o83(;'wIy>/Mޝ}שeqU~1ۼT$98ty-׀]NSh8[Lsdaongpq|X|{/oeQ?̏^8;2~nߔ۹/9fk_ūT=˄;Y4Vr\'Y< 'Z. {+H7 'e|wIO|oB`)"^ݰq!3L3GJVTuFasCKr ),K&qB|Qw߄ȨDq{\%˗NQg9UN; q`qjGG6M%vt($Bwo>*q.dvx2e+\tsF+߳%y/,4]߳H0Z:Cä +J$Q+u]{y0U:j"^>Y6vŃ|4lt"Q>.NsUm2<|oӦJGÏ9 p{:/d8^8ƲA ¤}{mn~rlԎH@?sߔuv%j'ݷv0z_6Os?o]zNvԽNv'+FmWeGvRunuFIm"Dhܕvi>;Wtz-fKv|.09ȖO&hq+ Pĝlp-+ֆݲ_ gj>[#۫fLV2Nit(kF׬ĝNhآ1:SimjONtY_ؕ:]H25km`f]yua.LRdi!LQ<z/cU+EX=[m:[7~+%s1H۩~~W!t~\ݎo"i |gvڨ_$']xyIqwֵݸ,lt/{_~hu-+wW|>k}D +{'gf f +tvޭu: +ѝDncu_6>}?.ziiCv.nov+gui\)h)]1\ (vDQgk0YPc҅\wL}_$KK;:o+>xkn#8! f=]YI -YsrakiAmdj[N7\w- _T_@[ʹ6>k݃]:'ҒшLu_g),;Lq4.`!_pak;7ul?ڴE +F'[I8NGvڻpnsЩEptvɦ;r(]{jg\˔@%x{/oZ. nym2;71jrE0NmG Ͽ}o:L>=a`m$mzf%R<́T:MW.Bfg3[TҕP9K`_Rrvc{z`8W6]"{o&V^Z]`pR-gA!σ*]>[m}Z\4D lL8u]6h~$\̠R/1h٠qOȴ73M{7r]|N{IYWA?_Iu$LQ.HZImuSP:X7!VҬ[;R&ߏ9{qa; g6/#VJG,p>\w"l(C=NR8gˬ¹]:Q-% +tPo)U[Iր/OOſ^7Ⅼ{zgIr{QՈ*F`#XOZ!x}2dɚQIfuXYu#m{U[2^zQ|]@Wk6\Z&`Yݻ{nuuݱٺؽ3ynzކXe|GïR04l~(]:K:P~|_wZJu{Uy^#}޻û5gq \.X+0RŃ-6W<9_l`g`wElR2Itw=W3u-_6Tt0Wk7`q \Z`-,~ \g9~n4H^h-vXV1X66Ͷ]toCpnT9!ጟD`:bt=[7#Ha-L'Fy4KOOi6ɇ~+/m6ac쀈/nӼUj5 'mꢾW_ՒgV֭wԠC@oMye7UzqCVghXau;ֿSt7FsjgJwuL"S;37ѺACຠx3/Åu>&Sv=0ɷ56\6 &،`7v= BOl\}o4vop-߬Elw7nӝ6vL&a*0y4Kǝ-& \[9kfl9l>nGѱ! r)XՓMf3d ^:˩X)LFv ֋ۛ ,reNwb^da߮E(l,ǸUO~ًpv𜘽0Y?W te-[i/#i%UeqփCu-< +lQ/Loj=d+V ow?,mfzvq#Tl/^:vwc)~wJcz۩Į6僃7[y`԰ֳRBSN+ym-7 n6 7{Dn +&rg+Guw|vh(׉q" +֮A~?XJ6bt{P- _E*\{P +Hcylg~6eɔvW -MM< hJ;Q*m8' tt?OYEk;.s_n؏B- +rW#l"ꎷRĨX[!&ܻj-qtT1M ؗY@F 8KFwVX:p lcl.*Vi\h JZI7W-qqZqnz4Ÿa5k>DlHO"j j۽I3P4/|dVXq)YNNݎAh4N% KO`u6J{NҨ͒&xrßka5A ۺ)ni< 4.Q;l~-@h]/sx{3qAzKF鿩:\|;ڤV(l.ۍ~z{ǧ#nqʸ d_eJ{k&*`V ; i/a(_. qw⹏& a 6nc/!馱Ifj}~/FAViYۅuuj/dhZ#zT laܲ;vl-A`=mpגP4S؉f/ KRxZ a R{yTmJ[[4¹FxհfWVJ"l)3eF4awpơ\ xiM h`NT6RT~;x㼻 _*Gkq6g8TVXM0.ŽMl([9gʡY?_Zg fo1ہ9Ezkfsըg+vԬh S; ;E88{/tvN^,.ef~)KRjE0Bk5U u4^yU۵Lo/%Q 3'ޝռ5@d5mUo9Qcs]Nr]嘳wa#h2?3fg3SZKX 1;&Jdyhld|B dõoj`w-NKlGrylZ8&Y#زz`(9:2|zf5VLaԆ5.$+Z +>׎J"ZS}AXDyvӬd\h8`cָȵCz~xR4_'Lq]NUAO[JPn(sU0ts=YMwH *t6QO#s |˗_u/T=UoTem1iX4)!6{K&EƝ&H3Кj'_'*G zvV(u&壈3IXaoݮQ9<3|(l +\!ňQ17Ѐ*fk+?:be*I ",HM| +k*wzAņz*dGN? [z}J/ rv" Zp "jNje9pKR9KA` Iq* ~Ô *l۪\܃eT- ,$W( ^;7d%jB/Vyashmf+zeGDaVlzjeC~i㪬 sZ9k[K-:0Z;O2Hl߶_o9{BclvNάo|"5Ճb#;|耖^< | 6;~_nQ8k0]ĝmWUYN( :]Gk 8jό9Lu?Q5sۈ{ER8 ;Ob4lwhꂼ07M f>4d8?L+B-4l0M` Nr-}"zRj׬muW}[GOQ2]ywGʖ N+,GӐؕhe#0@V3Ո=ȕObT3JvrI;+_/f!^W˹8xnL+삼EM{p i^ܽJ6F_l! KI&{O\\G[F]~p-0?"ÉZ̀\VWd$1wo)_L3BG~u?MnaR|Cqe}uTl80^+wWuVAv.`8.05aJSը뇌B&l"V*pU,=JH4NO'hZafhΪ-m_,'C2jt w6.mʱ<^Oo`'Fܧ<2pPx9t̀#jG;Il={D[d7tX_Fުх5X(U۽^#P 5d/ Jt'8Sn:>ׂmC_.h}PA4@ci:i&vҝDK +PISVGZ_&#Mcϰ]ns7;🮐B9j֚Bi;+0S8(v/LPha?]?!]0$AՓ,ZNW=.ˋ'`u|:( g  ŝ7T,khŦIgۮ5p@68R±Y2K0>Ty9Y $pj"\px&Z@ßmۋR,gqgb*<L~ ҥS^6*,9 ;KkЄ@3pF_W }>K ,c~=pF\ g!q2`P@voUB2sD06 - @ܚ,Hl dpa dB3b; + ~- lTX ;OPz,zX 5x ,X]=r X3*DR$>l:b$n`ZL3Acvxap ܈.ƙ36359 &6oN54:s尨0Z*4D&:oe ZWWXBp[)иޝwmOrJ2 $QCK4xZ l;ka P@U΢ -] )`9OwHȌڙj*"2J"ib?r4(GD32]wXJ鈁^y" +2{=lv ēI# z wH A ⭧jvlpX {6r}Fa*2$K$*Pk**crTTˆ'3#3F0(دu yFZac1=)Jh\3g>#Sx +a2P}BzS'DF[Xy4s@ +PqN>O* +,:`܀{" *zf_0B^.\I5U+״M+Z"KhYMhb +xgvGfo]1/fₕ/[DfoQLɓsMj`rF671)V<*TgYOeԈOP62̖ΔJl=8'oAt.R?z}f^Mlؼ2@D_p'Ĕ 4r" W<8G=u9$h5IB]{OZ}5$ȸ#ؐ;7dH: +AaB+\p |Y|5wz4`tFTW%#m0'~˱ۙjH8w>ƓbBlãQD0ⲯv(߫M!SJKΡvetKeHJaZL,||&VXy- l 4ЩI2qp!33jEJ$hebYwV5%zsʲݟ2dEZhI&ơ@Y7,NY"겉q&9 =S@D396h) aWr{jeB84nM\ёNn8$4hP8*:l\@u֕7`4`y" bVښ?^9Kp-̳< +s٩ՕDqda:l p3]vLZJ`bmy]6-,`} Xm_(ۮLwNvBޓA#=Gh| ~U ZY0iOΗ@q5vHNlC(o=eun9,X3:b.h$,ҝ6@>50Qe|#2Dp<9~4ѱbo+SSIƥKp+9+Ɲvw&WAXFx WSǓb͙[PS!'CzTzNlo{+T<Y[<MX:0B~FIoOUΤgVV"B NB +!Hgg/&1uHi.Q_@찍&&vhO0YqtsKO ǜe<9˕Wd4D@_ CBKWhIɺX'Ѯ?b cL]pxabiKtgejt==~zݘ~/kX]cWrStj>v5wþ_NMno7}qӫgG-,3C&j鱭{Gfю_66 ]XM-zt`DPBB-<̴n1mqyxA螶GɕfS$Qur+:3L:\sCfƏOڃmܼ73qw;jD9X_5 bK_?U6!\{.[lW^K:+}:"$yFrLy̕Y2b0*` +sfn/U~rF+3H.no  +Vui ,=lnԝoxjXؙ;ҏ*LBw©Gw6|8z?|`u#PZ>; +z+gLL*P^tflyuozv`gtVCK[1 :BqALF +مwlr:=qcqf:̀-j A!3W+v]*T +'‚.t|PQ,M H%Ӱ<9B'Ԙ&qEvt%zgpwd{4w:?s +myhƄ:VkQu +ud7C}ew {mj{(t&Vba8mYW+Z*X] "kmܥ"Ïyx} H@Z +endstream endobj 106 0 obj <>stream +?K"frwB58!RVAű€6:PBi)5y"?{~}|Jz/|vlg}ƪ 72&@]ںOHkJ{{d}*d=)beT+ʪHQEDdp4;ÃJ ]l9 +xJCD% ;ؤH 6]h'Z 't@}bXyLG{(`nVl_ܬ/].Lںy |{`yv|t$e#ŝRQ#ig T.z@޾2s>Z>W8n j(S "\95jqY\\(6;ZO`t*=,x!=q10 kXZ7ՑQ-I46s'@cQ,ֽ9ěcr;mrǘ͛3z*eh}0q +b +rǂL)*]#=;fg U֝ǃcd wnVGl\[\R r&w`H>O >%nr@dD۷=t jZԌ(j @=?]ov_;6M͹?sXF"_503Whlj_Yytq(Y|):vlmq XH?Χ\'^Â9<?^?Q3dآ4>X_4eArMȈQ<9vEQ_,PU*Q22gT&3ha;u4wT+1Z<ݗ^o}/~*;i ;[5N+$\3[;C\ܸpw=׏~>ybnl:sI=!b +U &$Rngviz3g}'z@Jr+eF9.T +$k?H+kG[[Z{±s>oOtozurݟjʹ̼ DeLt8Jb6/SG8s;|~z\.q2,*LW\=Yi:s#|>՟}ʷ ǒYH$̤6c|h]}G}񁧟|~^{W~η{8wXaMN3H + p$:H4sͅCg33O?|٫՟|???/Gb8xL8 +eWFtay0&mqU>#tkuKlv>з8~4}"Bٽ1J4&g;{>˯??G|Oū?~`n\< +2Ct]:ug/cO/=Ok?śo_xy?ϝ'y3&Υr+{o+O r=B fcҊ %K#sϣ߾gz7}/?gy_/m_gL-a&G't^lN,n=}[w^}ǟ>y_3CF*3G .ě8(Ds#w>ՇyO_ooGw?gꉋl r r}T,Jǒ.=>?>o}ͷ?~'~烏zZDM#E +7TJU˝ʱ3੾+{?_?#˯ؓ=v|55yة ?~OLJ|}/^cve-\h2 m,Lp'B!_\ܾ|އ3Ͻww_y?_`8?x_}WN;Gb7S兕;/]xG?z'?ٛo~ɧǟ/Obuۛl %l0[,:q౓[ۇyƫ?307?|?}G|K~{Y3&[rI C(/C=w߿ǿ⋿^ 7^^;q+T1akpJ7765uģO>xW|<׿_|?xgw.1Q!.!Hyz~o=?ͻx?sP֏?|ǿ%ϯ}Zo_! +Wer!\ C([9}zk/Wpws/;VfbJ;_2dwry;3>{3zKWϞ9w<]J2NZ=jdTiL X:QV[N{es}ysuj{{+.qλ1= p.KP_Qmʂ!t[/n'|sÏ?g gZ3SL(VRaI:xpgOt^Zyⶋ.]t?/~yl89+z%Bj͸"-dTܚή<FuJas$H 9X3<^ gY1iصpP("2iZ?hp쑨fh$ވYCt>91"㠎:_ 0a=9j qo쮠 n_q/bp8OY. GFKd@j6fwk4 p"I8o+fɨ ťf#ˆ#n- #*dHa$W'Y{)6"B&|ʑ[L]/ ^1.'/`Ha}@g@7K@zqtyӼ +Df͉႗'RFsݞxܑH CZ'w+]JLba\!WPcsN#Ut:Xo/]Mpz&3rCe|19N7 )L.¡7 E"P8sلϲB Ffh UWu>iTh.3s0xaru+5!ws6o'QظA%y%5e@Gj "blq%,Tta:Xs3i@JYUYH4V. /+jYQ~OQ~H>]F`v GԈP! ,3=bF7 b)@)n>zAѠٝ“*O(-/JTn)3N[! L쀖ג;[%舞} +Xbp=FjM^#`&|wmL$^H%A k[ue ؾkolB-/xcwH[ -N,d\B ךZ#Ä__fSY]Wѓκ5~@CM2Bv o눘3sFgdVr]ѕY4@#&Y{f~F2XBՎpcx6W +LXԷoĠF%H̛YimGclZtފS1bA3i$8rT %U+ʹK(_5{a&3'G :n?798ΚC [0K+oU[N&&|z܃Jg72GT%!g<{wgu WʈUHD\H-L@θٛwe+nbrhhN/|UO!:'/HQg& n1b c֯޾(x +94+vo˘ +ZWځɄədENZvN.X=39'a"y=GmfvT1HwI{ЀX=ņtt O}Z:,dģ\'52[=o[n6szM G\Bv`6rͻW2:V0 ̖" 6:Bg=V5 |@E=F#sLzN )W1zMZ)*\byq0aH8"xӯ$h(9$/8*vHʓ|ӌXRjo3 5W kJM!6_ X!5F{ q-!SFoA犓Buf;TQaĄF'}U4ǎ`\~06qWS>o|fieU[b,v Θ?\PA,@jTds>j(~-#ԑ 1 +إ]'1aLЈ!ꉸ+ (pG%[v]ВzV:t⊻żi휕`ޥqF2rz2jm,A=5AI- +ՙd8rg0jȯAZRjcG^3R *Gm +Dl4hɓђQ3amg'>Ɲsw$ +EkJ4OIka6NQQ`M(=q%tgIy wSsWϟ(w% $tȔ;6/d6!jvuAcN8=`([Wńf LqYA ƀ +շ\ŶcJtX(>`$ ħ 2l# >OGDi2ShhDG }L&_\c] l$Ew\]9t6_>,DoK-JM c&g0_yӭ 7FL &Tqq3 }ih CXO>^Y:<mds`wGA-8rb@(&taYmfM=ʯ)捥; wzΉgJ,ܞ!-ڜ]rx4,l5A:@~S*6ln'N76z 7y)4h-wCݝMr gcʙs\fD`6b"L2[b΀UT`)% $GC;Xٜ)#<Z5,E͸_[X kTfT`Cm Ytff`sXYuΩ6K]dHUxvPu8{tv'ݍXcEEML8o9TYKuz=R@ngx(31nk +4j r۷nÓ*v@Kڨ[л@ G-^UbC ! D-wb:P^|kiu2X7:#̫t@+R]\:0JTL +W`k1Pmé^sȢ =LlL`<_=yΧ'oc+$&"ZRo_6Uh4 jzOJL[@MX [ɠ`P(P%piK Q+]\7k*QUbmȝ8Pgl{hhy\qj0JlհWG"KjۧB xj:fu`__aeE= H&2$vGmٓXDۉvU&Q4X.H@[$BA[ۯ".)+S`R3WYxT RZ4jR +{Zwfˆ l`vwЗt%g\l2Dj@P T 휮{UQGJ@go3rQzFEl|]oS# HUȭ}*5sz"E#;hca pf@u8*GlqgsXwgAnf$QRGab&oo2 6D:b߯w#b VZAΞ-whj9͘ 3P #„m,^V1`- gn6$6VƐ@ [e7WgVB49pa~yg?}ètw~{_V J"fj\v97~9Kcz I22N@ƨ"6jw8Yl6.TMΤ.͕ϛ⋕bv9w|FM4(^~yp]r\!o =V߈  dt@lsɣm^~l>}l<l!,Alch ,] +; œѡ~_5jr & +#hg"FD%uovқ9=G{>q̴Z4g,P@{C8 ;It(m_֨FV{3=sF/{Qy>< A@ ć\/1hrb<"((OEB E=bCO8i0FNKxIdnfx>\Kgׯ&n.)'ƖOr3 '5L*|qe?j!BO Xm4 +kXcgl>悕\vyO5a/㩑Cfꘁ*"W{'LAh0&unAaR,O/`ٯ c;^.o}VS>A'"D.1GWFibK.7s'|+ bS Jq)v[IJҋ|r1PZ=x|Pmd={]V}A$4ցa'Exf;eRj_ Zi7dC=xra2PP*K3 +iFwImh>X!6Lx} +/yȬyX(R_wIXgά]~ WH%2T"0q̉XӉ. x̘l;xDv~'c# V 8;BaTj8bb&?Zڙܺ2{g䭕{˗M6RyHlC`~3FoЎzoDK<Vm4@'P:脓ٹjp_-pX u5=ˆG|)r~cHW mTƷOAr@a0_;;w^z:>yY QQVXB Z賑FHy<ܔ*+ɅsdCC\j1^_?s㭝`}rł{4F"Cl|֭>`/NsN Gm+EG@Ew6DŽvqk՟rrE44Rz"XK@d"#' 4zrvk8~wЌ$ &oD#ﴐV7d(n4ƫՉBr$?:u=\I(4jcJxm;ICqn&*u/'ԊIJ>QnGR %8^;k%AˊX&T *õ;?Y,XVra4hL.Z6b}v~^wǠ :N#TGk]x&vW/uh4 #ŴFӑ73#vI' "QDa2StoCC]&<Ȗ#Fd4#% 9ӧzl1x;xQĎ $cZH&s6, E*;ڎӲjzTHfmX^gsYT]Z5rA*&7ƿE;؄㝖;@g@[n+riM-Ab)T3-޿#Xʣb + cf>We=\f:l5y:IկJ[6 di +BC A eTmfwl8 _u[c1w)F :7eFM^ANL_=tjdurm:QCĴ`+3v*aAe.Y=+N `ڰ$l;p?2}rL40&B`nP 7Kc'mlL(qʥZج g 8CuEmBp:J(5ࠁ1xhՎһX/If&/V.ťlP*T̷׮Al~-aem!/$lb!2 +!1aE䷏}COu:ɫ0r#B(=Z0 *,1B33rr'׿n* RnMN񙃇|2&fVX#}nMgG$P>Ņ*ŕ#rMscՙtc.<H@qM-gFNo=ZޘTa-cf"뢋ƃ$TRF.z"#6UDnZz慝f&vO\/dc2,C|PSVXPm +@ \rp,\? +B89|m"6^:4s&W_7<|̯hS&ѭb`"Q'E$;<ZZל<ٚ=E\ +:mjRtUf +~+kF^t7.3$ FkIXmzkuϱEP5S3k>ѯ>f W[ Jd쾒❃^=QvXvT,Ya0&N=79/htv_X(~[.aGlNϟ|jS'Q)N9PZ24p!Vgxt[Gzu9:>; Cs;Ѻe_(fZtqz3Zi0&BBrONf"CZS5* Gpmx`%#=/U6:ᔾ5$c^K[Jny 7vfl[JObjML2i<8N62J ;2̀;`jfo]"ljOK=v⨅GJ#CLm&&,RhWC*b k%1 &cz'S."j}fU<VKt$gdž׮͜|va+gNfC 2C{6TR&r^B#z+q T3E91g0Oz Ni!R &FDNZԢRm._8}gu"Jp 7|L n̶S?YH8?>mP. "Jڈ?:Nfu^ I2ڈ /6olݩ +ɉpzj˧z,WcC[&_L8>fvl L+3ّSN?s #[`F*ٱ̀D@̅`qKUhA yP-&,Fs64,ذVK7!K 'v@a>R_WP85wcz㼍l6 ˊḙtm)%49?k@/2b^>Zyw~PZ 6dRGǯU]aS͙wN?fka[뗃y!efoE6ħÛPNnC\f.E'|j V@ WN:s5<Y*,OTȎ߈66DNPJ$g4^AX7vA,faN:r,H@hӎ'}BJM5.džrȊbjyuƉo,=V䐛 b|b-9/T7Bt?&G,HQ {CA5!@v*\Fܓ.7{VM_ d|umK(񚇎'Br-vY.^}T:j$ ޠɑv?l"\ڭG@;:uWߑF,&B~W<ʡAdB:6-VB9~"1yL @Cu0BzsorԸ If޿vm",7@%#:H|7G Ov;A4Bowڭ^)]:Yd!-"fHjd;>lR-7Ξ8̭?,Mm ˯^왗km::.-z{ܼ+UnDj$1Ԝ,CFr|vrK Mo^, o7 +4si=K9#WbJQl"q+WiRa)`ZNː7T$9-Z[ۺ;}p%@k@5wtPswí25AF2D`jUX#6,w 0>X bL%Ll 951 sՋw޼̛ע9>0AWrBl`|:\MזB>;upe0EE=ts6ڴ+v4[4/K./&~vY/n KR5H㯎X]2Dg0xJ ټkϾ闊n:Ӝ<1S6W&|v :١G]$*7||KmXnNOn:;15=J&,Ѱ[#W򓻥V<ǚӻO\ljaxG+xvbT e: jVm^{kfnm҉/{o06KVLJOo9yLM`Q~!=qq~s6ߨmo^OD'Vz3#bS6zsn6V/ʥK/\Nom?^;|eEO `f'&kRl(ԬBmDQN* X]+J# "&ĕa& ȫÀ \HgwQ)[8جM\ +dDFLv7Ҭ:\Pң3cW萇Y Gts\m#F8uUEN6G.O˹9sBTڨREak>.ce ݝfB[^S';=fʍ 7h`f8j58> }gcVbh(Rb$^N vbz +hm19JDDTbT畭h6@1I X:17#8mm?}ƃĉ/LySfWx]I  0\4}2!>*x=Ykgol!BzOŕ^J6VS&fJqvwo~~W>jÏ>ѽ>ˋJiEۭ[Wߝ8WR9fupPU\\Ƥ|usqJ-sQ1?M&F@􇆋gοsR"%G|fqlui!f%.&g+rJ zRu^B!\ղp*9揎/z XEp%P5P86l@`׌X+T[>@ +iRLClzi|\|C}&DQg,d׹D6vԀuXA_N&`)2bj$9j#T5RljVɌI&>!$#picL0c\vA|Kd4y'd<D5@FQK gU;tӆZS;ǯ'2c[VR)4P%ém_j BHi\C|F=|K`y獹L&-Hh~pA$1Ĕ$͌sndS7!ZäX8kPp॒}{PG=aw[y+'F:TEd[r &ޢ"#PH f`>tU VUH +"a.0!K LB 8>3X;]G\]&?`aCTcs  ռI6.V7q0z|z;{wM&fB͓[WމT"ֳϽww]R`kLmLm>{;7ȵ6^ňʄȎ;5񩙳_KV8?J)\WneJ/Y6[{4z;QGL1+iN"(Ç tuWT^p"s`*DXՆ)V~թّUOqbbjt>܂nBSېA9Arx</xkNq\H{jcuF0EFJ~F-"H(bE[ܜ$"499_m..S3FIqdyv.m"3IT BF =BB#u'JSkk#bA?9%l4!l^9#>+H%T/a2HԠC!6'&ULF/դ$F BqA#4:;ɧzmv8A Tt2ze:T "&eX59arZeDMGPt]AB>?xtv 5xxe 2x[02g0Ed Yז993%QBj$A]9h 3.!PZFܫX>^RRNˡ'(`7زLEIT*b'D^?1)h{ }&C5֐^BrCXf…@Bdd c I9p1?CXNp^ +f6,0`:^frOuz #bxMv Km>XzMy:3no +\ *J97}#ƧzG&ׂXqZR~ˆ:ܐÁl mMuOٜtIsZ>- x~+dp1^*Wٱ#fc(FV#Y? +x0mrͦ -ZJP>DvB4&7kF ۯz(O֍ZT'1Z#9 F$Wz٭G|Gzͽ.ф%Ƅ[bG3KK@~A#C`z>ÇnO͞8u&A jN7 +IpRNhp].&P<>8?)MjK9TȂ#3:'uF|Єv:tv;M~Wd@nIfۧllBjh_sy> _zȷz͔çCBHFzw|2ɦ`,ds8$Anj:{ +Cp6 +Ƿ.J4B@B}rd,vO]ï察9myFT0틠D4xTBEc`$iWs@G5hf0qt09{;D0H2-7=t΁(A @+aDKqB +SNJZ߆phGF~:YV2A+.QY d B&퀅dRXj({pi6e`~Fvw49wyP}n;PP$EetJfwvObuxAWJ)%6Ǩ@:ot`7,[|jhe7KRp,`AgA!x^=QNslI6Adp P148=FVHXQo*"6ڸ~vkBx G~QsZ=h&W + ۽BZPkrCOX;\V7#I-*0rjvu1+>Jb +I<:8tQ"Hg"zPz1hJk8N' -PP"9a6@Jw|`LV+yQQ]|s)$ʸH>%D\:;aXد A܈!L\dgSP8ċb ӄ`sK4Ttzy Ƃ6hq.d9V[UY*Fҥӣw'D$P(o=jR67k2B>dtDUC2ŝN/4Ka~ð@.JVJ|1 +q!K3'Fyik&sGϞ|/۽qe{nLFvP#b2V3x=0V ̍"wv ޚtOw앻'w6%Yf72 "{ T#<n.޸}qεW=ڹST**K4v-.ψqG3 6T.4r j1Y.fx"}̡c~ŎnB8"q(9=ݯ_?]}~W?y껏{w?Ͽ}'{v&`2A2%h:l+ zda+ryУS/ߞx|~.2hpJ!( aq<`/7{ޕ_~v|3/Y<a@\X P]nṊoKTbm*vDW_|NnM`6:쇎tL*P!Mdi8ޝ rw㕇gK__QEf'ڋ;wX +;aNp+Vk9S:3?w>͏_z&?ꣽ_zio%d(C,)Pnm'o~{wMO?'׏˫}>7~{[Z*&4{1J0 +$"S x*?zϯ~xo-gN-6 ~*e*XA&3imo.ryE{z?/՗.^ܫLWE.P6M +`b1(r[ wvJ>Zo~pO_>Ͽz߽vGsR uDf,F5bg)ep>w[߿}_>?ҿï?ݗ޾74䃳QnKU*q|,6-ܧLj;[.>8ۼ{د?^#{ӯ]i_\H,Ę3Fu(#mk'\dj~իXxdpB93G ,CqvN)RHj^\SJafe(7=7zKly\;h'|wUyx""DեD%6? M 9`&gB/I}؟_K㕄(HЍpaˇF,Áŵ쳧*yk_=wc:,luF+hvN>RD3:2qqwnU+O_:^~|r&.T͂;÷O|}x珖>7`\rV^2ft0*%#Xw'q|+ܣkˋXXS@V`&7|YetY# $QnȩBN{o0a1H2a(wr&H?ҥD9`8 Dԗx%" B%(VˣǻQ)^h59)yH PLZW׊C%f2 i,R&0@#}'m>;P7J*4WܥoZ>=UI +D)%TT + K4<~C@/ZKp!))`@IpzX "J|AY`cM\ #\61|v7efH +ˡO|†1CX& ͵SQ-&,%PH{&hF{L}R᠖hb5-WV[b\&3;--F r&7*tDBk1@wypÛ{ CTPd)܇Q!alhGbٱdf³3+g/PwfjH2vM BA3:.W\Rx}O9f6:U!?VWSm!7k 6.xXLL%.W;[<ÜLN)llJG䠍ظ ?ypϭDTX1ݯs^ +!GsJPH$h챧 \v)09pRyjƧ!0|ZCNQ`)ϥ6>k&3εNo]y#6@yBr5 Svxpn4֡ZsP%D$lL矗bM_Ԏ2 }i8= M7΄Ҟ\TNL^<"5L s6%tBHlQa?g_(o?=;k{O梭XI#tW(|n2ukkè&9'ѻڑ̥;6u] +LnqOjK4qR\j\:L/,_hƜ*'bǖ}1{%JT +IXzS}CҲ5s3R/6 6Ku36'.Z¾TjLJeaE'd',>_*J4 dsPuigjyoD"cuFHފir'|^? q&cCvA{_8&LncICzN6̥g_brͅPWba/;|%rȁYrPd)ķʅ~Fɪ8~Od_IGR=<;v^23z_˃˛F&Oz~S=V8Y{_)E[n6(|Hmk OgF/La2){T{F#{wR4z@, X=!ru[7_.|[9s;XfL կnX*SMS}KqOwN_gNuwPXT#4B!\{??mqì:k1c B;%e率![~܉K=7)>0q򗷡m*M:{N^hi~*G0xf4wnO򑏫J/T{w)`4{ׅrTpQ1W:sU+:;< bq9ڞ3cڋ۹ѫA"Xs%s3ގIl~ڽt"IL:M@,n+kO\*@ZGa+սϿCeoTlw+;gV=pYW2wLT"r[?~{^l>2b~֎׍÷2Ey:*7쀰1לOu2;ߔ}gFi1X92Og_={_{/,8<+M? CDDnXjӦba{88}K&(yp7~2yPR$}4{'̚ӷ7ʋVRb xf0wz]؍ȵ.&AQv?aSz?ռ̴Cb7zSmVߛVAn4{ƽT\+3\8j/T9`3XFpmq~EyTj^_N=j}U;|_=Dڻo{ycJr~tս[H +2ϗܸ/֬F{v'Ѻ@;^b)@qЦ9+t= +GdFȢ:qx /~m 3ȗ|TT7 X"3TSe*88yGhç{y7ϔ>k/Z_lP`Es[{?t/0 3rT ǓG!Tym> `mR珿}ɣ_w^˹zwC:?_@9W9GauNoPv{bai{_ѯ2Ӌ׿]~ZCwG|]~7㳟BEè6 OgO2朰vL/TwqlԞ@ӽTۗ~C^znc{3k}[x7A+]2{+U iv˯֑PaԎ"+سO~)w=p~q f4^<Ԏ[NjK5A:9<>}eM^ `9dtLd:<TvWG~p˙-rDfFdb2ոx:"ց.)-0>L*-Z\.F?Hd8/ikdf`tPnD8Vumu I57p=4;;xkH덃awfw㟐i/t!_昷ιݿ >"2Y'zT$k6Ty Oy`Ku5%e{7oRn]hᅐFoo"rt~n T+rUEҝPi>= in+ D3p);ي*gMZXn䍘fkVii'E H]HƉ#|yqftnjB vDj&q2n0qb1{NB'ѿT[R3c/cى4)_;"6-S!~*;/=Y#\ Zz";x +fɎIl$4ByT2jύϥ xIu)jgzgף߷O[HVs&~V?o=>'m\i3 nH_ NLUl.yյ磲ry^&=6:tSEp"6Xtpx~[2Uؚ>\M<:Q[?Miw_;JuP$kpv2;xo!{&Bqn=K=Q~P:>G!nVwS-?qDn3Z8\| +D-ny4:zr"w6b( }ɬR7v<63{W77ћnz+YH~aNR@Ujf5Dݠ<@f'Zڼd 0,R ɌeO,I Yr/5xe 0go[g?;yABdکV\ $aASPAJ- ̈́ ,hj#~LY<hgTAw/b5G+@M}=~nʣ}FEz暑,mFZa!3pcvRyO"tnp^\ %;g B "Le+y& UΞJ]a|y=bL9=T(xzZ1p[|aD=~uX DvK_ߓd9j7$Tb5 xЩufW/_?aJ(-s.Ɓ:Jٻ:Wwхs/Ti+L_|qs;ifc2]"{zRFTA2,䦟GBT( ۩t+mDՈpۗgT8kpzG[ڊgtj߁x7T0@KG%bb0iD1QRw#rٟMD2~۳ѷݣRӏ}Z,Q\h|)JS4'Zgtm'bh;$4ik[ =ti2j +0YSf}eiMP0F:.)M[ooz MRj}\ *S+3p[s?nS4υΧ]20`1; 3F6tO#b%ab/t ˋIP_pd~#Tv f Gfу#._飯}]>P4_وid9$ɳ_^*]f1eF|~I\JӸ 5p:}!H>ΌUw5L Yێ譭zT؈Ԭ²L,@F$œхCrOi3ꈧ{fsKAloVHhqHl-GS+!!]r㶟B `ͬΓypĘRmP)n/h΄QIk/D3* vdփ`Ƕ}-ZK<A-GzXe$ c1.J_qMݣb8c,Uie9o"*n{ucZ<>RhމH(cȰZz9(`M^QN\cb%I-B۔~Y}3/[E+͕OikifL%-i8QM.vwޔH{JۍR ژh~[v>Ocrs9N,Տ-z/xL 7*\v'%;KAMC4&ULj}hg2M9v:ko'Lv7.VBO7$nqqiVw?ٿ=Xڻ#Cf*B47nr+W07lNr]Mh%Rkm3 nD-SCL+(PØ~f\ ? V<*UUt!iM@p /,dT_d:O&ꦼЪlkQv ('=1%ct;j(}+7XqqVl6.I j;ox.*x{H̰*mF ))moZҘ6ٱ/Y)yI05%6LnPD9-LH.„׏]AlȍP!X^v+3#0kQy=l@Lz!!*T%/͙#L.]s}`[!vOzphq?=h)Q0Sxl׈%WTYGѴ1| +{͌©! ,⩄Oսoava{qBqx+{$FHeuT*`*cOqp0ft-UtIOe޹*G>Ӹ vy{/ʥ+CRBfΧ'O[Cu9O<%B.p/' + r(BHU ó\u/pԧk}|d4 [xT>?yy ][,Md\ܙ6X:)H)l2 "bk+VBAo>/-u&/ק!M$LnGC\{v^:LP!+$!Rs`\{wBuO|:`ZqlvBrn,YC@r/aBĔVN5d/@F\ 3;2Ԧne7:7AWB\)۹켮o?* h+& =7Ox`\<`1o8= os 8_]wb+.T>b+ )4e60+@Qpƒ26?_Ot%7]*g[~u²0O6C#BKx@Tgt ͸~7K-t>E͠Hz/?]ât-V`p}N7J+5uV>̞Tw^(ÈԈ>Hս`AœO}θbS|MmZ*90%لލ-` +lv<9~_y7"D" #ѻ AVcxUD-]EN]soBM&l/U睓or*NDlŦ; ťZp-İ6_:m=EX +a1.jcx෣{?/#Z|,; 'Mhm:,I'anyHŬ>\w<erOڇtͅ~R P9Wĕ~B Rsq +a`9.g7QVfּH$V>6Zr8ԏiQ2æV)R曧FHoOd&>S0v2Ɣd*BHbsԏ7$7ìYV'o{ CbQnX={{c#n{؅YcDŽŞ|4ŒIZ4vm2GR5O҆ 2e0n1X\p !f"erq{jjpf+kUZQpu!fq'D< uЇkS"3 +`f͛,.E؉Ik]. KQu&0~~qkQ WIdƱOwK'Zi .!;AɁ9%]&aTɁeʐ"<_Ҏ0\ R# SL,5p*0U+MT[ rPTvg.,sI8xy5gTqiF>|mz)J[k4#T90]{Lم CF/6 +ЮQ>eּ#Pr k?ZGW +2Y8HWe9KŶkw  MD(wS;P3V8)0eљ>lvDd3ׂ"qOhݸ\Z|>݀!UN]G_O&T\EoUTu6RnXs0~bjԐ+_,.81mTOxj/R,&om7<oԸQ3L5] +W,Im+wZT#ֈoJLv,.+`Js5,9Q IWO$h"d{!f9\Į\:i|N^-vQtK˒Hj{X{׉w\fTEn*M;R8$4?iyPkJ/rDiD56,#$؊^zYwyK/`JI}{=bir۳%'eAb*QƲ77O +@kV4㌩]ub-72b +S%`xÛ׿Gk'N1Uጋ^\[lLd#tz3@]ŀ\B\eɥä9cTmyif+z<|ͳXkg{)|Xo+ّ3w}kƔ>iL/p]t*"6-?|9DIdN)csgMdo"*ЄQ4cX(&l~xbv5; sQ=AHHjTF Mp3K~TraߛBl,|P҇*a&"dt~y9ojYD@@ӥt' ּT*GQx7&Ë%<*@ Pk G[ %" 1I-;ز_^fP9q&^\N殇B٢މ5ԓȺ̲OE-{ť.uˉ/,.6w6cisЏS1e +Fρۛ$ kx#?{%\#3m9Pe} c@^jPq0|u%h+qC#b-;BH$ ʨ Dc@!݊q!zQBJݤ>&Iut OfVD-q@-'] ?i""QsEf, n>fP3! f!(g1 X̍_˕♔}_N_I.)`]gsJyw9 .9p1kk#xɕ;ŝxn4R~}-ͭH0`Cuhrx1;L`VL>1m+a Lr5 m|~&  V2x:nh%ꗼDHuL뮸q)u6POP—Ohj4 +ek}(D}?[w'AڎIdfl +O(y7QJ:PKPoXW:S*':9jM_nUtn=eRB(fvjyj7@(% +Z > *0E"gQ$#Ri,_50z\e ]lYv*9v\Sȝp'J-Ab H=ĖEl0FKq_c`"Rˍw=t-&/>3v=xT2,tTQJ{޽RvG:Yen[^>ΕlL꣈u uwM0#J Pw أ{Ş0bkNX 2SDz;IJr2l h&"w=zow~Z I"N +] Qn4/݇҆oLS؉ZwJ=|o-LwE'^mp0r'xT'm腭DVM5c| rr]\#2+хވgڄ6z 4a`ƎPY SSmcI9T,xکX *X'1npDhg\!3$"ַueqJa:OdFb.b "U -""RfLnNo4L)3x@UaPbt?]Z!hQGkqO,Mȍ#W=#,&޼s{@zc/)#DcJOm|9^h_'inBZb{?k5 l ~5>^v7퀸Rtp 9q(Y+tfZ~"B2!jZ&Do{(Tw9k>LO70w\Cgͳ>z?{'dau/D_gXG3ޅϪ*Z+4@Yu6a& +a[,7/S&PPQ 0— OTN4%Gj jO P0׍ +=C>܎@ B|S>fbϸʼn-ޭp' f-xTxj@O\'eg7r 8'4H ʚ M0z/Lĕbga +Ml[çZI.H{ SC|>.js9\F'YV܇f͍,GթD2k %|3DrIIRK. 3ێ%/w'-Rm˻[ 3hkwq [qxۍoSWݠ*v6ܭt/1cG- n-CATکrӑXxf-a34aIm'qT|}>ʞd5 Yjd\UXzfE_!A[\vNPZp[Fk.C [Aq=\:lD]7Zf`}V\JxfU Bi3W#)7 +>Bw%GL p@( zL P%dp ?]uPFEQOʽ>U]Za] +$kXj'yrB\E_{:Jh^NH5`yP,*+'1ᠴ-wqtkqBYvw +3yC[qՃ#j?$TїAU8z0Y+6RX@l/] hz3˩\O.P@{{ +ΠJl#-EsN'aJ^Fz\w%m8?[ RyvZmb)r0-t*i# +BŻ%BK n[BTK!8}Al > \RIUAFٜS'J-֎KzKz!w>x:\pj?kVX!x@#0~楪Dz嫛 AtBBezOjSʍ9/-lm|zN[Q>h>7ϻLr#b3.Ur+N lO/^!^c~x} Jbәc\ (7]F$,/^L~?UnemάD\(v1\PV\\צI}H lPWTf{-d݊i +@k xD`|T)թ9~:&U;!*ԺS.'l% +Ԅ0P6˱ $janTy45Vj47L9 mYK@oLBqC/t(וXg T-#r+Ḥ>7ǔL/nb)Df<-joeq"p cR/e W{7Ic'Mc 0xXFOtV, kڏP2ֹ;s _;w&P!\@ UғUWRY|vO9e=BEW#bg:t's1]SWz9u`g25>\U +ۼ='/Yވ(d=$ml'4ĆJ7ܜ'!#eܸ}iQчvN 7LeC1|k{3}d.m'm P2 ظV|kE|T͋!& ` k}g16sT~Z]h0#p:Rg +)kXvƸI V?*Lߕ]7|).lYjŽ?;\c=2řF9jxf4PbDcA&aNB\M*->| Wsl8||$+m$@Ҍqp] ++Ae-^ Nw|O;/Hk +TzT3D 8>gRṔ}DO7h*J8)fTB?WL[D){G_4v +a"K{Fp"4b $= FHvvkFӣ]A[|t+rOD>.O?y0YX Qm".<z!~HO6cV\Th,SlQ$*v?">HHlWo9'Jݤk0[]: o:q̅ND9~_f|3 ӭjPFؖPf$⍨KI}\Lw"[_[d>ʫ!Ù($mΤUbg7Rcq U8vO|ՃQ6 H}kvU; ˕K5sMti=pRF}cJwj,Aj?@?uЃބ opIk*w/Yu 8O=L? +M >P^BK*Uw>n(a"/yΞTOg_*b3&St`>&g̹?>{#,G:tnǴHA҃0$~mR1+KtQn[L"=RXALjc's;M',3l(*G*^4b>n>TJ/܈捽JUπC?u9WjDAܻ0gGq/Y)vH6>kcbu%ZkNbћghB\tvBߍc( +ҼX9!OӨֻSk= zBT@!aH.vN6_wL]DjnW>qVD)wXIgIVCʼ7cK-e >mLΔtU=bS>W- 9b s0fGL3H.{ NfA|Ғa#Mרm9.;"hu?_5]uP}/6tDiE[tbDN2{N1:gӯe'鍤|3$T~ACO4eXK8WجKl5(1u Ż=c!{JD~ѫ?ew$9m:ƻ&4 C$`13kHl9[Cv C2ٝm8ʖ{/p-.[+B閟/̺?!f0y9(qJRҦr0#)FkG1)UC}خo=c@[2.e垝(x4lԢ[ HPe7Sp5;U -7] pM771]S+~n8}u`De}Xg{nzhv'| p +-<ŰrƒOZ(ˁP|N$/]pe,N骍m.=tEKA;xjӄʛNaI: S44'IG\qa=梋[rrPyd\ZT*o#KMfq|$EV| /f_3cf>bꖰa g|;_$ʊOŖi/SORevR9whς5޽K6~mVbaOltlTɔ@ @-XV˗lF.:;͇! +naC'W] +A&LRlf h+5]\/6H\mKdvl`>(-'KdfuUwE<>ru7[qEp +ςAùPDޟ.JP,cw"Mxn*sSTҙA ْkgwӽN 6nn9ɍxTE$'x ;kآ_2`.h{NHLm\ŵҘ͝䎍Fݰ6Y >ysU/[t)k&E;c -+.yg$gf{ ,z>e=ڛ|,"wVg$$B)S4}<9 `X] gLᬋ)G6Hb$Ƈz&\ 56o\[w۔> WٜGb6:NVz"ԴR`aYЌϺ钋)]ck~N0KW 3f؉֛nvѫE$>%]"5E)C?YiּZrHϖu )sHZ<}K^i-~芄=%X s0 ߇vuy=AA>'6R`a}LZ45z8jA>dݸ褮k6z=3y9' g1}TAKHvN̙Q;0%p+^H!Q]ɠ0%)Δ)˽ +5f&{:&cͰR"avuߎ\ltź2R9* }'GN>ۘ&xOjCQb ۔ zxbfwԤ9~\<[u<u0u(FN k&h| bK< Rsu_M41bwP90 P+1䎤1@aJ`'囦PWW}ª7@ϡ [ -<^HAd +Tb lxn߰GVy+Z]+ި I@ AN~-H'VI6̨ +=amknI +."}ûؒO Q }v +TP ,6UohmʔTnrKh M"ՍZH1*mi)eYfW)d*7|X>-l?A2}$ sŃ52ocg۫sh !.,PoEYv- =D6%] 4rS6Ge R0YVC2,)U+K×a<\HNCюї<<̲Cg`ְ*5$d&g˰, mq_ȋnI0YuPJ/?:Y DTQ%L%Dn H*^Dj;wF|aWz͈6=<%RK$ l%2XbH:uJ}7d%$@l o +)^~/BbK3J>-{hs*4fB8hd(69z3'm\_ x V$!8dGޢgu1ZEggfBH\uMTKC[q2ɪyFO^(UH]S 3 5dQ:lb09|52c+ 17%let>/~!s^yDR-ZhcLW|8Vgn@^3nX# \HS~i'u+Z􂍒.T mBB)Nm+BpvYA.Cv!=W8D.<mKн>IM?_`@+%tທ.xxXgN-U7앗 +*5{/W蚓ښa#,p*qP +F']|2/֍Bl[qJ*=& +;jkb)Vڃf3Jڿ|WW҅uL]Kq@#M|jZp aû)\lr: @Q`݄HzK(z|v_H`>6 +!I.&uewhjt:sI;IGȭ#PBʎw/>,|ӄ0W] V*u'R5$yYv32z25;X*"#BO1}dE ;M!_ta)l0JaJ0nL>i# 'TWDcUVm;1o x`lpFE[Q+>h7% yFCjX Ɩ/ܢ _tPN<&TiMi#@MC܄ v.~#xR#Q8/C՜f\t +d!5]L7Ү_,2"}|)0C?qފ!y%ET6EXDR l;d<ںvbm Um8xqb1(-%XE؆mp,zX ͆%Vg+2!:2t\pL3vaNW}!W] ;_zRLj HmnZ@ƭ*ϒdۗ ĒW EGxɎ-9"N +8(a͸Ǯ+4Yфf6s*n IP۬?KHNXF[ܡ-l<;Y Hxr'Y)~}Gd|+ƍivDw1.fa겋r# +%o̮}Q P؊* o8sВ^p΂3DTRw=3yLuߢ}:-6r#-c0IX܂Z ZzސBIěamtB\KJ4 [. YV4 9ńV"> 9b8HI,0ƾ/^f .&'tN8pre[pPs54ja#YѦ.֗ah˂-D1(F< {\@9ȗ9p #؟Z0b$ ,j&n:fm(!ea> 8=gA~~MΙ Nr=6E6%D.AdfD!º%R\\ A{UXu, I<\Vhu=a̓-!|AM-,ɦ&Lgrj\~cvm>fl[4EOԊ%!ɾi@6Y|% 8FDnD?r8 dGO^~+Y"+. K k~ϊG*Ѷ9ůxe[6y-8Z@8Xw>mT)iHƵ-(5KLX%b݈:u(W +s5gՠ 2tf;{$o:2?2 VqtxFGN2cw1A(".DHrl#`lv/rEf\ۉ)lshfuv5؀>  ȍطekX[qLr9G؂ÉVB Dr4|8f g7SqS%YX$=Э!Y DW4A`Bq +\ $%;,+!mIʘ1JQ女7vb%1hT6$8W\oB+{#v<d'T:" <z#e7o;Vȯ-x YCebi!= D&MU&&gFL.ֽQ mp2BDdž%[p'F r Tl%doX75!2KYD"PɭtuC;p GE3]qȜ3Ñ``<L{IeA~ y~] +XeaFKnjFB0C)`jP}suu7 & ,p$+!iqGTW8Tj~2';HMi3xWZ&B[G3Vj TQDr#ռMCTpY{v$א̼Z0J2mتO3n wJ:z` p(Ù4n*ePX?DCژ 8n줲@p65XGT6ك<hz54S(%!* +J?X x2&ԜX#ꢛE^-تrhE\r<,|L|Xjfx0_!ʚp +qFްQם]_rX BT&Dvܰu)*5t>(TC|^?+u'|@z<nQk+h wtuPZv_C=7_zÊ]MT/"y؆ʯ}w W\a86 +$L]JA" :+Y4@lSH!, 12gQ+9$D +~B*<$ d [3H-5Kn5z&HU O/iDĚ#$X;$P-7nX-$#boY% Q:ќ_u^2b &$ =來Xl4W$g' V€e_Dz+H +TXa%!9]U]Br@),ojXNPUnH(nf0A!|qvd6"6bŖ$L}g,hR^P_\&טTLBrALr޼R'1Cո5Dj`jDC*we4 kXr@KCb-P5AY2([^nAIfOdPǒ4 HCg.R!6@)t颌Հb3B$6і)E5BiĦu+iƍկ]`HI.B7a@)8q݌ezV0#4"vHBEn.v鲇,| X+X&Zs]uѐ kq l/;'cAf$ `K>5hUMXP0$D6{@"O%(Bb-4,pʴࠁ!qCD2Bu6H:uZ&RHfImŦT.9+n$Y0>pr`~,`mbmTEXpІ+>t-8BMH&xGhXE@V^0Κ"jXs1eLj چʁԯ.[ 7P}SȎڮXpAq߱R% ¼+c,HOp 3nB3#szdPIrJoRځAҢO@=]OhCGlaG!b:m smtEe7HϧC"3 +ڋ$|a66ZO e7wx=XPn N: ”N| ؜@PSt"TN-&ˤ3|JdJ'Z>˷!m/@䚃xLX'*8I5o|סCr `kg/CT*{XѤ)*p@~ /X.%{d?Q[M6Oc#7<Ԉ2N&#-V%:D+vL[jR<^MR݃5FkAjn(BkE'xr:vYck!RЍ^Y5F>H/p`Iks}|ln0E]/sl]y'!ӃpJ6t|pnZ&Wƴ!BOظ?~`v,T@r9a8E.W>"s{}'JU'o3p + +KGDz/paT v2C x =p0>NVR$7 9X#Y#|GOoewRd^\d&'BjmiwlBhcVlfL`U[ +Gck܂5*/Go|a+Q=r;Bl[WR#Ԗ|.fIzkV_f7p޼ ;aX7{:$7jny߿|{>{\~^GWR}_^ny;r8o +GKSWzXyo?n_hqfFܻCUNfx+ ,scevyv<<jA{&VT=.ki}BgҰhdnmvaj+lO2$;gAm@8xRrf'd.( U\ԆQwdN$I~wQ۟Jˆ=&wQeeqav1}D8kA2O|賃'ml(;@]:` +{繍{; nKۭWg/= [~IvcX碸<3Z{*&lɖ9$jqo|;{w>?~<:f hrf"5VMQp_fix;c[+NGȕSr?SZ 7|Lt'ͧѻG_|yߦI}68{=;L1>yh5v {/oNudꝓ_n'v#3}{ry3 +HU㽫xP4mL.TкJu78L>RGcJz^U_@QM6UQڼ{tZ2qylxnsyi 4'kLټEԆ1o<<{,°}o|{ =tBhՀ!Bn^?kP>Lm<Wj:hN\LNgP;'Z6z@܂͕㽻R\߸4)+@rX)ƆR9o=,,v(jc5-NΌх;M6#Rg ?Tu?%h NټGoz?vo%}/OT{Tfc2k*}p}?>}0?ػ|Ic-fOxO3K6p@g7@=RmWWR 5<@T=Gq +ԣq۹gW\V$In$B}G靽1`2v}=zs.[AU~5N!r@" ܻ=ᓏ;zyvӇzOo&[G?w?] 5RG>{s1"Wh\޼}}ʱ)Tbq;U.^|挠>'! ?ΏH-顾q75\~Nj|yhEhf}*?Oo7_FÃ^[otr{>]cx(? =}v+N߸ mRγ?} +(}Ku|<4l$n0~atU쵶XE,L1[؆pnvNޖj{]p.|iH5h̯2eB{N6sz VцWhjʝ/\ǧ`×Jˍ FR`4='rqޣ`l7^hO>SkMf4=zoJ~?O@U{n!n_.Mqڠ0}靼Wr.MC3ŝpj\Qܿx +AkNaKBllIz?̏b0~(U<Ֆnҹ}2*AQ:U{GÓO?M#XD㱂R{WٍGgO^0:Rfp-M5vj{n1uXuO ۏ/goo>+b[~)`J=4ܬ!jeK6x4?GjLHR!mLUAՃ\ɫGn6$Tn89 +(@Ls1P}EXUN}ދgqܦm}xھDRxV޸ Ui|gp/}Dܖ?@R6I,,րEyqup U@y6E̷6gjGк1$[~(۝d1rJy1iʵN}.(n?+u/|bnO>w\Q(^6ji[?b8uvjw>.XOc-G$*9uCJ].6e ^ft)lۈL@,sZWmZ0Mkdzga8Ij[\nkvGȨN4xX,fg|#mpJ23srP,[c< +貾,Xqz{ON_}U}K,leXA(Ktaݘ¨d}7܏@ +2>Cj]{<|TuW)dN̡+3*'+{畝gdaP5ӝP}:x /S+!Lj LTluϲ;Y}ѫ/涙H$:ɇoCŴ 2>ye}ŷ:ϳzXI~ٻfP&koc~$=Z@plƄzQT>ц7b:rÕC+V?J-: +R;$\dP*|E\PrD笶,Y3W>ٹ.c%{stju~@g *=ʍO|gx[Op .i yif +E"Uۏ'`hi77~]ֽl*ֵGkɁڸU>hC/cђVPO1CL9c=DHCշ7.>-M:h݌DdM|6anp dx/EmtGҊڔ g!7"B>$˻A` b=>n1(V뇙ڸfX_Tr睑B{ƶTbH 'A;1=FKXˎiO%kO>l]I-\+J^qr)Fųƅ\w|On=~VVEmyυ\ #&/ X'd⌶z{oSVc"] M6s-99yPrry'^=D Za+vQ S}LZ.w7N?-$s١`TUwnWwFgwҍwΌVA76{W3$T4X{sK^Hs)!e'y>??՟ٿ_o?WCq*Zvx9=ٳן|/?/W>>{꛷8E8'VSO?~/O{_oWNͷ)bqJ`rryݧÓՃ/^}/>͇Hy|9M(e*E~veVntT޺|ۯ}O{~Xm=X\LvecSiL +ik߿ػz_wW?_wW9.+ErZOgx2d[ͽAn~~o[_~џ~G/>2xI)@;q,͝ųΞы>_1EZVwρ&QC;WX#-7ѿ+$Y13ʲ,$[$lagfi!M4I!i$M)I.8s|朝||H(Z9{zΗqJiz7=qكbp*PiL.m9~|o??|O|O_[|F`nO<MW#+[|ʍǟz7 +F̋/__z?y^ګgo2#La|=Rrlibnӷ~{ᥗ_7__WLoݱ& RJkfemzemikO=7^y/}o|w{?BN\)lO`iE&K季}/~[O=7w>ջۿ7s5Naq\W^lN,n;#=W~o_~?Z񛏿ݟ3GI!C{T7{}>yg~o}?~? ym@;*a*+bTkbm+~o_ß7?~G~[_z8,`}2Jg Rr{2:r 8߼G>W׋}^z1wau0lM/n;~nܼ'ӟw˗]]Y  ,,B |q}szKyϿ__?[?w_7^tldLy2h5V jTqljyaemmcƕo|{o?z>/o'ӛ_ztbuK6o4kc3Kۻ?sڍ민{.ͷ~ß'}ɇ_{ՇY0AP哓f*R*+ww~wy߽zk;B=y5X1>7:5ulɻϾo};k_ӟӿ~ʛ?z ++*HKԤR[;̂زs{/|{zOO_;O?Ͽ~_>V ̄Cȱ?R߸ȗ^{ǿzwo◟`Z?~?ۿzwߺlIQS) 0V3GO_oK_ +;@>x\z4c5*R=6'G&FfƖg8ȝW=sDt]V;:+#R"MK҉bjW6ח7WFNZ=vo:z,N|żEҘ)3Qv[G.,n'|'|ڗ~G?|>|ɇ/ɋgZ3SPBd@u(Kw;{= ё᥅S'?y'O~_|㹯7^wǿo;׾˧u6U+V/Bjd|rzanK\r/>oa2 ̌3+k[n>‹x/s>鳻kkKh(! Hc!46#Dյk׮|绯|'z[| /|˫RyAXm $:B6j[3#kƭF0[hh"=[:$u0k¼Z x!(Rn_8zUc,6:8ē! *Փz<}zJLݛex#V"X<ΧG׎N8A-ҫrKA)ғw VGЈsBD8', #zVȥ= kP 50?2a35\Otx.Z3d4 ťf#ˆõ@<:y04d )_jŦ:Yc)6ʍGL"{ڵG +p\,ۍr"YA^1rՁ>m*D=B*K9;5, OJ$8#8DžaK#+} +\ yq@y#8tM9žHd W:X^TڥѠKn6%`b} )uߠ谠+l!0V:G +Hl`tVdcfRl 8g1_fU0 QBpOJy #_yVY:<'|f: 2PC:P#R&֡&GrY-tJJqzb?(;ԯS9{49sTxRǪ g +DuzfN /5}{,-cC:k5(Gz_k`ȩm~GֶDEDe90jȽn)l@b ~?@`bΘ+2A=23-Cx4FZc7=W-ȬU +ȈܚOm5HdxϮJTxW6&Z{J{zedfL7&7`U"=T̜'6!U{F+02*Bif_GT|90d/jdAi驸՝&2.Ā ؂Z,bSXH{Wf48RV&mGDms|PIS[2j+O|}rIL]R#@ +5 $*L(/r:Z + +[B~[m w,J#-Dj*Na\cK}0$5v5;(5Nk&:)EBz:7`t=]=! pHe5aɕ^AMjpPz  IS {D=rK&G5+6[ߥ7`'A{ve*K[wˬ}Jt_A{ CttF +y`: Ċġ~CbD +BF=dv;L"8[r_xz2 H 9te*׭֓139Vv!LL3.%a J 3+O,"!PP0Z,2quL{ rqȑ3-@;ꈺ%7syt2{`܀ǂ 0 `٩= F* +NJ ҜّUۻV028(Đʭ},5TOh`Gf4X ~&Ha~_O+$r3wv6#2kUo>$`!풫~qWaH M؜.)As084xBUpcDpGB& ҫ:fqՇ#u4&a,ԧ'n*Psv@D:H@v_uh+2Dar9"3:rHOI ̡!!U|~`h gԮJ,_!F._l\ثz ig~[Y'V._o>FUI^pP䃝@Ct +v D\FTD ])7qyP9Fw KaWBA3Nz +v_AKO&{sϠvϐk8>} P4^%";+Vyʸ +JT*@ĵdH'݁%ĕ< zV Nr "Ǯ :`~Tf!l.*, UW2P}bAܧVG%@C Wt ?׫! PO-2Q0||\bp!3ꃘ={M B XTH!4ha3_X +ۀ@,`-Ej-qڦ H0}Jb!BA 2IϹsJ"k  )[2pFGBΔDOɌ;+/p!=/7aD*=jJ iO ҆5א +8 z,rg6j7m<(hȨɕavl$w>.!Ea$DǍDKju!-էΩd橰q 'I?֯6k!C6Jk萅,)i(͐#11WjmyC=O~)\JfJM+Qɻ +endstream endobj 107 0 obj <>stream +@ `4p2SeXhHk7P 38qf{6>_FZ" 7WΝOgNZp}nאj: + oؗ_LmQBht59SG<5#6tk}!D> }iX EY&O,LnG[9[:_v/?{6Gl68|8 #}ǠVgBIfնsϿuGeC:6mΝRfLB'ɐ. o*mt}r=iLS`s'>qyXn)G8C#E2|쵸˙|fD`e(0ɰsO)ƞP>>iceS[xP 3,LWM Y1kTfT`C_+9"]l@=QqWJk!I5ѐ*- р TxT q{`04hXB.RSI,r&e*\ϷvoqNˤ5,Vt1!?g X 1z_\b Ƌm Z,d"c|iOj"JE1aXl< J!f>׭08ZŃXfGT TN\?rđ,2WEPqOR:VQ@Y7(!g$?A/:$'lήk|nEp5MvPb# L薘ݥ^Y#lt*1?4j:&Ӡ _ H0De3B*ϨԀ-;@~AA9,2{|%\?;-r;3dgWoTF[3s!%NVWFxT$:g ['t)1=v@&4t.h-SQ+ 6/ʀ ȴײ חFUgON [{b\KCC +$ -CcD m+WVځ.(.S3 g(،Y2q'`CkL{3䌉o%[&#ɋ*{O"PtWpJ-JrȪB|"=/gpSWb2j[=W1 By&̘0sWy48lNfvl7t :MbSg&Nb`FVft_zO#2L$rHΡf6jdj3X:{t!>EFkf&rӝM S „m,^UcZtn48VP A\ +#*dml0=~ug=#W:s|*qAa]΍n_/B{ڞ$#cȕN3Fm#Ɂ&&N\i]z.4δ/@|AdtūwOF p)!\'z +a \jƓ/LۼU`F{XjPaOzF-x3K0Rځ0Z0 d>UAĈdϛhL̟zjckS:W-q ;Gl:pXfK`@q+P/*%:Թ\RDn|pHhWa*,w_rqg$ԈPRy2uf D$Z(; Kt0=.9e.k#T66kֹ$ ` AƦm\ldBFXP\4ؕ0oeR&*-6{T֠Ց)KjC@`@@"(?3Cz ^&"98.͝U ʌuDŽ,ܩ9_iO+ + ͝א" ( A #o*ܷGb\aᜡ6 U7oaf#91`pN9+?DH_i6he:>q8 L f:*12Rpl^)7q\hsb|63 9r;@7d:,֓z{@fLtCu{xKo%79멑ðrd6AVufէ&B9sRgI{ >XjOm۫L {_ZZ}TùCJ-uwlAIY||\ָZzFFe(T2Bw:(>%֫@=jϺᙈ Ah(̟;.<|镋Ϧg/`I3'gGY"Q?QԀ;i *% +49`P] +ېEF+DzF+:*D6W"=Ԝ8?s}z[Mf/ f@} &W*ȣX\k(L.Ґ6g)(˪1֑*P-S_:0+a|\_S93Cz'K rO_[(_Hi+Q2,fOwnyëk^0J"]mq#Θ*3(r[q.,ŧOl$fOwX315Gl.\^=vK_ Zhe *?%ESz^;z 搆<`^94Ho ZsޑE|u[qGEWlH#pȹ-*3CFU@^ I ~Q@!.GWh#X޸.kPI.P[9;|MKDӐF*peș\:4>~SF ~s@kPƁ|Kf&򘿔/>_͛Slf&7~8/;͑ųi|r!.eR-Cxۯ8$`Cl`LDAYi)egU C* @Щ2`[/6 rAMi8\v&Xg< Il LM(kCgf.J1Wx`O p;EˬRkUb-*f50ȷxL 9:*@q-XYCţW'j#\nvCq*PSC<  W &,0iP~,UT)șJ \Tnl'Q #mᎯUGjJƅ=8DGuDN?^9uWQ#/2bv‚ ];~/oy[Y V0q}t +, #2R?#v.&֠&0o:hB>5)>mH;_mSғI>R\9KLȝ-_:`nlbKM"32@hHTl{rgf^nEj8(s=D-Y\&c3|LdqV \Ft$~MnpδTk Ĥ"6;lLf:-6;ƩDB9] K+'71f"hF}R5/G "gh_GnU@fld SŇ%jgdVfm&&TNZ'&V_o߰9_fݩI::A';`#UXࠪOh!-pPcw +8D[<oWk$o9OvO-$GG6n/UO?^9r!%4YF-50`` 4p ܽRA61MlvmJyl +Ĩo,{t ѝlk4ȘP0i4ȒԨ)mAqРx/*"S@]@媱 0HSZGp^P<*ϥ&g`U&K H)L> ɖ}D8ɡֲ/ҫm5lu%p|∑ə6#d2? (%Ăܥ4HR ِ &6NX}N院M.}_ +LL'qMWeׯ&ho4u6jG HmR]ka 0π%IGj~ўӐ֡rK bo=+2*la3hLyKK֣|4ptk;;qMOhc!^xoȱA- uF3 <ͺMa";m.\q.3m:sF'@ K\x$Y_lbDAMMHfGWhDEa{pr1wz~byt|;=mό_]?HSóǞ}-{-ǂ0W%wb +OAnF=]Gj u0Mdv:ϱb3iX=5Ov!=r.T\1--ĖF7S;I[s/&'ݾtⱛ%4V?|@ΞM{=ʆZ,KԘH@]:{ PY62x,pPdzH)`\Q4IgTuGo/qs ΌJY`P>)qHT +ˊH-t&W_8z bLpghN&&z!oGN>0yIij 0Ql|1}rl'9z˅_y9;vs&9-ҍ:XZٽ}gM<}&  j:C$l`a^fe!NC#Z,EeP`: 'VvD?d gV‘Oqq56;Hӑ6mͧY/aWKAA;AL3鰸38ۼ]h*Vhʉ$o Xsdؙkw#[GH33S1 23#2:?۫7r24BGbMswk-G.q3!EvA2:%PiW瀬[dV_Cf9ؙ9|UlC2dpΎȸbIbvQ*G׮QDpsCG\'=Ϧg=%"2a(%%3*{PE|}OQ|?=V5BdubG5*CN`_Qw+Rkq#LWc$BtzJJ,$C +4ĦH\d0\nD~x~DibMzcn94s"!|7.Udk|#R>)܎J՟h|O#Nb 7=yo=k >3.7tk#3|,09=WkNh m +ħ ٱsq"Ha <AbP9\_ώ:|x'q#/b{_0EQ-k̋n̝1MlvPpsgtv4?|+/:rzxRsSڇon_[ع&+Ӟ[W@>+`MS{$V i9 oԺh`j0GK.[#dlJQ_ΟʏnJ;\ظ^ZoQ||g#7!.gaچg`~T{Q7d. +20-L&s3Gq#Í [Ր1kT9+5R\DiovD&F j3N&fq4:Mtdԓ&NB~:^Bj#-eGMOf&P^ `r) V +SnFg1V~é^)ڣ"xy +Kq=Vj.7V[<%Zq66>MCOR!%y@bUSgQ;%r 4q3 sxe͖gvW})1zD(Ρ"8Cyc09Yŝ]2?_rP+pQ΃@F6b\x8D׏9{|sLqLl򔫴NNO^9zL9czGUdӧ= 2dSd d'7x걫Opc>;uӞ>Y+qٝ4N 2>gp0FG\ʉm!Փ)c{D V(Hxndu\ E@;+:B|~rgf?hi*Q>W4#+bLT3nD| RnlJ +DRi._,qjg H 3_@@uő;%wdl1%wUa# uwfVX2$4(W̤e0/3aGBzf3'\. o~_?˱Hk!JNL/̑+ҹ oe4wxv죧Jnˏs#3lzaw;pSjӁYoO|jZ9[X6FAèAZ('ʟϜBe!5f9::evW͎J% Ā1lȄ  8bg@C +jLfqJIgx"fρh_~o_i7>3 CjTv1w흛c&2`ܬ'dw…X}17iv재'ZQOzP@uiI VHo)vl +T#f7 5#1D HpN'͹镣'/]:=<1wd}.sF:s3>gsg'6fNkKlz ّ7ڽ%fSDx.3}N_{?={)W.fv Oݼ{^|7O|G;gzoz%6?t\y᫣2T)+8#db8}KOHu|+=ADLbzv;7fv3e559::eK+A/^dbU@w\}f=:\9(D=y̗BJԓr.tQ[ > j؇ PP)26&d&Nf:J aGD +W>?t밀m ޫ"NAM籱C2[~-&&5%  Ŋl\匍QQ&2sS(!G8ovaGr i3牌 ѩyU0+5:Ħ}:"􈀂ЇHY\9%ԛi!?+r6S!_F#*4.ۅudXӁp/lI;M F(^jƯz|xi 3;G9sc_;s7GG3G.=][R_6qpV#֯>2[i 2Z]i=鹃a{N2ʵHr2)5K5D%\rlW?m.]z4w h1 ,0Ie2 R%?_v S7r;tFt<=@ L =c6V_wV7/^ؿWvn*$}胩T~6po+E=-(mIpTw$,U0sW.}R*̳b_7~^@3FJm翽~Z,o 'lT\P[7< f{齫Ͻ;GVb͹g?_^~zH\ҥzK/\VV|źÙWJV:OR?adf%b.2ٵoyz^xG)̜pmIgy "M>jNY".>uvX [#/'KQv1wH^\g$;2.bPD5&9q9eT_oU.s>B1+KBnނk3 Dq&JYOCa:fވIQ :;^*KˇzgVnIAnt`HyA7b(_WhNh>,~-:+] UVo22FZ/B1A`&9:Qo,_\>xyCHM(iF)eRQ2'Vwx1%p:" +$AL@EO!\RF՘^+Nm"JcZVbiQOzᴃ5\' D䊟J'H|,JkƒlknGX^2!_޾rL~t|`bA:MKQgdg_Yá@(jmWKZ?FO[Z|y !#lBN FMW;ڄ45.[ȭ /\3.dP<'aLrJ/F?(V1nܕs!* +EI6pp $0# VbZ]v'bwVOdTen͜N[[ă0B,›@rf*< fғ;).ȹ7ӛA'8éQtdqE%#a' Ii'bx5PG~ dIڴ@QkՔW'!T6|bSȸب-4"&=tt)17텣\ ]!);C Y@P`|W lqF6!BtwbpPO6%Npb_2Yo$b$K͞l\O͗Ln=\{ L BxԇI^\Atғ(c騚A(*b 8Dsb*t0"$+*D9u=(ZX*LJ' +~\oHF qE(޼7=c>T KwGlMxhGPt%(y;,\VLMl<Sd}M).9>GScdN]yՊ;> eC'ĉqR0:xt 'SF2Gf`E"gIpݨ20@6%=2HPXBZMdg|%Bd dRY9uc@101OpzRBx`8fL&cА GN&/"[=;pܔRth1D2@CT2Vq;D .'QfżտtGLJ6tȁ:qJ4"Q"!;.4Zs=Zk|rE|aK| xUXv'dA8nIZ0d,Ab8M ٶN&S6gOy^)ñ 7n#\c$ȃZDpA f:>dEmuZ&{\A8`>ݕV (.6L?]_̞ƽ$p>#|`>Emkq`P VP-(ST E[BzR\6!F? bNrZ SNpų##^?)pRP!Nm 8cÑh}'PKXȣ|dE8K=tlb܊Ё!ɓS[q*IY-lemIqE"#ux4dPv@t6d'=GNL Siq@'F@PH0iS]>SX'_xlA'^㌬jÛb:X!PѦQ/y/<6`whOFb٨vp ЄP*f `!BT"5' +夌a="M]p:XRR)w HfT& q"b.ZՅ\3HZhx儣s$SV zyą({@DI cN f?O% #pB k6lD1<0%U!"=nrS8(!\ gWo8d0<8vvb  @TV n_9N8ʅd%rj;9>=r'{1&0hB2泻 + P xݏ2b.O. +! Q)afuGþ! L,ɄB[6<g󵶚ΡB!Rx>:O~ZSjr4Ht^\U6Dp!eR)=SHf񍵙;˧-SSk(D)lFxz4 eJYxnNgN !xyt;aAGEY6$Aƌ$N\Hb$-Ջ}Nˤ@P<6 dxLJj_ZJ1_,٬ 1F1%V+̸pC " +~  XQ`¹j*ʲH!:ؙ,u(b~ +BS\`?zNu;cb]2Z3K;ϼ+!9a ;8IYÔ1IE({A(!flRRN>1xYOx#aKЗOy GE:A/aaRR>1fб1{ :mt"3߉//WD$M˻7ww;ެ%)3$8ظ3eMDȫTi-i\,QL򵪸^z̃/>}k'7(Bp!ϥz j3KO>xfwnTbEKy8M빴>f:d&0ٔAsQzo4 +S͵_yԙqȄ'40}lCi-8v2^ DӼج/_bJ{0LRXԔ6*hb)2IT(%uJ:Vtvnn*3Y,d~s~+ϟ|#2P Z, !b"ֲL!wRW;\3/7_?kgOqd,F ABi3BǑ@0KF+Izfo\^w{_ꅋz: +{=lE 'm =|Bj +'xr498D?zrbpc#ˍ;\޽Ooۏ{l: r(Z)tT 4n136̭ͳt_{Ϝ9wf.*-v݋Ĩ>x2IPQ  +4Kwxp3~W^[gz{{ ExD/K_m޻Tt_/Í@Q0!(8Ҽs=o~K=;W~O}o_?g+.W +T,I”<0)'\x]go~_?~럼لd'G6/EP1F|HDZdt?\]_޷oy덗ʚ;!!JU-P@6W/~ ?[?~woon-峉(FU=ŒaN&*|e.|g]|Rm'7/g/o}m7_?o^?{ooK?zw|d!_al}OlN _}O^_+s{_?}o_?rf^'Ȩ  ⹳3goi?>{??ՙTd`Vυ(8gڿoݷw>o߾z_{wX*͎?:Ҝs!#|&+Yg bO^['W>o8W;h7g;-ވ#X]w!Ҝpa8B ґ&s8yʥ7^~~ՌQ G, O'#NbviVC|w.!e"FRnp`Ԓ +x); F[:FjöQT崦蹄,jF̬~ޜΖ^$u:>8ampҎ~y}AQXֳPTYFJRL/⭳:Ү(C!4+p#NsɋTA$F%Co:\MzDIޜ/롃i"(5*uL3YS8&,_#c *)rBSB0.|\8$FԄXo0mtٖcm +q(,D%[􄎍<\HS trk.hd}tSZ`Տ(Z!ׄ X%'w`-BދC^~'E/f`NZU˴hU\ F)RVkJv& +IFVŃy0T:ln<Ա1߰_pňޙ!Wd&FA +BȫRTI+¦7-#vkn8%'J97?h#->!Ș\6>5 ŎڨO3la3uEfOV)NJ?:5mʌB"L%˝}/xp-jkzeG(l_M`Xvĉ $NK+ϙ܄_Fѿ<=>y<rLbnn99pQU&YAx "8F J&P܁@`M|XFf4٭]% "B\\kdqx扯&&wvRH2\fgP}Ǖ:|dj^*$.2k3Lj SHcAłpVdOzKT? +* +ȭs^ʦx\]+m;D +$)+M'Wre6=[4wͤO8#X0ZG=fw4#TPr5/F18V܂>zK:)"W1u,>)Ď)R/l3`j͉jPQ3TssՓQ+ 1)kcG&*5h`M!J & v, )][paΔ#"2"7VI=-Ц/7=zژ:_Dnf̓ad`IkfRq1iDTHjz2jtC.MN.\^:x;£X\(n$&/+C0m-ᔃ=$QOk?7gpK Gj&TN ']EҶҘ9%|OyY[ 8pUgP&RA]$äuևbXkܱl<-XJȭ {IXKQcFae會.<]\ήj'Z +3Rq}N#łƜ%n:$NB6!=԰W'чOXx b φc·ƈER5$NZ¦y2 l';L3\cssN6UT&s>)s}ڜ0cd/G" e6a%D.g׻/X;Heffׯ EF$ց〉\^F8>)-LmTK~g{+W^p/;{AiePSgHL$;r ǻ1sƖDhPW;O5VooHf*@|UXvF@4מK>)z2 Ƨvq#> bkd|JE[j}Etn73jOS!؈ֱxIϳU$0$-h\0+׃\n<(]1yK,yO5S=)3'فє*љ 'QXܻNh-MɍX͗tcWt6Z|s?x,š^]SsщY"YNF<6Hc5"vড়.$^$M`Dȅk,,3(gr=} pS7S˻n*sh%v‰t*X.KJMeJeJNčVz"X5Tm]%fBmLNb@!z/zI\,]-|>v؜Kd_|9:wiH'{=&f/IanLi}!?Du9롓i/Uf2kMm>yo~;̲݃F畷>3Q[@rRq˩`Xx¯tam +ye.Z 3~q::Z$2Ux|wpcV-߹׀[+Tf>5'GVYo6 7pL,Gf=lщ6*|f[xm G k*+bL8AX)-\ҋlf4"W IGw7n^WwS.ҳ(9xs!Xnpp#7%; @[WzDe殴6,-?n` 3WX+~5Rߓk8RJo D}Cm6ޛ;{??sFrc\i$8dě犳zl&찙yuVlsPNn?\L*ӻ`4[W_>%h[:l-br5^]ݽƕ'w \xʳg. ACOBr3i~̬fxEM֘vj:;Ʋ^hmކ&_2mn 5`n|7+IMPbSgWl]mX"zH 7obIiec(iJ6P馕HԦ5/W wӇ92'^ݺ09?_UkۙE^ X:77 Z6:{V(1>N_y!S]tRDgɽXnM/y#E3,][F y}@iչnR&[Ps/bXBqSŵ~Hlّc XN=jgFq$Ab]&-lZ_0y.K E0^rT\3! T$XXa}CXCnc!@Zaw0g96yΎBvx<)bZX^>xf]Y"fS"3ONOi*!ӳPV=\+nC% gVc}Vnz׊ &5/pѣ!yQ )w;FHA% 6eK69僤1{ Tw$ϤWpyҬm$*[N41'=WBaɇ h$=lVX|'@cRZCdT)MͮK1TKTnn<\ 4Xn3tbFȮbuOXNgzruL˺%5vtdAX#^ZJW!XBzT L}.* GtP˱J~tk:8EXﴇMPk~!LՏ9#C+=X,8#I'g\vCpKwbir}xi~7MpӧAd&KWO8")+ezfzgolkpWsݝū٩3J>j]heGD\Cf:s>__3;Eť^ۻ}ՀXi_ S=pEj\䏖TF_Fڜܸ&HDmZ9|-U|SQ۝0W~d8Q]]jgcf##,aJ~CϯsF2hUb̪ 7@uj]_T–X\sFL/9Cr͕l)k)2=#*,\dCCBAoYQm':'.=t$VgGKl@;:)CJTQDE U,&-`F7GQ5ݧgrH t HH";N49`U .ș32:c4jkJmR[bj0ZQ(65}8#7{'OXuY;S.?,pҊK~{ jT6A7x8$r-j*jpCAGƍ*e+K'0 s-1m]1Q`4칸=2I/QsjGy§=qe#rx|ͯ@l'n{j-Ē?Vw U6@ra5L,Pr3U,1c!RbkD|V"rEGFCc0)S_U]'dc|1P_~8!(_dI)BpgatG4[pŰ>-fQS5~e$ $Ob_tLb- ͭ^nv6qΌ(E%OK G,G E-=4vXH[]{H=mg\D:V\[0hm*9.=* ΰP4a2 ;] @}Y\\&-dfK yy?5ݒ3+3YXb8qiqoWoӋD!x ,b\j~i0qH% Z9oeoyƥ3hj\t$_Hl,c6"uB:@P8'zqz!/@͜-Y,XVfipr̬5;hg`{]t9]'.t=墅٩D3n+[L>"koNi V=|gSbnGAʧ'\S̅2*6}d86bfrDO@"g;B! HM 8,V!$xM}lT4:m|ڼ[te  rGLK  sAA$^81;˃>Tcpp8fr{!7{""rݺ5{Gj_^N{[[2E%f0`X]LuKV,̤fc-U ,D^&p+(H:|!%cZ|݋±\ TᤋG$VqjԎvI ";\9٫Ml׋Efj֕Π'ƴa"OC^?+N"e ڠ)D*#bAdsÐ Sɩlf &%ƬR?[^ʤbwn~ +zc єf/%~&#&}DFG_`:qzbA.+x"} wR줝 +y*VvTY{$Ǧ N(!9 bf!k y\;z zh/ሤlTg4BBLx rCu1瀗tI+2*5!c65L _=agᴝ[qEh.q_d@ڸ&w܂+ Kn"!aȂ/',/ zG%̣ckS4_7W +M(rG(g4R=O]<- !)Aih}yV'h堈 ɠ%I:%` C :5bg`sMĔ;P;V\ol=lqL|Άp"^"ٰ>-l#j[QZ y"RHhXท.ЙyƜY$M6W\v( Qy*1yAnGEbD}`H({ٹŐTsFh$Mݭ',, !8)(qbB>)@T!Jcԅ R9T)]F\l+[.]kCu2k81+@!,B'06b b @qyqɸ$=@O x iCy,dٌƑy=&` H[EcH dmO[ ]xzDtu]M /Sv|"855`g_𳹰RCjP$>/U/dO %GH +׹ܒ#6l>xkr6, /hz8s5VZSnp}0"SZe#ӻI5BJk[$gL%KZ? ! YG+]c1+itsK.kgV@bSn߮Μ@ 7Ss5֜g ޱ Е(4+ +0$9-{pv +MfefgwktCrKj!ՆLB/wI/)BB0p.Qs|oV`T{.gUk.ޗFբKT<) ӧQ +AQً7qV%5!yJ={W?9d(n\ꔨ0_ 9k; BI^P)w7DPx;|?w˻_īlxy+sgߝ~ pFR5'_~u8yQcj֟X'N_cpTj7sO[(cpp񡵸4 ~\ N`qO R qs:p_Ɯ1Z LP-!1v2SOǸ}]~$t|~t9c`i[7wLpTZ;\d 'Y>&sAkz/GZT7+T jz4GS3%>uNmB6F]1 =ɛ6zAk{Ux Z[vK5g-ϻo:/57PX3#,a!,SgpK=}p9=y'zݪg>۾3?2Norvw~vq/w T &6.NﶊO]cXB*!'{v{SHFs=Li ߶!k;ċ[Œ!,LʞCpS;X ^ 9|wFi0$7sܽi&y43;կS?:ت@Ƈdacy Gg8˒MQ1 c.SU;vNm=WXA3W1Ms-28f%܎FJe׼Zp pBj&)._P'Z9gH k)*H]T='EYذ"N-Hy1d-K ({4yU̙Vr]F +_0ZQj bDjzUeE.w@(a1ʭۚ9'WZFp*1g%bI B[ yE؇ifh&G,,W/]ӬJzOLXO]{)Fg)] dxz'30F`U9gY}_CO@<|q<›:x|L"dg +Y?/˗V<ڃ[`+~οLpҽ%'5s\UGP3m>P4_BpB4]^*+X~)VϪZ HQj;RZWbꮲ|TIް7u k/ޟ.i3'OsDd +H'oK .: #b3%.)9ylxdv[_opXhV_f&3>@ r#>ӻwFJUDHmgskxsS:1g{uo ˗&DMl ~ u ЂAׯ*{WeoHfwb|֯2QѵP)LjwgOW?TO!UaI!$ל†ShBo֠"Ņd/w`^7# 02mGYSʙ#r= %Dk1^@ +@Z]Jv8Rp\"`fM֩ x h|DZ"{b5[)\ 5c8S1ؗ+J|FC?G!, "f4 oЙ'X@ִ5/sCA2tc|ؘݰbrLCnX+wO`K|إ; =߁Y^Qj0:L ]SCƚrXEUVU{U _LNֵbBp+D,6'VT +Q]qX NPmC'EGYPP6j JE O˚_U5åѾܟÌEYqU ފ!ԛ\?J>Oϝ RԼ&u ]7k NioyLJp!:ʸfNX{ZS#ywk5gA3.Re9=d{4G1}(Dfj jO\_:7P-LxVN "vH ,ƚ3պi]7s1<X{8/OMXTm7毴 +20\^,17}XVۻd{;wgO\oUM.U5 Y4:8/dOm7ٚSfk_r%m̕ҸEd&ʷŒfh_~|j!le v9y2ϥ +uHs]_V;U};&K 8sDTd):SZ7fAyo q/w)Dmϳ\E! ++[,7 Lmʘ֌4VrNíyQsGy]VڗBt( +gqM^DTqX +=MX%4 rCn&C/wL{mYm#RI贤aٲU; H aymK2DyrK W>Ël 'jZT{J2ir!d1DݪGr|>03[ehot5Ҝ:1EfEq[KoZj?A ҚzE3 iY BO|k%oqw]&eH=õԺn~;DaA9^R渳|~8Emm.XY!1'Ug%n+kR!O0 |jLkTQnJl,pO93}N^J<2:w`War nLn舌7-McV1E'^%dy}!i6H +QTQȟ:aj +7Z%ePѦB|=E{(BL\IjUkeIft;~ rZj^O}_DPvQw~8eQX B;} +I:5+BG8{pPO6T7r +b譳dE^U_ RarG{5] r,Es~ps~\MT "r@یEM&FViInپɳ'E̷*ڬ/pqčX m*X}FwTtT0,uarsA/pk]Q'PY&@.;3}+F5A.K3q \@dXoZb'Իݡ"i\p'gқW骖tH SV ewSDh3 몵7`Nxo&S9CI?[}@eA.mC +87 .sr;Muνѭ9CZqryQ5F|_~) +\u\N VU3mBmƓoxp}^{sduh}duoHAEmVń*|#Uu먽 \ lUaPķ6r!b,t$O,2K +l V-u) />NOywbf*$bԂ0Rg~IP5}* 9EX=#jMz鋿 t +\k+= u_a^-揹ƕֻa k<ƄvW,kp}?{tV7dixw +&,FHuXߑXϖwOk tAW \SmsqIks*UVVwL|6}ֻ,q8Ӓ)k}{r{\ޘZ{ x",8]q?֟<+QUk\IV@#,Νs?lxJygRfO- O25bpT3f6F1޹Ҹ.Gy>KfTYї;.8y\6 +!v1~Q!ڈ O u84l"n>eЕ:| )1AԢ=s4}{N,+9*c-"am4/t j/-vKژp 9f*Ͷ7(Gwebto ܝ#ƀ lt9f=Fd'=$䔫ߊWB1)sMN +ODrz]{/ۇ?@a f(x'=#UQVQgB(m":A\a^Լ}}ps1u .Ƕ cBXvcE 9| ܥ5pe`pV ;`(xzy?/2lQF1{ޭ?~_kYZd"߇UST|Ι<8g\0擲\3^ۨYVB[i\cA@5b-Ga@of>{Ʌ09ua7?g!_TŦ3=x'O{ͪYuQe6/sl3EE/?nOF.ރrǕe\_],L=ô}EW?w\40MPpINK3[[D_}נT-zr +0؝+Tn 鬂yI[faYJ51stf.k朱gvIRy6(m1Kx_ɾqkDj.ڝ--Navs5(.c@o\ͫ"*6jM"5<n0c0m<_N~+6/( ˋ {ゼCR +{f'WLi<܊UFB!b<.{L `?^byk_¨~k _oQ_H;jo#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵ܷБ:rCG[{}ko#=t侵_HkeU,z7??Qъ}~Ԃkˋg72rrIl;Y_g*p +~~qvq7'HK$~#2CeOMG8Gr AqS$)JliJ)Rd)ӽD`_R+{]4)Ip$'i+#,ň%3??hGHTdt:RziLmca@枼8:vf>O ?|_}L" )Id2 MRC}lraaD $}ө'"gx7&'TiOhwX\W n)fqePd1V'\pˊ ͂PGk3=gtx\ 0瀉.b+C\a<pсܺWtt%b}$ū:3um ^Լ5N3egc̘뽧sI8C8U9;yF@>)og䭻ViAŦ{>W;}gUYI: ܚN 216{D:=Ldvo.nHw0'$)ς[1iCi:,Mq*Fwe<~ ψ]^djVE+. ХwY&,SaA&{I(\VR,ɖUAYQEۨhmLjQZ1d_޹](KL>'Ò8ӊ k[ۘWs`QuPg%yB+T%sG%]GZw:g_i։>c_uo&'_9(Wxa sy\Uݓr +;[vkN<l=AE)ӢByb~aۄYqE٨,4>mѨ"gV +1f +KLC 9w;&nlW-DͱS.3=Q9̳-Ҙ6$ qcWB| `䳒SQCS8DpǵG96GX(ĵ\uHc_thc(:nn1xJAÕv,I*{w 4޼jVz¸hӢ2*i<#PP<`Ƹ rQZprUmH[ 68 +0$ԡi3d_`s>%ee=Rp\|,su JC>89M*%lžz}Gw_ƄƬ`#y _ +55FJ狧T۸OSLFY I$.Z' fFEj%vŽ,gy>) C{nqg(*~T4@I9y#CʜV C: ]az"}y3}f66uwh@IO}tgytO٫gJۓW|tZ6):.kE&4%^VǨ:CޙYUsFrѾLzt>,7Jbf(q֤D㻊 5㬔8/糏/ݒ&}&:3wu<GfmTS|7΁k,7|'͵2\QB|jCnş?d0gZ6X| V_/ӹo>ܤ/닊>C@Y9,f&e?mgZ%*#D=*i‚`tnI) >CmC:5U1CN&Y'1m.hc^{y",n`&jjUVwpc p/Gp;kY,FU&ƍ`aEuVyY7 +5l&.r P(<**Y2 >FEB +߮pl>-p[?"%P]7rL jjo0a֣C{ ^Vf-;Gm ۚ`3a3\ϲM_r(lr:iDmּOֵ7y98Ol㜭_P!KهIY Xe/7.(O3~߮UW9iTT'5kd"۪OJBfkP?7.]Ш2Tڮ:6QiKaUoidpo"HaF * |8.S_UGy L`Rw#ʜ3 7iMB(-fgGz ڬ?~AꧦMik)rL503tp\$q'UF9m v +ӓf(/%keg8wtk{٘';5_af\Z%Y} 4ޘ63\GxE/O[G~QKvI{NנIagFPD{c:-cCG%,$Q*C\0>?xٻBʝp} @ehrg(a^W xSU5enH}(92Ei5 aN\ðY"حU}QK\ & s]&w_ai(Idꤪa~P#HЮCTkQaAӪҠ*tH+"'*ר):1, =*TI!Up̵A͞C~$=ڭPy}ҚROpwjo[|yY- X.ִg##U,Uews{gD>вXnrɵ]U7LpQG;lhwl] aƀrb b/ /~e n!^a޺j/ƙܽ7ltA:k~P]pņ'R9]W#L!-TQvgfE|R9*?K;gN!UdJճ܂<7#5::=@eE·8u&:)(m/)}\;{ ,X sb ᙿZdӲ3O]^hU6Y{sسܧ ec#x}ŵ_1gUkNV\`*; &ŧNۨkcZ<jNAXٞ|\A@`qXA쪪"hFY,[IA2r#HD 1+C0(!˒㲚mVvU2w}*z +3<$ 5HaN5e3>.0@ joTc༤hń& +4x sv 'G6~ .\IR"7Z Y҄ {Y*JEew1K~j-T\~bLp=Bm;ū&FHͰe),0=}YQ0M8~kR}3Ec²2& ֎9 +a |%Z=Wrwĭ9qZcExkWdxWi "c_Z z%<;dIa:a 7n :.m4&E|pԷHo Wtg4=h2X.Cp_v9r1ɦuBuVoPLXF +׫RE&Bܺ>~AyG%0@?ށ_͚U>⽅ջ?gG۟ +2 dp};pkĘ0B<+,5R:X|a__[k|% %a@?6ꔹ{ sJ(he4>Ta zG׿c=~4Z_V1B#TJ;odwp}*yjҟ%LZd\[(XVӣ7 LZ` FۄS_wysUz\]` r꼵ۗY>xRAj6nX9DaUOf/~7(E4.ɞZ`1 ӊ@ӹ0wvݯ>Wt,]R9{ᯆ'_4C?ɑ{¹lf*Wi:~RvvIpM[Sڝl6Sf9̉ ti @vga!l"SovFP=IW D*BLh ZG[%q3ϥ\;h0X @p#5S5cawKRp2]rTvwNIejyU] LȶI#FjV&&DgӪ1YD?G,v!-o/3Ƙv1>yM*"86ڣiƐqf=%m[ӼP߂RW]Q{{Q=X4yptvHf _PyQ[zfeh$6ld=C!)Iؕ*s׻ϼ x^^&NIbWhɫiL/uM}ܢ̪i2SbwnE:#Upm +<60ös|fhW>Fd 'C3 ,aZwVI*P-(k!uEzk|ŝAp-Ӆ\lTYEF117uQt~v=ٙ?I}[ePl"6J"ƅl䨝UI3DTo:[3U[W O풜<;Eijm`~=YkFMT J:,O ڔ*` F 򸢯p9ydxi 9%w b\RWt9.bp9P5xvcۘBke}^EhԜ~ .WBQY Kl(C:$䅆 ^sZ*F Ugeq\]dWU;yփXɂ/Q}cȍ*}0, BSqUpz##Jl"efF$(_w @[ Q8]Qg ì0kF#0Y6[QFU}Z~&Jtԯ(UQ|(>m엥aE +YLkR_a5JdZ?p(K B<ʱE-hTv.1$dBpp炻H5r[ҸE< Zρ7B +~l3Oiƒ#Q \F +sk8CzM6Wp:p5 7[EyDygJ7o\ӻa$,@诅茲YbY4ͰiŖz:)kcHR)P:\쾬RFb# +h/gE"j1f}D Kb?u\oi%Wu@Z  F.jQQF ++ꝍ2g.>)rO2Tl0!<ķ pk,誺%S'e ]v7˩2T=vj`6 +T{%~ӼTPyb.YwUFpT[e +@F().7 +̣%| T ',dTN SOjBYN>TFID40%7q !yP,GGeSCx`ꃵ#!ZTŊbFTyJ|Ey +ȝ|bA⬋h/Rl[B8G +qhk oRLj@+?µ1qsU{5m_\جO6t;6 +[5]<L'ں6eY L|Ȑh2l"+b2~%.d|6'O +2 p gBd|+]U!0P'e8Y[Ab}fHsJ ,gz_s9:Eb66[LI8(<_4dU}X*w+\6\$t Vzr-drr-"ˑ@,NsMT6 v`o)sgQfiݛ2̱qy*aE&fI{8q$lbE}],vQE NEf[Œ[ı\ǎ\b:8v;S{0of3I|?{> &;wZ '̌@MK + DLGz].@<ALܹu #p;dJp|Ɣ0HY_XdfFXAMt3T +F<¯h&}#s jda}J@jv%8gn n{j=kԾgB3 +F2h9K5 q{TRc~ x!{5b=Yju~5pqF`uHKyZʞHwa_~mȞK߹˭(]9eľ[M=n6)4UWwKjk@%oٯ=3d䴮y\baP@y;3 +-^g t(Q"eRAR[X6R&ꀙwM;[(c2[4De͞8gB,b\ 7xR5ht]K+oWA 7i=x9bWd[eQ[@ #rGL nԃl" *t'BJܞق}w ?# dɪ + b ~V x BR3z-5dxF#;2ٿgLDˁ(ү|H0Ap(#p$A`Zv˜_4mtˠHCRig7cQ-'8@C.Klkk{{Fэ9ET;RCz{uu렩O) Ȑ V0]mh@2F~Q%݊QQCa= +@tHXmco M&_\ jWRCf"xlcIWbNH! ,[x3R{x +>"9g=rL޼O [P%+SY;[պrzWVlu.9o ++d2@jr{L' Tޥt\b=9#]1R$ +g1(#S +4V&$;ݪtѸW{@k˜ɗܭ@ALiג ]Jm>51SQ;S#D[K>#7d 9`{odOR$DA oV X = M%3  ~-d7v l + +˭3 @C@2t!pkR RdpadB;j'̀6Im)@ěٯD03CX xl< +' + 2}$n},fvio9-<4z#FnTjoHL"v[WԸb["cSLi="*Klj- 5Pa3U1E'gJH+[p_j*"$5@SGxFl7gslf!8(jw@5lSGUdXRXWpEdh']  W*WL5lXH*dv.i#zap#{uz>[@p8 +OKJf`H=D + :o}%a*FwF` =&āV*G#> $P+$T쁺L0 +e`6zDv~gH'3QJ?78z<Y K(1`|3RP:8l(] +XɯFO|1 +b}l B;QPb |Wؠofv *2 =GLn`VfOJؘkY+[9)$M4E<6f`JvGheO]Z+w0X㠅-)аٛ3kF:ob + )sF 0pE])uW dVU +~Ch@|ui-6q {hLi8І|q ,8ÓXx +CHX5Tr+,zTr8v+俕=tDu ѧuڂ{ } +XbQpky~$ :}y/gBۗ!PSN +4)Us +H}Ó1U<#⓮X{3D;ʤ9"5 _i.(~{52Uxv}<" +4)VU'FLȬ}rL/9;\[HW4ޗU9S9ֻN=T\2Vnw z6^GPAQ)":Zb%3-#*4XmYvvaQ+nfiM,e =D匶hHN*F`r40r%g$ +S'"4 t*R|-f&jyJuWSC;º,e0eXbjĨR5 *a M*d8LNRl'N"3hd)&R x/k<#egd|RmG"͍#7?nWlalu|e\w|yXchJL9_wrLkLčݹ<5UVԀ2yt +T w @.=q:bu_s3d1~ooo..g3?ܽIfN֮f.D' Kw ;'^f<W$gܙ7c~9ZH6ڪ߸vS3'ˍC6xdT\a%=u̩'@k̬,2@;d[pόo= [쁊ɛ@r<-sbw\O_nYWhGZ֝?_9#ѻ#9. +3"6{2Ll &01+fwulOwG3졎x~-,trJ J(K]|"7qlvv.ǥDŽX?X;vG,,гSAiȤ +O|_:?8tN>}͟31Ggj+x J4LF;@OA `@5"=Xߚ?rY5-@0W":2rC'^1EBk;TNvގ46RSg OƎ!l_77sݍLg6ssFGږ͢zy恉Wx8T_ 6'&M`PkԽ~ݎ@˓v}ӓǃե/1'_쮜_<WOAYoM6=_Z43S[@f\+4<_41Y#!J ΡX{3:v)\aRsS*_9p}jgX yn.37鋷1gL=Q*S\aJglr$`H}舍ВR3}@]H'=iM# +,+dtJ΃521-NS-ï@H@]f [BCF}2_ +㇩ Rdsd]  +2_z-T;`] Y޴KLN R]jf`j|z|qAԒ; W+0yRGbX=Q\(gbF|ynA0•LDLmެ4:+w^>um=}zBG`T|+hbAo]"X%І._ +Տjݩ!3r\rΤd06_d!wZ%ff@87I ;WB[ X W^r6yv'XI67 :qZ}9\hqx R ~芆 + }*X;ްl;[AXкD&:ĉ`a-J!P7!T0e&|]ӾČ15Xq&meS0#Mz6wRy;uP}J{*סۊ~ +b_ $6+ +.DTB&耖A8dlTvTBgCt_N86%6{扩gJˇdOS;Xc";1hĕJp>T}3#4v·:O&6fSL_'$t:ވhS3O ǃq2U#eK !'&.MgY1xèЃA>Nj&txΤ:0/[X +T:^vgjj" +q31j f=+R#~`ϸ 7tYl:ԝ@VRA| . fBdU!HU3|?̏{~O>yd]TAJL>3§zz :]}z{ݏ~ҽq=޼ro%VZ} +rıΕO,|kqS\v}ǟ}??o,MlgNsz߈A>'3jDؽp}68q+ NR6斷?wҝ=˯??G|?Oū?z|~|= +'±L]:}].O/@}'ͷW6vcb`6 bg{y_~;|;#y7U-ΥmN&NWo<߻7'O?O`"'.-p2Ld|_['/piv>fѣy3 XqqDG?y?|gO>z 1׆=l0x<ݞ\]XV %p{eؠaatu2P[=~/?/^S0|_Ͽ?uCtiη Kǎx煻o\yGOoOݻ/⥫wͭG-:ѣ! Dw8ͦ?n&+'f<#Wv~|ow?ӏ?>W_֜)Z!PRSV2b@HJ<{߼/__;=+XM.^mǧ緎|쩧/*x/?ϿO77|Y8zR%fJkct&Se}k_z_|Ϸ=oGλ<7_G6lLaA%z#P!,lG_}g~o?o_~ ow~{~ozo._쓣J 6{LWC`=sy׿k/ T_Kw-exujPnTwje;;rpgݗ;{DE`hP!9`LT[c̓+k{z];3sl$s9*>K V n:raiX"RΝ?>?>O?zϟx=;M1g#D=BPB8vn0z@S{>_nC?x֡r{(,nKP!-5ȨSp$#s՛/k/|߼~‹uz*NDoH\cS?׿;ŻNE368"*Xd(S't7n\~}٧n]?}HD}&,+R<|k׮oꭷAqo=zӏ=xFk<$#C*܈56B0x~|k='{_kW-5J.Ʀ^ӭJ{;h-r-XG =Ql C>!A}(I"9FLv2@I=,g%@ʍ9CF^F[Zg%Lv˟q!v$x");'WWD#FFԈ MP2;Ya`<R15DžBhѬǘ!f=1_cr@ /Tcc|)JDD,--|.DrhiUJhHnd3A2tܕW*fFT,ƚSJ2U4}R=4{CJWB:τyo@n/'F,Ht3yF`%3{TnSj;"/ln5'éLy|>}&CL5q)͇ B5&gXi@(lFH4>Ge>>%&Pcm_eRDl wЙDqj Y7SyS0<'UBܐ +1 +fwnTYv#p5'G=I+8!=F*GN&5l v`VBj"a"ilֆA8cD}pi H+_|r̳78E#E55E&Lj@-X`s &CJJq( + ^7`!7OFdfUY}w@nU*La+ F Ns.Ak@G>)׺ vVehpQA3f$SϹݽa\_a< 7#Y.3i!Bxi;|#Ǣ&wzP,,6ҸhM>Qj&,;ZvDevw +Yi2d| aO\LV}66A"\S(:"bM-̎ PrQ1Ag(Gx`}2ʹ4nJ+7`Nɑѝ6UK [+oW,$D ,쓚r+C2藐LqDKh + "ߦ:gm3:,'H&ȑ=5ͻeKe3bO +_aT +?j;sf6vG<ɓY +2@f$)"D Vs;zhN1T^I0+i$R}RTvaWHĭ4ȹ>IoP8v;}̌qP;#&wk6ćAԤR625kBNoŬl|Իd”PN'c/s#Bm<4fHx&Q`9(x8fDaw՝ֻ+BD=+5+E +F ҄/56f&/Ι` #Ҝ=ih9@YՕRV{ր摝h,>8:-V\l 4 FCj!M߈y@ +_By2EE쐁52o!mĮ`._}`vp=޽ZjQk[n`L>#SE"3ºzHNBv*wt0SrGLLL Xx @ +NÞ OѨ;X阑Jk [p'aXx,#|TR 7AEW'D%PœmDۨ kN`@;EP#XP8SFoV1@H)Z-n\B^m@i;dmޢWԻSǮ =`~4VJdK*+H(ne9c `JaOS XJ.ѓ!͊l-#[G,v C$Z\l aWA>c0SՖ.BTBűhPAKmcl013j<1`bm[.4ӧQeĚ=E_y2#0GԸԸŮ'5rJ3 DP 2o@:%[_ݧ!mO-3mrd6q׈_9u`4 @:(Bz24v'tTHMآޓ ڝ[w=&#z<TtMSԸmur[ OxBc f Q5 +ꯁZ48#d#2m#FL?$0Ss[Fꈘy@Mfkd +-DN~9$5z$I =g{MmljH>A2dS1mZ s.)a-o&"LzrP # +!Wdr': Ƈ!=:jѐ!X_RRL$SShdNd'3lq%}q 19:Q5Z {F:D)#bƤzsZyȟ&{ғ_Y7/^|W.<(APru>,AL c ٯr4ĵY&ÛW`}0W-9"MW_}pAb0IM0N{ R((8JQPY16NHN\Aj j 1Obv)eJ+Z<b `h.2cUSzg^4l Ȉgsas65Ui W[6s p` ۽ Ie H4} +QJgQ_jD `; +tz踍)|9Oe%FZuhR="1 'i`ȵvO +[ѕx58ɗV2 >]FU=bm=`4XHb5(JLs'aF;XKebV}=TNZ@x"c| ]BkPO( .#X~Si *Ez2_\x¤Kv7\X'bi9;v>{z}0 8 5@ u?ta~St|65q&3u-OH!- P3Q Aج+T#M-M6;[er&'mWMؿs Yzgg~ ZlK6^.x R#9 ]tcG[uAӡrxl;=VYHvLa0(=15zO~ t15TeÕYQ3@e/Y|Y֗nww[߰1` @R~:A? wa;OR93]6Nq<:,IvUmT–Az NP ip9H VLC/֓ )6ZB޼FSZ'0,;/%q1yg +M:BxwRB\ +Řœف'l4kCґ(%"-Oǖ] 2PnNl9E"_X46RnlP5 ,v6g(e"2$8highͱL F,Fz\;;Nw=Q= DueWGGh 0(.N\"`7>gv|R;/҉RtsאqL;.a8ha@/O U(㋷ +3'ScCtn7w=s\s*<:ψAao%g/y +0ϾuKi^lGVn wrٯ#,~+S-δp@i$.+ g~(?uoUGC + ѕy."B" +L2[bΠMT:*gRJjaa7?r 9 +ruȈh%kYXYp2R0dt'#vv.f'@%Pd\V6D!sj+x <,iPV`Fmɛ KsK˗o݈7WdLgܬ;9ie+z{̗rk $z@ +_Wb1;AuzW07ª75 0bu!hWp3ZY=yc#ck-l\p`nJbS߸7#)-?# 2- y@D񟌌KmR d + ə`e4 +7PjޗQ9hmiCBazD019~:XZu&@{@X73%gt+ S~4s6cd Yj(N&5f + |5g +M rꉩkG>5yze;5~АgnڧčL͝[ \~La4vq~c ݧpJ 0ER3-ƀyFUcA-8d{@ ޝ=e da;b#B +@XJuf5=ҒX5ݧ%VF'̟*X8+â;h;#Be#0 k`JV&8woNZjJ>|J30S2d5lAj} Q;#Vu"Tel76w|!"bu/##Jtt22P8&XTev'Iƕ}{vg^(fD΅BTBU9 $R@ɒh%۲sqn;znw3䳳;gK9A:${y>{cM`=N $؄G!ri=F r'@;8DA g.4uy!2r}Ld4ӊKWn3Qa&`}{US @B #}.M~X^:o]Xls}:f1=puPpIg'[<TN0(^jE#ce;/W6}d0!mAUPDFFd|.ҹUwDy+$`bO薎0?mo3@dt + +TdH.L˥6 B|Å}R6$ŧ ް# Z2yDȺ\?0#i@n`82'Usl=DPxQLd 瓍Diafr>bjBoz1nY612P|s4*KWr"f"dNhKJ-Dۣ,m]2SN U=lNJ%cz*T鲳Os3llECйpBupAK>p9[0uX ;h#s <LuJ?$+ Pi?R/mSr~r4{v`a~etmzj3{g,I'Lp%c% ȸ+g~?JɉvBv[W'zUm4"Cll,^`/N's +GR3EF@Iw~ޡvq'񝱕NZMD@D0*5:<$õFl026A!*O3m=v$bhHBlm1i"Xtd$"0! >vhTu"0wz'oCd!J D>QdQ|Dnh=.ւpy;Z"ZfJIM8-S+xs\U&F5WBG>ke6_^@lDtv3b‚ *d!1TMٹ;W޻CX̡,4bFc&ߡga\ml5x:Hŧez2FJ|R\WLb ́A7W4C۹iEV/z5'[1g+t. #O0F %.Μx692z~y&"?=ƛkϔ'بPfz|0a$57b0zfHj; ~ϓc:Oދrr< f' 97q8zFZ{*i-_:x(@j nAX;S]ƣ: ZsNM&@L +qYbU>|U8p^(Si؎.=o`2k'#F̄("(%|ZN.|kszLMBVlʍKumR(ލ elI{%ŕHeNG ztNaD;,DGţ}.3fJVl܀ȸIzrϤתT/'pL < ܈}aTqZЖxg{_+N_{̄I \vgr[u61JhC&<QF?e:[RKw^>\܊Z~|}7?ܿ/)D.l߸ND*2*S@C%'?OK  +ts;`)̆[n3J>}\(; Q171zuԽX,idvzG6Fk7z\ۂGh=!V,w6=a{]8$m2Յ͘A;'=l҉p擝F#S}vh]38y`ZXl +'!ÉڅTX4OB;,l7Q48mu n| DF <4` ~KGP>#9ۍ)|c>YpN +Hi`Uى ّSSk?aHPy^N):6}W3f_HSg^ Jq2!gp9o'cTbSZez;Ur _R#n(*٥WXKMNh2j"2N@i-<8GNA%|)g?j&<)'g }6Ehe>=SKWμ}Na{Bf0& Bp1<\5 ^ӂ (Ma+6A+t|OA}}QkE@C^%DІ[˗dk Ƭi$GsFw&ruo/"0YZ*hi\*q:`.In>Qly:__`&@w2Ab3J V6Wn/}.8ɗ^MX0e^6CHuyU,$,Wgpot`VKN"5 $>C}Ov{m46 +?l={>'db#C\~&X]TfNgɓ\΍l,(-H;\Py3<2ؑC=vg=:R3"n Z*Lm$KnJOFАS TXfh +gBa\,d-򅸼JJc}pS1*2|bnqJm|]17)OlظBaGϼϩxx +Tƒcڲ*X5OUg` +a_m;Xw56Qa @a)7Ki JOLTW@VǷ3; <rƃ +<ɣ~'H 6.qL£ŹK-&2q#7˩A;uõ?""ZgDUzL#>Vt(eFVL|n~gLfET=Tn *!EG%)RY|v q T 3)>k0b]rRY\q; )8Xv&hehzKO̤Wwzk|qhUibaN( OJ*S瞛ۺjB6<B=7|)rmw>-L#%,&''r;ll҈淮ScsYH=I;LMfjsskKdWbfTH Rzx'}˭4Lxz`Tư@5\\tf͗a '|6DzJuQ2&'jddlg&͋/ +S\vn+1J+mFdKቭϽ @՚2SG{B96f曥:(4qNBL^*>^DKq6>ll@]Mܾzx-eb.5V8qZd @v{,\ݯ2@RY!TXdr FvN/̝VCzdp\|҄p ނ,DD=1~=;sGT57tmrRn>PX!f#L!bv*ggC&BE.@FTGʕf|xnl;=΄K+.1䤓 NxBWG^yAE4+όVok5PH݈aB)tڄ'cVYl!>wg$NЋL4r#3V áj+sd46#2bZaOnV"ߦS}`h ̈s˸Z m&fNYDjCL } Jk懅 +(QTYD?DX@AJ-?y?V]\\{/&_ݸ:yAvJvRK;7Ck_+sT6PCFOaR)@cӃbpPÆC]hDdj ZAa_dN<"*I2Rׇ7oUWo;db\MM}a\JtpS92n:L$o +cFhp l<^;usϼ8q%6 6t9( Ѓ\HX,,@R-X< t۩~ +^UBw8f.ABiTc rJa| +µhm ɡkS筄dge0IFa܉țgn=M4" 52z$-N(@96;'WVK3yG6|upp9k'"̳Kw}.1׆(g/>|jo7Ӡ,D +֮JV͙m#t1)8PEU/[ iF5чuXqER8m)hnOi2!N TP;{SZeUzل޼_MF}NIǽJ A O8s54^,,OT[ό]7Lj#BxŃE{3xdN-`ܠ廝K9~,jf +: r,H@HÆ'BRN'5/EqD@C50Bj7_‡Jr̂D.ՙgn]ه:HdpXu#: !7SAwmYmx`]> prx+:Z.fgO}[Bnbҫ>9zK_ݤ##ʩrv!\ WFネ-\%Tl͕[o^Hqԍe4[sJ5VRPfF\1VLsR7y)5WG ml͵+{KE'_'^t/.nR6pDg(uК ⷯ}g_p]LZtS g+ +s{Buaod/{'\]5zKRY`3؀dy~ IN*sImp:mV4 K|T+Lx؈k,>=wQ]Ly95R93r ٨٧9qsx,o:s}6~=#JS쬝8x!*mIp1$S0!/vm-PpvS.C40OL31 upJCL$PV(8VJ-'(C,aR`I-/|D,h֩@2v X|:1%ԲR47 gg>w^q'Nes&'|j\6.Nm]/] H1:VKƮ~͗dLH͐qGȀ<\3x hU +ҍc֭h؇"V3 x,6vp")MZ}%(/:#EzW= .2f܊z,Tu: +endstream endobj 108 0 obj <>stream +K{cm߫8,BڟN Xx4Y Z#|r paN-R FX b\lQ!|1P[Hw`AWpm""JZ\JzpdVHV'qTALQD%PVH%;sp16\%^3#@.K)T92yK+Bܜ9}7}郫߿l?{K/4ΞSG.husI51t﵎?sH[H#`};7y!#7RAC1. JB1G6BwýoD|O,$ZBnK3&B`cNAzT0 q)D*`1aZ Fkz'<0 L2-8p|dN0ƛןл!PeM؉ &,,\EVdL8LIICD9HJNJj44S^)Fcleju6;\949ukWHjecN\rt"Y[:yQіc:l#6k\T 8ɓw]VMqR?.ˡfxle/~.\Tⅇo|wmN'ftq8;b8|=nSl)ɍ;7ۺTZ#P3g^8w>9}k.+g|!VZY~KRd|M/.콺쇩\{osmV?f!Ay萞nד'O_| k3<~$B䩉kBvIY13U|c]n?F99m0F(; mlgpٙ,ZE-d>hU,{9xҌi"lRP)/UcLG߀^ʼnk\Y)+,FJ Vg"$Cjb0kyp*eh6wznzke_L4순n9il0sq7ʄùB UDЁbg^*ldM@ + OСb8٨51J6{>=ʏjVh 6sf +X>$Uo8JH2u|FgZ뗓# +"j~&MR-򑲋[ (D7))%C+Bm1RuM&Χwy97S^\;~vՃ'\"p| b&ȥ> g){o=x}2Ox۬No.VCPiIVo3S:ݽv?*5NqoS$CnB`AL @|'Og ,P>i+gp9('v0*ܦDx#1.ܚ\_پO᚜K6R(J1itfE`2916 f$a*%NU mTNAlNR\8Q쵱X4v\*! +#&;!JК_b֩@fZŗV_VLIZ$IYv3iWy$jСL\  p +!L؉ pDlL(}FJ iƩ0¥1SzS҄{01*@Hqd4ߴ{)".:̆J tɃkHq~&؈ XrIkupiXy}osބP0l K0=Hz‚Bd+@T/ Bb8yvhz} XKiN~'&;pfÄ('P!!(I(Ъ-"t` 8`* +Pn6ܕn*YN]x^C=lϻdO\z 2x; z}|F#ѐ#\ p>-%`.!\JI!6E;R 9>AD 5dAi\RlROu9@,Ėd` ,Lb/n'b Z|1I0oCW1"mQNl !4' )TǝXv$Q1pHLҍ> +Rq1ا݄Ŏt0v)` a6n}66bFt{q pyF[ ]DMDt vܝ=6 `')n\ DrIY}]#=N#m,8-Ib ~ÊZcCLQkV:$8-WGp D; +)hvީwwl=vc(FR +$ x0p?^I围w|$=(Elnč. EOl^hX +jbu2ShY +gA/x mNG=mvXZ|fGx >;Z RScoY0U6 1'@;ܘzF*k@peBuB#`aTx 1L: vh':lf0˧y N̉SaR7&p'v$j#ˣ#^Brz࿠Z|b2Ht߈vvۏ3w:z>G(/AnIK[lτBjfPH=z8 +hs$t 9l6Qvz BBoVs[ 'H6 c!ř48fx. !@Hm^bi@_@Br̰"GwN]}WOu4Y #d0}PЀi!XIॣZ`C0JSvCC%f0qt08p#6`DdFOpCtvDƥ4ǬZx|&B,S+ 7C+rrFԊVHJJoA`SD,Ʋ[;.%!0pJ =и2i;,8 2DDG̰͍8NA/.yq.`sERs0΃2wn3uڀ€2 0(*C{5g{fݭb.V.&`0.Xխ]dqǺlO~!X +\$Vyu@wOm7;MVdnD>g5:Xu C8e;n`Ԏu4B`UEN`#:zFw a(}h b~ގJ$ Tl C!-6C,}N j)9tn˂a?B(1Ih\,,/_u:2סwl}f <$ Ţs8L RQ;}r~dn0PEJ̀NK@XC~%Ù0TC% |sWS|T!T0;ɣ=LzHvQv ˱r}llv/+N7gJ%\Cl8SN-ĔF  j.D&.s2`H ~ ф`4S#4TtxxƂV0mY?X6bŋG³[[P|(Ǟ=a[(5 /D2>:(!E% y0aX CE Ĵu>s訡ѩz==zvnW0Z)pz<00Lr$M$J)>xwM^+@Na12-HdnTf +p#޸>ҨkJ,1.nYN8qQO&ِgi=٫]=]y~W>y{g?Ͽ{履}ŽV:`4Zm~2Dh* Ourd~o3}tֹ'_9޽?~?=sm'U"LP" +~֊As޸=ꍡL}}g~~g_pd=8UQ1q0.5u읯cyb+<_^ Ƹhn٦0̆^ʃ3nn}ůK/^V#3㭅퉍[V&܌LW~ɣ,ww_ɿï>_waۍ7A9Ĝ,eV7o7pˏv>8y_^~v֙|.P2Hr(˳lJvR:}e-ʳΕ{~k?77}p[ls4A+ӆ8M[$-*7W&/-i.|_˯<=ۼ^V5L\_޻>?>~~˷?ֿケ1MGi g(.᳓KҋgbO{{gΖ3v7n=n$*˚'?~1fß|p7˗7zo~ٙuDVl^ali||,2,^^ ~tՇ;< Ks_7/чg741u&U.q6^&;<+ _?}?}vcg<>5(XU%!e|[(x7/\k_̿o>7׾x_~o>{g&9*<َI2q3Wo?7oo^{/?9ˏ@=hMSEr>_!޹9[[,_~_~_~|~}O?7/Fk٠̀HsqQTtcC|bW/?9_~soP6Iї]Id?[}o/_=v޽XH4y02r0 +$"~̗sk'N?~/|xw-o~Sz,Yd +rhnF(piR( ⁼JBBU]W~[[_|/o}$b7E$R?P܋Iy󙗟)}7G^^}DF@-K(d;u%nm&]qc+|߻ +Fw^{?P+ⴵF۳+{{W/vmkq̄:W @NYlN'I!Wr/eŨ\TLܴg~?߽3p["?8]kaF"bdV  9^gwۛ$?xnwӯGwhReKAt! `9ǩ<2[Lf;UO^;kەzfaդ38LAKU5xUF*tjy|gv"QgxpDtU 4V (1! !q1M5PD*C"r1*T{ KV+`lBb4%U0gp3N^\[].*C +ㅳLw/^Ywg߾\.\UTCF vPxb8=& ^]Ѿxe?zo{xeViU5 dXfv!<χj&@4gA&2'ovq(2HE:0d0~ԛRTג\NKd>V|q}PﯔFh!Awb,=ktP&r~V'K3#Qq\^-l +ANPR抡9z `|ɎzOZP7 +4WjyիoX:=YN +D)9T<>C@/*R-5 +t0$8N6ÈX`>m̰DQY$LCHWSb6<#p E fz-Dg%R2߹*5 DkÃхdDJ,/q%TB^m"R`ԮcOp$B2`=΍Bvoyp(Zp)9Б`لc&n[rpn>[YJgGh5JHAl/xp}wo}f~ Y +>T[}Q/Xft/=t:9ufz*\L&U)hgtnriHL:WG)1c3ð vgAA2zN4R1y1dr]YܼK}N!!>bTXRL`KDPV+Ua=JP ^ +$ FpÎE`&kǟy= DPChEFH2; AR7 FvԤ/MlK醃{(VJ 0|_7Z]v~W4DϒR>Mۡ9x(Apȅi([#;&> +,bFo<RKrPIN!A-AŸ@+%;uIT +>6H)2XP)=1̀TNuă^. aB`z\IZ +J8# c*2V6mCO:{\ʓ,v[n ${Ȓewb]̴y|Uzo"2#"û̈H,_{g{p.!Z ocMZ@@BuUTf83PRJssFLLwփ77Pudyq{cq<#(m8e3B57]toi8H(__2 +s*(Ød~m'USu\/S!/]ny*"6~Djy ÆH6K0W[%3B8aLXc@-{LwʢVk9 +%ߧmƔ6aʹdqq&wtsdڨ +;q}A%=&(#%;r>^$R9t֔&1}ayDxf܅~+q: c7*t]9 3{?{UGQeaWk~"C.,cjaݠYF[nM, :'xsJ-B HʛzHx*eqSK.@M䌫Rzdm —0|}ѷp#4p,/ʽNf/a:S^va%Thي3WlD' IWj׷es%Кry +EG;E͝X |Ծe#Q}K793 U||)YٗGgx7ڮL/!&nŔQiIqGeDi{H׆L)S/߀ {Z/:Hen'O%CbG[0gcn\õXϬC~<nZ?3}ݻ/GjM^w8W{er\2Sia0 pMLaͱ< QD6ոȍ7\TǕcR݋)^B]QJR W3^s2o #SK)?|Wb@GR2!x ,%.;#b.*O[Jֺԛ6 +OTAMJS3Dj-y)?[DDnvם,[PKdFWNƌ)ܞ(R֮ڸqGUYL(EĦ,Y@Jd~68eq'JYmvF@ڊe\<ٸoXJ_ GOg?G:;йKdҁX9óxEdSg1iPWB~73xƳ3j`%zΉbk 9~DJ],3O_["=|ş_K˛F­яU9/sO.[NW]LAu2ꪏ\72j2L23~udى dDTl񜓪t Q#I'nrP+GAH3*wP}Zju/NWO)`ְf01}(UΡsӷb$O(H(]ƳG!e4^,V-QXzD1r|i'(߮<9W?W퓗C}#90y+!!G䆗χԦ-{o sYyG!dNn\^q1&ݘ=dXzN^6mT!q{u mTfx<ij5GU~̛s&3ҚF6h?~ӿrTA P:+gA\87~.I3t$ $^?9} L]ܦ>'_~S(rዟ~֎[գϫ*H{w> ӹ\-^wMe|)$,v,ӸXU=ֺOoy$YԛhjpǍ/G6f9wDSYT];*woXo2'nT,r,;|L/rQad\cVy-4La>Ծv11cݷΑ/2F8V?NWa,B*T}'6yi_gqc9qxxHuD*X.,:dfS^<˞&-`e Oυe~&TH] 3&7b +@XnPgRi{~ʠQwI_"}s,vb ¡*o*۟҅Pi ~ə_ԼP[ >7O_STs|Vl?|'j>z!7%kF=?_Lt9eǟWoˣxGèqPrs/i*{rejp !Hɋ>&:Kp}H]ވ,pr[CޛWB<,}Tj>z< ͹&P[ 6$`H6_+'HGG?"mp1Q X̌r5Ku-}F2U8zGjB"׾'r$meC*|'y~djTvl@ VHlQ"[N0qB6v\#޻T)gNJo MUNt/D sb+UɦֺJHY3#y%qJu2R#23r &+j ?mmX6[ie76œi+-x*@O;ψT [9g6z~gϒC?KAN* Re-zȌTGg_eN揅"Aœe|Kv.1E7]3%d + N;_u>L产_? ߺfP"^ O~&3zTܑot|'cڄ/vHQ|M6\67ͨFr|y&XpxSDjoD+>A0F/R릝^Ʉ:o>i ;/nn7Vz¬ݓT怪jA2sJr]=ĴAPj&.L"IYR+ae 0tfo?9~g7~[VT%rAz~;P~R½-q͸eMhj#^DY?6hfdF\u.~ QC &kQ6~:g&t[-:O]!v6`]3{Nd64B|ro© /-ҎR;tr_Y\񄯝oT_lrP3Ews݇f(JqIdƶJ,րb//BNsǵSS[v98bعH[#z=X>PJ{/"BDfFQeVkۯqBg?^$72.oUwD~Z1;WZ$ik'yuGTϣ fDjlvnbb^}bkx fOgй];/8LWijTs:5Ocz 8k5tqe P S`QIkBgk*cr}}*MuT9׀Ik*T+촏?s&,<٨ϟZ&2.@d COmF*Hdv@jx\Xȇ|*?M&[v#D;CWX;EɚDf4 :8Wz6$i-/&jynP=- =Dm]:;Qj'O$n0;Κ̝|"i诵@`Ct1Vk5Lc/.LCYASrw]DK蠟5e e2=33?#΋k?`R uuD?{;]Rzm'?:~ +m=tk!h+Q4g^X +n6лK ?0\^L)OUd-$0|FUܱ8N(K7.m(R`uy2h׺DQޯn:b.nů~Wґ yFDu&J%B.0HM;r1XzW!JI8J_*}ۈX L:XuS\ZDs|\aUtqV(Ր3*.G[4Y]7cGNT~J^n A҃53ۏKfM'0]; s7=zDƅ`Ƕm-(R0K.,@-Z8e$זh#xJ㷿ObeNuK茒@ͻtDhDJg8T"E>35dά}f(o)(dH*0X%I6R"ݦ3}Ti|-ET" Ef %%APĖ0LKxLaK*qH,KՓUu4=D<Л'ѣvXmENiu_?&La=8oq'PBq/$2qu D$e4U=o|V}Z37]A+}N(syfD$LQU*_v?MuVLMWb ꈲv)~[V6Qb;셥\9O|yFlSø2do\4x۸ mbOVI/GvLc{ SLgvR%h3vו S;v,Ӎλ??wX`w Y @ QtLjŠjLjnFe8Xs-vWgR8jP@|[}5 2%2հ#zExjKL8kË-[xy O3pc +5pY>Qkc>rnhUHհ\g;r + *Mim~]|S;՗lQE* 6X% Duކ3c/[ao/6| =.}V1UM(k }kS4m^ȥS?]t#"o9s-\i]jqcqUХ֞{js^o|Sl^8=G8߿ +e%?)LƜ.^DX^{%*bR-]?{.^shz!lKlaKd$‘zhDzs \RP diP!PZv`R3)C0kaiGdAL㆐&*|dށez%7ØY>e G̺;&b?\h)qa ]`l[PEGX^rQm 1\=ۦ +oPS4= &\&j/YܯM^UvՂ|Sg-~7~"FH(b>֘%q}Oc2JJb!aL?8d0^#r;\n>BN7v.Stij([UOSd阵(s?Y;<&yKUU,wųaΗ~J~p*΅$7~ _殇0zw2x K'?-|RԮ*\l+AՉ5x94μ;_d;gMmDR^M@t~˟HF鋸 ͭXuAX{xyP?'2sLz8cR4|` `3'p~rJ|.!0! l`0&mH#/VB'@TmHŵIlXfJy/Y:t\8TmxΎkhRvB5WT EB<ܲ r7/DĘ\o['?GTTRzP;1}5wyUU}›mIc_zz3^TecV?NWJwDLNR70r-Cl9E,)sBI  xU\C2w YcB;>|IUD[,yRyV%ʦtEaB\ǒ}'fCŨD? Ef ~ꈥoqm?Vjv4 w_X{?A`1νd7!$yk'!Ɂ  [la15M.lb6 MUIJ,Yc2CBi&5)=\DbT*|d8tWد~: _9u`<&MVygv=9m{tD Ɏ9, X'V YDڈnpri9Pk!B-rHiDpUc,n[=VԪ%Y*jZAt=sRrfKv"LT)@l@?\!( ͬS[=؂{[o9P//}tv+"ï7Sr[.(Ϳv_}hlōŦx&D堪72UXeȕ(W⭡TF:HPr䗇 Ύ1K^P:R~ϝ鼟)o,|PƒA:bC dt*^i9:gJﮛ^DA@Rx'ڸˇapW{_&тKyXPא&4qJ([@c&(W]';wle;4v-.֡r6Mҿ&7]{CIghz"ݼ `bV{~ܼeǖU;ͅ1zŲwɈ<gì͘a'kX}/sCŶT%ePy} a2@^J!_: (hJ颀TϔBH$tʰ +ը@Z,}À +Cab; mMkBj,3e9.T,3tRjqW&>"/reo +2DB +H +F5xDg|vBΓbI+6"@Fyp 5B45Ti+,xXhM[.j+"_ȎS1uJeO>;͈¬H궟6)CtaIߍ^Iq/Ķ.oerig',{Yp1kьmCp҈`Kbeoi5NXW~tsk# ?fEx}`xn% q0a:7~q)/OtEu[+A <3Zn<';T +5GTiczdD8p w÷VPc5r +"v̞9?eEJ"=қ±+Qފќ/ xm&-XXO-Q t.cT &XEB.h7* *;5\GZQ ^_*h҉2yPG J 0fxKA 7^2(W!!7/{*=>.,LDj+*HcLX[icvZbok`6D"ARShF/SRT׷=Έ[;t4h.*Ȕ+w`TiW:., `&:,EǤ5 eTYGkmxE+0ķ~BqK88z@RbOmw5'xyTanzj<5B[|I:"7M4R圯N^~C)G(uNu1k>)E[P3RQNP5mdfϿߊiN`~O܎hθ uzqu +,Fd[~xzg%ѴӢb WG@QxlX&ȕS +/n"FBdSxIHk\~KeVbAYTȻlL+! @B/#g QLfqHm!!TO?Pٕ&iDjHDa=ScjWrC? +XrOR!ˈڿVuERT +pkbՅۂB\nk ! Dw㩚#KT-"wy7rFk*vc +AaJQ.XUI9ecvT`ێp}R@c-!FPY^7V}7BP6tEB%݋?1k%~4h#挪Xgyy&@OtvjPa머7uѴ{>& g(m)}$PVY @;|V<MI]$h2& qE{\Y?Qs h!S}d%v|BTùmy:݇1͋l-ޭpu[\L:%WOc8*w7; h +ej. r>fqWbDл/]-{l~۬@982PS`-"׽7a|Z.] #&WK&wLg̶"RM PZV4锹Ä);̊W6|΃+߉dڛ-xuS[SSk'M[|/آwۜ]O DC|}[r%;`Mn˖PK+)sLT%u:2_֣*J#Fq͕pۊjaM($`"6(-' (P҉Bj#7WqPՈѴ?QQE_KnǵC@97UZs7h-kKt*8JTꦬi\5R͇N`QT?U>m&4 Ͼ*u`X*j.Cm0_lɟr˘6BvtO&Hx6$\3ʕ cARٯL>ihKK~Sod815x$=bcW-bĕ6x5? eEQkNOɽtb=npwVTqŒ!~5pok>Id*Q͟(FŝQc)l p4ОQdT*#^(K]y_p%Vwv4>r Bt{'nBձ|TEY2-8?[>9zR~\*~RoY-İ㖝;*)k!2BxŻE\S 箏]BK8 x骛~lM^}<~E/>+ 1;g6?}$GxvaNA}\=J7Ys,jX8Ru E#ИQ?؈$6ZvD݊$cO7ܘ 厛[ !@u\|G\fak`3@&3b#W̭l2^B ?s`{W 墋D#4eaOS[_ܴ-nƎ|nV#*(1@ﶘoS#F`LlU,.>| UL(U=\ $+eǵm_ˆd1 +] +~y-Z H>J}\K+ sKף:zXDu86&gRPՆ3D->y0[`>؟s=45-M>!y0_a-os,`O7#EV|l/&[La8,t?؈{ lWm`Y; SYr3qw:bkQ́讨L9^鮋[ g\zO_B6ؖ0_f(:K°F}⡋>w}c,Bj?@?Ѓo0s*Crw'Pu 8N\tC/ +M : Wn\M&;wn ADZ +r5̟O?K!TfDI$;}L"Gs>wpmrCs#(tfEmPFR $|ۊ$#|f|# ?¶xjKaA2) +4CL|#n0Xq#yv@.p" +wM"Y9|dq S!_ٿ>{z`.N9}n\ ݻ7Gي+--4LdbWJ}KS%OLǥg q{1XS£}ͭVr>?u0ۑR@QH]1H>6T!Gr#._WƜC(H&H|Gvzσy";L_I#xSG`o[A)im䈥@yS|dfF+s6%KAV趏W 74݋Jj1ᦲb>[<ڈh7W-"8-춝pa&`h#"$gF o9(FӀ1aYPA +v}1 QN> >-P>^|jW `w6ڙΏ«>Ohܲ'_jry?ȔÊ\QF'~/Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jqUDZ\'r:׉\Nu"W-jQ_/$hc^AI1{¡cl9^-<в4˶2$D=*|(!/ +E= G^Me}9ZgKd1n_kM(݁Qmtژt^ˁ@oZ ]p>e~±eoYY.U|mxbX>($ |a_6S~'gspO.<=~0F+2 ZCP%8; 8+,,Nr2[$Z^l|w֊-Gab3[\[ Ry7n[^䎛!ٛaNX 3֢z4 ayQ"Lޏ) +-SJ D]`KΘ-(3,c0R6L[\ub&"puLK8iʌpI5ZI$APk-t-"\V"#uUVeVVUWvWwWt݋]c7{ds֌N9}wUKOBbKN,QW|'6#,*тtrc鞓3jF#r]J)n):ɼT:JnƅP=U7pTAk'1^hEӶH2@flMbrMRkqÁn Kҏ LFfo$/Da+"7gs3R MJHcRۅѴ(J7[?O &آ r0 BR?$v7ci;òJn V / /T/ezjOe@A%K;H[q- Q8WF` 3I}Ϭ47^p& 15Y5B$B4k4|!XjDmSI'gGN4(~yZVH-e! q h ?]BRc,= UQcI[TB&_EHqDZm+.D r%ؕ[QB (} Y[>1%?m~WɁ.V[ܸLd C䃫=+xz;a6jqeIJ>퟾ HE7 _ _pzV=|+6T#s'jqXԱJzI#BCr^8L pAK,T;lٚ{o,N@hçּDΎwB;r%?waG,A^,爥d%_=K7|춗-?M?ߎc?-\-h +q-/ҫ>1??wb^=&3Um]Kw趏 +ЍK]2~l1V(nD4R/Wg~LۂE ,O%B, S>yٿ_";[^ٻ64 C#a1 V$KY4W{r{0&JF=WGArT\L=$RaYmn<6#J/L8/. mGyQF>ftfDernD^iDn);TѮyh848d.L cԈ+_G/iyvB42 +ՄSVXގtmxzC[r6HL,ͭ*\߳fD'ڑ,1K~>$# n4k J;~ͱQBn-[w3>n:0f"+sDC: +1! ?U #r~Hl|!|*D&H)e7(^pǑ)\϶ ӝ(Ƅ> JʍNm!nKao15HdB}c)PBKC\k骏; @H{6LK{/J0U>&D*IuBfHfD@R3FYsW*RYD$eǠAR T=@U,ķ\TAX ωAR<9µVT"B#&ձTD~BijC0f{Jse~"(6pa+ 1O2S_ 5+Yc͈lg\<h{C6`n1yΕnMQ"؎kae3W9/:S-jMM;c)[H +>aW'la˸N|DQYk\AKjY9?׈c%Md W&ra{nIYҚ$ʨ2+sbETh)\̍fX4Kt[f<}s(?w&@KPpNlCتѸWh ڦsel=^LQ؊&t@0V0s$F4ي+Tƒߤs~kM@l{L~F׿o&%3W/r7$#sf:7v,O D . mn?NN|-Ftvo8L>oZǯ|BI./܇DLW\W&r'5'c `0jq l(ְb )hZ k'a$h'l4BD&"ui}Ṕjc!ֶ(Юpa'r0vBjS^JRT>|0NQi*&wJԇIs/׾$ӭh@eD^.38P \Җ@Ev4}Y]|HW<竧VV;d!!*Pǖ`E'ڥND"j`gDT#bMIy+e{ KC%͸> &AVTQl.B )ȷ2xc #O,2\lf'5w"w)$ۀɹ:,x[݊fDLj:J0edG ֘Jdl#ԡd~~PD4H.ЮgT,4-HUtՎh db TIvLٕE` DvƀLZª7ao1k;(@+:㺟,Ǥ@]*r+R\va:ӄڷ䍰#Ml, "gưX"*]͙ x[Rn@,-{u|d}4=pӵ-05D鋅}BjH6Oƾd+6IuNC +`Ky1m>qy.8`Y2S8EO +$b ]k.°c hp̣_u"Df8 +ڐyR 'Yp:`. ZHi ("M /_Z(WYN9 +p=n wa".#Lcg5,@!?rb6pL|,i;$A`k[P ҁۑ$[K)M? ?YeYqE?aRJύ>5$r+b+`TzJfnpM܎3 څ D#匹ixVH$@\Hf{|V$ N QTiP!&6$S,hT-숕8 +_cIT:}:;L6O©nXjR#7S@t&}j\"94@dԼSH~fs[zD吊 # ׃v>: p_Ɣ9ncFLB3V|4zfއL' +!ȯ"6H63*BxY^gQ H.Bۉ^*Y]XȻ1V(N&"6`qņ}E/魠t9$qC4#LW1."pSA+89-/p@"kZe7Q\I\s' +e[\ Nm*dlއk ]wQ@ѻ1]{`v=h2X6Pl;Ǜ+ ]m_X +B0b~.J*y0(Gn',5oƣI 73WGquC4e۷:2/ף- R0[5\H%'1}Sc@ /3~rdL;Ԏ**Lw LqR}g-$ ?RۋH}BAW77QtdATc[fȗjxU[G>3&ma;a +t' gG Ppbr+= /DnͿнΆL jèȎޱ# \P7C`Ԧ_pTH[Єk}2߈.yvnX:VxmOdcPdۏmw3,Hع* 6<b:Y/nNP@8I5=vh퐲QQ;:$>2A\s५m7UQeMH*3 +:Lh |d!.T e7#H萢{z(=u'e\V͎fXW&^Lh@f[ +0<>~S\@Z7)uRr|T뭣JLjlvdT5?揀3b*vLیQiBOPr=OD& AA g$P4 ٠X _nξݔv׉)00W*j11x<=(j\gWd +w}2|dɒ\~[> Yd wbĒm[R+&䦇%:s3DiG!4xCY N &c Mܵɏ`N"`-mam㚟q&uA,eC;;~\ۺҨ]u.=نwsFۉ +mH XjC"-oM/ËA°kv45EU U +&&dU{P U NrfAU9D?4gT!#DekG x!Ө^k4?yYN,܊'ۉURIjl&{H|Rˊjn8brXjxjux77 Q=d΍e,m y]cD-Z?KUwA(HGy2H6GQTńWwt[Tw:l7♭ʛĖ> + +H< ʹ#Y c9YՆ܌pdž6ƶIV7\tK rGULhځD.gaمhGlB af x&⺟ |\ʍi~:ܾEo{A93`+>!CLO9[^f÷ +QC{4e &dﮋ^}:wVPN ) ГN-Xb. ZzސB U ]n>'d?[ u,gbMYތ*P0eJǑ0 $U.Y/ɐ +p?[ŒK0O}|M~[^lEv'Dng @[6Ė_՘4%G DdJQJ _%knt5`ATE,^or2ȃQ\oIm:uEkZ6|=E7] & @+m ǶBITD50 W%cY>nhN@}LHܑ"TG\gwR$hF./<1~ٺ>$[4`҅e!~$ D@2cP:ְYN䶏{TЭtXqI?"N,gNPt]C}GK )QnqP{p:p Xc-,Z\3ƹx.K + I6K;8$'V9a%&zS8(^^*SK, VI'BflR![1!ٹ2wbr*}?Us!˶iM,hPEAL@Ŋ_(ENT+ pΰB5o‰W S8typ@k~ͬi='b&w4A`i7 +_D3wmؖ6N⮇܉aM,٠I4W܉{W@/@ nTM/a+xbnxbn?lݻg? b+x+~s' 0q!0Bz ۱6a`d{$@ ~ CG!, zy/(mDPek$]a5!>DEkL @0 wzXӐɖѼdC +Ww.p+HLH(RUPLvewt始,Q~y&,M 8J"T~kuFjzc%R0Ws(8z7.2p1rLa _\EvLțcR-,YLoiH46裫>߷. yDlY"$-^Yf;!56AZ8cLrN[ %*9b0!\2Ϻ#=w[!0*D X!y*A~n9DX wE~lEB+*{s|2qeK<"JV47nED JH`;>fI90 8Z"v  $U.RF+Q<ǸXXBɭ(UG$D -1 Jwgp=,/0ϔH\3&w?兏*@sHs? W{6"gG .j?3_ oAu]G ջz*H kUw|I̋oZcytcNlE,v;` pH6u.lR;" +(jY23S}LDx7_m 8}7ogeG6[Y[L_$hqݍhJ;~;w"`1na;f^[E ^Q%9KtolAebT9!w jBhPJcN#{nղ[{(JM'Ye*3 6YH]&7'37Yމe` yu/g&~nH9@rDCC9!Lv-dZ.EbW8Vx>@qĴsbaWp桛:0 8O'*yɌY&\omcP2]=CQ-1u&X.TL7PG=L%$vgk`$t (VHy~ 14uu ?[ܣ b?" + /^45Arv,`>܄Hm~qN6 3@aĝpʆ|-W;ì?Yv 7Cy-zˮFpwrV\xܶ+*9P/xCNX0~zYE⼉+k8o|弳uy-@v"*-$lyH[XnAP'2h2ی0SaiE{C*-qQ䏧Zд?AOhޕ0Jӆ}dϔBI˔L,t;ى7qB#We!B̻ DCV.%-V3ȌDjA+HL2 1܌6*yk:} QcXh&GC@hɵ@Kb2xh;5B MB#v׉B6 Е~:l_Ph×Dj.H.fɐA iz,i: $ : ӑ(8!tnsCAk0ϼ-!C MDŞxm@h $8;k6HU eR,~΃ $o 86{;[-DMz.4bˉ`-)T@F\ ÆSe} K"J"MXv;VAtPn3Vچ(L=5 L QͿcyUųS T3zUզ}|$5.΍Ozؚb4ٍH?WwQ0 k@qW$[6]xA}qmB3Li+,U1Liѽʃ8j| K"wtB0}\͌],;MHfu})!^Hlڠ\1惐Ҷ$@JPlc=؎|,ώ37:d|bQn ]iU] x!6n4գxT;qiۖ?iA_KD۵ Y$Y(:IÆQ V!BXMn~nFzB 8XCɊikPM m/chށ\-LWxm` %Ri"@qge:%Md*Sf /:(xI#.a|(ԓ0hj3bo>CP0|f1fԺB3_ S9zYQ>S$cKXIcqeaiz]g\ c)ZmDF5|-N4=%Q8@݀ e'J$ Լ'>K0|Y.ZHlNr ~Dh,8W,Z͊jpU t] =x!J/"4@ +W +6;Z3vA,ن-ܰ| +cP"(66I Va,`+GSIհT2fSNNc6$ @\?9,ƒ]TG!+I$6°$r~X:}1K 4`.(Tsu$U|iR"]tIc0$,A饋\-'mIU8Q sDi*WL/ mR!d6" +x"ʭ,?*r,L˴sf. ak,BbFDv,Ts/ dB~u)y3z }j)1m7RØhFǔAʁPY2ŅW;HOqc.ƥ|X}\ST0vBZ%L!JS^GΥ}NA܀n+=ɟfS-.{lĥ&rJ~/UXeG8>W9vRsvJw2p}F_[KV2Dq!.Һ}m@mF +n'FmÚr0nkGxv:W8s!rǚЍ!Y=5gb1HM8 PXCQ1>y׹Xffdo->'>xv\tQ3. TDW'1v9Hhhc˗1M0m@K\i̙CulIC{Ζ]Z$> 5dp2fi{39r|\>_9rSX^X[8Ǘ"$,3.7ysXl\hv +%i";D!_?JDŽqHsrСpvNFpk8T\44YMwNJ&icEv>/UBSQJ\=bJwLAaDfWJd0AaLi)/G1w -•pyPZxxc4X[sqyi~z+T3YTn'2CҀ2=GfeD:<}j]^w)Qu vOVA(Yx^~wqqtuWbI5+ +|uܾ + /sqwlW͓|PkxIC+kw\^À@+(6xZ?_<~sJ// +Ӈ#}bLoG{[{OwbjϴX;l~\]M$7e":* [en2qHUgAXJwч]{=TIvx-5/ܼ(NN2EaWJ̘ŴHiX,:WdץE @8xKf)( B|Mӭ&81hǔ>z:YJ/&(UX= yCueu9{|L"A2*/_̟y/ ڄ/i+>Kp/7ʻ.?kDvj_w3{܈Yd{Dj.}w鏿ɋxjjsrf TK +3;ǠeX֦?TQS q%6j!?2GB +T|=qohsQ_OY/NnҌH g'8}D覺,rs1:T$`ʣ~~rT/g7p"/>y_ :ӇaQ;ByI"Ie:8?BS P;\]w5\nwCR UuXg>JF4U_.LoMUo: }P{W|i.w2{w.cɒ`A +qi.*Ӈ__o\c{ar"W_o_M$% Ma&?{jտT/'_>svgOxEܤ8{2o~w̘& pE}^OzO*7XbcEy<{y)6q/!gJ'TvkEEÍ'iΧ/|dV,cTD)㩊Z3FgoT'RB Z[<JRRIT37_\>Nja)|EC-[?vsX8S2w1mf*{ӷiMy +suD`J $UO>T|=&~2Ld']Q]uO'G/9Exv&m㰽o=YTkqOji;IxU}2ҿW/<'RKq7\ߦ:h'o~ݜ<@UP=s|WׅWCh]^D*ng9:4#|ICv 4 eygӳՃO)D]K8G' (VgvOO?em|KpHŽOރgo|!~};&?V쇸2 +]\G_<.@ꃳ'YEyaJZʝ<% -B@(ز[#k,p5rdQKl3tnLWGjTiZz*Wt6N>Pq +=Fgrf׭ֱ>z_z#v)_ȭ ڂoBIgN_^_&O>}m˖VK{U<R&U.ׅ x3WWUwϙVPX3,V P\+d*!ٱ\?!XBlnRqOAAiu|L-Dnv^/L[Qi0 #Fk8ڹ9SKDO~p3\> cT~y/."]"b9UZdG1+R?;GE>+oyilEDB8tmGd|19`ڱV?xue'i^Ow>[zN0N狭Th[cj=YM._3Ƙζn?Hn(TU.RetqڽUTb)_X1c4߽ ryWË5kEDO>bix/'[>Qg.)yf?D&:z1~_o~w_ٗaAUDťX:ۗ\vcKQPP`H#rZO\X# t?ƘNoZW.9ctdMUR=V^}?7E93S"-{LtĒTv$WU{2߾X24k亙Q q qy7˓6s5XZI%.UsEGTFٿ.oK5,~*12Mu?YC"R־GSJXM8}Jh鈫U݉d庇ݳW.^~ӯgOJ9eqoS3!,b?Xd;XnL*˯ʋ3"|ow83? YJ1[\ks 2M/7?ȽX%YR'2qGkXYhCucx;}'mRфB]m|Ut֔)rӣ҃ZRxq}ˍxUWF{Q<3f]ZƵ2U ÅPn{_S~e"wU'Q֡"X +PbI*%\ˏ>o26ιY]XAK2&7$s^"Rky.BPW_U.ZÆ'I#ܣzƖȍR-̗xpկ'*BkN*|q*di*fͣ'zgIs>90*ՖᄲiX¼:zDi#GTA%#=ε_p3sUթ:Ts(QDYB@DƀmE08‍&l}|{5kiU]>\.nndp5wbDZ'ɗw,̭On<}÷|Ggg|x2kfwD]ICx(h$Ly$לΌ/on>}ëg/n_ً?he/P2}de95?vbg}}oqܗTn D0 }* Rdmvy`~wg|2MK Nz,K s2أ&pW8 UǽPm|\y[Ϝ}T@V8) VOz|(gN\O~}پDy +a.LPoR2+9xȝ,{sK=C~܃\y;{Ե>kxܹx#)=m$dlcvz3\>yK/׿}'_wcO_rcH\\8~x W~%^}^~y/^zx?w~G`8Y WmL$S:~čg7鯿o:0WApIgd?<~7y>/. +U_ XOX^8t=}?oO}_o] ,@\Yg|Ssk+O\}O~Oy?ݏ_P/`aGGw1ާIaQ|$;0zC^~1p!ٛݝџ?ϧ_>w͟mDoh0DqtyЩ oxW/~ޛoO??}ɿw?#Oy}"KbA ab \߾^}o+X7;ṋ>rg\ȣ77?~W^{ܥSˡ|PAHAn>+m]w???}տ__#7GDq.N3L:<9}zȱ\?\[o}O>?zw{ӗuH @,¥>?{|7|`Z?ӟɟW8zWwϬ:qR+t]B`4'8s_{xy׿#P^xsg1Frby W%ә+;޺rɝGSń4[Il՘*PX* 8yO4/T*+.x[bCI8C0P*#eD0J6fñDKL>}.=?[>>~w6"jĥAX:up@gǎ[~O?>/~7޸syq}c?$ZoeסSarsxhuq_ʫo/gzX6lxҠn56Yݨ %@v?瞻/ϿGϞ?^x dX&ww(Nl4s>>瓃#c[ǶO;{k.?_~Ͻ;G6t(Da +Kx?yW[#7z打P0l! nł +!QY嗖/]Wy'~~/7\xyna)S4*"2PRԲR"BIM@y4>.1`[8"\P'FhҘ,i;-@*T%x@{}BHi6 .ԙVOxo91IDcT.902|h{|q\t|:%L'S 1XH-q̛'=)!D0Za;=:JkIouHt<+ ^#>Unr(jP% &:jv&Q(, Y*4RmRTft( {he2HK5Zdvބ:!'3]*kl--b}'k+EZ[ֺDfUZ|2 .ocHaYZ0v1CCB7(~߫@K`rQgx@x:$F/i_yqJgm4WO]lR1eS֐aa5w +j5(YR'H -xzPmb/Rykc:2[-R# OS 6>]XiVͬLUr##}j<>^fX&vurWK̮451> +иI)%::jE6nPjD-ivp,7 B=ih5xj&gZi:@MHS, +ۢxI!\CF:TZBm\Of{5DY|(ǘb + Fx`~4.hhFS#}U#A-ѳm2Lz6vyH00HFN~Eldp@z *I!]RMeWaGߓRa"chbdobO~Ye(Lv .1w=Z jkБI1-X"#um +n֠Yh53zFC뗚}Z(.25%I=J-5IsX9 (z"&'tdLttf,Jfvw>脨VL\ͮHp81}RSVR)S@Ugt8& G r3C@S `/`mb[{aŏ19W#4KL23"G].-.l#PP0}j2qic9{Hٔfd4”Pw?@;j8Edӣst8V`K! B]Z,`qTi-ѩ`~%p@h !#:$5sN31F'Tab-`]0 ++\pVj4,}{Ŧn--#T`N\ޯیH~W5lc=jCy{xwTaY},3}jWiba}FW +,GS%΃3722n&$P_[Vitt&4zhM/,l18&‚]jpbLUde uDՍw-zBx)Ad/(0+ݭ!H8Z:< 0+`om-̡}ҹWnV3XΡeHhž[WO?,Ý[)DxfjDhy+PpmIapy5"ZgRA l—4ޕłC-'ջ*aHY;GK[ IwÀ'uxB53 ҒۥJ @Q`SOQ>.B}r:rĸͫm1L.ݻq +WQ62ILx#'pct)Z"f 4Kg"5o}.4J?Z:Gj?̶0%9*b&9dfoR LɴҚ + +!WPAIr7 [tԙһZGEG|dXr!l;0={J *ҭ 5YnZ*ird5l7"] T,ɞ5XB5hg&x+ysѣg=6!&W\Yߟg- +@x +rёHs{#B#GE8"&:GnT`O3%jIoE[͇c'MPi=8Z$.AG;ͥgA:܏ -1 K q%Gí6V&:z@+Y=*@x:DFMLIKj*0V֝Q d&B յxix~!ig@Y\:{*XY.L.̟Cj(zWLQ#[ +R@nffPp:>ltWXLzx˗2lnў `y`=XXܾuVs鴁M3g>ˌ >iuأS\ )h4QIvKcW%_`dABCB-4BC"rJ`~{|WZB\52Pa%Ϊ)3ύwH@1Pav#&E54{fLOi8ug vI%"#?6KX\ghWh`đ\#pmF[Dp To]>xtb +P> ֩N\^0ߥv*0l*,_nVt=%NŷwZBg]e.œrOzjoMd/BKpHwjhfDtBU#S o?l=! Hfb #U/%VK +s=RX`r>α[ʹ3SKW*s#K g9NfgZ+'"{4US#21-@&Ttʫ$)Q!+ &^d<\Όkw(T\8U:F@|`+ȏnY#, +X.8 L&Moj +tl&C!WޕN\-l@7{u`90_3Rߜ?z'vtF!Az.1ڡ)ѐJѠ@\9Ʒ)P lvvsyWa]' "3":<t]}zKG' |?=jk0@y|8Iu L *. +b|].6y=s@gw{U#&wMvK>Sv^FUXFZkSML֕[f0SX62YE0YWT^bp v!5"Cg$z'wuу ԁDxP h5Xj WNT7H舨mu'%΋H(?oEJS(0@4{u6bQ$C[2JYz O \;}/<ŝ_yOF2kUBvDc +O}-FA 1ʭlA-N7WtBKFA  gWRmf1ӿp+\}p=B` ryPZ2ҫ&&'ٙ3]~?xT`䳳1bC1:j mOL|CKg=&%%4mB8$1߰/n:" nhotN1ƒz'a@'GT)hڳڿxvާ:+*-3djAmOp$?;"C, /+ҁwujvhڤ[9P^Z5Pc3cln2ܿIFL`[=F1&ea_c£R/|*9#iRB[amibfb,"(M`p%'@Ey p- '6ǣHnz|L&in_Bu(WYC⌧3ëG.Ol\;r6{SYQ"po,c^0q)Q#r~5S[2SabTŞ =By3J̣!Z:%޲-XM7?{m g8>%*rW[m(WH3;si8*+Q:2NϥG&'6{2s Kc+z6ĩ0JUir!D˓(URK&NpLJp58ttS瞱Che +ף&ERZ/C^:Ho:t}*#йm~;ӫ#;P +!]r $hƦĢZ[O +Y@2S-5Co^nOf:#2#$ipPJ X=BТ#ROV*+7g/M/Z&i6=GdO\@6΍ tQ2*zunGmQƁv|KFG0_1U{7ƻՙm'fƙdvH\:b3v_%~U{{zmBH [kӭ=2Tlzqhkpd=r<, +K#J<'5q`DD dpz8o5t:<2 +v[IG.5HqOM:PI3S8వу*ZLTX%:Bր̹c + t3%f.jHAy"SBMobZ:Ot,;wh{[7?{_c:`vyf}} +{בi:,ǽ"qO%PV\~Kix*Lv1:̸=Y9"R ldG'7ol}g?hKNXT}-P]#8_.[)ߐj-Ԯ7zFhp5*CG.>t՝jf㫗V.ƒC1Z(3heBjN֣i1U"~Rwary48Z2cǼ~#J W΍/;y2FM&ǶNRS|@hPҮLslkrNvYĬF(s5 +D-Q[>제Ydv(ٴ@chHuRTgW@i=ЫT#*džN4vL +q gtJgZ;w(>]O@UfVjphi`2#w߽﮽=Yte)Q9R>_]z'_8rd _śr%(k-͝V`.JF`^le"dfrtX*mʓg/vm3h*oHK+9;n7DFI׍F2jJ%F@oz +[J0VּWc#NmV ĕU2t@TjUڄHE']$$FOBU'sG; "]Rx`|!9~ !|L2 6ݩ&5# @)֡0zWquC"PF+:gН̟ VfLsR+Z\9vv&p.]>#ܿS'tr,(A24"(Ĥ*\`(lv xn`fhqtY3ڼrbq0E|oJWDVsJt(\2/^ǹLqGX)3ر t>+ouW*GVKi*2H ,|f;4 +jm]wܧ|0fXW +V2G/ϝ"原9o\V;M(”TxDhzJP"4:R5q#TY8,X97rĩK[Dy浟ߣ/0.X=55Sq&pˀc5 +>.]{ jA[ I_@?ױ A.ԛsCD-w+꫗ }-"2䋍lm?8{fML!X]$ P1JlZ[E@&'SIY&OJtƍKp/VO4xA0z a:„'kCuTÎud.l5oH[9h=j>`Z*?♧ +3g t4^_[|ۍ#h,' ;ѱ+11tЙ'j3;_GG#@iO(KO`4AK @G0O8wvtr#LfH=Qi91p4y>P^>5Ee+jGdl JGGm13+TFK&=PQ #$G#*35)^%rSg: W"U͇:CCs'@VCyaoT x+mN*+K^b3҂/q96T4vzxLꝝ + D3WHq PI"ۑƖ={c(Q@ ^|v3ܒ^WOHG<(A+rBfhfřΥG/<<TZ|슍K ktq|Ĕ%u@v(ˌe1&ݥ Z[sj(UcobWmmݙTS*  d$ tRQg0&WSi,8z2{ޘ3r 5r +dȐ`kP=#7 oWuLX}5ohHOzsed2y.5|_dFTX+Z0F2&FtXaʰ= YC*W^&jKԩb F+VOZ?l$Xm.5J rc`%Y_ݺ8~*?+Ls1G٤]T@G`BPgO4ph1vSc[׊fߞ$mړCb>ryܓ{3k>XxClhg+/=Kpݩg!JVL͟ QOy8}ɛ'{_M5]p7UB=ܔku`Z(W&WTD-*QW~PZk&RndS47*F[D%@jX:eY"=ڬqůB&:bEM+P ە[yԓ,K3tj +ZC2מj/58DE5VNF1 -ի;<i:":"fvC(Hѽӡݡ[׈A3Rzݭ}gJkf;;[P~4Zˎlذ՝qGjY7➜/?篬Y"Q"~S K jH.Gu 9SAܗ2jcz{bб7fgo߷ڼ3Tb#tejk=6ĥ'*'G.'OLj "W߾9bDhM5qV<Y_3 U2[#ǯݾ/G𳭝_Mi:>/5.M-te<""**F' gԄWF\wFpI[ ^8~ $]+Rva^GrAIdtt y9No @S=L9@IQ"%J$JV,ɲ׶dzuX[޽Uݺ܃bs,_z׾~ч7_~w|fjs zowO=uĄ!>3~ _5'O%cٗ֯غWsn6fB+Nol]7ۿ&b7yTy"ǭGaiW)v/n2Zk;uTFI 7=`F@|Xԍ(H>RΠT$&IF/ԗf:{JCyRJ ZR֒'m@cشW\Z"̨O ++h.uOJOX8}~<y.9%6VbrK&OÓ~ $Hr^ʮR¦"RXkwMĘԦӎ {F6hcznHÕtƍB\ѕA[婭gk7~އDCA"~4AD7*ir :)KrR*!RxL*΋+vlDP`R $`I3[gBK+́[qO\ދF]! I?sK_9Ĺ0+t8 66jxgl=8  [= b@|Rg". OgÕz4KVykG 7 qKxؤ? +|ЂzXdaCG] WJi`|*Mb5i Rvꤏ3( sڼ9!6êEK:}b>a Ϝ>LmՉ,%IC ;9!.ba &xB! ?Z|`$cn򱣓fttZ®qVnIf{nt|̊Z k6_ #+$2IKG-V@?10 2%M.F@ө 8<4J%qyl/<9ĐTPZV !Qqf?kXhpS̘-(sg?::hu(KDc"͕@''njEWP0NU30"~BU0VL G]0IQ3Ï6!ɤ3LIcHfNI.HD & B|h|&=YgH?e,F10\A~sDy38n\Ш)A1 +ӛrи"]AIR8xN;}($ BpNo,ۿr=@#㾣A'p ցnҜ]>5*J)%FfC&QqDn?1nSXf./Q5%\0a~D'?izutcu8A„?87=hr>yL v'$DBNx-'&mAb:Ŝ춐BP)U[J* s3+f\!1KBRS ""U+7W\q‡ ![02˱'2k& 1FD8TQ#>_F2iP}R?Kڅ+{|+"{q ?2 QPAuW"@);M~2ZaǪda(և~y'G_HC1QizKQ1kȋʼ2~Z^dbOO81E0\5/1gTTQ6eB$@{&&Y;H<'CuYN$DZE}]*ݸоznW[1t"DW/րѓvpxiT%IDQ0,KQ 9FLc'_>>:baܞP<]BT0Hbƭ84[CP{BΘhvly\kųEq_:ݼ{}v5X҈D^;:06>ay2#aleUVkL4\"ԗ}…go{zTN8NNxAؓT#8dcn5~N~/~>|F1"@$plJjdw*ҙNv"Wk[k^{؞uФ+48~rMm?=FVx nOFpV+c+B@HDᐟ!)J'bB-jZ~:=w2zr}joiL?v +딐c<#W3t.wjRG=X+׿r/?_~ƃ;S͒Ǐ[$L8|(fV.'~C]K/v;k7_Z{덗^yp SZ*xu8mj ǎ[_kO^ýL\4Y|7_{3L} s'z?O\&a%"R8^ ^ ^L|||p;on_~c?}ۿy=O>yfev~6YU5 ^߹wyk[WokPnbRؑՒb YY֖{{쥟Ͽ7oσ麾whJ08@s +Bjj<ݚZM/B"{}uo>:OWݛ?':ވ?Tne E +w37=Oo;WG}k޻3;N +ڨ"W"/>~߻ׯo_?}o?8 kŤJpܐ9EN"TQTg +/^0Ss{ ￵[;]_+5ÁlD„g*F !sv޽S/{K6_>ANTOlY$>JQɒ!T 5~G}xן/o7g/~͝OV,.HRtG4!mͷrY^So{_Ǐ>η ksI|P:T8&)a:~6^`wSlt^g;Ͽ}7_csA1M6;Qo&XinK3s/U߼{wW梗fŋsr]ON%i`p.`sR\,F+~y˿߼AѾ`S|x&t܉C`u>Ƥ# d'M :ՠfvW/|o_/][*FDZbWR)$R +S+|.}o~u%a0Nt -5XU"fZ91{\(=2O75%!!Š1jIKś[׶`njɹbR*C;6q*^Î}*EvS+gNǿ|տ?7?}޻ոM^"Bfs;8o?k?߻ͽj7j#gL2 ZB,*b-+e kt)c\IIJrcU5ydt3(tr) +AI'Ҫ\L'*iQ2#la2$7za>Q肚 #Z(ʋvkҭ^o!O7ղ\R*<Πex;:1:*Edep%?'7̍;>AB)&D(V +s7 :Ii.H6.dUQZZ/岪P ^l>jԎ Z,%֕z΅VY#ѠL6ZvV[~L 4+aӨb@ 6ZCuh22f^RZ6mqi;.m6g2sE 4yM8n<JK <˨ =yҋafbYJ8pO Z ^ى >ޠׇ1; x(L$2B8ca& k!2+S1;b + *BZV V/ׂWL2D5X@>:v! ˣ_|b|h"ŨWp).&,b>4lGaJħΉ>- 8SJy5a>"ʐ+tt;bC\}H.:Mn2c +*^D1d ;&]KZ)ڑ -!snTvsCa+ycS+jE Tvaq7*&Im6"4-ۉ VmftraƄ_EBRJ5RӼVFABԠ̐mr!.D%m&.Qψw\kOa>l=F H)b"*aÎs*.WcS!>QԬ& L.Q +1?h}t)Qe2 2a$+ {CB/K[1$]1fܚV>K&ITG_ʌX=N'2}6/?ŀrD/fODH@r>~t|; }a+t$=:1[AS&|ˆf,9 ǿɮ"dVN(l֔ͅ +5"NaML`X+AnnSħcP"Xf +%+XCŪL۱Ȣ,\BiBix ju[8TDWcZMd/Q +KeJk2Hu'RXe=T*Uіj/H6lɕ\q]')X<|Z=K3>Nۙkx0V)CjM!+2륫&gr\û?Pu:ZRk;^则Is"c,62W,xo[ϻ*1sx1/;=B%ܑ*цJ9R([[8KL~ɬ?>H =|tfgLPJ颛ȘC +ac,H⤝+~EtNax(6X7e/3#FcJ·}8w#c?:\9،JE2}.x $y!7;J>nB+չMe @r7䲓oXƘ+Trv&SiHqla0gچ̐ u&5ֶ3zm[̯AZ+ՙ g;Ϸէϥ{(e*}z"9t0ē+rLzѽm;$1m:$6\ ;XQ.-m1$6S/?cspFl8AZMz%bᵚ +RE&Jm,Z%Ϟcp'܌{GTs=Zavpg\ڌGB8:V`m&3!I>cKְH:_jH06sr%*TxrѯtƑdX nf2(P,ܦ9S M +endstream endobj 109 0 obj <>stream + 6dg(K(Rq/FԐqm_LX|H: O$,VB<()lX'Mh]Љ^M'..LogR\,G)QHHB)SY/_stBngLYNu^).1Sg8Lέ_nj!(1\L/}y\8>ñi$Dk  \r3s, {iݓQDjvfs1ƛcUʭ(-^H/Us98 +%;RZX{>9P=". +~zD?S%bKdr-RRj tnbjjuicTr19bm Gҩy& +F FofZNd+:16!`lid}GLϟVs8 Tz-I$w.0 ǞR\+R r}{+Լpy#2!\Y~YEƂVYAxdSY7qٍ1lGQjē6z+g6թ9;>r*8 S(aC ; '*,O!OdҝdIi'PY_R|}CP.ٞJNd:{ +j Dlf ||^v!H)*5 > +i](cؿR?6=|,VؘrKD[|y*s2)o@%ٹʩd~MHw^~|oHu>rۘ>'\7p+p1" i3;EXk֙]D[Cļѽ6Q}/9b pЉ$wpu\GKg-? ++TyCp#NrſL7Lӷ_G쿀,Dۯ)=XB}Ҕډ$63KBn +;_\U꧍9K._-]rs}hp.djGlrO7#f~շ3^LV'GZKn^z27O*JO مL{7?{>? 76h%Huλ! 5SgN ;ZRHmD3˕E :w[wsu09:Vk[J}/9zzZmݝYM}b-TL/4Y-Joԗؔ 7YE\~&_n<;ֹgFPcL30x镚Awv8s'm0CZ0ėz)WӬorA(̧/+-kƪ[L._WWX\Oel{pL-2E x V4\HW[Q\;N`ѹ_r+ApkhmG64-n134` ?a!l\PƔ6u&cCn ;T]UNg_R ˓b'S@  ,(5j jxmEhe4vgOyepT-.^v*Xla>}Ak*J7DI3BsMR-Q;=u96ࠓy~xpʋJwK\UVO_}u뽽Sy6V8wK/~w5P;CW}B#V\rqZ9Efյko2_lnk }ْkӽpt7[+7'Є̺[l)lvrgVvo֮VP@ZoKY4o{Ne} +(}i%PK\?\f.fH2ιm]~(S^, X7z7b dRS/.5A*fvP|6|Lٻbh RKvS;RvI-١1h.]y<}Nڏ6qLF0_üMj/$4P8b4Tj#Vz,6$uf$ic^E@4Z+3 "baM͆5{XmE֦\T +;:dW1c) d+H|yoA{M8>m'K>hU+5RSJj,e&FR#I7 Up[(?](l0g4F#!c *>MFW:OUTJ:t at/=lm|irEmsHnI-^[ϽĘan7[^q>,7}[O{2{}uu8. RK//[9{W--/9(Di*ONMS2&Rs~Z;Z%6!#ElMJh _9j3tnAx`p*n ͣ >O)\bԩQ7 %;Z6vأ8VM.Q݈p|'b]"U:|~Ӊ±6RXJϗ\L!m!YS!NbJuh5Zk +DGBqGaAL uKgJHZff/ݗ+kDr.5l)ʥ ~Ne\t5LmiťDm5EK َV1!EZ ZgY^lB~tA E0$UW2[# #V)_p %Nke{g`J^FJ^}Z$`?$k|lfEXPMubqj}̭Xq~5Mpf@dƧK{OЅZFrgw{vd8*nomwK&)oGAsvG>q=CP<nv'TTƕ4e,@JxN,YH06al476;)B.4oL-_atFJr#ȖN8XlW.d{=1b2<\L=rE4 ZP@uP݀jUfG;b~K(q#lÐpE;SIhyvH͂q%$>:8 r@@sK^ة4$"Q`CN"kv*@vRk!FFyy +hK1cg͘ᥳ\ $Hnނ:cZÎǽH*vI٘#*.ƬAFu\\]%)zg/ :H\]1sEXR IT;NfdrʭD.Dt@3CWEzvN Sc 9s缴Af͝\"_i39o]V189D<3~ m,Zbv)׽ \ʥFg sHtI*9W]xEM~<ңnF|4kvL 9"ޓ*gOԐ DJ۩>(#B>^fbуi,>\ kSdH8c667,pK~is jd4@!"*|p†dzhy TWᴋʁ蕗M":);g["4#ABG2cT3H` V<n*'f"vOc҂e[39:SӋ,a'RW x4$|R.>cL.r#Y,1Hԅ%|b {-='B>Ɋޮ-ܪ,A_Ѓ נK λheJ̭`z;,\5j f"51+kl7:sܯ94*MajێH!O.)`&M5h!%륥KІ&b%EN9P +6H[kH9iXJ*Rc'' K@ך]y{8 +P$AV42x$N M7(vs^2a %f.{!f`RsA +KLs+ݷ:"b2 ,MPPi2='.{>0H O&iͳ[.:t}9y/ mu}LI Zj '01Q琛vZ̀ec1hB;b N5.fŒCa7ה¬l@*E2DbA#'VrHVIi'&1̶NqN>q< +ͺ+zLnUSHql':9/ ް0\hTfI`lRv^.C W..շ)c{3xҊ0U7M~C!yZȮB8? sX "'$(s> ;> H-:uF"-a Hj5m!mMz$qTԺ_(фHyᷩpt(T=( -xy0`J&X O_KLa'@!֫?|r\Ťlv99Z#> ruuk+^i_>b|LImi2>hjBS;0#1 `:9'ŦΡZ+4mdނtsNXtu4:gr틄6U|ŗsfn֖pj#ZG"ZLv/ ٫|*Hr&=Ϥն_l0m\q +DHs ˂bnC*H@~l5RS>6x`raV7 Ka,3jws 'qE&eD{xuc[׋ Jo=O'EӐ<㗺ZmKرPJԦ! %~΍2b[0],Ek|aMT9u7׿ Knbsni +$D}KĴ1)*uBǺ%Ş04\e)+pU6,5H&gG|u>G&{ N,aay'pscnSdxm*dnᗚHX$٧٥aH;ᕝTi" Nn0{gg +*Sv8~\3)*$h;ȗo3P.V^spGƧTGbov{ޜD2e-b#%B kH&2'm!3$)sSy*=O}7"Dcf&p S9H*. ! u3+gS+XzU87u^v[(ZClL6n*Aq{xۡ_MDcQ;[XwQꚟ;"ρdTr,vB?{h҄c{z$یȌt建{{jgw{vf!Ha'IHq*P"Ǽy~GOt&}1XNϾ"1wՊDaQjC$Mq?DlspM3A1<(͒SG@Op}&CLno>,Yw!:}YR2t,AAz QPERzt>\!B Z>A#1'Xypu$'$qb_>vu&\FHm'\2x8av ;{5ѼڒT#KXK6fV.8w)]Ťgn{ TO(HuR26C8 DƬSnr$zK>Os.<5P^z@z-b|oƩFoէz?0SzTfiQ ׄC~ǤGYߎUB(]d+VYnq4+:˂f.Pmgw@WO-^]LR0ᥜ S?m!5rcbϤ9[=kowj$1IX/msv,VVW/].<{/tRis\EG8S;s,OIY FbCݛ/7%UT +"7LXڡ?|PQRWOPi*HSU،bק)fR]$t2d@P8.Q" ѝpfZ% +VE=y TVLa w8I%T}B3t +g|;S[pXDTaVg>oΉ?6{qoU2LԞpҾ%᫇>,6eyv"R˲u;Ei6aΥyI+z7.ReӲf<RŪ-wtsuUI6(Do*E6ꪳ7'/X0=JfJ`.a0yzZq,:Eے| 5XE+9&Xcȃe};{o+]m̍(,&:,zgՇ..@R b88zD| s2l3'P^9'ʘӊ1%cbw++<xXigE^B4:ӭ[eK/sgCqP~Qۈә^W.r*7C.m sLułY) =\ᜩ? &/X&"JBHjDV缱z=z\&(g;*rgד EtqƞBtR3ښ~e (gJ}ڙ"R5x4d_Y<'V%3[[(u/ZyA[VgߖٚwN}ˇK@&z^ "\uYnqC[TTQŚeaBH,mf̎X -ĭm̄ٓ`LmF ,`^s0eL`Vsș,K=w"Ey/#q!ykkn%2&w>I)GR=4GW[k yﰤz*!|a~R褘*+8RC{[{e[1?ךW58# t~yz?#s^ SD B;S1s:nWUk03#>L$wݻ|,ޢGrTgՓq},Dc\jqKp&^L W qkA3aBtd9=dw =sVy#.½%T # [5a,m(vJ,5~ٺ؂M5\rzfJr6} TfplG޿"Ygkļ4!m=|ȕZvA~rDwmƘċ]V]ޑ1|FEgjќB;BxxgT;Y %zm>9I;ScţRk%Sw+M^~%PˋyQŨ+K^lqQU}gP=VYA]Acq{!/ `uXlbʍgJi:5r9+Σh~ARάx-6'9s{9y_M~_mFhQΚ\F"VFL5y +Ui^B|C18)CY<"30!LR W}u·_R,^}ȸGCܧ(F9¶Z4fC.7K|XW+R weW6.Ipl'K{@em/1cF[SPGi&P\ǔ.rZ:b.}6氬~m4UKb=abB7{;e9G9TxRr@r`wpw52l =̋5LJ'wP1kӕp e*^kǜ ]\j'Y%49@hhK!X/Tõlb>nOX;נE _4zQ[ z/CyhI٫Pۮx֎+FlL9y\󚩟1,DNBiAA@jY.SZGd) P(u3l'oO}1/PmB0Nt9_?~gqsԙIg5+ژ0&7R%jLg$0E0}'/@ j+_@Bo_EZ@Dk'k}@=ЄoK~Wkbmk`5z̾[yUR r-ΚsfjH6 %7DpVTJP@腌k͓g~_';>))%%# +6$b(4S6vP 3RgcXntv1aNY#1 *\MX/zCĩzj'aL7s5:F$aX',ӈP{UPFy]{dis*}qX3>]Q  '}Z|6kӍ-ԆNQQZk!q^(@5XJ +p]N^u%n0 kb6Oѭ8ɋuSve"V ~x'g6ITE:[ \CҬriMV|B: T+ƙ^AsI̓2Q)UgB+:vto9H.iu +w֌ (v;>:ϸ`d/ 7+$ cЙ3y%!*I[%5KW./vĺs]\g`7E|㴾x;JdH{d) mo%XFkPrRk]K50JM9<כWi8+FA_u77Eg]6'Ts?VgZpt=ӏQa^ } e`|Tbd#ŴSLkR|lΔsoVT}=HKІA>EUAA&)$Yo꣗+ƨ(!`P3bqNftN{s] '2Sjk3\JQ!9:dO.X6ھ,8C?P[eci΄sb0n;zǃ,yFJ4!H{،f{gpw]2w]·gqigViQ!Ӳ q ^pt Nl'CCqѺȐI\omk*bY{wv"m i֨f&J;[slQVLݽ"sm I1<KlP;9܃C4( L_b /.5q13:jx9; d@)@Bw b7'vY{M\m3i<.I3)9Ee.ggw 稵NUpS;W:7<6T%6_;}㎞eɠ, {0)!ac ?8Bjz{}M2qmRR%yHGs".rlAM6.Tu"ƢZ}]]}xʣ}]EeZ8y6 +>Zlķ)L]I3݌0=}R1yRw 0S9V>+MOʝ8)Cއguo|&G;8@.J#}e(EGY͉O{H)SϹ9XCS {.0uV 4PcU^9PE̜"+w #+zC{6*AT~ZΞڻ؈<}6Œa ^swR>/7UZ8zoai<¼]F:K +qʱN>KPDky::4;3|.w0X9K&+ƍ5~kvB`Ry1VYw +ek[%}#/繦T;L XGEslM<}G-/aRdl-< +'O!_5^>:Q6vI]U_h ޳XPIC-^߷7OR( >?h_3գdԙ~E%fqY3> V3G 3lk;N:~9ss2u`b[ VNLiCYgr#6nP'EU½/ћ5aqңqm䭒ҝ}VLVom,&#wz7 RE8lxŅx[TFjŗ=TW8xMTKu^i@#eDX oSIBuE:SDD/s\RB*Rzy ?& +j HOn{_ړWYY2cnXSTNy w19v4?Q<̉]-}k=5_vv+uN?Mw ㌸MB6s}fFWD3)‡,Cx0#R#p YFج&mwjk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵ܵv?r@Z]kk~ w䮵Ϥ5Lڿf{uGY#`ӏ?jM{>ݿ=}rz:!FI'"Q;'^+8,&R?"?B1'Yig1#x$E'.EsU!i#d C s4p/*4C 0ݝOQ^'4?j(a4>nV> Ô<) |xۇ/N;Of8zw(S!*4.Zi`*1O=Ewp@'><:Q H%UsM +R0G= 5Wwק! !-)w^;i%}\:k `O1>b-47/!,S?'ci$}!\+ wV%yLx>4"gO\feVICSdP;Bon1-|vJ YCD_1H4_7:O[}\?oWeg5CQ^l)/%>D:ek%($LͬF aa>.h?-j8خquv d(8o0Ľ"y8X۴9KfAеs׮XKY#Ϸ/IUaZJb{9'`3l#F8y:}t>(( +j&PKa|5VeHAm&iP;J߈ qwl6eZ1hw͹78vA1ށ>cuӘ]d[eeY6 xNҘh%G88Ӭ؄(ݧ׫$a&p4ROk 锕<&/zVR2_5Wr(3Z}˜Dbײl5̈́ixཛྷϋxAmvt66X-cvj߶W_=Uhe*mQ{EZ]2T{9@ԃRtDul]CVI)yj0QӒ9ʃݣ:Mey1:Bygi:6is!GwPZsbsTSNA@:+y ȷb l4ĂUi^QQf+G0 EwS\o=߽a/ląGA7JP!lو0ǷBR0+C{F´>4Y#xkvJ\UVVl/?W[e e)76.7Y\{euG(I#\nrQ '6 @itۿm˼"́8tqJykm0~9:?KA0S O +l5x>c/B{vpgJ~LWG9qW;tS8,Jo=+m %[=KP-'ɰtjN¨F +e#Vvz稚{UT *,FV*(E9EGb^Yn85 JBJ ϭKD}jIh`$(ubcR̃Œ[GYQvio/I[o6QG!xJFfAihﰠ+P>&`_i 1Lj5/c̘@I5=ZG=cqBee +XPg#DQAꃰ$*_@ؓLbtK=LƐvgtVgJk]ֽ:Tx'.__SGq&Sx/+>.Wqa@y~☻[6ӥ}D/M(mb7FQB]"ţ@6+et|N8̀Ieml͜@9i J51iF9k6<$xoZ8em'@>xtphgaNjޭ;{A*tgQ35PsN@yf +#aVΒ$"p`'ehDKa."Z="\lzWU\'/R (pcdȓ,,ks\,'qSAkl4*4 @TsbbcЍ k1yJ:Qv4eAC1\` nPѧq̎vCZ@ Amd+cҘ@@!:PITVT>"M f Qe(wRև5}EEX=+}V۸+{Ynun3y {Vl ƵCa4~9dctӸ*j9 AX:1qEt/°-0kN:{K|(JRgwnǿPbŸs&<P~ &ت@ _Uiuh/ +Nb.ds'ʣO^. +](9"Ya  !V\´imUsL& k+#Y{gNR8DL!,Yb+}$tx$BXwд+$e$amCnn`qe{A?h`f &e{LicԞ.в\vZA,K;Ȋm7ι~rW|d_0gy}uozgU6\Xl_+:8%_=Hsu.po|JkYIH2\3IWt c>A~tQ*Sȼ1kNyo*`Nl$G4#Μ<_Z9,Dj&qg+AC\iEäQ,2@0$8DgA@ &"C:$Y@S%[4Y*JiY{y[{YUڂȒNQfE J%plm(3#5kBo@96q̃4U-m$b&0 +ol 7P,Shno~($Nl$LLKIF4lO3,U:9Ĭ8bDDL3{Cݗj ]cò5%\]ޝR=kIJUqsRz^.(BV)VP{H؝})wo(tڽIsЬ8n]IՆ֋MB3P䚏&RY3q̄$jnfGYiM=z\R%aY 8s_cA +W2V +N/qYT!^7J|Pqu[4CBuY mޥsFo޻Hr~"|%J\*s1\ԝƔpYi7WPJ9^o[cDߒ]M hhST(]([;806ƥ7|AسTlsCMq|y6NS:|׺(,Ii\g7nQNN Qlg y.,Գ4ZۨJcRp+vt7j2ol<+iA I6 "$1(-ZCJ-}|X4U/I=ʘFR+1a֚f,VT' 6lkDA]̀v$Pu@o j#ÂFAFR Ra/Ix VCZz+fJ -Tty# +E:˒E"tr4,G-e!T Ƣ|<2ڌ}^q&r"`l 0,% \IfYhrW33:|}tuCa@ 6g,j#ʚ)'i63smo_ËdfQ0c6%JViA2*N|opi {v+tx2j`U@5)+㨭$W{T.t?*8bCTm +7F$ >•㺴s-lT*ji + EXdj7X.Cv^EȄ9- fAnVof/1 b3A)~&" ceT;o6rNI-iPZ;95_&FOxYy.ȋpN"X"e?r1uIV%`Dc+٣USxPBZEgԳ;oP"M.̒>1θ `ڠ$wJR=o)Ppu,8k~N^2yMwp Ŗcqg1? ?$"tYq oLN݃ c-Se}yPNl x{lB!&k(x~nӵMT:pV L3'3`4 %$2%',!ذ,48of>+Ⱐ.+>zU{6ʰ0R$rJmgnZBg)&-p)P{!op5cURzEC7_H/ӂ:r2*铼ԍSf:Y8]qiR-Yn>a s] cqtpgR: _%yY*ڌ`eE,N`NKR:(3l S,Qy8(Me0-^%͂d {h4nnC_7#L OPmI G`Jt 8 $ _LLz鲖\R P+% bsz*{DIAllFA:yeyiP[e3Cd?MsMbȗnp,2S|JaNAv0q5+>JsIILtŏcğXYP5DP^¥<W 4I}ԁ0_#Ȋs,5o{vKVvY4Ƽ1K#Nuw =7ecWe=%M$jJl(}`Ded$ʵ'Z?a#CEŢ5x^`|<~\66K:DX8BU30rB=g& 0FQD[_; u!I}Ba@fNctHD%/bɣ"e8tڻ^|u7RSd7slgjWRd(g1+@n2G!bÇi@IȪ2qݟŰqj<ƩxɂP\NGɷEY[ 3\'Nՠ"6A;S@ĭf+HiQNAOј:1Xdml\ MD9z.smܵIlKVMgA @ ކpӻF3FY\$Knqkq%v؉c'8{_f-YK )RB"!?,K%R^_h ]{1DaXJ5x-z@~AM#:2 腖!S*r 6E:d.|Wn +-3"ӰޯsTPDGELR, =DTҩU4ݭC9*Gu7 MξxJZ!gL; bZ@aqH`cFl`xDg*Ry?FWqdTRnv!w T!CUbA%[lQcj7~ʯČiR$ƅZzLi7b{-7ocjjRnQ:=Jҥ4tdJ?K,Q=z@