Commit ba98c3cb03619980a6f4f955e8a81ae4423fcc53
1 parent
098ad7cf8d
Exists in
master
and in
6 other branches
人脸识别
Showing 21 changed files with 551 additions and 21 deletions
- platform-biz-patient-service/src/main/java/com/lyms/platform/biz/BasicConfigServiceTest.java
- platform-dal/src/main/java/com/lyms/platform/query/PatientsQuery.java
- platform-operate-api/pom.xml
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/controller/MeasureInfoController.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/facade/MeasureInfoFacade.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/service/impl/PatientWeightServiceImpl.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/ResolveUtils.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFD_FSDKLibrary.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFD_FSDK_Version.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDKLibrary.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_FACEINPUT.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_FACEMODEL.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_Version.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/ASVLOFFSCREEN.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AfrFaceUtil.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/CLibrary.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/LoadUtils.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/MRECT.java
- platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/_AFD_FSDK_OrientPriority.java
- platform-operate-api/src/main/webapp/WEB-INF/lib/jna-4.4.0.jar
- pom.xml
platform-biz-patient-service/src/main/java/com/lyms/platform/biz/BasicConfigServiceTest.java
View file @
ba98c3c
... | ... | @@ -793,7 +793,10 @@ |
793 | 793 | public static void weightMange(String fileName) |
794 | 794 | { |
795 | 795 | |
796 | - WeightManageConfigModel model = new WeightManageConfigModel(); | |
796 | + ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/spring/applicationContext_biz_patient1.xml"); | |
797 | + MongoTemplate mongoTemplate | |
798 | + = (MongoTemplate) applicationContext.getBean("mongoTemplate"); | |
799 | + mongoTemplate.getDb().authenticate("platform", "platform123".toCharArray()); | |
797 | 800 | File file = new File(fileName); |
798 | 801 | Workbook wb = null; |
799 | 802 | try { |
... | ... | @@ -804,6 +807,9 @@ |
804 | 807 | if(rows > 0){ |
805 | 808 | //遍历每行 |
806 | 809 | for(int i = 1 ;i < rows ; i++){ |
810 | + | |
811 | + WeightManageConfigModel model = new WeightManageConfigModel(); | |
812 | + | |
807 | 813 | Cell[] cells = s.getRow(i); |
808 | 814 | if(cells.length > 0){ |
809 | 815 | //遍历每行中的每列 |
810 | 816 | |
811 | 817 | |
812 | 818 | |
... | ... | @@ -837,15 +843,14 @@ |
837 | 843 | } |
838 | 844 | |
839 | 845 | } |
846 | + | |
847 | + mongoTemplate.save(model); | |
840 | 848 | } |
841 | 849 | } |
842 | - ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/spring/applicationContext_biz_patient1.xml"); | |
843 | - MongoTemplate mongoTemplate | |
844 | - = (MongoTemplate) applicationContext.getBean("mongoTemplate"); | |
845 | - mongoTemplate.getDb().authenticate("platform", "platform123".toCharArray()); | |
846 | 850 | |
847 | - mongoTemplate.save(model); | |
848 | 851 | |
852 | + | |
853 | + | |
849 | 854 | } catch (IOException e) { |
850 | 855 | e.printStackTrace(); |
851 | 856 | } catch (BiffException e) { |
... | ... | @@ -898,7 +903,8 @@ |
898 | 903 | |
899 | 904 | } |
900 | 905 | |
901 | - WeightManageConfigModel weightManageConfigModel = mongoTemplate.findOne(Query.query(Criteria.where("week").is(cookbook.getWeek()).and("weightType").is(cookbook.getWeightType())), | |
906 | + WeightManageConfigModel weightManageConfigModel = | |
907 | + mongoTemplate.findOne(Query.query(Criteria.where("week").is(cookbook.getWeek()).and("weightType").is(cookbook.getWeightType())), | |
902 | 908 | WeightManageConfigModel.class); |
903 | 909 | |
904 | 910 | List<WeightManageConfigModel.Cookbook> cookbooks = weightManageConfigModel.getCookbooks(); |
... | ... | @@ -929,8 +935,8 @@ |
929 | 935 | |
930 | 936 | |
931 | 937 | public static void main(String[] args) { |
932 | - weightMange("F:\\体重营养配置模板.xls"); | |
933 | - weightFood("F:\\体重营养配置模板.xls"); | |
938 | + weightMange("F:\\体重与营养管理\\体重营养配置模板.xls"); | |
939 | + weightFood("F:\\体重与营养管理\\体重营养配置模板.xls"); | |
934 | 940 | } |
935 | 941 | |
936 | 942 | public static void addBaby(ApplicationContext applicationContext) { |
platform-dal/src/main/java/com/lyms/platform/query/PatientsQuery.java
View file @
ba98c3c
... | ... | @@ -59,6 +59,9 @@ |
59 | 59 | |
60 | 60 | private String oRiskFactor; |
61 | 61 | |
62 | + //面部识别是否存在 | |
63 | + private boolean isFace; | |
64 | + | |
62 | 65 | public Integer getDueStatus() { |
63 | 66 | return dueStatus; |
64 | 67 | } |
... | ... | @@ -140,6 +143,14 @@ |
140 | 143 | private Integer buildDaysStart; |
141 | 144 | private Integer buildDaysEnd; |
142 | 145 | |
146 | + public boolean isFace() { | |
147 | + return isFace; | |
148 | + } | |
149 | + | |
150 | + public void setIsFace(boolean isFace) { | |
151 | + this.isFace = isFace; | |
152 | + } | |
153 | + | |
143 | 154 | public String getPvc() { |
144 | 155 | return pvc; |
145 | 156 | } |
... | ... | @@ -1115,6 +1126,11 @@ |
1115 | 1126 | |
1116 | 1127 | if (pcerteTypeId != null) { |
1117 | 1128 | condition = condition.and("pcerteTypeId", pcerteTypeId, MongoOper.IS); |
1129 | + } | |
1130 | + | |
1131 | + | |
1132 | + if (isFace) { | |
1133 | + condition = condition.and("face", true, MongoOper.EXISTS); | |
1118 | 1134 | } |
1119 | 1135 | |
1120 | 1136 | if (bookbuildingDoctor != null) { |
platform-operate-api/pom.xml
View file @
ba98c3c
... | ... | @@ -27,6 +27,11 @@ |
27 | 27 | </dependency> |
28 | 28 | |
29 | 29 | <dependency> |
30 | + <groupId>net.java.dev.jna</groupId> | |
31 | + <artifactId>jna</artifactId> | |
32 | + </dependency> | |
33 | + | |
34 | + <dependency> | |
30 | 35 | <groupId>com.lyms.core</groupId> |
31 | 36 | <artifactId>platform-common</artifactId> |
32 | 37 | <version>${project.version}</version> |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/controller/MeasureInfoController.java
View file @
ba98c3c
... | ... | @@ -173,6 +173,22 @@ |
173 | 173 | |
174 | 174 | |
175 | 175 | /** |
176 | + * 面部识别以及获取信息 | |
177 | + * @param nutritionInfoRequest | |
178 | + * @param request | |
179 | + * @return | |
180 | + */ | |
181 | + @RequestMapping(method = RequestMethod.GET, value = "/getFacePairMatching") | |
182 | + @ResponseBody | |
183 | + public BaseObjectResponse getFacePairMatching(@RequestBody NutritionInfoRequest nutritionInfoRequest, | |
184 | + HttpServletRequest request | |
185 | + ) | |
186 | + { | |
187 | + return measureInfoFacade.getFacePairMatching(nutritionInfoRequest); | |
188 | + } | |
189 | + | |
190 | + | |
191 | + /** | |
176 | 192 | * 添加面部信息 |
177 | 193 | * @param nutritionInfoRequest |
178 | 194 | * @param request |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/facade/MeasureInfoFacade.java
View file @
ba98c3c
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | import com.lyms.platform.operate.web.service.PatientWeightService; |
19 | 19 | import com.lyms.platform.operate.web.utils.CommonsHelper; |
20 | 20 | import com.lyms.platform.operate.web.utils.MongoUtil; |
21 | +import com.lyms.platform.operate.web.utils.face.AfrFaceUtil; | |
21 | 22 | import com.lyms.platform.permission.dao.master.CouponMapper; |
22 | 23 | import com.lyms.platform.permission.model.Organization; |
23 | 24 | import com.lyms.platform.permission.service.MeasureDataInfoService; |
24 | 25 | |
... | ... | @@ -706,7 +707,19 @@ |
706 | 707 | objectResponse.setErrormsg("测量用户还未建档"); |
707 | 708 | return objectResponse; |
708 | 709 | } |
710 | + | |
709 | 711 | Patients pat = patientses.get(0); |
712 | + Map<String,String> patInfo = getPatInfo(pat,hospitalId,certType); | |
713 | + objectResponse.setData(patInfo); | |
714 | + objectResponse.setErrorcode(ErrorCodeConstants.SUCCESS); | |
715 | + objectResponse.setErrormsg("成功"); | |
716 | + return objectResponse; | |
717 | + } | |
718 | + | |
719 | + | |
720 | + public Map<String,String> getPatInfo(Patients pat,String hospitalId,Integer certType) | |
721 | + { | |
722 | + | |
710 | 723 | Map<String,String> patInfo = new HashMap<>(); |
711 | 724 | patInfo.put("userName",pat.getUsername()); |
712 | 725 | patInfo.put("age",DateUtil.getAge(pat.getBirth())+"岁"); |
... | ... | @@ -715,7 +728,7 @@ |
715 | 728 | patInfo.put("phone",pat.getPhone()); |
716 | 729 | patInfo.put("vcCardNo",pat.getVcCardNo()); |
717 | 730 | patInfo.put("certType",String.valueOf(certType)); |
718 | - patInfo.put("certNo",certNo); | |
731 | + patInfo.put("certNo",pat.getCardNo()); | |
719 | 732 | |
720 | 733 | String beforeWeight = ""; |
721 | 734 | String beforeHeight = ""; |
722 | 735 | |
... | ... | @@ -758,11 +771,8 @@ |
758 | 771 | patInfo.put("patientId",pat.getId()); |
759 | 772 | patInfo.put("lastWeight",lastWeight); |
760 | 773 | patInfo.put("pid",pat.getPid()); |
774 | + return patInfo; | |
761 | 775 | |
762 | - objectResponse.setData(patInfo); | |
763 | - objectResponse.setErrorcode(ErrorCodeConstants.SUCCESS); | |
764 | - objectResponse.setErrormsg("成功"); | |
765 | - return objectResponse; | |
766 | 776 | } |
767 | 777 | |
768 | 778 | public BaseObjectResponse addNutritionInfo(NutritionInfoRequest nutritionInfoRequest) { |
... | ... | @@ -926,6 +936,39 @@ |
926 | 936 | bloodPressureService.update(bloodPressure); |
927 | 937 | } |
928 | 938 | return RespBuilder.buildSuccess(); |
939 | + } | |
940 | + | |
941 | + public BaseObjectResponse getFacePairMatching(NutritionInfoRequest request) { | |
942 | + BaseObjectResponse objectResponse = new BaseObjectResponse(); | |
943 | + | |
944 | + PatientsQuery patientsQuery = new PatientsQuery(); | |
945 | + patientsQuery.setYn(YnEnums.YES.getId()); | |
946 | + patientsQuery.setIsFace(true); | |
947 | + patientsQuery.setBookbuildingDateStart(DateUtil.addYear(new Date(), -1)); | |
948 | + patientsQuery.setBookbuildingDateEnd(DateUtil.addDay(new Date(), 1)); | |
949 | + List<Patients> patientses = patientsService.queryPatient(patientsQuery); | |
950 | + if (CollectionUtils.isNotEmpty(patientses)) | |
951 | + { | |
952 | + for (Patients pat : patientses) | |
953 | + { | |
954 | + if (StringUtils.isNotEmpty(pat.getFace()) && StringUtils.isNotEmpty(request.getFace())) | |
955 | + { | |
956 | + if (AfrFaceUtil.facePairMatching(pat.getFace(),request.getFace()) >= 0.5f) | |
957 | + { | |
958 | + Map<String,String> patInfo = getPatInfo(pat,request.getHospitalId(),1); | |
959 | + objectResponse.setData(patInfo); | |
960 | + objectResponse.setErrorcode(ErrorCodeConstants.SUCCESS); | |
961 | + objectResponse.setErrormsg("成功"); | |
962 | + return objectResponse; | |
963 | + } | |
964 | + } | |
965 | + | |
966 | + } | |
967 | + } | |
968 | + | |
969 | + objectResponse.setErrorcode(ErrorCodeConstants.NO_DATA); | |
970 | + objectResponse.setErrormsg("匹配失败"); | |
971 | + return objectResponse; | |
929 | 972 | } |
930 | 973 | } |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/service/impl/PatientWeightServiceImpl.java
View file @
ba98c3c
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/ResolveUtils.java
View file @
ba98c3c
... | ... | @@ -427,12 +427,12 @@ |
427 | 427 | } |
428 | 428 | |
429 | 429 | |
430 | - public static void main(String[] str) { | |
431 | - List<Map<String, Object>> listMap = new ArrayList<>(); | |
432 | - String s="[{\"fxpf\":\"5769f0640cf2d37f034793a2\",\"fxysu\":\"色盲遗传史\",\"fyyse\":\"315107bd-91fe-42a1-9237-752f3c046a40\",\"score\":5,\"color\":\"risk_yellow\",\"otherId\":\"5a531d6bc07dbb92526b3566\"},{\"fxpf\":\"5769f0640cf2d37f034793a3\",\"fxysu\":\"阿斯顿发送到\",\"fyyse\":\"224b2329-cb82-4da3-a071-8527f8283aab\",\"score\":10,\"color\":\"risk_purple\",\"otherId\":\"5a531d6ac07dbb92526b3556\"}]"; | |
433 | - ResolveUtils.queryOtherRisk(s, listMap); | |
434 | - System.out.println(listMap); | |
435 | - } | |
430 | +// public static void main(String[] str) { | |
431 | +// List<Map<String, Object>> listMap = new ArrayList<>(); | |
432 | +// String s="[{\"fxpf\":\"5769f0640cf2d37f034793a2\",\"fxysu\":\"色盲遗传史\",\"fyyse\":\"315107bd-91fe-42a1-9237-752f3c046a40\",\"score\":5,\"color\":\"risk_yellow\",\"otherId\":\"5a531d6bc07dbb92526b3566\"},{\"fxpf\":\"5769f0640cf2d37f034793a3\",\"fxysu\":\"阿斯顿发送到\",\"fyyse\":\"224b2329-cb82-4da3-a071-8527f8283aab\",\"score\":10,\"color\":\"risk_purple\",\"otherId\":\"5a531d6ac07dbb92526b3556\"}]"; | |
433 | +// ResolveUtils.queryOtherRisk(s, listMap); | |
434 | +// System.out.println(listMap); | |
435 | +// } | |
436 | 436 | |
437 | 437 | } |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFD_FSDKLibrary.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import com.sun.jna.Library; | |
4 | +import com.sun.jna.NativeLong; | |
5 | +import com.sun.jna.Platform; | |
6 | +import com.sun.jna.Pointer; | |
7 | +import com.sun.jna.ptr.PointerByReference; | |
8 | + | |
9 | +public interface AFD_FSDKLibrary extends Library { | |
10 | + | |
11 | + AFD_FSDKLibrary INSTANCE = (AFD_FSDKLibrary)LoadUtils.loadLibrary(Platform.isWindows()?"libarcsoft_fsdk_face_detection.dll":"libarcsoft_fsdk_face_detection.so",AFD_FSDKLibrary.class); | |
12 | + | |
13 | + NativeLong AFD_FSDK_InitialFaceEngine(String appid, String sdkid, Pointer pMem, int lMemSize, PointerByReference phEngine, int iOrientPriority, int nScale, int nMaxFaceNum); | |
14 | + | |
15 | + NativeLong AFD_FSDK_StillImageFaceDetection(Pointer hEngine, ASVLOFFSCREEN pImgData, PointerByReference pFaceRes); | |
16 | + | |
17 | + NativeLong AFD_FSDK_UninitialFaceEngine(Pointer hEngine); | |
18 | + | |
19 | + AFD_FSDK_Version AFD_FSDK_GetVersion(Pointer hEngine); | |
20 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFD_FSDK_Version.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Structure; | |
7 | + | |
8 | +public class AFD_FSDK_Version extends Structure { | |
9 | + public int lCodebase; | |
10 | + public int lMajor; | |
11 | + public int lMinor; | |
12 | + public int lBuild; | |
13 | + public String Version; | |
14 | + public String BuildDate; | |
15 | + public String CopyRight; | |
16 | + | |
17 | + @Override | |
18 | + protected List getFieldOrder() { | |
19 | + return Arrays.asList(new String[] { "lCodebase", "lMajor", "lMinor", "lBuild", "Version", "BuildDate", "CopyRight" }); | |
20 | + } | |
21 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDKLibrary.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import com.sun.jna.Library; | |
4 | +import com.sun.jna.NativeLong; | |
5 | +import com.sun.jna.Platform; | |
6 | +import com.sun.jna.Pointer; | |
7 | +import com.sun.jna.ptr.FloatByReference; | |
8 | +import com.sun.jna.ptr.PointerByReference; | |
9 | + | |
10 | +public interface AFR_FSDKLibrary extends Library { | |
11 | + AFR_FSDKLibrary INSTANCE = (AFR_FSDKLibrary)LoadUtils.loadLibrary(Platform.isWindows()?"libarcsoft_fsdk_face_recognition.dll":"libarcsoft_fsdk_face_recognition.so",AFR_FSDKLibrary.class); | |
12 | + | |
13 | + NativeLong AFR_FSDK_InitialEngine( | |
14 | + String appid, | |
15 | + String sdkid, | |
16 | + Pointer pMem, | |
17 | + int lMemSize, | |
18 | + PointerByReference phEngine | |
19 | + ); | |
20 | + | |
21 | + NativeLong AFR_FSDK_ExtractFRFeature( | |
22 | + Pointer hEngine, | |
23 | + ASVLOFFSCREEN pImgData, | |
24 | + AFR_FSDK_FACEINPUT pFaceRes, | |
25 | + AFR_FSDK_FACEMODEL pFaceModels | |
26 | + ); | |
27 | + | |
28 | + NativeLong AFR_FSDK_FacePairMatching( | |
29 | + Pointer hEngine, | |
30 | + AFR_FSDK_FACEMODEL reffeature, | |
31 | + AFR_FSDK_FACEMODEL probefeature, | |
32 | + FloatByReference pfSimilScore | |
33 | + ); | |
34 | + | |
35 | + NativeLong AFR_FSDK_UninitialEngine(Pointer hEngine); | |
36 | + | |
37 | + AFR_FSDK_Version AFR_FSDK_GetVersion(Pointer hEngine); | |
38 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_FACEINPUT.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Structure; | |
7 | + | |
8 | +public class AFR_FSDK_FACEINPUT extends Structure { | |
9 | + | |
10 | + public MRECT.ByValue rcFace; | |
11 | + public int lOrient; | |
12 | + | |
13 | + @Override | |
14 | + protected List getFieldOrder() { | |
15 | + return Arrays.asList(new String[] { | |
16 | + "rcFace", "lOrient" | |
17 | + }); | |
18 | + } | |
19 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_FACEMODEL.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Pointer; | |
7 | +import com.sun.jna.Structure; | |
8 | +import com.sun.jna.ptr.ByteByReference; | |
9 | + | |
10 | +public class AFR_FSDK_FACEMODEL extends Structure { | |
11 | + | |
12 | + public ByteByReference pbFeature; | |
13 | + public int lFeatureSize; | |
14 | + | |
15 | + protected boolean bAllocByMalloc; | |
16 | + @Override | |
17 | + protected List getFieldOrder() { | |
18 | + return Arrays.asList(new String[] { | |
19 | + "pbFeature", "lFeatureSize" | |
20 | + }); | |
21 | + } | |
22 | + | |
23 | + public AFR_FSDK_FACEMODEL deepCopy() throws Exception{ | |
24 | + | |
25 | + if(!isValid()){ | |
26 | + throw new Exception("invalid feature"); | |
27 | + } | |
28 | + | |
29 | + AFR_FSDK_FACEMODEL feature = new AFR_FSDK_FACEMODEL(); | |
30 | + feature.bAllocByMalloc = true; | |
31 | + feature.lFeatureSize = lFeatureSize; | |
32 | + feature.pbFeature = new ByteByReference(); | |
33 | + feature.pbFeature.setPointer(CLibrary.INSTANCE.malloc(feature.lFeatureSize)); | |
34 | + CLibrary.INSTANCE.memcpy(feature.pbFeature.getPointer(),pbFeature.getPointer(),feature.lFeatureSize); | |
35 | + return feature; | |
36 | + } | |
37 | + | |
38 | + public synchronized void freeUnmanaged(){ | |
39 | + if(bAllocByMalloc&&isValid()){ | |
40 | + CLibrary.INSTANCE.free(pbFeature.getPointer()); | |
41 | + pbFeature = null; | |
42 | + //System.out.println("gc feature freeUnmanaged"); | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + protected void finalize() throws Throwable { | |
48 | + freeUnmanaged(); | |
49 | + } | |
50 | + | |
51 | + | |
52 | + public static AFR_FSDK_FACEMODEL fromByteArray(byte[] byteArray) throws Exception{ | |
53 | + if(byteArray == null){ | |
54 | + throw new Exception("invalid byteArray"); | |
55 | + } | |
56 | + | |
57 | + AFR_FSDK_FACEMODEL feature = new AFR_FSDK_FACEMODEL(); | |
58 | + feature.lFeatureSize = byteArray.length; | |
59 | + feature.bAllocByMalloc = true; | |
60 | + feature.pbFeature = new ByteByReference(); | |
61 | + feature.pbFeature.setPointer(CLibrary.INSTANCE.malloc(feature.lFeatureSize)); | |
62 | + feature.pbFeature.getPointer().write(0, byteArray, 0, feature.lFeatureSize); | |
63 | + return feature; | |
64 | + } | |
65 | + | |
66 | + public byte[] toByteArray() throws Exception{ | |
67 | + if(!isValid()){ | |
68 | + throw new Exception("invalid feature"); | |
69 | + } | |
70 | + return pbFeature.getPointer().getByteArray(0, lFeatureSize); | |
71 | + } | |
72 | + | |
73 | + private boolean isValid() { | |
74 | + return ((pbFeature != null)&&(Pointer.nativeValue(pbFeature.getPointer())!= 0)); | |
75 | + } | |
76 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AFR_FSDK_Version.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Structure; | |
7 | + | |
8 | +public class AFR_FSDK_Version extends Structure { | |
9 | + public int lCodebase; | |
10 | + public int lMajor; | |
11 | + public int lMinor; | |
12 | + public int lBuild; | |
13 | + public int lFeatureLevel; | |
14 | + public String Version; | |
15 | + public String BuildDate; | |
16 | + public String CopyRight; | |
17 | + | |
18 | + @Override | |
19 | + protected List getFieldOrder() { | |
20 | + return Arrays.asList(new String[] { | |
21 | + "lCodebase", "lMajor", "lMinor", "lBuild","lFeatureLevel","Version", "BuildDate", "CopyRight" | |
22 | + }); | |
23 | + } | |
24 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/ASVLOFFSCREEN.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Pointer; | |
7 | +import com.sun.jna.Structure; | |
8 | + | |
9 | +public class ASVLOFFSCREEN extends Structure { | |
10 | + public int u32PixelArrayFormat; | |
11 | + public int i32Width; | |
12 | + public int i32Height; | |
13 | + public Pointer[] ppu8Plane = new Pointer[4]; | |
14 | + public int[] pi32Pitch = new int[4]; | |
15 | + | |
16 | + public ASVLOFFSCREEN(){ | |
17 | + | |
18 | + } | |
19 | + | |
20 | + @Override | |
21 | + protected List getFieldOrder() { | |
22 | + return Arrays.asList(new String[] { | |
23 | + "u32PixelArrayFormat", "i32Width", "i32Height", "ppu8Plane","pi32Pitch" | |
24 | + }); | |
25 | + } | |
26 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/AfrFaceUtil.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import com.sun.jna.NativeLong; | |
4 | +import com.sun.jna.Platform; | |
5 | +import com.sun.jna.Pointer; | |
6 | +import com.sun.jna.ptr.FloatByReference; | |
7 | +import com.sun.jna.ptr.PointerByReference; | |
8 | + | |
9 | +/** | |
10 | + * Created by Administrator on 2018-05-11. | |
11 | + */ | |
12 | +public class AfrFaceUtil { | |
13 | + | |
14 | + public static String APPID = ""; | |
15 | + public static String FD_SDKKEY = ""; | |
16 | + public static String FR_SDKKEY = ""; | |
17 | + | |
18 | + public static final int FD_WORKBUF_SIZE = 20 * 1024 * 1024; | |
19 | + public static final int FR_WORKBUF_SIZE = 40 * 1024 * 1024; | |
20 | + public static final int MAX_FACE_NUM = 50; | |
21 | + | |
22 | + static { | |
23 | + if (Platform.isWindows()) | |
24 | + { | |
25 | + APPID = "GhFotbNTYEUhXygfpAAab9cpUUi6qR64QEVj7LZEpzr3"; | |
26 | + FD_SDKKEY = "DMBTm7o32Tya97cXh19eX27RYbZBta3bxCi4MiVjRjgr"; | |
27 | + FR_SDKKEY = "DMBTm7o32Tya97cXh19eX27YhzpMuVE3VHfH85RBZNmi"; | |
28 | + } | |
29 | + else | |
30 | + { | |
31 | + APPID = "GhFotbNTYEUhXygfpAAab9cwdsyJ3SrjVBqi1dw2ESEU"; | |
32 | + FD_SDKKEY = "J3fq1oM9zdbPNpUw661RELhjce2unEHtZbX8fsEVqdQt"; | |
33 | + FR_SDKKEY = "J3fq1oM9zdbPNpUw661RELhrn3J5VdPRqiLa8DRFxAkp"; | |
34 | + } | |
35 | + } | |
36 | + | |
37 | + // init Engine | |
38 | + public static Pointer pFDWorkMem = CLibrary.INSTANCE.malloc(FD_WORKBUF_SIZE); | |
39 | + public static Pointer pFRWorkMem = CLibrary.INSTANCE.malloc(FR_WORKBUF_SIZE); | |
40 | + | |
41 | + private static Pointer getFREngine() | |
42 | + { | |
43 | + PointerByReference phFDEngine = new PointerByReference(); | |
44 | + NativeLong ret = AFD_FSDKLibrary.INSTANCE.AFD_FSDK_InitialFaceEngine(APPID, FD_SDKKEY, pFDWorkMem, FD_WORKBUF_SIZE, phFDEngine, _AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT, 32, MAX_FACE_NUM); | |
45 | + if (ret.longValue() != 0) { | |
46 | + CLibrary.INSTANCE.free(pFDWorkMem); | |
47 | + CLibrary.INSTANCE.free(pFRWorkMem); | |
48 | + } | |
49 | + Pointer hFDEngine = phFDEngine.getValue(); | |
50 | + AFD_FSDK_Version versionFD = AFD_FSDKLibrary.INSTANCE.AFD_FSDK_GetVersion(hFDEngine); | |
51 | + PointerByReference phFREngine = new PointerByReference(); | |
52 | + ret = AFR_FSDKLibrary.INSTANCE.AFR_FSDK_InitialEngine(APPID, FR_SDKKEY, pFRWorkMem, FR_WORKBUF_SIZE, phFREngine); | |
53 | + if (ret.longValue() != 0) { | |
54 | + AFD_FSDKLibrary.INSTANCE.AFD_FSDK_UninitialFaceEngine(hFDEngine); | |
55 | + CLibrary.INSTANCE.free(pFDWorkMem); | |
56 | + CLibrary.INSTANCE.free(pFRWorkMem); | |
57 | + } | |
58 | + | |
59 | + Pointer hFREngine = phFREngine.getValue(); | |
60 | + return hFREngine; | |
61 | + } | |
62 | + | |
63 | + public static float facePairMatching(String faceA,String faceB) | |
64 | + { | |
65 | + FloatByReference fSimilScore = new FloatByReference(0.0f); | |
66 | + try { | |
67 | + Pointer hFREngine = getFREngine(); | |
68 | + AFR_FSDK_FACEMODEL faceFeatureA = AFR_FSDK_FACEMODEL.fromByteArray(hexStrToByteArray(faceA)); | |
69 | + AFR_FSDK_FACEMODEL faceFeatureB = AFR_FSDK_FACEMODEL.fromByteArray(hexStrToByteArray(faceB)); | |
70 | + | |
71 | + NativeLong ret1 = AFR_FSDKLibrary.INSTANCE.AFR_FSDK_FacePairMatching(hFREngine, faceFeatureA, faceFeatureB, fSimilScore); | |
72 | + faceFeatureA.freeUnmanaged(); | |
73 | + faceFeatureB.freeUnmanaged(); | |
74 | + if (ret1.longValue() != 0) { | |
75 | + System.out.println(String.format("AFR_FSDK_FacePairMatching failed:ret 0x%x" ,ret1.longValue())); | |
76 | + return 0.0f; | |
77 | + } | |
78 | + System.out.println("AFR_FSDK_FacePairMatching success:"+fSimilScore.getValue()); | |
79 | + } catch (Exception e) { | |
80 | + System.out.println(e.toString()); | |
81 | + return 0.0f; | |
82 | + } | |
83 | + return fSimilScore.getValue(); | |
84 | + } | |
85 | + | |
86 | + public static byte[] hexStrToByteArray(String str) | |
87 | + { | |
88 | + if (str == null) { | |
89 | + return null; | |
90 | + } | |
91 | + if (str.length() == 0) { | |
92 | + return new byte[0]; | |
93 | + } | |
94 | + byte[] byteArray = new byte[str.length() / 2]; | |
95 | + for (int i = 0; i < byteArray.length; i++){ | |
96 | + String subStr = str.substring(2 * i, 2 * i + 2); | |
97 | + byteArray[i] = ((byte)Integer.parseInt(subStr, 16)); | |
98 | + } | |
99 | + return byteArray; | |
100 | + } | |
101 | + | |
102 | + public static void main(String[] args) { | |
103 | + String faceA = "AF2E83D499122D873D268B8AB8E80CDDDBEE857AF1757FC018A54DBC9D8D397EF739AC308EB5C915CB0EA57C8F5D48328699D3DC513AD2071B952FFE79742187049A23BC64D400385D47E20ECA4CBCBF2F641A817C7174F492A58090043F30FABFB6A6476F4F29D14DDD3BC1523BF4AC8EF73231AA19B182B0A61C808F6801F09B768A57533AECE39267BA11204B63AF14560907B076A16D46E4BB4FB5FC7FB99BFE4E93F617CBF8749A14055D0AC3B2A336F91E95FC5AE2D9145D221CE217E3933FD3289CA2467E20BB59386E4173C0DA001724027BEF278C55CB2645B9D7F694ABAB4667B0DA76E3E4FBE59A428B9C81C76991AD519EDDFA992D8071680F3B7F6FDF8C52595EB8FC6C936FF8120860522115C43B4FA76D27A58C54CCD3C5CA2288084DBBA56BC5E8D28E1B84E86D1D149DB1031FA8E7D1C9F88411CF82FC63250DF35B0D1124EBA501FE37FE963FDE513D0EE8D37F5C8128B1523143EB5EFEA2F4C1509038494B92659C96A168C621D86EB8051DD5A562BC0AE6CF8AEB183F61E3517F29CFA0B3D603691A96EA5C3CEC30D0BAEA4273F788401E51BE176876E2CDF906D25DE320588E280FFCB841CA9ED9F77E9FCF8B249933E7C69779DDD9F80EE80458BBE13C37D2545A8066C001B57D04184AA996E836110D3295E7908E6783003F96C75F7C653C051F62EC6F796F690B95992CBCC22C975412234F4A552BB3FE2653448A4A37C2277A82799BF4CEAEC6DDC701F874225FE636AD95BEEFC24A6FD1F52997AEC966B732ABD60A0B03551D1512E3FB86C600E3F743FC481E07B38263AEC91FE2E8F666C6BB3FCD1DC00822DE49AECED9536A0787957F5D473BE79348FFC3DBF2019244D2050041F09E3E41BD123A289F70CD5515A27B6FBB462C3B77F09FC9EF36FD1B4529CE6283CD561922CC7AB99631C7B6FC1BAF20623905174CBE9ECD32401AC4615A08F3200FF07BBB1564BF0F5CBCA4AD0ACB1E9BA5F5E59107A35868727D4DC78F10E4ECF6853BA5E332E5A11BFB08F06D242A2EFA383C0D4D75B42CC018F4C60CC35F350437E5A4D9BCCFE8D7ACE6139E92F9AABBA818F8059ECA37F75BAECEC04CF7DB2B6844123720B696C97EC8552941F746D91B831BC16D01F7C2782514C938655DA90E37175BD635F8134B77BDB7FA14A0D5EF5E44F9B7838F068F4330C1826B83B3F9EFDB7AE8FEEA3F9221C1EB69F6047B856EC40E40CA065BD468CE11A85ADF3C3111AE05E4D90245348E47A15FD11BF9FE6CB8ADEB373A4D036FAA7532DFA760E330CA7F939307BD8C6274BFD192F7BADD584B732BC0A97E85D94477269FC43B1088BA42AC18CEBDD5FFDB9EF80D40C490486DA83125337D27F5110B3857E671A67BA2028DE7A50CEFDE7C70CD14BB2E7D6D41D7E24CCAB4C043486D5505FD7404F6956C42BDE105B41B271486C8541B39134B7B4CC1157718461C2837BD7B9DA769B3331DC99A3AC228DF58A0EBD8CAAE3E142AFB5D84A2645FFB54E7402454957C5DD6F938DB44F9B4043015F1DC1632CFE841C7917C977B28AB65B78C965C4DAD6EC373B88BC107C6201F8A8F1A7339FD511AE6A6B97C30ACF1813E9E48B965248B30834B85CA450B5F92207DE2EE80276EC9CF840A30E5C079E6880764E670597AAAFC338DCFF55276CD132800AC391E321126273DC8C65D115A61DB331AE313FC04634BD4A1540AAB742222242C4846F89901724CBB402DE7B421EEAFB49AD1710B672FFB882F4D5A40CC484292362BE1E15498F469FB9928A3696C320DC25036154EB3E225B70FA49AFBEF8F00A5A56256E93A18545AFA026032C59528F49B314E08A7C119E68CD1EA458A6D0542644B795AE9812E5E3B1FAE2A7A71B683D5FCE2455F3C275AEE30426F5A5A0111710810CD51FDF62E634BCE16A0D9D5550B47A13164C50C7AEE9F8CD0BBF2B339CD4E7E60373DEB7781826BA17CB28D110723ACEE0879C61011A0E5549687C5A2D2D79E0E1AC6CAD9679BA9140AD5E2A6C8F92B4C0C9F618BE1799D7A55B86ABC4AEC8CC49220E13672EC25530708E1F24E92806DE53EA49EF3112B7854A42E0C1DA1529D4DD1B381B9802204FD88A8A18D298DBF1CD06048D28C173FE3DFB5BA44545DE1A44E4ECE118610C4E02C3FDF88C64612AD6702A811F0D6D113456B3C607C89D87B51CDFCEFA42356F81402AE93DD1B5EBAEA18B9EDD5082ADD42DD0CD3BD6F6894E2B5863D409A9A3DD8693FA8F41EFCA8A1DB37AC3C2D73A58A83AE7E94F1C1F563D48361AE49E2FE92118B4842283484BEA4BDDE29D67FCE36C44B39FED1D909B0ECE5FA738254EF1E9532C167255B126C0BE170F6324C84E796C006F0413A392FA3918AD1ACF6200B8E9C0F7653CEFB3BBB1589F0B3D7A34278C88AAB980AA8180EF2AD61B6B749458C5A025D87AA4D77A33127303F3022F29FD1BC1078E07369B8C0D3C896079354AD6B41A6C258BCAEFDFF331EFC14F64D5C1F419E70B84CE9652DCE59475004BE96DB35ED486907E9B33997BC6A6D8125A5DB5F73D5B0FD1333F4EEB161A06F3B793AB1468CEABABC8DC6AB91B82D937A99004BD7D8B30137E9F672865FE2DE0E86176475045CDD5F917A17590ED1E9F4120600AB6972D4BB6AEB9FCCADDA22B826972BE7271845AC803B6517E9153AC45686AB8538C8A8D75E741112DDAF5F8707E400959467CBEF67A6A7F15431062F179D0C69CF6CC16335692908CBCEE8580042F4D093CD2C6844E7DF32BF5A0780B6C3A2A96FBC9724AAA4618BB5DB529EBF1306ACF1C17088A75B403022B6F24C6DEDE388BC8C7F7B5A64E0CF49D0F082D83C4B18CD5D7343DF8F62E0C94BA2FC7CB504B1A34F53539C3D4FD80CC08DAF8AC6A7D93D3A8F6314F4C77421136C0487DFB7C3B7D397E6E733703AFD88D4F9323E3AFDADA00B0F090BF94CC6E079B7AD8363C696C4D6601E1D9C47D221603A42FFD60B303CEE7E8F69F454046BBA902333A1367C7ED01900BD32411A6F60C82861D050131CD7D2305B6B4E5DC191884BE6078FDB65B8E3A9D968E780E862260D7B84FA9B0EBC2A1C926DD1AD480E69D92EA9BA33175DE04C22824FB67F1ECA9D12FBEC061E55A0FD9B724208350B98F856643BB174F3360B4014256E81B31F3FD40116829CAFBA1430D03D24206B86F54E34D5C68A77DC234E4274823989D8B515DA702DEB82C00660A7835D0C83EA0B020808CD42FCA52FF1BF76D5DDB1745FC871B11FCCFA934EC8C5AD12004D9CF025CE8B6C4E94A42802D6F7453D29F8218B2F462032D6E226216B6B7CCF1185C6DD4C1FEAC57B3027FA4DD7C89C3EB8121F43C9EE7734E68311036705CEA230E5F4F0887E9999BF354F23B76CE0BC30EA2D749BF677D875B859F4892DE4EFA4307CFAFE5A2DDDFE8917892ED7FE729B12A8D743C5253C91F5AF784A555D068C160BD6865CB0A27C4D8460EE975749DEA3DDAEBA58349551E33B6CB98D58AE06677A1C1F37B6F648DF66B2E7255DFC35528074243727635C9F94D1F294A57F9486402D259E2891A9E29D4BB64B924BA98C133A52103EA266602962AE56DE7703FB6738F0C8460F3E7307B3B97E410925D3E5D72854D0607691A7CAB85AFE88CB785E4082DA05C4F05BCB8692C60B433BFEA69E36E18966F0E3C80CBD327198AF51E576AD7BC84056A54EE81BE06A65DAA70653DBDB120301A4AE2A1DB337796228BBE659E0D863CA5BD3B6987A87A0BEC9162C70D49E00EBB7A6C13994CECF60CCA2173077B52DC26B66AD2CDF7A451CC49D796BB7ADC9412566DDF162D59AAA5A77E59E2313362F437290AF7204D5EB681A108609A62BDF3C1765E356FEC60C5F4C7674A5854E9CC44CD87A61FF71102EB7AB268F690CCF998DBDA5F22052E39F3D097A955D15FAA57B27A13973638008CC2E3B9804B43E6E98E38E2781756C57292B020303F1F6EFB1DAE7DCCF16CB727C1A89220402905F2D7BF145F1E49745F7549C83BC8548187207CD15B79837E0A7C6BD732CC757B38556ABB27A81CFAE2A29382040005156A7E647D7E213FA053FC926F4447CEC93C36591A8D2CEB563D8FCF6B8FA2D30E1175F2A786BB6DB5CBB776EE296A5149019962602EDE1C9D0C368DA87DA4FFEE4D0CF42062F1A4D1B616FA0D1BD484E0BCB375A26DB88C081295C601EEB4919321161933739DE35335DBC724ADA3538641A2D189F1616FC58EF97266DE3B5DF4E631F2C61E020FD973E6D6FBC0CAA9DD8CD568713E4532843C14858662DBE3C48BCB2EC431BB8AA468D624437DAD7868537A841069A366CCDE6D4027CC12E959959BA6C290DD92E80B5DA262729DC1CE18857D444D7F5E6D9A7003712116B7988F8FBF4C992946D3CB4FEEB60D4250A32167B034DD73473D4FAEF3A8591E0E6A96F1C3EA63E23C097225B0B77A371D7F17D9CA39DA473EB4421FCF7359BBD9CCF4AB0C479B9FA7BF8A0D8BC2E568241DB947C5A256E11CFE27A6AA4296BCF235FADA8280409CDFC1395D1310A66E2CDCC83FB7A0357FC0E631FEB7022E4EFC757B48CBB96548E608AAA28747AB219E5C00BAF2A672D224841265A69B6F336105E8C0CB3AA1D9D326E1ABB17B50F645AE399D5B08DB4D4A71A1E2F4F65A0E886655096B37F880DB94F58F8A22EB3099922C7D546ECEFE5F34B6A2AACABE09EB63DE06C3AC423105F7351D88119FDA36676C2E851BE804A20BB0DB295EACBE5529F69112B74C8C2FC3F56A89E8369860FC5B49E66195EB4E3A8763C6486C3D8E2F93E4742A8CCF7C3F013AA1BCD273CD10707D22C95898C9486F166A075856D10FA961DA9A93BC8D7755A7928524EA5B681605F1F4AFB436377042A401AF13707680AA9AD0806D92FE2F7BD16E0D667FDEDCA0582EF8A90E5DD8D6FFBCB6FD40178681FBA5E9A2864E9AC326BE368038E39122F9F0D9B415BBAC94A73DD0C7FBF719FAAE4480340F762EA2860FE1934B2C03C16857BDD59AF6F20E3B63552A7F5112D8E9BAC0A5BCBBF15B40529849E1807B5B22F8A0925C8244741CC8C5849E00CCFB7984F7ED3FEFB5BF69FC036C4D6C8893AD58A9564307AA3065CE1B37E391BA3EECEE9EBD690A4D8CA8417BAABEB5AD084F9EFBE26D6562AEDE3DDFD74CB4BFC27DC49B104A3C925A318B3B3F17470255D593404CFB42C4D9790553CC5281978E869B4B3FF8288492BC782D1E3D67C511EE61DFBB50F7FDFD9250E233B8752C64A1FEEAE29C0F73C9D4B6094D7D0546D84FDF37A1E57F9C196488DAFD03544D48A91B1117ABFF98779A3AE9813EBA7889264D99847DBF38FF7D93FCAFCEBBC5A8A75CF2F37E0EDABC76920DB1061BF4FFDBB74ED638391BB528D2D82501423B7A2C4917DCBA5A0945D0A53DB8AC3CB0A060465672C8C0F6FD09454DDC99C8D84FCD28028ADBBC0F000BBCBA9096CFCA024B3C3C0E3C22E8911AD3F92CE91185C56A4158631FEA67A51996261D0ADFC8CFF61C20B6E30C2564EBF2EC598C960E04F04F63E9979695F09B271AA65FA113ECC3C7ACAED9B20E683A4753A7294492A7BBBBEB28212DD7B2D1CED90BCF0C8EBED0D76B06EDDF3AF7F863019ED9CE303944458E27EFD0BE427A9C6E3268BEE684F5BD73207BA0C262AEB07570F9CBD033B4510E84BD37FE7F43E35893FB7A09412618C7CB2929E2984519836468CA82265FE0F684391424E40743E1AFFEB67D80426DDB2058114AA37A425A5D870B2964E4CA0DB357676F6042D117BB47AC1B699E4E495576A0FB1FA21E2FFCF9D026CD39576F7D6A41D38027195B48A004B18AC507AD02AFA1E4E57C3848A45A631EB990F3FB9256D7D574F1D0FFCF11F13854121C2F19470E3D86DF5DF8C8FFED893FA92991640FA8B3776E8CF4815FAC72EDB94538D0A9CA6288EF65420ECC39846EA65282596E7F37B1184A906DF56129034DBF113D3B87B9BDA057EE8D9320F9F562B93FF5AF96D7B1FBE4CD7B627066DEA4D4B9FD68C6BC6DCE62A0F6F9E4DF7BD7BEB274A200CC5928744879806537D3E05E73BFE945870FD8CE5D77673002351C0275D12EB246D6C204A2E6D40C553F533E000410E83A46617B27FCDA4B6BA18115D5D970416176008E33DB6BF395BE79B7574A5FBD4F4650AC8BB5C726BBA8169D81FC202087789D7778BE4ABA4DB6828417BDDA811D591CC81C72F3A615AA603F1EEBB693DEF82A7E6F96D77867A95B48A13F8D18D893C61D2E40BF10A134781AAB405507D67DBBFF8DC6607B93CE3CC709D1DA3ECCBAB700F161450091D9064F3E33088571B0F80ADB6B2C5642810C417C4F7C4A60C661377C482136E69B211C0B3DEE9C5BF772E689085120D511BD1BBF7F07FD33DFC2C1ECDD197DB4C2E04CE9F4673234C12E65CA9D135A5751BA641D75575C8855F7BD0FAFA5404FB4FE521E3959A5D33ACFC20F89844A84335F876D13344DCFE08DECEDE80EBC95AA43AFCAF879278DE7862FECA816E8E96D97A23940855654495232C1E8AF2B8C00533FB542DE2F0FB50D070C5FC619741A21948B8C8E28CBCF29D3A9D9AF90E3D7E9CD0485419FB1A091DCD1F77ADA853E6ED08E8068D2F7D67E004CB21B271A3101D0509F523A7E660EA6AF91B2267692F153D273475A5D7AD111AF08929E1DD58B286122E12E16F2F5B56B0095FB6E5C775FF8E3556996766AC1AA998C765FDF10C0D0D7AD01627C503D1E9B60B23B1F851D86AD0D210DB73BC7DD301CB4D08266ED40C14420B4F7B3344E14DF9C69951E0375DC25C890C0FC3A28BC8571BD76B0F60F62AAFC9CE0A1E1299B2C54A60C8D07749BE38E0C0D00DA3667390AAF1999BA949495AA5F78901351C86F2901EC20237E64BFE3A255B95D6B9F816D9442FCD1C3E381E723220B16234452355BCC8A41D15351B6ED708B508E9749097A9ED100FD55E5EAAE42EF6C895A3A94989579DC7E1C89E79E7DF3D5BB2039E67FAD63878CDEA8F666AEB5704142CBB6AD8A834C2F64D43A6B6BAA0036D43A3CE09AC10ABF5FB28C21E848713EF6CF2655A386BFBB7C5B66F6D79282BD0F2D911D141367C159C8BA65C1666EE73B25C01C37249037F5DEE09BDF374977926B9FF535FB106CAA11EE5069497A28E21153CCB78915A4B744B782B1C023BF951D3A28BC6D5F5BC9C1A184BBC7B7BE9D8180E108E437DD33E6AB4FE21057FF168ECD56242F32DC5F5C38293730CD95547B48A8A827D1B6A14D234F181DD9FA38F1A0195B8CA6D3384F2F1E787F1A92316DDA72624D5F21A51E384D9D32A7D302F324C844A944EEA4B3A9C1819BE4AE8441BF1E01EF0D08D88731B6B87D10EEA0BB7F643AD4D654E0DFE56562FE31F7A5D3534A9DF3999CC7B1BFE393DFDC42E8E0D55A8CB9A26BCC63175286866F2BC9B50FDF23FF8A5CC8A5FA7A6269E5BA952FF2271FD82209B739390EEB981FE3E5DD0B5E503040A6206580609A1DD606F29EBA9818AFBB5CE15B55A0A02C69979F91825A4ADD73E5C0A28DE13D17CF7E9B77956CE20761A1825160FF7DDAEB8A6822DDDF5F87F0B11E759AE9C2100388FD14A5629AD671746937BD63AD61101B49BAE862D31C926DAEDDA819406E9E9C56B5367DB72A39D9C1F18602C2D93F0ECDECB696D9C3ED6D8C00C05D91CF6F573708499463B8FB495773DD3731462E38D66FE38FFD485A3F436D19D82F7925483603759D1967F981CB1F02528E68BC3B4931AA8CE96B521D77018CFD079D7FFC2F37AC2D876644C319442DD409F736723C64874726DDE3E04E2885D6FFE60F915A5AD036F60344D1D61FEF479DE5C25C9BA7D28F531C8777BD706623088653C69A7276F5140AE7251003693A170C54F7A21223146668C807F63952811D4F5E759E7E03448428650102B13AA0CAC0A0772C435BB1C5D093594709156AB25D2BE168286E467E27177C55C2A873AD7EA861E7369AFE3194925D7790589FC9DA86F0010E8C8B1D613A5F891CA57AC7C26D1B19491C2B9AEFE6F1470163C901E2A7105F3C752C8F6DD079162A212F31C18E507DAC2F5DBFF4B3EC3A92D7AC0CEC8658A696CB72AB528A15CC3D2B30EB6BF7D75141635E87CEDC8951D942BACA92DE88109475A543C47695379D3379534DDAE15A03B05BDD8CBDD0AFD8E5A59C99C85A82A522E164224059F5302B63485835F694C1C91DB29BDCB22E2EE3225F0A8390248B3C938ED37F3FAF54928EAA2B0E01EAF46E493F1ED2C7B5EF581EC09A86D7BEEB8805A8911B3F8DF0C0D75D31271AF850E1FD69872DD7BD7BF54395F58945BF4DA21A8C0B20BC7437B74AB5114AFF4CAC5A455E5E7AF5026A4BE71FBAFBA0A5345E993A190DFC19AE26CA049DC7150926203FFDC470D3E678560B3635980CA73BE9345C5761A62EC102150919088D2E4DA7500C8B0A0AACC26AA995ED0334FE462F4F1A17D45648E39E6BA57EFF0EB355C1481BD2A78747672094C9BE118716EF38524B7C4681E67ABD60327A665D29E2D5DC0D12A816F451594562A6E5FEC43DBFFEC01BF6A9A9074C6B6D4D8841C536F0E7D2CB4223AE42AC9011C6B317CC1CB3D3C3441FF8390E26D50FA41A5D736FE2E59E3973BC0B63025DCF434DC699FFB9C06E964A824F3B763B134D9776B19685A3E3F4A0F7E04A0014B5CCC4C4D03765C1C27BE278A56159DD35BCAE7388AB0DFE29485523712CD0DF999ABFBE03659C05D4E52423F2F1B883D0F9DD8A5C2A99231597F7D0D677754F84FCF7F69923AB2502852DD3C04BF6FA3FC2FCE6726618C9B574F64D574BD85D8F899E7945A8A0729F230144675785963F5FCEA1CDA10D189C2D67E84558A5C2F5267E06C23105C51B7F40B9D0DE614D088EF2D6BFE4C21DA031D826871BAB3909230064F184DFA4101708715FBA7B7A8E6D5D373897A6E8777D7A2162C693244B4938DEFD559D17D86D1ED10721433C883CDBF04ACE1B0E86033327E07BAC25B16036CF5351D385D1954ED6A612755A01A00334CC02122502B8A0EB62B9306129A7137F79136162149DE18289FC48F10AA442252145AD63AB202658D5F8863CE2955715BBD062DC58398018D8059C05EB101AC972A5F2B88FFB97812E51DA752A9C8A34E53C94C147E9EAF332586B17FE2CA2F33CEBA4AB558B6509E3C3D66372D8816A2431D0F750A524E60B5D6CD1FF665953C6169B265247B83149BA998E8CB84BA86FCAB18EA3DDAF78232973608DBA4FA85149DEEFCAF7F4BADA442455E62C7ADC81EF433037171C59D072A30246D172FABC00CF3C1B3B85DD00D568D65FE3E123A3CC9D84DF5250B7E7DA933E009C20C8E963D39B353BDDE0C56FC193D790C8289B16908E19F276F158F6B69F14018144793CC07525A8E46A3EA8D76CBC5074821EBF8303D4BC9151E8A381D1E529B829DCCCBC48C1AA136C48B14CE71B3E14FC5EE6A965FE91E3C60E0CBE4A8DBA36309D15FC0CF0CA7B1C28A93CCB52B1649BD2DEF48C8ECBEC7609EF9A95F9EED3C0C5120011B84F1D0D47CD56DB204C75F509179EF02389907A04A920B89134C9EF6E857CEA22AF4D35CB8E21E48AA2B90B93C4326B1228D57A0925DB43CC10C56BBA523A35EB1A0D1AD507821C5237AFD0669EB1024ED792A2D9B88DB3E97B8DD7AF832F30968EEA33FB80F9BF4DC1B07A94ADDB6849D1F0CB0615B38193089213D3717CCDA8160CE30A27CBDB344D3CE250824AE6868F5698195BD780E106BD6F9367D228B9DEE537535F25A0E3372CD1D547A5AFDEF3622F084FA3D5C4429C42C48AAAEE1A06D84285012133BB295A284C61A87358036C8E343E57CA44D1DF7B9399AB68728475298B184FC418CB2F9B2452159C416DFD8421F7B35EDA828370C0C4E2970C9358316D7F17BEC30F04CD227F88CA907BE0CD00F2CA52B27F0DDEA832859983CEEFD231C25B50DFF15E3E1C5B409B706F1026D7985D2FF47645C73C0DF139F2E9CF2F847E38562869D6EF4DFB51F6380F1A17316175DBEBD42DF3EC3342A64B6886D1B26935CA6C2CD397D0AC88E5753ED694613C231BF4240004B81D997C4A3F1C26A394D3751541AD0D27988EAE7A44BB5234E78355C9AD6DFC2CCCE4CB644F2D3549616891BB019DB77F3C460882A9FEBFFBB292FF149B8F3B079827D39EEF220C723B67AD91E7212200C4A74F07685200D7A30EFF3C247FE2B80123CFD9EDC923FE1E4CE9AC975240B3D1631C80A0A40ECD2F2FC4940116651137A666F1ABE2BA613D45B9851DF946188E8303ADB6C11E68376FFF6A46D12215C9B5BCA758809DE1BA26AE6ADCF7A7ACA3DA6BFB519956801333EBDB2FD6F6DA6E94343687A5CCC2484CDFE13631F1BE0715349DC2BCE22CE6FD8A6AF0DBCDBCC4F6CE03A6684FD136AFB9FD4732D19BBDC59772BDE24DABD1FDF1F3CB3449BF3DE6210CD3D61E74F67E1810EAF8B73FF8BF55F0DD056DD37CE295AE830EA30C53B28E349DD104BCA4A523067D293799CBBA3CD2470FAE1A2606742B7C05DB0DE67C8A22AC8086EE2810D3048AC8B622DEA3AB090AF1D3C4ADCE5DD00A5C9D39333549369B11FFC5F2D2591B835AEDA91ADFD9BD2CA26AB77995C71F5C256E94756E279E5CC41EAFF5BCE51A7CC02C34CCAA55387B099AE96059ED3BDEFBC67479F232410941A7A877CFC1BAC74488874764C3E722313D41625A0053C6559C8BB4BDE9367C5BFBC770A5CEA8B82E9B9A5AEF033234A6FF8FC556B5BA200F434437D113DFDB2D8FB46E26D02347C20324914164AFF1EAF709D042FE0B23288DFCAD7977CEB71032D1C60AD152B47181B81BFF31D696E84395DFE14B693CC160629CB83A3FD2D25EC0CAA33EE940A1EAC7FF7459B372EE58DA52B40571BC5D0C28816C0FF92049761F8C373291A0D675DFD101F6055CE2B5A1D9A24B61546330772F6A265F9E0AA74E2B066C82D8D50E9C922EDB1DB63FF1A0377D427FC00944BCD027CD68A91A69BD067A30AD84820DF555B1E73694CC6A16295304573648DF87030F548FADEB0578B961BAC15191A6D86316784DD0C60185F4829E1A9A2E49D65BDF87E25FA56C65597237B62EB20BA47FCDC8A97759EF0BA11DB9C4145D7E45693DFD6066F3D296E53A3F2A22774534B8D144088DE856E21766B56504C73105445B5638B279FC1A31283C9407DE9E4829D150726155745B4B5F7DA2A3ABFFACE44363E8573080717D56640D5BAB977759CF6529435FAE409CB788C4667A8F30A2CB3F97831124E6CFA26C274640039350C47FBFF7AEF5FF005E3D50C690A958832D164F4CB94840E354FEDB98A7AD6D4385918A5B0DE5AC8AB439FC23E2A4C4D43703C148A81CCC3753FAFAFDEC8D2497DDB932A0EF4B1440A3A159710573A4107B9BBC2D40DF1F1B51DA29F88A3762787AFE488EFDD65A488EB8D7258433A1366816FB6A99B1F3AEBD73A6889951036D5E77933A030829D7835859178B34453565F88F8081AE3548E859434DD3389C75E74A21DA028DDFB92E208D45C79684B7BF04771917C37F1C98AE99DF98A31A4B13F878456EDE3F2A9DBEBB7D28BC8115D2F2C6828E09EACEBD3867781E3A73599E574E6E3849936C076358BE2478E92263FABA86A69BB7E0CEECE65B3CAEB9A77F41AF5E0E69DBC9132DEC8FEF6D69D42379726CEAC92F836F44A24F230B6FFD19875948E41D56C28B81734F6E834AA58039E6487E735939F39825C9F2669BB85B879B4C420779ED41FC70190DB4EEE8ECE6B14D44D9448CAB6E87B143804EB3630AB820491D7E0EB05669B6B74B2E634A3EC0A8160202EDD1DD7D2EFB49B3B83CA379EE5B4B696C3B0D611933F2134EF163238CEA2BCC85BB7B16D3A850041D59A22087B1BD1757585E0A470A6E85B257DE3FF0A80445B681AD0FA71561CA7DC6E8E60AB4E01FF0DDE651AC2BADE6AE026A55FB954DD3B6D7420347BC06B131CEDBAE935D55E5441ED42E4A95C83BD68D6E907CC195EC95E1450C3BD4683D980352C7618E79D4234C843A958416531BFAB6983A1C1BE1BBD241761B8669507B2714E064F739C0430F46298FA8A245C1A46CF5993D9D0E908191E80F87995498616D3DFE535E5515A42C2362B04C82CDFE72F912B86B3FC0A5FE66B329F8360848AE96E99666B72BFF3F2F7E824BE652327C722017E86A687D23E7D5EB0ABA6310CFC41F8C5424DC74FB70577952C8406F2AE6B6D6D6F87A8EF1BEE7BD01151DDA94EC3D2BA1703719D0D640ABED3BCF06C4D02697CAB4F9A46D4BA12DDB6F0631E2BE7858758DE49A5CEB254A78CC80ABA4A5401ED6452C904118CD9390F482FF5FB893373F10A50A4B25D3ABF222AF5BF1BA41C4235443992C934FA5E9DF61027ED73D57391F1104BA308BFAD839DC23A3765E9995D19162DE0FEEB3383CEC970031C61A566CEEE64B230E62E3791B9CD9718D290C8722AD3382BE6618525AADFE0F01EEFEA8A163724EF9F9197E88394EA1F036FCC458E19A6443D7DD57E0588A6E640F221D8650CC5443E314416468D9D390A265B0C51EFEDBA22E5AC0EA2E8B204A51962BCB6DEF6E92F90253CFD067D6844A6B35111423A66A831B01E2E5F683649822B4EE05909E4AD2C02B37D3435D9E2D437D53B8172708AEBFAC4F1F70FBDBAACE9068C8D6F00039463C28709DB9F83D91127C48A4A374F94601AA52979D2B08AEF34F87040CAC200BE2D277C094E2B99DB7822DAF18DF5F76AB9AA5AF7A33E8D096601CF02A83E491A6050BCFB5C79AF8B71BD5958A0111EB7922229795BC7CC5229537CDCE1F6100B9334145BB266A5E3CABA03B751EB4661C08E50A8CB2C41E0A284BE9431F7B11C55A43DF4F399092037A3C3AE11844F4086580FDA0F35CAFC343FAC7203BD9EEEB7B280A09BF9753D50C5092FDC7D8CEB8F3DDC053B2BC60A644A82F3E87B81A9D323B7446EE52FD5BC178E19B66E5B06292FC693BC100909E59C260FDC4204724771DAAA05CAC237BD6207270E86581F749744EC1B08038F3F079DA1BB4702C8D45C200C9A9212F2860161C9F1D7AF42B7331E84C77249BD22C3CC722BF4D80C9C5E6FCB5138198768DDDF8C28D1EDF2A6B96F5F9284C0CF2A856C6F53A5E0F4BFB75F2C7FF118D306CD5F9833A770EB7DCBA7E997D49EFDD24A66B490B732B1A553E0A5B95C977BA42C5882720F0EF2534E24B1189F68D83068D1E4897F0C4D3447AF300341916913B3F8BD0E86731761EC44E89A1657BACD2229F0F63CF680A577465D0CB386EBC7D3F21BF01019EB196F660D903724C7428E8624A5D2DF96751E3724B445126E71910B3510CECD0FABBF45BA855173DDB30C8B7FBD8FB04F050CCC540894E33938486F4F7CFF93C0A26E2AF268F8C69844FE7DB6C038CBCCE63C81292CFAAAC08FFAE6E40E1478F25176A1D2C317CCBB169D52B6CC6F59EE6C18E42D81828A5E171353F300CD903A9BAFE1A9000E95785A1BB33CDBF8638384D58B28F4582FA6A99BC0CFFB37FDA42D1D116792573BB59A4C1F67F3BAC84830CF7F1610E0B65A1BFBB3B031A4D5C784A0C85DA91E09117890D2CF1572AB5B1FA8A378DD39BC558C7766E44D6BD453972092FDA70A904C8CBA5659919E0F033D87209EF98B153A0D166AAB966E03DC6FA4AF33C8D0415208C795EEA38F423CAD1386047CCE99079A5E1CC2F8709EB6ECDCCD6981186E6814CD22AD5E18DBDBBE2824A74B0733469187B2275C16E784599CA0450C66DA7304022975FF626B4CD0669D5C559C35E23F0F88DDB6DD4AFB07E0183A3B76B1CEFF48B0762B4D2D31092ADAED00C663446E83241004AF3AA4CAF7C6CA1990DEEF3DF829DAB222F4673D42FE5911FCBE501E07508AB5EA477CF78F12BCA00F82609497A46B170AD7F6805390A0EA8D6A7F0B12C2D15509EF6463048FB7F27CA4897321C6368C43672DFE4E7A20032F56D93805FB8FCB423AD4727B088805C090A163D9C1342F973C3396CF16726B140B238DB1B281904FD6932A9210351B4BC6048A7788E3411FEA0944DD360DB2F5A9BC6D26F9386D3CBCF56E34DE057B09F5E983613BAC6E126C44E27ED8A2047E99B20CB734EEFE380F8EB263FF33562DDD28336F6DBA6BB6C1FBC59A11860FF9E217678E63FDE32B3FB7E5ED95A35E31A73DDC6E9D4038FB45DD5F6417F8AEBF4E6066CD4E052368E60F843EEE9EC498C7B0DEAA8BFBCC562FC2809ED89D4C2C7CC4E8C17F443554BEC3AE6F98CCC56E1657FB989D43F955B7CABD2D27EC56AF0FD17B2F1287ECB6C6D6D8E4AFDB7BC4E56D5CFCACF7FB75065B152ED352BDE83F72E49D2500870AC071A5980CDB2AF3B6BF79243B4D19CC63B41E4F42107F455980EE8E945A855F3947E667C7A87FC1DDE2EC86CD062737CCD64537B94375E7020C2BCDF22146C10A873EBB8217D937CCA56863C6082D9492B9AAC99196003BABA77D54BC68D1E8E0C4065F4E0CD9F9C22C4E7FAD4C8F5C5CF517C759EC20C0C956FCD7993A4F5F56C4CF12CF05EAD6179F4930FDC718279B8C800C7F8BA3A1A13C4AB2E7EEC1762A2DC079064297A71534BE6BB3922C60835FDB9AEF54D4BF00768828419C29B85687DF3736355CAA466A0AFE004B2D3E92746A3ABFEE59A12C5909FF50EC9BBE4F59DF331DA09DE1D17D51E047053994627C0A98DB04735679C893A55873257894B1F63052A21DF269741123F21AF18DDC60609448A5CCEEBA7C5C6879325DFB2F1D77F7FD3E7523B618DE8621E659E45BE7BEC2C980EFE755BC419E3034C29D2E083C667F06DEF2E2D308B14EAD483503EDEFE3E30A48A7F94AE5AD0672485F2F22DE3B4095B6D0B2198506E08666CA6278A8E221440814CF5F3434A24B8E2D8482F679FD36FA9E8E2F47F5078E9FF3EB222D5B15B3B6268575946DBF9A8CB4E6A01EBFFCD3F532197B88204DF7CDDB71E97A1AF0831650DD337F8177364E4556D1D4A1BA374C053882A5D19D02254A60A2979355B6671CE9BE57C4373460AFC098946661A05385A061FFD52302A8098671AD2013D9153397902980497069294929371A4142F3D5D646469BB167830A81EE8D94A018C1576DC2D2E978BE9DB13C586ACE492A7C03961A8B5F9E54B2129C0609A7E091719D49AA0162A943D6AF03261B715913DBE9E1CA3EC6ED9386964E9217FB3FCFE7916925690D87E0FB0523D63C30079759FF0E839858EF2CECF5652B8D029413B8DEFFE9B8893678B0066F090F40FF6FC27F5EE2DDD7984C3AA71DE3B59637A1B470782C09294D5F763144E8EB037B28C7244898426B0AA676F3A000300EBB04D1AA2B0242459B4F1335575A451A1CC39BCCCBBD8439A8FC950A05C58287201B22A2F5A561076B6D313209E08F00D0292405AAE45BDBAA6B28BF411CB997E8FE9322247CB57B18D61A654243A9609F17687271893E37B3C0669CEC8594FFDC728395E98ECB05C14CFDD80BD627492C23B809D33B49F5285AF7E0CC6101A34FDB669A25844C2C3AA07BF2F7D2DC13DC1FBE07ADE59868B753AC7C5844A0E8A90361CCC0CDB99A843F602D302454800B0784507884781BC19C9740CEA0A5E71E7CAF6778EFB2E2575ABA43CD68485E4944A7AD8C03D6FC4341831B0F074B0B61CC1B3F6335F22CB490E3B8CA7DD232C98E1CF764E0977C29BF914FEBB40AA766181545FD922776021D4CF8BF2A54D66383FF2C95628AD798D8BB0951256CF2523920AE2A61C45FA30053E0AD5E7634178641FF6139229A5C10DDEDDBBB6C4ABA0DAC27DB177E28D594B51238C512CA13CAF522CD547B3E24A3A67490619D1596E68FC0DA415EE5E43D7DC98BEBD136349D6D724F5AC5ADD38AD2BD4A042314551E4784521C2414A461A3EC21D9FD56EDBF982620786E0E93C789818A196ACC72B38C99002679452A078A08876CC0DBD42FD6516A0284220EFC8F6A59F33D72E31B9AE1E36833986B67F9FBE99E3A1B223352E74304C42A8A8C5A3A8206C0AFCB7E5E3DF6B6129E7F17081926C1F5DBE8912859528625224784B8A3BA3D540A309059C353C0DA3B9462AD6E5727935CE00DB9FBEED1C2543AECB992480A98F6B6D289AEC8A9A46D2FE6E821C650B1BC51CA34CD50B38B45412F30F89BD324561F5A94976622968A6706EFEE1D6C02D8D0D2A680E8FB7124DA411684579F506B3F3B86241FA009B70CBE5D5E81319CBB59A7F2D2DD631C3EB5488A076360ED1D86573480936C3C779BE4C204147237CD52600B4CF18ACC5D21FD88D3E5DE84C58EF163D14F899A74E903B227D74E7C0A0474B3E0E533999DDAC85236175571B802417AE86A55838BBF6E366FD8B844A7CD50981B26C59EFF14BAB8DB30DC25743543853A9A59F0E3FDE2927BA49394E7C12D8F5C977D16887E6FCB1993B5060AFCF9FF5C690B77AE5E6EC7F8668DDA6936AF88E2EA4C9A0B4D910B8B98B4BECCA570086023F3F7B87F6797844743CB213FD8B6E2407CE6CAF7E481BCE89B20775142BEA54EBD17472BDB271E112E4E0506FDD7CBE44E83CCE38309F909C978A17CC193F6790865A44E8285C6D8912658A853E565BFEBDFA7FAA91CF06FF89307338935743F462C5EF251F2BEB590952387A0665FB82EC21C10DE1DD4A0F5C7B572C3F8B81BE4EC3FC8EEC569F31FE097010EC2D041051E8562AFF1813333A82E7AB08419AEF0E505ADBA9BB2B9CFE0F24471F3134675E34605E3AEF17733ADE7C49E3D633BB7C8AFDAD4C5F6AC81098550A0FF0038AA1ECBAF7AC13BF7564491FCE5319181D1BC86C69C822582625CE79E7E4CD95B688C7A4C8C06E22E6767158E20F904BBB9FD83C05E70E4A18D599C5081886A07C866006F52464BA93F42E20D2B1E95B0F4DAA505B50B2F568B07A768EA4A1622BAB9823134DA1B04E6A5D30E97DBF16270044A42CE0B2E13CA44CF9BC8381B07280EBE62B6AD46FECEA7B72DEF6BA84EDA10A8DF2022AC2145B810DA5ECDF2DE2FFA319D10B37846637084C28414BD7AFB19A82F2D20A3E2E458508A6B23C75489FDE62EBFD39065AB94D3ABD7772C48C192C81911F39B8A3986F85520C3AEF753980F3799AB50C646497471F657CCCB813F17257CBFCC2A62374C71313A2A81EDCBF8B790C3682FB50D19F686AD51079F6B5CC69B7FC1F782A2FDF4D60C2E7B6E594595BDEAFEECCC34372A6CB30771B759B411D4BC80564F594FF2C788EB03F7242A1825B8396DCC3D0D8C15A47BC908122973357B7632967B70371A78067149C176377BCBBDE95C91932C41F0AEA7A90633593F2A1A3ABA30A0F426A88FEF0F8EF18777210006520F2D7AF0AD8D7C8ADE5A313FD820D68ADDFDD0C3B6059F5D5E3C9F5669E3289FCA0AC698FD955887BFC679F01919C133F3A701AB42F30765DD0029EED389AA51F705A0CA0551C4FFA8718BE49B2281B53BB788BC8976031AD46A08C8DB16C326D98A6E976938CB7E3BECC42E73718710239E941ECA86094FF4C133E0F52BCE8A733EB009E8F34FCA00EA1EDD6BE4699BF93E7D377F042D4244E213DD9EF9BFBBE9F7980E17592DA05DF5B1CC1123E15931A8BAA114EFD76FB89AFCEA769E99739D30FED0D240632F2D1AF886C928206DC7246CAC6EF89944FD6A54735A38578377157AAC29BB90BA96110DB400764CC4A86619B2827B94D17159DD9F1EC6B304216065A20DEF191EDAC2DF423BE590502F4F58402BF00DEAAA153E38BC05C462AEF1EDE0592C70F0CDE4737B4E78D36D98C3A2DD82B981B28EDF13BAB5394FCB643FEDEABE3553BBBC1BE49AF7DD775030974F58FCACE85FA395053AE414BC2758D1E71F3DB4CCA36BE6A980DCE9DCC83CC4D4E9D49DCB4CA81C2B825ED24F624A9176538A2FAD7FA678239DBF6CB475B4328A8E0334D72AD875424A1121165D921BDA289B347D483F0667BDF0094686EC983DF64CA4C4DA7204267940255E18E09F58FA2F489A6ADCCC47C0B6DD057E74072482EAFECA23DF7DB0129ACCC8A6878C3D8C1E0151C9A19AA8753CAC5606864D8DF4B1FB8AAAA5921EE8B851B2544B673C3A5B7AF7FFED7EE77D8790BED7DECFC0E84ABAD3B7388C26349388824E2F328CE53E77E4790CAA16906FC96469BCA894CE1DDB181021CFA63B862C9534F4DFB30083AA56D4D4542318736E1A176C5F45C6C81E065819D7DEFFBC00A197FA9C91C1CBF52400EE778CCBBC0946CAE929AFB03662AB7DBB58DF7601FE9DD12E00AE7693088894173354A925FD95610ABB7DF7831D271E576753A9F20BC5DA37BEB093EC835D9EA49FC70A51ED0DA4E12DA844A6ED4B98780BD7501AD0D4D651B61774976580B52B9C9CFF7D92FEFA382CCCCEBA4B8167C80337176EFE709F8CFDF4B69979C16796BD8AB0C626BE9830385887E0F5339B53A49CA3FBCF04B64B1B9C8E2D35406A6B35C3F43B6CA9E616BE4CEE669D17B57AC4F76F7E4532DEDAD03D8B2A13753F743240685D803180E72C738DC540D7D9766321CB5E7520EC082035493B09A056C4C0604D0F65A9260804A02B7C1D693B1E48DD71084249BA03FD8F7BE4E0D104A72680AA03E046F7C2846EE3425675484AC5FA1DA8BD9E9103DCACDE09F39E82DE5079C92DCF91AD7527CCDC6E814B7F727DE8DE83D3A0ACB20FBF9A9598EB1347A333463EE9731C5EFEB13732B3942DA354CDD56A1E698BB01153E52BBEC193DB3667FB67764B38B5373F5AB215079FFA2472F9439371F1C068F72E54AAABF014E0AD80F0BC1810D9F316CE89A90F3C2CC95BA18D8C1567E0FDF7A103495A583EF57E7748FD538F1B0AF53F162361027B94DCE9C51E935FA8E7A91166B60726C76F4DE231002B9E38E391F0EE4BBA27DF91127F85A49130F6EBCC43A95E7CE835D863E27F174BFA6FADF83850C985F025551C7B91B37F78E2C0E43B43DE8593C678EB6CC09B3409F92789A3AD6C017B1D54C28A01F8AC90F207D82F5D908E328ECD11EA82C92CD8ED9E76E621C9E980745F443096DBDEC7000057A38D2F9C160ED8DB764555ADEB5F2F846B0B2F964795706E4BA8DED7C7D96AF18B943AC80B613F96332630BEAEEB4CDD044CDA7F4E820472126C561ED3652904A365820013ABAF15FDC7E73009D8A03A28E27B686DEC177F7852D7A10DA38D05EB61E078ACDDDDDB302A205DB58F45A934D756576526A8AF631A8F8EF7126E8D7224AFD3CFD7F97EA732BFF6DBE669A086BF9F0CCEC90227E771195EC3600FDDA8CCE27ED9D8BE2D4F04E150C1FDBB88087ECC2B5B401C0A34135CE69EB2A756CD4A322553FF8A3C8551042B60C6BEB1209808BBE3A2759B9968FF36650AD760228EA4F0E4E32094A321CBCFF9A5605DC063C2AD036D4C7DCAC7E020CCE405BF75B9A6F1A3A13C06C3DB7C57B9AB82B76BB534A5A4A9DCBA4EBDE08D9B2A37E4860433B809C65E6119AD71E2B5F9A009E112B3E4CCB0DB51EB2B8E93E28D46B9A79303D3B33C6159E3F64FE852AB03C841A0FFB4C22C1E0754B4EB4716C665EEF04DB11AC37FC73B2881846D99764C1B1294076B6C64DEA438FE8F894D4DE737096535CC4DEB6AC9F913A9874A6E5DCC781AA35EC58618BF13B24E8BA1A5C8E3F182A8BCAB8BD626F9E0BDF0395716EA71042F9881A3B6AFC5F6869205E7A5960CFFFE524CB1DDA6270BDF0BA369082601E54FA1BC60CCF3D5E0606BCD8568758DDC745DB9803FC6C2164B9695E9C0568C3F0A62413DA9D0B516B43C0B61815AB56B17F2773A995A379C364E73A4E10EF647E3BDEB374246219AF920E9085BF2300C28D5C80D06BC20F3F8012A295326E9680E8F521EE278981914DDF7D303AB05AC0563AD288DC6CC6E84119B226C32ADCC2398972B429AB8FA666FC02109DCC90CF326CECF81D7DDBC7BC01B6910C78D0F8F41971521F17C5794E9174E9F1B4C8EB7B7D5BCC981C1B2A0A0BF72CE7C3AA6DDA75EFAF654DA071BDE2A95BA4EB5B66EF2182C994167ED3FBFA2AF9ACC13B3C262509A92D97FDC343DF6B384F41C6AD32EB70FE1C7E28CCF0862F890D201DC5C98A548DC8267E9642643266E0F4C45BFE9E7B0427E0DBB6EB29A65E7BED09D5A937DE249B354215A0105339C8E9D57066F4D9004475C371B34900E153034A8D02BDEC177843D2CA98556D9BFE72EF9FC62F8B122123AFA471604B794CF96C7982B98888CFEE5C1036051FF49C6439D7701CA9880A3F65AD1906A5D4D476E165CB458B65477D509D01D35F10E3C9F3657AAFE700CB5EC706A9DA32545BDD5AAFBF56EDD8F5CB6D50333A1E1BD38868360D8893D6E5D4560996AAFC1B63A82CADEF92B6ACF63ABD705B8BF6A7D634CAD01CB5644A83992B440933C5FEFA2A213806F5FA10BCC79039510EA42B9D2ACFB4C47A69731C9FC15D25ABA9D58ACE08954F2B5FAD6B1AD56CE6ED49D4A13C9DACEBFBF9AAF194F68C543B7D1D6F8460334C410664505FC400A22385FDA1DBFC491860CC874F5672A9721F6DE58830325048B636948FFA042FC0076CA37B0E5A4F76A9E2AEDE3A188ED1E3A3DC9A59DA98162CB6C5C7ACEEECDB8F3541E984E783B2591E3DC97A5F9A9AB93841BDE2BEA8F392D630156FD5DDD37D5FF37CDE2EF413735CD8DBD674C94FD105985FBCDC8F234F7A0F31DBB9B04E0EDD45199AF5F0861CCC5EA2A981E6BCB48E239B409908C2C23E88663D1A808EBE84207FBDE979F84541E8FAE3A370FC2E1F7C82FD01D240AF2D6088F7F73E6FDABA14B58384C8E6214C6153420CD32E652A65EEA4E46ADB2E43773544A502574F3075F02989FC84224C1F3D0AE5BD62CCA6E912EFDD3FEE2A08857CC6F0017AA4B812F136CA47DDC511C2C3EFD902F771A9D41333AA9553F6AA5888783F32C39C92ADCC9F39B375E71E4A31B6B71463153ABD97AAB6527FC040A5524BEB6F2197A8F9A550D3F7C25AF1FC5C3A3FEC4AF76100CC55F571CE8718AFA138449068800BDC06C56385935A79684A784E2843016AF562818BFE1671BB534FD88D5D9279E6A25B81687CB193A1C719C950555035DFAF6AF39A40C6C6ACC27BAB8AC508CE37C77B612D70401B7FDFCA01C01641583A274A72612FAFC52B4216155D7B2B2125D74EBF953BC27D7B544DC49C1AFDBB158EC3CE2EE2E54685FE3EF17D4DE8729EC47994BF282F7F0660E2FAC4E44BE34BEA7F792CF30BA0366141396D74B453C700DCFC3771AADB13E61537747C7CA20E51EA3F4003FBD4DA0A6F777D366F141B192D83469810DB4EC1CD599C6B5B3F1927FF77C1BAF24E7936CB244EFADABF1E97ACD8A8D71021163CBE1837367C5ECF945D97AA50E0A9BFB7C5B36F42B35E7DEF277FB030DA515D89A427220950BF0ED381A04AAF203D87BBADE951D672ABBDE0FC9F5332D4FCD3E0E1C0F078C4CEE3D882652A1D1EA5FCE1A8A7C55CA55439564DD44812B2A67405932364E2A2F99C0633070EF18513B093E5FFB374EF147A77E1C3687AD523EB5D6BE62C89FE577762285456DB838133D518DFBEA9EA61FF89D1FA8F26D783CA370F418118E207FB87F6EAF60F7D25252CC42D1482CCF027A362713C6D384CC9F45F7DDD364DDF3F47BDBFC2062CD51695AF4BC9AE379CFA93843A86F9337A9428F286EC774D4257E83967A6CEB215E6F167BEAB2F3CA6A99AB38912863A365651670A31382918E39DDB388DB3EB7291B8FB38D5E27BB41B3403C3F37A69756291230A1809613B77B2B836CE59549EA4777C8687DF108313461A551EFC42AF64371115E30E18CEB4E06B1C0780DB0B0E117724F2C8814144B4C4A637856AFFF606911536CDCB677AB1EA2888CFECAAF9B22112B13C8CB87CA85B384C3A82EF0588D4DF882CE193ED2DBF61DEBC0F452CA8E26BB67009839C8F6F23B6E3631692DCD6CB63B52EC48F941DD2D2E0258B9C31A85989E39CBE2674F71134981D349F3D66FE1033E0ABFEFCDEA03E255C6C1BA6B39ED8D00A96782866F3CA39227374F95A280F0F0F2F13CCD4E25AC9E1B53AF623316C6E0243CCE3DEDB4F828FAF9AF9F4115052BA38EC94CE3486227651D40417EDD117AB86FB35ADD094D18568144E39D56041F35994DBD3D2AD2460F7A98D4FD11A4ABEAE52BEA948E820714DA2AF2E0B54A34342D6D65E485AA06920DB3483AA8384871DCC9F5284B8E9726A6B5AE9DF90BAC889C4C8A9A75E1D74ACA0AEB3DE17B0973706FDB0921FB269337A6F60B96BE1FAED7553325EBDA20F456D65C02314AD9B7B8BC80A54A2A7F96428CF4C2FF3182EAC5E2F879690C90A1D2BF56D12B6482CA90A72516AD935A439365DD1538745052FFE0DF9F526D184A26AA335A7430E07DC10CD072DA068300A105760546ACC789653D683E28EB525ED49DB7214AFA95E4E6616203A7E7593B706BE766865AEC23C62222B74671E505120C304C55D077B39B77570417FAB1BDFDFFCBB7E4B396FC491909251CE9B6831B3BE7C46C28A73A7E7C9754AD8CF99B8E45AC3A23A64F1239A6FEA219D22DEC46E612EEDAE28B9CF5E747D1521876F1767FB1EF22E51389B0121F25D2C1A917C33D19E964A80DB0DE064F1E1E1F06F1590973B3D23D3D16CB42F9E233E4CAAF3AA62FBCE422288DEACB7A4C97BE6313702E732CAFE76842782D2E8B1AC876F751A8C2BC1E246AB016962C63C0EB24037B13DB14507C22616C38C530E8EB01F7C2D86DCCF9307D6D0B4524717E8BD9B79D9A4EB61FDAF24530F257C011DF510B85953FAC2A11F9D3FE0F39C7ADC14E00A62E9287B2F2F66E7FD1086FDAC4958BE37D81CFF43DE89100B756C0ADF2E52F9A57A47C6FD489FC80B5ACAD9B66D2338CE8A1899AACCFB21D5A7A1358D06EC170A4A36E4C31053C7CDC91FD7E63D91B9BE720C4973387010C6665F0E598D97BE8A88F4C17A28CA907A1C4205BABB893E45E77A88419ED2DCF47AA1E77C86F44B493AFB3B12B642A0D86A4B0E908E4B9D6010C4D1671A79DE552B33A6B9A1BE103C30AA2C15E7E8B085C3467F19D5974853D6110C1C5B62C4C7C96AD9DDEDA78AA22AA1535EF231448F1826E7558EAD7E1A84580A9A7A6ACC6BA130C23E6E2EE6EBACB46DC68A38DAE77FF72681B74C1E2E2D876D243C3CB71AFF1C074B05415162EA51284C3D5370756B9FEB15B9B0C159842A909A30772CA613B2E1CD803984CCDDE887B7FBA75A7661ACB6E2BDDCD13A3BE6E9A1C9AACE3D3740EA5AF65DBA334744D570431B622D8862C959E7BE51D10E7AF9A23E9D703567D48EB8D8FCED3166603FC9D3E593E944B4755CF666A4B37A89234601A476AAC8A4126221F39A89C754CFD91A5A35D6357F5CB32A9698D8CE02975E4C9C3D2E574156600A0E9D84758AD3194D7F244FC211ED639588D6524A3A556EEB92CA5B87625B141047A18DD197F2D38C0271C17E1DAB5BBF2CDB100D1960F7EAB7A7181098F037019AD7D4DCEA57441EC75E3C7AF22D616D9AC0D80E700881D43CA2099174548914DD08371C7F9CF14C8282F23DC5F2E1541695FE2C08C67F18B664BA8028EDD9689AE62180F0BD89C3A322253FB699D50890422D559D4ED9F2341416A047820C69735C2D5B38BE98DA301DF97989E47A2ADDD78ACF51F4F41B8F8EA19B163D4633778DF1EE9CE0926BFB2B47033AD37F44E511A9C6443A4BFB895D429D210B8D5DC53AF8708105CB2D9350DECB3FC042044B5E666B960967D4960347E7168F5D442FAD4DE580833258D81C3464F9F1F35D22E19266BBF5B01730B1B6F41C2A015A7EF8FA90014C1891C8A47BA9BB1E636CA5203E9CCA2E1AE03F46CD9D3F8CB2539389B79354DBB219DC0D20F1B53C8C5F7DBAE5A7B6D942FEF8D2294DDE15DEBC5599A4FD2C73B2001E2C72B4EAA90DCD7CEC10B2334DF702EA02CCAACA63D2016BF0E88D91B177880B73FAB2C31B3B6B248EE5E617C58CF149EF3C4E0D6F2543F697A8CF4F3EDA70417682F6B19D2C667FAA5A75E17659B6E5F38A18BBB0F3993F94A2769DA6631C90ED73698810DA61001B11F94DC4134769A834B582C039F51F59DE7BC71977ABF7A2BEAD7190F25FA974545A49147B91B86AE39E7D1893D890625C764926B9C91495832AF9171AB9EE8821BD4FFC7C2ADAF1B1A0A6B89AE9B8AAADCEB902BDD5C9BF8C4E93A9D52F74FC5807AA5889E9292419D43746C724424C0FEB42F4C34CE00E971A3DC19E3D46F5490E593F32FF193B1D5A78559DD0C9C8E29190D85A359585C941793968BCFEE66E846DC9E38862240A4FE6DD697507F9506068876F536B388B486DC04515495801A80477FB6B276D2FF641A957FFA471F525F8A55325C1313F543A03DA2C695C43784815B8ED9C7A6A6E0C4E31C9B1320A58BF69822C2EDD595CC848D8874AA20CC226064ABF12760014CB57AD8F9322EDB91F8771D1A0A488905EEA1D727D366960459548B7084BD94E22D87C46FC1464475684E95C0B1DB2D6AFF3CF9E220D8B2DDEDF009BA28CFBED15FD5D6121D65D8D99B25506ED53E2A4BCD03CB4CE1999A829F1598ED00A8B2990FA0AF8F72F045AC1FC0E1C85890F5A3A8F60B02DCA1BD08842723FCE45DF58DDE4129F36BC92EF2428C4B5B73CA34F5ADCE0F1F15EC27BC7A93B77AFEE0D31EB689BB44D2FA575E73CCE5A6BBEBEC6065B38944AE86BAA3397A64D6BB471016B4864BE8F4EB3CC8EDC99EF10C70024CB30C7DB8F48DED1B2635DF7828C6443AAEE9B69901C6B6BDAD1DC55D1BD8CA94DCA6F23878B1FF915206B34C5489D34980D7E74659EFED84050830FE901791D3AA9D02FBF76B2CC0A29984CCA349A47D674BBFAFC3B1A0708A84B23CFE73353F35A2CC98EADD1F8D61B8F069BA6BC76F751A2A92A9A218CF031D5621EE3849D96B7D444189622B98D76DD138E884DED39A7B1344BD9E52FFB1B2CB36467B73AB7CF9986A9542C330CE4199ED1B9C5DA0EF812F65B2A3DD9F8BD39359CE10EC3CE4670EF39D3A8769923707A373D7BDAAC7A8EA03FBCAC03038DB5AFC60C5C261629F2417BCE1E700F2BCB164B845EF7260A409B8B3E18FA776023A94BC82C99E728EA4BEE47E46864BA95D9B167E3FD77F0E50D4C3BDBB488CA49EFECA10C92A0717F7E8F64890228E32E536B95A49B0A412973FEB5D505921CE1FA1F14D65DFBDEA67B4484A93FCF9BFDD945DE292955F76DC73B4EB939465E41B9ED77DD161A93A4E1D87CF8A8A30AAC88ED0764C7730DEA526EFEA41908782DF8C7D832EC7946D392DCA000D00FA84E0AAA29D92A1B836CF612B69961B3C795B3DE69FFFC94C6301EA18E34C48C034DAD7642D3AC73F5C9AEC3E3DDDECF59CD87F144802D3EE1CA6C77670F89CB7E3456723A3D3808CC668FE68FFC8BE9C5C8F47CEE1C27CE27249C6D44059314712FF39827D6D355E1C94D07F09DE25D7DCF39F1506A4F8D65901738D35AC4609E344855CFC44408EA7087A61C51D620F213812CF003354EAC06F0F8D1DD9FDB4DA16FC5428B20B2A8386F5F181895D860531E6D4F34E5AFEA07A7EBC431BD7382AA5905B7918C11F8AD233A711237AEEC456EAC8CB15DDB0C31D38098C9B7310C543F4DFB58264CBA1A5FB804D291C70482409DFA81014C9B096BAF5991D596A071BCD2087324984D5006B19278B09ECE8C2B907EC2BDD262C61C29E1E741145386CB7F6894E997123F983534543E76B22003DE1E11C86D1F28894F73C96EFC72B98F571F1B463A288D575437B83735EDB530B47BF4DC2690916C8F36FE3ACB807BDF81156744B1B92FF8185B7531CB244306CD0426957FEDB171B81CE01167D6D40F40A34593C48CEE4F6FEA1819C725BBDBD18BB07A7F59147181607D990E375519D3288B7ADC7B0F6C7847878740B5EF39BB429FD2E9EBB23A9886F27E2E0DBE715A5D508328B49F597CCD82C3AFDBD47FAEC2B9B1CFEAB004742DC16E05FCCECFC2472F3FDE7EEFB56D1F3E45E94A225C9BBA3ECB53DC364EEFF0080A26C2128367D3A5429E4AB83E511447A11A0BC52FCD1C76DD76D9E75470B6162260CE086A642D56426E570CD3188628AED7E249D247B1957CF3074490B08C9E313322EED81E9C485C13237B6925216CD8C008E23DF0CB1317C06A5B0563E3DAF2510A29565A8CAB49857A32561D28DD2148B176163632810013EC4079F703317888165FC85A9111059926DF1F00BE60B9E70B469AA963101C97A9CE3BB7298630A3B233A3CE4D75C0E36C7892669BACA4A77D598B3E3D5F935AAD3488EA0064AFD66916A2E6837033895554CD519443D9A1052F2F2BBA6ABC8E43350F3CC6D3E64F8E03CEC780190BA10B3A6D87C629398F6E9F5379490DDA5FEED902D55EDEA2E78F68CA179424C7F98547A2E933A1D1461A4FC81FB1C3C1553357CF6925776C665979CE60D721BD08D13D2A27F7E61876638DD03FDEF5B886705977FE6CF24FFE09243BFFF77BFE2685BD94B7E2193E0615163344074FFA649D495B026D0907A8264D0D19166F909DE6966E520FC7226AB49E92E48740F8C2DBEBC4DCEBCB71C3EF2FA60F4248F9116F228EAF18C8587B97D022396A432290CC3C17F85284874ABFC38A724CC57FAD59FA7703004A02EF5B321C96AB2DC2F24E06DC397D6D31E28DD93DCA28F9BF0C9296C6C0979BE2BCBA837E612FFC802671A13A251B9B2FE9A0A828DE065B189BB9CD2FAF71698595E64B16FE2132A5F0A319FB3880563FCAE6DE6BA4B22E5EFFEB063BFE6A8441FA60D03AD8EDECAE973D3840177B23DF38192B6C95E7FF8FE086BC5BE9FF61A46D99FF39D292B9D87854419261015EF5210D5CDCDFB0671E70B1181D665A0361AD7D3488524681FD1B4B37A09FAAAB4D11BE250B02BC8E66298BC4B32E64F445ECD41727261D50089BDDF0C4EE67D72E16E5C907D7621F010E55FEA4C44924744382934980BBFA38382FEE13BAEBE6CAECC194F1B82E4BED98BEC0058B8C3343AD9A694B3DF7D2CA8FA253BC46B4175AE35DCDA709F52FCA2AA3BD53D17BBF176B84DD11EF666E88423900D7AB0814B5B8266A957C5572AC1EB3F6E6A83FFD78E1EB30326689072F1AF374B617063A3C27035D827431018E979B025CD1439C4E563113848F1B40E30E28EF0EB519F1BBFF80976B4C6F30B373C5912FB7C371F93BC399D4E697937C5B88C75295A8C63AEC3B0AD20314A892BFE68F769E6CEB0B3E663C3FAB94B2FE40A5828A3DDE643A10F7CC02587C1506D608537A3FD97E0F1EA384B5BEB3F18EC8C22E10886ABD60C84FF99B248EA6BD68EE628F6FB1AEEE48EEE63B8E5BD112A68750328A3B8E6E9AC5A5F51358987C436C335B78EDF7EC6CB531C52399EB97F3AADCB23C83815ED54E09B965B6C4D2D5E6F710494B601192703A29BEF4076E3C25DC15C88BB5EE5E5B5A1B4C5CD5F830C81B3C106B24EEF64F32CD9531F3BD86136E5AB004D5C8159C9206252C9DC51E109615660C13F984A197AEEDD10E5E3742972A57BEA699A5A29A87718D989972120C52E961C80BD5AA9B4BFB9318C28F05D8606442FF877FD999CB3F70E8F3DE4A15CCB42E3BEED648B5999F683ED51E6BD924B91823E704413605793BE89363EFAE2D22105A311E6C1A81BF00777812FE290EF4D943477EC2267832537A2652B6CA24D9C03ADA0775246C40AFFDE78B9D9F9C3C29A1428D4D47653FED613C656C8172782DA55F734703FCA9CB7E884D7878D0B013ECBC85BC4A7229112704243A2E81116210E1BEF19F3D3B9DC76A39FB455B7E974FEDA87B59A2A7E75734B081A6B11214C125059389B8920E863F941134D544E8116FB99C9CE3BD4B0D430F0B4CD142F9AFA968E23D94696D337A9098CD9E48E0F67BF273E31DE458C400836CA571DD49B44BB781D50C04735A0B09FCAA3A69546FBB43C3B8865CDB90D1E1C42F2A6422505283276C97047C7047CEFA5C793B8AAD9173AB6AE49A99A5D54429E388A004C13F87E3586A1B89725E0FCCB78B33FCB31CF101E0D6665362D07B6BAD910002A6A035ED52C254F9EF6EB3FBE10619E092D199C740A60C04E5D9F581D578A0E4DE2492FFA213838ECBBE36263A6D1BB40243357526243638C87190BB252766C6C3A955C8191CDEF4E5BED143E64BA6BB3F692DF0E4E105A2E206F7BAAD8498C6E441303D3A9AE4D845BDD1B5D6BF9F36909C8B0D2ACFAF3C7DFD83152AD0329466DD13541A07DD142B83C1CDF783D6AD0D0635CCF9CC5F98F026BBC8B12A752BCCDEB1C49B5C559600961C150850B17BD662781750C3317F2A511B43AE3F0768F1A1C7E4BC4B48197B9675A5C76D96B2BB8864799215811B94424DC87AA146151EF2C858368D00DDF743DF80F8D5C0C708AB3915CB9E092C3547979B9FC4A91A756C0A54AEF780A8EFB08AA9B9985C4476712AF545CB320647BD1A2DDC5E0B99FDE45590462A6A19F6FE529934343CA9C6E3A93080910AF1D3513C435DFC1106B1D850E710E4C1F05AA0C634C2B56AC52BA88CE5E231FB0A08873D674FA783DE326AAC007108F4EB01E60D90901A35FD2738A206E2B1799F8B2E1F4740B5B20C132EF8DC3BB9FFF49FB00EDFB80FC9FA7579FA526A95F4CB37EF2626416BEADA9A4EE22E720455C2335C9FBFB067D4C00760CE4E26FDD2C7058058AB14681138E6AFDF967077E6E0FFBF1469F3140D6F4356AA64A3783BA52239C0873BB6CFD64D3923A4615ECF3159296049E51F1311E54ADAFB358C75383A5C9563B043013B3FACCDB6B7F4F47F2003DB5F54475223950DCB4F9089B37A298BD440BE7C55CC4B4BD02E92782AD96ACCDB8889CFE68F240E0A31272668B7F5C1D61800A3B4E7824A72FDE6626764D9B8CB77FA9B99F2976BB144BDA956AD91196F23F81B88F8F170003EA093B05AFEB20BC01F757B3549D6919987D2CF19B447DB301789EAB84DA2F869E96E7C06F6DE65BEA8D2C38995302BF991947903A2DF6D33FAADB6CEC0CD978C267F975DB10A17A4FD1123611DCB6A0ADB033A0FA476415B5B350ACBF53C669127AE9A13186615CB08B6FA15504C272FFF2F5D1C1E374B3C24A9AC84D762A39EDF7AA2CBE8A9D451E9E5488697F6C19CE6C609051F82BFFD02B203DD74FD9187E74693E04A042FC63943E750A566A8DDBD4F2CB8AD929F9DFC51CC6722F8E416FD4410F12D125DF3B41B74756999D0D287242CD3DE4BFDF6D52EA63E8FB745710FFDA2ADF9A4D1F94A7E2308C3870D21BFCFCE2AB398A58C39504E1A26EA190F09A9A1EC6D936C982F1535D0BF628D58BC4491097B7A50F8FCD800E2AE07D35C23641436BB41E7A00D0B9FE9978F627F040BC430D50E830288895F28E8A2E2E8FE14608F9F4407B1A89244FA337CDC5763082587C8410EBF3D0EA51692D1A49067DBFC8FB9B3D871261C719DC52C224B1CA646F7F334DF5B9A7B2DE2CF9E9B1EA756BA9F665026765D97478F935E35A6C7C0A01B1EEEC960959BFC9605D62B0D4BC12877C66B33CB39BA3D5A92638EF155CA9A2E20C3633A2CBDFA9991BC2098888BD7D26DB3F92C85A741173E619A2D1E348A37A3851521B95D317EDFB771BBD394CF80FADADB8642F621CB88E78D1EA3CA74DA586162B3BB70CEBFE3AAF5E0B89D347AD726F005491A1D9B53772BE42FAF5FECF1DFEE73B2F21895D23DFD683B8C483FDF1AF7CBA0FBDD3DD2A59395FEAD0ED249F27FC0B141C63F53298F854A091E6E4B5FD1B42B9F45BA3AFFD7C54461BAB6B5E578CC5C288635038EBC1E2819A24B14CCD8CB8DD7F95DE6BFB5D1E9AD34AF3CF9F3B941F1E1B468A06D1814453DF8ADCC76B1ABA3A4FC112F79FBF05CFD5827A518B1C3A98E162C6DF6427F7EFD0ED4A63DDCF9AF5A79F56CE52AC2A63110A1CE80E18E4F971258C935B57800805A69C69699A23620118040C68B8612B3FD7FF130FA322018E6451455F50925C692DCE4D059AE43ABDFB3A11B77376E609CED119456F33F43326FCDD62BAC087583CEE834DB98CF130DDB8470AA2659F7E9EC8178CB905901E9F5F3E893D8099E349D5D48EC2CE5004A26E4F101E7F69AB14ABE2FF91E998B04C6C2D1AF0FA11CC83FD9770B4FF98C33B5D926E13907D512C7F8788A9995D8301203B839701BB106586D0FCCA1EA47F2B02DC6FB09D375919A811CFDA722FA760512F79037D63C29D752F4F23C1E065D392C4D70D34E2876AE780B5832C9C8681E29EC3DF2DC116BB212BED58DC29EDA8F7FDB472DE3C336E27203D146497CD2A951E641115342835665AD59FFBD95800D8220AE1248E4C0B8F8EED4E653B4C0397A2634684D961093F1F4CFFFCEB85557C7504AB13458EC4E85504CF4B07F0EAE5F79AFDCC2AFB02CBA6F9EE35373589F1F631AF536A218602A1AC1FD3F4BD4CBB1A1B0227C032E683F7E0F1BDC447C2CAD540821917D365E3FCC151C20464A6B4CE9EF4ED1B2D62B3AE87C9B9949B76408539EC763B047C36C3FFEFA51E1D0564CCB53668FBAE16C70B2345B1DD1A3DEEEBB34A91A222EC80D648CA21BDA8FC14816415DEEBDBF2F891B595411513E2F798AC1FE9BB0C2A5789EBCC60F3754C00F025E00AA2309750449B4F7C23433EB02937BBF09B8C31FCB53472D70D5B0FE5AB4C4401EB61F5C036D5388A31A322C1D3855522E6FD9880975B83902D7A62BC195F565C1819D63CD991CE58D24C8A274268E74E826D6EAEB31781B937A27C561AC76E0A0DCD000287E260BD1C1C907D075E741238CC96FC818683BD01C0A83841B7BD0ECC8232166CFA4A149053CCCF4D2599D5D1B6444B10A66E6E19E2FB454BA8764B42988BB27DEC24F5B95697C432DC6BDC2ED2AC8C2559D428597D180102D5647E0F2736CB9250DB5BD124AA2B48D56B4ECEA9169AFF4CCABB7522930F4AD612675DACA7CDAB44A5836C6D1F3FB6676DF68595694121D1065C42754317A6A6AC702BFC2271C80A4B550CCD1D8B1BD53D24A74C7674584706EDFC1D47933587830DCCEBC05A453412F2F69F8B285D3C891E452844021C331584C3EFDE21E018E8F1CF24157BF0767BD3FC07A38E624544CD98BC8829297C503DF683ECDBA1A084301B5D3C00BE58C57016DB53E3497303DCA9184E8362EE867FE19982116A3215F32571805003DED7E0892025A4A9112CDC6BD451DBC498CA4D8A510382E7526DA8082FF8B2F8B543A259834A89A02F0CE41FD822AA60E8AEC5D4CCD3F30CD9FC384D334EEECA519128A1C4F2A19BD5D39573BAA67F61B7472FB59673A10A3DAE334EAFCC7F818CF3D7F10E95B40E79B5DA51FAB107E1182DEB489E38D9AA07AE79977660807B477D5D458D27D8B8DA4B0B9EB3522C8CE666E19256200E989FA85EB2932B91CBF147D88F84CA8374941AB7E05910D6A38686B8014DEB24DD05DB1E71"; | |
104 | + String faceB = "AF2E83D48C33566A63263BBC7605C936A71302786C65843E1715A8C9CBE5B36389759B3722B66D0192FC5EA77F37E638C6B3A1D8A0C33641635D1C22D882F88622494AF8ACF6B3363351E36E2C5D4EBFC1A8988D60751A1EC4B7958FD42F5BE9904B946F90AC590B5EFF36EFB0FD0E9B51CA2761D3F9035F46598E8994A043AE0E731F4668CDAEBEA66E1AE3185A7BAEBA4F4A1FCF98DF5F9F2A10BB8B86646F7E2F842B06C250052188455CA6E46A44446BC7DA66EEDFD6FBCED6C4718F75DF411A2EC6AE588081A6C83A362969C00233E432DFB5375BCF0274560B51616F27A2FEF5A8DF8B82A42EC602C73E4EA4C54127C0EA406B76D23CF5FC5FA98F2F0BAA6D0C8551592959128E6B8E61CFE57E90C34D342A3085766FB8BC87BCD926207596D34F7180A1310DFF8A7FFA41381D5B5C1F01B0B1A13610B94A12EA42F64FCE22EC706203FFA5763DB2F749CE87FC9E00D828A6780D98E6B71F30FE99B6F18EB7074B3CD8AB84264760493774642E7147573E63D2BD569C3A50C8F23307C8BBEB529FB1D527788EFE65D31FF1A1301B5F08B1A38BBC00B373732405069852D10DE531EC5B0F0E090E1D09124A92C1FC9050BF9BC4C207B6CFDFE16DA191CAA913865582A17C590D04EC71549E1CCDFE7A8DF1849B4A38EB256EF59FCA094515EA55DFEEE1B7B799590D43422B73A9898F2AB9002B138E091F2D002CE620712F618A0653448A4A37C2277A82799BF4CEAEC6DDC701F874225FE636AD95BEEFC24A6FD1F52997AEC966B732ABD60A0B03551D1512E3FB86C600E3F743FC481E07B38263AEC91FE2E8F666C6BB3FCD1DC00822DE49AECED9536A0787957F5D473BE79348FFC3DBF2019244D2050041F09E3E41BD123A289F70CD5515A27B6FBB462C3B77F09FC9EF36FD1B4529CE6283CD561922CC7AB99631C7B6FC1BAF20623905174CBE9ECD32401AC4615A08F3200FF07BBB1564BF0F5CBCA4AD0ACB1E9BA5F5E59107A35868727D4DC78F10E4ECF6853BA5E332E5A11BFB08F06D242A2EFA383C0D4D75B42CC018F4C60CC35F350437E5A4D9BCCFE8D7ACE6139E92F9AABBA818F8059ECA37F75BAECEC04CF7DB2B6844123720B696C97EC8552941F746D91B831BC16D01F7C2782514C938655DA90E37175BD635F8134B77BDB7FA14A0D5EF5E44F9B7838F068F4330C1826B83B3F9EFDB7AE8FEEA3F9221C1EB69F6047B856EC40E40CA065BD468CE11A85ADF3C3111AE05E4D90245348E47A15FD11BF9FE6CB8ADEB373A4D036FAA7532DFA760E330CA7F939307BD8C6274BFD192F7BADD584B732BC0A97E85D94477269FC43B1088BA42AC18CEBDD5FFDB9EF80D40C490486DA83125337D27F5110B3857E671A67BA2028DE7A50CEFDE7C70CD14BB2E7D6D41D7E24CCAB4C043486D5505FD7404F6956C42BDE105B41B271486C8541B39134BD2D861B517743E64524ECD0EF4CD06C04376A8C0609767901EE6A99B8FEE7A5769BB19C0E1251EBB6BA7036214D73F1E93BE7F9C0CBFF14F7F5DB4844966BCA0F15205D8F71752D311CFFEE23726C001AB1ADAD29857897059B5CD5E3378BD125BA6E2FF3875EFB0BE7CA108862764CA74CB0CC58E024C14D86D38BFB1C75642425413A7A98FB6079EFD7311931E3116C69968D798A4023888516B42927A5B73501B187F88831F53675CE70D21DF52C044220B90E41C42EE306E6C6F6C0D3CD40C9ADDE7D82F579CC4539FD9DCF4BC19630577ACDF7F041F058E7500AE0B6BDCDC6BA5B42BBEA46A9F5C510F30F86E0B2B708DA663FE46EDD1B4AFCE58FEDC09D80694B7CE3C88701E4FB0FA449EF1562968FF994BABC497A807C82F397F26093967AAC06C1A7E5CEE17404C8BB9EFC4DE056602661FA678062F171D454B0663A931F7516E41143EB165D2B1B0316F24C16C3D9D5D3DA6D9C798F9CFF37C8E0B3823767BA831C6C52F9F458FBA2B301990D33144F85457E9AE17D6C292FDA3A82AE1A26456B610E5DC6667B287C7979B771757C92CC0A23CD93E118029F902AACA83D065A67B38AA63133C30DAC872ACBD54DF0099DEB45B623715E2644B4EDEF83FF57A2A17CFF85A738AF8C2FEED48EDDE458932199ECA5272AD8FF9FD03131BABE2031A9D58CB55FBA212019CC9F97A2F9159389755BA939E530E3564360D667BCCF4527098DF5DD27F9474D9E6B07336DE8D4BEBA185457B8C13894282F02123DCA5F9C87210D7D179902B7FE2B252A9E0F19579FE68653BE1CFDDF62BE70C6147CB490F162ACA6F6F0A8719CFC2574CF5C8CBDA827B852A926B9A1C60AA9C8947E3B1B6AE21D507A049C06194017331720A7B9505945818C3ADC899558EAB9F8F813C070E51206DB8A8223C95DAC46E6CAB289B0890DBBFC42E1192DDFDC05FFB4F58AAF73BEEEC1827E8C266CB0236D9D3019B83565C5F64B2DE88E8658845D2C32B59505410822EE329D4F6066F816D7F2B489D8A73649E2E357C1EC327E901BB3F749B3023365C000033B013CEF09560166AC4F13204F37FE08115013B6759ABA26A613DDF1BDABFF6B642BA076926360C4D2E2C0FB1F11CFC6F2E8886E85367879801D2F65604E87EC48D9CEC963FC507DDA7FB5684A68554414ADABAA67501FE662A461B619313C343F708DFF3AC5B64C9F081518554A723E0C6EC6D9FF981110640457B11F525D747A65C56D472D835FBFCB6117F426B59D4411D02BB7BDA83DAA1A06C6245F9A5E4597CDB70B8FFDE7B568108CF6316DDA4C5C503EFDA6BD9C808D51E7CF33D1B4D6DD39C9721C4E92C3A705BF28D3617A795FE7056CDCAEACA4473FC7C6713AB442E719934082ABA2CD55F7BE63462E7D565D7C5292227E257157FA8662ECEE6A4FB856F73C1294AB79B386250277CF2A4C1B77A723E4A5087C4B564154681495C66ABF8F24152797B91D66F76EB233C130FA2E9B5AE136075FCDA4B43014537A48140797AA536C521BC17412BFBD1584BD941B7A76990BE39B2CA9CFD0FAD410786025C5098936F181B3839660715D98861F59037F1A9DFA81289EF8A1B5A7A0DDBB1D443F0672FD8278AEF044B2F9063EDF5E8BAEE5DCCA309F63FEE8CA0F86B88A3475B0BFDAAD2022B79506A0667381F73EF37B074450B6E450EE1C96647A04F5AC9C7CBC57B638B7863662AFE82367195142CCD659DF2FDC906963575E84A993C5992EDB47819C0EB316AE5759D646C5C880ACDE46C8CD71DBABAD1183D9C33E53CC3E38E48A4A5DD564331E9B86C84CBB0F23C2EAEBD6B7CCF98B9198A236330BF5DAD4CCE79040011A278E856AB2648D6FF4D7965B534A85505A31ABBD352D8E594C8FDBB2B03015A86D24397B9B4CCAC3D0826B2C2912F950B37B560DA01F96914B9EE48D94110708487C55B039AAE6711E4B7CC5CC3427666CE4F945CB735614C51556F5BDBBCF6F96BF367538DDF8C1C3FE9C807E8651FC1D3243C07ECC72A40FCE2B6B39EF0E934C16610057F49778FCC028822FF9E42FD38C5E83800545550167CCF38552E38F71CF1D3036E785584032594EECA1FF81BC22C0FA32618406D0CDB1CA7F17121B719628A1666BCF27E317A3957F1E4180BADB649446C72228024AFDBF9AAD909A5D490361F03C6159C558724B4FDE3B092C4BE4601213C037E3AB5A1B145C16F16E6CA238D2DFA3AFC7C10EE18B9599118279CFB54086F77A8096BEFDD586DEB773A206983AB11344DF4BF24A7C7F403EA263656B184DA530F697AD8CFA057C3A8AA1BBFC5407B4D8114FD292BF96095170F63ABE01710D0EBA30C502C95842698D9ED1A31A6D98881A75C3C03FECB1367BC76F08982E96635BC4C5D7601BA0C98A8622E282E3F9CBF76AB800EED4258B63D734A263FA0060071BAD3C9CAF8B26014A6DB76403534CF6689D7094FF8662136FD66AEB6A40567D6460CF487D573E3191A3C4C734B343BC9CCADF59BDCE78D579E001A811ABF6660FD286239BB02B3A7D304B318D02E24083A7118669741FBD270B2DABBC00F5EBD3ADBDE36F0ED10F7ACC94F75741D7D3B6B16E5A60093DF57B65F6DB95EB03B0A9BFF8525D4E8EE8CF3209CBFB40865A342897302702E2FFF9709EF2C3B8DFFC345CA41CF7861878BACB7A03096B9E079C0DAEF8D00456B5B04562D31F892FE0D0B498B75631DE4DB80BC6E1A3AB779D86B44773ECA6D6A92707B17F321178F606132417778F57F719B3F8FCF6F52DB8BE30E5F5D695DA41DBCDF7D2926EE4DE6DA9D8E15C52CA06F14078C0519BDBC29492CD0EFB01955F8ED00DF260C7E8A8FD0D16FF11C63FD5308AA8688493CF617D5A71BF951684D9B10C0F6E6636C6C9A5EDEB569EA7CE9C8A79DEA4476D1B9F50BF7989E9790C0D32A7BE5B3A132986A5F7C4E216326A7581EB6A4BF7CB9A8DFA6E82F5C7FE77F1E81AA1D664B4AE031E9CD42A09CA5E64EAB046EBFACFA3D20F2B433D2A226EAB43FBCE48AF9651DCA088DCF2528501A60A68A273BE01052F21D63EEE0614B4B8BBC2DA8EF063559DFF2F1C1C345386CBD4D225BB62AC05B61AC3DD4EDDBCC07DD2CC6ED6D323DE15EA1845ACA4DEDAB5D3B2945092F8AC6012F1AC94FEAE352D8795021812C89325B65A2A59489B58C91E7575A6A17671746170F35F7DD16D25AEB051DBEEA6EF44ADD6695B9D070629F8129347FEBE8DCAB8D03A7226798754E173266E6BA2EC2985F4DFAD768FFC60A66F84CF2DBD50E41C809067543199B93B77D1CE1D9BF2FC04582E6E3FE872ACD8AC82E6E2DC6FBEED0CB700F1EE58EBE94B92DE822F5110AE93E38E114D1C9CECDC6B122E87154D1BE64F767DCC66A938720103F6B6F0C98F4C12A37972D892C00135B7C0A23DC1B35583AE4F05255A062BBB5FA28DBE95BC1DAFB3CBAD7C9D2A480C9288FE96761B4F5F77EC536F17632A2E1772CA52C40DA616C750872EE283AD8971D21E83C569643D3E4D51B5E3AB628B56125BB26088CF7002FC4309512F23765A9C63156714EBBB4EBE4D4620D9AF55FFC4A6FC4D8474FC02D4AEA6E4CAA492E129ECB180AA6368CF5DA7E2AA1B88513B4DD8208FFEEFABA07E1C2C13C6B20ED4A2D9B83B984B73B80AD948D87C3F19282CF5CFEF7AC29BA157696C050ACD05283BB87A7229D18A2718000E575E48266E14DF0F1B74C4B1C1B6B7B5790EF7A02E3EA2A602383AED48A0ACFCC94D1D7116F82DE8CA9A10C02826697682D90E05EA44D6A4552ED01BA3579BDF35CB6B578D00A3DDF9B9D1A2EDAA8A12C4101ABAEE224F5F82DFCE57B2AFCD76F00F2ACD625FCF4C15E98ECDA04EA4416813D130262B341B08196D1BA74BD535F739A94D4872960815A2AF505B6EE26B625D1C1F62F9659F4BBD7991A079DF405B2D7E9C208501588FEBCBA5CA88EE0F9D764FDAF5008C449A7C5350C76500E4ED3DD88B57BF88DED5630A7E071EA9D98B48B5EF96B9656E3DE42AAE6F40275E24884D60B06CD3529A1D89BE55DFD46EF97FE38C7A102954A3A675DD56FBD5360E7282DC570F63CEE24A74E7F9663309CBBE85390EEA31A7246569389DA1F1ED4E66BAE0D4153A7DDCA99A493B6BBE43CE443163CE515BDAE4FADC02EA5766B891CAD5EA76DE385A364C8AB2C0900907954C979543CED4B1A57636EBA96EA8F8C25B70098834B79E054DDCFEA70C12DC47D3E36F358C7308A13EFC44505857A0213C61615083D7455BDAB239C416196FD49F064C700B54CEE8A956C27EBEC06BD571311887D5C7D15DC15A1D5E6807C37F2F49110A960D9B982F67D199DDF20A79CEC527A593ADAFAC5410557EC1B319A5A8969556DD6F6C50FBFEC4225AF9ED94602102C316765929E7272E23F5CBA6219008CBB3FBB9BC6F3B69ED5B3CBC45205B7CB762FB9830059B6886D9AD52BF570E8CF18B2EB2768ABFA52EE52C38E87F08F921E6CFFCC65B63076F449A57D9EA3C900EEA3790984927F5CCF3E7FC7A319BE2B3C40E21B9EFE6E4B20A6000FE7A8F936F0DB055D7814C8B32015C04683D34E6FA7F2FD21E6F87C2A0BB4876AB472E32D0F9CE785A81B2357733A95740947BF7B3431701B5E220D8E1AB64B94793061AB9275E3B309B6E7A67BB0AEE7F00A6D7F79036F8042D5C5492F6E1CFBF72C8CAF933B5B9EDF0B3434E8E838B276AA6E5822DB8507FFA8E3E896286E0600A4FD3CD3860EA7815043518F09A051401EF2A582E1C0809F061AF6F0133603857B5AFDF56C3E8A8A5DB34C4D12D5C0D0782E041EA9F4B6902C4BF44EAD8C35D95084E2C0BEA726626F1353F857C953469514CC7162EEC4D92556F8A9955A8F477BB1D46E30482C94D24E392EF25FB6CFA48CA9DE07651CD9CD524E105BA9C2BDAE55E70F1E8139FF90D19959E6D66A3BE6D7BE2470843BCB44AE3FF49A28DA4CD6F47F31FD36A18DB4004ABB11A45594F5023E51D080528CD305E70D74B932991A6AD9E5CAACFFF9FFA38E095CE04E172531D179190799532BDF36431E88BF01F6ADE6B164FC92A6271C403DF8DE25FAAB79774B039835BABB2FD401E35803E3E2D38151588717BDBF8E7C7B6B5904FAEFBA5ABC57BD6CB0D11D3DC9751C8C7AB33EA6FCDA63F83CA737986AD1D0E6EF04D6573CD4B72B875B62242B6E526D02054CBA22D60036D7AF44A3A7074A58DE82AE5EC08DFDF916B5FB0C2A17893F76CEA04EB7AE5AE05CBDEF2AA0A4504F4C2FCB4D767C5794A9F77455F1BC06854DE3D1077F6CA34DFD28FB3374656427D1C391BDF1DD87F050F3458FCDF4578EF564EC2A5E5299E5DF802D6295244B20BC53D48DB8564D40D9F58408269B805175B9211996C9148C4B5EB5C18FDED44985978C77463CBB89AAC7B7DD4962A2965DF542869303C083F7B75F970C76846C40486E0F4F53E03E6D0B6F1CFA9A8022203016D4C313AC20C65FBBBDD5976A5B319A9B7739E544762A15E2E625FD26635C773CD44F7A9908E353DA2BB4967109AF93FC252EA61B5D4975FC30868B0DF7FB43949FAFA5B024476086E61ADC67D6C631EF19C0545EA451DC4EC8F696D44C146F17CEC9DC9597734D7846980574347ACCC3EF1E5926AB2AEF065FE84A7E3262A3F622A8E364B3550EA7E5707AC271B4A2D725DA4C456839E7A98A65CD37E6EBAA969CDAE1FFBC78D2293A177096A2E0C251531AED3722B68349232ABB767B20787A92E23A1264C34FCACD485CB45BBB86D14A50A9D90DE2F20D343B2AD6B0C9B70AE7047B2B644178EFF15C7C0B2463DFADB8BDCABBF47B46888A1716DDF95941FB9AC8C9095E1A09115AA86F9F0A9539788BECD17C9C23F2A04CABB4BE9E212ACFA9A62B03D844C107307B91073A1848B71A1068AB4A2A0E1105BAD73323CC6402E12B1BD1E40BAD134B99EDC262CDB74237389BB7296D5192495C6CABF36D2F3F010F74CB14EF17A46339A6CD60DA35E9E194FECCA0647DE4B8E008DA7B6811421A0ABDED484A617C0CFCFC98FC8D68C614310F3C57A731AE9A0AFB8A610A577B885B9932B6A8F639188B650965625D6F49B192E8E784B13BDAF20ED19F8A6E0ECF231A380F3EDD6F0D40D20E590CD706AD16D604E57A581C34829978788C8A84D4C653ABAD8210131E980BDEE1E4595D266A67C5D8D1DBD5649151B4427D547076A7CFF0750F1EC8DA3C5CEEFAE83476A83D1F770F6E883A885B7B2AF9A16286CFD5BDCC14CF2E790C91D002E55ACBBE6864B5DEFEB290125F351E338D6EFD8FA5AEA72941B9873B88AC03160C7AD403A134919085CE21AEB0C5D77194A1BCDE0A3BA724A756FAE5582A25750F5E29ACA829F97E32C5B7712442B64AD6C5618EF9B65786BE29DC5A231C32D231184A73EFD27D24BA85C7D6D399AA3D35D4C8CF7B4890B0A31BA1B9700D07C10B576F46FF2F921E0377D52617A3E6BF9E32C314D12AEB233B56CBC7AD21993134BE2158C040C7C248E183944002C08EED69C74FDDB6D2EF2B4C50A280E8894EF6A8C0E1779A7ADF246BB24E7500185DB8CFCA938714D7DF225DA0932B527E768D0DC706B6907470876EA0BD8AAB8C384EA9DD4615AEA0A609E20404D04BEC71F90F919DFF42F2FA3833565108AB3DAEF1AB21A969ED9511D7BC37061B157E032F113C9775D676E7952C9B053E80E2F0E430C4B26664F2A0C5E86E166B5005634DD61A46F278C8C21E210A41CE8C41CFA271242EEA6684EF74592FD7B3A0589A036156E2807235D58A6DD43994E3809D590E319BEE8962C5061384DFE404D248EBA08F464238955732EBC34A22E9D94DE046978314791D19AA64C89B61EA81F24B81063F30946C2B92CFF2FE9968D9DD956C1F9D854FC59080356D06ACD4E7D79288D3A824E306933E16D73E46A9AF3D606DA941BE0A330AC99516DEE1C04EE1FDC258A689C804FEF8A06DA40871BAC3D6D8A348C6FE37B9582BBA0194ACFD251D3CDE77ADFD10AAB8AF771A55C1FD16464F48334873DEDE254F2CB1C71B89842F5C22EE9043189A58E8A51461F9ED10B9567D2CAE6F115362D07CE5BAAC42F923D3DB3F82F49497C5581736562943C6476F5FC23BB76E0F7828A4A04DA08FDF042D2C4BCACD922ED5A6BF8C572A90E548ADDE5543B89151BF0DFD9BC15AB333F172A1F824F67E9F342C572D1F7F7E77333C41E33F0E19890A7246351D5962FD62CF1850DB961988DA01B388E1DBADB2680E2BF730C4A494C6DA0B67FE1F0B100B776650C37F4CDC96E085F1C868160D0563DFA9B94E3E903726F050C2CB97B53E96BB1AC53F65444314541EFEEF2C2008B910D8E6BB99FA84F53AE95C75A56642133B371226B1BDAF5D9F5D95CA839441C117CF156B1723A52D62541415F2B348D643AD5E98CDAC1250CB741CE03E26B950488089ACAB0C3B742473C701434FC05CB2EBFDE4A89B923ACC2E31DD26A6D3716EBEDBE7F1CBC7BEB43555E7323109A7C9BA91531BA1CC72DD92C29C16435F1561DFA63A726308946B415807420DBB3C2C691EE45948710A8165671468B349F46ED04158DD3771B0D77452640F995165D48CC756ED0663132F64EE0D88395FB11FB55EF3176D4A67813810FAC3D146CBC910891DFB43E0D1620775CEA8CA0564A7B042F9D397E81708BFCE9FD067318C822C25DA7DA75D46B4C33BC028D83FF55458005475D54AC6217C6C145308142FE69D835AB321DD782921F82A762AC05CD3ECDFAF8CC1FCC3BBED5DA27395BACD7FD1704E9AE2C7B92AA4D3C3913E0BED997C7B635BFA95F124C90E3D313083D64F6F7A69215A61EC8451B184F8F42DA754E269D38A61586365B45CE15EDEAEC5CB039A7899537EFBEE4340CA24C5A97E2291735E196CE0EBD30B6881C77A3143DD383ABD0D525102D5874C1C14C10AEFA1C73D8C834B0065A5B279731A98424CC5714D5315DEC3DC8C8F85CD5B9E7285CA558F4C8FA172FAAF28AC1EAB5D7A2BAB85AEE48EE22C4C851E9D9444EEC7B3E32E201E554103E74998C86E715267DC365303CE0F604D79D4587F65FA8DACAB09A219C06CAF3839F71A89665BF866FC11C058C65D06D2B8A51A9EF065BA9E0CE8B25005EC63DCF5730A6BF76EDE06EEC20CE572894911FAE161E21FF0E394EB103069836636B84820AE5562AF336460D6C59277D8FD903DA36DAE513D9CD64CEC4A48459C4442F72DAE312678F3AF0DCBF39187A11D564B4D6D4E5A04E644B72AFFC1CA38AFBA56644FC3000C930FE4CDE02E5F403A86A9652977DEC5BD032266A6095D623D834E1F3117B6A17A72BED6B56F0E1466896700E1E5ADE22BC76119595A75E4CFFFD2984FD662D06695BB1CB933F70E58B0FF79C7ECC06E3427E4E2D13885C1ECBCEE2759C867F6337DFCADD4A07E3BBB4284893255F545A40D874363F761BD77CFAD5181F5D770D563BE6F77FE7070A48EBFD47E0EC461B7A47E447DEC55AD5AACB095F95EEF54AC5A2328D781AB1F350C278B8D5ED07DD2BFB114BBDD3DD9C50A93BEDC6317F98CCB147D7C0BE8F6079C7B8168703CE0DA1D6954C0737FB290712C69B111FCAC39CDF7A4689A2ED0CF8B3D0458124C2D7A5FF3A3D5A8CBC593595AF00465692ECD36543C13593DC0888892839228EA24918835C141D943E14C8D27A59731DA7BC6B3AAE87879A71EEFA5E42CD32E66B49A4BAD4ED719B36E1471467029139AE3FA486A1B46B7A9880DBC6EDE4A67A5CBB1E14F90B0E46BBF2D6E5A5E6E9E6BECDCE451684B57D9D387E9D696FCE5E58016B102B376F83DCA4030C712749F9C7DFF8A7D08F8878DDB044C453CFE05A91DE060BD40F539B2F999222F9D69E9E8E24FC231596B66E5E7A33632FBBE2A200A0137B6441B5E6E74067F847B2FF4E274869043AD09A4C5FE47F89A8F0F36B86D08F18D6136C7749D226557E4A2FA95C003816019BC758FA324C3167257F78678B2CA6FFFC14522AE0923DA5E2E4BE7B070F348A15BBFC16D439C4CB34C5F8F27B07F2CA82A0B693F88C42FD3F5F4917325ACB7FC3F3E28DDAC3CD0B91EADCDB660B6EF67019CBCC52635CB8E46991B3409B59FD58B8DB368FA8F93D27601C93CE26F8F2079086BF960EA92CFDD477121178A0BC93AF6E76B5BD275CDC16CF96073C35A49DE49E9157BB661E066788552654A7F45A829792E482CE733E2534F72F87412E41AA140F1231EDD25271C6A2F79498F4172CC6C410433AFE2EA7D22F05E373D87FED36A7B19752D27105290701C20B9B80E0F2F306EA56F03394D67AFC4AA8A3A8B45F94D2F6579286AB4A515C50CCC3EA287712DAA11425C5D2EFE56CE8597A5E31498ACCE96980A460F9A98917FD08A20BD172442A184BE4BFDDB92404A8D6DCF6DB6C95742E32DA516CB697EB3E1F65B3D25735B7E6739C912136AE36A831A2D9CC6F68A96C250ABBDC3F5668DFA42C17BEA7D25584532B0FA3CB4ACDF029CC24B3342DC1DA1AF53475A34B52DA4A6CD7DB5659B12C14F88F86B3728102F55E53A9D54AED723A5D794EDF6C85438F617B2CFF0E30A4FFCA0673784A2D435E5F47FF74C454435D86336D68F612E742E3568BFFB115F51B85202B0D508832EBB7BC1929B14C341D97E420333C9306CE74C86C91C11A79111D69A8E493F485211278300FC703A1C29FAC7AF5C0351D59AD7C2C6CFCDC492FAF80DDD39952B7D15BA252EBC8B0F0E6406F7E5CF84B8DF5D4B004BBAA8047D7CDAA353EE17777873B00F298EE5E62E2BCDA60CCD79B6947BB824C1E8CD1E5BD8FB6F10A9C2F0A89103DE0789AFC2E7EA3005BEAB28BBF4A0A5BB8F582047EEC4699D2DBAB8E0F6725F59F9A7DB3399B452EBEF746E0AFC6B11F51458B1A4FCC3FFC694A831336169A6EA7370051C02BA8B2169D6F50343BFF0D0FE0DB7E38AC8AF2BD0A1B065878BCB76CDF4DCF62076D7F8B4DDA6AC1AD1D9B0DEDCE0F684A4CE23DB050737B88C2A018BDF2EC746778FB3296CE368CBDF237EFAD23EE602131819DEB47D6E9626F8A6813AF77BC79337B156EE718F774237578B51E3F7E2FDD249F8C43FDC995E632747294B38FD697E972E11C87D77653D487F2A7E3976A1CDBDB4074789F5DA89B7EC14E988F665CEB63AA997FAE8599629692E4BE0343283990908CCC213D35698B41ACDB19BDD0F815A899C98D9CBDE47A78B84A0A4E50271DA50B9D9E28241E95E14DF79F3B2B55B895951EA77D49F02A2886767BB13F9AE33CF2445952A229B26C3F64E06D0EAE219117D96C02879B14F8F186EF15823670F8F4626FC20AAD48C1D72447285647FFBF47FE3BE8F82533F3EC6D51D4796387796E7034349B04B828DB0EFC275C4887BD292C0FAD2B3F2936BE14A4F7D946F444FB6D5CEBB2FD59A4711CF450CA746D8C7A2BE78C9C33A5312D8034EFC83DF5A4EA42DD5C8FE75A785083171C7B700E017D024659CAF7CC2A6730660DB568F33C727C148500A115A521EA4026B6E9CC7994AA82F38194BE34103F7211E09B5896CB071399302450288F006CE95C6746C3444A1D50C78850CE318011E42C3D31CF4E6B7CB6FC64000499221A84CC4AFBBF79DD234B08745D5385D259DFAB1CB45CF04444A9B726D61E19423CA14DF44828EB45E9E292B289C9187B566876D488205BA1B2D60633884134BE0F52CF3FD9C1EEA110617E055566B4A8024074042BA486B24D9F1D79D773414F3E2E97945B505B985000C840DF64739E156FA7888D61D2A1416F6D3850933569F241CA06BBF0E0917BEABC02FBEC1A10E660B71F4D79EFCE8D837E33CB8D64882E6BC364D78B3D7D80E9032DBA7D5C93322669E2BD8C6967FFACF596F70E9A2597B3D5B8388FD40059966303F2FC0A5D84C4490C06CCA4A1E6A0E70DB8071BC12D5BC596EA43A9E35D0B6500DE346FEEDC7DEB8404C1D91D02A6C6245CA31F838BC888EB2C2D1BD05D57562D03EB65294BC1E314908845EFDA0134AB055478C3BD577F995AFBF53B4B5DD5A7E5483FCF6F3711503758F96FC50D0E07FC6204302A30F49C4EC92318C5EB30F6BA123505F266F3DF8EB49667F034B19A8A1F86BADE13CECD8FD4AED533FFAF09EB4A66ED4617D81433B2D00E9C52667220BA8B730882D5D9A97FC95259CF75BD0B46329AC8133F4B1AE4B74BC50B15AE7121DE1B6A492BEBE43FCF6EBA944C9CE24707DF90B9E20954D0E1E4582B1A6E6314A3ADF2F48EE6E3698FAFD9E4B801F2EA5AD62D955540F72385DD481206892BFCCB8BE2689E56AB9E976D8503C438D4EE97B0D5B271AFBB01D3FE0FD07C632666F6B0587A454FFB28F1D6CE791E2F55D6177918F2BBD96C22EF23388A2DE62D23684173C9DDC1FEB896804A1E5C3F4DD7986C2703FC25F6B6C0894B25AC8B9D942CC0918DA064B994A7F838A4A47C3126DD3FF88CDC3FED4E08F026B09824368852ADDBDDA6D8B52607C80513E12CEBDA83AC5D59B54C3332AA86194CA62E22578094E2D0A5C105167B7A8B55C259D8E5DFCBEFAC1C6523D955551A7D603694C78F325663EDD07AC405E40CB794ED2D5CA3B75BBBA3A436DF90E826CEB611BA3B995ED1CF7705DDB843B03F450BEAD114891B96BF92109B737436AFA2FAB97C67EB58A88DFC60F34F8D4878E6CC1202A2FE2A68FF6C02B5006BE589270B146A4F7F653F85FA07E24467C3D416BF2D83611338B0E1CE9582A30CB26DFF17F0BDF27434D89100953CC66EE2DAF4523A798F11465205D2BC65567DF02FD7DC884D741C2284E3FAE05B4D85F21C4BB55429D965399E5C114243C77DBCCA98CABB6598878639C6B1E1667FA5E53B30FCDC363E5A8A6EC0D557F6CFF095D2F37E96737D491FF158FC6917B56F8CE6D0B8531FC07300BF3878C4DECA1325D9998EC230836CDB2E3827071AA34A696C33C801BD5AF54A2A18F56E5424E933C54E58081885C423EB71742EC8A8357B9C665E826DBA20C3B89067572BA2D303A135A4775CB3DEFB91FA6A4E7A21660F5182C65CE419E8715F5CC9CFE62BE166FE6E6E2A9C53D6FC8C60A64E1A641F89B1D36C29AE5700576F38749FAA6B24B01F0BA2B755FF482FC9CD0E58E03E7A6DDF8B5DDBBA07B13C2327BC4C91EBC55D5C6F80D0AB31A3F976DAA69DFB1F94AD906FDC6272DFFFD9598A81B8C244D3EDDE6FCF2954D679CF10EBDA69505FEDC5D356CAFD0ABD5F33D4EDD61F5743483D947C82D7CCE173D84DBD0AD05AA5FB2CAC38042AC2DDA9D656B12B8BE27C5F9B9CC240309A3F46281E7277C65CE851FB6F49EF1E0269E000E2EB20FF73532F15C8C4971E181E49776C540DA2D747F35F58DB90CC11E43D1B0AE908D6842D51297873FC67F94FE2D71EA183D1C193492DCE619D27093C1568F144632B10C57B9E50A4D742D8B61D1511BBC9ADD7E70BF20F6040620EE988163432BC76345061DFAFB82954E56E34D970619AE05D3961ACA3D8FA45BD2DB21014B9E28194B664C38B24D7A94D2950507ED4B483BC34384C8EA2393BD59473DA59F2F7BC3A5868AE456E9DAD05D5A22B1FD7D4DF9DAE3D76ACA7BAD2042E5758B7132B06057EAB1F0F821558235B1FBB793342632C8AAB5557318FDA235F59ED4FB75EC355C9CCD260A8233BE6D246F77FBCDFB7E593057B3BA91C69728B7E9AE99ADF27BE56E97956113F703A4B66D038BD3D8ADED146BF8739326EE28605AE27DE5ADEB6C5B3BB21C17B33EBF911D987ACDD64D1942124E223045176A64334DBFF5CB81C71270279FBEB10758E960A9BEFA00720415D3BDC7680C16C460C9344208A1B013B932934F86DE9B0D068BB9ABA596DEA300AD51900B57251070C875217745BE32DF875B0490E9495FD34D804C9DA0369E66A5EEFB316545277A513F05DCA1B295C5F1DCCE9CFEF338E82C4B0CA19182F4D3555B7D3D287152735AAAB3116FE40329A05C577CBE983C610F2CFF57CF5BD9198F6439F5E84A80A61C08341343040195B33E2AEEC90EE61FE7B6975F12396585594D973A340BE909DB1B896EA1398A42A0AC218DBFFF64161B6AF1F529F741AC964FCC147CB0BA7941CDC13E8DFC3B313E109C1ADD909EB103607DE9615239F215A099140DC1E5512CD10685DCAC1A97FB492EDB672B82057070F98522E2F99613DEF69871703C5A4E1EEAFE921067E62AABEF8879EE5B2352540196654F103E455C3E2FB0ECBCDB7D540B58F3A364163000B8E2CF3E2F6A3EAE88CE096DE15ABC3D274B61AE5A87FF902ED816C41C598C1D90F731115C30AF6C4793CEB7762D81D571B3F276B900BB06B1F18387CFAFA410E21ACB4723F65B79085600A4C112557E439AC23FDD374477649D6F6A9EDF2E7ACB6412B9C6EF98D8C58A9CE2381115FF5FFD4BB72035913E3BFAB6553A6C73B02F455DC313DC68B8BBC24CBF75B9D6C67C17A758D2CD80AA787BFAAD142F86DFC733CB1DCCD9075C5E13ECBD9E865A7F05F46D0FB8839033AA3959B6CF5B1F977621D70421799E7CDAA7C162F484A4A21236A6EE7159351EDDE7EF22D9FB9E613EDA50BC80D80C70A48275549C79C1E72482AB5748C373E120F67075A66F4CEAE25BE914293E68771D02277E01B1929E1713CEF524C762E2BDFCEFDC5C840D2C9E9E06B1F1DC95CC733B830E650972E068FC09C515F250D0454F9EA5D534D302E04434D954E27D53297C16B7DC74497C5C51B29CEFFAE43BE1628345BF880EECABE29F137B5FAD8A49B7BD74F33F9998E0F832884C88970B74DB5FFC75DEA58E94D6E36B2DFE47533F3876CA2DFE4616AD8E9ED3037BF373B3EEF34DC0D00E315C485236110B5C1FA3A44F325FB56B07D0373553EF35B0E5447649FB4491E56959190CEF2C18E701572E79CA0E3660512A154CD281EE7F75B4E8E9567E56C86029E79DF8F0AD5696452C9D42BBB392CF70C9B2C8094FDB2840E2F38891FD5E5117DB1B418E542075709158AB2C543532C57262FD8923D4BCD4D98DBC1F17026F185C6A56D864425C80543D5969EF46A04601AA6A1ABAA2872146E40A9B22D565CD166A4DC47D1CA4BAB17200DD11A73376E91ACB2DD80F2D37C983C9630EB7A95927051EA1F6B85B4FCDEE9F6B11C4EF1F1D7AA0E2F02394F3FFBE7813C50C0998D9810B0BF47EF55E746873739CEFCF4298CE0B78C45D5859037D02507DADFDA276AA320770D8A803AA4087C6548A21ACCA3B6AF9D709A0F04AE2235A5809B3DB793773714B1DF42040B17F41498408F6F9A1E8AACF79224A07950B607DF84B025CC03D90D66632CFE1A2831B2360015B40F93D70BEB287EE362EDB62D84CA065144A8EC0FB2D0FF328F328F7CB198B17337C1CE6E349C239DC5DE686EC5C4BDAC0757552EBACED8BAA4743E61403071B85E192C996FB0E406451105D07C512586650D3009F3277A4F75ACD7E3988B4F41E7AE3B5FFF3E6710A952BECDEC65B4706264D66149119F45A464C4DB33E0D65F85F6299E1EA0AAE66128177F597890559FA3035B5BADEA9022D1A0B6CDA78408369B2B71F03BF4C82EC9837224E9BD2760FE48A687F425E958A99EF65170CC56C637BC685E3F878114B7BD5148E1E848279E203947807319B52FEC21D6D71A1B3274A9CD5FA2C6AC6ACEC85DBE79DF2F61A5F9F8D48A93EDAD638AC49B433CEEF2C147248A4C08B79307432F9F8084BF1EB3A53A3A6275137E2E9E998C2D4B931649F0453BF14D81B297F62F7526DDE7EC043D13236F240E4CA26E1B093902A5B7AF408C847215CAE58C11276CDDE2F662FEF85FB12591220C347A5A1C16F01BC2E5296E6B882BEDD91DAA72C9C05C3D12BB975C558A03C077E7603C7988C5DF2C381AA0E544E0E12DD6A3317840F32E4EAE0397B2EE5857A9DF768A55B1B87DCBF558182E00C99603E7901DF62F6178094BEA2D209D2DEDEAE9076C81ED33B52CE4250895BD1F14237B6BDBC152B482CE42800C5ED518DC0643F612D4D70C6EE7930FB63E3FFD7E99BE83C462C67B1B4F02633C8D52D25A04A5789DD8F1827BA90ACB0DEE5B0C643123B28D5C229D4702675896D582D1276303FC097F5D872C1F0A9BF4DBD4C823DE4318DDEBA2B5D30F817DDDA849FCC6519E610A725F8D3E794C39620B52DB9D54774CD7633790670108430F361848C96518469B7CA25A54D6C6EAB79B3C2A992E02792BDF754ABA27486A59237A24A8EFA6959AB8B1E5545DC39F4A8DE6F53C24410D8E07DCF95825AFAEBD6F687F5DACA7C4FCC2D7A49A10445A1EACA3377E9A38DDA742875E593F2999582ACE1CD4ECE12E6BE457E9623F490478270CA1605D6BBA07BC9DA8FFFCFB4FC8F38BF3A289FA28AE671C4F1010831F862854C383A4FDA70B448F6F7BACD89103EB3EBD101C609D9D433529E3E573A0B1A29C858278965437DF4EC91B9F95CE14C6C6DB2309D57D574571E86FBC17477E02141A5E4924EDE91B0243A4A1C0B9B416C5381078EDF8F03213A6A33815FF49079BC8DE3F668AC29EB0C9B56E2AE4A36491874AA6ADBAD005F41BC8B43EF67DC1F273E2ADB99D059F236A95EEF61646BEBABAF0807DB3F779C03DDB7BF74E188CE39C1FEB9C1B3104B2FA4F1954041BDA4B403BCC26B1DFD90CA11DA3374D8EB6A8205753631B3178D8AC1775D6F33F58E6B24770B4F0D7B17C3AF89C6F5D6FE5512F74B59B6C8ED1646DF2B2CB9FC761DCCC1DD81E520D481E8FAD731EBC4889489AE6B68703FE04D35F31EF0509FF2CA1A00171AA197DBB159A37371437AE16631A65666E870C11FAA6E71492C7B353372AA434E0E25463B330B83340B3B8BF8AA19D3D11301B293E1E944751F70635D7DFD76E3C864E8B0AD30B1CDBE481F3D4713496B37BFEFCA3DD098114459CCFEECCABC86CF366EBF0EC2C849EE310B8249C396559EC8B2D865C3FF8632BB51578A7AB8EF48FD17A357298C5977B38AEBCD3B9D60CAA06C34A29AC82FDCABDC61BC8F018DB283C9493E59E9294A8B9C57FF67E4CB50D32D7BF04006AD866B3536C7501DDEA822F5BA3170C8FE0FDDC8698DCB327BF349AAB2108F449A78C0773B5CA7905A10D4A2A484DCD08C67A2F998D0DF8B94C4595A1F6AE41BB2F0855C70A91D7BFAEDEE44A18734E8CDA4B72EC1FC19F55D96BCBD2D074D4D40ABC9816C1C56FE1853EC2EB8D907B72B14361A0311BE4B2A3A921786AE87AD2E3089403473FB9659258DBD47A8EE4E62E1D923FBF045612027E242AC4559918EB8552C20DB1A48303553E15299783D7A4847C57DAC00C896B2B10D6335B48AA0373B09329428D190EE92C5F7CCFDD98E4BE3EE5D23A217539A9CD75D36DEDC44B7D4BFE24F6A08AC711CC1EFAA19E7D14879A157F9651AEED9200089F19F5CA694BDE1D7E3F702FAEBD1EAA2F572942510BF1C90082108DF3B12CB6FF739E90E48885E408027C659E28CCD8B63B848E437336C597B30F07E8170CD6632037B4322FBB7590DC3A6D379BA01E9828924557E2C18462E6994EC258B5E21F002B890178CF3E23C494F3E1BBBD4C388609B34FE58D78C89E2C0CC03B3213F6FF49BACEE4A0193693BB90DB3CBF3C5B3949CA827D28416F2170A28737E0024ACBAA20C8F4B634BA08CA0A8ADDEB3177624AA1A4D42EAF4E9204E51EBBB6A21A82B43E35CC12B8E2E3BF6EFDA9456905D566E9EF259DD4FFE478BA0CD71F1DA38B1B40D76573650262C546973FAF722421B5F948AA9F64BEDD5B1DBDA85F5CB1E39D24FB2F6823378F4D76B938F0B5DE8408060E24844BFDD916D42E12CCD4CD0D35A4C31ACDA20BC6968C505DB6FD399B4C0F039C5886CA4BC55DED7CABFD60ECCE9D48A4317A245E7A86AE00DEFAC0FD33C45810D7FB6AD58D83C900AE416EED24EFBCFAE3AD6C4C20F14F4F2FB70BA22844F63482BA53ACAC3B7BDF0A740FC5AAA86B48CFC1B81D90F781DBBDDCA75D96A99A5E5BC8F46F70A5BD8D06E7307231844AFF6C57BEFCE7FC03E8C7B40AE19EB5B6102183E51B2BABC52DA754E2074277F0F2E12C77DCAA26B35CA8205939D322F76913B0B4B758CAF4ECE4878CF369B9A381D44269419363E9A13402553795D008A2F551E10E456ACC539DBDDE9339C1FBC9535A006CAFCC459DF7B69357273FCBB5AEAFADEDD479FE99E4EA8D7CDAC2E1FDAD9C5AC98165CB9C4644CFBDCD9EF7C49EAB4D8CCD466D3F1C4C6BB580AF07B087AAC39561ABF8C7774F2D068E51890BF037FF410319A249B5BCDA5F285693FB52C3E0A028F0008638C283CD9B66928A703D43BBA9E3FB96B6B979DCA29D793B7CC82202CEECF2AF3B791317816F31EE0CCCC5F21A3A0ABFF430E171455826597BBFF6CB86E6A991827C4D5B9E9024D7DAD71FB3DD190C27E37ED556D8F2902A6744B6EDF7BDED4B0A80CFA6393D94312F9CB06BD647AB439DD36138F6C8537AD365375C2559ECF0B64FBBFB86C104524DBF63C36A995B8700C9CBBA8FC42DD5AF8A30330C111B09997593F44276C87CB42B6F8CEB2589A6E1ED4C446FAA9230250CA0AF08CE415FD24C6353BD2CCD6A003B7BEB864663DF1C373CA424593963E0F13EBAE6611C72A496AC40DD82E0330C9415B53BA0B90EFF051AD6F3B63C0636D70809ADE7EF3367AE64E02CA4C2B4E3407579821614CFD28CA4650949529C6F0D00B3AE1990111DD43555ED45F393B108EFC57E2C944AE26A735DCA2BCE7C5E32B7F9FEF3CC82FD2538EDF870739FE85E1EE936804E82175F08A9986AD2BE575F9B398DA549DBB82D84F8F8B546E9A1F80DAAF1977AEC0A4801EBD86E2781E4FA06AF6D397A23B4CFE146A06515C6C4E0CB5E1CCDC189813796712BEB506B96A3A1757F8888614AA3183DB994DA3DA29BD6B3B4A922078C9F3BE9296449D66F9CFEEABD81C39A668C052B1C9E4E85B5A8140A89A7ED71CEFF3ACFDF4694D809E3910F9E9BEF756F571E6E3F397F33EE7701BF84B4B92D7685DD868A5023748E74FDA84D58E20CF268DD4FB819F14BC72DECCA6C83AF7E8DA5B9AF37C2365DFB573D76B9036FD7492C08C846B264418F6AB03498739AFB717FA6FBF0EEE24E15CEC4CB413317977B7009BA7DB6730B66810E82D369B5F630F609218BC3E82B057ECC10D2D1B8A3D50EC169BD157C179D3C413C7DEBC8F98EAC9DDCCE98C71AEB5F4C50C6039C3562D1AAFB2EEF9E889B9D5CF559FE0D778B2A9160EF3999A624BE1309854301F3DD97299FA22F8BC9CAB2B2191DB3033C9973B2AC8EB042202C82EA8DE80BF2FEA0B086B9C9508761F822F576805FD22C20141A6276DCD117ED57D0B34E4A24EB405AEE1B67335344C0D784E94723C805E6648B9AD6965E775A1B04111176811DF5C33C61A55A13ED357388BA9A841E879E64B3EE960CF8A8053C72FA4185A0C90F019A7A71F08D7F0B321339E7B50968243BE54BDAB8E351F6419FF5A3B77A0EE01B14E4BB98246D7C30B847D2DE26634E4DDE189ED99D48AF8ECEBF737893A7BE987FA1C8D8C23B9959BB750F4DE2FDDDA0B816B43FA1A3BB870F9EAEDDD8B57F2842210C1CB8237EF196EACDAC9B459109B65E849A689A0CD8A3159BFA8E032E066AA937D92CA2DBF337A187C36460136CC9792924F87D26F7BF02B0B80DCBBEB55958F33F505FB8BC6646453FBF3FC3F6C391FCD5611177F527ED04255727BEF917499B502E962B73EF125A3DC844B99841381C1507563A1124F57E6DE82C488D273C8D9DBA0A48D4E340E95068F02DD37478CD8D9E4BB1690D02F640902542F628669861B3881558F436DAA4D77D15A23D0917E177A31CF32D4E07F24DDB4CC9DC68E0228FF157AA4ACC380DC46F8E90AB4D36F32080C2CD03EF386E07DD88981B96311BA09324D9830CC1A021232D46842D9C0D24CF8D718C66605B6F9F542D1380CC46C9C3A41D349B513CF9BE6B00C0BE1D66D94BB59916282DB61E8D8CE13AF9CCA9AFFF90590378EDA1C5FB9ACBCC9DCA641DCE9C76B03F3A5AD9B217F47ECF5968AB84AEFA6845F3FB97BC7B9E5E8629924AE376ED263B2891EDC5D784EC1101D389502C0798EFDBA463D972F73EC1CAE6593CBE28E46665A95FCC7F4D50AAC0E3E109BBB96E7B72655EE31397C5EDFA481CAE1BAE9E5D1C055EB66AFD77B72535003A803826E96B4649C909F305C55C1636CD6E03BB0570AFA99A9AD8614E85126A7193AAB4A88B83AFDD42970178096BA77C4413F8E0EBA63E954D5FF5D56A3D732743188707DD7956D41151904D79C08DD435361AF8F9CA04581774D719748A3160F0D96B7EADC3D2C4436F31C5D8553767C9277AF1BEB1EA10602ECF1B2612306130E7A31A457136EF5ECB12F0BD5117927C1642F8B34EF4099AD89BDB565977DD1A2B80D2BE5417916DB07A41D507D68ABC4722844C2037379EF234E1FECC5D72774A3B057B75E475961C1B2B36F2783E719205033D4BC03D21C5149FFEDA8DB6C3A926E32CBE92E7E423D5AEB5D8788EDBD81E73D53478F141C56A63ADDA14DD9115FC252EDAD1D25523957988D630732BCCF053881284F67D7940B104DF54C2B757983C40E45DB6CFEB96E4D6C3CD0C352045406A2ACE97FD447191ABC69E91E39E9096FFBCB6EE71BD1DB62155E3987910B7FE0C615C14167420DA04DE5AC8D6820D06020028B8A27FB51ADF4099B109FED9BF31DA778A6A669023F05BDBC428C84CC64A209F73E8EE5E1F373F38B1837758E1E8FA696F5BB45F20187DDC32F6AE6E99B2D6AA0A10A65D4CB4C31043D10939D7BB058E4BA4F4BC23CD1D0A1237AE576F937104BCE866BFF4117DB681E5D2B236B07119A16B316A96804E208FB643FC89F9306ABDAC433416D268BA3C230259AB2B91F8327E5595FC1A422016EAC7C7CAC9282048D7E63951EC16FFAE631A03CDDDF20766BC18570D49A760123BFC688188A5093984B4B2BB8487F506253DB1AB666C06F1FD0A29B25B460E7D7FE7DCFC009823F8A53C5AEF3A080E0BDC4A5A20A53FC6FD742B502794F76F75582E25015DC144068C3DD1379CF9DF02E8CDEA5292C7EDC1829F9654E670CD4A0B3C9F25188ED6DD28B08452A43AB56AD18BE13538F5102C51684A6724F268204F49661A1DF917975A8B5FDB3EB3287AF9E3296A5A32D9DB75015B62810279EE23A53ED4125CDA14F945DEE21DC16C3F378CA6E9DCC1434DE3CD5106C463CB5550B516D23E2FA6ACA6801CB13225D3AEE58C7D3D16786F2CB9A66EC7043D4F9DB1670F733FD334C4052B59145C2D59108A4A726984001EA09A9DF3F8C53B009B4D548AE9295C2FB3084AE4E893D03612C4492DEA0055EFB8B087CC7D586750D2E8E348098CCCEDDFEFFC84336EDF3FAB7E2553DCE1FBD0022BBCBE08CAC0AC0EFAB73AFE9AEE2E0D59AE140BA12C401B5CD8F587A959BB045B384AD0A93CC68F33354D448B98C81440C0C377BC716E1E81C6AC267CE7FAF407F4A10D2C9E25E4655866C42CEECD0762EE7B0358BA91D90724C67CEA183A74E9323B2ABD907428CD2B01FF8141380B13B00B3C3BA0F21057F74717E8F73F91787BD41718A550338E0825C41A25BBCE5AA6BBDB5E1D10C5E4F65EECF8A0CA70D25662344180428954229CA1CC228AC60541B529AB6482E2B25211BAC6388424DA40E440F9A203AC26F134A48894E3510E66675A0538E9EC73443475E2228ABE8C36DFA60D12F45CE58EDD57F6A21F69B2D30C679627A056D98371533F3CFC46886B92BAE698751870E711912348B5972AB7FCD71ECB941DCF351E39515736EAC9C7BB112911649790495C4C8CFF4D72A1C7C995F4152699E12B5DBF7D2C2731162DFE99E8CB91FFBB0356F310981B133F03822FD03BB6E4C0B26248CAFAEF23906732245C555270A547DDB64A07CC465B531A711B8C2CC8C006C24DF7F355A4B8C353FABFEC8582097F88DB0313754EFAC1F60332CAC23CB10A16E85636DF50530A741574A7804199C3CC5ED01276E0EC0B3B0183A7019D490A7CD782C39037B82F9C05166FA3EBD83179DDFD036F10DEAA1F9EC24C8405DD23A684FD38FF376B845862A84778DA198EFFF697DE07407BCD357D3DC125E61DE27BFFA46535BA8A7D169BF4E55A534F85ADD865F17595C5145B007413AF89F717F548400B6AF72A687ED7EED63F2A46C5DFB99BA0D228784643F9FF0CBBC9ECC5C6B571414BA63BD3EBC1AF8D44DC3F0D800B6348CC3618B40611B70BC73311B471B184CA95E8C856198ADB501AB834D041666D9B6E9E2EAB02BFD0210E94F91AC056EB61DBA63AD2640C9D47DEE6F4BAE8CA849708CE1890D44FB74C7CEFBBCB924309C492F918BD7C0AA33C182BB4D9BE07ECC3EA09FCBDD3A688315E67DFEB9D3B08F969EE615BD7ACAA2A578407C661AA2F8DBB1FBB0F4A211C9CC0C2850794505AAFB90100CB475F48541A3EF4EFE787AF6F76075EEA91083C3EC1A47ECC0F253EB87622DEDFFD7A7193EECDD43B0728B02EC5339892101EFCFF9E6FD612F6540C4E5FFAA48A4FB9440460B5039D0E19026DD235DA416FBF76998E3D57248BD3B6B035E82E12838F27C4E090116659BF5C7370C3C7BBB1DCB4CC77852895B763286E9031A3787BA8BC328E6D7D2DDD3BBCE637FAD88979A1AD3AA2C942CE7C0C102833425573F95B8B68D21811B9F8936E8B08736F615564E77FA42D38A9A7B4A1BF5B2FF14DA415BD901EE4EE47C01BA0B58022ED90E878C694CB56E53874297542CF77D58AF8753E3E57A6FC832015B6BD0A0050DC442C85F1821366549D759BDE24DF7F21587797585CAE55194A97124F33B9AFDFFB8A866006089E24C2157FD340F0699363E1B5EC1FF6238411F28F0D60662675961F3C02910AAC8EFEF172B19B98E78EC25CCC3AF510D9DB6B0A78D503B5304B40F11E738A43EB1E5C177CF102AF54D2DF81865E6BBAF296F800218D28412E39B1E74B4751C4E58A55E677382BCD2D890ADD066AFEA7B02DD0B050885078A0069DF003EB8C01A2A9A1185A5C973864B89FE5CEE8551DA451B9175C3541912CA148ADA2296AF9B7A866167679413625C0B251AA386F41E8BF51627F228BCE0AB994DA4B1771EE9A10807146DCF5BB739FB42629316E40F59F3EDE5CBBFD38E6733A9A8BCDFE785EFC561A3F4FAFF27C4CAA401D48695C7C9377466933CEFA6EB460EA86193AC6570D0D5C90F40FB69A61A0F4AF40129F4EDEBC0837B8245EC8C8207F1D25F430DE2A97C49A9F9B7466908F59C1FC125D1003729585E595AF0DE5632794B301B2219BFADE4747CAE3329AF585E6126EE4BCAA9A5ACD2F9660DB7047317C06B7DACE97DEF24C5E4D38756AE287C90BB2862208C74EF5B5A7643534DB0EB035026E974F4AEA86A78069295A686FC291E04FB42BCE14FFAB3B50ABC990ECE16809455494EA88D6104E4DE929A8C85735A4CA40369D178EA80AF3C2D0B7DAB1EE5111D59B8871098151D9D80CF3EAC24283E4831D748587C5D6951F998F2E0EB909583CB66740F530F71ADBE1B84DDD42D98E614E7D7B22D0B34854CE38E3B5904893F6E8B5CBB50CCD251E34950E07BFE8C10591CF0E52232446DF500A6CEB5E820D934CA3264A29951426BB5D70603E4D73CC66ED7F51DC8E98E2D68C080AA7A867EA8A57B760796BF598ADF96FD66ADBAF7246566B4BEB1CB28003B280E468CFD40BD32F998A4805CE42B8323B6F0F52A0D141116C817C2F4E1073154BE83D27F1469915B831BF58641A6922B08C6B2C4A3449CF6D2A9D1E232BD7FF1C2625742C9D3151615DB5ADED8FC8DAF26A903A4DE43C975678EF252D984A8BA3B531E9256C57482B981B9E82A7B7CE8FA65FD3D56415FB77F52C6A435DA5FE6BCCBC7EE385E3C72729720C35AC8510153A50F06C4165C462F2F7A6F6C6AE16B53C0E49ADE7F83AF82C294DBC8CD30ED638F783A16C6985C187937CA19BE81485890DDB73E5255430AC445AFE393649D26D6421A12C222D99ABCD329B4DA9C0ECE7969726CA0FC9AEB1F57CF12D3D65EA7CE9CA1A7115FF2051676FC7472B2B4C54242FC433B01BB504920A26CA1DF710B061501951C6D9C332B1F8B2DDDF909803DCC7294BB8905C5A6F3F7A2525D87E0F94DC069508D9C2181F0BD244F9212BA61BF0DF800133D867AB4ED8D4E5355AF62F938D4FE20D9CDE628BE85AE887A614E456DEBD3938BC6C75D539FAE5CFCF8C6E47D3F482A7581C2BB1539EC4B4F4A966A7751FD9D611B662FD065E4DB64107180A6B05BFBAD5BDDA237702F049555DFD2CE77940C4EB39AF9ACD6834C31CD82E61E4DC73F29F5A727E3B68A2127929FF2777E47B4D85ADC93EBD042BAB4296DB8E6D2D7908760914063505B7364A9BB6495A69C0AD354180E018DEBB9EDA262CB26FCAD7F47AE17C5D9BC92310906BF6B9C863F46825B2ABE0D1FD92817FFB21656E950B9671E464918E089C4312BFC5710E58548370C06DF3BA33221D502836C8E02D09A6DE832C67723B103DFD8A2E2F7A1E12D845DAC7DAB2D40B2DC7AC429DB79508456F981A8CDB91EA066E5D32020F468C04FE2EA5551B309339B98A444B0F1F152598935DCCD01B31816422C02D3A159F2DBE450F9E4EE3C2776F3CB3FF320E71F91F38B63FDB1DF595F2B37A518072BB68D459878B8B9520B149C42E3CC7FAD61EB04161B16A539A68836232D57B76ED7B50E2B9DFEA42BF40909EFB8B2F285B371D6AC9B469F19FDEFCE8D8671C429A6FB54FF559B087D35A7C3C3CB7DE88BD138918BA0E06E1D9B4E4FE1382C297ED322E04C5D33F09D87668785DF1445286C516A714145DE5AEBB5E763ECC887AEEE562B5863AD8EFB11E519B4A23ED53436F9BDB02CD6D005619A948CA5B1D8A0006E0F439DAE53E5863531BBD7FBB6604C0D9DDB8A9A39D3927BE8D6A2826FBC74E9CDF649CC4067EEF76627420958BA78BE93BDF48AAC3E76C1AB7E8B7874AEC44AA6075E70F3A9DA35B42FD8E06EB17AA81098E61A118FCFD671A9E786B9B1E125EAD9A2184AE292178A536F1877C25AF9F75FFADD7177665439C503C64B779A93B30E18BEE03A05C5035D9C6A728EB9684515C3F0645F13AE043C66F0E96AD0E1E23BEC9CEE361F2FAB91367E89028C96A77DA81672745031F588A6D3E181547EF14BB769153C1C5F37BCC1B7D9F735D16DDD952E66ABCBB58220B9655C4E26F505A353A4DB863956E48CEDA9CA9A5A1D60AE759FCA334C8FF4F6A12F6F41469CA65DC691B2CDD1B67BDFBB9C0ABAC141F6B27E4245B26E5064996F7FEE6E3D699163EF45223BE2DB42FDDEF24CFF83576D9ABBDF582C533412F5A509E794C1721BCDF85C7AB2B92661CDD4B8BDB203F9F698F3850C223404557668BE926A27865FF5503C4796CB264891C0B22D1FCE0CB19080ED8BC37E3EC6CF28531BB3DBF254836BE5FA62EBCA2473B0B5F7DE2A92D40B257AF8D989D3C23525D99070CBDA06AB32D9852B7669FC3BEF138BAA87583CF4042E343285055843FA2D1C8F67190C44189B76DF5644B93B182CE0E4FEB5FDA7C24571244AB4F7CBAC1F07E7241AEE40F757C426037A2D2E6849AFDFE6009B2848881D8342D4CC32A3257BDB643F592B8F4B3709484081B74B1015DEB2EDC29E2EEE45AB8D490ED5AC2ABF16E923821D50218E81641317870964E0EF19D28B9C73A164FAB6055E00B73EA0DCD4C281BCAA8B77BB2BC380A0C3D03E573319A5BFF705CF5E41AA4244CF20EA2C04D168438A3AEA9AC332D9204261676777AE9B147248BDC85F1DEE9A1A2786C9F0A194BF76E9970EC6F25415DE40AD5819642EEDD5356E55CE005C20BB3F7CC6C5958880E6CC187BC3E2451D4DC09847990440D384E87D671AA1B243325E52408A2B2E601349532C94E857AD6521AE2E02D9E5F0DA21FFD98A3384AD4139F5A9DCB2576F58077738B2D2123D9020D6DCA94B0C66A4FB5690DD3D2D33D936648644B2A91CCA2F41DD2ABA900FC7D8A873B7F860482F0043C352673888C44F65530D705BD38B63FABB9F17FDB95EA56F96AFEE20B442CF96AF22FE23A5F204FF449AF8C8BC309A02010E88FDFB496A565BC154872C28B44E92574E333532E1245373C0E87A795E888633CB620C2FEEB24ADC58B2278DA3E2E4324B71ED7CA1EE7A8D2FFC9F6369AB2B9EC680E8211CEBA6D6BB8172A6E53375771060A102F98604DC3DD2E32D4C3522927C979AD6B02EF0CBA41FC8CAE288283936C9408483B362DF55A098E1BE852BF5CD4E28AC05C04A1FEE83404C5E15D1095C1AEFAC07A85FFDDE9181A43B98CD493EF879B7D9FFCAB42703879C7C11B8C2DE8D54168BC0ACC07F65DDCCC31E447B3831D37725D8C2D1F6E1CCE31B0B9CCA7BBE1733E6FC7FBC13592DE1919F5126D1999EF530C05BF450B59D11D181A4C121948180149FA0A4AA18B1370063B1F651C9DEB2C2F73AC8CF9B53AE44E452ECE538EAEF9C8496C65AEDF0D6D5B6A475E2FE2BED8B53386DE881C5ACF9AA441AFC83757A91FFCAEF803A6BF3A67867EC4C7C409A01D1DF7E6690A9B68226CB2304A6D45C9265FC21C04BDCAA09B92A529AAA6C7CA5498769BC135CA5924B63854E3F1757C06CC5F6A047A747178DF4D1C6D1F097DE9B758FFBBFA94ACD1A8C6FBD9A795AD7A68EFF5D15AA92B528A6B901DF5CFDBA4A3DC4AC9B784076135EB63A7251DFF073C41C373B739FE4D2220A61B7579BF1B7ADD3EA04B726F47CE17CF2DF9A94C65EFACB8F651DCB21750F87F4C566842155E033A5B22D1312F874AD085B273237E4948938EDCE5F359B57B43E1861A02A55310BF34DC7792C408A6D5EB543412A52D8015507B39DD4D7A984F2F0A7A4EB181C197FDCD48B7E947FF8CF913788860C450F63DBFC226BFAED1FFE0221DD59FE92633765563945736F1888AD2137153195A2D86C43CCEB77E674A59175FDCF948096FF932EFD6BFFC39D1C498629A32FF70383CEED17D7825C6EB8FFE831F57095CBF7757DF244AFC1F6FA51AD73AFF0ED7F24941D61E0B9E904D446C1251766F02F4789D8C06A6B8D7DDF4ECDF612F7F7E1FC70D462A371A6307119CB78F49565F1C11E9224FBB640D258FF95C257BE6BAFC5ACC363CE94BA61BFAA1753600B4070BE8BC847418D9DA50E1052C8250573C42DD0A14CE55A2456F42B89CB5D8F2B35809018C78ACE799B7CEA435887A0B149FA6E55974E29062B2140C79D6F963E18AF804D9F10824375D08A1A84703A6797D9E2BBAAFDA3B73F340AFBC1592E6A7C9A086F5F58B6F00901012B2CDF2FC1E48EEC438DB59F4990D853D4FFA4AC850C496C473C7E661867576AFFB79EF55C4BF33FA92F8FA4F9E0FB3AAB4629626492631A6D91531515F2CD7713756EC220BA7A3DD647E36B381D7EDEBA70E9FD099417D718526A931F4C83CB37F12E41179D1C62F199BEF197949948F4B7C8F8CB7CD3A215050750ECBA5C0726050244FB477EE83657C580DABA969AFE311BAFB46184BA4D0938ED46F576042A158EF946657D4AF234317DC20C8B738873A1AFBACDCB9E9CB8151A71B7DAF0B8D6891EFECCA0741C1ED26BC3B75DD4ECDE5B41474E931201C2075719DA5804AC047EB2796661BD92CC4859A9E388483D3B8617585573999F031ABE496C4A4413BE70B1BBF4D46076C03E234693409DD5B0C019553C69083C4E35D1A431FE1E0529E12367668A449A0BD696DD4E49D3B07BFB9B1B4D5D9591778AEE13B986E8A203E79073D707EA15EFD512CAF454EEEA586E87C99CAEC4442DF4C05CEA24CA81A2551DE39A0C35255FF36197041EA392F5C314102D0BE8B803A42BFDEC59A73E365366EA89BCA7944A7F7F54F04F019099678503773C9E4D0598F0D5671225A769B8659A1BDD1AAEFD35BE3AEBC2C338183A0CEAB3C0920ADCD51556EB3F1FEE7419F75BC9B53546B114DFDDC386082B5EFE0B18F0602B3692EF97B6A7FFDA970A125133F4F4B348D91BA04D49D572B893C2051D04BA0B220FDE20C7E322433AA62647227A22378724446A0B71897DA696D143002F9B9DE227963F89024C9056E78D360066A25FCFBB10C7C96C9E1CCE2C8E3D7B44CAACE74552D097387E9A6647DC99E1DDBF0EB041ADB9C2B1DFEF0AC4EF6BE91C0DCB388B272867C7EAD3E8A171B9731E7A0007FCF6F6017C45E5BC53B3E863D4326C4D1793B157A521A640DDD84A2A4E5A21D3D962B81767FEDB2A13E8049320D1234AC34E3BF6198319A8D37A12180115F97E41C6559B38FED6E11C001B029D05D8FB980D635D6C42DFB7988435200F13B5447BF3B00135647E0B9DF0BC4EE372D9E3C50072A2861D86FAF557B973A682AEA7C3B08D9EF39620EB783A5E0CFB07F3D9A70FAD191769510D880DFF4F0A4161B3AD91578190B25EC0DE6D008DF418AB65F5B472C2F8F7F366714CB53B3BE65302F06BC039E507E121D2B130DB7550C51D14E45029CEFBD39165C9DDD8A68E222EA71AA7CF6240D31045C3DA5B3AD47F558EA646ED9A29A8429F249E4EDA48DC1BB7604EDFF0D9AD5235333126ABC48E3B12901C366B8E9A75E64C3F54C79405AC407497A36E1BED13D7569F969AA8B09C17F28703DB8C350F507BABCBAE36526978A9C75C9B20D4C0C5B061CAC538F29F4C96857B7F6987078F56343B287145E40ABD21D6790041102FF39995B1B0CAA153839A825F883B65C91137F6683B1DC436C631BE519FE3101AA682E82EB9489DCAA2F7826C73D6DF59783EDCF31FEAB26636B3CF6E94F325678C43ABAF85C954EA1589DE469BE316D9D6BBA69B05CF35C9326D299192BA4A9D79226FEBAF26EFF068D9A4D15B7FB435618D7D010126F166024290FEBBDA3F8C59B603C13B4F13AE736ECDD3BDC2DE7C70A6CA7107FCEA4472EC73F8F028B94755D797133116FA639A95033EF048103D52205E9EFACDB710BB45E17258CF42AF6CFE821F1304502B87F0D0F79B6DB4A8F4AB5966BBE476F49A9830A3BF378B53FDC7D2A5A612B1BAC65B31E99F360829FE9FE048C73C27FE7DFDD3E89AEB5B43966B21D6DD9F727F7BF18493E7CB419721AFB5B47B24D4336437BAB898F85F941E685AD837E85A2B2C6C3101F4A5CF55329C1968C72F9ADB16E2900410DDFF0190AB71D635C0ED6D5F76E247ACB97EEE187ED1D153426582EDBE73460F7784C202E556575E6E47A6BF6E7A71D90F738B82D2EB8ECABFB3E531F445F69E9D6E197C259197AD5EDE69A85E414A31A96BC1DD63A894EDE4BE0AE3B16B4CD0262976D9EAE29320E4C0C5E0B3645083A98AEDFAD7AEB508C5F14618016303E8AA208C1F53D0A73C87BCE14DD055535904CC75ADFB3266CB60332B800952DDAD2BD7232E0DBD647B2DD90DD64264CFB53691893270BDB58CAD11398D89D3B3EFDE188F1EEF6F23534656BC5D4BB8A4247CA9B26E5F9D0705A29F646469ACD6BAA083B6CA02D89A895F7A8E93C198DB6C99A5D3E40A8367C2A041C286155F79F88E7D6DFB3333AE7EB1A26B0B2F44BE7660BA981BC4B5854CDB0763AC53671AD2395786DE6BD725D73760BA27EF51CE47C8086DD764DEC7BF129097C185930B42EA2A0658573822EC57EFABAEC2BDCCE56C491216F7F21FC182E8927F1342207182E033C3B427C1EB92FF00082C24907CE6C0D1637B9FC48DE5055A78479CEC3B6941A32BFADD7B1068D5628E98345FEE29146806760C7EF4799EDABDDF250E8E38733509D4FB5A38D34D281F287EC7D9DDBEC7989F699852F86272A810816EABEAB1BBF3369A66742C637D6B4331B6E814A8096B15163D3A23765F033A4461DEB96F88A2408E3DFE8D0C0B62C4C8F0B3EE755C80A71732F093A5ACFC4D70A7C51202354EE95700CCBA9C1D4889087E82AC91BFE287B13CCDDB2155021DCFCCD2671816CF7890BD9339BC161EAB9EBDEC1DE05F5D426C8D7CABDBB0A4B7FF9B199F8C8909DA474C8A3AB2ACE864EB254493ACCA69F5E6FB0C79B6732F7603232DC09C549B31DE88B9FB8B4A727978EBE3EB893B45C2876C25884D8E95F334A25A69AE96F519DCE36F97CF95088F65C6DD8B65F5246BAAFEEDD8265D4F6BBCE2E31015774DE1227BD6E79E365571DEB93C044DBC6EAE4CE576D41900D8032B6B1064E27765EEA6CFDF65D39C1D53E83B6A18EEA3B6AADDC946E715E07F833D8017911F035F8B8551791E392BDC0944EC838856F5ACA4A6F5914EB1572D7AD8A10DC96A0121AE08FE2923EEFC58C3C443D00B256CB912796AD63BD64122A27CD9EC678FF0B497E1CA00483B44474A74C67D1483F808FBB38C418DAE2CBD025CDE039C991A71CD82859C6F642F9B484009EBFD4CBF7CA763658C6A71D75C904012E43010E702B07CA06F10369CDE5FE5A6B5C8EEEF249488EBB1B4451DE767D7AF6AE9650CA1120889EB5BDE8E018DFE055EE2783494691F3CB995E47287754697AADBF47C959B16606E9998FA18CB988FB680D4646369B1EB3EE94AF337766839FB2EB932FD1709947748507D691EF6F3EEAA7AEC505024D2132F8DEF81B92F5E3A55E488E853FEF1ABF0BEA0BF954F03190FF332CD1A1B39BA93FB7CCCF854804AECC81832308EDAF0CA6F6B3F11488EF992A5E6E1C0487E423F2A69980F9DE425AB2B88B1C62C40F6BC7E933856A23F4759D5A2FFDE25EEBB4B9ECBEEE0D6BC0A1F9F8C340AF84DF67DFEDB8BC0A26DB8DC582D9C458BFBC6341E55169271C3209E466BDFDD03945B9A16DC6D0D05170A0027C61734C9B0A9CE6345DB2BADDE8CB2D8E6A1A7D337F3E53D2DF70954CBD407DA757FEC4A2DA9D4455550381B3AE66543FEBB7418910744E81BEECA1A864CF10C72D27CA943A4B65BAD91AD8F93A50AF796F46928BFA84A389CF485344F93E0C359B48443525EF524692089332F5E014DA55EC95070D5A96B11085A7DFDB126EA10C32DE882"; | |
105 | + float f = facePairMatching(faceA, faceB); | |
106 | + System.out.println(f); | |
107 | + } | |
108 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/CLibrary.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import com.sun.jna.Library; | |
4 | +import com.sun.jna.Native; | |
5 | +import com.sun.jna.Platform; | |
6 | +import com.sun.jna.Pointer; | |
7 | + | |
8 | +public interface CLibrary extends Library { | |
9 | + CLibrary INSTANCE = (CLibrary)Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class); | |
10 | + | |
11 | + Pointer malloc(int len); | |
12 | + void free(Pointer p); | |
13 | + void printf(String format, Object... args); | |
14 | + Pointer memcpy(Pointer dst, Pointer src, long size); | |
15 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/LoadUtils.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import com.sun.jna.Native; | |
4 | +import com.sun.jna.Platform; | |
5 | + | |
6 | +public class LoadUtils { | |
7 | + public static <T> T loadOSLibrary(String dirPath,String libname, Class<T> interfaceClass) { | |
8 | + String filePath = dirPath+"/"; | |
9 | + if(Platform.isWindows()){ | |
10 | + if(Platform.is64Bit()){ | |
11 | + filePath += "win/x64/"+"lib"+libname+".dll"; | |
12 | + }else{ | |
13 | + filePath += "win/x86/"+"lib"+libname+".dll"; | |
14 | + } | |
15 | + }else if(Platform.is64Bit() && Platform.isLinux()){ | |
16 | + filePath += "linux/x64/"+"lib"+libname+".so"; | |
17 | + }else{ | |
18 | + System.out.println("unsupported platform"); | |
19 | + System.exit(0); | |
20 | + } | |
21 | + | |
22 | + return loadLibrary(filePath,interfaceClass); | |
23 | + } | |
24 | + | |
25 | + public static <T> T loadLibrary(String filePath, Class<T> interfaceClass) { | |
26 | + return Native.loadLibrary(filePath,interfaceClass); | |
27 | + } | |
28 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/MRECT.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +import java.util.Arrays; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import com.sun.jna.Pointer; | |
7 | +import com.sun.jna.Structure; | |
8 | + | |
9 | +public class MRECT extends Structure { | |
10 | + public static class ByValue extends MRECT implements Structure.ByValue { | |
11 | + public ByValue() { | |
12 | + | |
13 | + } | |
14 | + | |
15 | + public ByValue(Pointer p) { | |
16 | + super(p); | |
17 | + } | |
18 | + } | |
19 | + | |
20 | + public static class ByReference extends MRECT implements Structure.ByReference{ | |
21 | + public ByReference() { | |
22 | + | |
23 | + } | |
24 | + | |
25 | + public ByReference(Pointer p) { | |
26 | + super(p); | |
27 | + } | |
28 | + }; | |
29 | + | |
30 | + public int left; | |
31 | + public int top; | |
32 | + public int right; | |
33 | + public int bottom; | |
34 | + | |
35 | + public MRECT() { | |
36 | + | |
37 | + } | |
38 | + | |
39 | + public MRECT(Pointer p) { | |
40 | + super(p); | |
41 | + read(); | |
42 | + } | |
43 | + | |
44 | + @Override | |
45 | + protected List getFieldOrder() { | |
46 | + return Arrays.asList(new String[] { | |
47 | + "left", "top", "right", "bottom" | |
48 | + }); | |
49 | + } | |
50 | +} |
platform-operate-api/src/main/java/com/lyms/platform/operate/web/utils/face/_AFD_FSDK_OrientPriority.java
View file @
ba98c3c
1 | +package com.lyms.platform.operate.web.utils.face; | |
2 | + | |
3 | +public class _AFD_FSDK_OrientPriority { | |
4 | + public static final int AFD_FSDK_OPF_0_ONLY = 0x1; // 0; 0; ... | |
5 | + public static final int AFD_FSDK_OPF_90_ONLY = 0x2; // 90; 90; ... | |
6 | + public static final int AFD_FSDK_OPF_270_ONLY = 0x3; // 270; 270; ... | |
7 | + public static final int AFD_FSDK_OPF_180_ONLY = 0x4; // 180; 180; ... | |
8 | + public static final int AFD_FSDK_OPF_0_HIGHER_EXT = 0x5; // 0; 90; 270; 180; 0; 90; 270; 180; ... | |
9 | +} |
platform-operate-api/src/main/webapp/WEB-INF/lib/jna-4.4.0.jar
View file @
ba98c3c
pom.xml
View file @
ba98c3c
... | ... | @@ -86,6 +86,16 @@ |
86 | 86 | </dependency> |
87 | 87 | |
88 | 88 | <dependency> |
89 | + <groupId>net.java.dev.jna</groupId> | |
90 | + <artifactId>jna</artifactId> | |
91 | + <version>4.4.0</version> | |
92 | + <scope>system</scope> | |
93 | + <systemPath> | |
94 | + ${project.basedir}/../platform-operate-api/src/main/webapp/WEB-INF/lib/jna-4.4.0.jar | |
95 | + </systemPath> | |
96 | + </dependency> | |
97 | + | |
98 | + <dependency> | |
89 | 99 | <groupId>commons-httpclient</groupId> |
90 | 100 | <artifactId>commons-httpclient</artifactId> |
91 | 101 | <version>3.1</version> |