├── .gitignore ├── LICENSE ├── README.md ├── get-dependabot-alerts.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tony Cheung Chun Hing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Get Dependabot Alerts from a repository 2 | 3 | ## Overview 4 | 5 | This Node script takes in a given `org` and `repo` to dump out all [Dependabot Alerts](https://help.github.com/en/github/managing-security-vulnerabilities/viewing-and-updating-vulnerable-dependencies-in-your-repository) in the Security tab page. 6 | 7 | ## How to use 8 | 1. Clone this repo to your local machine 9 | 2. Create a filed called `.env` 10 | 3. Create a GitHub [Personal Access Token](https://help.github.com/articles/authorizing-a-personal-access-token-for-use-with-a-saml-single-sign-on-organization/) with `repo` permission 11 | 4. Add the token to your `.env` file as `GITHUB_TOKEN=insert-token-here` 12 | 5. Run `npm install` then run `get-dependabot-alerts.js` with `org` and `repo` 13 | ### Example 14 | ```.sh 15 | npm install 16 | node get-dependabot-alerts.js octodemo activemq > output.csv 17 | ``` 18 | ## License 19 | This project is licensed under the MIT License. -------------------------------------------------------------------------------- /get-dependabot-alerts.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('dotenv').config() 4 | 5 | const [, , org, repo] = process.argv 6 | 7 | let { graphql } = require('@octokit/graphql') 8 | graphql = graphql.defaults({ 9 | headers: { 10 | authorization: `token ${process.env.GITHUB_TOKEN}` 11 | } 12 | }) 13 | 14 | DumpDependabotAlerts() 15 | 16 | async function DumpDependabotAlerts() { 17 | let pagination = null 18 | const query = 19 | `query ($org: String! $repo: String! $cursor: String){ 20 | repository(owner: $org name: $repo) { 21 | name 22 | vulnerabilityAlerts(first: 100 after: $cursor) { 23 | pageInfo { 24 | hasNextPage 25 | endCursor 26 | } 27 | totalCount 28 | nodes { 29 | id 30 | securityAdvisory { 31 | ...advFields 32 | } 33 | securityVulnerability { 34 | package { 35 | ...pkgFields 36 | } 37 | vulnerableVersionRange 38 | } 39 | vulnerableManifestFilename 40 | vulnerableManifestPath 41 | vulnerableRequirements 42 | } 43 | } 44 | } 45 | } 46 | 47 | fragment advFields on SecurityAdvisory { 48 | ghsaId 49 | permalink 50 | severity 51 | description 52 | summary 53 | } 54 | 55 | fragment pkgFields on SecurityAdvisoryPackage { 56 | name 57 | ecosystem 58 | }` 59 | 60 | try { 61 | console.log("org,repo,package,ecosystem,summary,severity,permalink") 62 | let hasNextPage = false 63 | do { 64 | const getVulnResult = await graphql({ query, org: org, repo: repo, cursor: pagination }) 65 | hasNextPage = getVulnResult.repository.vulnerabilityAlerts.pageInfo.hasNextPage 66 | const vulns = getVulnResult.repository.vulnerabilityAlerts.nodes 67 | 68 | for (const vuln of vulns) { 69 | console.log(`${org},${repo},${vuln.securityVulnerability.package.name},${vuln.securityVulnerability.package.ecosystem},"${vuln.securityAdvisory.summary}",${vuln.securityAdvisory.severity},${vuln.securityAdvisory.permalink}`) 70 | } 71 | 72 | if (hasNextPage) { 73 | pagination = getVulnResult.repository.vulnerabilityAlerts.pageInfo.endCursor 74 | } 75 | } while (hasNextPage) 76 | } catch (error) { 77 | console.log('Request failed:', error.request) 78 | console.log(error.message) 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get-dependabot-alerts", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@octokit/endpoint": { 8 | "version": "6.0.3", 9 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.3.tgz", 10 | "integrity": "sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg==", 11 | "requires": { 12 | "@octokit/types": "^5.0.0", 13 | "is-plain-object": "^3.0.0", 14 | "universal-user-agent": "^5.0.0" 15 | } 16 | }, 17 | "@octokit/graphql": { 18 | "version": "4.5.1", 19 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.1.tgz", 20 | "integrity": "sha512-qgMsROG9K2KxDs12CO3bySJaYoUu2aic90qpFrv7A8sEBzZ7UFGvdgPKiLw5gOPYEYbS0Xf8Tvf84tJutHPulQ==", 21 | "requires": { 22 | "@octokit/request": "^5.3.0", 23 | "@octokit/types": "^5.0.0", 24 | "universal-user-agent": "^5.0.0" 25 | } 26 | }, 27 | "@octokit/request": { 28 | "version": "5.4.5", 29 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.5.tgz", 30 | "integrity": "sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg==", 31 | "requires": { 32 | "@octokit/endpoint": "^6.0.1", 33 | "@octokit/request-error": "^2.0.0", 34 | "@octokit/types": "^5.0.0", 35 | "deprecation": "^2.0.0", 36 | "is-plain-object": "^3.0.0", 37 | "node-fetch": "^2.3.0", 38 | "once": "^1.4.0", 39 | "universal-user-agent": "^5.0.0" 40 | } 41 | }, 42 | "@octokit/request-error": { 43 | "version": "2.0.2", 44 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz", 45 | "integrity": "sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==", 46 | "requires": { 47 | "@octokit/types": "^5.0.1", 48 | "deprecation": "^2.0.0", 49 | "once": "^1.4.0" 50 | } 51 | }, 52 | "@octokit/types": { 53 | "version": "5.0.1", 54 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.0.1.tgz", 55 | "integrity": "sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA==", 56 | "requires": { 57 | "@types/node": ">= 8" 58 | } 59 | }, 60 | "@types/node": { 61 | "version": "14.0.13", 62 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz", 63 | "integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==" 64 | }, 65 | "cross-spawn": { 66 | "version": "6.0.5", 67 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 68 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 69 | "requires": { 70 | "nice-try": "^1.0.4", 71 | "path-key": "^2.0.1", 72 | "semver": "^5.5.0", 73 | "shebang-command": "^1.2.0", 74 | "which": "^1.2.9" 75 | } 76 | }, 77 | "deprecation": { 78 | "version": "2.3.1", 79 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 80 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 81 | }, 82 | "dotenv": { 83 | "version": "8.2.0", 84 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", 85 | "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" 86 | }, 87 | "end-of-stream": { 88 | "version": "1.4.4", 89 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 90 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 91 | "requires": { 92 | "once": "^1.4.0" 93 | } 94 | }, 95 | "execa": { 96 | "version": "1.0.0", 97 | "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", 98 | "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", 99 | "requires": { 100 | "cross-spawn": "^6.0.0", 101 | "get-stream": "^4.0.0", 102 | "is-stream": "^1.1.0", 103 | "npm-run-path": "^2.0.0", 104 | "p-finally": "^1.0.0", 105 | "signal-exit": "^3.0.0", 106 | "strip-eof": "^1.0.0" 107 | } 108 | }, 109 | "get-stream": { 110 | "version": "4.1.0", 111 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 112 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 113 | "requires": { 114 | "pump": "^3.0.0" 115 | } 116 | }, 117 | "is-plain-object": { 118 | "version": "3.0.0", 119 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", 120 | "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", 121 | "requires": { 122 | "isobject": "^4.0.0" 123 | } 124 | }, 125 | "is-stream": { 126 | "version": "1.1.0", 127 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 128 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 129 | }, 130 | "isexe": { 131 | "version": "2.0.0", 132 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 133 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 134 | }, 135 | "isobject": { 136 | "version": "4.0.0", 137 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", 138 | "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==" 139 | }, 140 | "macos-release": { 141 | "version": "2.3.0", 142 | "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", 143 | "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==" 144 | }, 145 | "nice-try": { 146 | "version": "1.0.5", 147 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 148 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" 149 | }, 150 | "node-fetch": { 151 | "version": "2.6.0", 152 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 153 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 154 | }, 155 | "npm-run-path": { 156 | "version": "2.0.2", 157 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 158 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 159 | "requires": { 160 | "path-key": "^2.0.0" 161 | } 162 | }, 163 | "once": { 164 | "version": "1.4.0", 165 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 166 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 167 | "requires": { 168 | "wrappy": "1" 169 | } 170 | }, 171 | "os-name": { 172 | "version": "3.1.0", 173 | "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", 174 | "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", 175 | "requires": { 176 | "macos-release": "^2.2.0", 177 | "windows-release": "^3.1.0" 178 | } 179 | }, 180 | "p-finally": { 181 | "version": "1.0.0", 182 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 183 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" 184 | }, 185 | "path-key": { 186 | "version": "2.0.1", 187 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 188 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" 189 | }, 190 | "pump": { 191 | "version": "3.0.0", 192 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 193 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 194 | "requires": { 195 | "end-of-stream": "^1.1.0", 196 | "once": "^1.3.1" 197 | } 198 | }, 199 | "semver": { 200 | "version": "5.7.1", 201 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 202 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 203 | }, 204 | "shebang-command": { 205 | "version": "1.2.0", 206 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 207 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 208 | "requires": { 209 | "shebang-regex": "^1.0.0" 210 | } 211 | }, 212 | "shebang-regex": { 213 | "version": "1.0.0", 214 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 215 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" 216 | }, 217 | "signal-exit": { 218 | "version": "3.0.3", 219 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 220 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" 221 | }, 222 | "strip-eof": { 223 | "version": "1.0.0", 224 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 225 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" 226 | }, 227 | "universal-user-agent": { 228 | "version": "5.0.0", 229 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", 230 | "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", 231 | "requires": { 232 | "os-name": "^3.1.0" 233 | } 234 | }, 235 | "which": { 236 | "version": "1.3.1", 237 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 238 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 239 | "requires": { 240 | "isexe": "^2.0.0" 241 | } 242 | }, 243 | "windows-release": { 244 | "version": "3.3.1", 245 | "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.1.tgz", 246 | "integrity": "sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==", 247 | "requires": { 248 | "execa": "^1.0.0" 249 | } 250 | }, 251 | "wrappy": { 252 | "version": "1.0.2", 253 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 254 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get-dependabot-alerts", 3 | "version": "1.0.0", 4 | "description": "Gets Dependabot Alerts from a repository", 5 | "main": "get-dependabot-alerts.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "tonycch", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@octokit/graphql": "^4.5.1", 13 | "dotenv": "^8.2.0" 14 | } 15 | } 16 | --------------------------------------------------------------------------------