├── docs ├── CNAME ├── _includes │ ├── page.scss │ └── example.html ├── robots.txt ├── _layouts │ └── default.html ├── _sass │ ├── _syntax.scss │ └── _page.scss ├── github-btn.html └── index.md ├── .gitattributes ├── .github ├── codeql │ └── codeql-config.yml ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── ci.yml ├── Gemfile ├── .stylelintrc.json ├── _config.yml ├── src ├── btn.html ├── styles.css └── js.js ├── .gitignore ├── html-minifier.json ├── xo.config.js ├── README.md ├── package.json ├── Gemfile.lock └── LICENSE /docs/CNAME: -------------------------------------------------------------------------------- 1 | ghbtns.com -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL config" 2 | paths-ignore: 3 | - docs/github-btn.html 4 | -------------------------------------------------------------------------------- /docs/_includes/page.scss: -------------------------------------------------------------------------------- 1 | // Our bundle CSS files are listed here so that we inlcude the dist file in Jekyll 2 | @use "page"; 3 | @use "syntax"; 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'jekyll', '~> 4.4.1' 4 | gem 'jekyll-seo-tag', '~> 2.8.0' 5 | gem 'jekyll-sitemap', '~> 1.4.0' 6 | gem 'wdm', '~> 0.2.0', :install_if => Gem.win_platform? 7 | -------------------------------------------------------------------------------- /docs/robots.txt: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | # www.robotstxt.org/ 5 | 6 | # Allow crawling of all content 7 | User-agent: * 8 | Disallow: {% if jekyll.environment == "netlify" %}/{% else %}/*?*{% endif %} 9 | Sitemap: {{ site.url }}/sitemap.xml 10 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "stylelint-config-twbs-bootstrap" 4 | ], 5 | "reportInvalidScopeDisables": true, 6 | "reportNeedlessDisables": true, 7 | "rules": { 8 | "no-duplicate-selectors": true, 9 | "property-no-vendor-prefix": null, 10 | "value-no-vendor-prefix": null 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: "Unofficial GitHub Buttons" 2 | description: "A set of static buttons with dynamic watch and fork counts for any repo hosted on GitHub." 3 | url: "https://ghbtns.com" 4 | 5 | # Social 6 | author: 7 | name: "Mark Otto" 8 | 9 | twitter: 10 | username: "mdo" 11 | 12 | permalink: pretty 13 | 14 | sass: 15 | style: compressed 16 | 17 | source: docs 18 | 19 | plugins: 20 | - jekyll-seo-tag 21 | - jekyll-sitemap 22 | -------------------------------------------------------------------------------- /src/btn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore docs files 2 | /.sass-cache/ 3 | /_site/ 4 | /docs/.jekyll-cache/ 5 | /.ruby-version 6 | 7 | # Numerous always-ignore extensions 8 | *.diff 9 | *.err 10 | *.orig 11 | *.log 12 | *.rej 13 | *.swo 14 | *.swp 15 | *.zip 16 | *.vi 17 | *~ 18 | 19 | # OS or Editor folders 20 | .DS_Store 21 | ._* 22 | Thumbs.db 23 | .cache 24 | .project 25 | .settings 26 | .tmproj 27 | *.esproj 28 | nbproject 29 | *.sublime-project 30 | *.sublime-workspace 31 | .idea 32 | 33 | # Komodo 34 | *.komodoproject 35 | .komodotools 36 | 37 | # Folders to ignore 38 | /.bundle/ 39 | /node_modules/ 40 | /vendor/ 41 | 42 | # Local Netlify folder 43 | .netlify 44 | -------------------------------------------------------------------------------- /docs/_includes/example.html: -------------------------------------------------------------------------------- 1 | {%- comment -%} 2 | Usage: include example.html content=markup [args], 3 | where content is a capture with the HTML content 4 | 5 | args can be one of the following: 6 | id - null (default) 7 | class - "example" (default) 8 | {%- endcomment -%} 9 | 10 | {%- assign id = include.id -%} 11 | {%- assign class = include.class -%} 12 | 13 | 14 | {%- assign url = site.url | append: '/' -%} 15 | {{- include.content | replace: url, '' | replace: ' frameborder="0" scrolling="0"' '' -}} 16 | 17 | 18 | {%- highlight html -%} 19 | {{- include.content -}} 20 | {%- endhighlight -%} 21 | -------------------------------------------------------------------------------- /html-minifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "collapseBooleanAttributes": true, 3 | "collapseWhitespace": true, 4 | "conservativeCollapse": false, 5 | "decodeEntities": true, 6 | "includeAutoGeneratedTags": false, 7 | "minifyCSS": { 8 | "level": { 9 | "1": { 10 | "specialComments": 0, 11 | "roundingPrecision": 6 12 | }, 13 | "2": { 14 | "all": false, 15 | "mergeMedia": true, 16 | "removeDuplicateMediaBlocks": true, 17 | "removeEmpty": true 18 | } 19 | } 20 | }, 21 | "minifyJS": { 22 | "compress": { 23 | "passes": 2 24 | }, 25 | "mangle": true 26 | }, 27 | "processConditionalComments": true, 28 | "removeAttributeQuotes": true, 29 | "removeComments": true, 30 | "removeOptionalTags": true, 31 | "removeRedundantAttributes": true, 32 | "removeScriptTypeAttributes": true, 33 | "removeStyleLinkTypeAttributes": true, 34 | "removeTagWhitespace": false, 35 | "sortAttributes": true, 36 | "sortClassName": true 37 | } 38 | -------------------------------------------------------------------------------- /xo.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const globals = require('globals'); 4 | 5 | module.exports = [ 6 | { 7 | languageOptions: { 8 | ecmaVersion: 2020, 9 | sourceType: 'commonjs', 10 | globals: { 11 | ...globals.browser 12 | } 13 | }, 14 | space: 2, 15 | rules: { 16 | '@stylistic/comma-dangle': [ 17 | 'error', 18 | 'never' 19 | ], 20 | '@stylistic/object-curly-spacing': [ 21 | 'error', 22 | 'always' 23 | ], 24 | '@stylistic/spaced-comment': 'off', 25 | '@stylistic/space-before-function-paren': [ 26 | 'error', 27 | 'never' 28 | ], 29 | camelcase: [ 30 | 'error', 31 | { 32 | properties: 'never' 33 | } 34 | ], 35 | 'no-negated-condition': 'off', 36 | 'capitalized-comments': 'off', 37 | 'default-case': 'off', 38 | 'prefer-template': 'error', 39 | 'unicorn/no-negated-condition': 'off', 40 | 'unicorn/prefer-global-this': 'off', 41 | 'unicorn/prefer-module': 'off', 42 | 'unicorn/prefer-top-level-await': 'off', 43 | 'unicorn/prevent-abbreviations': 'off' 44 | } 45 | } 46 | ]; 47 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - "!dependabot/**" 8 | pull_request: 9 | branches: 10 | - master 11 | - "!dependabot/**" 12 | schedule: 13 | - cron: "0 0 * * 0" 14 | workflow_dispatch: 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | runs-on: ubuntu-latest 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 33 | with: 34 | config-file: ./.github/codeql/codeql-config.yml 35 | languages: "javascript" 36 | queries: +security-and-quality 37 | 38 | - name: Autobuild 39 | uses: github/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 40 | 41 | - name: Perform CodeQL Analysis 42 | uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 43 | with: 44 | category: "/language:javascript" 45 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% seo %} 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 |
25 | 26 |

