@prosopo/provider 3.3.0 → 3.12.14

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.
Files changed (377) hide show
  1. package/CHANGELOG.md +718 -0
  2. package/coverage/base.css +224 -0
  3. package/coverage/block-navigation.js +87 -0
  4. package/coverage/clover.xml +4278 -0
  5. package/coverage/coverage-final.json +42 -0
  6. package/coverage/favicon.png +0 -0
  7. package/coverage/index.html +311 -0
  8. package/coverage/prettify.css +1 -0
  9. package/coverage/prettify.js +2 -0
  10. package/coverage/sort-arrow-sprite.png +0 -0
  11. package/coverage/sorter.js +210 -0
  12. package/coverage/src/api/admin/apiAdminRoutesProvider.ts.html +214 -0
  13. package/coverage/src/api/admin/apiRegisterSiteKeyEndpoint.ts.html +259 -0
  14. package/coverage/src/api/admin/apiRemoveDetectorKeyEndpoint.ts.html +283 -0
  15. package/coverage/src/api/admin/apiToggleMaintenanceModeEndpoint.ts.html +334 -0
  16. package/coverage/src/api/admin/apiUpdateDetectorKeyEndpoint.ts.html +298 -0
  17. package/coverage/src/api/admin/createApiAdminRoutesProvider.ts.html +163 -0
  18. package/coverage/src/api/admin/index.html +191 -0
  19. package/coverage/src/api/blacklistRequestInspector.ts.html +751 -0
  20. package/coverage/src/api/block.ts.html +187 -0
  21. package/coverage/src/api/captcha.ts.html +2803 -0
  22. package/coverage/src/api/domainMiddleware.ts.html +493 -0
  23. package/coverage/src/api/headerCheckMiddleware.ts.html +256 -0
  24. package/coverage/src/api/ignoreMiddleware.ts.html +181 -0
  25. package/coverage/src/api/index.html +266 -0
  26. package/coverage/src/api/ja4Middleware.ts.html +400 -0
  27. package/coverage/src/api/public.ts.html +343 -0
  28. package/coverage/src/api/robotsMiddleware.ts.html +157 -0
  29. package/coverage/src/api/validateAddress.ts.html +214 -0
  30. package/coverage/src/api/verify.ts.html +871 -0
  31. package/coverage/src/compositeIpAddress.ts.html +340 -0
  32. package/coverage/src/index.html +161 -0
  33. package/coverage/src/index.ts.html +175 -0
  34. package/coverage/src/pairs.ts.html +238 -0
  35. package/coverage/src/rules/index.html +116 -0
  36. package/coverage/src/rules/lang.ts.html +187 -0
  37. package/coverage/src/schedulers/captchaScheduler.ts.html +250 -0
  38. package/coverage/src/schedulers/getClientList.ts.html +271 -0
  39. package/coverage/src/schedulers/index.html +131 -0
  40. package/coverage/src/services/index.html +131 -0
  41. package/coverage/src/services/ipComparison.ts.html +685 -0
  42. package/coverage/src/services/ipInfo.ts.html +490 -0
  43. package/coverage/src/tasks/captchaManager.ts.html +865 -0
  44. package/coverage/src/tasks/client/clientTasks.ts.html +1381 -0
  45. package/coverage/src/tasks/client/index.html +116 -0
  46. package/coverage/src/tasks/dataset/datasetTasks.ts.html +268 -0
  47. package/coverage/src/tasks/dataset/datasetTasksUtils.ts.html +271 -0
  48. package/coverage/src/tasks/dataset/index.html +131 -0
  49. package/coverage/src/tasks/detection/decodePayload.js.html +127 -0
  50. package/coverage/src/tasks/detection/getBotScore.ts.html +244 -0
  51. package/coverage/src/tasks/detection/index.html +131 -0
  52. package/coverage/src/tasks/frictionless/frictionlessTasks.ts.html +1216 -0
  53. package/coverage/src/tasks/frictionless/frictionlessTasksUtils.ts.html +247 -0
  54. package/coverage/src/tasks/frictionless/index.html +131 -0
  55. package/coverage/src/tasks/imgCaptcha/imgCaptchaTasks.ts.html +1972 -0
  56. package/coverage/src/tasks/imgCaptcha/imgCaptchaTasksUtils.ts.html +232 -0
  57. package/coverage/src/tasks/imgCaptcha/index.html +131 -0
  58. package/coverage/src/tasks/index.html +146 -0
  59. package/coverage/src/tasks/index.ts.html +127 -0
  60. package/coverage/src/tasks/powCaptcha/index.html +131 -0
  61. package/coverage/src/tasks/powCaptcha/powTasks.ts.html +961 -0
  62. package/coverage/src/tasks/powCaptcha/powTasksUtils.ts.html +244 -0
  63. package/coverage/src/tasks/tasks.ts.html +388 -0
  64. package/coverage/src/util.ts.html +1627 -0
  65. package/coverage/src/utils/hashUserAgent.ts.html +184 -0
  66. package/coverage/src/utils/index.html +116 -0
  67. package/dist/api/admin/apiAdminRoutesProvider.d.ts +9 -0
  68. package/dist/api/admin/apiAdminRoutesProvider.d.ts.map +1 -0
  69. package/dist/api/admin/apiAdminRoutesProvider.js +13 -18
  70. package/dist/api/admin/apiAdminRoutesProvider.js.map +1 -0
  71. package/dist/api/admin/apiRegisterSiteKeyEndpoint.d.ts +14 -0
  72. package/dist/api/admin/apiRegisterSiteKeyEndpoint.d.ts.map +1 -0
  73. package/dist/api/admin/apiRegisterSiteKeyEndpoint.js.map +1 -0
  74. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts +23 -0
  75. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -0
  76. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +7 -4
  77. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js.map +1 -0
  78. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts +13 -0
  79. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts.map +1 -0
  80. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +40 -0
  81. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js.map +1 -0
  82. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts +14 -0
  83. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts.map +1 -0
  84. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js.map +1 -0
  85. package/dist/api/admin/createApiAdminRoutesProvider.d.ts +4 -0
  86. package/dist/api/admin/createApiAdminRoutesProvider.d.ts.map +1 -0
  87. package/dist/api/admin/createApiAdminRoutesProvider.js.map +1 -0
  88. package/dist/api/blacklistRequestInspector.d.ts +19 -0
  89. package/dist/api/blacklistRequestInspector.d.ts.map +1 -0
  90. package/dist/api/blacklistRequestInspector.js +14 -12
  91. package/dist/api/blacklistRequestInspector.js.map +1 -0
  92. package/dist/api/block.d.ts +3 -0
  93. package/dist/api/block.d.ts.map +1 -0
  94. package/dist/api/block.js.map +1 -0
  95. package/dist/api/captcha.d.ts +4 -0
  96. package/dist/api/captcha.d.ts.map +1 -0
  97. package/dist/api/captcha.js +226 -48
  98. package/dist/api/captcha.js.map +1 -0
  99. package/dist/api/domainMiddleware.d.ts +4 -0
  100. package/dist/api/domainMiddleware.d.ts.map +1 -0
  101. package/dist/api/domainMiddleware.js +8 -8
  102. package/dist/api/domainMiddleware.js.map +1 -0
  103. package/dist/api/headerCheckMiddleware.d.ts +4 -0
  104. package/dist/api/headerCheckMiddleware.d.ts.map +1 -0
  105. package/dist/api/headerCheckMiddleware.js +4 -0
  106. package/dist/api/headerCheckMiddleware.js.map +1 -0
  107. package/dist/api/ignoreMiddleware.d.ts +3 -0
  108. package/dist/api/ignoreMiddleware.d.ts.map +1 -0
  109. package/dist/api/ignoreMiddleware.js +4 -1
  110. package/dist/api/ignoreMiddleware.js.map +1 -0
  111. package/dist/api/ja4Middleware.d.ts +10 -0
  112. package/dist/api/ja4Middleware.d.ts.map +1 -0
  113. package/dist/api/ja4Middleware.js +5 -23
  114. package/dist/api/ja4Middleware.js.map +1 -0
  115. package/dist/api/public.d.ts +4 -0
  116. package/dist/api/public.d.ts.map +1 -0
  117. package/dist/api/public.js +26 -3
  118. package/dist/api/public.js.map +1 -0
  119. package/dist/api/robotsMiddleware.d.ts +3 -0
  120. package/dist/api/robotsMiddleware.d.ts.map +1 -0
  121. package/dist/api/robotsMiddleware.js.map +1 -0
  122. package/dist/api/validateAddress.d.ts +5 -0
  123. package/dist/api/validateAddress.d.ts.map +1 -0
  124. package/dist/api/validateAddress.js.map +1 -0
  125. package/dist/api/verify.d.ts +4 -0
  126. package/dist/api/verify.d.ts.map +1 -0
  127. package/dist/api/verify.js +27 -3
  128. package/dist/api/verify.js.map +1 -0
  129. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +13 -18
  130. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +2 -1
  131. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +9 -5
  132. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +41 -0
  133. package/dist/cjs/api/blacklistRequestInspector.cjs +13 -11
  134. package/dist/cjs/api/captcha.cjs +226 -48
  135. package/dist/cjs/api/domainMiddleware.cjs +8 -8
  136. package/dist/cjs/api/headerCheckMiddleware.cjs +4 -0
  137. package/dist/cjs/api/ignoreMiddleware.cjs +3 -0
  138. package/dist/cjs/api/ja4Middleware.cjs +6 -23
  139. package/dist/cjs/api/public.cjs +26 -3
  140. package/dist/cjs/api/verify.cjs +27 -3
  141. package/dist/cjs/compositeIpAddress.cjs +53 -0
  142. package/dist/cjs/index.cjs +7 -0
  143. package/dist/cjs/pairs.cjs +27 -0
  144. package/dist/cjs/services/ipComparison.cjs +123 -0
  145. package/dist/cjs/services/ipInfo.cjs +87 -0
  146. package/dist/cjs/tasks/captchaManager.cjs +41 -10
  147. package/dist/cjs/tasks/client/clientTasks.cjs +31 -43
  148. package/dist/cjs/tasks/detection/decodePayload.cjs +616 -281
  149. package/dist/cjs/tasks/detection/getBotScore.cjs +28 -4
  150. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +227 -36
  151. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +17 -0
  152. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +78 -30
  153. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +49 -21
  154. package/dist/cjs/util.cjs +262 -17
  155. package/dist/cjs/utils/hashUserAgent.cjs +10 -0
  156. package/dist/compositeIpAddress.d.ts +5 -0
  157. package/dist/compositeIpAddress.d.ts.map +1 -0
  158. package/dist/compositeIpAddress.js +53 -0
  159. package/dist/compositeIpAddress.js.map +1 -0
  160. package/dist/index.d.ts +17 -0
  161. package/dist/index.d.ts.map +1 -0
  162. package/dist/index.js +8 -1
  163. package/dist/index.js.map +1 -0
  164. package/dist/pairs.d.ts +3 -0
  165. package/dist/pairs.d.ts.map +1 -0
  166. package/dist/pairs.js +27 -0
  167. package/dist/pairs.js.map +1 -0
  168. package/dist/rules/lang.d.ts +3 -0
  169. package/dist/rules/lang.d.ts.map +1 -0
  170. package/dist/rules/lang.js.map +1 -0
  171. package/dist/schedulers/captchaScheduler.d.ts +4 -0
  172. package/dist/schedulers/captchaScheduler.d.ts.map +1 -0
  173. package/dist/schedulers/captchaScheduler.js.map +1 -0
  174. package/dist/schedulers/getClientList.d.ts +4 -0
  175. package/dist/schedulers/getClientList.d.ts.map +1 -0
  176. package/dist/schedulers/getClientList.js.map +1 -0
  177. package/dist/schedulers/setClientEntropy.d.ts +4 -0
  178. package/dist/schedulers/setClientEntropy.d.ts.map +1 -0
  179. package/dist/schedulers/setClientEntropy.js +31 -0
  180. package/dist/schedulers/setClientEntropy.js.map +1 -0
  181. package/dist/services/ipComparison.d.ts +3 -0
  182. package/dist/services/ipComparison.d.ts.map +1 -0
  183. package/dist/services/ipComparison.js +123 -0
  184. package/dist/services/ipComparison.js.map +1 -0
  185. package/dist/services/ipInfo.d.ts +3 -0
  186. package/dist/services/ipInfo.d.ts.map +1 -0
  187. package/dist/services/ipInfo.js +87 -0
  188. package/dist/services/ipInfo.js.map +1 -0
  189. package/dist/tasks/captchaManager.d.ts +34 -0
  190. package/dist/tasks/captchaManager.d.ts.map +1 -0
  191. package/dist/tasks/captchaManager.js +39 -9
  192. package/dist/tasks/captchaManager.js.map +1 -0
  193. package/dist/tasks/client/clientTasks.d.ts +21 -0
  194. package/dist/tasks/client/clientTasks.d.ts.map +1 -0
  195. package/dist/tasks/client/clientTasks.js +31 -43
  196. package/dist/tasks/client/clientTasks.js.map +1 -0
  197. package/dist/tasks/dataset/datasetTasks.d.ts +13 -0
  198. package/dist/tasks/dataset/datasetTasks.d.ts.map +1 -0
  199. package/dist/tasks/dataset/datasetTasks.js.map +1 -0
  200. package/dist/tasks/dataset/datasetTasksUtils.d.ts +3 -0
  201. package/dist/tasks/dataset/datasetTasksUtils.d.ts.map +1 -0
  202. package/dist/tasks/dataset/datasetTasksUtils.js.map +1 -0
  203. package/dist/tasks/detection/decodePayload.d.ts +5 -0
  204. package/dist/tasks/detection/decodePayload.d.ts.map +1 -0
  205. package/dist/tasks/detection/decodePayload.js +616 -281
  206. package/dist/tasks/detection/decodePayload.js.map +1 -0
  207. package/dist/tasks/detection/getBotScore.d.ts +20 -0
  208. package/dist/tasks/detection/getBotScore.d.ts.map +1 -0
  209. package/dist/tasks/detection/getBotScore.js +29 -5
  210. package/dist/tasks/detection/getBotScore.js.map +1 -0
  211. package/dist/tasks/frictionless/frictionlessTasks.d.ts +67 -0
  212. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -0
  213. package/dist/tasks/frictionless/frictionlessTasks.js +227 -36
  214. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -0
  215. package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts +6 -0
  216. package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts.map +1 -0
  217. package/dist/tasks/frictionless/frictionlessTasksUtils.js +18 -1
  218. package/dist/tasks/frictionless/frictionlessTasksUtils.js.map +1 -0
  219. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts +30 -0
  220. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -0
  221. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +80 -32
  222. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -0
  223. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts +7 -0
  224. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts.map +1 -0
  225. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js.map +1 -0
  226. package/dist/tasks/index.d.ts +2 -0
  227. package/dist/tasks/index.d.ts.map +1 -0
  228. package/dist/tasks/index.js.map +1 -0
  229. package/dist/tasks/powCaptcha/powTasks.d.ts +17 -0
  230. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -0
  231. package/dist/tasks/powCaptcha/powTasks.js +50 -22
  232. package/dist/tasks/powCaptcha/powTasks.js.map +1 -0
  233. package/dist/tasks/powCaptcha/powTasksUtils.d.ts +3 -0
  234. package/dist/tasks/powCaptcha/powTasksUtils.d.ts.map +1 -0
  235. package/dist/tasks/powCaptcha/powTasksUtils.js.map +1 -0
  236. package/dist/tasks/tasks.d.ts +25 -0
  237. package/dist/tasks/tasks.d.ts.map +1 -0
  238. package/dist/tasks/tasks.js.map +1 -0
  239. package/dist/tests/index.d.ts +2 -0
  240. package/dist/tests/index.d.ts.map +1 -0
  241. package/dist/tests/index.js +2 -0
  242. package/dist/tests/index.js.map +1 -0
  243. package/dist/tests/integration/accessRules.integration.test.d.ts +2 -0
  244. package/dist/tests/integration/accessRules.integration.test.d.ts.map +1 -0
  245. package/dist/tests/integration/accessRules.integration.test.js +588 -0
  246. package/dist/tests/integration/accessRules.integration.test.js.map +1 -0
  247. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.d.ts +2 -0
  248. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.d.ts.map +1 -0
  249. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js +60 -0
  250. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js.map +1 -0
  251. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.d.ts +2 -0
  252. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.d.ts.map +1 -0
  253. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +368 -0
  254. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -0
  255. package/dist/tests/integration/imgCaptcha.integration.test.d.ts +2 -0
  256. package/dist/tests/integration/imgCaptcha.integration.test.d.ts.map +1 -0
  257. package/dist/tests/integration/imgCaptcha.integration.test.js +272 -0
  258. package/dist/tests/integration/imgCaptcha.integration.test.js.map +1 -0
  259. package/dist/tests/integration/ipValidation.integration.test.d.ts +2 -0
  260. package/dist/tests/integration/ipValidation.integration.test.d.ts.map +1 -0
  261. package/dist/tests/integration/ipValidation.integration.test.js +75 -0
  262. package/dist/tests/integration/ipValidation.integration.test.js.map +1 -0
  263. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts +32 -0
  264. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts.map +1 -0
  265. package/dist/tests/integration/mocks/solvedTestCaptchas.js +1046 -0
  266. package/dist/tests/integration/mocks/solvedTestCaptchas.js.map +1 -0
  267. package/dist/tests/integration/powCaptcha.integration.test.d.ts +2 -0
  268. package/dist/tests/integration/powCaptcha.integration.test.d.ts.map +1 -0
  269. package/dist/tests/integration/powCaptcha.integration.test.js +308 -0
  270. package/dist/tests/integration/powCaptcha.integration.test.js.map +1 -0
  271. package/dist/tests/integration/registerSitekey.d.ts +3 -0
  272. package/dist/tests/integration/registerSitekey.d.ts.map +1 -0
  273. package/dist/tests/integration/registerSitekey.js +24 -0
  274. package/dist/tests/integration/registerSitekey.js.map +1 -0
  275. package/dist/tests/integration/userAccessPolicy.d.ts +2 -0
  276. package/dist/tests/integration/userAccessPolicy.d.ts.map +1 -0
  277. package/dist/tests/integration/userAccessPolicy.js +2 -0
  278. package/dist/tests/integration/userAccessPolicy.js.map +1 -0
  279. package/dist/tests/unit/api/blacklistRequestInspector.unit.test.d.ts +2 -0
  280. package/dist/tests/unit/api/blacklistRequestInspector.unit.test.d.ts.map +1 -0
  281. package/dist/tests/unit/api/blacklistRequestInspector.unit.test.js +60 -0
  282. package/dist/tests/unit/api/blacklistRequestInspector.unit.test.js.map +1 -0
  283. package/dist/tests/unit/api/ignoreMiddleware.unit.test.d.ts +2 -0
  284. package/dist/tests/unit/api/ignoreMiddleware.unit.test.d.ts.map +1 -0
  285. package/dist/tests/unit/api/ignoreMiddleware.unit.test.js +43 -0
  286. package/dist/tests/unit/api/ignoreMiddleware.unit.test.js.map +1 -0
  287. package/dist/tests/unit/api/ja4Middleware.unit.test.d.ts +2 -0
  288. package/dist/tests/unit/api/ja4Middleware.unit.test.d.ts.map +1 -0
  289. package/dist/tests/unit/api/ja4Middleware.unit.test.js +57 -0
  290. package/dist/tests/unit/api/ja4Middleware.unit.test.js.map +1 -0
  291. package/dist/tests/unit/compositeIpAddress.unit.test.d.ts +2 -0
  292. package/dist/tests/unit/compositeIpAddress.unit.test.d.ts.map +1 -0
  293. package/dist/tests/unit/compositeIpAddress.unit.test.js +86 -0
  294. package/dist/tests/unit/compositeIpAddress.unit.test.js.map +1 -0
  295. package/dist/tests/unit/pairs.unit.test.d.ts +2 -0
  296. package/dist/tests/unit/pairs.unit.test.d.ts.map +1 -0
  297. package/dist/tests/unit/pairs.unit.test.js +83 -0
  298. package/dist/tests/unit/pairs.unit.test.js.map +1 -0
  299. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.d.ts +2 -0
  300. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.d.ts.map +1 -0
  301. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +75 -0
  302. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +1 -0
  303. package/dist/tests/unit/services/ipComparison.unit.test.d.ts +2 -0
  304. package/dist/tests/unit/services/ipComparison.unit.test.d.ts.map +1 -0
  305. package/dist/tests/unit/services/ipComparison.unit.test.js +258 -0
  306. package/dist/tests/unit/services/ipComparison.unit.test.js.map +1 -0
  307. package/dist/tests/unit/services/ipInfo.unit.test.d.ts +2 -0
  308. package/dist/tests/unit/services/ipInfo.unit.test.d.ts.map +1 -0
  309. package/dist/tests/unit/services/ipInfo.unit.test.js +210 -0
  310. package/dist/tests/unit/services/ipInfo.unit.test.js.map +1 -0
  311. package/dist/tests/unit/tasks/captchaManager.unit.test.d.ts +2 -0
  312. package/dist/tests/unit/tasks/captchaManager.unit.test.d.ts.map +1 -0
  313. package/dist/tests/unit/tasks/captchaManager.unit.test.js +311 -0
  314. package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -0
  315. package/dist/tests/unit/tasks/client/clientTasks.unit.test.d.ts +2 -0
  316. package/dist/tests/unit/tasks/client/clientTasks.unit.test.d.ts.map +1 -0
  317. package/dist/tests/unit/tasks/client/clientTasks.unit.test.js +289 -0
  318. package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -0
  319. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts +2 -0
  320. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts.map +1 -0
  321. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js +92 -0
  322. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js.map +1 -0
  323. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts +2 -0
  324. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts.map +1 -0
  325. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js +75 -0
  326. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js.map +1 -0
  327. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.d.ts +2 -0
  328. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.d.ts.map +1 -0
  329. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js +143 -0
  330. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js.map +1 -0
  331. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.d.ts +2 -0
  332. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.d.ts.map +1 -0
  333. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +145 -0
  334. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +1 -0
  335. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.d.ts +2 -0
  336. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.d.ts.map +1 -0
  337. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js +64 -0
  338. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js.map +1 -0
  339. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts +2 -0
  340. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts.map +1 -0
  341. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js +388 -0
  342. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js.map +1 -0
  343. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts +2 -0
  344. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts.map +1 -0
  345. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +46 -0
  346. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -0
  347. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts +2 -0
  348. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts.map +1 -0
  349. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +216 -0
  350. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -0
  351. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts +2 -0
  352. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts.map +1 -0
  353. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js +69 -0
  354. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js.map +1 -0
  355. package/dist/tests/unit/util.evaluateIpValidationRules.unit.test.d.ts +2 -0
  356. package/dist/tests/unit/util.evaluateIpValidationRules.unit.test.d.ts.map +1 -0
  357. package/dist/tests/unit/util.evaluateIpValidationRules.unit.test.js +505 -0
  358. package/dist/tests/unit/util.evaluateIpValidationRules.unit.test.js.map +1 -0
  359. package/dist/tests/unit/util.ipDistance.unit.test.d.ts +2 -0
  360. package/dist/tests/unit/util.ipDistance.unit.test.d.ts.map +1 -0
  361. package/dist/tests/unit/util.ipDistance.unit.test.js +93 -0
  362. package/dist/tests/unit/util.ipDistance.unit.test.js.map +1 -0
  363. package/dist/tests/unit/util.unit.test.d.ts +2 -0
  364. package/dist/tests/unit/util.unit.test.d.ts.map +1 -0
  365. package/dist/tests/unit/util.unit.test.js +170 -0
  366. package/dist/tests/unit/util.unit.test.js.map +1 -0
  367. package/dist/util.d.ts +24 -0
  368. package/dist/util.d.ts.map +1 -0
  369. package/dist/util.js +263 -18
  370. package/dist/util.js.map +1 -0
  371. package/dist/utils/hashUserAgent.d.ts +2 -0
  372. package/dist/utils/hashUserAgent.d.ts.map +1 -0
  373. package/dist/utils/hashUserAgent.js +10 -0
  374. package/dist/utils/hashUserAgent.js.map +1 -0
  375. package/package.json +31 -29
  376. package/vite.test.config.ts +3 -2
  377. package/vite.threads.test.config.ts +33 -0
