Full Code of antonmedv/spark for AI

master 7cf8fc551f14 cached
13 files
51.6 KB
19.8k tokens
11 symbols
1 requests
Download .txt
Repository: antonmedv/spark
Branch: master
Commit: 7cf8fc551f14
Files: 13
Total size: 51.6 KB

Directory structure:
gitextract_teum0vry/

├── .gitignore
├── README.md
├── api.js
├── db.js
├── index.js
├── package.json
├── page.js
├── queue.js
├── render.js
├── style.css
├── svg.js
├── sync.js
└── ttl.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/node_modules/
.env


================================================
FILE: README.md
================================================
# ⚡️ Spark <img src="https://stars.medv.io/deployphp/deployer.svg" align="right"/>

Go to [stars.medv.io](https://stars.medv.io)

Spark is a generator of pretty little graphs called sparklines, which shows GitHub stars velocity of a repo.

## Development

Clone repo, create _.env_ file with [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/):
```
ACCESS_TOKEN=...
```

Install packages, start server:
```
npm install
node index.js
```

## Rate limit

Spark can't eagerly load all stars of a repo, only 100 stargazers per requset allowed, and GitHub API v4 has rate limit of 5000 points per hour. 

Spark has special endpoint for monitoring remaining rate limit, queue size and processing svg: [stars.medv.io/status](https://stars.medv.io/status)

## Related

- https://github.com/qoomon/starline

## License

MIT


================================================
FILE: api.js
================================================
const delay = require('delay')
const r2 = require('r2')

const token = process.env.ACCESS_TOKEN
const headers = {
  Authorization: `bearer ${token}`
}

async function fetch(query, variables) {
  let data
  do {
    try {

      const response = await r2.post('https://api.github.com/graphql', {
        headers,
        json: {query, variables}
      }).response

      const json = await response.json()

      if (json.data) {
        data = json.data
      } else {

        if (json.message) {
          process.stderr.write(json.message + '\n')
        } else {
          process.stderr.write(JSON.stringify(json) + '\n')
        }

        if (response.headers.has('Retry-After')) {
          const retryAfter = parseInt(response.headers.get('Retry-After'))
          await delay(retryAfter * 1000)
        } else {
          await delay(60 * 1000)
        }

      }

    } catch (err) {
      process.stderr.write(JSON.stringify(json) + '\n')
      await delay(5 * 1000)
    }
  } while (!data)

  return data
}

module.exports = {fetch}


================================================
FILE: db.js
================================================
module.exports = {
  "freeCodeCamp/freeCodeCamp": 291967,
  "twbs/bootstrap": 123665,
  "EbookFoundation/free-programming-books": 103899,
  "tensorflow/tensorflow": 96276,
  "facebook/react": 93486,
  "vuejs/vue": 90762,
  "sindresorhus/awesome": 82886,
  "getify/You-Dont-Know-JS": 79982,
  "d3/d3": 74789,
  "airbnb/javascript": 69412,
  "robbyrussell/oh-my-zsh": 68753,
  "github/gitignore": 64371,
  "facebook/react-native": 62561,
  "jwasham/coding-interview-university": 60616,
  "electron/electron": 58918,
  "angular/angular.js": 58302,
  "torvalds/linux": 57592,
  "FortAwesome/Font-Awesome": 55827,
  "daneden/animate.css": 50628,
  "jquery/jquery": 48660,
  "moby/moby": 48468,
  "vinta/awesome-python": 48435,
  "Microsoft/vscode": 47941,
  "nodejs/node": 47596,
  "kamranahmedse/developer-roadmap": 47131,
  "facebook/create-react-app": 46967,
  "atom/atom": 44391,
  "apple/swift": 43374,
  "laravel/laravel": 42122,
  "mrdoob/three.js": 40970,
  "socketio/socket.io": 40690,
  "Semantic-Org/Semantic-UI": 40679,
  "golang/go": 40273,
  "h5bp/html5-boilerplate": 40215,
  "reactjs/redux": 39939,
  "hakimel/reveal.js": 39882,
  "webpack/webpack": 39860,
  "axios/axios": 39780,
  "meteor/meteor": 39593,
  "rails/rails": 39331,
  "expressjs/express": 37664,
  "moment/moment": 36429,
  "chartjs/Chart.js": 36245,
  "nodejs/node-v0.x-archive": 35921,
  "rg3/youtube-dl": 35900,
  "resume/resume.github.com": 35698,
  "toddmotto/public-apis": 35543,
  "angular/angular": 35067,
  "kubernetes/kubernetes": 35043,
  "mui-org/material-ui": 34936,
  "jakubroztocil/httpie": 34896,
  "nvbn/thefuck": 34760,
  "pallets/flask": 34711,
  "jlevy/the-art-of-command-line": 34536,
  "h5bp/Front-end-Developer-Interview-Questions": 34300,
  "google/material-design-icons": 34253,
  "getlantern/lantern": 34117,
  "jekyll/jekyll": 33940,
  "ionic-team/ionic": 33858,
  "nwjs/nw.js": 33529,
  "impress/impress.js": 33358,
  "x64dbg/x64dbg": 33232,
  "django/django": 33192,
  "Microsoft/TypeScript": 33047,
  "tensorflow/models": 33001,
  "mtdvio/every-programmer-should-know": 32793,
  "ReactiveX/RxJava": 32304,
  "Dogfalo/materialize": 32236,
  "iluwatar/java-design-patterns": 32110,
  "josephmisiti/awesome-machine-learning": 32064,
  "requests/requests": 31725,
  "vuejs/awesome-vue": 31362,
  "ossu/computer-science": 31247,
  "yarnpkg/yarn": 31173,
  "NARKOZ/hacker-scripts": 31155,
  "lodash/lodash": 31045,
  "justjavac/free-programming-books-zh_CN": 31042,
  "AFNetworking/AFNetworking": 30922,
  "necolas/normalize.css": 30623,
  "bitcoin/bitcoin": 30577,
  "typicode/json-server": 30345,
  "GoogleChrome/puppeteer": 30269,
  "elastic/elasticsearch": 30180,
  "google/material-design-lite": 29880,
  "avelino/awesome-go": 29742,
  "ansible/ansible": 29635,
  "ReactTraining/react-router": 29565,
  "wasabeef/awesome-android-ui": 29559,
  "papers-we-love/papers-we-love": 29543,
  "gulpjs/gulp": 29198,
  "adobe/brackets": 28857,
  "firehol/netdata": 28824,
  "blueimp/jQuery-File-Upload": 28585,
  "Homebrew/legacy-homebrew": 28560,
  "antirez/redis": 28521,
  "keras-team/keras": 28244,
  "adam-p/markdown-here": 27980,
  "rust-lang/rust": 27682,
  "Alamofire/Alamofire": 27570,
  "scikit-learn/scikit-learn": 27385,
  "square/retrofit": 27360,
  "zurb/foundation-sites": 27211,
  "jashkenas/backbone": 27104,
  "babel/babel": 27072,
  "thedaviddias/Front-End-Checklist": 27038,
  "ant-design/ant-design": 26940,
  "apache/incubator-echarts": 26919,
  "scrapy/scrapy": 26731,
  "neovim/neovim": 26690,
  "googlesamples/android-architecture": 26559,
  "Trinea/android-open-project": 26470,
  "chrislgarry/Apollo-11": 26319,
  "creationix/nvm": 26079,
  "square/okhttp": 26058,
  "jgthms/bulma": 25902,
  "ElemeFE/element": 25416,
  "TryGhost/Ghost": 25352,
  "google/protobuf": 25225,
  "ariya/phantomjs": 25207,
  "donnemartin/system-design-primer": 25206,
  "vsouza/awesome-ios": 25077,
  "enaqx/awesome-react": 24971,
  "gohugoio/hugo": 24884,
  "tiimgreen/github-cheat-sheet": 24824,
  "discourse/discourse": 24721,
  "FreeCodeCampChina/freecodecamp.cn": 24548,
  "shadowsocks/shadowsocks": 24458,
  "Unitech/pm2": 24269,
  "zeit/next.js": 24248,
  "gogits/gogs": 24192,
  "nylas/nylas-mail": 23977,
  "dypsilon/frontend-dev-bookmarks": 23969,
  "awesomedata/awesome-public-datasets": 23885,
  "johnpapa/angular-styleguide": 23803,
  "lukehoban/es6features": 23794,
  "prakhar1989/awesome-courses": 23768,
  "caolan/async": 23759,
  "opencv/opencv": 23757,
  "BVLC/caffe": 23710,
  "minimaxir/big-list-of-naughty-strings": 23630,
  "joshbuchea/HEAD": 23569,
  "prettier/prettier": 23564,
  "tastejs/todomvc": 23459,
  "google/guava": 23457,
  "spring-projects/spring-boot": 23328,
  "facebook/immutable-js": 23239,
  "sahat/hackathon-starter": 23180,
  "sindresorhus/awesome-nodejs": 23168,
  "alvarotrigo/fullPage.js": 23108,
  "karan/Projects": 23076,
  "serverless/serverless": 22872,
  "lord/slate": 22839,
  "jashkenas/underscore": 22699,
  "storybooks/storybook": 22583,
  "almasaeed2010/AdminLTE": 22550,
  "Modernizr/Modernizr": 22390,
  "Kickball/awesome-selfhosted": 22364,
  "codepath/android_guides": 22291,
  "tonsky/FiraCode": 22223,
  "XX-net/XX-Net": 22205,
  "select2/select2": 22182,
  "kdn251/interviews": 22174,
  "zeit/hyper": 22161,
  "astaxie/build-web-application-with-golang": 21908,
  "JetBrains/kotlin": 21862,
  "certbot/certbot": 21829,
  "git/git": 21829,
  "zenorocha/clipboard.js": 21776,
  "sdmg15/Best-websites-a-programmer-should-visit": 21692,
  "mozilla/pdf.js": 21674,
  "PhilJay/MPAndroidChart": 21600,
  "hexojs/hexo": 21588,
  "harvesthq/chosen": 21549,
  "flutter/flutter": 21540,
  "aymericdamien/TensorFlow-Examples": 21512,
  "fastlane/fastlane": 21405,
  "parcel-bundler/parcel": 21376,
  "Leaflet/Leaflet": 21320,
  "kenwheeler/slick": 21261,
  "bayandin/awesome-awesomeness": 21207,
  "bumptech/glide": 21193,
  "grafana/grafana": 21171,
  "shadowsocks/shadowsocks-windows": 21168,
  "rethinkdb/rethinkdb": 21086,
  "Hack-with-Github/Awesome-Hacking": 21048,
  "photonstorm/phaser": 21043,
  "videojs/video.js": 20869,
  "gatsbyjs/gatsby": 20781,
  "JakeWharton/butterknife": 20742,
  "koajs/koa": 20716,
  "alex/what-happens-when": 20630,
  "gitlabhq/gitlabhq": 20595,
  "kamranahmedse/design-patterns-for-humans": 20494,
  "spring-projects/spring-framework": 20385,
  "yangshun/tech-interview-handbook": 20238,
  "syncthing/syncthing": 20116,
  "airbnb/lottie-android": 20046,
  "juliangarnier/anime": 19820,
  "kelseyhightower/nocode": 19752,
  "nvie/gitflow": 19707,
  "rs/SDWebImage": 19705,
  "k88hudson/git-flight-rules": 19686,
  "Chalarangelo/30-seconds-of-code": 19611,
  "open-guides/og-aws": 19555,
  "Polymer/polymer": 19393,
  "request/request": 19165,
  "FezVrasta/bootstrap-material-design": 19159,
  "square/leakcanary": 19085,
  "herrbischoff/awesome-macos-command-line": 19010,
  "Reactive-Extensions/RxJS": 18929,
  "emberjs/ember.js": 18904,
  "IanLunn/Hover": 18898,
  "facebook/pop": 18820,
  "balderdashy/sails": 18818,
  "mathiasbynens/dotfiles": 18810,
  "apache/incubator-superset": 18775,
  "MaximAbramchuck/awesome-interview-questions": 18650,
  "ReactiveCocoa/ReactiveCocoa": 18597,
  "aosabook/500lines": 18588,
  "ZuzooVn/machine-learning-for-software-engineers": 18559,
  "Bilibili/ijkplayer": 18550,
  "plataformatec/devise": 18503,
  "pure-css/pure": 18488,
  "huginn/huginn": 18488,
  "railsware/upterm": 18464,
  "ripienaar/free-for-dev": 18460,
  "github/fetch": 18454,
  "jondot/awesome-react-native": 18453,
  "ziadoz/awesome-php": 18451,
  "developit/preact": 18398,
  "Tencent/weui": 18330,
  "pixijs/pixi.js": 18305,
  "t4t5/sweetalert": 18278,
  "soimort/you-get": 18211,
  "tipsy/profile-summary-for-github": 18167,
  "postcss/postcss": 18166,
  "hammerjs/hammer.js": 18147,
  "google/web-starter-kit": 18141,
  "zxing/zxing": 18126,
  "ryanmcdermott/clean-code-javascript": 18083,
  "isocpp/CppCoreGuidelines": 18009,
  "GitbookIO/gitbook": 18001,
  "apache/incubator-dubbo": 17976,
  "greenrobot/EventBus": 17933,
  "jaywcjlove/awesome-mac": 17925,
  "danielgindi/Charts": 17925,
  "Prinzhorn/skrollr": 17880,
  "numbbbbb/the-swift-programming-language-in-chinese": 17866,
  "coreos/etcd": 17784,
  "react-boilerplate/react-boilerplate": 17755,
  "freeCodeCamp/devdocs": 17708,
  "tesseract-ocr/tesseract": 17684,
  "bailicangdu/vue2-elm": 17663,
  "quilljs/quill": 17555,
  "bevacqua/dragula": 17513,
  "standard/standard": 17433,
  "FallibleInc/security-guide-for-developers": 17407,
  "kriasoft/react-starter-kit": 17390,
  "RocketChat/Rocket.Chat": 17371,
  "Blankj/AndroidUtilCode": 17295,
  "VundleVim/Vundle.vim": 17278,
  "symfony/symfony": 17277,
  "BradLarson/GPUImage": 17270,
  "ajaxorg/ace": 17268,
  "0xAX/linux-insides": 17253,
  "elsewhencode/project-guidelines": 17238,
  "php/php-src": 17209,
  "racaljk/hosts": 17176,
  "python/cpython": 17156,
  "CyC2018/Interview-Notebook": 17075,
  "exacity/deeplearningbook-chinese": 17075,
  "verekia/js-stack-from-scratch": 17034,
  "kahun/awesome-sysadmin": 16983,
  "SamyPesse/How-to-Make-a-Computer-Operating-System": 16980,
  "dkhamsing/open-source-ios-apps": 16949,
  "angular/angular-cli": 16940,
  "getlantern/forum": 16922,
  "facebook/jest": 16911,
  "apache/spark": 16903,
  "tldr-pages/tldr": 16848,
  "floodsung/Deep-Learning-Papers-Reading-Roadmap": 16795,
  "raywenderlich/swift-algorithm-club": 16778,
  "mholt/caddy": 16736,
  "SwiftyJSON/SwiftyJSON": 16721,
  "ethereum/go-ethereum": 16623,
  "petkaantonov/bluebird": 16611,
  "mbeaudru/modern-js-cheatsheet": 16544,
  "usablica/intro.js": 16521,
  "hashicorp/vagrant": 16519,
  "webtorrent/webtorrent": 16422,
  "alibaba/weex": 16417,
  "pugjs/pug": 16417,
  "houshanren/hangzhou_house_knowledge": 16415,
  "gin-gonic/gin": 16402,
  "akullpp/awesome-java": 16321,
  "getsentry/sentry": 16297,
  "SnapKit/Masonry": 16258,
  "dimsemenov/PhotoSwipe": 16229,
  "Valloric/YouCompleteMe": 16217,
  "ftlabs/fastclick": 16201,
  "futurice/android-best-practices": 16175,
  "angular/material": 16117,
  "facebook/flow": 16114,
  "nostra13/Android-Universal-Image-Loader": 16061,
  "npm/npm": 16047,
  "bcit-ci/CodeIgniter": 15985,
  "nolimits4web/swiper": 15974,
  "markedjs/marked": 15968,
  "rstacruz/nprogress": 15950,
  "knsv/mermaid": 15893,
  "prometheus/prometheus": 15800,
  "defunkt/jquery-pjax": 15759,
  "cheeriojs/cheerio": 15648,
  "ReactiveX/RxAndroid": 15601,
  "jcjohnson/neural-style": 15565,
  "tornadoweb/tornado": 15541,
  "wg/wrk": 15520,
  "dhg/Skeleton": 15489,
  "google/iosched": 15475,
  "less/less.js": 15463,
  "styled-components/styled-components": 15432,
  "dokku/dokku": 15420,
  "Automattic/mongoose": 15414,
  "fouber/blog": 15407,
  "Kong/kong": 15364,
  "bower/bower": 15306,
  "segmentio/nightmare": 15297,
  "square/picasso": 15291,
  "fzaninotto/Faker": 15285,
  "facebook/hhvm": 15252,
  "mochajs/mocha": 15148,
  "twitter/typeahead.js": 15119,
  "DefinitelyTyped/DefinitelyTyped": 15091,
  "postcss/autoprefixer": 15070,
  "facebook/flux": 15048,
  "faif/python-patterns": 14964,
  "parse-community/parse-server": 14954,
  "jlmakes/scrollreveal": 14936,
  "ggreer/the_silver_searcher": 14919,
  "astaxie/beego": 14870,
  "tobiasahlin/SpinKit": 14775,
  "grpc/grpc": 14759,
  "domnikl/DesignPatternsPHP": 14757,
  "CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers": 14721,
  "jashkenas/coffeescript": 14676,
  "syl20bnr/spacemacs": 14666,
  "VincentGarreau/particles.js": 14657,
  "angular-ui/bootstrap": 14634,
  "godotengine/godot": 14623,
  "puikinsh/gentelella": 14526,
  "containous/traefik": 14476,
  "skylot/jadx": 14473,
  "mobxjs/mobx": 14469,
  "CodeHubApp/CodeHub": 14459,
  "kripken/emscripten": 14443,
  "gothinkster/realworld": 14439,
  "reddit-archive/reddit": 14438,
  "julianshapiro/velocity": 14436,
  "jdg/MBProgressHUD": 14414,
  "terryum/awesome-deep-learning-papers": 14393,
  "codemirror/CodeMirror": 14371,
  "facebook/fresco": 14366,
  "twbs/ratchet": 14311,
  "matteocrippa/awesome-swift": 14292,
  "jiahaog/nativefier": 14284,
  "remy/nodemon": 14258,
  "Microsoft/CNTK": 14225,
  "ruby/ruby": 14198,
  "sindresorhus/awesome-electron": 14175,
  "kriskowal/q": 14127,
  "iview/iview": 14093,
  "kennethreitz/python-guide": 14081,
  "zeeshanu/learn-regex": 14055,
  "composer/composer": 14044,
  "pytorch/pytorch": 14014,
  "junegunn/fzf": 13992,
  "hubotio/hubot": 13980,
  "StreisandEffect/streisand": 13957,
  "designmodo/Flat-UI": 13940,
  "shadowsocks/shadowsocks-android": 13922,
  "sequelize/sequelize": 13911,
  "drone/drone": 13901,
  "vuejs/vuex": 13887,
  "angular/material2": 13878,
  "sorrycc/awesome-javascript": 13862,
  "bbatsov/ruby-style-guide": 13828,
  "pandas-dev/pandas": 13824,
  "angular-ui/ui-router": 13815,
  "rwaldron/idiomatic.js": 13809,
  "google/styleguide": 13806,
  "Marak/faker.js": 13790,
  "cmderdev/cmder": 13784,
  "dotnet/corefx": 13758,
  "home-assistant/home-assistant": 13735,
  "limetext/lime": 13722,
  "libgdx/libgdx": 13677,
  "madrobby/zepto": 13670,
  "apache/incubator-mxnet": 13670,
  "julycoding/The-Art-Of-Programming-By-July": 13651,
  "enyo/dropzone": 13623,
  "wangshub/wechat_jump_game": 13600,
  "markerikson/react-redux-links": 13569,
  "facebookresearch/fastText": 13565,
  "netty/netty": 13550,
  "avajs/ava": 13535,
  "HubSpot/pace": 13522,
  "mongodb/mongo": 13499,
  "MostlyAdequate/mostly-adequate-guide": 13457,
  "jasmine/jasmine": 13442,
  "facebookresearch/Detectron": 13434,
  "brillout/awesome-react-components": 13430,
  "justjavac/awesome-wechat-weapp": 13410,
  "yangshun/front-end-interview-handbook": 13401,
  "airbnb/enzyme": 13394,
  "vapor/vapor": 13359,
  "naptha/tesseract.js": 13325,
  "google/leveldb": 13322,
  "airbnb/lottie-ios": 13297,
  "lkzhao/Hero": 13266,
  "i0natan/nodebestpractices": 13264,
  "angular/angular-seed": 13261,
  "ruanyf/jstraining": 13244,
  "Netflix/Hystrix": 13241,
  "alibaba/fastjson": 13201,
  "legomushroom/mojs": 13189,
  "wycats/handlebars.js": 13184,
  "NativeScript/NativeScript": 13171,
  "cockroachdb/cockroach": 13157,
  "xitu/gold-miner": 13138,
  "nefe/You-Dont-Need-jQuery": 13135,
  "GoogleChrome/lighthouse": 13102,
  "inconshreveable/ngrok": 13100,
  "influxdata/influxdb": 13097,
  "jaredhanson/passport": 13096,
  "RubaXa/Sortable": 13081,
  "wsargent/docker-cheat-sheet": 13045,
  "desandro/masonry": 13041,
  "tootsuite/mastodon": 13020,
  "afollestad/material-dialogs": 13009,
  "drduh/macOS-Security-and-Privacy-Guide": 13002,
  "CymChad/BaseRecyclerViewAdapterHelper": 12990,
  "ReactiveX/RxSwift": 12986,
  "riot/riot": 12928,
  "fxsjy/jieba": 12874,
  "chrisbanes/PhotoView": 12858,
  "kilimchoi/engineering-blogs": 12846,
  "amix/vimrc": 12844,
  "feathericons/feather": 12836,
  "PerfectlySoft/Perfect": 12826,
  "Popmotion/popmotion": 12819,
  "redux-saga/redux-saga": 12818,
  "chenglou/react-motion": 12810,
  "wagerfield/parallax": 12807,
  "fffaraz/awesome-cpp": 12803,
  "etsy/statsd": 12791,
  "ipader/SwiftGuide": 12774,
  "react-bootstrap/react-bootstrap": 12758,
  "caskroom/homebrew-cask": 12741,
  "interagent/http-api-design": 12736,
  "braydie/HowToBeAProgrammer": 12730,
  "paularmstrong/normalizr": 12719,
  "elixir-lang/elixir": 12719,
  "ruanyf/react-demos": 12703,
  "git-tips/tips": 12703,
  "donnemartin/interactive-coding-challenges": 12672,
  "ageitgey/face_recognition": 12669,
  "pingcap/tidb": 12649,
  "geekcompany/ResumeSample": 12646,
  "ipython/ipython": 12641,
  "wekan/wekan": 12631,
  "twbs/bootstrap-sass": 12625,
  "github/hub": 12623,
  "facebook/draft-js": 12609,
  "visionmedia/superagent": 12586,
  "ionic-team/ionicons": 12570,
  "danielmiessler/SecLists": 12551,
  "sentsin/layui": 12541,
  "adobe-fonts/source-code-pro": 12512,
  "infernojs/inferno": 12472,
  "facebookarchive/AsyncDisplayKit": 12469,
  "ipfs/ipfs": 12469,
  "keystonejs/keystone": 12466,
  "SnapKit/SnapKit": 12454,
  "graphcool/chromeless": 12427,
  "docker/compose": 12406,
  "altercation/solarized": 12374,
  "ccgus/fmdb": 12374,
  "rollup/rollup": 12357,
  "vim/vim": 12310,
  "guzzle/guzzle": 12281,
  "FormidableLabs/webpack-dashboard": 12275,
  "google/gson": 12270,
  "donnemartin/data-science-ipython-notebooks": 12258,
  "ruanyf/es6tutorial": 12223,
  "mattermost/mattermost-server": 12216,
  "google/xi-editor": 12194,
  "uikit/uikit": 12189,
  "JacksonTian/fks": 12174,
  "gorhill/uBlock": 12131,
  "framework7io/framework7": 12127,
  "alsotang/node-lessons": 12124,
  "fbsamples/f8app": 12123,
  "spf13/spf13-vim": 12122,
  "hyperapp/hyperapp": 12105,
  "yabwe/medium-editor": 12100,
  "MengTo/Spring": 12096,
  "node-inspector/node-inspector": 12084,
  "alebcay/awesome-shell": 12080,
  "reactjs/react-redux": 12066,
  "facebook/osquery": 12056,
  "realm/realm-cocoa": 12045,
  "isagalaev/highlight.js": 12017,
  "buunguyen/octotree": 12012,
  "rapid7/metasploit-framework": 11982,
  "nsqio/nsq": 11964,
  "airyland/vux": 11941,
  "browserify/browserify": 11904,
  "janl/mustache.js": 11878,
  "hashicorp/consul": 11868,
  "yiisoft/yii2": 11843,
  "Homebrew/brew": 11839,
  "ibireme/YYKit": 11822,
  "cocos2d/cocos2d-x": 11798,
  "CoderMJLee/MJRefresh": 11794,
  "diaspora/diaspora": 11791,
  "Bilibili/flv.js": 11774,
  "gruntjs/grunt": 11771,
  "laravel/framework": 11771,
  "hemanth/functional-programming-jargon": 11759,
  "ReactiveX/rxjs": 11759,
  "hashicorp/terraform": 11728,
  "mysqljs/mysql": 11726,
  "ramda/ramda": 11688,
  "localForage/localForage": 11680,
  "iissnan/hexo-theme-next": 11662,
  "Tencent/tinker": 11650,
  "oxford-cs-deepnlp-2017/lectures": 11636,
  "facebook/prepack": 11624,
  "HelloZeroNet/ZeroNet": 11612,
  "phoenixframework/phoenix": 11606,
  "amazeui/amazeui": 11596,
  "bolshchikov/js-must-watch": 11590,
  "textmate/textmate": 11579,
  "dmlc/xgboost": 11563,
  "Developer-Y/cs-video-courses": 11548,
  "lukasz-madon/awesome-remote-job": 11543,
  "substack/stream-handbook": 11521,
  "servo/servo": 11512,
  "benweet/stackedit": 11510,
  "localstack/localstack": 11506,
  "reactnativecn/react-native-guide": 11492,
  "chriskempson/tomorrow-theme": 11484,
  "lhc70000/iina": 11479,
  "requirejs/requirejs": 11477,
  "powerline/fonts": 11473,
  "android10/Android-CleanArchitecture": 11468,
  "nuxt/nuxt.js": 11466,
  "onevcat/Kingfisher": 11444,
  "ampproject/amphtml": 11438,
  "niklasvh/html2canvas": 11435,
  "openai/gym": 11432,
  "airbnb/react-sketchapp": 11373,
  "lgvalle/Material-Animations": 11352,
  "denysdovhan/wtfjs": 11347,
  "Carthage/Carthage": 11344,
  "jgm/pandoc": 11340,
  "fatedier/frp": 11319,
  "tj/git-extras": 11306,
  "jtoy/awesome-tensorflow": 11294,
  "scottjehl/Respond": 11282,
  "hackiftekhar/IQKeyboardManager": 11271,
  "sass/sass": 11262,
  "swagger-api/swagger-ui": 11231,
  "cayleygraph/cayley": 11219,
  "PanJiaChen/vue-element-admin": 11217,
  "JedWatson/react-select": 11211,
  "apache/predictionio": 11200,
  "keon/algorithms": 11188,
  "stedolan/jq": 11177,
  "adobe-webplatform/Snap.svg": 11154,
  "marcuswestin/store.js": 11152,
  "google/flexbox-layout": 11150,
  "h5bp/Effeckt.css": 11147,
  "google/deepdream": 11145,
  "sqlmapproject/sqlmap": 11142,
  "scwang90/SmartRefreshLayout": 11129,
  "Flipboard/react-canvas": 11124,
  "erikras/react-redux-universal-hot-example": 11121,
  "Shopify/dashing": 11111,
  "eslint/eslint": 11103,
  "google/guetzli": 11098,
  "akveo/ngx-admin": 11082,
  "reactjs/reselect": 11064,
  "linnovate/mean": 11039,
  "binux/pyspider": 11038,
  "abhishekbanthia/Public-APIs": 11034,
  "react-navigation/react-navigation": 11023,
  "jessesquires/JSQMessagesViewController": 11018,
  "foreverjs/forever": 11012,
  "viccalexander/Chameleon": 11009,
  "yaronn/blessed-contrib": 10993,
  "shadowsocks/ShadowsocksX-NG": 10989,
  "vuejs/vue-cli": 10985,
  "philipwalton/solved-by-flexbox": 10985,
  "airbnb/lottie-web": 10979,
  "shieldfy/API-Security-Checklist": 10957,
  "ty4z2008/Qix": 10954,
  "Mantle/Mantle": 10952,
  "jfeinstein10/SlidingMenu": 10943,
  "minio/minio": 10937,
  "sampotts/plyr": 10934,
  "cubiq/iscroll": 10930,
  "alibaba/druid": 10907,
  "JohnCoates/Aerial": 10904,
  "frappe/charts": 10895,
  "nickbutcher/plaid": 10885,
  "nagadomi/waifu2x": 10875,
  "jmcunningham/AngularJS-Learning": 10870,
  "PHPMailer/PHPMailer": 10869,
  "selectize/selectize.js": 10868,
  "strongloop/loopback": 10858,
  "SVProgressHUD/SVProgressHUD": 10847,
  "facebook/relay": 10819,
  "tj/commander.js": 10815,
  "WordPress/WordPress": 10797,
  "source-foundry/Hack": 10789,
  "sindresorhus/quick-look-plugins": 10769,
  "loverajoel/jstips": 10740,
  "uxsolutions/bootstrap-datepicker": 10730,
  "pyenv/pyenv": 10728,
  "hzlzh/Best-App": 10700,
  "leereilly/games": 10683,
  "Kotlin/anko": 10656,
  "JuliaLang/julia": 10645,
  "vim-airline/vim-airline": 10645,
  "magicalpanda/MagicalRecord": 10642,
  "Shopify/draggable": 10641,
  "koalaman/shellcheck": 10630,
  "gionkunz/chartist-js": 10619,
  "MrRio/jsPDF": 10613,
  "begriffs/postgrest": 10612,
  "luanfujun/deep-photo-styletransfer": 10574,
  "react-native-training/react-native-elements": 10566,
  "marcuswestin/WebViewJavascriptBridge": 10547,
  "nswbmw/N-blog": 10546,
  "crystal-lang/crystal": 10524,
  "junegunn/vim-plug": 10517,
  "ocornut/imgui": 10504,
  "aurelia/framework": 10482,
  "google/fonts": 10481,
  "ElemeFE/mint-ui": 10473,
  "Tencent/mars": 10461,
  "mitmproxy/mitmproxy": 10452,
  "FFmpeg/FFmpeg": 10438,
  "rbenv/rbenv": 10433,
  "facebook/folly": 10431,
  "nicklockwood/iCarousel": 10402,
  "transloadit/uppy": 10398,
  "VerbalExpressions/JSVerbalExpressions": 10396,
  "equinusocio/material-theme": 10395,
  "chaozh/awesome-blockchain-cn": 10391,
  "grab/front-end-guide": 10389,
  "jquery/jquery-ui": 10388,
  "xgrommx/awesome-redux": 10386,
  "pouchdb/pouchdb": 10386,
  "jwagner/smartcrop.js": 10385,
  "CocoaPods/CocoaPods": 10384,
  "resin-io/etcher": 10374,
  "phanan/htaccess": 10372,
  "DrkSephy/es6-cheatsheet": 10370,
  "bang590/JSPatch": 10346,
  "playframework/playframework": 10340,
  "capistrano/capistrano": 10323,
  "facebook/rocksdb": 10322,
  "froala/design-blocks": 10249,
  "RestKit/RestKit": 10246,
  "AllThingsSmitty/css-protips": 10242,
  "encode/django-rest-framework": 10236,
  "jeromeetienne/AR.js": 10230,
  "androidannotations/androidannotations": 10206,
  "loopj/android-async-http": 10201,
  "pypa/pipenv": 10196,
  "browserstate/history.js": 10185,
  "SeleniumHQ/selenium": 10177,
  "ptmt/react-native-macos": 10162,
  "thomaspark/bootswatch": 10158,
  "CocoaLumberjack/CocoaLumberjack": 10154,
  "dimsemenov/Magnific-Popup": 10139,
  "yudai/gotty": 10138,
  "jwilm/alacritty": 10137,
  "cjwirth/awesome-ios-ui": 10134,
  "davezuko/react-redux-starter-kit": 10132,
  "alcatraz/Alcatraz": 10130,
  "chriso/validator.js": 10129,
  "HubSpot/youmightnotneedjquery": 10125,
  "maxwellito/vivus": 10123,
  "parkjs814/AlgorithmVisualizer": 10120,
  "learn-anything/learn-anything": 10119,
  "dzenbot/DZNEmptyDataSet": 10115,
  "LightTable/LightTable": 10110,
  "jhipster/generator-jhipster": 10110,
  "graphql/graphql-js": 10101,
  "TeamStuQ/skill-map": 10099,
  "emilwallner/Screenshot-to-code-in-Keras": 10094,
  "norvig/pytudes": 10078,
  "php-fig/fig-standards": 10052,
  "octocat/Spoon-Knife": 10051,
  "tpope/vim-pathogen": 10049,
  "scala/scala": 10038,
  "bvaughn/react-virtualized": 10037,
  "go-martini/martini": 10033,
  "nikitavoloboev/my-mac-os": 10033,
  "PHPOffice/PHPExcel": 10032,
  "bmorelli25/Become-A-Full-Stack-Web-Developer": 10031,
  "labstack/echo": 10031,
  "jquery/jquery-mobile": 10023,
  "petehunt/webpack-howto": 10022,
  "winstonjs/winston": 10006,
  "veggiemonk/awesome-docker": 10006,
  "xdissent/ievms": 10006,
  "petehunt/react-howto": 10001,
  "keen/dashboards": 10001,
  "geeeeeeeeek/electronic-wechat": 9988,
  "littlecodersh/ItChat": 9975,
  "dawnlabs/carbon": 9958,
  "PowerShell/PowerShell": 9955,
  "jamiebuilds/the-super-tiny-compiler": 9942,
  "vurtun/nuklear": 9937,
  "acdlite/recompose": 9935,
  "robbiehanson/CocoaAsyncSocket": 9927,
  "sinatra/sinatra": 9924,
  "kangax/fabric.js": 9921,
  "you-dont-need/You-Dont-Need-JavaScript": 9918,
  "daimajia/AndroidSwipeLayout": 9889,
  "kataras/iris": 9880,
  "Automattic/wp-calypso": 9876,
  "allenwong/30DaysofSwift": 9876,
  "so-fancy/diff-so-fancy": 9852,
  "tmux/tmux": 9848,
  "jaredreich/pell": 9833,
  "vuetifyjs/vuetify": 9832,
  "SheetJS/js-xlsx": 9831,
  "fabric/fabric": 9828,
  "BrowserSync/browser-sync": 9826,
  "goldfire/howler.js": 9803,
  "greenrobot/greenDAO": 9775,
  "Seldaek/monolog": 9771,
  "flatpickr/flatpickr": 9769,
  "WickyNilliams/headroom.js": 9768,
  "date-fns/date-fns": 9736,
  "openfaas/faas": 9713,
  "revel/revel": 9708,
  "nicolargo/glances": 9701,
  "JakeWharton/ViewPagerIndicator": 9701,
  "google/ExoPlayer": 9689,
  "addyosmani/backbone-fundamentals": 9675,
  "handsontable/handsontable": 9672,
  "gdi2290/angular-starter": 9664,
  "go-kit/kit": 9651,
  "scrooloose/nerdtree": 9651,
  "cmusatyalab/openface": 9650,
  "CosmicMind/Material": 9648,
  "DmitryBaranovskiy/raphael": 9644,
  "tensorflow/magenta": 9635,
  "sebastianbergmann/phpunit": 9630,
  "jsdom/jsdom": 9629,
  "janpaepke/ScrollMagic": 9625,
  "facebook/yoga": 9620,
  "jessepollak/card": 9618,
  "karma-runner/karma": 9613,
  "OAI/OpenAPI-Specification": 9612,
  "zeit/pkg": 9598,
  "scottjehl/picturefill": 9590,
  "imathis/octopress": 9556,
  "dexteryy/spellbook-of-modern-webdev": 9552,
  "tj/co": 9539,
  "redox-os/redox": 9533,
  "salomonelli/best-resume-ever": 9531,
  "gaearon/redux-devtools": 9529,
  "gabrielecirulli/2048": 9525,
  "phacility/phabricator": 9517,
  "facebook/stetho": 9515,
  "shuzheng/zheng": 9510,
  "css-modules/css-modules": 9510,
  "fish-shell/fish-shell": 9510,
  "kesenhoo/android-training-course-in-chinese": 9501,
  "DrKLO/Telegram": 9494,
  "hdodenhof/CircleImageView": 9491,
  "vuejs/vue-router": 9474,
  "metabase/metabase": 9427,
  "Microsoft/dotnet": 9425,
  "realm/realm-java": 9419,
  "NodeRedis/node_redis": 9413,
  "erikras/redux-form": 9409,
  "svg/svgo": 9395,
  "ochococo/Design-Patterns-In-Swift": 9393,
  "eczarny/spectacle": 9371,
  "jobbole/awesome-python-cn": 9360,
  "hapijs/hapi": 9348,
  "tpope/vim-fugitive": 9343,
  "nodemailer/nodemailer": 9339,
  "jakevdp/PythonDataScienceHandbook": 9325,
  "odoo/odoo": 9315,
  "kailashahirwar/cheatsheets-ai": 9300,
  "peachananr/onepage-scroll": 9295,
  "gztchan/awesome-design": 9294,
  "tabler/tabler": 9292,
  "Konloch/bytecode-viewer": 9287,
  "joewalnes/websocketd": 9278,
  "google/flatbuffers": 9276,
  "daimajia/AndroidViewAnimations": 9262,
  "fivethirtyeight/data": 9259,
  "hehonghui/android-tech-frontier": 9259,
  "googlesamples/android-UniversalMusicPlayer": 9258,
  "signalapp/Signal-Android": 9255,
  "pockethub/PocketHub": 9238,
  "Tencent/wepy": 9237,
  "imakewebthings/waypoints": 9226,
  "roots/sage": 9225,
  "react-community/create-react-native-app": 9213,
  "dotnet/coreclr": 9205,
  "mxcl/PromiseKit": 9204,
  "nlohmann/json": 9203,
  "kevinzhow/PNChart": 9193,
  "elastic/kibana": 9173,
  "celery/celery": 9164,
  "aria2/aria2": 9160,
  "ethereum/wiki": 9159,
  "dotnet/roslyn": 9159,
  "gollum/gollum": 9141,
  "realm/SwiftLint": 9130,
  "spree/spree": 9129,
  "philipwalton/flexbugs": 9118,
  "paperjs/paper.js": 9113,
  "mikepenz/MaterialDrawer": 9107,
  "js-cookie/js-cookie": 9099,
  "luongvo209/Awesome-Linux-Software": 9095,
  "StevenBlack/hosts": 9094,
  "FelisCatus/SwitchyOmega": 9091,
  "obsproject/obs-studio": 9075,
  "nathanmarz/storm": 9075,
  "NetEase/pomelo": 9053,
  "winterbe/java8-tutorial": 9048,
  "matomo-org/matomo": 9041,
  "bitcoinbook/bitcoinbook": 9037,
  "matryer/bitbar": 9035,
  "Matt-Esch/virtual-dom": 9034,
  "stylus/stylus": 9031,
  "google/python-fire": 9024,
  "apenwarr/sshuttle": 9023,
  "channelcat/sanic": 9018,
  "vim-syntastic/syntastic": 9011,
  "Flipboard/FLEX": 9009,
  "spotify/luigi": 9006,
  "karpathy/convnetjs": 8990,
  "lerna/lerna": 8989,
  "fgnass/spin.js": 8986,
  "systemjs/systemjs": 8985,
  "phanan/koel": 8965,
  "kelseyhightower/kubernetes-the-hard-way": 8962,
  "palantir/blueprint": 8956,
  "ncw/rclone": 8956,
  "hashicorp/vault": 8951,
  "liaohuqiu/android-Ultra-Pull-To-Refresh": 8950,
  "Wox-launcher/Wox": 8948,
  "libuv/libuv": 8947,
  "explosion/spaCy": 8938,
  "vasanthk/react-bits": 8938,
  "tonybeltramelli/pix2code": 8937,
  "thoughtbot/paperclip": 8936,
  "tj/n": 8931,
  "binhnguyennus/awesome-scalability": 8922,
  "metafizzy/isotope": 8921,
  "dvajs/dva": 8919,
  "acgotaku/BaiduExporter": 8917,
  "yeoman/yeoman": 8915,
  "bbatsov/rubocop": 8903,
  "sdelements/lets-chat": 8896,
  "rwaldron/johnny-five": 8893,
  "javve/list.js": 8888,
  "apache/incubator-weex": 8884,
  "slimphp/Slim": 8869,
  "getredash/redash": 8869,
  "aFarkas/html5shiv": 8867,
  "uNetworking/uWebSockets": 8866,
  "orhanobut/logger": 8864,
  "google/grumpy": 8860,
  "philc/vimium": 8843,
  "phalcon/cphalcon": 8841,
  "knockout/knockout": 8837,
  "elastic/logstash": 8836,
  "getgrav/grav": 8834,
  "feathersjs/feathers": 8832,
  "powerline/powerline": 8825,
  "sorin-ionescu/prezto": 8825,
  "daylerees/colour-schemes": 8815,
  "Ramotion/animated-tab-bar": 8790,
  "audreyr/favicon-cheat-sheet": 8781,
  "forkingdog/UITableView-FDTemplateLayoutCell": 8775,
  "francistao/LearningNotes": 8771,
  "google/WebFundamentals": 8766,
  "fogleman/primitive": 8765,
  "EnterpriseQualityCoding/FizzBuzzEnterpriseEdition": 8762,
  "dcloudio/mui": 8762,
  "v8/v8": 8760,
  "saltstack/salt": 8756,
  "ant-design/ant-design-pro": 8743,
  "briannesbitt/Carbon": 8741,
  "Rochester-NRT/RocAlphaGo": 8731,
  "datasciencemasters/go": 8731,
  "buger/goreplay": 8713,
  "ccampbell/mousetrap": 8710,
  "gaearon/react-hot-loader": 8702,
  "deeplearning4j/deeplearning4j": 8701,
  "bazelbuild/bazel": 8699,
  "WebAssembly/design": 8694,
  "ksoichiro/Android-ObservableScrollView": 8689,
  "Netflix/falcor": 8688,
  "akveo/blur-admin": 8682,
  "byoungd/English-level-up-tips-for-Chinese": 8681,
  "zyedidia/micro": 8674,
  "recharts/recharts": 8673,
  "navasmdc/MaterialDesignLibrary": 8668,
  "docker/kitematic": 8663,
  "jquery-validation/jquery-validation": 8650,
  "chalk/chalk": 8645,
  "fullstackio/FlappySwift": 8637,
  "airbnb/lottie-react-native": 8634,
  "chrisbanes/Android-PullToRefresh": 8633,
  "Microsoft/monaco-editor": 8628,
  "ApolloAuto/apollo": 8624,
  "OpenEmu/OpenEmu": 8623,
  "basecamp/trix": 8619,
  "markets/awesome-ruby": 8605,
  "Hacker0x01/hacker101": 8597,
  "NodeBB/NodeBB": 8596,
  "zenorocha/alfred-workflows": 8590,
  "nfarina/homebridge": 8583,
  "nodejitsu/node-http-proxy": 8581,
  "thoughtbot/bourbon": 8577,
  "jinzhu/gorm": 8573,
  "golang/dep": 8567,
  "wulkano/kap": 8560,
  "BurntSushi/ripgrep": 8558,
  "apple/swift-evolution": 8558,
  "dropbox/zxcvbn": 8556,
  "Moya/Moya": 8546,
  "ConnorAtherton/loaders.css": 8531,
  "mperham/sidekiq": 8528,
  "MithrilJS/mithril.js": 8523,
  "raywenderlich/swift-style-guide": 8522,
  "NUKnightLab/TimelineJS": 8517,
  "necolas/react-native-web": 8516,
  "gfwlist/gfwlist": 8514,
  "mxgmn/WaveFunctionCollapse": 8499,
  "ChristosChristofidis/awesome-deep-learning": 8490,
  "chentsulin/electron-react-boilerplate": 8488,
  "gaearon/redux-thunk": 8485,
  "mishoo/UglifyJS2": 8481,
  "shichuan/javascript-patterns": 8477,
  "carhartl/jquery-cookie": 8474,
  "onevcat/VVDocumenter-Xcode": 8468,
  "alibaba/p3c": 8458,
  "facebook/Shimmer": 8456,
  "swoole/swoole-src": 8452,
  "alexjc/neural-doodle": 8442,
  "FezVrasta/popper.js": 8438,
  "sqlitebrowser/sqlitebrowser": 8426,
  "chinese-poetry/chinese-poetry": 8425,
  "guillaumepotier/Parsley.js": 8424,
  "ruby-grape/grape": 8423,
  "jordansissel/fpm": 8422,
  "kubernetes/minikube": 8421,
  "akka/akka": 8420,
  "GeekyAnts/NativeBase": 8416,
  "StackExchange/Dapper": 8389,
  "purifycss/purifycss": 8386,
  "coryhouse/react-slingshot": 8381,
  "slackhq/SlackTextViewController": 8372,
  "irungentoo/toxcore": 8366,
  "boltdb/bolt": 8357,
  "Idnan/bash-guide": 8345,
  "Automattic/_s": 8313,
  "mhinz/vim-galore": 8310,
  "teamcapybara/capybara": 8310,
  "fatih/vim-go": 8306,
  "rasbt/python-machine-learning-book": 8304,
  "facebook/infer": 8298,
  "sindresorhus/pageres": 8296,
  "cyclejs/cyclejs": 8278,
  "mbadolato/iTerm2-Color-Schemes": 8274,
  "qrohlf/trianglify": 8257,
  "connors/photon": 8255,
  "jikexueyuanwiki/tensorflow-zh": 8251,
  "afaqurk/linux-dash": 8250,
  "websockets/ws": 8249,
  "nosir/cleave.js": 8238,
  "arasatasaygin/is.js": 8236,
  "aFarkas/lazysizes": 8228,
  "1c7/chinese-independent-developer": 8199
}


================================================
FILE: index.js
================================================
require('dotenv').config()
const koa = require('koa')
const route = require('koa-route')
const serve = require('koa-static')
const fs = require('mz/fs')
const {createTextSvg} = require('./svg')
const {total, rateLimit} = require('./render')
const queue = require('./queue')
const page = require('./page')
const ttl = require('./ttl')

const app = new koa()
queue.worker()
app.use(serve('public'));

app.use(route.get('/:owner/:name.svg', async (ctx, owner, name) => {
  ctx.type = 'image/svg+xml; charset=utf-8'

  const repo = `${owner}/${name}`
  const path = `svg/${owner}/${name}.svg`.toLowerCase()

  let stats
  try {
    const maxAge = ttl(repo)
    stats = await fs.stat(path)

    ctx.set('Last-Modified', stats.mtime.toUTCString())
    ctx.set('Cache-Control', 'max-age=' + maxAge)
    ctx.body = fs.createReadStream(path)

    const now = new Date().getTime()
    const mtime = stats.mtime.getTime()

    if (now - mtime > maxAge * 1000) {
      queue.push(path, owner, name)
    }

  } catch (err) {
    if (err.code === 'ENOENT') {
      queue.push(path, owner, name)

      const p = total.get(path)
      if (p) {
        ctx.body = createTextSvg(`⚡️ loading stars ${p}%`)
      } else {
        ctx.body = createTextSvg(`👋️ waiting in queue ${queue.indexOf(path) + 1}`)
      }
    } else {
      ctx.body = createTextSvg(`⚠️ error`)
    }
  }
}))

app.use(route.get('/', async (ctx) => {
  if (ctx.query.repo) {
    ctx.redirect('/' + ctx.query.repo)
  } else {
    ctx.type = 'text/html'
    ctx.body = page.index()
  }
}))

app.use(route.get('/:owner/:name', async (ctx, owner, name) => {
  ctx.type = 'text/html'
  ctx.body = page.repo({owner, name})
}))

app.use(route.get('/status', async (ctx) => {
  ctx.type = 'application/json'
  ctx.body = {
    queueSize: queue.size(),
    processing: [...total.keys()],
    rateLimit: rateLimit.remaining
  }
}))

const port = process.env.PORT || 3000
app.listen(port)
console.log('App started on port ' + port)


================================================
FILE: package.json
================================================
{
  "name": "@medv/spark",
  "version": "1.0.0",
  "description": "GitHub Stars Sparklines",
  "main": "index.js",
  "author": "Anton Medvedev <anton@medv.io>",
  "repository": "antonmedv/spark",
  "license": "MIT",
  "dependencies": {
    "delay": "^2.0.0",
    "dotenv": "^5.0.1",
    "koa": "^2.5.0",
    "koa-route": "^3.2.0",
    "koa-static": "^4.0.2",
    "mz": "^2.7.0",
    "r2": "^2.0.1"
  }
}


================================================
FILE: page.js
================================================
const style = require('fs').readFileSync('style.css')
const rand = () => Math.round(100 * Math.random())

const layout = (content) => `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>⚡️ GitHub Stars Sparklines</title>
  <meta name="description" content="⚡️ Spark is GitHub stars graph generator, it plots tiny little graph called sparkline, which reflects the growth rate of stars on GitHub thought history.">
  <meta name="viewport" content="width=device-width, user-scalable=yes">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon.png">
  <style>
    ${style}
  </style>
  <style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
  <script async src="https://www.googletagmanager.com/gtag/js?id=UA-72806543-2"></script>
  <script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
  
    gtag('config', 'UA-72806543-2');
  </script>
</head>
<body>
  <a href="https://github.com/antonmedv/spark" class="github-corner" aria-label="View source on Github">
    <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#70B7FD; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg>
  </a>
  <div class="content">
    ${content}
  </div>
  <div class="r">
    <div class="r1" style="${`top: ${rand()}vh; left: ${rand()}vw`}"></div>
    <div class="r2" style="${`top: ${rand()}vh; left: ${rand()}vw`}"></div>
    <div class="r3" style="${`top: ${rand()}vh; left: ${rand()}vw`}"></div>
    <div class="r4" style="${`top: ${rand()}vh; left: ${rand()}vw`}"></div>
  </div>
</body>
</html>
`

const box = (owner, name) => {
  let title = owner + '/' + name
  if (title.length > 20) {
    title = name
  }
  return `
    <div class="box">
      <div class="name">${title}</div>
      <img class="spark" src="/${owner + '/' + name}.svg"/>
    </div>
  `
}

const a = (path) => {
  const [owner, name] = path.split('/')
  return `
    <a href="/${owner + '/' + name}">
      ${box(owner, name)}
    </a>  
  `
}

const h1 = () => `<h1><a href="/">⚡️ Spark </a><span>GitHub Stars Sparklines</span></h1>`

exports.index = () => layout(`
${h1()}
<div class="grid">
  ${a('facebook/react')}
  ${a('angular/angular')}
  ${a('vuejs/vue')}
  ${a('freeCodeCamp/freeCodeCamp')}
  ${a('jquery/jquery')}
  ${a('twbs/bootstrap')}
  ${a('rails/rails')}
  ${a('FortAwesome/Font-Awesome')}
  ${a('jashkenas/backbone')}
  ${a('php/php-src')}
  ${a('nodejs/node')}
  ${a('torvalds/linux')}
  ${a('moby/moby')}
  ${a('laravel/laravel')}
  ${a('reactjs/redux')}
  ${a('d3/d3')}
  ${a('axios/axios')}
  ${a('robbyrussell/oh-my-zsh')}
  ${a('facebook/react-native')}
  ${a('meteor/meteor')}
</div>
<div class="add-repo">
  <form method="get">
    <label for="repo">Create sparkline for any repo:</label>
    <input id="repo" name="repo" type="text" placeholder="owner/repo">
    <button type="submit">Let's Go 🔮</button>
  </form>
</div>
`)


exports.repo = ({owner, name}) => layout(`
${h1()}
<div class="one">
  <a class="one-link" href="https://github.com/${owner + '/' + name}">   
    ${box(owner, name)}
  </a>
  <p>
    The Sparkline shows GitHub stars velocity of <em>${owner + '/' + name}</em> repo for the entire lifetime of the repository.
    <br>
    <br>
    Add the Sparkline to repo's readme, copy markdown code below.
  </p>
  <code>[![Sparkline](https://stars.medv.io/${owner + '/' + name}.svg)](https://stars.medv.io/${owner + '/' + name})</code>
</div>
`)


================================================
FILE: queue.js
================================================
const {render} = require('./render')
const delay = require('delay')

const queue = []
const set = new Set()

function size() {
  return queue.length
}

async function worker() {
  do {
    try {
      const work = queue.shift()
      if (work) {
        const [path, owner, name] = work

        await render(path, owner, name)

        set.delete(path)
      } else {
        await delay(100)
      }
    } catch (err) {
      console.error(err)
    }
  } while (true)
}

function push(path, owner, name) {
  if (!set.has(path)) {
    queue.push([path, owner, name])
    set.add(path)
  }
}

function indexOf(path) {
  return queue.findIndex(([p]) => path === p)
}

module.exports = {worker, push, size, indexOf}


================================================
FILE: render.js
================================================
const {dirname} = require('path')
const fs = require('mz/fs')
const {fetch} = require('./api')
const {createSvg} = require('./svg')

const total = new Map()

const query = `
  query($owner: String!, $name: String!, $endCursor: String) {
    repository(owner: $owner, name: $name) {
      stargazers(first: 100, after: $endCursor) {
        totalCount
        edges {
          starredAt
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
    rateLimit {
      remaining
    }  
  }
`

let rateLimit = {
  remaining: 5000
}

async function render(path, owner, name) {
  total.set(path, 0)

  const data = await fetch(query, {owner, name})

  if (data.repository) {
    let {
      stargazers: {
        totalCount,
        edges: dates,
        pageInfo: {hasNextPage, endCursor}
      }
    } = data.repository

    while (hasNextPage) {
      total.set(path, Math.round(100 * dates.length / totalCount))
      console.log(`${owner}/${name}: ${total.get(path)}%`)

      const data = await fetch(query, {owner, name, endCursor})

      hasNextPage = data.repository.stargazers.pageInfo.hasNextPage
      endCursor = data.repository.stargazers.pageInfo.endCursor
      rateLimit.remaining = data.rateLimit.remaining

      dates = dates.concat(data.repository.stargazers.edges)
    }

    dates = dates.map(({starredAt}) => +(new Date(starredAt)))

    const svg = createSvg(dates)

    const dir = dirname(path)
    await fs.exists(dir) || await fs.mkdir(dir)

    fs.writeFile(path, svg)
  }

  total.delete(path)
}

module.exports = {render, total, rateLimit}


================================================
FILE: style.css
================================================
html {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

*, *:before, *:after {
    -webkit-box-sizing: inherit;
    -moz-box-sizing: inherit;
    box-sizing: inherit;
    padding: 0;
    margin: 0;
}

body {
    font-family: Helvetica, serif;
    font-size: 14px;
    line-height: 1.5;
    color: rgba(0, 0, 0, .65);
    background-color: #f9fbff;
}

.content {
    display: flex;
    flex-direction: column;
    margin: 40px auto;
    padding-left: 20px;
    padding-right: 20px;
    max-width: 1400px;
}

h1 {
    margin-bottom: 50px;
    font-size: 32px;
}

h1 > span {
    font-size: 16px;
    font-weight: normal;
}

@media only screen and (max-device-width: 350px) {
    h1 > span {
        display: block;
    }
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    grid-gap: 15px 15px;
}

a {
    color: inherit;
    text-decoration: none;
}

.box {
    display: flex;
    flex-direction: column;
    padding: 10px 15px;
    white-space: nowrap;
    font-size: 16px;
    font-weight: 500;
    color: inherit;
    background: #fff;
    border-radius: 3px;
    -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
    -webkit-transition: all .3s cubic-bezier(.25, .8, .25, 1);
    -o-transition: all .3s cubic-bezier(.25, .8, .25, 1);
    transition: all .3s cubic-bezier(.25, .8, .25, 1);
}

.box:hover {
    text-decoration: none;
    color: inherit;
    -webkit-transform: scale(1.01);
    -ms-transform: scale(1.01);
    transform: scale(1.01);
    -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, .19), 0 6px 6px rgba(0, 0, 0, .23);
    box-shadow: 0 10px 20px rgba(0, 0, 0, .19), 0 6px 6px rgba(0, 0, 0, .23);
}

.name {
    font-weight: 500;
    font-size: 18px;
    margin-bottom: 5px;
    padding-left: 20px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='currentColor' preserveAspectRatio='xMidYMid meet' height='1em' width='1em' viewBox='0 0 40 40' style='vertical-align: middle;'%3E%3Cg%3E%3Cpath d='m17.5 10h-2.5v2.5h2.5v-2.5z m0-5h-2.5v2.5h2.5v-2.5z m15-5h-25s-2.5 1.3-2.5 2.5v30s1.3 2.5 2.5 2.5h5v5l3.8-3.7 3.7 3.7v-5h12.5s2.5-1.2 2.5-2.5v-30s-1.2-2.5-2.5-2.5z m0 31.3c0 0.6-0.6 1.2-1.2 1.2h-11.3v-2.5h-7.5v2.5h-3.7s-1.3-0.7-1.3-1.2v-3.8h25v3.8z m0-6.3h-20v-22.5h20l0 22.5z m-15-5h-2.5v2.5h2.5v-2.5z m0-5h-2.5v2.5h2.5v-2.5z'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
    background-position: 0 8px;
    background-repeat: no-repeat;
    overflow-x: hidden;
    -o-text-overflow: ellipsis;
    text-overflow: ellipsis;
}

.spark {
    width: 200px;
    align-self: center;
}

.one {
    display: flex;
    flex-direction: column;
}

.one-link {
    display: inline-block;
    align-self: center;
    margin-top: 30px;
    margin-bottom: 60px;
    transform: scale(1.5);
}

.one > p {
    display: block;
    font-size: 16px;
    margin-top: 10px;
    max-width: 600px;
    align-self: center;    
}

code {
    margin-top: 40px;
    padding: 10px 15px;
    max-width: 600px;
    overflow-x: scroll;
    align-self: center;
    white-space: nowrap;
    font-family: monospace;
    background-color: #eeeeee;
}

@media only screen and (max-device-width: 812px) {
    code {
        width: 100%;
        max-width: none;
    }
}

.add-repo {
    margin-top: 90px;
    align-self: center;
}

.add-repo label {
    display: block;
    padding: 5px;
    font-size: 16px;
    text-align: center;
}

.add-repo input[type="text"] {
    border: none;
    border-radius: 4px;
    outline: none;
    padding: 10px 17px;
    font-family: monospace;
    font-size: 16px;
    width: 200px;
    background-color: #fff;
    box-shadow: 2px 5px 10px rgb(228, 228, 228);
}

.add-repo button {
    margin: 10px;
    padding: 12px 12px;
    cursor: pointer;
    user-select: none;
    text-align: center;
    white-space: nowrap;
    border: 0 none;
    border-radius: 4px;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.3;
    -webkit-appearance: none;
    -moz-appearance: none;
    box-shadow: 2px 5px 10px rgb(228, 228, 228);
    color: #7e8091;
    background-color: #fff;
    transition: background-color 150ms linear;
}

.add-repo button:hover {
    background-color: #f2f2f2;
}

.r {
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    position: absolute;
    z-index: -1;
    overflow: hidden;
}

.r1, .r2, .r3, .r4{
    position: relative;
    width: 50px;
    height: 50px;
    border-radius: 100%;
    border: solid 12px #fc607f;
}

.r2 {
    border-color: #4580fe;
}

.r3 {
    border-color: #fcb84d;
}

.r4 {
    border-color: #78faca;
    border-radius: 0;
}


================================================
FILE: svg.js
================================================
const height = 30
const x0 = 5
const y0 = 40
const steps = 40
const dx = 5
const basis = 1.5
const gradient = ['#3023AE', '#C86DD7']

const round = num => Math.round(num * 100) / 100
const vec = (x, y) => ({
  x, y,
  toString() {
    return `${round(this.x)} ${round(this.y)}`
  }
})
const norm = v => Math.sqrt(v.x * v.x + v.y * v.y)
const unit = v => {
  const n = norm(v)
  return vec(basis * v.x / n, basis * v.y / n)
}
const add = (a, b) => vec(a.x + b.x, a.y + b.y)
const sub = (a, b) => vec(a.x - b.x, a.y - b.y)
const end = px => px[px.length - 1]

function createSvg(data) {
  if (data.length <= steps) {
    return createTextSvg('⭐️ not enough stars')
  }

  const min = data[0]
  const max = end(data)
  const step = (max - min) / steps

  const yx = []
  {
    let i = min
    let count = 0
    for (let d of data) {
      if (d < i + step) {
        count++
      } else {
        yx.push(count)
        count = 1
        i += step
      }
    }
  }

  const scale = Math.max(...yx) / height
  {
    for (let i = 0; i < yx.length; i++) {
      yx[i] = round(yx[i] / scale)
    }
  }

  const points = []
  {
    let x = x0
    for (let y of yx) {
      x += dx
      points.push(vec(x, y0 - y))
    }
  }

  const p0 = vec(x0, y0)
  const p1 = points[0]
  const p2 = points[1]
  const c1 = add(p0, unit(sub(p1, p0)))
  const c2 = add(p1, unit(sub(p0, p2)))
  let path = `M${p0} C ${c1}, ${c2}, ${p1}`

  for (let i = 1; i < points.length; i++) {
    const p0 = points[i - 1]
    const p1 = points[i]
    const p2 = points[i + 1] || p1
    const c = add(p1, unit(sub(p0, p2)))
    path += ` S ${c}, ${p1}`
  }

  const pN = end(points)

  return `<svg width="200" height="50" viewBox="0 0 210 50" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="a">
            <stop stop-color="${gradient[0]}" offset="0%"/>
            <stop stop-color="${gradient[1]}" offset="100%"/>
        </linearGradient>
    </defs>
    <path stroke="url(#a)"
          stroke-width="3"
          stroke-linejoin="round"
          stroke-linecap="round"
          d="${path}"
          fill="none"/>
    <circle r="4" cx="${p0.x}" cy="${p0.y}" fill="${gradient[0]}"/>
    <circle r="4" cx="${pN.x}" cy="${pN.y}" fill="${gradient[1]}"/>      
</svg>`
}

function createTextSvg(text) {
  return `<svg width="200" height="50" viewBox="0 0 210 50" xmlns="http://www.w3.org/2000/svg">
    <text x="40" y="30">${text}</text>     
</svg>`
}

module.exports = {createSvg, createTextSvg}


================================================
FILE: sync.js
================================================
require('dotenv').config()
const fs = require('mz/fs')
const {fetch} = require('./api')

const query = `
  query ($endCursor: String) {
    search(type: REPOSITORY, query: "stars:>8000", first: 100, after: $endCursor) {
      repositoryCount
      nodes {
        ... on Repository {
          owner {
            login
          }
          name
          stargazers {
            totalCount
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
`

async function main() {
  let {
    search: {
      repositoryCount,
      nodes,
      pageInfo: {hasNextPage, endCursor}
    }
  } = await fetch(query)

  while (hasNextPage) {
    const pt = Math.round(100 * nodes.length / repositoryCount)
    console.log(`loading ${pt}%  ${nodes.length}/${repositoryCount}`)

    const data = await fetch(query, {endCursor})

    endCursor = data.search.pageInfo.endCursor
    hasNextPage = data.search.pageInfo.hasNextPage
    nodes = nodes.concat(data.search.nodes)
  }

  console.log('Total repos: ' + nodes.length)

  const db = {}

  for (let node of nodes) {
    const {
      owner: {login},
      name,
      stargazers: {totalCount}
    } = node

    db[login + '/' + name] = totalCount
  }

  fs.writeFile('db.js', `module.exports = ${JSON.stringify(db, null, 2)}\n`)
}

main().catch(console.log)


================================================
FILE: ttl.js
================================================
const db = require('./db')

function ttl(repo) {
  const stars = db[repo] || 0

  if (stars > 10000) {
    return 604800 // one week
  } else if (stars > 8000) {
    return 3 * 86400 // three days
  } else {
    return 86400 // one day
  }
}

module.exports = ttl
Download .txt
gitextract_teum0vry/

├── .gitignore
├── README.md
├── api.js
├── db.js
├── index.js
├── package.json
├── page.js
├── queue.js
├── render.js
├── style.css
├── svg.js
├── sync.js
└── ttl.js
Download .txt
SYMBOL INDEX (11 symbols across 6 files)

FILE: api.js
  function fetch (line 9) | async function fetch(query, variables) {

FILE: queue.js
  function size (line 7) | function size() {
  function worker (line 11) | async function worker() {
  function push (line 30) | function push(path, owner, name) {
  function indexOf (line 37) | function indexOf(path) {

FILE: render.js
  function render (line 32) | async function render(path, owner, name) {

FILE: svg.js
  method toString (line 12) | toString() {
  function createSvg (line 25) | function createSvg(data) {
  function createTextSvg (line 100) | function createTextSvg(text) {

FILE: sync.js
  function main (line 28) | async function main() {

FILE: ttl.js
  function ttl (line 3) | function ttl(repo) {
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (57K chars).
[
  {
    "path": ".gitignore",
    "chars": 20,
    "preview": "/node_modules/\n.env\n"
  },
  {
    "path": "README.md",
    "chars": 876,
    "preview": "# ⚡️ Spark <img src=\"https://stars.medv.io/deployphp/deployer.svg\" align=\"right\"/>\n\nGo to [stars.medv.io](https://stars."
  },
  {
    "path": "api.js",
    "chars": 1046,
    "preview": "const delay = require('delay')\nconst r2 = require('r2')\n\nconst token = process.env.ACCESS_TOKEN\nconst headers = {\n  Auth"
  },
  {
    "path": "db.js",
    "chars": 32506,
    "preview": "module.exports = {\n  \"freeCodeCamp/freeCodeCamp\": 291967,\n  \"twbs/bootstrap\": 123665,\n  \"EbookFoundation/free-programmin"
  },
  {
    "path": "index.js",
    "chars": 1975,
    "preview": "require('dotenv').config()\nconst koa = require('koa')\nconst route = require('koa-route')\nconst serve = require('koa-stat"
  },
  {
    "path": "package.json",
    "chars": 404,
    "preview": "{\n  \"name\": \"@medv/spark\",\n  \"version\": \"1.0.0\",\n  \"description\": \"GitHub Stars Sparklines\",\n  \"main\": \"index.js\",\n  \"au"
  },
  {
    "path": "page.js",
    "chars": 4793,
    "preview": "const style = require('fs').readFileSync('style.css')\nconst rand = () => Math.round(100 * Math.random())\n\nconst layout ="
  },
  {
    "path": "queue.js",
    "chars": 714,
    "preview": "const {render} = require('./render')\nconst delay = require('delay')\n\nconst queue = []\nconst set = new Set()\n\nfunction si"
  },
  {
    "path": "render.js",
    "chars": 1606,
    "preview": "const {dirname} = require('path')\nconst fs = require('mz/fs')\nconst {fetch} = require('./api')\nconst {createSvg} = requi"
  },
  {
    "path": "style.css",
    "chars": 4731,
    "preview": "html {\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n*, *:before, "
  },
  {
    "path": "svg.js",
    "chars": 2529,
    "preview": "const height = 30\nconst x0 = 5\nconst y0 = 40\nconst steps = 40\nconst dx = 5\nconst basis = 1.5\nconst gradient = ['#3023AE'"
  },
  {
    "path": "sync.js",
    "chars": 1344,
    "preview": "require('dotenv').config()\nconst fs = require('mz/fs')\nconst {fetch} = require('./api')\n\nconst query = `\n  query ($endCu"
  },
  {
    "path": "ttl.js",
    "chars": 264,
    "preview": "const db = require('./db')\n\nfunction ttl(repo) {\n  const stars = db[repo] || 0\n\n  if (stars > 10000) {\n    return 604800"
  }
]

About this extraction

This page contains the full source code of the antonmedv/spark GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (51.6 KB), approximately 19.8k tokens, and a symbol index with 11 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!