Introducing the unofficial

27 |

GitHub buttons

28 |

Showcase your GitHub repo’s success with hotlinkable GitHub star, fork, sponsor, and follow buttons. Available in two sizes with up-to-date counts.

29 |

Made by @mdo. Available on GitHub. Licensed Apache 2.

30 | 31 |
32 | 33 | {{ content }} 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/_sass/_syntax.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-block-single-line-max-declarations 2 | 3 | .hll { background-color: #ffc; } 4 | .c { color: #727272; } 5 | .k { color: #069; } 6 | .o { color: #555; } 7 | .cm { color: #727272; } 8 | .cp { color: #008085; } 9 | .c1 { color: #727272; } 10 | .cs { color: #727272; } 11 | .gd { background-color: #fcc; border: 1px solid #c00; } 12 | .ge { font-style: italic; } 13 | .gr { color: #f00; } 14 | .gh { color: #030; } 15 | .gi { background-color: #cfc; border: 1px solid #0c0; } 16 | .go { color: #aaa; } 17 | .gp { color: #009; } 18 | .gu { color: #030; } 19 | .gt { color: #9c6; } 20 | .kc { color: #069; } 21 | .kd { color: #069; } 22 | .kn { color: #069; } 23 | .kp { color: #069; } 24 | .kr { color: #069; } 25 | .kt { color: #078; } 26 | .m { color: #bc511f; } 27 | .s { color: #d82d36; } 28 | .na { color: #006ee0; } 29 | .nb { color: #366; } 30 | .nc { color: #168174; } 31 | .no { color: #360; } 32 | .nd { color: #685fe3; } 33 | .ni { color: #727272; } 34 | .ne { color: #c00; } 35 | .nf { color: #b715f4; } 36 | .nl { color: #685fe3; } 37 | .nn { color: #007ca5; } 38 | .nt { color: #2f6f9f; } 39 | .nv { color: #033; } 40 | .ow { color: #000; } 41 | .w { color: #bbb; } 42 | .mf { color: #bc511f; } 43 | .mh { color: #bc511f; } 44 | .mi { color: #bc511f; } 45 | .mo { color: #bc511f; } 46 | .sb { color: #c30; } 47 | .sc { color: #c30; } 48 | .sd { font-style: italic; color: #c30; } 49 | .s2 { color: #c30; } 50 | .se { color: #c30; } 51 | .sh { color: #c30; } 52 | .si { color: #a00; } 53 | .sx { color: #c30; } 54 | .sr { color: #337e7e; } 55 | .s1 { color: #c30; } 56 | .ss { color: #fc3; } 57 | .bp { color: #366; } 58 | .vc { color: #033; } 59 | .vg { color: #033; } 60 | .vi { color: #033; } 61 | .il { color: #bc511f; } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Buttons [![Build Status](https://img.shields.io/github/actions/workflow/status/mdo/github-buttons/ci.yml?branch=master&label=CI&logo=github)](https://github.com/mdo/github-buttons/actions/workflows/ci.yml?query=branch%3Amaster) 2 | 3 | Showcase your GitHub (repo's) success with these static buttons featuring links to your GitHub repo or profile page and up-to-date watch, fork, sponsor, and follower counts. 4 | 5 | To get started, checkout ! 6 | 7 | ## Bug tracker 8 | 9 | Have a bug? Please create an issue here on GitHub at . 10 | 11 | ## Development 12 | 13 | Clone the project and install dependencies before getting started. GitHub Buttons require Node.js, Ruby, and Bundler for local development. 14 | 15 | ```shell 16 | npm i 17 | bundle i 18 | ``` 19 | 20 | The GitHub buttons source code is split across three files in `src/`—the HTML, CSS, and JS. We use inline-source-cli and html-minifer to include it all in the compiled [`docs/github-btn.html`](docs/github-btn.html) file. To build this file: 21 | 22 | ```shell 23 | npm run build 24 | ``` 25 | 26 | The `https://ghbtns.com/` site is built with Jekyll. After installing the dependencies, you can run a local server: 27 | 28 | ```shell 29 | bundle exec jekyll serve 30 | ``` 31 | 32 | Open `http://127.0.0.1:4000` to browse locally. 33 | 34 | ## See also 35 | 36 | * [ntkme/github-buttons](https://buttons.github.io/) 37 | 38 | ## Twitter account 39 | 40 | Keep up to date on announcements and more by following Mark on Twitter, [@mdo](https://twitter.com/mdo). 41 | 42 | ## Author 43 | 44 | **Mark Otto** 45 | 46 | * 47 | * 48 | 49 | ## Copyright and license 50 | 51 | Copyright 2014-2022 Mark Otto. Released under the [Apache 2.0 License](LICENSE). 52 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - "dependabot/**" 7 | tags: 8 | - "*" 9 | pull_request: 10 | workflow_dispatch: 11 | 12 | env: 13 | FORCE_COLOR: 2 14 | NODE: 22 15 | RUBY: "3.4" 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Clone repository 23 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 24 | with: 25 | persist-credentials: false 26 | 27 | - name: Set up Node.js 28 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 29 | with: 30 | node-version: ${{ env.NODE }} 31 | cache: npm 32 | 33 | - name: Set up Ruby 34 | uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0 35 | with: 36 | ruby-version: ${{ env.RUBY }} 37 | bundler-cache: true 38 | 39 | - name: Install npm dependencies 40 | run: npm ci 41 | 42 | - name: Run tests 43 | run: npm test 44 | 45 | - name: Upload docs 46 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 47 | if: github.repository == 'mdo/github-buttons' && startsWith(github.ref, 'refs/tags/') 48 | with: 49 | name: docs 50 | path: ./_site/ 51 | if-no-files-found: error 52 | 53 | deploy: 54 | runs-on: ubuntu-latest 55 | needs: test 56 | if: github.repository == 'mdo/github-buttons' && startsWith(github.ref, 'refs/tags/') 57 | 58 | steps: 59 | - name: Clone repository 60 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 61 | with: 62 | persist-credentials: false 63 | 64 | - name: Download docs 65 | uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 66 | with: 67 | name: docs 68 | path: ./_site/ 69 | 70 | - name: Deploy 71 | uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 72 | with: 73 | allow_empty_commit: false 74 | personal_token: ${{ secrets.PERSONAL_TOKEN }} 75 | publish_branch: gh-pages 76 | publish_dir: ./_site/ 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-buttons", 3 | "version": "4.2.3", 4 | "description": "Showcase your GitHub (repo's) success with these buttons", 5 | "private": true, 6 | "homepage": "https://ghbtns.com/", 7 | "author": "Mark Otto (https://github.com/mdo)", 8 | "license": "Apache-2.0", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mdo/github-buttons.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/mdo/github-buttons/issues" 15 | }, 16 | "keywords": [ 17 | "github", 18 | "buttons", 19 | "iframe", 20 | "html" 21 | ], 22 | "scripts": { 23 | "start": "npm-run-all --parallel build docs-serve watch", 24 | "docs-build": "bundle exec jekyll build", 25 | "docs-serve": "bundle exec jekyll serve", 26 | "build": "inline-source --compress false --root src src/btn.html | html-minifier-terser --config-file html-minifier.json -o docs/github-btn.html", 27 | "dist": "npm run build", 28 | "stylelint": "stylelint \"**/*.{css,scss}\" --ignore-path .gitignore", 29 | "lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json", 30 | "lint": "npm-run-all --continue-on-error --parallel lockfile-lint stylelint xo", 31 | "xo": "xo", 32 | "netlify": "cross-env-shell JEKYLL_ENV=netlify npm-run-all build docs-build", 33 | "test": "npm-run-all lint build docs-build", 34 | "watch": "npm-run-all --parallel watch-*", 35 | "watch-css": "chokidar \"{src,docs/_sass}/**/*.{css,scss}\" --initial --command \"npm run stylelint\"", 36 | "watch-js": "chokidar \"src/*.js\" --initial --command \"npm run xo\"", 37 | "watch-main": "chokidar src/ --initial --command \"npm run build\"" 38 | }, 39 | "devDependencies": { 40 | "chokidar-cli": "^3.0.0", 41 | "cross-env": "^10.0.0", 42 | "globals": "^16.4.0", 43 | "html-minifier-terser": "^7.2.0", 44 | "inline-source-cli": "^2.0.0", 45 | "lockfile-lint": "^4.14.1", 46 | "npm-run-all2": "^8.0.4", 47 | "stylelint": "^16.24.0", 48 | "stylelint-config-twbs-bootstrap": "^16.1.0", 49 | "xo": "^1.2.2" 50 | }, 51 | "engines": { 52 | "node": ">=20" 53 | }, 54 | "overrides": { 55 | "inline-source-cli": { 56 | "inline-source": "^8.0.2" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.7) 5 | public_suffix (>= 2.0.2, < 7.0) 6 | base64 (0.3.0) 7 | bigdecimal (3.2.3) 8 | colorator (1.1.0) 9 | concurrent-ruby (1.3.5) 10 | csv (3.3.5) 11 | em-websocket (0.5.3) 12 | eventmachine (>= 0.12.9) 13 | http_parser.rb (~> 0) 14 | eventmachine (1.2.7) 15 | ffi (1.17.2) 16 | ffi (1.17.2-x64-mingw-ucrt) 17 | forwardable-extended (2.6.0) 18 | google-protobuf (4.32.1) 19 | bigdecimal 20 | rake (>= 13) 21 | google-protobuf (4.32.1-x64-mingw-ucrt) 22 | bigdecimal 23 | rake (>= 13) 24 | http_parser.rb (0.8.0) 25 | i18n (1.14.7) 26 | concurrent-ruby (~> 1.0) 27 | jekyll (4.4.1) 28 | addressable (~> 2.4) 29 | base64 (~> 0.2) 30 | colorator (~> 1.0) 31 | csv (~> 3.0) 32 | em-websocket (~> 0.5) 33 | i18n (~> 1.0) 34 | jekyll-sass-converter (>= 2.0, < 4.0) 35 | jekyll-watch (~> 2.0) 36 | json (~> 2.6) 37 | kramdown (~> 2.3, >= 2.3.1) 38 | kramdown-parser-gfm (~> 1.0) 39 | liquid (~> 4.0) 40 | mercenary (~> 0.3, >= 0.3.6) 41 | pathutil (~> 0.9) 42 | rouge (>= 3.0, < 5.0) 43 | safe_yaml (~> 1.0) 44 | terminal-table (>= 1.8, < 4.0) 45 | webrick (~> 1.7) 46 | jekyll-sass-converter (3.1.0) 47 | sass-embedded (~> 1.75) 48 | jekyll-seo-tag (2.8.0) 49 | jekyll (>= 3.8, < 5.0) 50 | jekyll-sitemap (1.4.0) 51 | jekyll (>= 3.7, < 5.0) 52 | jekyll-watch (2.2.1) 53 | listen (~> 3.0) 54 | json (2.13.2) 55 | kramdown (2.5.1) 56 | rexml (>= 3.3.9) 57 | kramdown-parser-gfm (1.1.0) 58 | kramdown (~> 2.0) 59 | liquid (4.0.4) 60 | listen (3.9.0) 61 | rb-fsevent (~> 0.10, >= 0.10.3) 62 | rb-inotify (~> 0.9, >= 0.9.10) 63 | mercenary (0.4.0) 64 | pathutil (0.16.2) 65 | forwardable-extended (~> 2.6) 66 | public_suffix (6.0.2) 67 | rake (13.3.0) 68 | rb-fsevent (0.11.2) 69 | rb-inotify (0.11.1) 70 | ffi (~> 1.0) 71 | rexml (3.4.4) 72 | rouge (4.6.0) 73 | safe_yaml (1.0.5) 74 | sass-embedded (1.92.1) 75 | google-protobuf (~> 4.31) 76 | rake (>= 13) 77 | sass-embedded (1.92.1-x64-mingw-ucrt) 78 | google-protobuf (~> 4.31) 79 | terminal-table (3.0.2) 80 | unicode-display_width (>= 1.1.1, < 3) 81 | unicode-display_width (2.6.0) 82 | wdm (0.2.0) 83 | webrick (1.9.1) 84 | 85 | PLATFORMS 86 | ruby 87 | x64-mingw-ucrt 88 | 89 | DEPENDENCIES 90 | jekyll (~> 4.4.1) 91 | jekyll-seo-tag (~> 2.8.0) 92 | jekyll-sitemap (~> 1.4.0) 93 | wdm (~> 0.2.0) 94 | 95 | BUNDLED WITH 96 | 2.7.2 97 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | overflow: hidden; 5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; 6 | font-size: 11px; 7 | font-weight: 700; 8 | line-height: 14px; 9 | } 10 | .github-btn { 11 | height: 20px; 12 | overflow: hidden; 13 | } 14 | .gh-btn, 15 | .gh-count, 16 | .gh-ico { 17 | float: left; 18 | } 19 | .gh-btn, 20 | .gh-count { 21 | padding: 2px 5px 2px 4px; 22 | color: #333; 23 | text-decoration: none; 24 | white-space: nowrap; 25 | cursor: pointer; 26 | border-radius: 3px; 27 | } 28 | .gh-btn { 29 | background-color: #eee; 30 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fcfcfc), to(#eee)); 31 | background-image: linear-gradient(to bottom, #fcfcfc 0, #eee 100%); 32 | background-repeat: no-repeat; 33 | border: 1px solid #d5d5d5; 34 | } 35 | .gh-btn:hover, 36 | .gh-btn:focus { 37 | text-decoration: none; 38 | background-color: #ddd; 39 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #eee), to(#ddd)); 40 | background-image: linear-gradient(to bottom, #eee 0, #ddd 100%); 41 | border-color: #ccc; 42 | } 43 | .gh-btn:active { 44 | background-color: #dcdcdc; 45 | background-image: none; 46 | border-color: #b5b5b5; 47 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, .15); 48 | } 49 | .gh-ico { 50 | width: 14px; 51 | height: 14px; 52 | margin-right: 4px; 53 | background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='12 12 40 40'%3e%3cpath fill='%23333' d='M32 13.4c-10.5 0-19 8.5-19 19 0 8.4 5.5 15.5 13 18 1 .2 1.3-.4 1.3-.9v-3.2c-5.3 1.1-6.4-2.6-6.4-2.6-.9-2.1-2.1-2.7-2.1-2.7-1.7-1.2.1-1.1.1-1.1 1.9.1 2.9 2 2.9 2 1.7 2.9 4.5 2.1 5.5 1.6.2-1.2.7-2.1 1.2-2.6-4.2-.5-8.7-2.1-8.7-9.4 0-2.1.7-3.7 2-5.1-.2-.5-.8-2.4.2-5 0 0 1.6-.5 5.2 2 1.5-.4 3.1-.7 4.8-.7 1.6 0 3.3.2 4.7.7 3.6-2.4 5.2-2 5.2-2 1 2.6.4 4.6.2 5 1.2 1.3 2 3 2 5.1 0 7.3-4.5 8.9-8.7 9.4.7.6 1.3 1.7 1.3 3.5v5.2c0 .5.4 1.1 1.3.9 7.5-2.6 13-9.7 13-18.1 0-10.5-8.5-19-19-19z'/%3e%3c/svg%3e") 0 0 / 100% 100% no-repeat; 54 | } 55 | .gh-count { 56 | position: relative; 57 | display: none; /* hidden to start */ 58 | margin-left: 4px; 59 | background-color: #fafafa; 60 | border: 1px solid #d4d4d4; 61 | } 62 | .gh-count:hover, 63 | .gh-count:focus { 64 | color: #0366d6; 65 | } 66 | .gh-count::before, 67 | .gh-count::after { 68 | position: absolute; 69 | display: inline-block; 70 | width: 0; 71 | height: 0; 72 | content: ""; 73 | border-color: transparent; 74 | border-style: solid; 75 | } 76 | .gh-count::before { 77 | top: 50%; 78 | left: -3px; 79 | margin-top: -4px; 80 | border-width: 4px 4px 4px 0; 81 | border-right-color: #fafafa; 82 | } 83 | .gh-count::after { 84 | top: 50%; 85 | left: -4px; 86 | z-index: -1; 87 | margin-top: -5px; 88 | border-width: 5px 5px 5px 0; 89 | border-right-color: #d4d4d4; 90 | } 91 | .github-btn-large { 92 | height: 30px; 93 | } 94 | .github-btn-large .gh-btn, 95 | .github-btn-large .gh-count { 96 | padding: 3px 10px 3px 8px; 97 | font-size: 16px; 98 | line-height: 22px; 99 | border-radius: 4px; 100 | } 101 | .github-btn-large .gh-ico { 102 | width: 20px; 103 | height: 20px; 104 | } 105 | .github-btn-large .gh-count { 106 | margin-left: 6px; 107 | } 108 | .github-btn-large .gh-count::before { 109 | left: -5px; 110 | margin-top: -6px; 111 | border-width: 6px 6px 6px 0; 112 | } 113 | .github-btn-large .gh-count::after { 114 | left: -6px; 115 | margin-top: -7px; 116 | border-width: 7px 7px 7px 0; 117 | } 118 | .no-text .gh-ico { 119 | margin-right: 0; 120 | } 121 | -------------------------------------------------------------------------------- /docs/_sass/_page.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Reset 3 | */ 4 | 5 | * { 6 | -webkit-box-sizing: border-box; 7 | -moz-box-sizing: border-box; 8 | box-sizing: border-box; 9 | } 10 | 11 | html { 12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; 13 | font-size: 16px; 14 | line-height: 1.5; 15 | } 16 | 17 | body { 18 | padding: 1.5rem 1.5rem 3rem; 19 | margin: 0; 20 | font-size: 1rem; 21 | color: #333; 22 | background-color: #fff; 23 | } 24 | 25 | iframe { 26 | overflow: hidden; 27 | border: 0; 28 | } 29 | 30 | h1, 31 | h2 { 32 | margin-top: 0; 33 | line-height: 1; 34 | text-rendering: optimizelegibility; 35 | } 36 | 37 | h1 { 38 | margin-bottom: .5rem; 39 | font-size: 3rem; 40 | } 41 | 42 | h2 { 43 | margin-top: 2rem; 44 | margin-bottom: 1rem; 45 | } 46 | 47 | h3 { 48 | margin-top: 2rem; 49 | margin-bottom: .5rem; 50 | } 51 | 52 | p { 53 | margin-top: 0; 54 | margin-bottom: 1rem; 55 | } 56 | 57 | h1 + p { 58 | font-size: 1.25rem; 59 | color: #555; 60 | } 61 | 62 | a { 63 | color: #0366d6; 64 | text-decoration: none; 65 | 66 | &:hover { 67 | text-decoration: underline; 68 | } 69 | } 70 | 71 | table { 72 | width: 100%; 73 | border-collapse: collapse; 74 | } 75 | 76 | th, 77 | td { 78 | padding: .5rem; 79 | font-size: 90%; 80 | vertical-align: top; 81 | border: 1px solid #eee; 82 | } 83 | 84 | th { 85 | background-color: #f5f5f5; 86 | } 87 | 88 | .deprecated { 89 | display: inline-block; 90 | padding: .25rem .5rem; 91 | font-size: 75%; 92 | font-weight: 700; 93 | line-height: 1.6; 94 | color: #fff; 95 | background-color: #e5271c; 96 | border-radius: .2rem; 97 | } 98 | 99 | /* 100 | * Code 101 | */ 102 | 103 | code, 104 | pre { 105 | font-family: Menlo, "Courier New", monospace; 106 | font-size: 95%; 107 | } 108 | 109 | code { 110 | padding: 2px 4px; 111 | font-size: 85%; 112 | color: #d53049; 113 | background-color: #f7f7f9; 114 | border-radius: .2rem; 115 | } 116 | 117 | pre { 118 | display: block; 119 | margin: 0 0 1rem; 120 | line-height: 1.4; 121 | white-space: pre; 122 | white-space: pre-wrap; 123 | 124 | code { 125 | padding: 0; 126 | color: inherit; 127 | background-color: transparent; 128 | border: 0; 129 | } 130 | } 131 | 132 | .highlight { 133 | padding: 1rem; 134 | margin: 0 0 1rem; 135 | background-color: #f7f7f9; 136 | 137 | pre { 138 | margin-bottom: 0; 139 | word-wrap: break-word; 140 | } 141 | 142 | + .highlight { 143 | margin-top: 1rem; 144 | } 145 | } 146 | 147 | /* 148 | * Download button 149 | */ 150 | 151 | .btn { 152 | display: inline-block; 153 | padding: .5rem 1.25rem; 154 | font-weight: 700; 155 | color: #fff; 156 | text-decoration: none; 157 | background-color: #0366d6; 158 | border: 1px solid #0366d6; 159 | border-radius: 6px; 160 | 161 | &:hover { 162 | text-decoration: none; 163 | background-color: #005cc5; 164 | } 165 | 166 | &:active { 167 | border-color: #005cc5; 168 | box-shadow: inset 0 5px 10px rgba(0, 0, 0, .2); 169 | } 170 | } 171 | 172 | /* 173 | * Masthead 174 | */ 175 | 176 | .tweet-button { 177 | height: 30px; 178 | overflow: hidden; 179 | 180 | + p { 181 | margin-top: 1rem; 182 | color: #767676; 183 | } 184 | } 185 | 186 | 187 | /* 188 | * Grid and columns 189 | */ 190 | 191 | .container { 192 | max-width: 40rem; 193 | margin-right: auto; 194 | margin-left: auto; 195 | } 196 | 197 | 198 | /* 199 | * Misc 200 | */ 201 | 202 | hr { 203 | display: block; 204 | width: 7rem; 205 | height: 1px; 206 | margin: 2.5rem 0; 207 | background-color: #eee; 208 | border: 0; 209 | } 210 | 211 | /* 212 | * Embed spacing 213 | */ 214 | 215 | .example { 216 | margin-bottom: 1rem; 217 | overflow: auto; 218 | 219 | iframe { 220 | display: block; 221 | 222 | + iframe { 223 | margin-top: 1rem; 224 | } 225 | } 226 | } 227 | 228 | @media (min-width: 34em) { 229 | .example { 230 | display: inline-block; 231 | line-height: 30px; 232 | 233 | iframe { 234 | float: left; 235 | 236 | + iframe { 237 | margin-top: 5px; 238 | margin-left: 1rem; 239 | } 240 | } 241 | } 242 | } 243 | 244 | // stylelint-disable-next-line selector-max-id 245 | #markdown-toc li { 246 | margin-bottom: .25rem; 247 | } 248 | -------------------------------------------------------------------------------- /docs/github-btn.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | const allowedQueryParams = new Set(['user', 'repo', 'type', 'count', 'size', 'text', 'v']); 5 | 6 | function getUrlParameters() { 7 | // TODO: Replace with URLSearchParams later 8 | const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); 9 | const parameters = new Map(); 10 | 11 | for (const hash of hashes) { 12 | const [parameter, value] = hash.split('='); 13 | 14 | if (allowedQueryParams.has(parameter)) { 15 | parameters.set(parameter, value); 16 | } 17 | } 18 | 19 | return parameters; 20 | } 21 | 22 | // Add commas to numbers 23 | function addCommas(n) { 24 | // eslint-disable-next-line unicorn/prefer-string-replace-all 25 | return String(n).replace(/(\d)(?=(\d{3})+$)/g, '$1,'); 26 | } 27 | 28 | function jsonp(path) { 29 | const script = document.createElement('script'); 30 | 31 | script.src = `${path}?callback=callback`; 32 | document.head.insertBefore(script, document.head.firstChild); 33 | } 34 | 35 | // Parameters 36 | const parameters = getUrlParameters(); 37 | const user = parameters.get('user'); 38 | const repo = parameters.get('repo'); 39 | const type = parameters.get('type'); 40 | const count = parameters.get('count'); 41 | const size = parameters.get('size'); 42 | const noText = parameters.get('text'); 43 | const v = parameters.get('v'); 44 | 45 | // Elements 46 | const button = document.querySelector('.gh-btn'); 47 | const mainButton = document.querySelector('.github-btn'); 48 | const text = document.querySelector('.gh-text'); 49 | const counter = document.querySelector('.gh-count'); 50 | 51 | // Constants 52 | const LABEL_SUFFIX = 'on GitHub'; 53 | const GITHUB_URL = 'https://github.com/'; 54 | const API_URL = 'https://api.github.com/'; 55 | const REPO_URL = `${GITHUB_URL + user}/${repo}`; 56 | const USER_REPO = `${user}/${repo}`; 57 | 58 | window.callback = function(obj) { 59 | if (obj.data.message === 'Not Found') { 60 | return; 61 | } 62 | 63 | switch (type) { 64 | case 'watch': { 65 | if (v === '2') { 66 | counter.textContent = obj.data.subscribers_count && addCommas(obj.data.subscribers_count); 67 | counter.setAttribute('aria-label', `${counter.textContent} watchers ${LABEL_SUFFIX}`); 68 | } else { 69 | counter.textContent = obj.data.stargazers_count && addCommas(obj.data.stargazers_count); 70 | counter.setAttribute('aria-label', `${counter.textContent} stargazers ${LABEL_SUFFIX}`); 71 | } 72 | 73 | break; 74 | } 75 | 76 | case 'star': { 77 | counter.textContent = obj.data.stargazers_count && addCommas(obj.data.stargazers_count); 78 | counter.setAttribute('aria-label', `${counter.textContent} stargazers ${LABEL_SUFFIX}`); 79 | break; 80 | } 81 | 82 | case 'fork': { 83 | counter.textContent = obj.data.network_count && addCommas(obj.data.network_count); 84 | counter.setAttribute('aria-label', `${counter.textContent} forks ${LABEL_SUFFIX}`); 85 | break; 86 | } 87 | 88 | case 'follow': { 89 | counter.textContent = obj.data.followers && addCommas(obj.data.followers); 90 | counter.setAttribute('aria-label', `${counter.textContent} followers ${LABEL_SUFFIX}`); 91 | break; 92 | } 93 | } 94 | 95 | // Show the count if asked and if it's not empty 96 | if (count === 'true' && counter.textContent !== '') { 97 | counter.style.display = 'block'; 98 | counter.removeAttribute('aria-hidden'); 99 | } 100 | }; 101 | 102 | // Set href to be URL for repo 103 | button.href = REPO_URL; 104 | 105 | let title; 106 | 107 | // Add the class, change the text label, set count link href 108 | switch (type) { 109 | case 'watch': { 110 | if (v === '2') { 111 | mainButton.classList.add('github-watchers'); 112 | text.textContent = 'Watch'; 113 | counter.href = `${REPO_URL}/watchers`; 114 | } else { 115 | mainButton.classList.add('github-stargazers'); 116 | text.textContent = 'Star'; 117 | counter.href = `${REPO_URL}/stargazers`; 118 | } 119 | 120 | title = `${text.textContent} ${USER_REPO}`; 121 | break; 122 | } 123 | 124 | case 'star': { 125 | mainButton.classList.add('github-stargazers'); 126 | text.textContent = 'Star'; 127 | counter.href = `${REPO_URL}/stargazers`; 128 | title = `${text.textContent} ${USER_REPO}`; 129 | break; 130 | } 131 | 132 | case 'fork': { 133 | mainButton.classList.add('github-forks'); 134 | text.textContent = 'Fork'; 135 | button.href = `${REPO_URL}/fork`; 136 | counter.href = `${REPO_URL}/network`; 137 | title = `${text.textContent} ${USER_REPO}`; 138 | break; 139 | } 140 | 141 | case 'follow': { 142 | mainButton.classList.add('github-me'); 143 | text.textContent = `Follow @${user}`; 144 | button.href = GITHUB_URL + user; 145 | counter.href = `${GITHUB_URL + user}?tab=followers`; 146 | title = text.textContent; 147 | break; 148 | } 149 | 150 | case 'sponsor': { 151 | mainButton.classList.add('github-me'); 152 | text.textContent = `Sponsor @${user}`; 153 | button.href = `${GITHUB_URL}sponsors/${user}`; 154 | title = text.textContent; 155 | break; 156 | } 157 | } 158 | 159 | if (noText === 'false') { 160 | button.classList.add('no-text'); 161 | text.setAttribute('aria-hidden', true); 162 | text.style.display = 'none'; 163 | text.textContent = ''; 164 | } 165 | 166 | button.setAttribute('aria-label', `${title} ${LABEL_SUFFIX}`); 167 | document.title = `${title} ${LABEL_SUFFIX}`; 168 | 169 | // Change the size if requested 170 | if (size === 'large') { 171 | mainButton.classList.add('github-btn-large'); 172 | } 173 | 174 | // If count is not requested or type is sponsor, 175 | // there's no need to make an API call 176 | if (count !== 'true' || type === 'sponsor' || noText === 'false') { 177 | return; 178 | } 179 | 180 | if (type === 'follow') { 181 | jsonp(`${API_URL}users/${user}`); 182 | } else { 183 | jsonp(`${API_URL}repos/${user}/${repo}`); 184 | } 185 | })(); 186 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | ## Contents 6 | {:.no_toc} 7 | 8 | * Comment to trigger ToC generation 9 | {:toc} 10 | 11 | --- 12 | 13 | ## Star 14 | 15 | {% capture example %} 16 | 17 | 18 | 19 | {% endcapture %} 20 | {% include example.html content=example %} 21 | 22 | ## Watch 23 | 24 | Originally, GitHub's Watch button was used for notification settings (today's Watch) and repository bookmarking (today's Star). In August 2012, [they split the functionality into two buttons](https://github.blog/2012-08-06-notifications-stars/), after these unofficial buttons were released. 25 | 26 | As such, for today's unofficial Watch button, **you must add `v=2` to the parameters**. If you don't, you'll get [the deprecated button](#deprecated). 27 | 28 | {% capture example %} 29 | 30 | 31 | 32 | {% endcapture %} 33 | {% include example.html content=example %} 34 | 35 | ## Fork 36 | 37 | {% capture example %} 38 | 39 | 40 | 41 | {% endcapture %} 42 | {% include example.html content=example %} 43 | 44 | ## Follow 45 | 46 | {% capture example %} 47 | 48 | 49 | 50 | {% endcapture %} 51 | {% include example.html content=example %} 52 | 53 | ## Sponsor 54 | 55 | {% capture example %} 56 | 57 | 58 | 59 | {% endcapture %} 60 | {% include example.html content=example %} 61 | 62 | ## No text variant 63 | 64 | {% capture example %} 65 | 66 | {% endcapture %} 67 | {% include example.html content=example %} 68 | 69 | --- 70 | 71 | ## Available options 72 | 73 | ### SSL support 74 | 75 | Example buttons are shown with `https://` URLs. While they're hosted on GitHub Pages, the SSL option is provided via [Cloudflare's free Universal SSL](https://blog.cloudflare.com/introducing-universal-ssl/) offering. 76 | 77 | ### Required parameters 78 | 79 | You **must** declare a value for each of the following URL parameters: 80 | 81 | | Option | Description | 82 | | ------ | ----------- | 83 | | `user` | GitHub username that owns the repo/Username to sponsor | 84 | | `repo` | GitHub repository to pull the forks and watchers counts | 85 | | `type` | Type of button to show: `watch`, `fork`, `sponsor`, or `follow` | 86 | 87 | ### Optional parameters 88 | 89 | The following URL parameters are **not** required. Add them as you wish. 90 | 91 | | Option | Description | 92 | | ------ | ----------- | 93 | | `count` | Show the optional watchers or forks count: *none* by default or `true` | 94 | | `size` | Optional flag for using a larger button: *none* by default or `large` | 95 | | `text` | Optional flag for hiding the text: *none* by default or `false` | 96 | 97 | --- 98 | 99 | Deprecated 100 | 101 | ## Original Watch, aka Star 102 | 103 | With the button split in August 2012, GitHub's API continued to return the Star count for old Watch buttons. Thus, the original unofficial Watch button returns a makeshift Star button. 104 | 105 | This deprecated button is still around to avoid breaking every site that currently utilizes these embeds. 106 | 107 | {% capture example %} 108 | 109 | 110 | 111 | {% endcapture %} 112 | {% include example.html content=example %} 113 | 114 | --- 115 | 116 | ## Limitations 117 | 118 | For these first versions, functionality is limited and some concessions made: 119 | 120 | * Mind the GitHub API rate limit which is 60 requests per hour for unauthenticated users. 121 | * Width and height must be specified for all buttons (which actually adds some fun control for people like me). 122 | * Make sure you adapt the snippets to your needs by modifying the parameters and the title. 123 | * All attributes must be passed through via URL parameters. 124 | * CSS and JavaScript are all included in the same HTML file to reduce complexity. 125 | * We include the `frameborder` and `scrolling` attributes by default since we cannot know your setup, but you can optionally remove them and set them yourself via CSS: 126 | 127 | {% highlight css %} 128 | iframe { 129 | overflow: hidden; 130 | border: 0; 131 | } 132 | {% endhighlight %} 133 | 134 | More refinement and functionality is planned with open-sourcing—any help is always appreciated! 135 | 136 | --- 137 | 138 | ## Open source 139 | 140 | The unofficial GitHub buttons are available on GitHub for downloading, forking, or contributing. 141 | 142 |

143 | 144 | 145 |

146 | 147 | View on GitHub 148 | 149 | --- 150 | 151 | ❤️ 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2011 Mark Otto 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------