circle-ir 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +200 -0
  3. package/configs/sinks/code_injection.yaml +672 -0
  4. package/configs/sinks/command.yaml +917 -0
  5. package/configs/sinks/deserialization.yaml +105 -0
  6. package/configs/sinks/ldap.yaml +136 -0
  7. package/configs/sinks/nodejs.json +629 -0
  8. package/configs/sinks/path.yaml +715 -0
  9. package/configs/sinks/python.json +501 -0
  10. package/configs/sinks/rust.json +339 -0
  11. package/configs/sinks/sql.yaml +233 -0
  12. package/configs/sinks/ssrf.yaml +160 -0
  13. package/configs/sinks/xpath.yaml +121 -0
  14. package/configs/sinks/xss.yaml +727 -0
  15. package/configs/sources/db_sources.yaml +90 -0
  16. package/configs/sources/env_sources.yaml +94 -0
  17. package/configs/sources/express.json +197 -0
  18. package/configs/sources/file_sources.yaml +164 -0
  19. package/configs/sources/http_sources.yaml +379 -0
  20. package/configs/sources/io_sources.yaml +519 -0
  21. package/configs/sources/network_sources.yaml +99 -0
  22. package/configs/sources/python.json +230 -0
  23. package/configs/sources/rust.json +286 -0
  24. package/configs/sources/spring.yaml +70 -0
  25. package/dist/analysis/advisory-db.d.ts +86 -0
  26. package/dist/analysis/advisory-db.js +104 -0
  27. package/dist/analysis/advisory-db.js.map +1 -0
  28. package/dist/analysis/cargo-parser.d.ts +42 -0
  29. package/dist/analysis/cargo-parser.js +102 -0
  30. package/dist/analysis/cargo-parser.js.map +1 -0
  31. package/dist/analysis/config-loader.d.ts +37 -0
  32. package/dist/analysis/config-loader.js +1561 -0
  33. package/dist/analysis/config-loader.js.map +1 -0
  34. package/dist/analysis/constant-propagation/ast-utils.d.ts +25 -0
  35. package/dist/analysis/constant-propagation/ast-utils.js +34 -0
  36. package/dist/analysis/constant-propagation/ast-utils.js.map +1 -0
  37. package/dist/analysis/constant-propagation/evaluator.d.ts +32 -0
  38. package/dist/analysis/constant-propagation/evaluator.js +296 -0
  39. package/dist/analysis/constant-propagation/evaluator.js.map +1 -0
  40. package/dist/analysis/constant-propagation/index.d.ts +62 -0
  41. package/dist/analysis/constant-propagation/index.js +152 -0
  42. package/dist/analysis/constant-propagation/index.js.map +1 -0
  43. package/dist/analysis/constant-propagation/patterns.d.ts +8 -0
  44. package/dist/analysis/constant-propagation/patterns.js +126 -0
  45. package/dist/analysis/constant-propagation/patterns.js.map +1 -0
  46. package/dist/analysis/constant-propagation/propagator.d.ts +180 -0
  47. package/dist/analysis/constant-propagation/propagator.js +1985 -0
  48. package/dist/analysis/constant-propagation/propagator.js.map +1 -0
  49. package/dist/analysis/constant-propagation/types.d.ts +63 -0
  50. package/dist/analysis/constant-propagation/types.js +5 -0
  51. package/dist/analysis/constant-propagation/types.js.map +1 -0
  52. package/dist/analysis/constant-propagation.d.ts +9 -0
  53. package/dist/analysis/constant-propagation.js +18 -0
  54. package/dist/analysis/constant-propagation.js.map +1 -0
  55. package/dist/analysis/dependency-scanner.d.ts +79 -0
  56. package/dist/analysis/dependency-scanner.js +122 -0
  57. package/dist/analysis/dependency-scanner.js.map +1 -0
  58. package/dist/analysis/dfg-verifier.d.ts +116 -0
  59. package/dist/analysis/dfg-verifier.js +399 -0
  60. package/dist/analysis/dfg-verifier.js.map +1 -0
  61. package/dist/analysis/findings.d.ts +11 -0
  62. package/dist/analysis/findings.js +228 -0
  63. package/dist/analysis/findings.js.map +1 -0
  64. package/dist/analysis/index.d.ts +16 -0
  65. package/dist/analysis/index.js +18 -0
  66. package/dist/analysis/index.js.map +1 -0
  67. package/dist/analysis/interprocedural.d.ts +99 -0
  68. package/dist/analysis/interprocedural.js +526 -0
  69. package/dist/analysis/interprocedural.js.map +1 -0
  70. package/dist/analysis/path-finder.d.ts +133 -0
  71. package/dist/analysis/path-finder.js +354 -0
  72. package/dist/analysis/path-finder.js.map +1 -0
  73. package/dist/analysis/rules.d.ts +75 -0
  74. package/dist/analysis/rules.js +332 -0
  75. package/dist/analysis/rules.js.map +1 -0
  76. package/dist/analysis/semver.d.ts +27 -0
  77. package/dist/analysis/semver.js +127 -0
  78. package/dist/analysis/semver.js.map +1 -0
  79. package/dist/analysis/taint-matcher.d.ts +15 -0
  80. package/dist/analysis/taint-matcher.js +634 -0
  81. package/dist/analysis/taint-matcher.js.map +1 -0
  82. package/dist/analysis/taint-propagation.d.ts +67 -0
  83. package/dist/analysis/taint-propagation.js +298 -0
  84. package/dist/analysis/taint-propagation.js.map +1 -0
  85. package/dist/analysis/unresolved.d.ts +14 -0
  86. package/dist/analysis/unresolved.js +202 -0
  87. package/dist/analysis/unresolved.js.map +1 -0
  88. package/dist/analyzer.d.ts +43 -0
  89. package/dist/analyzer.js +1010 -0
  90. package/dist/analyzer.js.map +1 -0
  91. package/dist/browser/circle-ir.js +16576 -0
  92. package/dist/browser.d.ts +38 -0
  93. package/dist/browser.js +38 -0
  94. package/dist/browser.js.map +1 -0
  95. package/dist/core/circle-ir-core.cjs +13626 -0
  96. package/dist/core/circle-ir-core.d.ts +59 -0
  97. package/dist/core/circle-ir-core.js +13591 -0
  98. package/dist/core/extractors/calls.d.ts +13 -0
  99. package/dist/core/extractors/calls.js +1429 -0
  100. package/dist/core/extractors/calls.js.map +1 -0
  101. package/dist/core/extractors/cfg.d.ts +9 -0
  102. package/dist/core/extractors/cfg.js +519 -0
  103. package/dist/core/extractors/cfg.js.map +1 -0
  104. package/dist/core/extractors/dfg.d.ts +12 -0
  105. package/dist/core/extractors/dfg.js +1081 -0
  106. package/dist/core/extractors/dfg.js.map +1 -0
  107. package/dist/core/extractors/exports.d.ts +14 -0
  108. package/dist/core/extractors/exports.js +80 -0
  109. package/dist/core/extractors/exports.js.map +1 -0
  110. package/dist/core/extractors/imports.d.ts +9 -0
  111. package/dist/core/extractors/imports.js +739 -0
  112. package/dist/core/extractors/imports.js.map +1 -0
  113. package/dist/core/extractors/index.d.ts +10 -0
  114. package/dist/core/extractors/index.js +11 -0
  115. package/dist/core/extractors/index.js.map +1 -0
  116. package/dist/core/extractors/meta.d.ts +10 -0
  117. package/dist/core/extractors/meta.js +109 -0
  118. package/dist/core/extractors/meta.js.map +1 -0
  119. package/dist/core/extractors/types.d.ts +10 -0
  120. package/dist/core/extractors/types.js +1479 -0
  121. package/dist/core/extractors/types.js.map +1 -0
  122. package/dist/core/index.d.ts +5 -0
  123. package/dist/core/index.js +8 -0
  124. package/dist/core/index.js.map +1 -0
  125. package/dist/core/parser.d.ts +84 -0
  126. package/dist/core/parser.js +250 -0
  127. package/dist/core/parser.js.map +1 -0
  128. package/dist/core-lib.d.ts +59 -0
  129. package/dist/core-lib.js +62 -0
  130. package/dist/core-lib.js.map +1 -0
  131. package/dist/index.d.ts +15 -0
  132. package/dist/index.js +20 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/languages/index.d.ts +11 -0
  135. package/dist/languages/index.js +14 -0
  136. package/dist/languages/index.js.map +1 -0
  137. package/dist/languages/plugins/base.d.ts +44 -0
  138. package/dist/languages/plugins/base.js +82 -0
  139. package/dist/languages/plugins/base.js.map +1 -0
  140. package/dist/languages/plugins/index.d.ts +14 -0
  141. package/dist/languages/plugins/index.js +25 -0
  142. package/dist/languages/plugins/index.js.map +1 -0
  143. package/dist/languages/plugins/java.d.ts +49 -0
  144. package/dist/languages/plugins/java.js +402 -0
  145. package/dist/languages/plugins/java.js.map +1 -0
  146. package/dist/languages/plugins/javascript.d.ts +48 -0
  147. package/dist/languages/plugins/javascript.js +445 -0
  148. package/dist/languages/plugins/javascript.js.map +1 -0
  149. package/dist/languages/plugins/python.d.ts +47 -0
  150. package/dist/languages/plugins/python.js +480 -0
  151. package/dist/languages/plugins/python.js.map +1 -0
  152. package/dist/languages/plugins/rust.d.ts +47 -0
  153. package/dist/languages/plugins/rust.js +405 -0
  154. package/dist/languages/plugins/rust.js.map +1 -0
  155. package/dist/languages/registry.d.ts +30 -0
  156. package/dist/languages/registry.js +80 -0
  157. package/dist/languages/registry.js.map +1 -0
  158. package/dist/languages/types.d.ts +184 -0
  159. package/dist/languages/types.js +8 -0
  160. package/dist/languages/types.js.map +1 -0
  161. package/dist/resolution/cross-file.d.ts +146 -0
  162. package/dist/resolution/cross-file.js +439 -0
  163. package/dist/resolution/cross-file.js.map +1 -0
  164. package/dist/resolution/index.d.ts +12 -0
  165. package/dist/resolution/index.js +10 -0
  166. package/dist/resolution/index.js.map +1 -0
  167. package/dist/resolution/symbol-table.d.ts +136 -0
  168. package/dist/resolution/symbol-table.js +336 -0
  169. package/dist/resolution/symbol-table.js.map +1 -0
  170. package/dist/resolution/type-hierarchy.d.ts +124 -0
  171. package/dist/resolution/type-hierarchy.js +515 -0
  172. package/dist/resolution/type-hierarchy.js.map +1 -0
  173. package/dist/types/config.d.ts +45 -0
  174. package/dist/types/config.js +5 -0
  175. package/dist/types/config.js.map +1 -0
  176. package/dist/types/index.d.ts +392 -0
  177. package/dist/types/index.js +7 -0
  178. package/dist/types/index.js.map +1 -0
  179. package/dist/utils/logger.d.ts +85 -0
  180. package/dist/utils/logger.js +198 -0
  181. package/dist/utils/logger.js.map +1 -0
  182. package/dist/wasm/tree-sitter-java.wasm +0 -0
  183. package/dist/wasm/tree-sitter-javascript.wasm +0 -0
  184. package/dist/wasm/tree-sitter-python.wasm +0 -0
  185. package/dist/wasm/tree-sitter-rust.wasm +0 -0
  186. package/dist/wasm/web-tree-sitter.wasm +0 -0
  187. package/docs/SPEC.md +1021 -0
  188. package/examples/browser-example.html +610 -0
  189. package/examples/node-example.ts +215 -0
  190. package/package.json +107 -0
  191. package/wasm/tree-sitter-java.wasm +0 -0
  192. package/wasm/tree-sitter-javascript.wasm +0 -0
  193. package/wasm/tree-sitter-python.wasm +0 -0
  194. package/wasm/tree-sitter-rust.wasm +0 -0
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Node.js Example - Circle-IR Core Library
4
+ *
5
+ * This example demonstrates how to use circle-ir-core to:
6
+ * 1. Parse Java code
7
+ * 2. Extract IR components (types, calls, CFG, DFG)
8
+ * 3. Detect taint sources and sinks
9
+ * 4. Find source-to-sink flows
10
+ *
11
+ * Run: npx tsx examples/node-example.ts
12
+ */
13
+
14
+ import {
15
+ initParser,
16
+ parse,
17
+ collectAllNodes,
18
+ extractMeta,
19
+ extractTypes,
20
+ extractCalls,
21
+ buildCFG,
22
+ buildDFG,
23
+ analyzeTaint,
24
+ propagateTaint,
25
+ analyzeConstantPropagation,
26
+ isFalsePositive,
27
+ getDefaultConfig,
28
+ } from '../src/core-lib.js';
29
+
30
+ // Sample vulnerable Java code
31
+ const vulnerableCode = `
32
+ package com.example;
33
+
34
+ import javax.servlet.http.*;
35
+ import java.sql.*;
36
+
37
+ public class UserController extends HttpServlet {
38
+
39
+ public void doGet(HttpServletRequest request, HttpServletResponse response) {
40
+ // SOURCE: User input from HTTP parameter
41
+ String userId = request.getParameter("id");
42
+
43
+ // No sanitization - direct use in SQL query
44
+ String query = "SELECT * FROM users WHERE id = '" + userId + "'";
45
+
46
+ try {
47
+ Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
48
+ Statement stmt = conn.createStatement();
49
+
50
+ // SINK: SQL injection vulnerability
51
+ ResultSet rs = stmt.executeQuery(query);
52
+
53
+ while (rs.next()) {
54
+ response.getWriter().println(rs.getString("name"));
55
+ }
56
+ } catch (Exception e) {
57
+ e.printStackTrace();
58
+ }
59
+ }
60
+ }
61
+ `;
62
+
63
+ // Sample safe Java code (uses PreparedStatement)
64
+ const safeCode = `
65
+ package com.example;
66
+
67
+ import javax.servlet.http.*;
68
+ import java.sql.*;
69
+
70
+ public class SafeUserController extends HttpServlet {
71
+
72
+ public void doGet(HttpServletRequest request, HttpServletResponse response) {
73
+ String userId = request.getParameter("id");
74
+
75
+ try {
76
+ Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
77
+
78
+ // SAFE: Using PreparedStatement with parameterized query
79
+ PreparedStatement stmt = conn.prepareStatement(
80
+ "SELECT * FROM users WHERE id = ?"
81
+ );
82
+ stmt.setString(1, userId);
83
+
84
+ ResultSet rs = stmt.executeQuery();
85
+
86
+ while (rs.next()) {
87
+ response.getWriter().println(rs.getString("name"));
88
+ }
89
+ } catch (Exception e) {
90
+ e.printStackTrace();
91
+ }
92
+ }
93
+ }
94
+ `;
95
+
96
+ // Node types needed for analysis
97
+ const NODE_TYPES = new Set([
98
+ 'method_invocation',
99
+ 'object_creation_expression',
100
+ 'class_declaration',
101
+ 'method_declaration',
102
+ 'constructor_declaration',
103
+ 'field_declaration',
104
+ 'import_declaration',
105
+ 'interface_declaration',
106
+ 'enum_declaration',
107
+ ]);
108
+
109
+ async function analyzeCode(code: string, filename: string): Promise<void> {
110
+ console.log(`\n${'='.repeat(60)}`);
111
+ console.log(`Analyzing: ${filename}`);
112
+ console.log('='.repeat(60));
113
+
114
+ // Parse the code
115
+ const tree = await parse(code, 'java');
116
+ const nodeCache = collectAllNodes(tree.rootNode, NODE_TYPES);
117
+
118
+ // Extract IR components
119
+ const meta = extractMeta(code, tree, filename, 'java');
120
+ const types = extractTypes(tree, nodeCache);
121
+ const calls = extractCalls(tree, nodeCache);
122
+ const cfg = buildCFG(tree);
123
+ const dfg = buildDFG(tree, nodeCache);
124
+
125
+ console.log(`\nIR Summary:`);
126
+ console.log(` Lines of code: ${meta.loc}`);
127
+ console.log(` Classes: ${types.length}`);
128
+ console.log(` Method calls: ${calls.length}`);
129
+ console.log(` CFG blocks: ${cfg.blocks.length}`);
130
+ console.log(` DFG definitions: ${dfg.defs.length}`);
131
+
132
+ // Analyze taint
133
+ const config = getDefaultConfig();
134
+ const taint = analyzeTaint(calls, types, config);
135
+
136
+ console.log(`\nTaint Analysis:`);
137
+ console.log(` Sources: ${taint.sources.length}`);
138
+ taint.sources.forEach(s => {
139
+ console.log(` - Line ${s.line}: ${s.type} (${s.location})`);
140
+ });
141
+
142
+ console.log(` Sinks: ${taint.sinks.length}`);
143
+ taint.sinks.forEach(s => {
144
+ console.log(` - Line ${s.line}: ${s.type} (${s.location})`);
145
+ });
146
+
147
+ console.log(` Sanitizers: ${taint.sanitizers.length}`);
148
+ taint.sanitizers.forEach(s => {
149
+ console.log(` - Line ${s.line}: ${s.type} (${s.method})`);
150
+ });
151
+
152
+ // Find taint flows
153
+ const propagationResult = propagateTaint(
154
+ dfg,
155
+ calls,
156
+ taint.sources,
157
+ taint.sinks,
158
+ taint.sanitizers ?? []
159
+ );
160
+
161
+ // Run constant propagation for false positive elimination
162
+ const constPropResult = analyzeConstantPropagation(tree, code);
163
+
164
+ // Filter false positives
165
+ const verifiedFlows = propagationResult.flows.filter(flow => {
166
+ // Check each step in the path - if any variable has a constant value, it's a FP
167
+ for (const step of flow.path) {
168
+ const fpCheck = isFalsePositive(constPropResult, step.line, step.variable);
169
+ if (fpCheck.isFalsePositive) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ });
175
+
176
+ console.log(`\nVulnerability Detection:`);
177
+ if (verifiedFlows.length > 0) {
178
+ console.log(` Found ${verifiedFlows.length} potential vulnerabilities:`);
179
+ verifiedFlows.forEach((flow, i) => {
180
+ console.log(`\n [${i + 1}] ${flow.sink.type.toUpperCase()}`);
181
+ console.log(` Source: Line ${flow.source.line} (${flow.source.type})`);
182
+ console.log(` Sink: Line ${flow.sink.line} (${flow.sink.type})`);
183
+ console.log(` Confidence: ${(flow.confidence * 100).toFixed(0)}%`);
184
+ if (flow.path.length > 0) {
185
+ console.log(` Path:`);
186
+ flow.path.forEach(step => {
187
+ console.log(` -> ${step.variable} (line ${step.line})`);
188
+ });
189
+ }
190
+ });
191
+ } else {
192
+ console.log(` No vulnerabilities detected.`);
193
+ }
194
+ }
195
+
196
+ async function main(): Promise<void> {
197
+ console.log('Circle-IR Core Library - Node.js Example');
198
+ console.log('=========================================\n');
199
+
200
+ // Initialize the parser
201
+ console.log('Initializing parser...');
202
+ await initParser();
203
+ console.log('Parser initialized.\n');
204
+
205
+ // Analyze vulnerable code
206
+ await analyzeCode(vulnerableCode, 'VulnerableController.java');
207
+
208
+ // Analyze safe code
209
+ await analyzeCode(safeCode, 'SafeUserController.java');
210
+
211
+ console.log('\n' + '='.repeat(60));
212
+ console.log('Analysis complete.');
213
+ }
214
+
215
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "circle-ir",
3
+ "version": "3.1.0",
4
+ "description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/core/circle-ir-core.d.ts",
16
+ "import": "./dist/core/circle-ir-core.js",
17
+ "require": "./dist/core/circle-ir-core.cjs"
18
+ },
19
+ "./browser": {
20
+ "types": "./dist/browser.d.ts",
21
+ "import": "./dist/browser/circle-ir.js"
22
+ }
23
+ },
24
+ "sideEffects": false,
25
+ "files": [
26
+ "dist",
27
+ "configs",
28
+ "examples",
29
+ "wasm",
30
+ "docs/SPEC.md"
31
+ ],
32
+ "scripts": {
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "test:coverage": "vitest run --coverage",
36
+ "build": "tsc",
37
+ "build:browser": "esbuild src/browser.ts --bundle --format=esm --platform=browser --external:fs --external:fs/promises --external:path --external:module --external:crypto --external:pino --outfile=dist/browser/circle-ir.js && mkdir -p dist/wasm && cp node_modules/web-tree-sitter/web-tree-sitter.wasm dist/wasm/ && cp wasm/*.wasm dist/wasm/",
38
+ "build:core": "esbuild src/core-lib.ts --bundle --format=esm --platform=neutral --external:fs --external:fs/promises --external:path --external:module --external:pino --external:crypto --outfile=dist/core/circle-ir-core.js && esbuild src/core-lib.ts --bundle --format=cjs --platform=neutral --external:fs --external:fs/promises --external:path --external:module --external:pino --external:crypto --outfile=dist/core/circle-ir-core.cjs && cp dist/core-lib.d.ts dist/core/circle-ir-core.d.ts",
39
+ "build:all": "npm run build && npm run build:browser && npm run build:core",
40
+ "typecheck": "tsc --noEmit",
41
+ "prepublishOnly": "npm run build:all && npm test",
42
+ "prepack": "npm run build:all"
43
+ },
44
+ "keywords": [
45
+ "sast",
46
+ "security",
47
+ "static-analysis",
48
+ "taint-analysis",
49
+ "vulnerability-detection",
50
+ "code-analysis",
51
+ "java",
52
+ "javascript",
53
+ "typescript",
54
+ "python",
55
+ "rust",
56
+ "tree-sitter",
57
+ "sql-injection",
58
+ "xss",
59
+ "command-injection",
60
+ "path-traversal",
61
+ "owasp"
62
+ ],
63
+ "author": {
64
+ "name": "Cognium Labs",
65
+ "url": "https://github.com/cogniumhq"
66
+ },
67
+ "license": "ISC",
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "git+https://github.com/cogniumhq/circle-ir.git"
71
+ },
72
+ "homepage": "https://github.com/cogniumhq/circle-ir#readme",
73
+ "bugs": {
74
+ "url": "https://github.com/cogniumhq/circle-ir/issues"
75
+ },
76
+ "funding": {
77
+ "type": "github",
78
+ "url": "https://github.com/sponsors/cognitim"
79
+ },
80
+ "engines": {
81
+ "node": ">=18.0.0"
82
+ },
83
+ "type": "module",
84
+ "publishConfig": {
85
+ "access": "public",
86
+ "registry": "https://registry.npmjs.org/"
87
+ },
88
+ "dependencies": {
89
+ "pino": "^10.3.0",
90
+ "web-tree-sitter": "^0.26.3",
91
+ "yaml": "^2.8.2"
92
+ },
93
+ "devDependencies": {
94
+ "@types/node": "^25.0.10",
95
+ "@types/unzipper": "^0.10.11",
96
+ "@vitest/coverage-v8": "^3.0.0",
97
+ "esbuild": "^0.27.2",
98
+ "pino-pretty": "^13.1.3",
99
+ "tree-sitter-java": "^0.23.5",
100
+ "tree-sitter-python": "^0.25.0",
101
+ "tree-sitter-rust": "^0.24.0",
102
+ "ts-node": "^10.9.2",
103
+ "typescript": "^5.9.3",
104
+ "unzipper": "^0.12.3",
105
+ "vitest": "^3.0.0"
106
+ }
107
+ }
Binary file
Binary file
Binary file
Binary file