forgecode 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -0
- package/bin/darwin/arm64/forge-aarch64-apple-darwin +0 -0
- package/bin/darwin/x64/forge-x86_64-apple-darwin +0 -0
- package/bin/linux/arm64/forge-aarch64-unknown-linux-gnu +0 -0
- package/bin/linux/arm64/forge-aarch64-unknown-linux-musl +0 -0
- package/bin/linux/x64/forge-x86_64-unknown-linux-gnu +0 -0
- package/bin/linux/x64/forge-x86_64-unknown-linux-musl +0 -0
- package/bin/win32/arm64/forge-aarch64-pc-windows-msvc.exe +0 -0
- package/bin/win32/x64/forge-x86_64-pc-windows-msvc.exe +0 -0
- package/forge.js +40 -0
- package/install.js +289 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Code Forge CLI
|
|
2
|
+
|
|
3
|
+
Code Forge is an AI-powered coding assistant CLI that helps you write, review, and understand code.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Global Installation (Recommended)
|
|
8
|
+
|
|
9
|
+
You can install Code Forge globally to use it with the simple `forge` command:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g forgecode
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
After installation, you can run the command from anywhere:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
forge --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Using npx (No Installation)
|
|
22
|
+
|
|
23
|
+
If you prefer not to install anything globally, you can use npx to run Code Forge directly:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx forgecode
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Both methods will automatically download the appropriate binary for your platform.
|
|
30
|
+
|
|
31
|
+
## Supported Platforms
|
|
32
|
+
|
|
33
|
+
- macOS (Intel, Apple Silicon)
|
|
34
|
+
- Linux (x64, ARM64)
|
|
35
|
+
- Windows (x64, ARM64)
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
Once installed, you can use the `forge` command:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# If installed globally
|
|
43
|
+
forge --version
|
|
44
|
+
|
|
45
|
+
# Or with npx
|
|
46
|
+
npx forgecode --version
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Troubleshooting
|
|
50
|
+
|
|
51
|
+
### Linux glibc Compatibility Issues
|
|
52
|
+
|
|
53
|
+
If you encounter errors like:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.XX' not found
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This means the binary requires a newer version of glibc than what's available on your system. You can use one of these solutions:
|
|
60
|
+
|
|
61
|
+
1. **Force using the musl binary** (recommended for environments like Codespaces):
|
|
62
|
+
```bash
|
|
63
|
+
# Set environment variable to force musl before installing
|
|
64
|
+
export FORCE_MUSL=1
|
|
65
|
+
npm install -g forgecode
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
2. **Update your system's glibc** (if you have administrative access)
|
|
69
|
+
|
|
70
|
+
3. **Use a Docker container with a newer Linux distribution**
|
|
71
|
+
|
|
72
|
+
The musl binary has fewer system dependencies and should work on most Linux systems regardless of glibc version.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/forge.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const { existsSync } = require('fs');
|
|
6
|
+
|
|
7
|
+
// Get the correct binary extension based on platform
|
|
8
|
+
const getBinaryExtension = () => {
|
|
9
|
+
return process.platform === 'win32' ? '.exe' : '';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Get the path to the forge binary in the same directory as this script
|
|
13
|
+
const forgeBinaryPath = join(__dirname, 'forge' + getBinaryExtension());
|
|
14
|
+
|
|
15
|
+
// Check if the binary exists
|
|
16
|
+
if (!existsSync(forgeBinaryPath)) {
|
|
17
|
+
console.error(`โ Forge binary not found at: ${forgeBinaryPath}`);
|
|
18
|
+
console.error('Please try reinstalling the package with: npm install -g @antinomyhq/forge');
|
|
19
|
+
console.error(`System information: ${process.platform} (${process.arch})`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Execute the binary with the same arguments
|
|
24
|
+
const forgeProcess = spawn(forgeBinaryPath, process.argv.slice(2), {
|
|
25
|
+
stdio: 'inherit',
|
|
26
|
+
shell: process.platform === 'win32' // Use shell on Windows
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Pass through SIGINT signals to the child process
|
|
30
|
+
process.on('SIGINT', () => {
|
|
31
|
+
// Instead of handling here, forward to the child
|
|
32
|
+
forgeProcess.kill('SIGINT');
|
|
33
|
+
// Don't exit - let the child process determine what happens
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Handle process exit
|
|
37
|
+
forgeProcess.on('exit', (code) => {
|
|
38
|
+
// Only exit with code when the child actually exits
|
|
39
|
+
process.exit(code || 0);
|
|
40
|
+
});
|
package/install.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { platform, arch } = process;
|
|
4
|
+
const { join } = require('path');
|
|
5
|
+
const { chmodSync, copyFileSync, existsSync } = require('fs');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
// Function to get the glibc version on Linux
|
|
10
|
+
function getGlibcVersion() {
|
|
11
|
+
try {
|
|
12
|
+
// Using ldd to get version info (common on most Linux distros)
|
|
13
|
+
const lddOutput = spawnSync('ldd', ['--version'], { encoding: 'utf8' }).stderr.toString() ||
|
|
14
|
+
spawnSync('ldd', ['--version'], { encoding: 'utf8' }).stdout.toString();
|
|
15
|
+
|
|
16
|
+
// Check if this is musl libc
|
|
17
|
+
if (lddOutput.toLowerCase().includes('musl')) {
|
|
18
|
+
return { type: 'musl', version: null };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Extract glibc version using regex
|
|
22
|
+
const versionMatch = /\b(\d+\.\d+)\b/.exec(lddOutput);
|
|
23
|
+
if (versionMatch && versionMatch[1]) {
|
|
24
|
+
return { type: 'gnu', version: versionMatch[1] };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Alternative method using GNU-specific getconf
|
|
28
|
+
try {
|
|
29
|
+
const getconfOutput = spawnSync('getconf', ['GNU_LIBC_VERSION'], { encoding: 'utf8' }).stdout.toString();
|
|
30
|
+
const getconfMatch = /\b(\d+\.\d+)\b/.exec(getconfOutput);
|
|
31
|
+
if (getconfMatch && getconfMatch[1]) {
|
|
32
|
+
return { type: 'gnu', version: getconfMatch[1] };
|
|
33
|
+
}
|
|
34
|
+
} catch (e) {
|
|
35
|
+
// Ignore error if getconf is not available
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// If we got here, we couldn't get the specific version
|
|
39
|
+
return { type: 'gnu', version: null };
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.warn('Warning: Could not detect libc version details.');
|
|
42
|
+
return { type: 'unknown', version: null };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check if the glibc version is sufficient for our binary
|
|
47
|
+
function isGlibcVersionSufficient(version) {
|
|
48
|
+
if (!version) return false;
|
|
49
|
+
|
|
50
|
+
// Our binary requires 2.32 or higher based on the error message
|
|
51
|
+
const requiredVersion = 2.32;
|
|
52
|
+
const currentVersion = parseFloat(version);
|
|
53
|
+
|
|
54
|
+
return currentVersion >= requiredVersion;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Enhanced libc detection for Linux
|
|
58
|
+
function detectLibcType() {
|
|
59
|
+
if (platform !== 'linux') {
|
|
60
|
+
return null; // Not relevant for non-Linux platforms
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const libcInfo = getGlibcVersion();
|
|
64
|
+
console.log(`๐ Detected libc: ${libcInfo.type}${libcInfo.version ? ` version ${libcInfo.version}` : ''}`);
|
|
65
|
+
|
|
66
|
+
// If it's musl, or if it's an older glibc version, prefer musl
|
|
67
|
+
if (libcInfo.type === 'musl' ||
|
|
68
|
+
(libcInfo.type === 'gnu' && !isGlibcVersionSufficient(libcInfo.version))) {
|
|
69
|
+
return 'musl';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return 'gnu';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Test if a binary will run on this system
|
|
76
|
+
function testBinary(binaryPath) {
|
|
77
|
+
try {
|
|
78
|
+
const result = spawnSync(binaryPath, ['--version'], {
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
timeout: 5000 // 5 second timeout
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Check if execution was successful (return code 0)
|
|
84
|
+
if (result.status === 0) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check specific errors that indicate glibc version problems
|
|
89
|
+
if (result.stderr && result.stderr.includes('GLIBC_')) {
|
|
90
|
+
console.warn(`โ ๏ธ Binary compatibility issue: ${result.stderr.split('\n')[0]}`);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return false;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.warn(`โ ๏ธ Binary test failed: ${error.message}`);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Map of supported platforms and architectures to binary names
|
|
102
|
+
const PLATFORMS = {
|
|
103
|
+
'darwin': {
|
|
104
|
+
'x64': 'forge-x86_64-apple-darwin',
|
|
105
|
+
'arm64': 'forge-aarch64-apple-darwin'
|
|
106
|
+
},
|
|
107
|
+
'linux': {
|
|
108
|
+
'x64': {
|
|
109
|
+
'gnu': 'forge-x86_64-unknown-linux-gnu',
|
|
110
|
+
'musl': 'forge-x86_64-unknown-linux-musl'
|
|
111
|
+
},
|
|
112
|
+
'arm64': {
|
|
113
|
+
'gnu': 'forge-aarch64-unknown-linux-gnu',
|
|
114
|
+
'musl': 'forge-aarch64-unknown-linux-musl'
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
'win32': {
|
|
118
|
+
'x64': 'forge-x86_64-pc-windows-msvc.exe',
|
|
119
|
+
'arm64': 'forge-aarch64-pc-windows-msvc.exe'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Platform-specific binary extension
|
|
124
|
+
function getBinaryExtension() {
|
|
125
|
+
return platform === 'win32' ? '.exe' : '';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Print available platform information for debugging
|
|
129
|
+
function printPlatformInfo() {
|
|
130
|
+
console.log('System Information:');
|
|
131
|
+
console.log(` - Platform: ${platform}`);
|
|
132
|
+
console.log(` - Architecture: ${arch}`);
|
|
133
|
+
console.log(` - Node.js: ${process.version}`);
|
|
134
|
+
console.log(` - OS: ${os.type()} ${os.release()}`);
|
|
135
|
+
|
|
136
|
+
if (platform === 'linux') {
|
|
137
|
+
const libcInfo = getGlibcVersion();
|
|
138
|
+
console.log(` - Libc: ${libcInfo.type}${libcInfo.version ? ` version ${libcInfo.version}` : ''}`);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const distroInfo = spawnSync('cat', ['/etc/os-release'], { encoding: 'utf8' }).stdout.toString();
|
|
142
|
+
const distroName = /PRETTY_NAME="([^"]+)"/.exec(distroInfo);
|
|
143
|
+
if (distroName && distroName[1]) {
|
|
144
|
+
console.log(` - Distribution: ${distroName[1]}`);
|
|
145
|
+
}
|
|
146
|
+
} catch (e) {
|
|
147
|
+
// Ignore if we can't get distribution info
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Install binary based on platform and architecture
|
|
153
|
+
function install() {
|
|
154
|
+
printPlatformInfo();
|
|
155
|
+
|
|
156
|
+
// Check if platform is supported
|
|
157
|
+
if (!PLATFORMS[platform]) {
|
|
158
|
+
console.error(`โ Unsupported platform: ${platform}`);
|
|
159
|
+
console.error('Supported platforms: macOS, Linux, Windows');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check if architecture is supported
|
|
164
|
+
if (!PLATFORMS[platform][arch]) {
|
|
165
|
+
console.error(`โ Unsupported architecture: ${arch} for platform ${platform}`);
|
|
166
|
+
console.error(`Supported architectures for ${platform}: ${Object.keys(PLATFORMS[platform]).join(', ')}`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let binaryName;
|
|
171
|
+
let binaryPath;
|
|
172
|
+
const targetPath = join(__dirname, 'forge' + getBinaryExtension());
|
|
173
|
+
|
|
174
|
+
// Handle Linux specially for libc type
|
|
175
|
+
if (platform === 'linux') {
|
|
176
|
+
let libcType = detectLibcType();
|
|
177
|
+
|
|
178
|
+
// Always try musl first if available (it's more portable)
|
|
179
|
+
const muslBinaryName = PLATFORMS[platform][arch]['musl'];
|
|
180
|
+
const muslBinaryPath = join(__dirname, 'bin', platform, arch, muslBinaryName);
|
|
181
|
+
|
|
182
|
+
// Check if musl binary exists
|
|
183
|
+
if (existsSync(muslBinaryPath)) {
|
|
184
|
+
console.log('๐ฆ Found musl binary, which should work on most Linux systems');
|
|
185
|
+
binaryName = muslBinaryName;
|
|
186
|
+
binaryPath = muslBinaryPath;
|
|
187
|
+
}
|
|
188
|
+
// Fall back to detected libc type
|
|
189
|
+
else {
|
|
190
|
+
// Check if the detected libc type is supported in our binaries
|
|
191
|
+
if (!PLATFORMS[platform][arch][libcType]) {
|
|
192
|
+
// If not supported, try the alternative
|
|
193
|
+
libcType = (libcType === 'gnu') ? 'musl' : 'gnu';
|
|
194
|
+
console.warn(`โ ๏ธ Detected libc type is not supported, trying ${libcType} instead`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
binaryName = PLATFORMS[platform][arch][libcType];
|
|
198
|
+
binaryPath = join(__dirname, 'bin', platform, arch, binaryName);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// If binary doesn't exist, try the alternative
|
|
202
|
+
if (!existsSync(binaryPath)) {
|
|
203
|
+
const alternativeLibc = libcType === 'gnu' ? 'musl' : 'gnu';
|
|
204
|
+
const alternativeBinaryName = PLATFORMS[platform][arch][alternativeLibc];
|
|
205
|
+
const alternativeBinaryPath = join(__dirname, 'bin', platform, arch, alternativeBinaryName);
|
|
206
|
+
|
|
207
|
+
if (existsSync(alternativeBinaryPath)) {
|
|
208
|
+
console.warn(`โ ๏ธ Binary for ${libcType} not found, trying ${alternativeLibc} instead`);
|
|
209
|
+
binaryName = alternativeBinaryName;
|
|
210
|
+
binaryPath = alternativeBinaryPath;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
binaryName = PLATFORMS[platform][arch];
|
|
215
|
+
binaryPath = join(__dirname, 'bin', platform, arch, binaryName);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check if binary exists
|
|
219
|
+
if (!existsSync(binaryPath)) {
|
|
220
|
+
console.error(`โ Binary not found: ${binaryPath}`);
|
|
221
|
+
console.error('If this is a new architecture or platform, please check the repository for updates.');
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
// Copy binary to target location
|
|
227
|
+
copyFileSync(binaryPath, targetPath);
|
|
228
|
+
// Make binary executable (not needed on Windows)
|
|
229
|
+
if (platform !== 'win32') {
|
|
230
|
+
chmodSync(targetPath, '755');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// For Linux, test if the binary will actually run
|
|
234
|
+
if (platform === 'linux') {
|
|
235
|
+
console.log('๐งช Testing binary compatibility...');
|
|
236
|
+
if (!testBinary(targetPath)) {
|
|
237
|
+
// If current binary fails and we haven't tried musl yet, try the musl version
|
|
238
|
+
if (binaryName.includes('-gnu')) {
|
|
239
|
+
const muslBinaryName = binaryName.replace('-gnu', '-musl');
|
|
240
|
+
const muslBinaryPath = join(__dirname, 'bin', platform, arch, muslBinaryName);
|
|
241
|
+
|
|
242
|
+
if (existsSync(muslBinaryPath)) {
|
|
243
|
+
console.log('๐ GNU binary not compatible, trying musl binary instead');
|
|
244
|
+
copyFileSync(muslBinaryPath, targetPath);
|
|
245
|
+
chmodSync(targetPath, '755');
|
|
246
|
+
|
|
247
|
+
if (!testBinary(targetPath)) {
|
|
248
|
+
console.error('โ Both GNU and musl binaries failed to run on this system.');
|
|
249
|
+
reportCompatibilityError();
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
console.error('โ GNU binary not compatible, and musl binary not available.');
|
|
254
|
+
reportCompatibilityError();
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
console.error('โ Binary compatibility test failed.');
|
|
259
|
+
reportCompatibilityError();
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
console.log(`โ
Successfully installed forge for ${platform}/${arch}`);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error(`โ Error installing binary: ${error.message}`);
|
|
268
|
+
reportCompatibilityError();
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function reportCompatibilityError() {
|
|
274
|
+
console.error('\n๐ง Possible solutions:');
|
|
275
|
+
console.error('1. Try using the musl binary, which has fewer system dependencies:');
|
|
276
|
+
console.error(' - Set FORCE_MUSL=1 before installing');
|
|
277
|
+
console.error('2. Update your system\'s glibc to a newer version');
|
|
278
|
+
console.error('3. Contact support with the following information:');
|
|
279
|
+
printPlatformInfo();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Check for environment variable to force musl
|
|
283
|
+
if (process.env.FORCE_MUSL === '1' && platform === 'linux') {
|
|
284
|
+
console.log('๐ง FORCE_MUSL=1 environment variable detected, forcing musl binary');
|
|
285
|
+
process.env.FORCE_LIBC = 'musl';
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Run installation
|
|
289
|
+
install();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "forgecode",
|
|
3
|
+
"version": "0.96.0",
|
|
4
|
+
"description": "Code Forge CLI - an AI-powered coding assistant",
|
|
5
|
+
"bin": {
|
|
6
|
+
"forge": "forge.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node install.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/antinomyhq/forge.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"code-forge",
|
|
17
|
+
"ai",
|
|
18
|
+
"assistant",
|
|
19
|
+
"cli"
|
|
20
|
+
],
|
|
21
|
+
"author": "Antinomy Inc.",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/antinomyhq/forge/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://antinomy.ai/",
|
|
27
|
+
"files": [
|
|
28
|
+
"bin/**/*",
|
|
29
|
+
"install.js",
|
|
30
|
+
"forge.js"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
}
|
|
38
|
+
}
|