From d3b9fc7c51b409e5a11060bda85a5079cabe4df1 Mon Sep 17 00:00:00 2001 From: Tomasz Stefaniak Date: Fri, 15 Aug 2025 09:55:19 -0700 Subject: [PATCH] fix: formatting --- actions/README.md | 50 ++-- actions/detailed-review/annotate-diff.js | 60 ++--- actions/detailed-review/annotate-diff.test.js | 236 +++++++++--------- actions/detailed-review/package.json | 2 +- 4 files changed, 188 insertions(+), 160 deletions(-) diff --git a/actions/README.md b/actions/README.md index beb67fbb6..464867658 100644 --- a/actions/README.md +++ b/actions/README.md @@ -7,6 +7,7 @@ GitHub Actions that provide automated code reviews for pull requests using Conti This repository provides two GitHub Actions for different review styles: ### 1. General Review Action + Provides high-level PR assessment with overall feedback and recommendations. - **Path:** `continuedev/continue/actions/general-review@` @@ -14,6 +15,7 @@ Provides high-level PR assessment with overall feedback and recommendations. - **Output:** Summary comment with strengths, issues, and recommendations ### 2. Detailed Review Action + Provides line-by-line inline comments on specific code changes. - **Path:** `continuedev/continue/actions/detailed-review@` @@ -45,8 +47,8 @@ jobs: - uses: continuedev/continue/actions/general-review@ with: continue-api-key: ${{ secrets.CONTINUE_API_KEY }} - continue-org: 'your-org-name' - continue-config: 'your-org-name/review-bot' + continue-org: "your-org-name" + continue-config: "your-org-name/review-bot" detailed-review: runs-on: ubuntu-latest @@ -55,8 +57,8 @@ jobs: - uses: continuedev/continue/actions/detailed-review@ with: continue-api-key: ${{ secrets.CONTINUE_API_KEY }} - continue-org: 'your-org-name' - continue-config: 'your-org-name/review-bot' + continue-org: "your-org-name" + continue-config: "your-org-name/review-bot" ``` ### General Review Only @@ -82,8 +84,8 @@ jobs: - uses: continuedev/continue/actions/general-review@ with: continue-api-key: ${{ secrets.CONTINUE_API_KEY }} - continue-org: 'your-org-name' - continue-config: 'your-org-name/review-bot' + continue-org: "your-org-name" + continue-config: "your-org-name/review-bot" ``` ### Detailed Review Only @@ -109,24 +111,26 @@ jobs: - uses: continuedev/continue/actions/detailed-review@ with: continue-api-key: ${{ secrets.CONTINUE_API_KEY }} - continue-org: 'your-org-name' - continue-config: 'your-org-name/review-bot' + continue-org: "your-org-name" + continue-config: "your-org-name/review-bot" ``` ## Inputs Both actions accept the same inputs: -| Input | Description | Required | -|-------|-------------|----------| -| `continue-api-key` | API key for Continue service | Yes | -| `continue-org` | Organization for Continue config | Yes | -| `continue-config` | Config path (e.g., "myorg/review-bot") | Yes | +| Input | Description | Required | +| ------------------ | -------------------------------------- | -------- | +| `continue-api-key` | API key for Continue service | Yes | +| `continue-org` | Organization for Continue config | Yes | +| `continue-config` | Config path (e.g., "myorg/review-bot") | Yes | ## Setup Requirements ### 1. Continue API Key + Add your Continue API key as a secret named `CONTINUE_API_KEY` in your repository: + 1. Go to your repository's Settings 2. Navigate to Secrets and variables → Actions 3. Click "New repository secret" @@ -134,13 +138,17 @@ Add your Continue API key as a secret named `CONTINUE_API_KEY` in your repositor 5. Value: Your Continue API key ### 2. Continue Configuration + Set up your review bot configuration in Continue: + 1. Create a configuration for your organization 2. Configure the review bot settings 3. Note your organization name and config path ### 3. Workflow Permissions + The workflow requires these permissions: + - `contents: read` - To checkout and read repository code - `pull-requests: write` - To post review comments on PRs - `issues: write` - To respond to comment triggers @@ -150,25 +158,32 @@ The workflow requires these permissions: Both actions can be triggered in two ways: ### Automatic Triggers + - When a PR is opened by a team member (OWNER, MEMBER, or COLLABORATOR) - When a PR is marked as "ready for review" by a team member ### Manual Triggers + Team members can trigger reviews by commenting on any pull request: + - `@continue-general-review` - Triggers a general review - `@continue-detailed-review` - Triggers a detailed inline review ## Review Outputs ### General Review Output + The general review provides a structured comment that includes: + - **Strengths**: What was done well in the PR - **Issues Found**: Categorized by severity (Critical, High, Medium, Low) - **Suggestions**: Improvement recommendations - **Overall Assessment**: Final recommendation (APPROVE, REQUEST_CHANGES, or COMMENT) ### Detailed Review Output + The detailed review provides: + - **Inline Comments**: Specific feedback on individual lines of code - **Position Markers**: Comments appear directly on the changed lines - **Review Summary**: Overall assessment of the changes @@ -177,6 +192,7 @@ The detailed review provides: ## How It Works ### General Review Process + 1. Checks out repository code 2. Fetches PR diff using GitHub CLI 3. Generates a comprehensive review prompt @@ -184,6 +200,7 @@ The detailed review provides: 5. Posts review as a PR comment ### Detailed Review Process + 1. Checks out repository code 2. Fetches PR diff with GitHub API positions 3. Annotates diff with position markers @@ -200,6 +217,7 @@ We recommend using a specific commit SHA for stability and predictability: - `@v1` - Uses a version tag when available Example: + ```yaml uses: continuedev/continue/actions/general-review@17fe39cc4f1760838ce4428aad0a984af13f8266 ``` @@ -207,16 +225,19 @@ uses: continuedev/continue/actions/general-review@17fe39cc4f1760838ce4428aad0a98 ## Troubleshooting ### Review not triggering + - Ensure the PR author or commenter has appropriate permissions (OWNER, MEMBER, or COLLABORATOR) - Check that the workflow file is in the default branch - Verify the Continue API key is correctly set as a repository secret ### No review output generated + - Check the action logs for any errors - Verify your Continue configuration is correct - Ensure your Continue API key is valid ### Inline comments not appearing (Detailed Review) + - Check that the PR has a valid diff - Verify GitHub API permissions are correct - Review action logs for position calculation errors @@ -224,6 +245,7 @@ uses: continuedev/continue/actions/general-review@17fe39cc4f1760838ce4428aad0a98 ## Support For issues or questions: + - [Continue Documentation](https://docs.continue.dev) - [GitHub Issues](https://github.com/continuedev/continue/issues) -- [Discord Community](https://discord.gg/vapESyrFmJ) \ No newline at end of file +- [Discord Community](https://discord.gg/vapESyrFmJ) diff --git a/actions/detailed-review/annotate-diff.js b/actions/detailed-review/annotate-diff.js index 54b651ceb..b4bdb803e 100644 --- a/actions/detailed-review/annotate-diff.js +++ b/actions/detailed-review/annotate-diff.js @@ -2,45 +2,47 @@ /** * Annotates a git diff with GitHub API positions - * + * * Takes a raw diff and adds [POS:N] markers with the correct * GitHub API positions (cumulative, with +1 between hunks) */ -const fs = require('fs'); +const fs = require("fs"); function annotateDiff(diffContent) { - const lines = diffContent.split('\n'); + const lines = diffContent.split("\n"); const output = []; let githubPos = 0; let inHunk = false; - + for (const line of lines) { // Handle new file - reset position counter - if (line.startsWith('diff --git')) { + if (line.startsWith("diff --git")) { githubPos = 0; inHunk = false; output.push(line); continue; } - + // Pass through other git headers unchanged - if (line.startsWith('index ') || - line.startsWith('---') || - line.startsWith('+++') || - line.startsWith('rename ') || - line.startsWith('similarity ') || - line.startsWith('new file') || - line.startsWith('deleted file') || - line.startsWith('old mode') || - line.startsWith('new mode') || - line.startsWith('Binary files')) { + if ( + line.startsWith("index ") || + line.startsWith("---") || + line.startsWith("+++") || + line.startsWith("rename ") || + line.startsWith("similarity ") || + line.startsWith("new file") || + line.startsWith("deleted file") || + line.startsWith("old mode") || + line.startsWith("new mode") || + line.startsWith("Binary files") + ) { output.push(line); continue; } - + // Handle hunk headers - if (line.startsWith('@@')) { + if (line.startsWith("@@")) { if (inHunk) { githubPos++; // GitHub's +1 between hunks } @@ -48,16 +50,16 @@ function annotateDiff(diffContent) { output.push(line); continue; } - + // Handle "no newline" marker - it counts as a position but isn't annotated - if (line.startsWith('\\ No newline')) { + if (line.startsWith("\\ No newline")) { if (inHunk) { githubPos++; // GitHub counts this as a position } output.push(line); // Don't annotate it continue; } - + // Annotate actual diff lines with GitHub positions if (inHunk) { githubPos++; @@ -66,23 +68,23 @@ function annotateDiff(diffContent) { output.push(line); } } - - return output.join('\n'); + + return output.join("\n"); } // Main function main() { // Read diff from stdin or file - let input = ''; - + let input = ""; + if (process.argv.length > 2) { // Read from file - input = fs.readFileSync(process.argv[2], 'utf8'); + input = fs.readFileSync(process.argv[2], "utf8"); } else { // Read from stdin - input = fs.readFileSync(0, 'utf8'); + input = fs.readFileSync(0, "utf8"); } - + const annotated = annotateDiff(input); console.log(annotated); } @@ -91,4 +93,4 @@ if (require.main === module) { main(); } -module.exports = { annotateDiff }; \ No newline at end of file +module.exports = { annotateDiff }; diff --git a/actions/detailed-review/annotate-diff.test.js b/actions/detailed-review/annotate-diff.test.js index 28a527a2c..e13c66068 100644 --- a/actions/detailed-review/annotate-diff.test.js +++ b/actions/detailed-review/annotate-diff.test.js @@ -1,7 +1,7 @@ -const { annotateDiff } = require('./annotate-diff.js'); +const { annotateDiff } = require("./annotate-diff.js"); -describe('annotateDiff', () => { - test('single file, single hunk', () => { +describe("annotateDiff", () => { + test("single file, single hunk", () => { const diff = `diff --git a/file.js b/file.js index abc123..def456 100644 --- a/file.js @@ -13,13 +13,13 @@ index abc123..def456 100644 line3`; const result = annotateDiff(diff); - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] line2'); - expect(result).toContain('[POS:3] +added line'); - expect(result).toContain('[POS:4] line3'); + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] line2"); + expect(result).toContain("[POS:3] +added line"); + expect(result).toContain("[POS:4] line3"); }); - test('single file, multiple hunks with +1 between', () => { + test("single file, multiple hunks with +1 between", () => { const diff = `diff --git a/file.js b/file.js index abc123..def456 100644 --- a/file.js @@ -36,21 +36,21 @@ index abc123..def456 100644 line12`; const result = annotateDiff(diff); - + // First hunk - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old line'); - expect(result).toContain('[POS:3] +new line'); - expect(result).toContain('[POS:4] line3'); - + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old line"); + expect(result).toContain("[POS:3] +new line"); + expect(result).toContain("[POS:4] line3"); + // Second hunk (should start at 6, because 4 lines + 1 for between hunks) - expect(result).toContain('[POS:6] line10'); - expect(result).toContain('[POS:7] -old line 11'); - expect(result).toContain('[POS:8] +new line 11'); - expect(result).toContain('[POS:9] line12'); + expect(result).toContain("[POS:6] line10"); + expect(result).toContain("[POS:7] -old line 11"); + expect(result).toContain("[POS:8] +new line 11"); + expect(result).toContain("[POS:9] line12"); }); - test('multiple files reset position counter', () => { + test("multiple files reset position counter", () => { const diff = `diff --git a/file1.js b/file1.js index abc123..def456 100644 --- a/file1.js @@ -69,20 +69,20 @@ index abc123..def456 100644 +new2`; const result = annotateDiff(diff); - + // File 1 - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old'); - expect(result).toContain('[POS:3] +new'); - + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old"); + expect(result).toContain("[POS:3] +new"); + // File 2 - positions should reset - const file2Section = result.split('diff --git a/file2.js')[1]; - expect(file2Section).toContain('[POS:1] first'); - expect(file2Section).toContain('[POS:2] -old2'); - expect(file2Section).toContain('[POS:3] +new2'); + const file2Section = result.split("diff --git a/file2.js")[1]; + expect(file2Section).toContain("[POS:1] first"); + expect(file2Section).toContain("[POS:2] -old2"); + expect(file2Section).toContain("[POS:3] +new2"); }); - test('handles new file', () => { + test("handles new file", () => { const diff = `diff --git a/newfile.js b/newfile.js new file mode 100644 index 0000000..abc123 @@ -94,13 +94,13 @@ index 0000000..abc123 +line3`; const result = annotateDiff(diff); - expect(result).toContain('new file mode 100644'); - expect(result).toContain('[POS:1] +line1'); - expect(result).toContain('[POS:2] +line2'); - expect(result).toContain('[POS:3] +line3'); + expect(result).toContain("new file mode 100644"); + expect(result).toContain("[POS:1] +line1"); + expect(result).toContain("[POS:2] +line2"); + expect(result).toContain("[POS:3] +line3"); }); - test('handles deleted file', () => { + test("handles deleted file", () => { const diff = `diff --git a/deleted.js b/deleted.js deleted file mode 100644 index abc123..0000000 @@ -112,13 +112,13 @@ index abc123..0000000 -line3`; const result = annotateDiff(diff); - expect(result).toContain('deleted file mode 100644'); - expect(result).toContain('[POS:1] -line1'); - expect(result).toContain('[POS:2] -line2'); - expect(result).toContain('[POS:3] -line3'); + expect(result).toContain("deleted file mode 100644"); + expect(result).toContain("[POS:1] -line1"); + expect(result).toContain("[POS:2] -line2"); + expect(result).toContain("[POS:3] -line3"); }); - test('handles renamed file with changes', () => { + test("handles renamed file with changes", () => { const diff = `diff --git a/old-name.js b/new-name.js similarity index 95% rename from old-name.js @@ -133,14 +133,14 @@ index abc123..def456 100644 line3`; const result = annotateDiff(diff); - expect(result).toContain('rename from old-name.js'); - expect(result).toContain('rename to new-name.js'); - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old line'); - expect(result).toContain('[POS:3] +new line'); + expect(result).toContain("rename from old-name.js"); + expect(result).toContain("rename to new-name.js"); + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old line"); + expect(result).toContain("[POS:3] +new line"); }); - test('handles no newline at end of file', () => { + test("handles no newline at end of file", () => { const diff = `diff --git a/file.js b/file.js index abc123..def456 100644 --- a/file.js @@ -153,19 +153,19 @@ index abc123..def456 100644 \\ No newline at end of file`; const result = annotateDiff(diff); - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old line'); + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old line"); // Position 3 is the first "No newline" marker (not annotated but counted) - expect(result).toContain('\\ No newline at end of file'); - expect(result).toContain('[POS:4] +new line'); // Position 4 due to "No newline" at position 3 + expect(result).toContain("\\ No newline at end of file"); + expect(result).toContain("[POS:4] +new line"); // Position 4 due to "No newline" at position 3 // Position 5 is the second "No newline" marker (not annotated but counted) - expect(result).toContain('\\ No newline at end of file'); + expect(result).toContain("\\ No newline at end of file"); // No newline markers should not get [POS:N] annotations - expect(result).not.toContain('[POS:3] \\'); - expect(result).not.toContain('[POS:5] \\'); + expect(result).not.toContain("[POS:3] \\"); + expect(result).not.toContain("[POS:5] \\"); }); - test('handles file mode changes', () => { + test("handles file mode changes", () => { const diff = `diff --git a/script.sh b/script.sh old mode 100644 new mode 100755 @@ -178,60 +178,64 @@ index abc123..def456 100644 +echo "new"`; const result = annotateDiff(diff); - expect(result).toContain('old mode 100644'); - expect(result).toContain('new mode 100755'); - expect(result).toContain('[POS:1] #!/bin/bash'); + expect(result).toContain("old mode 100644"); + expect(result).toContain("new mode 100755"); + expect(result).toContain("[POS:1] #!/bin/bash"); expect(result).toContain('[POS:2] -echo "old"'); expect(result).toContain('[POS:3] +echo "new"'); }); - test('empty diff returns empty', () => { - const diff = ''; + test("empty diff returns empty", () => { + const diff = ""; const result = annotateDiff(diff); - expect(result).toBe(''); + expect(result).toBe(""); }); - test('handles binary files - modified', () => { + test("handles binary files - modified", () => { const diff = `diff --git a/image.png b/image.png index abc123..def456 100644 Binary files a/image.png and b/image.png differ`; const result = annotateDiff(diff); - expect(result).toContain('diff --git a/image.png b/image.png'); - expect(result).toContain('Binary files a/image.png and b/image.png differ'); + expect(result).toContain("diff --git a/image.png b/image.png"); + expect(result).toContain("Binary files a/image.png and b/image.png differ"); // Binary files line should not be annotated - expect(result).not.toContain('[POS:'); + expect(result).not.toContain("[POS:"); }); - test('handles binary files - added', () => { + test("handles binary files - added", () => { const diff = `diff --git a/newimage.png b/newimage.png new file mode 100644 index 0000000..abc123 Binary files /dev/null and b/newimage.png differ`; const result = annotateDiff(diff); - expect(result).toContain('diff --git a/newimage.png b/newimage.png'); - expect(result).toContain('new file mode 100644'); - expect(result).toContain('Binary files /dev/null and b/newimage.png differ'); + expect(result).toContain("diff --git a/newimage.png b/newimage.png"); + expect(result).toContain("new file mode 100644"); + expect(result).toContain( + "Binary files /dev/null and b/newimage.png differ", + ); // Binary files line should not be annotated - expect(result).not.toContain('[POS:'); + expect(result).not.toContain("[POS:"); }); - test('handles binary files - deleted', () => { + test("handles binary files - deleted", () => { const diff = `diff --git a/oldimage.png b/oldimage.png deleted file mode 100644 index abc123..0000000 Binary files a/oldimage.png and /dev/null differ`; const result = annotateDiff(diff); - expect(result).toContain('diff --git a/oldimage.png b/oldimage.png'); - expect(result).toContain('deleted file mode 100644'); - expect(result).toContain('Binary files a/oldimage.png and /dev/null differ'); + expect(result).toContain("diff --git a/oldimage.png b/oldimage.png"); + expect(result).toContain("deleted file mode 100644"); + expect(result).toContain( + "Binary files a/oldimage.png and /dev/null differ", + ); // Binary files line should not be annotated - expect(result).not.toContain('[POS:'); + expect(result).not.toContain("[POS:"); }); - test('handles mixed text and binary files', () => { + test("handles mixed text and binary files", () => { const diff = `diff --git a/text.js b/text.js index abc123..def456 100644 --- a/text.js @@ -252,22 +256,22 @@ index 333333..444444 100644 +bar`; const result = annotateDiff(diff); - + // First file (text) - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old'); - expect(result).toContain('[POS:3] +new'); - + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old"); + expect(result).toContain("[POS:3] +new"); + // Second file (binary) - no positions - expect(result).toContain('Binary files a/image.png and b/image.png differ'); - + expect(result).toContain("Binary files a/image.png and b/image.png differ"); + // Third file (text) - positions reset - const lastFileSection = result.split('diff --git a/another.js')[1]; - expect(lastFileSection).toContain('[POS:1] -foo'); - expect(lastFileSection).toContain('[POS:2] +bar'); + const lastFileSection = result.split("diff --git a/another.js")[1]; + expect(lastFileSection).toContain("[POS:1] -foo"); + expect(lastFileSection).toContain("[POS:2] +bar"); }); - test('multiple no newline markers accumulate positions', () => { + test("multiple no newline markers accumulate positions", () => { const diff = `diff --git a/file.js b/file.js index abc123..def456 100644 --- a/file.js @@ -286,29 +290,29 @@ index abc123..def456 100644 \\ No newline at end of file`; const result = annotateDiff(diff); - + // First hunk - expect(result).toContain('[POS:1] line1'); - expect(result).toContain('[POS:2] -old1'); + expect(result).toContain("[POS:1] line1"); + expect(result).toContain("[POS:2] -old1"); // Position 3 is the first "No newline" marker - expect(result).toContain('[POS:4] +new1'); + expect(result).toContain("[POS:4] +new1"); // Position 5 is the second "No newline" marker - + // Second hunk (starts at position 7 = 5 + 1 for between hunks + 1) - expect(result).toContain('[POS:7] line10'); - expect(result).toContain('[POS:8] -old2'); + expect(result).toContain("[POS:7] line10"); + expect(result).toContain("[POS:8] -old2"); // Position 9 is the third "No newline" marker - expect(result).toContain('[POS:10] +new2'); + expect(result).toContain("[POS:10] +new2"); // Position 11 is the fourth "No newline" marker - + // Verify "No newline" markers are not annotated - expect(result).not.toContain('[POS:3] \\'); - expect(result).not.toContain('[POS:5] \\'); - expect(result).not.toContain('[POS:9] \\'); - expect(result).not.toContain('[POS:11] \\'); + expect(result).not.toContain("[POS:3] \\"); + expect(result).not.toContain("[POS:5] \\"); + expect(result).not.toContain("[POS:9] \\"); + expect(result).not.toContain("[POS:11] \\"); }); - test('complex multi-file, multi-hunk diff', () => { + test("complex multi-file, multi-hunk diff", () => { const diff = `diff --git a/src/app.js b/src/app.js index abc123..def456 100644 --- a/src/app.js @@ -335,25 +339,25 @@ index 111111..222222 100644 return true;`; const result = annotateDiff(diff); - + // src/app.js - first hunk expect(result).toContain('[POS:1] console.log("start");'); - expect(result).toContain('[POS:2] const x = 1;'); - expect(result).toContain('[POS:3] - const y = 2;'); - expect(result).toContain('[POS:4] + const y = 3;'); - expect(result).toContain('[POS:5] + const z = 4;'); - expect(result).toContain('[POS:6] return x + y;'); - + expect(result).toContain("[POS:2] const x = 1;"); + expect(result).toContain("[POS:3] - const y = 2;"); + expect(result).toContain("[POS:4] + const y = 3;"); + expect(result).toContain("[POS:5] + const z = 4;"); + expect(result).toContain("[POS:6] return x + y;"); + // src/app.js - second hunk (7 = 6 + 1 for between hunks) - expect(result).toContain('[POS:8] let a = 1;'); - expect(result).toContain('[POS:9] let b = 2;'); - expect(result).toContain('[POS:10] + let c = 3;'); - expect(result).toContain('[POS:11] return a + b;'); - + expect(result).toContain("[POS:8] let a = 1;"); + expect(result).toContain("[POS:9] let b = 2;"); + expect(result).toContain("[POS:10] + let c = 3;"); + expect(result).toContain("[POS:11] return a + b;"); + // src/util.js - new file, positions reset - const utilSection = result.split('diff --git a/src/util.js')[1]; - expect(utilSection).toContain('[POS:1] +import fs from \'fs\';'); - expect(utilSection).toContain('[POS:2] export function util() {'); - expect(utilSection).toContain('[POS:3] return true;'); + const utilSection = result.split("diff --git a/src/util.js")[1]; + expect(utilSection).toContain("[POS:1] +import fs from 'fs';"); + expect(utilSection).toContain("[POS:2] export function util() {"); + expect(utilSection).toContain("[POS:3] return true;"); }); -}); \ No newline at end of file +}); diff --git a/actions/detailed-review/package.json b/actions/detailed-review/package.json index 2fe6f122b..4ca8aee1c 100644 --- a/actions/detailed-review/package.json +++ b/actions/detailed-review/package.json @@ -16,4 +16,4 @@ "**/*.test.js" ] } -} \ No newline at end of file +}