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>[](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
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
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.