@trustchex/react-native-sdk 1.512.0 → 1.513.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +9 -2
- package/android/src/main/java/com/trustchex/reactnativesdk/opencv/OpenCVModule.kt +54 -0
- package/ios/Camera/TrustchexCameraView.swift +6 -2
- package/ios/OpenCV/OpenCVModule.mm +59 -0
- package/lib/module/Screens/Dynamic/AddressCaptureScreen.js +427 -112
- package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +9 -4
- package/lib/module/Screens/Static/ResultScreen.js +46 -0
- package/lib/module/Shared/Animations/address-scan.json +1 -0
- package/lib/module/Shared/Components/DebugNavigationPanel.js +10 -0
- package/lib/module/Shared/Components/EIDScanner.js +16 -4
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +100 -19
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +47 -0
- package/lib/module/Shared/Libs/addressProofHeuristic.js +130 -0
- package/lib/module/Shared/Libs/demo.utils.js +4 -0
- package/lib/module/Shared/Libs/sendDiagnosticReport.js +47 -1
- package/lib/module/Shared/Libs/vizName.js +138 -16
- package/lib/module/Translation/Resources/en.js +16 -3
- package/lib/module/Translation/Resources/tr.js +16 -3
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Dynamic/AddressCaptureScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts +8 -3
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +25 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/addressProofHeuristic.d.ts +34 -0
- package/lib/typescript/src/Shared/Libs/addressProofHeuristic.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/vizName.d.ts +31 -6
- package/lib/typescript/src/Shared/Libs/vizName.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +0 -5
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +13 -0
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +13 -0
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Screens/Dynamic/AddressCaptureScreen.tsx +434 -75
- package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +14 -4
- package/src/Screens/Static/ResultScreen.tsx +59 -0
- package/src/Shared/Animations/address-scan.json +1 -0
- package/src/Shared/Components/DebugNavigationPanel.tsx +13 -0
- package/src/Shared/Components/EIDScanner.tsx +38 -12
- package/src/Shared/Components/IdentityDocumentCamera.tsx +109 -17
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +53 -0
- package/src/Shared/Libs/addressProofHeuristic.ts +197 -0
- package/src/Shared/Libs/demo.utils.ts +5 -0
- package/src/Shared/Libs/sendDiagnosticReport.ts +65 -7
- package/src/Shared/Libs/vizName.ts +158 -20
- package/src/Shared/Types/identificationInfo.ts +0 -5
- package/src/Translation/Resources/en.ts +28 -3
- package/src/Translation/Resources/tr.ts +28 -3
- package/src/version.ts +1 -1
|
@@ -1147,6 +1147,39 @@ const ResultScreen = () => {
|
|
|
1147
1147
|
</ScrollView>
|
|
1148
1148
|
</>
|
|
1149
1149
|
)}
|
|
1150
|
+
|
|
1151
|
+
{/* MASAK 4/C(1)(d): captured address + proof-document image.
|
|
1152
|
+
Independent of the scanned document, so it renders even when
|
|
1153
|
+
the flow jumps straight to ADDRESS_CAPTURE. */}
|
|
1154
|
+
{appContext.identificationInfo.address &&
|
|
1155
|
+
(appContext.identificationInfo.address.addressText ||
|
|
1156
|
+
appContext.identificationInfo.address.proofImage) && (
|
|
1157
|
+
<View style={styles.addressSection}>
|
|
1158
|
+
<Text style={styles.mrzTextLabel}>
|
|
1159
|
+
{t('addressCaptureScreen.addressLabel')}
|
|
1160
|
+
</Text>
|
|
1161
|
+
{appContext.identificationInfo.address.addressText ? (
|
|
1162
|
+
<Text style={styles.addressText}>
|
|
1163
|
+
{appContext.identificationInfo.address.addressText}
|
|
1164
|
+
</Text>
|
|
1165
|
+
) : null}
|
|
1166
|
+
{appContext.identificationInfo.address.proofImage ? (
|
|
1167
|
+
<>
|
|
1168
|
+
<Text style={styles.addressProofLabel}>
|
|
1169
|
+
{t('addressCaptureScreen.proofLabel')}
|
|
1170
|
+
</Text>
|
|
1171
|
+
<Image
|
|
1172
|
+
style={styles.addressProofImage}
|
|
1173
|
+
resizeMode="contain"
|
|
1174
|
+
source={{
|
|
1175
|
+
uri: `data:image/jpeg;base64,${appContext.identificationInfo.address.proofImage}`,
|
|
1176
|
+
}}
|
|
1177
|
+
/>
|
|
1178
|
+
</>
|
|
1179
|
+
) : null}
|
|
1180
|
+
</View>
|
|
1181
|
+
)}
|
|
1182
|
+
|
|
1150
1183
|
{appContext.identificationInfo.livenessDetection?.videoPath && (
|
|
1151
1184
|
<>
|
|
1152
1185
|
<Text style={styles.sectionHeader}>
|
|
@@ -1472,6 +1505,32 @@ const styles = StyleSheet.create({
|
|
|
1472
1505
|
lineHeight: 14,
|
|
1473
1506
|
color: '#1F2937',
|
|
1474
1507
|
},
|
|
1508
|
+
addressSection: {
|
|
1509
|
+
marginTop: 16,
|
|
1510
|
+
padding: 12,
|
|
1511
|
+
backgroundColor: '#F3F4F6',
|
|
1512
|
+
borderRadius: 8,
|
|
1513
|
+
borderWidth: 1,
|
|
1514
|
+
borderColor: '#D1D5DB',
|
|
1515
|
+
},
|
|
1516
|
+
addressText: {
|
|
1517
|
+
fontSize: 14,
|
|
1518
|
+
lineHeight: 20,
|
|
1519
|
+
color: '#1F2937',
|
|
1520
|
+
},
|
|
1521
|
+
addressProofLabel: {
|
|
1522
|
+
fontSize: 12,
|
|
1523
|
+
fontWeight: '600',
|
|
1524
|
+
color: '#6B7280',
|
|
1525
|
+
marginTop: 12,
|
|
1526
|
+
marginBottom: 8,
|
|
1527
|
+
},
|
|
1528
|
+
addressProofImage: {
|
|
1529
|
+
width: '100%',
|
|
1530
|
+
// Portrait frame so the whole document shows upright, letterboxed not cropped.
|
|
1531
|
+
aspectRatio: 3 / 4,
|
|
1532
|
+
borderRadius: 8,
|
|
1533
|
+
},
|
|
1475
1534
|
trustchexLogo: {
|
|
1476
1535
|
width: 150,
|
|
1477
1536
|
height: 75,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"nm":"Search","ddd":0,"h":500,"w":500,"meta":{"g":"@lottiefiles/toolkit-js 0.25.8"},"layers":[{"ty":4,"nm":"Check Middle","sr":1,"st":-60,"op":145,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.134,"y":1},"s":[100,100,100],"t":4},{"s":[69,69,100],"t":16}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[250,250,0],"t":2,"ti":[33,0,0],"to":[-33,0,0]},{"s":[52,250,0],"t":14}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":2},{"s":[0],"t":20}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.5,11.5],[-11,50.5],[60.5,-34.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"c":{"a":0,"k":[0.0627,0.7255,0.5059],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Check Right","sr":1,"st":-2,"op":144,"ip":58,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.5,11.5],[-11,50.5],[60.5,-34.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"c":{"a":0,"k":[0.0627,0.7255,0.5059],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":58},{"s":[100],"t":65}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":2},{"ty":4,"nm":"Magnifying Glass","sr":1,"st":0,"op":144,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[86,86,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[-31.335,-31.31,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-29.547],[29.547,0],[0,29.547],[-29.547,0]],"o":[[0,29.547],[-29.547,0],[0,-29.547],[29.547,0]],"v":[[53.5,0],[0,53.5],[-53.5,0],[0,-53.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13,"ix":5},"c":{"a":0,"k":[0.0627,0.7255,0.5059],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[86,86],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3,"parent":4},{"ty":4,"nm":"Handle","sr":1,"st":0,"op":144,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-30.17,-31.17,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.394,"y":1},"s":[648.829,532.045,0],"t":18,"ti":[33.833,65.833,0],"to":[-71.333,-60.333,0]},{"o":{"x":0.333,"y":0.333},"i":{"x":0.667,"y":0.667},"s":[220.829,170.045,0],"t":24,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.216,"y":0},"i":{"x":0,"y":1},"s":[220.829,170.045,0],"t":28,"ti":[-17.667,-10.167,0],"to":[13.667,-11.333,0]},{"o":{"x":0.851,"y":0.851},"i":{"x":0,"y":0},"s":[284.829,168.045,0],"t":32,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.375,"y":0},"i":{"x":0.057,"y":1},"s":[284.829,168.045,0],"t":34,"ti":[-2.631,-12.748,0],"to":[1.667,31.5,0]},{"o":{"x":0.981,"y":0},"i":{"x":0.826,"y":1},"s":[216.829,246.045,0],"t":37,"ti":[-9.667,-12,0],"to":[4.333,21,0]},{"o":{"x":0.333,"y":0.333},"i":{"x":0.667,"y":0.667},"s":[280.829,246.045,0],"t":41,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.333,"y":0},"i":{"x":0.04,"y":1},"s":[280.829,246.045,0],"t":44,"ti":[-1,-13,0],"to":[-2.167,23.667,0]},{"o":{"x":0.871,"y":0},"i":{"x":0.667,"y":1},"s":[222.829,322.045,0],"t":48,"ti":[-10.667,-0.333,0],"to":[1,13,0]},{"o":{"x":0.333,"y":0.333},"i":{"x":0.667,"y":0.667},"s":[286.829,324.045,0],"t":54,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.923,"y":0},"i":{"x":0.667,"y":1},"s":[286.829,324.045,0],"t":56,"ti":[-60.667,-35.333,0],"to":[60.667,35.333,0]},{"s":[650.829,536.045,0],"t":60}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.221,1.12],[0,0],[1.122,-1.22],[0,0],[-1.221,-1.121],[0,0],[-1.12,1.221],[0,0]],"o":[[0,0],[-1.221,-1.12],[0,0],[-1.121,1.221],[0,0],[1.22,1.121],[0,0],[1.121,-1.219]],"v":[[46.352,42.076],[-23.804,-22.35],[-28.044,-22.169],[-36.836,-12.594],[-36.656,-8.355],[33.501,56.07],[37.74,55.889],[46.533,46.314]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0627,0.7255,0.5059],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[38.207,23.72],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Profile","sr":1,"st":4,"op":144,"ip":9,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[21.129,20.971,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,100],"t":9},{"s":[93.913,93.913,100],"t":15}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[37.904,43.851,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Profile","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[3.642,0],[0,0],[0,3.642],[0,0],[-3.643,0],[0,0],[0,-3.642],[0,0]],"o":[[0,0],[-3.643,0],[0,0],[0,-3.642],[0,0],[3.642,0],[0,0],[0,3.642]],"v":[[14.126,20.72],[-14.126,20.72],[-20.721,14.126],[-20.721,-14.126],[-14.126,-20.72],[14.126,-20.72],[20.721,-14.126],[20.721,14.126]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[21.129,20.971],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5,"parent":13},{"ty":4,"nm":"Line 1","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[50.672,13.223,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":10},{"s":[93.883,93.883,100],"t":16}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[65.64,36.578,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":10},{"s":[100],"t":16}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[20.074,4.963],[-20.074,4.963],[-23.074,1.963],[-23.074,-1.963],[-20.074,-4.963],[20.074,-4.963],[23.074,-1.963],[23.074,1.963]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9529,0.9569,0.9647],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[73.746,13.223],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6,"parent":13},{"ty":4,"nm":"Line 2","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[50.421,32.288,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":11},{"s":[93.883,93.883,100],"t":17}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[65.972,54.476,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":11},{"s":[100],"t":17}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 2","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.658],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.658],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[20.576,4.962],[-20.576,4.962],[-23.576,1.962],[-23.576,-1.962],[-20.576,-4.962],[20.576,-4.962],[23.576,-1.962],[23.576,1.962]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[73.996,32.288],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":7,"parent":13},{"ty":4,"nm":"Line 3","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.501,60.383,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":12},{"s":[93.883,93.883,100],"t":18}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[18.539,80.853,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":12},{"s":[100],"t":18}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 3","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[45.159,4.963],[-45.159,4.963],[-48.159,1.963],[-48.159,-1.963],[-45.159,-4.963],[45.159,-4.963],[48.159,-1.963],[48.159,1.963]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[48.66,60.383],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":8,"parent":13},{"ty":4,"nm":"Line 4","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.752,83.963,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":13},{"s":[93.883,93.883,100],"t":19}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[18.774,102.99,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":13},{"s":[100],"t":19}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 4","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[45.034,4.962],[-45.034,4.962],[-48.034,1.962],[-48.034,-1.962],[-45.034,-4.962],[45.034,-4.962],[48.034,-1.962],[48.034,1.962]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[48.786,83.963],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":9,"parent":13},{"ty":4,"nm":"Line 5","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.25,107.543,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":14},{"s":[93.883,93.883,100],"t":20}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[18.303,125.128,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":14},{"s":[100],"t":20}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 5","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[45.661,4.962],[-45.661,4.962],[-48.661,1.962],[-48.661,-1.962],[-45.661,-4.962],[45.661,-4.962],[48.661,-1.962],[48.661,1.962]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[48.911,107.543],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":10,"parent":13},{"ty":4,"nm":"Line 6","sr":1,"st":5,"op":144,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.25,131.876,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":15},{"s":[93.883,93.883,100],"t":21}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[18.303,147.972,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":15},{"s":[100],"t":21}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 6","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.656],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.656],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[45.661,4.963],[-45.661,4.963],[-48.661,1.963],[-48.661,-1.963],[-45.661,-4.963],[45.661,-4.963],[48.661,-1.963],[48.661,1.963]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[48.911,131.876],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":11,"parent":13},{"ty":4,"nm":"Line 7","sr":1,"st":5,"op":145,"ip":10,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.501,155.958,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,93.883,100],"t":16},{"s":[93.883,93.883,100],"t":22}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[18.539,170.581,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":16},{"s":[100],"t":22}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Line 7","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.656],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.656]],"v":[[45.159,4.963],[-45.159,4.963],[-48.159,1.963],[-48.159,-1.963],[-45.159,-4.963],[45.159,-4.963],[48.159,-1.963],[48.159,1.963]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[48.66,155.958],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":12,"parent":13},{"ty":4,"nm":"Right Page 1","sr":1,"st":-6,"op":145,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[64.304,101.087,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,94.05,100],"t":4},{"s":[138,138,100],"t":16}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[435.776,247,0],"t":4,"ti":[30.833,-0.003,0],"to":[-30.833,0.003,0]},{"s":[250.776,247.017,0],"t":16}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.048,0],[0,0],[0,7.048],[0,0],[-7.048,0],[0,0],[0,-7.048],[0,0]],"o":[[0,0],[-7.048,0],[0,0],[0,-7.048],[0,0],[7.048,0],[0,0],[0,7.048]],"v":[[51.292,100.837],[-51.293,100.837],[-64.054,88.076],[-64.054,-88.076],[-51.293,-100.837],[51.292,-100.837],[64.054,-88.076],[64.054,88.076]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0.9176,0.9176,0.9176],"t":4},{"s":[1,1,1],"t":16}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[101.747,96.634],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.304,101.087],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":13},{"ty":4,"nm":"Right Page 2","sr":1,"st":4,"op":148,"ip":4,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[64.304,101.087,0],"ix":1},"s":{"a":0,"k":[100,88.1,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[575.776,252.017,0],"t":8,"ti":[23.333,0.833,0],"to":[-23.333,-0.833,0]},{"s":[435.776,247.017,0],"t":20}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 9","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.048,0],[0,0],[0,7.048],[0,0],[-7.048,0],[0,0],[0,-7.047],[0,0]],"o":[[0,0],[-7.048,0],[0,0],[0,-7.047],[0,0],[7.048,0],[0,0],[0,7.048]],"v":[[51.292,100.837],[-51.293,100.837],[-64.054,88.076],[-64.054,-88.076],[-51.293,-100.837],[51.292,-100.837],[64.054,-88.076],[64.054,88.076]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.898,0.9059,0.9216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.304,101.087],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":14},{"ty":4,"nm":"Left Page 1","sr":1,"st":0,"op":145,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[64.303,101.087,0],"ix":1},"s":{"a":0,"k":[100,93.058,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[64.898,247.073,0],"t":-2,"ti":[26.333,0,0],"to":[-26.333,0,0]},{"s":[-93.102,247.073,0],"t":10}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.048,0],[0,0],[0,7.048],[0,0],[-7.048,0],[0,0],[0,-7.048],[0,0]],"o":[[0,0],[-7.048,0],[0,0],[0,-7.048],[0,0],[7.048,0],[0,0],[0,7.048]],"v":[[51.293,100.837],[-51.292,100.837],[-64.053,88.075],[-64.053,-88.076],[-51.292,-100.837],[51.293,-100.837],[64.054,-88.076],[64.054,88.075]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9176,0.9176,0.9176],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.303,101.087],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":15},{"ty":4,"nm":"Middle Text","sr":1,"st":0,"op":144,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[64.911,107,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100,100,100],"t":3},{"s":[75,75,100],"t":15}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[249.339,244.683,0],"t":2,"ti":[30.667,0,0],"to":[-30.667,0,0]},{"s":[65.339,244.683,0],"t":14}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":2},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":8},{"s":[0],"t":14}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[3.642,0],[0,0],[0,3.642],[0,0],[-3.642,0],[0,0],[0,-3.642],[0,0]],"o":[[0,0],[-3.642,0],[0,0],[0,-3.642],[0,0],[3.642,0],[0,0],[0,3.642]],"v":[[20.939,27.533],[-20.939,27.533],[-27.534,20.939],[-27.534,-20.939],[-20.939,-27.533],[20.939,-27.533],[27.534,-20.939],[27.534,20.939]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[27.993,27.784],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 2","ix":2,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.656],[0,0],[-1.657,0],[0,0],[0,-1.658],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.658],[0,0],[1.657,0],[0,0],[0,1.656]],"v":[[61.661,6.594],[-61.661,6.594],[-64.661,3.594],[-64.661,-3.594],[-61.661,-6.594],[61.661,-6.594],[64.661,-3.594],[64.661,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.911,142.822],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 3","ix":3,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[60.827,6.594],[-60.827,6.594],[-63.827,3.594],[-63.827,-3.594],[-60.827,-6.594],[60.827,-6.594],[63.827,-3.594],[63.827,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.744,111.488],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 4","ix":4,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.658,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[28.327,6.594],[-28.327,6.594],[-31.327,3.594],[-31.327,-3.594],[-28.327,-6.594],[28.327,-6.594],[31.327,-3.594],[31.327,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[98.244,42.822],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 5","ix":5,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[27.661,6.594],[-27.661,6.594],[-30.661,3.594],[-30.661,-3.594],[-27.661,-6.594],[27.661,-6.594],[30.661,-3.594],[30.661,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[97.911,17.489],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 6","ix":6,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[60.995,6.594],[-60.995,6.594],[-63.995,3.594],[-63.995,-3.594],[-60.995,-6.594],[60.995,-6.594],[63.995,-3.594],[63.995,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.577,80.155],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 7","ix":7,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[61.661,6.594],[-61.661,6.594],[-64.661,3.594],[-64.661,-3.594],[-61.661,-6.594],[61.661,-6.594],[64.661,-3.594],[64.661,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.911,175.155],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 8","ix":8,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[1.657,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0]],"o":[[0,0],[-1.657,0],[0,0],[0,-1.657],[0,0],[1.657,0],[0,0],[0,1.657]],"v":[[60.995,6.594],[-60.995,6.594],[-63.995,3.594],[-63.995,-3.594],[-60.995,-6.594],[60.995,-6.594],[63.995,-3.594],[63.995,3.594]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8471,0.8471,0.8471],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[64.577,207.155],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":16},{"ty":4,"nm":"Middle Page","sr":1,"st":0,"op":144,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[91.789,134.239,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.392,"y":0},"i":{"x":0.598,"y":1},"s":[100,100,100],"t":3},{"s":[69,69,100],"t":15}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.377,"y":0},"i":{"x":0.667,"y":1},"s":[227.461,246.517,0],"t":2,"ti":[30.167,0,0],"to":[-30.167,0,0]},{"s":[46.461,246.517,0],"t":14}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.048,0],[0,0],[0,7.048],[0,0],[-7.047,0],[0,0],[0,-7.048],[0,0]],"o":[[0,0],[-7.047,0],[0,0],[0,-7.048],[0,0],[7.048,0],[0,0],[0,7.048]],"v":[[78.779,133.989],[-78.779,133.989],[-91.539,121.227],[-91.539,-121.228],[-78.779,-133.989],[78.779,-133.989],[91.539,-121.228],[91.539,121.227]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 2","c":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[1,1,1],"t":2},{"s":[0.9529,0.9569,0.9647],"t":14}],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[115.102,134.239],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":17},{"ty":4,"nm":"Circle","sr":1,"st":0,"op":144,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[168.508,168.508,0],"ix":1},"s":{"a":0,"k":[115.452,115.452,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[246.09,247.079,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-92.927],[92.927,0],[0,92.926],[-92.927,0]],"o":[[0,92.926],[-92.927,0],[0,-92.927],[92.927,0]],"v":[[168.258,0],[-0.001,168.258],[-168.258,0],[-0.001,-168.258]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9647,0.9725,1],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[168.508,168.508],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":18}],"v":"5.4.4","fr":24,"op":72,"ip":0,"assets":[]}
|
|
@@ -210,6 +210,19 @@ const DebugNavigationPanel = () => {
|
|
|
210
210
|
}
|
|
211
211
|
},
|
|
212
212
|
},
|
|
213
|
+
{
|
|
214
|
+
screen: 'AddressCaptureScreen',
|
|
215
|
+
label: 'Address',
|
|
216
|
+
setupDemo: () => {
|
|
217
|
+
setupDemoSession(true);
|
|
218
|
+
const step = appContext.workflowSteps?.find(
|
|
219
|
+
(s) => s.type === 'ADDRESS_CAPTURE'
|
|
220
|
+
);
|
|
221
|
+
if (step) {
|
|
222
|
+
appContext.currentWorkflowStep = step;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
},
|
|
213
226
|
{
|
|
214
227
|
screen: 'LivenessDetectionScreen',
|
|
215
228
|
label: 'Liveness',
|
|
@@ -19,7 +19,11 @@ import { eidReader } from '../EIDReader/eidReader';
|
|
|
19
19
|
import NativeProgressBar from './NativeProgressBar';
|
|
20
20
|
import type { MRZFields } from '../Types/mrzFields';
|
|
21
21
|
import { buildDocumentName } from '../Libs/mrzTransliteration';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
recoverVizName,
|
|
24
|
+
recognizeVizBlocks,
|
|
25
|
+
voteVizName,
|
|
26
|
+
} from '../Libs/vizName';
|
|
23
27
|
import type { DocumentName } from '../Types/documentReadResult';
|
|
24
28
|
import {
|
|
25
29
|
normalizeFromMRZInfo,
|
|
@@ -59,11 +63,16 @@ interface eIDScannerProps {
|
|
|
59
63
|
*/
|
|
60
64
|
vizMrzFields?: MRZFields;
|
|
61
65
|
/**
|
|
62
|
-
* Full data-page image from the EID step's camera scan.
|
|
63
|
-
*
|
|
66
|
+
* Full data-page image(s) from the EID step's camera scan. Each is OCR'd to
|
|
67
|
+
* recover the diacritic printed name when the chip's DG11 is absent or
|
|
64
68
|
* one-sided — DG11 (the authenticated chip's own name) still takes precedence.
|
|
69
|
+
* When more than one image is available (e.g. passport page + ID front/back),
|
|
70
|
+
* the recovered names are fused by majority vote so a single noisy OCR pass
|
|
71
|
+
* can't corrupt the result.
|
|
65
72
|
*/
|
|
66
73
|
vizImage?: string;
|
|
74
|
+
/** Additional VIZ images to OCR and vote over, alongside `vizImage`. */
|
|
75
|
+
vizImages?: (string | undefined)[];
|
|
67
76
|
onScanSuccess?: (
|
|
68
77
|
mrzInfo: MRZFields,
|
|
69
78
|
faceImage: string,
|
|
@@ -79,6 +88,7 @@ const EIDScanner = ({
|
|
|
79
88
|
documentType,
|
|
80
89
|
vizMrzFields,
|
|
81
90
|
vizImage,
|
|
91
|
+
vizImages,
|
|
82
92
|
onScanSuccess,
|
|
83
93
|
isNFCSupported,
|
|
84
94
|
}: eIDScannerProps) => {
|
|
@@ -354,20 +364,36 @@ const EIDScanner = ({
|
|
|
354
364
|
const dg11HasBothNames =
|
|
355
365
|
!!passportData.dg11FirstName && !!passportData.dg11LastName;
|
|
356
366
|
// Only OCR the VIZ when DG11 didn't already provide a clean name.
|
|
357
|
-
|
|
358
|
-
|
|
367
|
+
// OCR every available image (data page + ID front/back) and fuse the
|
|
368
|
+
// recovered names by majority vote, so one noisy OCR pass can't corrupt
|
|
369
|
+
// the diacritic name. De-dup images so the same capture isn't voted
|
|
370
|
+
// twice (which would let a single pass outvote the others).
|
|
371
|
+
const vizSources = !dg11HasBothNames
|
|
372
|
+
? Array.from(
|
|
373
|
+
new Set([vizImage, ...(vizImages ?? [])].filter(Boolean))
|
|
374
|
+
)
|
|
359
375
|
: [];
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
376
|
+
const perImage = await Promise.all(
|
|
377
|
+
vizSources.map(async (img) => {
|
|
378
|
+
const blocks = await recognizeVizBlocks(img);
|
|
379
|
+
if (!blocks.length) return null;
|
|
380
|
+
return recoverVizName(
|
|
381
|
+
blocks,
|
|
363
382
|
documentData.firstName,
|
|
364
383
|
documentData.lastName,
|
|
365
|
-
Math.max(...
|
|
366
|
-
|
|
367
|
-
|
|
384
|
+
Math.max(...blocks.map((b) => b.top)),
|
|
385
|
+
documentData.issuingCountry
|
|
386
|
+
);
|
|
387
|
+
})
|
|
388
|
+
);
|
|
389
|
+
const candidates = perImage.filter(
|
|
390
|
+
(c): c is NonNullable<typeof c> => c !== null
|
|
391
|
+
);
|
|
392
|
+
const viz = candidates.length ? voteVizName(candidates) : null;
|
|
368
393
|
debugLog('VIZName', 'eid recovery', {
|
|
369
394
|
dg11HasBothNames,
|
|
370
|
-
|
|
395
|
+
sources: vizSources.length,
|
|
396
|
+
candidates: candidates.length,
|
|
371
397
|
matchedFirst: !!viz?.vizFirst,
|
|
372
398
|
matchedLast: !!viz?.vizLast,
|
|
373
399
|
mismatch: viz?.mismatch ?? false,
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
hasRequiredMRZFields,
|
|
51
51
|
validateFacePosition,
|
|
52
52
|
isPassportDocumentCode,
|
|
53
|
+
StableFlag,
|
|
53
54
|
} from './IdentityDocumentCamera.utils';
|
|
54
55
|
import {
|
|
55
56
|
handlePassportFlow,
|
|
@@ -175,6 +176,31 @@ const IdentityDocumentCamera = ({
|
|
|
175
176
|
const consecutiveQualityFailures = useRef(0);
|
|
176
177
|
const mrzDetectionCurrentRetryCount = useRef(0);
|
|
177
178
|
|
|
179
|
+
// Hysteresis for the on-screen quality guidance. Brightness/blur/glare are
|
|
180
|
+
// measured every frame; feeding the raw per-frame booleans straight into
|
|
181
|
+
// state made the guidance strobe (a single blurry hand-shake frame flipped
|
|
182
|
+
// "hold steady" on and off). These smooth each flag: it appears after a few
|
|
183
|
+
// confirming frames and lingers briefly before clearing, so the message is
|
|
184
|
+
// stable and only reflects a sustained condition. Raise fast (react to real
|
|
185
|
+
// problems), clear slow (don't flicker off on one good frame).
|
|
186
|
+
const brightnessLowFlag = useRef(new StableFlag(2, 5));
|
|
187
|
+
const blurryFlag = useRef(new StableFlag(3, 6));
|
|
188
|
+
const glareFlag = useRef(new StableFlag(2, 5));
|
|
189
|
+
// Glare is asserted by accept-time helpers that run inside the (separately
|
|
190
|
+
// scoped) handleFaceAndText callback, so it can't flow through a handler
|
|
191
|
+
// local. This ref is cleared at the top of each frame and set true if any
|
|
192
|
+
// glare check in that frame found glare; the handler reads it to feed
|
|
193
|
+
// `glareFlag`. `hadGlareText` distinguishes "card present but glaring" from
|
|
194
|
+
// an empty view so the warning only shows over an actual document.
|
|
195
|
+
const rawGlareRef = useRef(false);
|
|
196
|
+
// Whether a document was visible in the PREVIOUS frame (recognized text,
|
|
197
|
+
// barcode, or face). The quality guidance is stabilized BEFORE the quality
|
|
198
|
+
// gate (so dark/blurry frames — which the gate early-returns on — can still
|
|
199
|
+
// raise their warnings), but document-presence is only known LATER in the
|
|
200
|
+
// frame, so blur/glare are gated on the previous frame's value. One-frame lag
|
|
201
|
+
// at ~8fps is imperceptible and the hysteresis smooths it.
|
|
202
|
+
const documentPresentRef = useRef(false);
|
|
203
|
+
|
|
178
204
|
// MRZ stability tracking - require consistent valid reads
|
|
179
205
|
const lastValidMRZText = useRef<string | null>(null);
|
|
180
206
|
const lastValidMRZFields = useRef<any>(null);
|
|
@@ -618,8 +644,13 @@ const IdentityDocumentCamera = ({
|
|
|
618
644
|
100, // Full face height
|
|
619
645
|
MAX_BRIGHTNESS_THRESHOLD
|
|
620
646
|
);
|
|
621
|
-
|
|
622
|
-
|
|
647
|
+
// OR-accumulate into the per-frame glare signal (reset at frame top); the
|
|
648
|
+
// frame handler feeds it through the stabilized UI flag. Also record the
|
|
649
|
+
// diagnostic.
|
|
650
|
+
if (hasGlare) {
|
|
651
|
+
rawGlareRef.current = true;
|
|
652
|
+
diagStats.current.hadGlare = true;
|
|
653
|
+
}
|
|
623
654
|
return hasGlare;
|
|
624
655
|
} catch (error) {
|
|
625
656
|
return false; // Assume no glare on error
|
|
@@ -658,8 +689,13 @@ const IdentityDocumentCamera = ({
|
|
|
658
689
|
Math.round(height * 0.8),
|
|
659
690
|
MAX_BRIGHTNESS_THRESHOLD
|
|
660
691
|
);
|
|
661
|
-
|
|
662
|
-
|
|
692
|
+
// OR-accumulate into the per-frame glare signal (reset at frame top); the
|
|
693
|
+
// frame handler feeds it through the stabilized UI flag. Also record the
|
|
694
|
+
// diagnostic.
|
|
695
|
+
if (hasGlare) {
|
|
696
|
+
rawGlareRef.current = true;
|
|
697
|
+
diagStats.current.hadGlare = true;
|
|
698
|
+
}
|
|
663
699
|
return hasGlare;
|
|
664
700
|
} catch (error) {
|
|
665
701
|
return false;
|
|
@@ -740,6 +776,16 @@ const IdentityDocumentCamera = ({
|
|
|
740
776
|
}
|
|
741
777
|
validMRZConsecutiveCount.current = 0;
|
|
742
778
|
cachedBarcode.current = null; // Clear cached barcode on step change
|
|
779
|
+
// Start each step with clean, non-flickering guidance (no stale warning
|
|
780
|
+
// carried over from the previous side).
|
|
781
|
+
brightnessLowFlag.current.reset(false);
|
|
782
|
+
blurryFlag.current.reset(false);
|
|
783
|
+
glareFlag.current.reset(false);
|
|
784
|
+
rawGlareRef.current = false;
|
|
785
|
+
documentPresentRef.current = false;
|
|
786
|
+
setIsBrightnessLow(false);
|
|
787
|
+
setIsFrameBlurry(false);
|
|
788
|
+
setIsGlareDetected(false);
|
|
743
789
|
|
|
744
790
|
if (nextStepType !== 'COMPLETED') {
|
|
745
791
|
setTimeout(() => {
|
|
@@ -2082,17 +2128,25 @@ const IdentityDocumentCamera = ({
|
|
|
2082
2128
|
isRegionBright = isOverallBright;
|
|
2083
2129
|
}
|
|
2084
2130
|
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
//
|
|
2089
|
-
//
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
//
|
|
2094
|
-
//
|
|
2095
|
-
|
|
2131
|
+
// Raw per-frame quality readings. The UI-facing warnings are NOT set from
|
|
2132
|
+
// these directly — they are stabilized (hysteresis) and gated on document
|
|
2133
|
+
// presence at the end of the handler so the guidance doesn't strobe or nag
|
|
2134
|
+
// over an empty view. The raw values still feed the frame-processing
|
|
2135
|
+
// quality gate below unchanged.
|
|
2136
|
+
const rawBrightnessLow = !isRegionBright;
|
|
2137
|
+
if (rawBrightnessLow) diagStats.current.hadLowBrightness = true;
|
|
2138
|
+
|
|
2139
|
+
// Per-frame glare is asserted by the accept-time helpers (checkDocumentGlare
|
|
2140
|
+
// /checkFaceGlare), but those run inside handleFaceAndText which is fired
|
|
2141
|
+
// (async, un-awaited) LATER in this handler — so this frame's glare result
|
|
2142
|
+
// isn't known yet at the stabilization block below. We therefore feed the
|
|
2143
|
+
// stabilizer the PREVIOUS frame's glare signal (captured here before the
|
|
2144
|
+
// reset). At ~8fps the one-frame lag is imperceptible and the hysteresis
|
|
2145
|
+
// smooths it anyway; without this the read would always see false and the
|
|
2146
|
+
// glare warning could never fire. Reset after capturing so a now-clean
|
|
2147
|
+
// view clears (no latch).
|
|
2148
|
+
const prevFrameGlare = rawGlareRef.current;
|
|
2149
|
+
rawGlareRef.current = false;
|
|
2096
2150
|
|
|
2097
2151
|
// Check blur only in center region (area of interest) to avoid false positives
|
|
2098
2152
|
// from iOS depth-of-field background blur
|
|
@@ -2110,10 +2164,9 @@ const IdentityDocumentCamera = ({
|
|
|
2110
2164
|
50 // threshold
|
|
2111
2165
|
);
|
|
2112
2166
|
isNotBlurry = !isBlurry;
|
|
2113
|
-
setIsFrameBlurry(isBlurry);
|
|
2114
2167
|
if (isBlurry) diagStats.current.hadBlurryFrames = true;
|
|
2115
2168
|
} catch (error) {
|
|
2116
|
-
|
|
2169
|
+
isBlurry = false;
|
|
2117
2170
|
}
|
|
2118
2171
|
|
|
2119
2172
|
// Flush accumulated camera stats into the diagnostics collector.
|
|
@@ -2140,6 +2193,35 @@ const IdentityDocumentCamera = ({
|
|
|
2140
2193
|
// Only proceed if image quality is acceptable
|
|
2141
2194
|
const hasAcceptableQuality = isRegionBright && isNotBlurry;
|
|
2142
2195
|
|
|
2196
|
+
// --- Stabilized, presence-gated quality guidance -------------------
|
|
2197
|
+
// MUST run BEFORE the quality-gate early-return below: a dark or blurry
|
|
2198
|
+
// frame is exactly what makes hasAcceptableQuality false, so if this ran
|
|
2199
|
+
// after the gate the "too dark" / "hold steady" warnings could never
|
|
2200
|
+
// raise (their triggering frames would have already returned). Blur/glare
|
|
2201
|
+
// are gated on document presence; brightness shows regardless, since a
|
|
2202
|
+
// dark room is worth flagging before the card is even framed.
|
|
2203
|
+
//
|
|
2204
|
+
// Presence combines the previous frame's confirmed value (documentPresent-
|
|
2205
|
+
// Ref, set post-detection) with a CHEAP raw-frame proxy read directly off
|
|
2206
|
+
// the native ML Kit results (faces/text/barcodes are on `frame` before any
|
|
2207
|
+
// processing). Without the raw proxy, a document that is blurry/dark from
|
|
2208
|
+
// its very first framed moment would keep failing the quality gate and
|
|
2209
|
+
// early-returning before documentPresentRef is ever set true — suppressing
|
|
2210
|
+
// its blur/glare hints for ~30 frames. The proxy lets the hint fire on the
|
|
2211
|
+
// first framed frame.
|
|
2212
|
+
const rawDocumentPresent =
|
|
2213
|
+
(frame.faces?.length ?? 0) > 0 ||
|
|
2214
|
+
(frame.textBlocks?.length ?? 0) > 0 ||
|
|
2215
|
+
(frame.barcodes?.length ?? 0) > 0;
|
|
2216
|
+
const documentWasPresent =
|
|
2217
|
+
documentPresentRef.current || rawDocumentPresent;
|
|
2218
|
+
setIsBrightnessLow(brightnessLowFlag.current.push(rawBrightnessLow));
|
|
2219
|
+
setIsFrameBlurry(blurryFlag.current.push(documentWasPresent && isBlurry));
|
|
2220
|
+
setIsGlareDetected(
|
|
2221
|
+
glareFlag.current.push(documentWasPresent && prevFrameGlare)
|
|
2222
|
+
);
|
|
2223
|
+
// -------------------------------------------------------------------
|
|
2224
|
+
|
|
2143
2225
|
// Store quality metrics in ref for access in handleFaceAndText callback
|
|
2144
2226
|
lastFrameQuality.current = {
|
|
2145
2227
|
hasAcceptableQuality,
|
|
@@ -2442,6 +2524,16 @@ const IdentityDocumentCamera = ({
|
|
|
2442
2524
|
setAllElementsDetected(false);
|
|
2443
2525
|
}
|
|
2444
2526
|
|
|
2527
|
+
// Record whether a document is present THIS frame (recognized text, a
|
|
2528
|
+
// barcode, or a face) so next frame's blur/glare gating can read it.
|
|
2529
|
+
// The stabilized guidance itself is set earlier, before the quality
|
|
2530
|
+
// gate — see the block above `hasAcceptableQuality`.
|
|
2531
|
+
documentPresentRef.current =
|
|
2532
|
+
textBlocks.length > 0 ||
|
|
2533
|
+
barcodes.length > 0 ||
|
|
2534
|
+
detectedFaces.length > 0 ||
|
|
2535
|
+
cachedBarcode.current !== null;
|
|
2536
|
+
|
|
2445
2537
|
// Check if detected elements are inside the scan area
|
|
2446
2538
|
const { scanLeft, scanTop, scanRight, scanBottom, isInsideScan } =
|
|
2447
2539
|
getScanAreaBounds(frame.width, frame.height);
|
|
@@ -13,6 +13,59 @@ import {
|
|
|
13
13
|
} from './IdentityDocumentCamera.constants';
|
|
14
14
|
import { debugLog, isDebugEnabled } from '../Libs/debug.utils';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Debounced boolean with hysteresis, for stabilizing per-frame quality flags.
|
|
18
|
+
*
|
|
19
|
+
* The camera measures brightness/blur/glare on EVERY frame, and a single noisy
|
|
20
|
+
* frame (a momentary blur while the hand moves, one dark frame) would otherwise
|
|
21
|
+
* flip the on-screen guidance on and off many times a second — a distracting
|
|
22
|
+
* flicker. This smooths a raw per-frame boolean so it only turns ON after
|
|
23
|
+
* `raiseFrames` consecutive true readings and only turns OFF after `clearFrames`
|
|
24
|
+
* consecutive false readings; isolated opposite frames are absorbed. Asymmetric
|
|
25
|
+
* by design: warnings should appear promptly once a problem is real (small
|
|
26
|
+
* `raiseFrames`) but linger briefly so they don't strobe (larger `clearFrames`).
|
|
27
|
+
*/
|
|
28
|
+
export class StableFlag {
|
|
29
|
+
private value: boolean;
|
|
30
|
+
private streak = 0;
|
|
31
|
+
private lastRaw: boolean;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
private readonly raiseFrames: number,
|
|
35
|
+
private readonly clearFrames: number,
|
|
36
|
+
initial = false
|
|
37
|
+
) {
|
|
38
|
+
this.value = initial;
|
|
39
|
+
this.lastRaw = initial;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Feed one raw measurement; returns the current stabilized value. */
|
|
43
|
+
push(raw: boolean): boolean {
|
|
44
|
+
if (raw === this.lastRaw) {
|
|
45
|
+
this.streak++;
|
|
46
|
+
} else {
|
|
47
|
+
this.streak = 1;
|
|
48
|
+
this.lastRaw = raw;
|
|
49
|
+
}
|
|
50
|
+
if (raw !== this.value) {
|
|
51
|
+
const needed = raw ? this.raiseFrames : this.clearFrames;
|
|
52
|
+
if (this.streak >= needed) this.value = raw;
|
|
53
|
+
}
|
|
54
|
+
return this.value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Force the stabilized value (e.g. on step change) without waiting. */
|
|
58
|
+
reset(value: boolean): void {
|
|
59
|
+
this.value = value;
|
|
60
|
+
this.lastRaw = value;
|
|
61
|
+
this.streak = 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get current(): boolean {
|
|
65
|
+
return this.value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
16
69
|
/**
|
|
17
70
|
* Checks if a document code represents an ID card (TD1/TD2).
|
|
18
71
|
* Per ICAO 9303, valid ID card codes start with 'I', 'A', or 'C'.
|