@@ -0,0 +1,1627 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/util.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../prettify.css" />
9
+ <link rel="stylesheet" href="../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../index.html">All files</a> / <a href="index.html">src</a> util.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">39.68% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>152/383</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">88.37% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>38/43</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">12.5% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>1/8</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">39.68% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>152/383</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line low'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
508
+ <a name='L443'></a><a href='#L443'>443</a>
509
+ <a name='L444'></a><a href='#L444'>444</a>
510
+ <a name='L445'></a><a href='#L445'>445</a>
511
+ <a name='L446'></a><a href='#L446'>446</a>
512
+ <a name='L447'></a><a href='#L447'>447</a>
513
+ <a name='L448'></a><a href='#L448'>448</a>
514
+ <a name='L449'></a><a href='#L449'>449</a>
515
+ <a name='L450'></a><a href='#L450'>450</a>
516
+ <a name='L451'></a><a href='#L451'>451</a>
517
+ <a name='L452'></a><a href='#L452'>452</a>
518
+ <a name='L453'></a><a href='#L453'>453</a>
519
+ <a name='L454'></a><a href='#L454'>454</a>
520
+ <a name='L455'></a><a href='#L455'>455</a>
521
+ <a name='L456'></a><a href='#L456'>456</a>
522
+ <a name='L457'></a><a href='#L457'>457</a>
523
+ <a name='L458'></a><a href='#L458'>458</a>
524
+ <a name='L459'></a><a href='#L459'>459</a>
525
+ <a name='L460'></a><a href='#L460'>460</a>
526
+ <a name='L461'></a><a href='#L461'>461</a>
527
+ <a name='L462'></a><a href='#L462'>462</a>
528
+ <a name='L463'></a><a href='#L463'>463</a>
529
+ <a name='L464'></a><a href='#L464'>464</a>
530
+ <a name='L465'></a><a href='#L465'>465</a>
531
+ <a name='L466'></a><a href='#L466'>466</a>
532
+ <a name='L467'></a><a href='#L467'>467</a>
533
+ <a name='L468'></a><a href='#L468'>468</a>
534
+ <a name='L469'></a><a href='#L469'>469</a>
535
+ <a name='L470'></a><a href='#L470'>470</a>
536
+ <a name='L471'></a><a href='#L471'>471</a>
537
+ <a name='L472'></a><a href='#L472'>472</a>
538
+ <a name='L473'></a><a href='#L473'>473</a>
539
+ <a name='L474'></a><a href='#L474'>474</a>
540
+ <a name='L475'></a><a href='#L475'>475</a>
541
+ <a name='L476'></a><a href='#L476'>476</a>
542
+ <a name='L477'></a><a href='#L477'>477</a>
543
+ <a name='L478'></a><a href='#L478'>478</a>
544
+ <a name='L479'></a><a href='#L479'>479</a>
545
+ <a name='L480'></a><a href='#L480'>480</a>
546
+ <a name='L481'></a><a href='#L481'>481</a>
547
+ <a name='L482'></a><a href='#L482'>482</a>
548
+ <a name='L483'></a><a href='#L483'>483</a>
549
+ <a name='L484'></a><a href='#L484'>484</a>
550
+ <a name='L485'></a><a href='#L485'>485</a>
551
+ <a name='L486'></a><a href='#L486'>486</a>
552
+ <a name='L487'></a><a href='#L487'>487</a>
553
+ <a name='L488'></a><a href='#L488'>488</a>
554
+ <a name='L489'></a><a href='#L489'>489</a>
555
+ <a name='L490'></a><a href='#L490'>490</a>
556
+ <a name='L491'></a><a href='#L491'>491</a>
557
+ <a name='L492'></a><a href='#L492'>492</a>
558
+ <a name='L493'></a><a href='#L493'>493</a>
559
+ <a name='L494'></a><a href='#L494'>494</a>
560
+ <a name='L495'></a><a href='#L495'>495</a>
561
+ <a name='L496'></a><a href='#L496'>496</a>
562
+ <a name='L497'></a><a href='#L497'>497</a>
563
+ <a name='L498'></a><a href='#L498'>498</a>
564
+ <a name='L499'></a><a href='#L499'>499</a>
565
+ <a name='L500'></a><a href='#L500'>500</a>
566
+ <a name='L501'></a><a href='#L501'>501</a>
567
+ <a name='L502'></a><a href='#L502'>502</a>
568
+ <a name='L503'></a><a href='#L503'>503</a>
569
+ <a name='L504'></a><a href='#L504'>504</a>
570
+ <a name='L505'></a><a href='#L505'>505</a>
571
+ <a name='L506'></a><a href='#L506'>506</a>
572
+ <a name='L507'></a><a href='#L507'>507</a>
573
+ <a name='L508'></a><a href='#L508'>508</a>
574
+ <a name='L509'></a><a href='#L509'>509</a>
575
+ <a name='L510'></a><a href='#L510'>510</a>
576
+ <a name='L511'></a><a href='#L511'>511</a>
577
+ <a name='L512'></a><a href='#L512'>512</a>
578
+ <a name='L513'></a><a href='#L513'>513</a>
579
+ <a name='L514'></a><a href='#L514'>514</a>
580
+ <a name='L515'></a><a href='#L515'>515</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
581
+ <span class="cline-any cline-neutral">&nbsp;</span>
582
+ <span class="cline-any cline-neutral">&nbsp;</span>
583
+ <span class="cline-any cline-neutral">&nbsp;</span>
584
+ <span class="cline-any cline-neutral">&nbsp;</span>
585
+ <span class="cline-any cline-neutral">&nbsp;</span>
586
+ <span class="cline-any cline-neutral">&nbsp;</span>
587
+ <span class="cline-any cline-neutral">&nbsp;</span>
588
+ <span class="cline-any cline-neutral">&nbsp;</span>
589
+ <span class="cline-any cline-neutral">&nbsp;</span>
590
+ <span class="cline-any cline-neutral">&nbsp;</span>
591
+ <span class="cline-any cline-neutral">&nbsp;</span>
592
+ <span class="cline-any cline-neutral">&nbsp;</span>
593
+ <span class="cline-any cline-neutral">&nbsp;</span>
594
+ <span class="cline-any cline-yes">1x</span>
595
+ <span class="cline-any cline-yes">1x</span>
596
+ <span class="cline-any cline-yes">1x</span>
597
+ <span class="cline-any cline-neutral">&nbsp;</span>
598
+ <span class="cline-any cline-neutral">&nbsp;</span>
599
+ <span class="cline-any cline-neutral">&nbsp;</span>
600
+ <span class="cline-any cline-neutral">&nbsp;</span>
601
+ <span class="cline-any cline-yes">1x</span>
602
+ <span class="cline-any cline-neutral">&nbsp;</span>
603
+ <span class="cline-any cline-neutral">&nbsp;</span>
604
+ <span class="cline-any cline-neutral">&nbsp;</span>
605
+ <span class="cline-any cline-neutral">&nbsp;</span>
606
+ <span class="cline-any cline-neutral">&nbsp;</span>
607
+ <span class="cline-any cline-neutral">&nbsp;</span>
608
+ <span class="cline-any cline-neutral">&nbsp;</span>
609
+ <span class="cline-any cline-neutral">&nbsp;</span>
610
+ <span class="cline-any cline-neutral">&nbsp;</span>
611
+ <span class="cline-any cline-neutral">&nbsp;</span>
612
+ <span class="cline-any cline-yes">1x</span>
613
+ <span class="cline-any cline-yes">1x</span>
614
+ <span class="cline-any cline-yes">1x</span>
615
+ <span class="cline-any cline-neutral">&nbsp;</span>
616
+ <span class="cline-any cline-yes">1x</span>
617
+ <span class="cline-any cline-neutral">&nbsp;</span>
618
+ <span class="cline-any cline-yes">1x</span>
619
+ <span class="cline-any cline-no">&nbsp;</span>
620
+ <span class="cline-any cline-no">&nbsp;</span>
621
+ <span class="cline-any cline-no">&nbsp;</span>
622
+ <span class="cline-any cline-no">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-no">&nbsp;</span>
625
+ <span class="cline-any cline-no">&nbsp;</span>
626
+ <span class="cline-any cline-no">&nbsp;</span>
627
+ <span class="cline-any cline-no">&nbsp;</span>
628
+ <span class="cline-any cline-no">&nbsp;</span>
629
+ <span class="cline-any cline-neutral">&nbsp;</span>
630
+ <span class="cline-any cline-yes">1x</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-no">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-neutral">&nbsp;</span>
640
+ <span class="cline-any cline-neutral">&nbsp;</span>
641
+ <span class="cline-any cline-neutral">&nbsp;</span>
642
+ <span class="cline-any cline-neutral">&nbsp;</span>
643
+ <span class="cline-any cline-neutral">&nbsp;</span>
644
+ <span class="cline-any cline-neutral">&nbsp;</span>
645
+ <span class="cline-any cline-neutral">&nbsp;</span>
646
+ <span class="cline-any cline-no">&nbsp;</span>
647
+ <span class="cline-any cline-no">&nbsp;</span>
648
+ <span class="cline-any cline-no">&nbsp;</span>
649
+ <span class="cline-any cline-no">&nbsp;</span>
650
+ <span class="cline-any cline-no">&nbsp;</span>
651
+ <span class="cline-any cline-no">&nbsp;</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
653
+ <span class="cline-any cline-no">&nbsp;</span>
654
+ <span class="cline-any cline-no">&nbsp;</span>
655
+ <span class="cline-any cline-neutral">&nbsp;</span>
656
+ <span class="cline-any cline-neutral">&nbsp;</span>
657
+ <span class="cline-any cline-no">&nbsp;</span>
658
+ <span class="cline-any cline-no">&nbsp;</span>
659
+ <span class="cline-any cline-no">&nbsp;</span>
660
+ <span class="cline-any cline-no">&nbsp;</span>
661
+ <span class="cline-any cline-no">&nbsp;</span>
662
+ <span class="cline-any cline-no">&nbsp;</span>
663
+ <span class="cline-any cline-no">&nbsp;</span>
664
+ <span class="cline-any cline-no">&nbsp;</span>
665
+ <span class="cline-any cline-no">&nbsp;</span>
666
+ <span class="cline-any cline-neutral">&nbsp;</span>
667
+ <span class="cline-any cline-yes">1x</span>
668
+ <span class="cline-any cline-no">&nbsp;</span>
669
+ <span class="cline-any cline-no">&nbsp;</span>
670
+ <span class="cline-any cline-no">&nbsp;</span>
671
+ <span class="cline-any cline-no">&nbsp;</span>
672
+ <span class="cline-any cline-no">&nbsp;</span>
673
+ <span class="cline-any cline-no">&nbsp;</span>
674
+ <span class="cline-any cline-no">&nbsp;</span>
675
+ <span class="cline-any cline-no">&nbsp;</span>
676
+ <span class="cline-any cline-no">&nbsp;</span>
677
+ <span class="cline-any cline-no">&nbsp;</span>
678
+ <span class="cline-any cline-neutral">&nbsp;</span>
679
+ <span class="cline-any cline-yes">1x</span>
680
+ <span class="cline-any cline-no">&nbsp;</span>
681
+ <span class="cline-any cline-no">&nbsp;</span>
682
+ <span class="cline-any cline-no">&nbsp;</span>
683
+ <span class="cline-any cline-no">&nbsp;</span>
684
+ <span class="cline-any cline-no">&nbsp;</span>
685
+ <span class="cline-any cline-no">&nbsp;</span>
686
+ <span class="cline-any cline-no">&nbsp;</span>
687
+ <span class="cline-any cline-no">&nbsp;</span>
688
+ <span class="cline-any cline-no">&nbsp;</span>
689
+ <span class="cline-any cline-neutral">&nbsp;</span>
690
+ <span class="cline-any cline-neutral">&nbsp;</span>
691
+ <span class="cline-any cline-neutral">&nbsp;</span>
692
+ <span class="cline-any cline-neutral">&nbsp;</span>
693
+ <span class="cline-any cline-neutral">&nbsp;</span>
694
+ <span class="cline-any cline-neutral">&nbsp;</span>
695
+ <span class="cline-any cline-neutral">&nbsp;</span>
696
+ <span class="cline-any cline-neutral">&nbsp;</span>
697
+ <span class="cline-any cline-yes">1x</span>
698
+ <span class="cline-any cline-no">&nbsp;</span>
699
+ <span class="cline-any cline-no">&nbsp;</span>
700
+ <span class="cline-any cline-no">&nbsp;</span>
701
+ <span class="cline-any cline-no">&nbsp;</span>
702
+ <span class="cline-any cline-no">&nbsp;</span>
703
+ <span class="cline-any cline-no">&nbsp;</span>
704
+ <span class="cline-any cline-no">&nbsp;</span>
705
+ <span class="cline-any cline-neutral">&nbsp;</span>
706
+ <span class="cline-any cline-no">&nbsp;</span>
707
+ <span class="cline-any cline-no">&nbsp;</span>
708
+ <span class="cline-any cline-no">&nbsp;</span>
709
+ <span class="cline-any cline-no">&nbsp;</span>
710
+ <span class="cline-any cline-no">&nbsp;</span>
711
+ <span class="cline-any cline-no">&nbsp;</span>
712
+ <span class="cline-any cline-no">&nbsp;</span>
713
+ <span class="cline-any cline-no">&nbsp;</span>
714
+ <span class="cline-any cline-no">&nbsp;</span>
715
+ <span class="cline-any cline-neutral">&nbsp;</span>
716
+ <span class="cline-any cline-neutral">&nbsp;</span>
717
+ <span class="cline-any cline-no">&nbsp;</span>
718
+ <span class="cline-any cline-no">&nbsp;</span>
719
+ <span class="cline-any cline-no">&nbsp;</span>
720
+ <span class="cline-any cline-no">&nbsp;</span>
721
+ <span class="cline-any cline-no">&nbsp;</span>
722
+ <span class="cline-any cline-no">&nbsp;</span>
723
+ <span class="cline-any cline-no">&nbsp;</span>
724
+ <span class="cline-any cline-no">&nbsp;</span>
725
+ <span class="cline-any cline-neutral">&nbsp;</span>
726
+ <span class="cline-any cline-no">&nbsp;</span>
727
+ <span class="cline-any cline-no">&nbsp;</span>
728
+ <span class="cline-any cline-no">&nbsp;</span>
729
+ <span class="cline-any cline-no">&nbsp;</span>
730
+ <span class="cline-any cline-no">&nbsp;</span>
731
+ <span class="cline-any cline-neutral">&nbsp;</span>
732
+ <span class="cline-any cline-no">&nbsp;</span>
733
+ <span class="cline-any cline-no">&nbsp;</span>
734
+ <span class="cline-any cline-no">&nbsp;</span>
735
+ <span class="cline-any cline-no">&nbsp;</span>
736
+ <span class="cline-any cline-no">&nbsp;</span>
737
+ <span class="cline-any cline-no">&nbsp;</span>
738
+ <span class="cline-any cline-no">&nbsp;</span>
739
+ <span class="cline-any cline-no">&nbsp;</span>
740
+ <span class="cline-any cline-no">&nbsp;</span>
741
+ <span class="cline-any cline-no">&nbsp;</span>
742
+ <span class="cline-any cline-no">&nbsp;</span>
743
+ <span class="cline-any cline-neutral">&nbsp;</span>
744
+ <span class="cline-any cline-no">&nbsp;</span>
745
+ <span class="cline-any cline-no">&nbsp;</span>
746
+ <span class="cline-any cline-neutral">&nbsp;</span>
747
+ <span class="cline-any cline-neutral">&nbsp;</span>
748
+ <span class="cline-any cline-neutral">&nbsp;</span>
749
+ <span class="cline-any cline-neutral">&nbsp;</span>
750
+ <span class="cline-any cline-neutral">&nbsp;</span>
751
+ <span class="cline-any cline-neutral">&nbsp;</span>
752
+ <span class="cline-any cline-neutral">&nbsp;</span>
753
+ <span class="cline-any cline-neutral">&nbsp;</span>
754
+ <span class="cline-any cline-yes">1x</span>
755
+ <span class="cline-any cline-yes">14x</span>
756
+ <span class="cline-any cline-yes">14x</span>
757
+ <span class="cline-any cline-yes">14x</span>
758
+ <span class="cline-any cline-neutral">&nbsp;</span>
759
+ <span class="cline-any cline-neutral">&nbsp;</span>
760
+ <span class="cline-any cline-neutral">&nbsp;</span>
761
+ <span class="cline-any cline-neutral">&nbsp;</span>
762
+ <span class="cline-any cline-yes">14x</span>
763
+ <span class="cline-any cline-neutral">&nbsp;</span>
764
+ <span class="cline-any cline-yes">14x</span>
765
+ <span class="cline-any cline-no">&nbsp;</span>
766
+ <span class="cline-any cline-no">&nbsp;</span>
767
+ <span class="cline-any cline-neutral">&nbsp;</span>
768
+ <span class="cline-any cline-yes">14x</span>
769
+ <span class="cline-any cline-yes">14x</span>
770
+ <span class="cline-any cline-yes">14x</span>
771
+ <span class="cline-any cline-yes">14x</span>
772
+ <span class="cline-any cline-neutral">&nbsp;</span>
773
+ <span class="cline-any cline-neutral">&nbsp;</span>
774
+ <span class="cline-any cline-yes">14x</span>
775
+ <span class="cline-any cline-yes">14x</span>
776
+ <span class="cline-any cline-yes">14x</span>
777
+ <span class="cline-any cline-yes">14x</span>
778
+ <span class="cline-any cline-yes">14x</span>
779
+ <span class="cline-any cline-yes">14x</span>
780
+ <span class="cline-any cline-yes">14x</span>
781
+ <span class="cline-any cline-no">&nbsp;</span>
782
+ <span class="cline-any cline-no">&nbsp;</span>
783
+ <span class="cline-any cline-yes">14x</span>
784
+ <span class="cline-any cline-yes">3x</span>
785
+ <span class="cline-any cline-yes">3x</span>
786
+ <span class="cline-any cline-yes">14x</span>
787
+ <span class="cline-any cline-yes">3x</span>
788
+ <span class="cline-any cline-yes">3x</span>
789
+ <span class="cline-any cline-yes">3x</span>
790
+ <span class="cline-any cline-yes">3x</span>
791
+ <span class="cline-any cline-yes">3x</span>
792
+ <span class="cline-any cline-yes">3x</span>
793
+ <span class="cline-any cline-yes">3x</span>
794
+ <span class="cline-any cline-yes">3x</span>
795
+ <span class="cline-any cline-yes">3x</span>
796
+ <span class="cline-any cline-yes">3x</span>
797
+ <span class="cline-any cline-yes">3x</span>
798
+ <span class="cline-any cline-yes">3x</span>
799
+ <span class="cline-any cline-yes">3x</span>
800
+ <span class="cline-any cline-yes">3x</span>
801
+ <span class="cline-any cline-neutral">&nbsp;</span>
802
+ <span class="cline-any cline-neutral">&nbsp;</span>
803
+ <span class="cline-any cline-yes">14x</span>
804
+ <span class="cline-any cline-yes">4x</span>
805
+ <span class="cline-any cline-yes">4x</span>
806
+ <span class="cline-any cline-yes">4x</span>
807
+ <span class="cline-any cline-yes">4x</span>
808
+ <span class="cline-any cline-yes">4x</span>
809
+ <span class="cline-any cline-yes">4x</span>
810
+ <span class="cline-any cline-neutral">&nbsp;</span>
811
+ <span class="cline-any cline-neutral">&nbsp;</span>
812
+ <span class="cline-any cline-yes">14x</span>
813
+ <span class="cline-any cline-yes">14x</span>
814
+ <span class="cline-any cline-yes">14x</span>
815
+ <span class="cline-any cline-yes">3x</span>
816
+ <span class="cline-any cline-yes">3x</span>
817
+ <span class="cline-any cline-yes">3x</span>
818
+ <span class="cline-any cline-yes">3x</span>
819
+ <span class="cline-any cline-yes">3x</span>
820
+ <span class="cline-any cline-yes">3x</span>
821
+ <span class="cline-any cline-neutral">&nbsp;</span>
822
+ <span class="cline-any cline-neutral">&nbsp;</span>
823
+ <span class="cline-any cline-yes">14x</span>
824
+ <span class="cline-any cline-yes">2x</span>
825
+ <span class="cline-any cline-yes">2x</span>
826
+ <span class="cline-any cline-yes">2x</span>
827
+ <span class="cline-any cline-yes">2x</span>
828
+ <span class="cline-any cline-yes">2x</span>
829
+ <span class="cline-any cline-yes">2x</span>
830
+ <span class="cline-any cline-yes">2x</span>
831
+ <span class="cline-any cline-yes">2x</span>
832
+ <span class="cline-any cline-neutral">&nbsp;</span>
833
+ <span class="cline-any cline-neutral">&nbsp;</span>
834
+ <span class="cline-any cline-yes">14x</span>
835
+ <span class="cline-any cline-yes">14x</span>
836
+ <span class="cline-any cline-yes">14x</span>
837
+ <span class="cline-any cline-yes">4x</span>
838
+ <span class="cline-any cline-yes">14x</span>
839
+ <span class="cline-any cline-yes">3x</span>
840
+ <span class="cline-any cline-yes">3x</span>
841
+ <span class="cline-any cline-yes">3x</span>
842
+ <span class="cline-any cline-yes">3x</span>
843
+ <span class="cline-any cline-yes">3x</span>
844
+ <span class="cline-any cline-yes">3x</span>
845
+ <span class="cline-any cline-neutral">&nbsp;</span>
846
+ <span class="cline-any cline-yes">14x</span>
847
+ <span class="cline-any cline-neutral">&nbsp;</span>
848
+ <span class="cline-any cline-yes">14x</span>
849
+ <span class="cline-any cline-yes">14x</span>
850
+ <span class="cline-any cline-yes">14x</span>
851
+ <span class="cline-any cline-yes">4x</span>
852
+ <span class="cline-any cline-yes">14x</span>
853
+ <span class="cline-any cline-yes">3x</span>
854
+ <span class="cline-any cline-yes">3x</span>
855
+ <span class="cline-any cline-yes">3x</span>
856
+ <span class="cline-any cline-yes">3x</span>
857
+ <span class="cline-any cline-yes">3x</span>
858
+ <span class="cline-any cline-yes">3x</span>
859
+ <span class="cline-any cline-yes">14x</span>
860
+ <span class="cline-any cline-yes">14x</span>
861
+ <span class="cline-any cline-yes">14x</span>
862
+ <span class="cline-any cline-yes">4x</span>
863
+ <span class="cline-any cline-yes">14x</span>
864
+ <span class="cline-any cline-yes">1x</span>
865
+ <span class="cline-any cline-yes">1x</span>
866
+ <span class="cline-any cline-yes">1x</span>
867
+ <span class="cline-any cline-yes">1x</span>
868
+ <span class="cline-any cline-yes">1x</span>
869
+ <span class="cline-any cline-yes">1x</span>
870
+ <span class="cline-any cline-neutral">&nbsp;</span>
871
+ <span class="cline-any cline-neutral">&nbsp;</span>
872
+ <span class="cline-any cline-yes">14x</span>
873
+ <span class="cline-any cline-yes">2x</span>
874
+ <span class="cline-any cline-yes">2x</span>
875
+ <span class="cline-any cline-neutral">&nbsp;</span>
876
+ <span class="cline-any cline-yes">12x</span>
877
+ <span class="cline-any cline-yes">12x</span>
878
+ <span class="cline-any cline-yes">12x</span>
879
+ <span class="cline-any cline-neutral">&nbsp;</span>
880
+ <span class="cline-any cline-neutral">&nbsp;</span>
881
+ <span class="cline-any cline-yes">14x</span>
882
+ <span class="cline-any cline-neutral">&nbsp;</span>
883
+ <span class="cline-any cline-yes">1x</span>
884
+ <span class="cline-any cline-yes">1x</span>
885
+ <span class="cline-any cline-yes">1x</span>
886
+ <span class="cline-any cline-neutral">&nbsp;</span>
887
+ <span class="cline-any cline-neutral">&nbsp;</span>
888
+ <span class="cline-any cline-yes">1x</span>
889
+ <span class="cline-any cline-yes">1x</span>
890
+ <span class="cline-any cline-yes">1x</span>
891
+ <span class="cline-any cline-yes">1x</span>
892
+ <span class="cline-any cline-no">&nbsp;</span>
893
+ <span class="cline-any cline-no">&nbsp;</span>
894
+ <span class="cline-any cline-neutral">&nbsp;</span>
895
+ <span class="cline-any cline-neutral">&nbsp;</span>
896
+ <span class="cline-any cline-yes">1x</span>
897
+ <span class="cline-any cline-yes">1x</span>
898
+ <span class="cline-any cline-yes">1x</span>
899
+ <span class="cline-any cline-no">&nbsp;</span>
900
+ <span class="cline-any cline-yes">1x</span>
901
+ <span class="cline-any cline-yes">1x</span>
902
+ <span class="cline-any cline-yes">1x</span>
903
+ <span class="cline-any cline-yes">1x</span>
904
+ <span class="cline-any cline-yes">14x</span>
905
+ <span class="cline-any cline-neutral">&nbsp;</span>
906
+ <span class="cline-any cline-yes">11x</span>
907
+ <span class="cline-any cline-yes">15x</span>
908
+ <span class="cline-any cline-yes">4x</span>
909
+ <span class="cline-any cline-yes">4x</span>
910
+ <span class="cline-any cline-yes">4x</span>
911
+ <span class="cline-any cline-yes">4x</span>
912
+ <span class="cline-any cline-yes">15x</span>
913
+ <span class="cline-any cline-yes">10x</span>
914
+ <span class="cline-any cline-yes">10x</span>
915
+ <span class="cline-any cline-yes">10x</span>
916
+ <span class="cline-any cline-yes">11x</span>
917
+ <span class="cline-any cline-yes">11x</span>
918
+ <span class="cline-any cline-yes">11x</span>
919
+ <span class="cline-any cline-neutral">&nbsp;</span>
920
+ <span class="cline-any cline-yes">12x</span>
921
+ <span class="cline-any cline-no">&nbsp;</span>
922
+ <span class="cline-any cline-no">&nbsp;</span>
923
+ <span class="cline-any cline-no">&nbsp;</span>
924
+ <span class="cline-any cline-no">&nbsp;</span>
925
+ <span class="cline-any cline-no">&nbsp;</span>
926
+ <span class="cline-any cline-no">&nbsp;</span>
927
+ <span class="cline-any cline-yes">12x</span>
928
+ <span class="cline-any cline-neutral">&nbsp;</span>
929
+ <span class="cline-any cline-neutral">&nbsp;</span>
930
+ <span class="cline-any cline-yes">12x</span>
931
+ <span class="cline-any cline-yes">12x</span>
932
+ <span class="cline-any cline-yes">12x</span>
933
+ <span class="cline-any cline-yes">14x</span>
934
+ <span class="cline-any cline-yes">14x</span>
935
+ <span class="cline-any cline-yes">14x</span>
936
+ <span class="cline-any cline-yes">14x</span>
937
+ <span class="cline-any cline-neutral">&nbsp;</span>
938
+ <span class="cline-any cline-neutral">&nbsp;</span>
939
+ <span class="cline-any cline-neutral">&nbsp;</span>
940
+ <span class="cline-any cline-neutral">&nbsp;</span>
941
+ <span class="cline-any cline-neutral">&nbsp;</span>
942
+ <span class="cline-any cline-neutral">&nbsp;</span>
943
+ <span class="cline-any cline-neutral">&nbsp;</span>
944
+ <span class="cline-any cline-neutral">&nbsp;</span>
945
+ <span class="cline-any cline-neutral">&nbsp;</span>
946
+ <span class="cline-any cline-neutral">&nbsp;</span>
947
+ <span class="cline-any cline-yes">1x</span>
948
+ <span class="cline-any cline-no">&nbsp;</span>
949
+ <span class="cline-any cline-no">&nbsp;</span>
950
+ <span class="cline-any cline-no">&nbsp;</span>
951
+ <span class="cline-any cline-no">&nbsp;</span>
952
+ <span class="cline-any cline-no">&nbsp;</span>
953
+ <span class="cline-any cline-no">&nbsp;</span>
954
+ <span class="cline-any cline-neutral">&nbsp;</span>
955
+ <span class="cline-any cline-neutral">&nbsp;</span>
956
+ <span class="cline-any cline-neutral">&nbsp;</span>
957
+ <span class="cline-any cline-neutral">&nbsp;</span>
958
+ <span class="cline-any cline-neutral">&nbsp;</span>
959
+ <span class="cline-any cline-no">&nbsp;</span>
960
+ <span class="cline-any cline-no">&nbsp;</span>
961
+ <span class="cline-any cline-no">&nbsp;</span>
962
+ <span class="cline-any cline-neutral">&nbsp;</span>
963
+ <span class="cline-any cline-no">&nbsp;</span>
964
+ <span class="cline-any cline-neutral">&nbsp;</span>
965
+ <span class="cline-any cline-no">&nbsp;</span>
966
+ <span class="cline-any cline-no">&nbsp;</span>
967
+ <span class="cline-any cline-neutral">&nbsp;</span>
968
+ <span class="cline-any cline-no">&nbsp;</span>
969
+ <span class="cline-any cline-no">&nbsp;</span>
970
+ <span class="cline-any cline-no">&nbsp;</span>
971
+ <span class="cline-any cline-no">&nbsp;</span>
972
+ <span class="cline-any cline-no">&nbsp;</span>
973
+ <span class="cline-any cline-no">&nbsp;</span>
974
+ <span class="cline-any cline-no">&nbsp;</span>
975
+ <span class="cline-any cline-neutral">&nbsp;</span>
976
+ <span class="cline-any cline-no">&nbsp;</span>
977
+ <span class="cline-any cline-no">&nbsp;</span>
978
+ <span class="cline-any cline-neutral">&nbsp;</span>
979
+ <span class="cline-any cline-neutral">&nbsp;</span>
980
+ <span class="cline-any cline-no">&nbsp;</span>
981
+ <span class="cline-any cline-no">&nbsp;</span>
982
+ <span class="cline-any cline-no">&nbsp;</span>
983
+ <span class="cline-any cline-neutral">&nbsp;</span>
984
+ <span class="cline-any cline-no">&nbsp;</span>
985
+ <span class="cline-any cline-no">&nbsp;</span>
986
+ <span class="cline-any cline-no">&nbsp;</span>
987
+ <span class="cline-any cline-no">&nbsp;</span>
988
+ <span class="cline-any cline-no">&nbsp;</span>
989
+ <span class="cline-any cline-no">&nbsp;</span>
990
+ <span class="cline-any cline-no">&nbsp;</span>
991
+ <span class="cline-any cline-no">&nbsp;</span>
992
+ <span class="cline-any cline-no">&nbsp;</span>
993
+ <span class="cline-any cline-neutral">&nbsp;</span>
994
+ <span class="cline-any cline-no">&nbsp;</span>
995
+ <span class="cline-any cline-no">&nbsp;</span>
996
+ <span class="cline-any cline-no">&nbsp;</span>
997
+ <span class="cline-any cline-no">&nbsp;</span>
998
+ <span class="cline-any cline-no">&nbsp;</span>
999
+ <span class="cline-any cline-neutral">&nbsp;</span>
1000
+ <span class="cline-any cline-no">&nbsp;</span>
1001
+ <span class="cline-any cline-no">&nbsp;</span>
1002
+ <span class="cline-any cline-no">&nbsp;</span>
1003
+ <span class="cline-any cline-neutral">&nbsp;</span>
1004
+ <span class="cline-any cline-no">&nbsp;</span>
1005
+ <span class="cline-any cline-neutral">&nbsp;</span>
1006
+ <span class="cline-any cline-neutral">&nbsp;</span>
1007
+ <span class="cline-any cline-no">&nbsp;</span>
1008
+ <span class="cline-any cline-no">&nbsp;</span>
1009
+ <span class="cline-any cline-no">&nbsp;</span>
1010
+ <span class="cline-any cline-no">&nbsp;</span>
1011
+ <span class="cline-any cline-no">&nbsp;</span>
1012
+ <span class="cline-any cline-no">&nbsp;</span>
1013
+ <span class="cline-any cline-no">&nbsp;</span>
1014
+ <span class="cline-any cline-no">&nbsp;</span>
1015
+ <span class="cline-any cline-no">&nbsp;</span>
1016
+ <span class="cline-any cline-neutral">&nbsp;</span>
1017
+ <span class="cline-any cline-no">&nbsp;</span>
1018
+ <span class="cline-any cline-no">&nbsp;</span>
1019
+ <span class="cline-any cline-no">&nbsp;</span>
1020
+ <span class="cline-any cline-no">&nbsp;</span>
1021
+ <span class="cline-any cline-no">&nbsp;</span>
1022
+ <span class="cline-any cline-no">&nbsp;</span>
1023
+ <span class="cline-any cline-no">&nbsp;</span>
1024
+ <span class="cline-any cline-no">&nbsp;</span>
1025
+ <span class="cline-any cline-no">&nbsp;</span>
1026
+ <span class="cline-any cline-no">&nbsp;</span>
1027
+ <span class="cline-any cline-no">&nbsp;</span>
1028
+ <span class="cline-any cline-no">&nbsp;</span>
1029
+ <span class="cline-any cline-no">&nbsp;</span>
1030
+ <span class="cline-any cline-no">&nbsp;</span>
1031
+ <span class="cline-any cline-no">&nbsp;</span>
1032
+ <span class="cline-any cline-no">&nbsp;</span>
1033
+ <span class="cline-any cline-no">&nbsp;</span>
1034
+ <span class="cline-any cline-neutral">&nbsp;</span>
1035
+ <span class="cline-any cline-neutral">&nbsp;</span>
1036
+ <span class="cline-any cline-no">&nbsp;</span>
1037
+ <span class="cline-any cline-no">&nbsp;</span>
1038
+ <span class="cline-any cline-no">&nbsp;</span>
1039
+ <span class="cline-any cline-no">&nbsp;</span>
1040
+ <span class="cline-any cline-no">&nbsp;</span>
1041
+ <span class="cline-any cline-no">&nbsp;</span>
1042
+ <span class="cline-any cline-no">&nbsp;</span>
1043
+ <span class="cline-any cline-no">&nbsp;</span>
1044
+ <span class="cline-any cline-no">&nbsp;</span>
1045
+ <span class="cline-any cline-neutral">&nbsp;</span>
1046
+ <span class="cline-any cline-no">&nbsp;</span>
1047
+ <span class="cline-any cline-no">&nbsp;</span>
1048
+ <span class="cline-any cline-no">&nbsp;</span>
1049
+ <span class="cline-any cline-no">&nbsp;</span>
1050
+ <span class="cline-any cline-no">&nbsp;</span>
1051
+ <span class="cline-any cline-no">&nbsp;</span>
1052
+ <span class="cline-any cline-neutral">&nbsp;</span>
1053
+ <span class="cline-any cline-neutral">&nbsp;</span>
1054
+ <span class="cline-any cline-no">&nbsp;</span>
1055
+ <span class="cline-any cline-no">&nbsp;</span>
1056
+ <span class="cline-any cline-no">&nbsp;</span>
1057
+ <span class="cline-any cline-no">&nbsp;</span>
1058
+ <span class="cline-any cline-no">&nbsp;</span>
1059
+ <span class="cline-any cline-neutral">&nbsp;</span>
1060
+ <span class="cline-any cline-no">&nbsp;</span>
1061
+ <span class="cline-any cline-no">&nbsp;</span>
1062
+ <span class="cline-any cline-no">&nbsp;</span>
1063
+ <span class="cline-any cline-no">&nbsp;</span>
1064
+ <span class="cline-any cline-no">&nbsp;</span>
1065
+ <span class="cline-any cline-no">&nbsp;</span>
1066
+ <span class="cline-any cline-no">&nbsp;</span>
1067
+ <span class="cline-any cline-no">&nbsp;</span>
1068
+ <span class="cline-any cline-no">&nbsp;</span>
1069
+ <span class="cline-any cline-no">&nbsp;</span>
1070
+ <span class="cline-any cline-no">&nbsp;</span>
1071
+ <span class="cline-any cline-no">&nbsp;</span>
1072
+ <span class="cline-any cline-no">&nbsp;</span>
1073
+ <span class="cline-any cline-no">&nbsp;</span>
1074
+ <span class="cline-any cline-no">&nbsp;</span>
1075
+ <span class="cline-any cline-no">&nbsp;</span>
1076
+ <span class="cline-any cline-no">&nbsp;</span>
1077
+ <span class="cline-any cline-no">&nbsp;</span>
1078
+ <span class="cline-any cline-no">&nbsp;</span>
1079
+ <span class="cline-any cline-no">&nbsp;</span>
1080
+ <span class="cline-any cline-no">&nbsp;</span>
1081
+ <span class="cline-any cline-no">&nbsp;</span>
1082
+ <span class="cline-any cline-no">&nbsp;</span>
1083
+ <span class="cline-any cline-no">&nbsp;</span>
1084
+ <span class="cline-any cline-no">&nbsp;</span>
1085
+ <span class="cline-any cline-no">&nbsp;</span>
1086
+ <span class="cline-any cline-neutral">&nbsp;</span>
1087
+ <span class="cline-any cline-no">&nbsp;</span>
1088
+ <span class="cline-any cline-no">&nbsp;</span>
1089
+ <span class="cline-any cline-no">&nbsp;</span>
1090
+ <span class="cline-any cline-no">&nbsp;</span>
1091
+ <span class="cline-any cline-no">&nbsp;</span>
1092
+ <span class="cline-any cline-no">&nbsp;</span>
1093
+ <span class="cline-any cline-no">&nbsp;</span>
1094
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">// Copyright 2021-2025 Prosopo (UK) Ltd.
1095
+ //
1096
+ // Licensed under the Apache License, Version 2.0 (the "License");
1097
+ // you may not use this file except in compliance with the License.
1098
+ // You may obtain a copy of the License at
1099
+ //
1100
+ // http://www.apache.org/licenses/LICENSE-2.0
1101
+ //
1102
+ // Unless required by applicable law or agreed to in writing, software
1103
+ // distributed under the License is distributed on an "AS IS" BASIS,
1104
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1105
+ // See the License for the specific language governing permissions and
1106
+ // limitations under the License.
1107
+ &nbsp;
1108
+ import { hexToU8a } from "@polkadot/util/hex";
1109
+ import { isHex } from "@polkadot/util/is";
1110
+ import {
1111
+ type Logger,
1112
+ ProsopoContractError,
1113
+ ProsopoEnvError,
1114
+ } from "@prosopo/common";
1115
+ import {
1116
+ type IIPValidation,
1117
+ type IIPValidationRules,
1118
+ type IPAddress,
1119
+ type IPComparisonResult,
1120
+ type IPValidateCondition,
1121
+ IPValidationAction,
1122
+ type ScheduledTaskNames,
1123
+ ScheduledTaskStatus,
1124
+ } from "@prosopo/types";
1125
+ import type { IProviderDatabase } from "@prosopo/types-database";
1126
+ import { at } from "@prosopo/util";
1127
+ import { decodeAddress, encodeAddress } from "@prosopo/util-crypto";
1128
+ import { Address4, Address6 } from "ip-address";
1129
+ import type { ObjectId } from "mongoose";
1130
+ import { compareIPs } from "./services/ipComparison.js";
1131
+ &nbsp;
1132
+ export <span class="fstat-no" title="function not covered" >function encodeStringAddress(address: string) {</span>
1133
+ <span class="cstat-no" title="statement not covered" > try {</span>
1134
+ <span class="cstat-no" title="statement not covered" > return encodeAddress(</span>
1135
+ <span class="cstat-no" title="statement not covered" > isHex(address) ? hexToU8a(address) : decodeAddress(address),</span>
1136
+ <span class="cstat-no" title="statement not covered" > );</span>
1137
+ <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
1138
+ <span class="cstat-no" title="statement not covered" > throw new ProsopoContractError("CONTRACT.INVALID_ADDRESS", {</span>
1139
+ <span class="cstat-no" title="statement not covered" > context: { address },</span>
1140
+ <span class="cstat-no" title="statement not covered" > });</span>
1141
+ <span class="cstat-no" title="statement not covered" > }</span>
1142
+ <span class="cstat-no" title="statement not covered" >}</span>
1143
+ &nbsp;
1144
+ export <span class="fstat-no" title="function not covered" >function shuffleArray&lt;T&gt;(array: T[]): T[] {</span>
1145
+ <span class="cstat-no" title="statement not covered" > for (let arrayIndex = array.length - 1; arrayIndex &gt; 0; arrayIndex--) {</span>
1146
+ <span class="cstat-no" title="statement not covered" > const randIndex = Math.floor(Math.random() * (arrayIndex + 1));</span>
1147
+ <span class="cstat-no" title="statement not covered" > const tmp = at(array, randIndex);</span>
1148
+ <span class="cstat-no" title="statement not covered" > array[randIndex] = at(array, arrayIndex);</span>
1149
+ <span class="cstat-no" title="statement not covered" > array[arrayIndex] = tmp;</span>
1150
+ <span class="cstat-no" title="statement not covered" > }</span>
1151
+ <span class="cstat-no" title="statement not covered" > return array;</span>
1152
+ <span class="cstat-no" title="statement not covered" >}</span>
1153
+ &nbsp;
1154
+ /**
1155
+ * Check if there is a scheduled task running.
1156
+ * If the scheduled task is running and not completed, return true.
1157
+ * If the scheduled task is running and completed, return false.
1158
+ * Otherwise, the scheduled task is not running, return false.
1159
+ */
1160
+ <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >export async function checkIfTaskIsRunning(</span></span>
1161
+ <span class="cstat-no" title="statement not covered" > taskName: ScheduledTaskNames,</span>
1162
+ <span class="cstat-no" title="statement not covered" > db: IProviderDatabase,</span>
1163
+ <span class="cstat-no" title="statement not covered" >): Promise&lt;boolean&gt; {</span>
1164
+ <span class="cstat-no" title="statement not covered" > const runningTask = await db.getLastScheduledTaskStatus(</span>
1165
+ <span class="cstat-no" title="statement not covered" > taskName,</span>
1166
+ <span class="cstat-no" title="statement not covered" > ScheduledTaskStatus.Running,</span>
1167
+ <span class="cstat-no" title="statement not covered" > );</span>
1168
+ <span class="cstat-no" title="statement not covered" > const twoMinutesAgo = new Date().getTime() - 1000 * 60 * 2;</span>
1169
+ // If the task is running and the task was started within the last 2 minutes
1170
+ // TODO: This is a temporary fix to prevent failed tasks from blocking the next task
1171
+ <span class="cstat-no" title="statement not covered" > if (runningTask &amp;&amp; runningTask.datetime &gt; twoMinutesAgo) {</span>
1172
+ <span class="cstat-no" title="statement not covered" > const completedTask = await db.getScheduledTaskStatus(</span>
1173
+ <span class="cstat-no" title="statement not covered" > runningTask._id as ObjectId,</span>
1174
+ <span class="cstat-no" title="statement not covered" > ScheduledTaskStatus.Completed,</span>
1175
+ <span class="cstat-no" title="statement not covered" > );</span>
1176
+ <span class="cstat-no" title="statement not covered" > return !completedTask;</span>
1177
+ <span class="cstat-no" title="statement not covered" > }</span>
1178
+ <span class="cstat-no" title="statement not covered" > return false;</span>
1179
+ <span class="cstat-no" title="statement not covered" >}</span>
1180
+ &nbsp;
1181
+ export const getIPAddress = <span class="fstat-no" title="function not covered" >(ipAddressString: string): IPAddress =&gt; {</span>
1182
+ <span class="cstat-no" title="statement not covered" > try {</span>
1183
+ <span class="cstat-no" title="statement not covered" > try {</span>
1184
+ <span class="cstat-no" title="statement not covered" > return new Address4(ipAddressString);</span>
1185
+ <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
1186
+ <span class="cstat-no" title="statement not covered" > return new Address6(ipAddressString);</span>
1187
+ <span class="cstat-no" title="statement not covered" > }</span>
1188
+ <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
1189
+ <span class="cstat-no" title="statement not covered" > throw new ProsopoEnvError("API.INVALID_IP");</span>
1190
+ <span class="cstat-no" title="statement not covered" > }</span>
1191
+ <span class="cstat-no" title="statement not covered" >};</span>
1192
+ &nbsp;
1193
+ export const getIPAddressFromBigInt = <span class="fstat-no" title="function not covered" >(ipAddressBigInt: bigint): IPAddress =&gt; {</span>
1194
+ <span class="cstat-no" title="statement not covered" > try {</span>
1195
+ <span class="cstat-no" title="statement not covered" > if (ipAddressBigInt &gt; 4228250626n) {</span>
1196
+ <span class="cstat-no" title="statement not covered" > return Address6.fromBigInt(BigInt(ipAddressBigInt));</span>
1197
+ <span class="cstat-no" title="statement not covered" > }</span>
1198
+ <span class="cstat-no" title="statement not covered" > return Address4.fromBigInt(BigInt(ipAddressBigInt));</span>
1199
+ <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
1200
+ <span class="cstat-no" title="statement not covered" > throw new ProsopoEnvError("API.INVALID_IP");</span>
1201
+ <span class="cstat-no" title="statement not covered" > }</span>
1202
+ <span class="cstat-no" title="statement not covered" >};</span>
1203
+ &nbsp;
1204
+ /**
1205
+ * Validates that the provided IP address matches the challenge record's IP address
1206
+ * @param ip - The IP address string to validate
1207
+ * @param challengeIpAddress - The IP address from the challenge record
1208
+ * @param logger - Logger instance for debug messages
1209
+ * @returns Object with validation result and optional error message
1210
+ */
1211
+ export const validateIpAddress = <span class="fstat-no" title="function not covered" >(</span>
1212
+ <span class="cstat-no" title="statement not covered" > ip: string | undefined,</span>
1213
+ <span class="cstat-no" title="statement not covered" > challengeIpAddress: IPAddress,</span>
1214
+ <span class="cstat-no" title="statement not covered" > logger: Logger,</span>
1215
+ <span class="cstat-no" title="statement not covered" >): { isValid: boolean; errorMessage?: string } =&gt; {</span>
1216
+ <span class="cstat-no" title="statement not covered" > if (!ip) {</span>
1217
+ <span class="cstat-no" title="statement not covered" > return { isValid: true }; // IP validation is optional</span>
1218
+ <span class="cstat-no" title="statement not covered" > }</span>
1219
+ &nbsp;
1220
+ <span class="cstat-no" title="statement not covered" > let ipV4orV6Address: IPAddress;</span>
1221
+ <span class="cstat-no" title="statement not covered" > try {</span>
1222
+ <span class="cstat-no" title="statement not covered" > ipV4orV6Address = getIPAddress(ip);</span>
1223
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({ data: { ipV4orV6Address } }));</span>
1224
+ <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
1225
+ <span class="cstat-no" title="statement not covered" > const errorMessage = `Invalid IP address: ${ip}`;</span>
1226
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({ msg: errorMessage }));</span>
1227
+ <span class="cstat-no" title="statement not covered" > return { isValid: false, errorMessage };</span>
1228
+ <span class="cstat-no" title="statement not covered" > }</span>
1229
+ &nbsp;
1230
+ // Make sure both IP addresses are of the same type (either both IPv4 or both IPv6)
1231
+ <span class="cstat-no" title="statement not covered" > ipV4orV6Address =</span>
1232
+ <span class="cstat-no" title="statement not covered" > "address4" in ipV4orV6Address &amp;&amp; ipV4orV6Address.address4</span>
1233
+ <span class="cstat-no" title="statement not covered" > ? ipV4orV6Address.address4</span>
1234
+ <span class="cstat-no" title="statement not covered" > : ipV4orV6Address;</span>
1235
+ <span class="cstat-no" title="statement not covered" > challengeIpAddress =</span>
1236
+ <span class="cstat-no" title="statement not covered" > "address4" in challengeIpAddress &amp;&amp; challengeIpAddress.address4</span>
1237
+ <span class="cstat-no" title="statement not covered" > ? challengeIpAddress.address4</span>
1238
+ <span class="cstat-no" title="statement not covered" > : challengeIpAddress;</span>
1239
+ &nbsp;
1240
+ <span class="cstat-no" title="statement not covered" > if (ipV4orV6Address.v4 &amp;&amp; !challengeIpAddress.v4) {</span>
1241
+ <span class="cstat-no" title="statement not covered" > challengeIpAddress = new Address4(</span>
1242
+ <span class="cstat-no" title="statement not covered" > (&lt;Address6&gt;challengeIpAddress).to4().correctForm(),</span>
1243
+ <span class="cstat-no" title="statement not covered" > );</span>
1244
+ <span class="cstat-no" title="statement not covered" > }</span>
1245
+ &nbsp;
1246
+ <span class="cstat-no" title="statement not covered" > if (challengeIpAddress.bigInt() - ipV4orV6Address.bigInt() !== 0n) {</span>
1247
+ <span class="cstat-no" title="statement not covered" > const errorMessage = `IP address mismatch: ${challengeIpAddress.address} !== ${ipV4orV6Address.address}`;</span>
1248
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({</span>
1249
+ <span class="cstat-no" title="statement not covered" > msg: errorMessage,</span>
1250
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1251
+ <span class="cstat-no" title="statement not covered" > challengeIp: challengeIpAddress.address,</span>
1252
+ <span class="cstat-no" title="statement not covered" > providedIp: ipV4orV6Address.address,</span>
1253
+ <span class="cstat-no" title="statement not covered" > },</span>
1254
+ <span class="cstat-no" title="statement not covered" > }));</span>
1255
+ <span class="cstat-no" title="statement not covered" > return { isValid: false, errorMessage };</span>
1256
+ <span class="cstat-no" title="statement not covered" > }</span>
1257
+ &nbsp;
1258
+ <span class="cstat-no" title="statement not covered" > return { isValid: true };</span>
1259
+ <span class="cstat-no" title="statement not covered" >};</span>
1260
+ &nbsp;
1261
+ /**
1262
+ * Evaluates IP validation rules based on IP comparison results
1263
+ * @param comparison - IP comparison results from compareIPs
1264
+ * @param rules - IP validation rules configuration
1265
+ * @param logger - Logger instance
1266
+ * @returns Validation result with action to take
1267
+ */
1268
+ export const evaluateIpValidationRules = (
1269
+ comparison: IPComparisonResult,
1270
+ rules: IIPValidationRules,
1271
+ logger: Logger,
1272
+ ): {
1273
+ action: IPValidationAction;
1274
+ errorMessage?: string;
1275
+ shouldFlag?: boolean;
1276
+ } =&gt; {
1277
+ // Early return if no comparison data is provided
1278
+ if (!comparison.comparison) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1279
+ <span class="cstat-no" title="statement not covered" > return { action: IPValidationAction.Allow };</span>
1280
+ <span class="cstat-no" title="statement not covered" > }</span>
1281
+ &nbsp;
1282
+ const conditions: IPValidateCondition[] = [];
1283
+ const rejectActions = Object.values(rules.actions).filter(
1284
+ (action) =&gt; action === IPValidationAction.Reject,
1285
+ );
1286
+ &nbsp;
1287
+ // Apply country-specific overrides if they exist
1288
+ const ip1Country = comparison.comparison.ip1Details?.country;
1289
+ const ip2Country = comparison.comparison.ip2Details?.country;
1290
+ const ip1CountryCode = comparison.comparison.ip1Details?.countryCode;
1291
+ const ip2CountryCode = comparison.comparison.ip2Details?.countryCode;
1292
+ let effectiveRules = rules;
1293
+ let countryOverride: undefined | IIPValidation = undefined;
1294
+ if (ip1CountryCode &amp;&amp; rules.countryOverrides?.[ip1CountryCode]) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1295
+ <span class="cstat-no" title="statement not covered" > countryOverride = rules.countryOverrides[ip1CountryCode];</span>
1296
+ <span class="cstat-no" title="statement not covered" > }</span>
1297
+ if (ip2CountryCode &amp;&amp; rules.countryOverrides?.[ip2CountryCode]) {
1298
+ countryOverride = rules.countryOverrides[ip2CountryCode];
1299
+ }
1300
+ if (countryOverride) {
1301
+ effectiveRules = {
1302
+ ...rules,
1303
+ actions: {
1304
+ ...rules.actions,
1305
+ ...countryOverride.actions,
1306
+ },
1307
+ distanceThresholdKm:
1308
+ countryOverride.distanceThresholdKm ?? rules.distanceThresholdKm,
1309
+ abuseScoreThreshold:
1310
+ countryOverride.abuseScoreThreshold ?? rules.abuseScoreThreshold,
1311
+ requireAllConditions:
1312
+ countryOverride.requireAllConditions ?? rules.requireAllConditions,
1313
+ };
1314
+ }
1315
+ &nbsp;
1316
+ // Check for country change
1317
+ if (ip1Country !== ip2Country) {
1318
+ conditions.push({
1319
+ met: true,
1320
+ action: effectiveRules.actions.countryChangeAction,
1321
+ message: `Country changed from ${ip1Country} to ${ip2Country}`,
1322
+ });
1323
+ }
1324
+ &nbsp;
1325
+ // Check for city change
1326
+ const ip1City = comparison.comparison.ip1Details?.city;
1327
+ const ip2City = comparison.comparison.ip2Details?.city;
1328
+ if (ip1City !== ip2City) {
1329
+ conditions.push({
1330
+ met: true,
1331
+ action: effectiveRules.actions.cityChangeAction,
1332
+ message: `City changed from ${ip1City} to ${ip2City}`,
1333
+ });
1334
+ }
1335
+ &nbsp;
1336
+ // Check for ISP change
1337
+ if (comparison.comparison.differentProviders) {
1338
+ const ip1Provider = comparison.comparison.ip1Details?.provider;
1339
+ const ip2Provider = comparison.comparison.ip2Details?.provider;
1340
+ conditions.push({
1341
+ met: true,
1342
+ action: effectiveRules.actions.ispChangeAction,
1343
+ message: `ISP changed from ${ip1Provider} to ${ip2Provider}`,
1344
+ });
1345
+ }
1346
+ &nbsp;
1347
+ // Check for distance exceed condition
1348
+ const distanceKm = comparison.comparison.distanceKm;
1349
+ if (
1350
+ distanceKm !== undefined &amp;&amp;
1351
+ distanceKm &gt; effectiveRules.distanceThresholdKm
1352
+ ) {
1353
+ conditions.push({
1354
+ met: true,
1355
+ action: effectiveRules.actions.distanceExceedAction,
1356
+ message: `IP addresses are ${distanceKm.toFixed(2)}km apart (&gt;${effectiveRules.distanceThresholdKm}km limit)`,
1357
+ });
1358
+ }
1359
+ &nbsp;
1360
+ console.log(JSON.stringify(effectiveRules, null, 2));
1361
+ // Check for abuse score exceed condition
1362
+ const ip2AbuseScore = comparison.comparison.ip2Details?.abuserScore;
1363
+ if (
1364
+ ip2AbuseScore !== undefined &amp;&amp;
1365
+ ip2AbuseScore &gt; effectiveRules.abuseScoreThreshold
1366
+ ) {
1367
+ conditions.push({
1368
+ met: true,
1369
+ action: effectiveRules.actions.abuseScoreExceedAction,
1370
+ message: `Abuse score ${ip2AbuseScore.toFixed(4)} exceeds threshold ${effectiveRules.abuseScoreThreshold}`,
1371
+ });
1372
+ }
1373
+ const ip1AbuseScore = comparison.comparison.ip1Details?.abuserScore;
1374
+ if (
1375
+ ip1AbuseScore !== undefined &amp;&amp;
1376
+ ip1AbuseScore &gt; effectiveRules.abuseScoreThreshold
1377
+ ) {
1378
+ conditions.push({
1379
+ met: true,
1380
+ action: effectiveRules.actions.abuseScoreExceedAction,
1381
+ message: `Abuse score ${ip1AbuseScore.toFixed(4)} exceeds threshold ${effectiveRules.abuseScoreThreshold}`,
1382
+ });
1383
+ }
1384
+ &nbsp;
1385
+ // If no conditions are met, allow
1386
+ if (conditions.length === 0) {
1387
+ return { action: IPValidationAction.Allow };
1388
+ }
1389
+ &nbsp;
1390
+ const errorMessages: string[] = [];
1391
+ let finalAction = IPValidationAction.Allow;
1392
+ let shouldFlag = false;
1393
+ &nbsp;
1394
+ // Determine action based on requireAllConditions flag
1395
+ if (effectiveRules.requireAllConditions) {
1396
+ // Apply AND logic: all reject actions must be met to reject
1397
+ const rejectConditions = conditions.filter(
1398
+ (c) =&gt; c.action === IPValidationAction.Reject,
1399
+ );
1400
+ &nbsp;
1401
+ // If at least as many reject conditions as reject actions exist, we reject
1402
+ if (
1403
+ rejectConditions.length &gt; 0 &amp;&amp;
1404
+ rejectConditions.length &gt;= rejectActions.length
1405
+ ) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1406
+ <span class="cstat-no" title="statement not covered" > finalAction = IPValidationAction.Reject;</span>
1407
+ <span class="cstat-no" title="statement not covered" > }</span>
1408
+ &nbsp;
1409
+ // Collect error messages for all reject/flag conditions
1410
+ for (const condition of conditions) {
1411
+ if (
1412
+ condition.action === IPValidationAction.<span class="branch-0 cbranch-no" title="branch not covered" >Reject ||</span>
1413
+ <span class="cstat-no" title="statement not covered" > condition.action === IPValidationAction.Flag</span>
1414
+ ) {
1415
+ errorMessages.push(condition.message);
1416
+ }
1417
+ }
1418
+ } else {
1419
+ // Apply OR logic: the first reject condition triggers rejection
1420
+ for (const condition of conditions) {
1421
+ if (condition.action === IPValidationAction.Reject) {
1422
+ finalAction = IPValidationAction.Reject;
1423
+ errorMessages.push(condition.message);
1424
+ break; // Reject is the most restrictive, no need to check further
1425
+ }
1426
+ if (condition.action === IPValidationAction.Flag) {
1427
+ finalAction = IPValidationAction.Flag;
1428
+ shouldFlag = true;
1429
+ }
1430
+ errorMessages.push(condition.message);
1431
+ }
1432
+ }
1433
+ &nbsp;
1434
+ logger.info(() =&gt; ({
1435
+ <span class="cstat-no" title="statement not covered" > msg: `IP validation rules evaluated: ${finalAction}`,</span>
1436
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1437
+ <span class="cstat-no" title="statement not covered" > conditions,</span>
1438
+ <span class="cstat-no" title="statement not covered" > finalAction,</span>
1439
+ <span class="cstat-no" title="statement not covered" > requireAllConditions: effectiveRules.requireAllConditions,</span>
1440
+ <span class="cstat-no" title="statement not covered" > },</span>
1441
+ }));
1442
+ &nbsp;
1443
+ // Return the evaluation result
1444
+ return {
1445
+ action: finalAction,
1446
+ errorMessage:
1447
+ errorMessages.length &gt; 0 ? errorMessages.join("; "<span class="branch-0 cbranch-no" title="branch not covered" >) : undefined,</span>
1448
+ shouldFlag,
1449
+ };
1450
+ };
1451
+ &nbsp;
1452
+ /**
1453
+ * @param ip - The IP address string to validate
1454
+ * @param challengeIpAddress - The IP address from the challenge record
1455
+ * @param logger - Logger instance for debug messages
1456
+ * @param apiKey
1457
+ * @param apiUrl
1458
+ * @param ipValidationRules - IP validation rules configuration
1459
+ * @returns Object with validation result, optional error message, and distance info
1460
+ */
1461
+ export const deepValidateIpAddress = <span class="fstat-no" title="function not covered" >async (</span>
1462
+ <span class="cstat-no" title="statement not covered" > ip: string,</span>
1463
+ <span class="cstat-no" title="statement not covered" > challengeIpAddress: IPAddress,</span>
1464
+ <span class="cstat-no" title="statement not covered" > logger: Logger,</span>
1465
+ <span class="cstat-no" title="statement not covered" > apiKey: string,</span>
1466
+ <span class="cstat-no" title="statement not covered" > apiUrl: string,</span>
1467
+ <span class="cstat-no" title="statement not covered" > ipValidationRules?: IIPValidationRules,</span>
1468
+ ): Promise&lt;{
1469
+ isValid: boolean;
1470
+ errorMessage?: string;
1471
+ distanceKm?: number;
1472
+ shouldFlag?: boolean;
1473
+ <span class="cstat-no" title="statement not covered" >}&gt; =&gt; {</span>
1474
+ <span class="cstat-no" title="statement not covered" > const standardValidation = validateIpAddress(ip, challengeIpAddress, logger);</span>
1475
+ <span class="cstat-no" title="statement not covered" > if (!standardValidation.isValid) {</span>
1476
+ // Check if this is a format error or a mismatch
1477
+ <span class="cstat-no" title="statement not covered" > if (standardValidation.errorMessage?.includes("Invalid IP address")) {</span>
1478
+ // Format error - return the error
1479
+ <span class="cstat-no" title="statement not covered" > return standardValidation;</span>
1480
+ <span class="cstat-no" title="statement not covered" > }</span>
1481
+ // IP mismatch - continue to distance checking if not forcing consistent IPs
1482
+ <span class="cstat-no" title="statement not covered" > if (ipValidationRules?.forceConsistentIp === true) {</span>
1483
+ <span class="cstat-no" title="statement not covered" > return {</span>
1484
+ <span class="cstat-no" title="statement not covered" > isValid: false,</span>
1485
+ <span class="cstat-no" title="statement not covered" > errorMessage: standardValidation.errorMessage,</span>
1486
+ <span class="cstat-no" title="statement not covered" > };</span>
1487
+ <span class="cstat-no" title="statement not covered" > }</span>
1488
+ <span class="cstat-no" title="statement not covered" > } else {</span>
1489
+ // IPs match exactly - return valid without distance checking
1490
+ <span class="cstat-no" title="statement not covered" > return { isValid: true };</span>
1491
+ <span class="cstat-no" title="statement not covered" > }</span>
1492
+ &nbsp;
1493
+ // Both IPs valid but different -&gt; check distance
1494
+ <span class="cstat-no" title="statement not covered" > try {</span>
1495
+ <span class="cstat-no" title="statement not covered" > const challengeIpString = challengeIpAddress.address;</span>
1496
+ <span class="cstat-no" title="statement not covered" > const comparison = await compareIPs(challengeIpString, ip, apiKey, apiUrl);</span>
1497
+ &nbsp;
1498
+ <span class="cstat-no" title="statement not covered" > if ("error" in comparison) {</span>
1499
+ <span class="cstat-no" title="statement not covered" > logger.error(() =&gt; ({</span>
1500
+ <span class="cstat-no" title="statement not covered" > msg: "Failed to get IP distance comparison",</span>
1501
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1502
+ <span class="cstat-no" title="statement not covered" > error: comparison.error,</span>
1503
+ <span class="cstat-no" title="statement not covered" > challengeIp: challengeIpString,</span>
1504
+ <span class="cstat-no" title="statement not covered" > providedIp: ip,</span>
1505
+ <span class="cstat-no" title="statement not covered" > },</span>
1506
+ <span class="cstat-no" title="statement not covered" > }));</span>
1507
+ // If we can't do distance comparison and IPs don't match exactly, be strict
1508
+ <span class="cstat-no" title="statement not covered" > return {</span>
1509
+ <span class="cstat-no" title="statement not covered" > isValid: false,</span>
1510
+ <span class="cstat-no" title="statement not covered" > errorMessage: "Could not determine IP distance",</span>
1511
+ <span class="cstat-no" title="statement not covered" > };</span>
1512
+ <span class="cstat-no" title="statement not covered" > }</span>
1513
+ &nbsp;
1514
+ <span class="cstat-no" title="statement not covered" > if (comparison.ipsMatch) {</span>
1515
+ <span class="cstat-no" title="statement not covered" > return { isValid: true };</span>
1516
+ <span class="cstat-no" title="statement not covered" > }</span>
1517
+ &nbsp;
1518
+ <span class="cstat-no" title="statement not covered" > const distanceKm = comparison.comparison?.distanceKm;</span>
1519
+ &nbsp;
1520
+ // If no validation rules provided, use legacy logic (1000km threshold)
1521
+ <span class="cstat-no" title="statement not covered" > if (!ipValidationRules) {</span>
1522
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({</span>
1523
+ <span class="cstat-no" title="statement not covered" > msg: "No IP validation rules provided, using legacy logic",</span>
1524
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1525
+ <span class="cstat-no" title="statement not covered" > challengeIp: challengeIpString,</span>
1526
+ <span class="cstat-no" title="statement not covered" > providedIp: ip,</span>
1527
+ <span class="cstat-no" title="statement not covered" > distanceKm: distanceKm,</span>
1528
+ <span class="cstat-no" title="statement not covered" > },</span>
1529
+ <span class="cstat-no" title="statement not covered" > }));</span>
1530
+ // Legacy distance &gt; 1000km -&gt; fail and log
1531
+ <span class="cstat-no" title="statement not covered" > if (distanceKm !== undefined &amp;&amp; distanceKm &gt; 1000) {</span>
1532
+ <span class="cstat-no" title="statement not covered" > const errorMessage = `IP addresses are too far apart: ${distanceKm.toFixed(2)}km (&gt;1000km limit)`;</span>
1533
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({</span>
1534
+ <span class="cstat-no" title="statement not covered" > msg: "IP validation failed - distance too great",</span>
1535
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1536
+ <span class="cstat-no" title="statement not covered" > challengeIp: challengeIpString,</span>
1537
+ <span class="cstat-no" title="statement not covered" > providedIp: ip,</span>
1538
+ <span class="cstat-no" title="statement not covered" > distanceKm: distanceKm,</span>
1539
+ <span class="cstat-no" title="statement not covered" > comparison: comparison.comparison,</span>
1540
+ <span class="cstat-no" title="statement not covered" > },</span>
1541
+ <span class="cstat-no" title="statement not covered" > }));</span>
1542
+ <span class="cstat-no" title="statement not covered" > return {</span>
1543
+ <span class="cstat-no" title="statement not covered" > isValid: false,</span>
1544
+ <span class="cstat-no" title="statement not covered" > errorMessage,</span>
1545
+ <span class="cstat-no" title="statement not covered" > distanceKm,</span>
1546
+ <span class="cstat-no" title="statement not covered" > };</span>
1547
+ <span class="cstat-no" title="statement not covered" > }</span>
1548
+ &nbsp;
1549
+ // Legacy distance &lt;= 1000km -&gt; allow flag
1550
+ <span class="cstat-no" title="statement not covered" > logger.info(() =&gt; ({</span>
1551
+ <span class="cstat-no" title="statement not covered" > msg: "IP addresses differ but within acceptable distance",</span>
1552
+ <span class="cstat-no" title="statement not covered" > data: {</span>
1553
+ <span class="cstat-no" title="statement not covered" > challengeIp: challengeIpString,</span>
1554
+ <span class="cstat-no" title="statement not covered" > providedIp: ip,</span>
1555
+ <span class="cstat-no" title="statement not covered" > distanceKm: distanceKm,</span>
1556
+ <span class="cstat-no" title="statement not covered" > comparison: comparison.comparison,</span>
1557
+ <span class="cstat-no" title="statement not covered" > },</span>
1558
+ <span class="cstat-no" title="statement not covered" > }));</span>
1559
+ &nbsp;
1560
+ <span class="cstat-no" title="statement not covered" > return {</span>
1561
+ <span class="cstat-no" title="statement not covered" > isValid: true,</span>
1562
+ <span class="cstat-no" title="statement not covered" > distanceKm,</span>
1563
+ <span class="cstat-no" title="statement not covered" > shouldFlag: true,</span>
1564
+ <span class="cstat-no" title="statement not covered" > };</span>
1565
+ <span class="cstat-no" title="statement not covered" > }</span>
1566
+ &nbsp;
1567
+ // Use configurable validation rules
1568
+ <span class="cstat-no" title="statement not covered" > const ruleEvaluation = evaluateIpValidationRules(</span>
1569
+ <span class="cstat-no" title="statement not covered" > comparison,</span>
1570
+ <span class="cstat-no" title="statement not covered" > ipValidationRules,</span>
1571
+ <span class="cstat-no" title="statement not covered" > logger,</span>
1572
+ <span class="cstat-no" title="statement not covered" > );</span>
1573
+ &nbsp;
1574
+ <span class="cstat-no" title="statement not covered" > switch (ruleEvaluation.action) {</span>
1575
+ <span class="cstat-no" title="statement not covered" > case IPValidationAction.Reject:</span>
1576
+ <span class="cstat-no" title="statement not covered" > return {</span>
1577
+ <span class="cstat-no" title="statement not covered" > isValid: false,</span>
1578
+ <span class="cstat-no" title="statement not covered" > errorMessage: ruleEvaluation.errorMessage,</span>
1579
+ <span class="cstat-no" title="statement not covered" > distanceKm,</span>
1580
+ <span class="cstat-no" title="statement not covered" > };</span>
1581
+ <span class="cstat-no" title="statement not covered" > case IPValidationAction.Flag:</span>
1582
+ <span class="cstat-no" title="statement not covered" > return {</span>
1583
+ <span class="cstat-no" title="statement not covered" > isValid: true,</span>
1584
+ <span class="cstat-no" title="statement not covered" > distanceKm,</span>
1585
+ <span class="cstat-no" title="statement not covered" > shouldFlag: true,</span>
1586
+ <span class="cstat-no" title="statement not covered" > errorMessage: ruleEvaluation.errorMessage,</span>
1587
+ <span class="cstat-no" title="statement not covered" > };</span>
1588
+ <span class="cstat-no" title="statement not covered" > default:</span>
1589
+ <span class="cstat-no" title="statement not covered" > return {</span>
1590
+ <span class="cstat-no" title="statement not covered" > isValid: true,</span>
1591
+ <span class="cstat-no" title="statement not covered" > distanceKm,</span>
1592
+ <span class="cstat-no" title="statement not covered" > };</span>
1593
+ <span class="cstat-no" title="statement not covered" > }</span>
1594
+ <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
1595
+ <span class="cstat-no" title="statement not covered" > logger.error(() =&gt; ({</span>
1596
+ <span class="cstat-no" title="statement not covered" > msg: "Error during IP distance validation",</span>
1597
+ <span class="cstat-no" title="statement not covered" > err: error,</span>
1598
+ <span class="cstat-no" title="statement not covered" > data: { challengeIp: challengeIpAddress.address, providedIp: ip },</span>
1599
+ <span class="cstat-no" title="statement not covered" > }));</span>
1600
+ // Something weird going on -&gt; allow but flag
1601
+ <span class="cstat-no" title="statement not covered" > return {</span>
1602
+ <span class="cstat-no" title="statement not covered" > isValid: true,</span>
1603
+ <span class="cstat-no" title="statement not covered" > shouldFlag: true,</span>
1604
+ <span class="cstat-no" title="statement not covered" > errorMessage: "IP distance validation error",</span>
1605
+ <span class="cstat-no" title="statement not covered" > };</span>
1606
+ <span class="cstat-no" title="statement not covered" > }</span>
1607
+ <span class="cstat-no" title="statement not covered" >};</span>
1608
+ &nbsp;</pre></td></tr></table></pre>
1609
+
1610
+ <div class='push'></div><!-- for sticky footer -->
1611
+ </div><!-- /wrapper -->
1612
+ <div class='footer quiet pad2 space-top1 center small'>
1613
+ Code coverage generated by
1614
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1615
+ at 2025-10-22T12:32:26.285Z
1616
+ </div>
1617
+ <script src="../prettify.js"></script>
1618
+ <script>
1619
+ window.onload = function () {
1620
+ prettyPrint();
1621
+ };
1622
+ </script>
1623
+ <script src="../sorter.js"></script>
1624
+ <script src="../block-navigation.js"></script>
1625
+ </body>
1626
+ </html>
1627
+